codekingpro/portable-devtools
114k
1" Vim indent file2" Language: JSON3" Maintainer: Eli Parra <eli@elzr.com> https://github.com/elzr/vim-json4" Last Change: 2020 Aug 305" https://github.com/jakar/vim-json/commit/20b650e22aa750c4ab6a66aa646bdd95d7cd548a#diff-e81fc111b2052e306d126bd9989f7b7c6" 2022 Sep 07: b:undo_indent added by Doug Kearns7" Original Author: Rogerz Zhang <rogerz.zhang at gmail.com> http://github.com/rogerz/vim-json8" Acknowledgement: Based off of vim-javascript maintained by Darrick Wiebe 9" http://www.vim.org/scripts/script.php?script_id=276510 11" 0. Initialization {{{112" =================13 14" Only load this indent file when no other was loaded.15if exists("b:did_indent")16 finish17endif18let b:did_indent = 119 20setlocal nosmartindent21 22" Now, set up our indentation expression and keys that trigger it.23setlocal indentexpr=GetJSONIndent(v:lnum)24setlocal indentkeys=0{,0},0),0[,0],!^F,o,O,e25 26let b:undo_indent = "setl inde< indk< si<"27 28" Only define the function once.29if exists("*GetJSONIndent")30 finish31endif32 33let s:cpo_save = &cpo34set cpo&vim35 36" 1. Variables {{{137" ============38 39let s:line_term = '\s*\%(\%(\/\/\).*\)\=$'40" Regex that defines blocks.41let s:block_regex = '\%({\)\s*\%(|\%([*@]\=\h\w*,\=\s*\)\%(,\s*[*@]\=\h\w*\)*|\)\=' . s:line_term42 43" 2. Auxiliary Functions {{{144" ======================45 46" Check if the character at lnum:col is inside a string.47function s:IsInString(lnum, col)48 return synIDattr(synID(a:lnum, a:col, 1), 'name') == 'jsonString'49endfunction50 51" Find line above 'lnum' that isn't empty, or in a string.52function s:PrevNonBlankNonString(lnum)53 let lnum = prevnonblank(a:lnum)54 while lnum > 055 " If the line isn't empty or in a string, end search.56 let line = getline(lnum)57 if !(s:IsInString(lnum, 1) && s:IsInString(lnum, strlen(line)))58 break59 endif60 let lnum = prevnonblank(lnum - 1)61 endwhile62 return lnum63endfunction64 65" Check if line 'lnum' has more opening brackets than closing ones.66function s:LineHasOpeningBrackets(lnum)67 let open_0 = 068 let open_2 = 069 let open_4 = 070 let line = getline(a:lnum)71 let pos = match(line, '[][(){}]', 0)72 while pos != -173 let idx = stridx('(){}[]', line[pos])74 if idx % 2 == 075 let open_{idx} = open_{idx} + 176 else77 let open_{idx - 1} = open_{idx - 1} - 178 endif79 let pos = match(line, '[][(){}]', pos + 1)80 endwhile81 return (open_0 > 0) . (open_2 > 0) . (open_4 > 0)82endfunction83 84function s:Match(lnum, regex)85 let col = match(getline(a:lnum), a:regex) + 186 return col > 0 && !s:IsInString(a:lnum, col) ? col : 087endfunction88 89" 3. GetJSONIndent Function {{{190" =========================91 92function GetJSONIndent(...)93 " 3.1. Setup {{{294 " ----------95 " For the current line, use the first argument if given, else v:lnum96 let clnum = a:0 ? a:1 : v:lnum97 98 " Set up variables for restoring position in file. Could use clnum here.99 let vcol = col('.')100 101 " 3.2. Work on the current line {{{2102 " -----------------------------103 104 " Get the current line.105 let line = getline(clnum)106 let ind = -1107 108 " If we got a closing bracket on an empty line, find its match and indent109 " according to it.110 let col = matchend(line, '^\s*[]}]')111 112 if col > 0 && !s:IsInString(clnum, col)113 call cursor(clnum, col)114 let bs = strpart('{}[]', stridx('}]', line[col - 1]) * 2, 2)115 116 let pairstart = escape(bs[0], '[')117 let pairend = escape(bs[1], ']')118 let pairline = searchpair(pairstart, '', pairend, 'bW')119 120 if pairline > 0 121 let ind = indent(pairline)122 else123 let ind = virtcol('.') - 1124 endif125 126 return ind127 endif128 129 " If we are in a multi-line string, don't do anything to it.130 if s:IsInString(clnum, matchend(line, '^\s*') + 1)131 return indent('.')132 endif133 134 " 3.3. Work on the previous line. {{{2135 " -------------------------------136 137 let lnum = prevnonblank(clnum - 1)138 139 if lnum == 0140 return 0141 endif142 143 " Set up variables for current line.144 let line = getline(lnum)145 let ind = indent(lnum)146 147 " If the previous line ended with a block opening, add a level of indent.148 " if s:Match(lnum, s:block_regex)149 " return indent(lnum) + shiftwidth()150 " endif151 152 " If the previous line contained an opening bracket, and we are still in it,153 " add indent depending on the bracket type.154 if line =~ '[[({]'155 let counts = s:LineHasOpeningBrackets(lnum)156 if counts[0] == '1' || counts[1] == '1' || counts[2] == '1'157 return ind + shiftwidth()158 else159 call cursor(clnum, vcol)160 end161 endif162 163 " }}}2164 165 return ind166endfunction167 168" }}}1169 170let &cpo = s:cpo_save171unlet s:cpo_save172 173" vim:set sw=2 sts=2 ts=8 noet:174 