Function: forms-mode
forms-mode is an autoloaded, interactive and byte-compiled function
defined in forms.el.gz.
Signature
(forms-mode &optional PRIMARY)
Documentation
Major mode to visit files in a field-structured manner using a form.
Commands: Equivalent keys in read-only mode:
TAB forms-next-field TAB
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 q
C-c C-o forms-insert-record
C-c C-l forms-jump-record l
C-c C-n forms-next-record n
C-c C-p forms-prev-record p
C-c C-r forms-search-reverse r
C-c C-s forms-search-forward s
C-c C-x forms-exit x
Key Bindings
Source Code
;; Defined in /usr/src/emacs/lisp/forms.el.gz
;;;###autoload
(defun forms-mode (&optional primary)
;; FIXME: use define-derived-mode
"Major mode to visit files in a field-structured manner using a form.
Commands: Equivalent keys in read-only mode:
TAB forms-next-field TAB
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 q
C-c C-o forms-insert-record
C-c C-l forms-jump-record l
C-c C-n forms-next-record n
C-c C-p forms-prev-record p
C-c C-r forms-search-reverse r
C-c C-s forms-search-forward s
C-c C-x forms-exit x"
(interactive)
;; This is not a simple major mode, as usual. Therefore, forms-mode
;; takes an optional argument `primary' which is used for the
;; initial set-up. Normal use would leave `primary' to nil.
;; A global buffer-local variable `forms--mode-setup' has the same
;; effect but makes it possible to auto-invoke forms-mode using
;; `find-file'.
;; Note: although it seems logical to have `make-local-variable'
;; executed where the variable is first needed, I have deliberately
;; placed all calls in this function.
;; Primary set-up: evaluate buffer and check if the mandatory
;; variables have been set.
(if (or primary (not forms--mode-setup))
(progn
;;(message "forms: setting up...")
(kill-all-local-variables)
;; Make mandatory variables.
(make-local-variable 'forms-file)
(make-local-variable 'forms-number-of-fields)
(make-local-variable 'forms-format-list)
;; Make optional variables.
(make-local-variable 'forms-field-sep)
(make-local-variable 'forms-read-only)
(make-local-variable 'forms-multi-line)
(make-local-variable 'forms-forms-scroll)
(make-local-variable 'forms-forms-jump)
(make-local-variable 'forms-insert-after)
(make-local-variable 'forms-use-text-properties)
;; Make sure no filters exist.
(setq-local forms-read-file-filter nil)
(setq-local forms-write-file-filter nil)
(setq-local forms-new-record-filter nil)
(setq-local forms-modified-record-filter nil)
;; Setup faces to show read-only and read-write fields.
(make-local-variable 'forms-ro-face)
(make-local-variable 'forms-rw-face)
;; eval the buffer, should set variables
;;(message "forms: processing control file...")
;; If enable-local-eval is not set to t the user is asked first.
(if (or (eq enable-local-eval t)
(yes-or-no-p
(concat "Evaluate lisp code in buffer "
(buffer-name) " to display forms? ")))
(eval-buffer)
(error "`enable-local-eval' inhibits buffer evaluation"))
;; Check if the mandatory variables make sense.
(or forms-file
(error (concat "Forms control file error: "
"`forms-file' has not been set")))
;; Check forms-field-sep first, since it can be needed to
;; construct a default format list.
(or (stringp forms-field-sep)
(error (concat "Forms control file error: "
"`forms-field-sep' is not a string")))
(if forms-number-of-fields
(or (and (numberp forms-number-of-fields)
(> forms-number-of-fields 0))
(error (concat "Forms control file error: "
"`forms-number-of-fields' must be a number > 0")))
(or (null forms-format-list)
(error (concat "Forms control file error: "
"`forms-number-of-fields' has not been set"))))
(or forms-format-list
(forms--intuit-from-file))
(if forms-multi-line
(if (and (stringp forms-multi-line)
(eq (length forms-multi-line) 1))
(if (string= forms-multi-line forms-field-sep)
(error (concat "Forms control file error: "
"`forms-multi-line' is equal to `forms-field-sep'")))
(error (concat "Forms control file error: "
"`forms-multi-line' must be nil or a one-character string"))))
;; Validate and process forms-format-list.
;;(message "forms: pre-processing format list...")
(make-local-variable 'forms--elements)
(forms--process-format-list)
;; Build the formatter and parser.
;;(message "forms: building formatter...")
(make-local-variable 'forms--format)
(make-local-variable 'forms--markers)
(make-local-variable 'forms--dyntexts)
;;(message "forms: building parser...")
(forms--make-format)
(make-local-variable 'forms--parser)
(forms--make-parser)
;;(message "forms: building parser... done.")
;; Check if record filters are defined.
(if (and forms-new-record-filter
(not (functionp forms-new-record-filter)))
(error (concat "Forms control file error: "
"`forms-new-record-filter' is not a function")))
(if (and forms-modified-record-filter
(not (functionp forms-modified-record-filter)))
(error (concat "Forms control file error: "
"`forms-modified-record-filter' is not a function")))
;; The filters access the contents of the forms using `forms-fields'.
(make-local-variable 'forms-fields)
;; Dynamic text support.
(make-local-variable 'forms--dynamic-text)
;; Prevent accidental overwrite of the control file and auto-save.
;; We bind change-major-mode-with-file-name to nil to prevent
;; set-visited-file-name from calling set-auto-mode, which
;; might kill all local variables and set forms-file nil,
;; which will then barf in find-file-noselect below. This can
;; happen when the user sets the default major mode that is
;; different from the Fundamental mode.
(let (change-major-mode-with-file-name)
(set-visited-file-name nil))
;; Prepare this buffer for further processing.
(setq buffer-read-only nil)
(erase-buffer)
;;(message "forms: setting up... done.")
))
;; initialization done
(setq forms--mode-setup t)
;; Copy desired faces to the actual variables used by the forms formatter.
(make-local-variable 'forms--ro-face)
(make-local-variable 'forms--rw-face)
(if forms-read-only
(progn
(setq forms--ro-face forms-ro-face)
(setq forms--rw-face forms-ro-face))
(setq forms--ro-face forms-ro-face)
(setq forms--rw-face forms-rw-face))
;; Make more local variables.
(make-local-variable 'forms--file-buffer)
(make-local-variable 'forms--total-records)
(make-local-variable 'forms--current-record)
(make-local-variable 'forms--the-record-list)
(make-local-variable 'forms--search-regexp)
;; The keymaps are global, so multiple forms mode buffers can share them.
;;(make-local-variable 'forms-mode-map)
;;(make-local-variable 'forms-mode-ro-map)
;;(make-local-variable 'forms-mode-edit-map)
(if forms-mode-map ; already defined
nil
;;(message "forms: building keymap...")
(forms--mode-commands)
;;(message "forms: building keymap... done.")
)
;; set the major mode indicator
(setq major-mode 'forms-mode)
(setq mode-name "Forms")
(cursor-intangible-mode 1)
;; find the data file
(setq forms--file-buffer (find-file-noselect forms-file))
;; Pre-transform.
(let ((read-file-filter forms-read-file-filter)
(write-file-filter forms-write-file-filter))
(if read-file-filter
(with-current-buffer forms--file-buffer
(let ((inhibit-read-only t)
(file-modified (buffer-modified-p)))
(forms--run-functions read-file-filter)
(if (not file-modified) (set-buffer-modified-p nil)))
(if write-file-filter
(add-hook 'write-file-functions write-file-filter nil t)))
(if write-file-filter
(with-current-buffer forms--file-buffer
(add-hook 'write-file-functions write-file-filter nil t)))))
;; count the number of records, and set see if it may be modified
(let (ro)
(setq forms--total-records
(with-current-buffer forms--file-buffer
(prog1
(progn
;;(message "forms: counting records...")
(bury-buffer (current-buffer))
(setq ro buffer-read-only)
(count-lines (point-min) (point-max)))
;;(message "forms: counting records... done.")
)))
(if ro
(setq forms-read-only t)))
;;(message "forms: proceeding setup...")
;; Since we aren't really implementing a minor mode, we hack the mode line
;; directly to get the text " View " into forms-read-only form buffers. For
;; that reason, this variable must be buffer only.
(make-local-variable 'minor-mode-alist)
(setq minor-mode-alist (list (list 'forms-read-only " View")))
;;(message "forms: proceeding setup (keymaps)...")
(forms--set-keymaps)
;;(message "forms: proceeding setup (commands)...")
(forms--change-commands)
;;(message "forms: proceeding setup (buffer)...")
(set-buffer-modified-p nil)
(if (= forms--total-records 0)
;;(message "forms: proceeding setup (new file)...")
(progn
(insert
"GNU Emacs Forms Mode\n\n"
(if (file-exists-p forms-file)
(format-message
"No records available in file `%s'\n\n" forms-file)
(format-message
"Creating new file `%s'\nwith %d field%s per record\n\n"
forms-file forms-number-of-fields
(if (= 1 forms-number-of-fields) "" "s")))
"Use " (substitute-command-keys "\\[forms-insert-record]")
" to create new records.\n")
(setq forms--current-record 1)
(setq buffer-read-only t)
(set-buffer-modified-p nil))
;; setup the first (or current) record to show
(if (< forms--current-record 1)
(setq forms--current-record 1))
(forms-jump-record forms--current-record)
(if forms-insert-after
(forms-last-record)
(forms-first-record))
)
;; user customizing
;;(message "forms: proceeding setup (user hooks)...")
(run-mode-hooks 'forms-mode-hook 'forms-mode-hooks)
;;(message "forms: setting up... done.")
;; be helpful
(forms--help))