/target
files/test_site/build
+files/README/build
files/bench_site/build
--- /dev/null
+<!DOCTYPE html>
+<html>
+&{head}
+&{body}
+&{foot}
+</html>
--- /dev/null
+<body>
+ <a href="../index.html">home</a>
+ <h1>${title}</h1>
+ <p>${description}</p>
+ <article>
+ &{SOURCE}
+ </article>
+</body>
--- /dev/null
+<foot>
+made with <strong>metaforge</strong>
+</foot>
--- /dev/null
+<head>
+ <title>${title}</title>
+ <meta name="description" content="${description}">
+ <meta name="author" content="${author}">
+</head>
--- /dev/null
+${
+ author = 'huck boles'
+ version = '0.1.1'
+ home = './index.html'
+}
--- /dev/null
+${
+ var = '${'
+ arr = '@{'
+ pat = '&{'
+ head = '#{'
+ com = '-{'
+}
--- /dev/null
+${
+ title = 'definitions'
+ description = 'definining variables and patterns'
+}
+
+## rules
+
+definition blocks are allowed in all files, but have to be before any source
+text, and after any header settings (which are a special type of definition block)
+
+a block is a sigil for the definition type, followed by braces that
+surround assignment statements
+
+assignments are identifiers, followed by an equals sign, then a value
+
+definition blocks can have spaces and new lines arbitrarily inserted
+between each component, and support multiple assignments per block
+
+## identifiers
+
+identifiers can contain alphanumeric ascii values as well as _ and separating dots .
+
+variable identifiers without dots are available to any pattern called by the file
+
+array identifiers without dots are available only to the pattern they are defined in
+
+variable and array identifiers with separating dots use the final item
+as the variable, and the preceding items are expanded like a pattern identifier to make
+a mask on the definition. the definition is only valid in that pattern directory (not children), otherwise it is undefined.
+
+pattern identifiers expand to a directory of files in the pattern
+directory by replacing .'s with /'s, appending necessary file extensions when called.
+the value selects a single file in the directory as the desired pattern.
+
+an identifier preceded by an star (*) will be marked as local to the file it is defined in.
+entire blocks can be marked as local by preceding them with a star. if necessary, a single
+assignment in a local block can be made global again by prefixing it with an exclamation mark (!).
+
+## values
+
+values can be a double or single quoted string, if defining an array,
+a value is a bracket surrounded, comma separated list of strings
+
+all values can optionally be assigned as BLANK, which expands to nothing
+
+patterns can also be assigned as DEFAULT, for overriding globally defined patterns.
+
+## scope
+
+any value defined in a file called **default.meta** in the source
+directory is defined in all files in the current and child directories.
+
+values defined normally are defined for any file called in the chain of expansion.
+this value can be overridden, either for a single file in the chain by prefixing the
+definition with a star *, or for any files further down the chain, by defining a new
+value normally.
+
+## examples
+
+ ${var}
+ *foo = 'bar' ${com} foo is only equal to bar in this file }
+ bar.baz = BLANK ${com} this only applies to pattern/bar/*.meta }
+ baz = quux ${com} baz is equal to quux in every file called during
+ expansion, unless it gets overridden }
+ }
+
+ ${arr}
+ bar = ['foo','bar']
+ baz.blank = BLANK ${com} this inserts nothing }
+
+ foo.bar = [ 'foobar', 'foobaz' ]
+ ${com} this will copy pattern/foo/*.meta twice, inserting 'foobar and 'foobaz'
+ once each at the location of @{bar} }
+ }
+
+ ${com} all of these patterns are only defined for this file }
+ *${pat}
+ foo.bar = BLANK
+ bar.default = DEFAULT
+
+ !baz = "bar"
+ ${com} except for this definition, which
+ continues down the expansion chain }
+ }
--- /dev/null
+${
+ title = 'expansions'
+ description = 'expanding variables and patterns in a file'
+}
+
+## syntax
+
+a sigil followed by braces, with an identifier inside.
+
+happens inside the source, expanding to the relevant value
+when the file is built
+
+### examples
+
+ ...this is a string with a ${var}variable} to be expanded...
+
+ ...this line has a ${pat}pattern} inside of it...
+
+ ...this ${arr}array} will be replaced...
+
+## behavior
+
+all expansions are decided by the value defined for the identifier,
+following inheritance rules, and directory masking for variables and arrays.
+
+### variables
+
+variables are simply replaced by the defined value, with no other substitution.
+they're useful for small things that are frequently changed in a pattern, but
+don't need any extra expansion.
+
+#### example
+
+ definition:
+ ${var}
+ baz = "foo"
+ bar.baz = "quux"
+ quux = BLANK
+ }
+
+ pattern [foo]: <p>${var}baz} ${var}quux}</p>
+
+ expanded [foo]: <p>foo </p>
+
+ pattern [bar]: <p>${var}baz} ${var}quux}</p>
+
+ expanded [bar]: <p>quux </p>
+
+### arrays
+
+arrays are similar to variables, but are closely related to the masking pattern.
+after all expansions happen in a pattern, each defined array maps its contents
+across copies of the pattern, resulting in a easy method for duplicating repetitive
+parts of patterns.
+
+#### example
+
+ pattern [foo]: <p>${arr}bar}</p>
+
+ defintion: ${arr} foo.bar = ['foo', 'bar', 'baz'] }
+
+ expands to: <p>foo</p><p>bar</p><p>baz</p>
+
+it's generally best to keep arrays inside small self-contained
+patterns, otherwise unwanted parts of the file may be duplicated.
+
+### patterns
+
+patterns expand by looking for files using the pattern directory as a root.
+the identifier becomes a directory by changing .'s to /'s.
+if a defined value exists, it's used as the filename, with a **.meta**
+extension added automatically. if no value is defined, metaforge next looks
+for files with the exact name in the identifier, again substituting .'s to /'s.
+if a file still hasn't been found, or the pattern has most recently been defined
+as ***DEFAULT***, then **default.meta** is selected from the identified directory.
+
+#### example search
+ foo.bar => pattern/foo/bar/*.meta => pattern/foo/bar.meta => pattern/foo/bar/default.meta
+
+if no file is found metaforge will either insert an empty string, or panic depending
+on the flags and header settings in effect. a pattern defined as ***BLANK*** will always
+expand to a blank string without errors.
+
+if the identifier in the pattern is ***SOURCE***, the pattern will expand using the
+processed source from the original calling file in the source directory. this
+goes through an extra step right before insertion, calling pandoc on the file
+to convert between the chosen filetypes.
+
+once the filename is determined, it is parsed and expands any contained variables,
+arrays and patterns. if it is a ***SOURCE*** pattern, it is converted to html after
+the expansions. the expanded pattern is then inserted in place of the calling identifier.
+
+## building
+
+as each file is built, the first thing expanded is the relevant **base/[FILE].meta** pattern,
+so it is required to have at least a **default.meta** in the **pattern/base** directory
+
+### example
+
+ pattern [base]: <html>${pat}body}</html>
+
+ pattern [body]: <body>${pat}SOURCE}</body>
+
+ source [SOURCE]: foo *bar* baz
+
+ expanded [base] : <html><body><p>foo <italic>bar</italic> baz</p></body></html>
--- /dev/null
+${
+ title = 'flags'
+ description = 'available flags for running metaforge'
+}
+
+## available flags
+
+ -r, --root <ROOT_DIR>
+ root directory, contains source, pattern and build directories
+ defaults to current working directory
+ -s, --source <SOURCE_DIR>
+ source file directory, contains directory structure and .meta files for completed site
+ defaults to [root_dir]/source
+ -b, --build <BUILD_DIR>
+ build directory, directory where the final site gets built
+ defaults to [root_dir]/build
+ -p, --pattern <PATTERN_DIR>
+ pattern directory, contains .meta files that are available for expansion
+ defaults to [root_dir]/pattern
+ -f, --file <FILENAME>
+ builds a single file and outputs it to stdout
+ -v, --verbose
+ enable extra output. repeated flags give more info
+ v => list source files/directories being created
+ vv => list expansions and substitutions
+ vvv => full debug information (function calls, interior parameters)
+ -q, --quiet
+ minimal output
+ -o, --output <OUTPUT_FILETYPE>
+ output filetype, defaults to html
+ options:
+ - html
+ - markdown
+ - json
+ - latex
+ - man
+ - txt
+ - asciidoc
+ - pdf
+ -i, --input <INPUT_FILETYPE>
+ input filetype, defaults to markdown
+ options:
+ - markdown
+ - html
+ - json
+ - latex
+ - org
+ -h, --help
+ print a brief help page
+ -V, --version
+ print version
+ --clean
+ clean build directory before building site,
+ will remove anything currently in build directory
+ --new
+ create a new skeleton directory in the root dir
+ --force
+ don't stop building site if a single file fails
+ --undefined
+ panics and stops building site if any undefined variables are encountered
+ --no-pandoc
+ don't call pandoc on source files
+ allows metaforge to run without pandoc installed
--- /dev/null
+${
+ title = 'headers'
+ description = 'file headers to change behavior'
+}
+
+## header blocks
+
+define settings for the parser, allowing better control over how a single file gets
+processed.
+
+header blocks works similarly as any other definition block, with keys consisting
+of pre-defined keywords, and values are booleans (unquoted) or strings, and the ***DEFAULT***
+option for overriding.
+
+the header block must be the first block in a file, as it determines how the parser
+reads and constructs the rest of the file
+
+in a **default.meta** file, any keys preceded by an exclamation mark (!) get applied
+as global header settings, following the same inheritance rules as other global definitions.
+
+prefixing a definition block with an exclamation mark makes the entire block globally defined.
+inside, you can mark individual assignments as local by preceding them with a star (*) as in
+normal definition blocks.
+
+### example
+
+ ${head}
+ filetype = 'txt'
+ !pandoc = 'false'
+ }
+
+## keywords
+
+### any
+
+- blank = BOOL - stops parsing and returns an empty string
+- panic_default = BOOL - if true, panics on an undefined default pattern
+- panic_undefined = BOOL - if true, panics on an undefined variable or array
+- equal_arrays = BOOL - if true, panics if arrays in the same pattern have different sizes
+
+### source
+
+- ignore = BOOL - stops parsing and skips this file, useful for ignoring directories with scoped definitions
+- filetype = STRING - change the filetype of the output file
+- source = STRING - change the the filetype of the source file
+- pandoc = BOOL - toggles if pandoc is ran on this file to convert between filetypes
--- /dev/null
+## file locations
+metaforge parses files with the **.meta** extension.
+
+files in the pattern directory are available for file expansion.
+**default.meta** files are fallback files if the pattern directory
+gets called without a defined value.
+
+the structure of the source directory gets mirrored to the build
+directory as the site is build, with any **.meta** files
+becoming **.html** files, except **default.meta** files,
+which define default values for a directory and its children.
+
+the source section of files in the source directory can be written
+in markdown and will converted to html.
+
+files from the pattern directory the should generally contain html snippets,
+but can contain anything that you'd like to substitute.
+
+required directories are:
+- source - site structure and contents
+- pattern - patterns for expansion
+- pattern/base - gets expanded to start building each pattern.
+
+the build directory doesn't need to exist, as metaforge will create a
+new one if it's missing
+
+a new skeleton site can be built in the given root directory by passing
+the ***--new*** flag to metaforge,
+
+## skeleton structure
+ ./
+ L pattern/
+ | L base/
+ | | L default.meta
+ | L body/
+ | | L default.meta
+ | L head/
+ | | L default.meta
+ | L foot/
+ | L default.meta
+ L source/
+ | L hello_world.meta
+ L build/
+ L hello_world.html
--- /dev/null
+${
+ title = 'syntax'
+ description = 'basic syntax rules'
+}
+
+## sigils
+- $ variables
+- @ arrays
+- & patterns
+- \# settings
+- \- comments
+
+## definition block
+a sigil followed by assignment operations enclosed by brackets
+
+### examples
+ ${var} foo = 'bar' }
+
+ ${pat}
+ foo.bar = "baz"
+ bar.baz = 'foo'
+ }
+
+## strings
+double or single quoted strings, double quoted strings require escaping
+control characters, and single quoted strings get copied as is.
+single quoted strings can stretch across newlines.
+
+### examples
+ "foo bar baz\n"
+
+ 'foo
+ bar
+ baz'
+
+## arrays
+a list of strings, separated by commas, enclosed by brackets.
+whitespace and newlines between list values are accepted
+
+### examples
+ [ 'foo', 'bar', 'baz', 'quux' ]
+
+ ["foo","bar","baz"]
+
+ [
+ 'foo',
+ 'bar',
+ 'baz'
+ ]
+
+## comments
+a comment sigil \- followed by a comment in braces
+the only characters not allowed are braces.
+
+comments get removed during the first pass through of parsing, and can occur
+anywhere in or across a line.
+
+### examples
+ ${com} foobar }
+
+ ${com}
+ foobar
+ foobaz
+ }
+
+## layout
+- optional header definition block
+- optional variable, array, pattern definition blocks
+- source
+
+### example
+ ${head} foo = 'bar' } ${com} settings for parsing file }
+
+ ${var}
+ foo = 'foobar'
+ bar.foo = 'foobaz'
+ }
+
+ ${arr}
+ foo = ['foobar','foobaz']
+ foo.bar.baz = [ 'foobar', 'foobaz', 'barbaz' ]
+ }
+
+ ${pat}
+ foo.bar = 'foobar'
+ bar = "foo_bar"
+ }
+
+ # FOOBAR
+ Foo bar baz quux lorem ipsum...
--- /dev/null
+${
+ title = 'metaforge documentation'
+}
+
+this is the documentation for metaforge, generated by metaforge itself.
+
+currently it's unstyled html rendered by your browser, so it's pretty bare-bones right now, but
+you can change that easily.
+
+open **files/README** in metaforge's repository, and explore the source and pattern
+files to get a glimpse into a working project.
+
+## contents
+- [syntax](docs/syntax.html)
+- [definitions](docs/definitions.html)
+- [expansions](docs/expansions.html)
+- [structure](docs/structure.html)
+- [headers](docs/headers.html)
+- [flags](docs/flags.html)
#[arg(short, long, value_name = "FILENAME")]
pub file: Option<String>,
/// parallel processing
- #[arg(short, long, default_value_t = false)]
+ #[arg(long, default_value_t = false)]
pub parallel: bool,
/// create a new skeleton directory
#[arg(long, default_value_t = false)]