Syntax highlighting for HTML and select storyformats (see Features) on top of Twee 3 code.
Made possible through contributions from:
And feedback from the folks over at the Twine Games Discord Server.
The extension relies on a workspace (or a folder) being open. If single files are to be edited, the storyformat must be configured manually.
Supported file extensions:
.tw.twee
To set the correct storyformat for the files, a StoryData passage with the storyformat (and version) (see example below) mentioned in it is preferred. If not, the extension provides the option to set the format explictly. (See Extension Settings.)
:: StoryData
{
"ifid": "<ifid here>",
"format": "<story format here, i.e. 'SugarCube'>",
"format-version": "<story format version here, i.e. '2.34.1'>"
}-
Syntax highlighting.
-
Command palette tool to generate IFID: open the command palette (Ctrl/Cmd + Shift + P or F1 by default) and search for "IFID".
-
A list of passages for quick jumps (can be grouped by files, folders, or passage tags. See extension-settings.) Open from the Twee 3 Language Tools tab on the activity bar (the forking paths logo.)
-
A story-map view (Contributed by @Goctionni) that opens in the browser! Still in very early stages. Also accessible from the Twee 3 Language Tools tab on the activity bar.
-
Currently implemented features:
- Snap to grid (button on top-left.)
- Arrows to linked passages.
- Passage position, size, and tags can be edited via a sidebar. Changes are not currently autosaved, and a manual save button is present.
- Multi-select, and thereby mass editing of position, size, and tags.
- Ability to move passages across files.
-
Usage:
- Use the middle-mouse button, or hold down Shift while dragging the mouse to pan the map grid.
- Scroll the mousewheel or stretch/pinch on trackpad to zoom in/out.
- Hold Ctrl/Cmd while selecting to add new passages to selection, or remove already added passages from it.
-
(id: sugarcube-2)
- Syntax highlighting:

- Macro documentation on hover. (Contributed by @MinusGix) (Custom definitions can be added via
*.twee-config.yml. See: Custom macro definitions for SC): - Container macro pair highlights:
- Snippets. (Contributed by @rambdev) Type macro names to get code snippet inserts with placeholder values:
- Diagnostics:
- Macros with opening tags but no closes (and vice-versa):
- Deprecated macros:
- Deprecated
<<end...>>closing macros: - Unrecognized macros. New/custom macros can be defined manually (see: Custom macro definitions for SC), but anything else will throw a warning. This can be turned off by the
twee3LanguageTools.sugarcube-2.undefinedMacroWarningssetting (see settings):- Screenshot - diagnostic
- Screenshot - quick fix (Writes definitions to
t3lt.twee-config.ymlin the root of the first workspace folder.)
- Invalid argument syntax in macros (Contributed by @MinusGix):
- Argument validation (Contributed by @MinusGix): Read here for more information.
(id: chapbook-1)
(id: harlowe-3)
The extension adds diagnostics for erroneous usage of macros in TwineScript for the sugarcube-2 storyformat. By default, only the definitions for the core SugarCube library are present, but custom definitions can be added. The process is as follows:
- Add a
*.twee-config.yaml(or.yml) OR*.twee-config.json(*represents any valid file name) file to your project folder (or anywhere in the workspace.) - Define custom macros as follows:
- If using
*.twee-config.yaml(indentation is important for YAML files):sugarcube-2: macros: customMacroName: container: true anotherOne: {}
- If using
*.twee-config.json:{ "sugarcube-2": { "macros": { "customMacroName": { "container": true }, "anotherOne": {} } } }
- If using
The following properties are currently programmed, even though not all of them are used as of now:
- name
(string)optional: Name of the macro (currently unused in code; the name of the object suffices for now.) - description
(string)optional: Description of macro. Shown on hover. Supports markdown. - container
(boolean)optional: If the macro is a container (i.e. requires a closing tag) or not.falseby default. - selfClose
(boolean)optional: If the macro is a self-closable. Requires macro to be a container first.falseby default. - children
(string array)optional: If the macro has children, specify their names as an array (currently unused in code.) - parents
(string array)optional: If the macro is a child macro, specify the names of its parents as an array (currently unused in code.) - deprecated
(boolean)optional: If the macro is deprecated or not.falseby default. - deprecatedSuggestions
(string array)optional: If the macro is deprecated, specify any alternatives to the macro as an array. - parameters
(object)optional: Allows for macro argument validation. Read here for more information.
NOTE: Multiple twee-config files can be present in a workspace. They will stack and add to the macro definitions for the workspace. The recommended strategy is to make separate files for separate macro sets/libraries, e.g. (the following file can also be used as an example):
click-to-proceed.twee-config.yaml(Link)
This extension contributes the following settings:
Automatically set by the StoryData special passage (if it exists):
twee3LanguageTools.storyformat.current: Identifier of the storyformat in use.
Manual settings:
NOTE: It's recommended to change these settings separately for each workspace instead of globally.
twee3LanguageTools.storyformat.override: Identifier of the storyformat to override the format set byStoryData.
⠀twee3LanguageTools.directories.include: Directories in which to look for twee files. Use glob patterns relative to the root of the workspace folders (e.g.src/unprocessed/twee,src/static,external). (Searches the entire workspace by default.)twee3LanguageTools.directories.exclude: Directories to exclude from the search of twee files. Use absolute glob patterns (e.g.**/src/processed/**). (Excludes**/node_modules/**by default.) If passage listing is active, excluded files will not be scanned for passages. They also will not be scanned for errors until manually opened.
⠀twee3LanguageTools.storyMap.unusedPortClosingDelay: Duration in milliseconds before the story-map server port is closed after the UI in the browser window has been closed. (5000by default.) ⠀twee3LanguageTools.passage.list: Display list of passages with quick 'jump' links? (falseby default.)twee3LanguageTools.passage.group: Group passages by? (Noneby default. Can be grouped by file of origin, folder of origin, or passage tags.)
⠀twee3LanguageTools.twee-3.warning.spaceAfterStartToken: Warn about missing space after the start token (::) in passage headers? (trueby default.)twee3LanguageTools.twee-3.error.storyData.format: Throw an error when missing the story format field (format) inStoryDataspecial passage? (trueby default.)twee3LanguageTools.twee-3.error.storyData.formatVersion: Throw an error when missing the story format version field (format-version) inStoryDataspecial passage? (trueby default.)
⠀twee3LanguageTools.sugarcube-2.warning.undefinedMacro: Warn about macros/widgets which were not found in definitions (*.twee-config.yamlor*.twee-config.jsonfiles) or the core SugarCube macro library? (trueby default.)twee3LanguageTools.sugarcube-2.warning.deprecatedMacro: Warn about deprecated macros/widgets? (trueby default.)twee3LanguageTools.sugarcube-2.warning.endMacro: Warn about the deprecated<<end...>>closing tag syntax? (trueby default.)twee3LanguageTools.sugarcube-2.warning.barewordLinkPassageChecking: Provides warnings for links like[[passage]]whenpassageis not a valid passage name. This could cause false positives in cases where you are using a global variable. (trueby default.)
⠀twee3LanguageTools.sugarcube-2.error.argumentParsing: Provide errors about invalid argument syntax being passed into macros? (trueby default.)twee3LanguageTools.sugarcube-2.error.parameterValidation: Provide errors about invalid argument types being passed into macros? (trueby default.)
⠀twee3LanguageTools.sugarcube-2.features.macroTagMatching: Highlight opening and closing tags of container macros? (trueby default.)
⠀twee3LanguageTools.experimental.sugarcube-2.selfClosingMacros.enable: Enable self-closing syntax for container macros? Read here for more information. (falseby default.)twee3LanguageTools.experimental.sugarcube-2.selfClosingMacros.warning.irrationalSelfClose: Warn about self-closed instances of content focused macros (e.g.<<script />>)? (trueby default.)
Uses a simple packing algorithm to space out passages into clusters based on the file they originate from.
To use, search for Pack passages to clusters from the command palette (Ctrl/Cmd + Shift + P or F1 by default).
NOTE: SugarCube 2 does NOT have a self-closing syntax for container macros, this feature is just to support custom passage processing functions.
Example of such a function which replaces self-closed instances with the actual closing macro tag (i.e. <<macro />> with <<macro>><</macro>>):
Config.passages.onProcess = function(p) {
const macroNamePattern = `[A-Za-z][\\w-]*|[=-]`;
const selfCloseMacroRegex = new RegExp(`<<(${macroNamePattern})((?:\\s*)(?:(?:/\\*[^*]*\\*+(?:[^/*][^*]*\\*+)*/)|(?://.*\\n)|(?:\`(?:\\\\.|[^\`\\\\])*\`)|(?:"(?:\\\\.|[^"\\\\])*")|(?:'(?:\\\\.|[^'\\\\])*')|(?:\\[(?:[<>]?[Ii][Mm][Gg])?\\[[^\\r\\n]*?\\]\\]+)|[^>]|(?:>(?!>)))*?)\\/>>`, 'gm');
return p.text.replace(selfCloseMacroRegex, "<<$1$2>><</$1>>");
};The twee3LanguageTools.experimental.sugarcube-2.selfClosingMacros.enable setting enables detection of self-closed macros.
Argument validation is still a work in progress. Passage name validation, especially. Shouldn't hinder workflow, however.
Changelog here.



