mirror of
1
0
Fork 0
ultimate-vim/vim_plugins_src/VOoM-4.3/VOoM-4.3/doc/voom.txt

4123 lines
167 KiB
Plaintext

*voom.txt* VOoM -- Vim two-pane outliner
Last Modified: 2012-05-06
VOoM -- Vim two-pane outliner, plugin for Python-enabled Vim version 7.x
Version: 4.3
Website: http://www.vim.org/scripts/script.php?script_id=2657
Author: Vlad Irnov (vlad DOT irnov AT gmail DOT com)
License: WTFPL Version 2, see http://sam.zoy.org/wtfpl/COPYING
Overview . . . . . . . . . . . . . . . . . . . .|voom_overview|
Requirements . . . . . . . . . . . . . . . . . .|voom_requirements|
Installation . . . . . . . . . . . . . . . . . .|voom_install|
Options . . . . . . . . . . . . . . . . . . . . .|voom_options|
ALL MAPPINGS & COMMANDS . . . . . . . . . . . . .|voom_map|
OUTLINING (:Voom) . . . . . . . . . . . . . . . .|voom_Voom|
EXECUTING NODES (:Voomexec) . . . . . . . . . . .|voom_Voomexec|
__PyLog__ BUFFER (:Voomlog) . . . . . . . . . . .|voom_Voomlog|
Add-ons . . . . . . . . . . . . . . . . . . . . .|voom_addons|
Implementation notes . . . . . . . . . . . . . .|voom_notes|
==============================================================================
Overview [[[1~
*voom_overview*
VOoM (Vim Outliner of Markers) is a plugin for Vim that emulates a two-pane
text outliner.
Screenshots and an animation: http://vim-voom.github.com/
VOoM was originally written to work with start fold markers with level numbers,
such as in this help file. This is the most versatile outline markup -- it is
suitable for organizing all kinds of files, including source code, and it
allows features not possible with other markups (|fold-marker|).
Markers are specified by option 'foldmarker'. End fold markers with levels are
not supported.
VOoM currently can handle several other markup formats that have headlines and
support an outline structure. (Headlines are also called headings, headers,
section headers, titles.) Available markup modes:
wiki |voom_mode_wiki|
vimwiki |voom_mode_vimwiki|
viki |voom_mode_viki|
org |voom_mode_org|
rest |voom_mode_rest|
markdown |voom_mode_markdown|
hashes |voom_mode_hashes|
txt2tags |voom_mode_txt2tags|
asciidoc |voom_mode_asciidoc|
html |voom_mode_html|
thevimoutliner |voom_mode_thevimoutliner|
vimoutliner |voom_mode_vimoutliner|
python |voom_mode_python|
fmr1, fmr2 |voom_mode_fmr|
various other |voom_mode_various|
FEATURES:
- Works with Vim buffers, not with files on disk as ctags-based tools.
- Automatic outline update on entering the Tree buffer.
- Not a 'filetype' plugin. Not tied to a particular outline format.
Has (almost) no side effects on the buffer being outlined.
- Fast and efficient enough to handle MB-sized files with >1000 headlines.
(Some modes can be slower.)
- Many one-character mappings for efficient outline navigation, which can
be combined into complex commands, e.g., "UVD" selects all siblings of
the current node. Outlines can also be navigated with the mouse.
- Outline structure manipulation: move nodes Up/Down, Promote/Demote,
Copy/Cut/Paste, Insert New Headline, Sort in various ways.
- Command to search nodes. Boolean AND/NOT search (in addition to |/bar|).
There are four main Ex commands: Voom, Voomhelp, Voomexec, Voomlog.
:Voom
:Voom {MarkupMode}
Create outline of the current buffer. By default, outline is
constructed from lines with start fold markers with level numbers.
To work with headlines in a different format, an argument
specifying the desired markup mode must be provided, see above and
|voom_markup_modes|.
Outline is displayed in a special buffer in a separate window which
emulates the tree pane of a two-pane outliner. Such buffers are
referred to as Tree buffers. The current buffer becomes a Body
buffer. Each Tree line is associated with a region (node) of the
corresponding source buffer (Body). Nodes can be navigated and
manipulated in the Tree: moved up/down, promoted/demoted,
copied/cut/pasted, marked/unmarked, sorted, etc.
See OUTLINING (|voom_Voom|) for details.
*voom_Voomhelp*
:Voomhelp Open help file voom.txt as outline in a new tabpage. If voom.txt
is installed via |helptags|, it is opened as a Vim help file
(:tab help voom.txt) so that all tags will be active.
The VOoM plugin includes two utilities useful when working with Vim and Python
scripts -- commands :Voomexec and :Voomlog. They can be used independently of
the outlining functionality provided by the command :Voom. These commands
attempt to emulate similar features of Leo outlining editor. A Python file with
code snippets organized via fold markers, plus the command :Voomexec, plus the
PyLog buffer is an alternative to running Python's interactive interpreter.
:Voomexec Execute text in the current node or fold as Vim script or Python
script. This is useful for testing code snippets and for
organizing scripts by segregating them into folds. This command
does not require an outline to be created and can be used with any
buffer that has folds and has fold method set to marker.
See EXECUTING SCRIPTS (|voom_Voomexec|) for details.
:Voomlog Create scratch buffer __PyLog__ and redirect Python's stdout and
stderr to it. This is useful when developing Python scripts and
when scripting Vim with Python. This feature is not related to
folding or outlining and is completely independent from the rest of
the plugin.
See __PyLog__ BUFFER (|voom_Voomlog|) for details.
==============================================================================
QUICK DEMO (no installation needed) [[[2~
Extract VOoM archive to any folder. Open "plugin/voom.vim" in Vim, and do >
:so %
:Voom
This will create Tree buffer for "voom.vim", which will become a Body buffer.
All VOoM mappings, except Return and Tab, are for Tree buffers only.
<Up>, <Down>, <Left>, <Right> arrow keys move around the Tree and select new
node (Normal mode).
<Return> selects node under the cursor and then cycles between Tree and Body.
So, to select another node, move to it with h, j, etc. and hit Return.
<Tab> cycles between Tree and Body windows without selecting node.
<Space> expands/contracts node without selecting it. Standard Vim folding
command (zo, zc, zR, zM, etc.) can be used as well.
Left mouse click in the Tree selects node. If the click is outside of headline
text, the node's expanded/contracted status is toggled.
Edit a headline (line with a start fold marker) in "voom.vim" and go back into
the Tree: the outline will be updated.
<C-Up>, <C-Down> move node or a range of sibling nodes Up/Down.
<C-Left>, <C-Right> move nodes Left/Right (promote/demote).
(If the above CTRL mappings are not recognized by your Vim, you can also move
nodes Up/Down/Left/Right with ^^ __ << >> or <LocalLeader>u/d/l/r .)
Execute the command :Voomhelp to see all commands and mappings.
To create outline for another buffer, execute the command :Voom for it: >
:tab h netrw
:Voom
Folder "voom_samples" contains some outlines to experiment with.
File "calendar_outline.txt" is a rather large outline for stress-testing
purposes: 3.1 MB, 56527 lines, 4160 headlines.
To outline the most common Wiki format (headlines marked by strings of =) >
:Voom wiki
To try Python Log Buffer feature: >
:Vooml
:py assert 2==3
:py print u"\u042D \u042E \u042F"
:py import this
==============================================================================
Limitations [[[2~
==============================================================================
File size [[[3~
VOoM outlining is not scalable to large outlines. The bottleneck is the brute
force update of outline data. Such update, which scans Body for headlines and
recreates outline, must be done whenever the user enters a Tree buffer after
modifying corresponding Body--we can't possibly know what the user did with the
Body while he was away from the Tree.
Sample outline "calendar_outline.txt" seems to be approaching the usable size
limit on my 2002 notebook (1.6GHz Pentium 4 Mobile): >
3.2 Mb, 56527 lines, 4160 headlines.
When moving to Tree after modifying Body, the pause due to outline update is
noticeable but is still less than a second.
Browsing an outline is fast regardless of it's size.
In case of stress test file "calendar_outline.txt", the time-consuming step is
not just scanning for fold markers, but also comparing >4000 headlines between
the old and new outlines, or, if outlines are very different, setting all
lines in the Tree buffer. This means that even larger files can be outlined
comfortably if they have much fewer headlines.
==============================================================================
Numbered Markers: Pros and Cons [[[3~
Start fold markers with levels have many advantages:
- It's a built-in Vim folding method (:set fdm=marker).
- Fast folding suitable for Mb-sized files with >1000 headlines.
- More flexible than indent-based or syntax-based folding. Suitable for
outlining of most file types, including source code.
- Easy to parse and to search for. Area after level number is a natural
place for storing node attributes.
- Fold markers without levels are handy for folding smaller regions.
One drawback of numbered fold markers is that inserting them is somewhat
awkward and slow. This is not a big deal if outline nodes have a lot of body
text: most of the time is spent writing body text rather than creating
headlines (also known as headings). For outlines that consist mostly of
headlines (e.g., a shopping list) an indent based outlining mode is more
appropriate. See VO (VimOutliner) and TVO (The Vim Outliner) plugins.
P.S. I wrote a simple plugin that helps insert start fold markers with levels:
http://www.vim.org/scripts/script.php?script_id=2891
P.S. Version 4.0 added support for outline markups other than start fold
markers with levels, including common Wiki markups (|voom_markup_modes|).
==============================================================================
VOoM is not a 'filetype' plugin [[[3~
This is a design philosophy rather than a limitation. VOoM is expected to work
with files of any 'filetype': source code, plain text notes, Vim help file, a
large wiki file, a custom GTD format. The command :Voom, which creates outline,
does not configure the current buffer (Body) in any substantial way: it does
not set Body syntax highlighting, indent settings, folding settings, mappings
(with the exception of |voom_shuttle_keys|).
In other words, VOoM is designed to have (almost) no side effects on the buffer
being outlined (Body). All mappings are bound to the Tree pane (except for
shuttle keys).
In contrast, other text outliners are usually geared toward taking notes and
managing tasks (VO, TVO, Emacs Org-mode). They use special format and typically
have features such as: custom syntax highlighting and folding, a tagging
system, clickable URLs, intra- and inter-outline linking, mappings to insert
dates and other things. VOoM does not provide such features because they should
be 'filetype'-specific.
==============================================================================
Other Text Outliners [[[2~
Leo outlining editor:
http://webpages.charter.net/edreamleo/front.html
- The __PyLog__ buffer, which is created by the command :Voomlog, is the
equivalent of Leo's log pane.
- The :Voomexec command is like Leo's Execute Script command when executed
in a node which contains the @others directive.
- Mark/Unmark nodes operations are modeled after identical Leo commands.
- Like Leo, VOoM can save which nodes in the Tree are expanded/contracted
and which node is the selected node. The difference from Leo is that this
is done manually via Tree commands and mappings.
The "Tag List" Vim plugin:
http://vim.sourceforge.net/scripts/script.php?script_id=273
- Conceptually, VOoM is similar to the "Tag List" plugin and other source
code browsers. "Tag List" uses the "ctags" program to scan files for
tags. VOoM uses Python script to scan Vim buffer for start fold markers
with levels or some other headline markers.
Other Vim scripts for outlining are listed at
http://vim.wikia.com/wiki/Script:List_of_scripts_for_outlining?useskin=monobook
Emacs Org-mode:
http://orgmode.org/
Emacs oultining modes:
http://www.emacswiki.org/emacs/CategoryOutline
Code Browser:
http://code-browser.sourceforge.net/
Listings of outliner programs:
http://en.wikipedia.org/wiki/Outliner
http://www.psychinnovations.com/directory/outliners-mind-maps
http://texteditors.org/cgi-bin/wiki.pl?OutlinerFamily
http://www.marktaw.com/reviews/Outliners.html
http://www.outlinersoftware.com/topics/viewt/807/0/list-of-outliners
==============================================================================
Requirements [[[1~
*voom_requirements*
VOoM uses Python and requires Python-enabled Vim 7.x, that is Vim compiled
with the Python interface. Your Vim is Python-enabled if it can do >
:py print 2**0.5
:py import sys; print sys.version
Python version should be 2.4 - 2.7. Python 3 is not supported.
Vim version 7.2 or above is preferred. Version 7.1 should also work.
Version 7.0 might work as well but has not been tested.
Vim should be compiled using normal or bigger feature set.
Vim patch 7.2.161 is required in order to be able to work on the same outline
(or any buffer with folds) in separate tabpages.
==============================================================================
Vim and Python on Windows [[[2~
Getting Vim and Python to work together on Windows can be a bit tricky
(|python-dynamic|).
- Obviously, Python must be installed. Use Python version 2.6 or 2.7
Windows installer from http://www.python.org/ . The installer will put
Python DLL in system search path.
- Vim must be compiled with the Python interface (:echo has("python")).
- Finally, the version of Python DLL against which Vim was compiled must
match the installed Python version.
There are several Windows Vim installers (version 7.3).
Installer from vim.org, http://www.vim.org/download.php#pc, probably installs
Vim compiled against Python 2.7.
Installer from http://sourceforge.net/projects/cream/files/ (gVim one-click
installer for Windows) has Vim compiled against Python 2.6 according to release
notes.
It is not hard to compile your own Python-enabled gvim.exe and vim.exe. See
http://vim.wikia.com/wiki/Build_Python-enabled_Vim_on_Windows_with_MinGW?useskin=monobook
==============================================================================
Installation [[[1~
*voom_install*
Copy content of the plugin folder (file "voom.vim", directory "voom" with
Python files) to your local Vim plugin folder: >
$HOME/vimfiles/plugin/ (Windows)
$HOME/.vim/plugin/ (*nix)
Copy "doc/voom.txt" to the local doc folder. >
$HOME/vimfiles/doc/ (Windows)
$HOME/.vim/doc/ (*nix)
This will make commands Voom, Voomlog, Voomexec, Voomhelp available in any
buffer.
Execute the :helptags command to install "voom.txt" as Vim help and to
generate help tags (|add-local-help|): >
:helptags $HOME/vimfiles/doc
:helptags $HOME/.vim/doc
VOoM can also be run from any directory without installing anything, see
Overview -> QUICK DEMO.
NOTE: VOoM uses quickload mechanism (|write-plugin-quickload|). The bulk of
the script "voom.vim" is sourced and Python module "voom.py" is imported only
after a Voom command is executed for the first time.
NOTE: VOoM Python modules are located in folder "voom" which must be in the
directory of "voom.vim". When "voom.vim" is sourced, its Python code adds
"voom" directory to sys.path and then imports "voom.py". This creates file
"voom.pyc" if needed.
==============================================================================
Options [[[1o~
*voom_options*
==============================================================================
Vim Options [[[2~
When outline of the current buffer is created by the command :Voom, the
following Vim options determine how outline is constructed:
(NOTE: not applicable when a markup mode is specified)
- 'foldmarker' is used to obtain the start fold marker string. There is
rarely a reason to change this option from default, which is {{{,}}} .
- 'commentstring' and 'filetype' affect how Tree headline text is
constructed. For details, see node
OUTLINING (:Voom) -> Create Outline -> Tree Headline Text
'foldmethod' for the buffer for which the command :Voom is executed should be
"marker" (:set fdm=marker). This, however, is not required to create an
outline or to use it. Outline operations do not rely on Vim folds, they use
start fold markers with levels. Other folding options (|fold-options|), such
as 'foldtext', can be set according to personal preferences and are usually
'filetype'-specific.
<LocalLeader> is used to start many outline operations while in a Tree buffer.
By default, it's backslash. For example, "\i" inserts new node. To change it
to another character, assign maplocalleader in .vimrc: >
let maplocalleader=','
'scrolloff' should be 0 (default) or a small number (1 or 2). This global
option affects how the headline is positioned in Body window after selecting
node in Tree window. For example, after :set scrolloff=1, the headline will be
on the 2nd window line in Body window. A very large value can be confusing
when switching between Tree and Body windows.
Vim commands for creating and deleting folds are not very useful and are
potentially dangerous when typed accidentally. They can be disabled in .vimrc
as follows: >
" Disable commands for creating and deleting folds.
noremap zf <Nop>
noremap zF <Nop>
noremap zd <Nop>
noremap zD <Nop>
noremap zE <Nop>
Some color schemes (including default) use the same or similar background
colors for selected text (Visual), folded lines (Folded), and current line
(CursorLine) highlight groups. These highlight groups are used in Tree buffers
and it's better if they are easily distinguished from each other.
==============================================================================
VOoM Options [[[2o~
VOoM options are Vim global variables that can be defined by users in their
.vimrc files. Example: >
let g:voom_tree_placement = "top"
let g:voom_tree_height = 14
==============================================================================
Window positioning [[[3~
g:voom_tree_placement ~
Where Tree window is created: "left", "right", "top", "bottom"
This is relative to the current window.
Default: "left"
g:voom_tree_width ~
Initial Tree window width.
Default: 30
g:voom_tree_height ~
Initial Tree window height.
Default: 12
g:voom_log_placement ~
Where __PyLog__ window is created: "left", "right", "top", "bottom"
This is far left/right/top/bottom.
Default: "bottom"
g:voom_log_width ~
Initial __PyLog__ window width.
Default: 30
g:voom_log_height ~
Initial __PyLog__ window height.
Default: 12
==============================================================================
Tree/Body shuttle keys [[[3~
*voom_shuttle_keys*
Since VOoM emulates a two-pane outliner, it's important to have keys that
shuttle between the two panes. By default, such keys are <Return> and <Tab>.
These keys are used in buffer-local mappings in Trees (Normal and Visual
modes) and in Bodies (Normal mode).
These are the only keys that get mapped in Body buffer when the command :Voom
is executed.
Note that these keys have default meaning in Vim:
<Return> moves cursor down. This is not very useful since "j" does almost
the same thing.
By default, <Tab>/CTRL-I in Normal mode goes to newer position in the jump
list (opposite of CTRL-O, see |CTRL-I|). Thus, although tempting, mapping
<Tab> is usually a bad idea. It seems that Ctrl-Tab still works like
default <Tab>/CTRL-I, at least in GUI Vim, when <Tab> is mapped.
The following two settings allow to use keys or key combinations other than
<Return> and <Tab>.
g:voom_return_key ~
Mapping that selects node under the cursor and, if the node is already
selected, shuttles between Tree and Body windows.
Default: "<Return>"
g:voom_tab_key ~
Mapping that shuttles between Tree and Body windows without selecting
node.
Default: "<Tab>"
Example, use Ctrl-Return and Ctrl-Tab: >
let g:voom_return_key = '<C-Return>'
let g:voom_tab_key = '<C-Tab>'
==============================================================================
g:voom_ft_modes, g:voom_default_mode [[[3~
*g:voom_ft_modes* *g:voom_default_mode*
By default, the :Voom command without an argument creates outline from lines
with start fold markers with level numbers (the default mode). To outline
another format, an argument specifying the desired markup mode must be
provided. E.g., for a Markdown (MultiMarkdown, Pandoc) file: >
:Voom markdown
User options "g:voom_ft_modes" and "g:voom_default_mode" change which markup
mode the command :Voom will use when it is invoked without an argument. These
variables do not exist by default, they must be created by the user in .vimrc.
g:voom_ft_modes ~
"g:voom_ft_modes" is a Vim dictionary: keys are filetypes (|ft|), values are
corresponding markup modes (|voom_markup_modes|). Example: >
let g:voom_ft_modes = {'markdown': 'markdown', 'pandoc': 'markdown'}
This option allows automatic selection of markup mode according to filetype of
the source buffer. If "g:voom_ft_modes" is defined as above, and 'filetype' of
the current buffer is "markdown" or "pandoc", then the command >
:Voom
is identical to the command >
:Voom markdown
g:voom_default_mode ~
"g:voom_default_mode" is a string with the name of the default markup mode.
Example, if there is this in vimr: >
let g:voom_default_mode = 'asciidoc'
then, the command >
:Voom
is equivalent to >
:Voom asciidoc
unless "g:voom_ft_modes" is defined and has an entry for the current filetype.
NOTE: To overide these two options, that is to force the original default mode,
specify the "fmr" mode (|voom_mode_fmr|): >
:Voom fmr
==============================================================================
Various options [[[3~
g:voom_verify_oop ~
Verify outline after every outline operation (doesn't apply to :VoomSort).
Default is 1 (enabled).
Set to 0 to disable (not recommended, especially with markup modes).
This option turns on outline verification after most outline operations.
It will alert to outline corruption, which is very likely if there is a bug
in outline operation. The downside is that there is a performance hit,
usually noticeable only with large outlines (>1000 headlines).
NOTE: do not disable this option when using "rest" or "python" outlining
modes -- these markups have some intrinsic problems.
g:voom_rstrip_chars_{filetype} ~
NOTE: Not applicable when a non-default markup mode is used
(|voom_markup_modes|).
This variable must be created for each 'filetype' of interest.
Value is a string of characters to be stripped from the right side of Tree
headlines (from before fold marker) when the default Tree headline
construction procedure is used and Body has 'filetype' {filetype}.
Usually, the chars to be stripped are comment chars, space and tab. For
details, see node >
OUTLINING (:Voom) -> Create Outline -> Tree Headline Text
<
Defaults exist for filetypes "vim", "text", "help": >
let g:voom_rstrip_chars_vim = "\"# \t"
let g:voom_rstrip_chars_text = " \t"
let g:voom_rstrip_chars_help = " \t"
g:voom_user_command ~
This option allows to execute an arbitrary user-defined command when file
voom.vim is sourced. It is a string to be executed via |execute| at the
very end of voom.vim. It does not exist by default. This option is intended
for loading user add-ons. For details, see |voom_addons|.
g:voom_create_devel_commands ~
If this variable exists, several commands are created to help during VOoM
development. See "Commands" node in voom.vim for details.
==============================================================================
Customization tips [[[3~
When a Tree buffer is created, its 'filetype' is set to "voomtree"
When __PyLog__ buffer is created, its 'filetype' is set to "voomlog".
This should allow user customization of these buffers (bufhidden, syntax,
wrap/norwap, list/nolist, etc.) via standard Vim configuration files: >
$HOME/.vim/ftplugin/voomtree.vim
$HOME/.vim/syntax/voomtree.vim
$HOME/.vim/after/syntax/log.vim
etc.
To modify default Tree buffer-local mappings or create new ones:
1. Create file ftplugin/voomtree.vim .
2. Copy relevant mappings from voom.vim function Voom_TreeMap().
3. Change {lhs} and/or {rhs}.
Most VOoM commands can be mapped to key shortcuts in .vimrc: >
nnoremap <LocalLeader><LocalLeader> :Voom<CR>
nnoremap <LocalLeader>n :Voomunl<CR>
To make Body headlines stand out, lines with fold markers can be highlighted.
Since I use .txt files for notes, I have the following line in .vimrc >
au BufWinEnter *.txt if &ft==#'text' | exe 'syn match ModeMsg /\V\.\*' . split(&fmr, ',')[0] . '\.\*/' | endif
This method is better than using syntax/txt.vim because it also works when a
nonstandard foldmarker is specified on file's modeline.
==============================================================================
# ALL MAPPINGS & COMMANDS # [[[1x= ~
*voom_map*
------------------------------------------------------------------------------
MAIN COMMANDS ~
------------------------------------------------------------------------------
:Voom Create outline of the current buffer. |voom_Voom|
:Voom {MarkupName} Create outline using markup mode defined in module
"voom_mode_{MarkupName}.py". |voom_markup_modes|
:Voomhelp Open voom.txt as outline in a new tabpage. |voom_Voomhelp|
:Voomexec [vim|py] Execute node or fold as [type] script. |voom_Voomexec|
:Voomlog Create __PyLog__ buffer. |voom_Voomlog|
------------------------------------------------------------------------------
SHUTTLE KEYS (BODY AND TREE BUFFERS) ~
------------------------------------------------------------------------------
These cycle between Tree and Body windows. Configurable by the user.
Body: Normal mode. Tree: Normal and Visual modes. |voom_shuttle_keys|
<Return> Select node under the cursor. If already selected, move
cursor to Tree or Body window. A Tree or Body window is
created in the current tabpage if there is none.
<Tab> Move cursor to Tree or Body window.
------------------------------------------------------------------------------
OUTLINE NAVIGATION (TREE BUFFER) ~
------------------------------------------------------------------------------
<LeftRelease> Mouse left button click. Select node under mouse.
Toggle node's expanded/contracted state if the click is
outside of headline text. (N)
<2-LeftMouse> Mouse left button double-click. Disabled.
<Up> Move cursor Up and select new node. (N)
<Down> Move cursor Down and select new node. (N)
<Right> Move cursor to the first child and select it. (N)
<Left> Move cursor to the parent and select it. (N)
If the current node is expanded, it is contracted first.
------------------------------------------------------------------------------
expand/contract nodes
------------------------------------------------------------------------------
zc, zo, zM, zR, zv, etc.
These are Vim's standard folding commands.
They expand/contract nodes (|fold-commands|).
Note: zf, zF, zd, zD, zE are disabled.
<Space> Expand/contract the current node (node under the cursor). (N)
O Recursively expand the current node and its siblings. (N)
Recursively expand all nodes in Visual selection. (V)
Similar to |zO|.
C Recursively contract the current node and its siblings. (N)
Recursively contract all nodes in Visual selection. (V)
Similar to |zC|.
------------------------------------------------------------------------------
move cursor to another node (in addition to j, k, H, M, L, etc.)
------------------------------------------------------------------------------
o Down to the first child of the current node (like |zo|). (N)
c Up to the parent node and contract it (like |zc|). (N)
P Up to the parent node. (N)
K Up to the previous sibling. (N,V,count)
J Down to the next sibling. (N,V,count)
U Up to the uppermost sibling. (N,V)
D Down to the downmost sibling. (N,V)
= Put cursor on the currently selected node. (N)
------------------------------------------------------------------------------
go to specially marked node |voom_special_marks|
------------------------------------------------------------------------------
x Go to next marked node (find headline marked with 'x'). (N)
X Go to previous marked node. (N)
+ Put cursor on the startup node (node with '=' mark in Body
headline). Warns if there are several such nodes. (N)
------------------------------------------------------------------------------
show (echo) information for node under the cursor
------------------------------------------------------------------------------
s Show Tree headline (text after first '|'). (N)
S Show UNL. Same as :Voomunl (|voom_Voomunl|). (N)
------------------------------------------------------------------------------
OUTLINE OPERATIONS (TREE BUFFER) ~
------------------------------------------------------------------------------
i I a A Edit headline of node under the cursor. (N)
R Switch to Body buffer, select the line range corresponding
to the current node or to nodes in Visual selection. (N,V)
<LocalLeader>i Insert new node after the current node. (N)
<LocalLeader>I Insert new node as first child of the current node. (N)
<C-Up>
^^
<LocalLeader>u Move node(s) Up. (N,V)
<C-Down>
__
<LocalLeader>d Move node(s) Down. (N,V)
<C-Left>
<<
<LocalLeader>l Move node(s) Left (Promote). (N,V)
Nodes must be at the end of their subtree.
<C-Right>
>>
<LocalLeader>r Move node(s) Right (Demote). (N,V)
------------------------------------------------------------------------------
COPY/CUT/PASTE (these use Vim's + register: system clipboard)
------------------------------------------------------------------------------
yy Copy node(s). (N,V)
dd Cut node(s). (N,V)
pp Paste node(s) after the current node. (N)
------------------------------------------------------------------------------
MARK/UNMARK |voom_special_marks|
------------------------------------------------------------------------------
<LocalLeader>m Mark node(s): add 'x' to Body headlines. (N,V)
<LocalLeader>M Unmark node(s): remove 'x' from Body headlines. (N,V)
<LocalLeader>= Mark node as startup node: add '=' to Body headline and
remove '=' from all other headlines. When cursor is on
Tree line 1, all '=' marks are removed. (N)
------------------------------------------------------------------------------
SORTING |voom_sort|
------------------------------------------------------------------------------
:VoomSort [options] Sort siblings of node under the cursor.
Options are: "deep" (also sort all descendant nodes),
"i" (ignore-case), "u" (Unicode-aware), "r" (reverse-sort),
"flip" (reverse), "shuffle".
:[range]VoomSort [options]
Sort siblings in the [range], start and end range lines
must be different.
------------------------------------------------------------------------------
SAVE/RESTORE TREE BUFFER FOLDING |voom_tree_folding|
------------------------------------------------------------------------------
:[range]VoomFoldingSave
Save Tree folding (writes 'o' marks in Body headlines).
:[range]VoomFoldingRestore
Restore Tree folding (reads 'o' marks in Body headlines).
:[range]VoomFoldingCleanup
Cleanup 'o' marks: remove them from nodes without children.
<LocalLeader>fs Save Tree folding for the current node and all descendant
nodes. Same as :VoomFoldingSave. (N)
<LocalLeader>fr Restore Tree folding for the current node and all descendant
nodes. Same as :VoomFoldingRestore. (N)
<LocalLeader>fas Save Tree folding for entire outline.
Same as :%VoomFoldingSave. (N)
<LocalLeader>far Restore Tree folding for entire outline.
Same as :%VoomFoldingRestore. (N)
------------------------------------------------------------------------------
SEARCH NODES (Body and Tree buffers) ~
------------------------------------------------------------------------------
:Voomunl Display node's UNL: Uniform Node Locator. |voom_Voomunl|
:Voomgrep [pattern(s)]
Search current outline for pattern and display results in
the quickfix window as list of UNLs of nodes with matches.
Performs boolean AND and NOT searches if there are several
patterns separated by words "and" or "not". Uses word at
cursor if no patterns are provided. |voom_Voomgrep|
------------------------------------------------------------------------------
QUIT (DELETE), TOGGLE OUTLINE ~
------------------------------------------------------------------------------
(see |voom_quit|)
q Delete outline. (Tree buffer Normal mode mapping)
:Voomquit Delete outline. (Tree or Body buffer)
:VoomQuitAll Delete all VOoM outlines. (any buffer)
:VoomToggle [MarkupMode]
Create outline if current buffer is a non-VOoM buffer.
Delete outline if current buffer is a Tree or Body buffer.
:Voomtoggle Minimize/Restore Tree window. (Tree or Body)
------------------------------------------------------------------------------
VARIOUS ~
------------------------------------------------------------------------------
<LocalLeader>e Execute node. Same as :Voomexec. Tree buffer only. (N)
Several additional commands is created if there exists variable
"g:voom_create_devel_commands". These commands are useful only during VOoM
development. See node "Commands" in ../plugin/voom.vim for details.
==============================================================================
OUTLINING (:Voom) [[[1o~
==============================================================================
Create Outline [[[2o~
*voom_Voom*
:Voom [MarkupMode]
Scan the current buffer for headlines, construct an indent-based
outline from them, and display it in a specially configured,
non-modifiable buffer called Tree buffer. The current buffer
becomes a Body buffer.
:Voom By default, headlines are lines with start fold markers with level
numbers: {{{3, {{{1, etc. The level of each headline is set to the
number after the fold marker. Headline text is part of line before
the fold marker (this can be customized).
NOTE: End fold markers with levels, }}}1, }}}3, etc., are ignored
and should not be used.
Matching fold markers without level numbers, {{{ and }}}, are
ignored. They are handy for folding small areas inside numbered
folds, e.g. parts of functions. The region between {{{ and }}}
should not contain fold markers with levels.
For best results, Body 'foldmethod' should be "marker"
(|fold-marker|). If this is the case, Body nodes are also folds.
This is not required. Body buffer folding has no effect on outline
construction or outline operations.
:Voom {MarkupMode}
The format of headlines is specified by the {MarkupMode}
(|voom_markup_modes|).
NOTE: A TREE BUFFER IS NOT MODIFIABLE AND SHOULD NEVER BE EDITED DIRECTLY.
It has many buffer-local mappings for navigating the outline and for performing
outline operations. Most of Vim standard Normal and Visual text change commands
are either disabled or remapped.
Tree buffers are named {bufname}_VOOM{bufnr} where {bufname} and {bufnr} are
the name and number of the corresponding source buffer (Body). The 'filetype'
of Tree buffers is set to "voomtree".
A Tree buffer is displayed in a separate window. It is configured to behave as
the tree pane of a two-pane outliner. Every line in a Tree buffer is associated
with a node of the corresponding Body.
Each "node" is a range of Body buffer lines beginning with headline and ending
before the next headline (or end-of-buffer). The first Tree line (outline
title) is treated as a special node number 1: it is associated with the region
from start of Body buffer to its first headline (or end-of-file); it has zero
lines if the first Body line is a headline.
When a headline is selected in a Tree window (<Return>, <Up>, <Down>, <Left>,
<Right>), the corresponding node is displayed in Body window. Nodes can be
manipulated from Tree window: deleted, moved, promoted, demoted, marked, etc.
Obviously, Body buffers can be edited directly as any other buffers with fold
markers.
The outline data and the Tree are updated automatically on entering the Tree
buffer (on |BufEnter|). The actual update happens if the Body has been
modified since the last update (when Body's |b:changedtick-variable| is
different). This update is the bottleneck that limits the size of outlines
that can be edited comfortably.
A Body buffer is not configured in any substantial way by the command :Voom.
It has only two VOoM-specific mappings: <Return> and <Tab> in Normal mode
(local to buffer). These mappings select node under the cursor and cycle
between Body and Tree windows. These two mappings can be changed by the user
(|voom_shuttle_keys|). The user is responsible for setting all other Body
settings to his liking: folding, indenting, syntax highlighting and so on
(these are usually determined by Body 'filetype').
==============================================================================
About Fold Markers [[[3~
The command :Voom does not create an outline of folds. It creates an outline
of start fold markers with level numbers. When Body has 'foldmethod' set to
"marker", lines in Tree buffer also represent Body folds.
The start fold marker string is obtained from window-local option 'foldmarker'
when outline is created by the command :Voom. For example, after >
:set fmr=<<<,>>>
:Voom
the outline will be created from lines with <<<1, <<<2, <<<3, etc.
'foldmarker' should not be changed while using an outline. If you change it,
make sure to recreate the outline: delete Tree buffer and execute the command
:Voom again.
VOoM scans only for **start** fold markers with level numbers. End fold markers
with levels and fold markers without levels are ignored. This assumes that the
user follows certain rules of using fold markers. These rules make a lot of
sense and are similar to recommendations given in Vim help (|fold-marker|).
1) Use start fold markers with levels, <<<1, <<<2, etc. to start new
fold/node. These should correspond to important structures: parts and
chapters in a book, functions and classes in a code.
2) DO NOT USE END FOLD MARKERS WITH LEVELS: >>>1, >>>2, etc. They are
redundant and are hard to keep track of in a large outline.
3) Do use pairs of matching fold markers without level, <<< and >>>, to fold
small areas of text (a screenful), such as parts of functions. Make sure
the area doesn't contain any fold markers with levels.
Files that do have end fold markers with levels are ok for browsing with VOoM,
but outline operations will most definitely produce unintended results.
Consider the following structure: >
node 0
node 1 <<<1
node 1.1 <<<2
>>>1
? ? ? ?
? ? ? ?
node 2 <<<1
node 3 <<<1
Lines with ? are not part of any fold. But VOoM considers them part of node
1.1 and will move them accordingly when node 1.1 is moved. When node's level
is changed, only number after the start fold marker is updated.
==============================================================================
Special Node Marks [[[3~
*voom_special_marks*
NOTE: Special node marks are available only when outlining start fold markers
with levels. They are not available when using a markup mode
(|voom_markup_modes|) unless it's an "fmr" mode (|voom_mode_fmr|).
The following characters in Body headline immediately after the start fold
marker level number have special meaning. They are used by VOoM to indicate
node properties:
'x' - Node is marked. This is like a checked checkbox. If the node is
marked, 'x' is displayed in the second column of Tree buffer.
'o' - Node is opened (expanded). The corresponding Tree buffer fold
will be opened when outline is created by the command :Voom.
Obviously, this applies only to nodes with children.
'=' - Startup node. This node will be selected when outline is created
by the command :Voom.
Various VOoM mappings and commands read and write these special marks.
Each mark is optional, but the order must be xo= . Examples, assuming that
foldmarker is set to <<<,>>> : >
headline <<<1xo= --node is marked, opened, startup node
headline <<<1xo --node is marked, opened
headline <<<1o --node is opened
headline <<<1x= --node is marked, startup node
headline <<<1=xo --node is startup node, 'x' and 'o' are ignored
headline <<<1 xo= --all marks are ignored
==============================================================================
~~~===--- Tree Headline Text ---===~~~ [[[3~
NOTE: This section does not apply when a markup mode is in use (|voom_markup_modes|).
Tree headline text is constructed from the corresponding Body buffer headline.
The default procedure is to take part before the matching fold marker and to
strip whitespace and other distracting characters. The exact procedure depends
on Body 'filetype' and can be customized by the user. For most filetypes, the
following happens:
- Part of the Body line before the first start fold marker with level
number is taken.
- Whitespace is stripped from the left side.
- Spaces, tabs, and comment characters are stripped from the right side.
Which chars are comment chars is determined by option 'commentstring',
or by user option "g:voom_rstrip_chars_{filetype}", see below.
- Leading and trailing filler chars -=~ are removed. These chars can be
used as decorators to make headlines stand out.
- Whitespace is stripped again on both ends.
In step 3, characters that are stripped from the right side of headline (from
before the fold marker) are determined as follows:
- If variable "g:voom_rstrip_chars_{filetype}" exists, it's value is used.
{filetype} here is Body 'filetype'. Value is string of characters to be
stripped from the right side (Space and Tab must be included).
- If "g:voom_rstrip_chars_{filetype}" does not exist, comment characters
are obtained from option 'commentstring'. They, Spaces, and Tabs are
stripped from the right side.
By default, "g:voom_rstrip_chars_{filetype}" are defined for filetypes "vim",
"text" and "help". For most source code filetypes 'commentstring' is set
correctly by the corresponding ftplugin. If not defined, 'commentstring'
defaults to /*%s*/, which makes no sense for filetypes like text and help.
So, to change what characters are stripped from the right side of Tree
headlines for particular Body filetypes, you can either set 'commentstring' or
you can define "g:voom_rstrip_chars_{filetype}" in vimrc (or in an add-on).
Example for "autohotkey" filetype, ';' is line comment char: >
let g:voom_rstrip_chars_autohotkey = "; \t"
The above procedure can be replaced completely by a custom Python function
which returns Tree headline text. The function must be registered in Python
dictionary voom.MAKE_HEAD: key is Body filetype, value is the function to be
used with this filetype. By default, this is done for "html" files (we can't
just strip <!-- characters from the right side). For other filetypes, this
should be done via an add-on. Sample add-on "custom_headlines.vim" shows how,
see comments there.
NOTE: Tree headlines are constructed by function makeOutline() or
makeOutlineH() in voom.py. Markup modes use function hook_makeOutline().
You can aslo customize how Tree headline text is constructed by invoking an
"fmr" markup mode, see |voom_mode_fmr|.
==============================================================================
Selected Node [[[3~
At any moment, one node is designated as selected. It is marked by = character
in the Tree buffer. This is sort of like "current position" in a true two-pane
outliner.
In contrast, "current node" here means node under the cursor. Current node may
or may not be selected.
A node is selected by pressing <Return> (Tree or Body, Normal mode), or by
selecting new node in Tree window with arrow keys or mouse left button click.
It is possible to automatically select a node on startup. (This feature is not
available when using a markup mode.) A startup node has character '=' in Body
headline after the level number and after optional 'x' and 'o' marks
(|voom_special_marks|). Tree mapping <LocalLeader>= inserts '=' in current
node's Body headline and removes '=' marks from all other headlines. Next time,
when outline is created by the command :Voom, the node with '=' will be
automatically selected.
Related Tree mappings, Normal mode:
= Put cursor on currently selected node.
+ Put cursor on startup node, that is node marked with '=' in Body
headline, if any. This will also warn if there are several such
nodes. Mnemonic: + is Shift-=
Note: it would be nice to have current headline highlighted in the Tree buffer
(as Leo does). Sadly, Vim does not allow to apply syntax highlighting to
folded lines--the Folded hi group overrides all other highlighting. The
current headline is easy to highlight, but it doesn't work for contracted
nodes: >
:syn match Pmenu /^=.\{-}|\zs.*/
This code is commented out in Voom_TreeSyntax().
==============================================================================
Delete Outline [[[2~
*voom_quit*
To delete (quit) VOoM outline for a particular Body buffer:
unload, delete, or wipe out the corresponding Tree buffer (:bun, :bd, :bw).
You can also delete an outline by closing all corresponding Tree windows via
|CTRL-W_c|, |CTRL-W_o|, etc. This happens because Tree buffers have 'bufhidden'
set to "wipe". (If this is inconvenient, change 'bufhidden' to "hide". To do
this by default for all Tree buffers, configure filetype "voomtree": add
"setl bufhidden=hide" in file ~/.vim/after/ftplugin/voomtree.vim or similar.)
NOTE: outline is deleted automatically whenever the Tree buffer is unloaded.
When a VOoM outline is deleted:
- The Tree buffer is wiped out, which obviously closes all Tree windows.
- VOoM-specific mappings (|voom_shuttle_keys|) and autocommands are removed
from the Body buffer. (Mappings may remain at first. They will silently
unmap themselves the next time they are invoked.)
There are also the following convenience commands:
q Delete outline. Tree buffer Normal mode mapping.
:Voomquit Delete outline if current buffer is a Tree or Body buffer.
:VoomQuitAll Delete all VOoM outlines. Can be executed from any buffer.
:VoomToggle [MarkupMode]
Create outline if the current buffer is a non-VOoM buffer.
(Same as the :Voom command except that cursor stays in the
current buffer.)
Delete outline if current buffer is a Tree or Body buffer.
:Voomtoggle Minimize/Restore Tree buffer window in the current tabpage.
(Tree or Body)
==============================================================================
Unloaded Body buffers [[[3~
A buffer cannot be outlined if it is not loaded in memory. A Body buffer is
unloaded after commands :bun :bd :bw . It can also become unloaded after it is
no longer displayed in any window (this depends on options 'hidden' and
'bufhidden').
If Body buffer is not loaded, the outline is locked. The following actions in
the corresponding Tree buffer are blocked:
- Automatic outline update on Tree BufEnter.
- Selecting nodes.
- All outline operations.
- Commands :Voomgrep, :Voomunl, etc.
Everything should be back to normal once the Body buffer is loaded again.
If a Body buffer has been wiped out (:bw) it can not be loaded again. The
corresponding Tree buffer is useless and you should delete it.
One way to load an unloaded Body buffer is to execute the command :Voom in the
Tree buffer: it will create a new window, load Body there, and update outline.
If Body buffer no longer exists, outline will be deleted.
==============================================================================
Custom commands for deleting outline [[[3~
It would be convenient if outline was automatically deleted and Tree buffer
wiped out when Body buffer is unloaded, deleted, and definitely when it is
wiped out. This is how VOoM worked prior to version 3.0. Such design turned out
to be unsafe and had to be abandoned.
The workaround is function Voom_DeleteOutline([ex_command]). It can be used to
create custom commands and mappings that automatically delete outline. This
function does the following:
- if current buffer is a Tree, it deletes outline (Tree is wiped out).
- if current buffer is a Body, it deletes outline, and then executes
argument as an Ex command via |:execute|
- if current buffer is not a VOoM buffer, it executes argument as an Ex
command
Argument (a string) should be an Ex command you use most often to get rid of
buffers: "q", "bun", "bd", "bw", etc.
Example >
nnoremap <silent> <M-w> :call Voom_DeleteOutline('bw')<CR>
com! BW call Voom_DeleteOutline('bw')
Mapping ALT-w and command :BW are identical to the command :bw (wipe out
buffer), except that if current buffer is a Body they also delete the outline.
==============================================================================
Outline Navigation [[[2o~
See |voom_map| for list of all mappings. This section explains the basics.
------------------------------------------------------------------------------
If mouse is enabled (GUI Vim), outline can be browsed with the mouse alone
thanks to the following Tree buffer local mappings:
<LeftRelease>
Mouse left button click. Select node under mouse.
Toggle node's expanded/contracted state if the click is outside of
headline text. (N)
<2-LeftMouse>
Mouse left button double-click. Disabled.
------------------------------------------------------------------------------
The most essential keyboard mappings for outline navigation are:
<Return> -- Tree (Normal, Visual), Body (Normal)
<Tab> -- Tree (Normal, Visual), Body (Normal)
<Space> -- Tree (Normal)
<Return> and <Tab> shuttle between the corresponding Tree and Body windows.
They are the only keys mapped by the command :Voom in Body buffer. Other keys
can be used instead by defining custom "g:voom_return_key" and "g:voom_tab_key"
(|voom_shuttle_keys|).
<Return> - In Body buffer: select current node and show it in Tree window.
If current node is already selected, move cursor to Tree window.
- In Tree buffer: select current node and show it in Body window.
If Body 'foldmethod' is marker, Body folds are closed so that
only the selected node is visible (zMzvzt).
If current node is already selected, move cursor to Body window.
If the current tabpage has no windows with the required Body or
Tree buffer, a new window is created. Thus, hitting <Return>
after ":tab split" will create tabpage with a new outline view.
<Tab> - In Body buffer: move cursor to window with the corresponding
Tree buffer.
- In Tree buffer: move cursor to window with the corresponding
Body buffer.
(The command :Voom also cycles between Tree and Body. This is like <Return> but
without selecting new node.)
All other mappings are for Tree buffers only.
<Space> Toggle node's expanded/contracted state without selecting it. (N)
If current line is hidden in a fold (after zc or zC), it is made
visible first.
Nodes in the Tree buffer window can be navigated with just <Return>, <Tab>,
<Space>, and standard Vim commands:
cursor motion: j, k, H, M, L, ...
|fold-commands|: zc, zo, zM, zR, zv, zj, zk, ...
(note: zf, zF, zd, zD, zE are disabled in Trees)
Examples:
- To select the first child of the current node when it's contracted:
<Space>j<Return>
- To recursively contract subtree of the current node: contract it with
<Space> if it's expanded, hit VzC to close folds, hit <Space> again if
it's become hidden.
- To go to the parent of the current node: zckj , zcjk .
------------------------------------------------------------------------------
There are about 19 other mappings for easy Tree navigation, see |voom_map|.
Many of them use keys that otherwise would have been wasted because they change
text and thus have to be disabled in Tree buffers. For example, "c" and "P"
move cursor to the parent of the current node.
Most Tree mappings are defined only for the Normal mode and do not accept a
count. The exceptions are:
- K, J, U, D in Visual mode extend Visual selection. To select all siblings
of the current node: UVD . To expand all sibling: UVDzo .
- K, J accept a count: 5J moves cursor 5 siblings down, if possible.
- O, C can operate on nodes in Visual region.
------------------------------------------------------------------------------
In addition to <Return>, the following Tree keys also select a node:
<Up> <Down> <Right> <Left> x X . All other keys just position the cursor.
Every time a node is selected, the cursor has to jump between the corresponing
Tree and Body windows in the current tabpage. Other tabpages are ignored. If
there is no window with the target buffer, a new window is created. If there
are multiple windows, previous window (^Wp) is re-used if possible.
==============================================================================
:Voomunl [[[3~
*voom_Voomunl*
:Voomunl This commands displays UNL (Uniform Node Locator) of node under
the cursor. The UNL string is also copied into register "n" for
easy pasting.
The current buffer must be a Tree or a Body. If current buffer is a Body, the
outline data and the Tree will be updated if needed.
The term UNL is from Leo's unl.py plugin:
http://webpages.charter.net/edreamleo/plugins.html#unl-py
An UNL is like a path to the node. It lists headlines of all ancestor nodes.
Example: >
Part 2 -> Chapter 4 -> Section 3 -> subsection 5
Related Tree mappings:
s Show Tree headline text. (N)
S Show UNL. Same as :Voomunl. (N)
==============================================================================
:Voomgrep [[[3~
*voom_Voomgrep*
:Voomgrep {pattern}
Search Body buffer for {pattern} and display results in the
|quickfix| window as a list of UNLs of nodes with matches.
:Voomgrep
As above, but use word under the cursor for pattern, as when
starting search with * or #.
:Voomgrep {pattern1} and {pattern2} and {pattern3} ...
Boolean AND search. Search Body for each pattern and show nodes
that match all patterns.
:Voomgrep not {pattern1} not {pattern2} not {pattern3} ...
Boolean NOT search. Search Body for each pattern and show nodes
that don't match any of the patterns.
:Voomgrep {pattern1} and {pattern2} not {pattern3} not {pattern4} ...
Boolean AND and NOT searches combined.
The current buffer must be a Tree or a Body. If current buffer is a Body, the
outline data and the Tree are updated if needed. Searches are always performed
in Body buffer. If current buffer is a Tree buffer, the cursor moves to window
with the corresponding Body.
For each pattern, function |search()| is used to search the entire Body
buffer, from top to bottom. According to docs, 'ignorecase', 'smartcase' and
'magic' are used.
The search with each pattern stops after >10,000 matches are found. Results of
boolean searches are likely to be wrong in this case.
The results are displayed in the quickfix window (|quickfix-window|) as a list
of UNLs of nodes. For example, after executing >
:Voomg Spam and ham not bacon
in "test_outline.txt" the result is: >
|| Voomgrep Spam {32 matches} AND ham {5 matches} NOT bacon {5 matches}
test_outline.txt|130| n43:28|tests -> Voomgrep tests -> n43 lunch
test_outline.txt|137| n44:2 |tests -> Voomgrep tests -> n44 dinner
Numbers after the file name are:
- Body line number of the first match in this node
- node number, that is node's Tree line number
- number of matches in this node for all AND patterns
If the search was successful, the first AND pattern is copied into the search
register "@/" so that "n" and "N" commands and search highlight can be used.
PATTERNS AND BOOLEAN OPERATORS:
- Patterns should not span several lines. Multi-line patterns are likely
to produce meaningless results because they can span several nodes.
- Operators AND and NOT that separate patterns are not case sensitive:
they can be "and", "AND", "not", "NOT", "aND", etc.
- Operators AND and NOT should not be combined or grouped. Command
:Voomgrep ham and not spam
searches for "ham" AND "not spam".
- Whitespace around each pattern and around AND and NOT is ignored.
Use "\s", "\t", "[ ]", "\%x20" to specify leading or trailing
whitespace.
- To include literal words "and" or "not" in a pattern: >
:Voomgrep Spam and\ ham not\ bacon
:Voomgrep Spam[ ]and ham[ ]not bacon
<
- Patterns separated by AND and NOT are treated independently.
Switches like \c, \v, \m, \zs, etc. affect only one pattern. For
example, to do case-insensitive search for nodes with ham and spam: >
:Voomgrep \cham and \cspam
<
TIPS:
- The readability of UNLs in the quickfix window is much better when
the -> separators are highlighted, see screenshot at
http://vim-voom.github.com/ . I have the following two lines in
$HOME/vimfiles/after/syntax/qf.vim: >
syn match Title / -> /
syn match LineNr /| n\d\+:\d\+\s*|/
<
- To avoid long paths in the quickfix window, set working directory to the
current file, see
http://vim.wikia.com/wiki/Set_working_directory_to_the_current_file
==============================================================================
Outline Operations [[[2o~
Outline operations are performed using Tree buffer-local mappings, that is
they are always performed in a Tree buffer.
When appropriate, operations are automatically applied to branches, that is to
top level nodes and all their descendant nodes. E.g., moving a node, moves the
node and all its descendants. The level numbers of the node and its
descendants are automatically adjusted to the new position in the outline.
Most operations can be performed on a range of sibling nodes using Visual
mode. The range is checked for being a valid range: all top level nodes should
be at the same level.
Where the moved or inserted nodes end up depends on the expanded/contracted
status of the node after which the nodes are inserted. This should be obvious
and replicates default behavior of the tree pane in Leo outlining editor.
Most outline operations usually modify the corresponding Body buffer. Thus,
they are disabled if the Body is 'nomodifiable' or 'readonly'. The exceptions
are Copy and some other commands that never modify Body buffers.
An outline operation can be undone with one undo command in the corresponding
Body buffer.
==============================================================================
Edit Headline [[[3~
The only way to edit headline text is to edit the corresponding Body line.
While in a Tree buffer, Normal mode:
i I a A Start editing headline under the cursor. The cursor is
moved into Body window and placed on the first word
character in Body headline (node's first line).
To find the first word char, pattern |/\<| is used.
Most other text changing keys are either disabled or mapped to VOoM functions.
==============================================================================
Select Body Region [[[3~
R Move cursor from Tree to Body buffer and select the line
range corresponding to node under the cursor (Normal mode)
or to all nodes in Visual selection (Visual mode).
This Tree buffer mapping is handy when you want to limit :substitute or some
other range-accepting Vim command to a single node or a group of nodes. The
command deals with individual nodes, not trees. Mnemonic: Range, Region.
==============================================================================
Insert New Node [[[3~
To insert new node while in a Tree buffer (Normal mode):
<LocalLeader>i Insert new node after the current node.
<LocalLeader>I Insert new node as first child of the current node.
By default, the new headline is "---NewHeadline---".
The cursor is moved to Body window and placed on the new
headline, where it can be edited ("caw", "caW", etc.).
Often, it's easier to just edit Body buffer to insert a numbered fold marker.
I wrote a simple plugin that helps with that:
http://www.vim.org/scripts/script.php?script_id=2891
NOTE: When a markup mode is used, the format of new headlines is determined by
the markup mode (|voom_markup_modes|). Text is always "NewHeadline".
TODO: make new headline text an argument of function Insert Node to make
programmatic creation of outlines more convenient, especially when there are
undelines/overlines (markdown, reST). Example code at #ID_20111006013436 .
==============================================================================
Move/Copy/Cut/Paste Nodes [[[3~
<C-Up>
^^
<LocalLeader>u Move node(s) up. (N,V)
<C-Down>
__
<LocalLeader>d Move node(s) down. (N,V)
<C-Left>
<<
<LocalLeader>l Move node(s) left (promote). (N,V)
Nodes must be at the end of their subtree.
<C-Right>
>>
<LocalLeader>r Move node(s) right (demote). (N,V)
dd Cut node(s). (N,V)
yy Copy node(s). (N,V)
pp Paste node(s) after the current node. (N)
With the exception of Paste, these Tree buffer mappings are available in
Normal and Visual modes. In Visual mode the range is checked for being valid:
top level nodes in the range must be siblings.
These commands always apply to branches, that is to top level nodes and all
their descendant nodes, even when only part of a branch is selected.
Commands Cut/Copy/Paste use Vim's + register, that is system clipboard.
The command Paste checks clipboard for being a valid VOoM outline. The first
line in the clipboard must be a headline.
==============================================================================
Mark/Unmark Nodes [[[3~
NOTE: Not available when a markup mode is used (|voom_markup_modes|), unless
it's an "fmr" mode (|voom_mode_fmr|).
Marking node is like checking a checkbox. A node is marked/unmarked by
adding/removing 'x' in Body headline after the start fold marker level number
(|voom_special_marks|). The 'x' is also displayed in the Tree.
<LocalLeader>m Normal mode: mark node under the cursor.
Visual mode: mark all nodes in the range.
'x' is inserted in Body headlines. (N,V)
<LocalLeader>M Normal mode: unmark node under the cursor.
Visual mode: unmark all nodes in the range.
'x' is removed from Body headlines. (N,V)
The above commands apply to individual nodes only, not to their descendants.
To unmark all: ggVG<LocalLeader>M
Related Tree mappings, Normal mode:
x Go to next marked node and select it.
X Go to previous marked node and select it.
TODO: mark/unmark only visible nodes (not hidden in folds). Could be add-on.
==============================================================================
Mark Node As Startup Node [[[3~
NOTE: Not available when a markup mode is used (|voom_markup_modes|), unless
it's an "fmr" mode (|voom_mode_fmr|).
<LocalLeader>= Mark the current node as startup node. (N)
This command inserts character '=' in Body headline after the start fold marker
level number and after optional 'x' and 'o' marks (|voom_special_marks|). The
'=' mark is removed from all other Body headlines. If current line is the
first Tree line (outline title), '=' are removed from all Body headlines.
The '=' mark affects only Voom startup: last node marked with '=' is selected
when outline is created for the first time by the command :Voom.
Related Tree mappings, Normal mode:
+ Put cursor on the startup node, if any. Warn if there are
several such nodes. Mnemonic: + is Shift-=
==============================================================================
Save/Restore Tree Folding [[[3~
*voom_tree_folding*
NOTE: Not available when a markup mode is used (|voom_markup_modes|), unless
it's an "fmr" mode (|voom_mode_fmr|).
Opened/closed folds in a Tree buffer are equivalent to expanded/contracted
nodes. VOoM allows to save and restore Tree buffer folding. To do this, it
relies on special marks in Body headlines: character 'o' immediately after the
start fold marker level number and after optional 'x' (|voom_special_marks|).
The 'o' mark indicates that the fold is opened. Such folds are opened
automatically on startup. (This help file uses 'o' node marks.)
The following commands execute only a Tree buffer. They read and write 'o'
marks in Body headlines.
:[range]VoomFoldingSave
Save Tree folding by writing 'o' marks in Body headlines.
If a range is supplied, this is done for individual nodes
in the range. Without a range, this is done for current
node and all descendant nodes.
:[range]VoomFoldingRestore
Restore Tree folding according to 'o' marks in Body
headlines. If a range is supplied, this is done for
individual nodes in the range. Without a range, this is
done for the current node and all descendant nodes.
:VoomFoldingCleanup
Cleanup 'o' marks: remove them from nodes without
children. Such marks are redundant but harmless, they
don't do anything. This is done for the entire outline,
even if a range is supplied.
To save or restore folding for entire outline: >
:%VoomFoldingSave
:%VoomFoldingRestore
There as also the following Tree buffer mappings, Normal mode:
<LocalLeader>fs Save Tree folding for the current node and all descendant
nodes. Same as :VoomFoldingSave.
<LocalLeader>fr Restore Tree folding for the current node and all descendant
nodes. Same as :VoomFoldingRestore.
<LocalLeader>fas Save Tree folding for entire outline.
Same as :%VoomFoldingSave.
<LocalLeader>far Restore Tree folding for entire outline.
Same as :%VoomFoldingRestore.
Mnemonics for mappings: Foldins Save/Restore, Folding All Save/Restore.
==============================================================================
Sort Outline [[[3~
*voom_sort*
The command :VoomSort sorts sibling nodes according to their Tree headline text
(string after character | in Tree buffer). Nodes are siblings if they have the
same level and the same parent. This command must be executed in Tree buffer.
:VoomSort Sort siblings of the current node (node under the cursor).
Headlines are sorted by byte value, in ascending order.
:[range]VoomSort Sort siblings in the range. Start and end range lines must
be different (|[range]|).
Note that if the range is actually one line, all siblings
of the node at that line are sorted. E.g.,
:57,57VoomSort
:57VoomSort
sorts siblings of node at Tree line 57.
:VoomSort [options]
:[range]VoomSort [options]
Sort according to options. Options are any combination of
the following words, separated by whitespace:
deep, i, u, r, flip, shuffle.
OPTIONS:
deep Deep (recursive) sort. Sort top level siblings and siblings
of their descendants. When the cursor is on the 2nd Tree
line (first headline) and no range is given, entire outline
is sorted.
i Ignore-case. Case-insensitive sort. Without the "u" option
this should affect only A-Za-z letters. To handle other
letters, include the "u" option.
u Unicode-aware sort. Convert headlines to Python Unicode
strings before sorting. This option is probably needed only
for case-insensitive sorts.
r Reverse-sort, sort in descending order.
flip Reverse the order of nodes without sorting anything.
shuffle Shuffle nodes randomly.
Example 1, perform deep sort, ignore-case, Unicode-aware: >
:VoomSort deep i u
Example 2, sort siblings in Visual selection: >
:'<,'>VoomSort
NOTE: make sure at least 2 lines are selected. Otherwise, the range contains
only one line, which means all siblings of the selected line will be sorted.
Sorting and reverse-sorting do not change relative order of nodes with equal
headlines.
Options "r", "flip", "shuffle" cannot be combined.
It is easy to create custom commands that perform sorting with a particular set
of options. For example, if you often do case-insensitive, non-recursive sort
you can add the following line to vimrc: >
com! VoomSortI call Voom_OopSort(line('.'), line('.'), 'i u')
The command :VoomSortI will be identical to ":VoomSort i u".
It does not except a range. To make it work with a range: >
com! -range VoomSortI call Voom_OopSort(<line1>, <line2>, 'i u')
==============================================================================
MARKUP MODES [[[2~
*voom_markup_modes*
By default, the command :Voom creates outlines from lines with start fold
markers with levels. To outline buffer with a different headline markup, it is
necessary to specify the markup mode. For example, command >
:Voom MySuperDuperWiki
will try to create outline using MySuperDuperWiki markup mode.
(To change the markup mode that the command :Voom uses when it is invoked
without an argument, see |g:voom_ft_modes| and |g:voom_default_mode|.)
A markup mode is defined in Python module named "voom_mode_{MarkupName}.py".
It can be located anywhere in Python search path. The above command will try to
import module "voom_mode_MySuperDuperWiki.py", which should modify the core
code when handling this particular outline to accommodate idiosyncrasies of the
MySuperDuperWiki markup language.
A fully functional markup mode will support all major VOoM commands and outline
operations. Not supported are operations that rely on special node marks,
|voom_special_marks|, unless the mode is an "fmr" mode (|voom_mode_fmr|):
- mark/unmark nodes
- startup node
- save/restore Tree folding.
You can create your own command or mapping identical to the above command >
:com! Voow call Voom_Init("MySuperDuperWiki")
or, if you prefer :VoomToggle behavior >
:com! Voow call Voom_Init("MySuperDuperWiki",1)
To customize or create new markup mode: modify one of the existing
voom_mode_{MarkupName}.py files, save it as voom_mode_{YourName}.py anywhere in
Python search path.
The following sections describe available markup modes. These modes are fully
functional unless stated otherwise. Command line completion is available when
typing these modes: type ":Voom " and hit <Tab> or <C-d>.
==============================================================================
wiki [[[3~
*voom_mode_wiki*
:Voom wiki
MODULE: ../plugin/voom/voom_mode_wiki.py
MediaWiki headline markup. This is the most common Wiki format. Should be
suitable for Wikipedia, vim.wikia.com, etc. >
= headline level 1 =
some text
== headline level 2 ==
more text
=== headline level 3 === <!--comment-->
==== headline level 4 ====<!--comment-->
etc.
First = must be at the start of the line.
Closing = are required.
Trailing whitespace is ok.
Whitespace around the text is not required.
HTML comment tags are ok if they are after the headline: >
==== headline level 4 ==== <!--{{{4-->
===== headline level 5 ===== <!--comment--> <!--comment-->
KNOWN PROBLEMS
--------------
1) Headlines are not ignored inside <pre>, <nowiki> and other special blocks.
2) Only trailing HTML comment tags are stripped.
The following valid headline is not recognized: >
<!-- comment -->=== missed me ===
A comment inside headline is ok, but it will be displayed in Tree buffer: >
== <!-- comment --> headline level 2 ==
REFERENCES
----------
http://www.mediawiki.org/wiki/Help:Formatting
http://www.mediawiki.org/wiki/Markup_spec
http://meta.wikimedia.org/wiki/Help:Section
http://en.wikipedia.org/wiki/Help:Section
http://en.wikipedia.org/wiki/Wikipedia:Manual_of_Style#Section_headings
==============================================================================
vimwiki [[[3~
*voom_mode_vimwiki*
:Voom vimwiki
MODULE: ../plugin/voom/voom_mode_vimwiki.py
Headline markup used by vimwiki plugin:
http://www.vim.org/scripts/script.php?script_id=2226
Like wiki mode except that:
there can be leading whitespace (centered headline?)
HTML comment tags are not stripped
>
= headline level 1 =
body text
== headline level 2 ==
body text
=== headline level 3 ===
==============================================================================
viki [[[3~
*voom_mode_viki*
:Voom viki
MODULE: ../plugin/voom/voom_mode_viki.py
Mode for outlining Viki/Deplate headings:
http://www.vim.org/scripts/script.php?script_id=861
http://deplate.sourceforge.net/Markup.html#hd0010004
>
* headline level 1
some text
** headline level 2
more text
*** headline level 3
**** headline level 4
The first * must be at the start of the line.
There must be a whitespace after the last * .
Headlines are ignored inside special regions other than #Region:
http://deplate.sourceforge.net/Regions.html
http://deplate.sourceforge.net/Regions.html#hd00110013
Special regions have the following format: >
#Type [OPTIONS] <<EndOfRegion
.......
EndOfRegion
Except for ignoring special regions, this mode is identical to the org mode.
==============================================================================
org [[[3~
*voom_mode_org*
:Voom org
MODULE: ../plugin/voom/voom_mode_org.py
Mode for outlining Emacs Org-mode headlines:
http://orgmode.org/org.html#Headlines
>
* headline level 1
some text
** headline level 2
more text
*** headline level 3
**** headline level 4
The first * must be at the start of the line.
There must be a whitespace after the last * .
==============================================================================
rest [[[3~
*voom_mode_rest*
:Voom rest
MODULE: ../plugin/voom/voom_mode_rest.py
Mode for outlining reStructuredText (reST) section titles.
http://docutils.sourceforge.net/rst.html
http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#sections
http://docutils.sourceforge.net/docs/user/rst/quickstart.html#sections
http://docs.python.org/documenting/rest.html#sections
For examples of reST files, click "Show Source" or similar link on above pages.
Vim has reST syntax highlighting, do :set ft=rst to enable.
To customize the order in which adornment styles are used: modify constant
AD_STYLES near the top of module. It's a string containing preferred adornment
styles in order of preference.
KNOWN PROBLEMS
--------------
1) Sort can make headlines disappear if some sections are not terminated with a
blank line (including last section, that is end of file). The command :VoomSort
will detect that **after** sort is finished and display an error message.
Example, sorting nodes C and B kills node C because it is moved down after B. >
=========
A level 1
=========
C level 2
---------
some text in node C
B level 2
---------
some text in node B
=========
E level 1
=========
Note that there is no such problem with other outline operations--they will
insert blank line before headline if needed to prevent headline loss. E.g., it
is safe to move node C down.
2) Outline verification can fail after an outline operation if there are
inconsistent levels, that is when node's level is incremented by >1. VOoM will
complain about different Tree lines, different levels, and force outline
update.
Example 1. Errors when moving node D up. >
A level 1
===========
B level 2
-----------
C level 3
"""""""""""
D level 1
===========
E level 3
"""""""""""
Example 2. Errors when moving node C left. This is because node E is also moved
left, even though it is in a different branch. >
A level 1
=========
B level 2
---------
C level 3
+++++++++
D level 1
=========
E level 4
*********
==============================================================================
markdown [[[3~
*voom_mode_markdown*
:Voom markdown
MODULE: ../plugin/voom/voom_mode_markdown.py
Mode for outlining of Markdown headers.
http://daringfireball.net/projects/markdown/
http://daringfireball.net/projects/markdown/syntax#header
http://daringfireball.net/projects/markdown/dingus --online demo
http://babelmark.bobtfish.net/ --derivatives
http://fletcherpenney.net/multimarkdown/ --MultiMarkdown
http://johnmacfarlane.net/pandoc/ --Pandoc
https://gist.github.com/1035030 --Vim folding for Markdown
There are two types of header styles. Both can be used in the same outline.
Underline-style, levels 1 and 2 only: >
header level 1
==============
header level 2
--------------
Hashes-style (also see |voom_mode_hashes|): >
# header level 1
## header level 2
### header level 3 ###
A blank line before or after a headline is optional. (NOTE: Pandoc version of
Markdown does require blank lines before headlines, unlike standard Markdown.)
One = or - in column 1 is sufficient for underline-style.
Spaces after opening #'s and before closing #'s are optional.
Closing #'s are optional. Their number is not important.
Differences from the actual Markdown parser (according to dinguses):
- Hashes-style overrides underline-style. In Markdown, underline overrides
hashes: >
#### this is headline level 4, not level 2
------------------------------------------
<
- Line consisting only of hashes is interpreted as a blank headline.
For example, line "###" is blank headline at level 3. In contrast,
Markdown interprets it as header "#" at level 2, that is <h2>#</h2>.
HOW OUTLINE OPERATIONS CHOOSE HEADLINE FORMAT
---------------------------------------------
When an outline operation changes headline level, it has to choose between
several possible headline formats:
- When changing to level 1 or 2, choose underline-style or hashes-style.
- When using hashes-style, choose to add not to add closing hashes.
Outline operations try to keep the format of headlines consistent throughout
the current outline. The above ambiguities are resolved as follows:
A) If possible, preserve the current style of headline and closing hashes.
Demoting headline
Headline
========
changes it to
Headline
--------
Demoting "# Headline" changes it to "## Headline".
Demoting "#Headline#" changes it to "##Headline##". And so on.
B) When a choice must be made between underline-style and hashes-style
(changing level from >2 to 1 or 2): the style of the first headline with
level 1 or 2 is used. The default (in case there are no headlines with
level 1 or 2) is to use underline-style.
C) When a choice must be made to add or not to add closing hashes (changing
from underline-style to hashes-style): the first headline which is in
hashes-style is checked. If it ends with "#", then closing hashes are
added. The default (in case there are no headlines in hashes-style) is to
add closing hashes.
The headline format is always chosen as in B) and C) above when:
- Inserting new headline.
- Pasting nodes (because we may paste from another outline with a
different style).
OTHER NOTES
------------
If a headline is not preceded by a blank line, outline operations may add one.
An underline-style headline should not contain leading or trailing #'s.
==============================================================================
hashes [[[3~
*voom_mode_hashes*
:Voom hashes
MODULE: ../plugin/voom/voom_mode_hashes.py
Headlines are marked by #'s. This is a subset of Markdown format (atx-style
headers): >
# headline level 1
## headline level 2
text
###headline level 3
### headline level 3
#'s must be at the start of the line.
A whitespace after #'s is optional.
This mode is much simpler and more efficient than the full Markdown mode
(|voom_mode_markdown|) because it does not have to deal with underlined
headlines and closing #'s.
NOTE: This mode can be easily modified:
a) To use any ASCII character as a marker instead of '#'.
b) To require a whitespace after the marker chars (as in org-mode).
c) To strip optional closing #'s.
See comments in the module file.
==============================================================================
txt2tags [[[3~
*voom_mode_txt2tags*
:Voom txt2tags
MODULE: ../plugin/voom/voom_mode_txt2tags.py
Mode for outlining txt2tags titles.
http://txt2tags.org/
http://txt2tags.org/userguide/TitleNumberedTitle.html#6_2
Both Titles and Numbered Titles are recognized. Anchors are OK. >
= title level 1 =
== title level 2 ==[anchor-A]
+++ numbered title level 3 +++
+++ numbered title level 3 +++[anchor-B]
There can be leading spaces, but not tabs.
The number of = or + chars must be the same on both sides.
Titles are ignored inside Verbatim, Raw, and Tagged Areas, that is between
pairs of lines of ```, """, '''. These areas cannot be nested.
In the Tree, the text of Numbered Titles is prepended with "+ " to help
distinguish them from regular titles. The type of the title is preserved during
outline operations.
==============================================================================
asciidoc [[[3~
*voom_mode_asciidoc*
:Voom asciidoc
MODULE: ../plugin/voom/voom_mode_asciidoc.py
Mode for outlining of AsciiDoc Document and Section Titles.
http://www.methods.co.nz/asciidoc/
http://www.methods.co.nz/asciidoc/userguide.html#X17
The AsciiDoc Userguide source is an example of a large and complex document:
http://www.methods.co.nz/asciidoc/userguide.txt
Both two-line and one-line title styles are recognized and can be used in the
same outline. Document Titles, that is topmost nodes, are not treated
specially. Note that the topmost level in VOoM is level 1, not level 0 as in
AsciiDoc documentation.
Two-line style, levels 1 to 5 only: >
Level 1
=======
Level 2
-------
Level 3
~~~~~~~
Level 4
^^^^^^^
Level 5
+++++++
The underline must be of the same size as the title line +/- 2 chars.
Both the underline and the title line must be at least 2 chars long.
Trailing whitespace is always ignored and is not counted.
One-line style: >
= Level 1 =
== Level 2 ==
=== Level 3 ===
Closing ='s are optional: >
= Level 1
== Level 2
=== Level 3
There must be a whitespace between headline text and ='s. The number of closing
='s must match the number of opening ='s.
One-line style overrides two-line style: >
===== Level 5
-------------
listing
-------------
When a style must be chosen during an outline operation (when level changes or
when a new node is inserted), the style is chosen so that to preserve the
current style of the document. When that's not possible, the default is to use
two-line and to add closing ='s. See |voom_mode_markdown| for details.
In addition to Titles, the VOoM asciidoc mode is also aware of:
- Standard Delimited Blocks. Titles are ignored inside of them.
- Lines with [[ BlockID ]] and [ AttributeList ] preceding the title line.
See below for details.
Because AsciiDoc is a complex format, there are various edge cases and gotchas,
see below. See also file voom_samples/asciidoc.asciidoc for examples.
------------------------------------------------------------------------------
Delimited Blocks [[[4~
Headlines are ignored inside Delimited Blocks:
http://www.methods.co.nz/asciidoc/userguide.html#_delimited_blocks
A delimited block is started and ended by a line consisting of 4 or more of the
following characters: >
////
++++
----
....
****
____
====
Example: >
== headline ==
------------------------------------
== listing, not headline ==
------------------------------------
== headline ==
Confusing cases when the start of a Delimited Block looks like an underline: >
== headline ==
--------------
== listing, not headline ==
---------------------------
headline
--------
--------
listing, not headline
---------------------
------------------------------------------------------------------------------
BlockID, AttributeList [[[4~
Section titles in AsciiDoc are often preceded by lines with attributes. Thus,
in general, it is dangerous to move nodes around--sections can become separated
from their attributes. VOoM accommodates the most common usage pattern, at
least as seen in the "userguide.txt".
A headline may be preceded by any number of [...] lines, that is lines that
start with "[" and end with "]". This allows for any number of BlockID and
AttributeList elements and in any order. Examples: >
[[appendix_B]]
== Appendix B ==
[appendix]
== Appendix B ==
[[appendix_B]]
[appendix]
== Appendix B ==
[appendix]
[[appendix_B]]
== Appendix B ==
In such cases, the first line of the node is the topmost [[...]] or [...] line,
not the title line. This means that it is usually safe to move such nodes --
lines with the BlockId and AttributeList will stay with the section title.
NOTE: There must be no comment lines or blank lines in between.
NOTE: No attempt is made to detect any other directives, macros, etc. before
the headline. Stuff like Attribute Entries, that is lines >
:numbered:
:numbered!:
and other thingies as well as comments in front of the headline are part of the
preceding node.
------------------------------------------------------------------------------
Blank Lines [[[4~
A blank separator line is usually required before a headline. The VOoM behavior
is mostly in conformance with AsciiDoc specification for Section Titles, but it
is not perfect and false negatives can occur, see Gotchas below.
NOTE: There should be no blank lines or comment lines between preceding [[...]]
and [...] lines and the title line. That is, unless you do not want them to be
treated as part of the headline.
Wrong: >
== headline ==
text
== not headline ==
Correct: >
== headline ==
text
== headline ==
In the following example the second underline starts Delimited Block: >
headline
--------
text
not headline
------------
not headline
------------
Comment lines are OK, the check for a preceding blank line ignores them: >
== headline 1 ==
text
// comment
== not headline ==
// comment
== headline 2 ==
text
// comment
// comment
== headline 3 ==
A BLANK LINE IS NOT REQUIRED in the following cases (this matches AsciiDoc
behavior):
1) Between adjacent headlines: >
== headline 1 ==
== headline 2 ==
// comment
== headline 3 ==
headline 4
----------
[blah]
headline 5
----------
2) If the title line is preceded by [[...]] or [...] lines: >
== headline 1 ==
text
[[X1]]
[blah]
== headline 2 ==
3) After the end of a Delimited Block: >
== headline 1 ==
----------------------------
listing
----------------------------
== headline 2 ==
Outline operations other than Sort will insert blank lines before headlines if
needed. They are thus not sensitive to missing blank separator lines.
Sort does not check for blank lines before headlines and does not insert them.
There will be an error message after :VoomSort if some headlines disappear due
to a missing blank line at the end of some nodes.
------------------------------------------------------------------------------
Disallowed Headlines (2-line style) [[[4~
Some lines are never treated by VOoM as headlines when underlined because they
resemble certain AsciiDoc elements commonly found in front of Delimited Blocks.
The following are not headlines, the underline starts Delimited Block instead:
("AAA" can be any text or no text at all)
BlockID >
[[AAA]]
-------
Attribute List >
[AAA]
-----
Comment line (exactly two // at start) >
//AAA
-----
Block Title >
.AAA
----
Tab at start of the title line is also not allowed. Leading spaces are OK.
An underlined headline cannot be just one character. These are not recognized
as headlines (they can be in AsciiDoc): >
A
--
B
---
An underlined title cannot look like an underline or a Delimited Block line,
that is a line of only =,-,+, etc. There are no headlines here: >
=====
-----
=====
+++
+++++
^^^^^^^^^^
++++++++++
------------------------------------------------------------------------------
Gotchas [[[4~
1) Do not insert blank lines or comment lines between [[...]] or [...] and the
following headline.
2) There must be a blank line between a Macro or an Attribute Entry and the
following headline. The underline in the example below is mistaken for a
Delimited Block, which kills subsequent headlines. >
== headline
:numbered:
== not headline
ifdef::something[]
not headline
------------
== not headline
3) As already mentioned, any comment lines, Macros, Attribute Entries, etc.
before a headline belong to the previous node and can become separated from the
section title when nodes are moved.
------------------------------------------------------------------------------
Customizing [[[4~
1) If you use non-default characters for title underlines or for delimited
blocks, you will have to edit dictionaries ADS_LEVELS, LEVELS_ADS, BLOCK_CHARS
in module ../plugin/voom/voom_mode_asciidoc.py .
2) If you do not want VOoM to check for blank lines before AsciiDoc headlines
and to insert them when cutting/pasting/moving nodes, add the following to
your .vimrc: >
let g:voom_asciidoc_do_blanks = 0
NOTE: This is not recommended because after an outline operation, a section
title can cease to be a title due to a missing blank line. Example document: >
Title
=====
BBBB
----
AAAA
----
some text, end of file, no blank lines after it
When BBBB is moved after AAAA (via Move Down/Up, or Cut/Paste, or :VoomSort)
it is no longer a section title in accordance with AsciiDoc specifications, but
VOoM will not know that (false-positive node) and will not issue any warnings.
==============================================================================
html [[[3~
*voom_mode_html*
:Voom html
MODULE: ../plugin/voom/voom_mode_html.py
HTML heading tags. Single line only. >
<h1>headline level 1</h1>
some text
<h2> headline level 2 </h2>
more text
<H3 ALIGN="CENTER"> headline level 3 </H3>
< h4 > headline level 4 </H4 >
some text <h4> <font color=red> headline 5 </font> </H4> </td></div>
etc.
Both tags must be on the same line.
Closing tag must start with </h or </H --no whitespace after < or /
All HTML tags are deleted from Tree headlines.
WARNING: When outlining a real web page, moving nodes around will very likely
screw up HTML.
==============================================================================
thevimoutliner [[[3~
*voom_mode_thevimoutliner*
:Voom thevimoutliner
MODULE: ../plugin/voom/voom_mode_thevimoutliner.py
The Vim Outliner (TVO) format:
http://www.vim.org/scripts/script.php?script_id=517
Headlines and body lines are indented with Tabs. Number of Tabs indicates
level. 0 Tabs means level 1.
Headlines are lines with >=0 Tabs followed by any character except '|'.
Blank lines are not headlines.
KNOWN PROBLEMS
--------------
If TVO is installed, navigating .otl file with arrows in Tree pane is sluggish,
even with relatively small outlines like README.otl . The culprit seems to be a
time-consuming BufEnter autocommand. Function OtlEnterBuffer() is called on
BufEnter. It sets up among other things window-local folding options, which
apparently triggers recalculation of folds, which is expensive.
The following trick seems to speed up things: change the following lines in
function OtlEnterBuffer() >
setlocal foldtext=OtlFoldText()
setlocal foldmethod=expr
setlocal foldexpr=OtlFoldLevel(v:lnum)
To >
if &foldtext !=# "OtlFoldText()"
setlocal foldtext=OtlFoldText()
endif
if &foldmethod !=# "expr"
setlocal foldmethod=expr
endif
if &foldexpr !=# "OtlFoldLevel(v:lnum)"
setlocal foldexpr=OtlFoldLevel(v:lnum)
endif
==============================================================================
vimoutliner [[[3~
*voom_mode_vimoutliner*
:Voom vimoutliner
MODULE: ../plugin/voom/voom_mode_vimoutliner.py
VimOutliner format:
http://www.vimoutliner.org/
Headlines are lines with >=0 Tabs followed by any character except:
: ; | > <
Otherwise this mode is identical to the "thevimoutliner" mode.
==============================================================================
python [[[3~
*voom_mode_python*
:Voom python
MODULE: ../plugin/voom/voom_mode_python.py
Mode for outlining Python code. Like a class browser except that regions
between "class" and "def" blocks are also nodes.
Headlines are
1) Lines that start with:
class
def
@
'### ' (special comment headline)
'#---' (special comment headline)
2) First non-blank line after the end of any "class" or "def" code block.
NOTE: Such headlines can be killed or created by an outline operation.
NOTE: Comment lines are not ignored. Their indent is significant and can
influence the level of next headlines.
Headline level is determined by indent relative to previous (smaller) indents.
One tab equals one space (not eight). If indent is inconsistent, the headline
is marked with '!!!' to indicate possible indent error.
The mode uses tokenize.py to identify lines that should be ignored (multi-line
strings and expressions), as well as lines with "class" and "def".
Outline update is slow with large files (>2000 lines, e.g, Tkinter.py).
Note that tokenize.py also checks for inconsistent indenting and can raise
exceptions in which case outline update will not be completed.
OUTLINE OPERATIONS
------------------
This mode have several intrinsic problems with outline operations. Do not
disable post-operation outline verification (g:voom_verify_oop).
Outline operations assume that the Body buffer has tab-related options set
correctly to work with the Python code displayed in the buffer:
1. If 'et' is off, indenting is done with Tabs, one Tab for each level.
2. If 'et' is on, indenting is done with Spaces. The number of spaces is
set to the value of 'ts'.
The above settings must match indentation style used by the Python code being
outlined. If they don't, an outline operation will create wrong indents
whenever a level must be changed. Outline verification after outline operation
will detect that, display error messages, and force outline update.
Outline operations can cause some headlines to disappear. (It's not clear to me
if they can appear.) This happens because regions between "class" and "def"
blocks are also nodes. This is not a bug but a confusing behavior. In the
following code there are four headlines: >
def func1(): # headline
pass
a = 1 # headline (can disappear)
def func2(): # headline
pass
b = 1 # headline (can disappear)
After "func2" is moved Up, line "b = 1" ceases to be a headline. Outline
verification will detect that and complain about wrong Tree size. To protect
such fragile headline you can insert a special comment headline: >
def func1(): # headline
pass
a = 1 # headline (can disappear)
def func2(): # headline
pass
### b=1 # headline (persistent)
b = 1
Weirdly indented comment lines also can cause various confusing problems during
outline operations.
In summary:
- Errors "wrong Tree size" after outline operations are expected and can be
ignored. Such errors occur when nodes are moved and blocks of code
between "class" and "def" are merged.
- Errors "wrong levels", "wrong bnodes" indicate serious problems and must
not be ignored. Undo the operation after such an error. Make sure buffer
indent settings are set correctly to handle Python code.
==============================================================================
'fmr' modes [[[3~
*voom_mode_fmr*
"fmr" modes are very similar to the default mode, that is the :Voom command
without an argument. They deal with start fold markers with level numbers and
support special node marks (|voom_special_marks|).
"fmr" modes can be used to customize how Tree headline text is constructed and
to change the format of new headlines (Insert New Node).
:Voom fmr
MODULE: ../plugin/voom/voom_mode_fmr.py
This mode changes absolutely nothing, it is identical to the default mode.
The purpose of this mode is to make possible the original default mode when
|g:voom_ft_modes| or |g:voom_default_mode| have been defined, e.g., for an
AsciiDoc file with fold markers.
:Voom fmr1
MODULE: ../plugin/voom/voom_mode_fmr1.py
Headline text is before the fold marker. This mode is identical to the default
mode except that no chars other than leading and trailing whitespace are
stripped from headlines. >
headline level 1 {{{1
headline level 2 {{{2
:Voom fmr2
MODULE: ../plugin/voom/voom_mode_fmr2.py
Headline text is after the fold marker: >
{{{1 headline level 1
{{{2 headline level 2
as seen in some Vim plugins: >
"{{{1 my functions
"{{{2 s:DoSomething
func! s:DoSomething()
NOTE: If {{{'s are in the first column and |matchparen| is enabled, outline
navigation is slow. A workaround: >
:set mps-={:}
==============================================================================
Miscellaneous Modes [[[3~
*voom_mode_various*
:Voom cwiki
MODULE: ../plugin/voom/voom_mode_cwiki.py
For Vim cwiki plugin: http://www.vim.org/scripts/script.php?script_id=2176
==============================================================================
Known Issues [[[2~
1) Memory used by Vim can increase significantly when outline operations Move
Up/Down are applied repetitively to a large node or a block of nodes (>1MB).
These commands delete and then insert lines in Body buffer. If the range being
moved is large, this can cause dramatic increase in memory used by the undo
history. Thus, to move a large node over a long distance it's better to use
Cut/Paste rather than keep pressing Ctrl-Up/Down.
This problem doesn't exist if 'undolevels' is set to -1, 0, 1.
A handy way to clear undo history:
set 'undoreload' to 0, reload the file with :e or :e! .
2) Undoing some outline operations can take a longer than usual time if a large
number of Body folds (>1000) is affected. The workaround is to temporarily set
Body 'foldmethod' to manual (:set fdm=manual).
3) Outline navigation and outline operations can be sluggish if there are
time-consuming BufEnter, BufLeave, WinEnter, WinLeave autocommands associated
with the Body buffer. This is because most VOoM commands involve entering and
leaving Body buffer window, often temporarily. This is a problem with .otl
files of The Vim Outliner plugin (|voom_mode_thevimoutliner|).
Heavy syntax highlighting can also make outline navigation slow, especially
when selecting a node in a large outline for the first time. This is a problem
with large reST, Markdown, AsciiDoc files. Disabling cursorline or cursorcolumn
or both helps a bit (:set nocul nocuc).
4) Support for Vim Sessions (|:mksession|) is far from perfect. If 'ssop'
contains "blank", the command :mksession will save info about Tree buffers,
that is no-file buffers named {Body_name}_VOOM{Body_bufnr}. When the session is
restored, VOoM tries to recreate the outline for such buffers.
- Markup modes are not remembered. Outline is always created with the
command :Voom. You can use |g:voom_ft_modes| or |g:voom_default_mode| to
select the desired markup mode automatically.
- The Tree and corresponding Body buffer must be in the same tab page.
- If 'ssop' contains "options", the command :mksession saves all Tree
buffer-local mapping (because all voom.vim functions are global).
This is redundant and increases the size of the Session file for no good
reason -- about 120 mappings for each Tree buffer.
- If 'ssop' contains "folds", :mksession doesn't really save Tree folding,
only some folding options which will be restored anyway.
5) Some markup modes (rest, asciidoc, markdown) depend on 'encoding'. If it is
changed, outline needs to be recreated for the new value to take effect.
==============================================================================
EXECUTING NODES (:Voomexec) [[[1~
*voom_Voomexec*
:Voomexec [type] Execute text from the current node and descendant nodes
(Tree buffers) or from the current fold and subfolds
(Body and non-VOoM buffers) as [type] script. Supported
types are: "vim", "python" or "py".
In Tree buffers Voomexec is mapped to <LocalLeader>e.
The following happens when the command :Voomexec is executed:
1) The type of script is determined.
-----------------------------------
:Voomexec Without an argument, the type of script is set to
buffer 'filetype': "python" if filetype is "python",
"vim" if filetype is "vim", etc. When executed from a
Tree buffer (also with <LocalLeader>e), filetype of
the corresponding Body is used.
:Voomexec vim Execute as "vim" script.
:Voomexec python
:Voomexec py Execute as "python" script.
:Voomexec whatever Execute as "whatever" script.
If script type is neither "vim" nor "python", the command aborts.
It should be possible to add support for other script types.
2) The text of script is obtained.
---------------------------------
a) If the current buffer is a VOoM Tree buffer, the script's text is set to
that of the current node (including headline) and all descendant nodes,
that is to Body's text in the current VOoM subtree. Body folding does
not matter.
b) If the current buffer is a VOoM Body or a non-VOoM buffer, the script's
text is set to that of the current fold, including all subfolds. This is
most useful when 'foldmethod' is "marker". If 'foldmethod' is not
"marker", the command aborts and the script is not executed.
3) The script is executed according to its type.
-----------------------------------------------
a) A "vim" script is executed by copying text into a register and executing
that register (|:@|) in a function inside try/catch/finally/endtry.
If an error occurs, v:exception is echoed. (v:throwpoint is useless.)
b) A "python" script is executed as a string via the "exec" statement, see
http://docs.python.org/reference/simple_stmts.html#exec .
The following Python names are pre-defined: vim, voom, VOOMS.
An extra line is prepended to script lines to specify encoding as per
http://www.python.org/dev/peps/pep-0263/ , e.g.
# -*- coding: utf-8 -*-
Encoding is Vim's internal encoding ('utf-8' for all Unicode &enc).
The script is executed inside try/except block. If __PyLog__ is enabled
and an error occurs, Python traceback is printed to the __PyLog__ buffer
instead of Vim command line.
NOTE: The "end of script" message shows the first and last line number of the
script's text.
==============================================================================
sample Vim scripts [[[2~
Scripts in the following subnodes can be executed with >
:Voome vim
------------------------------------------------------------------------------
"---node 1---[[[3o~
echo 'in node 1'
" section [[[
echo 'inside section in node 1'
" ]]]
"----------------------------------------------------------------------------~
"---node 1.1---[[[4o~
echo 'in node 1.1'
"----------------------------------------------------------------------------~
"---node 1.1.1---[[[5~
echo 'in node 1.1.1'
"============================================================================~
sample Python scripts [[[2~
Scripts in the following subnodes can be executed with >
:Voome py
------------------------------------------------------------------------------
#---node 1---[[[3o~
print ' in node 1'
print 'current buffer number:', vim.eval('bufnr("")')
print 'VOoM Body buffer numbers:', voom.VOOMS.keys()
print 'voom.makeOutline() docstring:\n ', voom.makeOutline.__doc__ ,'\n'
import os
print 'current working dir:', os.getcwd()
# section [[[
print ' inside section in node 1'
# ]]]
#----------------------------------------------------------------------------~
#---node 1.1---[[[4o~
print ' in node 1.1'
#----------------------------------------------------------------------------~
#---node 1.1.1---[[[5~
print ' in node 1.1.1'
#============================================================================~
Alternatives to :Voomexec [[[2~
Other Vim commands and scripts can retrieve the content of VOoM nodes as a
range of Body lines and do something with it.
1) In a Tree buffer, the "R" command selects the corresponding Body line range,
which can then be passed to a range-accepting command.
2) Function Voom_GetExecRange(lnum) is what :Voomexec uses to obtain the
script's text, that is Body's lines from the current subtree (Tree buffers), or
lines from the current fold (Body buffers, non-VOoM buffers).
The following function shows how to use Voom_GetExecRange(): >
func! Voom_WriteExecRange()
" Write to a file lines that are executed by :Voomexec.
let filePath = '~/voomscript'
let [bufType, body, bln1, bln2] = Voom_GetExecRange(line('.'))
if body<1 | return | endif
let blines = getbufline(body, bln1, bln2)
call writefile(blines, expand(filePath))
endfunc
3) Function Voom_GetVoomRange(lnum,withSubnodes) can be used by other scripts
to obtain the content of a VOoM node at line number lnum (withSubnodes==0), or
the content of node and its subnodes (withSubnodes==1). Unlike
Voom_GetExecRange(), it works the same for Tree and Body buffers, and it
doesn't care about folding or non-VOoM buffers. Typical usage: >
let [bufType, body, bln1, bln2] = Voom_GetVoomRange(line('.'), 0)
" Error: Body not loaded, outline update failed, etc.
if body < 0
echo 'ERROR'
" Current buffer is not a VOoM buffer. Do something with the current line.
elseif bufType==#'None'
echo getline('.')
elseif bufType==#'Tree'
echo 'in Tree'
echo getbufline(body,bln1,bln2)
elseif bufType==#'Body'
echo 'in Body'
echo getbufline(body,bln1,bln2)
endif
4) Function Voom_GetBuffRange(ln1,ln2) can be used by other scripts to obtain
the content of VOoM nodes in Tree line range ln1,ln2 if the current buffer is a
Tree (same as the "R" command). If the current buffer is not a Tree, it returns
the ln1,ln2 range for the current buffer. Example: >
let [bufType, body, bln1, bln2] = Voom_GetBuffRange(line("'<"),line("'>"))
if body < 0 | return | endif
let blines = getbufline(body,bln1,bln2)
... do something with blines ...
==============================================================================
Known Issues [[[2~
1) Vim script code executed this way cannot use |line-continuation|.
2) When :Voomexec executes a Vim script with Python code and a Python error
occurs, Python traceback is not printed. However, Python traceback is printed
to the PyLog buffer if it is enabled. Example in the next fold can be executed
with ":Voome vim". >
" Vim script with Python error [[[
echo 'start of vim script'
py print bogus_name
py print 'py after error'
echo 'the end'
" ]]]
3) As the example above illustrates, Vim script is not terminated when an
error occurs in the Python code.
==============================================================================
__PyLog__ BUFFER (:Voomlog) [[[1~
*voom_Voomlog*
:Voomlog This command creates scratch buffer __PyLog__ and redirects
Python's stdout and stderr to that buffer.
Subsequent Python print statements and error messages are appended to the
__PyLog__ buffer instead of being printed on Vim command line.
Windows with the __PyLog__ buffer are scrolled automatically in all tabpages
when something is printed to the PyLog buffer. If a tabpage has several PyLog
windows, only the first one is scrolled. If the current tabpage has no PyLog
windows, the command :Voomlog will create one.
To restore original stdout and stderr (that is Vim command line): unload,
delete, or wipeout the __PyLog__ buffer (:bun, :bd, :bw).
NOTE: __PyLog__ buffer is configured to be wiped out when unloaded or
deleted. 'bufhidden' is set to "wipe".
The filetype of the PyLog buffer is set to "voomlog". Some syntax highlighting
is added automatically to highlight Python tracebacks, Vim error, and common
VOoM messages.
When Python attempts to print a unicode string, e.g. >
:py print u'ascii test'
:py print u'\u042D \u042E \u042F \u2248 \u2260'
the string is encoded using internal Vim encoding at the time of __PyLog__
buffer creation. Internal encoding is determined from Vim option 'encoding':
"utf-8" if &encoding is a Unicode encoding, &encoding otherwise.
==============================================================================
Known Issues [[[2~
1) All output lines appear in the __PyLog__ buffer simultaneously after the
script is finished, not in real time. Example (executable with :Voome py):
### demo Python code [[[
import time, datetime
print datetime.datetime.now()
time.sleep(5)
print datetime.datetime.now()
### ]]]
2) Printing many lines one by one can take a long time. Instead of doing >
:py for i in range(1000): print i
It is much faster to do >
:py print '\n'.join([str(i) for i in range(1000)])
(It's also easier to undo.)
3) Visiting other tabpages during automatic scrolling is slow on Linux in GUI
Vim (GTK). It's better to have PyLog window only in the current tabpage.
4) __PyLog__ is not usable when in the Ex mode, that is after 'Q' or 'gQ'.
The lines in the __PyLog__ buffer will appear after the Ex mode is exited.
id_20110213225841
5) When __PyLog__ is enabled, a Python error in a Vim script does not result in
Vim error. This is probably because Python's sys.stderr is redirected. This
changes Vim error handling when a Python code is executed by Vim inside
try/endtry. Example Vim script, try it with PyLog on: >
try
python assert 1==2
echo 'AFTER PYTHON ERROR -- should not be here'
finally
echo 'AFTER FINALLY'
endtry
echo 'AFTER TRY -- should not be here'
6) In versions before 1.7 there was problem with the output of help(), which
apparently uses Lib/pydoc.py, which does something strange to output trailing
\n. Steps to reproduce:
1. Open new instance of Vim.
2. Voomlog
3. :py help(help)
4. Wipe out __PyLog__ buffer to restore sys.stdout.
5. :py help(help)
An error occurs: '\n' is printed to the nonexisting log buffer.
The culprit is in Lib/pydoc.py:
help = Helper(sys.stdin, sys.stdout)
The current workaround is to delete pydoc from sys.modules when changing
stdout and stderr.
==============================================================================
Add-ons [[[1~
*voom_addons*
VOoM add-ons are Vim or Python scripts that use "voom.vim" and "voom.py"
functions and data. Add-ons allow to add new functionality or to customize
default features without modifying the core files.
LOADING ADD-ONS
---------------
Some Vim script add-ons can be sourced at any time, which means they can be
placed in $HOME/.vim/plugin/ like any other plugin.
For finer control, user option "g:voom_user_command" should be used to load
add-ons only when file voom.vim is being sourced. This option defines a string
to be executed via |execute|. This is the last thing done in voom.vim: >
if exists('g:voom_user_command')
execute g:voom_user_command
endif
There is no default "g:voom_user_command", it must be created by the user.
METHOD 1: Add-ons are .vim files located in $HOME/.vim/add-ons/voom/
To load them all via |runtime|, put this in vimrc: >
let g:voom_user_command = "runtime! add-ons/voom/*.vim"
METHOD 2: Add-ons are in one file, D:/SCRIPTS/VOoM/voom_addons.vim
To source the file, put this in vimrc: >
let g:voom_user_command = "source D:/SCRIPTS/VOoM/voom_addons.vim"
METHOD 3: Add-ons are in Python module voom_addons.py somewhere in Python
search path (directory ./plugin/voom will do). To import the module, put this
in vimrc: >
let g:voom_user_command = "python import voom_addons"
The voom.py module should be accessed from within voom_addons.py as follows: >
import sys
voom = sys.modules['voom']
WRITING ADD-ONS
---------------
There is no special API. The following applies:
- Python-side functions and data are available as attributes of module
"voom.py". Python-side outline data for each Body are attributes of an
instance of class VoomOutline (VO). These class instances are stored in
dictionary voom.VOOMS, keys are Body buffer numbers: VO=voom.VOOMS[body].
- All Vim functions in "voom.vim" are global and start with "Voom_".
- Vim-side data are script-local. Two functions in "voom.vim" allow
external scripts to read "voom.vim" script-local outline data:
Voom_GetBufInfo()
Voom_GetData()
Sample add-on "voom_info.vim" shows how to use them: >
:let [bufType, body, tree] = Voom_GetBufInfo()
:let [voom_bodies, voom_trees] = Voom_GetData()
<
Function Voom_GetVar(var) allows external scripts to read any "voom.vim"
script-local variable if it exists. Examples (these always exist) >
:echo Voom_GetVar('s:voom_logbnr')
:echo Voom_GetVar('s:voom_trees')
:echo Voom_GetVar('s:voom_bodies')
<
Example: move cursor to Log window in the current tab >
:let logwnr = bufwinnr(Voom_GetVar('s:voom_logbnr'))
:if logwnr > 0 | exe logwnr.'wincmd w' | endif
USING ADD-ONS TO ADD NEW FUNCTIONALITY
--------------------------------------
Add-ons can create global commands, menus and mappings.
A global command that accesses VOoM outline data must first check that the
current buffer is a VOoM buffer (Tree or Body) and refuse to execute if it's
not. It should update outline if current buffer is a Body. Sample add-on
"voom_info.vim" shows how to do that.
To create Tree-local mappings or commands use ~/.vim/ftplugin/voomtree.vim --
Tree buffer filetype is set to "voomtree" when Tree buffer is created.
USING ADD-ONS TO CUSTOMIZE VOoM
-------------------------------
Add-ons can overwrite and modify core code functions and some data. Add-on
"custom_headlines.vim" is an example of this approach. It shows how to
customize construction of Tree headline text for individual filetypes.
Such add-ons must be loaded after "voom.vim" has been sourced completely, that
is via option g:voom_user_command as explained above.
MARKUP MODES
------------
Markup modes are special kinds of add-ons. They change how outline is
constructed and how outline operations are performed (|voom_markup_modes|).
==============================================================================
Implementation notes [[[1~
*voom_notes*
==============================================================================
Theory of Operation [[[2~
==============================================================================
why Python [[[3~
The main reason VOoM uses Python is because some of its critical code is much
faster in Python than in Vim script.
Scanning a buffer for fold markers is >10 times faster with Python code than
with a similar Vim script code. A demo code is given below. To test: select
lines, copy into a register, and execute that register while in any buffer with
a large number of fold markers, or in any large buffer.
Results with "calendar_outline.txt": >
3.2MB, 56527 lines, 4160 headlines
Vim 7.3.145; Python 2.6.5; Win2k; Intel Pentium 4 Mobile, 1.6 GHz
Vim method 1: 1.53 sec
Vim method 2: 0.70 sec
Vim method 3: 0.14 sec
Python: 0.084 sec
While Vim method 3 is fast, it is inconvenient because:
a) It requires the cursor to be in Body buffer, but outline update should
be run after entering the Tree buffer.
b) It moves the cursor.
"--------------GET LINES WITH FOLD MARKERS---------------------------[[[
" Get list of headlines: lines with start fold marker followed by number.
" This is the bare minimum that must be done to create an outline.
""""" Vim method 1
func! Voom_VimTest1()
let headlines = []
let allLines = getline(1,'$')
for line in allLines
if stridx(line, '{{{')==-1 "}}}
continue
endif
if match(line, '{{{\d\+')!=-1 "}}}
call add(headlines, line)
endif
endfor
return len(headlines)
endfunc
""""" Vim method 2
func! Voom_VimTest2()
let lnums = filter(range(1,line('$')), 'getline(v:val)=~''{{{\d\+''')
let headlines = map(lnums, 'getline(v:val)')
return len(headlines)
endfunc
""""" Vim method 3
func! Voom_VimTest3()
let headlines = []
g/{{{\d\+/ call add(headlines, getline('.')) "}}}
return len(headlines)
endfunc
""""" Python code, similar to Vim method 1
python << EOF
def Voom_PyTest():
import vim
import re
re_marker = re.compile(r'{{{\d+') #}}}
headlines = []
allLines = vim.current.buffer[:]
for line in allLines:
if not '{{{' in line: continue #}}}
if re_marker.search(line):
headlines.append(line)
vim.command('let bnodes=%s' %len(headlines))
EOF
""""" timing
let start = reltime()
let nodeCount = Voom_VimTest1()
echo 'Vim method 1: ' . reltimestr(reltime(start)) . 'sec; '. nodeCount . ' nodes'
let start = reltime()
let nodeCount = Voom_VimTest2()
echo 'Vim method 2: ' . reltimestr(reltime(start)) . 'sec; '. nodeCount . ' nodes'
let start = reltime()
let nodeCount = Voom_VimTest3()
echo 'Vim method 3: ' . reltimestr(reltime(start)) . 'sec; '. nodeCount . ' nodes'
let start = reltime()
py Voom_PyTest()
echo 'Python: ' . reltimestr(reltime(start)) . 'sec; '. nodeCount . ' nodes'
unlet nodeCount
"--------------END OF CODE ------------------------------------------]]]
In addition, Python's FOR loop is >30 times faster then Vim's. In the demo
code below the Python function is >60 times faster.
"------ Vim FOR loop versus Python FOR loop -------------------------[[[
func! Time_VimForLoop()
let aList = range(1000000)
for i in aList
" pass
endfor
endfunc
python << EOF
def Time_PyForLoop():
aList = range(1000000)
for i in aList:
pass
EOF
""" 9.76 sec """
let start = reltime()
call Time_VimForLoop()
echo 'Vim: ' . reltimestr(reltime(start))
""" 0.15 sec """
let start = reltime()
py Time_PyForLoop()
echo 'Python: ' . reltimestr(reltime(start))
"-------END OF CODE--------------------------------------------------]]]
Thus, Python code should be much faster when handling large lists.
==============================================================================
separate Trees or single Tree [[[3~
A single Tree buffer could be used to display outlines of many files. Tlist
does that. This makes sense when working with several related files. Also,
having a single Tree would be more like Leo.
VOoM creates new Tree buffer for every new outline. This is simpler. It is
more appropriate for text notes, when outline files are likely to be
unrelated. Searching headlines is easier.
==============================================================================
checking Bodies for ticks [[[3~
Tree buffer and associated outline data are updated on entering Tree via
BufEnter autocommand. To perform update only when the Body has changed since
the last update, Body's b:changedtick is used as shown in the docs.
Unfortunately, b:changedtick cannot be read with getbufvar(), so it's not
accessible from Tree on BufEnter [1]. The workaround is to use Body's BufLeave
autocommand to save Body's b:changedtick. So the entire update scheme is:
- on Body BufLeave save Body's b:changedtick as "tick"
- on Tree BufEnter compare "tick_" to "tick"
- if different, do outline update and set "tick_" to "tick"
The outline must be up to date when the cursor is in the Tree buffer. If it's
not, the consequences could be unpleasant. Performing outline operations will
cause data corruption.
Outline update can fail when something goes wrong with autocommands, e.g.,
when the user messes with 'eventignore'. Or, the Body file can be modified by
an external application while cursor is in Tree.
Fortunately, most Voom commands involve a visit from Tree to Body or vice
versa, so we can compare "tick_" directly to Body's "b:changedtick". If they
are different: the command is aborted, outline update is forced, error message
is displayed. Such check is performed during:
- selecting node from Tree or Body
- Voomgrep command initiated from Tree
- during every outline operation, before modifying buffers
The function that does this check is Voom_BodyCheckTicks().
These checks can be tested by modifying Body and then moving to Tree with
":noau wincmd w" or after ":set ei=BufLeave", etc.
Another precaution is that "tick_" is not set to "tick" when an unexpected
error occurs during update. voom.updateTree()) is always called from Vim code
inside try/finally/endtry. It also sets Vim var l:ok to indicate success, see
#id_20110213212708 .
[1] 2011-01-21 Fixed by Patch 7.3.105 !!!
see #ID_20111006013436
==============================================================================
unloaded buffer + python == trouble [[[3~
Bad things happen when attempting to modify an unloaded buffer via Python
vim.buffer object. (This might be considered a Vim bug.) Example:
- Create two buffers: buf1 and buf2. They can be new, no-file buffers.
- With cursor in buf2
:py buf2=vim.current.buffer
- Buffer 2 can now be modified via Python:
:py buf2[0]="xxxxxxxxx"
- Unload buffer 2
:bun!
Buffer 1 is the current buffer.
- Try writing to buffer 2, which is not loaded
:py buf2[0]="yyyyy"
- Buffer 1 is modified instead of buffer 2, and the change cannot be undone!
Buffer 2 is no longer unloaded, so subsequent writes to it via buf2
happen correctly.
VOoM uses Python vim.buffer methods to modify Tree, Body, and PyLog buffers.
It is essential that these buffers are loaded (bufloaded())before being written
to. Writing to a non-existing (wiped out) buffer is not as dangerous because it
produces an error.
Tree and PyLog BufUnload autocommands make it unlikely that a Tree or PyLog
buffer is unloaded -- they are wiped out on BufUnload.
These buffers can still become unloaded when they are closed improperly with
"noa bun" or "noa bd" or when something goes wrong with autocommands.
Body buffers can be unloaded since v3.0.
There are checks that ensure that the buffer is loaded (bufloaded()) before it
is modified via Python vim.buffer object.
==============================================================================
wipe out Tree on BufUnload [[[3~
A Tree buffer should be wiped out and the corresponding VOoM data deleted
after:
1) Tree is unloaded. All content is lost, Tree reverts to blank buffer.
2) Tree is deleted. As above, plus buffer-local mappings are lost.
2) Tree is wiped out. VOoM data need to be cleaned up.
This is accomplished via BufUnload autocmd for Tree, which is also triggered on
BufDelete and BufWipeout.
Unloaded, deleted, and wiped out Body buffers are obviously also a problem, see
next node. Prior to v3.0 there was Body BufUnload au that wiped out Tree. That
was found to be too risky.
There are several fail-safe measures that ensure that nothing damaging will
happen if Tree BufUnload autocommand is not triggered, as after "noa bun", "noa
bd", "noa bw".
Most Voom commands check that: Tree is loaded, Body exists, Body is loaded (see
next). This relies on bufloaded() and bufexists().
Functions Voom_ToBody() and Voom_ToTree(), which are called when selecting
nodes and before almost every outline operation, perform all of the above
checks and will do cleanup if checks fail.
The PyLog buffer should also be wiped out when unloaded or deleted. There is a
check that ensures that PyLog is loaded before printing to it.
==============================================================================
unloaded, deleted, wiped out Bodies [[[3~
Unloaded Body buffers are a problem:
It is not possible to outline a buffer if it is unloaded.
Python vim.buffer object is useless for unloaded buffer, it's [""].
When unloaded Body is loaded again the following events are hard to detect:
- buffer changes were abandoned after q!, bun!, bd!
- file was modified by external process
Thus, a global outline update must be done after loading Body. This means we
should abort outline command if Body is found unloaded, even if we can load it
and force outline update.
PERFECT: Body b:changedtick is incremented by 2 after unloading/loading.
Outline update is guarantied on Tree BufEnter or when updating from Body.
We deal with unloaded Bodies by disabling Tree buffer commands -- as soon as
Body bufnr is computed, check if it's loaded and abort the command if it's not.
Helper function is Voom_BufLoaded(body). It will also detect if Body does not
exist. This must be done for:
outline update on BufEnter
all outline operations
node selection (always done by Voom_TreeSelect())
Voomgrep, Voomunl, Body text getters (Voomexec)
any other command that requires up-to-date outline, or reads/writes Body
The next line of defense is Voom_ToBody(), which is called by almost all Tree
commands. When it detects Body is unloaded it loads it in new window as usual,
runs outline update, returns -1. If Body does not exist it performs clean up.
The b:changedtick check (see "Checking Bodies for ticks") also should prevent
potential troubles after Body unload/reload. This is because b:changedtick
changes after unloading a buffer and loading it again.
When Body buffer is deleted (:bd) it is unloaded. In addition, buffer-local
mappings are lost. The loss of Body-local mappings (shuttle keys) is detected
by Body BufEnter au. It checks for hasmapto('Voom_ToTreeOrBodyWin') and
restores mappings if needed.
The command :Voom checks hasmapto('Voom_ToTreeOrBodyWin') when executed in Tree
or Body. If not found, it reconfigures Tree/Body. In theory, this can be used
to restore Tree and Body configurations after some perverted unloads/reloads
with ":noa bd", "noa b", etc.
Wiped out Bodies are also unloaded. Tree has no reason to exist after Body has
been wiped out. Sadly, wiping out Tree from Body BufWipeout au is too risky,
see v3.0 notes.
==============================================================================
CHANGELOG [[[2o~
v4.3, 2012-05-06 [[[3x~
PROBLEM: The Voom command cannot handle buffer names containing %, #, etc.
Session restore is also affected.
Whitespace in names is also a problem on some systems (Jonathan Reeve).
SOLUTION: Do fnameescape() when :edit, :file, :tabnew, etc.
Added |voom_mode_hashes|.
v4.2, 2012-04-04 [[[3~
New commands for quitting and toggling outline window (|voom_quit|):
"q", VoomToggle, Voomtoggle, Voomquit, VoomQuitAll.
https://github.com/vim-voom/vim-voom.github.com/issues/2
New Tree mappings ^^ (Move Up) and __ (Move Down) for symmetry with << and >>.
Added support for "fmr" modes (|voom_mode_fmr|). Modes fmr, fmr1, fmr2.
New options |g:voom_ft_modes|, |g:voom_default_mode| allow automatic selection
of markup mode according to filetype of the source buffer.
Improved asciidoc mode: there can be any number of preceding [] or [[]] lines
and in any order; blank line is not required before the topmost [] or [[]].
:Voomexec now executes Python scripts via "exec" instead of execfile(). Temp
file plugin/voom/_voomScript_.py is no longer created and should be deleted.
Python traceback's lnums match buffer lnums.
The "end of script" message shows script's start/end lnums.
Vim code
--------
Replaced Voom_GetBodyLines1() with more useful functions.
Voomexec fix: execute Vim scripts in a separate function Voom_ExecVim() to
avoid potential interference with Voom_Exec() local vars.
Python scripts still have access to Voom_Exec() vars. No big deal, unlikely to
cause any problems. Demo:
### :Voomexec py [[[
vim.command("echo [bufType,body,bln1,bln2]")
print vim.eval("[bufType,body,bln1,bln2]")
### ]]]
Python code
-----------
Mode-specific functions, such as makeOutline(), are now VO methods set during
outline init. Thus got rid of incessant getattr(VO.mmode,...) during outline
updates and outline operations. It's now easier to control what modes can do.
Split makeOutline() into makeOutline() and makeOutlineH() for efficiency sake.
(If needed, the old makeOutline() function can be in a fmr mode.)
Added check for clipboard size in setClipboard() to guard against failures with
very large clipboards.
Get &enc during outline init (VO.enc) instead of during markup mode imports.
Otherwise, it's impossible to change &enc without reloading everything.
v4.1, 2011-11-27 [[[3~
PROBLEM: Tree mappings J/K are supposed to accept a count, but they don't.
This is with Vim 7.3.145. No problem with Vim 7.2.
SOLUTION: Save original v:count1 before
exe 'normal...
in Voom_Tree_KJUD().
Better argument completion for the :Voom command. The list of modes is
constructed from file names voom_mode_{whatever}.py in ../plugin/voom .
v4.0, 2011-11-06 [[[3~
New markup modes: asciidoc, org (same as old viki), cwiki.
Viki mode now ignores special regions.
New Tree mapping: "R" selects corresponding Body range.
Tweaked Markdown mode.
Fix in viki/org mode: level changing outline operations converted any
whitespace after * into space.
Fixed Tree syntax hi to avoid false hi after "|" inside of headline text.
Example: part after # is not comment >
= . . |<<test link||#test>>
ID_20111006013436
Improved function Insert Node: use getbufvar(body,"changedtick") if
has("patch105"). This saves one trip to Body and back when checking for ticks.
Code for timing, execute from Tree, the Body is empty: >
let tree = bufnr('')
let start = reltime()
for i in range(1,100)
call Voom_OopInsert('')
call Voom_ToTree(tree)
endfor
echo reltimestr(reltime(start))
unlet tree start
0.71 sec vs 1.10-1.13 sec with the old code or if there is no patch.
It seems there are no other functions that would benefit from this.
Note: when check for ticks via getbufvar() fails, the next step should be to
move cursor into Body buffer--it may no longer exist, unloaded, etc.
v4.0b5, 2011-03-24 [[[3~
New markup mode: txt2tags.
Added support for Vim Sessions (:mksession) via BufFilePost autocmd for VOOM
Tree buffers and __PyLog__ buffers.
Fixed bug in :Voomexec -- Python script file encoding was set incorrectly.
Source code encoding of the temp script file should be Vim internal encoding,
not &fenc or &enc.
Fixed command Edit Headline (iIaA): cursor was not positioned on the first word
char in Body headline when there are was no foldmarker (markup modes).
Dealing with Python errors during outline update.
-------------------------------------------------
Working in the python mode revealed a flaw in safeguards against Python errors
during outline update. Such errors are expected while in python mode --
tokenize.py raises exception when indentation is wrong or a quote is missing.
id_20110213212708 , also see #id_20110213225841
Calling voom.updateTree() via try/python.../finally/endtry in the Vim code
(|try-finally|) does not guard against Python errors when PyLog is on. It looks
like Vim error is not triggered when Python's sys.stderr is redirected. The
result is that changedtick (tick_) is updated despite a failed update.
SOLUTION: always set Vim var l:ok in voom.updateTree() before returning to
indicate a successful update.
Python mode: catch exceptions raised by tokenize.py, echo the error, set Tree
lines to make it clear that update has failed and outline is invalid.
Refactoring
-----------
Insert New Headline -- don't need Body column, just search for "NewHeadline".
voom.newHeadline(), hook_newHeadline() no longer return column.
Voom_LogScroll() -- several optimizations. PyLog is usually only in the current
tabpage. Thus, check tabpagenr() before tabnext--faster than redundant tabnext.
v4.0b4, 2011-01-30 [[[3~
New Tree mappings for navigating outline:
P (go to parent node),
c (go to parent and contract it),
C (contract siblings or everything in Visual selection),
o (go to first child),
O (expand siblings or everything in Visual selection),
K/J/U/D (go to previous/next/uppermost/downmost sibling),
s (show headline text), S (show UNL).
id_20110121201243
PROBLEM: Longstanding annoyance with some Tree mappings. Example: hit "d"
(disabled by mapping to <Nop>), wait a few seconds, hit "dd" (cut node) --
there is no response. Can be very confusing.
SOLUTION: disable "d" and similar by mapping them to <Esc> instead of <Nop>.
Another option is to map them to 0f| .
Disabled more text changing keys in Tree: < > <Ctrl-x> etc.
PROBLEM: User placed VOoM package in ~/.vim/plugin. Everything gets loaded on
Vim startup (|load-plugins|). Add-on custom_headlines.vim causes error because
it must be loaded only after voom.vim has been sourced completely.
SOLUTION: finish loading custom_headlines.vim if !exists('*Voom_Exec').
PROBLEM: Command :Voomhelp does not reuse existing voom.txt windows if current
buffer is not voom.txt or its Tree.
SOLUTION: Start by searching all tabs for voom.txt window.
id_20110120011733
PROBLEM: Outline has only level 1 headlines and there is a stray 'o' mark.
vim.error in voom.foldingCreate() on startup after :Voom.
E490: No fold found, triggered by initial :foldopen, because Tree has no folds.
SOLUTION: Catch E490 when doing :foldopen in foldingCreate().
Note1: must execute :foldopen even when cFolds list is empty.
Note2: cFolds (lnums of closed folds) never contains nodes without children.
This means "zc" will not trigger E490 error. Unless Tree folding is messed up
or lost, e.g., because fdm was reset.
id_20110125210844
Fixed glitches with initial cursor positioning in Tree when markup mode is
used. snLn can be >1 when markup mode is used or when there is no startup node
(Body cursor on >1 node).
Create jumps marks when outline is created: line 1 and selected node.
Initial gg restores view after jumping around when creating folds.
Added "keepj" when jumping around Tree and Body via G or gg.
No jump marks are created in Tree or Body during node navigation or manipulation.
TODO: set jump mark when selecting node from Tree with <Enter> or other
actions. Outline browsing history.
Vim code for outline navigation id_20110116213809
---------------------------------------------------
Made Voom_TreeLeft() much faster with large outlines.
The final step (go to parent) used this inefficient code: >
let ind = stridx(getline('.'),'|')
let indp = ind
while indp>=ind
normal! k
let indp = stridx(getline('.'),'|')
endwhile
It is much faster to call search() to find line with required indent of |.
Multibyte chars should not be a problem because there are never any before |.
Timing: 5876 childless siblings, cursor on the last.
Old code: 0.28 sec. New code: 0.01 sec.
Voom_TreeToSiblings(), etc: also use search() to locate parents/siblings.
virtcol() ensures multibyte chars before | will never be a problem.
Simplified Voom_TreeSelect(lnum, focus) signature. No need for lnum, it's
always current line. focus is 1 (stay in Tree) or 0.
Got rid of Voom_TreePlaceCursor(), just do
call cursor(0,stridx(getline('.'),'|')+1)
or
normal! 0f|
v4.0b3, 2011-01-04 [[[3~
New markup mode: markdown.
Fixed severe bug in reST mode. Paste and level-changing outline operations were
affected. One manifestation: when pasting into an empty outline all headlines
become level 1.
The command :VoomSort now accepts a line range in front of it. If a range is
not a single line, siblings in the range are sorted.
Changed how some outline operations handle the first Tree line (outline title):
- VoomSort now aborts if the first Tree line is selected. This is to be
consistent with other outline operations (Cut, Copy, Move) which also
require a valid range.
- Print error message when an operation is aborted because the first Tree
line is selected (Cut, Copy, Move, Sort).
- Mark Node as Startup is allowed: remove "=" marks from all headlines.
Mode viki: allow any whitespace after last leading *, not just space.
Outline operation Copy: do not display error message complaining about Body
buffer being nomodifiable or readonly.
Code refactoring
----------------
s:voom_logbnr now always exists. It is 0 if there is no Log buffer.
New helper function Voom_GetVar(var) -- allows external scripts to read any
"voom.vim" script-local variable such as s:voom_logbnr.
:Voomexec -- improved printing of errors. When PyLog is not enabled,
Python traceback is echoed as Vim error message. See
../plugin/voom/voom.py#id_20101214100357
Assign VO.marker and VO.marker_re to MARKER and MARKER_RE instead of 0 when
foldmarker is default. MARKER_RE object is reused, so this is still efficient.
This eliminated the need for silly code
marker = VO.marker or MARKER
marker_re = VO.marker_re or MARKER_RE
------------------------------------------------------------------------------
v4.0b2, 2010-10-24 [[[3~
New markup modes: rest (reStructuredText), python, thevimoutliner, vimoutliner.
Changed default for g:voom_verify_oop to 1 (enabled). We need this to detect
inherent problems with "python" and "rest" modes, to debug other modes. Outline
verification is performed by new function Voom_OopVerify(). It forces outline
update if verification fails.
Option g:voom_rstrip_chars (dictionary) has been removed. Instead, there are
options g:voom_rstrip_chars_{filetype} (strings) for each Body filetype of
interest. REASON: it's easier to define a string for one filetype than to mess
with a dictionary that has settings for a bunch of other filetypes.
Command VoomSort now checks that the number of headlines is not changed after
sorting (after Tree update on BufEnter). When using modes "rest" or "python"
sorting can make some headlines cease to be headlines.
Added argument completion for command :Voom.
Added special syntax hi in Tree when Body's filetype is vim or python.
See Voom_TreeSyntax().
Python code refactoring:
- Name VOOMS is no longer defined in Vim module namespace. It is available
only as voom.VOOMS.
- Changed argument "body" in many functions like makeOutline() to "VO".
This makes more sense since "VO" is what we need. Makes it easier to
write markup modes and add-ons -- no need to look up VO in voom.VOOMS.
- Refactored oops Cut, Paste, Up, Down, Left, Right to accomodate modes
like "python" and "rest". The new sequence of actions is:
- modify Body lines (move);
- update VO.bnodes; update VO.levels;
- call hook_doBodyAfterOop() to finish updating Body lines -- change
indentation, headline adornment styles, etc;
- go back to Tree; update Tree lines.
'noautocmd' troubles [[[4~
Testing thevimoutliner mode with TVO plugin installed revealed serious flaw in
node selection functions -- they screw up TVO's BufEnter and BufLeave autocmds
that disable/enable TVO's menu. There are errors about missing menu, etc.
The culprit is "noautocmd" in Voom_TreeSelect() and Voom_BodySelect().
Same problem with VoomSort.
All outline operations use "noautocmd" when cycling between Body and Tree. This
can also cause problems -- if outline operation fails the cursor stuck in Body.
SOLUTION: do not use "noautocmd".
The original reason for "noautocmds" was to increase performance by disabling
autocmds when temporarily visiting Tree or Body window -- a frequent action,
e.g., when selecting nodes. The performance gain is usually minuscule and is
not worth the risk of screwing up autocommands created by other plugins.
There is also problem with Tree BufUnload au -- it must be "nested" to trigger
BufEnter, etc. after Tree is wiped out, and we cannot use "noautocmd" when
wiping out Tree. But without "noautocmd" we get recursive call.
SOLUTION: first delete Tree autocommands, then wipe out Tree without using
"noautocmd".
This change was made in Voom_TreeBufUnload() and Voom_UnVoom()
Same change was made in Log BufUnload au: made it nested, delete Log au before
wiping out Log.
"noautocmds" is now used only in Voom_LogScroll() for performance sake.
It's very unlikely that something will go wrong there.
------------------------------------------------------------------------------
v4.0b1, 2010-09-21 [[[3~
Added support for headline markups other than start fold markers with levels:
|voom_markup_modes|. Available markup modes: wiki, vimwiki, viki, html.
Changed plugin directory structure: all Python files are now located in folder
plugin/voom.
Changed how global outline data are stored.
Old scheme: class VOOM has a bunch of dictionaries as attribs. Keys are Body
bufnr. Data for one outline:
bnodes, levels = VOOM.bnodes[body], VOOM.levels[body]
New scheme: there is instance of class VoomOutline for each Body, attribs are
outline properties. These instances are stored in global dict VOOMS, keys are
Body bufnr.
VO = VOOMS[body]
bnodes, levels = VO.bnodes, VO.levels
PROBLEM introduced since setting Tree's "bufhidden" to "wipe".
Tabpage has two windows, Tree and Body. Load another buffer in Body window and
create outline. What is left is one window with new Tree.
FIX: Voom_ToTreeWin(), when re-using another Tree window: split it if current
tabpage has no other windows with this Tree buffer. This actually makes sense
regardless of Tree "bufhidden".
------------------------------------------------------------------------------
v3.0, 2010-08-01 [[[3~
New command :VoomSort [options] for sorting outline, |voom_sort|.
Tree buffer is no longer automatically wiped out when its Body buffer is
unloaded, deleted, or wiped out. Instead, outline is locked until Body is
loaded again. This change was needed to eliminate crashes after :q, :q! and
related problems. This can also make working with outlines easier when buffers
routinely get unloaded, as when 'hidden' and 'bufhidden' are not set.
Option 'bufhidden' for Tree buffers is set to "wipe" instead of "hide".
This should make it less likely that an orphan Tree is hanging around long
after its Body is gone.
PyLog buffer has 'bufhidden' set to "wipe" instead of "hide".
PyLog filetype is set to "voomlog" instead of "log".
PyLog syntax: better highlighting of Python tracebacks.
In several places in voom.py a new list of Body lines was created for no good
reason: VOOM.buffers[body][:]. These were changed to VOOM.buffers[body], which
is Vim buffer object. This substantially reduces memory usage, especially when
working with large buffers. This affects outline update. Timing tests with
calendar_outline.txt: makeOutline() is slower (0.15 vs 0.11 sec). But the
overall time to run update on Tree BufEnter is about the same (0.16 sec if no
outline change), so it's definitely worth it.
Similarly, there is no need to create a new list of current Tree lines in
updateTree() (tlines_ = Tree[:]) since we compare Tree lines one by one.
PROBLEM: Tree window-local settings can be wrong if new window is created
manually. Example: cursor is in Body, :split, :b[Tree bufnr].
FIX: On Tree BufEnter check if w:voom_tree exists. If not, call
Voom_TreeConfigWin()--it sets window-local options and creates w:voom_tree.
Added "vim" filetype to default g:voom_rstrip_chars: # is stripped in addition
to " because it's comment char in Python etc. sections of .vim files.
Various code changes
Renamed VOOM.nodes to VOOM.bnodes to make clearer it is list of Body lnums.
voom.py functions no longer access voom.vim script-local variables directly.
This means all voom.py functions can be called from add-ons.
Some functions used to compute tree from body like this
tree = int(vim.eval('s:voom_bodies[%s].tree' %body))
These now require both body and tree as arguments. (updateTree, verifyTree,
nodeUNL)
In several places snLn was set:
vim.command('let s:voom_bodies[%s].snLn=%s' %(body, snLn))
These now call Voom_SetSnLn(body,snLn) instead.
When converting buffer lines to/from Python Unicode objects encoding is set to
"utf-8" if &encoding is any Unicode encoding. It turns out Vim uses utf-8
internally in such cases. See voom.getVimEnc()
Vim code changes due to new scheme of dealing with unloaded and deleted Body
buffers. Body BufUnload au is gone. New Body BufEnter au detects loss of
buffer-local mappings.
Tree autocmds are now buffer-local. This seems more robust than relying on Tree
name pattern, easier to disable for individual Trees should we need to do so.
s:voom_TreeBufEnter is not needed anymore.
Got rid of b:voom_tree and b:voom_body. Use hasmapto('Voom_ToTreeOrBodyWin') to
detect loss of buffer-local mappings.
crash after :q, :q! [[[4 ~
(reported by William Fugy)
Current tabpage has two windows: Body and corresponding Tree.
There are no other windows with Body or Tree.
'hidden' is off, Body 'bufhidden' is "".
With cursor in Body, :q or :q! produce spectacular crash--sometimes gvim.exe
crashes, sometimes stream of E315 errors.
-------------------------------------------------
The culprit is Body BufUnload autocmd: it wipes out Tree buffer and thus can
close windows and tabs. This confuses :q but not :bun :bd :bw.
Setting hidden or bufhidden doesn't help because :q! always unloads buffer.
Kludge attempt in Body BufUnload, before Tree wipeout:
if winnr('$')==2 && bufwinnr(body)>0 && bufwinnr(tree)>0
new
endif
No crashes after :q or q!. New crash after :bd, :bw in Body.
Creating new window on BufUnload is as dangerous as closing one.
Not wiping out Tree on Body BufUnload is the only solution.
-------------------------------------------------
Got rid of Body BufUnload au.
Try Body BufWipeout au -- wipe out Tree when Body is wiped out.
Crash after :q still happens if Body 'bufhidden' is "wipe" -- obviously same
situation as with BufUnload. Such setting seems unlikely. :Voom can refuse to
create outline if current buffer has such setting.
ANOTHER NASTY GLITCH:
gvim.exe test_outline.txt
:Voom
:bw1
Tree is gone, window still shows test_outline.txt -- this is horribly wrong.
:Voom
Both Body and Tree are empty.
**CONCLUSION: DON'T DO IT**
The workaround is function Voom_Delete('ex_command') to be used in custom
mappings.
Also, set Tree 'bufhidden' to wipe instead of hide.
-------------------------
Possible Body BufWipeout au, should be safe:
if Tree is shown in a window: set Tree bufhidden to wipe
if not: wipe out Tree
This is too convoluted.
Tree folds are wrong in split windows after outline operation [[[4~
gvim.exe test_outline.txt
:Voom
:set fdc=6
:split
:split
Copy node "5", Paste after "5.2"
Folds are wrong in 2nd and 3rd window.
Also affects Tree windows in other tabs.
Folds in the current window are fixed after :setl fdm=expr
--------------------------
Sorting is not afflicted with this bug.
Sorting is different from other Oops--Tree is drawn while in Tree, on BufEnter.
Change
call Voom_OopFromBody(body,tree,l:blnShow,'')
to
if Voom_BodyUpdateTree()==-1 | let &lz=lz_ | return | endif
call Voom_OopFromBody(body,tree,l:blnShow,'noa')
and folds are wrong in split windows
--------------------------
Thus, the fix is to draw Tree lines while in Tree.
Current Oop scheme for most Oops, start in Tree, Vim code:
perform checks, get data
go to Body
check ticks
run Python code:
change Body lines; change Tree lines; adjust bnodes and levels
call Voom_OopFromBody() -- adjust Body view and go back to Tree
adjust Tree view
New Oop scheme, start in Tree, Vim code:
perform checks, get data
go to Body
check ticks
run Python code:
change Body lines; (adjust bnodes and levels)
call Voom_OopFromBody() -- adjust Body view and go back to Tree
change Tree lines; (adjust bnodes and levels)
adjust Tree view
Changed the following Oops: Paste, Cut, Up, Down, Right, Left.
These Oops do not change Tree folds: Mark/Unmark, Mark as selected
No change is needed for: Insert new node (done from Tree), Copy.
Save/Restore/Cleanup Folding do not modify Tree, they are done from Tree.
--------------------------
Folds can also be wrong in split Tree windows after outline update was forced
from Body after :Voomgrep, :Voomunl, etc. This is rare and no big deal.
v2.1, 2010-06-01 [[[3~
The procedure for constructing Tree headline text was modifed to permit
customization for individual filetypes:
- Comment chars that are stripped from the right side of Tree headlines
are by default obtained from Body's 'commentstring' option.
- User dictionary g:voom_rstrip_chars can be used to control exactly which
characters are stripped from the right side of Tree headlines. This is
done for individual filetypes and will overide 'commentstring' option.
- Finally, an arbitrary headline constructing function can be defined for
individual filetypes in an add-on. Add-on "custom_headlines.vim" shows
how.
For details, see node
OUTLINING (:Voom) -> Create Outline -> Tree Headline Text
New user option "g:voom_create_devel_commands" controls if development helper
commands are created. They are commented out in previous versions.
Removed <F1> Tree-local mapping (same as :Voomhelp).
Bug in PyLog buffer creation/destruction: Python original sys.stdout and
sys.stderr can be lost after some actions, e.g. after command :VoomReloadAll.
FIX: changed how original sys.stdout and sys.stderr are saved.
v2.0, 2010-04-01 [[[3~
The name of this plugin was changed from VOOF (Vim Outliner Of Folds) to VOoM
(Vim Outliner of Markers):
- The new name is more accurate. It deemphasizes the role of folds. Body
buffer folding has no effect on outline construction or on outline
operations. Markers are determined by option "foldmarker", but only
start fold markers with levels are used.
- Voom sounds better than Voof, more energetic -- vroom-zoom-boom.
(Look matey, this parrot wouldn't "voom" if I put four thousand volts
through it.)
Corresponding changes were made in file names, commands, user options, help
tags, names of functions and variables. All occurrences of VOOF/Voof/voof were
changed to VOOM/Voom/voom: the command "Voof" became "Voom",
"g:voof_tree_placement" became "g:voom_tree_placement", and so on.
If you are upgrading from previous versions, please delete old "voof" files
(voof.vim, voof.py, voof.pyc, voof.txt), delete file "voofScript.py" if any,
edit user options in .vimrc if you have any, run :helptags.
Added rudimentary support for add-ons, sample add-on "voom_info.vim". See node
Implementation notes -> Extending VOoM with add-ons
for details.
Added instructions for Windows users on how to get Python-enabled Vim.
Renamed some functions. Other minor code style changes.
There is an elusive bug in mouse left click Tree mapping. It seems it's
possible for <LeftRelease> to be triggered in a wrong buffer. Cannot
reproduce, has something to do with resizing windows.
FIX: added check that current buffer is Tree in Voom_TreeMouseClick().
v1.92, 2010-03-03 [[[3~
PROBLEM: outline operations Mark/Unmark, Move Right/Left can be slow when they
involve a large number of folds.
EXAMPLE: mark/unmark all nodes in calendar_outline.txt takes about 3 seconds.
But set Body foldmethod to "manual" and the time is reduced to 0.85 seconds.
Set Tree foldmethod to "manual" and the time is reduced further to 0.16 sec.
FIX: Set Tree and Body foldmethod to "manual" during Mark/Unmark. Set Body
foldmethod to manual during Move Right/Left. Other operations are not
susceptible.
Command :VoofFoldingSave is now much faster when applied to huge and deeply
nested branches with lots of closed folds. The problem was recursive function
foldingGet(). Got rid of recursion -- unnecessary and inefficient.
foldingGet() and foldingGetAll() were merged into foldingGet().
If Body "foldmethod" is not "marker", Body node could be hidden in fold after
selecting node.
FIX: do "zv" in Body after: selecting node in Tree, outline operations, on
startup. In other words, if foldmethod is marker, do "zMzvzt" to show selected
Body node. Otherwise do "zvzt".
Fixed stupid code in Voof_ToTreeOrBodyWin(), which is the <Tab> command -- no
need to visit all windows to find the target. It was causing confusion when
working with split windows.
Code tweaks to save precious microseconds:
voof.vim
- Use stridx(line,'|') instead of match(line,'|') in various Tree
functions, including foldexpr.
- Compacted and simplified Tree foldexpr function.
voof.py
- xrange() is now used in many places instead of other iteration methods.
- Cleaned up some code, especially for outline operations.
v1.91, 2010-02-06 [[[3~
Command :Voofgrep can now perform boolean AND and NOT searches.
Increased maximum number of matches when doing Voofgrep to 10000 from 1000.
Annoyance: when outline is created, there can be unnecessary scrolling down in
the Tree window.
Fix: Voof_TreeCreate() code that puts cursor on startup node. Do "gg" before
jumping to startup node to counteract scrolling caused by fiddling with folds.
Don't do "zz" if the first or the last Tree line is in the window.
There were some "normal" in voof.vim. Changed all to "normal!".
v1.9, 2009-12-19 [[[3~
It's now possible to save and restore Tree buffer folding. This feature uses
special node marks 'o' in Body headlines. See |voof_VoofFoldingSave|.
New Tree mapping: + (Shift-=) finds startup node, if any, that is node marked
with '=' in Body headline. Warns if there are several such nodes.
Command "Voofrun" was renamed "Voofexec".
Tree mapping for Execute Script was changed to "<LocalLeader>e" from
"<LocalLeader>r", which was in conflict with mapping for "Move Right".
Executing Python code via Voofexec: source code encoding is now specified on
the first line of script file as per http://www.python.org/dev/peps/pep-0263/.
Encoding is obtained from Body's 'fenc' or, if it's empty, from 'enc'.
Fixed bug in Voofexec: unsupported script type argument was ignored if
buffer's filetype was a supported script type. More informative message if
script type is unsupported.
Improved how the command Edit Headline (iIaA) positions cursor in Body
headline: "\<" is used instead of "\w" to find the first word char. This works
better with unicode.
"g:voof_tree_hight" and "g:voof_log_hight" were renamed "g:voof_tree_height"
and "g:voof_log_height" respectively.
v1.8, 2009-09-18 [[[3~
Bug in Normal mode mappings: nasty errors when attempting to use mapping with
a count, which is not supported, e.g., 3<Return>.
Fix: made all mappings start with ":<C-u>" to clear command line before
calling a function.
Added highlighting of warning and error messages.
Added fancy highlighting of Voofunl output: different highlights for headlines
and separators.
Correction in docs: <Tab>/CTRL-I is Vim default key for going forward in the
jumps list.
Distribution now follows Vim directory structure: there are /plugin and /doc
folders. Simplified Voofhelp accordingly: if voof.vim is in dir a/b, voof.txt
is assumed to be in a/doc.
Changed license to WTFPL, version 2.
v1.7, 2009-08-31 [[[3~
Checks that previously checked that Body or Tree buffer exists now check if
the buffer is loaded (bufloaded()). This is needed because bad things happen
when writing to an unloaded buffer via Python's vim.buffer.
See "Implementation notes -> unloaded buffer + python == trouble"
When killing Trees and PyLog do "bwipeout" instead of "bwipeout!" -- it's
sufficient and safer.
Adjusted how new Tree window is opened: previous window (^wp) is used if it
shows a Tree buffer.
PyLog:
Added fail-safe check that ensures PyLog buffer is loaded before being written
to. This can be tested by unloading PyLog with "noa bun" or "noa bd" and then
printing to it: py print "something".
Added workaround for a glitch with the output of help().
Made voof_logbnr variable script-local.
v1.6, 2009-08-23 [[[3~
Added checks to prevent data corruption when outline update fails for any
reason. When these checks fail, the Tree buffer is wiped out and outline data
are cleaned up. These checks can be tested as follows:
- Create outline with the Voof command.
- Delete some lines in Body buffer.
- Move to Tree buffer with
:noa wincmd w
- Tree update did not happen and outline data are out of sync with the
Body. In previous versions, performing outline operation at this stage
would cause data corruption.
- Select new node or try outline operation. Voof will issue error message,
wipe out Tree buffer, and perform clean up.
Another way to test these checks is to modify Body file with an external
application while cursor is in the Tree window.
There is more details in "Implementation notes -> Checking Bodies for ticks".
Added some other foolproofing measures.
Improved automatic scrolling of PyLog buffer. Both previous (^wp) and current
window numbers are preserved in tabpages where PyLog is scrolled. Previously,
only current window number was preserved.
Fixed some bugs. Streamlined some code.
v1.5, 2009-08-15 [[[3~
New commands: Voofgrep, Voofunl.
Fixed blunder in "Move Down" outline operation that could cause outline
corruption. To find node after which to move, the cursor must be put on the
last node of the branch. That was done in Visual mode, but not in Normal mode.
<Return> and <Tab> in Tree buffers now also work in Visual mode.
Changed behavior of <Tab>: move cursor to Body window if current window is
Tree and vice versa. Previous behavior (cycle through all Body and Tree
windows) was less useful and inconsistent with <Return> behavior.
Added checks for Body foldmethod. If it's not "marker":
- folds in Body are not collapsed (zMzv) after node selection in Tree and
after outline operations;
- Voofrun will refuse to run when executed while in Body buffer.
Made Tree buffers and PyLog buffer unlisted.
If possible, :Voofhelp command will open voof.txt via "tab help voof.txt"
command, so that tags will be active.
Made help tags start with "voof_".
Edited "Why VOoF uses Python": it turns out there is a fast, pure Vim method
to scan for headlines, but it's much less convenient than the Python way: >
let headlines=[]
g/{{{\d\+/ call add(headlines, getline('.')) "}}}
code improvements [[[4~
The way "eventignore" was used to temporarily disable autocommands was unsafe.
"eventignore" is no longer set anywhere. "noautocmd" is used instead:
|autocmd-disable|.
Modified voof.voofUpdate() (formally treeUpdate) to work from any buffer as
long as the Tree is "ma". Voof_TreeBufEnter() now calls voof.voofUpdate()
directly. Voof_BodyUpdateTree() updates Tree while in Body without moving to
Tree. This is extremely useful--can now use outline data while in Body.
Optimization in voof.voofOutline() parser function: >
if not marker in line: continue
This makes sense because search with marker regexp is 3-4 times slower than
the above membership test, and in a typical outline most lines don't have
markers. Timing voof.voofUpdate() in Voof_TreeBufEnter(),
"calendar_outline.txt" update when headlines unchanged:
0.17 sec instead of 0.24 sec.
Changed Vim data variables voof_bodies, voof_trees, etc. from global to
script-local. Command VoofPrintData prints these for debugging purposes.
Should external scripts need to read these, a function that returns these
could be provided.
voof.computeSnLn() uses bisect--should be faster than previous naive code.
Changed <f-args> in Voofrun to <q-args> -- simpler.
PyLog code is, hopefully, near the state of perfection: when something goes
wrong, the exception info is displayed no matter what.
voof.oopMarkSelected() -- don't remove just one =, strip all consecutive
Voof_GetLines() uses winsaveview()/winrestview() to prevent scrolling after
zc/zo.
Use setreg() to restore registers exactly as shown in help.
Doing "let @z=z_old" is not reliable enough--register mode can change.
v1.4, 2009-07-12 [[[3~
New Tree navigation commands (Normal mode):
x Go to next marked node (mnemonic: find headline marked with 'x').
X Go to previous marked node.
"Unmark Node" operation now removes all consecutive 'x' chars from Body
headline instead of just one. This eliminates confusion when a bunch of 'x' is
present after start fold marker level number. For the same reason, "Mark Node
as Selected" (<LocalLeader>=) now strips 'x' chars after removed '=' char.
Bug: When Body starts with a headline, click on the first line in Tree (path
info line) doesn't select first node.
Fix: in Python code of Voof_TreeSelect() replaced
nodeEnd = VOOF.nodes[body][lnum]-1
with
nodeEnd = VOOF.nodes[body][lnum]-1 or 1
Fixed errors in LogBufferClass write() method, printing messages when log
buffer doesn't exist.
Bug: Select more than one lines in Tree and press i/I/A/a. An error in
Voof_OopEdit() occurs.
Fix: Mapped i/I/A/a keys only for Normal mode with nnoremap. They were
mistakenly mapped with noremap.
A message is now printed when an outline operation is aborted because Body
buffer is readonly or nomodifiable.
Replaced most Python regions in voof.vim with voof.py functions.
Renamed some Python functions:
voof_WhatEver() means it's Python code for Voof_WhatEver() Vim function.
Voof_FoldLines() renamed Voof_GetLines().
Voof_FoldRun() renamed Voof_Run().
Various edits and additions in voof.txt.
v1.3, 2009-06-06 [[[3~
New: start fold marker string is obtained from Vim option 'foldmarker' when
the Voof command is run. Each Body buffer can have its own start fold marker.
Replaced Body's BufDelete autocommand with BufUnload autocommand. Tree buffer
is now wiped out when its Body is unloaded, deleted or wiped out. Corrected
Body and Tree BufUnload au functions: use "nested" and "noautocmd".
Added * to chars being stripped during headline construction to allow /**/
around fold markers. Better syntax highlight for commented headlines in Tree.
Changed how Tree buffer name is constructed: {bufname}_VOOF{bufnr} instead of
VOOF_{bufname}_{bufnr}.
When checking if current buffer is a Tree, instead of checking buffer name, do
has_key(g:voof_trees, bufnr('')).
When eventignore is set, save and restore original eventignore instead of
doing "set eventignore=" .
Annoyance: Moving Tree window to top/bottom (^W K/J) maximizes window height.
Fix: Don't set "winfixheight" when creating Tree window. I don't understand why
this happens. There is no such problem with "winfixwidth".
Got rid of Voof_ErrorMsg() and Voof_InfoMsg().
Expanded help file.
v1.2, 2009-05-30 [[[3~
Bug: after outline operation cursor may be on the last line of range instead
of first (if Visual and there is only one root node).
Fix: tweaked Voof_OopShowTree().
Re-wrote Voof_TreeToggleFold() to handle: no fold at cursor; cursor hidden in
fold.
Allow outline operation Copy when Body is noma or ro.
v1.1, 2009-05-26 [[[3~
Bug fix involving nomodifiable and readonly buffers.
Outline operations now silently abort if Body is noma or ro.
v1.0, 2009-05-25 [[[3~
Initial release.
==============================================================================
modelines [[[1~
vim:fdm=marker:fmr=[[[,]]]:ft=help:ai:et:noma:ro:
vim:foldtext=getline(v\:foldstart).'...'.(v\:foldend-v\:foldstart):