feat(syntax): a bare ::: figure opener is a composite figure - #29
Merged
Merged
Conversation
PART 9 S4c (markup-carve/carve#1215) reserves the kind word `figure` among the `:::` types: a BARE opener - the fence, its separator, the word, and NOTHING else - is ONE figure of ordered panels. An opener carrying a quoted title or a `[label]` is not that production at all and stays the generic Tier-2 container, with both preserved. Before this the two scoped identically, so a reader of the editor could not tell which of the two readings a line had - and the whole distinction lives in the tail of one line. A `figure-groups` context sits ahead of `divs` in `body`, because the `divs` pattern matches every `:::` line. It claims the bare opener only, and names it with this syntax's own vocabulary rather than carve-grammars': `markup.other.figure-group.carve` on the line, `punctuation.definition.figure-group.carve` on the fence and `entity.name.type.figure-group.carve` on the kind word, beside the `entity.name.type.div.carve` the generic context already uses. THE SEPARATOR IS A SPACE RUN, NEVER A TAB (grammar.ebnf PART 7, MARKER SEPARATORS; corpus 254): `:::<TAB>note` renders as a paragraph. So the new pattern is spelled ` +` rather than the `\s*` `divs` uses beside it. Claiming the tab form would be a stronger claim than the generic context makes, since that one merely over-colours a line this syntax has always over-coloured; a tab-separated opener falls to it and reads exactly as it did. THE GROUP CAPTION NEEDED NO RULE, verified rather than assumed: `divs` pops at end of line, so no `:::` container is ever open across lines here, and the `^ ` line below the closing fence is reached by `captions` at document level like any other. The assertions pin that position so a later narrowing of `captions` cannot take it away silently. RESIDUAL, written into the context's comment rather than left to be rediscovered: groups do not nest, so a bare `::: figure` at any depth inside an open group is a generic container - but with no multi-line `:::` region this syntax has no notion of being inside one, and over-colours the inner opener as a group. carve-grammars carries the rule through a begin/end pair plus a second container variant; giving `divs` a region is what it would take here too, and is out of scope for this change. Tests: `syntax_test_carve.crv` gains 22 assertions over seven opener spellings and the two caption positions - the bare opener, the titled one, the labelled one, both together, the tab-separated one, a longer fence, and `::: figures`, which is a different word. Each generic-container case carries a negative against the new scope as well as a positive for the old one, so the pair fails in both directions. Verified: with the `figure-groups` include removed the bare opener and the longer fence fail against the new scope, and with the pattern widened to accept a trailing title and label the titled, labelled and both-together lines fail their negatives - so those controls are reached by the rule and pass because it rejects them, not because it never sees them. No upgrade message: `messages/` is written at release time in this repo, and the last released version is 0.1.2. README's feature list gains the opener. Ports markup-carve/carve-grammars#223. Tracking: markup-carve/carve-grammars#222.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Carries PART 9 §4c (markup-carve/carve#1215) into
Carve.sublime-syntax. Ports markup-carve/carve-grammars#223; tracked by markup-carve/carve-grammars#222, which stays open.The distinction
The kind word
figureis reserved among the:::types. A bare opener - the fence, its separator, the word, and nothing else - is one figure of ordered panels:The same opener carrying a quoted title or a
[label]is not that production at all. It stays the generic Tier-2 container it has always been, with both preserved:Before this the two scoped identically, so the editor could not show which reading a line had - and the whole distinction sits in the tail of one line.
What changed
A
figure-groupscontext sits ahead ofdivsinbody, because thedivspattern matches every:::line. It claims the bare opener only, and names it with this syntax's own vocabulary rather than carve-grammars':markup.other.figure-group.carveon the line,punctuation.definition.figure-group.carveon the fence, andentity.name.type.figure-group.carveon the kind word, beside theentity.name.type.div.carvethe generic context already uses.The separator is a space run, never a tab (grammar.ebnf PART 7, MARKER SEPARATORS; corpus 254):
:::<TAB>noterenders as a paragraph. So the pattern is spelled+rather than the\s*divsuses beside it. Claiming the tab form would be a stronger claim than the generic context makes, since that one merely over-colours a line this syntax has always over-coloured. A tab-separated opener falls to it and reads exactly as it did.The group caption needed no rule, verified rather than assumed:
divspops at end of line, so no:::container is ever open across lines here, and the^line below the closing fence is reached bycaptionsat document level like any other. The new assertions pin that position so a later narrowing ofcaptionscannot take it away silently.README's feature list gains the opener. No
messages/entry: upgrade messages are written at release time in this repo (the last one is its own commit, "Add the 0.1.2 upgrade message"), and no feature or fix PR since has added one.Residual, deliberately
Groups do not nest, so a bare
::: figureat any depth inside an open group is a generic container. Butdivspops on$, so no:::region is ever open across lines here and this syntax has no notion of being inside one - the inner opener over-colours as a group. carve-grammars carries that rule through a begin/end pair plus a second container variant; givingdivsa multi-line region is what it would take here as well, and is out of scope. It is written into the context's comment rather than left to be rediscovered.Proof
syntax_test_carve.crvgains 22 assertions over seven opener spellings and the two caption positions: the bare opener, the titled one, the labelled one, both together, the tab-separated one, a longer fence, and::: figures, which is a different word. Each generic-container case carries a negative against the new scope alongside the positive for the old one.Measured both directions with the headless Sublime runner (build 4200) over the whole file, with the bundled default packages installed so the fenced-code embeds resolve:
include: figure-groupsline removed, 5 assertions fail: the four on::: figureand the one on:::: figure. Nothing else moves.::: figure "Titled",::: figure [g]and::: figure "Titled" [g], positives and negatives alike. So those control cases are reached by the rule and pass because it rejects them, not because it never sees them.The second half matters here specifically: removing the rule leaves the negatives passing trivially, so the revert alone would not have told us the controls were live.
Gates
gate-runreportsoutcome: "no-gates"for this repo, which is not green - it found no gate it knows how to run, since the checks here are Python scripts plus a Sublime binary rather than a package-manager test script. Every check CI runs was run locally instead, against the committed state:syntax_tests(headless build 4200, default packages installed): exit 0, 0 errorstools/lint-syntax-tests.py: exit 0, 231 assertions, none deadtools/generate-battery-tests.py --check: exit 0, generated block in syncCarve.sublime-syntaxparses as YAML