Mercurial > emacs
comparison lisp/forms.el @ 307:7fede845e304
*** empty log message ***
author | Richard M. Stallman <rms@gnu.org> |
---|---|
date | Mon, 01 Jul 1991 18:06:13 +0000 |
parents | e7eb71cbf478 |
children | 994bb6dc9249 |
comparison
equal
deleted
inserted
replaced
306:785babb5bb6f | 307:7fede845e304 |
---|---|
1 ;;; Forms Mode - A GNU Emacs Major Mode ; @(#)@ forms 1.2.2 | 1 ;;; forms.el -- Forms Mode - A GNU Emacs Major Mode |
2 ;;; Created 1989 - Johan Vromans <jv@mh.nl> | 2 ;;; SCCS Status : @(#)@ forms 1.2.7 |
3 ;;; See the docs for a list of other contributors. | 3 ;;; Author : Johan Vromans |
4 ;;; | 4 ;;; Created On : 1989 |
5 ;;; Last Modified By: Johan Vromans | |
6 ;;; Last Modified On: Mon Jul 1 14:13:20 1991 | |
7 ;;; Update Count : 15 | |
8 ;;; Status : OK | |
9 | |
5 ;;; This file is part of GNU Emacs. | 10 ;;; This file is part of GNU Emacs. |
6 | |
7 ;;; GNU Emacs is distributed in the hope that it will be useful, | 11 ;;; GNU Emacs is distributed in the hope that it will be useful, |
8 ;;; but WITHOUT ANY WARRANTY. No author or distributor | 12 ;;; but WITHOUT ANY WARRANTY. No author or distributor |
9 ;;; accepts responsibility to anyone for the consequences of using it | 13 ;;; accepts responsibility to anyone for the consequences of using it |
10 ;;; or for whether it serves any particular purpose or works at all, | 14 ;;; or for whether it serves any particular purpose or works at all, |
11 ;;; unless he says so in writing. Refer to the GNU Emacs General Public | 15 ;;; unless he says so in writing. Refer to the GNU Emacs General Public |
18 ;;; can know your rights and responsibilities. | 22 ;;; can know your rights and responsibilities. |
19 ;;; If you don't have this copy, write to the Free Software | 23 ;;; If you don't have this copy, write to the Free Software |
20 ;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 24 ;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
21 ;;; | 25 ;;; |
22 | 26 |
27 ;;; HISTORY | |
28 ;;; 1-Jul-1991 Johan Vromans | |
29 ;;; Normalized error messages. | |
30 ;;; 30-Jun-1991 Johan Vromans | |
31 ;;; Add support for forms-modified-record-filter. | |
32 ;;; Allow the filter functions to be the name of a function. | |
33 ;;; Fix: parse--format used forms--dynamic-text destructively. | |
34 ;;; Internally optimized the forms-format-list. | |
35 ;;; Added support for debugging. | |
36 ;;; Stripped duplicate documentation. | |
37 ;;; | |
38 ;;; 29-Jun-1991 Johan Vromans | |
39 ;;; Add support for functions and lisp symbols in forms-format-list. | |
40 ;;; Add function forms-enumerate. | |
41 | |
23 (provide 'forms-mode) | 42 (provide 'forms-mode) |
24 | 43 |
25 ;;; Visit a file using a form. | 44 ;;; Visit a file using a form. |
26 ;;; | 45 ;;; |
27 ;;; === Naming conventions | 46 ;;; === Naming conventions |
73 ;;; | 92 ;;; |
74 ;;; forms-format-list [list] formatting instructions. | 93 ;;; forms-format-list [list] formatting instructions. |
75 ;;; | 94 ;;; |
76 ;;; The forms-format-list should be a list, each element containing | 95 ;;; The forms-format-list should be a list, each element containing |
77 ;;; | 96 ;;; |
78 ;;; - either a string, e.g. "hello" (which is inserted \"as is\"), | 97 ;;; - a string, e.g. "hello" (which is inserted \"as is\"), |
79 ;;; | 98 ;;; |
80 ;;; - an integer, denoting a field number. The contents of the field | 99 ;;; - an integer, denoting a field number. The contents of the field |
81 ;;; are inserted at this point. | 100 ;;; are inserted at this point. |
82 ;;; The first field has number one. | 101 ;;; The first field has number one. |
102 ;;; | |
103 ;;; - a function call, e.g. (insert "text"). This function call is | |
104 ;;; dynamically evaluated and should return a string. It should *NOT* | |
105 ;;; have side-effects on the forms being constructed. | |
106 ;;; The current fields are available to the function in the variable | |
107 ;;; forms-fields, they should *NOT* be modified. | |
108 ;;; | |
109 ;;; - a lisp symbol, that must evaluate to one of the above. | |
83 ;;; | 110 ;;; |
84 ;;; Optional variables which may be set in the control file: | 111 ;;; Optional variables which may be set in the control file: |
85 ;;; | 112 ;;; |
86 ;;; forms-field-sep [string, default TAB] | 113 ;;; forms-field-sep [string, default TAB] |
87 ;;; The field separator used to separate the | 114 ;;; The field separator used to separate the |
109 ;;; forms-forms-jump [bool, default t] | 136 ;;; forms-forms-jump [bool, default t] |
110 ;;; If non-nil: redefine beginning/end-of-buffer | 137 ;;; If non-nil: redefine beginning/end-of-buffer |
111 ;;; to performs forms-first/last-field if in | 138 ;;; to performs forms-first/last-field if in |
112 ;;; forms mode. | 139 ;;; forms mode. |
113 ;;; | 140 ;;; |
114 ;;; forms-new-record-filter [function, no default] | 141 ;;; forms-new-record-filter [symbol, no default] |
115 ;;; If defined: this function is called when a new | 142 ;;; If defined: this should be the name of a |
143 ;;; function that is called when a new | |
116 ;;; record is created. It can be used to fill in | 144 ;;; record is created. It can be used to fill in |
117 ;;; the new record with default fields, for example. | 145 ;;; the new record with default fields, for example. |
146 ;;; Instead of the name of the function, it may | |
147 ;;; be the function itself. | |
148 ;;; | |
149 ;;; forms-modified-record-filter [symbol, no default] | |
150 ;;; If defined: this should be the name of a | |
151 ;;; function that is called when a record has | |
152 ;;; been modified. It is called after the fields | |
153 ;;; are parsed. It can be used to register | |
154 ;;; modification dates, for example. | |
155 ;;; Instead of the name of the function, it may | |
156 ;;; be the function itself. | |
118 ;;; | 157 ;;; |
119 ;;; After evaluating the control file, its buffer is cleared and used | 158 ;;; After evaluating the control file, its buffer is cleared and used |
120 ;;; for further processing. | 159 ;;; for further processing. |
121 ;;; The data file (as designated by "forms-file") is visited in a buffer | 160 ;;; The data file (as designated by "forms-file") is visited in a buffer |
122 ;;; (forms--file-buffer) which will not normally be shown. | 161 ;;; (forms--file-buffer) which will not normally be shown. |
124 ;;; outside of this package while it's being visited! | 163 ;;; outside of this package while it's being visited! |
125 ;;; | 164 ;;; |
126 ;;; A record from the data file is transferred from the data file, | 165 ;;; A record from the data file is transferred from the data file, |
127 ;;; split into fields (into forms--the-record-list), and displayed using | 166 ;;; split into fields (into forms--the-record-list), and displayed using |
128 ;;; the specs in forms-format-list. | 167 ;;; the specs in forms-format-list. |
129 ;;; A format routine 'forms--format' is build upon startup to format | 168 ;;; A format routine 'forms--format' is built upon startup to format |
130 ;;; the records. | 169 ;;; the records. |
131 ;;; | 170 ;;; |
132 ;;; When a form is changed the record is updated as soon as this form | 171 ;;; When a form is changed the record is updated as soon as this form |
133 ;;; is left. The contents of the form are parsed using forms-format-list, | 172 ;;; is left. The contents of the form are parsed using forms-format-list, |
134 ;;; and the fields which are deduced from the form are modified. So, | 173 ;;; and the fields which are deduced from the form are modified. So, |
135 ;;; fields not shown on the forms retain their origional values. | 174 ;;; fields not shown on the forms retain their origional values. |
136 ;;; The newly formed record and replaces the contents of the | 175 ;;; The newly formed record and replaces the contents of the |
137 ;;; old record in forms--file-buffer. | 176 ;;; old record in forms--file-buffer. |
138 ;;; A parse routine 'forms--parser' is build upon startup to parse | 177 ;;; A parse routine 'forms--parser' is built upon startup to parse |
139 ;;; the records. | 178 ;;; the records. |
140 ;;; | 179 ;;; |
141 ;;; Two exit functions exist: forms-exit (which saves) and forms-exit-no-save | 180 ;;; Two exit functions exist: forms-exit (which saves) and forms-exit-no-save |
142 ;;; (which doesn't). However, if forms-exit-no-save is executed and the file | 181 ;;; (which doesn't). However, if forms-exit-no-save is executed and the file |
143 ;;; buffer has been modified, emacs will ask questions. | 182 ;;; buffer has been modified, emacs will ask questions. |
194 ;;; For convenience, TAB is always bound to forms-next-field, so you | 233 ;;; For convenience, TAB is always bound to forms-next-field, so you |
195 ;;; don't need the C-c prefix for this command. | 234 ;;; don't need the C-c prefix for this command. |
196 ;;; | 235 ;;; |
197 ;;; Global variables and constants | 236 ;;; Global variables and constants |
198 | 237 |
199 (defconst forms-version "1.2.2" | 238 (defconst forms-version "1.2.7" |
200 "Version of forms-mode implementation") | 239 "Version of forms-mode implementation") |
201 | 240 |
202 (defvar forms-forms-scrolls t | 241 (defvar forms-forms-scrolls t |
203 "If non-null: redefine scroll-up/down to be used with forms-mode.") | 242 "If non-null: redefine scroll-up/down to be used with forms-mode.") |
204 | 243 |
209 "Hook functions to be run upon entering forms mode.") | 248 "Hook functions to be run upon entering forms mode.") |
210 ;;; | 249 ;;; |
211 ;;; Mandatory variables - must be set by evaluating the control file | 250 ;;; Mandatory variables - must be set by evaluating the control file |
212 | 251 |
213 (defvar forms-file nil | 252 (defvar forms-file nil |
214 "Name of the file holding the data.") | 253 "Name of the file holding the data.") |
215 | 254 |
216 (defvar forms-format-list nil | 255 (defvar forms-format-list nil |
217 "Formatting specifications: | 256 "List of formatting specifications.") |
218 | |
219 It should be a list, each element containing | |
220 | |
221 - either a string, e.g. "hello" (which is inserted \"as is\"), | |
222 | |
223 - an integer, denoting the number of a field which contents are | |
224 inserted at this point. | |
225 The first field has number one. | |
226 ") | |
227 | 257 |
228 (defvar forms-number-of-fields nil | 258 (defvar forms-number-of-fields nil |
229 "Number of fields per record.") | 259 "Number of fields per record.") |
230 | 260 |
231 ;;; | 261 ;;; |
285 "Internal - keeps track of forms-mode being set-up.") | 315 "Internal - keeps track of forms-mode being set-up.") |
286 (make-variable-buffer-local 'forms--mode-setup) | 316 (make-variable-buffer-local 'forms--mode-setup) |
287 | 317 |
288 (defvar forms--new-record-filter nil | 318 (defvar forms--new-record-filter nil |
289 "Internal - set if a new record filter has been defined.") | 319 "Internal - set if a new record filter has been defined.") |
320 | |
321 (defvar forms--modified-record-filter nil | |
322 "Internal - set if a modified record filter has been defined.") | |
323 | |
324 (defvar forms--dynamic-text nil | |
325 "Internal - holds dynamic text to insert between fields.") | |
326 | |
327 (defvar forms-fields nil | |
328 "List with fields of the current forms. First field has number 1.") | |
290 | 329 |
291 ;;; | 330 ;;; |
292 ;;; forms-mode | 331 ;;; forms-mode |
293 ;;; | 332 ;;; |
294 ;;; This is not a simple major mode, as usual. Therefore, forms-mode | 333 ;;; This is not a simple major mode, as usual. Therefore, forms-mode |
357 (make-local-variable 'forms--format) | 396 (make-local-variable 'forms--format) |
358 (forms--make-format) | 397 (forms--make-format) |
359 (make-local-variable 'forms--parser) | 398 (make-local-variable 'forms--parser) |
360 (forms--make-parser) | 399 (forms--make-parser) |
361 | 400 |
362 ;; check if a new record filter was defined | 401 ;; check if record filters are defined |
363 (make-local-variable 'forms--new-record-filter) | 402 (make-local-variable 'forms--new-record-filter) |
364 (setq forms--new-record-filter | 403 (setq forms--new-record-filter |
365 (and (fboundp 'forms-new-record-filter) | 404 (cond |
366 (symbol-function 'forms-new-record-filter))) | 405 ((fboundp 'forms-new-record-filter) |
406 (symbol-function 'forms-new-record-filter)) | |
407 ((and (boundp 'forms-new-record-filter) | |
408 (fboundp forms-new-record-filter)) | |
409 forms-new-record-filter))) | |
367 (fmakunbound 'forms-new-record-filter) | 410 (fmakunbound 'forms-new-record-filter) |
368 | 411 (make-local-variable 'forms--modified-record-filter) |
412 (setq forms--modified-record-filter | |
413 (cond | |
414 ((fboundp 'forms-modified-record-filter) | |
415 (symbol-function 'forms-modified-record-filter)) | |
416 ((and (boundp 'forms-modified-record-filter) | |
417 (fboundp forms-modified-record-filter)) | |
418 forms-modified-record-filter))) | |
419 (fmakunbound 'forms-modified-record-filter) | |
420 | |
421 ;; dynamic text support | |
422 (make-local-variable 'forms--dynamic-text) | |
423 (make-local-variable 'forms-fields) | |
369 | 424 |
370 ;; prepare this buffer for further processing | 425 ;; prepare this buffer for further processing |
371 (setq buffer-read-only nil) | 426 (setq buffer-read-only nil) |
372 | 427 |
373 ;; prevent accidental overwrite of the control file and autosave | 428 ;; prevent accidental overwrite of the control file and autosave |
443 ;;; Sets forms--number-of-markers and forms--markers. | 498 ;;; Sets forms--number-of-markers and forms--markers. |
444 | 499 |
445 (defun forms--process-format-list () | 500 (defun forms--process-format-list () |
446 "Validate forms-format-list and set some global variables." | 501 "Validate forms-format-list and set some global variables." |
447 | 502 |
503 (forms--debug "forms-forms-list before 1st pass:\n" | |
504 'forms-format-list) | |
505 | |
448 ;; it must be non-nil | 506 ;; it must be non-nil |
449 (or forms-format-list | 507 (or forms-format-list |
450 (error "'forms-format-list' has not been set")) | 508 (error "'forms-format-list' has not been set")) |
451 ;; it must be a list ... | 509 ;; it must be a list ... |
452 (or (listp forms-format-list) | 510 (or (listp forms-format-list) |
453 (error "'forms-format-list' is not a list")) | 511 (error "'forms-format-list' is not a list")) |
454 | 512 |
455 (setq forms--number-of-markers 0) | 513 (setq forms--number-of-markers 0) |
456 | 514 |
457 (let ((the-list forms-format-list) ; the list of format elements | 515 (let ((the-list forms-format-list) ; the list of format elements |
516 (this-item 0) ; element in list | |
458 (field-num 0)) ; highest field number | 517 (field-num 0)) ; highest field number |
518 | |
519 (setq forms-format-list nil) ; gonna rebuild | |
459 | 520 |
460 (while the-list | 521 (while the-list |
461 | 522 |
462 (let ((el (car-safe the-list)) | 523 (let ((el (car-safe the-list)) |
463 (rem (cdr-safe the-list))) | 524 (rem (cdr-safe the-list))) |
525 | |
526 ;; if it is a symbol, eval it first | |
527 (if (and (symbolp el) | |
528 (boundp el)) | |
529 (setq el (eval el))) | |
464 | 530 |
465 (cond | 531 (cond |
466 | 532 |
467 ;; try string ... | 533 ;; try string ... |
468 ((stringp el)) ; string is OK | 534 ((stringp el)) ; string is OK |
469 | 535 |
470 ;; try int ... | 536 ;; try numeric ... |
471 ((numberp el) ; check it | 537 ((numberp el) |
472 | 538 |
473 (if (or (<= el 0) | 539 (if (or (<= el 0) |
474 (> el forms-number-of-fields)) | 540 (> el forms-number-of-fields)) |
475 (error | 541 (error |
476 "forms error: field number %d out of range 1..%d" | 542 "Forms error: field number %d out of range 1..%d" |
477 el forms-number-of-fields)) | 543 el forms-number-of-fields)) |
478 | 544 |
479 (setq forms--number-of-markers (1+ forms--number-of-markers)) | 545 (setq forms--number-of-markers (1+ forms--number-of-markers)) |
480 (if (> el field-num) | 546 (if (> el field-num) |
481 (setq field-num el))) | 547 (setq field-num el))) |
482 | 548 |
549 ;; try function | |
550 ((listp el) | |
551 (or (fboundp (car-safe el)) | |
552 (error | |
553 "Forms error: not a function: %s" | |
554 (prin1-to-string (car-safe el))))) | |
555 | |
483 ;; else | 556 ;; else |
484 (t | 557 (t |
485 (error "invalid element in 'forms-format-list': %s" | 558 (error "Invalid element in 'forms-format-list': %s" |
486 (prin1-to-string el))) | 559 (prin1-to-string el)))) |
487 | |
488 ;; dead code - we'll need it in the future | |
489 ((consp el) ; check it | |
490 | |
491 (let ((str (car-safe el)) | |
492 (idx (cdr-safe el))) | |
493 | |
494 (cond | |
495 | |
496 ;; car must be string | |
497 ((not (stringp str)) | |
498 (error "forms error: car of cons %s must be string" | |
499 (prin1-to-string el))) | |
500 | |
501 ;; cdr must be number, > zero | |
502 ((or (not (numberp idx)) | |
503 (<= idx 0) | |
504 (> idx forms-number-of-fields)) | |
505 (error | |
506 "forms error: cdr of cons %s must be a number between 1 and %d" | |
507 (prin1-to-string el) | |
508 forms-number-of-fields))) | |
509 | |
510 ;; passed the test - handle it | |
511 (setq forms--number-of-markers (1+ forms--number-of-markers)) | |
512 (if (> idx field-num) | |
513 (setq field-num idx))))) | |
514 | 560 |
515 ;; advance to next element of the list | 561 ;; advance to next element of the list |
516 (setq the-list rem)))) | 562 (setq the-list rem) |
563 (setq forms-format-list | |
564 (append forms-format-list (list el) nil))))) | |
565 | |
566 (forms--debug "forms-forms-list after 1st pass:\n" | |
567 'forms-format-list) | |
568 | |
569 ;; concat adjacent strings | |
570 (setq forms-format-list (forms--concat-adjacent forms-format-list)) | |
571 | |
572 (forms--debug "forms-forms-list after 2nd pass:\n" | |
573 'forms-format-list | |
574 'forms--number-of-markers) | |
517 | 575 |
518 (setq forms--markers (make-vector forms--number-of-markers nil))) | 576 (setq forms--markers (make-vector forms--number-of-markers nil))) |
519 | 577 |
520 | 578 |
521 ;;; | 579 ;;; |
522 ;;; Build the format routine from forms-format-list. | 580 ;;; Build the format routine from forms-format-list. |
523 ;;; | 581 ;;; |
524 ;;; The format routine (forms--format) will look like | 582 ;;; The format routine (forms--format) will look like |
525 ;;; | 583 ;;; |
526 ;;; (lambda (arg) | 584 ;;; (lambda (arg) |
527 ;;; | 585 ;;; (setq forms--dynamic-text nil) |
528 ;;; ;; "text: " | 586 ;;; ;; "text: " |
529 ;;; (insert "text: ") | 587 ;;; (insert "text: ") |
530 ;;; ;; 6 | 588 ;;; ;; 6 |
531 ;;; (aset forms--markers 0 (point-marker)) | 589 ;;; (aset forms--markers 0 (point-marker)) |
532 ;;; (insert (elt arg 5)) | 590 ;;; (insert (elt arg 5)) |
533 ;;; ;; "\nmore text: " | 591 ;;; ;; "\nmore text: " |
534 ;;; (insert "\nmore text: ") | 592 ;;; (insert "\nmore text: ") |
593 ;;; ;; (tocol 40) | |
594 ;;; (let ((the-dyntext (tocol 40))) | |
595 ;;; (insert the-dyntext) | |
596 ;;; (setq forms--dynamic-text (append forms--dynamic-text | |
597 ;;; (list the-dyntext)))) | |
535 ;;; ;; 9 | 598 ;;; ;; 9 |
536 ;;; (aset forms--markers 1 (point-marker)) | 599 ;;; (aset forms--markers 1 (point-marker)) |
537 ;;; (insert (elt arg 8)) | 600 ;;; (insert (elt arg 8)) |
538 ;;; | 601 ;;; |
539 ;;; ... ) | 602 ;;; ... ) |
540 ;;; | 603 ;;; |
541 | 604 |
542 (defun forms--make-format () | 605 (defun forms--make-format () |
543 "Generate parser function for forms" | 606 "Generate format function for forms" |
544 (setq forms--format (forms--format-maker forms-format-list))) | 607 (setq forms--format (forms--format-maker forms-format-list)) |
608 (forms--debug 'forms--format)) | |
545 | 609 |
546 (defun forms--format-maker (the-format-list) | 610 (defun forms--format-maker (the-format-list) |
547 "Returns the parser function for forms" | 611 "Returns the parser function for forms" |
548 (let ((the-marker 0)) | 612 (let ((the-marker 0)) |
549 (` (lambda (arg) | 613 (` (lambda (arg) |
614 (setq forms--dynamic-text nil) | |
550 (,@ (apply 'append | 615 (,@ (apply 'append |
551 (mapcar 'forms--make-format-elt | 616 (mapcar 'forms--make-format-elt the-format-list))))))) |
552 (forms--concat-adjacent the-format-list)))))))) | |
553 | 617 |
554 (defun forms--make-format-elt (el) | 618 (defun forms--make-format-elt (el) |
555 (cond ((stringp el) | 619 (cond ((stringp el) |
556 (` ((insert (, el))))) | 620 (` ((insert (, el))))) |
557 ((numberp el) | 621 ((numberp el) |
558 (prog1 | 622 (prog1 |
559 (` ((aset forms--markers (, the-marker) (point-marker)) | 623 (` ((aset forms--markers (, the-marker) (point-marker)) |
560 (insert (elt arg (, (1- el)))))) | 624 (insert (elt arg (, (1- el)))))) |
561 (setq the-marker (1+ the-marker)))))) | 625 (setq the-marker (1+ the-marker)))) |
626 ((listp el) | |
627 (prog1 | |
628 (` ((let ((the-dyntext (, el))) | |
629 (insert the-dyntext) | |
630 (setq forms--dynamic-text (append forms--dynamic-text | |
631 (list the-dyntext))))) | |
632 ))) | |
633 )) | |
562 | 634 |
563 | 635 |
564 (defun forms--concat-adjacent (the-list) | 636 (defun forms--concat-adjacent (the-list) |
565 "Concatenate adjacent strings in the-list and return the resulting list" | 637 "Concatenate adjacent strings in the-list and return the resulting list" |
566 (if (consp the-list) | 638 (if (consp the-list) |
582 ;;; (let (here) | 654 ;;; (let (here) |
583 ;;; (goto-char (point-min)) | 655 ;;; (goto-char (point-min)) |
584 ;;; | 656 ;;; |
585 ;;; ;; "text: " | 657 ;;; ;; "text: " |
586 ;;; (if (not (looking-at "text: ")) | 658 ;;; (if (not (looking-at "text: ")) |
587 ;;; (error "parse error: cannot find \"text: \"")) | 659 ;;; (error "Parse error: cannot find \"text: \"")) |
588 ;;; (forward-char 6) ; past "text: " | 660 ;;; (forward-char 6) ; past "text: " |
589 ;;; | 661 ;;; |
590 ;;; ;; 6 | 662 ;;; ;; 6 |
591 ;;; ;; "\nmore text: " | 663 ;;; ;; "\nmore text: " |
592 ;;; (setq here (point)) | 664 ;;; (setq here (point)) |
593 ;;; (if (not (search-forward "\nmore text: " nil t nil)) | 665 ;;; (if (not (search-forward "\nmore text: " nil t nil)) |
594 ;;; (error "parse error: cannot find \"\\nmore text: \"")) | 666 ;;; (error "Parse error: cannot find \"\\nmore text: \"")) |
595 ;;; (aset the-recordv 5 (buffer-substring here (- (point) 12))) | 667 ;;; (aset the-recordv 5 (buffer-substring here (- (point) 12))) |
596 ;;; ... | 668 ;;; |
669 ;;; ;; (tocol 40) | |
670 ;;; (let ((the-dyntext (car-safe forms--dynamic-text))) | |
671 ;;; (if (not (looking-at (regexp-quote the-dyntext))) | |
672 ;;; (error "Parse error: not looking at \"%s\"" the-dyntext)) | |
673 ;;; (forward-char (length the-dyntext)) | |
674 ;;; (setq forms--dynamic-text (cdr-safe forms--dynamic-text))) | |
597 ;;; ... | 675 ;;; ... |
598 ;;; ;; final flush (due to terminator sentinel, see below) | 676 ;;; ;; final flush (due to terminator sentinel, see below) |
599 ;;; (aset the-recordv 7 (buffer-substring (point) (point-max))) | 677 ;;; (aset the-recordv 7 (buffer-substring (point) (point-max))) |
600 ;;; | 678 ;;; |
601 | 679 |
602 (defun forms--make-parser () | 680 (defun forms--make-parser () |
603 "Generate parser function for forms" | 681 "Generate parser function for forms" |
604 (setq forms--parser (forms--parser-maker forms-format-list))) | 682 (setq forms--parser (forms--parser-maker forms-format-list)) |
683 (forms--debug 'forms--parser)) | |
605 | 684 |
606 (defun forms--parser-maker (the-format-list) | 685 (defun forms--parser-maker (the-format-list) |
607 "Returns the parser function for forms" | 686 "Returns the parser function for forms" |
608 (let ((the-field nil) | 687 (let ((the-field nil) |
609 (seen-text nil) | 688 (seen-text nil) |
610 the--format-list) | 689 the--format-list) |
611 ;; concat adjacent strings and add a terminator sentinel | 690 ;; add a terminator sentinel |
612 (setq the--format-list | 691 (setq the--format-list (append the-format-list (list nil))) |
613 (append (forms--concat-adjacent the-format-list) (list nil))) | |
614 (` (lambda nil | 692 (` (lambda nil |
615 (let (here) | 693 (let (here) |
616 (goto-char (point-min)) | 694 (goto-char (point-min)) |
617 (,@ (apply 'append | 695 (,@ (apply 'append |
618 (mapcar 'forms--make-parser-elt the--format-list)))))))) | 696 (mapcar 'forms--make-parser-elt the--format-list)))))))) |
619 | 697 |
620 (defun forms--make-parser-elt (el) | 698 (defun forms--make-parser-elt (el) |
621 (cond ((stringp el) | 699 (cond |
622 (prog1 | 700 ((stringp el) |
623 (if the-field | 701 (prog1 |
624 (` ((setq here (point)) | 702 (if the-field |
625 (if (not (search-forward (, el) nil t nil)) | 703 (` ((setq here (point)) |
626 (error "Parse error: cannot find %s" (, el))) | 704 (if (not (search-forward (, el) nil t nil)) |
627 (aset the-recordv (, (1- the-field)) | 705 (error "Parse error: cannot find \"%s\"" (, el))) |
628 (buffer-substring here | 706 (aset the-recordv (, (1- the-field)) |
629 (- (point) (, (length el))))))) | 707 (buffer-substring here |
630 (` ((if (not (looking-at (, (regexp-quote el)))) | 708 (- (point) (, (length el))))))) |
631 (error "Parse error: not looking at %s" (, el))) | 709 (` ((if (not (looking-at (, (regexp-quote el)))) |
632 (forward-char (, (length el)))))) | 710 (error "Parse error: not looking at \"%s\"" (, el))) |
633 (setq seen-text t) | 711 (forward-char (, (length el)))))) |
634 (setq the-field nil))) | 712 (setq seen-text t) |
635 ((numberp el) | 713 (setq the-field nil))) |
636 (if the-field | 714 ((numberp el) |
637 (error "Cannot parse adjacent fields %d and %d" | 715 (if the-field |
638 the-field el) | 716 (error "Cannot parse adjacent fields %d and %d" |
639 (setq the-field el) | 717 the-field el) |
640 nil)) | 718 (setq the-field el) |
641 ((null el) | 719 nil)) |
642 (if the-field | 720 ((null el) |
643 (` ((aset the-recordv (, (1- the-field)) | 721 (if the-field |
644 (buffer-substring (point) (point-max))))))))) | 722 (` ((aset the-recordv (, (1- the-field)) |
723 (buffer-substring (point) (point-max))))))) | |
724 ((listp el) | |
725 (prog1 | |
726 (if the-field | |
727 (` ((let ((here (point)) | |
728 (the-dyntext (car-safe forms--dynamic-text))) | |
729 (if (not (search-forward the-dyntext nil t nil)) | |
730 (error "Parse error: cannot find \"%s\"" the-dyntext)) | |
731 (aset the-recordv (, (1- the-field)) | |
732 (buffer-substring here | |
733 (- (point) (length the-dyntext)))) | |
734 (setq forms--dynamic-text (cdr-safe forms--dynamic-text))))) | |
735 (` ((let ((the-dyntext (car-safe forms--dynamic-text))) | |
736 (if (not (looking-at (regexp-quote the-dyntext))) | |
737 (error "Parse error: not looking at \"%s\"" the-dyntext)) | |
738 (forward-char (length the-dyntext)) | |
739 (setq forms--dynamic-text (cdr-safe forms--dynamic-text)))))) | |
740 (setq seen-text t) | |
741 (setq the-field nil))) | |
742 )) | |
645 ;;; | 743 ;;; |
646 | 744 |
647 (defun forms--set-minor-mode () | 745 (defun forms--set-minor-mode () |
648 (setq minor-mode-alist | 746 (setq minor-mode-alist |
649 (if forms-read-only | 747 (if forms-read-only |
697 ;; | 795 ;; |
698 (if (fboundp 'forms--scroll-down) | 796 (if (fboundp 'forms--scroll-down) |
699 nil | 797 nil |
700 (fset 'forms--scroll-down (symbol-function 'scroll-down)) | 798 (fset 'forms--scroll-down (symbol-function 'scroll-down)) |
701 (fset 'scroll-down | 799 (fset 'scroll-down |
702 '(lambda (arg) | 800 '(lambda (&optional arg) |
703 (interactive "P") | 801 (interactive "P") |
704 (if (and forms--mode-setup | 802 (if (and forms--mode-setup |
705 forms-forms-scroll) | 803 forms-forms-scroll) |
706 (forms-prev-record arg) | 804 (forms-prev-record arg) |
707 (forms--scroll-down arg))))) | 805 (forms--scroll-down arg))))) |
710 ;; | 808 ;; |
711 (if (fboundp 'forms--scroll-up) | 809 (if (fboundp 'forms--scroll-up) |
712 nil | 810 nil |
713 (fset 'forms--scroll-up (symbol-function 'scroll-up)) | 811 (fset 'forms--scroll-up (symbol-function 'scroll-up)) |
714 (fset 'scroll-up | 812 (fset 'scroll-up |
715 '(lambda (arg) | 813 '(lambda (&optional arg) |
716 (interactive "P") | 814 (interactive "P") |
717 (if (and forms--mode-setup | 815 (if (and forms--mode-setup |
718 forms-forms-scroll) | 816 forms-forms-scroll) |
719 (forms-next-record arg) | 817 (forms-next-record arg) |
720 (forms--scroll-up arg))))) | 818 (forms--scroll-up arg))))) |
858 (- forms-number-of-fields | 956 (- forms-number-of-fields |
859 (length forms--the-record-list)) | 957 (length forms--the-record-list)) |
860 ""))))) | 958 ""))))) |
861 | 959 |
862 ;; call the formatter function | 960 ;; call the formatter function |
961 (setq forms-fields (append (list nil) forms--the-record-list nil)) | |
863 (funcall forms--format forms--the-record-list) | 962 (funcall forms--format forms--the-record-list) |
864 | 963 |
865 ;; prepare | 964 ;; prepare |
866 (goto-char (point-min)) | 965 (goto-char (point-min)) |
867 (set-buffer-modified-p nil) | 966 (set-buffer-modified-p nil) |
882 | 981 |
883 ;; build the vector | 982 ;; build the vector |
884 (setq the-recordv (vconcat forms--the-record-list)) | 983 (setq the-recordv (vconcat forms--the-record-list)) |
885 | 984 |
886 ;; parse the form and update the vector | 985 ;; parse the form and update the vector |
887 (funcall forms--parser) | 986 (let ((forms--dynamic-text forms--dynamic-text)) |
888 | 987 (funcall forms--parser)) |
889 ;; transform to a list and return | 988 |
890 (append the-recordv nil))) | 989 (if forms--modified-record-filter |
990 ;; As a service to the user, we add a zeroth element so she | |
991 ;; can use the same indices as in the forms definition. | |
992 (let ((the-fields (vconcat [nil] the-recordv))) | |
993 (setq the-fields (funcall forms--modified-record-filter the-fields)) | |
994 (cdr (append the-fields nil))) | |
995 | |
996 ;; transform to a list and return | |
997 (append the-recordv nil)))) | |
891 | 998 |
892 (defun forms--update () | 999 (defun forms--update () |
893 "Update current record with contents of form. As a side effect: sets | 1000 "Update current record with contents of form. As a side effect: sets |
894 forms--the-record-list ." | 1001 forms--the-record-list ." |
895 (if forms-read-only | 1002 (if forms-read-only |
1063 (if (equal ro forms-read-only) | 1170 (if (equal ro forms-read-only) |
1064 nil | 1171 nil |
1065 (forms-mode)))) | 1172 (forms-mode)))) |
1066 | 1173 |
1067 ;; Sample: | 1174 ;; Sample: |
1068 ;; (defun forms-new-record-filter (the-fields) | 1175 ;; (defun my-new-record-filter (the-fields) |
1069 ;; ;; numbers are relative to 1 | 1176 ;; ;; numbers are relative to 1 |
1070 ;; (aset the-fields 4 (current-time-string)) | 1177 ;; (aset the-fields 4 (current-time-string)) |
1071 ;; (aset the-fields 6 (user-login-name)) | 1178 ;; (aset the-fields 6 (user-login-name)) |
1072 ;; the-list) | 1179 ;; the-list) |
1180 ;; (setq forms-new-record-filter 'my-new-record-filter) | |
1073 | 1181 |
1074 (defun forms-insert-record (arg) | 1182 (defun forms-insert-record (arg) |
1075 "Create a new record before the current one. With ARG: store the | 1183 "Create a new record before the current one. With ARG: store the |
1076 record after the current one. | 1184 record after the current one. |
1077 If a function forms-new-record-filter is defined, is is called to | 1185 If a function forms-new-record-filter is defined, or forms-new-record-filter |
1186 contains the name of a function, it is called to | |
1078 fill (some of) the fields with default values." | 1187 fill (some of) the fields with default values." |
1079 ; The above doc is not true, but for documentary purposes only | 1188 ; The above doc is not true, but for documentary purposes only |
1080 | 1189 |
1081 (interactive "P") | 1190 (interactive "P") |
1082 | 1191 |
1191 (goto-char there) | 1300 (goto-char there) |
1192 (throw 'done t)))) | 1301 (throw 'done t)))) |
1193 (setq i (1+ i)))) | 1302 (setq i (1+ i)))) |
1194 nil | 1303 nil |
1195 (goto-char (aref forms--markers 0))))) | 1304 (goto-char (aref forms--markers 0))))) |
1305 | |
1306 ;;; | |
1307 ;;; Special service | |
1308 ;;; | |
1309 (defun forms-enumerate (the-fields) | |
1310 "Take a quoted list of symbols, and set their values to the numbers | |
1311 1, 2 and so on. Returns the higest number. | |
1312 | |
1313 Usage: (setq forms-number-of-fields | |
1314 (forms-enumerate | |
1315 '(field1 field2 field2 ...)))" | |
1316 | |
1317 (let ((the-index 0)) | |
1318 (while the-fields | |
1319 (setq the-index (1+ the-index)) | |
1320 (let ((el (car-safe the-fields))) | |
1321 (setq the-fields (cdr-safe the-fields)) | |
1322 (set el the-index))) | |
1323 the-index)) | |
1324 | |
1325 ;;; | |
1326 ;;; Debugging | |
1327 ;;; | |
1328 (defvar forms--debug nil | |
1329 "*Enables forms-mode debugging if not nil.") | |
1330 | |
1331 (defun forms--debug (&rest args) | |
1332 "Internal - debugging routine" | |
1333 (if forms--debug | |
1334 (let ((ret nil)) | |
1335 (while args | |
1336 (let ((el (car-safe args))) | |
1337 (setq args (cdr-safe args)) | |
1338 (if (stringp el) | |
1339 (setq ret (concat ret el)) | |
1340 (setq ret (concat ret (prin1-to-string el) " = ")) | |
1341 (if (boundp el) | |
1342 (let ((vel (eval el))) | |
1343 (setq ret (concat ret (prin1-to-string vel) "\n"))) | |
1344 (setq ret (concat ret "<unbound>" "\n"))) | |
1345 (if (fboundp el) | |
1346 (setq ret (concat ret (prin1-to-string (symbol-function el)) | |
1347 "\n")))))) | |
1348 (save-excursion | |
1349 (set-buffer (get-buffer-create "*forms-mode debug*")) | |
1350 (goto-char (point-max)) | |
1351 (insert ret))))) | |
1352 | |
1353 ;;; Local Variables: | |
1354 ;;; eval: (headers) | |
1355 ;;; eval: (setq comment-start ";;; ") | |
1356 ;;; End: |