| 
									
										
										
										
											2014-07-19 14:04:47 +02:00
										 |  |  | " Vim indent file | 
					
						
							|  |  |  | " Language:		JSON | 
					
						
							| 
									
										
										
										
											2014-08-29 15:12:19 +02:00
										 |  |  | " Mantainer:		Eli Parra <eli@elzr.com> https://github.com/elzr/vim-json | 
					
						
							| 
									
										
										
										
											2020-09-07 22:18:52 +02:00
										 |  |  | " Last Change:          2020 Aug 30 | 
					
						
							| 
									
										
										
										
											2014-08-29 15:12:19 +02:00
										 |  |  | "   https://github.com/jakar/vim-json/commit/20b650e22aa750c4ab6a66aa646bdd95d7cd548a#diff-e81fc111b2052e306d126bd9989f7b7c | 
					
						
							|  |  |  | " Original Author:	Rogerz Zhang <rogerz.zhang at gmail.com> http://github.com/rogerz/vim-json | 
					
						
							|  |  |  | " Acknowledgement:      Based off of vim-javascript maintained by Darrick Wiebe  | 
					
						
							|  |  |  | "                       http://www.vim.org/scripts/script.php?script_id=2765 | 
					
						
							| 
									
										
										
										
											2014-07-19 14:04:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-29 15:12:19 +02:00
										 |  |  | " 0. Initialization {{{1 | 
					
						
							|  |  |  | " ================= | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | " Only load this indent file when no other was loaded. | 
					
						
							|  |  |  | if exists("b:did_indent") | 
					
						
							|  |  |  |   finish | 
					
						
							| 
									
										
										
										
											2014-07-19 14:04:47 +02:00
										 |  |  | endif | 
					
						
							| 
									
										
										
										
											2014-08-29 15:12:19 +02:00
										 |  |  | let b:did_indent = 1 | 
					
						
							| 
									
										
										
										
											2014-07-19 14:04:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-29 15:12:19 +02:00
										 |  |  | setlocal nosmartindent | 
					
						
							| 
									
										
										
										
											2014-07-19 14:04:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-29 15:12:19 +02:00
										 |  |  | " Now, set up our indentation expression and keys that trigger it. | 
					
						
							| 
									
										
										
										
											2020-09-07 22:18:52 +02:00
										 |  |  | setlocal indentexpr=GetJSONIndent(v:lnum) | 
					
						
							| 
									
										
										
										
											2014-08-29 15:12:19 +02:00
										 |  |  | setlocal indentkeys=0{,0},0),0[,0],!^F,o,O,e | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | " Only define the function once. | 
					
						
							|  |  |  | if exists("*GetJSONIndent") | 
					
						
							|  |  |  |   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. GetJSONIndent Function {{{1 | 
					
						
							|  |  |  | " ========================= | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-07 22:18:52 +02:00
										 |  |  | function GetJSONIndent(...) | 
					
						
							| 
									
										
										
										
											2014-08-29 15:12:19 +02:00
										 |  |  |   " 3.1. Setup {{{2 | 
					
						
							|  |  |  |   " ---------- | 
					
						
							| 
									
										
										
										
											2020-09-07 22:18:52 +02:00
										 |  |  |   " For the current line, use the first argument if given, else v:lnum | 
					
						
							|  |  |  |   let clnum = a:0 ? a:1 : v:lnum | 
					
						
							| 
									
										
										
										
											2014-08-29 15:12:19 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-07 22:18:52 +02:00
										 |  |  |   " Set up variables for restoring position in file.  Could use clnum here. | 
					
						
							| 
									
										
										
										
											2014-08-29 15:12:19 +02:00
										 |  |  |   let vcol = col('.') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   " 3.2. Work on the current line {{{2 | 
					
						
							|  |  |  |   " ----------------------------- | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   " Get the current line. | 
					
						
							| 
									
										
										
										
											2020-09-07 22:18:52 +02:00
										 |  |  |   let line = getline(clnum) | 
					
						
							| 
									
										
										
										
											2014-08-29 15:12:19 +02:00
										 |  |  |   let ind = -1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   " If we got a closing bracket on an empty line, find its match and indent | 
					
						
							|  |  |  |   " according to it. | 
					
						
							|  |  |  |   let col = matchend(line, '^\s*[]}]') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-07 22:18:52 +02:00
										 |  |  |   if col > 0 && !s:IsInString(clnum, col) | 
					
						
							|  |  |  |     call cursor(clnum, col) | 
					
						
							| 
									
										
										
										
											2014-08-29 15:12:19 +02:00
										 |  |  |     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. | 
					
						
							| 
									
										
										
										
											2020-09-07 22:18:52 +02:00
										 |  |  |   if s:IsInString(clnum, matchend(line, '^\s*') + 1) | 
					
						
							| 
									
										
										
										
											2014-08-29 15:12:19 +02:00
										 |  |  |     return indent('.') | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   " 3.3. Work on the previous line. {{{2 | 
					
						
							|  |  |  |   " ------------------------------- | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-07 22:18:52 +02:00
										 |  |  |   let lnum = prevnonblank(clnum - 1) | 
					
						
							| 
									
										
										
										
											2014-08-29 15:12:19 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   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) | 
					
						
							| 
									
										
										
										
											2017-06-13 18:12:01 +02:00
										 |  |  |     " return indent(lnum) + shiftwidth() | 
					
						
							| 
									
										
										
										
											2014-08-29 15:12:19 +02:00
										 |  |  |   " 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' | 
					
						
							| 
									
										
										
										
											2017-06-13 18:12:01 +02:00
										 |  |  |       return ind + shiftwidth() | 
					
						
							| 
									
										
										
										
											2014-08-29 15:12:19 +02:00
										 |  |  |     else | 
					
						
							| 
									
										
										
										
											2020-09-07 22:18:52 +02:00
										 |  |  |       call cursor(clnum, vcol) | 
					
						
							| 
									
										
										
										
											2014-08-29 15:12:19 +02:00
										 |  |  |     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: |