aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/forms.el
diff options
context:
space:
mode:
authorRichard M. Stallman1994-07-26 19:47:39 +0000
committerRichard M. Stallman1994-07-26 19:47:39 +0000
commit9c308ed258917b661a2ebd101484ec0b7cb70b4b (patch)
treee3d2bde8d3471a909a78c4bd09b0dc2dc88e94f7 /lisp/forms.el
parent26d270ab4891cff6b75601c5f1c57c5e8529ef39 (diff)
downloademacs-9c308ed258917b661a2ebd101484ec0b7cb70b4b.tar.gz
emacs-9c308ed258917b661a2ebd101484ec0b7cb70b4b.zip
(forms-read-file-filter): new hook function to
preprocess file contents before being passed to forms mode. (forms-write-file-filter): new hook function to preprocess file contents before it is being saved to disk. Can be used to undo the effects of `forms-read-file-filter'. (forms-mode): Supply a default format if no `forms-format-list' was specified. Preprocess file contents using `forms-read-file-filter' and attach `forms-write-file-filter' to the `local-write-file-hooks' of the file buffer. Present a friendly message if the visited file is empty or new. (forms--intuit-from-file): New subroutine to get the number of fields from the data file; constructs a default format list. (forms-save-buffer): Forms mode wrapper for `save-buffer'. (forms--change-commands, forms--exit): Use it. (forms--update): Check for the presence of the field separator in any of the fields. Refuse update if found. (forms-delete-record): Allow the last record of the file to be deleted, even if not terminated by a newline. (forms--local-write-file-function): Remove. Didn't do any good. Replaced by `forms-save-buffer'.
Diffstat (limited to 'lisp/forms.el')
-rw-r--r--lisp/forms.el188
1 files changed, 155 insertions, 33 deletions
diff --git a/lisp/forms.el b/lisp/forms.el
index 4f5efe45498..156dcf82450 100644
--- a/lisp/forms.el
+++ b/lisp/forms.el
@@ -123,6 +123,19 @@
123;;; perform `beginning-of-buffer' or `end-of-buffer' 123;;; perform `beginning-of-buffer' or `end-of-buffer'
124;;; to perform `forms-first-field' resp. `forms-last-field'. 124;;; to perform `forms-first-field' resp. `forms-last-field'.
125;;; 125;;;
126;;; forms-read-file-filter [symbol, default nil]
127;;; If not nil: this should be the name of a
128;;; function that is called after the forms data file
129;;; has been read. It can be used to transform
130;;; the contents of the file into a format more suitable
131;;; for forms-mode processing.
132;;;
133;;; forms-write-file-filter [symbol, default nil]
134;;; If not nil: this should be the name of a
135;;; function that is called before the forms data file
136;;; is written (saved) to disk. It can be used to undo
137;;; the effects of `forms-read-file-filter', if any.
138;;;
126;;; forms-new-record-filter [symbol, default nil] 139;;; forms-new-record-filter [symbol, default nil]
127;;; If not nil: this should be the name of a 140;;; If not nil: this should be the name of a
128;;; function that is called when a new 141;;; function that is called when a new
@@ -269,7 +282,7 @@
269(defconst forms-version (substring "$Revision: 2.7 $" 11 -2) 282(defconst forms-version (substring "$Revision: 2.7 $" 11 -2)
270 "The version number of forms-mode (as string). The complete RCS id is: 283 "The version number of forms-mode (as string). The complete RCS id is:
271 284
272 $Id: forms.el,v 2.7 1994/06/13 12:07:44 rms Exp rms $") 285 $Id: forms.el,v 2.7 1994/07/25 20:38:23 jv Exp $")
273 286
274(defvar forms-mode-hooks nil 287(defvar forms-mode-hooks nil
275 "Hook functions to be run upon entering Forms mode.") 288 "Hook functions to be run upon entering Forms mode.")
@@ -305,6 +318,15 @@ The replacement commands performs forms-next/prev-record.")
305 "*Non-nil means redefine beginning/end-of-buffer in Forms mode. 318 "*Non-nil means redefine beginning/end-of-buffer in Forms mode.
306The replacement commands performs forms-first/last-record.") 319The replacement commands performs forms-first/last-record.")
307 320
321(defvar forms-read-file-filter nil
322 "The name of a function that is called after reading the data file.
323This can be used to change the contents of the file to something more
324suitable for forms processing.")
325
326(defvar forms-write-file-filter nil
327 "The name of a function that is called before writing the data file.
328This can be used to undo the effects of form-read-file-hook.")
329
308(defvar forms-new-record-filter nil 330(defvar forms-new-record-filter nil
309 "The name of a function that is called when a new record is created.") 331 "The name of a function that is called when a new record is created.")
310 332
@@ -428,10 +450,16 @@ Commands: Equivalent keys in read-only mode:
428 (make-local-variable 'forms-forms-scroll) 450 (make-local-variable 'forms-forms-scroll)
429 (make-local-variable 'forms-forms-jump) 451 (make-local-variable 'forms-forms-jump)
430 (make-local-variable 'forms-use-text-properties) 452 (make-local-variable 'forms-use-text-properties)
453
454 ;; Filter functions.
455 (make-local-variable 'forms-read-file-filter)
456 (make-local-variable 'forms-write-file-filter)
431 (make-local-variable 'forms-new-record-filter) 457 (make-local-variable 'forms-new-record-filter)
432 (make-local-variable 'forms-modified-record-filter) 458 (make-local-variable 'forms-modified-record-filter)
433 459
434 ;; Make sure no filters exist. 460 ;; Make sure no filters exist.
461 (setq forms-read-file-filter nil)
462 (setq forms-write-file-filter nil)
435 (setq forms-new-record-filter nil) 463 (setq forms-new-record-filter nil)
436 (setq forms-modified-record-filter nil) 464 (setq forms-modified-record-filter nil)
437 465
@@ -452,20 +480,29 @@ Commands: Equivalent keys in read-only mode:
452 (eval-current-buffer) 480 (eval-current-buffer)
453 (error "`enable-local-eval' inhibits buffer evaluation")) 481 (error "`enable-local-eval' inhibits buffer evaluation"))
454 482
455 ;; check if the mandatory variables make sense. 483 ;; Check if the mandatory variables make sense.
456 (or forms-file 484 (or forms-file
457 (error (concat "Forms control file error: " 485 (error (concat "Forms control file error: "
458 "'forms-file' has not been set"))) 486 "'forms-file' has not been set")))
459 (or forms-number-of-fields 487
460 (error (concat "Forms control file error: " 488 ;; Check forms-field-sep first, since it can be needed to
461 "'forms-number-of-fields' has not been set"))) 489 ;; construct a default format list.
462 (or (and (numberp forms-number-of-fields)
463 (> forms-number-of-fields 0))
464 (error (concat "Forms control file error: "
465 "'forms-number-of-fields' must be a number > 0")))
466 (or (stringp forms-field-sep) 490 (or (stringp forms-field-sep)
467 (error (concat "Forms control file error: " 491 (error (concat "Forms control file error: "
468 "'forms-field-sep' is not a string"))) 492 "'forms-field-sep' is not a string")))
493
494 (if forms-number-of-fields
495 (or (and (numberp forms-number-of-fields)
496 (> forms-number-of-fields 0))
497 (error (concat "Forms control file error: "
498 "'forms-number-of-fields' must be a number > 0")))
499 (or (null forms-format-list)
500 (error (concat "Forms control file error: "
501 "'forms-number-of-fields' has not been set"))))
502
503 (or forms-format-list
504 (forms--intuit-from-file))
505
469 (if forms-multi-line 506 (if forms-multi-line
470 (if (and (stringp forms-multi-line) 507 (if (and (stringp forms-multi-line)
471 (eq (length forms-multi-line) 1)) 508 (eq (length forms-multi-line) 1))
@@ -560,6 +597,25 @@ Commands: Equivalent keys in read-only mode:
560 ;; find the data file 597 ;; find the data file
561 (setq forms--file-buffer (find-file-noselect forms-file)) 598 (setq forms--file-buffer (find-file-noselect forms-file))
562 599
600 ;; Pre-transform.
601 (let ((read-file-filter forms-read-file-filter)
602 (write-file-filter forms-write-file-filter))
603 (if read-file-filter
604 (save-excursion
605 (set-buffer forms--file-buffer)
606 (let ((inhibit-read-only t))
607 (run-hooks 'read-file-filter))
608 (set-buffer-modified-p nil)
609 (if write-file-filter
610 (progn
611 (make-variable-buffer-local 'local-write-file-hooks)
612 (setq local-write-file-hooks (list write-file-filter)))))
613 (if write-file-filter
614 (save-excursion
615 (set-buffer forms--file-buffer)
616 (make-variable-buffer-local 'local-write-file-hooks)
617 (setq local-write-file-hooks write-file-filter)))))
618
563 ;; count the number of records, and set see if it may be modified 619 ;; count the number of records, and set see if it may be modified
564 (let (ro) 620 (let (ro)
565 (setq forms--total-records 621 (setq forms--total-records
@@ -592,10 +648,27 @@ Commands: Equivalent keys in read-only mode:
592 ;;(message "forms: proceeding setup (buffer)...") 648 ;;(message "forms: proceeding setup (buffer)...")
593 (set-buffer-modified-p nil) 649 (set-buffer-modified-p nil)
594 650
595 ;; setup the first (or current) record to show 651 (if (= forms--total-records 0)
596 (if (< forms--current-record 1) 652 ;;(message "forms: proceeding setup (new file)...")
597 (setq forms--current-record 1)) 653 (progn
598 (forms-jump-record forms--current-record) 654 (insert
655 "GNU Emacs Forms Mode version " forms-version "\n\n"
656 (if (file-exists-p forms-file)
657 (concat "No records available in file \"" forms-file "\".\n\n")
658 (format "Creating new file \"%s\"\nwith %d field%s per record.\n\n"
659 forms-file forms-number-of-fields
660 (if (= 1 forms-number-of-fields) "" "s")))
661 "Use " (substitute-command-keys "\\[forms-insert-record]")
662 " to create new records.\n")
663 (setq forms--current-record 1)
664 (setq buffer-read-only t)
665 (set-buffer-modified-p nil))
666
667 ;; setup the first (or current) record to show
668 (if (< forms--current-record 1)
669 (setq forms--current-record 1))
670 (forms-jump-record forms--current-record)
671 )
599 672
600 ;; user customising 673 ;; user customising
601 ;;(message "forms: proceeding setup (user hooks)...") 674 ;;(message "forms: proceeding setup (user hooks)...")
@@ -1082,6 +1155,52 @@ Commands: Equivalent keys in read-only mode:
1082 (setq forms--field nil))) 1155 (setq forms--field nil)))
1083 )) 1156 ))
1084 1157
1158(defun forms--intuit-from-file ()
1159 "Get number of fields and a default form using the data file."
1160
1161 ;; If `forms-number-of-fields' is not set, get it from the data file.
1162 (if (null forms-number-of-fields)
1163
1164 ;; Need a file to do this.
1165 (if (not (file-exists-p forms-file))
1166 (error "Need existing file or explicit 'forms-number-of-records'.")
1167
1168 ;; Visit the file and extract the first record.
1169 (setq forms--file-buffer (find-file-noselect forms-file))
1170 (let ((read-file-filter forms-read-file-filter)
1171 (the-record))
1172 (setq the-record
1173 (save-excursion
1174 (set-buffer forms--file-buffer)
1175 (let ((inhibit-read-only t))
1176 (run-hooks 'read-file-filter))
1177 (goto-char (point-min))
1178 (forms--get-record)))
1179
1180 ;; This may be overkill, but try to avoid interference with
1181 ;; the normal processing.
1182 (kill-buffer forms--file-buffer)
1183
1184 ;; Count the number of fields in `the-record'.
1185 (let (the-result
1186 (start-pos 0)
1187 found-pos
1188 (field-sep-length (length forms-field-sep)))
1189 (setq forms-number-of-fields 1)
1190 (while (setq found-pos
1191 (string-match forms-field-sep the-record start-pos))
1192 (progn
1193 (setq forms-number-of-fields (1+ forms-number-of-fields))
1194 (setq start-pos (+ field-sep-length found-pos))))))))
1195
1196 ;; Construct default format list.
1197 (setq forms-format-list (list "Forms file \"" forms-file "\".\n\n"))
1198 (let ((i 0))
1199 (while (<= (setq i (1+ i)) forms-number-of-fields)
1200 (setq forms-format-list
1201 (append forms-format-list
1202 (list (format "%4d: " i) i "\n"))))))
1203
1085(defun forms--set-keymaps () 1204(defun forms--set-keymaps ()
1086 "Set the keymaps used in this mode." 1205 "Set the keymaps used in this mode."
1087 1206
@@ -1170,10 +1289,9 @@ Commands: Equivalent keys in read-only mode:
1170 (current-local-map) 1289 (current-local-map)
1171 (current-global-map)))) 1290 (current-global-map))))
1172 ;; 1291 ;;
1173 ;; Use local-write-file-hooks to invoke our own buffer save 1292 ;; Save buffer
1174 ;; function. Note however that it usually does not work. 1293 (local-set-key "\C-x\C-s" 'forms-save-buffer)
1175 (make-local-variable 'local-write-file-hooks) 1294 ;;
1176 (add-hook 'local-write-file-hooks 'forms--local-write-file-function)
1177 ;; We have our own revert function - use it. 1295 ;; We have our own revert function - use it.
1178 (make-local-variable 'revert-buffer-function) 1296 (make-local-variable 'revert-buffer-function)
1179 (setq revert-buffer-function 'forms--revert-buffer) 1297 (setq revert-buffer-function 'forms--revert-buffer)
@@ -1182,18 +1300,12 @@ Commands: Equivalent keys in read-only mode:
1182 1300
1183(defun forms--help () 1301(defun forms--help ()
1184 "Initial help for Forms mode." 1302 "Initial help for Forms mode."
1185 ;; We should use
1186 (message (substitute-command-keys (concat 1303 (message (substitute-command-keys (concat
1187 "\\[forms-next-record]:next" 1304 "\\[forms-next-record]:next"
1188 " \\[forms-prev-record]:prev" 1305 " \\[forms-prev-record]:prev"
1189 " \\[forms-first-record]:first" 1306 " \\[forms-first-record]:first"
1190 " \\[forms-last-record]:last" 1307 " \\[forms-last-record]:last"
1191 " \\[describe-mode]:help")))) 1308 " \\[describe-mode]:help"))))
1192 ; but it's too slow ....
1193; (if forms-read-only
1194; (message "SPC:next DEL:prev <:first >:last ?:help q:exit")
1195; (message "C-c n:next C-c p:prev C-c <:first C-c >:last C-c ?:help C-c q:exit"))
1196; )
1197 1309
1198(defun forms--trans (subj arg rep) 1310(defun forms--trans (subj arg rep)
1199 "Translate in SUBJ all chars ARG into char REP. ARG and REP should 1311 "Translate in SUBJ all chars ARG into char REP. ARG and REP should
@@ -1213,9 +1325,7 @@ Commands: Equivalent keys in read-only mode:
1213 (forms--checkmod) 1325 (forms--checkmod)
1214 (if (and save 1326 (if (and save
1215 (buffer-modified-p forms--file-buffer)) 1327 (buffer-modified-p forms--file-buffer))
1216 (save-excursion 1328 (forms-save-buffer))
1217 (set-buffer forms--file-buffer)
1218 (save-buffer)))
1219 (save-excursion 1329 (save-excursion
1220 (set-buffer forms--file-buffer) 1330 (set-buffer forms--file-buffer)
1221 (delete-auto-save-file-if-necessary) 1331 (delete-auto-save-file-if-necessary)
@@ -1334,6 +1444,10 @@ As a side effect: sets `forms--the-record-list'."
1334 (setq the-record 1444 (setq the-record
1335 (mapconcat 'identity forms--the-record-list forms-field-sep)) 1445 (mapconcat 'identity forms--the-record-list forms-field-sep))
1336 1446
1447 (if (string-match (regexp-quote forms-field-sep)
1448 (mapconcat 'identity forms--the-record-list ""))
1449 (error "Field separator occurs in record - update refused!"))
1450
1337 ;; Handle multi-line fields, if allowed. 1451 ;; Handle multi-line fields, if allowed.
1338 (if forms-multi-line 1452 (if forms-multi-line
1339 (forms--trans the-record "\n" forms-multi-line)) 1453 (forms--trans the-record "\n" forms-multi-line))
@@ -1348,8 +1462,8 @@ As a side effect: sets `forms--the-record-list'."
1348 (set-buffer forms--file-buffer) 1462 (set-buffer forms--file-buffer)
1349 ;; Use delete-region instead of kill-region, to avoid 1463 ;; Use delete-region instead of kill-region, to avoid
1350 ;; adding junk to the kill-ring. 1464 ;; adding junk to the kill-ring.
1351 (delete-region (save-excursion (beginning-of-line) (point)) 1465 (delete-region (progn (beginning-of-line) (point))
1352 (save-excursion (end-of-line) (point))) 1466 (progn (beginning-of-line 2) (point))))
1353 (insert the-record) 1467 (insert the-record)
1354 (beginning-of-line)))))) 1468 (beginning-of-line))))))
1355 1469
@@ -1612,12 +1726,20 @@ it is called to fill (some of) the fields with default values."
1612 (re-search-forward regexp nil t)))) 1726 (re-search-forward regexp nil t))))
1613 (setq forms--search-regexp regexp)) 1727 (setq forms--search-regexp regexp))
1614 1728
1615(defun forms--local-write-file-function () 1729(defun forms-save-buffer (&optional args)
1616 "Local write file hook." 1730 "Forms mode replacement for save-buffer.
1731It saves the data buffer instead of the forms buffer.
1732Calls `forms-write-file-filter' before writing out the data."
1733 (interactive "p")
1617 (forms--checkmod) 1734 (forms--checkmod)
1618 (save-excursion 1735 (let ((read-file-filter forms-read-file-filter))
1619 (set-buffer forms--file-buffer) 1736 (save-excursion
1620 (save-buffer)) 1737 (set-buffer forms--file-buffer)
1738 (let ((inhibit-read-only t))
1739 (save-buffer args)
1740 (if read-file-filter
1741 (run-hooks 'read-file-filter))
1742 (set-buffer-modified-p nil))))
1621 t) 1743 t)
1622 1744
1623(defun forms--revert-buffer (&optional arg noconfirm) 1745(defun forms--revert-buffer (&optional arg noconfirm)