xref: /vim-8.2.3635/runtime/indent/json.vim (revision 6c391a74)
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