From: Brian Carbone Date: Tue, 28 Jul 2026 19:03:49 +0000 (+0000) Subject: patch 9.2.0870: filetype: marko files are not recognized X-Git-Tag: v9.2.0870^0 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=95da62a910809787cc8fdf26b131721359812d8f;p=thirdparty%2Fvim.git patch 9.2.0870: filetype: marko files are not recognized Problem: filetype: marko files are not recognized Solution: Detect *.marko files as marko filetype, include a syntax plugin and add syntax tests (Brian Carbone) References: https://markojs.com https://github.com/marko-js/tree-sitter https://github.com/marko-js/language-server https://v5.markojs.com/docs/editor-plugins/ closes: #20863 Signed-off-by: Brian Carbone Signed-off-by: Christian Brabandt --- diff --git a/.github/MAINTAINERS b/.github/MAINTAINERS index ea76824880..44ccadf6b4 100644 --- a/.github/MAINTAINERS +++ b/.github/MAINTAINERS @@ -629,6 +629,7 @@ runtime/syntax/m3quake.vim @dkearns runtime/syntax/mailcap.vim @dkearns runtime/syntax/mallard.vim @jhradilek runtime/syntax/markdown.vim @tpope +runtime/syntax/marko.vim @briancarbone runtime/syntax/mason.vim @petdance runtime/syntax/mbsync.vim @fymyte runtime/syntax/mediawiki.vim @avidseeker diff --git a/runtime/autoload/dist/ft.vim b/runtime/autoload/dist/ft.vim index 7ed41785f9..0d1e7119ce 100644 --- a/runtime/autoload/dist/ft.vim +++ b/runtime/autoload/dist/ft.vim @@ -3,7 +3,7 @@ vim9script # Vim functions for file type detection # # Maintainer: The Vim Project -# Last Change: 2026 Jul 27 +# Last Change: 2026 Jul 28 # Former Maintainer: Bram Moolenaar # These functions are moved here from runtime/filetype.vim to make startup @@ -2416,6 +2416,8 @@ const ft_from_ext = { "page": "mallard", # Manpage "man": "man", + # Marko + "marko": "marko", # Maple V "mv": "maple", "mpl": "maple", diff --git a/runtime/syntax/marko.vim b/runtime/syntax/marko.vim new file mode 100644 index 0000000000..be589534c3 --- /dev/null +++ b/runtime/syntax/marko.vim @@ -0,0 +1,382 @@ +" Vim syntax file +" Language: Marko +" Maintainer: Brian Carbone +" URL: https://markojs.com +" Filenames: *.marko +" Last Change: 2026 Jul 28 + +" 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: +"

if you want, stop by

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. + +if !exists("main_syntax") + if exists("b:current_syntax") + finish + endif + let main_syntax = "marko" +endif + +let s:cpo_save = &cpo +set cpo&vim + +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. +let s:iskeyword_save = &l:iskeyword +syn include @markoTS syntax/typescript.vim +unlet! b:current_syntax +syn include @markoCSS syntax/css.vim +unlet! b:current_syntax +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: +"
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. +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: +" 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. +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 */ https://example.com +syn region markoComment start="" contains=@Spell fold +syn match markoComment "^\s*//.*$" contains=@Spell display +syn region markoComment start="^\s*/\*" end="\*/" contains=@Spell fold +syn region markoTagComment contained start="/\*" end="\*/" +syn match markoTagComment contained "//.*" + +syn region markoCData start="" +" Declarations; "" may close with ">" or "?>": +" +syn region markoDeclaration start="" +syn region markoDeclaration start="" + +" Placeholders interpolate into text, and 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 "\%(\\\\\)*\\\$!\={" +syn region markoPlaceholder matchgroup=markoPlaceholderDelim + \ start="\$!\={" end="}" + \ contains=@markoExpr containedin=cssDefinition,cssAttrRegion extend + +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 +syn region markoScriptlet matchgroup=markoScriptletDelim + \ start="^\s*\$\s\+{\@!" end="$" + \ contains=@markoExpr keepend +syn region markoScriptlet matchgroup=markoScriptletDelim + \ start="^\s*\$\s\+{" end="};\=" + \ contains=@markoExpr + +" "--" marks one line of text in concise mode: +" 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 +syn match markoSpread contained "\.\.\." display +syn region markoAttrValue contained matchgroup=markoOperator + \ start=":\==>\@!\s*" end="\ze\%(\%(=>\)\@2\)\@!\|=\@1\|/>\)" end="$" + \ contains=@markoExpr +syn region markoString contained start=+\z(["']\)+ skip=+\\\z1+ end=+\z1+ contains=@Spell + +" Shorthands after the tag name: +" +syn match markoShorthandId contained "#[-[:alnum:]_$]\+" display +syn match markoShorthandClass contained "\.[-[:alnum:]_$]\+" display + +" Tag variables, arguments, |parameters|, and attribute method +" shorthand bodies: +" +" >
+" No body opens for html voids, parsed-text tags, bodiless core tags +" ( 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. +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\|[$:]\)\@!\)\@!' + \ . '\z(\%(\k\|[$:]\)\+\)\%(\_s\|[/>|(<.#=]\)\@=' . s:tag_end_ahead . '+' + \ . ' matchgroup=markoTagDelim' + \ . ' end="" end=""' + \ . ' contains=@markoHtmlContent' +exe 'syn region markoDynamicBody' + \ . ' start=+<\ze\%(\$!\={\)\@=' . s:tag_end_ahead . '+' + \ . ' matchgroup=markoTagDelim' + \ . ' end=""' + \ . ' contains=@markoHtmlContent' +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: +" -- +" A block of text, html mode. +" -- +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*$" + \ 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 +" keepend stops an unterminated embedded construct at the close tag. +syn region markoStyle matchgroup=markoTagNameBuiltin + \ start=+<\%(html-\)\=style\>\_[^>]\{-,300}/\@1+ + \ end="" + \ contains=@markoCSS,markoPlaceholder keepend fold +syn region markoStyle matchgroup=markoTagNameBuiltin + \ start="^\s*style\%([./][^ \t{]*\)\=\s*{" end="}" + \ contains=@markoCSS,markoPlaceholder fold +syn region markoScript matchgroup=markoTagNameBuiltin + \ start=+<\%(html-\)\=script\>\_[^>]\{-,300}/\@1+ + \ end="" + \ contains=@markoTS,markoPlaceholder keepend fold +syn region markoTextareaTag matchgroup=markoTagNameBuiltin + \ start=+\_[^>]\{-,300}/\@1+ + \ end="" + \ contains=markoPlaceholder,markoEntity,@Spell keepend +syn region markoHtmlCommentTag matchgroup=markoTagNameBuiltin + \ start=+\_[^>]\{-,300}/\@1+ + \ end="" + \ 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 "\%(<+0#e000e06#ffffff0|!|d|o|c|t|y|p|e| |h|t|m|l|>| +0#0000000&@59 +|<+0#0000e05&|!|-@1| |h|t|m|l| |m|o|d|e|:| |t|a|g|s|,| |a|t@1|r|i|b|u|t|e|s|,| |e|m|b|e|d@1|e|d| |l|a|n|g|u|a|g|e|s| |-@1|>| +0#0000000&@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 +@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 +@2|<+0#e000e06&|/|i+0#af5f00255&|f|>+0#e000e06&| +0#0000000&@67 +@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 +@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 new file mode 100644 index 0000000000..fc2493b8f4 --- /dev/null +++ b/runtime/syntax/testdir/dumps/marko_01.dump @@ -0,0 +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 +@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&|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 +|<+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|%| diff --git a/runtime/syntax/testdir/dumps/marko_02.dump b/runtime/syntax/testdir/dumps/marko_02.dump new file mode 100644 index 0000000000..a9c90cd698 --- /dev/null +++ b/runtime/syntax/testdir/dumps/marko_02.dump @@ -0,0 +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&|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#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| diff --git a/runtime/syntax/testdir/dumps/marko_concise_00.dump b/runtime/syntax/testdir/dumps/marko_concise_00.dump new file mode 100644 index 0000000000..3dcec6ce31 --- /dev/null +++ b/runtime/syntax/testdir/dumps/marko_concise_00.dump @@ -0,0 +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 +|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 +@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 new file mode 100644 index 0000000000..fb80cfb9f4 --- /dev/null +++ b/runtime/syntax/testdir/dumps/marko_concise_01.dump @@ -0,0 +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 +@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|%| diff --git a/runtime/syntax/testdir/dumps/marko_concise_02.dump b/runtime/syntax/testdir/dumps/marko_concise_02.dump new file mode 100644 index 0000000000..2c1356382e --- /dev/null +++ b/runtime/syntax/testdir/dumps/marko_concise_02.dump @@ -0,0 +1,20 @@ +|s+0#e000e06#ffffff0|t|y|l|e|.|s|c|s@1| |{| +0#0000000&@62 +@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| +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 +|-+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#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 new file mode 100644 index 0000000000..1281ce0bdc --- /dev/null +++ b/runtime/syntax/testdir/input/marko.marko @@ -0,0 +1,35 @@ + + +import { formatPrice } from "./util" +static const VERSION = 1 + + + + + + + + + buy()>Buy ${count + 1} + + + ${formatPrice(item.price)} + + a=1/> + <${dynamicTag} title="dynamic">body + <@footer>slot content + + +
text with & entity and \${an escaped placeholder}
+ + +rendered comment body + + diff --git a/runtime/syntax/testdir/input/marko_concise.marko b/runtime/syntax/testdir/input/marko_concise.marko new file mode 100644 index 0000000000..d8994cb46a --- /dev/null +++ b/runtime/syntax/testdir/input/marko_concise.marko @@ -0,0 +1,43 @@ +// concise mode: custom tags, builtins, statements, scriptlets, text blocks +import { fetchItems } from "./api" + +$ const doubled = input.count * 2; + +let/basket=[] +let/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. + +if=input.ready + for|item, i| of=fetchItems() + log "item loaded" + -- Price: ${item.price} + while(i<10) + -- counting +try + await(promise) +else + return=null +@then|result| + -- resolved + +style.scss { + .basket { color: red } +} + +-- +A delimited block is html mode, so bare words are prose. +bold ${doubled} +-- + +
+if you read this inside an element body, it stays plain prose +
diff --git a/src/testdir/test_filetype.vim b/src/testdir/test_filetype.vim index e98f308afb..9eff140299 100644 --- a/src/testdir/test_filetype.vim +++ b/src/testdir/test_filetype.vim @@ -505,6 +505,7 @@ def s:GetFilenameChecks(): dict> manconf: ['/etc/man.conf', 'man.config', 'any/etc/man.conf'], maple: ['file.mv', 'file.mpl', 'file.mws'], markdown: ['file.markdown', 'file.mdown', 'file.mkd', 'file.mkdn', 'file.mdwn', 'file.md'], + marko: ['file.marko'], masm: ['file.masm'], mason: ['file.mason', 'file.mhtml'], master: ['file.mas', 'file.master'], diff --git a/src/version.c b/src/version.c index 915e1c8e22..167dd49382 100644 --- a/src/version.c +++ b/src/version.c @@ -758,6 +758,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 870, /**/ 869, /**/