source: branches/working-0709/ccl/cocoa-ide/hemlock/src/archive/abbrev.lisp

Last change on this file was 6763, checked in by Gary Byers, 17 years ago

Archive ...

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.1 KB
Line 
1;;; -*- Log: hemlock.log; Package: Hemlock -*-
2;;;
3;;; **********************************************************************
4;;; This code was written as part of the CMU Common Lisp project at
5;;; Carnegie Mellon University, and has been placed in the public domain.
6;;;
7#+CMU (ext:file-comment
8 "$Header$")
9;;;
10;;; **********************************************************************
11;;;
12;;; Hemlock Word Abbreviation Mode
13;;; by Jamie W. Zawinski
14;;; 24 September 1985
15;;;
16(in-package :hemlock)
17
18;;;; These Things are Here:
19
20;;; C-X C-A Add Mode Word Abbrev
21;;; Define a mode abbrev for the word before point.
22;;; C-X + Add Global Word Abbrev
23;;; Define a global abbrev for the word before point.
24;;; C-X C-H Inverse Add Mode Word Abbrev
25;;; Define expansion for mode abbrev before point.
26;;; C-X - Inverse Add Global Word Abbrev
27;;; Define expansion for global abbrev before point.
28;;; Alt Space Abbrev Expand Only
29;;; Expand abbrev without inserting anything.
30;;; M-' Word Abbrev Prefix Mark
31;;; Mark a prefix to be glued to an abbrev following.
32;;; C-X U Unexpand Last Word
33;;; Unexpands last abbrev or undoes C-X U.
34
35;;; List Word Abbrevs Shows definitions of all word abbrevs.
36;;; Edit Word Abbrevs Lets you edit the definition list directly.
37;;; Read Word Abbrev File <filename> Define word abbrevs from a definition file.
38;;; Write Word Abbrev File Make a definition file from current abbrevs.
39
40;;; Make Word Abbrev <abbrev><expansion><mode> More General form of C-X C-A, etc.
41;;; Delete All Word Abbrevs Wipes them all.
42;;; Delete Mode Word Abbrev Kills all Mode abbrev.
43;;; Delete Global Word Abbrev Kills all Global abbrev.
44
45;;; Insert Word Abbrevs Inserts a list of current definitions in the
46;;; format that Define Word Abbrevs uses.
47;;; Define Word Abbrevs Defines set of abbrevs from a definition list in
48;;; the buffer.
49;;; Word Abbrev Apropos <string> Shows definitions containing <string> in abbrev,
50;;; definition, or mode.
51
52;;; Append Incremental Word Abbrev File Appends to a file changed abbrev
53;;; definitions since last dumping.
54
55(defmode "Abbrev" :major-p nil :transparent-p t :precedence 2.0)
56
57
58(defvar *global-abbrev-table* (make-hash-table :test #'equal)
59 "Hash table holding global abbrev definitions.")
60
61(defhvar "Abbrev Pathname Defaults"
62 "Holds the name of the last Abbrev-file written."
63 :value (pathname "abbrev.defns"))
64
65(defvar *new-abbrevs* ()
66 "holds a list of abbrevs (and their definitions and modes) changed since saving.")
67
68
69
70;;; C-X C-H Inverse Add Mode Word Abbrev
71;;; Define a mode expansion for the word before point.
72
73(defcommand "Inverse Add Mode Word Abbrev" (p)
74 "Defines a mode word abbrev expansion for the word before the point."
75 "Defines a mode word abbrev expansion for the word before the point."
76 (declare (ignore p))
77 (let ((word (prev-word 1 (current-point)))
78 (mode (buffer-major-mode (current-buffer))))
79 (make-word-abbrev-command nil word nil mode)))
80
81
82;;; C-X C-A Add Mode Word Abbrev
83;;; Define mode abbrev for word before point.
84
85(defcommand "Add Mode Word Abbrev" (p)
86 "Defines a mode word abbrev for the word before the point.
87 With a positive argument, uses that many preceding words as the expansion.
88 With a zero argument, uses the region as the expansion. With a negative
89 argument, prompts for a word abbrev to delete in the current mode."
90 "Defines or deletes a mode word abbrev."
91 (if (and p (minusp p))
92 (delete-mode-word-abbrev-command nil)
93 (let* ((val (if (eql p 0)
94 (region-to-string (current-region nil))
95 (prev-word (or p 1) (current-point))))
96 (mode (buffer-major-mode (current-buffer))))
97 (make-word-abbrev-command nil nil val mode))))
98
99
100
101;;; C-X - Inverse Add Global Word Abbrev
102;;; Define global expansion for word before point.
103
104(defcommand "Inverse Add Global Word Abbrev" (p)
105 "Defines a Global expansion for the word before point."
106 "Defines a Global expansion for the word before point."
107 (declare (ignore p))
108 (let ((word (prev-word 1 (current-point))))
109 (make-word-abbrev-command nil word nil "Global")))
110
111
112
113;;; C-X + Add Global Word Abbrev
114;;; Define global Abbrev for word before point.
115
116(defcommand "Add Global Word Abbrev" (p)
117 "Defines a global word abbrev for the word before the point.
118 With a positive argument, uses that many preceding words as the expansion.
119 With a zero argument, uses the region as the expansion. With a negative
120 argument, prompts for a global word abbrev to delete."
121 "Defines or deletes a global word abbrev."
122 (if (and p (minusp p))
123 (delete-global-word-abbrev-command nil)
124 (let ((val (if (eql p 0)
125 (region-to-string (current-region nil))
126 (prev-word (or p 1) (current-point)))))
127 (make-word-abbrev-command nil nil val "Global"))))
128
129
130
131;;;; Defining Abbrevs
132
133;;; Make Word Abbrev <abbrev><expansion><mode> More General form of C-X C-A, etc.
134
135(defvar *global-abbrev-string-table*
136 (make-string-table :initial-contents '(("Global" . nil))))
137
138(defcommand "Make Word Abbrev" (p &optional abbrev expansion mode)
139 "Defines an arbitrary word abbreviation.
140 Prompts for abbrev, expansion, and mode."
141 "Makes Abbrev be a word abbreviation for Expansion when in Mode. If
142 mode is \"Global\" then make a global abbrev."
143 (declare (ignore p))
144 (unless mode
145 (setq mode
146 (prompt-for-keyword
147 (list *mode-names* *global-abbrev-string-table*)
148 :prompt "Mode of abbrev to add: "
149 :default "Global"
150 :help
151 "Type the mode of the Abbrev you want to add, or confirm for Global.")))
152 (let ((globalp (string-equal mode "Global")))
153 (unless (or globalp (mode-major-p mode))
154 (editor-error "~A is not a major mode." mode))
155 (unless abbrev
156 (setq abbrev
157 (prompt-for-string
158 :trim t
159 :prompt
160 (list "~A abbreviation~@[ of ~S~]: " mode expansion)
161 :help
162 (list "Define a ~A word abbrev." mode))))
163 (when (zerop (length abbrev))
164 (editor-error "Abbreviation must be at least one character long."))
165 (unless (every #'(lambda (ch)
166 (zerop (character-attribute :word-delimiter ch)))
167 (the simple-string abbrev))
168 (editor-error "Word Abbrevs must be a single word."))
169 (unless expansion
170 (setq expansion
171 (prompt-for-string
172 :prompt (list "~A expansion for ~S: " mode abbrev)
173 :help (list "Define the ~A expansion of ~S." mode abbrev))))
174 (setq abbrev (string-downcase abbrev))
175 (let* ((table (cond (globalp *global-abbrev-table*)
176 ((hemlock-bound-p 'Mode-Abbrev-Table :mode mode)
177 (variable-value 'Mode-Abbrev-Table :mode mode))
178 (t
179 (let ((new (make-hash-table :test #'equal)))
180 (defhvar "Mode Abbrev Table"
181 "Hash Table of Mode Abbrevs"
182 :value new :mode mode)
183 new))))
184 (old (gethash abbrev table)))
185 (when (or (not old)
186 (prompt-for-y-or-n
187 :prompt
188 (list "Current ~A definition of ~S is ~S.~%Redefine?"
189 mode abbrev old)
190 :default t
191 :help (list "Redefine the expansion of ~S." abbrev)))
192 (setf (gethash abbrev table) expansion)
193 (push (list abbrev expansion (if globalp nil mode))
194 *new-abbrevs*)))))
195
196
197
198;;; Alt Space Abbrev Expand Only
199;;; Expand abbrev without inserting anything.
200
201(defcommand "Abbrev Expand Only" (p)
202 "This command expands the word before point into its abbrev definition
203 (if indeed it has one)."
204 "This command expands the word before point into its abbrev definition
205 (if indeed it has one)."
206 (declare (ignore p))
207 (let* ((word (prev-word 1 (current-point)))
208 (glob (gethash (string-downcase word) *global-abbrev-table*))
209 (mode (if (hemlock-bound-p 'Mode-Abbrev-Table)
210 (gethash (string-downcase word)
211 (value Mode-Abbrev-Table))))
212 (end-word (reverse-find-attribute (copy-mark (current-point)
213 :right-inserting)
214 :word-delimiter #'zerop))
215 (result (if mode mode glob)))
216 (when (or mode glob)
217 (delete-characters end-word (- (length word)))
218 (cond ((equal word (string-capitalize word))
219 (setq result (string-capitalize result)))
220 ((equal word (string-upcase word))
221 (setq result (string-upcase result))))
222 (insert-string end-word result)
223 (unless (hemlock-bound-p 'last-expanded)
224 (defhvar "last expanded"
225 "Holds a mark, the last expanded abbrev, and its expansion in a list."
226 :buffer (current-buffer)))
227 (setf (value last-expanded)
228 (list (copy-mark (current-point) :right-inserting)
229 word result)))
230 (delete-mark end-word))
231 (when (and (hemlock-bound-p 'prefix-mark)
232 (value prefix-mark))
233 (delete-characters (value prefix-mark) 1)
234 (delete-mark (value prefix-mark))
235 (setf (value prefix-mark) nil)))
236
237
238
239;;; This function returns the n words immediately before the mark supplied.
240
241(defun prev-word (n mark)
242 (let* ((mark-1 (reverse-find-attribute (copy-mark mark :temporary)
243 :word-delimiter #'zerop))
244 (mark-2 (copy-mark mark-1)))
245 (dotimes (x n (region-to-string (region mark-2 mark-1)))
246 (reverse-find-attribute (mark-before mark-2) :word-delimiter))))
247
248
249
250;;; M-' Word Abbrev Prefix Mark
251;;; Mark a prefix to be glued to an abbrev following.
252
253;;; When "Abbrev Expand Only" expands the abbrev (because #\- is an expander)
254;;; it will see that prefix-mark is non-nil, and will delete the #\- immediately
255;;; after prefix-mark.
256
257(defcommand "Word Abbrev Prefix Mark" (p)
258 "Marks a prefix to be glued to an abbrev following."
259 "Marks a prefix to be glued to an abbrev following."
260 (declare (ignore p))
261 (unless (hemlock-bound-p 'prefix-mark)
262 (defhvar "prefix mark"
263 "Holds a mark (or not) pointing to the current Prefix Mark."
264 :buffer (current-buffer)))
265 (when (value prefix-mark)
266 (delete-mark (value prefix-mark)))
267 (setf (value prefix-mark) (copy-mark (current-point) :right-inserting))
268 (insert-character (value prefix-mark) #\-))
269
270
271
272;;; C-X U Unexpand Last Word
273;;; Unexpands last abbrev or undoes last C-X U.
274
275(defcommand "Unexpand Last Word" (p)
276 "Undoes the last abbrev expansion, or undoes \"Unexpand Last Word\".
277 Only one abbrev may be undone."
278 "Undoes the last abbrev expansion, or undoes \"Unexpand Last Word\"."
279 (declare (ignore p))
280 (unless (or (not (hemlock-bound-p 'last-expanded))
281 (value last-expanded))
282 (editor-error "Nothing to Undo."))
283 (let ((mark (car (value last-expanded)))
284 (word1 (second (value last-expanded)))
285 (word2 (third (value last-expanded))))
286 (unless (string= word2
287 (region-to-string
288 (region (character-offset (copy-mark mark :temporary)
289 (- (length word2)))
290 mark)))
291 (editor-error "The last expanded Abbrev has been altered in the text."))
292 (delete-characters mark (- (length word2)))
293 (insert-string mark word1)
294 (character-offset mark (length word1))
295 (setf (value last-expanded) (list mark word2 word1))))
296
297
298
299;;; Delete Mode Word Abbrev Kills some Mode abbrevs.
300
301(defcommand "Delete Mode Word Abbrev"
302 (p &optional abbrev
303 (mode (buffer-major-mode (current-buffer))))
304 "Prompts for a word abbrev and deletes the mode expansion in the current mode.
305 If called with a prefix argument, deletes all word abbrevs define in the
306 current mode."
307 "Deletes Abbrev in Mode, or all abbrevs in Mode if P is true."
308 (let ((boundp (hemlock-bound-p 'Mode-Abbrev-Table :mode mode)))
309 (if p
310 (when boundp
311 (delete-variable 'Mode-Abbrev-Table :mode mode))
312 (let ((down
313 (string-downcase
314 (or abbrev
315 (prompt-for-string
316 :prompt (list "~A abbrev to delete: " mode)
317 :help
318 (list "Give the name of a ~A mode word abbrev to delete." mode)
319 :trim t))))
320 (table (and boundp (variable-value 'mode-abbrev-table :mode mode))))
321 (unless (and table (gethash down table))
322 (editor-error "~S is not the name of an abbrev in ~A mode."
323 down mode))
324 (remhash down table)))))
325
326
327;;; Delete Global Word Abbrevs Kills some Global abbrevs.
328
329(defcommand "Delete Global Word Abbrev" (p &optional abbrev)
330 "Prompts for a word abbrev and delete the global expansion.
331 If called with a prefix argument, deletes all global abbrevs."
332 "Deletes the global word abbreviation named Abbrev. If P is true,
333 deletes all global abbrevs."
334 (if p
335 (setq *global-abbrev-table* (make-hash-table :test #'equal))
336 (let ((down
337 (string-downcase
338 (or abbrev
339 (prompt-for-string
340 :prompt "Global abbrev to delete: "
341 :help "Give the name of a global word abbrev to delete."
342 :trim t)))))
343 (unless (gethash down *global-abbrev-table*)
344 (editor-error "~S is not the name of a global word abbrev." down))
345 (remhash down *global-abbrev-table*))))
346
347;;; Delete All Word Abbrevs Wipes them all.
348
349(defcommand "Delete All Word Abbrevs" (p)
350 "Deletes all currently defined Word Abbrevs"
351 "Deletes all currently defined Word Abbrevs"
352 (declare (ignore p))
353 (Delete-Global-Word-Abbrev-Command 1)
354 (Delete-Mode-Word-Abbrev-Command 1))
355
356
357
358;;;; Abbrev I/O
359
360;;; List Word Abbrevs Shows definitions of all word abbrevs.
361
362(defcommand "List Word Abbrevs" (p)
363 "Lists all of the currently defined Word Abbrevs."
364 "Lists all of the currently defined Word Abbrevs."
365 (word-abbrev-apropos-command p ""))
366
367
368;;; Word Abbrev Apropos <string> Shows definitions containing <string> in abbrev,
369;;; definition, or mode.
370
371(defcommand "Word Abbrev Apropos" (p &optional search-string)
372 "Lists all of the currently defined Word Abbrevs which contain a given string
373 in their abbrev. definition, or mode."
374 "Lists all of the currently defined Word Abbrevs which contain a given string
375 in their abbrev. definition, or mode."
376 (declare (ignore p))
377 (unless search-string
378 (setq search-string
379 (string-downcase
380 (prompt-for-string
381 :prompt "Apropos string: "
382 :help "The string to search word abbrevs and definitions for."))))
383 (multiple-value-bind (count mode-tables) (count-abbrevs)
384 (with-pop-up-display (s :height (min (1+ count) 30))
385 (unless (zerop (hash-table-count *global-abbrev-table*))
386 (maphash #'(lambda (key val)
387 (when (or (search search-string (string-downcase key))
388 (search search-string (string-downcase val)))
389 (write-abbrev key val nil s t)))
390 *global-abbrev-table*))
391 (dolist (modename mode-tables)
392 (let ((table (variable-value 'Mode-Abbrev-Table :mode modename)))
393 (if (search search-string (string-downcase modename))
394 (maphash #'(lambda (key val)
395 (write-abbrev key val modename s t))
396 table)
397 (maphash #'(lambda (key val)
398 (when (or (search search-string (string-downcase key))
399 (search search-string (string-downcase val)))
400 (write-abbrev key val modename s t)))
401 table))))
402 (terpri s))))
403
404
405
406(defun count-abbrevs ()
407 (let* ((count (hash-table-count *global-abbrev-table*))
408 (mode-tables nil))
409 (do-strings (which x *mode-names*)
410 (declare (ignore x))
411 (when (hemlock-bound-p 'Mode-Abbrev-Table :mode which)
412 (let ((table-count (hash-table-count (variable-value 'Mode-Abbrev-Table
413 :mode which))))
414 (unless (zerop table-count)
415 (incf count table-count)
416 (push which mode-tables)))))
417 (values count mode-tables)))
418
419
420
421;;; Edit Word Abbrevs Lets you edit the definition list directly.
422
423(defcommand "Edit Word Abbrevs" (p)
424 "Allows direct editing of currently defined Word Abbrevs."
425 "Allows direct editing of currently defined Word Abbrevs."
426 (declare (ignore p))
427 (when (getstring "Edit Word Abbrevs" *buffer-names*)
428 (delete-buffer (getstring "Edit Word Abbrevs" *buffer-names*)))
429 (let ((old-buf (current-buffer))
430 (new-buf (make-buffer "Edit Word Abbrevs")))
431 (change-to-buffer new-buf)
432 (unwind-protect
433 (progn
434 (insert-word-abbrevs-command nil)
435 (do-recursive-edit)
436 (unless (equal #\newline (previous-character (buffer-end (current-point))))
437 (insert-character (current-point) #\newline))
438 (delete-all-word-abbrevs-command nil)
439 (define-word-abbrevs-command nil))
440 (progn
441 (change-to-buffer old-buf)
442 (delete-buffer new-buf)))))
443
444
445
446;;; Insert Word Abbrevs Inserts a list of current definitions in the
447;;; format that Define Word Abbrevs uses.
448
449(defcommand "Insert Word Abbrevs" (p)
450 "Inserts into the current buffer a list of all currently defined abbrevs in the
451 format used by \"Define Word Abbrevs\"."
452 "Inserts into the current buffer a list of all currently defined abbrevs in the
453 format used by \"Define Word Abbrevs\"."
454
455 (declare (ignore p))
456 (multiple-value-bind (x mode-tables)
457 (count-abbrevs)
458 (declare (ignore x))
459 (with-output-to-mark (stream (current-point) :full)
460 (maphash #'(lambda (key val)
461 (write-abbrev key val nil stream))
462 *global-abbrev-table*)
463
464 (dolist (mode mode-tables)
465 (let ((modename (if (listp mode) (car mode) mode)))
466 (maphash #'(lambda (key val)
467 (write-abbrev key val modename stream))
468 (variable-value 'Mode-Abbrev-Table :mode modename)))))))
469
470
471
472;;; Define Word Abbrevs Defines set of abbrevs from a definition list in
473;;; the buffer.
474
475(defcommand "Define Word Abbrevs" (p)
476 "Defines Word Abbrevs from the definition list in the current buffer. The
477 definition list must be in the format produced by \"Insert Word Abbrevs\"."
478 "Defines Word Abbrevs from the definition list in the current buffer. The
479 definition list must be in the format produced by \"Insert Word Abbrevs\"."
480
481 (declare (ignore p))
482 (with-input-from-region (file (buffer-region (current-buffer)))
483 (read-abbrevs file)))
484
485
486
487;;; Read Word Abbrev file <filename> Define word abbrevs from a definition file.
488
489;;; Ignores all lines less than 4 characters, i.e. blankspace or errors. That is
490;;; the minimum number of characters possible to define an abbrev. It thinks the
491;;; current abbrev "wraps" if there is no #\" at the end of the line or there are
492;;; two #\"s at the end of the line (unless that is the entire definition string,
493;;; i.e, a null-abbrev).
494
495;;; The format of the Abbrev files is
496;;;
497;;; ABBREV<tab><tab>"ABBREV DEFINITION"
498;;;
499;;; for Global Abbrevs, and
500;;;
501;;; ABBREV<tab>(MODE)<tab>"ABBREV DEFINITION"
502;;;
503;;; for Modal Abbrevs.
504;;; Double-quotes contained within the abbrev definition are doubled. If the first
505;;; line of an abbrev definition is not closed by a single double-quote, then
506;;; the subsequent lines are read in until a single double-quote is found.
507
508(defcommand "Read Word Abbrev File" (p &optional filename)
509 "Reads in a file of previously defined abbrev definitions."
510 "Reads in a file of previously defined abbrev definitions."
511 (declare (ignore p))
512 (setf (value abbrev-pathname-defaults)
513 (if filename
514 filename
515 (prompt-for-file
516 :prompt "Name of abbrev file: "
517 :help "The name of the abbrev file to load."
518 :default (value abbrev-pathname-defaults)
519 :must-exist nil)))
520 (with-open-file (file (value abbrev-pathname-defaults) :direction :input
521 :element-type 'base-char :if-does-not-exist :error)
522 (read-abbrevs file)))
523
524
525;;; Does the actual defining of abbrevs from a given stream, expecting tabs and
526;;; doubled double-quotes.
527
528(defun read-abbrevs (file)
529 (do ((line (read-line file nil nil)
530 (read-line file nil nil)))
531 ((null line))
532 (unless (< (length line) 4)
533 (let* ((tab (position #\tab line))
534 (tab2 (position #\tab line :start (1+ tab)))
535 (abbrev (subseq line 0 tab))
536 (modename (subseq line (1+ tab) tab2))
537 (expansion (do* ((last (1+ (position #\" line))
538 (if found (min len (1+ found)) 0))
539 (len (length line))
540 (found (if (position #\" line :start last)
541 (1+ (position #\" line :start last)))
542 (if (position #\" line :start last)
543 (1+ (position #\" line :start last))))
544 (expansion (subseq line last (if found found len))
545 (concatenate 'simple-string expansion
546 (subseq line last
547 (if found found
548 len)))))
549 ((and (or (null found) (= found len))
550 (equal #\" (char line (1- len)))
551 (or (not (equal #\" (char line (- len 2))))
552 (= (- len 3) tab2)))
553 (subseq expansion 0 (1- (length expansion))))
554
555 (when (null found)
556 (setq line (read-line file nil nil)
557 last 0
558 len (length line)
559 found (if (position #\" line)
560 (1+ (position #\" line)))
561 expansion (format nil "~A~%~A" expansion
562 (subseq line 0 (if found
563 found
564 0))))))))
565
566 (cond ((equal modename "")
567 (setf (gethash abbrev *global-abbrev-table*)
568 expansion))
569 (t (setq modename (subseq modename 1 (1- (length modename))))
570 (unless (hemlock-bound-p 'Mode-Abbrev-Table
571 :mode modename)
572 (defhvar "Mode Abbrev Table"
573 "Hash Table of Mode Abbrevs"
574 :value (make-hash-table :test #'equal)
575 :mode modename))
576 (setf (gethash abbrev (variable-value
577 'Mode-Abbrev-Table :mode modename))
578 expansion)))))))
579
580
581;;; Write Word Abbrev File Make a definition file from current abbrevs.
582
583(defcommand "Write Word Abbrev File" (p &optional filename)
584 "Saves the currently defined Abbrevs to a file."
585 "Saves the currently defined Abbrevs to a file."
586 (declare (ignore p))
587 (unless filename
588 (setq filename
589 (prompt-for-file
590 :prompt "Write abbrevs to file: "
591 :default (value abbrev-pathname-defaults)
592 :help "Name of the file to write current abbrevs to."
593 :must-exist nil)))
594 (with-open-file (file filename :direction :output
595 :element-type 'base-char :if-exists :supersede
596 :if-does-not-exist :create)
597 (multiple-value-bind (x mode-tables) (count-abbrevs)
598 (declare (ignore x))
599 (maphash #'(lambda (key val)
600 (write-abbrev key val nil file))
601 *global-abbrev-table*)
602
603 (dolist (modename mode-tables)
604 (let ((mode (if (listp modename) (car modename) modename)))
605 (maphash #'(lambda (key val)
606 (write-abbrev key val mode file))
607 (variable-value 'Mode-Abbrev-Table :mode mode))))))
608 (let ((tn (truename filename)))
609 (setf (value abbrev-pathname-defaults) tn)
610 (message "~A written." (namestring tn))))
611
612
613
614;;; Append to Word Abbrev File Appends to a file changed abbrev
615;;; definitions since last dumping.
616
617(defcommand "Append to Word Abbrev File" (p &optional filename)
618 "Appends Abbrevs defined or redefined since the last save to a file."
619 "Appends Abbrevs defined or redefined since the last save to a file."
620 (declare (ignore p))
621 (cond
622 (*new-abbrevs*
623 (unless filename
624 (setq filename
625 (prompt-for-file
626 :prompt
627 "Append incremental abbrevs to file: "
628 :default (value abbrev-pathname-defaults)
629 :must-exist nil
630 :help "Filename to append recently defined Abbrevs to.")))
631 (write-incremental :append filename))
632 (t
633 (message "No Abbrev definitions have been changed since the last write."))))
634
635
636(defun write-incremental (mode filename)
637 (with-open-file (file filename :direction :output
638 :element-type 'base-char
639 :if-exists mode :if-does-not-exist :create)
640 (dolist (def *new-abbrevs*)
641 (let ((abb (car def))
642 (val (second def))
643 (mode (third def)))
644 (write-abbrev abb val mode file))))
645 (let ((tn (truename filename)))
646 (setq *new-abbrevs* nil)
647 (setf (value abbrev-pathname-defaults) tn)
648 (message "~A written." (namestring tn))))
649
650
651;;; Given an Abbrev, expansion, mode (nil for Global), and stream, this function
652;;; writes to the stream with doubled double-quotes and stuff.
653;;; If the flag is true, then the output is in a pretty format (like "List Word
654;;; Abbrevs" uses), otherwise output is in tabbed format (like "Write Word
655;;; Abbrev File" uses).
656
657(defun write-abbrev (abbrev expansion modename file &optional flag)
658 (if flag
659 (if modename
660 (format file "~5t~A~20t(~A)~35t\"" abbrev modename); pretty format
661 (format file "~5t~A~35t\"" abbrev)) ; pretty format
662 (cond (modename
663 (write-string abbrev file)
664 (write-char #\tab file)
665 (format file "(~A)" modename) ; "~A<tab>(~A)<tab>\""
666 (write-char #\tab file)
667 (write-char #\" file))
668 (t
669 (write-string abbrev file)
670 (write-char #\tab file) ; "~A<tab><tab>\""
671 (write-char #\tab file)
672 (write-char #\" file))))
673 (do* ((prev 0 found)
674 (found (position #\" expansion)
675 (position #\" expansion :start found)))
676 ((not found)
677 (write-string expansion file :start prev)
678 (write-char #\" file)
679 (terpri file))
680 (incf found)
681 (write-string expansion file :start prev :end found)
682 (write-char #\" file)))
683
684
685(defcommand "Abbrev Mode" (p)
686 "Put current buffer in Abbrev mode."
687 "Put current buffer in Abbrev mode."
688 (declare (ignore p))
689 (setf (buffer-minor-mode (current-buffer) "Abbrev")
690 (not (buffer-minor-mode (current-buffer) "Abbrev"))))
Note: See TracBrowser for help on using the repository browser.