antiquotation -> string interpolation
as proposed by @mkaito[1] and @tazjin[2] and discussed with @edolstra and Nix maintainers [1]: https://github.com/NixOS/nix.dev/pull/267#issuecomment-1270076332 [2]: https://github.com/NixOS/nix.dev/pull/267#issuecomment-1270201979 Co-authored-by: John Ericson <git@JohnEricson.me> Co-authored-by: Eelco Dolstra <edolstra@gmail.com>
This commit is contained in:
parent
80a0f77e49
commit
e0c4a95611
7 changed files with 136 additions and 82 deletions
|
@ -29,6 +29,7 @@
|
||||||
- [Nix Language](language/index.md)
|
- [Nix Language](language/index.md)
|
||||||
- [Data Types](language/values.md)
|
- [Data Types](language/values.md)
|
||||||
- [Language Constructs](language/constructs.md)
|
- [Language Constructs](language/constructs.md)
|
||||||
|
- [String interpolation](language/string-interpolation.md)
|
||||||
- [Operators](language/operators.md)
|
- [Operators](language/operators.md)
|
||||||
- [Derivations](language/derivations.md)
|
- [Derivations](language/derivations.md)
|
||||||
- [Advanced Attributes](language/advanced-attributes.md)
|
- [Advanced Attributes](language/advanced-attributes.md)
|
||||||
|
|
|
@ -60,7 +60,7 @@
|
||||||
cache](https://cache.nixos.org).
|
cache](https://cache.nixos.org).
|
||||||
|
|
||||||
- [store path]{#gloss-store-path}\
|
- [store path]{#gloss-store-path}\
|
||||||
The location in the file system of a store object, i.e., an
|
The location of a [store object] in the file system, i.e., an
|
||||||
immediate child of the Nix store directory.
|
immediate child of the Nix store directory.
|
||||||
|
|
||||||
Example: `/nix/store/a040m110amc4h71lds2jmr8qrkj2jhxd-git-2.38.1`
|
Example: `/nix/store/a040m110amc4h71lds2jmr8qrkj2jhxd-git-2.38.1`
|
||||||
|
@ -178,3 +178,12 @@
|
||||||
|
|
||||||
- [`ε`]{#gloss-epsilon}\
|
- [`ε`]{#gloss-epsilon}\
|
||||||
The epsilon symbol. In the context of a package, this means the version is empty. More precisely, the derivation does not have a version attribute.
|
The epsilon symbol. In the context of a package, this means the version is empty. More precisely, the derivation does not have a version attribute.
|
||||||
|
|
||||||
|
- [string interpolation]{#gloss-string-interpolation}\
|
||||||
|
Expanding expressions enclosed in `${ }` within a [string], [path], or [attribute name].
|
||||||
|
|
||||||
|
See [String interpolation](./language/string-interpolation.md) for details.
|
||||||
|
|
||||||
|
[string]: ./language/values.md#type-string
|
||||||
|
[path]: ./language/values.md#type-path
|
||||||
|
[attribute name]: ./language/values.md#attribute-set
|
||||||
|
|
82
doc/manual/src/language/string-interpolation.md
Normal file
82
doc/manual/src/language/string-interpolation.md
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
# String interpolation
|
||||||
|
|
||||||
|
String interpolation is a language feature where a [string], [path], or [attribute name] can contain expressions enclosed in `${ }` (dollar-sign with curly brackets).
|
||||||
|
|
||||||
|
Such a string is an *interpolated string*, and an expression inside is an *interpolated expression*.
|
||||||
|
|
||||||
|
Interpolated expressions must evaluate to one of the following:
|
||||||
|
|
||||||
|
- a [string]
|
||||||
|
- a [path]
|
||||||
|
- a [derivation]
|
||||||
|
|
||||||
|
[string]: ./values.md#type-string
|
||||||
|
[path]: ./values.md#type-path
|
||||||
|
[attribute name]: ./values.md#attribute-set
|
||||||
|
[derivation]: ../glossary.md#gloss-derivation
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### String
|
||||||
|
|
||||||
|
Rather than writing
|
||||||
|
|
||||||
|
```nix
|
||||||
|
"--with-freetype2-library=" + freetype + "/lib"
|
||||||
|
```
|
||||||
|
|
||||||
|
(where `freetype` is a [derivation]), you can instead write
|
||||||
|
|
||||||
|
```nix
|
||||||
|
"--with-freetype2-library=${freetype}/lib"
|
||||||
|
```
|
||||||
|
|
||||||
|
The latter is automatically translated to the former.
|
||||||
|
|
||||||
|
A more complicated example (from the Nix expression for [Qt](http://www.trolltech.com/products/qt)):
|
||||||
|
|
||||||
|
```nix
|
||||||
|
configureFlags = "
|
||||||
|
-system-zlib -system-libpng -system-libjpeg
|
||||||
|
${if openglSupport then "-dlopen-opengl
|
||||||
|
-L${mesa}/lib -I${mesa}/include
|
||||||
|
-L${libXmu}/lib -I${libXmu}/include" else ""}
|
||||||
|
${if threadSupport then "-thread" else "-no-thread"}
|
||||||
|
";
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that Nix expressions and strings can be arbitrarily nested;
|
||||||
|
in this case the outer string contains various interpolated expressions that themselves contain strings (e.g., `"-thread"`), some of which in turn contain interpolated expressions (e.g., `${mesa}`).
|
||||||
|
|
||||||
|
### Path
|
||||||
|
|
||||||
|
Rather than writing
|
||||||
|
|
||||||
|
```nix
|
||||||
|
./. + "/" + foo + "-" + bar + ".nix"
|
||||||
|
```
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
```nix
|
||||||
|
./. + "/${foo}-${bar}.nix"
|
||||||
|
```
|
||||||
|
|
||||||
|
you can instead write
|
||||||
|
|
||||||
|
```nix
|
||||||
|
./${foo}-${bar}.nix
|
||||||
|
```
|
||||||
|
|
||||||
|
### Attribute name
|
||||||
|
|
||||||
|
Attribute names can be created dynamically with string interpolation:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
let name = "foo"; in
|
||||||
|
{
|
||||||
|
${name} = "bar";
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
{ foo = "bar"; }
|
|
@ -13,41 +13,9 @@
|
||||||
returns and tabs can be written as `\n`, `\r` and `\t`,
|
returns and tabs can be written as `\n`, `\r` and `\t`,
|
||||||
respectively.
|
respectively.
|
||||||
|
|
||||||
You can include the result of an expression into a string by
|
You can include the results of other expressions into a string by enclosing them in `${ }`, a feature known as [string interpolation].
|
||||||
enclosing it in `${...}`, a feature known as *antiquotation*. The
|
|
||||||
enclosed expression must evaluate to something that can be coerced
|
|
||||||
into a string (meaning that it must be a string, a path, or a
|
|
||||||
derivation). For instance, rather than writing
|
|
||||||
|
|
||||||
```nix
|
[string interpolation]: ./string-interpolation.md
|
||||||
"--with-freetype2-library=" + freetype + "/lib"
|
|
||||||
```
|
|
||||||
|
|
||||||
(where `freetype` is a derivation), you can instead write the more
|
|
||||||
natural
|
|
||||||
|
|
||||||
```nix
|
|
||||||
"--with-freetype2-library=${freetype}/lib"
|
|
||||||
```
|
|
||||||
|
|
||||||
The latter is automatically translated to the former. A more
|
|
||||||
complicated example (from the Nix expression for
|
|
||||||
[Qt](http://www.trolltech.com/products/qt)):
|
|
||||||
|
|
||||||
```nix
|
|
||||||
configureFlags = "
|
|
||||||
-system-zlib -system-libpng -system-libjpeg
|
|
||||||
${if openglSupport then "-dlopen-opengl
|
|
||||||
-L${mesa}/lib -I${mesa}/include
|
|
||||||
-L${libXmu}/lib -I${libXmu}/include" else ""}
|
|
||||||
${if threadSupport then "-thread" else "-no-thread"}
|
|
||||||
";
|
|
||||||
```
|
|
||||||
|
|
||||||
Note that Nix expressions and strings can be arbitrarily nested; in
|
|
||||||
this case the outer string contains various antiquotations that
|
|
||||||
themselves contain strings (e.g., `"-thread"`), some of which in
|
|
||||||
turn contain expressions (e.g., `${mesa}`).
|
|
||||||
|
|
||||||
The second way to write string literals is as an *indented string*,
|
The second way to write string literals is as an *indented string*,
|
||||||
which is enclosed between pairs of *double single-quotes*, like so:
|
which is enclosed between pairs of *double single-quotes*, like so:
|
||||||
|
@ -75,7 +43,7 @@
|
||||||
Note that the whitespace and newline following the opening `''` is
|
Note that the whitespace and newline following the opening `''` is
|
||||||
ignored if there is no non-whitespace text on the initial line.
|
ignored if there is no non-whitespace text on the initial line.
|
||||||
|
|
||||||
Antiquotation (`${expr}`) is supported in indented strings.
|
Indented strings support [string interpolation].
|
||||||
|
|
||||||
Since `${` and `''` have special meaning in indented strings, you
|
Since `${` and `''` have special meaning in indented strings, you
|
||||||
need a way to quote them. `$` can be escaped by prefixing it with
|
need a way to quote them. `$` can be escaped by prefixing it with
|
||||||
|
@ -143,26 +111,23 @@
|
||||||
environment variable `NIX_PATH` will be searched for the given file
|
environment variable `NIX_PATH` will be searched for the given file
|
||||||
or directory name.
|
or directory name.
|
||||||
|
|
||||||
Antiquotation is supported in any paths except those in angle brackets.
|
When an [interpolated string][string interpolation] evaluates to a path, the path is first copied into the Nix store and the resulting string is the [store path] of the newly created [store object].
|
||||||
`./${foo}-${bar}.nix` is a more convenient way of writing
|
|
||||||
`./. + "/" + foo + "-" + bar + ".nix"` or `./. + "/${foo}-${bar}.nix"`. At
|
|
||||||
least one slash must appear *before* any antiquotations for this to be
|
|
||||||
recognized as a path. `a.${foo}/b.${bar}` is a syntactically valid division
|
|
||||||
operation. `./a.${foo}/b.${bar}` is a path.
|
|
||||||
|
|
||||||
When a path appears in an antiquotation, and is thus coerced into a string,
|
[store path]: ../glossary.md#gloss-store-path
|
||||||
the path is first copied into the Nix store and the resulting string is
|
[store object]: ../glossary.md#gloss-store-object
|
||||||
the Nix store path. For instance `"${./foo.txt}" will cause `foo.txt` in
|
|
||||||
the current directory to be copied into the Nix store and result in the
|
|
||||||
string `"/nix/store/<HASH>-foo.txt"`.
|
|
||||||
|
|
||||||
Note that the Nix language assumes that all input files will remain
|
For instance, evaluating `"${./foo.txt}"` will cause `foo.txt` in the current directory to be copied into the Nix store and result in the string `"/nix/store/<hash>-foo.txt"`.
|
||||||
_unchanged_ during the course of the Nix expression evaluation.
|
|
||||||
If you for example antiquote a file path during a `nix repl` session, and
|
Note that the Nix language assumes that all input files will remain _unchanged_ while evaluating a Nix expression.
|
||||||
then later in the same session, after having changed the file contents,
|
For example, assume you used a file path in an interpolated string during a `nix repl` session.
|
||||||
evaluate the antiquotation with the file path again, then Nix will still
|
Later in the same session, after having changed the file contents, evaluating the interpolated string with the file path again might not return a new store path, since Nix might not re-read the file contents.
|
||||||
return the first store path. It will _not_ reread the file contents to
|
|
||||||
produce a different Nix store path.
|
Paths themselves, except those in angle brackets (`< >`), support [string interpolation].
|
||||||
|
|
||||||
|
At least one slash (`/`) must appear *before* any interpolated expression for the result to be recognized as a path.
|
||||||
|
|
||||||
|
`a.${foo}/b.${bar}` is a syntactically valid division operation.
|
||||||
|
`./a.${foo}/b.${bar}` is a path.
|
||||||
|
|
||||||
- <a id="type-boolean" href="#type-boolean">Boolean</a>
|
- <a id="type-boolean" href="#type-boolean">Boolean</a>
|
||||||
|
|
||||||
|
@ -235,23 +200,33 @@ will evaluate to `"Xyzzy"` because there is no `c` attribute in the set.
|
||||||
You can use arbitrary double-quoted strings as attribute names:
|
You can use arbitrary double-quoted strings as attribute names:
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
{ "foo ${bar}" = 123; "nix-1.0" = 456; }."foo ${bar}"
|
{ "$!@#?" = 123; }."$!@#?"
|
||||||
```
|
```
|
||||||
|
|
||||||
This will evaluate to `123` (Assuming `bar` is antiquotable). In the
|
|
||||||
case where an attribute name is just a single antiquotation, the quotes
|
|
||||||
can be dropped:
|
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
{ foo = 123; }.${bar} or 456
|
let bar = "bar";
|
||||||
|
{ "foo ${bar}" = 123; }."foo ${bar}"
|
||||||
```
|
```
|
||||||
|
|
||||||
This will evaluate to `123` if `bar` evaluates to `"foo"` when coerced
|
Both will evaluate to `123`.
|
||||||
to a string and `456` otherwise (again assuming `bar` is antiquotable).
|
|
||||||
|
Attribute names support [string interpolation]:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
let bar = "foo"; in
|
||||||
|
{ foo = 123; }.${bar}
|
||||||
|
```
|
||||||
|
|
||||||
|
```nix
|
||||||
|
let bar = "foo"; in
|
||||||
|
{ ${bar} = 123; }.foo
|
||||||
|
```
|
||||||
|
|
||||||
|
Both will evaluate to `123`.
|
||||||
|
|
||||||
In the special case where an attribute name inside of a set declaration
|
In the special case where an attribute name inside of a set declaration
|
||||||
evaluates to `null` (which is normally an error, as `null` is not
|
evaluates to `null` (which is normally an error, as `null` cannot be coerced to
|
||||||
antiquotable), that attribute is simply not added to the set:
|
a string), that attribute is simply not added to the set:
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
{ ${if foo then "bar" else null} = true; }
|
{ ${if foo then "bar" else null} = true; }
|
||||||
|
|
|
@ -15,19 +15,6 @@
|
||||||
# NIX_PATH=nixpkgs=flake:nixpkgs nix-build '<nixpkgs>' -A hello
|
# NIX_PATH=nixpkgs=flake:nixpkgs nix-build '<nixpkgs>' -A hello
|
||||||
```
|
```
|
||||||
|
|
||||||
* Allow explicitly selecting outputs in a store derivation installable, just like we can do with other sorts of installables.
|
* Instead of "antiquotation", the more common term [string interpolation](../language/string-interpolation.md) is now used consistently.
|
||||||
For example,
|
Historical release notes were not changed.
|
||||||
```shell-session
|
|
||||||
$ nix-build /nix/store/gzaflydcr6sb3567hap9q6srzx8ggdgg-glibc-2.33-78.drv^dev`
|
|
||||||
```
|
|
||||||
now works just as
|
|
||||||
```shell-session
|
|
||||||
$ nix-build glibc^dev`
|
|
||||||
```
|
|
||||||
does already.
|
|
||||||
|
|
||||||
* On Linux, `nix develop` now sets the
|
|
||||||
[*personality*](https://man7.org/linux/man-pages/man2/personality.2.html)
|
|
||||||
for the development shell in the same way as the actual build of the
|
|
||||||
derivation. This makes shells for `i686-linux` derivations work
|
|
||||||
correctly on `x86_64-linux`.
|
|
||||||
|
|
|
@ -1930,8 +1930,8 @@ static RegisterPrimOp primop_toFile({
|
||||||
";
|
";
|
||||||
```
|
```
|
||||||
|
|
||||||
Note that `${configFile}` is an
|
Note that `${configFile}` is a
|
||||||
[antiquotation](language-values.md), so the result of the
|
[string interpolation](language/values.md#type-string), so the result of the
|
||||||
expression `configFile`
|
expression `configFile`
|
||||||
(i.e., a path like `/nix/store/m7p7jfny445k...-foo.conf`) will be
|
(i.e., a path like `/nix/store/m7p7jfny445k...-foo.conf`) will be
|
||||||
spliced into the resulting string.
|
spliced into the resulting string.
|
||||||
|
|
|
@ -110,7 +110,7 @@ let
|
||||||
And finally to interpret \n etc. as in a string: ''\n, ''\r, ''\t.
|
And finally to interpret \n etc. as in a string: ''\n, ''\r, ''\t.
|
||||||
'';
|
'';
|
||||||
|
|
||||||
# Regression test: antiquotation in '${x}' should work, but didn't.
|
# Regression test: string interpolation in '${x}' should work, but didn't.
|
||||||
s15 = let x = "bla"; in ''
|
s15 = let x = "bla"; in ''
|
||||||
foo
|
foo
|
||||||
'${x}'
|
'${x}'
|
||||||
|
|
Loading…
Reference in a new issue