home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3566 < prev    next >
Internet Message Format  |  1991-07-02  |  31KB

  1. From: jv@mh.nl (Johan Vromans)
  2. Newsgroups: gnu.emacs.sources,alt.sources
  3. Subject: GNU Emacs forms-mode version 1.2.7 (part 2 of 3)
  4. Message-ID: <1991Jul1.132216.10645@pronto.mh.nl>
  5. Date: 1 Jul 91 13:22:16 GMT
  6.  
  7.  
  8. Submitted-by: jv@mh.nl
  9. Archive-name: forms/part02
  10.  
  11. ---- Cut Here and feed the following to sh ----
  12. #!/bin/sh
  13. # this is forms.shr.02 (part 2 of forms)
  14. # do not concatenate these parts, unpack them in order with /bin/sh
  15. # file forms.ti continued
  16. #
  17. if test ! -r _shar_seq_.tmp; then
  18.     echo 'Please unpack part 1 first!'
  19.     exit 1
  20. fi
  21. (read Scheck
  22.  if test "$Scheck" != 2; then
  23.     echo Please unpack part "$Scheck" next!
  24.     exit 1
  25.  else
  26.     exit 0
  27.  fi
  28. ) < _shar_seq_.tmp || exit 1
  29. if test ! -f _shar_wnt_.tmp; then
  30.     echo 'x - still skipping forms.ti'
  31. else
  32. echo 'x - continuing file forms.ti'
  33. sed 's/^X//' << 'SHAR_EOF' >> 'forms.ti' &&
  34. @section Key bindings
  35. X
  36. This section describes the key bindings as they are defined when
  37. invoking forms mode.@*
  38. All commands must be prefixed with @kbd{C-c} when editing a forms. If a
  39. forms is read-only, @kbd{C-c} is not used.  The only exception to
  40. this rule is @code{forms-next-field}, which is bound to @kbd{TAB} in all
  41. maps.
  42. X
  43. @table @kbd
  44. X
  45. @itemx C-c @key{TAB}
  46. @code{forms-next-field}
  47. X
  48. @itemx C-c @key{SPC}
  49. @code{forms-next-record}
  50. X
  51. @itemx C-c <
  52. @code{forms-first-record}
  53. X
  54. @itemx C-c >
  55. @code{forms-first-record}
  56. X
  57. @itemx C-c d
  58. @code{forms-delete-record}
  59. X
  60. @itemx C-c e
  61. @code{forms-edit-mode}
  62. X
  63. @itemx C-c i
  64. @code{forms-insert-record}
  65. X
  66. @itemx C-c j
  67. @code{forms-jump-record}
  68. X
  69. @itemx C-c n
  70. @code{forms-next-record}
  71. X
  72. @itemx C-c p
  73. @code{forms-prev-record}
  74. X
  75. @itemx C-c q
  76. @code{forms-exit}
  77. X
  78. @itemx C-c s @var{regexp} 
  79. @code{forms-search}
  80. X
  81. @itemx C-c v
  82. @code{forms-view-mode}
  83. X
  84. @itemx C-c x
  85. @code{forms-exit-no-save}
  86. X
  87. @itemx C-c ?
  88. @code{describe-mode}
  89. X
  90. @itemx C-c @key{DEL}
  91. @code{forms-prev-record}
  92. X
  93. @end table
  94. X
  95. @node Miscellaneous, Error Messages, Key Bindings, Top
  96. @section Miscellaneous
  97. X
  98. @vindex forms-version
  99. A global variable @code{forms-version} holds the version information of
  100. the current implementation of forms mode.
  101. X
  102. @findex forms-enumerate
  103. It is very convenient to use symbolic names for the fields in a record.
  104. The function @code{forms-enumerate} provides an elegant means to define
  105. a series of variables to consecutive numbers.
  106. The function returns the higest number used, so it can be used to set
  107. @code{forms-number-of-fields} also:
  108. @example
  109. (setq forms-number-of-fields
  110. X      (forms-enumerate
  111. X       '(field1 field2 field3 ... )))
  112. @end example
  113. X
  114. @code{field1} will be set to 1, @code{field2} to 2 and so on.
  115. X
  116. Care has been taken to localize the current information of the forms
  117. mode, so it is possible to visit multiple files in forms mode
  118. simultaneously, even if they have different properties.
  119. X
  120. Since buffer-local functions are not available in this version of GNU
  121. Emacs, the definitions of the filter functions
  122. @code{forms-new-record-filter} and @code{forms-modified-record-filter}
  123. are copied into internal, buffer local variables when forms-mode is
  124. initialized.
  125. X
  126. If a control file is visited using the standard @code{find-file}
  127. commands, forms mode can be enabled with the command @code{M-x forms-mode}.@*
  128. Forms mode will be automatically enabled if the file contains
  129. the string @code{"-*- forms -*-"} somewhere in the first line. However,
  130. this makes it hard to edit the control file itself so you'd better think
  131. twice before using this.
  132. X
  133. The default format for the data file, using @key{TAB} to separate fields
  134. and @code{C-k} to separate multi-line fields, matches the file format of
  135. some popular Macintosh database programs, e.g. FileMaker. So
  136. @code{forms-mode} could decrease the need to use Apple computers.
  137. X
  138. @node Error Messages, Examples, Miscellaneous, Top
  139. @section Error Messages
  140. X
  141. This section describes all error messages which can be generated by
  142. forms mode.
  143. X
  144. @table @code
  145. @item 'forms-file' has not been set
  146. The variable @code{forms-file} was not set by the control file.
  147. X
  148. @item 'forms-number-of-fields' has not been set
  149. The variable @code{forms-number-of-fields} was not set by the control
  150. file.
  151. X
  152. @item 'forms-number-of-fields' must be > 0
  153. The variable @code{forms-number-of-fields} did not contain a positive
  154. number. 
  155. X
  156. @item 'forms-field-sep' is not a string
  157. @itemx 'forms-multi-line' must be nil or a one-character string
  158. The variable @code{forms-multi-line} was set to something other than
  159. @code{nil or} a single-character string.
  160. X
  161. @item 'forms-multi-line' is equal to 'forms-field-sep'
  162. The variable @code{forms-multi-line} may not be equal to
  163. @code{forms-field-sep} for this would make it impossible to distinguish
  164. fields and the lines in the fields.
  165. X
  166. @item 'forms-format-list' has not been set
  167. @itemx 'forms-format-list' is not a list
  168. The variable @code{forms-format-list} was not set to a lisp @code{list}
  169. by the control file.
  170. X
  171. @item Forms error: field number @var{XX} out of range 1..@var{NN}
  172. A field number was supplied with a value of @var{XX}, which was not
  173. greater than zero and smaller than or equal to the number of fields in the
  174. forms, @var{NN}.
  175. X
  176. @item Forms error: not a function @var{FUN}
  177. The first element of the lisp list specified in @code{forms-format-list}
  178. did not have a function value.
  179. X
  180. @item Invalid element in 'forms-format-list': @var{XX}
  181. A list element was supplied in @code{forms-format-list} which was not a
  182. @code{string}, @code{number} nor a @code{lisp list}.
  183. X
  184. @item Parse error: not looking at "..."
  185. When re-parsing the contents of a forms, the text shown could not
  186. be found.
  187. X
  188. @item Parse error: cannot find "..."
  189. When re-parsing the contents of a forms, the text shown, which
  190. separates two fields, could not be found.
  191. X
  192. @item Parse error: cannot parse adjacent fields @var{XX} and @var{YY}
  193. Fields @var{XX} and @var{YY} were not separated by text, so could not be
  194. parsed again.
  195. X
  196. @item Record has @var{XX} fields instead of @var{YY}
  197. The number of fields in this record in the data file did not match
  198. @code{forms-number-of-fields}. Missing fields will be set to empty.
  199. X
  200. @item Multi-line fields in this record - update refused!
  201. The current record contains newline characters, hence can not be written
  202. back to the data file, for it would corrupt it.@*
  203. probably a field was set to a multi-line value, while the setting of
  204. @code{forms-multi-line} prohibited this.
  205. X
  206. @item Record number @var{XX} out of range 1..@var{YY}
  207. A jump was made to non-existing record @var{XX}. @var{YY} denotes the
  208. number of records in the file.
  209. X
  210. @item Stuck at record @var{XX}
  211. An internal error prevented a specific record from being retrieved.
  212. X
  213. @end table
  214. X
  215. @node Examples, Credits, Error Messages, Top
  216. @section Examples
  217. X
  218. The following example exploits most of the features of forms-mode.
  219. This example is included in the distribution as file @file{demo2}.
  220. X
  221. @example
  222. ;; demo2 -- demo forms-mode    -*- emacs-lisp -*-
  223. X
  224. ;; SCCS Status     : demo2    1.1.2
  225. ;; Author          : Johan Vromans
  226. ;; Created On      : 1989
  227. ;; Last Modified By: Johan Vromans
  228. ;; Last Modified On: Mon Jul  1 13:56:31 1991
  229. ;; Update Count    : 2
  230. ;; Status          : OK
  231. ;; 
  232. ;; This sample forms exploit most of the features of forms mode.
  233. X
  234. ;; Set the name of the data file.
  235. (setq forms-file "demo2.dat")
  236. X
  237. ;; Use 'forms-enumerate' to set field names and number thereof.
  238. (setq forms-number-of-fields
  239. X      (forms-enumerate
  240. X       '(arch-newsgroup            ; 1
  241. X     arch-volume            ; 2
  242. X     arch-issue            ; and ...
  243. X     arch-article            ; ... so
  244. X     arch-shortname            ; ... ... on
  245. X     arch-parts
  246. X     arch-from
  247. X     arch-longname
  248. X     arch-keywords
  249. X     arch-date
  250. X     arch-remarks)))
  251. X
  252. ;; The following functions are used by this form for layout purposes.
  253. ;;
  254. (defun arch-tocol (target &optional fill)
  255. X  "Produces a string to skip to column TARGET. Prepends newline if needed.
  256. The optional FILL should be a character, used to fill to the column."
  257. X  (if (null fill)
  258. X      (setq fill ? ))
  259. X  (if (< target (current-column))
  260. X      (concat "\n" (make-string target fill))
  261. X    (make-string (- target (current-column)) fill)))
  262. ;;
  263. (defun arch-rj (target field &optional fill) 
  264. X  "Produces a string to skip to column TARGET minus the width of field FIELD.
  265. Prepends newline if needed. The optional FILL should be a character,
  266. used to fill to the column."
  267. X  (arch-tocol (- target (length (nth field forms-fields))) fill))
  268. X
  269. ;; Record filters.
  270. ;; This example uses the (defun ...) method of defining.
  271. ;;
  272. (defun forms-new-record-filter (the-record)
  273. X  "Form a new record with some defaults."
  274. X  (aset the-record arch-from (user-full-name))
  275. X  (aset the-record arch-date (current-time-string))
  276. X  the-record                ; return it
  277. )
  278. X
  279. ;; The format list.
  280. (setq forms-format-list
  281. X     (list
  282. X       "====== Public Domain Software Archive ======\n\n"
  283. X       arch-shortname
  284. X       " - "            arch-longname
  285. X       "\n\n"
  286. X       "Article: "        arch-newsgroup
  287. X       "/"            arch-article
  288. X       " "
  289. X       '(arch-tocol 40)
  290. X       "Issue: "        arch-issue
  291. X       " "
  292. X       '(arch-rj 73 10)
  293. X       "Date: "            arch-date
  294. X       "\n\n"
  295. X       "Submitted by: "        arch-from
  296. X       "\n"
  297. X       '(arch-tocol 79 ?-)
  298. X       "\n"
  299. X       "Keywords: "        arch-keywords
  300. X       "\n\n"
  301. X       "Parts: "        arch-parts
  302. X       "\n\n====== Remarks ======\n\n"
  303. X       arch-remarks
  304. X     ))
  305. X
  306. ;; That's all, folks!
  307. @end example
  308. X
  309. @node Credits, Concept Index, Examples, Top
  310. @section Credits
  311. X
  312. Forms mode is developed by Johan Vromans @code{<jv@@mh.nl>} at Multihouse
  313. Reseach in the Netherlands. 
  314. X
  315. Harald Hanche-Olsen @code{<hanche@@imf.unit.no>} supplied the idea for
  316. the new record filter, and provided better replacements for some
  317. internal functions. 
  318. X
  319. Bugfixes and other useful suggestions were supplied by
  320. cwitty@@portia.stanford.edu, Jonathan I. Kamens, Ignatios Souvatzis and
  321. Harald Hanche-Olsen.
  322. X
  323. This documentation was slightly inspired by the documentation of ``rolo
  324. mode'' by Paul Davis at Schlumberger Cambridge Research
  325. @code{<davis%scrsu1%sdr.slb.com@@relay.cs.net>}.
  326. X
  327. None of this would have been possible without GNU Emacs of the Free
  328. Software Foundation. Thanks, Richard!
  329. X
  330. @node Concept Index, Variable Index, Credits, Top
  331. @unnumbered Concept Index
  332. @printindex cp
  333. X
  334. @node Variable Index, Function Index, Concept Index, Top
  335. @unnumbered Variable Index
  336. @printindex vr
  337. X
  338. @node Function Index, , Variable Index, Top
  339. @unnumbered Function Index
  340. @printindex fn
  341. X
  342. @contents
  343. @bye
  344. X
  345. @c Local Variables:
  346. @c eval: (headers)
  347. @c eval: (setq comment-start "@c  ")
  348. @c eval: (setq comment-start-skip "@c +")
  349. @c End:
  350. SHAR_EOF
  351. echo 'File forms.ti is complete' &&
  352. chmod 0444 forms.ti ||
  353. echo 'restore of forms.ti failed'
  354. Wc_c="`wc -c < 'forms.ti'`"
  355. test 28722 -eq "$Wc_c" ||
  356.     echo 'forms.ti: original size 28722, current size' "$Wc_c"
  357. rm -f _shar_wnt_.tmp
  358. fi
  359. # ============= forms.el ==============
  360. if test -f 'forms.el' -a X"$1" != X"-c"; then
  361.     echo 'x - skipping forms.el (File already exists)'
  362.     rm -f _shar_wnt_.tmp
  363. else
  364. > _shar_wnt_.tmp
  365. echo 'x - extracting forms.el (Text)'
  366. sed 's/^X//' << 'SHAR_EOF' > 'forms.el' &&
  367. ;;; forms.el -- Forms Mode - A GNU Emacs Major Mode
  368. ;;; SCCS Status     : @(#)@ forms    1.2.7
  369. ;;; Author          : Johan Vromans
  370. ;;; Created On      : 1989
  371. ;;; Last Modified By: Johan Vromans
  372. ;;; Last Modified On: Mon Jul  1 14:13:20 1991
  373. ;;; Update Count    : 15
  374. ;;; Status          : OK
  375. X
  376. ;;; This file is part of GNU Emacs.
  377. ;;; GNU Emacs is distributed in the hope that it will be useful,
  378. ;;; but WITHOUT ANY WARRANTY.  No author or distributor
  379. ;;; accepts responsibility to anyone for the consequences of using it
  380. ;;; or for whether it serves any particular purpose or works at all,
  381. ;;; unless he says so in writing.  Refer to the GNU Emacs General Public
  382. ;;; License for full details.
  383. X
  384. ;;; Everyone is granted permission to copy, modify and redistribute
  385. ;;; GNU Emacs, but only under the conditions described in the
  386. ;;; GNU Emacs General Public License.   A copy of this license is
  387. ;;; supposed to have been given to you along with GNU Emacs so you
  388. ;;; can know your rights and responsibilities. 
  389. ;;; If you don't have this copy, write to the Free Software
  390. ;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  391. ;;;
  392. X
  393. ;;; HISTORY 
  394. ;;; 1-Jul-1991        Johan Vromans    
  395. ;;;    Normalized error messages.
  396. ;;; 30-Jun-1991        Johan Vromans    
  397. ;;;    Add support for forms-modified-record-filter.
  398. ;;;    Allow the filter functions to be the name of a function.
  399. ;;;    Fix: parse--format used forms--dynamic-text destructively.
  400. ;;;    Internally optimized the forms-format-list.
  401. ;;;    Added support for debugging.
  402. ;;;    Stripped duplicate documentation.
  403. ;;;   
  404. ;;; 29-Jun-1991        Johan Vromans    
  405. ;;;    Add support for functions and lisp symbols in forms-format-list.
  406. ;;;    Add function forms-enumerate.
  407. X
  408. (provide 'forms-mode)
  409. X
  410. ;;; Visit a file using a form.
  411. ;;;
  412. ;;; === Naming conventions
  413. ;;;
  414. ;;; The names of all variables and functions start with 'form-'.
  415. ;;; Names which start with 'form--' are intended for internal use, and
  416. ;;; should *NOT* be used from the outside.
  417. ;;;
  418. ;;; All variables are buffer-local, to enable multiple forms visits 
  419. ;;; simultaneously.
  420. ;;; Variable 'forms--mode-setup' is local to *ALL* buffers, for it 
  421. ;;; controls if forms-mode has been enabled in a buffer.
  422. ;;;
  423. ;;; === How it works ===
  424. ;;;
  425. ;;; Forms mode means visiting a data file which is supposed to consist
  426. ;;; of records each containing a number of fields. The records are
  427. ;;; separated by a newline, the fields are separated by a user-defined
  428. ;;; field separater (default: TAB).
  429. ;;; When shown, a record is transferred to an emacs buffer and
  430. ;;; presented using a user-defined form. One record is shown at a
  431. ;;; time.
  432. ;;;
  433. ;;; Forms mode is a composite mode. It involves two files, and two
  434. ;;; buffers.
  435. ;;; The first file, called the control file, defines the name of the
  436. ;;; data file and the forms format. This file buffer will be used to
  437. ;;; present the forms.
  438. ;;; The second file holds the actual data. The buffer of this file
  439. ;;; will be buried, for it is never accessed directly.
  440. ;;;
  441. ;;; Forms mode is invoked using "forms-find-file control-file".
  442. ;;; Alternativily forms-find-file-other-window can be used.
  443. ;;;
  444. ;;; You may also visit the control file, and switch to forms mode by hand
  445. ;;; with M-x forms-mode .
  446. ;;;
  447. ;;; Automatic mode switching is supported, so you may use "find-file"
  448. ;;; if you specify "-*- forms -*-" in the first line of the control file.
  449. ;;; 
  450. ;;; The control file is visited, evaluated using
  451. ;;; eval-current-buffer, and should set at least the following
  452. ;;; variables:
  453. ;;;
  454. ;;;    forms-file            [string] the name of the data file.
  455. ;;;
  456. ;;;    forms-number-of-fields        [integer]
  457. ;;;            The number of fields in each record.
  458. ;;;
  459. ;;;    forms-format-list           [list]   formatting instructions.
  460. ;;;
  461. ;;; The forms-format-list should be a list, each element containing
  462. ;;;
  463. ;;;  - a string, e.g. "hello" (which is inserted \"as is\"),
  464. ;;;
  465. ;;;  - an integer, denoting a field number. The contents of the field
  466. ;;;    are inserted at this point.
  467. ;;;    The first field has number one.
  468. ;;;
  469. ;;;  - a function call, e.g. (insert "text"). This function call is 
  470. ;;;    dynamically evaluated and should return a string. It should *NOT*
  471. ;;;    have side-effects on the forms being constructed.
  472. ;;;    The current fields are available to the function in the variable
  473. ;;;    forms-fields, they should *NOT* be modified.
  474. ;;;
  475. ;;;  - a lisp symbol, that must evaluate to one of the above.
  476. ;;;
  477. ;;; Optional variables which may be set in the control file:
  478. ;;;
  479. ;;;    forms-field-sep                [string, default TAB]
  480. ;;;            The field separator used to separate the
  481. ;;;            fields in the data file. It may be a string.
  482. ;;;
  483. ;;;    forms-read-only                [bool, default nil]
  484. ;;;            't' means that the data file is visited read-only.
  485. ;;;            If no write access to the data file is
  486. ;;;            possible, read-only mode is enforced. 
  487. ;;;
  488. ;;;    forms-multi-line            [string, default "^K"]
  489. ;;;            If non-null the records of the data file may
  490. ;;;            contain fields which span multiple lines in
  491. ;;;            the form.
  492. ;;;            This variable denoted the separator character
  493. ;;;            to be used for this purpose. Upon display, all
  494. ;;;            occurrencies of this character are translated
  495. ;;;            to newlines. Upon storage they are translated
  496. ;;;            back to the separator.
  497. ;;;
  498. ;;;    forms-forms-scroll            [bool, default t]
  499. ;;;            If non-nil: redefine scroll-up/down to perform
  500. ;;;            forms-next/prev-field if in forms mode.
  501. ;;;
  502. ;;;    forms-forms-jump            [bool, default t]
  503. ;;;            If non-nil: redefine beginning/end-of-buffer
  504. ;;;            to performs forms-first/last-field if in
  505. ;;;            forms mode.
  506. ;;;
  507. ;;;    forms-new-record-filter            [symbol, no default]
  508. ;;;            If defined: this should be the name of a 
  509. ;;;            function that is called when a new
  510. ;;;            record is created. It can be used to fill in
  511. ;;;            the new record with default fields, for example.
  512. ;;;            Instead of the name of the function, it may
  513. ;;;            be the function itself.
  514. ;;;
  515. ;;;    forms-modified-record-filter        [symbol, no default]
  516. ;;;            If defined: this should be the name of a 
  517. ;;;            function that is called when a record has
  518. ;;;            been modified. It is called after the fields
  519. ;;;            are parsed. It can be used to register
  520. ;;;            modification dates, for example.
  521. ;;;            Instead of the name of the function, it may
  522. ;;;            be the function itself.
  523. ;;;
  524. ;;; After evaluating the control file, its buffer is cleared and used
  525. ;;; for further processing.
  526. ;;; The data file (as designated by "forms-file") is visited in a buffer
  527. ;;; (forms--file-buffer) which will not normally be shown.
  528. ;;; Great malfunctioning may be expected if this file/buffer is modified
  529. ;;; outside of this package while it's being visited!
  530. ;;;
  531. ;;; A record from the data file is transferred from the data file,
  532. ;;; split into fields (into forms--the-record-list), and displayed using
  533. ;;; the specs in forms-format-list.
  534. ;;; A format routine 'forms--format' is built upon startup to format 
  535. ;;; the records.
  536. ;;;
  537. ;;; When a form is changed the record is updated as soon as this form
  538. ;;; is left. The contents of the form are parsed using forms-format-list,
  539. ;;; and the fields which are deduced from the form are modified. So,
  540. ;;; fields not shown on the forms retain their origional values.
  541. ;;; The newly formed record and replaces the contents of the
  542. ;;; old record in forms--file-buffer.
  543. ;;; A parse routine 'forms--parser' is built upon startup to parse
  544. ;;; the records.
  545. ;;;
  546. ;;; Two exit functions exist: forms-exit (which saves) and forms-exit-no-save
  547. ;;; (which doesn't). However, if forms-exit-no-save is executed and the file
  548. ;;; buffer has been modified, emacs will ask questions.
  549. ;;;
  550. ;;; Other functions are:
  551. ;;;
  552. ;;;    paging (forward, backward) by record
  553. ;;;    jumping (first, last, random number)
  554. ;;;    searching
  555. ;;;    creating and deleting records
  556. ;;;    reverting the form (NOT the file buffer)
  557. ;;;    switching edit <-> view mode v.v.
  558. ;;;    jumping from field to field
  559. ;;;
  560. ;;; As an documented side-effect: jumping to the last record in the
  561. ;;; file (using forms-last-record) will adjust forms--total-records if
  562. ;;; needed.
  563. ;;;
  564. ;;; Commands and keymaps:
  565. ;;;
  566. ;;; A local keymap 'forms-mode-map' is used in the forms buffer.
  567. ;;; As conventional, this map can be accessed with C-c prefix.
  568. ;;; In read-only mode, the C-c prefix must be omitted.
  569. ;;;
  570. ;;; Default bindings:
  571. ;;;
  572. ;;;    \C-c    forms-mode-map
  573. ;;;    TAB    forms-next-field
  574. ;;;    SPC     forms-next-record
  575. ;;;    <    forms-first-record
  576. ;;;    >    forms-last-record
  577. ;;;    ?    describe-mode
  578. ;;;    d    forms-delete-record
  579. ;;;    e    forms-edit-mode
  580. ;;;    i    forms-insert-record
  581. ;;;    j    forms-jump-record
  582. ;;;    n    forms-next-record
  583. ;;;    p    forms-prev-record
  584. ;;;    q    forms-exit
  585. ;;;    s    forms-search
  586. ;;;    v    forms-view-mode
  587. ;;;    x    forms-exit-no-save
  588. ;;;    DEL    forms-prev-record
  589. ;;;
  590. ;;; Standard functions scroll-up, scroll-down, beginning-of-buffer and
  591. ;;; end-of-buffer are wrapped with re-definitions, which map them to
  592. ;;; next/prev record and first/last record.
  593. ;;; Buffer-local variables forms-forms-scroll and forms-forms-jump
  594. ;;; may be used to control these redefinitions.
  595. ;;;
  596. ;;; Function save-buffer is also wrapped to perform a sensible action.
  597. ;;; A revert-file-hook is defined to revert a forms to original.
  598. ;;;
  599. ;;; For convenience, TAB is always bound to forms-next-field, so you
  600. ;;; don't need the C-c prefix for this command.
  601. ;;;
  602. ;;; Global variables and constants
  603. X
  604. (defconst forms-version "1.2.7"
  605. X  "Version of forms-mode implementation")
  606. X
  607. (defvar forms-forms-scrolls t
  608. X  "If non-null: redefine scroll-up/down to be used with forms-mode.")
  609. X
  610. (defvar forms-forms-jumps t
  611. X  "If non-null: redefine beginning/end-of-buffer to be used with forms-mode.")
  612. X
  613. (defvar forms-mode-hooks nil
  614. X  "Hook functions to be run upon entering forms mode.")
  615. ;;;
  616. ;;; Mandatory variables - must be set by evaluating the control file
  617. X
  618. (defvar forms-file nil
  619. X  "Name of the file holding the data.")
  620. X
  621. (defvar forms-format-list nil
  622. X  "List of formatting specifications.")
  623. X
  624. (defvar forms-number-of-fields nil
  625. X  "Number of fields per record.")
  626. X
  627. ;;;
  628. ;;; Optional variables with default values
  629. X
  630. (defvar forms-field-sep "\t"
  631. X  "Field separator character (default TAB)")
  632. X
  633. (defvar forms-read-only nil
  634. X  "Read-only mode (defaults to the write access on the data file).")
  635. X
  636. (defvar forms-multi-line "\C-k"
  637. X  "Character to separate multi-line fields (default ^K)")
  638. X
  639. (defvar forms-forms-scroll t
  640. X  "Redefine scroll-up/down to perform forms-next/prev-record when in
  641. X forms mode.")
  642. X
  643. (defvar forms-forms-jump t
  644. X  "Redefine beginning/end-of-buffer to perform forms-first/last-record
  645. X when in forms mode.")
  646. X
  647. ;;;
  648. ;;; Internal variables.
  649. X
  650. (defvar forms--file-buffer nil
  651. X  "Buffer which holds the file data")
  652. X
  653. (defvar forms--total-records 0
  654. X  "Total number of records in the data file.")
  655. X
  656. (defvar forms--current-record 0
  657. X  "Number of the record currently on the screen.")
  658. X
  659. (defvar forms-mode-map nil        ; yes - this one is global
  660. X   "Keymap for form buffer.")
  661. X
  662. (defvar forms--markers nil
  663. X  "Field markers in the screen.")
  664. X
  665. (defvar forms--number-of-markers 0
  666. X  "Number of fields on screen.")
  667. X
  668. (defvar forms--the-record-list nil 
  669. X   "List of strings of the current record, as parsed from the file.")
  670. X
  671. (defvar forms--search-regexp nil
  672. X  "Last regexp used by forms-search.")
  673. X
  674. (defvar forms--format nil
  675. X  "Formatting routine.")
  676. X
  677. (defvar forms--parser nil
  678. X  "Forms parser routine.")
  679. X
  680. (defvar forms--mode-setup nil
  681. X  "Internal - keeps track of forms-mode being set-up.")
  682. (make-variable-buffer-local 'forms--mode-setup)
  683. X
  684. (defvar forms--new-record-filter nil
  685. X  "Internal - set if a new record filter has been defined.")
  686. X
  687. (defvar forms--modified-record-filter nil
  688. X  "Internal - set if a modified record filter has been defined.")
  689. X
  690. (defvar forms--dynamic-text nil
  691. X  "Internal - holds dynamic text to insert between fields.")
  692. X
  693. (defvar forms-fields nil
  694. X  "List with fields of the current forms. First field has number 1.")
  695. X
  696. ;;;
  697. ;;; forms-mode
  698. ;;;
  699. ;;; This is not a simple major mode, as usual. Therefore, forms-mode
  700. ;;; takes an optional argument 'primary' which is used for the initial
  701. ;;; set-up. Normal use would leave 'primary' to nil.
  702. ;;;
  703. ;;; A global buffer-local variable 'forms--mode-setup' has the same effect
  704. ;;; but makes it possible to auto-invoke forms-mode using find-file.
  705. ;;;
  706. ;;; Note: although it seems logical to have (make-local-variable) executed
  707. ;;; where the variable is first needed, I deliberately placed all calls
  708. ;;; in the forms-mode function.
  709. (defun forms-mode (&optional primary)
  710. X  "Major mode to visit files in a field-structured manner using a form.
  711. X
  712. X Commands (prefix with C-c if not in read-only mode):
  713. X \\{forms-mode-map}"
  714. X
  715. X  (interactive)                ; no - 'primary' is not prefix arg
  716. X
  717. X  ;; Primary set-up: evaluate buffer and check if the mandatory
  718. X  ;; variables have been set.
  719. X  (if (or primary (not forms--mode-setup))
  720. X      (progn
  721. X    (kill-all-local-variables)
  722. X
  723. X    ;; make mandatory variables
  724. X    (make-local-variable 'forms-file)
  725. X    (make-local-variable 'forms-number-of-fields)
  726. X    (make-local-variable 'forms-format-list)
  727. X
  728. X    ;; make optional variables
  729. X    (make-local-variable 'forms-field-sep)
  730. X        (make-local-variable 'forms-read-only)
  731. X        (make-local-variable 'forms-multi-line)
  732. X    (make-local-variable 'forms-forms-scroll)
  733. X    (make-local-variable 'forms-forms-jump)
  734. X    (fmakunbound 'forms-new-record-filter)
  735. X
  736. X    ;; eval the buffer, should set variables
  737. X    (eval-current-buffer)
  738. X
  739. X    ;; check if the mandatory variables make sense.
  740. X    (or forms-file
  741. X        (error "'forms-file' has not been set"))
  742. X    (or forms-number-of-fields
  743. X        (error "'forms-number-of-fields' has not been set"))
  744. X    (or (> forms-number-of-fields 0)
  745. X        (error "'forms-number-of-fields' must be > 0")
  746. X    (or (stringp forms-field-sep))
  747. X        (error "'forms-field-sep' is not a string"))
  748. X    (if forms-multi-line
  749. X        (if (and (stringp forms-multi-line)
  750. X             (eq (length forms-multi-line) 1))
  751. X        (if (string= forms-multi-line forms-field-sep)
  752. X            (error "'forms-multi-line' is equal to 'forms-field-sep'"))
  753. X          (error "'forms-multi-line' must be nil or a one-character string")))
  754. X        
  755. X    ;; validate and process forms-format-list
  756. X    (make-local-variable 'forms--number-of-markers)
  757. X    (make-local-variable 'forms--markers)
  758. X    (forms--process-format-list)
  759. X
  760. X    ;; build the formatter and parser
  761. X    (make-local-variable 'forms--format)
  762. X    (forms--make-format)
  763. X    (make-local-variable 'forms--parser)
  764. X    (forms--make-parser)
  765. X
  766. X    ;; check if record filters are defined
  767. X    (make-local-variable 'forms--new-record-filter)
  768. X    (setq forms--new-record-filter 
  769. X          (cond
  770. X           ((fboundp 'forms-new-record-filter)
  771. X        (symbol-function 'forms-new-record-filter))
  772. X           ((and (boundp 'forms-new-record-filter)
  773. X             (fboundp forms-new-record-filter))
  774. X        forms-new-record-filter)))
  775. X    (fmakunbound 'forms-new-record-filter)
  776. X    (make-local-variable 'forms--modified-record-filter)
  777. X    (setq forms--modified-record-filter 
  778. X          (cond
  779. X           ((fboundp 'forms-modified-record-filter)
  780. X        (symbol-function 'forms-modified-record-filter))
  781. X           ((and (boundp 'forms-modified-record-filter)
  782. X             (fboundp forms-modified-record-filter))
  783. X        forms-modified-record-filter)))
  784. X    (fmakunbound 'forms-modified-record-filter)
  785. X
  786. X    ;; dynamic text support
  787. X    (make-local-variable 'forms--dynamic-text)
  788. X    (make-local-variable 'forms-fields)
  789. X
  790. X    ;; prepare this buffer for further processing
  791. X    (setq buffer-read-only nil)
  792. X
  793. X    ;; prevent accidental overwrite of the control file and autosave
  794. X    (setq buffer-file-name nil)
  795. X    (auto-save-mode nil)
  796. X
  797. X    ;; and clean it
  798. X    (erase-buffer)))
  799. X
  800. X  ;; make local variables
  801. X  (make-local-variable 'forms--file-buffer)
  802. X  (make-local-variable 'forms--total-records)
  803. X  (make-local-variable 'forms--current-record)
  804. X  (make-local-variable 'forms--the-record-list)
  805. X  (make-local-variable 'forms--search-rexexp)
  806. X
  807. X  ;; A bug in the current Emacs release prevents a keymap
  808. X  ;; which is buffer-local from being used by 'describe-mode'.
  809. X  ;; Hence we'll leave it global.
  810. X  ;;(make-local-variable 'forms-mode-map)
  811. X  (if forms-mode-map            ; already defined
  812. X      nil
  813. X    (setq forms-mode-map (make-keymap))
  814. X    (forms--mode-commands forms-mode-map)
  815. X    (forms--change-commands))
  816. X
  817. X  ;; find the data file
  818. X  (setq forms--file-buffer (find-file-noselect forms-file))
  819. X
  820. X  ;; count the number of records, and set see if it may be modified
  821. X  (let (ro)
  822. X    (setq forms--total-records
  823. X      (save-excursion
  824. X        (set-buffer forms--file-buffer)
  825. X        (bury-buffer (current-buffer))
  826. X        (setq ro buffer-read-only)
  827. X        (count-lines (point-min) (point-max))))
  828. X    (if ro
  829. X    (setq forms-read-only t)))
  830. X
  831. X  ;; set the major mode indicator
  832. X  (setq major-mode 'forms-mode)
  833. X  (setq mode-name "Forms")
  834. X  (make-local-variable 'minor-mode-alist) ; needed?
  835. X  (forms--set-minor-mode)
  836. X  (forms--set-keymaps)
  837. X
  838. X  (set-buffer-modified-p nil)
  839. X
  840. X  ;; We have our own revert function - use it
  841. X  (make-local-variable 'revert-buffer-function)
  842. X  (setq revert-buffer-function 'forms-revert-buffer)
  843. X
  844. X  ;; setup the first (or current) record to show
  845. X  (if (< forms--current-record 1)
  846. X      (setq forms--current-record 1))
  847. X  (forms-jump-record forms--current-record)
  848. X
  849. X  ;; user customising
  850. X  (run-hooks 'forms-mode-hooks)
  851. X
  852. X  ;; be helpful
  853. X  (forms--help)
  854. X
  855. X  ;; initialization done
  856. X  (setq forms--mode-setup t))
  857. X
  858. ;;;
  859. ;;; forms-process-format-list
  860. ;;;
  861. ;;; Validates forms-format-list.
  862. ;;;
  863. ;;; Sets forms--number-of-markers and forms--markers.
  864. X
  865. (defun forms--process-format-list ()
  866. X  "Validate forms-format-list and set some global variables."
  867. X
  868. X  (forms--debug "forms-forms-list before 1st pass:\n"
  869. X        'forms-format-list)
  870. X
  871. X  ;; it must be non-nil
  872. X  (or forms-format-list
  873. X      (error "'forms-format-list' has not been set"))
  874. X  ;; it must be a list ...
  875. X  (or (listp forms-format-list)
  876. X      (error "'forms-format-list' is not a list"))
  877. X
  878. X  (setq forms--number-of-markers 0)
  879. X
  880. X  (let ((the-list forms-format-list)    ; the list of format elements
  881. X    (this-item 0)            ; element in list
  882. X    (field-num 0))            ; highest field number 
  883. X
  884. X    (setq forms-format-list nil)    ; gonna rebuild
  885. X
  886. X    (while the-list
  887. X
  888. X      (let ((el (car-safe the-list))
  889. X        (rem (cdr-safe the-list)))
  890. X
  891. X    ;; if it is a symbol, eval it first
  892. X    (if (and (symbolp el)
  893. X         (boundp el))
  894. X        (setq el (eval el)))
  895. X
  896. X    (cond
  897. X
  898. X     ;; try string ...
  899. X     ((stringp el))            ; string is OK
  900. X      
  901. X     ;; try numeric ...
  902. X     ((numberp el) 
  903. X
  904. X      (if (or (<= el 0)
  905. X          (> el forms-number-of-fields))
  906. X          (error
  907. X           "Forms error: field number %d out of range 1..%d"
  908. X           el forms-number-of-fields))
  909. X
  910. X      (setq forms--number-of-markers (1+ forms--number-of-markers))
  911. X      (if (> el field-num)
  912. X          (setq field-num el)))
  913. X
  914. X     ;; try function
  915. X     ((listp el)
  916. X      (or (fboundp (car-safe el))
  917. X          (error 
  918. X           "Forms error: not a function: %s"
  919. X           (prin1-to-string (car-safe el)))))
  920. X
  921. X     ;; else
  922. X     (t
  923. X      (error "Invalid element in 'forms-format-list': %s"
  924. X         (prin1-to-string el))))
  925. X
  926. X    ;; advance to next element of the list
  927. X    (setq the-list rem)
  928. X    (setq forms-format-list
  929. X          (append forms-format-list (list el) nil)))))
  930. X
  931. X  (forms--debug "forms-forms-list after 1st pass:\n"
  932. X        'forms-format-list)
  933. X
  934. X  ;; concat adjacent strings
  935. X  (setq forms-format-list (forms--concat-adjacent forms-format-list))
  936. X
  937. X  (forms--debug "forms-forms-list after 2nd pass:\n"
  938. X        'forms-format-list
  939. X        'forms--number-of-markers)
  940. SHAR_EOF
  941. true || echo 'restore of forms.el failed'
  942. fi
  943. echo 'End of forms part 2'
  944. echo 'File forms.el is continued in part 3'
  945. echo 3 > _shar_seq_.tmp
  946. exit 0
  947. -- 
  948. Johan Vromans                       jv@mh.nl via internet backbones
  949. Multihouse Automatisering bv               uucp: ..!{uunet,hp4nl}!mh.nl!jv
  950. Doesburgweg 7, 2803 PL Gouda, The Netherlands  phone/fax: +31 1820 62911/62500
  951. ------------------------ "Arms are made for hugging" -------------------------
  952.