Skip to content

Commit d298418

Browse files
committed
Initial work for fenced language syntaxes
1 parent a3eed01 commit d298418

File tree

4 files changed

+210
-4
lines changed

4 files changed

+210
-4
lines changed

default.nix

+22-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{ pkgs ? import <nixpkgs> {} }:
22

33
let
4+
45
inherit (pkgs) stdenv fetchFromGitHub writeText runCommand vim;
56

67
# Fallback for nix 1.11
@@ -12,6 +13,7 @@ let
1213
rev = "ddb714246535e814ddd7c62b86ca07ffbec8a0af";
1314
sha256 = "0jlxbp883y84nal5p55fxg7a3wqh3zny9dhsvfjajrzvazmiz44n";
1415
};
16+
1517
in
1618

1719
stdenv.mkDerivation rec {
@@ -25,12 +27,12 @@ stdenv.mkDerivation rec {
2527

2628
buildInputs = [ vim ];
2729

28-
installPhase = ''
30+
installPhase = /* sh */ ''
2931
mkdir -p $out
3032
cp -r ftdetect ftplugin indent syntax $out
3133
'';
3234

33-
vimrc = writeText "vimrc" ''
35+
vimrc = writeText "vimrc" /* vim */ ''
3436
filetype off
3537
set rtp+=${vader}
3638
set rtp+=${src}
@@ -42,15 +44,31 @@ stdenv.mkDerivation rec {
4244
endfunction
4345
4446
command! Syntax call Syntax()
47+
48+
function! Nix_GetScriptID(fname) abort
49+
let l:snlist = '''
50+
redir => l:snlist
51+
silent! scriptnames
52+
redir END
53+
let l:mx = '^\s*\(\d\+\):\s*\(.*\)$'
54+
for l:line in split(l:snlist, "\n")
55+
if stridx(substitute(l:line, '\\', '/', 'g'), a:fname) >= 0
56+
return substitute(l:line, l:mx, '\1', ''')
57+
endif
58+
endfor
59+
endfunction
60+
function! Nix_GetFunc(fname, funcname) abort
61+
return function('<SNR>' . Nix_GetScriptID(a:fname) . '_' . a:funcname)
62+
endfunction
4563
'';
4664

47-
checkPhase = ''
65+
checkPhase = /* sh */ ''
4866
( vim -XNu ${vimrc} -i NONE -c 'Vader! test/*.vader' ) |& tee vim-nix-test.log >&2
4967
'';
5068

5169
doCheck = true;
5270

53-
shellHook = ''
71+
shellHook = /* sh */ ''
5472
vim() {
5573
command vim -XNu ${vimrc} -i NONE "$@"
5674
}

ftplugin/nix.vim

+113
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,116 @@ if get(g:, 'nix_recommended_style', 1)
1919
\ softtabstop=2
2020
\ expandtab
2121
endif
22+
23+
" Borrowed from vim-markdown: https://github.com/plasticboy/vim-markdown/
24+
if exists('g:vim_nix_fenced_languages')
25+
let s:filetype_dict = {}
26+
for s:filetype in g:vim_markdown_fenced_languages
27+
let key = matchstr(s:filetype, "[^=]*")
28+
let val = matchstr(s:filetype, "[^=]*$")
29+
let s:filetype_dict[key] = val
30+
endfor
31+
else
32+
let s:filetype_dict = {
33+
\ 'c++': 'cpp',
34+
\ 'viml': 'vim',
35+
\ 'bash': 'sh',
36+
\ 'ini': 'dosini'
37+
\ }
38+
endif
39+
40+
function! s:NixHighlightSources(force)
41+
" Syntax highlight source code embedded in notes.
42+
" Look for code blocks in the current file
43+
let filetypes = {}
44+
for line in getline(1, '$')
45+
let ft = matchstr(line, "/\\*\\s*\\zs[0-9A-Za-z_+-]*\\ze\\s*\\*/\\s*''")
46+
if !empty(ft) && ft !~ '^\d*$' | let filetypes[ft] = 1 | endif
47+
endfor
48+
if !exists('b:nix_known_filetypes')
49+
let b:nix_known_filetypes = {}
50+
endif
51+
if !exists('b:nix_included_filetypes')
52+
" set syntax file name included
53+
let b:nix_included_filetypes = {}
54+
endif
55+
if !a:force && (b:nix_known_filetypes == filetypes || empty(filetypes))
56+
return
57+
endif
58+
59+
" Now we're ready to actually highlight the code blocks.
60+
for ft in keys(filetypes)
61+
if a:force || !has_key(b:nix_known_filetypes, ft)
62+
if has_key(s:filetype_dict, ft)
63+
let filetype = s:filetype_dict[ft]
64+
else
65+
let filetype = ft
66+
endif
67+
let group = 'nixSnippet' . toupper(substitute(filetype, "[+-]", "_", "g"))
68+
if !has_key(b:nix_included_filetypes, filetype)
69+
let include = s:SyntaxInclude(filetype)
70+
let b:nix_included_filetypes[filetype] = 1
71+
else
72+
let include = '@' . toupper(filetype)
73+
endif
74+
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"
75+
execute printf(command, group, ft, include)
76+
execute printf("syn cluster nixExpr add=%s", group)
77+
execute printf("syn region nixInterpolation matchgroup=nixInterpolationDelimiter start=+\\(''\\)\\@<!\\${+ end=+}+ containedin=%s contains=@nixExpr,nixInterpolationParam", include)
78+
execute printf("syn match nixStringSpecial /''\\$/me=e-1 containedin=%s", include)
79+
execute printf("syn match nixStringSpecial /'''/me=e-2 containedin=%s", include)
80+
execute printf("syn match nixStringSpecial /''\\\\[nrt]/ containedin=%s", include)
81+
execute printf("syn match nixInvalidStringEscape /''\\\\[^nrt]/ containedin=%s", include)
82+
83+
let b:nix_known_filetypes[ft] = 1
84+
endif
85+
endfor
86+
endfunction
87+
88+
function! s:SyntaxInclude(filetype)
89+
" Include the syntax highlighting of another {filetype}.
90+
let grouplistname = '@' . toupper(a:filetype)
91+
" Unset the name of the current syntax while including the other syntax
92+
" because some syntax scripts do nothing when "b:current_syntax" is set
93+
if exists('b:current_syntax')
94+
let syntax_save = b:current_syntax
95+
unlet b:current_syntax
96+
endif
97+
try
98+
execute 'syntax include' grouplistname 'syntax/' . a:filetype . '.vim'
99+
execute 'syntax include' grouplistname 'after/syntax/' . a:filetype . '.vim'
100+
catch /E484/
101+
" Ignore missing scripts
102+
endtry
103+
" Restore the name of the current syntax
104+
if exists('syntax_save')
105+
let b:current_syntax = syntax_save
106+
elseif exists('b:current_syntax')
107+
unlet b:current_syntax
108+
endif
109+
return grouplistname
110+
endfunction
111+
112+
113+
function! s:NixRefreshSyntax(force)
114+
if &filetype =~ 'nix' && line('$') > 1
115+
call s:NixHighlightSources(a:force)
116+
endif
117+
endfunction
118+
119+
function! s:NixClearSyntaxVariables()
120+
if &filetype =~ 'nix'
121+
unlet! b:nix_included_filetypes
122+
endif
123+
endfunction
124+
125+
augroup Nix
126+
" These autocmd calling s:NixRefreshSyntax need to be kept in sync with
127+
" the autocmds calling s:NixSetupFolding in after/ftplugin/markdown.vim.
128+
autocmd! * <buffer>
129+
autocmd BufWinEnter <buffer> call s:NixRefreshSyntax(1)
130+
autocmd BufUnload <buffer> call s:NixClearSyntaxVariables()
131+
autocmd BufWritePost <buffer> call s:NixRefreshSyntax(0)
132+
autocmd InsertEnter,InsertLeave <buffer> call s:NixRefreshSyntax(0)
133+
autocmd CursorHold,CursorHoldI <buffer> call s:NixRefreshSyntax(0)
134+
augroup END

syntax/nix.vim

+4
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ syn match nixInvalidStringEscape /''\\[^nrt]/ contained
4444

4545
syn region nixSimpleString matchgroup=nixStringDelimiter start=+"+ skip=+\\"+ end=+"+ contains=nixInterpolation,nixSimpleStringSpecial,nixInvalidSimpleStringEscape
4646
syn region nixString matchgroup=nixStringDelimiter start=+''+ skip=+''['$\\]+ end=+''+ contains=nixInterpolation,nixStringSpecial,nixInvalidStringEscape
47+
syn region nixFencedString matchgroup=nixCodeStart start=+/\*\s*[0-9A-Za-z_+-]*\s*\*/\s*''+ skip=+''['$\\]+ matchgroup=nixCodeEnd end=+''+ keepend extend contains=nixInterpolation,nixStringSpecial,nixInvalidStringEscape
4748

4849
syn match nixFunctionCall "[a-zA-Z_][a-zA-Z0-9_'-]*"
4950

@@ -159,6 +160,8 @@ hi def link nixAttribute Identifier
159160
hi def link nixAttributeDot Operator
160161
hi def link nixBoolean Boolean
161162
hi def link nixBuiltin Special
163+
hi def link nixCodeEnd Delimiter
164+
hi def link nixCodeStart Delimiter
162165
hi def link nixComment Comment
163166
hi def link nixConditional Conditional
164167
hi def link nixHomePath Include
@@ -183,6 +186,7 @@ hi def link nixSimpleFunctionArgument Identifier
183186
hi def link nixSimpleString String
184187
hi def link nixSimpleStringSpecial SpecialChar
185188
hi def link nixString String
189+
hi def link nixFencedString String
186190
hi def link nixStringDelimiter Delimiter
187191
hi def link nixStringSpecial Special
188192
hi def link nixTodo Todo

test/nix.vader

+71
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
Before:
2+
unlet! b:nix_known_filetypes
3+
unlet! b:nix_included_filetypes
4+
15
Given nix (attribute):
26
{
37
foo = pkgs.callPackage ./examples/foo {};
@@ -188,6 +192,73 @@ Expect (indentation):
188192
''
189193
~~~~~~~
190194

195+
Given nix (fenced-multiline-string):
196+
/* vim */ ''
197+
line1 ${ref1}
198+
${ref2} line2
199+
line3 ${ref3}
200+
'';
201+
202+
Execute (syntax):
203+
AssertEqual SyntaxOf('vim'), 'nixCodeStart'
204+
AssertEqual SyntaxOf('line1'), 'nixFencedString'
205+
AssertEqual SyntaxOf('line2'), 'nixFencedString'
206+
AssertEqual SyntaxOf('line3'), 'nixFencedString'
207+
AssertEqual SyntaxOf('ref1'), 'nixInterpolationParam'
208+
AssertEqual SyntaxOf('ref2'), 'nixInterpolationParam'
209+
AssertEqual SyntaxOf('ref3'), 'nixInterpolationParam'
210+
211+
Given nix (fenced-multiline-string):
212+
{
213+
c = /* c++ */ ''
214+
#include <iostream>
215+
code
216+
'';
217+
218+
v = /* vim */ ''
219+
set bg=dark
220+
'';
221+
222+
s = /* sh */ ''
223+
${ref1}
224+
''${ref2}
225+
echo ${ref3}
226+
echo ''${ref4}
227+
'';
228+
}
229+
230+
Execute (syntax):
231+
let b:func = Nix_GetFunc('ftplugin/nix.vim', 'NixRefreshSyntax')
232+
call b:func(0)
233+
AssertEqual SyntaxOf('c++'), 'nixCodeStart'
234+
AssertEqual SyntaxOf('include'), 'cInclude'
235+
AssertEqual SyntaxOf('code'), 'nixSnippetCPP'
236+
AssertEqual SyntaxOf('set'), 'vimCommand'
237+
AssertEqual SyntaxOf('ref1'), 'nixInterpolationParam'
238+
AssertEqual SyntaxOf('ref2'), 'shDerefVar'
239+
AssertEqual SyntaxOf('ref3'), 'nixInterpolationParam'
240+
AssertEqual SyntaxOf('ref4'), 'shDerefVar'
241+
242+
Given nix (fenced-multiline-string-specials):
243+
/* sh */ ''
244+
'''
245+
''\n
246+
''\f
247+
$$
248+
''$
249+
'';
250+
251+
Execute (syntax):
252+
let b:func = Nix_GetFunc('ftplugin/nix.vim', 'NixRefreshSyntax')
253+
call b:func(0)
254+
AssertEqual SyntaxOf("'''"), 'nixStringSpecial'
255+
AssertEqual SyntaxAt(2, 4), 'shQuote'
256+
AssertEqual SyntaxAt(2, 5), 'shQuote'
257+
AssertEqual SyntaxOf('\\n'), 'nixStringSpecial'
258+
AssertEqual SyntaxOf('\\f'), 'nixInvalidStringEscape'
259+
AssertEqual SyntaxOf('$$'), 'shDerefSimple'
260+
AssertEqual SyntaxOf('\$', 3), 'nixSnippetSH'
261+
191262
Given nix (url):
192263
https://github.com/LnL7/vim-nix
193264

0 commit comments

Comments
 (0)