Commit: runtime(marko): improve syntax highlighting
Christian Brabandt <[email protected]> Thu, 30 Jul 2026 20:45:06 +0200
| Newsgroups | gmane.editors.vim.devel |
|---|---|
| Message-ID | <[email protected]> |
runtime(marko): improve syntax highlighting Commit: https://github.com/vim/vim/commit/99921ffc39591f7163d015dec43b29ae30a4462b Author: Brian Carbone <[email protected]> Date: Thu Jul 30 18:32:16 2026 +0000 runtime(marko): improve syntax highlighting closes: https://github.com/vim/vim/issues/20874 Signed-off-by: Brian Carbone <[email protected]> Signed-off-by: Christian Brabandt <[email protected]> diff --git a/runtime/syntax/marko.vim b/runtime/syntax/marko.vim index be589534c..96d24970a 100644 --- a/runtime/syntax/marko.vim +++ b/runtime/syntax/marko.vim @@ -1,21 +1,18 @@ " Vim syntax file " Language: Marko -" Maintainer: Brian Carbone <[email protected]> +" Maintainer: Brian Carbone <[email protected]> " URL: https://markojs.com " Filenames: *.marko -" Last Change: 2026 Jul 28 +" Last Change: 2026 Jul 29 -" Marko interleaves HTML-like tags, TypeScript expressions and CSS style -" blocks, in two modes: an HTML-like mode and an indentation-based concise -" mode. Mode is tracked structurally: the body of an html-mode element is -" an html-mode region (bare text stays plain there), while everywhere else -" is concise context, where a line-start name is a tag: +" Marko interleaves HTML-like tags, TypeScript expressions and CSS in two +" modes. Mode is tracked structurally: element bodies and "--" text blocks +" are html mode (bare text stays plain), everywhere else is concise, where +" a line-start name is a tag: " <p>if you want, stop by</p> body text, plain " my-tag size="large" concise tag, highlighted -" -" Same-position priority goes to the item defined last, so definition order -" is deliberate throughout; the load-bearing orderings are called out in -" the comments below. +" Same-position priority goes to the item defined last; definition order +" is deliberate throughout. if !exists("main_syntax") if exists("b:current_syntax") @@ -27,11 +24,11 @@ endif let s:cpo_save = &cpo set cpo&vim +" Top level is mostly markup; regions holding prose opt into @Spell. syn spell toplevel -" TypeScript for expressions and statement tags, CSS for style blocks. -" Both includes mutate shared state ("syn case", "syn iskeyword", sync -" rules, 'iskeyword'), all of it restored or restated afterwards. +" Both includes mutate shared state ("syn case", "syn iskeyword", sync, +" 'iskeyword'), restored or restated afterwards. let s:iskeyword_save = &l:iskeyword syn include @markoTS syntax/typescript.vim unlet! b:current_syntax @@ -41,107 +38,190 @@ let &l:iskeyword = s:iskeyword_save unlet s:iskeyword_save syn case match -" typescript.vim (yats) attaches type arguments via nextgroup after every -" identifier, so an unspaced "<" in any expression opens a region hunting a -" ">" that may never come: +" A "\%#=1" prefix pins a pattern to the backtracking regexp engine: the +" default NFA engine is much slower on this file's characteristic shapes +" (a lookbehind or bounded repeat in front of an alternation). Both +" engines answer alike; only patterns measured faster carry the prefix. + +" yats attaches type arguments via nextgroup after every identifier, so an +" unspaced "<" in any expression would hunt a ">" that may never come: " <div count=i<3> would swallow the rest of the file -" Its block comment carries "extend", which would let one stray "/*" escape -" every containing region below. Both are redefined bounded; the cost is -" generic-call coloring inside script blocks. +" That group stays cleared. The comment region replaces yats' block +" comment, whose "extend" would escape every containing region below. silent! syn clear typescriptTypeArguments silent! syn clear typescriptComment syn region typescriptComment contained start="/\*" end="\*/" contains=@Spell,typescriptCommentTodo -" Everything an embedded TypeScript expression may contain. The bracket -" pairs keep an outer region open across nested delimiters and shield the -" spaces inside groupings from attribute-value termination: +" yats claims call arguments, bodies, indexing, arrays, templates and +" parenthesized expressions via nextgroup, so the markoTS* pairs below +" never see those delimiters. Each row is yats' own definition plus +" "contained extend", the one difference from upstream: a multiline group +" keeps its containing attribute value open, and a bracketed one shields +" the spaces inside, as the parser's group tracking does: +" count=Math.max(0, tiers.findIndex((t) => t.featured)) +" pair=raw as [string, string] +for s:def in [ + \ 'typescriptBlock matchgroup=typescriptBraces start=/{/ end=/}/ contains=@typescriptStatement,@typescriptComments fold', + \ 'typescriptFuncCallArg matchgroup=typescriptParens start=/(/ end=/)/ contains=@typescriptValue,@typescriptComments,typescriptCastKeyword nextgroup=@typescriptSymbols,typescriptDotNotation skipwhite skipempty skipnl', + \ 'typescriptArray matchgroup=typescriptBraces start=/\[/ end=/]/ contains=@typescriptValue,@typescriptComments,typescriptCastKeyword nextgroup=@typescriptSymbols,typescriptDotNotation skipwhite skipempty fold', + \ 'typescriptTemplate start=/`/ skip=/\\\|\`\| / end=/`\|$/ contains=typescriptTemplateSubstitution,typescriptSpecial,@Spell nextgroup=@typescriptSymbols skipwhite skipempty', + \ 'typescriptObjectLiteral matchgroup=typescriptBraces start=/{/ end=/}/ contains=@typescriptComments,typescriptObjectLabel,typescriptStringProperty,typescriptComputedPropertyName,typescriptObjectAsyncKeyword,typescriptTernary,typescriptCastKeyword fold', + \ 'typescriptObjectType matchgroup=typescriptBraces start=/{/ end=/}/ contains=@typescriptTypeMember,typescriptEndColons,@typescriptComments,typescriptAccessibilityModifier,typescriptReadonlyModifier nextgroup=@typescriptTypeOperator skipwhite skipnl fold', + \ 'typescriptParenExp matchgroup=typescriptParens start=/(/ end=/)/ contains=@typescriptComments,@typescriptValue,typescriptCastKeyword nextgroup=@typescriptSymbols skipwhite skipempty', + \ 'typescriptIndexExpr matchgroup=typescriptProperty start=/\[/ end=/]/ contains=@typescriptValue,typescriptCastKeyword nextgroup=@typescriptSymbols,typescriptDotNotation,typescriptFuncCallArg skipwhite skipempty', + \ 'typescriptCall matchgroup=typescriptParens start=/(/ end=/)/ contains=typescriptDecorator,@typescriptParameterList,@typescriptComments nextgroup=typescriptTypeAnnotation,typescriptBlock skipwhite skipnl', + \ 'typescriptTupleType matchgroup=typescriptBraces start=/\[/ end=/\]/ contains=@typescriptType,@typescriptComments,typescriptRestOrSpread,typescriptTupleLable skipwhite', + \ 'typescriptParenthesizedType matchgroup=typescriptParens start=/(/ end=/)/ contains=@typescriptType nextgroup=@typescriptTypeOperator skipwhite skipempty fold', + \ 'typescriptFuncType matchgroup=typescriptParens start=/(\(\k\+:\|)\)\@=/ end=/)\s*=>/me=e-2 contains=@typescriptParameterList nextgroup=typescriptFuncTypeArrow skipwhite skipnl oneline', + \ 'typescriptStringLiteralType start=/\z(["'']\)/ skip=/\\\|\\z1\|\ / end=/\z1\|$/ nextgroup=typescriptUnion skipwhite skipempty', + \ 'typescriptTemplateLiteralType start=/`/ skip=/\\\|\`\| / end=/`\|$/ contains=typescriptTemplateSubstitutionType nextgroup=typescriptTypeOperator skipwhite skipempty', + \ ] + silent! exe 'syn clear ' . matchstr(s:def, '^\S\+') + exe 'syn region ' . s:def . ' contained extend' +endfor +unlet s:def +" yats' own arrow-function definitions, restated to stay last-defined at +" a "(": params eaten as a parenthesized expression turn the arrow's "{" +" body into an object literal, whose ternary region has no closing bound: +" f((x) => { value = x ?? other; }) +syntax match typescriptArrowFuncDef contained /\K\k*\s*=>/ + \ contains=typescriptArrowFuncArg,typescriptArrowFunc + \ nextgroup=@typescriptExpression,typescriptBlock + \ skipwhite skipempty +syntax match typescriptArrowFuncDef contained /(\%(\_[^()]\+\|(\_[^()]*)\)*)\_s*=>/ + \ contains=typescriptArrowFuncArg,typescriptArrowFunc,@typescriptCallSignature + \ nextgroup=@typescriptExpression,typescriptBlock + \ skipwhite skipempty +syntax region typescriptArrowFuncDef contained start=/(\%(\_[^()]\+\|(\_[^()]*)\)*):/ matchgroup=typescriptArrowFunc end=/=>/ + \ contains=typescriptArrowFuncArg,typescriptTypeAnnotation,@typescriptCallSignature + \ nextgroup=@typescriptExpression,typescriptBlock + \ skipwhite skipempty keepend + +" The bracket pairs keep an outer region open across nested delimiters +" and shield the spaces inside groupings from value termination: " a={ b: { c: 1 } } d=2 -" Without the matchgroup each region would re-match at its own start -" character through its own contains and consume the closing delimiter. -" markoTSDelim is deliberately unlinked: the delimiters render as plain -" text, like brackets in a TypeScript buffer. +" markoTSDelim is deliberately unlinked: delimiters render plain. syn cluster markoExpr contains=@markoTS,markoTSBraces,markoTSParens,markoTSBrackets -syn region markoTSBraces contained transparent matchgroup=markoTSDelim - \ start="{" end="}" - \ contains=@markoExpr extend -syn region markoTSParens contained transparent matchgroup=markoTSDelim - \ start="(" end=")" - \ contains=@markoExpr extend -syn region markoTSBrackets contained transparent matchgroup=markoTSDelim - \ start="\[" end="]" - \ contains=@markoExpr extend - -" Comments are recognized where the parser allows text to start; anchoring -" to the line start keeps "//" inside URLs as text: -" <!-- note --> // note /* note */ https://example.com +for [s:pair, s:open, s:close] in [["Braces", '{', '}'], ["Parens", '(', ')'], ["Brackets", '\[', ']']] + exe 'syn region markoTS' . s:pair . ' contained transparent matchgroup=markoTSDelim' + \ . ' start="' . s:open . '" end="' . s:close . '"' + \ . ' contains=@markoExpr extend' +endfor +unlet s:pair s:open s:close + +" html-mode "//" and "/* */" comments open wherever whitespace precedes +" the slash (a URL's "//" follows ":", so it stays plain); concise context +" takes only the line-anchored forms, defined second so they win at a line +" start and keep their fold and indent handling: +" // note <p>done // for now</p> <a href="https://x.co">plain</a> +" No comment item may take "display": a match skipped during offscreen +" state computation exposes its text, and a "<tag" inside a comment would +" open a body whose highlighting depends on scroll position. +syn match markoHtmlComment "\%(^\|\s\)\@1<=//.*$" contains=@Spell +syn region markoHtmlComment start="\%(^\|\s\)\@1<=/\*" end="\*/" contains=@Spell fold syn region markoComment start="<!--" end="-->" contains=@Spell fold -syn match markoComment "^\s*//.*$" contains=@Spell display +syn match markoComment "^\s*//.*$" contains=@Spell syn region markoComment start="^\s*/\*" end="\*/" contains=@Spell fold -syn region markoTagComment contained start="/\*" end="\*/" +syn region markoTagComment contained start="/\*" end="\*/" extend syn match markoTagComment contained "//.*" +" Declarations before CDATA: both open at "<!" and the later wins: +" <!doctype html> <?xml version="1.0"?> <![CDATA[ raw ]]> +syn region markoDeclaration start="<!\(--\)\@!" end=">" +syn region markoDeclaration start="<?" end=">" syn region markoCData start="<!\[CDATA\[" end="]]>" -" Declarations; "<?...>" may close with ">" or "?>": -" <!doctype html> <?xml version="1.0"?> -syn region markoDeclaration start="<!\%(--\|\[CDATA\)\@!" end=">" -syn region markoDeclaration start="<?" end="?\=>" -" Placeholders interpolate into text, and backslashes escape pairwise: +" Placeholders interpolate into text; backslashes escape pairwise: " ${user.name} $!{rawHtml} \${literal} \${live} -" The containedin lets them apply inside style rules and property values. -" markoEscape must never take "display": it exists to suppress -" markoPlaceholder, so skipping it during state computation would change -" what matches. -syn match markoEscape "\%(\\\)\+\ze\$!\={" -syn match markoEscape "\%(\\\)*\\$!\={" +" markoEscape must never take "display" (it exists to suppress +" markoPlaceholder); it consumes an escaped "$", or stops before a "${" +" an even backslash run leaves live. +syn match markoEscape "\%(\\\)*\%(\\$!\={\|\\\ze\$!\={\)" syn region markoPlaceholder matchgroup=markoPlaceholderDelim \ start="\$!\={" end="}" - \ contains=@markoExpr containedin=cssDefinition,cssAttrRegion extend + \ contains=@markoExpr extend +" The no-"extend" variant for keepend parsed-text bodies and the CSS +" contexts: an unterminated "\${" must stop at the container's close. +syn region markoPlaceholderText contained matchgroup=markoPlaceholderDelim + \ start="\$!\={" end="}" + \ contains=@markoExpr + \ containedin=cssDefinition,cssAttrRegion,cssStringQ,cssStringQQ syn match markoEntity "&\%(#\d\+\|#[xX]\x\+\|\w\+\);" display -" Scriptlets; the whitespace after "$" is required, so a line-start -" placeholder is not a scriptlet: -" $ count += 1 -" $ { let total = 0; } -" ${count} placeholder +" Scriptlets; the whitespace after "$" keeps line-start placeholders out. +" No keepend: an open bracket continues, as the parser's group tracking +" does. The "$ {" block form is second, so it wins where both start: +" $ count += 1 $ { let total = 0; } +" $ const rows = [ +" "a", +" ] syn region markoScriptlet matchgroup=markoScriptletDelim - \ start="^\s*\$\s\+{\@!" end="$" - \ contains=@markoExpr keepend + \ start="^\s*\$\s\+" end="$" + \ contains=@markoExpr syn region markoScriptlet matchgroup=markoScriptletDelim \ start="^\s*\$\s\+{" end="};\=" \ contains=@markoExpr -" "--" marks one line of text in concise mode: +" "--" marks the rest of the line as text; at end of line it opens an +" indented block instead: " p -- some text -syn match markoBlockDelim "\%(^\|\s\)\@1<=--\+\ze\%(\s\|$\)" display - -" Attributes. An unquoted value ends at whitespace (quoted strings and -" bracket pairs shield theirs), does not start at the "=" of an arrow, and -" continues across " => " so arrow values stay whole: -" size="large" total:=sum ...spread onClick=(e) => handle(e) -" The attr name must not match the "${" of a dynamic tag name. -syn match markoAttrName contained "\%(\$!\={\)\@![[:alnum:]_$@][-[:alnum:]_$.]*" display +" p -- +" A block of text, <b>html mode</b>. +" The inline form is a one-line html region, so later dash runs on the +" line sit inside it and are never delimiters (the parser's rule), and +" keepend bounds what the line opens. Both forms stand down on a line +" whose first non-blank is "<" (html content, where dashes are text). +" They overlap at a trailing "--": the nextgroup form is second and wins, +" and must not take "display". A bare "--" line belongs to the +" later-defined markoTextDelimBlock. +syn region markoInlineText oneline keepend matchgroup=markoBlockDelim + \ start="\%#=1\%(^\s*<.\{-}\)\@200<!\%(^\|\s\)\@1<=--\+\ze\s" end="$" + \ contains=@markoHtmlContent +syn match markoBlockDelim + \ "\%#=1\%(^\s*<.\{-}\)\@200<!\%(^\|\s\)\@1<=--\+\s*$" + \ nextgroup=markoTextIndent skipnl +" The shared block body: its indent is the first following line's leading +" whitespace run, blank lines included (the parser's rule); an empty run +" leaves only the column-0 delimiter close, the dedent end being a +" negative lookahead on an empty match. +let s:indent_block = ' start="^\z(\s*\)\ze\%(\S\|$\)"' + \ . ' matchgroup=markoBlockDelim end="^\z1--\+\s*$"' + \ . ' matchgroup=NONE end="^\%(\z1\)\@!\ze\s*\S"' +exe 'syn region markoTextIndent contained' . s:indent_block + \ . ' contains=@markoHtmlContent' + +" A name may hold ":" (not the ":=" of a bound value) and any keyword +" character, and must not match a dynamic tag name's "${": +" size="large" total:=sum xml:lang="es" <spinner café="ok"/> +" An unquoted value ends at whitespace or the mode's terminators, except +" that the parser continues across whitespace flanked by an operator: +" if=tag === "select" content=a.desc ?? b.desc onClick=(e) => go(e) +syn match markoAttrName contained "\%#=1\%(\$!\={\)\@![[:alnum:]_$@]\%(\k\|[$.]\|:=\@!\)*" display syn match markoSpread contained "\.\.\." display -syn region markoAttrValue contained matchgroup=markoOperator - \ start=":\==>\@!\s*" end="\ze\%(\%(=>\)\@2<!\s\%(\s*=>\)\@!\|=\@1<!>\|/>\)" end="$" - \ contains=@markoExpr syn region markoString contained start=+\z(["']\)+ skip=+\\z1+ end=+\z1+ contains=@Spell -" Shorthands after the tag name: -" <div.card#main> -syn match markoShorthandId contained "#[-[:alnum:]_$]\+" display -syn match markoShorthandClass contained "\.[-[:alnum:]_$]\+" display - -" Tag variables, arguments, |parameters|, <type args> and attribute method -" shorthand bodies: +" Regions so an interpolation can sit inside one (no keepend: the +" placeholder carries the region past its "}"): +" <div.card#main> <div#item-${id}> +syn region markoShorthandId contained oneline + \ start="#[-[:alnum:]_$]\@=" end="[-[:alnum:]_$]\@!" + \ contains=markoPlaceholder +syn region markoShorthandClass contained oneline + \ start="\.[-[:alnum:]_$]\@=" end="[-[:alnum:]_$]\@!" + \ contains=markoPlaceholder + +" Tag variables, arguments, |parameters|, <type args> and method bodies: " <let/count=1/> <for|item, i| of=list> <while(cond)> " <generic-list<string>> <button onClick(e) { handle(e) }> -" Params and type args must hug the preceding name (the "\k" follows the -" "syn iskeyword" set below, which is what admits hyphenated names) so a -" "|" or "<" inside an expression cannot open them, and both are oneline -" so an unmatched delimiter cannot run past its line. -syn match markoTagVar contained "/\%([[:alnum:]_$]\+\|\ze\s*[{[]\)" display +" Params and type args hug the preceding name, so a "|" or "<" inside an +" expression cannot open them; params and the plain type-args form are +" oneline so an unmatched delimiter stops at its line. +syn match markoTagVar contained "/\%([[:alnum:]_$]\+\|\ze\s*[{[]\)" + \ nextgroup=markoTagVarDestructure skipwhite display +syn region markoTagVarDestructure contained matchgroup=markoTagDelim + \ start="\[" end="]" + \ contains=@markoExpr extend syn region markoArgs contained matchgroup=markoTagDelim \ start="(" end=")" \ contains=@markoExpr extend @@ -150,48 +230,122 @@ syn region markoParams contained oneline matchgroup=markoTagDelim \ contains=@markoExpr syn region markoTypeArgs contained oneline matchgroup=markoTagDelim \ start="\%(\k\|\$\)\@4<=<" end=">" - \ contains=@markoExpr,markoTypeArgs + \ contains=@typescriptType,markoTypeArgs +" The braced form spans lines: the object type bounds it, and the parser +" reads "<{" after a name in tag scope as type args too. +syn region markoTypeArgs contained matchgroup=markoTagDelim + \ start="\%(\k\|\$\)\@4<=<\ze\s*{" end=">" + \ contains=@typescriptType,markoTypeArgs extend syn region markoMethodBody contained matchgroup=markoTagDelim \ start="{" end="}" \ contains=@markoExpr extend +" The three value variants differ only in terminators: html ends at "," +" "/>" or the tag's ">"; concise at "," ";" or whitespace-led "--" (">" +" is a comparison there); grouped at "," or "]". Defined after markoArgs +" so a "...spread" value wins at "(". keepend bounds foreign TypeScript +" at the value's end; the markoTS* and yats groups carry extend and punch +" through. A value survives its line end when either side of the break +" is an operator in html mode (the lookahead crosses blank lines), only +" a trailing one in concise: +" <a href=translated +" ? localizeUrl($global.url.href, { locale }).href +" : baseHref> +" s:val_nocont, the trailing set, mirrors the parser: "=>" and ">>" +" continue but a bare ">" ends (operator only outside type position, +" untrackable, and honoring it swallowed "</div>"-style line ends; +" mid-line "x > 1" continues via the break end's own guard); single +" "+"/"-" continue, postfix "i++" ends; unary keywords count unless a +" word character precedes ("a-new Date()" stays whole), binary and type +" keywords only after whitespace ("class=step-in" ends); a trailing "." +" continues when a word character follows, across blank lines. A "/" +" counts only when spaces flank it (ahead of the break it is ambiguous +" with "/>"), and the break demands a non-space before the space, so a +" continuation line's indent cannot end the value it continues: +" ratio=total / count max=10 +" total=base + +" tax +let s:val_nocont = '[&*^:=!<%|?~]\@1<!\%(=>\|>>\)\@2<!\%(+\@1<!+\|-\@1<!-\)\@1<!\%(\s/\)\@2<!' + \ . '\%([0-9A-Za-z_$.]\@1<!\%(async\|await\|class\|function\|new\|typeof\|void\)\|\s\%(as\|extends\|instanceof\|in\|satisfies\|asserts\|infer\|is\|keyof\|readonly\|unique\)\)\@12<!' + \ . '\%(\.\@1<=\_s*[0-9A-Za-z_$]\)\@!' +" Cheap zero-width lead tests keep the wide lookbehinds off most columns. +" s:val_last matches after the line's last non-blank, so trailing spaces +" and blank lines never host a value end. +let s:val_last = '\%#=1\%(\s*$\)\@=' . s:val_nocont . '\S\@1<=' +let s:val_break = '\%#=1\s\@=>\@1<!' . s:val_nocont . '\S\@1<=\s' +let s:val_op = '[&*^!<%|~+?:={(]\|\.\%(\_s*\w\)\@=\|\<\%(as\|extends\|instanceof\|in\|satisfies\)\%(\_s\+[^:,=/>; ]\)\@=' +let s:val_head = ' contained matchgroup=markoOperator start=":\==>\@!\s*"' + \ . ' matchgroup=NONE start="\.\@1<=\%(\.\.\.\)\@3<="' +let s:val_tail = ' contains=@markoExpr keepend extend' +exe 'syn region markoAttrValue' . s:val_head + \ . ' end="\ze," end="\ze/>" end="=\@1<!\ze>"' + \ . ' end="' . s:val_last . '\ze\s* \%(\_s*\%(' . s:val_op . '\|-\|/[/*>]\@!\)\)\@!"' + \ . ' end="' . s:val_break . '\%(\_s*\%(' . s:val_op . '\|-\|/[/*>]\@!\)\)\@!"' . s:val_tail +exe 'syn region markoAttrValueConcise' . s:val_head + \ . ' end="\ze[,;]" end="' . s:val_last . '"' + \ . ' end="' . s:val_break . '\%(\s*\%(' . s:val_op . '\|--\@!\|/[/*]\@!\|>\)\)\@!"' . s:val_tail +exe 'syn region markoAttrValueInGroup' . s:val_head + \ . ' end="\ze[,\]]" end="' . s:val_last . '"' + \ . ' end="' . s:val_break . '\%(\s*\%(' . s:val_op . '\|-\|/[/*]\@!\|>\)\)\@!"' . s:val_tail +unlet s:val_nocont s:val_last s:val_break s:val_op s:val_head s:val_tail + syn cluster markoTagStuff contains=markoTagVar,markoShorthandId,markoShorthandClass, - \markoAttrName,markoAttrValue,markoString,markoArgs,markoParams,markoTypeArgs, + \markoAttrName,markoString,markoArgs,markoParams,markoTypeArgs, \markoMethodBody,markoSpread,markoTagComment,markoPlaceholder -syn cluster markoTagNames contains=markoTagName,markoAttrTagName,markoTagNameConditional, - \markoTagNameRepeat,markoTagNameException,markoTagNameStatement,markoTagNameBuiltin - -" Concise attribute groups may span lines: -" define [ -" size = "large" -" ] +" The name groups themselves are defined near the end of the file; a +" cluster may name them before they exist. +syn cluster markoTagNames contains=markoTagName,markoTagNameTail,markoAttrTagName, + \markoTagNameConditional,markoTagNameRepeat,markoTagNameException, + \markoTagNameStatement,markoTagNameBuiltin + +" Attribute groups may span lines. The lookbehind keeps a spread's array +" literal out; that "[" opens a value, not a group: +" define [size = "large"] my-tag ...[1, 2] syn region markoAttrGroup contained matchgroup=markoTagDelim - \ start="\[" end="]" - \ contains=@markoTagStuff extend + \ start="\%(\.\.\.\)\@3<!\[" end="]" + \ contains=@markoTagStuff,markoAttrValueInGroup extend -" One name list per highlight class, shared by the concise regions here -" and the tag-name matches below. +" One list per highlight class. The builtin list is factored by first +" letter; no name is a prefix of another, so grouping changes nothing. let s:tag_name_classes = [ \ ["Conditional", 'if\|else-if\|else'], \ ["Repeat", 'for\|while'], \ ["Exception", 'try'], \ ["Statement", 'await\|return'], - \ ["Builtin", 'let\|const\|effect\|lifecycle\|id\|log\|debug\|context\|define\|macro\|html-comment'], + \ ["Builtin", 'l\%(et\|ifecycle\|og\)\|c\%(onst\|ontext\)\|d\%(ebug\|efine\)\|s\%(tyle\|cript\)\|effect\|id\|macro\|textarea\|html-\%(comment\|style\|script\)'], \ ] -" Concise mode: a line-start name is a tag. The generic rule is defined -" first, so the builtin classes, "@" attribute tags and the statement tags -" below all win over it for their names. keepend bounds each region to -" its line; brackets, method bodies and attr groups carry extend, which -" deliberately punches through for multiline constructs. -let s:concise_tag_end = ' matchgroup=markoTagDelim end=";" end="$" end="\s\zs\ze--\%(\s\|$\)"' - \ . ' contains=@markoTagStuff,markoAttrGroup keepend' +" Concise mode: a line-start name is a tag; so are "${tag}", ".class" and +" "#id". The generic rule is first, so class names, "@" tags and the +" statement tags win over it. A tag ends at its line unless a comma +" trails or leads the continuation; comments and blank lines may sit +" between, and a blank line never hosts the end. Brackets, method bodies +" and attr groups carry extend, punching through keepend for multiline +" constructs: +" link +" ,rel="canonical" +" // a comment between continued lines +" ,href=baseHref +" input type="text", +" value=name +" Whitespace-led dashes end the tag and start text. That end begins at +" the first dash with the space as lookbehind: the space is also the +" value's own break-end, and an end starting inside the value would be +" suppressed by its extend: +" p ---- some text +let s:concise_tag_end = ' matchgroup=markoTagDelim end=";"' + \ . ' end="\%#=1\%(,\s*\)\@9<!\%(^\s\{0,60}\)\@61<!\ze \%(\%(\s*\%(//.*\|/\*\_.\{-,200}\*/\s*\)\= \)\{0,20}\s*,\)\@!"' + \ . ' end="\s\@1<=\ze-\{2,}\%(\s\|$\)"' + \ . ' contains=@markoTagStuff,markoAttrGroup,markoAttrValueConcise,markoTagNameTail keepend' exe 'syn region markoConciseTag matchgroup=markoTagName' - \ . ' start="^\s*\zs[[:alnum:]][-[:alnum:]_$:]*\%([-[:alnum:]_$:]\)\@!"' + \ . ' start="^\s*\zs\%(-\@!\k\|\$[{ ]\@!\)\%(\k\|:\|\${\@!\)*"' + \ . s:concise_tag_end +exe 'syn region markoConciseTag' + \ . ' start="^\s*\ze\%(\$!\={\|[.#][-[:alnum:]_$]\)"' \ . s:concise_tag_end for [s:class_suffix, s:name_pattern] in s:tag_name_classes exe 'syn region markoConciseTag matchgroup=markoTagName' . s:class_suffix - \ . ' start="^\s*\zs\%(' . s:name_pattern . '\)\%([-[:alnum:]_$:]\)\@!"' + \ . ' start="^\s*\zs\%(' . s:name_pattern . '\)\%(\k\|\$\|:=\@!\)\@!"' \ . s:concise_tag_end endfor exe 'syn region markoConciseTag matchgroup=markoAttrTagName' @@ -199,151 +353,190 @@ exe 'syn region markoConciseTag matchgroup=markoAttrTagName' \ . s:concise_tag_end unlet s:concise_tag_end -" Statement tags contain one TypeScript statement. static/server/client -" are Marko keywords; import/export/class take their color from the -" TypeScript include. A statement may span lines through an open brace or -" class body, so an unterminated "/*" runs on, as it would in a TypeScript -" buffer. Defined after the concise regions so these names win there. +" One TypeScript statement each. static/server/client are Marko keywords; +" import/export/class take the include's colors. Defined after the +" concise regions so these names win there. syn region markoStatement matchgroup=markoStatementKeyword \ start="^\s*\zs\%(static\|server\|client\)\>" - \ end="$" contains=@markoExpr -syn region markoStatement - \ start="^\s*\ze\%(import\|export\|class\)\>" + \ matchgroup=NONE start="^\s*\ze\%(import\|export\|class\)\>" \ end="$" contains=@markoExpr " A tag name may be empty (<.card>), dynamic (<${tag}>) or an attribute -" tag (<@body>); the ">" of an arrow does not end the tag. +" tag (<@body>); an arrow's ">" does not end the tag. syn region markoTag matchgroup=markoTagDelim - \ start="<\ze[^/ !?<>=]" end="/>" end="=\@1<!>" - \ contains=@markoTagStuff,@markoTagNames + \ start="<\ze[^/ !?<>=]" end="/>" end="\%#=1=\@1<!>" + \ contains=@markoTagStuff,@markoTagNames,markoAttrValue +" Recovers a close tag no body end consumed, eg a stray one in concise +" context. syn region markoCloseTag matchgroup=markoTagDelim \ start="</" end=">" \ contains=@markoTagNames,markoPlaceholder -" The name of a close tag whose "</" was consumed by an element body's end -" match below, plus its trailing ">". -syn match markoCloseName "\%(</\)\@2<=@\=\%(\k\|[$:]\)\+\s*" nextgroup=markoCloseGt display +" The name of a close tag whose "</" a body end consumed, plus its ">". +" It stops before "${", so a dynamic close name's placeholder colors: +" </${tag}> +syn match markoCloseName + \ "/\@1<=\%(</\)\@2<=\%(\k\|:\|\$\%(!\={\)\@!\)\+\s*" + \ nextgroup=markoCloseGt,markoClosePlaceholder display syn match markoCloseGt contained ">" display - -" Everything html-mode content may contain. Statement tags and concise -" tags are absent: bare text inside an element body is prose. +" A dynamic close name's placeholder, chained so the closing ">" keeps +" its color: </${tag}> via the body's nextgroup, </h${size}> via the +" close name's. +syn region markoClosePlaceholder contained matchgroup=markoPlaceholderDelim + \ start="\$!\={" end="}" + \ contains=@markoExpr + \ nextgroup=markoCloseGt,markoCloseTail +syn match markoCloseTail contained "\%(\k\|:\)\+\s*" + \ nextgroup=markoCloseGt,markoClosePlaceholder display +" The anonymous form (</>): a body end consumed the "</" and there is no +" close name to carry the nextgroup, so the ">" takes its color directly. +syn match markoCloseAnon "\%(</\)\@2<=>" display + +" Statement and concise tags are absent: bare text in a body is prose. +" The close-name refinements keep </if> Conditional at any depth; generic +" markoTagName stays out or it would outrank markoCloseName. syn cluster markoHtmlContent contains=markoTag,markoHtmlBody,markoDynamicBody, \markoStyle,markoScript,markoTextareaTag,markoHtmlCommentTag, - \markoComment,markoCData,markoDeclaration,markoEscape,markoPlaceholder, - \markoEntity,markoScriptlet,markoCloseName - -" Whether "<name" begins an element body turns on how its open tag ends: -" an atomic (no-backtrack) run over quoted strings, (args), <type args>, -" "=>" and spaced comparisons finds the structural ">", and a "/>" there -" means self-closing, so no body: + \markoComment,markoHtmlComment,markoCData,markoDeclaration,markoEscape,markoPlaceholder, + \markoEntity,markoScriptlet,markoCloseName,markoCloseAnon,markoAttrTagName, + \markoTagNameConditional,markoTagNameRepeat,markoTagNameException, + \markoTagNameStatement,markoTagNameBuiltin + +" Whether "<name" begins a body turns on how its open tag ends: an atomic +" run over the groupings that may hold a ">" finds the structural one, +" and a "/>" there means self-closing, no body: " <my-tag onClick=() => go(a > b) /> +" <div onClick() { hidden = a > b }/> +" Nothing else hides a ">" (the parser ends an open tag at any ">" not +" preceded by "="), and the repeat counts bound the scan so a stray "<" +" costs a fixed lookahead; past them no body opens. let s:tag_end_ahead = '\%(\%(\%(<\%([^<>]\|<\%([^<>]\|<[^<>]\{-,40}>\)\{-,60}>\)\{-,100}>' \ . '\|"[^"]\{-,200}"\|' . "'[^']\{-,200}'" - \ . '\|([^()]\{-,200})\|=>\|[ ]>[ ]\@=\|\_[^>]\)\{0,400}\)\@>/\@1<!=\@1<!>\)\@=' + \ . '\|`[^`]\{-,200}`' + \ . '\|(\%(\_[^()]\|(\%(\_[^()]\|([^()]\{-,60})\)\{-,100})\)\{-,300})' + \ . '\|{\%(\_[^{}]\|{\_[^{}]\{-,100}}\)\{-,300}}' + \ . '\|=>\|\_[^>]\)\{0,800}\)\@>/\@1<!=\@1<!>\)\@=' " Element bodies: html mode from a non-void, non-self-closing open tag to -" its matching close. \z1 pairs the names, and the end consumes only -" "</" so an inner same-name close cannot end the outer bodies -" (markoCloseName colors the rest): +" its matching close. \z1 pairs the names; the end consumes only "</" so +" an inner same-name close cannot end the outer body: " <div><div>nested</div>still the outer body</div> -" No body opens for html voids, parsed-text tags, bodiless core tags -" (<let/x=1> takes no close tag) or "@" attribute tags (those auto-close -" at their parent, which no name pairing can track). Defined after -" markoTag so open tags still overlay inside bodies, and after the -" concise regions so html mode wins at a line-start "<". A mismatched or -" missing close leaves its body open for the rest of the buffer, as an -" unclosed tag does in html.vim. +" The excluded names are the parser's void and text lists (<let/x=1> +" takes no close tag; <effect> is in neither and opens a body). Defined +" after markoTag and the concise regions so a body wins at "<"; a missing +" close leaves the body open, as in html.vim. exe 'syn region markoHtmlBody' \ . ' start=+<\ze\%(\%(area\|base\|br\|col\|embed\|hr\|img\|input\|link\|meta\|param' \ . '\|source\|track\|wbr\|style\|script\|textarea\|html-comment\|html-style' - \ . '\|html-script\|let\|const\|id\|log\|debug\|effect\|lifecycle\|return\)' - \ . '\%(\k\|[$:]\)\@!\)\@!' + \ . '\|html-script\|let\|const\|id\|log\|debug\|lifecycle\|return\)' + \ . '\%(\k\|\$\|:=\@!\)\@!\)\@!' \ . '\z(\%(\k\|[$:]\)\+\)\%(\_s\|[/>|(<.#=]\)\@=' . s:tag_end_ahead . '+' \ . ' matchgroup=markoTagDelim' - \ . ' end="</\ze\z1\%(\k\|[$:]\)\@!\s*>" end="</\ze\s*>"' + \ . ' end="</\ze\z1\s*>" end="</\ze\s*>"' \ . ' contains=@markoHtmlContent' +" A dynamic name -- any mix of literal characters and "${...}" +" placeholders -- cannot be paired, so a dynamic body closes at the first +" close tag of dynamic shape, regardless of nesting: +" <h${size}>heading</h${size}> <${tag}>body</${tag}> exe 'syn region markoDynamicBody' - \ . ' start=+<\ze\%(\$!\={\)\@=' . s:tag_end_ahead . '+' + \ . ' start=+<\ze\%(\%(\k\|:\)*\$!\={\)\@=' . s:tag_end_ahead . '+' \ . ' matchgroup=markoTagDelim' - \ . ' end="</\ze\%(\$!\={\_[^}]*}\)\=\s*>"' - \ . ' contains=@markoHtmlContent' + \ . ' end="</\ze\%(\%(\k\|:\)*\%(\$!\={\_[^{}]*\%({\_[^{}]*}\_[^{}]*\)\{0,3}}\%(\k\|:\)*\)\+\)\=\s*>"' + \ . ' contains=@markoHtmlContent nextgroup=markoClosePlaceholder' unlet s:tag_end_ahead -" Delimited text blocks in concise mode contain html-mode content. An -" indented block closes at a matching delimiter line or at any line -" indented less than its opener; a column-0 block closes only at its -" matching delimiter: +" Standalone delimited blocks hold html content, like markoTextIndent. +" A block closes at its exact delimiter -- same indent, same dash count, +" longer or shorter runs are text -- or on any dedent; a column-0 block +" only at its delimiter (the empty \z1 kills the dedent end). Defined +" after the markoBlockDelim forms so a bare "--" line opens a block: " -- " A block of text, <b>html mode</b>. " -- -syn region markoTextBlock matchgroup=markoBlockDelim - \ start="^\z(\s\+\)--\+\s*$" - \ end="^\z1--\+\s*$" end="^\%(\z1\)\@!\ze\s*\S" - \ contains=@markoHtmlContent -syn region markoTextBlock matchgroup=markoBlockDelim - \ start="^--\+\s*$" - \ end="^--\+\s*$" +syn region markoTextDelimBlock matchgroup=markoBlockDelim + \ start="^\z(\s*\)\z(--\+\)\s*$" + \ end="^\z1\z2\s*$" end="^\%(\z1\)\@!\ze\s*\S" \ contains=@markoHtmlContent -" Parsed-text tags: bodies contain only text and placeholders (style and -" script embed CSS and TypeScript, a textarea body is plain text, an -" html-comment body is comment text). Defined after the generic tag and -" body regions to win at the same "<". The "/\@1<!" keeps self-closing -" open tags, which have no body, out: -" <script src="x" /> -" keepend stops an unterminated embedded construct at the close tag. -syn region markoStyle matchgroup=markoTagNameBuiltin - \ start=+<\%(html-\)\=style\>\_[^>]\{-,300}/\@1<!=\@1<!>+ - \ end="</\%(html-\)\=style\s*>" - \ contains=@markoCSS,markoPlaceholder keepend fold +" Parsed-text tags: bodies hold only text and placeholders (style/script +" embed CSS and TypeScript). Each region consumes only its "<"; the +" markoParsedOpen overlay colors the open tag normally: +" <style/styles> <script src="x" async> +" Defined after the generic tag and body regions to win at "<". The +" "/\@1<!" keeps self-closing tags out; keepend stops an unterminated +" embedded construct at the close tag. +syn region markoParsedOpen contained matchgroup=markoTagDelim + \ start="<\ze\%(html-\%(style\|script\|comment\)\|style\|script\|textarea\)\>\%(:=\@!\|\$\)\@!" + \ matchgroup=markoTagDelim end="/\@1<!=\@1<!>" + \ contains=@markoTagStuff,@markoTagNames,markoAttrValue +" The bounded lookahead for the open tag's own ">", shared by all four. +let s:open_end_ahead = '\%(\%("[^"]\{-,200}"\|''[^'']\{-,200}''\|`[^`]\{-,200}`\|=>\|\_[^>]\)\{-,300}/\@1<!=\@1<!>\)\@=' +for [s:name, s:pat, s:body] in [ + \ ['markoStyle', '\%(html-\)\=style', '@markoCSS,markoPlaceholderText,markoParsedOpen keepend fold'], + \ ['markoScript', '\%(html-\)\=script', '@markoTS,markoPlaceholderText,markoParsedOpen keepend fold'], + \ ['markoTextareaTag', 'textarea', 'markoPlaceholderText,markoEntity,@Spell,markoParsedOpen keepend'], + \ ['markoHtmlCommentTag', 'html-comment', 'markoPlaceholderText,@Spell,markoParsedOpen keepend'], + \ ] + exe 'syn region ' . s:name + \ . ' start=+<\ze' . s:pat . '\>\%(:=\@!\|\$\)\@!' . s:open_end_ahead . '+' + \ . ' matchgroup=markoTagDelim end="</\ze' . s:pat . '\s*>"' + \ . ' contains=' . s:body +endfor +unlet s:name s:pat s:body syn region markoStyle matchgroup=markoTagNameBuiltin \ start="^\s*style\%([./][^ {]*\)\=\s*{" end="}" - \ contains=@markoCSS,markoPlaceholder fold -syn region markoScript matchgroup=markoTagNameBuiltin - \ start=+<\%(html-\)\=script\>\_[^>]\{-,300}/\@1<!=\@1<!>+ - \ end="</\%(html-\)\=script\s*>" - \ contains=@markoTS,markoPlaceholder keepend fold -syn region markoTextareaTag matchgroup=markoTagNameBuiltin - \ start=+<textarea\>\_[^>]\{-,300}/\@1<!=\@1<!>+ - \ end="</textarea\s*>" - \ contains=markoPlaceholder,markoEntity,@Spell keepend -syn region markoHtmlCommentTag matchgroup=markoTagNameBuiltin - \ start=+<html-comment\>\_[^>]\{-,300}/\@1<!=\@1<!>+ - \ end="</html-comment\s*>" - \ contains=markoPlaceholder,@Spell keepend - -" Tag names inside "<...>"/"</...>" (concise names are colored by the -" region matchgroups above). The generic name is defined after the -" attribute name, so it wins right after "<"; the class-specific names are -" defined after the generic one, so they win over it. -syn match markoTagName contained "\%(</\=\)\@2<=[[:alnum:]][-[:alnum:]_$:]*" display -syn match markoAttrTagName contained "\%(</\=\)\@2<=@[-[:alnum:]_$:]\+" display + \ contains=@markoCSS,markoPlaceholderText fold +" A trailing "--" on a concise style tag opens a delimited block of CSS; +" the lookbehind claims only the dashes, winning over the generic +" trailing-"--" form. script works the same way with TypeScript: +" style/styles -- +" .root { color: red } +" -- +for [s:kind, s:body] in [["Style", '@markoCSS'], ["Script", '@markoTS']] + exe 'syn match marko' . s:kind . 'Delim' + \ . ' "\%#=1\%(^\s*' . tolower(s:kind) . '\%(\k\|[$:]\)\@![^;{]*\)\@200<=--\+\s*$"' + \ . ' nextgroup=marko' . s:kind . 'Text skipnl' + exe 'syn region marko' . s:kind . 'Text contained' . s:indent_block + \ . ' contains=' . s:body . ',markoPlaceholderText keepend fold' +endfor +unlet s:kind s:body s:indent_block +unlet s:open_end_ahead + +" Names inside "<...>"/"</...>": a name stops before "${" and +" markoTagNameTail resumes after "}"; the tail's lookbehind demands the +" placeholder, so a method body's "}" cannot start one: +" <h${size}> <div onClick() { go() }disabled> "disabled" is an attr +" Generic after attr name, class names after generic: later wins. +syn match markoTagName contained "\%(</\=\)\@2<=\%(-\@!\k\|\$[{ ]\@!\)\%(\k\|:\|\${\@!\)*" display +syn match markoTagNameTail contained + \ "}\@1<=\%(\$!\={[^{}]*}\)\@120<=\%(\k\|:\|\${\@!\)\+" display +syn match markoAttrTagName contained "\%#=1\%(</\=\)\@2<=@[-[:alnum:]_$:]\+" display " The un-contained variants refine markoCloseName after a body's end has " consumed the "</", so builtin and "@" close names keep their classes. -syn match markoAttrTagName "\%(</\)\@2<=@\%(\k\|[$:]\)\+\s*" nextgroup=markoCloseGt display +syn match markoAttrTagName "\%#=1\%(</\)\@2<=@\%(\k\|[$:]\)\+\s*" nextgroup=markoCloseGt display for [s:class_suffix, s:name_pattern] in s:tag_name_classes exe 'syn match markoTagName' . s:class_suffix - \ . ' contained "\%(</\=\)\@2<=\%(' . s:name_pattern . '\)\%([-[:alnum:]_$]\)\@!" display' + \ . ' contained "\%#=1\%(</\=\)\@2<=\%(' . s:name_pattern . '\)\%(\k\|\$\|:=\@!\)\@!" display' exe 'syn match markoTagName' . s:class_suffix - \ . ' "\%(</\)\@2<=\%(' . s:name_pattern . '\)\%(\k\|[$:]\)\@!\s*"' + \ . ' "\%#=1\%(</\)\@2<=\%(' . s:name_pattern . '\)\%(\k\|[$:]\)\@!\s*"' \ . ' nextgroup=markoCloseGt display' endfor unlet s:tag_name_classes s:class_suffix s:name_pattern -" The includes install their own sync rules; clear them and restate the -" keyword characters ("syn sync clear" clears "syn iskeyword" too). "-" -" keeps css.vim's hyphenated value keywords whole: -" font-family: sans-serif -" fromstart is the only safe strategy, since element bodies, concise -" regions and style/script bodies are all unbounded or line-anchored; a -" cold parse of a 5000 line file stays well under a second on current -" hardware. +" The includes install sync rules; clear them and restate the keyword set +" ("syn sync clear" clears "syn iskeyword" too; "-" keeps css.vim's +" font-family whole). fromstart is the only safe strategy -- bodies and +" blocks are unbounded -- and a 5000-line cold parse stays well under a +" second. syn sync clear syn sync fromstart syn iskeyword @,48-57,_,192-255,- +" Scoping regions (tags, bodies, brackets, values) take no link: they +" bound contents that carry their own colors. hi def link markoComment Comment hi def link markoTagComment Comment +hi def link markoHtmlComment Comment hi def link markoHtmlCommentTag Comment hi def link markoDeclaration PreProc hi def link markoCData String @@ -355,8 +548,11 @@ hi def link markoScriptletDelim Special hi def link markoBlockDelim Special hi def link markoTagDelim Special hi def link markoTagName Statement +hi def link markoTagNameTail Statement hi def link markoCloseName Statement +hi def link markoCloseTail Statement hi def link markoCloseGt Special +hi def link markoCloseAnon Special hi def link markoAttrTagName Identifier hi def link markoTagNameConditional Conditional hi def link markoTagNameRepeat Repeat @@ -365,6 +561,8 @@ hi def link markoTagNameStatement Statement hi def link markoTagNameBuiltin Macro hi def link markoShorthandId Constant hi def link markoShorthandClass Identifier +hi def link markoStyleDelim Special +hi def link markoScriptDelim Special hi def link markoTagVar Identifier hi def link markoAttrName Type hi def link markoString String diff --git a/runtime/syntax/testdir/dumps/marko_00.dump b/runtime/syntax/testdir/dumps/marko_00.dump index becbe3883..7ad248d2e 100644 --- a/runtime/syntax/testdir/dumps/marko_00.dump +++ b/runtime/syntax/testdir/dumps/marko_00.dump @@ -3,18 +3,18 @@ |i+0#af5f00255&|m|p|o|r|t| +0#0000000&|{+0#00e0e07&| +0#0000000&|f|o|r|m|a|t|P|r|i|c|e| |}+0#00e0e07&| +0#0000000&|f+0#af5f00255&|r|o|m| +0#0000000&|"+0#e000002&|.|/|u|t|i|l|"| +0#0000000&@38 |s+0#af5f00255&|t|a|t|i|c| +0#0000000&|c+0#af5f00255&|o|n|s|t| +0#0000000&|V|E|R|S|I|O|N| |=| |1+0#e000002&| +0#0000000&@50 @75 -|<+0#e000e06&|s|t|y|l|e|>| +0#0000000&@67 +|<+0#e000e06&|s|t|y|l|e|/+0#00e0e07&|s|t|y|l|e|s|>+0#e000e06&| +0#0000000&@60 @2|.+0#00e0e07&|p|r|i|c|e| +0#0000000&|{+0#00e0e07&| +0#0000000&|c+0#00e0003&|o|l|o|r|:+0#0000000&| |g+0#e000002&|r|e@1|n| +0#0000000&|}+0#00e0e07&| +0#0000000&@49 |<+0#e000e06&|/|s|t|y|l|e|>| +0#0000000&@66 -@75 |<+0#e000e06&|l|e|t|/+0#00e0e07&|c|o|u|n|t|=+0#af5f00255&|1+0#e000002&|/+0#e000e06&|>| +0#0000000&@60 -|<+0#e000e06&|c|o|n|s|t|/+0#00e0e07&|{+0#e000e06&| +0#0000000&|i|t|e|m|s| |}+0#e000e06&|=+0#af5f00255&|i+0#0000000&|n|p|u|t|/+0#e000e06&|>| +0#0000000&@50 -@75 -|<+0#e000e06&|d+0#af5f00255&|i|v|.+0#00e0e07&|c|a|r|d|#+0#e000002&|m|a|i|n| +0#0000000&|c+0#00e0003&|l|a|s@1|=+0#af5f00255&|"+0#e000002&|c|a|r|t|"| +0#0000000&|d+0#00e0003&|a|t|a|-|t|o|t|a|l|:+0#af5f00255&|=|t+0#0000000&|o|t|a|l| |.+0#af5f00255&@2|r+0#00e0003&|e|s|t|>+0#e000e06&| +0#0000000&@20 -@2|<+0#e000e06&|i+0#af5f00255&|f|=|c+0#0000000&|o|u|n|t|>+0#e000e06&| +0#0000000&@62 -@4|<+0#e000e06&|m+0#af5f00255&|y|-|b|u|t@1|o|n| +0#0000000&|s+0#00e0003&|i|z|e|=+0#af5f00255&|"+0#e000002&|l|a|r|g|e|"| +0#0000000&|o+0#00e0003&|n|C|l|i|c|k|=+0#af5f00255&|(+0#0000000&|)| |=+0#00e0003&|>| +0#0000000&|b|u|y|(|)|>+0#e000e06&|B+0#0000000&|u|y| |$+0#e000e06&|{|c+0#0000000&|o|u|n|t| |+| |1+0#e000002&|}+0#e000e06&|<|/|m+0#af5f00255&|y|-|b|u|t@1|o|n -|>+0#e000e06&| +0#0000000&@73 +|<+0#e000e06&|c|o|n|s|t|/+0#00e0e07&|[+0#e000e06&|w+0#0000000&|i|d|t|h|,| |,| |.@2|d|i|m|s|]+0#e000e06&|=+0#af5f00255&|b+0#0000000&|o|x|/+0#e000e06&|>| +0#0000000&@43 +|<+0#e000e06&|d+0#af5f00255&|i|v|.+0#00e0e07&|c|a|r|d|#+0#e000002&|m|a|i|n| +0#0000000&|c+0#00e0003&|l|a|s@1|=+0#af5f00255&|"+0#e000002&|c|a|r|t|"| +0#0000000&|t+0#00e0003&|o|t|a|l|:+0#af5f00255&|=|s+0#0000000&|u|m| |.+0#af5f00255&@2|r+0#0000000&|e|s|t| |.+0#af5f00255&@2|(+0#0000000&|a| |?| |b| |:| |c|)|>+0#e000e06&| +0#0000000&@12 +@2|<+0#e000e06&|i+0#af5f00255&|f|=|t+0#0000000&|a|g| |=@2| |"+0#e000002&|s|e|l|e|c|t|"| +0#0000000&||@1| |c|o|u|n|t| |>+0#e000e06&| +0#0000000&|0|>| @38 +@4|<+0#e000e06&|m+0#af5f00255&|y|-|b|u|t@1|o|n| +0#0000000&|s+0#00e0003&|i|z|e|=+0#af5f00255&|"+0#e000002&|l|g|"| +0#0000000&|o+0#00e0003&|n|C|l|i|c|k|=+0#af5f00255&|(+0#0000000&|e|)| |=+0#00e0003&|>| +0#0000000&|b|u|y|(|e+0#e000e06&|)+0#0000000&|>+0#e000e06&|$|{|c+0#0000000&|o|u|n|t| |+| |1+0#e000002&|}+0#e000e06&|<|/|m+0#af5f00255&|y|-|b|u|t@1|o|n|>+0#e000e06&| +0#0000000&@3 @2|<+0#e000e06&|/|i+0#af5f00255&|f|>+0#e000e06&| +0#0000000&@67 +@2|<+0#e000e06&|e+0#af5f00255&|l|s|e|-|i|f|=|f+0#0000000&|a|l@1|b|a|c|k| |?@1| |c|h|o|i|c|e|s|/+0#e000e06&|>| +0#0000000&@42 @2|<+0#e000e06&|f+0#af5f00255&|o|r||+0#e000e06&|i+0#0000000&|t|e|m|,| |i|n|d|e|x||+0#e000e06&| +0#0000000&|o+0#00e0003&|f|=+0#af5f00255&|i+0#0000000&|t|e|m|s|>+0#e000e06&| +0#0000000&@45 @4|<+0#e000e06&|s+0#af5f00255&|p|a|n|>+0#e000e06&|$|{|f+0#0000000&|o|r|m|a|t|P|r|i|c|e|(|i+0#e000e06&|t|e|m|.+0#0000000&|p+0#e000e06&|r|i|c|e|)+0#0000000&|}+0#e000e06&|<|/|s+0#af5f00255&|p|a|n|>+0#e000e06&| +0#0000000&@31 +@2|<+0#e000e06&|/|f+0#af5f00255&|o|r|>+0#e000e06&| +0#0000000&@66 +@2|<+0#e000e06&|g+0#af5f00255&|e|n|e|r|i|c|-|l|i|s|t|<+0#e000e06&|C+0#00e0e07&|o|n|f|i|g|<+0#e000e06&|s+0#00e0003&|t|r|i|n|g|>+0#e000e06&@1| +0#0000000&|a+0#00e0003&|=+0#af5f00255&|1+0#e000002&|/+0#e000e06&|>| +0#0000000&@37 @57|1|,|1| @10|T|o|p| diff --git a/runtime/syntax/testdir/dumps/marko_01.dump b/runtime/syntax/testdir/dumps/marko_01.dump index fc2493b8f..dbe0c74ee 100644 --- a/runtime/syntax/testdir/dumps/marko_01.dump +++ b/runtime/syntax/testdir/dumps/marko_01.dump @@ -1,20 +1,20 @@ -| +0&#ffffff0@1|<+0#e000e06&|i+0#af5f00255&|f|=|c+0#0000000&|o|u|n|t|>+0#e000e06&| +0#0000000&@62 -@4|<+0#e000e06&|m+0#af5f00255&|y|-|b|u|t@1|o|n| +0#0000000&|s+0#00e0003&|i|z|e|=+0#af5f00255&|"+0#e000002&|l|a|r|g|e|"| +0#0000000&|o+0#00e0003&|n|C|l|i|c|k|=+0#af5f00255&|(+0#0000000&|)| |=+0#00e0003&|>| +0#0000000&|b|u|y|(|)|>+0#e000e06&|B+0#0000000&|u|y| |$+0#e000e06&|{|c+0#0000000&|o|u|n|t| |+| |1+0#e000002&|}+0#e000e06&|<|/|m+0#af5f00255&|y|-|b|u|t@1|o|n -|>+0#e000e06&| +0#0000000&@73 -@2|<+0#e000e06&|/|i+0#af5f00255&|f|>+0#e000e06&| +0#0000000&@67 +| +0&#ffffff0@1|<+0#e000e06&|/|i+0#af5f00255&|f|>+0#e000e06&| +0#0000000&@67 +@2|<+0#e000e06&|e+0#af5f00255&|l|s|e|-|i|f|=|f+0#0000000&|a|l@1|b|a|c|k| |?@1| |c|h|o|i|c|e|s|/+0#e000e06&|>| +0#0000000&@42 @2|<+0#e000e06&|f+0#af5f00255&|o|r||+0#e000e06&|i+0#0000000&|t|e|m|,| |i|n|d|e|x||+0#e000e06&| +0#0000000&|o+0#00e0003&|f|=+0#af5f00255&|i+0#0000000&|t|e|m|s|>+0#e000e06&| +0#0000000&@45 -@4><+0#e000e06&|s+0#af5f00255&|p|a|n|>+0#e000e06&|$|{|f+0#0000000&|o|r|m|a|t|P|r|i|c|e|(|i+0#e000e06&|t|e|m|.+0#0000000&|p+0#e000e06&|r|i|c|e|)+0#0000000&|}+0#e000e06&|<|/|s+0#af5f00255&|p|a|n|>+0#e000e06&| +0#0000000&@31 +@4|<+0#e000e06&|s+0#af5f00255&|p|a|n|>+0#e000e06&|$|{|f+0#0000000&|o|r|m|a|t|P|r|i|c|e|(|i+0#e000e06&|t|e|m|.+0#0000000&|p+0#e000e06&|r|i|c|e|)+0#0000000&|}+0#e000e06&|<|/|s+0#af5f00255&|p|a|n|>+0#e000e06&| +0#0000000&@31 @2|<+0#e000e06&|/|f+0#af5f00255&|o|r|>+0#e000e06&| +0#0000000&@66 -@2|<+0#e000e06&|g+0#af5f00255&|e|n|e|r|i|c|-|l|i|s|t|<+0#e000e06&|s+0#0000000&|t|r|i|n|g|>+0#e000e06&| +0#0000000&|a+0#00e0003&|=+0#af5f00255&|1+0#e000002&|/+0#e000e06&|>| +0#0000000&@45 -@2|<+0#e000e06&|$|{|d+0#0000000&|y|n|a|m|i|c|T|a|g|}+0#e000e06&| +0#0000000&|t+0#00e0003&|i|t|l|e|=+0#af5f00255&|"+0#e000002&|d|y|n|a|m|i|c|"|>+0#e000e06&|b+0#0000000&|o|d|y|<+0#e000e06&|/|>+0#0000000&| @34 -@2|<+0#e000e06&|@+0#00e0e07&|f|o@1|t|e|r|>+0#e000e06&|s+0#0000000&|l|o|t| |c|o|n|t|e|n|t|<|/|@+0#af5f00255&|f|o@1|t|e|r|>+0#e000e06&| +0#0000000&@41 +@2><+0#e000e06&|g+0#af5f00255&|e|n|e|r|i|c|-|l|i|s|t|<+0#e000e06&|C+0#00e0e07&|o|n|f|i|g|<+0#e000e06&|s+0#00e0003&|t|r|i|n|g|>+0#e000e06&@1| +0#0000000&|a+0#00e0003&|=+0#af5f00255&|1+0#e000002&|/+0#e000e06&|>| +0#0000000&@37 +@2|<+0#e000e06&|$|{|d+0#0000000&|y|n|a|m|i|c|T|a|g|}+0#e000e06&| +0#0000000&|t+0#00e0003&|i|t|l|e|=+0#af5f00255&|"+0#e000002&|d|y|n|a|m|i|c|"|>+0#e000e06&|b+0#0000000&|o|d|y|<+0#e000e06&|/|$|{|d+0#0000000&|y|n|a|m|i|c|T|a|g|}+0#e000e06&|>| +0#0000000&@21 |<+0#e000e06&|/|d+0#af5f00255&|i|v|>+0#e000e06&| +0#0000000&@68 -@75 -|<+0#e000e06&|d+0#af5f00255&|i|v| +0#0000000&@70 -@2|c+0#00e0003&|l|a|s@1|=+0#af5f00255&|"+0#e000002&|m|u|l|t|i|l|i|n|e|"| +0#0000000&@55 -@2|d+0#00e0003&|a|t|a|-|x|=+0#af5f00255&|1+0#e000002&| +0#0000000&@64 -|>+0#e000e06&|t+0#0000000&|e|x|t| |w|i|t|h| |&+0#e000e06&|a|m|p|;| +0#0000000&|e|n|t|i|t|y| |a|n|d| |\+0#e000e06&|$|{|a+0#0000000&|n| |e|s|c|a|p|e|d| |p|l|a|c|e|h|o|l|d|e|r|}|<+0#e000e06&|/|d+0#af5f00255&|i|v|>+0#e000e06&| +0#0000000&@14 -@75 -|<+0#e000e06&|t|e|x|t|a|r|e|a| |r|o|w|s|=|3|>|l+0#0000000&|i|t|e|r|a|l| |<|b|>|t|e|x|t|<|/|b|>| |w|i|t|h| |$+0#e000e06&|{|c+0#0000000&|o|u|n|t|}+0#e000e06&|<|/|t|e|x|t|a|r|e|a|>| +0#0000000&@13 -|<+0#e000e06&|h|t|m|l|-|c|o|m@1|e|n|t|>|r+0#0000e05&|e|n|d|e|r|e|d| |<|i|>|c|o|m@1|e|n|t|<|/|i|>| |b|o|d|y|<+0#e000e06&|/|h|t|m|l|-|c|o|m@1|e|n|t|>| +0#0000000&@17 -@57|1|8|,|5| @9|7|6|%| +|<+0#e000e06&|l+0#af5f00255&|i|n|k| +0#0000000&@69 +@2|r+0#00e0003&|e|l|=+0#af5f00255&|"+0#e000002&|c|a|n|o|n|i|c|a|l|"| +0#0000000&@57 +@2|h+0#00e0003&|r|e|f|=+0#af5f00255&|t+0#0000000&|r|a|n|s|l|a|t|e|d| @57 +@4|?| |l|o|c|a|l|i|z|e|U|r|l|(|u+0#e000e06&|r|l|,| |{+0#00e0e07&| +0#0000000&|l+0#af5f00255&|o|c|a|l|e| |}+0#00e0e07&|)+0#0000000&|.|h+0#af5f00255&|r|e|f| +0#0000000&@35 +@4|:| |b|a|s|e|H|r|e|f| @60 +|>+0#e000e06&| +0#0000000&@73 +|<+0#e000e06&|a+0#af5f00255&|u|d|i|o|-|p|l|a|y|e|r| +0#0000000&|r+0#00e0003&|a|t|i|o|=+0#af5f00255&|t+0#0000000&|o|t|a|l| |/| |c|o|u|n|t| |v+0#00e0003&|o|l|u|m|e|=+0#af5f00255&|M+0#00e0003&|a|t|h|.+0#0000000&|m+0#af5f00255&|a|x|(+0#0000000&| @24 +| +0#e000e06&@1|0+0#e000002&|,+0#e000e06&| +0#0000000&@70 +| +0#e000e06&@1|s|e|t@1|i|n|g|s|.+0#0000000&|f+0#af5f00255&|i|n|d|I|n|d|e|x|(+0#0000000&@1|s+0#e000e06&|)+0#0000000&| |=+0#00e0003&|>| +0#e000e06&|s|.+0#0000000&|a+0#e000e06&|c|t|i|v|e|)+0#0000000&|,+0#e000e06&| +0#0000000&@36 +|)|/+0#e000e06&|>| +0#0000000&@71 +|<+0#e000e06&|h+0#af5f00255&|$+0#e000e06&|{|s+0#0000000&|i|z|e|}+0#e000e06&| +0#0000000&|i+0#00e0003&|d|:|s|c|o|p|e|d|>+0#e000e06&|h+0#0000000&|e|a|d|i|n|g|<+0#e000e06&|/|>| +0#0000000&@44 +@57|1|9|,|3| @9|4@1|%| diff --git a/runtime/syntax/testdir/dumps/marko_02.dump b/runtime/syntax/testdir/dumps/marko_02.dump index a9c90cd69..945a3cda5 100644 --- a/runtime/syntax/testdir/dumps/marko_02.dump +++ b/runtime/syntax/testdir/dumps/marko_02.dump @@ -1,20 +1,20 @@ -|<+0#e000e06#ffffff0|h|t|m|l|-|c|o|m@1|e|n|t|>|r+0#0000e05&|e|n|d|e|r|e|d| |<|i|>|c|o|m@1|e|n|t|<|/|i|>| |b|o|d|y|<+0#e000e06&|/|h|t|m|l|-|c|o|m@1|e|n|t|>| +0#0000000&@17 -@75 +|<+0#e000e06#ffffff0|h+0#af5f00255&|$+0#e000e06&|{|s+0#0000000&|i|z|e|}+0#e000e06&| +0#0000000&|i+0#00e0003&|d|:|s|c|o|p|e|d|>+0#e000e06&|h+0#0000000&|e|a|d|i|n|g|<+0#e000e06&|/|>| +0#0000000&@44 +|<+0#e000e06&|$|{|"+0#e000002&|h|e|l@1|o|"|}+0#e000e06&|-+0#af5f00255&|w|o|r|l|d|/+0#e000e06&|>| +0#0000000&@55 +|<+0#e000e06&|b+0#af5f00255&|a|d|g|e|#+0#e000002&|i|t|e|m|-|$+0#e000e06&|{|i+0#0000000&|d|}+0#e000e06&|.+0#00e0e07&|t|o|n|e|-|$+0#e000e06&|{|k+0#0000000&|i|n|d|}+0#e000e06&| +0#0000000&|c+0#00e0003&|a|f|é|=+0#af5f00255&|"+0#e000002&|f|a|ç|a|d|e|"| +0#0000000&|x+0#00e0003&|=+0#af5f00255&|`+0#e000002&|a|$+0#af5f00255&|{|`+0#e000002&|b| |$+0#af5f00255&|{|c+0#0000000&|}+0#af5f00255&|`+0#e000002&|}+0#af5f00255&|d+0#e000002&|`|/+0#e000e06&|>| +0#0000000&@10 +|<+0#e000e06&|f+0#af5f00255&|o|r|m| +0#0000000&|o+0#00e0003&|n|S|u|b|m|i|t|<+0#e000e06&|T+0#00e0e07&|>+0#e000e06&|(|e+0#0000000&|)+0#e000e06&| +0#0000000&|{+0#e000e06&| +0#0000000&|g|o|<|T|>|(|e|)| |}+0#e000e06&| +0#0000000&|a+0#00e0003&|c|t|i|o|n|(+0#e000e06&|a+0#0000000&|,| |b|)+0#e000e06&| +0#0000000&|m+0#00e0003&|s|g|=+0#af5f00255&|"+0#e000002&|s|a|y| |\+0#e000e06&|"|h+0#e000002&|i|\+0#e000e06&|"|"+0#e000002&|/+0#e000e06&|>| +0#0000000&@9 +|<+0#e000e06&|e|f@1|e|c|t|(|)| +0#0000000&|{+0#e000e06&| +0#0000000&|c|l|e|a|n|u|p|(|)| |}+0#e000e06&|>|b+0#0000000&|o|d|y| |p|r|o|s|e|<+0#e000e06&|/|e|f@1|e|c|t|>| +0#0000000&@31 +><+0#e000e06&|a+0#af5f00255&|w|a|i|t|(+0#e000e06&|p+0#0000000&|r|o|m|i|s|e|)+0#e000e06&|>| +0#0000000&@58 +@2|<+0#e000e06&|@+0#00e0e07&|t|h|e|n||+0#e000e06&|r+0#0000000&|e|s|u|l|t||+0#e000e06&|>|$|{|r+0#0000000&|e|s|u|l|t|}+0#e000e06&|<+0#0000000&|/|@+0#00e0e07&|t|h|e|n|>+0#e000e06&| +0#0000000&@40 +|<+0#e000e06&|/|a+0#af5f00255&|w|a|i|t|>+0#e000e06&| +0#0000000&@66 +|<+0#e000e06&|m|a|c|r|o| +0#0000000&|r+0#00e0003&|e|n|d|e|r|P|r|i|c|e||+0#e000e06&|a+0#0000000&|m|o|u|n|t||+0#e000e06&|>|$|{|f+0#0000000&|o|r|m|a|t|P|r|i|c|e|(|a+0#e000e06&|m|o|u|n|t|)+0#0000000&|}+0#e000e06&|<|/|m|a|c|r|o|>| +0#0000000&@17 +|<+0#e000e06&|d+0#af5f00255&|i|v| +0#0000000&@70 +@2|c+0#00e0003&|l|a|s@1|=+0#af5f00255&|"+0#e000002&|m|u|l|t|i|l|i|n|e|"| +0#0000000&@55 +@2|d+0#00e0003&|a|t|a|-|x|=+0#af5f00255&|1+0#e000002&| +0#0000000&@64 +|>+0#e000e06&|t+0#0000000&|e|x|t| |w|i|t|h| |&+0#e000e06&|a|m|p|;| +0#0000000&|e|n|t|i|t|y| |a|n|d| |\+0#e000e06&|$|{|a+0#0000000&|n| |e|s|c|a|p|e|d| |p|l|a|c|e|h|o|l|d|e|r|}|<+0#e000e06&|/|d+0#af5f00255&|i|v|>+0#e000e06&| +0#0000000&@14 +|<+0#e000e06&|t|e|x|t|a|r|e|a| +0#0000000&|r+0#00e0003&|o|w|s|=+0#af5f00255&|3+0#e000002&|>+0#e000e06&|l+0#0000000&|i|t|e|r|a|l| |<|b|>|t|e|x|t|<|/|b|>| |w|i|t|h| |$+0#e000e06&|{|c+0#0000000&|o|u|n|t|}+0#e000e06&|<|/|t|e|x|t|a|r|e|a|>| +0#0000000&@13 |<+0#e000e06&|s|c|r|i|p|t|>| +0#0000000&@66 @2|c+0#af5f00255&|o|n|s|t| +0#0000000&|e|l| |=| |d+0#00e0003&|o|c|u|m|e|n|t|.+0#0000000&|q+0#af5f00255&|u|e|r|y|S|e|l|e|c|t|o|r|(+0#0000000&|"+0#e000002&|.|p|r|i|c|e|"|)+0#0000000&|;| @28 -><+0#e000e06&|/|s|c|r|i|p|t|>| +0#0000000&@65 +|<+0#e000e06&|/|s|c|r|i|p|t|>| +0#0000000&@65 |~+0#4040ff13&| @73 |~| @73 -|~| @73 -|~| @73 -|~| @73 -|~| @73 -|~| @73 -|~| @73 -|~| @73 -|~| @73 -|~| @73 -|~| @73 -|~| @73 -|~| @73 -| +0#0000000&@56|3|5|,|1| @9|B|o|t| +| +0#0000000&@56|3|7|,|1| @9|B|o|t| diff --git a/runtime/syntax/testdir/dumps/marko_concise_00.dump b/runtime/syntax/testdir/dumps/marko_concise_00.dump index 3dcec6ce3..e3db1d6b5 100644 --- a/runtime/syntax/testdir/dumps/marko_concise_00.dump +++ b/runtime/syntax/testdir/dumps/marko_concise_00.dump @@ -1,20 +1,20 @@ ->/+0#0000e05#ffffff0@1| |c|o|n|c|i|s|e| |m|o|d|e|:| |c|u|s|t|o|m| |t|a|g|s|,| |b|u|i|l|t|i|n|s|,| |s|t|a|t|e|m|e|n|t|s|,| |s|c|r|i|p|t|l|e|t|s|,| |t|e|x|t| |b|l|o|c|k|s +>/+0#0000e05#ffffff0@1| |c|o|n|c|i|s|e| |m|o|d|e|:| |c|u|s|t|o|m| |t|a|g|s|,| |b|u|i|l|t|i|n|s|,| |s|t|a|t|e|m|e|n|t|s|,| |s|c|r|i|p|t|l|e|t|s|,| |b|l|o|c|k|s| +0#0000000&@4 |i+0#af5f00255&|m|p|o|r|t| +0#0000000&|{+0#00e0e07&| +0#0000000&|f|e|t|c|h|I|t|e|m|s| |}+0#00e0e07&| +0#0000000&|f+0#af5f00255&|r|o|m| +0#0000000&|"+0#e000002&|.|/|a|p|i|"| +0#0000000&@40 -@75 -|$+0#e000e06&| |c+0#af5f00255&|o|n|s|t| +0#0000000&|d|o|u|b|l|e|d| |=| |i|n|p|u|t|.|c+0#af5f00255&|o|u|n|t| +0#0000000&|*| |2+0#e000002&|;+0#0000000&| @40 -@75 -|l+0#e000e06&|e|t|/+0#00e0e07&|b|a|s|k|e|t|=+0#af5f00255&|[+0#0000000&|]| @61 -|l+0#e000e06&|e|t|<|n+0#0000000&|u|m|b|e|r|>+0#e000e06&|/+0#00e0e07&|t|y|p|e|d|=+0#af5f00255&|0+0#e000002&| +0#0000000&@55 -@75 -|c+0#af5f00255&|o|n|t|a|i|n|e|r| +0#0000000&|f+0#00e0003&|l|u|i|d| +0#0000000&@59 -@2|s+0#af5f00255&|e|c|t|i|o|n|-|h|e|a|d|i|n|g| +0#0000000&|a+0#00e0003&|s|=+0#af5f00255&|"+0#e000002&|h|2|"| +0#0000000&|-+0#e000e06&@1| +0#0000000&|E|v|e|r|y|t|h|i|n|g| |p|a|r|t|n|e|r|s|h|i|p|s| |n|e@1|d| @17 -@2|b+0#af5f00255&|e|n|t|o| +0#0000000&|c+0#00e0003&|o|l|s|=+0#af5f00255&|4+0#e000002&| +0#0000000&@60 -@4|b+0#af5f00255&|e|n|t|o|-|c|e|l@1| +0#0000000&|[+0#e000e06&| +0#0000000&@58 -@6|f+0#00e0003&|e|a|t|u|r|e|d| +0#0000000&@60 -@6|c+0#00e0003&|o|l|S|p|a|n|=+0#af5f00255&|2+0#e000002&| +0#0000000&@59 -@6|t+0#00e0003&|i|t|l|e|=+0#af5f00255&|"+0#e000002&|O|n|e| |p|l|a|t|f|o|r|m|"| +0#0000000&@48 -@4|]+0#e000e06&| +0#0000000&@69 -@6|p+0#af5f00255&| +0#0000000&|-+0#e000e06&@1| +0#0000000&|O|n|b|o|a|r|d|i|n|g| |a|n|d| |e|n|a|b|l|e|m|e|n|t|,| |u|n|i|f|i|e|d|.| @28 -@75 -|i+0#af5f00255&|f|=|i+0#0000000&|n|p|u|t|.|r+0#af5f00255&|e|a|d|y| +0#0000000&@60 +|$+0#e000e06&| |c+0#af5f00255&|o|n|s|t| +0#0000000&|p|e|r|s|o|n| |=| |{+0#00e0e07&| +0#0000000&@56 +@2|n+0#af5f00255&|a|m|e|:+0#0000000&| |"+0#e000002&|F|r|a|n|k|"|,+0#0000000&| @58 +|}+0#00e0e07&| +0#0000000&@73 +|l+0#e000e06&|e|t|/+0#00e0e07&|[+0#e000e06&|h+0#0000000&|,| |i|,| |,| |.@2|j|]+0#e000e06&|=+0#af5f00255&|[+0#0000000&|1+0#e000002&|,+0#0000000&| |2+0#e000002&|,+0#0000000&| |3+0#e000002&|,+0#0000000&| |4+0#e000002&|,+0#0000000&| |5+0#e000002&|]+0#0000000&| |a+0#e000e06&|s| +0#0000000&|c+0#00e0e07&|o|n|s|t| +0#0000000&@31 +|c+0#e000e06&|o|n|s|t|/+0#00e0e07&|i|s|L|o|c|a|l|i|z|e|d|=+0#af5f00255&|l+0#0000000&|o|c|a|l|e| |!|=@1| |b|a|s|e|L|o|c|a|l|e| @35 +|c+0#e000e06&|o|n|s|t|/+0#00e0e07&|n|o|d|e|s|=+0#af5f00255&|i+0#0000000&|n|p|u|t|.|n|o|d|e|s| |?@1| @48 +|(|t+0#af5f00255&|y|p|e|o|f| +0#0000000&|p|a|r|t|s| |=@2| |"+0#e000002&|f|u|n|c|t|i|o|n|"| +0#0000000&@46 +@2|?| |b|u|i|l|d|N|o|d|e|s|(|p+0#e000e06&|a|r|t|s|(+0#0000000&|i+0#e000e06&|n|p|u|t|.+0#0000000&|i+0#e000e06&|n|p|u|t|s|)+0#0000000&@1| @39 +@2|:| |u+0#e000002&|n|d|e|f|i|n|e|d|)+0#0000000&| @60 +|b+0#af5f00255&|e|n|t|o|-|c|e|l@1| +0#0000000&|[+0#e000e06&| +0#0000000&@62 +@2|f+0#00e0003&|e|a|t|u|r|e|d| +0#0000000&@64 +@2|c+0#00e0003&|o|l|S|p|a|n|=+0#af5f00255&|2+0#e000002&| +0#0000000&@63 +@2|t+0#00e0003&|i|t|l|e|=+0#af5f00255&|h+0#0000000&|e|a|d|.|t+0#af5f00255&|i|t|l|e| +0#0000000&|?@1| |"+0#e000002&|O|n|e| |p|l|a|t|f|o|r|m|"| +0#0000000&@38 +|]+0#e000e06&| +0#0000000&@73 +|l+0#af5f00255&|i|n|k| +0#0000000&@70 +@2|,|r+0#00e0003&|e|l|=+0#af5f00255&|"+0#e000002&|a|l|t|e|r|n|a|t|e|"| +0#0000000&@56 +@2|/+0#0000e05&@1| |a| |c|o|m@1|e|n|t| |m|a|y| |s|i|t| |b|e|t|w|e@1|n| |c|o|n|t|i|n|u|e|d| |a|t@1|r|i|b|u|t|e|s| +0#0000000&@23 @57|1|,|1| @10|T|o|p| diff --git a/runtime/syntax/testdir/dumps/marko_concise_01.dump b/runtime/syntax/testdir/dumps/marko_concise_01.dump index fb80cfb9f..c64e36b1c 100644 --- a/runtime/syntax/testdir/dumps/marko_concise_01.dump +++ b/runtime/syntax/testdir/dumps/marko_concise_01.dump @@ -1,20 +1,20 @@ -| +0&#ffffff0@5|c+0#00e0003&|o|l|S|p|a|n|=+0#af5f00255&|2+0#e000002&| +0#0000000&@59 -@6|t+0#00e0003&|i|t|l|e|=+0#af5f00255&|"+0#e000002&|O|n|e| |p|l|a|t|f|o|r|m|"| +0#0000000&@48 -@4|]+0#e000e06&| +0#0000000&@69 -@6|p+0#af5f00255&| +0#0000000&|-+0#e000e06&@1| +0#0000000&|O|n|b|o|a|r|d|i|n|g| |a|n|d| |e|n|a|b|l|e|m|e|n|t|,| |u|n|i|f|i|e|d|.| @28 -@75 ->i+0#af5f00255&|f|=|i+0#0000000&|n|p|u|t|.|r+0#af5f00255&|e|a|d|y| +0#0000000&@60 +| +0&#ffffff0@1|c+0#00e0003&|o|l|S|p|a|n|=+0#af5f00255&|2+0#e000002&| +0#0000000&@63 +@2|t+0#00e0003&|i|t|l|e|=+0#af5f00255&|h+0#0000000&|e|a|d|.|t+0#af5f00255&|i|t|l|e| +0#0000000&|?@1| |"+0#e000002&|O|n|e| |p|l|a|t|f|o|r|m|"| +0#0000000&@38 +|]+0#e000e06&| +0#0000000&@73 +|l+0#af5f00255&|i|n|k| +0#0000000&@70 +@2|,|r+0#00e0003&|e|l|=+0#af5f00255&|"+0#e000002&|a|l|t|e|r|n|a|t|e|"| +0#0000000&@56 +@2>/+0#0000e05&@1| |a| |c|o|m@1|e|n|t| |m|a|y| |s|i|t| |b|e|t|w|e@1|n| |c|o|n|t|i|n|u|e|d| |a|t@1|r|i|b|u|t|e|s| +0#0000000&@23 +@2|,|h+0#00e0003&|r|e|f|=+0#af5f00255&|(+0#0000000&| @65 +@4|t|r|a|n|s|l|a|t|e|d| |?| |l|o|c|a|l|i|z|e|U|r|l|(|u+0#e000e06&|r|l|,| |{+0#00e0e07&| +0#0000000&|l+0#af5f00255&|o|c|a|l|e| |}+0#00e0e07&|)+0#0000000&|.|h+0#af5f00255&|r|e|f| +0#0000000&|:| |b|a|s|e|H|r|e|f| @13 +@2|)| @71 +@2|,|o+0#00e0003&|n|L|o|a|d|(+0#e000e06&|e+0#0000000&|)+0#e000e06&| +0#0000000&|{+0#e000e06&| +0#0000000&@60 +@4|r|e|a|d|y| |=| |t+0#e000002&|r|u|e|;+0#0000000&| @57 +@2|}+0#e000e06&| +0#0000000&@71 +|i+0#af5f00255&|n|p|u|t| +0#0000000&|t+0#00e0003&|y|p|e|=+0#af5f00255&|"+0#e000002&|t|e|x|t|"|,+0#0000000&| @56 +@2|v+0#00e0003&|a|l|u|e|=+0#af5f00255&|n+0#00e0003&|a|m|e| +0#0000000&|c+0#00e0003&|h|e|c|k|e|d|:+0#af5f00255&|=|m+0#0000000&|o|d|e| |=@2| |"+0#e000002&|e|d|i|t|"| +0#0000000&@37 +|i+0#af5f00255&|f|=|i+0#0000000&|n|p|u|t|.|r+0#af5f00255&|e|a|d|y| +0#0000000&@60 @2|f+0#af5f00255&|o|r||+0#e000e06&|i+0#0000000&|t|e|m|,| |i||+0#e000e06&| +0#0000000&|o+0#00e0003&|f|=+0#af5f00255&|f+0#0000000&|e|t|c|h|I|t|e|m|s|(|)| @44 -@4|l+0#e000e06&|o|g| +0#0000000&|"+0#e000002&|i|t|e|m| |l|o|a|d|e|d|"| +0#0000000&@53 -@4|-+0#e000e06&@1| +0#0000000&|P|r|i|c|e|:| |$+0#e000e06&|{|i+0#0000000&|t|e|m|.|p|r|i|c|e|}+0#e000e06&| +0#0000000&@47 -@2|w+0#af5f00255&|h|i|l|e|(+0#e000e06&|i+0#0000000&|<|1+0#e000002&|0|)+0#e000e06&| +0#0000000&@61 -@4|-+0#e000e06&@1| +0#0000000&|c|o|u|n|t|i|n|g| @59 -|t+0#af5f00255&|r|y| +0#0000000&@71 -@2|a+0#af5f00255&|w|a|i|t|(+0#e000e06&|p+0#0000000&|r|o|m|i|s|e|)+0#e000e06&| +0#0000000&@58 -|e+0#af5f00255&|l|s|e| +0#0000000&@70 -@2|r+0#af5f00255&|e|t|u|r|n|=|n+0#e000002&|u|l@1| +0#0000000&@61 -|@+0#00e0e07&|t|h|e|n||+0#e000e06&|r+0#0000000&|e|s|u|l|t||+0#e000e06&| +0#0000000&@61 -@2|-+0#e000e06&@1| +0#0000000&|r|e|s|o|l|v|e|d| @61 -@75 -|s+0#e000e06&|t|y|l|e|.|s|c|s@1| |{| +0#0000000&@62 -@57|1|9|,|1| @9|5|4|%| +@2|w+0#af5f00255&|h|i|l|e|(+0#e000e06&|i+0#0000000&| |<| |1+0#e000002&|0|)+0#e000e06&| +0#0000000&@59 +@4|m+0#af5f00255&|y|-|t|a|g| +0#0000000&|.+0#af5f00255&@2|[+0#0000000&|1+0#e000002&|,+0#0000000&| |2+0#e000002&|]+0#0000000&| |.+0#af5f00255&@2|r+0#0000000&|e|s|t| |t+0#00e0003&|o|t|a|l|=+0#af5f00255&|b+0#0000000&|a|s|e| |+| @33 +@6|t|a|x| @65 +@57|1|9|,|3| @9|4@1|%| diff --git a/runtime/syntax/testdir/dumps/marko_concise_02.dump b/runtime/syntax/testdir/dumps/marko_concise_02.dump index 2c1356382..899864c3b 100644 --- a/runtime/syntax/testdir/dumps/marko_concise_02.dump +++ b/runtime/syntax/testdir/dumps/marko_concise_02.dump @@ -1,20 +1,20 @@ -|s+0#e000e06#ffffff0|t|y|l|e|.|s|c|s@1| |{| +0#0000000&@62 +| +0&#ffffff0@5|t|a|x| @65 +@2|a+0#af5f00255&|w|a|i|t|(+0#e000e06&|p+0#0000000&|r|o|m|i|s|e|)+0#e000e06&| +0#0000000&@58 +@2|r+0#af5f00255&|e|t|u|r|n|=|x+0#0000000&| |i+0#af5f00255&|n|s|t|a|n|c|e|o|f| +0#0000000&|B| @51 +|@+0#00e0e07&|t|h|e|n||+0#e000e06&|r+0#0000000&|e|s|u|l|t||+0#e000e06&| +0#0000000&|-+0#e000e06&@1| +0#0000000&|r|e|s|o|l|v|e|d| @49 +|$+0#e000e06&|{|`+0#e000002&|b|u|t@1|o|n|`|}+0#e000e06&| +0#0000000&|t+0#00e0003&|y|p|e|=+0#af5f00255&|"+0#e000002&|b|u|t@1|o|n|"| +0#0000000&|c+0#00e0003&|l|a|s@1|=+0#af5f00255&|s+0#0000000&|t|y|l|e|s|.|b|u|t@1|o|n| |-+0#e000e06&@1| +0#0000000&|P|r|e|s@1| |m|e| @17 +>h+0#af5f00255&|$+0#e000e06&|{|s+0#0000000&|i|z|e|}+0#e000e06&| +0#0000000&|-+0#e000e06&@1| +0#0000000&|D|y|n|a|m|i|c| |h|e|a|d|i|n|g| @47 +|.+0#00e0e07&|h|e|r|o|-|c|o|p|y|#+0#e000002&|m|a|i|n|/+0#00e0e07&|$|e|l| +0#0000000&|-+0#e000e06&@1| +0#0000000&|S|h|o|r|t|h|a|n|d| |t|a|g| @38 +|s+0#e000e06&|t|y|l|e|/+0#00e0e07&|s|t|y|l|e|s| +0#0000000&|-+0#e000e06&@1| +0#0000000&@59 @2|.+0#00e0e07&|b|a|s|k|e|t| +0#0000000&|{+0#00e0e07&| +0#0000000&|c+0#00e0003&|o|l|o|r|:+0#0000000&| |r+0#e000002&|e|d| +0#0000000&|}+0#00e0e07&| +0#0000000&@50 -|}+0#e000e06&| +0#0000000&@73 -@75 +| +0#e000e06&@1|-@1| +0#0000000&@70 +|p+0#af5f00255&| +0#0000000&|-+0#e000e06&@1| +0#0000000&@70 +@2|A|n| |i|n|d|e|n|t|e|d| |t|e|x|t| |b|l|o|c|k| |r|u|n|s| |u|n|t|i|l| |d|e|d|e|n|t|,| |w|i|t|h| |<+0#e000e06&|b+0#af5f00255&|>+0#e000e06&|h+0#0000000&|t|m|l|<+0#e000e06&|/|b+0#af5f00255&|>+0#e000e06&|.+0#0000000&| @13 +|p+0#af5f00255&| +0#0000000&|-+0#e000e06&@3| +0#0000000&|t|e|x|t| |a|f|t|e|r| |a| |l|o|n|g|e|r| |d|a|s|h| |r|u|n| @39 |-+0#e000e06&@1| +0#0000000&@72 ->A| |d|e|l|i|m|i|t|e|d| |b|l|o|c|k| |i|s| |h|t|m|l| |m|o|d|e|,| |s|o| |b|a|r|e| |w|o|r|d|s| |a|r|e| |p|r|o|s|e|.| @18 -|<+0#e000e06&|b+0#af5f00255&|>+0#e000e06&|b+0#0000000&|o|l|d| |$+0#e000e06&|{|d+0#0000000&|o|u|b|l|e|d|}+0#e000e06&|<|/|b+0#af5f00255&|>+0#e000e06&| +0#0000000&@52 +|A| |d|e|l|i|m|i|t|e|d| |b|l|o|c|k| |i|s| |h|t|m|l| |m|o|d|e|:| |<+0#e000e06&|b+0#af5f00255&|>+0#e000e06&|b+0#0000000&|o|l|d| |$+0#e000e06&|{|p+0#0000000&|e|r|s|o|n|.|n+0#af5f00255&|a|m|e|}+0#e000e06&|<|/|b+0#af5f00255&|>+0#e000e06&| +0#0000000&|a|n|d| |b|a|r|e| |p|r|o|s|e|.| |-+0#e000e06&@1| +0#0000000&@72 -@75 -|<+0#e000e06&|f+0#af5f00255&|o@1|t|e|r|>+0#e000e06&| +0#0000000&@66 -|i|f| |y|o|u| |r|e|a|d| |t|h|i|s| |i|n|s|i|d|e| |a|n| |e|l|e|m|e|n|t| |b|o|d|y|,| |i|t| |s|t|a|y|s| |p|l|a|i|n| |p|r|o|s|e| @13 -|<+0#e000e06&|/|f+0#af5f00255&|o@1|t|e|r|>+0#e000e06&| +0#0000000&@65 +|<+0#e000e06&|f+0#af5f00255&|o@1|t|e|r|>+0#e000e06&|e+0#0000000&|l|e|m|e|n|t| |b|o|d|i|e|s| |s|t|a|y| |h|t|m|l| |m|o|d|e|,| |s|o| |t|h|i|s| |i|s| |p|l|a|i|n| |p|r|o|s|e|<+0#e000e06&|/|f+0#af5f00255&|o@1|t|e|r|>+0#e000e06&| +0#0000000&@4 |~+0#4040ff13&| @73 |~| @73 -|~| @73 -|~| @73 -|~| @73 -|~| @73 -|~| @73 | +0#0000000&@56|3|7|,|1| @9|B|o|t| diff --git a/runtime/syntax/testdir/input/marko.marko b/runtime/syntax/testdir/input/marko.marko index 1281ce0bd..1be6727df 100644 --- a/runtime/syntax/testdir/input/marko.marko +++ b/runtime/syntax/testdir/input/marko.marko @@ -3,33 +3,46 @@ import { formatPrice } from "./util" static const VERSION = 1 -<style> +<style/styles> .price { color: green } </style> - <let/count=1/> -<const/{ items }=input/> - -<div.card#main class="cart" data-total:=total ...rest> - <if=count> - <my-button size="large" onClick=() => buy()>Buy ${count + 1}</my-button> +<const/[width, , ...dims]=box/> +<div.card#main class="cart" total:=sum ...rest ...(a ? b : c)> + <if=tag === "select" || count > 0> + <my-button size="lg" onClick=(e) => buy(e)>${count + 1}</my-button> </if> + <else-if=fallback ?? choices/> <for|item, index| of=items> <span>${formatPrice(item.price)}</span> </for> - <generic-list<string> a=1/> - <${dynamicTag} title="dynamic">body</> - <@footer>slot content</@footer> + <generic-list<Config<string>> a=1/> + <${dynamicTag} title="dynamic">body</${dynamicTag}> </div> - +<link + rel="canonical" + href=translated + ? localizeUrl(url, { locale }).href + : baseHref +> +<audio-player ratio=total / count volume=Math.max( + 0, + settings.findIndex((s) => s.active), +)/> +<h${size} id:scoped>heading</> +<${"hello"}-world/> +<badge#item-${id}.tone-${kind} café="façade" x=`a${`b ${c}`}d`/> +<form onSubmit<T>(e) { go<T>(e) } action(a, b) msg="say \"hi\""/> +<effect() { cleanup() }>body prose</effect> +<await(promise)> + <@then|result|>${result}</@then> +</await> +<macro renderPrice|amount|>${formatPrice(amount)}</macro> <div class="multiline" data-x=1 >text with & entity and \${an escaped placeholder}</div> - <textarea rows=3>literal <b>text</b> with ${count}</textarea> -<html-comment>rendered <i>comment</i> body</html-comment> - <script> const el = document.querySelector(".price"); </script> diff --git a/runtime/syntax/testdir/input/marko_concise.marko b/runtime/syntax/testdir/input/marko_concise.marko index d8994cb46..23987244f 100644 --- a/runtime/syntax/testdir/input/marko_concise.marko +++ b/runtime/syntax/testdir/input/marko_concise.marko @@ -1,43 +1,48 @@ -// concise mode: custom tags, builtins, statements, scriptlets, text blocks +// concise mode: custom tags, builtins, statements, scriptlets, blocks import { fetchItems } from "./api" - -$ const doubled = input.count * 2; - -let/basket=[] -let<number>/typed=0 - -container fluid - section-heading as="h2" -- Everything partnerships need - bento cols=4 - bento-cell [ - featured - colSpan=2 - title="One platform" - ] - p -- Onboarding and enablement, unified. - +$ const person = { + name: "Frank", +} +let/[h, i, , ...j]=[1, 2, 3, 4, 5] as const +const/isLocalized=locale !== baseLocale +const/nodes=input.nodes ?? +(typeof parts === "function" + ? buildNodes(parts(input.inputs)) + : undefined) +bento-cell [ + featured + colSpan=2 + title=head.title ?? "One platform" +] +link + ,rel="alternate" + // a comment may sit between continued attributes + ,href=( + translated ? localizeUrl(url, { locale }).href : baseHref + ) + ,onLoad(e) { + ready = true; + } +input type="text", + value=name checked:=mode === "edit" if=input.ready for|item, i| of=fetchItems() - log "item loaded" - -- Price: ${item.price} - while(i<10) - -- counting -try + while(i < 10) + my-tag ...[1, 2] ...rest total=base + + tax await(promise) -else - return=null -@then|result| - -- resolved - -style.scss { + return=x instanceof B +@then|result| -- resolved +${`button`} type="button" class=styles.button -- Press me +h${size} -- Dynamic heading +.hero-copy#main/$el -- Shorthand tag +style/styles -- .basket { color: red } -} - + -- +p -- + An indented text block runs until dedent, with <b>html</b>. +p ---- text after a longer dash run -- -A delimited block is html mode, so bare words are prose. -<b>bold ${doubled}</b> +A delimited block is html mode: <b>bold ${person.name}</b> and bare prose. -- - -<footer> -if you read this inside an element body, it stays plain prose -</footer> +<footer>element bodies stay html mode, so this is plain prose</footer> -- -- You received this message from the "vim_dev" maillist. Do not top-post! Type your reply below the text you are replying to. For more information, visit http://www.vim.org/maillist.php --- You received this message because you are subscribed to the Google Groups "vim_dev" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion visit https://groups.google.com/d/msgid/vim_dev/E1wpVkg-004YWi-3D%40256bit.org.