Vim LatexSuite missing features

Posted on 2014 03 21 by phimuemue

Since Emacs needs quite an amount of time to start, I decided to give vim a try and am quite happy with it. However, I missed a feature that I appreciated since I came to know it in AucTeX: Showing and browsing the table of contents. So, I implemented a basic table of contents myself.

You can simply copy this to your plugins folder (usually ~/.vim/plugin), and then call :TOC from within an opened tex-file. Moreover, this script enables automatic recognition of custom commands.

For both provided features, the whole document is scanned for sectioning commands and for newcommand-commands.

" latex_helper.vim
python << EOP
import os
import os.path
import re
import codecs
import vim
known_files = [] # a list of files that have already been processed
toc = [] # a list representing the currently viewed table of contents
def readFile(p):
    """Reads a file and extracts custom commands"""
    f = open(p)
    commands = []
    for _line in f:
        line = _line.strip()
        # search for included files
        tmp ="(input|include){(.*)}", line)
        if tmp != None:
            path =
            newpath = os.path.join(os.path.dirname(p), path)
            def _validpath(_path):
                return os.path.exists(_path) and os.path.isfile(_path)
            if _validpath(newpath):
            elif _validpath(newpath+".tex"):
        tmp ="newcommand{(.*?)}\[(.*?)\]", line)
        if tmp != None:
            cmd =
            argc = int(
            commands.append((cmd[1:], argc))
    return commands
def readFile2(p, pattern, successfunc):
    """Reads a file and extracts custom stuff"""
    f = open(p)
    results = []
    for (nr, _line) in enumerate(f, 1):
        line = _line.strip()
        # search for included files
        tmp ="(input|include){(.*)}", line)
        if tmp != None:
            path =
            newpath = os.path.join(os.path.dirname(p), path)
            def _validpath(_path):
                return os.path.exists(_path) and os.path.isfile(_path)
            if _validpath(newpath):
                results.extend(readFile2(newpath, pattern, successfunc))
            elif _validpath(newpath+".tex"):
                results.extend(readFile2(newpath+".tex", pattern, successfunc))
        # search for specific stuff
        tmp =, line)
        if tmp != None:
            results.append(successfunc(tmp, p, nr))
    return results
def getMain(path, startingpoint = None):
    """Goes folders upwards until it finds a *.latexmain file"""
    if startingpoint==None:
        startingpoint = path
    files = []
    if os.path.isdir(path):
        files = os.listdir(path)
    files = [os.path.join(path, s) for s in files if s.split(".")[-1] == "latexmain"]
    if len(files) >= 1:
        return os.path.splitext(files[0])[0]
    if os.path.dirname(path) != path:
        return getMain(os.path.dirname(path), startingpoint)
    return startingpoint
def getCustomLatexCommands():
    """Reads all custom commands and adds them to givm"""
    pattern = r"newcommand{(.*?)}\[(.*?)\]"
    def successfunc(tmp, path, line):
        cmd =
        argc = int(
        return (cmd[1:], argc)
    cmds = readFile2(getMain(, pattern, successfunc)
    for (cmd, argc) in cmds:
        rawstring = 'let g:Tex_Com_%s="\\\\%s%s <++>"'
        vim.command(rawstring%(cmd, cmd, "{<++>}"*argc))
def getTableOfContents(encoding=None):
    """Retrieves the whole table of contents and returns it as a list"""
    sectionings = [ "part", "chapter", "section", "subsection", "subsubsection", "paragraph", "subparagraph", ]
    pattern = "(%s){(.*?)}"%("|".join(sectionings))
    def successfunc(res, path, line):
        depth = sectionings.index(
        name =
        return (name, path, line, depth)
    contents = readFile2(getMain(, pattern, successfunc)
    encodings = []
    if encoding == None:
        encodings = ["utf-8", "iso-8859-1"]
        encodings = [encoding]
    # open a new window and typeset table of contents
    vim.command(":map <CR> :python gotoTocEntry()<CR>")
    vim.command(":map q :bwipeout!<CR>")
    global toc
    toc = []
    for (n, f, l, d) in contents:
        # we simply try several encodings until it works!
        for enc in encodings:
                n=unicode(n, enc)
            vim.current.buffer.append(" "*d + n.encode("utf-8"))
            vim.current.buffer.append("Error (%s:%d)"%(f, l))
        toc.append((f, l))
def gotoTocEntry():
    global toc
    (f, l) = toc[vim.current.window.cursor[0]-2]
    print "opening at line %d..."%(l)
    vim.command(":e! %s"%(f))
    vim.current.window.cursor = (l, 0)
    vim.command(":normal zo")
autocmd BufRead *.tex :py getCustomLatexCommands()
command TOC :python getTableOfContents()