aboutsummaryrefslogtreecommitdiffstats
path: root/lisp
diff options
context:
space:
mode:
authorRichard M. Stallman1994-12-24 01:26:51 +0000
committerRichard M. Stallman1994-12-24 01:26:51 +0000
commit6163b3ba745fd0fe24d0924b70884ef2295d80df (patch)
tree15624107c2b5c22103dbfd3d501fcb16fd663744 /lisp
parent2c62739ddcc078e28673733a706f1204312006a0 (diff)
downloademacs-6163b3ba745fd0fe24d0924b70884ef2295d80df.tar.gz
emacs-6163b3ba745fd0fe24d0924b70884ef2295d80df.zip
Complete rewrite by Lars.Lindberg@sypro.cap.se.
Diffstat (limited to 'lisp')
-rw-r--r--lisp/dabbrev.el1089
1 files changed, 852 insertions, 237 deletions
diff --git a/lisp/dabbrev.el b/lisp/dabbrev.el
index e89e8d13aa7..fdb9e27c805 100644
--- a/lisp/dabbrev.el
+++ b/lisp/dabbrev.el
@@ -1,279 +1,894 @@
1;;; dabbrev.el --- dynamic abbreviation package for GNU Emacs. 1;;; new-dabbrev.el --- dynamic abbreviation package
2
3;; Copyright (C) 1985, 1986 Free Software Foundation, Inc.
4
5;; Last-Modified: 16 Mar 1992
6;; Copyright (C) 1985, 1986 Free Software Foundation, Inc. 2;; Copyright (C) 1985, 1986 Free Software Foundation, Inc.
7 3
8;; Maintainer: FSF 4;; Author: Don Morrison
9;; Keywords: abbrev 5;; Maintainer: Lars Lindberg <Lars.Lindberg@sypro.cap.se>
6;; Created: 16 Mars 1992
7;; Version: 4.4.2 beta
8(defun dabbrev--version () "4.4.2 beta")
9;; Keywords: abbrev expand completion
10 10
11;; This file is part of GNU Emacs. 11;; This program is free software; you can redistribute it and/or modify
12
13;; GNU Emacs is free software; you can redistribute it and/or modify
14;; it under the terms of the GNU General Public License as published by 12;; it under the terms of the GNU General Public License as published by
15;; the Free Software Foundation; either version 2, or (at your option) 13;; the Free Software Foundation; either version 2 of the License, or
16;; any later version. 14;; (at your option) any later version.
17 15;;
18;; GNU Emacs is distributed in the hope that it will be useful, 16;; This program is distributed in the hope that it will be useful,
19;; but WITHOUT ANY WARRANTY; without even the implied warranty of 17;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21;; GNU General Public License for more details. 19;; GNU General Public License for more details.
22 20;;
23;; You should have received a copy of the GNU General Public License 21;; You should have received a copy of the GNU General Public License
24;; along with GNU Emacs; see the file COPYING. If not, write to 22;; along with this program; if not, write to the Free Software
25;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 23;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 24
27;;; Commentary: 25;;; Commentary:
28 26
29; DABBREVS - "Dynamic abbreviations" hack, originally written by Don Morrison 27;; The purpose with this package is to let you write just a few
30; for Twenex Emacs. Converted to mlisp by Russ Fish. Supports the table 28;; characters of words you've written earlier to be able to expand
31; feature to avoid hitting the same expansion on re-expand, and the search 29;; them.
32; size limit variable. Bugs fixed from the Twenex version are flagged by 30;;
33; comments starting with ;;; . 31;; To expand a word, just put the point right after the word and press
34; 32;; M-/ (dabbrev-expand) or M-C-/ (dabbrev-completion).
35; converted to Emacs Lisp by Spencer Thomas. 33;;
36; Thoroughly cleaned up by Richard Stallman. 34;; There are powerful things in this package that aren't turned on by
37; 35;; default. I recommend you to do the following.
38; If anyone feels like hacking at it, Bob Keller (Keller@Utah-20) first 36;;
39; suggested the beast, and has some good ideas for its improvement, but 37;; Put the following 2 lines in your .emacs file:
40; doesn't know TECO (the lucky devil...). One thing that should definitely 38;; (setq dabbrev-always-check-other-buffers t)
41; be done is adding the ability to search some other buffer(s) if you can?t 39;; (setq dabbrev-abbrev-char-regexp "\\sw\\|\\s_")
42; find the expansion you want in the current one. 40;;
41;; Dabbrev will now search in all buffers with the same major mode for
42;; your expansions. It will also search for complete symbols, the old
43;; dabbrev package only looked half-heartedly for symbols.
44;;
45;; Check out the customizable variables below to learn about all the
46;; features of this package.
47
48;;; Hints and tips for major modes writers:
49
50;; Recommended values C/Lisp etc text
51;; dabbrev-case-fold-search nil t
52;; dabbrev-case-replace nil t
53;;
54;; Set the variables you want special for your mode like this:
55;; (set (make-local-variable 'dabbrev-case-replace) nil)
56;; Then you don't interfer with other modes.
57;;
58;; If your mode handles buffers that refers to other buffers
59;; (i.e. compilation-mode, gud-mode), then try to set
60;; `dabbrev-select-buffers-function' or `dabbrev-friend-buffer-function'
61;; to a function that point out those buffers.
62
63;; Same goes for major-modes that are connected to other modes. There
64;; are for instance a number of mail-modes. One for reading, one for
65;; creating a new mail etc. Maybe those should be connected.
66
67;; Example for GNUS (when we write a reply, we want dabbrev to look in
68;; the article for expansion):
69;; (set (make-local-variable 'dabbrev-friend-buffer-function)
70;; (lambda (buffer)
71;; (save-excursion
72;; (set-buffer buffer)
73;; (memq major-mode '(news-reply-mode gnus-article-mode)))))
74
75;;; Change Log
76;; 4.4.2 1994-11-25
77;; Added new variable; `dabbrev-check-rest-of-buffers'.
78;; 4.4.1 1994-11-24
79;; Now has correct creation date.
80;; Added kill-ring idea to "Future enhancements".
81;; 4.4 1994-11-22
82;; Changed the copyright text. Thanks [hymie].
83;; new-dabbrev now handles abbrevs that starts with symbol
84;; syntax. Thanks [burgett] for kicking me to do it.
85;; Now also handles `dabbrev-abbrev-skip-leading-regexp' better.
86;; 4.3 1994-11-14
87;; Now only displays "Expansion found in <buffer>" when the
88;; expansion has been found in buffers that hasn't been examined
89;; yet. Thanks [kifer].
90;; Added a new variable; `dabbrev-search-these-buffers-only'.
91;; Fixed bug in mini-buffer completion. Thanks [kifer].
92;; Found a real time-waster when using `dabbrev-completion'.
93;; Thanks for the elp.el package Barry Warsaw!
94;; Found bug that made point move in other buffers.
95;; Now handles Lucid emacs define-key style.
96;; Thanks [jules].
97;; Now uses the `<symbol>' syntax in doc strings.
98;; Cosmetic bugs and syntactical bugs in documentation strings.
99;; Thanks [hawley].
100;; 4.2 1994-03-04
101;; Now searches other buffers again. Thanks [ake].
102;; 4.1 1994-02-22
103;; Introduced the new variables `dabbrev-case-fold-search' and
104;; `dabbrev-case-replace'.
105;; Introduced the new variable `dabbrev-select-buffers-function'.
106;; Introduced the new variable `dabbrev-abbrev-skip-leading-regexp'.
107;; Changed `dabbrev-always-check-other-buffers' to not buffer local.
108;; Thanks [kifer].
109;; Bug in `dabbrev-completion', x expanded to xxy instead of xy.
110;; Thanks [kifer].
111;; Added `dabbrev-submit-feedback' for better error-reporting.
112;; The hooks (`dabbrev-select-buffers-function' and
113;; `dabbrev-friend-buffer-function') are now not automatically
114;; buffer local.
115;; Now provides dabbrev too.
116;; 3.2 1993-12-14
117;; Message for expansion found in buffer other than current.
118;; Minor bugs.
119;; 3.1 1993-12-13
120;; Better comment for `dabbrev-abbrev-char-regexp'.
121;; 3.0 1993-12-09
122;; Freshed things up for the release.
123;; `dabbrev-completion' now doesn't have to use the minibuffer.
124;; Thanks [alon].
125;; 2.0 1993-12-02 Lars Lindberg <lli@sypro.cap.se>
126;; Searches in other buffers for the expansion.
127;; Works also for the minibuffer.
128;; Added `dabbrev-completion'.
129;; More efficient code.
130;; Found minor bugs.
131;; 1.0 converted to Emacs Lisp by Spencer Thomas.
132;; Thoroughly cleaned up by Richard Stallman.
133;; 0.0
134;; DABBREVS - "Dynamic abbreviations" hack, originally written by
135;; Don Morrison for Twenex Emacs. Converted to mlisp by Russ Fish.
136;; Supports the table feature to avoid hitting the same expansion on
137;; re-expand, and the search size limit variable.
138
139;; Known bugs and limitations.
140;; - Possible to do several levels of `dabbrev-completion' in the
141;; minibuffer.
142;; - dabbrev-completion doesn't handle resetting the globals variables
143;; right. It resets them after finding the abbrev.
144
145;; Future enhancements
146;; - Check the tags-files? Like tags-complete?
147;; - Add the possibility of searching both forward and backward to
148;; the nearest expansion.
149;; - Check the kill-ring when everything else fails. (Maybe something
150;; for hippie-expand?). [Bng] <boris@cs.rochester.edu>
151
152;;; Thanks goes to
153;; [hymie] Hyman Rosen <marks!hymie@jyacc.jyacc.com>
154;; [burgett] Steve Burgett <burgett@bizet.eecs.berkeley.edu>
155;; [jules] Julian Gosnell <jules@x.co.uk>
156;; [kifer] Michael Kifer <kifer@sbcs.sunysb.edu>
157;; [ake] Ake Stenhoff <extaksf@aom.ericsson.se>
158;; [alon] Alon Albert <al%imercury@uunet.uu.net>
159;; [tromey] Tom Tromey <tromey@busco.lanl.gov>
160;; [Rolf] Rolf Schreiber <rolf@mathematik.uni-stuttgart.de>
161;; [Petri] Petri Raitio <per@tekla.fi>
162;; [ejb] Jay Berkenbilt <ejb@ERA.COM>
163;; [hawley] Bob Hawley <rth1@quartet.mt.att.com>
164;; ... and to all the people who have participated in the beta tests.
43 165
44;;; Code: 166;;; Code:
167(require 'cl)
168
169;;;----------------------------------------------------------------
170;;;----------------------------------------------------------------
171;;; Customization variables
172;;;----------------------------------------------------------------
173;;;----------------------------------------------------------------
174(defvar dabbrev-backward-only nil
175 "*If non-NIL, `dabbrev-expand' only looks backwards.")
176
177(defvar dabbrev-limit nil
178 "*Limits region searched by `dabbrev-expand' to this many chars away.")
179
180(defvar dabbrev-abbrev-skip-leading-regexp nil
181 "*Regexp for skipping leading characters of an abbreviation.
182
183Example: Set this to \"\\\\$\" for programming languages that sometimes
184has and sometimes has not a leading $ for variable names.
185
186Set this to nil if no characters should be skipped.")
187
188;; I recommend that you set this to nil.
189(defvar dabbrev-case-fold-search 'case-fold-search
190 "*T if dabbrev searches should ignore case.
191nil if case is significant.
192Non-nil and not t means evaluate for value.
193
194Example:Setting this to 'case-fold-search means evaluate that variable
195to see if it is t or non-nil.")
196
197(defvar dabbrev-upcase-means-case-search nil
198 "*The significance of an uppercase character in an abbreviation.
199
200This variable only makes sense when the value of
201`dabbrev-case-fold-search' evaluates to t.
202
203nil = case fold search
204t = case sensitive search")
205
206;; I recommend that you set this to nil.
207(defvar dabbrev-case-replace 'case-replace
208 "*T if dabbrev should preserve case when expanding the abbreviation.
209nil if it should not.
210Non-nil and not t means evaluate for value.
211
212This variable only makes sense when the value of
213`dabbrev-case-fold-search' evaluates to t.
214
215Example: Setting this to 'case-replace means evaluate that variable to
216see if it is t or non-nil.")
217
218;; I recommend that you set this to "\\sw\\|\\s_"
219(defvar dabbrev-abbrev-char-regexp nil
220 "*A regexp that recognizes a character in an abbreviation or an
221expansion. Will be surrounded with \\\\( ... \\\\) when used.
222
223Set this to \"\\\\sw\" if you want ordinary words or
224\"\\\\sw\\\\|\\\\s_\" if you want symbols.
225
226You can also set it to nil if you want old-style dabbrev searching
227(the abbreviation is from point to previous word-start, the
228search is for symbols).
229
230For instance, if you are programming in Lisp, yes-or-no-p is a symbol,
231while 'yes', 'or', 'no' and 'p' are considered words. If you set this
232variable to nil, then expanding yes-or-no- will look for a symbol
233starting with or containing 'no-'. If you set this variable to
234\"\\\\sw\\\\|\\\\s_\" dabbrev will look for a symbol starting with
235\"yes-or-no-\". Finally, if you set this variable to \"\\\\sw\", then an
236error will be signalled, because \"-\" is not part of a word but if you
237try to expand \"yes-or-no\", dabbrev will look for a word starting with
238\"no\".
239
240The recommended value is \"\\\\sw\\\\|\\\\s_\".")
241
242;; I recommend that you set this to t.
243(defvar dabbrev-check-rest-of-buffers nil
244 "*Should dabbrev package search in all buffers?.
245
246Non-nil means first look in buffers pointed out by
247`dabbrev-select-buffers-function' and then look in the rest of the
248buffers.")
249
250
251;; I recommend that you set this to t.
252(defvar dabbrev-always-check-other-buffers nil
253 "*Should \\[dabbrev-expand] look in other buffers?\
254nil = Don't look in other buffers.\n\
255t = Look in other buffers.\n\
256Value other than nil and t = ask the user if he want's to look in
257other buffers.
258
259The recommended value is t.")
260
261;; I guess setting this to a function that selects all C- or C++-
262;; mode buffers would be a good choice for a debugging buffer,
263;; when debugging C- or C++-code.
264(defvar dabbrev-select-buffers-function 'dabbrev--select-buffers
265 "A function that selects buffers that should be searched by dabbrev.
266
267The function should take no arguments and return a list of buffers to
268search for expansions. Have a look at `dabbrev--select-buffers' for
269an example.
270
271A mode setting this variable should make it buffer local.")
272
273(defvar dabbrev-friend-buffer-function 'dabbrev--same-major-mode-p
274 "*A function to check if OTHER-BUFFER should be searched by dabbrev.
275
276The function should take one argument, OTHER-BUFFER, and return
277non-nil if that buffer should be searched. Have a look at
278`dabbrev--same-major-mode-p' for an example.
279
280Setting this makes sense only if the function pointed out by
281`dabbrev-select-buffers-function' uses it. The package function
282`dabbrev--select-buffers' is such a function.
283
284A mode setting this variable should make it buffer local.")
285
286(defvar dabbrev-search-these-buffers-only nil
287 "Should be a list of buffers if non-nil.
288
289Dabbrev search will only look in these buffers. It will not even look
290in the current buffer if it is not a member of this list.")
45 291
46;; (defun dabbrevs-help () 292;;;----------------------------------------------------------------
47;; "Give help about dabbrevs." 293;;;----------------------------------------------------------------
48;; (interactive) 294;;; Internal variables
49;; (&info "emacs" "dabbrevs") ; Select the specific info node. 295;;;----------------------------------------------------------------
50;; ) 296;;;----------------------------------------------------------------
51(defvar dabbrevs-limit nil
52 "*Limits region searched by `dabbrevs-expand' to this many chars away.")
53(make-variable-buffer-local 'dabbrevs-limit)
54 297
55(defvar dabbrevs-backward-only nil 298;; Last obarray of completions in `dabbrev-completion'
56 "*If non-NIL, `dabbrevs-expand' only looks backwards.") 299(defvar dabbrev--last-obarray nil)
57 300
58; State vars for dabbrevs-re-expand. 301;; Table of expansions seen so far
59(defvar last-dabbrevs-table nil 302(defvar dabbrev--last-table nil)
60 "Table of expansions seen so far (local)")
61(make-variable-buffer-local 'last-dabbrevs-table)
62 303
63(defvar last-dabbrevs-abbreviation "" 304;; Last string we tried to expand.
64 "Last string we tried to expand (local).") 305(defvar dabbrev--last-abbreviation nil)
65(make-variable-buffer-local 'last-dabbrevs-abbreviation)
66 306
67(defvar last-dabbrevs-direction 0 307;; Location last abbreviation began
68 "Direction of last dabbrevs search (local)") 308(defvar dabbrev--last-abbrev-location nil)
69(make-variable-buffer-local 'last-dabbrevs-direction)
70 309
71(defvar last-dabbrevs-abbrev-location nil 310;; Direction of last dabbrevs search
72 "Location last abbreviation began (local).") 311(defvar dabbrev--last-direction 0)
73(make-variable-buffer-local 'last-dabbrevs-abbrev-location)
74 312
75(defvar last-dabbrevs-expansion nil 313;; Last expansion of an abbreviation.
76 "Last expansion of an abbreviation. (local)") 314(defvar dabbrev--last-expansion nil)
77(make-variable-buffer-local 'last-dabbrevs-expansion)
78 315
79(defvar last-dabbrevs-expansion-location nil 316;; Location the last expansion was found.
80 "Location the last expansion was found. (local)") 317(defvar dabbrev--last-expansion-location nil)
81(make-variable-buffer-local 'last-dabbrevs-expansion-location) 318
319;; The list of remaining buffers with the same mode as current buffer.
320(defvar dabbrev--friend-buffer-list nil)
321
322;; The buffer we looked in last.
323(defvar dabbrev--last-buffer nil)
324
325;; The buffer we found the expansion last time.
326(defvar dabbrev--last-buffer-found nil)
327
328;; The buffer we last did a completion in.
329(defvar dabbrev--last-completion-buffer nil)
330
331;; Same as dabbrev-always-check-other-buffers, but is set for every expand.
332(defvar dabbrev--check-other-buffers dabbrev-always-check-other-buffers)
333
334;; The regexp for recognizing a character in an abbreviation.
335(defvar dabbrev--abbrev-char-regexp nil)
336
337;;;----------------------------------------------------------------
338;;;----------------------------------------------------------------
339;;; Macros
340;;;----------------------------------------------------------------
341;;;----------------------------------------------------------------
342
343;;; Get the buffer that mini-buffer was activated from
344(defsubst dabbrev--minibuffer-origin ()
345 (car (cdr (buffer-list))))
346
347;;;----------------------------------------------------------------
348;;;----------------------------------------------------------------
349;;; Exported functions
350;;;----------------------------------------------------------------
351;;;----------------------------------------------------------------
352
353;;;###autoload
354(define-key esc-map "/" 'dabbrev-expand)
355;;;###autoload
356(if (string-match "Lucid$" emacs-version)
357 (define-key esc-map [(control /)] 'dabbrev-completion)
358 (define-key esc-map [?\C-/] 'dabbrev-completion))
359
360;;;###autoload
361(defun dabbrev-completion (&optional arg)
362 "Completion on current word.
363
364Like \\[dabbrev-expand] but finds all expansions in the current buffer
365and presents suggestions for completion.
366
367If you call this function with prefix ARG, then it searches all
368buffers accepted by the function pointed out by
369`dabbrev-friend-buffer-function' to find the completions.
370
371With no prefix ARG it tries to reuse the old completion list
372before making a new one."
373
374 (interactive "*P")
375 (let* ((dabbrev-always-check-other-buffers (and arg t))
376 (abbrev (dabbrev--abbrev-at-point))
377 (ignore-case-p (and (eval dabbrev-case-fold-search)
378 (or (not dabbrev-upcase-means-case-search)
379 (string= abbrev (downcase abbrev)))))
380 (my-obarray dabbrev--last-obarray)
381 init)
382 (save-excursion
383 (if (and (null arg)
384 my-obarray
385 (or (eq dabbrev--last-completion-buffer (current-buffer))
386 (and (window-minibuffer-p (selected-window))
387 (eq dabbrev--last-completion-buffer
388 (dabbrev--minibuffer-origin))))
389 dabbrev--last-abbreviation
390 (>= (length abbrev) (length dabbrev--last-abbreviation))
391 (string= dabbrev--last-abbreviation
392 (substring abbrev 0
393 (length dabbrev--last-abbreviation)))
394 (setq init (try-completion abbrev my-obarray)))
395 ;;--------------------------------
396 ;; This is a continue.
397 ;;--------------------------------
398 (progn)
399 ;;--------------------------------
400 ;; New abbreviation to expand.
401 ;;--------------------------------
402 (dabbrev--reset-global-variables)
403 (setq dabbrev--last-abbreviation abbrev)
404 ;; Find all expansion
405 (let ((completion-list
406 (dabbrev--find-all-expansions abbrev ignore-case-p)))
407 ;; Make an obarray with all expansions
408 (setq my-obarray (make-vector (length completion-list) 0))
409 (or (> (length my-obarray) 0)
410 (error "No dynamic expansion for \"%s\" found%s."
411 abbrev
412 (if dabbrev--check-other-buffers "" " in this-buffer")))
413 (cond
414 ((or (not ignore-case-p)
415 (not dabbrev-case-replace))
416 (mapc (function (lambda (string)
417 (intern string my-obarray)))
418 completion-list))
419 ((string= abbrev (upcase abbrev))
420 (mapc (function (lambda (string)
421 (intern (upcase string) my-obarray)))
422 completion-list))
423 ((string= (substring abbrev 0 1)
424 (upcase (substring abbrev 0 1)))
425 (mapc (function (lambda (string)
426 (intern (dabbrev--capitalize string) my-obarray)))
427 completion-list))
428 (t
429 (mapc (function (lambda (string)
430 (intern (downcase string) my-obarray)))
431 completion-list)))
432 (setq dabbrev--last-obarray my-obarray)
433 (setq dabbrev--last-completion-buffer (current-buffer))
434 ;; Find the longest common string.
435 (setq init (try-completion abbrev my-obarray)))))
436 ;;--------------------------------
437 ;; Let the user choose between the expansions
438 ;;--------------------------------
439 (or (stringp init)
440 (setq init abbrev))
441 (cond
442 ;; * Replace string fragment with matched common substring completion.
443 ((and (not (string-equal init ""))
444 (not (string-equal (downcase init) (downcase abbrev))))
445 (if (> (length (all-completions init my-obarray)) 1)
446 (message "Repeat '%s' to see all completions" this-command)
447 (message "The only possible completion"))
448 (dabbrev--substitute-expansion nil abbrev init))
449 (t
450 ;; * String is a common substring completion already. Make list.
451 (message "Making completion list...")
452 (with-output-to-temp-buffer " *Completions*"
453 (display-completion-list (all-completions init my-obarray)))
454 (message "Making completion list... Done.")))
455 (and (window-minibuffer-p (selected-window))
456 (message nil))))
82 457
83;;;###autoload 458;;;###autoload
84(defun dabbrev-expand (arg) 459(defun dabbrev-expand (arg)
85 "Expand previous word \"dynamically\". 460 "Expand previous word \"dynamically\".
86Expands to the most recent, preceding word for which this is a prefix.
87If no suitable preceding word is found, words following point are considered.
88 461
89If `case-fold-search' and `case-replace' are non-nil (usually true) 462Expands to the most recent, preceding word for which this is a prefix.
90then the substituted word may be case-adjusted to match the abbreviation 463If no suitable preceding word is found, words following point are
91that you had typed. This takes place if the substituted word, as found, 464considered. If still no suitable word is found, then look in the
92is all lower case, or if it is at the beginning of a sentence and only 465buffers accepted by the function pointed out by variable
93its first letter was upper case. 466`dabbrev-friend-buffer-function'.
94 467
95A positive prefix arg N says to take the Nth backward DISTINCT 468A positive prefix argument, N, says to take the Nth backward _distinct_
96possibility. A negative argument says search forward. The variable 469possibility. A negative argument says search forward.
97`dabbrev-backward-only' may be used to limit the direction of search to
98backward if set non-nil.
99 470
100If the cursor has not moved from the end of the previous expansion and 471If the cursor has not moved from the end of the previous expansion and
101no argument is given, replace the previously-made expansion 472no argument is given, replace the previously-made expansion
102with the next possible expansion not yet tried." 473with the next possible expansion not yet tried.
474
475The variable `dabbrev-backward-only' may be used to limit the
476direction of search to backward if set non-nil.
477
478To make it more powerful, make sure that
479`dabbrev-always-check-other-buffers' is set to t.
480
481Also check out `dabbrev-abbrev-char-regexp' and \\[dabbrev-completion]."
103 (interactive "*P") 482 (interactive "*P")
104 (let (abbrev expansion old which loc n pattern 483 (let (abbrev expansion old direction)
105 (do-case (and case-fold-search case-replace)))
106 ;; abbrev -- the abbrev to expand 484 ;; abbrev -- the abbrev to expand
107 ;; expansion -- the expansion found (eventually) or nil until then 485 ;; expansion -- the expansion found (eventually) or nil until then
108 ;; old -- the text currently in the buffer 486 ;; old -- the text currently in the buffer
109 ;; (the abbrev, or the previously-made expansion) 487 ;; (the abbrev, or the previously-made expansion)
110 ;; loc -- place where expansion is found
111 ;; (to start search there for next expansion if requested later)
112 ;; do-case -- non-nil if should transform case when substituting.
113 (save-excursion 488 (save-excursion
114 (if (and (null arg) 489 (if (and (null arg)
115 (eq last-command this-command) 490 dabbrev--last-abbrev-location
116 last-dabbrevs-abbrev-location) 491 (or (eq last-command this-command)
492 (and (window-minibuffer-p (selected-window))
493 (= dabbrev--last-abbrev-location
494 (point)))))
495 ;;--------------------------------
496 ;; This is a redo.
497 ;;--------------------------------
498 (progn
499 (setq abbrev dabbrev--last-abbreviation)
500 (setq old dabbrev--last-expansion)
501 (setq direction dabbrev--last-direction))
502 ;;--------------------------------
503 ;; New abbreviation to expand.
504 ;;--------------------------------
505 (dabbrev--reset-global-variables)
506 (setq direction (if (null arg)
507 (if dabbrev-backward-only 1 0)
508 (prefix-numeric-value arg)))
509 (setq abbrev (dabbrev--abbrev-at-point))
510 (setq old nil))
511
512 ;;--------------------------------
513 ;; Find the expansion
514 ;;--------------------------------
515 (setq expansion
516 (dabbrev--find-expansion abbrev direction
517 (and (eval dabbrev-case-fold-search)
518 (or (not dabbrev-upcase-means-case-search)
519 (string= abbrev (downcase abbrev)))))))
520 (cond
521 ((not expansion)
522 (dabbrev--reset-global-variables)
523 (if old
524 (save-excursion
525 (search-backward (substring old (length abbrev)))
526 (delete-region (match-beginning 0) (match-end 0))))
527 (error "No%s dynamic expansion for \"%s\" found."
528 (if old " further" "") abbrev))
529 (t
530 (if (not (eq dabbrev--last-buffer dabbrev--last-buffer-found))
117 (progn 531 (progn
118 (setq abbrev last-dabbrevs-abbreviation) 532 (message "Expansion found in '%s'"
119 (setq old last-dabbrevs-expansion) 533 (buffer-name dabbrev--last-buffer))
120 (setq which last-dabbrevs-direction)) 534 (setq dabbrev--last-buffer-found dabbrev--last-buffer))
121 (setq which (if (null arg) 535 (message nil))
122 (if dabbrevs-backward-only 1 0)
123 (prefix-numeric-value arg)))
124 (setq loc (point))
125 (forward-word -1)
126 (setq last-dabbrevs-abbrev-location (point)) ; Original location.
127 (setq abbrev (buffer-substring (point) loc))
128 (setq old abbrev)
129 (setq last-dabbrevs-expansion-location nil)
130 (setq last-dabbrev-table nil)) ; Clear table of things seen.
131
132 (setq pattern (concat "\\b" (regexp-quote abbrev) "\\(\\sw\\|\\s_\\)+"))
133 ;; Try looking backward unless inhibited.
134 (if (>= which 0)
135 (progn
136 (setq n (max 1 which))
137 (if last-dabbrevs-expansion-location
138 (goto-char last-dabbrevs-expansion-location))
139 (while (and (> n 0)
140 (setq expansion (dabbrevs-search pattern t do-case)))
141 (setq loc (point-marker))
142 (setq last-dabbrev-table (cons expansion last-dabbrev-table))
143 (setq n (1- n)))
144 (or expansion
145 (setq last-dabbrevs-expansion-location nil))
146 (setq last-dabbrevs-direction (min 1 which))))
147
148 (if (and (<= which 0) (not expansion)) ; Then look forward.
149 (progn
150 (setq n (max 1 (- which)))
151 (if last-dabbrevs-expansion-location
152 (goto-char last-dabbrevs-expansion-location))
153 (while (and (> n 0)
154 (setq expansion (dabbrevs-search pattern nil do-case)))
155 (setq loc (point-marker))
156 (setq last-dabbrev-table (cons expansion last-dabbrev-table))
157 (setq n (1- n)))
158 (setq last-dabbrevs-direction -1))))
159
160 (if (not expansion)
161 (let ((first (string= abbrev old)))
162 (setq last-dabbrevs-abbrev-location nil)
163 (if (not first)
164 (progn (undo-boundary)
165 (search-backward old)
166 (if (eq major-mode 'picture-mode)
167 (picture-replace-match abbrev t 'literal)
168 (replace-match abbrev t 'literal))))
169 (error (if first
170 "No dynamic expansion for \"%s\" found."
171 "No further dynamic expansions for \"%s\" found.")
172 abbrev))
173 ;; Success: stick it in and return. 536 ;; Success: stick it in and return.
174 (undo-boundary) 537 (dabbrev--substitute-expansion old abbrev expansion)
175 (search-backward old)
176 ;; Make case of replacement conform to case of abbreviation
177 ;; provided (1) that kind of thing is enabled in this buffer
178 ;; and (2) the replacement itself is all lower case.
179 ;; First put back the original abbreviation with its original
180 ;; case pattern.
181 (save-excursion
182 (if (eq major-mode 'picture-mode)
183 (picture-replace-match abbrev t 'literal)
184 (replace-match abbrev t 'literal)))
185 (search-forward abbrev)
186 (let ((do-case (and do-case
187 (string= (substring expansion 1)
188 (downcase (substring expansion 1))))))
189 ;; First put back the original abbreviation with its original
190 ;; case pattern.
191 (save-excursion
192 (replace-match abbrev t 'literal))
193;;; This used to be necessary, but no longer,
194;;; because now point is preserved correctly above.
195;;; (search-forward abbrev)
196 (if (eq major-mode 'picture-mode)
197 (picture-replace-match (if do-case (downcase expansion) expansion)
198 (not do-case)
199 'literal)
200 (replace-match (if do-case (downcase expansion) expansion)
201 (not do-case)
202 'literal)))
203 ;; Save state for re-expand. 538 ;; Save state for re-expand.
204 (setq last-dabbrevs-abbreviation abbrev) 539 (setq dabbrev--last-expansion expansion)
205 (setq last-dabbrevs-expansion expansion) 540 (setq dabbrev--last-abbreviation abbrev)
206 (setq last-dabbrevs-expansion-location loc)))) 541 (setq dabbrev--last-abbrev-location (point-marker))))))
207 542
208;;;###autoload (define-key esc-map "/" 'dabbrev-expand) 543(eval-when-compile (require 'reporter))
209 544(defun dabbrev-submit-feedback ()
210 545 "Submit via mail a bug report on the dabbrev package."
211;; Search function used by dabbrevs library. 546 (interactive)
212;; First arg is string to find as prefix of word. Second arg is 547 (require 'reporter)
213;; t for reverse search, nil for forward. Variable dabbrevs-limit 548 (and (y-or-n-p "Do you really want to submit a report on the dabbrev package? ")
214;; controls the maximum search region size. 549 (reporter-submit-bug-report
215 550 "Lars Lindberg <lli@sypro.cap.se>"
216;; Table of expansions already seen is examined in buffer last-dabbrev-table, 551 (format "new-dabbrev.el (Release %s)" (dabbrev--version))
217;; so that only distinct possibilities are found by dabbrevs-re-expand. 552 '(dabbrev-backward-only
218;; Note that to prevent finding the abbrev itself it must have been 553 dabbrev-limit
219;; entered in the table. 554 dabbrev-case-fold-search
220 555 dabbrev-case-replace
221;; IGNORE-CASE non-nil means treat case as insignificant while 556 dabbrev-upcase-means-case-search
222;; looking for a match and when comparing with previous matches. 557 dabbrev-abbrev-char-regexp
223;; Also if that's non-nil and the match is found at the beginning of a sentence 558 dabbrev-always-check-other-buffers
224;; and is in lower case except for the initial 559 dabbrev-select-buffers-function
225;; then it is converted to all lower case for return. 560 dabbrev-friend-buffer-function)
226 561 nil nil nil)))
227;; Value is the expansion, or nil if not found. After a successful 562
228;; search, point is left right after the expansion found. 563;;;----------------------------------------------------------------
229 564;;;----------------------------------------------------------------
230(defun dabbrevs-search (pattern reverse ignore-case) 565;;; Local functions
231 (let (missing result (case-fold-search ignore-case)) 566;;;----------------------------------------------------------------
232 (save-restriction ; Uses restriction for limited searches. 567;;;----------------------------------------------------------------
233 (if dabbrevs-limit 568
234 (narrow-to-region last-dabbrevs-abbrev-location 569(defun dabbrev--capitalize (string)
235 (+ (point) 570 ;; Capitalize STRING (See capitalize-word)
236 (* dabbrevs-limit (if reverse -1 1))))) 571 (let ((new-string ""))
237 ;; Keep looking for a distinct expansion. 572 (save-match-data
238 (setq result nil) 573 (while (string-match "\\w+" string)
239 (setq missing nil) 574 (let* ((mb (match-beginning 0))
240 (while (and (not result) (not missing)) 575 (me (match-end 0))
241 ; Look for it, leave loop if search fails. 576 (ms (substring string mb me)))
242 (setq missing 577 (setq new-string
243 (not (if reverse 578 (concat new-string
244 (re-search-backward pattern nil t) 579 (substring string 0 mb)
245 (re-search-forward pattern nil t)))) 580 (upcase (substring ms 0 1))
246 581 (downcase (substring ms 1))))
247 (if (not missing) 582 (setq string (substring string me)))))
248 (progn 583 new-string))
249 (setq result (buffer-substring (match-beginning 0) 584
250 (match-end 0))) 585;;; Checks if OTHER-BUFFER has the same major mode as current buffer.
251 (let* ((test last-dabbrev-table)) 586(defun dabbrev--same-major-mode-p (other-buffer)
252 (while (and test 587 (let ((orig-mode major-mode))
253 (not 588 (save-excursion
254 (if ignore-case 589 (set-buffer other-buffer)
255 (string= (downcase (car test)) 590 (eq orig-mode major-mode))))
256 (downcase result)) 591
257 (string= (car test) result)))) 592;;; Back over all abbrev type characters and then moves forward over
258 (setq test (cdr test))) 593;;; all skip characters.
259 (if test (setq result nil)))))) ; if already in table, ignore 594(defun dabbrev--goto-start-of-abbrev ()
260 (if result 595 ;; Move backwards over abbrev chars
261 (save-excursion 596 (save-match-data
262 (let ((beg (match-beginning 0))) 597 (when (not (bobp))
263 (goto-char beg) 598 (forward-char -1)
264 (and ignore-case 599 (while (and (looking-at dabbrev--abbrev-char-regexp)
265 (string= (substring result 1) 600 (not (bobp)))
266 (downcase (substring result 1))) 601 (forward-char -1))
267 (if (string= paragraph-start 602 (or (looking-at dabbrev--abbrev-char-regexp)
268 (concat "^$\\|" page-delimiter)) 603 (forward-char 1)))
269 (and (re-search-backward sentence-end nil t) 604 (and dabbrev-abbrev-skip-leading-regexp
270 (= (match-end 0) beg)) 605 (while (looking-at dabbrev-abbrev-skip-leading-regexp)
271 (forward-char 1) 606 (forward-char 1)))))
272 (backward-sentence) 607
273 (= (point) beg)) 608;;; Extract the symbol at point to serve as abbrevitation.
274 (setq result (downcase result)))))) 609(defun dabbrev--abbrev-at-point ()
275 result))) 610 ;; Check for error
276 611 (save-excursion
612 (save-match-data
613 (if (or (bobp)
614 (progn
615 (forward-char -1)
616 (not (looking-at (concat "\\("
617 (or dabbrev-abbrev-char-regexp
618 "\\sw\\|\\s_")
619 "\\)+")))))
620 (error "Not positioned immediately after an abbreviation."))))
621 ;; Return abbrev at point
622 (save-excursion
623 (setq dabbrev--last-abbrev-location (point))
624 (buffer-substring (point)
625 (progn (dabbrev--goto-start-of-abbrev)
626 (point)))))
627
628;;; Initializes all global variables
629(defun dabbrev--reset-global-variables ()
630 ;; dabbrev--last-obarray and dabbrev--last-completion-buffer
631 ;; must not be reset here.
632 (setq dabbrev--last-table nil
633 dabbrev--last-abbreviation nil
634 dabbrev--last-abbrev-location nil
635 dabbrev--last-direction nil
636 dabbrev--last-expansion nil
637 dabbrev--last-expansion-location nil
638 dabbrev--friend-buffer-list nil
639 dabbrev--last-buffer nil
640 dabbrev--last-buffer-found nil
641 dabbrev--abbrev-char-regexp (or dabbrev-abbrev-char-regexp
642 "\\sw\\|\\s_")
643 dabbrev--check-other-buffers dabbrev-always-check-other-buffers))
644
645;;; Find all buffers that are considered "friends" according to the
646;;; function pointed out by dabbrev-friend-buffer-function.
647(defun dabbrev--select-buffers ()
648 (save-excursion
649 (and (window-minibuffer-p (selected-window))
650 (set-buffer (dabbrev--minibuffer-origin)))
651 (let ((orig-buffer (current-buffer)))
652 (loop for buffer
653 in (buffer-list)
654 if (and (not (eq orig-buffer buffer))
655 (boundp 'dabbrev-friend-buffer-function)
656 (funcall dabbrev-friend-buffer-function buffer))
657 collect buffer))))
658
659;;; Try to find ABBREV in REVERSE direction N times.
660(defun dabbrev--try-find (abbrev reverse n ignore-case)
661 (save-excursion
662 (let ((case-fold-search-is-local (memq 'case-fold-search
663 (buffer-local-variables)))
664 (expansion nil))
665 (and dabbrev--last-expansion-location
666 (goto-char dabbrev--last-expansion-location))
667 (unwind-protect
668 (progn
669 (or case-fold-search-is-local
670 (make-local-variable 'case-fold-search))
671 ;; Tricky! If `case-fold-search' isn't buffer-local, then
672 ;; this innocent let creates a buffer-local variable and
673 ;; when the let returns, it is still there! The
674 ;; unwind-protect stuff around this makes sure that there
675 ;; exists one before the let, and removes it afterwards.
676 (let ((case-fold-search ignore-case))
677 (loop repeat n
678 while (setq expansion (dabbrev--search abbrev
679 reverse
680 ignore-case)))))
681 (or case-fold-search-is-local
682 (kill-local-variable 'case-fold-search)))
683 (and expansion
684 (setq dabbrev--last-expansion-location (point)))
685 expansion)))
686
687;;; Find all expansions of ABBREV
688(defun dabbrev--find-all-expansions (abbrev ignore-case)
689 (let ((all-expansions nil)
690 expansion)
691 (save-excursion
692 (goto-char (point-min))
693 (while (setq expansion (dabbrev--find-expansion abbrev -1 ignore-case))
694 (push expansion all-expansions)))
695 all-expansions))
696
697(defun dabbrev--scanning-message ()
698 (message "Scanning '%s'" (buffer-name (current-buffer))))
699
700;;; Find one occasion of ABBREV.
701;;; DIRECTION > 0 means look that many times backwards.
702;;; DIRECTION < 0 means look that many times forward.
703;;; DIRECTION = 0 means try both backward and forward.
704;;; IGNORE-CASE non-nil means ignore case when searching.
705(defun dabbrev--find-expansion (abbrev direction ignore-case)
706 (let (expansion)
707 (save-excursion
708 (cond
709 (dabbrev--last-buffer
710 (set-buffer dabbrev--last-buffer)
711 (dabbrev--scanning-message))
712 ((and (not dabbrev-search-these-buffers-only)
713 (window-minibuffer-p (selected-window)))
714 (set-buffer (dabbrev--minibuffer-origin))
715 ;; In the minibuffer-origin buffer we will only search from
716 ;; the top and down.
717 (goto-char (point-min))
718 (setq direction -1)
719 (dabbrev--scanning-message)))
720 (cond
721 ;; ------------------------------------------
722 ;; Look backwards
723 ;; ------------------------------------------
724 ((and (not dabbrev-search-these-buffers-only)
725 (>= direction 0)
726 (setq dabbrev--last-direction (min 1 direction))
727 (setq expansion (dabbrev--try-find abbrev t
728 (max 1 direction)
729 ignore-case)))
730 expansion)
731 ;; ------------------------------------------
732 ;; Look forward
733 ;; ------------------------------------------
734 ((and (or (not dabbrev-search-these-buffers-only)
735 dabbrev--last-buffer)
736 (<= direction 0)
737 (setq dabbrev--last-direction -1)
738 (setq expansion (dabbrev--try-find abbrev nil
739 (max 1 (- direction))
740 ignore-case)))
741 expansion)
742 ;; ------------------------------------------
743 ;; Look in other buffers.
744 ;; Start at (point-min) and look forward.
745 ;; ------------------------------------------
746 (t
747 (setq dabbrev--last-direction -1)
748 ;; Make sure that we should check other buffers
749 (or dabbrev--friend-buffer-list
750 dabbrev--last-buffer
751 (setq dabbrev--friend-buffer-list
752 (mapcar (function get-buffer)
753 dabbrev-search-these-buffers-only))
754 (not dabbrev--check-other-buffers)
755 (not (or (eq dabbrev--check-other-buffers t)
756 (progn
757 (setq dabbrev--check-other-buffers
758 (y-or-n-p "Check in other buffers this time? ")))))
759 (let* (friend-buffer-list non-friend-buffer-list)
760 (setq dabbrev--friend-buffer-list
761 (funcall dabbrev-select-buffers-function))
762 (when dabbrev-check-rest-of-buffers
763 (setq non-friend-buffer-list
764 (nreverse
765 (loop for buffer
766 in (buffer-list)
767 if (not (memq buffer dabbrev--friend-buffer-list))
768 collect buffer)))
769 (setq dabbrev--friend-buffer-list
770 (append dabbrev--friend-buffer-list
771 non-friend-buffer-list)))))
772 ;; Walk through the buffers
773 (while (and (not expansion) dabbrev--friend-buffer-list)
774 (setq dabbrev--last-buffer
775 (car dabbrev--friend-buffer-list))
776 (setq dabbrev--friend-buffer-list
777 (cdr dabbrev--friend-buffer-list))
778 (set-buffer dabbrev--last-buffer)
779 (dabbrev--scanning-message)
780 (setq dabbrev--last-expansion-location (point-min))
781 (setq expansion (dabbrev--try-find abbrev nil 1 ignore-case)))
782 expansion)))))
783
784(eval-when-compile (require 'picture))
785
786(defun dabbrev--safe-replace-match (string &optional fixedcase literal)
787 (if (eq major-mode 'picture-mode)
788 (picture-replace-match string fixedcase literal)
789 (replace-match string fixedcase literal)))
790
791;;;----------------------------------------------------------------
792;;; Substitute the current string in buffer with the expansion
793;;; OLD is nil or the last expansion substring.
794;;; ABBREV is the abbreviation we are working with.
795;;; EXPANSION is the expansion substring.
796(defun dabbrev--substitute-expansion (old abbrev expansion)
797 ;;(undo-boundary)
798 (let ((use-case-replace (and (eval dabbrev-case-fold-search)
799 (or (not dabbrev-upcase-means-case-search)
800 (string= abbrev (downcase abbrev)))
801 (eval dabbrev-case-replace))))
802 (and nil use-case-replace
803 (setq old (concat abbrev (or old "")))
804 (setq expansion (concat abbrev expansion)))
805 (if old
806 (save-excursion
807 (search-backward old))
808 ;;(store-match-data (list (point-marker) (point-marker)))
809 (search-backward abbrev))
810 ;; Make case of replacement conform to case of abbreviation
811 ;; provided (1) that kind of thing is enabled in this buffer
812 ;; and (2) the replacement itself is all lower case.
813 (dabbrev--safe-replace-match expansion
814 (not use-case-replace)
815 t)))
816
817
818;;;----------------------------------------------------------------
819;;; Search function used by dabbrevs library.
820
821;;; ABBREV is string to find as prefix of word. Second arg, REVERSE,
822;;; is t for reverse search, nil for forward. Variable dabbrev-limit
823;;; controls the maximum search region size. Third argment IGNORE-CASE
824;;; non-nil means treat case as insignificant while looking for a match
825;;; and when comparing with previous matches. Also if that's non-nil
826;;; and the match is found at the beginning of a sentence and is in
827;;; lower case except for the initial then it is converted to all lower
828;;; case for return.
829
830;;; Table of expansions already seen is examined in buffer
831;;; `dabbrev--last-table' so that only distinct possibilities are found
832;;; by dabbrev-re-expand.
833
834;;; Value is the expansion, or nil if not found.
835
836(defun dabbrev--search (abbrev reverse ignore-case)
837 (save-match-data
838 (let ((pattern1 (concat (regexp-quote abbrev)
839 "\\(" dabbrev--abbrev-char-regexp "\\)"))
840 (pattern2 (concat (regexp-quote abbrev)
841 "\\(\\(" dabbrev--abbrev-char-regexp "\\)+\\)"))
842 (found-string nil))
843 ;; Limited search.
844 (save-restriction
845 (and dabbrev-limit
846 (narrow-to-region dabbrev--last-expansion-location
847 (+ (point)
848 (if reverse (- dabbrev-limit) dabbrev-limit))))
849 ;;--------------------------------
850 ;; Look for a distinct expansion, using dabbrev--last-table.
851 ;;--------------------------------
852 (while (and (not found-string)
853 (if reverse
854 (re-search-backward pattern1 nil t)
855 (re-search-forward pattern1 nil t)))
856 (cond
857 ((progn
858 (goto-char (match-beginning 0))
859 (dabbrev--goto-start-of-abbrev)
860 (/= (point) (match-beginning 0)))
861 ;; Prefix of found abbreviation not OK
862 nil)
863 (t
864 (goto-char (match-beginning 0))
865 (re-search-forward pattern2)
866 (setq found-string
867 (buffer-substring (match-beginning 1) (match-end 1)))
868 (and ignore-case (setq found-string (downcase found-string)))
869 ;; Throw away if found in table
870 (when (some
871 (function
872 (lambda (table-string) (string= found-string table-string)))
873 dabbrev--last-table)
874 (setq found-string nil))))
875 (if reverse
876 (goto-char (match-beginning 0))
877 (goto-char (match-end 0))))
878 (cond
879 (found-string
880 ;;--------------------------------
881 ;; Put in `dabbrev--last-table' and decide if we should return
882 ;; result or (downcase result)
883 ;;--------------------------------
884 (push found-string dabbrev--last-table)
885 (let ((result (buffer-substring (match-beginning 0) (match-end 0))))
886 (if (and ignore-case (eval dabbrev-case-replace))
887 (downcase result)
888 result))))))))
889
890(provide 'new-dabbrev)
277(provide 'dabbrev) 891(provide 'dabbrev)
892;; new-dabbrev.el ends here
893
278 894
279;;; dabbrev.el ends here