TIP 193: Simple Syntax Help System

Login
Bounty program for improvements to Tcl and certain Tcl packages.
State:		Draft
Type:		Project
Tcl-Version:	8.7
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:

[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.