<feed xmlns='http://www.w3.org/2005/Atom'>
<title>tree-sitter-sisu, branch main</title>
<subtitle>SiSU Spine: tools</subtitle>
<link rel='alternate' type='text/html' href='https://www.amissah.com/projects/tree-sitter-sisu/'/>
<entry>
<title>grammar: accept original SiSU bespoke @key: header dialect</title>
<updated>2026-05-13T03:02:54+00:00</updated>
<author>
<name>Ralph Amissah</name>
<email>ralph.amissah@gmail.com</email>
</author>
<published>2026-05-13T03:02:54+00:00</published>
<link rel='alternate' type='text/html' href='https://www.amissah.com/projects/tree-sitter-sisu/commit/?id=d4f99d5be4a9329568911270bed0e64707c1ab7d'/>
<id>d4f99d5be4a9329568911270bed0e64707c1ab7d</id>
<content type='text'>
Until now the grammar handled only the sisudoc-spine YAML header form.
Real SiSU markup uses two textually disjoint header dialects with an
identical body grammar:

  bespoke (original SiSU, ruby):    yaml (sisudoc-spine):
    % SiSU 4.0.0                      # SiSU 8.0
    @title: Alice's Adventures        title: "Alice's Adventures"
    @creator:                         creator:
     :author: Carroll, Lewis            author: "Carroll, Lewis"

Add bespoke-dialect rules alongside the existing yaml ones; the body
grammar is shared between the two.

grammar.js:
- version_comment widened from /# SiSU(spine)? &lt;ver&gt;/ to
  /[#%] SiSU[^\n]*\n/. Real banners observed across both corpora
  include "# SiSU 8.0", "# SiSUspine 8.0", "# SiSU master 8.0",
  "# SiSU: http://...", "% SiSU 4.0.0", "% SiSU 0.72",
  "% SiSU http://...", "% SiSU markup for 0.16 and later".
- Added sisu_header_field / sisu_header_key / sisu_header_value /
  sisu_header_continuation.
- sisu_header_key whitelists the 14 @keys observed in the sisu
  corpus (including the @links:+ additive variant), parallel to
  the existing yaml header_key whitelist.
- sisu_header_continuation accepts any 1+ space indented line whose
  first non-space character is not a newline. Covers " :sub: val",
  " { text }url" freeform under @links:, and 3+ space wrap-line
  continuations (10690 occurrences across the sisu corpus, almost
  all inside @classify: :topic_register: entries).
- Wired sisu_header_field into _toplevel alongside header_field.

queries/highlights.scm:
- Added @keyword / @string captures for the new sisu_* nodes,
  parallel to the existing yaml header captures.

test/corpus/headers_sisu.txt:
- 12 new cases: % SiSU banner variants, @title: with inline value,
  @creator: + :author:, @date: with multiple sub-keys, @make:
  mixed sub-keys, @links: with freeform { text }url continuations,
  @links:+ additive, full bespoke header block, and a coexistence
  case confirming yaml + bespoke at the same top level.

README.md and sisu-markup_tree-sitter.md:
- Describe dual-dialect support; add sisu corpus results table.

Test results:
- tree-sitter test: 79 / 79 pass.
- sisu-markup-samples/data/samples/ (full sisu corpus): 44 / 65
  parse cleanly (was 0 / 65). current/ layout parses at 20 / 21
  (95 %); the dominant failure mode is the wrapped/ layout
  (7 / 21) which trips the pre-existing one-line-per-paragraph
  limitation, not the new header rules.
- sisudoc-spine-samples/markup/ (full spine corpus): 37 / 46
  unchanged. No regression in the yaml dialect.

Mixing the two dialects inside one document remains parseable but
non-idiomatic; enforcement is left to a future linter pass rather
than the grammar.

(assisted by Claude-Code)
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Until now the grammar handled only the sisudoc-spine YAML header form.
Real SiSU markup uses two textually disjoint header dialects with an
identical body grammar:

  bespoke (original SiSU, ruby):    yaml (sisudoc-spine):
    % SiSU 4.0.0                      # SiSU 8.0
    @title: Alice's Adventures        title: "Alice's Adventures"
    @creator:                         creator:
     :author: Carroll, Lewis            author: "Carroll, Lewis"

Add bespoke-dialect rules alongside the existing yaml ones; the body
grammar is shared between the two.

grammar.js:
- version_comment widened from /# SiSU(spine)? &lt;ver&gt;/ to
  /[#%] SiSU[^\n]*\n/. Real banners observed across both corpora
  include "# SiSU 8.0", "# SiSUspine 8.0", "# SiSU master 8.0",
  "# SiSU: http://...", "% SiSU 4.0.0", "% SiSU 0.72",
  "% SiSU http://...", "% SiSU markup for 0.16 and later".
- Added sisu_header_field / sisu_header_key / sisu_header_value /
  sisu_header_continuation.
- sisu_header_key whitelists the 14 @keys observed in the sisu
  corpus (including the @links:+ additive variant), parallel to
  the existing yaml header_key whitelist.
- sisu_header_continuation accepts any 1+ space indented line whose
  first non-space character is not a newline. Covers " :sub: val",
  " { text }url" freeform under @links:, and 3+ space wrap-line
  continuations (10690 occurrences across the sisu corpus, almost
  all inside @classify: :topic_register: entries).
- Wired sisu_header_field into _toplevel alongside header_field.

queries/highlights.scm:
- Added @keyword / @string captures for the new sisu_* nodes,
  parallel to the existing yaml header captures.

test/corpus/headers_sisu.txt:
- 12 new cases: % SiSU banner variants, @title: with inline value,
  @creator: + :author:, @date: with multiple sub-keys, @make:
  mixed sub-keys, @links: with freeform { text }url continuations,
  @links:+ additive, full bespoke header block, and a coexistence
  case confirming yaml + bespoke at the same top level.

README.md and sisu-markup_tree-sitter.md:
- Describe dual-dialect support; add sisu corpus results table.

Test results:
- tree-sitter test: 79 / 79 pass.
- sisu-markup-samples/data/samples/ (full sisu corpus): 44 / 65
  parse cleanly (was 0 / 65). current/ layout parses at 20 / 21
  (95 %); the dominant failure mode is the wrapped/ layout
  (7 / 21) which trips the pre-existing one-line-per-paragraph
  limitation, not the new header rules.
- sisudoc-spine-samples/markup/ (full spine corpus): 37 / 46
  unchanged. No regression in the yaml dialect.

Mixing the two dialects inside one document remains parseable but
non-idiomatic; enforcement is left to a future linter pass rather
than the grammar.

(assisted by Claude-Code)
</pre>
</div>
</content>
</entry>
<entry>
<title>docs: add README; adopt git.sisudoc.org/tools/ namespace</title>
<updated>2026-05-12T00:41:17+00:00</updated>
<author>
<name>Ralph Amissah</name>
<email>ralph.amissah@gmail.com</email>
</author>
<published>2026-05-12T00:41:17+00:00</published>
<link rel='alternate' type='text/html' href='https://www.amissah.com/projects/tree-sitter-sisu/commit/?id=ee472b17812a7f73186d7b7bd4f9ff2bc7145f4d'/>
<id>ee472b17812a7f73186d7b7bd4f9ff2bc7145f4d</id>
<content type='text'>
Add a top-level README.md describing what tree-sitter-sisu is, its
audience (editor / IDE tooling maintainers), its relationship to
sisudoc-spine, quickstart instructions for Neovim and Emacs 29+,
and a pointer to the existing sisu-markup_tree-sitter.md for
corpus results and grammar design notes.

Move the canonical repository URL from
https://git.sisudoc.org/software/tree-sitter-sisu to
https://git.sisudoc.org/tools/tree-sitter-sisu in both
package.json and tree-sitter.json. The new tools/ namespace
mirrors the local sisudoc-spine-tools/ directory containing this
and the other spine-companion artefacts (ssp-reader,
doc-abstraction-format), and continues the existing functional
namespace pattern on git.sisudoc.org alongside software/, markup/,
and projects/.

The README's cross-references to ssp-reader and
doc-abstraction-format use the same tools/ namespace.

(assisted by Claude-Code)
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Add a top-level README.md describing what tree-sitter-sisu is, its
audience (editor / IDE tooling maintainers), its relationship to
sisudoc-spine, quickstart instructions for Neovim and Emacs 29+,
and a pointer to the existing sisu-markup_tree-sitter.md for
corpus results and grammar design notes.

Move the canonical repository URL from
https://git.sisudoc.org/software/tree-sitter-sisu to
https://git.sisudoc.org/tools/tree-sitter-sisu in both
package.json and tree-sitter.json. The new tools/ namespace
mirrors the local sisudoc-spine-tools/ directory containing this
and the other spine-companion artefacts (ssp-reader,
doc-abstraction-format), and continues the existing functional
namespace pattern on git.sisudoc.org alongside software/, markup/,
and projects/.

The README's cross-references to ssp-reader and
doc-abstraction-format use the same tools/ namespace.

(assisted by Claude-Code)
</pre>
</div>
</content>
</entry>
<entry>
<title>docs: update README for v2 grammar changes</title>
<updated>2026-05-10T04:05:07+00:00</updated>
<author>
<name>Ralph Amissah</name>
<email>ralph.amissah@gmail.com</email>
</author>
<published>2026-05-10T04:05:07+00:00</published>
<link rel='alternate' type='text/html' href='https://www.amissah.com/projects/tree-sitter-sisu/commit/?id=53052a79504bc99e18856d1106faf3c8b324afec'/>
<id>53052a79504bc99e18856d1106faf3c8b324afec</id>
<content type='text'>
Reflect the current state of the grammar, queries, and corpus
results:

- v2 changes section listing the four grammar fixes (multi-line note
  bodies, digit-leading segment names, header_key keyset restriction,
  editor_note_marker promotion).
- Test results across the full pod-samples corpus (22 / 26 docs
  parse with zero errors). The remaining four are itemised: three
  source markup bugs the grammar now correctly surfaces (crossed
  inline nesting, missing footnote close `~`, bare editor note
  without channel marker) and one acknowledged grammar gap (bare
  collection-link form `{text}filename.sst`).
- Known limitations updated: removed the multi-line footnote entry,
  added the bare-collection-link gap and the bare-editor-note
  rejection rule.
- New query files (textobjects.scm, indents.scm) listed.

(assisted by Claude-Code)
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Reflect the current state of the grammar, queries, and corpus
results:

- v2 changes section listing the four grammar fixes (multi-line note
  bodies, digit-leading segment names, header_key keyset restriction,
  editor_note_marker promotion).
- Test results across the full pod-samples corpus (22 / 26 docs
  parse with zero errors). The remaining four are itemised: three
  source markup bugs the grammar now correctly surfaces (crossed
  inline nesting, missing footnote close `~`, bare editor note
  without channel marker) and one acknowledged grammar gap (bare
  collection-link form `{text}filename.sst`).
- Known limitations updated: removed the multi-line footnote entry,
  added the bare-collection-link gap and the bare-editor-note
  rejection rule.
- New query files (textobjects.scm, indents.scm) listed.

(assisted by Claude-Code)
</pre>
</div>
</content>
</entry>
<entry>
<title>queries: add textobjects.scm and indents.scm</title>
<updated>2026-05-10T04:04:45+00:00</updated>
<author>
<name>Ralph Amissah</name>
<email>ralph.amissah@gmail.com</email>
</author>
<published>2026-05-10T04:04:45+00:00</published>
<link rel='alternate' type='text/html' href='https://www.amissah.com/projects/tree-sitter-sisu/commit/?id=04bac0f37f652e59401e78a7533f29472bd034dd'/>
<id>04bac0f37f652e59401e78a7533f29472bd034dd</id>
<content type='text'>
textobjects.scm exposes the structure that hosts (Neovim's
nvim-treesitter-textobjects, Helix, Emacs treesit) can bind to keys
like af / if (footnote / inside footnote), ah / ih (heading section),
ab / ib (block body):

  @class.outer / @class.inner       headings (part and segment)
  @function.outer / @function.inner block elements (code, poem,
                                    block, group, table, quote,
                                    pipe-table)
  @comment.outer / @comment.inner   footnotes and editor notes
  @parameter.outer / @parameter.inner links and images
  @block.outer / @block.inner       paragraphs
  @assignment.outer                 inline-formatting runs and
                                    header fields
  @attribute.outer                  book-index entries

indents.scm anchors top-level structures at column 0 and marks block
elements / header continuations as @indent.align. SiSU markup is
largely flat-indented, so this file is mostly defensive: it stops
auto-indent on &lt;CR&gt; from drifting away from column 0 inside paragraph
text, and lets editors line up subsequent header continuation lines
with the previous one.

(assisted by Claude-Code)
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
textobjects.scm exposes the structure that hosts (Neovim's
nvim-treesitter-textobjects, Helix, Emacs treesit) can bind to keys
like af / if (footnote / inside footnote), ah / ih (heading section),
ab / ib (block body):

  @class.outer / @class.inner       headings (part and segment)
  @function.outer / @function.inner block elements (code, poem,
                                    block, group, table, quote,
                                    pipe-table)
  @comment.outer / @comment.inner   footnotes and editor notes
  @parameter.outer / @parameter.inner links and images
  @block.outer / @block.inner       paragraphs
  @assignment.outer                 inline-formatting runs and
                                    header fields
  @attribute.outer                  book-index entries

indents.scm anchors top-level structures at column 0 and marks block
elements / header continuations as @indent.align. SiSU markup is
largely flat-indented, so this file is mostly defensive: it stops
auto-indent on &lt;CR&gt; from drifting away from column 0 inside paragraph
text, and lets editors line up subsequent header continuation lines
with the previous one.

(assisted by Claude-Code)
</pre>
</div>
</content>
</entry>
<entry>
<title>grammar: promote editor-note channel marker to named node</title>
<updated>2026-05-10T04:04:25+00:00</updated>
<author>
<name>Ralph Amissah</name>
<email>ralph.amissah@gmail.com</email>
</author>
<published>2026-05-10T04:04:25+00:00</published>
<link rel='alternate' type='text/html' href='https://www.amissah.com/projects/tree-sitter-sisu/commit/?id=8e359296007fc7bf561355a8454b88db4457483b'/>
<id>8e359296007fc7bf561355a8454b88db4457483b</id>
<content type='text'>
Editor notes have two semantic channels in original SiSU markup:

  ~[* ... ]~   asterisk set, general annotations (e.g. on the author)
  ~[+ ... ]~   plus set, a separate channel (e.g. TODO / review)

These are not interchangeable - the channel is meaningful, and
themes should be free to colour them differently. Promote the
opener from an inline literal to a named child node
(editor_note_marker) on a `marker:` field, and give it the
@attribute capture in highlights.scm - distinct from the generic
@punctuation.special used for ~{ / }~ / ]~.

A bare `~[ ... ]~` without `*` or `+` is intentionally rejected:
authors must pick a channel. This surfaces the markup bug at
/Not Without Help/ line 695 (which uses the bare form) as a parse
error, consistent with the project rule that strict structural
parsing is preferred over silent regex permissiveness.

Test corpus updated to expect the new (editor_note_marker) child.

(assisted by Claude-Code)
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Editor notes have two semantic channels in original SiSU markup:

  ~[* ... ]~   asterisk set, general annotations (e.g. on the author)
  ~[+ ... ]~   plus set, a separate channel (e.g. TODO / review)

These are not interchangeable - the channel is meaningful, and
themes should be free to colour them differently. Promote the
opener from an inline literal to a named child node
(editor_note_marker) on a `marker:` field, and give it the
@attribute capture in highlights.scm - distinct from the generic
@punctuation.special used for ~{ / }~ / ]~.

A bare `~[ ... ]~` without `*` or `+` is intentionally rejected:
authors must pick a channel. This surfaces the markup bug at
/Not Without Help/ line 695 (which uses the bare form) as a parse
error, consistent with the project rule that strict structural
parsing is preferred over silent regex permissiveness.

Test corpus updated to expect the new (editor_note_marker) child.

(assisted by Claude-Code)
</pre>
</div>
</content>
</entry>
<entry>
<title>grammar: restrict header_key to recognised SiSU YAML keys</title>
<updated>2026-05-10T04:03:30+00:00</updated>
<author>
<name>Ralph Amissah</name>
<email>ralph.amissah@gmail.com</email>
</author>
<published>2026-05-10T04:03:30+00:00</published>
<link rel='alternate' type='text/html' href='https://www.amissah.com/projects/tree-sitter-sisu/commit/?id=e20b25f797a343c41c98bf4471698d77db2db43d'/>
<id>e20b25f797a343c41c98bf4471698d77db2db43d</id>
<content type='text'>
The previous header_key pattern /[a-z][a-z_]*:/ was permissive enough
to match URL prefixes such as `http:` or `https:` when a bare URL
appears on a line by itself, and to match sentence fragments like
`said:` mid-document. The first match would launch a fake
header_field which then forced the entire rest of the file into
ERROR recovery (visible on /Free Culture/ at line 5659:
`http://www.lessig.org/blog/...`).

Replace with an explicit choice over the recognised top-level keys:
title, creator, date, rights, classify, identifier, original, notes,
links, make, publisher, license. This set was derived from the
pod-samples corpus by collecting `^[a-z]+:` matches before the first
:A~ heading. Adding new keys is a one-line edit.

Sub-keys nested inside indented header continuations (e.g.
"  author: ...", "  copyright: ...") are unaffected - those are
captured by header_continuation, not header_key.

(assisted by Claude-Code)
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The previous header_key pattern /[a-z][a-z_]*:/ was permissive enough
to match URL prefixes such as `http:` or `https:` when a bare URL
appears on a line by itself, and to match sentence fragments like
`said:` mid-document. The first match would launch a fake
header_field which then forced the entire rest of the file into
ERROR recovery (visible on /Free Culture/ at line 5659:
`http://www.lessig.org/blog/...`).

Replace with an explicit choice over the recognised top-level keys:
title, creator, date, rights, classify, identifier, original, notes,
links, make, publisher, license. This set was derived from the
pod-samples corpus by collecting `^[a-z]+:` matches before the first
:A~ heading. Adding new keys is a one-line edit.

Sub-keys nested inside indented header continuations (e.g.
"  author: ...", "  copyright: ...") are unaffected - those are
captured by header_continuation, not header_key.

(assisted by Claude-Code)
</pre>
</div>
</content>
</entry>
<entry>
<title>grammar: allow digit-leading segment names</title>
<updated>2026-05-10T04:02:55+00:00</updated>
<author>
<name>Ralph Amissah</name>
<email>ralph.amissah@gmail.com</email>
</author>
<published>2026-05-10T04:02:55+00:00</published>
<link rel='alternate' type='text/html' href='https://www.amissah.com/projects/tree-sitter-sisu/commit/?id=daf5457585e55a7a76391b90d79c47d021163325'/>
<id>daf5457585e55a7a76391b90d79c47d021163325</id>
<content type='text'>
Segment ids such as `2~1` and `1~12` appear in real samples (most
visibly /Free Culture/'s `2~1 1. More Formalities`). The previous
segment_name regex required a leading [a-zA-Z_!]; relax to also
accept digits at the first position. The internal-hyphen and
no-trailing-hyphen constraints (the latter to avoid colliding with
the suppress marker) are unchanged.

(assisted by Claude-Code)
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Segment ids such as `2~1` and `1~12` appear in real samples (most
visibly /Free Culture/'s `2~1 1. More Formalities`). The previous
segment_name regex required a leading [a-zA-Z_!]; relax to also
accept digits at the first position. The internal-hyphen and
no-trailing-hyphen constraints (the latter to avoid colliding with
the suppress marker) are unchanged.

(assisted by Claude-Code)
</pre>
</div>
</content>
</entry>
<entry>
<title>grammar: allow multi-line footnote and editor-note bodies</title>
<updated>2026-05-10T04:01:59+00:00</updated>
<author>
<name>Ralph Amissah</name>
<email>ralph.amissah@gmail.com</email>
</author>
<published>2026-05-10T04:01:59+00:00</published>
<link rel='alternate' type='text/html' href='https://www.amissah.com/projects/tree-sitter-sisu/commit/?id=ab36311d7cfdffb9645cec2728f5d30fe1ec67f6'/>
<id>ab36311d7cfdffb9645cec2728f5d30fe1ec67f6</id>
<content type='text'>
Footnotes and editor notes whose body wraps across physical lines
previously failed to parse because the shared _inline rule excludes
newlines (paragraphs need that to terminate). Add a parallel
_note_inline rule with _note_text_word and _note_text_char fallbacks
that admit \n in text runs, and point footnote / editor_note at it.
The closing }~ / ]~ tokens still terminate the body because they
have higher precedence than the text fallbacks.

Verified against the test corpus (67/67 unit tests pass) and against
real samples: /Free Culture/ (5,690 lines) and /The Autonomous
Contract/, both of which previously errored on this case, now parse
past the multi-line note region.

Side benefit: /Free Culture/'s remaining failure was actually a URL
line being misread as a header_key - that is addressed in a follow-up
commit, not here.

(assisted by Claude-Code)
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Footnotes and editor notes whose body wraps across physical lines
previously failed to parse because the shared _inline rule excludes
newlines (paragraphs need that to terminate). Add a parallel
_note_inline rule with _note_text_word and _note_text_char fallbacks
that admit \n in text runs, and point footnote / editor_note at it.
The closing }~ / ]~ tokens still terminate the body because they
have higher precedence than the text fallbacks.

Verified against the test corpus (67/67 unit tests pass) and against
real samples: /Free Culture/ (5,690 lines) and /The Autonomous
Contract/, both of which previously errored on this case, now parse
past the multi-line note region.

Side benefit: /Free Culture/'s remaining failure was actually a URL
line being misread as a header_key - that is addressed in a follow-up
commit, not here.

(assisted by Claude-Code)
</pre>
</div>
</content>
</entry>
<entry>
<title>add tree-sitter grammar for SiSU Spine markup</title>
<updated>2026-05-09T19:44:59+00:00</updated>
<author>
<name>Ralph Amissah</name>
<email>ralph.amissah@gmail.com</email>
</author>
<published>2026-04-17T17:09:41+00:00</published>
<link rel='alternate' type='text/html' href='https://www.amissah.com/projects/tree-sitter-sisu/commit/?id=72cd5a8a94100054b27848e0ed62f8bb0962e488'/>
<id>72cd5a8a94100054b27848e0ed62f8bb0962e488</id>
<content type='text'>
Tree-sitter parser for .sst/.ssm/.ssi document markup files.
Parses headers, headings, block elements (code, poem, block,
group, table, quote - both curly and tic syntax), inline
formatting (10 types, recursive/nestable), footnotes, editor
notes, links, images, book index entries, and special markers.

Includes external scanner for raw block content, highlight
queries for syntax coloring, fold queries, 67 test cases,
and project configuration for tree-sitter CLI.

Tested against sample documents: error-free on Alice in
Wonderland (1877 lines), Wealth of Networks (5833 lines),
GPL v3 (297 lines). Known limitation: multi-line footnotes
that wrap across physical lines.

(assisted by Claude-Code)

Co-Authored-By: Claude Opus 4.6 (1M context)
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Tree-sitter parser for .sst/.ssm/.ssi document markup files.
Parses headers, headings, block elements (code, poem, block,
group, table, quote - both curly and tic syntax), inline
formatting (10 types, recursive/nestable), footnotes, editor
notes, links, images, book index entries, and special markers.

Includes external scanner for raw block content, highlight
queries for syntax coloring, fold queries, 67 test cases,
and project configuration for tree-sitter CLI.

Tested against sample documents: error-free on Alice in
Wonderland (1877 lines), Wealth of Networks (5833 lines),
GPL v3 (297 lines). Known limitation: multi-line footnotes
that wrap across physical lines.

(assisted by Claude-Code)

Co-Authored-By: Claude Opus 4.6 (1M context)
</pre>
</div>
</content>
</entry>
</feed>
