107d87790SBram Moolenaar" Vim indent file 207d87790SBram Moolenaar" Language: JSON 3*6c391a74SBram Moolenaar" Maintainer: Eli Parra <[email protected]> https://github.com/elzr/vim-json 41c6737b2SBram Moolenaar" Last Change: 2020 Aug 30 534401ccaSBram Moolenaar" https://github.com/jakar/vim-json/commit/20b650e22aa750c4ab6a66aa646bdd95d7cd548a#diff-e81fc111b2052e306d126bd9989f7b7c 634401ccaSBram Moolenaar" Original Author: Rogerz Zhang <rogerz.zhang at gmail.com> http://github.com/rogerz/vim-json 734401ccaSBram Moolenaar" Acknowledgement: Based off of vim-javascript maintained by Darrick Wiebe 834401ccaSBram Moolenaar" http://www.vim.org/scripts/script.php?script_id=2765 907d87790SBram Moolenaar 1034401ccaSBram Moolenaar" 0. Initialization {{{1 1134401ccaSBram Moolenaar" ================= 1234401ccaSBram Moolenaar 1334401ccaSBram Moolenaar" Only load this indent file when no other was loaded. 1434401ccaSBram Moolenaarif exists("b:did_indent") 1534401ccaSBram Moolenaar finish 1634401ccaSBram Moolenaarendif 1734401ccaSBram Moolenaarlet b:did_indent = 1 1834401ccaSBram Moolenaar 1934401ccaSBram Moolenaarsetlocal nosmartindent 2034401ccaSBram Moolenaar 2134401ccaSBram Moolenaar" Now, set up our indentation expression and keys that trigger it. 221c6737b2SBram Moolenaarsetlocal indentexpr=GetJSONIndent(v:lnum) 2334401ccaSBram Moolenaarsetlocal indentkeys=0{,0},0),0[,0],!^F,o,O,e 2434401ccaSBram Moolenaar 2534401ccaSBram Moolenaar" Only define the function once. 2634401ccaSBram Moolenaarif exists("*GetJSONIndent") 2707d87790SBram Moolenaar finish 2807d87790SBram Moolenaarendif 2907d87790SBram Moolenaar 3034401ccaSBram Moolenaarlet s:cpo_save = &cpo 3134401ccaSBram Moolenaarset cpo&vim 3207d87790SBram Moolenaar 3334401ccaSBram Moolenaar" 1. Variables {{{1 3434401ccaSBram Moolenaar" ============ 3534401ccaSBram Moolenaar 3634401ccaSBram Moolenaarlet s:line_term = '\s*\%(\%(\/\/\).*\)\=$' 3734401ccaSBram Moolenaar" Regex that defines blocks. 3834401ccaSBram Moolenaarlet s:block_regex = '\%({\)\s*\%(|\%([*@]\=\h\w*,\=\s*\)\%(,\s*[*@]\=\h\w*\)*|\)\=' . s:line_term 3934401ccaSBram Moolenaar 4034401ccaSBram Moolenaar" 2. Auxiliary Functions {{{1 4134401ccaSBram Moolenaar" ====================== 4234401ccaSBram Moolenaar 4334401ccaSBram Moolenaar" Check if the character at lnum:col is inside a string. 4434401ccaSBram Moolenaarfunction s:IsInString(lnum, col) 4534401ccaSBram Moolenaar return synIDattr(synID(a:lnum, a:col, 1), 'name') == 'jsonString' 4634401ccaSBram Moolenaarendfunction 4734401ccaSBram Moolenaar 4834401ccaSBram Moolenaar" Find line above 'lnum' that isn't empty, or in a string. 4934401ccaSBram Moolenaarfunction s:PrevNonBlankNonString(lnum) 5034401ccaSBram Moolenaar let lnum = prevnonblank(a:lnum) 5134401ccaSBram Moolenaar while lnum > 0 5234401ccaSBram Moolenaar " If the line isn't empty or in a string, end search. 5334401ccaSBram Moolenaar let line = getline(lnum) 5434401ccaSBram Moolenaar if !(s:IsInString(lnum, 1) && s:IsInString(lnum, strlen(line))) 5534401ccaSBram Moolenaar break 5634401ccaSBram Moolenaar endif 5734401ccaSBram Moolenaar let lnum = prevnonblank(lnum - 1) 5834401ccaSBram Moolenaar endwhile 5934401ccaSBram Moolenaar return lnum 6034401ccaSBram Moolenaarendfunction 6134401ccaSBram Moolenaar 6234401ccaSBram Moolenaar" Check if line 'lnum' has more opening brackets than closing ones. 6334401ccaSBram Moolenaarfunction s:LineHasOpeningBrackets(lnum) 6434401ccaSBram Moolenaar let open_0 = 0 6534401ccaSBram Moolenaar let open_2 = 0 6634401ccaSBram Moolenaar let open_4 = 0 6734401ccaSBram Moolenaar let line = getline(a:lnum) 6834401ccaSBram Moolenaar let pos = match(line, '[][(){}]', 0) 6934401ccaSBram Moolenaar while pos != -1 7034401ccaSBram Moolenaar let idx = stridx('(){}[]', line[pos]) 7134401ccaSBram Moolenaar if idx % 2 == 0 7234401ccaSBram Moolenaar let open_{idx} = open_{idx} + 1 7334401ccaSBram Moolenaar else 7434401ccaSBram Moolenaar let open_{idx - 1} = open_{idx - 1} - 1 7534401ccaSBram Moolenaar endif 7634401ccaSBram Moolenaar let pos = match(line, '[][(){}]', pos + 1) 7734401ccaSBram Moolenaar endwhile 7834401ccaSBram Moolenaar return (open_0 > 0) . (open_2 > 0) . (open_4 > 0) 7934401ccaSBram Moolenaarendfunction 8034401ccaSBram Moolenaar 8134401ccaSBram Moolenaarfunction s:Match(lnum, regex) 8234401ccaSBram Moolenaar let col = match(getline(a:lnum), a:regex) + 1 8334401ccaSBram Moolenaar return col > 0 && !s:IsInString(a:lnum, col) ? col : 0 8434401ccaSBram Moolenaarendfunction 8534401ccaSBram Moolenaar 8634401ccaSBram Moolenaar" 3. GetJSONIndent Function {{{1 8734401ccaSBram Moolenaar" ========================= 8834401ccaSBram Moolenaar 891c6737b2SBram Moolenaarfunction GetJSONIndent(...) 9034401ccaSBram Moolenaar " 3.1. Setup {{{2 9134401ccaSBram Moolenaar " ---------- 921c6737b2SBram Moolenaar " For the current line, use the first argument if given, else v:lnum 931c6737b2SBram Moolenaar let clnum = a:0 ? a:1 : v:lnum 9434401ccaSBram Moolenaar 951c6737b2SBram Moolenaar " Set up variables for restoring position in file. Could use clnum here. 9634401ccaSBram Moolenaar let vcol = col('.') 9734401ccaSBram Moolenaar 9834401ccaSBram Moolenaar " 3.2. Work on the current line {{{2 9934401ccaSBram Moolenaar " ----------------------------- 10034401ccaSBram Moolenaar 10134401ccaSBram Moolenaar " Get the current line. 1021c6737b2SBram Moolenaar let line = getline(clnum) 10334401ccaSBram Moolenaar let ind = -1 10434401ccaSBram Moolenaar 10534401ccaSBram Moolenaar " If we got a closing bracket on an empty line, find its match and indent 10634401ccaSBram Moolenaar " according to it. 10734401ccaSBram Moolenaar let col = matchend(line, '^\s*[]}]') 10834401ccaSBram Moolenaar 1091c6737b2SBram Moolenaar if col > 0 && !s:IsInString(clnum, col) 1101c6737b2SBram Moolenaar call cursor(clnum, col) 11134401ccaSBram Moolenaar let bs = strpart('{}[]', stridx('}]', line[col - 1]) * 2, 2) 11234401ccaSBram Moolenaar 11334401ccaSBram Moolenaar let pairstart = escape(bs[0], '[') 11434401ccaSBram Moolenaar let pairend = escape(bs[1], ']') 11534401ccaSBram Moolenaar let pairline = searchpair(pairstart, '', pairend, 'bW') 11634401ccaSBram Moolenaar 11734401ccaSBram Moolenaar if pairline > 0 11834401ccaSBram Moolenaar let ind = indent(pairline) 11934401ccaSBram Moolenaar else 12034401ccaSBram Moolenaar let ind = virtcol('.') - 1 12134401ccaSBram Moolenaar endif 12234401ccaSBram Moolenaar 12334401ccaSBram Moolenaar return ind 12434401ccaSBram Moolenaar endif 12534401ccaSBram Moolenaar 12634401ccaSBram Moolenaar " If we are in a multi-line string, don't do anything to it. 1271c6737b2SBram Moolenaar if s:IsInString(clnum, matchend(line, '^\s*') + 1) 12834401ccaSBram Moolenaar return indent('.') 12934401ccaSBram Moolenaar endif 13034401ccaSBram Moolenaar 13134401ccaSBram Moolenaar " 3.3. Work on the previous line. {{{2 13234401ccaSBram Moolenaar " ------------------------------- 13334401ccaSBram Moolenaar 1341c6737b2SBram Moolenaar let lnum = prevnonblank(clnum - 1) 13534401ccaSBram Moolenaar 13634401ccaSBram Moolenaar if lnum == 0 13734401ccaSBram Moolenaar return 0 13834401ccaSBram Moolenaar endif 13934401ccaSBram Moolenaar 14034401ccaSBram Moolenaar " Set up variables for current line. 14134401ccaSBram Moolenaar let line = getline(lnum) 14234401ccaSBram Moolenaar let ind = indent(lnum) 14334401ccaSBram Moolenaar 14434401ccaSBram Moolenaar " If the previous line ended with a block opening, add a level of indent. 14534401ccaSBram Moolenaar " if s:Match(lnum, s:block_regex) 1463ec574f2SBram Moolenaar " return indent(lnum) + shiftwidth() 14734401ccaSBram Moolenaar " endif 14834401ccaSBram Moolenaar 14934401ccaSBram Moolenaar " If the previous line contained an opening bracket, and we are still in it, 15034401ccaSBram Moolenaar " add indent depending on the bracket type. 15134401ccaSBram Moolenaar if line =~ '[[({]' 15234401ccaSBram Moolenaar let counts = s:LineHasOpeningBrackets(lnum) 15334401ccaSBram Moolenaar if counts[0] == '1' || counts[1] == '1' || counts[2] == '1' 1543ec574f2SBram Moolenaar return ind + shiftwidth() 15534401ccaSBram Moolenaar else 1561c6737b2SBram Moolenaar call cursor(clnum, vcol) 15734401ccaSBram Moolenaar end 15834401ccaSBram Moolenaar endif 15934401ccaSBram Moolenaar 16034401ccaSBram Moolenaar " }}}2 16134401ccaSBram Moolenaar 16234401ccaSBram Moolenaar return ind 16334401ccaSBram Moolenaarendfunction 16434401ccaSBram Moolenaar 16534401ccaSBram Moolenaar" }}}1 16634401ccaSBram Moolenaar 16734401ccaSBram Moolenaarlet &cpo = s:cpo_save 16834401ccaSBram Moolenaarunlet s:cpo_save 16934401ccaSBram Moolenaar 17034401ccaSBram Moolenaar" vim:set sw=2 sts=2 ts=8 noet: 171