diff runtime/indent/tex.vim @ 8392:1bf1b88968a2

commit https://github.com/vim/vim/commit/328da0dcb7be34b594725eef6dc98d3ea6516d69 Author: Bram Moolenaar <Bram@vim.org> Date: Fri Mar 4 22:22:32 2016 +0100 Update runtime files.
author Christian Brabandt <cb@256bit.org>
date Fri, 04 Mar 2016 22:30:06 +0100
parents eb6ab7e78925
children d183d629509e
line wrap: on
line diff
--- a/runtime/indent/tex.vim
+++ b/runtime/indent/tex.vim
@@ -2,10 +2,9 @@
 " Language:     LaTeX
 " Maintainer:   YiChao Zhou <broken.zhou AT gmail.com>
 " Created:      Sat, 16 Feb 2002 16:50:19 +0100
-" Last Change:	2012 Mar 18 19:19:50
-" Version: 0.7
-"   Please email me if you found something we can do.  Bug report and
-"   feature request is welcome.
+" Version: 0.9.2
+"   Please email me if you found something I can do.  Comments, bug report and
+"   feature request are welcome.
 
 " Last Update:  {{{
 "               25th Sep 2002, by LH :
@@ -41,7 +40,7 @@
 "               (*) Trust user when in "verbatim" and "lstlisting"
 "               2012/03/11 by Zhou Yichao <broken.zhou AT gmail.com>
 "               (*) Modify "&" so that only indent when current line start with
-"               "&".
+"                   "&".
 "               2012/03/12 by Zhou Yichao <broken.zhou AT gmail.com>
 "               (*) Modify indentkeys.
 "               2012/03/18 by Zhou Yichao <broken.zhou AT gmail.com>
@@ -49,6 +48,17 @@
 "               2013/05/02 by Zhou Yichao <broken.zhou AT gmail.com>
 "               (*) Fix problem about GetTeXIndent checker. Thank Albert Netymk
 "                   for reporting this.
+"               2014/06/23 by Zhou Yichao <broken.zhou AT gmail.com>
+"               (*) Remove the feature g:tex_indent_and because it is buggy.
+"               (*) If there is not any obvious indentation hints, we do not
+"                   alert our user's current indentation.
+"               (*) g:tex_indent_brace now only works if the open brace is the
+"                   last character of that line.
+"               2014/08/03 by Zhou Yichao <broken.zhou AT gmail.com>
+"               (*) Indent current line if last line has larger indentation
+"               2014/08/09 by Zhou Yichao <broken.zhou AT gmail.com>
+"               (*) Add missing return value for s:GetEndIndentation(...)
+"
 " }}}
 
 " Document: {{{
@@ -60,7 +70,17 @@
 " * g:tex_indent_brace
 "
 "   If this variable is unset or non-zero, it will use smartindent-like style
-"   for "{}" and "[]"
+"   for "{}" and "[]".  Now this only works if the open brace is the last
+"   character of that line.
+"
+"         % Example 1
+"         \usetikzlibrary{
+"           external
+"         }
+"
+"         % Example 2
+"         \tikzexternalize[
+"           prefix=tikz]
 "   
 " * g:tex_indent_items
 "
@@ -98,14 +118,6 @@
 "
 "   A list of environment names. separated with '\|', where no indentation is 
 "   required. The default is 'document\|verbatim'.
-"
-" * g:tex_indent_and
-"
-"   If this variable is unset or zero, vim will try to align the line with first
-"   "&". This is pretty useful when you use environment like table or align.
-"   Note that this feature need to search back some line, so vim may become
-"   a little slow.
-"
 " }}} 
 
 " Only define the function once
@@ -126,8 +138,8 @@ endif
 if !exists("g:tex_indent_brace")
     let g:tex_indent_brace = 1
 endif
-if !exists("g:tex_indent_and")
-    let g:tex_indent_and = 1
+if !exists("g:tex_max_scan_line")
+    let g:tex_max_scan_line = 60
 endif
 if g:tex_indent_items
     if !exists("g:tex_itemize_env")
@@ -140,10 +152,6 @@ else
     let g:tex_items = ''
 endif
 
-if !exists("g:tex_indent_paretheses")
-    let g:tex_indent_paretheses = 1
-endif
-
 if !exists("g:tex_noindent_env")
     let g:tex_noindent_env = 'document\|verbatim\|lstlisting'
 endif "}}}
@@ -160,6 +168,7 @@ let g:tex_items = '^\s*' . substitute(g:
 function! GetTeXIndent() " {{{
     " Find a non-blank line above the current line.
     let lnum = prevnonblank(v:lnum - 1)
+    let cnum = v:lnum
 
     " Comment line is not what we need.
     while lnum != 0 && getline(lnum) =~ '^\s*%'
@@ -171,8 +180,8 @@ function! GetTeXIndent() " {{{
         return 0 
     endif
 
-    let line = substitute(getline(lnum), '%.*', ' ','g')     " last line
-    let cline = substitute(getline(v:lnum), '%.*', ' ', 'g') " current line
+    let line = substitute(getline(lnum), '\s*%.*', '','g')     " last line
+    let cline = substitute(getline(v:lnum), '\s*%.*', '', 'g') " current line
 
     "  We are in verbatim, so do what our user what.
     if synIDattr(synID(v:lnum, indent(v:lnum), 1), "name") == "texZone"
@@ -183,26 +192,12 @@ function! GetTeXIndent() " {{{
         end
     endif
     
-    " You want to align with "&"
-    if g:tex_indent_and
-        " Align only when current line start with "&"
-        if line =~ '&.*\\\\' && cline =~ '^\s*&'
-            return indent(v:lnum) + stridx(line, "&") - stridx(cline, "&")
-        endif
-
-        " set line & lnum to the line which doesn't contain "&"
-        while lnum != 0 && (stridx(line, "&") != -1 || line =~ '^\s*%')
-            let lnum = prevnonblank(lnum - 1)
-            let line = getline(lnum)
-        endwhile
-    endif
-
-
     if lnum == 0
         return 0 
     endif
 
     let ind = indent(lnum)
+    let stay = 1
 
     " New code for comment: retain the indent of current line
     if cline =~ '^\s*%'
@@ -216,77 +211,197 @@ function! GetTeXIndent() " {{{
     " ZYC modification : \end after \begin won't cause wrong indent anymore
     if line =~ '\\begin{.*}' && line !~ g:tex_noindent_env
         let ind = ind + &sw
+        let stay = 0
 
         if g:tex_indent_items
             " Add another sw for item-environments
             if line =~ g:tex_itemize_env
                 let ind = ind + &sw
+                let stay = 0
             endif
         endif
     endif
 
+    if cline =~ '\\end{.*}'
+        let retn = s:GetEndIndentation(v:lnum)
+        if retn != -1
+            return retn
+        endif
+    end
     " Subtract a 'shiftwidth' when an environment ends
-    if cline =~ '\\end{.*}' && cline !~ g:tex_noindent_env
-
+    if cline =~ '\\end{.*}'
+                \ && cline !~ g:tex_noindent_env
+                \ && cline !~ '\\begin{.*}.*\\end{.*}'
         if g:tex_indent_items
             " Remove another sw for item-environments
             if cline =~ g:tex_itemize_env
                 let ind = ind - &sw
+                let stay = 0
             endif
         endif
 
         let ind = ind - &sw
+        let stay = 0
     endif
 
     if g:tex_indent_brace
-        let sum1 = 0
-        for i in range(0, strlen(line)-1)
-            if line[i] == "}" || line[i] == "]" ||
-                        \ strpart(line, i, 7) == '\right)'
-                let sum1 = max([0, sum1-1])
-            endif
-            if line[i] == "{" || line[i] == "[" ||
-                        \ strpart(line, i, 6) == '\left('
-                let sum1 += 1
+        let char = line[strlen(line)-1]
+        if char == '[' || char == '{'
+            let ind += &sw
+            let stay = 0
+        endif
+
+        let cind = indent(v:lnum)
+        let char = cline[cind]
+        if (char == ']' || char == '}') &&
+                    \ s:CheckPairedIsLastCharacter(v:lnum, cind)
+            let ind -= &sw
+            let stay = 0
+        endif
+
+        for i in range(indent(lnum)+1, strlen(line)-1)
+            let char = line[i]
+            if char == ']' || char == '}'
+                if s:CheckPairedIsLastCharacter(lnum, i)
+                    let ind -= &sw
+                    let stay = 0
+                endif
             endif
         endfor
-
-        let sum2 = 0
-        for i in reverse(range(0, strlen(cline)-1))
-            if cline[i] == "{" || cline[i] == "[" ||
-                        \ strpart(cline, i, 6) == '\left('
-                let sum2 = max([0, sum2-1])
-            endif
-            if cline[i] == "}" || cline[i] == "]" ||
-                        \ strpart(cline, i, 7) == '\right)'
-                let sum2 += 1
-            endif
-        endfor
-
-        let ind += (sum1 - sum2) * &sw
-    endif
-
-    if g:tex_indent_paretheses
     endif
 
     " Special treatment for 'item'
     " ----------------------------
 
     if g:tex_indent_items
-
         " '\item' or '\bibitem' itself:
         if cline =~ g:tex_items
             let ind = ind - &sw
+            let stay = 0
         endif
-
         " lines following to '\item' are intented once again:
         if line =~ g:tex_items
             let ind = ind + &sw
+            let stay = 0
         endif
+    endif
 
+    if stay
+        " If there is no obvious indentation hint, we trust our user.
+        if empty(cline)
+            return ind
+        else
+            return max([indent(v:lnum), s:GetLastBeginIndentation(v:lnum)])
+        endif
+    else
+        return ind
+    endif
+endfunction "}}}
+
+function! s:GetLastBeginIndentation(lnum) " {{{
+    let matchend = 1
+    for lnum in range(a:lnum-1, max([a:lnum - g:tex_max_scan_line, 1]), -1)
+        let line = getline(lnum)
+        if line =~ '\\end{.*}'
+            let matchend += 1
+        endif
+        if line =~ '\\begin{.*}'
+            let matchend -= 1
+        endif
+        if matchend == 0
+            if line =~ g:tex_itemize_env
+                return indent(lnum) + 2 * &sw
+            endif
+            if line =~ g:tex_noindent_env
+                return indent(lnum)
+            endif
+            return indent(lnum) + &sw
+        endif
+    endfor
+    return -1
+endfunction
+
+function! s:GetEndIndentation(lnum) " {{{
+    if getline(a:lnum) =~ '\\begin{.*}.*\\end{.*}'
+        return -1
     endif
 
-    return ind
+    let min_indent = 100
+    let matchend = 1
+    for lnum in range(a:lnum-1, max([a:lnum-g:tex_max_scan_line, 1]), -1)
+        let line = getline(lnum)
+        if line =~ '\\end{.*}'
+            let matchend += 1
+        endif
+        if line =~ '\\begin{.*}'
+            let matchend -= 1
+        endif
+        if matchend == 0
+            return indent(lnum)
+        endif
+        if !empty(line)
+            let min_indent = min([min_indent, indent(lnum)])
+        endif
+    endfor
+    return min_indent - &sw
+endfunction
+
+" Most of the code is from matchparen.vim
+function! s:CheckPairedIsLastCharacter(lnum, col) "{{{
+    " Get the character under the cursor and check if it's in 'matchpairs'.
+    let c_lnum = a:lnum
+    let c_col = a:col+1
+
+
+    let c = getline(c_lnum)[c_col-1]
+    let plist = split(&matchpairs, '.\zs[:,]')
+    let i = index(plist, c)
+    if i < 0
+        return 0
+    endif
+
+    " Figure out the arguments for searchpairpos().
+    if i % 2 == 0
+        let s_flags = 'nW'
+        let c2 = plist[i + 1]
+    else
+        let s_flags = 'nbW'
+        let c2 = c
+        let c = plist[i - 1]
+    endif
+    if c == '['
+        let c = '\['
+        let c2 = '\]'
+    endif
+
+    " Find the match.  When it was just before the cursor move it there for a
+    " moment.
+    let save_cursor = winsaveview()
+    call cursor(c_lnum, c_col)
+
+    " When not in a string or comment ignore matches inside them.
+    " We match "escape" for special items, such as lispEscapeSpecial.
+    let s_skip ='synIDattr(synID(line("."), col("."), 0), "name") ' .
+                \ '=~?  "string\\|character\\|singlequote\\|escape\\|comment"'
+    execute 'if' s_skip '| let s_skip = 0 | endif'
+
+    let stopline = max([0, c_lnum - g:tex_max_scan_line])
+
+    " Limit the search time to 300 msec to avoid a hang on very long lines.
+    " This fails when a timeout is not supported.
+    try
+        let [m_lnum, m_col] = searchpairpos(c, '', c2, s_flags, s_skip, stopline, 100)
+    catch /E118/
+    endtry
+
+    call winrestview(save_cursor)
+
+    if m_lnum > 0
+        let line = getline(m_lnum)
+        return strlen(line) == m_col
+    endif
+
+    return 0
 endfunction "}}}
 
 let &cpo = s:cpo_save