From 193372dd54709926bdab588d5c665e07f0e5fff6 Mon Sep 17 00:00:00 2001 From: clsr Date: Fri, 18 Aug 2017 13:51:25 +0200 Subject: Initial commit --- ftdetect/cnm.vim | 1 + ftdetect/cnp.vim | 1 + ftplugin/cnm.vim | 29 +++++++++++ ftplugin/cnp.vim | 6 +++ syntax/cnm.vim | 151 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ syntax/cnmfmt.vim | 87 +++++++++++++++++++++++++++++++ syntax/cnp.vim | 113 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 388 insertions(+) create mode 100644 ftdetect/cnm.vim create mode 100644 ftdetect/cnp.vim create mode 100755 ftplugin/cnm.vim create mode 100755 ftplugin/cnp.vim create mode 100644 syntax/cnm.vim create mode 100644 syntax/cnmfmt.vim create mode 100644 syntax/cnp.vim diff --git a/ftdetect/cnm.vim b/ftdetect/cnm.vim new file mode 100644 index 0000000..3261022 --- /dev/null +++ b/ftdetect/cnm.vim @@ -0,0 +1 @@ +au BufNewFile,BufRead *.cnm setfiletype cnm diff --git a/ftdetect/cnp.vim b/ftdetect/cnp.vim new file mode 100644 index 0000000..33c95ea --- /dev/null +++ b/ftdetect/cnp.vim @@ -0,0 +1 @@ +au BufNewFile,BufRead *.cnp setfiletype cnp diff --git a/ftplugin/cnm.vim b/ftplugin/cnm.vim new file mode 100755 index 0000000..990c73a --- /dev/null +++ b/ftplugin/cnm.vim @@ -0,0 +1,29 @@ +" utf-8 with LF-only line terminators is the proper way to write text files +setlocal encoding=utf-8 +setlocal fileencodings=utf-8 +setlocal fileformat=unix + +" style stuff +setlocal tabstop=4 +setlocal softtabstop=4 +setlocal shiftwidth=4 + +" important! cnm requires the tab character to indent +setlocal noexpandtab +" match indents of the current line +setlocal autoindent + +" break lines at whitespace or symbol +setlocal linebreak +" match the indent of the current line when breaking lines +setlocal breakindent +" make line breaks obvious +setlocal showbreak=… + +" show tab indents and trailing spaces +setlocal list +setlocal list listchars=tab:\|\ ,trail:· +" in gray +"highlight SpecialKey ctermfg=8 +" for neovim +"highlight Whitespace ctermfg=8 diff --git a/ftplugin/cnp.vim b/ftplugin/cnp.vim new file mode 100755 index 0000000..0ef35d0 --- /dev/null +++ b/ftplugin/cnp.vim @@ -0,0 +1,6 @@ +" it's a binary protocol, but any would likely be encoded as utf-8 anyway +setlocal encoding=utf-8 +setlocal fileencodings=utf-8 + +" crlf is wrong +setlocal fileformat=unix 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: +" 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: diff --git a/syntax/cnmfmt.vim b/syntax/cnmfmt.vim new file mode 100644 index 0000000..8787f08 --- /dev/null +++ b/syntax/cnmfmt.vim @@ -0,0 +1,87 @@ +" Vim syntax file +" Language: CNMfmt (CNM 0.3) +" Maintainer: +" Last Change: 2017-08-18 +" Version: 0.1.0 +" Bugs: expects LIFO tags + +if !exists('g:main_syntax') + if exists('b:current_syntax') + finish + endif + let g:main_syntax = 'cnmfmt' +endif + +let s:fmts = { + \ 'B': {'tag': '\*', 'cterm': 'bold'}, + \ 'I': {'tag': '/', 'cterm': 'italic'}, + \ 'U': {'tag': '_', 'cterm': 'underline'}, + \ 'M': {'tag': '`', 'cterm': 'inverse'}, +\ } + +let s:fmtkeepend = 1 + +function! s:generateFmt(name) + let l:region = 'cnmfmt' . a:name + let l:cterm = 'cterm=' + let l:containedin = [] + let l:fmts = split(a:name, '\zs') + let l:tag = s:fmts[l:fmts[-1]]['tag'] + let l:tag2 = l:tag . l:tag + let l:containedin = '' + + for l:f in l:fmts + let l:cterm = l:cterm . s:fmts[l:f]['cterm'] . ',' + endfor + + if strlen(a:name) > 1 + let l:containedin = ' containedin=cnmfmt' . a:name[:-2] + endif + + " XXX: with keepend, URLs close too soon; without, tags don't close if not LIFO + exe 'syn region ' . l:region . ' start="' . l:tag2 . '" end="' . l:tag2 . '\|\n\t*\n" skip="\\\\\|\\' . l:tag . '" contained contains=@cnmfmts' . l:containedin . (s:fmtkeepend?' keepend':'') + exe 'hi def ' . l:region . ' ' . l:cterm[:-2] + + for l:k in keys(s:fmts) + if index(l:fmts, l:k) < 0 + call s:generateFmt(a:name . l:k) + endif + endfor +endfunction + +for s:f in keys(s:fmts) + call s:generateFmt(s:f) +endfor + + +syn cluster cnmfmt contains=@cnmfmts,@cnmfmtStyles +syn cluster cnmfmts contains=cnmfmtLink,cnmfmtEscape +syn cluster cnmfmtStyles contains=cnmfmtB,cnmfmtI,cnmfmtU,cnmfmtM + +syn region cnmfmtLink matchgroup=cnmfmtLinkAt start="@@" end="@@\|\n\t*\n" skip="\\\\\|\\@" keepend contained contains=cnmfmtLinkUrl + +syn match cnmfmtLinkText ".*" contained contains=@cnmfmtStyles +syn match cnmfmtLinkUrl "\(\\ \|\S\)\+" contained nextgroup=cnmfmtLinkText + +syn match cnmfmtEscape +\\[nt\\ */_`@]+ +syn match cnmfmtEscape +\\x\x\{2\}+ +syn match cnmfmtEscape +\\u\x\{4\}+ +syn match cnmfmtEscape +\\U\x\{8\}+ + + +syn match cnmfmtText "\%^\_.*\%$" contains=@cnmfmt,@Spell + + +hi def link cnmfmtEscape Special +hi def link cnmfmtLinkAt Special +hi def link cnmfmtLinkUrl String +hi def link cnmfmtLinkText Underlined + + +let b:current_syntax = 'cnmfmt' +if g:main_syntax ==# 'cnmfmt' + unlet g:main_syntax +endif + + +" vim: set noet: diff --git a/syntax/cnp.vim b/syntax/cnp.vim new file mode 100644 index 0000000..da9f4ba --- /dev/null +++ b/syntax/cnp.vim @@ -0,0 +1,113 @@ +" Vim syntax file +" Language: CNP 0.3rc1 +" Maintainer: +" Last Change: 2017-08-05 +" Version: 0.1.0-dev + +if !exists('g:main_syntax') + if exists('b:current_syntax') + finish + endif + let g:main_syntax = 'cnp' + syn sync minlines=50 +endif + + +function! s:generateParamKey(kname, vname, key) + exe 'syn match cnpKey' . a:kname . ' "' . a:key . '=" contained contains=cnpParameterEquals nextgroup=cnpVal' . a:vname . ',cnpError' + exe 'syn cluster cnpDefinedParams add=cnpKey' . a:kname + exe 'hi def link cnpKey' . a:kname . ' cnpParameterKey' +endfunction + +function! s:generateParamVal(vname, value) + exe 'syn match cnpVal' . a:vname . ' "' . a:value . '" contained contains=cnpEscape nextgroup=cnpError' + exe 'hi def link cnpVal' . a:vname . ' cnpParameterValue' +endfunction + + +syn match cnpError ".*" +syn match cnpCR "\r$" + +if g:main_syntax ==# 'cnp' + syn match cnpVersion "^cnp/\(0\|[1-9][0-9]*\)\.\(0\|[1-9][0-9]*\)" contains=cnpSupported,cnpUnsupported nextgroup=cnpIntent +else " allow embedding in e.g. markdown or cnm with indent + syn match cnpVersion "^\s*cnp/\(0\|[1-9][0-9]*\)\.\(0\|[1-9][0-9]*\)" contains=cnpSupported,cnpUnsupported nextgroup=cnpIntent +endif + +syn match cnpUnsupported "cnp/\d\+\.\d\+" contained +syn match cnpSupported "cnp/0\.3" contained +"syn match cnpSupported "cnp/0\.4" contained + +syn match cnpIntent " \([^\n=\\ ]\|\\[n_0\\-]\)\+\n\?" contained contains=cnpError,cnpIntentMisc,cnpIntentResponse,cnpIntentRequest keepend nextgroup=cnpParameters,cnpBody + +syn match cnpIntentMisc " \([^/\n=\\ ]\|\\[n_0\\-]\)\+" contained contains=cnpEscape + +syn match cnpIntentResponse " ok\>" contained +syn match cnpIntentResponse " not_modified\>" contained +syn match cnpIntentResponse " redirect\>" contained +syn match cnpIntentResponse " error\>" contained + +syn match cnpIntentRequest " \([^/\n=\\ ]\|\\[n_0\\-]\)*/" contained nextgroup=cnpIntentFilename contains=cnpIntentSlash,cnpEscape +syn match cnpIntentFilename "\([^/\n=\\ ]\|\\[n_0\\-]\)\+" contained nextgroup=cnpIntentSlash contains=cnpEscape +syn match cnpIntentSlash "/\+" contained nextgroup=cnpIntentFilename + +syn region cnpParameters start=" " end="\n\+" contains=cnpError,cnpParameter contained nextgroup=cnpBody +syn match cnpParameter " \([^\n=\\ ]\|\\[n_0\\-]\)*=\([^\n=\\ ]\|\\[n_0\\-]\)*" contained contains=cnpParameterKey,@cnpDefinedParams keepend nextgroup=cnpParameter +syn match cnpParameterKey "\([^\n=\\ ]\|\\[n_0\\-]\)*" contained nextgroup=cnpParameterEquals contains=cnpEscape +syn match cnpParameterEquals "=" contained nextgroup=cnpParameterValue +syn match cnpParameterValue "\([^\n=\\ ]\|\\[n_0\\-]\)*" contained contains=cnpEscape,cnpCR + +syn region cnpBody start="^" end="\%$" contained +"syn match cnpBody "\_.*" contained + +syn match cnpEscape "\\[n_0\\-]" contained + + +call s:generateParamKey('Length', 'Number', 'length') +call s:generateParamVal('Number', '0\|[1-9][0-9]*') + +call s:generateParamKey('Type', 'MIME', 'type') +call s:generateParamVal('MIME', '\(x-\)\?[a-z]\+/\([a-zA-Z0-9+._-]\+\|\*\)') + +call s:generateParamKey('Name', 'Filename', 'name') +call s:generateParamVal('Filename', '\([^\n=\\/ ]\|\\[n_\\-]\)*') + +call s:generateParamKey('Time', 'RFC3339', 'time') +call s:generateParamKey('Modified', 'RFC3339', 'modified') +call s:generateParamKey('IfModified', 'RFC3339', 'if_modified') +call s:generateParamVal('RFC3339', '\d\{4}-\d\{2}-\d\{2}T\d\{2}:\d\{2}:\d\{2}Z') + +call s:generateParamKey('Location', 'ReqIntent', 'location') +call s:generateParamVal('ReqIntent', '\([^/\n=\\ ]\|\\[n_\\-]\)*\(/\([^/\n=\\ ]\|\\[n_\\-]\)*\)\+') + +call s:generateParamKey('Reason', 'Reason', 'reason') +call s:generateParamVal('Reason', '\<\(syntax\|version\|invalid\|not_supported\|too_large\|not_found\|denied\|rejected\|server_error\)\>') + +call s:generateParamKey('Select', 'Selector', 'select') +call s:generateParamVal('Selector', 'bytes:\(0\|[1-9][0-9]*\)\?-\(0\|[1-9][0-9]*\)\?') + + +hi def link cnpError Error +hi def link cnpUnsupported TODO +hi def link cnpSupported Keyword +hi def link cnpIntentRequest Identifier +hi def link cnpIntentSlash String +hi def link cnpIntentFilename String +hi def link cnpIntentResponse Special +hi def link cnpIntentMisc TODO +hi def link cnpParameterKey Identifier +hi def link cnpParameterEquals Special +hi def link cnpParameterValue String +hi def link cnpEscape Special +hi def link cnpBody Comment + +hi def link cnpCR TODO + + +let b:current_syntax = 'cnp' +if g:main_syntax ==# 'cnp' + unlet g:main_syntax +endif + + +" vim: set noet: -- cgit