State: Draft
Type: Project
Tcl-Version: 9.1
Vote: Pending
Post-History:
Author: Donal K. Fellows <[email protected]>
Created: 29-Apr-2004
Keywords: Tcl
Abstract
This TIP proposes a simple scheme to allow commands to provide basic syntax help for themselves. This information would allow for more advanced processing by programs doing interactive input of Tcl commands (by providing a mechanism for them to discover what possible completions of the current command fragment are available) and could be processed automatically by the interp alias and namespace ensemble mechanisms so that help could be automatically extended to commands defined through those mechanisms.
Rationale
Currently, Tcl commands are only partially consistent in how they provide information about their own syntax; the only way of getting any syntax help is by providing invalid input to the command, but not all commands have invalid input sequences (e.g. list) and nor is there any way of knowing what those invalid sequences are (where they do exist) unless you know the command beforehand.
Such help would be useful in a number of situations, such as command expansion in something like tkcon. It would also provide a mechanism for supplying the sort of detailed information which the likes of [incr Tcl]'s ensembles can generate, but which the Tcl ensembles of [112] do not do (for the reason that this would produce output significantly different in kind from existing core commands.)
Note that I do not want to provide extended help such as might be obtained from manual pages; this help system is designed to be mechanically queryable first.
Proposed Change: Tcl Script Level
There are three main components:
Data Model
Every command would supply help for itself by providing a callback to generate the information on demand; there will be a compatability callback installed by default that states that the command may take any number of unknown arguments.
The result of the callback will be a list of command call descriptions. Each description will be itself a list of terms that describe a particular way of calling the command, with one term per argument. Each term may in turn be one of:
Required literal - this might be something like a subcommand name.
Optional literal - a good example of this are the then and else words in a call to if.
Required varying (with name for display to the user) - a normal argument which may be whatever the caller wants it to be, subject to the higher level constraints implicit in the name.
Optional varying (with name for display to the user) - a normal optional argument.
All remaining arguments - this would be used in the default help outlined above, but would also be useful for modelling the args parameter to a procedure.
[ToDo: say how these are expressed in C code]
Information Access
There will be a new subcommand of info to provide access to this information at the Tcl level: help. The first argument to info help will be the name of a command, or, if no such command exists and the argument is a two- or three-element list, a lambda term; if no further arguments are supplied, the result will be a multi-line string with one invokation per line; the invokations will be just the string parts with the literal/varying information omitted and the optional/required information converted into surrounding question marks.
Otherwise, the second argument to info help will be one of:
summary: No further arguments. Returns a brief description of what the
command does, such as the summary text from the manual page (e.g.,
"Increment the value of a variable.
" for incr).
info help cmd summary
get: Two optional arguments; an index into the list of command definition lines (first) and an index within the line (second). If one index is supplied, returns the list of values (without lit/var or opt/req info) for the indexed line. If two indexes are supplied, returns the string form for the indexed word within the indexed line. If no indexes are supplied, or returns a list of every such value list when no index is supplied. (See Help Definitions below for the description of which lines this is referring to.)
info help cmd get ?lineIndex? ?wordIndex?
literal: Two required arguments; an index into the list of help "lines" and an index into the list of values for that line. Returns a boolean that is true when the indexed word within the indexed line is a literal.
info help cmd literal lineIndex wordIndex
required: Two required arguments; an index into the list of help "lines" and an index into the list of values for that line. Returns a boolean that is true when the indexed word within the indexed line is required.
info help cmd required lineIndex wordIndex
all: No further arguments. Returns the whole of the string registered as the help definition for the command.
info help cmd all
There shall be an equivalent for TclOO methods. In that case, because methods are not commands, instead of info help, the subcommand to use will be info class help class method for methods defined by classes, and info object help object method for methods defined by objects. Subsequent arguments shall be as for info help above. Overall help on a class or object will be via the basic info help as those are commands.
Information Definition
There will be a new doc command. It will take one or two arguments.
If it takes a single argument, and is run inside a procedure, lambda term, or method, then that argument is a help definition to apply to that procedure, lambda term or method. When a procedure or method is defined, the creation process shall minimally parse the provided script and determine if the first command in it is a single-argument doc call; if it is, the help definition in that argument will be applied during the creation of the procedure/method. For lambda terms, this parsing will occur when the lambda term is first interpreted as such by Tcl. (Note that this is the only way of documenting a lambda.)
The single-argument form otherwise has no effect.
In the two argument form, the first argument shall be the name of a Tcl command and the second argument shall be the help definition.
There will also be a doc definition in the definition set supported by oo::define and oo::objdefine, that takes two arguments. The first argument will be the name of a method (any method, not just one created by the method definition). This is necessary as it will be the only way to create help definitions for forwarded methods.
Help Definitions
Help definitions will consist of a string that is potentially multi-line. The string will be split into paragraphs by visually blank lines (i.e., lines that are empty after being passed through string trimright) and the common whitespace prefix from all paragraphs shall be stripped.
The first paragraph shall be the summary text.
The lines of the second paragraph shall be the data indexed by the other
info help subcommands (get, literal and required); one line
per description. The words of each of the lines of the second paragraph shall
be sequences of non-whitespace characters, rather than Tcl words per se. If
a word (other than the initial one, which should be the conventional command
name) starts with ?
and finishes with ?
then it shall be internally
interpreted as optional after the question marks are stripped. If a
non-initial word starts and ends with =
, it shall be interpreted as literal
after the equals signs are stripped. If both ?
and =
are present at each
end, in either order, the word shall be both optional and literal and both
will be stripped. Note that command names are always both required and
literal. If the final word of a line is ...
, it shall be always optional and
not literal.
Subsequent paragraphs are not interpreted by this specification, but will be provided as part of the information returned by info help's all.
Examples
Help for the incr command might be done with:
doc incr {
Increment the value of a variable.
incr varName ?increment?
The default amount to increment by is 1.
}
Then you'd be able to do:
puts [info help incr summary]
# ==> Increment the value of a variable.
puts [info help incr get]
# ==> {incr varName increment}
puts [info help incr get 0]
# ==> incr varName increment
puts [info help incr literal 0 0]
# ==> 1
puts [info help incr literal 0 1]
# ==> 0
puts [info help incr required 0 1]
# ==> 1
puts [info help incr required 0 2]
# ==> 0
Help for the if command might be done with:
doc if {
Execute scripts conditionally.
if expr ?=then=? body
if expr ?=then=? body1 ?=else=? body2
if expr1 ?=then=? body1 =elseif= expr2 ?=then=? body2 ...
Each of the expr arguments is evaluated as an expression in order until one
evaluates to a true value. Then the corresponding body is evaluated as a
script. The words 'then' and 'else' are optional; 'elseif' is required if
more than one expression. If an 'else' is present or a final body, and no
expression evaluates to true, the last body is evaluated instead.
}
Defining your own help for a procedure:
proc foo {a b {c 123}} {
doc {
Do the foo to the bar.
foo a b ?c?
}
# ...
}
Copyright
This document has been placed in the public domain.