diff options
Diffstat (limited to 'syntax/cnm.vim')
-rw-r--r-- | syntax/cnm.vim | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/syntax/cnm.vim b/syntax/cnm.vim new file mode 100644 index 0000000..5d3fabf --- /dev/null +++ b/syntax/cnm.vim @@ -0,0 +1,151 @@ +" Vim syntax file +" Language: CNM 0.3 +" Maintainer: <clsr@clsr.net> +" Last Change: 2017-08-18 +" Version: 0.1.0 +" Filenames: *.cnm +" Bugs: Nested syntaxes in raw blocks include block indentation + +if !exists('g:main_syntax') + if exists('b:current_syntax') + finish + endif + let g:main_syntax = 'cnm' + + " sync from the current top-level element + syn sync match cnmSync grouphere NONE "^[^\t]" + "syn sync fromstart +endif + + +function! s:generateRawSyntaxes() + if !exists('g:cnm_raw_syntaxes') + "let g:cnm_raw_syntaxes = { + " \ 'text/json': 'json', + " \ 'application/json': 'json', + " \ 'json': 'json', + let g:cnm_raw_syntaxes = { + \ 'text/cnm': 'cnm', + \ 'cnm': 'cnm', + \ 'message/cnp': 'cnp', + \ 'application/cnp': 'cnp', + \ 'cnp': 'cnp', + \ 'text/cnm-fmt': 'cnmfmt', + \ 'cnm-fmt': 'cnmfmt', + \ 'cnmfmt': 'cnmfmt', + \ } + endif + if exists('g:cnm_raw_syntaxes_extra') + for [l:k, l:v] in items(g:cnm_raw_syntaxes_extra) + let g:cnm_raw_syntaxes[l:k] = l:v + endfor + endif + " CNM and CNMfmt syntaxes are already defined below as clusters + let l:syntaxes = {'Cnm': 1, 'Cnmfmt': 1} + for [l:lang, l:syntax] in items(g:cnm_raw_syntaxes) + let l:slang = substitute(l:syntax, '\(\w\+\)\W\?', '\u\1', 'g') + "try + if !has_key(l:syntaxes, l:slang) + exe 'syn include @cnmLang' . l:slang . ' syntax/' . l:syntax . '.vim' + unlet! b:current_syntax + let l:syntaxes[l:slang] = 1 + endif + call s:generateBlock('raw ' . l:lang, 'cnmRaws', 'contained contains=@cnmLang' . l:slang) + "catch + "endtry + endfor +endfunction + +function! s:generateBlock(name, cluster, options) + let l:region = 'cnm' . substitute(substitute(a:name, '\(\w\+\) \?', '\u\1', 'g'), '\W', '', 'g') + let l:name = substitute(a:name, ' ', '\\s\\+', 'g') + exe 'syn region ' . l:region . ' matchgroup=cnmBlock start="^\z(\t*\)\<' . l:name . '\(\s\|$\)\@=.*$" end="^\(\t*[^\t]\)\@=" skip="^\z1\t\+\([^\t]\)\@=" keepend ' . a:options + exe 'syn cluster ' . a:cluster . ' add=' . l:region +endfunction + + +syn include @cnmFmt syntax/cnmfmt.vim + + +" XXX: make `raw text/cnm` work +syn cluster cnmLangCnm contains=@cnmToplevelBLocks,@cnmContentBlocks,cnmError +" `raw text/cnm-fmt` +syn cluster cnmLangCnmfmt contains=@cnmFmt + +" all blocks that contain other blocks +syn cluster cnmToplevelBlocks contains=cnmUnknown +syn cluster cnmContainerBlocks contains=cnmUnknown +syn cluster cnmContentBlocks contains=cnmUnknown,@cnmContainerBlocks,@cnmTexts,@cnmRaws,cnmEmbed +syn cluster cnmTableBlocks contains=cnmUnknown + +" misc. +syn match cnmError ".*" +syn match cnmEscape "\\[nt\\ ]" contained +syn match cnmEscape "\\x\x\{2\}" contained +syn match cnmEscape "\\u\x\{4\}" contained +syn match cnmEscape "\\U\x\{8\}" contained + +" top-level blocks +syn region cnmUnknown matchgroup=cnmError start="^\z(\t*\)[^\t].*$" end="^\(\t*[^\t]\)\@=" skip="^\z1\t\+\([^\t]\)\@=" keepend contains=cnmError +call s:generateBlock('content', 'cnmToplevelBlocks', 'contains=@cnmContentBlocks') +call s:generateBlock('site', 'cnmToplevelBlocks', 'contains=cnmSiteLines,cnmError') +call s:generateBlock('title', 'cnmToplevelBlocks', 'contains=cnmEscape,@Spell') +call s:generateBlock('links', 'cnmToplevelBlocks', 'contains=cnmLinkLines') + +" content/ +call s:generateBlock('section', 'cnmContainerBlocks', 'contained contains=@cnmContentBlocks') +call s:generateBlock('table', 'cnmContainerBlocks', 'contained contains=@cnmTableBlocks') +call s:generateBlock('list', 'cnmContainerBlocks', 'contained contains=@cnmContentBlocks') + +" content/table/ +call s:generateBlock('header', 'cnmTableBlocks', 'contained contains=@cnmContentBlocks') +call s:generateBlock('row', 'cnmTableBlocks', 'contained contains=@cnmContentBlocks') + +" content/raw +call s:generateBlock('raw', 'cnmRaws', 'contained') +call s:generateRawSyntaxes() + +" content/text +call s:generateBlock('text', 'cnmTexts', 'contained contains=cnmEscape,@Spell') +call s:generateBlock('text plain', 'cnmTexts', 'contained contains=cnmEscape,@Spell') +call s:generateBlock('text fmt', 'cnmTexts', 'contained contains=@cnmFmt,@Spell') + +" content/embed +call s:generateBlock('embed', 'cnmEmbed', 'contained contains=cnmEscape,@Spell') + +" links/ +syn match cnmLinkLines "^.*$" keepend contained contains=cnmLinkUrl,cnmLinkText +syn match cnmLinkText "^\t\t.*" contained contains=cnmEscape +syn match cnmLinkUrl "\S\+" contained + +" site/ +syn match cnmSiteLines "^\t*[^\t ]\+\(\s.*\)\?$" keepend contained contains=cnmSitePath,cnmSiteText +syn match cnmSitePath "\S\+" contained contains=cnmSiteSlash +syn match cnmSiteText "\([^ \t]\)\@<=\s\+.*" contained contains=cnmEscape +syn match cnmSiteSlash "/\S\@=" contained + + +hi def link cnmBlock Keyword +hi def link cnmError Error +hi def link cnmLinkUrl Underlined +hi def link cnmLinkText String +hi def link cnmSitePath Underlined +hi def link cnmSiteSlash Keyword +hi def link cnmSiteText String +"hi def link cnmText String +hi def link cnmRaw String +hi def link cnmEmbed String +hi def link cnmTitle String +hi def link cnmEscape Special + +syn match TODO "TODO" contained containedin=cnmText,@cnmFmt +hi def link TODO TODO + + +let b:current_syntax = 'cnm' +if g:main_syntax ==# 'cnm' + unlet g:main_syntax +endif + + +" vim: set noet: |