HaXtatic Docs

Project setup: *.haxproj files

A near-empty default.haxproj was created during project creation. This plain-text file exists to contain any number of (fairly trivial) "directives" — lean-yet-expressive statements that may: define reusable micro-contents, fine-tune the overall processing flow, associate certain content pages with one another, or compose and direct custom rendering logic.

(Note that you can combine multiple *.haxproj files — eg. if they grow too big to grasp at once, or for more advanced purposes such as temporary overriding of some directives or separately co-existing "named setups" in a single project.)

Directives

Here's what they look like:

|T|greeting: Hello stranger!
|C|_hax_domainname: www.haxtatic.foo
	

Simples. A "directive" begins with a line starting precisely with one of |T|, |B|, |X|, |P|, or |C|, and spans all subsequent lines until the one that begins the next directive. Best practice (for readability and avoiding subtle pitfalls) is to indent all subsequent lines "belonging" to each directive, but this isn't strictly required. Everything before the first directive is ignored, everything after necessarily belongs to some directive or other.

Specifying local paths

Directives of type |B| and |C| allow specifying of local paths. These are typically considered relative to the project's build directory and in any event, nowhere are paths pointing outside the project directory supported. HaXtatic does attempt to sanitize those and then interpret them as relative to the currently supposed context.

|T| directives: for text values

  • Define named plain-text/simple-markup snippets like so:
    |T|AuthBlurb: The author is a serial enthusiast
    role-playing <a>on XingedIn</a>.
  • Embed as T-tags anywhere: {T|AuthBlurb|}
  • Leading/trailing white-space is stripped of both the name and the value, which as shown are separated by the first colon encountered.

|B| directives: for "Bloks"

Just as |T| directives consist of a name connected via a  : to their value, so each and every |B| directive defines a Blok (a section-of-related-pages, or indeed a simple "poor-man's blog-of-sorts") by connecting via a  : that Blok's name to its properties — eg. here's how this site's current Basics section (also just a "Blok") is (approximately, the original includes haXtags) defined:

|B|basics:
    title="Basics",
    atomFile = "-xml/basics.atom",
    blokIndexPageFile="basics/index.html",
    inSitemap = True,
    desc=>
       <p>This material may appear "unduly exhaustive" at
	first glance, but this is all blatantly-simple-stuff
	and mostly just spelled out in (almost) every last
	minor detail for completeness and future reference.</p>
	<p>Notably no article on <b>"how to author pages"</b>.
	That's because there's nothing to it once a quick note
	is made of <a href="../basics/projdir.html">where to place them</a>,
	<a href="../basics/tmplsnip.html">which outer-template is applied during processing &amp; how</a>,
	as well as the diverse range of <a href="../tags/index.html">haXtags</a>
	that any page (indeed any user-authored/-customized file
	in a project) may embed and combine in any manner.</p>

Stringent syntactic rules apply here! The properties in detail:

  • title and desc — self-explanatory, and used (for one) in these associated auto-generated files, if any:
  • atomFile and blokIndexPageFile both describe a site-root-relative (aka. build-directory-relative) file path and if empty, these files will not be generated.
  • inSitemap includes or excludes all pages associated with this Blok in/from the generated sitemap.xml (if any)

The values set for the above properties can be output anywhere via B-tags — so in essence each |B| directive automatically defines 5 uniquely distinct B-tags.

|X| directives: for rendering

Just as each |T| directive practically defines a uniquely distinct T-tag that can be embedded many times anywhere (to effect in-place text substitution), so each and every |X| directive in essence defines a uniquely distinct X-tag that can be embedded many times anywhere (to effect in-place output rendering by some custom logic).

That is to say: with |X|x-renderer-type:mytagname: .. we declare that {X|mytagname: ..|} encountered anywhere will during processing invoke the X-renderer x-renderer-type with the defined properties in effect.

So every |X| directive associates with a chosen custom (X-)tag name: both a specified X-renderer type to invoke for output rendering (in-place of every X-tag encountered with that given name), and that X-renderer's properties effective while it produces output.

For example, this site declares (among others) these two |X| directives in order to automatically generate on every page (the shaded box near the top to the right) a listing of "Jump To" shortcuts for every chapter heading on that page:

|X|hax.miniTag:h:h2:
    attr=[("id","{:content:}")]

|X|hax.htmlAnchors:doxpagetoc:h2:
    considerEmpty = 1,
    outputIfEmpty = "<style type='text/css'>.hd-toc { display: none; }</style>",
    xmlEscapeHref = False

No particularly substantial extra effort here for all the individual content pages: these simply contain their chapter headings not as plain <h2> HTML tags but as {X|h: Chapter Heading Here|} X-tags instead (2 quick "find&replace-in-folders" commands in any minimally capable text editor if this change is introduced late). Meanwhile just the default.haxtmpl.html employs a single {X|doxpagetoc:li: attr = [] |} X-tag to dynamically produce these desired, page-content-specific <li><a href="#... outputs in all generated pages.

To recapitulate

what becomes immediately apparent from just this example:

  1. Specify first the X-renderer type (here hax.miniTag and hax.htmlAnchors)
  2. followed by a  : and a custom (X-)tag name (here  h and doxpagetoc) and another  :
  3. followed by some individually-varying X-renderer-specific settings notation (aka. tag config) that each X-renderer defines and documents separately.
  4. In turn, usage of any {X| tag embedded anywhere begins with the very custom tag name from 2. (again, here  h and doxpagetoc) pointing to the associated |X| directive, followed by a  : and then possibly some further individually-varying X-renderer-specific per-instance settings notation (aka. tag params), if any.
  5. For the built-in X-renderers, both the per-tag settings (aka. tag config) and per-instantiation settings (aka. tag params) notation is (either one or the other but) usually a combination of:

|P| directives: for "postings"

Create "micro-content records" with |P| directives. All such "posts" are categorized first into "feed names" (or think arbitrary "primary category", really) and a further sub-level of "cat"(egory). The general format is as the following 2 examples illustrate:

|P|quotes:
    dt = "2016-01-23",
    cat="Programming",
    title="Brian Beckman",
    link="http://youtu.be/ZhuHCtR3xq8?t=1003",
    more=[],
    content=>
    As software gets ever more complicated, we need better control over the complexity. [...]
    <i>The</i> way to control complexity is compositionality.

|P|quotes:
    dt = "2016-03-21",
    cat="Programming",
    title="John Carmack",
    link="http://number-none.com/blow/john_carmack_on_inlined_code.html",
    more=[	("customfield1","data value 1"),
    		("customfield2","dat data value 2"),
    		("customfieldX","funky dis") ],
    content=>
    I have gotten much more bullish about pure functional programming.

Stringent syntactic rules apply here! The property names should be self-explanatory, except more (normally not needed and then best kept  [] empty — when such custom "record data" fields become a serious consideration, check out the default.haxproj for this very site for usage). The above example constitutes:

  • 1 "feed" (aka. arbitrary primary category) named quotes
  • made up of 2 "posts" (aka. micro-content records),
  • both in the "cat"(egory) of Programming.

Usage

Such "feeds" can be output as *.atom XML files (just add a |C|_hax_relpath_postatoms directive) but other than that no separate pages or other files will be auto-generated from them. To embed such micro-contents in the project's generated output pages in versatile ways (without coding up a custom X-renderer from scratch), use the "feed"-related iterators of the built-in hax.iterator X-renderer (those, incidentally, treat |P| "feeds" and Bloks as (for their purposes) functionally equivalent types of content sources, allowing for some neat mixing-and-mashing).

|C| directives: more control

All quite unnecessary at first, and only promising some relief for increasingly extensive projects on the verge of becoming unwieldy.

|C|process:ing of source directories

For processing source directories, 2 directives are parsed if present: |C|process:static: (raw files to be batch-copied unprocessed) and |C|process:pages: (dynamically processed files to be templated-and-generated). Examples:

|C|process:static:
    skip=["*_thumb.jpg"], force=[],
    dirs=["static1","static2","static3"]

|C|process:pages:
    skip=[], force=["*"], dirs=[]

Implicit factory defaults:

|C|process:static:
    skip=[], force=[],
    dirs=["static"]

|C|process:pages:
    skip=[], force=[],
    dirs=["pages"]

For any such |C|process: directive:

  • Stringent syntactic rules apply here.
  • dirs to specify the list of names (not patterns or paths) of all direct sub-directories (situated inside the project directory) to source contents from. If empty  [], defaults to pages for |C|process:pages: and to static for |C|process:static:.
  • skip to specify a list of "simpleton file name (not path) patterns" designating which files to always-skip during processing, regardless of current file modification timestamps. (A "simpleton" pattern either begins with, or ends with, or both, or is devoid of, or consists entirely of an  * and interprets no other wildcards or wildcard placements.)
  • force to specify a list of "simpleton file name (not path) patterns" designating which files to always force processing for, regardless of current file modification timestamps.
  • skip = ["*"] force-skips all except what's forced by force. If the skip = [ .. ] list contains a single "*" among other values, this is interpreted as simply skip = ["*"].
  • force = ["*"] force-processes all except what's excluded by skip. If the force = [ .. ] list contains a single "*" among other values, this is interpreted as simply force = ["*"].
  • If both skip = ["*"] and force = ["*"] end up as effectively present in the same directive, both cancel each other and the default combination skip=[], force=[] is thusly assumed for both.

|C|dtformat:

Defines a custom date-time format.

Example:

|C|dtformat:slang:
    Way back on %Y-%m-%d it was!

Format strings are parsed as documented here.

|C| .. (miscellaneous)

Choose by example what might be needed from:

|C|_hax_domainname: www.haxtatic.foo
|C|_hax_dir_build: généré
|C|_hax_dir_deploy: redistribuer
|C|_hax_dir_cache: 
|C|_hax_relpath_postatoms: xml/posts/
|C|_hax_relpath_sitemap: xml/sitemap.xml
|C|_hax_htmlequivexts: php,shtml,xhtml
|C|_hax_onparseerror: abort
|C|process:tags: T,P,C

Implicit factory defaults are:

|C|_hax_domainname: <name-of-project-directory>
|C|_hax_dir_build: build
|C|_hax_dir_deploy: 
|C|_hax_dir_cache: _cache_tmp
|C|_hax_relpath_postatoms: 
|C|_hax_relpath_sitemap: sitemap.xml
|C|_hax_htmlequivexts: 
|C|_hax_onparseerror: 
|C|process:tags: T,P,B,X

To elaborate:

  • _hax_domainname is used in sitemap.xml and all generated *.atom XML feed files
  • _hax_relpath_sitemap — site-root-relative file path to the output sitemap.xml, set to   (no value) to disable generating the sitemap.
  • _hax_relpath_postatoms — generation of *.atom XML files for |P| feeds can be enabled by setting this directive with a site-root-relative (aka build-output-directory-relative) directory path to store them in; by default, such files are not generated
  • _hax_htmlequivexts — file extensions other than the built-in always-on .html, .htm and   (no file extension) can be designated to also be processed via the applicable *.haxtmpl.html template
  • _hax_onparseerror — if manually set to abort, all processing will halt upon the first failure to parse some directive properties or X-tag parameters. By default, parse errors result in the process continuing but the error details being written out directly in-place into generated output files.
  • process:tags: — comma-separated list of haXtags to be processed. Removing those that will never be embedded anywhere in the project output may marginally speed up processing (perhaps only noticably-so with many 1000s of processable input files). Also allows enabling the disabled-by-default {C|misc_setting_name|} C-tag prefix, which simply outputs the current setting of any (except |C|process:.. & |C|dtformat:..) named configuration directive. Note: use of haXtags in this one directive is (other than plain puzzling) probably ill-advised
  • _hax_dir_deploy sets a secondary build-output directory (name, not path) where by default there is none.
  • Note: both the _hax_dir_build and _hax_dir_deploy directory names will each (at runtime) be combined (via  - dash) with the current setup name for the final actual build-output directory name: hence in new projects the implicit-default value for _hax_dir_build —that is, build— results in the actual build-output directory name default-build.