diff options
| author | Ralph Amissah <ralph.amissah@gmail.com> | 2026-05-15 17:25:47 -0400 |
|---|---|---|
| committer | Ralph Amissah <ralph.amissah@gmail.com> | 2026-05-15 19:40:46 -0400 |
| commit | d0cd8444fa69269803d9cda8af6277d2cdbecaee (patch) | |
| tree | 6e7d34e1e0774dcc684dd93459d1b4df94fe1083 /sundry/editor-syntax-etc/nvim/queries/sisu | |
| parent | ssp test-abstraction-ssp.sh script minor (diff) | |
editors syntax highlighting ...
- emacs syntax: add tree-sitter major mode for SiSU spine markup
New file sisu-spine-ts-mode.el is a sibling of the existing regex
mode, backed by Emacs 29+'s built-in treesit.el and the
tree-sitter-sisu grammar. It replaces the long font-lock keyword list
with treesit-font-lock-rules grouped into eight features (comment,
header, heading, block, inline, note, link, index, misc) so users
can dial verbosity via treesit-font-lock-level. It also wires up:
- treesit-simple-imenu-settings for a heading outline,
- treesit-thing-settings for sentence / paragraph motions,
- treesit-defun-type-regexp so C-M-a / C-M-e jump heading-to-heading,
- a sisu-spine-ts-install-grammar command that registers
treesit-language-source-alist and runs
treesit-install-language-grammar so users can install the parser
from inside Emacs without leaving the editor.
- the original sisu-spine-mode.el is unchanged and supported for
Emacs < 29 and for users who prefer regex highlighting.
- nvim drop-in: point parser fetch at tools/tree-sitter-sisu
sundry/editor-syntax-etc/nvim/
The nvim-treesitter install_info now fetches the parser from
https://git.sisudoc.org/projects/tree-sitter-sisu which can be cloned
via git://git.sisudoc.org/tools/tree-sitter-sisu The fetched paths:
files = { "src/parser.c", "src/scanner.c" }
submission of the sisu parser to nvim-treesitter's parsers.lua should
be a near-trivial one-liner.
- the original vim regex highlighter remains as before
- sundry/editor-syntax-etc/vim/syntax/sisu-spine.vim
- sundry/editor-syntax-etc/vim/templates/{sst,ssm,ssi}.tpl
new skeleton templates for the three SiSU markup file types
sets up the YAML header (title, creator, date, rights, classify,
identfier)
- .gitignore - whitelist the new files
(assisted by Claude-Code)
Diffstat (limited to 'sundry/editor-syntax-etc/nvim/queries/sisu')
5 files changed, 416 insertions, 0 deletions
diff --git a/sundry/editor-syntax-etc/nvim/queries/sisu/folds.scm b/sundry/editor-syntax-etc/nvim/queries/sisu/folds.scm new file mode 100644 index 0000000..69c44d2 --- /dev/null +++ b/sundry/editor-syntax-etc/nvim/queries/sisu/folds.scm @@ -0,0 +1,23 @@ +; Code folding queries for SiSU Spine markup + +; Block elements are foldable +(code_block_curly) @fold +(code_block_tic) @fold +(poem_block_curly) @fold +(poem_block_tic) @fold +(block_block_curly) @fold +(block_block_tic) @fold +(group_block_curly) @fold +(group_block_tic) @fold +(table_block_curly) @fold +(table_block_tic) @fold +(quote_block_tic) @fold + +; Multi-line book index entries are foldable +(book_index) @fold + +; Pipe tables are foldable +(pipe_table) @fold + +; Header fields with continuations are foldable +(header_field) @fold diff --git a/sundry/editor-syntax-etc/nvim/queries/sisu/highlights.scm b/sundry/editor-syntax-etc/nvim/queries/sisu/highlights.scm new file mode 100644 index 0000000..3454bd4 --- /dev/null +++ b/sundry/editor-syntax-etc/nvim/queries/sisu/highlights.scm @@ -0,0 +1,189 @@ +; Syntax highlighting queries for SiSU Spine markup +; Compatible with tree-sitter highlight capture names from +; https://tree-sitter.github.io/tree-sitter/syntax-highlighting + +; ================================================================= +; Comments +; ================================================================= +(version_comment) @comment.documentation +(header_comment) @comment +(body_comment) @comment + +; ================================================================= +; Header (document metadata) +; ================================================================= +(header_field + key: (header_key) @keyword) + +(header_field + value: (header_value) @string) + +(header_continuation) @string + +; ================================================================= +; Headings +; ================================================================= +(part_marker) @keyword.directive +(segment_marker) @keyword.directive + +(heading_part + content: (heading_content) @markup.heading) + +(heading_segment + content: (heading_content) @markup.heading) + +(segment_name) @label +(suppress_marker) @punctuation.special + +; Heading levels for more specific styling +(heading_part + marker: (part_marker) @markup.heading.1 + (#match? @markup.heading.1 "^:A~$")) + +(heading_part + marker: (part_marker) @markup.heading.2 + (#match? @markup.heading.2 "^:B~$")) + +(heading_part + marker: (part_marker) @markup.heading.3 + (#match? @markup.heading.3 "^:C~$")) + +(heading_part + marker: (part_marker) @markup.heading.4 + (#match? @markup.heading.4 "^:D~$")) + +(heading_segment + marker: (segment_marker) @markup.heading.5 + (#match? @markup.heading.5 "^1~$")) + +(heading_segment + marker: (segment_marker) @markup.heading.6 + (#match? @markup.heading.6 "^2~$")) + +; ================================================================= +; Inline formatting +; ================================================================= +(emphasis) @markup.italic +(bold) @markup.bold +(italic) @markup.italic +(underline) @markup.underline +(citation_mark) @markup.quote +(superscript) @markup.superscript +(subscript) @markup.subscript +(inserted) @markup.underline +(strikethrough) @markup.strikethrough +(monospace_inline) @markup.raw + +; Formatting delimiters +["*{" "}*"] @punctuation.special +["!{" "}!"] @punctuation.special +["/{" "}/"] @punctuation.special +["_{" "}_"] @punctuation.special +["\"{" "}\""] @punctuation.special +["^{" "}^"] @punctuation.special +[",{" "},"] @punctuation.special +["+{" "}+"] @punctuation.special +["-{" "}-"] @punctuation.special +["#{" "}#"] @punctuation.special + +; ================================================================= +; Footnotes and editor notes +; ================================================================= +(footnote) @markup.link +(footnote_marker) @punctuation.special +(editor_note) @markup.link + +["~{" "}~"] @punctuation.special +; Editor-note channel selector: ~[* (asterisk set) or ~[+ (plus set). +; A distinct capture lets themes colour the two channels separately +; from the generic footnote delimiters above. +(editor_note_marker) @attribute +["]~"] @punctuation.special + +; ================================================================= +; Links and images +; ================================================================= +(link + text: (link_text) @markup.link.label) + +(link + target: (url) @markup.link.url) + +(link + target: (anchor_ref) @markup.link.url) + +(link + target: (collection_path) @markup.link.url) + +(auto_footnote_marker) @punctuation.special + +(image + spec: (image_spec) @markup.link.label) + +(url) @markup.link.url + +(inline_anchor) @label +(anchor_name) @label + +; ================================================================= +; Block elements +; ================================================================= +(block_open) @keyword.directive +(block_close) @keyword.directive +(raw_content) @markup.raw + +; Code blocks get more specific highlighting +(code_block_curly + open: (block_open) @keyword.directive) +(code_block_curly + content: (raw_content) @markup.raw.block) +(code_block_curly + close: (block_close) @keyword.directive) + +(code_block_tic + open: (block_open) @keyword.directive) +(code_block_tic + content: (raw_content) @markup.raw.block) +(code_block_tic + close: (block_close) @keyword.directive) + +; ================================================================= +; Book index +; ================================================================= +(book_index) @markup.list +(index_content) @string + +; ================================================================= +; Paragraph prefixes +; ================================================================= +(paragraph_prefix) @punctuation.special + +; ================================================================= +; Special markers +; ================================================================= +(ocn_suppress) @comment +(ocn_suppress_open) @comment +(ocn_suppress_close) @comment + +(page_break) @punctuation.special +(horizontal_rule) @punctuation.special + +; ================================================================= +; Composite includes +; ================================================================= +(composite_include) @keyword.import +(include_path) @string.special.path + +; ================================================================= +; Pipe table +; ================================================================= +(table_spec) @keyword.directive +(table_row) @markup.raw + +; ================================================================= +; Text +; ================================================================= +(text) @spell + +; Line break +(line_break) @punctuation.special diff --git a/sundry/editor-syntax-etc/nvim/queries/sisu/indents.scm b/sundry/editor-syntax-etc/nvim/queries/sisu/indents.scm new file mode 100644 index 0000000..aa73af8 --- /dev/null +++ b/sundry/editor-syntax-etc/nvim/queries/sisu/indents.scm @@ -0,0 +1,48 @@ +; Indentation queries for SiSU Spine markup. +; +; SiSU markup is largely flat: paragraphs and headings live at column 0, +; block bodies preserve their author-supplied indentation verbatim, and +; nesting is by markers rather than by indent. So indents.scm is mostly a +; no-op - the goal is to ensure that auto-indent on <CR> stays at column 0 +; for normal lines and respects existing indentation inside header +; continuations and blocks. + +; Tree-sitter indent semantics (per nvim-treesitter and treesit): +; @indent.begin - increases indent for the following line +; @indent.end - matches the @indent.begin and decreases indent +; @indent.zero - resets indent to column 0 +; @indent.align - aligns following lines with this node +; @indent.branch - same level as the parent (for else/elif-style joins) + +; Top-level structures live at column 0 - reset to zero on the next line. +(heading_part) @indent.zero +(heading_segment) @indent.zero +(paragraph) @indent.zero +(book_index) @indent.zero +(composite_include) @indent.zero +(page_break) @indent.zero +(horizontal_rule) @indent.zero +(ocn_suppress_open) @indent.zero +(ocn_suppress_close) @indent.zero +(body_comment) @indent.zero + +; Block elements: opening line increases indent for the body, closing +; line returns to zero. Editors that respect this will visually indent +; raw content one step from the delimiter line, which is conventional. +(code_block_curly) @indent.align +(code_block_tic) @indent.align +(poem_block_curly) @indent.align +(poem_block_tic) @indent.align +(block_block_curly) @indent.align +(block_block_tic) @indent.align +(group_block_curly) @indent.align +(group_block_tic) @indent.align +(table_block_curly) @indent.align +(table_block_tic) @indent.align +(quote_block_tic) @indent.align + +; Header continuation lines are indented by two spaces from column 0; +; mark continuations as align so a host that chooses to auto-indent the +; next continuation line matches the previous one. +(header_field) @indent.align +(header_continuation) @indent.align diff --git a/sundry/editor-syntax-etc/nvim/queries/sisu/injections.scm b/sundry/editor-syntax-etc/nvim/queries/sisu/injections.scm new file mode 100644 index 0000000..27f622b --- /dev/null +++ b/sundry/editor-syntax-etc/nvim/queries/sisu/injections.scm @@ -0,0 +1,16 @@ +; Language injection queries for SiSU Spine markup +; +; Code blocks could potentially inject language-specific highlighting, +; but SiSU code blocks don't specify language. These queries are +; provided as a starting point for future extension. + +; Code block content could be injected with a specific language +; if the block type or context provides a hint. +; For now, raw content in code blocks is left unhighlighted. + +; Example: if code blocks specified a language, e.g. code(d){ +; ((code_block_curly +; open: (block_open) @_open +; content: (raw_content) @injection.content) +; (#match? @_open "code\\(d\\)") +; (#set! injection.language "d")) diff --git a/sundry/editor-syntax-etc/nvim/queries/sisu/textobjects.scm b/sundry/editor-syntax-etc/nvim/queries/sisu/textobjects.scm new file mode 100644 index 0000000..0a82481 --- /dev/null +++ b/sundry/editor-syntax-etc/nvim/queries/sisu/textobjects.scm @@ -0,0 +1,140 @@ +; Text-object queries for SiSU Spine markup. +; +; Capture conventions follow nvim-treesitter/textobjects: +; @<thing>.outer -> select including delimiters / surrounding whitespace +; @<thing>.inner -> select content only +; +; Hosts that consume these (Neovim's nvim-treesitter-textobjects, Helix, +; Emacs treesit) bind keys such as `af` / `if` to .outer / .inner. + +; ================================================================= +; Headings (sectioning units) +; ================================================================= +; A whole heading line is a "section header" object. Heading sections +; (the heading plus its body content up to the next heading of equal or +; higher level) are not directly expressible in tree-sitter without +; additional grammar work; hosts can synthesise that from these captures. + +(heading_part) @class.outer +(heading_part + content: (heading_content) @class.inner) + +(heading_segment) @class.outer +(heading_segment + content: (heading_content) @class.inner) + +; ================================================================= +; Block elements (code / poem / block / group / table / quote) +; ================================================================= +; Whole block including delimiters; raw_content is the inner. + +(code_block_curly) @function.outer +(code_block_curly + content: (raw_content) @function.inner) + +(code_block_tic) @function.outer +(code_block_tic + content: (raw_content) @function.inner) + +(poem_block_curly) @function.outer +(poem_block_curly + content: (raw_content) @function.inner) + +(poem_block_tic) @function.outer +(poem_block_tic + content: (raw_content) @function.inner) + +(block_block_curly) @function.outer +(block_block_curly + content: (raw_content) @function.inner) + +(block_block_tic) @function.outer +(block_block_tic + content: (raw_content) @function.inner) + +(group_block_curly) @function.outer +(group_block_curly + content: (raw_content) @function.inner) + +(group_block_tic) @function.outer +(group_block_tic + content: (raw_content) @function.inner) + +(table_block_curly) @function.outer +(table_block_curly + content: (raw_content) @function.inner) + +(table_block_tic) @function.outer +(table_block_tic + content: (raw_content) @function.inner) + +(quote_block_tic) @function.outer +(quote_block_tic + content: (raw_content) @function.inner) + +(pipe_table) @function.outer + +; ================================================================= +; Footnotes and editor notes +; ================================================================= +; Both share the same outer/inner shape; the inner skips the markers and +; closing delimiters. + +(footnote) @comment.outer +(footnote + (_)+ @comment.inner) + +(editor_note) @comment.outer +(editor_note + (_)+ @comment.inner) + +; ================================================================= +; Links and images +; ================================================================= + +(link) @parameter.outer +(link + text: (link_text) @parameter.inner) + +(image) @parameter.outer +(image + spec: (image_spec) @parameter.inner) + +; ================================================================= +; Paragraph / inline-formatting runs +; ================================================================= + +(paragraph) @block.outer +(paragraph + (_)+ @block.inner) + +; Inline formatting pairs - useful as fine-grained text objects. +; The same delimiter character pattern (e.g. `*{` / `}*`) opens and +; closes each, so .inner is everything between them. + +(emphasis) @assignment.outer +(bold) @assignment.outer +(italic) @assignment.outer +(underline) @assignment.outer +(citation_mark) @assignment.outer +(superscript) @assignment.outer +(subscript) @assignment.outer +(inserted) @assignment.outer +(strikethrough) @assignment.outer +(monospace_inline) @assignment.outer + +; ================================================================= +; Book index entries +; ================================================================= + +(book_index) @attribute.outer +(book_index + (index_content) @attribute.inner) + +; ================================================================= +; Header fields +; ================================================================= + +(header_field) @assignment.outer +(header_field + value: (header_value) @assignment.inner) |
