Skip to content

Commit ff82bb0

Browse files
author
Nate Soares
committed
Initial public release
0 parents  commit ff82bb0

File tree

14 files changed

+2551
-0
lines changed

14 files changed

+2551
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
*.pyc
2+
/build/
3+
/deb_dist/

README.md

Lines changed: 324 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,324 @@
1+
Vimdoc - Helpfile generation for vim plugins
2+
============================================
3+
4+
Vimdoc generates vim helpfiles from documentation in vimscript files. You
5+
annotate vimscript like this:
6+
7+
""
8+
" This is my function. It does different things to the {required} argument,
9+
" depending upon the [optional] argument.
10+
function! myplugin#MyFunction(required, ...) abort
11+
...
12+
endfunction
13+
14+
and you get helpfiles that look like this:
15+
16+
===========================================================================
17+
FUNCTIONS *myplugin-functions*
18+
19+
myplugin#MyFunction({required}, [optional]) *myplugin#MyFunction()*
20+
This is my function. It does different things to the {required} argument,
21+
depending upon the [optional] argument.
22+
23+
This allows you to keep all of your documentation in one place (the code!) and
24+
generate nicely formatted help files without manually aligning text and adding
25+
tags and so on.
26+
27+
To see an example of vimdoc in use, see
28+
[maktaba](https://github.com/google/maktaba), specifically the
29+
[helloworld](https://github.com/google/maktaba/tree/master/examples/helloworld)
30+
example plugin therein, which shows some of the basics.
31+
32+
**Vimdoc is unstable**. It's a collection of regexes and hacks masquerading as
33+
a complete vim documentation tool. But it works, and it's useful, and it will
34+
continue to be useful while it gets cleaned up.
35+
36+
Installation
37+
------------
38+
39+
Use setup.py to install vimdoc in the usual way. On most systems, this is:
40+
41+
python setup.py config
42+
python setup.py build
43+
sudo python setup.py install
44+
45+
Execution
46+
---------
47+
48+
Run vimdoc on a directory containing a plugin. It will generate a help file in
49+
the 'doc' directory of that plugin. For example:
50+
51+
vimdoc plugins/myplugin
52+
53+
will generate the helpfile
54+
55+
plugins/myplugin/doc/myplugin.txt
56+
57+
Usage
58+
-----
59+
60+
Vimdoc operates on comment blocks, which are a continuous group of lines
61+
starting with the "" header:
62+
63+
""
64+
" Documentation for function
65+
function! ...
66+
67+
Vimdoc automatically recognizes the type of these blocks. It can detect the
68+
following:
69+
70+
- function definitions
71+
- command definitions
72+
- global settings
73+
- maktaba flags
74+
- plugin descriptions (at the top of plugin files)
75+
76+
The names of functions/commands/settings are automatically detected from the
77+
line below the comment block. The arguments for functions/commands are
78+
automatically deduced from the body of the text and (in the case of functions)
79+
from the name of the arguments in the function definition, as follows:
80+
81+
- If the names of all mentioned required arguments in the comment block match
82+
the names of the arguments in the function definition, then the required
83+
arguments are ordered according to their placement in the function definition.
84+
- Otherwise, the names used in the comment block are used instead of the names
85+
used in the function definition, in the order of mention in the comment block.
86+
- Optional arguments (which cannot be named in a function definition, as their
87+
existence is indicated only by an ellipsis) are used as named in the comment
88+
block, in the order of mention.
89+
90+
These defaults are usually correct, but can be overridden.
91+
92+
Vimdoc has a number of builtin directives, which are marked by @ signs.
93+
94+
### Block Directives
95+
96+
Block directives take up an entire line in the comment block. They look like
97+
this:
98+
99+
""
100+
" @usage req1 req2 \[opt1] \[opt2]
101+
" description...
102+
function! MyFunction(badName1, badName2, ...)
103+
104+
Available block directives include:
105+
106+
- `@stylized name` allows you to define the stylized version of a plugin name
107+
(for example, myplugin could be stylized as "My Plugin").
108+
- `@tagline ...` allows you to give a tagline to your plugin, which will show up
109+
at the top of the help file.
110+
- `@author name` allows you to define an author for the plugin, which will show
111+
up in the help file.
112+
- `@library` marks your plugin as a library plugin. This makes functions public
113+
by default.
114+
- `@public` marks a function public. In most plugins, functions are private by
115+
default, though this default may be overridden on a per-plugin basis.
116+
- `@private` marks a function private.
117+
- `@section name [id]` allows you to write a new section for the helpfile.
118+
- `@order ...` allows you to define the order of the sections.
119+
- `@dict name` (above blank lines) allows you to define a new dictionary.
120+
- `@dict dict.fn` (above a function) allows you to add a function to
121+
a dictionary.
122+
- `@usage ...` allows you to rename and reorder the arguments of a function or
123+
command.
124+
- `@function ...` allows you to alter the function tag directly, for when @usage
125+
does not offer enough control.
126+
- `@command ...` allows you to alter the command tag directly, for when @usage
127+
does not offer enough control.
128+
- `@default arg=value` describes the default value of an optional arg.
129+
- `@throws exception` describes the type of exceptions that a function or
130+
command may throw.
131+
132+
The global directives (@stylized, @tagline, @author, @order, and @library) are
133+
all detected from the 'main' plugin file. The main plugin file is the first
134+
file that exists in the following list:
135+
136+
- <plugin-name>/plugin/<plugin-name<.vim
137+
- <plugin-name>/instant/flags.vim
138+
- A unique .vim file in <plugin-name>/ftplugin
139+
- <plugin-name>/autoload/<plugin-name>.vim
140+
- A unique .vim file in <plugin-name>/autoload
141+
142+
### Inline Directives
143+
144+
Inline directives occur in the body of comment blocks. Most take one argument
145+
enclosed in parenthesis.
146+
147+
- `@function(name)` generates a link to a function defined in the plugin.
148+
- `@command(name)` generates a link to a command defined in the plugin.
149+
- `@flag(name)` generates a link to a flag defined in the plugin.
150+
- `@setting(name)` generates a link to a setting defined in the plugin.
151+
- `@section(name)` generates a link to a section defined in the plugin.
152+
- `@dict(name)` generates a link to a dictionary defined in the plugin.
153+
- `@plugin(attr)` Outputs some plugin data, such as the name or author. `attr`
154+
must be one of `stylized`, `name`, `tagline`, or `author`. If the attr (and
155+
parenthesis) are left off, `stylized` is used.
156+
157+
158+
Syntax
159+
------
160+
161+
Vimdoc syntax is reminiscent of helpfile syntax.
162+
163+
- Use quotes to reference settings, such as 'filetype'.
164+
- Use brackets to reference [optional] function arguments.
165+
- Use braces to reference {required} function arguments.
166+
- Use |pipes| to link to tags in other helpfiles.
167+
168+
Helpfile Structure
169+
------------------
170+
171+
The generated helpfile for a plugin has the following structure:
172+
173+
Header
174+
Table of Contents
175+
1. Introduction
176+
2. Configuration
177+
3. Commands
178+
5. Settings
179+
6. Dictionaries
180+
7. Functions
181+
8. Mappings
182+
9. About
183+
184+
All of these (except Header and Table of Contents) are optional and predicated
185+
upon the comment blocks existing in the right places in the file. You may
186+
eliminate sections by omitting the comment blocks. You may add custom sections
187+
with the @section directive.
188+
189+
#### Header
190+
The header is a simple line or two following the vim helpfile style guide. It
191+
looks something like:
192+
193+
*myplugin* My Plugin’s Tagline
194+
author *Stylized-Name*
195+
196+
#### Table of Contents
197+
Of the form
198+
199+
=====================================================================
200+
CONTENTS *myplugin-contents*
201+
1. Introduction |myplugin-intro|
202+
2. Configuration |myplugin-config|
203+
...
204+
205+
And so on for each section.
206+
207+
#### Introduction
208+
209+
The introductory comment block at the top of the main plugin file is used to
210+
populate this section.
211+
212+
#### Configuration
213+
214+
This section contains descriptions of all the flags and settings that were
215+
annotated by vimdoc comment blocks.
216+
217+
#### Commands
218+
219+
Contains a list of commands available to the user. Vimdoc understands -bang,
220+
-nargs, -range, -count, -register, and -buffer. (It ignores -bar.) It will
221+
parse out the arguments in the order that they are mentioned in the comment
222+
block above the command and will generate a usage line for the command. For
223+
example, the following comment block:
224+
225+
""
226+
" Spawns two new zerglings from the given {hatchery}
227+
" Attacks all units in the selected [range] upon spawning.
228+
" [larva], if given, will be used to spawn the zerglings.
229+
" Otherwise a larva will be selected at random.
230+
" [!] forces the zerglings to spawn even if you don’t have enough
231+
" overlords. Caution: this may make your swarm uncontrollable.
232+
command -range -bang -nargs=+ -bar SpawnZerglings
233+
\ call zerg#spawn(ZERGLINGS, '<bang>' == '!', <f-args>)
234+
235+
will generate the following usage line:
236+
237+
:[range]SpawnZerglings[!] {hatchery} [larva]
238+
239+
You can override the usage line with the @usage command, which takes a list of
240+
arguments. Any arguments that look like vim variable names (\I\i+) will be
241+
assumed to be parameters, and their required-ness will be inferred from the
242+
docs. You can force required-ness by providing arguments that look like vim
243+
variables wrapped in curly (required) or square (optional) brackets. Empty
244+
curly brackets stand in for the remainder of the inferred required variables.
245+
Empty square brackets stand in for the remainder of the inferred optional
246+
variables. For example:
247+
248+
""
249+
" @usage {} [first] []
250+
" Start with {base}, add [second] to [first] and divide by [third].
251+
command SomeCommand ...
252+
253+
generates:
254+
255+
:SomeCommand {base} [first] [second] [third]
256+
257+
For more advanced usage, you may use the @command directive. This is useful
258+
either when your command takes a non-standard argument list (like :substitute)
259+
or when your command is not recognized by vimdoc (when you :execute 'command'
260+
s:name).
261+
262+
The @command directive takes one argument, which is the entire usage line. {}
263+
expands to all of the inferred required parameters, [] to all of the inferred
264+
optional parameters, and <> to the complete inferred command name with built-in
265+
flags included. For example:
266+
267+
""
268+
" @command <>/{pattern}/{string}/[flags] [count]
269+
command -range -bang -nargs=1 Substitute ...
270+
271+
generates the usage line:
272+
273+
:[range]Substitute[!]/{pattern}/{string}/[flags] [count]
274+
275+
An argument which may be given multiple times should be suffixed with an
276+
ellipsis. For example, {arg...} documents an argument that may appear once or
277+
more and [arg...] denotes an argument that may appear zero or more times.
278+
279+
280+
Sometimes you want a command to have more than one usage. For that you may use
281+
more than one usage directive. Example:
282+
283+
""
284+
" @usage {list} {index} {item}
285+
" Add {item} to {list} at {index}.
286+
" @usage {dict} {key} {value}
287+
" Set {dict} {key} to {value}.
288+
" @usage
289+
" WARNING: Will launch the nuclear missiles.
290+
291+
This will generate two docs for the command: one for list, one for dicts. An
292+
empty @usage directive denotes that the remainder of the block will be included
293+
in all usages. In the above example, the warning will be included in both the
294+
list and the dict version of the command docs.
295+
296+
#### Dictionaries
297+
298+
Vimscript kinda-sorta supports object oriented programming via dictionaries
299+
with functions attached. (See :help Dictionary-function.) Vimdoc helps you
300+
group these dictionaries and their methods in one place in the documentation.
301+
302+
You may describe a dictionary object type using the @dict annotation in
303+
a comment block that is above a blank line. Then you may annotate the
304+
dictionary functions with the @dict directive to have them grouped with the
305+
dictionary description. (Such functions will not be listed in the functions
306+
section.)
307+
308+
#### Functions
309+
310+
Function documentation is very similar to command documentation.
311+
312+
The order of required parameters is inferred by looking at the function
313+
declaration.
314+
315+
The order of optional parameters is inferred by the order they are mentioned in
316+
the comment block. Use the @usage command as described in the Command section
317+
to correct the order of optional arguments.
318+
319+
Functions may have multiple usages just like commands. Functions are not
320+
exposed in the help docs by default. Use @public to make them public by
321+
default.
322+
323+
@function can be used to tell vimdoc about a non-obvious function (such as one
324+
created by :execute). (), {}, and [] expand as in @command.

scripts/vimdoc

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#!/usr/bin/env python3
2+
3+
import argparse
4+
import os
5+
6+
from vimdoc.module import Modules
7+
from vimdoc.output import Helpfile
8+
9+
10+
def Source(path):
11+
if not os.path.isdir(path):
12+
raise argparse.ArgumentTypeError('{} not found'.format(path))
13+
if not os.access(path, os.R_OK):
14+
raise argparse.ArgumentTypeError('Cannot access {}'.format(path))
15+
return path
16+
17+
parser = argparse.ArgumentParser(description='Generate vim helpfiles')
18+
parser.add_argument('plugin', type=Source, metavar='PLUGIN')
19+
args = parser.parse_args()
20+
21+
docdir = os.path.join(args.plugin, 'doc')
22+
if not os.path.isdir(docdir):
23+
os.mkdir(docdir)
24+
25+
for module in Modules(args.plugin):
26+
Helpfile(module, docdir).Write()

setup.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
"""Distribution for vimdoc."""
2+
from distutils.core import setup
3+
4+
setup(
5+
name='vimdoc',
6+
version='0.1.0',
7+
description='Generate vim helpfiles',
8+
author='Nate Soares',
9+
author_email='[email protected]',
10+
packages=[
11+
'vimdoc',
12+
],
13+
scripts=[
14+
'scripts/vimdoc',
15+
])

vimdoc/__init__.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
"""Vimdoc: Vim helpfile generation."""
2+
3+
SECTION = 'SECTION'
4+
BACKMATTER = 'BACKMATTER'
5+
EXCEPTION = 'EXCEPTION'
6+
DICTIONARY = 'DICTIONARY'
7+
FUNCTION = 'FUNCTION'
8+
COMMAND = 'COMMAND'
9+
SETTING = 'SETTING'
10+
FLAG = 'FLAG'

0 commit comments

Comments
 (0)