Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add fenced language syntaxes #28

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -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
26 changes: 22 additions & 4 deletions default.nix
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{ pkgs ? import <nixpkgs> {} }:

let

inherit (pkgs) stdenv fetchFromGitHub writeText runCommand vim;

# Fallback for nix 1.11
Expand All @@ -12,6 +13,7 @@ let
rev = "ddb714246535e814ddd7c62b86ca07ffbec8a0af";
sha256 = "0jlxbp883y84nal5p55fxg7a3wqh3zny9dhsvfjajrzvazmiz44n";
};

in

stdenv.mkDerivation rec {
Expand All @@ -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}
Expand All @@ -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('<SNR>' . 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 "$@"
}
Expand Down
113 changes: 113 additions & 0 deletions ftplugin/nix.vim
Original file line number Diff line number Diff line change
Expand Up @@ -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_nix_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=+\\(''\\)\\@<!\\${+ end=+}+ containedin=%s contains=@nixExpr,nixInterpolationParam", include)
execute printf("syn match nixStringSpecial /''\\$/me=e-1 containedin=%s", include)
execute printf("syn match nixStringSpecial /'''/me=e-2 containedin=%s", include)
execute printf("syn match nixStringSpecial /''\\\\[nrt]/ containedin=%s", include)
execute printf("syn match nixInvalidStringEscape /''\\\\[^nrt]/ containedin=%s", include)

let b:nix_known_filetypes[ft] = 1
endif
endfor
endfunction

function! s:SyntaxInclude(filetype)
" Include the syntax highlighting of another {filetype}.
let grouplistname = '@' . toupper(a:filetype)
" Unset the name of the current syntax while including the other syntax
" because some syntax scripts do nothing when "b:current_syntax" is set
if exists('b:current_syntax')
let syntax_save = b:current_syntax
unlet b:current_syntax
endif
try
execute 'syntax include' grouplistname 'syntax/' . a:filetype . '.vim'
execute 'syntax include' grouplistname 'after/syntax/' . a:filetype . '.vim'
catch /E484/
" Ignore missing scripts
endtry
" Restore the name of the current syntax
if exists('syntax_save')
let b:current_syntax = syntax_save
elseif exists('b:current_syntax')
unlet b:current_syntax
endif
return grouplistname
endfunction


function! s:NixRefreshSyntax(force)
if &filetype =~ 'nix' && line('$') > 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! * <buffer>
autocmd BufWinEnter <buffer> call s:NixRefreshSyntax(1)
autocmd BufUnload <buffer> call s:NixClearSyntaxVariables()
autocmd BufWritePost <buffer> call s:NixRefreshSyntax(0)
autocmd InsertEnter,InsertLeave <buffer> call s:NixRefreshSyntax(0)
autocmd CursorHold,CursorHoldI <buffer> call s:NixRefreshSyntax(0)
augroup END
4 changes: 4 additions & 0 deletions syntax/nix.vim
Original file line number Diff line number Diff line change
Expand Up @@ -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_'-]*"

Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
71 changes: 71 additions & 0 deletions test/nix.vader
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
Before:
unlet! b:nix_known_filetypes
unlet! b:nix_included_filetypes

Given nix (attribute):
{
foo = pkgs.callPackage ./examples/foo {};
Expand Down Expand Up @@ -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 <iostream>
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

Expand Down
2 changes: 1 addition & 1 deletion test/run-tests.sh
Original file line number Diff line number Diff line change
@@ -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! *'
16 changes: 16 additions & 0 deletions test/vimrc
Original file line number Diff line number Diff line change
Expand Up @@ -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('<SNR>' . Nix_GetScriptID(a:fname) . '_' . a:funcname)
endfunction