diff --git a/cmd/docs.gen.go b/cmd/docs.gen.go index b225dd8cd48..5f02830aeb6 100644 --- a/cmd/docs.gen.go +++ b/cmd/docs.gen.go @@ -3199,7 +3199,7 @@ func init() { assets["docs/TEMPLATING.md"] = []byte("" + "# chezmoi Templating Guide\n" + "\n" + - " \n" + + "\n" + "* [Introduction](#introduction)\n" + "* [Creating a template file](#creating-a-template-file)\n" + "* [Debugging templates](#debugging-templates)\n" + @@ -3211,90 +3211,152 @@ func init() { "\n" + "## Introduction\n" + "\n" + - "Templates are used to create different configurations depending on the enviorment.\n" + - "For example, you can use the hostname of the machine to create different\n" + - "configurations.\n" + + "Templates are used to change the contents of a file depending on the\n" + + "environment. For example, you can use the hostname of the machine to create\n" + + "different configurations on different machines.\n" + "\n" + "chezmoi uses the [`text/template`](https://pkg.go.dev/text/template) syntax from\n" + - "Go, extended with [text template functions from `sprig`](http://masterminds.github.io/sprig/)\n" + - "You can look there for more information.\n" + + "Go extended with [text template functions from\n" + + "`sprig`](http://masterminds.github.io/sprig/).\n" + + "\n" + + "When reading files from the source state, chezmoi interprets them as a template\n" + + "if either of the following is true:\n" + + "\n" + + "* The file name has a `.tmpl` suffix.\n" + + "* The file is in the `.chezmoitemplates` directory, or a subdirectory of\n" + + " `.chezmoitemplates`.\n" + + "\n" + + "## Template data\n" + + "\n" + + "chezmoi provides a variety of template variables. For a full list, run\n" + + "\n" + + " chezmoi data\n" + + "\n" + + "These come from a variety of sources:\n" + + "\n" + + "* Variables populated by chezmoi are in `.chezmoi`, for example `.chezmoi.os`.\n" + + "* Variables created by you in the `data` section of the configuration file.\n" + + "\n" + + "Furthermore, chezmoi provides a variety of functions to retrieve data at runtime\n" + + "from password managers, environment variables, and the filesystem.\n" + "\n" + "## Creating a template file\n" + "\n" + - "chezmoi will not interpret all files as templates. It will only do that if the \n" + - "filename ends with .tmpl or it is in the .chezmoitemplates directory.\n" + + "There are several ways to create a template:\n" + + "\n" + + "* When adding a file for the first time, pass the `--template` argument, for example:\n" + + "\n" + + " chezmoi add --template ~/.zshrc\n" + + "\n" + + "* When adding a file for the first time, you can pass the `--autotemplate`\n" + + " argument, which tells chezmoi to make the file as a template and automatically\n" + + " replace variables that chezmoi knows about, for example:\n" + + "\n" + + " chezmoi add --autotemplate ~/.zshrc\n" + + "\n" + + "* If a file is already managed by chezmoi, but is not a template, you can make\n" + + " it a template by running, for example:\n" + + "\n" + + " chezmoi chattr +template ~/.zshrc\n" + "\n" + - "There are a few ways to create a template file in chezmoi. \n" + - "If the file is not yet known by chezmoi you can do the following:\n" + + "* You can create a template manually in the source directory by giving it a\n" + + " `.tmpl` extension, for example:\n" + "\n" + - "\tchezmoi add ~/.zshrc --template\n" + + " chezmoi cd\n" + + " $EDITOR dot_zshrc.tmpl\n" + "\n" + - "This will add ~/.zshrc as a template to the source state. This means that chezmoi\n" + - "will add a .tmpl extension to file and interpret any templates in the source upon\n" + - "updating.\n" + + "* Templates in `.chezmoitemplates` must be created manually, for example:\n" + "\n" + - "You can also use the command\n" + + " chezmoi cd\n" + + "\t mkdir -p .chezmoitemplates\n" + + "\t cd .chezmoitemplates\n" + + "\t $EDITOR mytemplate\n" + "\n" + - "\tchezmoi add ~/.zshrc --autotemplate\n" + + "## Editing a template file\n" + "\n" + - "to add ~/.zshrc to the source state as a template, while replacing any strings\n" + - "that it can match with the variables from the data section of the chezmoi config.\n" + + "The easiest way to edit a template is to use `chezmoi edit`, for example:\n" + "\n" + - "If the file is already known by chezmoi, you can use the command\n" + + "\tchezmoi edit ~/.zshrc\n" + "\n" + - "\tchezmoi chattr template ~/.zshrc\n" + + "This will open the source file for `~/.zshrc` in `$EDITOR`. When you quit the\n" + + "editor, chezmoi will check the template syntax.\n" + "\n" + - "Or you can simply add the file extension .tmpl to the file in the source directory.\n" + - "This way chezmoi will interpret the file as a template.\n" + + "If you want the changes you make to be immediately applied after you quit the\n" + + "editor, use the `--apply` option, for example:\n" + + "\n" + + "\tchezmoi edit --apply ~/.zshrc\n" + + "\n" + + "## Testing templates\n" + + "\n" + + "Templates can be tested with the `chezmoi execute-template` command which treats\n" + + "each of its arguments as a template and executes it. This can be useful for\n" + + "testing small fragments of templates, for example:\n" + + "\n" + + " chezmoi execute-template '{{ .chezmoi.hostname }}'\n" + + "\n" + + "If there are no arguments, `chezmoi execute-template` will read the template\n" + + "from the standard input. This can be useful for testing whole files, for example:\n" + + "\n" + + "\tchezmoi cd\n" + + "\tchezmoi execute-template < dot_zshrc.tmpl\n" + "\n" + "## Template syntax\n" + "\n" + - "Every template expression starts and ends with double curly brackets ('{{' and '}}').\n" + - "Between these brackets can be either variables or functions.\n" + + "Template actions are written inside double curly brackets, `{{` and `}}`.\n" + + "Actions can be variables, pipelines, or control statements. Text outside actions\n" + + "is copied literally.\n" + "\n" + - "An example with a variable\n" + + "Variables are written literally, for example:\n" + "\n" + - "\t{{.chezmoi.hostname}}\n" + + " {{ .chezmoi.hostname }}\n" + "\n" + - "An example with a function\n" + + "Conditional expressions can be written using `if`, `else if`, `else`, and `end`,\n" + + "for example:\n" + "\n" + - "\t{{if expression}} Some text {{end}}\n" + + "\t{{ if (eq .chezmoi.os \"darwin\") }}\n" + + "\t# darwin\n" + + "\t{{ else if (eq .chezmoi.os \"linux\" ) }}\n" + + "\t# linux\n" + + "\t{{ else }}\n" + + "\t# other operating system\n" + + "\t{{ end }}\n" + "\n" + - "If the result of the expression is empty (false, 0, empty string, ...), no output\n" + - "will be generated. Otherwise this will result in the text in between the if and the \n" + - "end.\n" + + "For a full description of the template syntax, see the [`text/template`\n" + + "documentation](https://pkg.go.dev/text/template).\n" + "\n" + - "### Remove whitespace\n" + + "### Removing whitespace\n" + "\n" + - "For formatting reasons you might want to leave some whitespace after or before the \n" + - "template code. This whitespace will remain in the final file, which you might not want.\n" + + "For formatting reasons you might want to leave some whitespace after or before\n" + + "the template code. This whitespace will remain in the final file, which you\n" + + "might not want.\n" + "\n" + - "A solution for this is to place a minus sign and a space next to the brackets. So\n" + - "'{{- ' for the left brackets and ' -}}' for the right brackets. Here's an example:\n" + + "A solution for this is to place a minus sign and a space next to the brackets.\n" + + "So `{{- ` for the left brackets and ` -}}` for the right brackets. Here's an\n" + + "example:\n" + "\n" + - "\tHOSTNAME= \t\t\t{{- .chezmoi.hostname }}\n" + + "\tHOSTNAME= {{- .chezmoi.hostname }}\n" + "\n" + "This will result in\n" + "\n" + "\tHOSTNAME=myhostname\n" + "\n" + - "Notice that this will remove any number of tabs, spaces and even newlines and carriage\n" + - "returns.\n" + + "Notice that this will remove any number of tabs, spaces and even newlines and\n" + + "carriage returns.\n" + "\n" + "## Debugging templates\n" + "\n" + "If there is a mistake in one of your templates and you want to debug it, chezmoi\n" + - "can help you. You can use this subcommand to test and play with the examples in these\n" + - "docs as well.\n" + + "can help you. You can use this subcommand to test and play with the examples in\n" + + "these docs as well.\n" + "\n" + - "There is a very handy subcommand called \"execute-template\". chezmoi will interpret\n" + - "any data coming from stdin or at the end of the command. It will then interpret all\n" + - "templates and output the result to stdout.\n" + - "For example with the command:\n" + + "There is a very handy subcommand called `execute-template`. chezmoi will\n" + + "interpret any data coming from stdin or at the end of the command. It will then\n" + + "interpret all templates and output the result to stdout. For example with the\n" + + "command:\n" + "\n" + "\tchezmoi execute-template '{{ .chezmoi.os }}/{{ .chezmoi.arch }}'\n" + "\n" + - "chezmoi will output the current os and architecture to stdout.\n" + + "chezmoi will output the current OS and architecture to stdout.\n" + "\n" + "You can also feed the contents of a file to this command by typing:\n" + "\n" + @@ -3302,59 +3364,57 @@ func init() { "\n" + "## Simple logic\n" + "\n" + - "A very useful feature of chezmoi templates is the ability to perform logical operations.\n" + + "A very useful feature of chezmoi templates is the ability to perform logical\n" + + "operations.\n" + "\n" + "\t# common config\n" + "\texport EDITOR=vi\n" + - "\t\n" + + "\n" + "\t# machine-specific configuration\n" + "\t{{- if eq .chezmoi.hostname \"work-laptop\" }}\n" + "\t# this will only be included in ~/.bashrc on work-laptop\n" + "\t{{- end }}\n" + "\n" + - "In this example chezmoi will look at the hostname of the machine and if that is equal to\n" + - "\"work-laptop\", the text between the \"if\" and the \"end\" will be included in the result.\n" + - "\n" + - "### Locical operators\n" + - "\n" + - "The following operators are available:\n" + - "\n" + - "* `eq` - Return true if the first argument is equal to any other argument.\n" + - "* `or` - Return boolean or of the arguments.\n" + - "* `and` - Return boolean and of the arguments.\n" + - "* `not` - Return boolean negative of the argument.\n" + - "* `len` - Return the length of the argument.\n" + + "In this example chezmoi will look at the hostname of the machine and if that is\n" + + "equal to \"work-laptop\", the text between the `if` and the `end` will be included\n" + + "in the result.\n" + "\n" + - "Notice that some operators can accept more than two arguments.\n" + + "### Boolean functions\n" + "\n" + - "### Integer operators\n" + + "| Function | Return value |\n" + + "| -------- | --------------------------------------------------------- |\n" + + "| `eq` | Returns true if the first argument is equal to any of the other arguments. |\n" + + "| `not` | Returns the boolean negation of its single argument. |\n" + + "| `and` | Returns the boolean AND of its arguments by returning the first empty argument or the last argument, that is, `and x y` behaves as `if x then y else x`. All the arguments are evaluated. |\n" + + "| `or` | Returns the boolean OR of its arguments by returning the first non-empty argument or the last argument, that is, `or x y` behaves as `if x then x else y` All the arguments are evaluated. |\n" + "\n" + - "There are separate operators for comparing integers.\n" + + "### Integer functions\n" + "\n" + - "* `eq` - Return true if the first argument is equal to any other argument. - arg1 == arg2 \t\t \n" + - "* `ne` - Returns if arg1 is not equal to arg2 - arg1 != arg2\n" + - "* `lt` - Returns if arg1 is less than arg2. - arg1 < arg2 \n" + - "* `le` - Returns if arg1 is less than or equal to arg2. - arg1 <= arg2\n" + - "* `gt` - Returns if arg1 is greater than arg2. - arg1 > arg2\n" + - "* `ge` - Returns if arg1 is greater than or equal to arg2. - arg1 >= arg2\n" + - "\n" + - "`eq` can handle multiple arguments again, the same way as the \"eq\" above.\n" + + "| Function | Return value |\n" + + "| -------- | ------------------------------------------- |\n" + + "| `len` | Returns the integer length of its argument. |\n" + + "| `eq` | Returns the boolean truth of arg1 == arg2. |\n" + + "| `ne` | Returns the boolean truth of arg1 != arg2. |\n" + + "| `lt` | Returns the boolean truth of arg1 < arg2. |\n" + + "| `le` | Returns the boolean truth of arg1 <= arg2. |\n" + + "| `gt` | Returns the boolean truth of arg1 > arg2. |\n" + + "| `ge` | Returns the boolean truth of arg1 >= arg2. |\n" + "\n" + "## More complicated logic\n" + "\n" + - "Up until now, we have only seen if statements that can handle at most two variables.\n" + - "In this part we will see how to create more complicated expressions.\n" + + "Up until now, we have only seen if statements that can handle at most two\n" + + "variables. In this part we will see how to create more complicated expressions.\n" + "\n" + - "You can also create more complicated expressions. The `eq` command can accept multiple\n" + - "arguments. It will check if the first argument is equal to any of the other arguments.\n" + - "\t\n" + - "\t{{ if eq \"foo\" \"foo\" \"bar\" }}hello{{end}}\n" + + "You can also create more complicated expressions. The `eq` command can accept\n" + + "multiple arguments. It will check if the first argument is equal to any of the\n" + + "other arguments.\n" + "\n" + + "\t{{ if eq \"foo\" \"foo\" \"bar\" }}one{{end}}\n" + "\t{{ if eq \"foo\" \"bar\" \"foo\" }}hello{{end}}\n" + - "\n" + "\t{{ if eq \"foo\" \"bar\" \"bar\" }}hello{{end}}\n" + "\n" + - "The first two examples will output \"hello\" and the last example will output nothing.\n" + + "The first two examples will output `hello` and the last example will output\n" + + "nothing.\n" + "\n" + "The operators `or` and `and` can also accept multiple arguments.\n" + "\n" + @@ -3362,39 +3422,41 @@ func init() { "\n" + "You can perform multiple checks in one if statement.\n" + "\n" + - "\t{{ and ( eq .chezmoi.os \"linux\" ) ( ne .email \"john@home.org\" ) }}\n" + + "\t{{ if (and (eq .chezmoi.os \"linux\") (ne .email \"john@home.org\")) }}\n" + + "\t...\n" + + "\t{{ end }}\n" + "\n" + - "This will check if the operating system is Linux and the configured email\n" + - "is not the home email. The brackets are needed here, because otherwise all the\n" + + "This will check if the operating system is Linux and the configured email is not\n" + + "the home email. The brackets are needed here, because otherwise all the\n" + "arguments will be give to the `and` command.\n" + "\n" + "This way you can chain as many operators together as you like.\n" + "\n" + "## Helper functions\n" + "\n" + - "chezmoi has added multiple helper functions to the [`text/template`](https://pkg.go.dev/text/template) \n" + - "syntax. \n" + + "chezmoi has added multiple helper functions to the\n" + + "[`text/template`](https://pkg.go.dev/text/template) syntax.\n" + "\n" + - "Chezmoi includes [`Sprig`](http://masterminds.github.io/sprig/), an extension to \n" + - "the text/template format that contains many helper functions. Take a look at \n" + + "chezmoi includes [`sprig`](http://masterminds.github.io/sprig/), an extension to\n" + + "the `text/template` format that contains many helper functions. Take a look at\n" + "their documentation for a list.\n" + "\n" + - "Chezmoi adds a few functions of its own as well. Take a look at the \n" + + "chezmoi adds a few functions of its own as well. Take a look at the\n" + "[`reference`](REFERENCE.md#template-functions) for complete list.\n" + "\n" + "## Template variables\n" + "\n" + - "Chezmoi defines a few useful templates variables that depend on the system\n" + - "you are currently on. A list of the variables defined by chezmoi can be found \n" + + "chezmoi defines a few useful templates variables that depend on the system you\n" + + "are currently on. A list of the variables defined by chezmoi can be found\n" + "[here](REFERENCE.md#template-variables).\n" + "\n" + - "There are, however more variables than\n" + - "that. To view the variables available on your system, execute:\n" + + "There are, however more variables than that. To view the variables available on\n" + + "your system, execute:\n" + "\n" + "\tchezmoi data\n" + "\n" + "This outputs the variables in JSON format by default. To access the variable\n" + - "`chezmoi>kernel>osrelease` in a template, use\n" + + "`chezmoi.kernel.osrelease` in a template, use\n" + "\n" + "\t{{ .chezmoi.kernel.osrelease }}\n" + "\n" + @@ -3402,108 +3464,78 @@ func init() { "\n" + "## Using .chezmoitemplates for creating similar files\n" + "\n" + - "When you have multiple similar files, but they aren't quite the same, you can create\n" + - "a template file in the directory .chezmoitemplates. This template can be inserted\n" + - "in other template files. \n" + - "For example:\n" + + "When you have multiple similar files, but they aren't quite the same, you can\n" + + "create a template file in the directory `.chezmoitemplates`. This template can\n" + + "be inserted in other template files, for example:\n" + "\n" + - "Create:\n" + - "\n" + - "\t.local/share/chezmoi/.chezmoitemplates/alacritty:\n" + - "\n" + - "Notice the file name doesn't have to end in .tmpl, as all files in the directory\n" + - ".chemzoitemplates are interpreted as templates.\n" + + "Create `.local/share/chezmoi/.chezmoitemplates/alacritty`:\n" + "\n" + "\tsome: config\n" + "\tfontsize: {{ . }}\n" + "\tsomemore: config\n" + "\n" + - "Create other files using the template\n" + + "Notice the file name doesn't have to end in `.tmpl`, as all files in the\n" + + "directory `.chemzoitemplates` are interpreted as templates.\n" + "\n" + - "`.local/share/chezmoi/small-font.yml.tmpl`\n" + + "Create other files using the template `.local/share/chezmoi/small-font.yml.tmpl`\n" + "\n" + - "```\n" + - "{{- template \"alacritty\" 12 -}}\n" + - "```\n" + + " {{- template \"alacritty\" 12 -}}\n" + "\n" + "`.local/share/chezmoi/big-font.yml.tmpl`\n" + "\n" + - "```\n" + - "{{- template \"alacritty\" 18 -}}\n" + - "```\n" + + " {{- template \"alacritty\" 18 -}}\n" + "\n" + - "Here we're calling the shared `alacritty` template with the he font size as \n" + - "the `.` value passed in. You can test this with `chezmoi cat`:\n" + + "Here we're calling the shared `alacritty` template with the he font size as the\n" + + "`.` value passed in. You can test this with `chezmoi cat`:\n" + "\n" + - "\t$ chezmoi cat ~/small-font.yml\n" + - "\tsome: config\n" + - "\tfontsize: 12\n" + - "\tsomemore: config\n" + - "\t$ chezmoi cat ~/big-font.yml\n" + - "\tsome: config\n" + - "\tfontsize: 18\n" + - "\tsomemore: config\n" + + " $ chezmoi cat ~/small-font.yml\n" + + " some: config\n" + + " fontsize: 12\n" + + " somemore: config\n" + + " $ chezmoi cat ~/big-font.yml\n" + + " some: config\n" + + " fontsize: 18\n" + + " somemore: config\n" + "\n" + "### Passing multiple arguments\n" + - "In the example above only one arguments is passed to the template. To pass\n" + - "more arguments to the template, you can do it in two ways.\n" + "\n" + - "#### Via chezmoi.toml\n" + + "In the example above only one arguments is passed to the template. To pass more\n" + + "arguments to the template, you can do it in two ways.\n" + + "\n" + + "#### Via the config file\n" + "\n" + "This method is useful if you want to use the same template arguments multiple\n" + "times, because you don't specify the arguments every time. Instead you specify\n" + - "them in the file `.chezmoi.toml`.\n" + - "\n" + - "`.config/chezmoi/chezmoi.toml`:\n" + + "them in the file `.config/chezmoi/.chezmoi.toml`:\n" + "\n" + - "```\n" + + "```toml\n" + "[data.alacritty.big]\n" + - " fontsize = 18\n" + - " font = DejaVu Serif\n" + + " fontsize = 18\n" + + " font = \"DejaVu Serif\"\n" + "[data.alacritty.small]\n" + - " fontsize = 12\n" + - " font = DejaVu Sans Mono\n" + + " fontsize = 12\n" + + " font = \"DejaVu Sans Mono\"\n" + "```\n" + "\n" + - "`.local/share/chezmoi/.chezmoitemplates/alacritty`:\n" + + "Use the variables in `.local/share/chezmoi/.chezmoitemplates/alacritty`:\n" + "\n" + - "```\n" + - "some: config\n" + - "fontsize: {{ .fontsize }}\n" + - "font: {{ .font }}\n" + - "somemore: config\n" + - "```\n" + + " some: config\n" + + " fontsize: {{ .fontsize }}\n" + + " font: {{ .font }}\n" + + " somemore: config\n" + "\n" + - "`.local/share/chezmoi/small-font.yml.tmpl`\n" + + "And connect them with `.local/share/chezmoi/small-font.yml.tmpl`:\n" + "\n" + - "```\n" + - "{{- template \"alacritty\" .alacritty.small -}}\n" + - "```\n" + - "\n" + - "`.local/share/chezmoi/big-font.yml.tmpl`\n" + + " {{- template \"alacritty\" .alacritty.small -}}\n" + "\n" + - "```\n" + - "{{- template \"alacritty\" .alacritty.big -}}\n" + - "```\n" + - "\n" + - "At the moment, this means that you'll have to duplicate the alacritty data in \n" + + "At the moment, this means that you'll have to duplicate the alacritty data in\n" + "the config file on every machine, but a feature will be added to avoid this.\n" + "\n" + "#### By passing a dictionary\n" + "\n" + "Using the same alacritty configuration as above, you can pass the arguments to\n" + - "it with a dictionary.\n" + - "\n" + - "`.local/share/chezmoi/small-font.yml.tmpl`\n" + + "it with a dictionary, for example `.local/share/chezmoi/small-font.yml.tmpl`:\n" + "\n" + - "```\n" + - "{{- template \"alacritty\" dict \"fontsize\" 12 \"font\" \"DejaVu Sans Mono\" -}}\n" + - "```\n" + - "\n" + - "`.local/share/chezmoi/big-font.yml.tmpl`\n" + - "\n" + - "```\n" + - "{{- template \"alacritty\" dict \"fontsize\" 18 \"font\" \"DejaVu Serif\" -}}\n" + - "```\n" + + " {{- template \"alacritty\" dict \"fontsize\" 12 \"font\" \"DejaVu Sans Mono\" -}}\n" + "\n") } diff --git a/docs/TEMPLATING.md b/docs/TEMPLATING.md index 6d3dcf81b3d..4dd2e01f2e9 100644 --- a/docs/TEMPLATING.md +++ b/docs/TEMPLATING.md @@ -1,6 +1,6 @@ # chezmoi Templating Guide - + * [Introduction](#introduction) * [Creating a template file](#creating-a-template-file) * [Debugging templates](#debugging-templates) @@ -12,90 +12,152 @@ ## Introduction -Templates are used to create different configurations depending on the enviorment. -For example, you can use the hostname of the machine to create different -configurations. +Templates are used to change the contents of a file depending on the +environment. For example, you can use the hostname of the machine to create +different configurations on different machines. chezmoi uses the [`text/template`](https://pkg.go.dev/text/template) syntax from -Go, extended with [text template functions from `sprig`](http://masterminds.github.io/sprig/) -You can look there for more information. +Go extended with [text template functions from +`sprig`](http://masterminds.github.io/sprig/). + +When reading files from the source state, chezmoi interprets them as a template +if either of the following is true: + +* The file name has a `.tmpl` suffix. +* The file is in the `.chezmoitemplates` directory, or a subdirectory of + `.chezmoitemplates`. + +## Template data + +chezmoi provides a variety of template variables. For a full list, run + + chezmoi data + +These come from a variety of sources: + +* Variables populated by chezmoi are in `.chezmoi`, for example `.chezmoi.os`. +* Variables created by you in the `data` section of the configuration file. + +Furthermore, chezmoi provides a variety of functions to retrieve data at runtime +from password managers, environment variables, and the filesystem. ## Creating a template file -chezmoi will not interpret all files as templates. It will only do that if the -filename ends with .tmpl or it is in the .chezmoitemplates directory. +There are several ways to create a template: + +* When adding a file for the first time, pass the `--template` argument, for example: + + chezmoi add --template ~/.zshrc + +* When adding a file for the first time, you can pass the `--autotemplate` + argument, which tells chezmoi to make the file as a template and automatically + replace variables that chezmoi knows about, for example: + + chezmoi add --autotemplate ~/.zshrc + +* If a file is already managed by chezmoi, but is not a template, you can make + it a template by running, for example: + + chezmoi chattr +template ~/.zshrc -There are a few ways to create a template file in chezmoi. -If the file is not yet known by chezmoi you can do the following: +* You can create a template manually in the source directory by giving it a + `.tmpl` extension, for example: - chezmoi add ~/.zshrc --template + chezmoi cd + $EDITOR dot_zshrc.tmpl -This will add ~/.zshrc as a template to the source state. This means that chezmoi -will add a .tmpl extension to file and interpret any templates in the source upon -updating. +* Templates in `.chezmoitemplates` must be created manually, for example: -You can also use the command + chezmoi cd + mkdir -p .chezmoitemplates + cd .chezmoitemplates + $EDITOR mytemplate - chezmoi add ~/.zshrc --autotemplate +## Editing a template file -to add ~/.zshrc to the source state as a template, while replacing any strings -that it can match with the variables from the data section of the chezmoi config. +The easiest way to edit a template is to use `chezmoi edit`, for example: -If the file is already known by chezmoi, you can use the command + chezmoi edit ~/.zshrc - chezmoi chattr template ~/.zshrc +This will open the source file for `~/.zshrc` in `$EDITOR`. When you quit the +editor, chezmoi will check the template syntax. -Or you can simply add the file extension .tmpl to the file in the source directory. -This way chezmoi will interpret the file as a template. +If you want the changes you make to be immediately applied after you quit the +editor, use the `--apply` option, for example: + + chezmoi edit --apply ~/.zshrc + +## Testing templates + +Templates can be tested with the `chezmoi execute-template` command which treats +each of its arguments as a template and executes it. This can be useful for +testing small fragments of templates, for example: + + chezmoi execute-template '{{ .chezmoi.hostname }}' + +If there are no arguments, `chezmoi execute-template` will read the template +from the standard input. This can be useful for testing whole files, for example: + + chezmoi cd + chezmoi execute-template < dot_zshrc.tmpl ## Template syntax -Every template expression starts and ends with double curly brackets ('{{' and '}}'). -Between these brackets can be either variables or functions. +Template actions are written inside double curly brackets, `{{` and `}}`. +Actions can be variables, pipelines, or control statements. Text outside actions +is copied literally. -An example with a variable +Variables are written literally, for example: - {{.chezmoi.hostname}} + {{ .chezmoi.hostname }} -An example with a function +Conditional expressions can be written using `if`, `else if`, `else`, and `end`, +for example: - {{if expression}} Some text {{end}} + {{ if (eq .chezmoi.os "darwin") }} + # darwin + {{ else if (eq .chezmoi.os "linux" ) }} + # linux + {{ else }} + # other operating system + {{ end }} -If the result of the expression is empty (false, 0, empty string, ...), no output -will be generated. Otherwise this will result in the text in between the if and the -end. +For a full description of the template syntax, see the [`text/template` +documentation](https://pkg.go.dev/text/template). -### Remove whitespace +### Removing whitespace -For formatting reasons you might want to leave some whitespace after or before the -template code. This whitespace will remain in the final file, which you might not want. +For formatting reasons you might want to leave some whitespace after or before +the template code. This whitespace will remain in the final file, which you +might not want. -A solution for this is to place a minus sign and a space next to the brackets. So -'{{- ' for the left brackets and ' -}}' for the right brackets. Here's an example: +A solution for this is to place a minus sign and a space next to the brackets. +So `{{- ` for the left brackets and ` -}}` for the right brackets. Here's an +example: - HOSTNAME= {{- .chezmoi.hostname }} + HOSTNAME= {{- .chezmoi.hostname }} This will result in HOSTNAME=myhostname -Notice that this will remove any number of tabs, spaces and even newlines and carriage -returns. +Notice that this will remove any number of tabs, spaces and even newlines and +carriage returns. ## Debugging templates If there is a mistake in one of your templates and you want to debug it, chezmoi -can help you. You can use this subcommand to test and play with the examples in these -docs as well. +can help you. You can use this subcommand to test and play with the examples in +these docs as well. -There is a very handy subcommand called "execute-template". chezmoi will interpret -any data coming from stdin or at the end of the command. It will then interpret all -templates and output the result to stdout. -For example with the command: +There is a very handy subcommand called `execute-template`. chezmoi will +interpret any data coming from stdin or at the end of the command. It will then +interpret all templates and output the result to stdout. For example with the +command: chezmoi execute-template '{{ .chezmoi.os }}/{{ .chezmoi.arch }}' -chezmoi will output the current os and architecture to stdout. +chezmoi will output the current OS and architecture to stdout. You can also feed the contents of a file to this command by typing: @@ -103,59 +165,57 @@ You can also feed the contents of a file to this command by typing: ## Simple logic -A very useful feature of chezmoi templates is the ability to perform logical operations. +A very useful feature of chezmoi templates is the ability to perform logical +operations. # common config export EDITOR=vi - + # machine-specific configuration {{- if eq .chezmoi.hostname "work-laptop" }} # this will only be included in ~/.bashrc on work-laptop {{- end }} -In this example chezmoi will look at the hostname of the machine and if that is equal to -"work-laptop", the text between the "if" and the "end" will be included in the result. +In this example chezmoi will look at the hostname of the machine and if that is +equal to "work-laptop", the text between the `if` and the `end` will be included +in the result. -### Locical operators +### Boolean functions -The following operators are available: +| Function | Return value | +| -------- | --------------------------------------------------------- | +| `eq` | Returns true if the first argument is equal to any of the other arguments. | +| `not` | Returns the boolean negation of its single argument. | +| `and` | Returns the boolean AND of its arguments by returning the first empty argument or the last argument, that is, `and x y` behaves as `if x then y else x`. All the arguments are evaluated. | +| `or` | Returns the boolean OR of its arguments by returning the first non-empty argument or the last argument, that is, `or x y` behaves as `if x then x else y` All the arguments are evaluated. | -* `eq` - Return true if the first argument is equal to any other argument. -* `or` - Return boolean or of the arguments. -* `and` - Return boolean and of the arguments. -* `not` - Return boolean negative of the argument. -* `len` - Return the length of the argument. +### Integer functions -Notice that some operators can accept more than two arguments. - -### Integer operators - -There are separate operators for comparing integers. - -* `eq` - Return true if the first argument is equal to any other argument. - arg1 == arg2 -* `ne` - Returns if arg1 is not equal to arg2 - arg1 != arg2 -* `lt` - Returns if arg1 is less than arg2. - arg1 < arg2 -* `le` - Returns if arg1 is less than or equal to arg2. - arg1 <= arg2 -* `gt` - Returns if arg1 is greater than arg2. - arg1 > arg2 -* `ge` - Returns if arg1 is greater than or equal to arg2. - arg1 >= arg2 - -`eq` can handle multiple arguments again, the same way as the "eq" above. +| Function | Return value | +| -------- | ------------------------------------------- | +| `len` | Returns the integer length of its argument. | +| `eq` | Returns the boolean truth of arg1 == arg2. | +| `ne` | Returns the boolean truth of arg1 != arg2. | +| `lt` | Returns the boolean truth of arg1 < arg2. | +| `le` | Returns the boolean truth of arg1 <= arg2. | +| `gt` | Returns the boolean truth of arg1 > arg2. | +| `ge` | Returns the boolean truth of arg1 >= arg2. | ## More complicated logic -Up until now, we have only seen if statements that can handle at most two variables. -In this part we will see how to create more complicated expressions. +Up until now, we have only seen if statements that can handle at most two +variables. In this part we will see how to create more complicated expressions. -You can also create more complicated expressions. The `eq` command can accept multiple -arguments. It will check if the first argument is equal to any of the other arguments. - - {{ if eq "foo" "foo" "bar" }}hello{{end}} +You can also create more complicated expressions. The `eq` command can accept +multiple arguments. It will check if the first argument is equal to any of the +other arguments. + {{ if eq "foo" "foo" "bar" }}one{{end}} {{ if eq "foo" "bar" "foo" }}hello{{end}} - {{ if eq "foo" "bar" "bar" }}hello{{end}} -The first two examples will output "hello" and the last example will output nothing. +The first two examples will output `hello` and the last example will output +nothing. The operators `or` and `and` can also accept multiple arguments. @@ -163,39 +223,41 @@ The operators `or` and `and` can also accept multiple arguments. You can perform multiple checks in one if statement. - {{ and ( eq .chezmoi.os "linux" ) ( ne .email "john@home.org" ) }} + {{ if (and (eq .chezmoi.os "linux") (ne .email "john@home.org")) }} + ... + {{ end }} -This will check if the operating system is Linux and the configured email -is not the home email. The brackets are needed here, because otherwise all the +This will check if the operating system is Linux and the configured email is not +the home email. The brackets are needed here, because otherwise all the arguments will be give to the `and` command. This way you can chain as many operators together as you like. ## Helper functions -chezmoi has added multiple helper functions to the [`text/template`](https://pkg.go.dev/text/template) -syntax. +chezmoi has added multiple helper functions to the +[`text/template`](https://pkg.go.dev/text/template) syntax. -Chezmoi includes [`Sprig`](http://masterminds.github.io/sprig/), an extension to -the text/template format that contains many helper functions. Take a look at +chezmoi includes [`sprig`](http://masterminds.github.io/sprig/), an extension to +the `text/template` format that contains many helper functions. Take a look at their documentation for a list. -Chezmoi adds a few functions of its own as well. Take a look at the +chezmoi adds a few functions of its own as well. Take a look at the [`reference`](REFERENCE.md#template-functions) for complete list. ## Template variables -Chezmoi defines a few useful templates variables that depend on the system -you are currently on. A list of the variables defined by chezmoi can be found +chezmoi defines a few useful templates variables that depend on the system you +are currently on. A list of the variables defined by chezmoi can be found [here](REFERENCE.md#template-variables). -There are, however more variables than -that. To view the variables available on your system, execute: +There are, however more variables than that. To view the variables available on +your system, execute: chezmoi data This outputs the variables in JSON format by default. To access the variable -`chezmoi>kernel>osrelease` in a template, use +`chezmoi.kernel.osrelease` in a template, use {{ .chezmoi.kernel.osrelease }} @@ -203,106 +265,76 @@ This way you can also access the variables you defined yourself. ## Using .chezmoitemplates for creating similar files -When you have multiple similar files, but they aren't quite the same, you can create -a template file in the directory .chezmoitemplates. This template can be inserted -in other template files. -For example: - -Create: - - .local/share/chezmoi/.chezmoitemplates/alacritty: +When you have multiple similar files, but they aren't quite the same, you can +create a template file in the directory `.chezmoitemplates`. This template can +be inserted in other template files, for example: -Notice the file name doesn't have to end in .tmpl, as all files in the directory -.chemzoitemplates are interpreted as templates. +Create `.local/share/chezmoi/.chezmoitemplates/alacritty`: some: config fontsize: {{ . }} somemore: config -Create other files using the template +Notice the file name doesn't have to end in `.tmpl`, as all files in the +directory `.chemzoitemplates` are interpreted as templates. -`.local/share/chezmoi/small-font.yml.tmpl` +Create other files using the template `.local/share/chezmoi/small-font.yml.tmpl` -``` -{{- template "alacritty" 12 -}} -``` + {{- template "alacritty" 12 -}} `.local/share/chezmoi/big-font.yml.tmpl` -``` -{{- template "alacritty" 18 -}} -``` + {{- template "alacritty" 18 -}} -Here we're calling the shared `alacritty` template with the he font size as -the `.` value passed in. You can test this with `chezmoi cat`: +Here we're calling the shared `alacritty` template with the he font size as the +`.` value passed in. You can test this with `chezmoi cat`: - $ chezmoi cat ~/small-font.yml - some: config - fontsize: 12 - somemore: config - $ chezmoi cat ~/big-font.yml - some: config - fontsize: 18 - somemore: config + $ chezmoi cat ~/small-font.yml + some: config + fontsize: 12 + somemore: config + $ chezmoi cat ~/big-font.yml + some: config + fontsize: 18 + somemore: config ### Passing multiple arguments -In the example above only one arguments is passed to the template. To pass -more arguments to the template, you can do it in two ways. -#### Via chezmoi.toml +In the example above only one arguments is passed to the template. To pass more +arguments to the template, you can do it in two ways. + +#### Via the config file This method is useful if you want to use the same template arguments multiple times, because you don't specify the arguments every time. Instead you specify -them in the file `.chezmoi.toml`. +them in the file `.config/chezmoi/.chezmoi.toml`: -`.config/chezmoi/chezmoi.toml`: - -``` +```toml [data.alacritty.big] - fontsize = 18 - font = DejaVu Serif + fontsize = 18 + font = "DejaVu Serif" [data.alacritty.small] - fontsize = 12 - font = DejaVu Sans Mono -``` - -`.local/share/chezmoi/.chezmoitemplates/alacritty`: - -``` -some: config -fontsize: {{ .fontsize }} -font: {{ .font }} -somemore: config + fontsize = 12 + font = "DejaVu Sans Mono" ``` -`.local/share/chezmoi/small-font.yml.tmpl` +Use the variables in `.local/share/chezmoi/.chezmoitemplates/alacritty`: -``` -{{- template "alacritty" .alacritty.small -}} -``` + some: config + fontsize: {{ .fontsize }} + font: {{ .font }} + somemore: config -`.local/share/chezmoi/big-font.yml.tmpl` +And connect them with `.local/share/chezmoi/small-font.yml.tmpl`: -``` -{{- template "alacritty" .alacritty.big -}} -``` + {{- template "alacritty" .alacritty.small -}} -At the moment, this means that you'll have to duplicate the alacritty data in +At the moment, this means that you'll have to duplicate the alacritty data in the config file on every machine, but a feature will be added to avoid this. #### By passing a dictionary Using the same alacritty configuration as above, you can pass the arguments to -it with a dictionary. - -`.local/share/chezmoi/small-font.yml.tmpl` +it with a dictionary, for example `.local/share/chezmoi/small-font.yml.tmpl`: -``` -{{- template "alacritty" dict "fontsize" 12 "font" "DejaVu Sans Mono" -}} -``` - -`.local/share/chezmoi/big-font.yml.tmpl` - -``` -{{- template "alacritty" dict "fontsize" 18 "font" "DejaVu Serif" -}} -``` + {{- template "alacritty" dict "fontsize" 12 "font" "DejaVu Sans Mono" -}}