Navigating Python modules with ctags in Vim?
Asked Answered
S

2

7

I'm using Vim with ctags for Python and that works very well for classes, fields, etc, but what it doesn't seem to include are Python file names aka module names. Is this possible? I'd far prefer to type ta <module> to jump to a module, rather than navigate level-by-level with a file browser like NERDtree, and I'm very accustomed to doing this in Java, which works out since class names are file names.

Sprite answered 28/5, 2014 at 15:23 Comment(0)
V
8

If you generate your tags file using exuberant ctags (Is there any other way?) then try adding the --extra=+f option. See the man page at http://ctags.sourceforge.net/ctags.html#OPTIONS for details.

Vinegary answered 28/5, 2014 at 21:48 Comment(1)
Sadly, not on ubuntu 12.04, which doesn't have that option (or the very useful -R option). I use a script that collects the files, runs ctags, appends a line for each filename to tags, and then sorts it. What's with ubuntu and ctags from the 90's anyway?Overgrowth
L
3

Exuberant tags (with --extra=+f) generates tags for python file-names (e.g. my_module.py), but not for the module name (e.g. my_module). I ended up creating a modified version of the ptags script. Save the following to a file named ptags somewhere in your path and make it executable:

#! /usr/bin/env python

# ptags
#
# Create a tags file for Python programs, usable with vi.
# Tagged are:
# - functions (even inside other defs or classes)
# - classes
# - filenames
# Warns about files it cannot open.
# No warnings about duplicate tags.

import sys, re, os
import argparse

tags = []    # Modified global variable!

def main():
    for root, folders, files in os.walk(args.folder_to_index):
        for filename in files:
            if filename.endswith('.py'):
                full_path = os.path.join(root, filename)
                treat_file(full_path)
        if not args.recursive:
            break

    if tags:
        fp = open(args.ctags_filename, 'w')
        tags.sort()
        for s in tags: fp.write(s)

expr = '^[ \t]*(def|class)[ \t]+([a-zA-Z0-9_]+)[ \t]*[:\(]'
matcher = re.compile(expr)

def treat_file(filename):
    try:
        fp = open(filename, 'r')
    except:
        sys.stderr.write('Cannot open %s\n' % filename)
        return
    base = os.path.basename(filename)
    if base[-3:] == '.py':
        base = base[:-3]
    s = base + '\t' + filename + '\t' + '1\n'
    tags.append(s)
    while 1:
        line = fp.readline()
        if not line:
            break
        m = matcher.match(line)
        if m:
            content = m.group(0)
            name = m.group(2)
            s = name + '\t' + filename + '\t/^' + content + '/\n'
            tags.append(s)

if __name__ == '__main__':
    p = argparse.ArgumentParser()
    p.add_argument('-f', '--ctags-filename', type=str, default='tags')
    p.add_argument('-R', '--recursive', action='store_true')
    p.add_argument('folder_to_index', type=str, default='.')
    args = p.parse_args()
    main()

Now run the following to generate a tags file by recursively processing the current directory:

ptags -R -f tags_file_to_create /path/to/index

Laughlin answered 8/6, 2017 at 13:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.