From bbb75c099e75624775a4dc3927daa1657624c2a3 Mon Sep 17 00:00:00 2001 From: "*Kim Zick (rummik)" Date: Mon, 2 Sep 2019 09:40:14 -0400 Subject: [PATCH 1/4] Initial work for fenced language syntaxes --- default.nix | 26 +++++++++-- ftplugin/nix.vim | 113 +++++++++++++++++++++++++++++++++++++++++++++++ syntax/nix.vim | 4 ++ test/nix.vader | 71 +++++++++++++++++++++++++++++ 4 files changed, 210 insertions(+), 4 deletions(-) diff --git a/default.nix b/default.nix index 190972b..30ddb4e 100644 --- a/default.nix +++ b/default.nix @@ -1,6 +1,7 @@ { pkgs ? import {} }: let + inherit (pkgs) stdenv fetchFromGitHub writeText runCommand vim; # Fallback for nix 1.11 @@ -12,6 +13,7 @@ let rev = "ddb714246535e814ddd7c62b86ca07ffbec8a0af"; sha256 = "0jlxbp883y84nal5p55fxg7a3wqh3zny9dhsvfjajrzvazmiz44n"; }; + in stdenv.mkDerivation rec { @@ -25,12 +27,12 @@ stdenv.mkDerivation rec { buildInputs = [ vim ]; - installPhase = '' + installPhase = /* sh */ '' mkdir -p $out cp -r ftdetect ftplugin indent syntax $out ''; - vimrc = writeText "vimrc" '' + vimrc = writeText "vimrc" /* vim */ '' filetype off set rtp+=${vader} set rtp+=${src} @@ -42,15 +44,31 @@ stdenv.mkDerivation rec { endfunction command! Syntax call Syntax() + + function! Nix_GetScriptID(fname) abort + let l:snlist = ''' + redir => l:snlist + silent! scriptnames + redir END + let l:mx = '^\s*\(\d\+\):\s*\(.*\)$' + for l:line in split(l:snlist, "\n") + if stridx(substitute(l:line, '\\', '/', 'g'), a:fname) >= 0 + return substitute(l:line, l:mx, '\1', ''') + endif + endfor + endfunction + function! Nix_GetFunc(fname, funcname) abort + return function('' . Nix_GetScriptID(a:fname) . '_' . a:funcname) + endfunction ''; - checkPhase = '' + checkPhase = /* sh */ '' ( vim -XNu ${vimrc} -i NONE -c 'Vader! test/*.vader' ) |& tee vim-nix-test.log >&2 ''; doCheck = true; - shellHook = '' + shellHook = /* sh */ '' vim() { command vim -XNu ${vimrc} -i NONE "$@" } diff --git a/ftplugin/nix.vim b/ftplugin/nix.vim index 2ea7c88..0999bca 100644 --- a/ftplugin/nix.vim +++ b/ftplugin/nix.vim @@ -19,3 +19,116 @@ if get(g:, 'nix_recommended_style', 1) \ softtabstop=2 \ expandtab endif + +" Borrowed from vim-markdown: https://github.com/plasticboy/vim-markdown/ +if exists('g:vim_nix_fenced_languages') + let s:filetype_dict = {} + for s:filetype in g:vim_markdown_fenced_languages + let key = matchstr(s:filetype, "[^=]*") + let val = matchstr(s:filetype, "[^=]*$") + let s:filetype_dict[key] = val + endfor +else + let s:filetype_dict = { + \ 'c++': 'cpp', + \ 'viml': 'vim', + \ 'bash': 'sh', + \ 'ini': 'dosini' + \ } +endif + +function! s:NixHighlightSources(force) + " Syntax highlight source code embedded in notes. + " Look for code blocks in the current file + let filetypes = {} + for line in getline(1, '$') + let ft = matchstr(line, "/\\*\\s*\\zs[0-9A-Za-z_+-]*\\ze\\s*\\*/\\s*''") + if !empty(ft) && ft !~ '^\d*$' | let filetypes[ft] = 1 | endif + endfor + if !exists('b:nix_known_filetypes') + let b:nix_known_filetypes = {} + endif + if !exists('b:nix_included_filetypes') + " set syntax file name included + let b:nix_included_filetypes = {} + endif + if !a:force && (b:nix_known_filetypes == filetypes || empty(filetypes)) + return + endif + + " Now we're ready to actually highlight the code blocks. + for ft in keys(filetypes) + if a:force || !has_key(b:nix_known_filetypes, ft) + if has_key(s:filetype_dict, ft) + let filetype = s:filetype_dict[ft] + else + let filetype = ft + endif + let group = 'nixSnippet' . toupper(substitute(filetype, "[+-]", "_", "g")) + if !has_key(b:nix_included_filetypes, filetype) + let include = s:SyntaxInclude(filetype) + let b:nix_included_filetypes[filetype] = 1 + else + let include = '@' . toupper(filetype) + endif + let command = "syn region %s matchgroup=nixCodeStart start=@/\\*\\s*%s\\s*\\*/\\s*''@ matchgroup=NONE skip=+''['$\\\\]+ matchgroup=nixCodeEnd end=+''+ keepend extend contains=nixInterpolation,nixStringSpecial,nixInvalidStringEscape,%s" + execute printf(command, group, ft, include) + execute printf("syn cluster nixExpr add=%s", group) + execute printf("syn region nixInterpolation matchgroup=nixInterpolationDelimiter start=+\\(''\\)\\@ 1 + call s:NixHighlightSources(a:force) + endif +endfunction + +function! s:NixClearSyntaxVariables() + if &filetype =~ 'nix' + unlet! b:nix_included_filetypes + endif +endfunction + +augroup Nix + " These autocmd calling s:NixRefreshSyntax need to be kept in sync with + " the autocmds calling s:NixSetupFolding in after/ftplugin/markdown.vim. + autocmd! * + autocmd BufWinEnter call s:NixRefreshSyntax(1) + autocmd BufUnload call s:NixClearSyntaxVariables() + autocmd BufWritePost call s:NixRefreshSyntax(0) + autocmd InsertEnter,InsertLeave call s:NixRefreshSyntax(0) + autocmd CursorHold,CursorHoldI call s:NixRefreshSyntax(0) +augroup END diff --git a/syntax/nix.vim b/syntax/nix.vim index 499971a..6f18112 100644 --- a/syntax/nix.vim +++ b/syntax/nix.vim @@ -46,6 +46,7 @@ syn match nixInvalidStringEscape /''\\[^nrt]/ contained syn region nixSimpleString matchgroup=nixStringDelimiter start=+"+ skip=+\\"+ end=+"+ contains=nixInterpolation,nixSimpleStringSpecial,nixInvalidSimpleStringEscape syn region nixString matchgroup=nixStringDelimiter start=+''+ skip=+''['$\\]+ end=+''+ contains=nixInterpolation,nixStringSpecial,nixInvalidStringEscape +syn region nixFencedString matchgroup=nixCodeStart start=+/\*\s*[0-9A-Za-z_+-]*\s*\*/\s*''+ skip=+''['$\\]+ matchgroup=nixCodeEnd end=+''+ keepend extend contains=nixInterpolation,nixStringSpecial,nixInvalidStringEscape syn match nixFunctionCall "[a-zA-Z_][a-zA-Z0-9_'-]*" @@ -162,6 +163,8 @@ hi def link nixAttribute Identifier hi def link nixAttributeDot Operator hi def link nixBoolean Boolean hi def link nixBuiltin Special +hi def link nixCodeEnd Delimiter +hi def link nixCodeStart Delimiter hi def link nixComment Comment hi def link nixConditional Conditional hi def link nixHomePath Include @@ -186,6 +189,7 @@ hi def link nixSimpleFunctionArgument Identifier hi def link nixSimpleString String hi def link nixSimpleStringSpecial SpecialChar hi def link nixString String +hi def link nixFencedString String hi def link nixStringDelimiter Delimiter hi def link nixStringSpecial Special hi def link nixTodo Todo diff --git a/test/nix.vader b/test/nix.vader index f5795df..2395cbc 100644 --- a/test/nix.vader +++ b/test/nix.vader @@ -1,3 +1,7 @@ +Before: + unlet! b:nix_known_filetypes + unlet! b:nix_included_filetypes + Given nix (attribute): { foo = pkgs.callPackage ./examples/foo {}; @@ -188,6 +192,73 @@ Expect (indentation): '' ~~~~~~~ +Given nix (fenced-multiline-string): + /* vim */ '' + line1 ${ref1} + ${ref2} line2 + line3 ${ref3} + ''; + +Execute (syntax): + AssertEqual SyntaxOf('vim'), 'nixCodeStart' + AssertEqual SyntaxOf('line1'), 'nixFencedString' + AssertEqual SyntaxOf('line2'), 'nixFencedString' + AssertEqual SyntaxOf('line3'), 'nixFencedString' + AssertEqual SyntaxOf('ref1'), 'nixInterpolationParam' + AssertEqual SyntaxOf('ref2'), 'nixInterpolationParam' + AssertEqual SyntaxOf('ref3'), 'nixInterpolationParam' + +Given nix (fenced-multiline-string): + { + c = /* c++ */ '' + #include + code + ''; + + v = /* vim */ '' + set bg=dark + ''; + + s = /* sh */ '' + ${ref1} + ''${ref2} + echo ${ref3} + echo ''${ref4} + ''; + } + +Execute (syntax): + let b:func = Nix_GetFunc('ftplugin/nix.vim', 'NixRefreshSyntax') + call b:func(0) + AssertEqual SyntaxOf('c++'), 'nixCodeStart' + AssertEqual SyntaxOf('include'), 'cInclude' + AssertEqual SyntaxOf('code'), 'nixSnippetCPP' + AssertEqual SyntaxOf('set'), 'vimCommand' + AssertEqual SyntaxOf('ref1'), 'nixInterpolationParam' + AssertEqual SyntaxOf('ref2'), 'shDerefVar' + AssertEqual SyntaxOf('ref3'), 'nixInterpolationParam' + AssertEqual SyntaxOf('ref4'), 'shDerefVar' + +Given nix (fenced-multiline-string-specials): + /* sh */ '' + ''' + ''\n + ''\f + $$ + ''$ + ''; + +Execute (syntax): + let b:func = Nix_GetFunc('ftplugin/nix.vim', 'NixRefreshSyntax') + call b:func(0) + AssertEqual SyntaxOf("'''"), 'nixStringSpecial' + AssertEqual SyntaxAt(2, 4), 'shQuote' + AssertEqual SyntaxAt(2, 5), 'shQuote' + AssertEqual SyntaxOf('\\n'), 'nixStringSpecial' + AssertEqual SyntaxOf('\\f'), 'nixInvalidStringEscape' + AssertEqual SyntaxOf('$$'), 'shDerefSimple' + AssertEqual SyntaxOf('\$', 3), 'nixSnippetSH' + Given nix (url): https://github.com/LnL7/vim-nix From c29a907b32e2d1fe6290e110406f787acd3495b1 Mon Sep 17 00:00:00 2001 From: "*Kim Zick (rummik)" Date: Mon, 2 Sep 2019 09:57:33 -0400 Subject: [PATCH 2/4] Add missing helper functions to vimrc --- test/vimrc | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/vimrc b/test/vimrc index 3fdd6ea..7338945 100644 --- a/test/vimrc +++ b/test/vimrc @@ -3,3 +3,19 @@ set rtp+=../vader.vim set rtp+=../ filetype plugin indent on syntax enable + +function! Nix_GetScriptID(fname) abort + let l:snlist = '' + redir => l:snlist + silent! scriptnames + redir END + let l:mx = '^\s*\(\d\+\):\s*\(.*\)$' + for l:line in split(l:snlist, "\n") + if stridx(substitute(l:line, '\\', '/', 'g'), a:fname) >= 0 + return substitute(l:line, l:mx, '\1', '') + endif + endfor +endfunction +function! Nix_GetFunc(fname, funcname) abort + return function('' . Nix_GetScriptID(a:fname) . '_' . a:funcname) +endfunction From a1c85c347f2847bdbb5cb63da3fb446305458343 Mon Sep 17 00:00:00 2001 From: "*Kim Zick (rummik)" Date: Mon, 2 Sep 2019 10:20:47 -0400 Subject: [PATCH 3/4] Fix unit tests --- .travis.yml | 4 ++-- test/run-tests.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 27e8060..776d5d8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ -language: vim +language: nix before_script: | git clone https://github.com/junegunn/vader.vim.git script: | - ./test/run-tests.sh + nix-shell --command ./test/run-tests.sh diff --git a/test/run-tests.sh b/test/run-tests.sh index c68c905..21c5893 100755 --- a/test/run-tests.sh +++ b/test/run-tests.sh @@ -1,3 +1,3 @@ #!/usr/bin/env bash -cd "$( dirname "${BASH_SOURCE[0]}" )" && vim -Nu vimrc -c 'Vader! *' +cd "$( dirname "${BASH_SOURCE[0]}" )" && vim -XNu vimrc -i NONE -c 'Vader! *' From 0def8020f152a51c011a707680780dac61a8989a Mon Sep 17 00:00:00 2001 From: *Kim Zick Date: Tue, 28 Jan 2020 11:04:45 -0500 Subject: [PATCH 4/4] Remove lingering mardown reference in fencing code --- ftplugin/nix.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ftplugin/nix.vim b/ftplugin/nix.vim index 0999bca..134a0e7 100644 --- a/ftplugin/nix.vim +++ b/ftplugin/nix.vim @@ -23,7 +23,7 @@ endif " Borrowed from vim-markdown: https://github.com/plasticboy/vim-markdown/ if exists('g:vim_nix_fenced_languages') let s:filetype_dict = {} - for s:filetype in g:vim_markdown_fenced_languages + for s:filetype in g:vim_nix_fenced_languages let key = matchstr(s:filetype, "[^=]*") let val = matchstr(s:filetype, "[^=]*$") let s:filetype_dict[key] = val