Vim LatexSuite missing features

Posted on October 10, 2011 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 = re.search(r"(input|include){(.*)}", line)
        if tmp != None:
            path = tmp.group(2)
            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):
                commands.extend(readFile(newpath))
            elif _validpath(newpath+".tex"):
                commands.extend(readFile(newpath+".tex"))
        tmp = re.search(r"newcommand{(.*?)}\[(.*?)\]", line)
        if tmp != None:
            cmd = tmp.group(1)
            argc = int(tmp.group(2))
            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 = re.search(r"(input|include){(.*)}", line)
        if tmp != None:
            path = tmp.group(2)
            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 = re.search(pattern, 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 = tmp.group(1)
        argc = int(tmp.group(2))
        return (cmd[1:], argc)
    cmds = readFile2(getMain(vim.current.buffer.name), 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(res.group(1))
        name = res.group(2)
        return (name, path, line, depth)
    contents = readFile2(getMain(vim.current.buffer.name), pattern, successfunc)
    encodings = []
    if encoding == None:
        encodings = ["utf-8", "iso-8859-1"]
    else:
        encodings = [encoding]
    # open a new window and typeset table of contents
    vim.command(":new")
    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:
            try:
                n=unicode(n, enc)
                break
            except:
                pass
        try:
            vim.current.buffer.append(" "*d + n.encode("utf-8"))
        except:
            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]
    vim.command(":bwipeout!")
    print "opening at line %d..."%(l)
    vim.command(":e! %s"%(f))
    vim.current.window.cursor = (l, 0)
    vim.command(":normal zo")
 
EOP
 
autocmd BufRead *.tex :py getCustomLatexCommands()
command TOC :python getTableOfContents()