A while ago I wrote a little script that generated an outline of the Python file I was working on. I’ve been using it for a while and quite like it, so I figured I’d share it.
define-command python-outline \
-docstring "Build an outline view of the current Python source file." \
%{
evaluate-commands -save-regs 'ab' %{
# Save the file we're building an outline for.
reg a %val{buffile}
try %{
# Don't save any registers,
# we want to keep the yank register for later.
execute-keys -draft -save-regs '' \
<percent> \
s\n?^\h*(class|def)[^\n]+\n<ret> \
'"by'
} catch %{
fail "No Python classes or functions in this source file."
}
# Make the outline appear in the toolsclient, if possible.
evaluate-commands -try-client %opt{toolsclient} %{
# Make a scratch buffer to render the outline
try %{ delete-buffer! *outline* }
edit -scratch *outline*
# Paste the filename, then all the landmarks
execute-keys -draft '"aP' A<ret><esc> '"b<a-p>'
set-option buffer filetype python
set-option buffer readonly true
map buffer normal <ret> ':python-outline-jump<ret>'
}
}
}
define-command -hidden python-outline-jump %{
evaluate-commands -save-regs ab %{
evaluate-commands -draft %{
# collect the line we want to search for in "b
execute-keys xs\w+[^\n]*<ret>"by
# collect the filename in "a
execute-keys ggxH"ay
}
evaluate-commands -try-client %opt{jumpclient} %{
buffer %reg{a}
execute-keys /\Q <c-r>b <ret> vt
}
}
}
hook global WinSetOption filetype=python %{
map window goto o -docstring "File outline" \
'<esc>:python-outline<ret>'
hook -once -always window WinSetOption filetype=.* %{
unmap window goto o
}
}
The hook at the end lets me go to the outline with go
, which seems natural enough.
To jump back to the source, it selects the line you hit <ret>
on and searches for it in the original buffer. That’s not 100% reliable, since (for example) there’s probably going to be many def __init__(self):
lines in a Python source file, for example. But since you’re looking at the full outline, it’s not difficult to just pick the nearest uniquely-named item, go there, and scroll to the one you want.