summaryrefslogtreecommitdiffstats
path: root/autoload/jsx_pretty/indent.vim
diff options
context:
space:
mode:
Diffstat (limited to 'autoload/jsx_pretty/indent.vim')
-rw-r--r--autoload/jsx_pretty/indent.vim204
1 files changed, 204 insertions, 0 deletions
diff --git a/autoload/jsx_pretty/indent.vim b/autoload/jsx_pretty/indent.vim
new file mode 100644
index 00000000..a4e7a839
--- /dev/null
+++ b/autoload/jsx_pretty/indent.vim
@@ -0,0 +1,204 @@
+if exists('g:polyglot_disabled') && index(g:polyglot_disabled, 'jsx') != -1
+ finish
+endif
+
+if exists('*shiftwidth')
+ function! s:sw()
+ return shiftwidth()
+ endfunction
+else
+ function! s:sw()
+ return &sw
+ endfunction
+endif
+
+" Get the syntax group of start of line
+function! s:syn_sol(lnum)
+ let line = getline(a:lnum)
+ let sol = matchstr(line, '^\s*')
+ return map(synstack(a:lnum, len(sol) + 1), 'synIDattr(v:val, "name")')
+endfunction
+
+" Get the syntax group of end of line
+function! s:syn_eol(lnum)
+ let lnum = prevnonblank(a:lnum)
+ let col = strlen(getline(lnum))
+ return map(synstack(lnum, col), 'synIDattr(v:val, "name")')
+endfunction
+
+function! s:prev_indent(lnum)
+ let lnum = prevnonblank(a:lnum - 1)
+ return indent(lnum)
+endfunction
+
+function! s:prev_line(lnum)
+ let lnum = prevnonblank(a:lnum - 1)
+ return substitute(getline(lnum), '^\s*\|\s*$', '', 'g')
+endfunction
+
+function! s:syn_attr_jsx(synattr)
+ return a:synattr =~ "^jsx"
+endfunction
+
+function! s:syn_xmlish(syns)
+ return s:syn_attr_jsx(get(a:syns, -1))
+endfunction
+
+function! s:syn_jsx_element(syns)
+ return get(a:syns, -1) =~ 'jsxElement'
+endfunction
+
+function! s:syn_js_comment(syns)
+ return get(a:syns, -1) =~ 'Comment$'
+endfunction
+
+function! s:syn_jsx_escapejs(syns)
+ return get(a:syns, -1) =~ '\(\(js\(Template\)\?\|javaScript\(Embed\)\?\|typescript\)Braces\|javascriptTemplateSB\|typescriptInterpolationDelimiter\)' &&
+ \ (get(a:syns, -2) =~ 'jsxEscapeJs' ||
+ \ get(a:syns, -3) =~ 'jsxEscapeJs')
+endfunction
+
+function! s:syn_jsx_attrib(syns)
+ return len(filter(copy(a:syns), 'v:val =~ "jsxAttrib"'))
+endfunction
+
+let s:start_tag = '<\s*\([-:_\.\$0-9A-Za-z]\+\|>\)'
+" match `/end_tag>` and `//>`
+let s:end_tag = '/\%(\s*[-:_\.\$0-9A-Za-z]*\s*\|/\)>'
+let s:opfirst = '^' . get(g:,'javascript_opfirst',
+ \ '\C\%([<>=,.?^%|/&]\|\([-:+]\)\1\@!\|\*\+\|!=\|in\%(stanceof\)\=\>\)')
+
+function! jsx_pretty#indent#get(js_indent)
+ let lnum = v:lnum
+ let line = substitute(getline(lnum), '^\s*\|\s*$', '', 'g')
+ let current_syn = s:syn_sol(lnum)
+ let current_syn_eol = s:syn_eol(lnum)
+ let prev_syn_sol = s:syn_sol(lnum - 1)
+ let prev_syn_eol = s:syn_eol(lnum - 1)
+ let prev_line = s:prev_line(lnum)
+ let prev_ind = s:prev_indent(lnum)
+
+ if s:syn_xmlish(current_syn)
+
+ " {
+ " <div></div>
+ " ##} <--
+ if s:syn_jsx_element(current_syn) && line =~ '}$'
+ let pair_line = searchpair('{', '', '}', 'b')
+ return indent(pair_line)
+ elseif line =~ '^-->$'
+ if prev_line =~ '^<!--'
+ return prev_ind
+ else
+ return prev_ind - s:sw()
+ endif
+ elseif prev_line =~ '-->$'
+ return prev_ind
+ " close tag </tag> or /> including </>
+ elseif prev_line =~ s:end_tag . '$'
+ if line =~ '^<\s*' . s:end_tag
+ return prev_ind - s:sw()
+ elseif s:syn_jsx_attrib(prev_syn_sol)
+ return prev_ind - s:sw()
+ else
+ return prev_ind
+ endif
+ elseif line =~ '^\(>\|/\s*>\)'
+ if prev_line =~ '^<'
+ return prev_ind
+ else
+ return prev_ind - s:sw()
+ endif
+ elseif prev_line =~ '^\(<\|>\)' &&
+ \ (s:syn_xmlish(prev_syn_eol) || s:syn_js_comment(prev_syn_eol))
+ if line =~ '^<\s*' . s:end_tag
+ return prev_ind
+ else
+ return prev_ind + s:sw()
+ endif
+ elseif line =~ '^<\s*' . s:end_tag
+ if !s:syn_xmlish(prev_syn_sol)
+ if s:syn_jsx_escapejs(prev_syn_eol)
+ \ || s:syn_jsx_escapejs(prev_syn_sol)
+ return prev_ind - s:sw()
+ else
+ return prev_ind
+ endif
+ else
+ return prev_ind - s:sw()
+ endif
+ elseif !s:syn_xmlish(prev_syn_eol)
+ if prev_line =~ '\(&&\|||\|=>\|[([{]\|`\)$'
+ " <div>
+ " {
+ " }
+ " </div>
+ if line =~ '^[)\]}]'
+ return prev_ind
+ else
+ return prev_ind + s:sw()
+ endif
+ else
+ return prev_ind
+ endif
+ elseif !s:syn_xmlish(prev_syn_sol)
+ if prev_line =~ '^\<\(return\|default\|await\|yield\)'
+ if line !~ '^/\s*>' || line !~ '^<\s*' . s:end_tag
+ return prev_ind + s:sw()
+ else
+ return prev_ind
+ endif
+ else
+ return prev_ind
+ endif
+ else
+ return prev_ind
+ endif
+ elseif s:syn_jsx_escapejs(current_syn)
+ if line =~ '^}'
+ let char = getline('.')[col('.') - 1]
+ " When pressing enter after the }, keep the indent
+ if char != '}' && search('}', 'b', lnum)
+ return indent(lnum)
+ else
+ let pair_line = searchpair('{', '', '}', 'bW')
+ return indent(pair_line)
+ endif
+ elseif line =~ '^{' || line =~ '^\${'
+ if s:syn_jsx_escapejs(prev_syn_eol)
+ \ || s:syn_jsx_attrib(prev_syn_sol)
+ return prev_ind
+ elseif s:syn_xmlish(prev_syn_eol) && (prev_line =~ s:end_tag || prev_line =~ '-->$')
+ return prev_ind
+ else
+ return prev_ind + s:sw()
+ endif
+ endif
+ elseif s:syn_jsx_escapejs(current_syn_eol)
+ let pair_line = searchpair('{', '', '}', 'bW')
+ return indent(pair_line)
+ elseif line =~ '^/[/*]' " js comment in jsx tag
+ if get(prev_syn_sol, -1) =~ 'Punct'
+ return prev_ind + s:sw()
+ elseif synIDattr(synID(lnum - 1, 1, 1), 'name') =~ 'jsxTag'
+ return prev_ind
+ else
+ return a:js_indent()
+ endif
+ else
+ let ind = a:js_indent()
+
+ " If current syntax is not a jsx syntax group
+ if s:syn_xmlish(prev_syn_eol) && line !~ '^[)\]}]'
+ let sol = matchstr(line, s:opfirst)
+ if sol is ''
+ " Fix javascript continue indent
+ return ind - s:sw()
+ else
+ return ind
+ endif
+ endif
+ return ind
+ endif
+
+endfunction