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

  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 3 of 3)
  4. Message-ID: <1991Jul1.132302.10708@pronto.mh.nl>
  5. Date: 1 Jul 91 13:23:02 GMT
  6.  
  7.  
  8. Submitted-by: jv@mh.nl
  9. Archive-name: forms/part03
  10.  
  11. ---- Cut Here and feed the following to sh ----
  12. #!/bin/sh
  13. # this is forms.shr.03 (part 3 of forms)
  14. # do not concatenate these parts, unpack them in order with /bin/sh
  15. # file forms.el 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" != 3; 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.el'
  31. else
  32. echo 'x - continuing file forms.el'
  33. sed 's/^X//' << 'SHAR_EOF' >> 'forms.el' &&
  34. X
  35. X  (setq forms--markers (make-vector forms--number-of-markers nil)))
  36. X
  37. X
  38. ;;;
  39. ;;; Build the format routine from forms-format-list.
  40. ;;;
  41. ;;; The format routine (forms--format) will look like
  42. ;;; 
  43. ;;; (lambda (arg)
  44. ;;;   (setq forms--dynamic-text nil)
  45. ;;;   ;;  "text: "
  46. ;;;   (insert "text: ")
  47. ;;;   ;;  6
  48. ;;;   (aset forms--markers 0 (point-marker))
  49. ;;;   (insert (elt arg 5))
  50. ;;;   ;;  "\nmore text: "
  51. ;;;   (insert "\nmore text: ")
  52. ;;;   ;;  (tocol 40)
  53. ;;;   (let ((the-dyntext (tocol 40)))
  54. ;;;     (insert the-dyntext)
  55. ;;;     (setq forms--dynamic-text (append forms--dynamic-text
  56. ;;;                      (list the-dyntext))))
  57. ;;;   ;;  9
  58. ;;;   (aset forms--markers 1 (point-marker))
  59. ;;;   (insert (elt arg 8))
  60. ;;;
  61. ;;;   ... )
  62. ;;; 
  63. X
  64. (defun forms--make-format ()
  65. X  "Generate format function for forms"
  66. X  (setq forms--format (forms--format-maker forms-format-list))
  67. X  (forms--debug 'forms--format))
  68. X
  69. (defun forms--format-maker (the-format-list)
  70. X  "Returns the parser function for forms"
  71. X  (let ((the-marker 0))
  72. X    (` (lambda (arg)
  73. X     (setq forms--dynamic-text nil)
  74. X     (,@ (apply 'append
  75. X            (mapcar 'forms--make-format-elt the-format-list)))))))
  76. X
  77. (defun forms--make-format-elt (el)
  78. X  (cond ((stringp el)
  79. X     (` ((insert (, el)))))
  80. X    ((numberp el)
  81. X     (prog1
  82. X         (` ((aset forms--markers (, the-marker) (point-marker))
  83. X         (insert (elt arg (, (1- el))))))
  84. X       (setq the-marker (1+ the-marker))))
  85. X    ((listp el)
  86. X     (prog1
  87. X         (` ((let ((the-dyntext (, el)))
  88. X           (insert the-dyntext)
  89. X           (setq forms--dynamic-text (append forms--dynamic-text
  90. X                             (list the-dyntext)))))
  91. X        )))
  92. X    ))
  93. X
  94. X
  95. (defun forms--concat-adjacent (the-list)
  96. X  "Concatenate adjacent strings in the-list and return the resulting list"
  97. X  (if (consp the-list)
  98. X      (let ((the-rest (forms--concat-adjacent (cdr the-list))))
  99. X    (if (and (stringp (car the-list)) (stringp (car the-rest)))
  100. X        (cons (concat (car the-list) (car the-rest))
  101. X          (cdr the-rest))
  102. X        (cons (car the-list) the-rest)))
  103. X      the-list))
  104. ;;;
  105. ;;; forms--make-parser.
  106. ;;;
  107. ;;; Generate parse routine from forms-format-list.
  108. ;;;
  109. ;;; The parse routine (forms--parser) will look like (give or take
  110. ;;; a few " " .
  111. ;;; 
  112. ;;; (lambda nil
  113. ;;;   (let (here)
  114. ;;;     (goto-char (point-min))
  115. ;;; 
  116. ;;;    ;;  "text: "
  117. ;;;     (if (not (looking-at "text: "))
  118. ;;;         (error "Parse error: cannot find \"text: \""))
  119. ;;;     (forward-char 6)    ; past "text: "
  120. ;;; 
  121. ;;;     ;;  6
  122. ;;;    ;;  "\nmore text: "
  123. ;;;     (setq here (point))
  124. ;;;     (if (not (search-forward "\nmore text: " nil t nil))
  125. ;;;         (error "Parse error: cannot find \"\\nmore text: \""))
  126. ;;;     (aset the-recordv 5 (buffer-substring here (- (point) 12)))
  127. ;;;
  128. ;;;    ;;  (tocol 40)
  129. ;;;    (let ((the-dyntext (car-safe forms--dynamic-text)))
  130. ;;;      (if (not (looking-at (regexp-quote the-dyntext)))
  131. ;;;          (error "Parse error: not looking at \"%s\"" the-dyntext))
  132. ;;;      (forward-char (length the-dyntext))
  133. ;;;      (setq forms--dynamic-text (cdr-safe forms--dynamic-text)))
  134. ;;;     ... 
  135. ;;;     ;; final flush (due to terminator sentinel, see below)
  136. ;;;    (aset the-recordv 7 (buffer-substring (point) (point-max)))
  137. ;;; 
  138. X
  139. (defun forms--make-parser ()
  140. X  "Generate parser function for forms"
  141. X  (setq forms--parser (forms--parser-maker forms-format-list))
  142. X  (forms--debug 'forms--parser))
  143. X
  144. (defun forms--parser-maker (the-format-list)
  145. X  "Returns the parser function for forms"
  146. X  (let ((the-field nil)
  147. X    (seen-text nil)
  148. X    the--format-list)
  149. X    ;; add a terminator sentinel
  150. X    (setq the--format-list (append the-format-list (list nil)))
  151. X    (` (lambda nil
  152. X     (let (here)
  153. X       (goto-char (point-min))
  154. X     (,@ (apply 'append
  155. X            (mapcar 'forms--make-parser-elt the--format-list))))))))
  156. X
  157. (defun forms--make-parser-elt (el)
  158. X  (cond
  159. X   ((stringp el)
  160. X    (prog1
  161. X    (if the-field
  162. X        (` ((setq here (point))
  163. X        (if (not (search-forward (, el) nil t nil))
  164. X            (error "Parse error: cannot find \"%s\"" (, el)))
  165. X        (aset the-recordv (, (1- the-field))
  166. X              (buffer-substring here
  167. X                    (- (point) (, (length el)))))))
  168. X      (` ((if (not (looking-at (, (regexp-quote el))))
  169. X          (error "Parse error: not looking at \"%s\"" (, el)))
  170. X          (forward-char (, (length el))))))
  171. X      (setq seen-text t)
  172. X      (setq the-field nil)))
  173. X   ((numberp el)
  174. X    (if the-field
  175. X    (error "Cannot parse adjacent fields %d and %d"
  176. X           the-field el)
  177. X      (setq the-field el)
  178. X      nil))
  179. X   ((null el)
  180. X    (if the-field
  181. X    (` ((aset the-recordv (, (1- the-field))
  182. X          (buffer-substring (point) (point-max)))))))
  183. X   ((listp el)
  184. X    (prog1
  185. X    (if the-field
  186. X        (` ((let ((here (point))
  187. X              (the-dyntext (car-safe forms--dynamic-text)))
  188. X          (if (not (search-forward the-dyntext nil t nil))
  189. X              (error "Parse error: cannot find \"%s\"" the-dyntext))
  190. X          (aset the-recordv (, (1- the-field))
  191. X            (buffer-substring here
  192. X                      (- (point) (length the-dyntext))))
  193. X          (setq forms--dynamic-text (cdr-safe forms--dynamic-text)))))
  194. X      (` ((let ((the-dyntext (car-safe forms--dynamic-text)))
  195. X        (if (not (looking-at (regexp-quote the-dyntext)))
  196. X            (error "Parse error: not looking at \"%s\"" the-dyntext))
  197. X        (forward-char (length the-dyntext))
  198. X        (setq forms--dynamic-text (cdr-safe forms--dynamic-text))))))
  199. X      (setq seen-text t)
  200. X      (setq the-field nil)))
  201. X   ))
  202. ;;;
  203. X
  204. (defun forms--set-minor-mode ()
  205. X  (setq minor-mode-alist
  206. X    (if forms-read-only
  207. X        " View"
  208. X      nil)))
  209. X
  210. (defun forms--set-keymaps ()
  211. X  "Set the keymaps used in this mode."
  212. X
  213. X  (if forms-read-only
  214. X      (use-local-map forms-mode-map)
  215. X    (use-local-map (make-sparse-keymap))
  216. X    (define-key (current-local-map) "\C-c" forms-mode-map)
  217. X    (define-key (current-local-map) "\t"   'forms-next-field)))
  218. X
  219. (defun forms--mode-commands (map)
  220. X  "Fill map with all commands."
  221. X  (define-key map "\t" 'forms-next-field)
  222. X  (define-key map " " 'forms-next-record)
  223. X  (define-key map "d" 'forms-delete-record)
  224. X  (define-key map "e" 'forms-edit-mode)
  225. X  (define-key map "i" 'forms-insert-record)
  226. X  (define-key map "j" 'forms-jump-record)
  227. X  (define-key map "n" 'forms-next-record)
  228. X  (define-key map "p" 'forms-prev-record)
  229. X  (define-key map "q" 'forms-exit)
  230. X  (define-key map "s" 'forms-search)
  231. X  (define-key map "v" 'forms-view-mode)
  232. X  (define-key map "x" 'forms-exit-no-save)
  233. X  (define-key map "<" 'forms-first-record)
  234. X  (define-key map ">" 'forms-last-record)
  235. X  (define-key map "?" 'describe-mode)
  236. X  (define-key map "\177" 'forms-prev-record)
  237. X ;  (define-key map "\C-c" map)
  238. X  (define-key map "\e" 'ESC-prefix)
  239. X  (define-key map "\C-x" ctl-x-map)
  240. X  (define-key map "\C-u" 'universal-argument)
  241. X  (define-key map "\C-h" help-map)
  242. X  )
  243. ;;;
  244. ;;; Changed functions
  245. ;;;
  246. ;;; Emacs (as of 18.55) lacks the functionality of buffer-local
  247. ;;; funtions. Therefore we save the original meaning of some handy
  248. ;;; functions, and replace them with a wrapper.
  249. X
  250. (defun forms--change-commands ()
  251. X  "Localize some commands."
  252. X  ;;
  253. X  ;; scroll-down -> forms-prev-record
  254. X  ;;
  255. X  (if (fboundp 'forms--scroll-down)
  256. X      nil
  257. X    (fset 'forms--scroll-down (symbol-function 'scroll-down))
  258. X    (fset 'scroll-down
  259. X      '(lambda (&optional arg) 
  260. X         (interactive "P")
  261. X         (if (and forms--mode-setup
  262. X              forms-forms-scroll)
  263. X         (forms-prev-record arg)
  264. X           (forms--scroll-down arg)))))
  265. X  ;;
  266. X  ;; scroll-up -> forms-next-record
  267. X  ;;
  268. X  (if (fboundp 'forms--scroll-up)
  269. X      nil
  270. X    (fset 'forms--scroll-up   (symbol-function 'scroll-up))
  271. X    (fset 'scroll-up
  272. X      '(lambda (&optional arg) 
  273. X         (interactive "P")
  274. X         (if (and forms--mode-setup
  275. X              forms-forms-scroll)
  276. X         (forms-next-record arg)
  277. X           (forms--scroll-up arg)))))
  278. X  ;;
  279. X  ;; beginning-of-buffer -> forms-first-record
  280. X  ;;
  281. X  (if (fboundp 'forms--beginning-of-buffer)
  282. X      nil
  283. X    (fset 'forms--beginning-of-buffer (symbol-function 'beginning-of-buffer))
  284. X    (fset 'beginning-of-buffer
  285. X      '(lambda ()
  286. X         (interactive)
  287. X         (if (and forms--mode-setup
  288. X              forms-forms-jump)
  289. X         (forms-first-record)
  290. X           (forms--beginning-of-buffer)))))
  291. X  ;;
  292. X  ;; end-of-buffer -> forms-end-record
  293. X  ;;
  294. X  (if (fboundp 'forms--end-of-buffer)
  295. X      nil
  296. X    (fset 'forms--end-of-buffer (symbol-function 'end-of-buffer))
  297. X    (fset 'end-of-buffer
  298. X      '(lambda ()
  299. X         (interactive)
  300. X         (if (and forms--mode-setup
  301. X              forms-forms-jump)
  302. X         (forms-last-record)
  303. X           (forms--end-of-buffer)))))
  304. X  ;;
  305. X  ;; save-buffer -> forms--save-buffer
  306. X  ;;
  307. X  (if (fboundp 'forms--save-buffer)
  308. X      nil
  309. X    (fset 'forms--save-buffer (symbol-function 'save-buffer))
  310. X    (fset 'save-buffer
  311. X      '(lambda (&optional arg)
  312. X         (interactive "p")
  313. X         (if forms--mode-setup
  314. X         (progn
  315. X           (forms--checkmod)
  316. X           (save-excursion
  317. X             (set-buffer forms--file-buffer)
  318. X             (forms--save-buffer arg)))
  319. X           (forms--save-buffer arg)))))
  320. X  ;;
  321. X  )
  322. X
  323. (defun forms--help ()
  324. X  "Initial help."
  325. X  ;; We should use
  326. X  ;;(message (substitute-command-keys (concat
  327. X  ;;"\\[forms-next-record]:next"
  328. X  ;;"   \\[forms-prev-record]:prev"
  329. X  ;;"   \\[forms-first-record]:first"
  330. X  ;;"   \\[forms-last-record]:last"
  331. X  ;;"   \\[describe-mode]:help"
  332. X  ;;"   \\[forms-exit]:exit")))
  333. X  ;; but it's too slow ....
  334. X  (if forms-read-only
  335. X      (message "SPC:next   DEL:prev   <:first   >:last   ?:help   q:exit")
  336. X    (message "C-c n:next   C-c p:prev   C-c <:first   C-c >:last   C-c ?:help   C-c q:exit")))
  337. X
  338. (defun forms--trans (subj arg rep)
  339. X  "Translate in SUBJ all chars ARG into char REP. ARG and REP should
  340. X be single-char strings."
  341. X  (let ((i 0)
  342. X    (x (length subj))
  343. X    (re (regexp-quote arg))
  344. X    (k (string-to-char rep)))
  345. X    (while (setq i (string-match re subj i))
  346. X      (aset subj i k)
  347. X      (setq i (1+ i)))))
  348. X
  349. (defun forms--exit (query &optional save)
  350. X  (let ((buf (buffer-name forms--file-buffer)))
  351. X    (forms--checkmod)
  352. X    (if (and save
  353. X         (buffer-modified-p forms--file-buffer))
  354. X    (save-excursion
  355. X      (set-buffer forms--file-buffer)
  356. X      (save-buffer)))
  357. X    (save-excursion
  358. X      (set-buffer forms--file-buffer)
  359. X      (delete-auto-save-file-if-necessary)
  360. X      (kill-buffer (current-buffer)))
  361. X    (if (get-buffer buf)    ; not killed???
  362. X      (if save
  363. X      (progn
  364. X        (beep)
  365. X        (message "Problem saving buffers?")))
  366. X      (delete-auto-save-file-if-necessary)
  367. X      (kill-buffer (current-buffer)))))
  368. X
  369. (defun forms--get-record ()
  370. X  "Fetch the current record from the file buffer."
  371. X  ;;
  372. X  ;; This function is executed in the context of the forms--file-buffer.
  373. X  ;;
  374. X  (or (bolp)
  375. X      (beginning-of-line nil))
  376. X  (let ((here (point)))
  377. X    (prog2
  378. X     (end-of-line)
  379. X     (buffer-substring here (point))
  380. X     (goto-char here))))
  381. X
  382. (defun forms--show-record (the-record)
  383. X  "Format THE-RECORD according to forms-format-list,
  384. X and display it in the current buffer."
  385. X
  386. X  ;; split the-record
  387. X  (let (the-result
  388. X    (start-pos 0)
  389. X    found-pos
  390. X    (field-sep-length (length forms-field-sep)))
  391. X    (if forms-multi-line
  392. X    (forms--trans the-record forms-multi-line "\n"))
  393. X    ;; add an extra separator (makes splitting easy)
  394. X    (setq the-record (concat the-record forms-field-sep))
  395. X    (while (setq found-pos (string-match forms-field-sep the-record start-pos))
  396. X      (let ((ent (substring the-record start-pos found-pos)))
  397. X    (setq the-result
  398. X          (append the-result (list ent)))
  399. X    (setq start-pos (+ field-sep-length found-pos))))
  400. X    (setq forms--the-record-list the-result))
  401. X
  402. X  (setq buffer-read-only nil)
  403. X  (erase-buffer)
  404. X
  405. X  ;; verify the number of fields, extend forms--the-record-list if needed
  406. X  (if (= (length forms--the-record-list) forms-number-of-fields)
  407. X      nil
  408. X    (beep)
  409. X    (message "Record has %d fields instead of %d."
  410. X         (length forms--the-record-list) forms-number-of-fields)
  411. X    (if (< (length forms--the-record-list) forms-number-of-fields)
  412. X    (setq forms--the-record-list 
  413. X          (append forms--the-record-list
  414. X              (make-list 
  415. X               (- forms-number-of-fields 
  416. X              (length forms--the-record-list))
  417. X               "")))))
  418. X
  419. X  ;; call the formatter function
  420. X  (setq forms-fields (append (list nil) forms--the-record-list nil))
  421. X  (funcall forms--format forms--the-record-list)
  422. X
  423. X  ;; prepare
  424. X  (goto-char (point-min))
  425. X  (set-buffer-modified-p nil)
  426. X  (setq buffer-read-only forms-read-only)
  427. X  (setq mode-line-process
  428. X    (concat " " forms--current-record "/" forms--total-records)))
  429. X
  430. (defun forms--parse-form ()
  431. X  "Parse contents of form into list of strings."
  432. X  ;; The contents of the form are parsed, and a new list of strings
  433. X  ;; is constructed.
  434. X  ;; A vector with the strings from the original record is 
  435. X  ;; constructed, which is updated with the new contents. Therefore
  436. X  ;; fields which were not in the form are not modified.
  437. X  ;; Finally, the vector is transformed into a list for further processing.
  438. X
  439. X  (let (the-recordv)
  440. X
  441. X    ;; build the vector
  442. X    (setq the-recordv (vconcat forms--the-record-list))
  443. X
  444. X    ;; parse the form and update the vector
  445. X    (let ((forms--dynamic-text forms--dynamic-text))
  446. X      (funcall forms--parser))
  447. X
  448. X    (if forms--modified-record-filter
  449. X    ;; As a service to the user, we add a zeroth element so she
  450. X    ;; can use the same indices as in the forms definition.
  451. X    (let ((the-fields (vconcat [nil] the-recordv)))
  452. X      (setq the-fields (funcall forms--modified-record-filter the-fields))
  453. X      (cdr (append the-fields nil)))
  454. X
  455. X      ;; transform to a list and return
  456. X      (append the-recordv nil))))
  457. X
  458. (defun forms--update ()
  459. X  "Update current record with contents of form. As a side effect: sets
  460. forms--the-record-list ."
  461. X  (if forms-read-only
  462. X      (progn
  463. X    (message "Read-only buffer!")
  464. X    (beep))
  465. X
  466. X    (let (the-record)
  467. X      ;; build new record
  468. X      (setq forms--the-record-list (forms--parse-form))
  469. X      (setq the-record
  470. X        (mapconcat 'identity forms--the-record-list forms-field-sep))
  471. X
  472. X      ;; handle multi-line fields, if allowed
  473. X      (if forms-multi-line
  474. X      (forms--trans the-record "\n" forms-multi-line))
  475. X
  476. X      ;; a final sanity check before updating
  477. X      (if (string-match "\n" the-record)
  478. X      (progn
  479. X        (message "Multi-line fields in this record - update refused!")
  480. X        (beep))
  481. X
  482. X    (save-excursion
  483. X      (set-buffer forms--file-buffer)
  484. X      ;; Insert something before kill-line is called. See kill-line
  485. X      ;; doc. Bugfix provided by Ignatios Souvatzis.
  486. X      (insert "*")
  487. X      (beginning-of-line)
  488. X      (kill-line nil)
  489. X      (insert the-record)
  490. X      (beginning-of-line))))))
  491. X
  492. (defun forms--checkmod ()
  493. X  "Check if this form has been modified, and call forms--update if so."
  494. X  (if (buffer-modified-p nil)
  495. X      (let ((here (point)))
  496. X    (forms--update)
  497. X    (set-buffer-modified-p nil)
  498. X    (goto-char here))))
  499. X
  500. ;;;
  501. ;;; Start and exit
  502. (defun forms-find-file (fn)
  503. X  "Visit file FN in forms mode"
  504. X  (interactive "fForms file: ")
  505. X  (find-file-read-only fn)
  506. X  (or forms--mode-setup (forms-mode t)))
  507. X
  508. (defun forms-find-file-other-window (fn)
  509. X  "Visit file FN in form mode in other window"
  510. X  (interactive "fFbrowse file in other window: ")
  511. X  (find-file-other-window fn)
  512. X  (eval-current-buffer)
  513. X  (or forms--mode-setup (forms-mode t)))
  514. X
  515. (defun forms-exit (query)
  516. X  "Normal exit. Modified buffers are saved."
  517. X  (interactive "P")
  518. X  (forms--exit query t))
  519. X
  520. (defun forms-exit-no-save (query)
  521. X  "Exit without saving buffers."
  522. X  (interactive "P")
  523. X  (forms--exit query nil))
  524. X
  525. ;;;
  526. ;;; Navigating commands
  527. X
  528. (defun forms-next-record (arg)
  529. X  "Advance to the ARGth following record."
  530. X  (interactive "P")
  531. X  (forms-jump-record (+ forms--current-record (prefix-numeric-value arg)) t))
  532. X
  533. (defun forms-prev-record (arg)
  534. X  "Advance to the ARGth previous record."
  535. X  (interactive "P")
  536. X  (forms-jump-record (- forms--current-record (prefix-numeric-value arg)) t))
  537. X
  538. (defun forms-jump-record (arg &optional relative)
  539. X  "Jump to a random record."
  540. X  (interactive "NRecord number: ")
  541. X
  542. X  ;; verify that the record number is within range
  543. X  (if (or (> arg forms--total-records)
  544. X      (<= arg 0))
  545. X    (progn
  546. X      (beep)
  547. X      ;; don't give the message if just paging
  548. X      (if (not relative)
  549. X      (message "Record number %d out of range 1..%d"
  550. X           arg forms--total-records))
  551. X      )
  552. X
  553. X    ;; flush
  554. X    (forms--checkmod)
  555. X
  556. X    ;; calculate displacement
  557. X    (let ((disp (- arg forms--current-record))
  558. X      (cur forms--current-record))
  559. X
  560. X      ;; forms--show-record needs it now
  561. X      (setq forms--current-record arg)
  562. X
  563. X      ;; get the record and show it
  564. X      (forms--show-record
  565. X       (save-excursion
  566. X     (set-buffer forms--file-buffer)
  567. X     (beginning-of-line)
  568. X
  569. X     ;; move, and adjust the amount if needed (shouldn't happen)
  570. X     (if relative
  571. X         (if (zerop disp)
  572. X         nil
  573. X           (setq cur (+ cur disp (- (forward-line disp)))))
  574. X       (setq cur (+ cur disp (- (goto-line arg)))))
  575. X
  576. X     (forms--get-record)))
  577. X
  578. X      ;; this shouldn't happen
  579. X      (if (/= forms--current-record cur)
  580. X      (progn
  581. X        (setq forms--current-record cur)
  582. X        (beep)
  583. X        (message "Stuck at record %d." cur))))))
  584. X
  585. (defun forms-first-record ()
  586. X  "Jump to first record."
  587. X  (interactive)
  588. X  (forms-jump-record 1))
  589. X
  590. (defun forms-last-record ()
  591. X  "Jump to last record. As a side effect: re-calculates the number
  592. X of records in the data file."
  593. X  (interactive)
  594. X  (let
  595. X      ((numrec 
  596. X    (save-excursion
  597. X      (set-buffer forms--file-buffer)
  598. X      (count-lines (point-min) (point-max)))))
  599. X    (if (= numrec forms--total-records)
  600. X    nil
  601. X      (beep)
  602. X      (setq forms--total-records numrec)
  603. X      (message "Number of records reset to %d." forms--total-records)))
  604. X  (forms-jump-record forms--total-records))
  605. X
  606. ;;;
  607. ;;; Other commands
  608. (defun forms-view-mode ()
  609. X  "Visit buffer read-only."
  610. X  (interactive)
  611. X  (if forms-read-only
  612. X      nil
  613. X    (forms--checkmod)            ; sync
  614. X    (setq forms-read-only t)
  615. X    (forms-mode)))
  616. X
  617. (defun forms-edit-mode ()
  618. X  "Make form suitable for editing, if possible."
  619. X  (interactive)
  620. X  (let ((ro forms-read-only))
  621. X    (if (save-excursion
  622. X      (set-buffer forms--file-buffer)
  623. X      buffer-read-only)
  624. X    (progn
  625. X      (setq forms-read-only t)
  626. X      (message "No write access to \"%s\"" forms-file)
  627. X      (beep))
  628. X      (setq forms-read-only nil))
  629. X    (if (equal ro forms-read-only)
  630. X    nil
  631. X      (forms-mode))))
  632. X
  633. ;; Sample:
  634. ;; (defun my-new-record-filter (the-fields)
  635. ;;   ;; numbers are relative to 1
  636. ;;   (aset the-fields 4 (current-time-string))
  637. ;;   (aset the-fields 6 (user-login-name))
  638. ;;   the-list)
  639. ;; (setq forms-new-record-filter 'my-new-record-filter)
  640. X
  641. (defun forms-insert-record (arg)
  642. X  "Create a new record before the current one. With ARG: store the
  643. X record after the current one.
  644. X If a function forms-new-record-filter is defined, or forms-new-record-filter
  645. X contains the name of a function, it is called to
  646. X fill (some of) the fields with default values."
  647. X ; The above doc is not true, but for documentary purposes only
  648. X
  649. X  (interactive "P")
  650. X
  651. X  (let ((ln (if arg (1+ forms--current-record) forms--current-record))
  652. X        the-list the-record)
  653. X
  654. X    (forms--checkmod)
  655. X    (if forms--new-record-filter
  656. X    ;; As a service to the user, we add a zeroth element so she
  657. X    ;; can use the same indices as in the forms definition.
  658. X    (let ((the-fields (make-vector (1+ forms-number-of-fields) "")))
  659. X      (setq the-fields (funcall forms--new-record-filter the-fields))
  660. X      (setq the-list (cdr (append the-fields nil))))
  661. X      (setq the-list (make-list forms-number-of-fields "")))
  662. X
  663. X    (setq the-record
  664. X      (mapconcat
  665. X      'identity
  666. X      the-list
  667. X      forms-field-sep))
  668. X
  669. X    (save-excursion
  670. X      (set-buffer forms--file-buffer)
  671. X      (goto-line ln)
  672. X      (open-line 1)
  673. X      (insert the-record)
  674. X      (beginning-of-line))
  675. X    
  676. X    (setq forms--current-record ln))
  677. X
  678. X  (setq forms--total-records (1+ forms--total-records))
  679. X  (forms-jump-record forms--current-record))
  680. X
  681. (defun forms-delete-record (arg)
  682. X  "Deletes a record. With ARG: don't ask."
  683. X  (interactive "P")
  684. X  (forms--checkmod)
  685. X  (if (or arg
  686. X      (y-or-n-p "Really delete this record? "))
  687. X      (let ((ln forms--current-record))
  688. X    (save-excursion
  689. X      (set-buffer forms--file-buffer)
  690. X      (goto-line ln)
  691. X      (kill-line 1))
  692. X    (setq forms--total-records (1- forms--total-records))
  693. X    (if (> forms--current-record forms--total-records)
  694. X        (setq forms--current-record forms--total-records))
  695. X    (forms-jump-record forms--current-record)))
  696. X  (message ""))
  697. X
  698. (defun forms-search (regexp)
  699. X  "Search REGEXP in file buffer."
  700. X  (interactive 
  701. X   (list (read-string (concat "Search for" 
  702. X                  (if forms--search-regexp
  703. X                   (concat " ("
  704. X                       forms--search-regexp
  705. X                       ")"))
  706. X                  ": "))))
  707. X  (if (equal "" regexp)
  708. X      (setq regexp forms--search-regexp))
  709. X  (forms--checkmod)
  710. X
  711. X  (let (the-line the-record here
  712. X         (fld-sep forms-field-sep))
  713. X    (if (save-excursion
  714. X      (set-buffer forms--file-buffer)
  715. X      (setq here (point))
  716. X      (end-of-line)
  717. X      (if (null (re-search-forward regexp nil t))
  718. X          (progn
  719. X        (goto-char here)
  720. X        (message (concat "\"" regexp "\" not found."))
  721. X        nil)
  722. X        (setq the-record (forms--get-record))
  723. X        (setq the-line (1+ (count-lines (point-min) (point))))))
  724. X    (progn
  725. X      (setq forms--current-record the-line)
  726. X      (forms--show-record the-record)
  727. X      (re-search-forward regexp nil t))))
  728. X  (setq forms--search-regexp regexp))
  729. X
  730. (defun forms-revert-buffer (&optional arg noconfirm)
  731. X  "Reverts current form to un-modified."
  732. X  (interactive "P")
  733. X  (if (or noconfirm
  734. X      (yes-or-no-p "Revert form to unmodified? "))
  735. X      (progn
  736. X    (set-buffer-modified-p nil)
  737. X    (forms-jump-record forms--current-record))))
  738. X
  739. (defun forms-next-field (arg)
  740. X  "Jump to ARG-th next field."
  741. X  (interactive "p")
  742. X
  743. X  (let ((i 0)
  744. X    (here (point))
  745. X    there
  746. X    (cnt 0))
  747. X
  748. X    (if (zerop arg)
  749. X    (setq cnt 1)
  750. X      (setq cnt (+ cnt arg)))
  751. X
  752. X    (if (catch 'done
  753. X      (while (< i forms--number-of-markers)
  754. X        (if (or (null (setq there (aref forms--markers i)))
  755. X            (<= there here))
  756. X        nil
  757. X          (if (<= (setq cnt (1- cnt)) 0)
  758. X          (progn
  759. X            (goto-char there)
  760. X            (throw 'done t))))
  761. X        (setq i (1+ i))))
  762. X    nil
  763. X      (goto-char (aref forms--markers 0)))))
  764. X
  765. ;;;
  766. ;;; Special service
  767. ;;;
  768. (defun forms-enumerate (the-fields)
  769. X  "Take a quoted list of symbols, and set their values to the numbers
  770. 1, 2 and so on. Returns the higest number.
  771. X
  772. Usage: (setq forms-number-of-fields
  773. X             (forms-enumerate
  774. X              '(field1 field2 field2 ...)))"
  775. X
  776. X  (let ((the-index 0))
  777. X    (while the-fields
  778. X      (setq the-index (1+ the-index))
  779. X      (let ((el (car-safe the-fields)))
  780. X    (setq the-fields (cdr-safe the-fields))
  781. X    (set el the-index)))
  782. X    the-index))
  783. X
  784. ;;;
  785. ;;; Debugging
  786. ;;;
  787. (defvar forms--debug nil
  788. X  "*Enables forms-mode debugging if not nil.")
  789. X
  790. (defun forms--debug (&rest args)
  791. X  "Internal - debugging routine"
  792. X  (if forms--debug
  793. X      (let ((ret nil))
  794. X    (while args
  795. X      (let ((el (car-safe args)))
  796. X        (setq args (cdr-safe args))
  797. X        (if (stringp el)
  798. X        (setq ret (concat ret el))
  799. X          (setq ret (concat ret (prin1-to-string el) " = "))
  800. X          (if (boundp el)
  801. X          (let ((vel (eval el)))
  802. X            (setq ret (concat ret (prin1-to-string vel) "\n")))
  803. X        (setq ret (concat ret "<unbound>" "\n")))
  804. X          (if (fboundp el)
  805. X          (setq ret (concat ret (prin1-to-string (symbol-function el)) 
  806. X                    "\n"))))))
  807. X    (save-excursion
  808. X      (set-buffer (get-buffer-create "*forms-mode debug*"))
  809. X      (goto-char (point-max))
  810. X      (insert ret)))))
  811. X
  812. ;;; Local Variables:
  813. ;;; eval: (headers)
  814. ;;; eval: (setq comment-start ";;; ")
  815. ;;; End:
  816. SHAR_EOF
  817. echo 'File forms.el is complete' &&
  818. chmod 0444 forms.el ||
  819. echo 'restore of forms.el failed'
  820. Wc_c="`wc -c < 'forms.el'`"
  821. test 41744 -eq "$Wc_c" ||
  822.     echo 'forms.el: original size 41744, current size' "$Wc_c"
  823. rm -f _shar_wnt_.tmp
  824. fi
  825. rm -f _shar_seq_.tmp
  826. echo You have unpacked the last part
  827. exit 0
  828. -- 
  829. Johan Vromans                       jv@mh.nl via internet backbones
  830. Multihouse Automatisering bv               uucp: ..!{uunet,hp4nl}!mh.nl!jv
  831. Doesburgweg 7, 2803 PL Gouda, The Netherlands  phone/fax: +31 1820 62911/62500
  832. ------------------------ "Arms are made for hugging" -------------------------
  833.