diff options
| author | Richard M. Stallman | 1994-07-26 19:47:39 +0000 |
|---|---|---|
| committer | Richard M. Stallman | 1994-07-26 19:47:39 +0000 |
| commit | 9c308ed258917b661a2ebd101484ec0b7cb70b4b (patch) | |
| tree | e3d2bde8d3471a909a78c4bd09b0dc2dc88e94f7 /lisp/forms.el | |
| parent | 26d270ab4891cff6b75601c5f1c57c5e8529ef39 (diff) | |
| download | emacs-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.el | 188 |
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. |
| 306 | The replacement commands performs forms-first/last-record.") | 319 | The 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. | ||
| 323 | This can be used to change the contents of the file to something more | ||
| 324 | suitable 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. | ||
| 328 | This 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. |
| 1731 | It saves the data buffer instead of the forms buffer. | ||
| 1732 | Calls `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) |