about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--doc/manual/expressions/language-values.xml9
-rw-r--r--src/libexpr/eval.cc3
-rw-r--r--src/libexpr/lexer.l2
-rw-r--r--src/libexpr/parser.y3
4 files changed, 14 insertions, 3 deletions
diff --git a/doc/manual/expressions/language-values.xml b/doc/manual/expressions/language-values.xml
index c3514e58f0de..0bf6632d6e3a 100644
--- a/doc/manual/expressions/language-values.xml
+++ b/doc/manual/expressions/language-values.xml
@@ -155,7 +155,14 @@ stdenv.mkDerivation {
   expression that contained it.  For instance, if a Nix expression in
   <filename>/foo/bar/bla.nix</filename> refers to
   <filename>../xyzzy/fnord.nix</filename>, the absolute path is
-  <filename>/foo/xyzzy/fnord.nix</filename>.</para></listitem>
+  <filename>/foo/xyzzy/fnord.nix</filename>.</para>
+
+  <para>If the first component of a path is a <literal>~</literal>,
+  it is interpreted as if the rest of the path were relative to the
+  user's home directory. e.g. <filename>~/foo</filename> would be
+  equivalent to <filename>/home/edolstra/foo</filename> for a user
+  whose home directory is <filename>/home/edolstra</filename>.
+  </para></listitem>
 
   <listitem><para><emphasis>Booleans</emphasis> with values
   <literal>true</literal> and
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 298f6a3a60e3..95b56e84d89a 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -1174,7 +1174,8 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
     else if (firstType == tPath) {
         if (!context.empty())
             throwEvalError("a string that refers to a store path cannot be appended to a path, at %1%", pos);
-        mkPath(v, s.str().c_str());
+        auto path = canonPath(s.str());
+        mkPath(v, path.c_str());
     } else
         mkString(v, s.str(), context);
 }
diff --git a/src/libexpr/lexer.l b/src/libexpr/lexer.l
index 82520ee7a59a..7051909008d1 100644
--- a/src/libexpr/lexer.l
+++ b/src/libexpr/lexer.l
@@ -80,6 +80,7 @@ static Expr * unescapeStr(SymbolTable & symbols, const char * s)
 ID          [a-zA-Z\_][a-zA-Z0-9\_\'\-]*
 INT         [0-9]+
 PATH        [a-zA-Z0-9\.\_\-\+]*(\/[a-zA-Z0-9\.\_\-\+]+)+
+HPATH       \~(\/[a-zA-Z0-9\.\_\-\+]+)+
 SPATH       \<[a-zA-Z0-9\.\_\-\+]+(\/[a-zA-Z0-9\.\_\-\+]+)*\>
 URI         [a-zA-Z][a-zA-Z0-9\+\-\.]*\:[a-zA-Z0-9\%\/\?\:\@\&\=\+\$\,\-\_\.\!\~\*\']+
 
@@ -159,6 +160,7 @@ or          { return OR_KW; }
 <IND_STRING>.    return yytext[0]; /* just in case: shouldn't be reached */
 
 {PATH}      { yylval->path = strdup(yytext); return PATH; }
+{HPATH}     { yylval->path = strdup(yytext); return HPATH; }
 {SPATH}     { yylval->path = strdup(yytext); return SPATH; }
 {URI}       { yylval->uri = strdup(yytext); return URI; }
 
diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y
index 091d59071c77..d70d29be8ba7 100644
--- a/src/libexpr/parser.y
+++ b/src/libexpr/parser.y
@@ -268,7 +268,7 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * err
 %token <id> ID ATTRPATH
 %token <e> STR IND_STR
 %token <n> INT
-%token <path> PATH SPATH
+%token <path> PATH HPATH SPATH
 %token <uri> URI
 %token IF THEN ELSE ASSERT WITH LET IN REC INHERIT EQ NEQ AND OR IMPL OR_KW
 %token DOLLAR_CURLY /* == ${ */
@@ -375,6 +375,7 @@ expr_simple
       $$ = stripIndentation(CUR_POS, data->symbols, *$2);
   }
   | PATH { $$ = new ExprPath(absPath($1, data->basePath)); }
+  | HPATH { $$ = new ExprPath(getEnv("HOME", "") + string{$1 + 1}); }
   | SPATH {
       string path($1 + 1, strlen($1) - 2);
       $$ = new ExprApp(CUR_POS,