Configuration Files
General Information
Section titled “General Information”ENiGMA½ configuration files such as the system config, menus and themes are formatted in the HJSON format.
Hot-Reload
Section titled “Hot-Reload”Nearly all of ENiGMA½’s configuration can be hot-reloaded. That is, a live system can have it’s configuration modified and it will be loaded in place.
Common Directives
Section titled “Common Directives”Includes
Section titled “Includes”Most configuration files offer an includes directive that allows users to break up large configuration files into smaller and organized parts. For example, consider a system with many menus/screens. Instead of a single menu.hjson, the SysOp may break this into message-base.hjson, file-base.hjson, etc.
The includes directive may be used the top-level scope of a configuration file:
{ includes: [ message-base.hjson file-base.hjson ]
menus: { someOtherMenu: { // ... } }}{ menus: { someMessageMenu: { // ... } }}References
Section titled “References”Often times in a configuration you will find that you’re repeating yourself quite a bit. ENiGMA½ provides an @reference that can help with this in the form of @reference:dot.path.to.section.
Consider actionKeys in a menu. Often times you may show a screen and the user presses Q or ESC to fall back to the previous. Instead of repeating this in many menus, a generic block can be referenced:
{ // note that 'recycle' here is arbitrary; // only 'menus' and 'prompts' is reserved at this level. recycle: { prevMenu: [ { keys: [ "escape" ] action: @systemMethod:prevMenu } ] }
menus: { someMenu: { form: { 0: { actionKeys: @reference:recycle.prevMenu } } } }}A reference replaces the value, it does not merge into it
Section titled “A reference replaces the value, it does not merge into it”@reference substitutes whatever it names in place of the whole value. That is
what you want when a menu’s actionKeys are nothing but the shared block, as
above. It is not what you want when the menu has keys of its own: writing
// wrong -- the menu's own key is all that survivesactionKeys: @reference:recycle.prevMenuand then adding a key to it is impossible, because there is nowhere to add it to. Referencing the block and listing an extra key are the same slot.
The way around this is to publish the entry as well as the array, so a menu can list the shared binding as one element among its own:
{ recycle: { // the binding on its own prevMenuEntry: { keys: [ "escape" ] action: @systemMethod:prevMenu }
// and wrapped, for menus that want nothing else prevMenu: [ @reference:recycle.prevMenuEntry ] }
menus: { someMenu: { form: { 0: { actionKeys: [ @reference:recycle.prevMenuEntry { keys: [ "p", "shift + p" ] action: @method:postNewMessage } ] } } } }}A reference standing as an array element resolves like any other value, so both shapes work and the two menus stay in step with one binding.
The menu templates ENiGMA½ ships follow this convention in their common
section: common.quitToPrev is the array, common.quitToPrevEntry is the entry.
Reach for the array when the shared binding is all the menu needs, and the entry
when it has keys of its own.
Environment Variables
Section titled “Environment Variables”Especially in a container environment such as Docker, environment variable access in configuration files can become very handy. ENiGMA½ provides a flexible way to access variables using the @environment directive. The most basic form of @environment:VAR_NAME produces a string value. Additionally a :type suffix can be supplied to coerece the value to a particular type. Variables pointing to a comma separated list can be turned to arrays using an additional :array suffix.
Below is a table of the various forms:
| Form | Variable Value | Produces |
|---|---|---|
@environment:SOME_VAR | “Foo” | "Foo" (without quotes) |
@environment:SOME_VAR | “123” | "123" (without quotes) |
@environment:SOME_VAR:string | “Bar” | "Bar" (without quotes) |
@environment:SOME_VAR:string:array | “Foo,Bar” | [ 'Foo', 'Bar' ] |
@environment:SOME_VAR:boolean | “1” | true |
@environment:SOME_VAR:boolean | “True” | true |
@environment:SOME_VAR:boolean | “false” | false |
@environment:SOME_VAR:boolean | “cat” | false |
@environment:SOME_VAR:boolean:array | “True,false,TRUE” | [ true, false, true ] |
@environment:SOME_VAR:number | “123” | 123 |
@environment:SOME_VAR:number:array | “123,456” | [ 123, 456 ] |
@environment:SOME_VAR:number | “kitten” | (invalid) |
@environment:SOME_VAR:object | ’{“a”:“b”}’ | { 'a' : 'b' } |
@environment:SOME_VAR:object:array | ’{“a”:“b”},{“c”:“d”}’ | [ { 'a' : 'b' }, { 'c' : 'd' } ] |
@environment:SOME_VAR:timestamp | “2020-01-05” | A moment object representing 2020-01-05 |
@environment:SOME_VAR:timestamp:array | “2020-01-05,2016-05-16T01:15:37’” | An array of moment objects representing 2020-01-05 and 2016-05-16T01:15:37 |
Consider the following fragment:
{ foo: { bar: @environment:BAR_VAR:number }}If the environment has BAR_VAR=1337, this would produce:
{ foo: { bar: 1337 }}Secret Files
Section titled “Secret Files”For secrets that should not be stored in config.hjson (passwords, API keys, tokens, etc.), ENiGMA½ supports the @file directive to read a value from a file at startup. This is particularly useful in container environments where secrets are injected as files (e.g. Docker/Podman secrets under /run/secrets/).
The path may be absolute or relative to the directory containing config.hjson.
loginServers: { ssh: { // absolute path (e.g. a Docker/Podman secret) privateKeyPass: "@file:/run/secrets/ssh_key_pass" }}
email: { transport: { auth: { user: bbs@example.com // relative path — resolved from the config directory pass: "@file:secrets/smtp_pass" } }}The file contents are trimmed of leading/trailing whitespace (including the trailing newline that most editors and secrets managers append).