I am trying to manually define indentation levels for .tex
files using ftplugin scripts.
~/.vim/ftplugin/tex/indent.vim
:
1 setlocal indentexpr=TeXIndent(v:lnum)
2
3 function! TeXIndent(lnum)
4 if a:lnum == 0
5 return 0
6 endif
7
8 let prev = getline(a:lnum - 1)
9 let line = getline(a:lnum)
10
11 " sections have hardcoded indentation; environments are always subordinate to sections
12 if prev =~ '^\s*\\section'
13 return 1
14 elseif prev =~ '^\s*\\subsection'
15 return 2
16 elseif prev =~ '^\s*\\subsubsection'
17 return 3
18 elseif prev =~ '^\s*\\paragraph'
19 return 4
20 " environment indentation
21 elseif prev =~ '\\begin'
22 return indent(a:lnum - 1) + 1 " increase indentation by 1 if previous line has \begin
23 elseif line =~ '\\end'
24 return indent(a:lnum - 1) - 1 " decrease indentation by 1 if line has \end
25 else
26 return indent(a:lnum - 1) " use previous indentation
27 endif
28 endfunction
When I type \section
, I expect pressing enter
to move the cursor to an indentation level of 1 on the next line (same for the other conditions, specified in TeXIndent
), and this is not the case. Testing with a simpler function which returns 2 every time also lacks this behavior, so I suspect my approach is flawed. How do I achieve the expected behavior?
In general, how can ftplugin scripts be debugged?
All usual approaches are available when debugging a ftplugin.
:debug exe "normal keysequence"
can be used to debug a mapping:debug Command
can be used to debug a command, a function (with :debug call
or :debug echo
)...:verbose
can be used to know what is actually defined and where it has been defined -- see this dedicated Q/A on vi.SE: https://vi.stackexchange.com/q/7722/626Now your problem is not with ftplugins but with indent expressions. If I'm not mistaken, it faces the same issues than the ones we can have with fold expression: the indenting/folding function is automatically called once per line by Vim. Messages will be silenced, internal uses of :debug
will end in nightmares.
What can we do:
log to a file, or elsewhere like the qf window
don't tie the function to v:lnum
in order to be able to call that function independently. That's perfect, it's what you already did. We can test response from all calls with
:echo map(range(1, line('$')), 'the_expr_function(v:val)')
play with balloons (requires gvim instead of vim)
play with signs
You'll find these methods used in a folding plugin I'm maintaining.
(See also this Q/A on vi.SE: https://vi.stackexchange.com/a/19916/626)
PS: indent plugins shall go into {rtp}/indent/
, not {rtp}/ftplugin/
, and we usually analyse the last non empty line. You should find examples in $VIMRUNTIME/indent
, and I have few TeX indent plugins written by Johannes Zellner circa 2002.