File: forms.el.html

Visit a file using a form. See etc/forms for examples.

=== Naming conventions

The names of all variables and functions start with 'forms-'. Names which start with 'forms--' are intended for internal use, and should *NOT* be used from the outside.

All variables are buffer-local, to enable multiple forms visits simultaneously. Variable forms--mode-setup is local to *ALL* buffers, for it controls if forms-mode has been enabled in a buffer.

=== How it works ===

Forms mode means visiting a data file which is supposed to consist of records each containing a number of fields. The records are separated by a newline, the fields are separated by a user-defined field separator (default: TAB). When shown, a record is transferred to an Emacs buffer and presented using a user-defined form. One record is shown at a time.

Forms mode is a composite mode. It involves two files, and two buffers. The first file, called the control file, defines the name of the data file and the forms format. This file buffer will be used to present the forms. The second file holds the actual data. The buffer of this file will be buried, for it is never accessed directly.

Forms mode is invoked using M-x forms-find-file control-file. Alternatively forms-find-file-other-window can be used.

You may also visit the control file, and switch to forms mode by hand with M-x forms-mode.

Automatic mode switching is supported if you specify
"-*- forms -*-" in the first line of the control file.

The control file is visited, evaluated using eval-buffer, and should set at least the following variables:

forms-file [string]
The name of the data file.

forms-number-of-fields [integer]
The number of fields in each record.

forms-format-list [list]
Formatting instructions.

forms-format-list should be a list, each element containing

  - a string, e.g. "hello". The string is inserted in the forms
"as is".

  - an integer, denoting a field number.
The contents of this field are inserted at this point.
    Fields are numbered starting with number one.

  - a function call, e.g. (insert "text").
This function call is dynamically evaluated and should return a
    string. It should *NOT* have side-effects on the forms being
    constructed. The current fields are available to the function
    in the variable forms-fields, they should *NOT* be modified.

  - a Lisp symbol, that must evaluate to one of the above.

Optional variables which may be set in the control file:

forms-field-sep [string, default TAB]
The field separator used to separate the
fields in the data file. It may be a string.

forms-read-only [bool, default nil]
Non-nil means that the data file is visited
read-only (view mode) as opposed to edit mode.
If no write access to the data file is
possible, view mode is enforced.

forms-check-number-of-fields [bool, default t]
If non-nil, a warning will be issued whenever
a record is found that does not have the number
of fields specified by forms-number-of-fields.

forms-multi-line [string, default "^K"]
If non-null, the records of the data file may
contain fields that can span multiple lines in
the form.
This variable denotes the separator string
to be used for this purpose. Upon display, all
occurrences of this string are translated
to newlines. Upon storage they are translated
back to the separator string.

forms-forms-scroll [bool, default nil]
Non-nil means: rebind locally the commands that
perform scroll-up or scroll-down to use
forms-next-field resp. forms-prev-field.

forms-forms-jump [bool, default nil]
Non-nil means: rebind locally the commands
beginning-of-buffer and end-of-buffer to
perform, respectively, forms-first-record and
forms-last-record instead.

forms-insert-after [bool, default nil]
Non-nil means: insertions of new records go after
current record, also initial position is at the
last record. The default is to insert before the
current record and the initial position is at the
first record.

forms-read-file-filter [symbol, default nil]
If not nil: this should be the name of a
function that is called after the forms data file
has been read. It can be used to transform
the contents of the file into a format more suitable
for forms-mode processing.

forms-write-file-filter [symbol, default nil]
If not nil: this should be the name of a
function that is called before the forms data file
is written (saved) to disk. It can be used to undo
the effects of forms-read-file-filter, if any.

forms-new-record-filter [symbol, default nil]
If not nil: this should be the name of a
function that is called when a new
record is created. It can be used to fill in
the new record with default fields, for example.

forms-modified-record-filter [symbol, default nil]
If not nil: this should be the name of a
function that is called when a record has
been modified. It is called after the fields
are parsed. It can be used to register
modification dates, for example.

forms-use-text-properties [bool, see text for default]
This variable controls if forms mode should use
text properties to protect the form text from being
modified (using text-property read-only).
Also, the read-write fields are shown using a
distinct face, if possible.
The intangible text property is used to
prevent moving into read-only fields.
This variable defaults to t.
The default face to show read-write fields is
copied from face region.

forms-ro-face [symbol, default 'default]
This is the face that is used to show
read-only text on the screen. If used, this
variable should be set to a symbol that is a
valid face.
E.g.
(make-face 'my-face)
(setq forms-ro-face 'my-face)

forms-rw-face [symbol, default 'region]
This is the face that is used to show
read-write text on the screen.

After evaluating the control file, its buffer is cleared and used for further processing. The data file (as designated by forms-file) is visited in a buffer forms--file-buffer which normally will not be shown. Great malfunctioning may be expected if this file/buffer is modified outside of this package while it is being visited!

Normal operation is to transfer one line (record) from the data file, split it into fields (into forms--the-record-list), and display it using the specs in forms-format-list. A format routine forms--format is built upon startup to format the records according to forms-format-list.

When a form is changed the record is updated as soon as this form is left. The contents of the form are parsed using information obtained from forms-format-list, and the fields which are deduced from the form are modified. Fields not shown on the forms retain their original values. The newly formed record then replaces the contents of the old record in forms--file-buffer. A parse routine forms--parser is built upon startup to parse the records.

Two exit functions exist: forms-exit and forms-exit-no-save. forms-exit saves the data to the file, if modified. forms-exit-no-save does not. However, if forms-exit-no-save is executed and the file buffer has been modified, Emacs will ask questions anyway.

Other functions provided by forms mode are:

paging (forward, backward) by record jumping (first, last, random number) searching creating and deleting records reverting the form (NOT the file buffer) switching edit <-> view mode v.v. jumping from field to field

As a documented side-effect: jumping to the last record in the file (using forms-last-record) will adjust forms--total-records if needed.

The forms buffer can be in one of two modes: edit mode or view mode. View mode is a read-only mode, whereby you cannot modify the contents of the buffer.

Edit mode commands:

TAB forms-next-field
\C-c TAB forms-next-field
\C-c < forms-first-record
\C-c > forms-last-record
\C-c ? describe-mode
\C-c \C-k forms-delete-record
\C-c \C-q forms-toggle-read-only
\C-c \C-o forms-insert-record
\C-c \C-l forms-jump-record
\C-c \C-n forms-next-record
\C-c \C-p forms-prev-record
\C-c \C-r forms-search-backward
\C-c \C-s forms-search-forward
\C-c \C-x forms-exit

Read-only mode commands:

SPC forms-next-record
DEL forms-prev-record
? describe-mode
\C-q forms-toggle-read-only
l forms-jump-record
n forms-next-record
p forms-prev-record
r forms-search-backward
s forms-search-forward
x forms-exit

Of course, it is also possible to use the \C-c prefix to obtain the same command keys as in edit mode.

The following bindings are available, independent of the mode:

[next] forms-next-record
[prior] forms-prev-record
[begin] forms-first-record
[end] forms-last-record
[S-TAB] forms-prev-field
[backtab] forms-prev-field

For convenience, TAB is always bound to forms-next-field, so you don't need the C-c prefix for this command.

As mentioned above (see forms-forms-scroll and forms-forms-jump), the bindings of standard functions scroll-up, scroll-down, beginning-of-buffer and end-of-buffer can be locally replaced with forms mode functions next/prev record and first/last record.

write-file-functions is defined to save the actual data file instead of the buffer data, revert-buffer-function is defined to revert a forms to original.

Defined variables (39)

forms--current-recordNumber of the record currently on the screen.
forms--debugIf non-nil, enable Forms mode debugging.
forms--dynamic-textArray that holds dynamic texts to insert between fields.
forms--dyntextsDynamic texts (resulting from function calls) on the screen.
forms--elementsArray with the order in which the fields are displayed.
forms--file-bufferBuffer which holds the file data.
forms--formatFormatting routine.
forms--iif-propertiesOriginal properties of the character being overridden.
forms--iif-startRecord start of modification command.
forms--markersField markers in the screen.
forms--mode-setupTo keep track of ‘forms-mode’ being set-up.
forms--parserForms parser routine.
forms--ro-faceFace used to represent read-only data on the screen.
forms--rw-faceFace used to represent read-write data on the screen.
forms--search-regexpLast regexp used by forms-search functions.
forms--the-record-listList of strings of the current record, as parsed from the file.
forms--total-recordsTotal number of records in the data file.
forms-check-number-of-fieldsIf non-nil, warn about records with wrong number of fields.
forms-field-sepField separator character (default TAB).
forms-fieldsList with fields of the current forms. First field has number 1.
forms-fileName of the file holding the data.
forms-format-listList of formatting specifications.
forms-forms-jumpNon-nil means redefine beginning/end-of-buffer in Forms mode.
forms-forms-scrollNon-nil means replace scroll-up/down commands in Forms mode.
forms-insert-afterNon-nil means: inserts of new records go after current record.
forms-mode-edit-mapKeymap for form buffer in edit mode.
forms-mode-hookHook run upon entering Forms mode.
forms-mode-mapKeymap for form buffer.
forms-mode-ro-mapKeymap for form buffer in view mode.
forms-modified-record-filterThe name of a function that is called when a record has been modified.
forms-multi-lineIf not nil: use this character to separate multi-line fields (default C-k).
forms-new-record-filterThe name of a function that is called when a new record is created.
forms-number-of-fieldsNumber of fields per record.
forms-read-file-filterThe name of a function that is called after reading the data file.
forms-read-onlyNon-nil means: visit the file in view (read-only) mode.
forms-ro-faceThe face (a symbol) that is used to display read-only text on the screen.
forms-rw-faceThe face (a symbol) that is used to display read-write text on the screen.
forms-use-text-propertiesNon-nil means to use text properties.
forms-write-file-filterThe name of a function that is called before writing the data file.

Defined functions (47)

forms--change-commands()
forms--checkmod()
forms--debug(&rest ARGS)
forms--exit(&optional SAVE)
forms--get-record()
forms--goto-record(RN &optional CURRENT)
forms--help()
forms--iif-hook(BEGIN END)
forms--iif-post-command-hook()
forms--intuit-from-file()
forms--make-format()
forms--make-format-elt(EL)
forms--make-format-elt-using-text-properties(EL)
forms--make-parser()
forms--make-parser-elt(EL)
forms--mode-commands()
forms--mode-commands1(MAP)
forms--mode-menu-edit(MAP)
forms--mode-menu-ro(MAP)
forms--parse-form()
forms--parser-using-text-properties()
forms--revert-buffer(&optional ARG NOCONFIRM)
forms--run-functions(FUNCTIONS)
forms--set-keymaps()
forms--show-record(THE-RECORD)
forms--trans(SUBJ ARG REP)
forms--update()
forms-delete-record(ARG)
forms-enumerate(THE-FIELDS)
forms-exit()
forms-exit-no-save()
forms-find-file(FN)
forms-find-file-other-window(FN)
forms-first-record()
forms-insert-record(ARG)
forms-jump-record(ARG &optional RELATIVE)
forms-last-record()
forms-mode(&optional PRIMARY)
forms-next-field(ARG)
forms-next-record(ARG)
forms-prev-field(ARG)
forms-prev-record(ARG)
forms-print()
forms-save-buffer(&optional ARGS)
forms-search-backward(REGEXP)
forms-search-forward(REGEXP)
forms-toggle-read-only(ARG)

Defined faces (0)