kiln(1) # NAME kiln - a simple static site generator # SYNOPSIS *kiln* build [-c _config_] *kiln* new _path_ *kiln* version # DESCRIPTION *kiln build* builds a kiln site. *kiln new* creates a new kiln site at the given path. *kiln version* prints version information for the kiln program. # OPTIONS ## kiln build *-c* _config_ Specifies the configuration file to use. Defaults to "config.toml". # OVERVIEW A kiln site is built in one or more steps called *tasks*. Tasks read content from the content directory, process the content, and write the content to the output directory. Tasks can also be configured to copy static content to the output directory. The following directories are common to all tasks: [[ *Directory* :[ *Description* | content/ : Content directory | templates/ : Templates directory # CONTENT DIRECTORY The content directory contains site content files, called *pages*, optionally nested in subdirectories. Any file or directory in the content directory whose name begins with "\_" will be ignored, with the exception of pages with the name "\_index" (e.g. "\_index.gmi"). Pages may be preprocessed, run through templates, and postprocessed (in that order). Each operation takes the output of the last operation as input. Pages can specify dates in their filenames. For example, the page content/2020-11-20-Hello-world.gmi will have a path of /Hello-world/ and a date of November 20, 2020. Pages with the name "\_index" are index pages and are treated specially. ## FRONTMATTER Pages can specify additional metadata in frontmatter. Frontmatter is delimited by "---" and is specified in YAML. Newlines after the closing delimiter are removed from the content. Example: ``` --- title: Page title date: 2021-04-24 params: custom: value --- Page content ``` The following keys are supported: *title* The title of the page. Example: ``` --- title: My first post --- ``` *date* The date of the page. Pages are sorted by date in reverse order, so newer pages will be placed above older pages. Example: ``` --- date: 2021-05-21 --- ``` *weight* The weight of the page. Pages are sorted by weight in increasing order, so pages with a smaller weight will be placed above pages with a larger weight. Example: ``` --- weight: 1 --- ``` *params* Specifies extra parameters to be provided to templates. Example: ``` --- params: key: value --- ``` ## SORTING Pages are sorted automatically. Pages are first ordered by weight in increasing order, then by date from newest to oldest, and then by filename in alphabetical order. # TEMPLATES DIRECTORY The templates directory contains templates for use when building the site. Templates use the Go templating language. The following templates are supported: [[ *Template* :[ *Description* | page.ext : Page template | index.ext : Directory index template | base.ext : Base template from which the page and index templates inherit | atom.xml : Atom feed template The extension of page and index templates is configurable and will replace ".ext" above. See *CONFIGURATION*. The scope of a template is limited by the directory it is placed in. For example, a template in the templates/blog directory will only apply to files in content/blog. Fallback templates can be specified in the templates/\_default directory. These templates will apply to any directory which does not have its own templates specified in the template directory. For more information on the Go templating language, see https://golang.org/pkg/text/template/. # CONFIGURATION By default, kiln looks for a configuration file named "config.toml". An alternative configuration file can be specified with the *-c* flag. See *OPTIONS*. The configuration file uses the _TOML_ format. The following keys are supported: [[ *Key* :[ *Description* | title : Site title | urls : A list of site URLs Site URLs may contain paths, but should not end with a trailing slash. Multiple site URLs may be specified for sites that are available at multiple locations. ## FEEDS Feeds can be specified in the [feeds] table of the configuration file. Keys denote the path to the feed directory and values denote the title of the feed. Feeds are written to the output directory plus the feed directory plus "atom.xml". Example feed configuration: ``` # This will generate a feed which will be written to public/blog/atom.xml [feeds] "/blog/" = "My blog" ``` ## PERMALINKS Permalinks can be used to rewrite page paths. Permalinks are specified in the \[permalinks] table of the configuration file. Keys denote a path to a directory, and values use the Go templating language to rewrite the final path of pages in that directory. The templates have the same data that page templates have available to them (see *PAGE TEMPLATES*). The following configuration will rewrite the paths of pages in the content/blog directory to /YYYY/MM/DD/slug. For example, the file content/blog/2021-05-12-hello-world.gmi will have a path of /2021/05/12/hello-world/. ``` [permalinks] "/blog/" = "/{{ .Date.Format `2006/01/02` }}/{{ path.Base .Path }}" ``` For more information on templates, see *TEMPLATES*. ## TASKS Tasks can be specified in the [[tasks]] array of tables. The following configuration options are supported per task: *input* A list of input file extensions. Files in the content directory with a matching extension will be processed. Example: ``` [[tasks]] input = [".gmi", ".md"] ``` *output* The output file extension. Files written to the output directory will use this extension. Example: ``` [[tasks]] output = ".html" ``` *template* The template file extension. Templates with this file extension will be used to format the content. If unset, no templates will be used. Example: ``` [[tasks]] template = ".gmi" ``` *preprocess* Maps file extensions to preprocess commands. Preprocess commands will run before templating. The commands will be provided the content of the page as standard input and should write the processed content to standard output. Example: ``` [[tasks]] input = [".gmi", ".md"] output = ".html" preprocess.gmi = "gmnitohtml" preprocess.md = "mdtohtml" ``` *postprocess* Specifies a command which will run after templating and before content is written to the output directory. It will be provided the content of the page as standard input and should write the processed content to standard output. Example: ``` [[tasks]] input = [".gmi"] output = ".html" template = ".gmi" postprocess = "gmnitohtml" ``` *static_dir* Specifies a directory from which to read static content. All files in this directory will be copied to the output directory without modificiation. Static assets like images should be stored in this directory. If unset, no static content directory will be used. Example: ``` [[tasks]] static_dir = "static" ``` *output_dir* Specifies the directory to which output files will be written. Example: ``` [[tasks]] output_dir = "public" ``` *ugly_urls* Specifies whether page permalinks will contain file extensions. By default, clean URLs without any extension are used. Example: ``` [[tasks]] ugly_urls = true ``` The following configuration builds a simple Gemini site. ``` [[tasks]] input = [".gmi"] output = ".gmi" template = ".gmi" output_dir = "public" ``` The following configuration generates a Gemini text site and also exports an HTML version of the site. This configuration makes use of the *gmnitohtml*(1) command to convert Gemini text to HTML. ``` # Build the site [[tasks]] input = [".gmi"] output = ".gmi" template = ".gmi" static_dir = "static" output_dir = "public" # Export an HTML version of the site [[tasks]] input = [".gmi"] output = ".html" template = ".gmi" postprocess = "gmnitohtml" static_dir = "static" output_dir = "public.html" ``` The following configuration generates an HTML site from Markdown files in the content directory and HTML templates in the templates directory. This configuration makes use of the *markdown*(1) comand to convert Markdown to HTML. ``` [[tasks]] input_ext = [".md"] output_ext = ".html" template_ext = ".html" preprocess.md = "markdown" static_dir = "static" output_dir = "public" ``` # TEMPLATES Templates have certain data and functions available to them. ## TEMPLATE FUNCTIONS All templates have the following functions available to them: *and* _args..._ 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. *call* _function_, _args..._ Returns the result of calling the first argument, which must be a function, with the remaining arguments as parameters. Thus "call .X.Y 1 2" is, in Go notation, dot.X.Y(1, 2) where Y is a func-valued field, map entry, or the like. The first argument must be the result of an evaluation that yields a value of function type (as distinct from a predefined function such as print). The function must return either one or two result values, the second of which is of type error. If the arguments don't match the function or the returned error value is non-nil, execution stops. *eq* _arg1_, _arg2_ Returns the boolean truth of _arg1_ == _arg2_. *ge* _arg1_, _arg2_ Returns the boolean truth of _arg1_ >= _arg2_. *gt* _arg1_, _arg2_ Returns the boolean truth of _arg1_ > _arg2_. *html* _args..._ Returns the escaped HTML equivalent of the textual representation of its arguments. This function is unavailable in HTML templates, with a few exceptions. *index* _collection_, _args..._ Returns the result of indexing its first argument by the following arguments. Thus "index x 1 2 3" is, in Go syntax, x[1][2][3]. Each indexed item must be a map, slice, or array. *js* _args..._ Returns the escaped JavaScript equivalent of the textual representation of its arguments. *le* _arg1_, _arg2_ Returns the boolean truth of _arg1_ <= _arg2_. *len* _list_ Returns the integer length of its argument. *lt* _arg1_, _arg2_ Returns the boolean truth of _arg1_ < _arg2_. *ne* _arg1_, _arg2_ Returns the boolean truth of _arg1_ != _arg2_. *not* _arg_ Returns the boolean negation of its single argument. *or* _args..._ 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. *partial* _name_, _data_ Executes the named partial template with the provided data. See *PARTIAL TEMPLATES*. Example: ``` {{ partial "header.gmi" . }} ``` *path.Base* _path_ Returns the last element of _path_. *path.Clean* _path_ Returns the shortest path name equivalent to _path_. *path.Dir* _path_ Returns all but the last element of _path_, typically the path's directory. *path.Ext* _path_ Returns the filename extension used by _path_. *path.Join* _elem..._ Joins any number of path elements into a single path. *print* _args..._ Formats using the default formats for its operands and returns the resulting string. Spaces are added between operands when neither is a string. *printf* _format_, _args..._ Formats according to a format specifier and returns the resulting string. *println* _args..._ Formats using the default formats for its operands and returns the resulting string. Spaces are always added between operands and a newline is appended. *reverse* _list_ Returns a reversed copy of the provided slice or array. *safeCSS* _css_ Encapsulates known safe CSS content. *safeHTML* _html_ Encapsulates a known safe HTML document fragment. *safeHTMLAttr* _attr_ Encapsulates an HTML attribute from a trusted source. *safeJS* _js_ Encapsulates a known safe JavaScript expression. *safeURL* _url_ Encapsulates a known safe URL or URL substring. *site* Returns site metadata (see *SITE METADATA*). *slice* _list_, _args..._ slice returns the result of slicing its first argument by the remaining arguments. Thus "slice x 1 2" is, in Go syntax, x[1:2], while "slice x" is x[:], "slice x 1" is x[1:], and "slice x 1 2 3" is x[1:2:3]. The first argument must be a string, slice, or array. *strings.Count* _string_, _substr_ Counts the number of non-overlapping instances of _substr_ in _string_. If _substr_ is an empty string, Count returns 1 + the number of Unicode code points in _string_. *strings.HasPrefix* _string_, _prefix_ Reports whether _string_ begins with _prefix_. *strings.HasSuffix* _string_, _suffix_ Reports whether _string_ ends with _suffix_. *strings.Join* _elems_, _sep_ Concatenates the elements of its first argument to create a single string. The separator string _sep_ is placed between elements in the resulting string. *strings.Repeat* _string_, _count_ Returns a new string consisting of _count_ copies of _string_. It panics if _count_ is negative or if the result of (len(_string_) \* _count_) overflows. *strings.Replace* _string_, _old_, _new_, _n_ Returns a copy of _string_ with the first _n_ non-overlapping instances of _old_ replaced by _new_. If _old_ is empty, it matches at the beginning of the string and after each UTF-8 sequence, yielding up to k+1 replacements for a k-rune string. If _n_ < 0, there is no limit on the number of replacements. *strings.ReplaceAll* _string_, _old_, _new_ Returns a copy of _string_ with all non-overlapping instances of _old_ replaced by _new_. If _old_ is empty, it matches at the beginning of the string and after each UTF-8 sequence, yielding up to k+1 replacements for a k-rune string. *strings.Split* _string_, _sep_ Slices _string_ into all substrings separated by _sep_ and returns a slice of the substrings between those separators. If _string_ does not contain _sep_ and _sep_ is not empty, Split returns a slice of length 1 whose only element is _string_. If _sep_ is empty, Split splits after each UTF-8 sequence. If both _string_ and _sep_ are empty, Split returns an empty slice. *strings.Title* _string_ Returns a copy of the string with all Unicode letters that begin words mapped to their Unicode title case. *BUG:* The rule Title uses for word boundaries does not handle Unicode punctuation properly. *strings.ToLower* _string_ Returns _string_ with all Unicode letters mapped to their lower case. *strings.ToUpper* _string_ Returns _string_ with all Unicode letters mapped to their upper case. *strings.Trim* _string_, _cutset_ Returns a slice of _string_ with all leading and trailing Unicode code points contained in _cutset_ removed. *strings.TrimLeft* _string_, _cutset_ Returns a slice of _string_ with all leading Unicode code points contained in _cutset_ removed. To remove a prefix, use *strings.TrimPrefix* instead. *strings.TrimPrefix* _string_, _prefix_ Returns _string_ without the provided leading _prefix_ string. If _string_ doesn't start with _prefix_, it is returned unchanged. *strings.TrimRight* _string_, _cutset_ Returns a slice of _string_ with all trailing Unicode code points contained in _cutset_ removed. To remove a suffix, use *strings.TrimSuffix* instead. *strings.TrimSpace* _string_ Returns a slice of _string_ with all leading and trailing white space removed, as defined by Unicode. *strings.TrimSuffix* _string_, _suffix_ Returns _string_ without the provided trailing _suffix_ string. If _string_ doesn't end with _suffix_, it is returned unchanged. *urlquery* _args..._ Returns the escaped value of the textual representation of its arguments in a form suitable for embedding in a URL query. This function is unavailable in HTML templates, with a few exceptions. ## SITE METADATA Site metadata contains the following data: package main import ( "fmt" "path" ) func main() { fmt.Println(path.Join("https://example.com", "hello-world")) } [[ *Variable* :[ *Description* | Title : The title of the site. | URLs : The URLs of the site. To configure these variables, see *CONFIGURATION*. ## PAGE TEMPLATES Page templates are provided with the following data: [[ *Variable* :[ *Description* | Title : The title of the page | Date : The date of the page | Path : Path to the page | Content : The contents of the page | Params : Extra parameters specified in frontmatter ## INDEX TEMPLATES Index templates are provided with all the data that page templates are provided, plus the following data: [[ *Variable* :[ *Description* | Pages : List of pages in this directory | Dirs : List of subdirectories ## FEED TEMPLATES Feed templates are provided with the following data: [[ *Variable* :[ *Description* | Title : Title of the feed | Path : Path to the feed directory | Entries : List of pages in this feed ## PARTIAL TEMPLATES Partial templates can be specified in the templates/\_partials directory. Partial templates can be executed from any other template with the *partial* function. See *TEMPLATE FUNCTIONS*.