diff options
author | Izhak Jakov <izak723@gmail.com> | 2021-09-04 13:49:17 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-09-04 19:49:17 +0200 |
commit | dce50312e1e9af81fb0e3b61d6e70bdf286fbffb (patch) | |
tree | ea53d13d9236cbcde1716aa42ec31f060848d8ad | |
parent | 61178778230e609d68b271ffd53ffd993cd23c42 (diff) | |
download | rneovim-dce50312e1e9af81fb0e3b61d6e70bdf286fbffb.tar.gz rneovim-dce50312e1e9af81fb0e3b61d6e70bdf286fbffb.tar.bz2 rneovim-dce50312e1e9af81fb0e3b61d6e70bdf286fbffb.zip |
vim-patch:90df4b9 (#15494)
Add JSONC runtime files
Co-authored-by: Izhak Jakov <izhakjakov>
-rw-r--r-- | runtime/ftplugin/jsonc.vim | 27 | ||||
-rw-r--r-- | runtime/indent/jsonc.vim | 189 | ||||
-rw-r--r-- | runtime/syntax/jsonc.vim | 44 |
3 files changed, 260 insertions, 0 deletions
diff --git a/runtime/ftplugin/jsonc.vim b/runtime/ftplugin/jsonc.vim new file mode 100644 index 0000000000..90d52cd0d3 --- /dev/null +++ b/runtime/ftplugin/jsonc.vim @@ -0,0 +1,27 @@ +" Vim filetype plugin +" Language: JSONC (JSON with Comments) +" Original Author: Izhak Jakov <izhak724@gmail.com> +" Acknowledgement: Based off of vim-jsonc maintained by Kevin Locke <kevin@kevinlocke.name> +" https://github.com/kevinoid/vim-jsonc +" License: MIT +" Last Change: 2021-07-01 + +runtime! ftplugin/json.vim + +if exists('b:did_ftplugin_jsonc') + finish +else + let b:did_ftplugin_jsonc = 1 +endif + +" A list of commands that undo buffer local changes made below. +let s:undo_ftplugin = [] + +" Set comment (formatting) related options. {{{1 +setlocal commentstring=//%s comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,:// +call add(s:undo_ftplugin, 'commentstring< comments<') + +" Let Vim know how to disable the plug-in. +call map(s:undo_ftplugin, "'execute ' . string(v:val)") +let b:undo_ftplugin = join(s:undo_ftplugin, ' | ') +unlet s:undo_ftplugin diff --git a/runtime/indent/jsonc.vim b/runtime/indent/jsonc.vim new file mode 100644 index 0000000000..bf8e501dd5 --- /dev/null +++ b/runtime/indent/jsonc.vim @@ -0,0 +1,189 @@ +" Vim indent file +" Language: JSONC (JSON with Comments) +" Original Author: Izhak Jakov <izhak724@gmail.com> +" Acknowledgement: Based off of vim-json maintained by Eli Parra <eli@elzr.com> +" https://github.com/elzr/vim-json +" Last Change: 2021-07-01 + +" 0. Initialization {{{1 +" ================= + +" Only load this indent file when no other was loaded. +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +setlocal nosmartindent + +" Now, set up our indentation expression and keys that trigger it. +setlocal indentexpr=GetJSONCIndent() +setlocal indentkeys=0{,0},0),0[,0],!^F,o,O,e + +" Only define the function once. +if exists("*GetJSONCIndent") + finish +endif + +let s:cpo_save = &cpo +set cpo&vim + +" 1. Variables {{{1 +" ============ + +let s:line_term = '\s*\%(\%(\/\/\).*\)\=$' +" Regex that defines blocks. +let s:block_regex = '\%({\)\s*\%(|\%([*@]\=\h\w*,\=\s*\)\%(,\s*[*@]\=\h\w*\)*|\)\=' . s:line_term + +" 2. Auxiliary Functions {{{1 +" ====================== + +" Check if the character at lnum:col is inside a string. +function s:IsInString(lnum, col) + return synIDattr(synID(a:lnum, a:col, 1), 'name') == 'jsonString' +endfunction + +" Find line above 'lnum' that isn't empty, or in a string. +function s:PrevNonBlankNonString(lnum) + let lnum = prevnonblank(a:lnum) + while lnum > 0 + " If the line isn't empty or in a string, end search. + let line = getline(lnum) + if !(s:IsInString(lnum, 1) && s:IsInString(lnum, strlen(line))) + break + endif + let lnum = prevnonblank(lnum - 1) + endwhile + return lnum +endfunction + +" Check if line 'lnum' has more opening brackets than closing ones. +function s:LineHasOpeningBrackets(lnum) + let open_0 = 0 + let open_2 = 0 + let open_4 = 0 + let line = getline(a:lnum) + let pos = match(line, '[][(){}]', 0) + while pos != -1 + let idx = stridx('(){}[]', line[pos]) + if idx % 2 == 0 + let open_{idx} = open_{idx} + 1 + else + let open_{idx - 1} = open_{idx - 1} - 1 + endif + let pos = match(line, '[][(){}]', pos + 1) + endwhile + return (open_0 > 0) . (open_2 > 0) . (open_4 > 0) +endfunction + +function s:Match(lnum, regex) + let col = match(getline(a:lnum), a:regex) + 1 + return col > 0 && !s:IsInString(a:lnum, col) ? col : 0 +endfunction + +" 3. GetJSONCIndent Function {{{1 +" ========================= + +function GetJSONCIndent() + if !exists("s:inside_comment") + let s:inside_comment = 0 + endif + + " 3.1. Setup {{{2 + " ---------- + + " Set up variables for restoring position in file. Could use v:lnum here. + let vcol = col('.') + + " 3.2. Work on the current line {{{2 + " ----------------------------- + + + " Get the current line. + let line = getline(v:lnum) + let ind = -1 + if s:inside_comment == 0 + " TODO iterate through all the matches in a line + let col = matchend(line, '\/\*') + if col > 0 && !s:IsInString(v:lnum, col) + let s:inside_comment = 1 + endif + endif + " If we're in the middle of a comment + if s:inside_comment == 1 + let col = matchend(line, '\*\/') + if col > 0 && !s:IsInString(v:lnum, col) + let s:inside_comment = 0 + endif + return ind + endif + if line =~ '^\s*//' + return ind + endif + + " If we got a closing bracket on an empty line, find its match and indent + " according to it. + let col = matchend(line, '^\s*[]}]') + + if col > 0 && !s:IsInString(v:lnum, col) + call cursor(v:lnum, col) + let bs = strpart('{}[]', stridx('}]', line[col - 1]) * 2, 2) + + let pairstart = escape(bs[0], '[') + let pairend = escape(bs[1], ']') + let pairline = searchpair(pairstart, '', pairend, 'bW') + + if pairline > 0 + let ind = indent(pairline) + else + let ind = virtcol('.') - 1 + endif + + return ind + endif + + " If we are in a multi-line string, don't do anything to it. + if s:IsInString(v:lnum, matchend(line, '^\s*') + 1) + return indent('.') + endif + + " 3.3. Work on the previous line. {{{2 + " ------------------------------- + + let lnum = prevnonblank(v:lnum - 1) + + if lnum == 0 + return 0 + endif + + " Set up variables for current line. + let line = getline(lnum) + let ind = indent(lnum) + + " If the previous line ended with a block opening, add a level of indent. + " if s:Match(lnum, s:block_regex) + " return indent(lnum) + shiftwidth() + " endif + + " If the previous line contained an opening bracket, and we are still in it, + " add indent depending on the bracket type. + if line =~ '[[({]' + let counts = s:LineHasOpeningBrackets(lnum) + if counts[0] == '1' || counts[1] == '1' || counts[2] == '1' + return ind + shiftwidth() + else + call cursor(v:lnum, vcol) + end + endif + + " }}}2 + + return ind +endfunction + +" }}}1 + +let &cpo = s:cpo_save +unlet s:cpo_save + +" vim:set sw=2 sts=2 ts=8 noet: diff --git a/runtime/syntax/jsonc.vim b/runtime/syntax/jsonc.vim new file mode 100644 index 0000000000..d0df16bbf1 --- /dev/null +++ b/runtime/syntax/jsonc.vim @@ -0,0 +1,44 @@ +" Vim syntax file +" Language: JSONC (JSON with Comments) +" Original Author: Izhak Jakov <izhak724@gmail.com> +" Acknowledgement: Based off of vim-jsonc maintained by Kevin Locke <kevin@kevinlocke.name> +" https://github.com/kevinoid/vim-jsonc +" License: MIT +" Last Change: 2021-07-01 + +" Ensure syntax is loaded once, unless nested inside another (main) syntax +" For description of main_syntax, see https://stackoverflow.com/q/16164549 +if !exists('g:main_syntax') + if exists('b:current_syntax') && b:current_syntax ==# 'jsonc' + finish + endif + let g:main_syntax = 'jsonc' +endif + +" Based on vim-json syntax +runtime! syntax/json.vim + +" Remove syntax group for comments treated as errors +if !exists("g:vim_json_warnings") || g:vim_json_warnings + syn clear jsonCommentError +endif + +syn match jsonStringMatch /"\([^"]\|\\\"\)\+"\ze\(\_s*\/\/.*\_s*\)*[}\]]/ contains=jsonString +syn match jsonStringMatch /"\([^"]\|\\\"\)\+"\ze\_s*\/\*\_.*\*\/\_s*[}\]]/ contains=jsonString +syn match jsonTrailingCommaError /\(,\)\+\ze\(\_s*\/\/.*\_s*\)*[}\]]/ +syn match jsonTrailingCommaError /\(,\)\+\ze\_s*\/\*\_.*\*\/\_s*[}\]]/ + +" Define syntax matching comments and their contents +syn keyword jsonCommentTodo FIXME NOTE TBD TODO XXX +syn region jsonLineComment start=+\/\/+ end=+$+ contains=@Spell,jsonCommentTodo keepend +syn region jsonComment start='/\*' end='\*/' contains=@Spell,jsonCommentTodo fold + +" Link comment syntax comment to highlighting +hi! def link jsonLineComment Comment +hi! def link jsonComment Comment + +" Set/Unset syntax to avoid duplicate inclusion and correctly handle nesting +let b:current_syntax = 'jsonc' +if g:main_syntax ==# 'jsonc' + unlet g:main_syntax +endif |