*** empty log message ***
[bpt/emacs.git] / lisp / completion.el
CommitLineData
c0274f38 1;;; completion.el --- dynamic word-completion code
b578f267 2
0d30b337
TTN
3;; Copyright (C) 1990, 1993, 1995, 1997, 2002, 2003, 2004,
4;; 2005 Free Software Foundation, Inc.
c0274f38 5
af4d5234 6;; Maintainer: FSF
f5f727f8 7;; Keywords: abbrev convenience
32168d16 8;; Author: Jim Salem <alem@bbnplanet.com> of Thinking Machines Inc.
9d0eba57 9;; (ideas suggested by Brewster Kahle)
d1c7011d 10
1add72b5 11;; This file is part of GNU Emacs.
d1c7011d 12
1add72b5
RS
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
15;; the Free Software Foundation; either version 2, or (at your option)
16;; any later version.
17
18;; GNU Emacs is distributed in the hope that it will be useful,
19;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21;; GNU General Public License for more details.
22
23;; You should have received a copy of the GNU General Public License
b578f267 24;; along with GNU Emacs; see the file COPYING. If not, write to the
086add15
LK
25;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
26;; Boston, MA 02110-1301, USA.
1add72b5
RS
27
28;;; Commentary:
b578f267
EN
29
30;; What to put in .emacs
31;;-----------------------
bb310d1e 32;; (dynamic-completion-mode)
59ca07b5 33\f
b578f267
EN
34;;---------------------------------------------------------------------------
35;; Documentation [Slightly out of date]
36;;---------------------------------------------------------------------------
37;; (also check the documentation string of the functions)
38;;
39;; Introduction
40;;---------------
71296446 41;;
b578f267 42;; After you type a few characters, pressing the "complete" key inserts
71296446 43;; the rest of the word you are likely to type.
b578f267 44;;
71296446 45;; This watches all the words that you type and remembers them. When
b578f267 46;; typing a new word, pressing "complete" (meta-return) "completes" the
71296446 47;; word by inserting the most recently used word that begins with the
b578f267
EN
48;; same characters. If you press meta-return repeatedly, it cycles
49;; through all the words it knows about.
50;;
51;; If you like the completion then just continue typing, it is as if you
71296446 52;; entered the text by hand. If you want the inserted extra characters
b578f267
EN
53;; to go away, type control-w or delete. More options are described below.
54;;
55;; The guesses are made in the order of the most recently "used". Typing
71296446
JB
56;; in a word and then typing a separator character (such as a space) "uses"
57;; the word. So does moving a cursor over the word. If no words are found,
b578f267
EN
58;; it uses an extended version of the dabbrev style completion.
59;;
71296446
JB
60;; You automatically save the completions you use to a file between
61;; sessions.
b578f267 62;;
71296446 63;; Completion enables programmers to enter longer, more descriptive
b578f267
EN
64;; variable names while typing fewer keystrokes than they normally would.
65;;
66;;
67;; Full documentation
68;;---------------------
69;;
71296446 70;; A "word" is any string containing characters with either word or symbol
b578f267
EN
71;; syntax. [E.G. Any alphanumeric string with hyphens, underscores, etc.]
72;; Unless you change the constants, you must type at least three characters
73;; for the word to be recognized. Only words longer than 6 characters are
74;; saved.
75;;
76;; When you load this file, completion will be on. I suggest you use the
77;; compiled version (because it is noticeably faster).
78;;
7975cb9f 79;; M-x completion-mode toggles whether or not new words are added to the
b578f267
EN
80;; database by changing the value of enable-completion.
81;;
82;; SAVING/LOADING COMPLETIONS
83;; Completions are automatically saved from one session to another
84;; (unless save-completions-flag or enable-completion is nil).
85;; Loading this file (or calling initialize-completions) causes EMACS
71296446 86;; to load a completions database for a saved completions file
b578f267 87;; (default: ~/.completions). When you exit, EMACS saves a copy of the
71296446 88;; completions that you
b578f267
EN
89;; often use. When you next start, EMACS loads in the saved completion file.
90;;
71296446
JB
91;; The number of completions saved depends loosely on
92;; *saved-completions-decay-factor*. Completions that have never been
b578f267
EN
93;; inserted via "complete" are not saved. You are encouraged to experiment
94;; with different functions (see compute-completion-min-num-uses).
95;;
71296446
JB
96;; Some completions are permanent and are always saved out. These
97;; completions have their num-uses slot set to T. Use
b578f267
EN
98;; add-permanent-completion to do this
99;;
100;; Completions are saved only if enable-completion is T. The number of old
71296446 101;; versions kept of the saved completions file is controlled by
b578f267
EN
102;; completions-file-versions-kept.
103;;
104;; COMPLETE KEY OPTIONS
71296446
JB
105;; The complete function takes a numeric arguments.
106;; control-u :: leave the point at the beginning of the completion rather
b578f267
EN
107;; than the middle.
108;; a number :: rotate through the possible completions by that amount
109;; `-' :: same as -1 (insert previous completion)
110;;
111;; HOW THE DATABASE IS MAINTAINED
112;; <write>
113;;
114;; UPDATING THE DATABASE MANUALLY
71296446 115;; m-x kill-completion
b578f267
EN
116;; kills the completion at point.
117;; m-x add-completion
118;; m-x add-permanent-completion
71296446 119;;
b578f267
EN
120;; UPDATING THE DATABASE FROM A SOURCE CODE FILE
121;; m-x add-completions-from-buffer
122;; Parses all the definition names from a C or LISP mode buffer and
123;; adds them to the completion database.
124;;
71296446 125;; m-x add-completions-from-lisp-file
b578f267
EN
126;; Parses all the definition names from a C or Lisp mode file and
127;; adds them to the completion database.
128;;
129;; UPDATING THE DATABASE FROM A TAGS TABLE
130;; m-x add-completions-from-tags-table
131;; Adds completions from the current tags-table-buffer.
132;;
133;; HOW A COMPLETION IS FOUND
134;; <write>
135;;
136;; STRING CASING
71296446 137;; Completion is string case independent if case-fold-search has its
b578f267 138;; normal default of T. Also when the completion is inserted the case of the
71296446
JB
139;; entry is coerced appropriately.
140;; [E.G. APP --> APPROPRIATELY app --> appropriately
b578f267
EN
141;; App --> Appropriately]
142;;
143;; INITIALIZATION
71296446
JB
144;; The form `(initialize-completions)' initializes the completion system by
145;; trying to load in the user's completions. After the first cal, further
146;; calls have no effect so one should be careful not to put the form in a
b578f267
EN
147;; site's standard site-init file.
148;;
149;;---------------------------------------------------------------------------
150;;
151;;
59ca07b5 152\f
b578f267
EN
153;;---------------------------------------------------------------------------
154;; Functions you might like to call
155;;---------------------------------------------------------------------------
156;;
157;; add-completion string &optional num-uses
158;; Adds a new string to the database
159;;
160;; add-permanent-completion string
161;; Adds a new string to the database with num-uses = T
162;;
163
164;; kill-completion string
165;; Kills the completion from the database.
166;;
167;; clear-all-completions
168;; Clears the database
169;;
170;; list-all-completions
171;; Returns a list of all completions.
172;;
173;;
174;; next-completion string &optional index
175;; Returns a completion entry that starts with string.
176;;
177;; find-exact-completion string
178;; Returns a completion entry that exactly matches string.
179;;
180;; complete
181;; Inserts a completion at point
182;;
183;; initialize-completions
71296446 184;; Loads the completions file and sets up so that exiting emacs will
b578f267
EN
185;; save them.
186;;
71296446 187;; save-completions-to-file &optional filename
b578f267
EN
188;; load-completions-from-file &optional filename
189;;
190;;-----------------------------------------------
191;; Other functions
192;;-----------------------------------------------
193;;
194;; get-completion-list string
195;;
196;; These things are for manipulating the structure
197;; make-completion string num-uses
71296446 198;; completion-num-uses completion
b578f267
EN
199;; completion-string completion
200;; set-completion-num-uses completion num-uses
201;; set-completion-string completion string
71296446 202;;
b578f267 203;;
59ca07b5 204\f
b578f267
EN
205;;-----------------------------------------------
206;; To Do :: (anybody ?)
207;;-----------------------------------------------
208;;
209;; Implement Lookup and keyboard interface in C
210;; Add package prefix smarts (for Common Lisp)
211;; Add autoprompting of possible completions after every keystroke (fast
212;; terminals only !)
213;; Add doc. to texinfo
214;;
215;;
216;;-----------------------------------------------
717e06e5 217;;; Change Log:
b578f267 218;;-----------------------------------------------
71296446 219;; Sometime in '84 Brewster implemented a somewhat buggy version for
b578f267 220;; Symbolics LISPMs.
71296446 221;; Jan. '85 Jim became enamored of the idea and implemented a faster,
b578f267
EN
222;; more robust version.
223;; With input from many users at TMC, (rose, craig, and gls come to mind),
71296446
JB
224;; the current style of interface was developed.
225;; 9/87, Jim and Brewster took terminals home. Yuck. After
226;; complaining for a while Brewster implemented a subset of the current
227;; LISPM version for GNU Emacs.
228;; 8/88 After complaining for a while (and with sufficient
b578f267
EN
229;; promised rewards), Jim reimplemented a version of GNU completion
230;; superior to that of the LISPM version.
231;;
232;;-----------------------------------------------
233;; Acknowledgements
234;;-----------------------------------------------
235;; Cliff Lasser (cal@think.com), Kevin Herbert (kph@cisco.com),
236;; eero@media-lab, kgk@cs.brown.edu, jla@ai.mit.edu,
237;;
238;;-----------------------------------------------
239;; Change Log
240;;-----------------------------------------------
241;; From version 9 to 10
242;; - Allowance for non-integral *completion-version* nos.
243;; - Fix cmpl-apply-as-top-level for keyboard macros
244;; - Fix broken completion merging (in save-completions-to-file)
245;; - More misc. fixes for version 19.0 of emacs
246;;
247;; From Version 8 to 9
248;; - Ported to version 19.0 of emacs (backcompatible with version 18)
249;; - Added add-completions-from-tags-table (with thanks to eero@media-lab)
250;;
251;; From Version 7 to 8
252;; - Misc. changes to comments
253;; - new completion key bindings: c-x o, M->, M-<, c-a, c-e
254;; - cdabbrev now checks all the visible window buffers and the "other buffer"
255;; - `%' is now a symbol character rather than a separator (except in C mode)
256;;
257;; From Version 6 to 7
258;; - Fixed bug with saving out .completion file the first time
259;;
260;; From Version 5 to 6
261;; - removed statistics recording
262;; - reworked advise to handle autoloads
263;; - Fixed fortran mode support
264;; - Added new cursor motion triggers
265;;
266;; From Version 4 to 5
267;; - doesn't bother saving if nothing has changed
268;; - auto-save if haven't used for a 1/2 hour
269;; - save period extended to two weeks
270;; - minor fix to capitalization code
271;; - added *completion-auto-save-period* to variables recorded.
272;; - added reenter protection to cmpl-record-statistics-filter
71296446 273;; - added backup protection to save-completions-to-file (prevents
b578f267 274;; problems with disk full errors)
59ca07b5 275\f
d1c7011d
ER
276;;; Code:
277
b578f267
EN
278;;---------------------------------------------------------------------------
279;; User changeable parameters
280;;---------------------------------------------------------------------------
59ca07b5 281
00ed33e7
RS
282(defgroup completion nil
283 "Dynamic word-completion code."
f5f727f8
DN
284 :group 'matching
285 :group 'convenience)
00ed33e7
RS
286
287
288(defcustom enable-completion t
a7a2b1f6 289 "*Non-nil means enable recording and saving of completions.
d2c49fd8 290If nil, no new words are added to the database or saved to the init file."
00ed33e7
RS
291 :type 'boolean
292 :group 'completion)
59ca07b5 293
00ed33e7 294(defcustom save-completions-flag t
a7a2b1f6 295 "*Non-nil means save most-used completions when exiting Emacs.
5c510e70 296See also `save-completions-retention-time'."
00ed33e7
RS
297 :type 'boolean
298 :group 'completion)
59ca07b5 299
00ed33e7
RS
300(defcustom save-completions-file-name (convert-standard-filename "~/.completions")
301 "*The filename to save completions to."
302 :type 'file
303 :group 'completion)
59ca07b5 304
00ed33e7 305(defcustom save-completions-retention-time 336
a7a2b1f6
RS
306 "*Discard a completion if unused for this many hours.
307\(1 day = 24, 1 week = 168). If this is 0, non-permanent completions
00ed33e7
RS
308will not be saved unless these are used. Default is two weeks."
309 :type 'integer
310 :group 'completion)
59ca07b5 311
00ed33e7 312(defcustom completion-on-separator-character nil
a7a2b1f6 313 "*Non-nil means separator characters mark previous word as used.
00ed33e7
RS
314This means the word will be saved as a completion."
315 :type 'boolean
316 :group 'completion)
59ca07b5 317
00ed33e7
RS
318(defcustom completions-file-versions-kept kept-new-versions
319 "*Number of versions to keep for the saved completions file."
320 :type 'integer
321 :group 'completion)
59ca07b5 322
00ed33e7
RS
323(defcustom completion-prompt-speed-threshold 4800
324 "*Minimum output speed at which to display next potential completion."
325 :type 'integer
326 :group 'completion)
59ca07b5 327
00ed33e7 328(defcustom completion-cdabbrev-prompt-flag nil
a7a2b1f6 329 "*If non-nil, the next completion prompt does a cdabbrev search.
00ed33e7
RS
330This can be time consuming."
331 :type 'boolean
332 :group 'completion)
59ca07b5 333
00ed33e7 334(defcustom completion-search-distance 15000
a7a2b1f6 335 "*How far to search in the buffer when looking for completions.
00ed33e7
RS
336In number of characters. If nil, search the whole buffer."
337 :type 'integer
338 :group 'completion)
59ca07b5 339
00ed33e7 340(defcustom completions-merging-modes '(lisp c)
a7a2b1f6
RS
341 "*List of modes {`c' or `lisp'} for automatic completions merging.
342Definitions from visited files which have these modes
00ed33e7
RS
343are automatically added to the completion database."
344 :type '(set (const lisp) (const c))
345 :group 'completion)
59ca07b5 346
b578f267
EN
347;;(defvar *record-cmpl-statistics-p* nil
348;; "*If non-nil, record completion statistics.")
59ca07b5 349
b578f267
EN
350;;(defvar *completion-auto-save-period* 1800
351;; "*The period in seconds to wait for emacs to be idle before autosaving
352;;the completions. Default is a 1/2 hour.")
59ca07b5 353
7975cb9f 354(defvar completion-min-length 6
59ca07b5
RS
355 "*The minimum length of a stored completion.
356DON'T CHANGE WITHOUT RECOMPILING ! This is used by macros.")
357
7975cb9f 358(defvar completion-max-length 200
59ca07b5
RS
359 "*The maximum length of a stored completion.
360DON'T CHANGE WITHOUT RECOMPILING ! This is used by macros.")
361
7975cb9f 362(defvar completion-prefix-min-length 3
59ca07b5
RS
363 "The minimum length of a completion search string.
364DON'T CHANGE WITHOUT RECOMPILING ! This is used by macros.")
365
b578f267
EN
366;;---------------------------------------------------------------------------
367;; Internal Variables
368;;---------------------------------------------------------------------------
59ca07b5
RS
369
370(defvar cmpl-initialized-p nil
a7a2b1f6
RS
371 "Set to t when the completion system is initialized.
372Indicates that the old completion file has been read in.")
59ca07b5
RS
373
374(defvar cmpl-completions-accepted-p nil
a7a2b1f6
RS
375 "Set to t as soon as the first completion has been accepted.
376Used to decide whether to save completions.")
59ca07b5 377
136f8f67 378(defvar cmpl-preceding-syntax)
438c6ef0
RS
379
380(defvar completion-string)
59ca07b5 381\f
b578f267
EN
382;;---------------------------------------------------------------------------
383;; Low level tools
384;;---------------------------------------------------------------------------
59ca07b5 385
b578f267
EN
386;;-----------------------------------------------
387;; String case coercion
388;;-----------------------------------------------
59ca07b5
RS
389
390(defun cmpl-string-case-type (string)
d2c49fd8 391 "Return :capitalized, :up, :down, :mixed, or :neither for case of STRING."
59ca07b5 392 (let ((case-fold-search nil))
d2c49fd8
DL
393 (cond ((string-match "[[:lower:]]" string)
394 (cond ((string-match "[[:upper:]]" string)
59ca07b5 395 (cond ((and (> (length string) 1)
d2c49fd8
DL
396 (null (string-match "[[:upper:]]" string 1)))
397 :capitalized)
59ca07b5 398 (t
d2c49fd8
DL
399 :mixed)))
400 (t :down)))
59ca07b5 401 (t
d2c49fd8
DL
402 (cond ((string-match "[[:upper:]]" string)
403 :up)
404 (t :neither))))))
59ca07b5 405
b578f267
EN
406;; Tests -
407;; (cmpl-string-case-type "123ABCDEF456") --> :up
408;; (cmpl-string-case-type "123abcdef456") --> :down
409;; (cmpl-string-case-type "123aBcDeF456") --> :mixed
410;; (cmpl-string-case-type "123456") --> :neither
411;; (cmpl-string-case-type "Abcde123") --> :capitalized
59ca07b5
RS
412
413(defun cmpl-coerce-string-case (string case-type)
d2c49fd8
DL
414 (cond ((eq case-type :down) (downcase string))
415 ((eq case-type :up) (upcase string))
416 ((eq case-type :capitalized)
59ca07b5
RS
417 (setq string (downcase string))
418 (aset string 0 (logand ?\337 (aref string 0)))
419 string)
d2c49fd8 420 (t string)))
59ca07b5
RS
421
422(defun cmpl-merge-string-cases (string-to-coerce given-string)
d2c49fd8 423 (let ((string-case-type (cmpl-string-case-type string-to-coerce)))
59ca07b5
RS
424 (cond ((memq string-case-type '(:down :up :capitalized))
425 ;; Found string is in a standard case. Coerce to a type based on
426 ;; the given string
427 (cmpl-coerce-string-case string-to-coerce
d2c49fd8 428 (cmpl-string-case-type given-string)))
59ca07b5
RS
429 (t
430 ;; If the found string is in some unusual case, just insert it
431 ;; as is
d2c49fd8 432 string-to-coerce))))
59ca07b5 433
b578f267
EN
434;; Tests -
435;; (cmpl-merge-string-cases "AbCdEf456" "abc") --> AbCdEf456
436;; (cmpl-merge-string-cases "abcdef456" "ABC") --> ABCDEF456
437;; (cmpl-merge-string-cases "ABCDEF456" "Abc") --> Abcdef456
438;; (cmpl-merge-string-cases "ABCDEF456" "abc") --> abcdef456
59ca07b5
RS
439
440\f
a7a2b1f6
RS
441(defun cmpl-hours-since-origin ()
442 (let ((time (current-time)))
5a3d3a16 443 (floor (+ (* 65536.0 (nth 0 time)) (nth 1 time)) 3600)))
59ca07b5 444\f
b578f267
EN
445;;---------------------------------------------------------------------------
446;; "Symbol" parsing functions
447;;---------------------------------------------------------------------------
448;; The functions symbol-before-point, symbol-under-point, etc. quickly return
449;; an appropriate symbol string. The strategy is to temporarily change
450;; the syntax table to enable fast symbol searching. There are three classes
451;; of syntax in these "symbol" syntax tables ::
452;;
453;; syntax (?_) - "symbol" chars (e.g. alphanumerics)
71296446 454;; syntax (?w) - symbol chars to ignore at end of words (e.g. period).
b578f267
EN
455;; syntax (? ) - everything else
456;;
457;; Thus by judicious use of scan-sexps and forward-word, we can get
71296446 458;; the word we want relatively fast and without consing.
b578f267
EN
459;;
460;; Why do we need a separate category for "symbol chars to ignore at ends" ?
71296446 461;; For example, in LISP we want starting :'s trimmed
b578f267
EN
462;; so keyword argument specifiers also define the keyword completion. And,
463;; for example, in C we want `.' appearing in a structure ref. to
71296446 464;; be kept intact in order to store the whole structure ref.; however, if
b578f267
EN
465;; it appears at the end of a symbol it should be discarded because it is
466;; probably used as a period.
467
468;; Here is the default completion syntax ::
469;; Symbol chars :: A-Z a-z 0-9 @ / \ * + ~ $ < > %
470;; Symbol chars to ignore at ends :: _ : . -
471;; Separator chars. :: <tab> <space> ! ^ & ( ) = ` | { } [ ] ; " ' #
472;; , ? <Everything else>
473
474;; Mode specific differences and notes ::
475;; LISP diffs ->
476;; Symbol chars :: ! & ? = ^
477;;
478;; C diffs ->
479;; Separator chars :: + * / : %
480;; A note on the hyphen (`-'). Perhaps the hyphen should also be a separator
71296446 481;; char., however, we wanted to have completion symbols include pointer
b578f267
EN
482;; references. For example, "foo->bar" is a symbol as far as completion is
483;; concerned.
484;;
485;; FORTRAN diffs ->
486;; Separator chars :: + - * / :
487;;
488;; Pathname diffs ->
489;; Symbol chars :: .
490;; Of course there is no pathname "mode" and in fact we have not implemented
491;; this table. However, if there was such a mode, this is what it would look
492;; like.
493
494;;-----------------------------------------------
495;; Table definitions
496;;-----------------------------------------------
59ca07b5 497
a7a2b1f6 498(defun cmpl-make-standard-completion-syntax-table ()
1aa323ac 499 (let ((table (make-syntax-table))
136f8f67 500 i)
1aa323ac
RS
501 ;; Default syntax is whitespace.
502 (setq i 0)
503 (while (< i 256)
504 (modify-syntax-entry i " " table)
505 (setq i (1+ i)))
59ca07b5 506 ;; alpha chars
136f8f67
RS
507 (setq i 0)
508 (while (< i 26)
59ca07b5 509 (modify-syntax-entry (+ ?a i) "_" table)
136f8f67
RS
510 (modify-syntax-entry (+ ?A i) "_" table)
511 (setq i (1+ i)))
59ca07b5 512 ;; digit chars.
136f8f67
RS
513 (setq i 0)
514 (while (< i 10)
515 (modify-syntax-entry (+ ?0 i) "_" table)
516 (setq i (1+ i)))
59ca07b5
RS
517 ;; Other ones
518 (let ((symbol-chars '(?@ ?/ ?\\ ?* ?+ ?~ ?$ ?< ?> ?%))
d2c49fd8 519 (symbol-chars-ignore '(?_ ?- ?: ?.)))
3f429351 520 (dolist (char symbol-chars)
59ca07b5 521 (modify-syntax-entry char "_" table))
3f429351 522 (dolist (char symbol-chars-ignore)
d2c49fd8 523 (modify-syntax-entry char "w" table)))
59ca07b5
RS
524 table))
525
a7a2b1f6 526(defconst cmpl-standard-syntax-table (cmpl-make-standard-completion-syntax-table))
59ca07b5 527
a7a2b1f6 528(defun cmpl-make-lisp-completion-syntax-table ()
59ca07b5 529 (let ((table (copy-syntax-table cmpl-standard-syntax-table))
d2c49fd8 530 (symbol-chars '(?! ?& ?? ?= ?^)))
3f429351 531 (dolist (char symbol-chars)
59ca07b5
RS
532 (modify-syntax-entry char "_" table))
533 table))
71296446 534
a7a2b1f6 535(defun cmpl-make-c-completion-syntax-table ()
59ca07b5 536 (let ((table (copy-syntax-table cmpl-standard-syntax-table))
d2c49fd8 537 (separator-chars '(?+ ?* ?/ ?: ?%)))
3f429351 538 (dolist (char separator-chars)
59ca07b5
RS
539 (modify-syntax-entry char " " table))
540 table))
541
a7a2b1f6 542(defun cmpl-make-fortran-completion-syntax-table ()
59ca07b5 543 (let ((table (copy-syntax-table cmpl-standard-syntax-table))
d2c49fd8 544 (separator-chars '(?+ ?- ?* ?/ ?:)))
3f429351 545 (dolist (char separator-chars)
59ca07b5
RS
546 (modify-syntax-entry char " " table))
547 table))
548
a7a2b1f6
RS
549(defconst cmpl-lisp-syntax-table (cmpl-make-lisp-completion-syntax-table))
550(defconst cmpl-c-syntax-table (cmpl-make-c-completion-syntax-table))
551(defconst cmpl-fortran-syntax-table (cmpl-make-fortran-completion-syntax-table))
59ca07b5
RS
552
553(defvar cmpl-syntax-table cmpl-standard-syntax-table
554 "This variable holds the current completion syntax table.")
555(make-variable-buffer-local 'cmpl-syntax-table)
556
b578f267
EN
557;;-----------------------------------------------
558;; Symbol functions
559;;-----------------------------------------------
59ca07b5 560(defvar cmpl-symbol-start nil
a7a2b1f6 561 "Holds first character of symbol, after any completion symbol function.")
59ca07b5 562(defvar cmpl-symbol-end nil
a7a2b1f6 563 "Holds last character of symbol, after any completion symbol function.")
b578f267
EN
564;; These are temp. vars. we use to avoid using let.
565;; Why ? Small speed improvement.
59ca07b5
RS
566(defvar cmpl-saved-syntax nil)
567(defvar cmpl-saved-point nil)
568
569(defun symbol-under-point ()
7975cb9f 570 "Return the symbol that the point is currently on.
a7a2b1f6 571But only if it is longer than `completion-min-length'."
59ca07b5 572 (setq cmpl-saved-syntax (syntax-table))
6f71c5cd
KH
573 (unwind-protect
574 (progn
575 (set-syntax-table cmpl-syntax-table)
71296446 576 (cond
6f71c5cd 577 ;; Cursor is on following-char and after preceding-char
71296446 578 ((memq (char-syntax (following-char)) '(?w ?_))
6f71c5cd
KH
579 (setq cmpl-saved-point (point)
580 cmpl-symbol-start (scan-sexps (1+ cmpl-saved-point) -1)
581 cmpl-symbol-end (scan-sexps cmpl-saved-point 1))
582 ;; Remove chars to ignore at the start.
583 (cond ((= (char-syntax (char-after cmpl-symbol-start)) ?w)
584 (goto-char cmpl-symbol-start)
585 (forward-word 1)
586 (setq cmpl-symbol-start (point))
d2c49fd8 587 (goto-char cmpl-saved-point)))
6f71c5cd
KH
588 ;; Remove chars to ignore at the end.
589 (cond ((= (char-syntax (char-after (1- cmpl-symbol-end))) ?w)
590 (goto-char cmpl-symbol-end)
591 (forward-word -1)
592 (setq cmpl-symbol-end (point))
d2c49fd8 593 (goto-char cmpl-saved-point)))
6f71c5cd 594 ;; Return completion if the length is reasonable.
7975cb9f 595 (if (and (<= completion-min-length
6f71c5cd
KH
596 (- cmpl-symbol-end cmpl-symbol-start))
597 (<= (- cmpl-symbol-end cmpl-symbol-start)
7975cb9f 598 completion-max-length))
6f71c5cd
KH
599 (buffer-substring cmpl-symbol-start cmpl-symbol-end)))))
600 (set-syntax-table cmpl-saved-syntax)))
59ca07b5 601
b578f267
EN
602;; tests for symbol-under-point
603;; `^' indicates cursor pos. where value is returned
604;; simple-word-test
605;; ^^^^^^^^^^^^^^^^ --> simple-word-test
606;; _harder_word_test_
607;; ^^^^^^^^^^^^^^^^^^ --> harder_word_test
608;; .___.______.
609;; --> nil
610;; /foo/bar/quux.hello
611;; ^^^^^^^^^^^^^^^^^^^ --> /foo/bar/quux.hello
612;;
59ca07b5
RS
613
614(defun symbol-before-point ()
7975cb9f 615 "Return a string of the symbol immediately before point.
71296446 616Returns nil if there isn't one longer than `completion-min-length'."
59ca07b5
RS
617 ;; This is called when a word separator is typed so it must be FAST !
618 (setq cmpl-saved-syntax (syntax-table))
6f71c5cd
KH
619 (unwind-protect
620 (progn
621 (set-syntax-table cmpl-syntax-table)
622 ;; Cursor is on following-char and after preceding-char
623 (cond ((= (setq cmpl-preceding-syntax (char-syntax (preceding-char))) ?_)
624 ;; Number of chars to ignore at end.
625 (setq cmpl-symbol-end (point)
d2c49fd8 626 cmpl-symbol-start (scan-sexps cmpl-symbol-end -1))
6f71c5cd
KH
627 ;; Remove chars to ignore at the start.
628 (cond ((= (char-syntax (char-after cmpl-symbol-start)) ?w)
629 (goto-char cmpl-symbol-start)
630 (forward-word 1)
631 (setq cmpl-symbol-start (point))
d2c49fd8 632 (goto-char cmpl-symbol-end)))
6f71c5cd
KH
633 ;; Return value if long enough.
634 (if (>= cmpl-symbol-end
7975cb9f 635 (+ cmpl-symbol-start completion-min-length))
d2c49fd8 636 (buffer-substring cmpl-symbol-start cmpl-symbol-end)))
6f71c5cd
KH
637 ((= cmpl-preceding-syntax ?w)
638 ;; chars to ignore at end
639 (setq cmpl-saved-point (point)
640 cmpl-symbol-start (scan-sexps cmpl-saved-point -1))
641 ;; take off chars. from end
642 (forward-word -1)
643 (setq cmpl-symbol-end (point))
644 ;; remove chars to ignore at the start
645 (cond ((= (char-syntax (char-after cmpl-symbol-start)) ?w)
646 (goto-char cmpl-symbol-start)
647 (forward-word 1)
d2c49fd8 648 (setq cmpl-symbol-start (point))))
6f71c5cd
KH
649 ;; Restore state.
650 (goto-char cmpl-saved-point)
651 ;; Return completion if the length is reasonable
7975cb9f 652 (if (and (<= completion-min-length
6f71c5cd
KH
653 (- cmpl-symbol-end cmpl-symbol-start))
654 (<= (- cmpl-symbol-end cmpl-symbol-start)
7975cb9f 655 completion-max-length))
6f71c5cd
KH
656 (buffer-substring cmpl-symbol-start cmpl-symbol-end)))))
657 (set-syntax-table cmpl-saved-syntax)))
59ca07b5 658
b578f267
EN
659;; tests for symbol-before-point
660;; `^' indicates cursor pos. where value is returned
661;; simple-word-test
662;; ^ --> nil
663;; ^ --> nil
664;; ^ --> simple-w
665;; ^ --> simple-word-test
666;; _harder_word_test_
667;; ^ --> harder_word_test
668;; ^ --> harder_word_test
669;; ^ --> harder
670;; .___....
671;; --> nil
59ca07b5
RS
672
673(defun symbol-under-or-before-point ()
b578f267
EN
674 ;; This could be made slightly faster but it is better to avoid
675 ;; copying all the code.
676 ;; However, it is only used by the completion string prompter.
677 ;; If it comes into common use, it could be rewritten.
6f71c5cd
KH
678 (cond ((memq (progn
679 (setq cmpl-saved-syntax (syntax-table))
680 (unwind-protect
681 (progn
682 (set-syntax-table cmpl-syntax-table)
683 (char-syntax (following-char)))
684 (set-syntax-table cmpl-saved-syntax)))
685 '(?w ?_))
59ca07b5
RS
686 (symbol-under-point))
687 (t
6f71c5cd 688 (symbol-before-point))))
59ca07b5
RS
689
690
691(defun symbol-before-point-for-complete ()
692 ;; "Returns a string of the symbol immediately before point
693 ;; or nil if there isn't one. Like symbol-before-point but doesn't trim the
694 ;; end chars."
695 ;; Cursor is on following-char and after preceding-char
696 (setq cmpl-saved-syntax (syntax-table))
6f71c5cd
KH
697 (unwind-protect
698 (progn
699 (set-syntax-table cmpl-syntax-table)
700 (cond ((memq (setq cmpl-preceding-syntax (char-syntax (preceding-char)))
701 '(?_ ?w))
702 (setq cmpl-symbol-end (point)
d2c49fd8 703 cmpl-symbol-start (scan-sexps cmpl-symbol-end -1))
6f71c5cd
KH
704 ;; Remove chars to ignore at the start.
705 (cond ((= (char-syntax (char-after cmpl-symbol-start)) ?w)
706 (goto-char cmpl-symbol-start)
707 (forward-word 1)
708 (setq cmpl-symbol-start (point))
d2c49fd8 709 (goto-char cmpl-symbol-end)))
6f71c5cd 710 ;; Return completion if the length is reasonable.
7975cb9f 711 (if (and (<= completion-prefix-min-length
6f71c5cd
KH
712 (- cmpl-symbol-end cmpl-symbol-start))
713 (<= (- cmpl-symbol-end cmpl-symbol-start)
7975cb9f 714 completion-max-length))
6f71c5cd
KH
715 (buffer-substring cmpl-symbol-start cmpl-symbol-end)))))
716 ;; Restore syntax table.
717 (set-syntax-table cmpl-saved-syntax)))
59ca07b5 718
b578f267
EN
719;; tests for symbol-before-point-for-complete
720;; `^' indicates cursor pos. where value is returned
721;; simple-word-test
722;; ^ --> nil
723;; ^ --> nil
724;; ^ --> simple-w
725;; ^ --> simple-word-test
726;; _harder_word_test_
727;; ^ --> harder_word_test
728;; ^ --> harder_word_test_
729;; ^ --> harder_
730;; .___....
731;; --> nil
59ca07b5
RS
732
733
734\f
b578f267
EN
735;;---------------------------------------------------------------------------
736;; Statistics Recording
737;;---------------------------------------------------------------------------
59ca07b5 738
b578f267
EN
739;; Note that the guts of this has been turned off. The guts
740;; are in completion-stats.el.
59ca07b5 741
b578f267
EN
742;;-----------------------------------------------
743;; Conditionalizing code on *record-cmpl-statistics-p*
744;;-----------------------------------------------
745;; All statistics code outside this block should use this
a7a2b1f6 746(defmacro cmpl-statistics-block (&rest body))
b578f267
EN
747;; "Only executes body if we are recording statistics."
748;; (list 'cond
749;; (list* '*record-cmpl-statistics-p* body)
71296446 750;; ))
59ca07b5 751
b578f267
EN
752;;-----------------------------------------------
753;; Completion Sources
754;;-----------------------------------------------
59ca07b5
RS
755
756;; ID numbers
757(defconst cmpl-source-unknown 0)
758(defconst cmpl-source-init-file 1)
759(defconst cmpl-source-file-parsing 2)
760(defconst cmpl-source-separator 3)
761(defconst cmpl-source-cursor-moves 4)
762(defconst cmpl-source-interactive 5)
763(defconst cmpl-source-cdabbrev 6)
764(defconst num-cmpl-sources 7)
765(defvar current-completion-source cmpl-source-unknown)
766
767
768\f
b578f267
EN
769;;---------------------------------------------------------------------------
770;; Completion Method #2: dabbrev-expand style
771;;---------------------------------------------------------------------------
772;;
71296446 773;; This method is used if there are no useful stored completions. It is
b578f267
EN
774;; based on dabbrev-expand with these differences :
775;; 1) Faster (we don't use regexps)
776;; 2) case coercion handled correctly
777;; This is called cdabbrev to differentiate it.
778;; We simply search backwards through the file looking for words which
779;; start with the same letters we are trying to complete.
780;;
59ca07b5
RS
781
782(defvar cdabbrev-completions-tried nil)
b578f267 783;; "A list of all the cdabbrev completions since the last reset.")
59ca07b5
RS
784
785(defvar cdabbrev-current-point 0)
b578f267 786;; "The current point position the cdabbrev search is at.")
59ca07b5
RS
787
788(defvar cdabbrev-current-window nil)
bb310d1e
RS
789;; "The current window we are looking for cdabbrevs in.
790;; Return t if looking in (other-buffer), nil if no more cdabbrevs.")
59ca07b5
RS
791
792(defvar cdabbrev-wrapped-p nil)
bb310d1e 793;; "Return t if the cdabbrev search has wrapped around the file.")
59ca07b5
RS
794
795(defvar cdabbrev-abbrev-string "")
796(defvar cdabbrev-start-point 0)
136f8f67 797(defvar cdabbrev-stop-point)
59ca07b5 798
b578f267
EN
799;; Test strings for cdabbrev
800;; cdat-upcase ;;same namestring
801;; CDAT-UPCASE ;;ok
802;; cdat2 ;;too short
803;; cdat-1-2-3-4 ;;ok
804;; a-cdat-1 ;;doesn't start correctly
805;; cdat-simple ;;ok
59ca07b5
RS
806
807
808(defun reset-cdabbrev (abbrev-string &optional initial-completions-tried)
7975cb9f 809 "Reset the cdabbrev search to search for ABBREV-STRING.
a7a2b1f6 810INITIAL-COMPLETIONS-TRIED is a list of downcased strings to ignore
59ca07b5
RS
811during the search."
812 (setq cdabbrev-abbrev-string abbrev-string
813 cdabbrev-completions-tried
d2c49fd8
DL
814 (cons (downcase abbrev-string) initial-completions-tried))
815 (reset-cdabbrev-window t))
59ca07b5
RS
816
817(defun set-cdabbrev-buffer ()
0ff9b955 818 ;; cdabbrev-current-window must not be nil
59ca07b5
RS
819 (set-buffer (if (eq cdabbrev-current-window t)
820 (other-buffer)
d2c49fd8 821 (window-buffer cdabbrev-current-window))))
59ca07b5
RS
822
823
824(defun reset-cdabbrev-window (&optional initializep)
7975cb9f 825 "Reset the cdabbrev search to search for abbrev-string."
59ca07b5
RS
826 ;; Set the window
827 (cond (initializep
d2c49fd8 828 (setq cdabbrev-current-window (selected-window)))
59ca07b5
RS
829 ((eq cdabbrev-current-window t)
830 ;; Everything has failed
831 (setq cdabbrev-current-window nil))
832 (cdabbrev-current-window
833 (setq cdabbrev-current-window (next-window cdabbrev-current-window))
834 (if (eq cdabbrev-current-window (selected-window))
835 ;; No more windows, try other buffer.
d2c49fd8 836 (setq cdabbrev-current-window t))))
136f8f67
RS
837 (if cdabbrev-current-window
838 (save-excursion
839 (set-cdabbrev-buffer)
840 (setq cdabbrev-current-point (point)
841 cdabbrev-start-point cdabbrev-current-point
842 cdabbrev-stop-point
843 (if completion-search-distance
844 (max (point-min)
845 (- cdabbrev-start-point completion-search-distance))
846 (point-min))
d2c49fd8 847 cdabbrev-wrapped-p nil))))
59ca07b5
RS
848
849(defun next-cdabbrev ()
850 "Return the next possible cdabbrev expansion or nil if there isn't one.
a7a2b1f6
RS
851`reset-cdabbrev' must've been called already.
852This is sensitive to `case-fold-search'."
59ca07b5
RS
853 ;; note that case-fold-search affects the behavior of this function
854 ;; Bug: won't pick up an expansion that starts at the top of buffer
136f8f67 855 (if cdabbrev-current-window
71296446 856 (let (saved-point
136f8f67
RS
857 saved-syntax
858 (expansion nil)
859 downcase-expansion tried-list syntax saved-point-2)
860 (save-excursion
861 (unwind-protect
862 (progn
863 ;; Switch to current completion buffer
864 (set-cdabbrev-buffer)
865 ;; Save current buffer state
866 (setq saved-point (point)
867 saved-syntax (syntax-table))
868 ;; Restore completion state
869 (set-syntax-table cmpl-syntax-table)
870 (goto-char cdabbrev-current-point)
871 ;; Loop looking for completions
872 (while
873 ;; This code returns t if it should loop again
874 (cond
875 (;; search for the string
876 (search-backward cdabbrev-abbrev-string cdabbrev-stop-point t)
877 ;; return nil if the completion is valid
878 (not
879 (and
880 ;; does it start with a separator char ?
881 (or (= (setq syntax (char-syntax (preceding-char))) ? )
882 (and (= syntax ?w)
883 ;; symbol char to ignore at end. Are we at end ?
884 (progn
885 (setq saved-point-2 (point))
886 (forward-word -1)
887 (prog1
888 (= (char-syntax (preceding-char)) ? )
d2c49fd8 889 (goto-char saved-point-2)))))
136f8f67
RS
890 ;; is the symbol long enough ?
891 (setq expansion (symbol-under-point))
892 ;; have we not tried this one before
893 (progn
894 ;; See if we've already used it
895 (setq tried-list cdabbrev-completions-tried
896 downcase-expansion (downcase expansion))
897 (while (and tried-list
898 (not (string-equal downcase-expansion
899 (car tried-list))))
900 ;; Already tried, don't choose this one
d2c49fd8 901 (setq tried-list (cdr tried-list)))
136f8f67
RS
902 ;; at this point tried-list will be nil if this
903 ;; expansion has not yet been tried
904 (if tried-list
905 (setq expansion nil)
d2c49fd8 906 t)))))
136f8f67
RS
907 ;; search failed
908 (cdabbrev-wrapped-p
909 ;; If already wrapped, then we've failed completely
910 nil)
911 (t
912 ;; need to wrap
913 (goto-char (setq cdabbrev-current-point
914 (if completion-search-distance
915 (min (point-max) (+ cdabbrev-start-point completion-search-distance))
916 (point-max))))
917
d2c49fd8 918 (setq cdabbrev-wrapped-p t))))
136f8f67
RS
919 ;; end of while loop
920 (cond (expansion
921 ;; successful
922 (setq cdabbrev-completions-tried
923 (cons downcase-expansion cdabbrev-completions-tried)
d2c49fd8 924 cdabbrev-current-point (point)))))
136f8f67 925 (set-syntax-table saved-syntax)
d2c49fd8 926 (goto-char saved-point)))
136f8f67
RS
927 ;; If no expansion, go to next window
928 (cond (expansion)
929 (t (reset-cdabbrev-window)
930 (next-cdabbrev))))))
59ca07b5 931
b578f267
EN
932;; The following must be eval'd in the minibuffer ::
933;; (reset-cdabbrev "cdat")
934;; (next-cdabbrev) --> "cdat-simple"
935;; (next-cdabbrev) --> "cdat-1-2-3-4"
936;; (next-cdabbrev) --> "CDAT-UPCASE"
937;; (next-cdabbrev) --> "cdat-wrapping"
938;; (next-cdabbrev) --> "cdat_start_sym"
939;; (next-cdabbrev) --> nil
940;; (next-cdabbrev) --> nil
941;; (next-cdabbrev) --> nil
59ca07b5 942
b578f267
EN
943;; _cdat_start_sym
944;; cdat-wrapping
59ca07b5
RS
945
946\f
b578f267
EN
947;;---------------------------------------------------------------------------
948;; Completion Database
949;;---------------------------------------------------------------------------
950
951;; We use two storage modes for the two search types ::
952;; 1) Prefix {cmpl-prefix-obarray} for looking up possible completions
953;; Used by search-completion-next
954;; the value of the symbol is nil or a cons of head and tail pointers
955;; 2) Interning {cmpl-obarray} to see if it's in the database
956;; Used by find-exact-completion, completion-in-database-p
957;; The value of the symbol is the completion entry
958
959;; bad things may happen if this length is changed due to the way
960;; GNU implements obarrays
59ca07b5
RS
961(defconst cmpl-obarray-length 511)
962
963(defvar cmpl-prefix-obarray (make-vector cmpl-obarray-length 0)
eb8c3be9 964 "An obarray used to store the downcased completion prefixes.
59ca07b5
RS
965Each symbol is bound to a list of completion entries.")
966
967(defvar cmpl-obarray (make-vector cmpl-obarray-length 0)
968 "An obarray used to store the downcased completions.
969Each symbol is bound to a single completion entry.")
970
b578f267
EN
971;;-----------------------------------------------
972;; Completion Entry Structure Definition
973;;-----------------------------------------------
59ca07b5 974
b578f267
EN
975;; A completion entry is a LIST of string, prefix-symbol num-uses, and
976;; last-use-time (the time the completion was last used)
0ff9b955 977;; last-use-time is t if the string should be kept permanently
b578f267 978;; num-uses is incremented every time the completion is used.
59ca07b5 979
71296446 980;; We chose lists because (car foo) is faster than (aref foo 0) and the
b578f267 981;; creation time is about the same.
59ca07b5 982
b578f267 983;; READER MACROS
59ca07b5
RS
984
985(defmacro completion-string (completion-entry)
986 (list 'car completion-entry))
987
988(defmacro completion-num-uses (completion-entry)
71296446 989 ;; "The number of times it has used. Used to decide whether to save
59ca07b5
RS
990 ;; it."
991 (list 'car (list 'cdr completion-entry)))
992
993(defmacro completion-last-use-time (completion-entry)
a7a2b1f6 994 ;; "The time it was last used. In hours since origin. Used to decide
0ff9b955 995 ;; whether to save it. t if one should always save it."
59ca07b5
RS
996 (list 'nth 2 completion-entry))
997
998(defmacro completion-source (completion-entry)
999 (list 'nth 3 completion-entry))
1000
b578f267 1001;; WRITER MACROS
59ca07b5
RS
1002(defmacro set-completion-string (completion-entry string)
1003 (list 'setcar completion-entry string))
1004
1005(defmacro set-completion-num-uses (completion-entry num-uses)
1006 (list 'setcar (list 'cdr completion-entry) num-uses))
1007
1008(defmacro set-completion-last-use-time (completion-entry last-use-time)
1009 (list 'setcar (list 'cdr (list 'cdr completion-entry)) last-use-time))
1010
b578f267 1011;; CONSTRUCTOR
59ca07b5 1012(defun make-completion (string)
7975cb9f 1013 "Return a list of a completion entry."
59ca07b5
RS
1014 (list (list string 0 nil current-completion-source)))
1015
1016;; Obsolete
1017;;(defmacro cmpl-prefix-entry-symbol (completion-entry)
1018;; (list 'car (list 'cdr completion-entry)))
1019
1020
1021\f
b578f267
EN
1022;;-----------------------------------------------
1023;; Prefix symbol entry definition
1024;;-----------------------------------------------
1025;; A cons of (head . tail)
59ca07b5 1026
b578f267 1027;; READER Macros
59ca07b5
RS
1028
1029(defmacro cmpl-prefix-entry-head (prefix-entry)
1030 (list 'car prefix-entry))
1031
1032(defmacro cmpl-prefix-entry-tail (prefix-entry)
1033 (list 'cdr prefix-entry))
1034
b578f267 1035;; WRITER Macros
59ca07b5
RS
1036
1037(defmacro set-cmpl-prefix-entry-head (prefix-entry new-head)
1038 (list 'setcar prefix-entry new-head))
1039
1040(defmacro set-cmpl-prefix-entry-tail (prefix-entry new-tail)
1041 (list 'setcdr prefix-entry new-tail))
1042
b578f267 1043;; Constructor
59ca07b5
RS
1044
1045(defun make-cmpl-prefix-entry (completion-entry-list)
7975cb9f 1046 "Make a new prefix entry containing only completion-entry."
59ca07b5
RS
1047 (cons completion-entry-list completion-entry-list))
1048
b578f267
EN
1049;;-----------------------------------------------
1050;; Completion Database - Utilities
1051;;-----------------------------------------------
59ca07b5
RS
1052
1053(defun clear-all-completions ()
d2c49fd8 1054 "Initialize the completion storage. All existing completions are lost."
59ca07b5
RS
1055 (interactive)
1056 (setq cmpl-prefix-obarray (make-vector cmpl-obarray-length 0))
1057 (setq cmpl-obarray (make-vector cmpl-obarray-length 0))
1058 (cmpl-statistics-block
d2c49fd8 1059 (record-clear-all-completions)))
59ca07b5 1060
136f8f67
RS
1061(defvar completions-list-return-value)
1062
59ca07b5 1063(defun list-all-completions ()
d2c49fd8 1064 "Return a list of all the known completion entries."
136f8f67 1065 (let ((completions-list-return-value nil))
59ca07b5 1066 (mapatoms 'list-all-completions-1 cmpl-prefix-obarray)
136f8f67 1067 completions-list-return-value))
59ca07b5
RS
1068
1069(defun list-all-completions-1 (prefix-symbol)
1070 (if (boundp prefix-symbol)
136f8f67 1071 (setq completions-list-return-value
59ca07b5 1072 (append (cmpl-prefix-entry-head (symbol-value prefix-symbol))
136f8f67 1073 completions-list-return-value))))
59ca07b5
RS
1074
1075(defun list-all-completions-by-hash-bucket ()
a7a2b1f6 1076 "Return list of lists of known completion entries, organized by hash bucket."
136f8f67 1077 (let ((completions-list-return-value nil))
59ca07b5 1078 (mapatoms 'list-all-completions-by-hash-bucket-1 cmpl-prefix-obarray)
136f8f67 1079 completions-list-return-value))
59ca07b5
RS
1080
1081(defun list-all-completions-by-hash-bucket-1 (prefix-symbol)
1082 (if (boundp prefix-symbol)
136f8f67 1083 (setq completions-list-return-value
59ca07b5 1084 (cons (cmpl-prefix-entry-head (symbol-value prefix-symbol))
136f8f67 1085 completions-list-return-value))))
59ca07b5
RS
1086
1087\f
b578f267
EN
1088;;-----------------------------------------------
1089;; Updating the database
1090;;-----------------------------------------------
1091;;
1092;; These are the internal functions used to update the datebase
1093;;
1094;;
59ca07b5
RS
1095(defvar completion-to-accept nil)
1096 ;;"Set to a string that is pending its acceptance."
1097 ;; this checked by the top level reading functions
1098
1099(defvar cmpl-db-downcase-string nil)
1100 ;; "Setup by find-exact-completion, etc. The given string, downcased."
1101(defvar cmpl-db-symbol nil)
1102 ;; "The interned symbol corresponding to cmpl-db-downcase-string.
1103 ;; Set up by cmpl-db-symbol."
1104(defvar cmpl-db-prefix-symbol nil)
1105 ;; "The interned prefix symbol corresponding to cmpl-db-downcase-string."
1106(defvar cmpl-db-entry nil)
1107(defvar cmpl-db-debug-p nil
0ff9b955 1108 "Set to t if you want to debug the database.")
59ca07b5 1109
b578f267 1110;; READS
59ca07b5 1111(defun find-exact-completion (string)
d2c49fd8 1112 "Return the completion entry for STRING or nil.
a7a2b1f6 1113Sets up `cmpl-db-downcase-string' and `cmpl-db-symbol'."
59ca07b5
RS
1114 (and (boundp (setq cmpl-db-symbol
1115 (intern (setq cmpl-db-downcase-string (downcase string))
1116 cmpl-obarray)))
d2c49fd8 1117 (symbol-value cmpl-db-symbol)))
59ca07b5
RS
1118
1119(defun find-cmpl-prefix-entry (prefix-string)
d2c49fd8 1120 "Return the prefix entry for string.
a7a2b1f6
RS
1121Sets `cmpl-db-prefix-symbol'.
1122Prefix-string must be exactly `completion-prefix-min-length' long
1123and downcased. Sets up `cmpl-db-prefix-symbol'."
59ca07b5
RS
1124 (and (boundp (setq cmpl-db-prefix-symbol
1125 (intern prefix-string cmpl-prefix-obarray)))
1126 (symbol-value cmpl-db-prefix-symbol)))
1127
1128(defvar inside-locate-completion-entry nil)
1129;; used to trap lossage in silent error correction
1130
1131(defun locate-completion-entry (completion-entry prefix-entry)
d2c49fd8 1132 "Locate the completion entry.
c2ced5d8
CZ
1133Returns a pointer to the element before the completion entry or nil if
1134the completion entry is at the head.
a7a2b1f6 1135Must be called after `find-exact-completion'."
59ca07b5 1136 (let ((prefix-list (cmpl-prefix-entry-head prefix-entry))
d2c49fd8 1137 next-prefix-list)
59ca07b5
RS
1138 (cond
1139 ((not (eq (car prefix-list) completion-entry))
1140 ;; not already at head
1141 (while (and prefix-list
1142 (not (eq completion-entry
d2c49fd8 1143 (car (setq next-prefix-list (cdr prefix-list))))))
59ca07b5
RS
1144 (setq prefix-list next-prefix-list))
1145 (cond (;; found
1146 prefix-list)
1147 ;; Didn't find it. Database is messed up.
1148 (cmpl-db-debug-p
1149 ;; not found, error if debug mode
1150 (error "Completion entry exists but not on prefix list - %s"
136f8f67 1151 completion-string))
59ca07b5
RS
1152 (inside-locate-completion-entry
1153 ;; recursive error: really scrod
1154 (locate-completion-db-error))
1155 (t
1156 ;; Patch out
1157 (set cmpl-db-symbol nil)
1158 ;; Retry
d2c49fd8 1159 (locate-completion-entry-retry completion-entry)))))))
59ca07b5
RS
1160
1161(defun locate-completion-entry-retry (old-entry)
1162 (let ((inside-locate-completion-entry t))
1163 (add-completion (completion-string old-entry)
1164 (completion-num-uses old-entry)
1165 (completion-last-use-time old-entry))
136f8f67
RS
1166 (let* ((cmpl-entry (find-exact-completion (completion-string old-entry)))
1167 (pref-entry
1168 (if cmpl-entry
1169 (find-cmpl-prefix-entry
1170 (substring cmpl-db-downcase-string
d2c49fd8 1171 0 completion-prefix-min-length)))))
59ca07b5
RS
1172 (if (and cmpl-entry pref-entry)
1173 ;; try again
1174 (locate-completion-entry cmpl-entry pref-entry)
1175 ;; still losing
d2c49fd8 1176 (locate-completion-db-error)))))
59ca07b5
RS
1177
1178(defun locate-completion-db-error ()
1179 ;; recursive error: really scrod
55535639 1180 (error "Completion database corrupted. Try M-x clear-all-completions. Send bug report"))
59ca07b5 1181
b578f267 1182;; WRITES
59ca07b5 1183(defun add-completion-to-tail-if-new (string)
c2ced5d8 1184 "If STRING is not in the database add it to appropriate prefix list.
eb8c3be9 1185STRING is added to the end of the appropriate prefix list with
c2ced5d8 1186num-uses = 0. The database is unchanged if it is there. STRING must be
a7a2b1f6 1187longer than `completion-prefix-min-length'.
59ca07b5
RS
1188This must be very fast.
1189Returns the completion entry."
1190 (or (find-exact-completion string)
1191 ;; not there
1192 (let (;; create an entry
1193 (entry (make-completion string))
1194 ;; setup the prefix
1195 (prefix-entry (find-cmpl-prefix-entry
1196 (substring cmpl-db-downcase-string 0
7975cb9f 1197 completion-prefix-min-length))))
59ca07b5
RS
1198 ;; The next two forms should happen as a unit (atomically) but
1199 ;; no fatal errors should result if that is not the case.
1200 (cond (prefix-entry
1201 ;; These two should be atomic, but nothing fatal will happen
1202 ;; if they're not.
1203 (setcdr (cmpl-prefix-entry-tail prefix-entry) entry)
1204 (set-cmpl-prefix-entry-tail prefix-entry entry))
1205 (t
d2c49fd8 1206 (set cmpl-db-prefix-symbol (make-cmpl-prefix-entry entry))))
59ca07b5
RS
1207 ;; statistics
1208 (cmpl-statistics-block
1209 (note-added-completion))
1210 ;; set symbol
d2c49fd8 1211 (set cmpl-db-symbol (car entry)))))
59ca07b5 1212
136f8f67
RS
1213(defun add-completion-to-head (completion-string)
1214 "If COMPLETION-STRING is not in the database, add it to prefix list.
1215We add COMPLETION-STRING to the head of the appropriate prefix list,
1216or it to the head of the list.
1217COMPLETION-STRING must be longer than `completion-prefix-min-length'.
59ca07b5
RS
1218Updates the saved string with the supplied string.
1219This must be very fast.
1220Returns the completion entry."
1221 ;; Handle pending acceptance
1222 (if completion-to-accept (accept-completion))
1223 ;; test if already in database
136f8f67 1224 (if (setq cmpl-db-entry (find-exact-completion completion-string))
59ca07b5
RS
1225 ;; found
1226 (let* ((prefix-entry (find-cmpl-prefix-entry
1227 (substring cmpl-db-downcase-string 0
7975cb9f 1228 completion-prefix-min-length)))
59ca07b5 1229 (splice-ptr (locate-completion-entry cmpl-db-entry prefix-entry))
d2c49fd8 1230 (cmpl-ptr (cdr splice-ptr)))
59ca07b5 1231 ;; update entry
136f8f67 1232 (set-completion-string cmpl-db-entry completion-string)
59ca07b5
RS
1233 ;; move to head (if necessary)
1234 (cond (splice-ptr
1235 ;; These should all execute atomically but it is not fatal if
1236 ;; they don't.
1237 ;; splice it out
1238 (or (setcdr splice-ptr (cdr cmpl-ptr))
1239 ;; fix up tail if necessary
1240 (set-cmpl-prefix-entry-tail prefix-entry splice-ptr))
1241 ;; splice in at head
1242 (setcdr cmpl-ptr (cmpl-prefix-entry-head prefix-entry))
d2c49fd8 1243 (set-cmpl-prefix-entry-head prefix-entry cmpl-ptr)))
59ca07b5
RS
1244 cmpl-db-entry)
1245 ;; not there
1246 (let (;; create an entry
136f8f67 1247 (entry (make-completion completion-string))
59ca07b5
RS
1248 ;; setup the prefix
1249 (prefix-entry (find-cmpl-prefix-entry
1250 (substring cmpl-db-downcase-string 0
7975cb9f 1251 completion-prefix-min-length))))
59ca07b5
RS
1252 (cond (prefix-entry
1253 ;; Splice in at head
1254 (setcdr entry (cmpl-prefix-entry-head prefix-entry))
1255 (set-cmpl-prefix-entry-head prefix-entry entry))
1256 (t
1257 ;; Start new prefix entry
d2c49fd8 1258 (set cmpl-db-prefix-symbol (make-cmpl-prefix-entry entry))))
59ca07b5
RS
1259 ;; statistics
1260 (cmpl-statistics-block
1261 (note-added-completion))
1262 ;; Add it to the symbol
d2c49fd8 1263 (set cmpl-db-symbol (car entry)))))
71296446 1264
136f8f67 1265(defun delete-completion (completion-string)
d2c49fd8 1266 "Delete the completion from the database.
a7a2b1f6 1267String must be longer than `completion-prefix-min-length'."
59ca07b5
RS
1268 ;; Handle pending acceptance
1269 (if completion-to-accept (accept-completion))
136f8f67 1270 (if (setq cmpl-db-entry (find-exact-completion completion-string))
59ca07b5 1271 ;; found
71296446 1272 (let* ((prefix-entry (find-cmpl-prefix-entry
59ca07b5 1273 (substring cmpl-db-downcase-string 0
7975cb9f 1274 completion-prefix-min-length)))
d2c49fd8 1275 (splice-ptr (locate-completion-entry cmpl-db-entry prefix-entry)))
59ca07b5
RS
1276 ;; delete symbol reference
1277 (set cmpl-db-symbol nil)
1278 ;; remove from prefix list
1279 (cond (splice-ptr
1280 ;; not at head
1281 (or (setcdr splice-ptr (cdr (cdr splice-ptr)))
1282 ;; fix up tail if necessary
d2c49fd8 1283 (set-cmpl-prefix-entry-tail prefix-entry splice-ptr)))
59ca07b5
RS
1284 (t
1285 ;; at head
1286 (or (set-cmpl-prefix-entry-head
1287 prefix-entry (cdr (cmpl-prefix-entry-head prefix-entry)))
1288 ;; List is now empty
d2c49fd8 1289 (set cmpl-db-prefix-symbol nil))))
59ca07b5 1290 (cmpl-statistics-block
d2c49fd8
DL
1291 (note-completion-deleted)))
1292 (error "Unknown completion `%s'" completion-string)))
59ca07b5 1293
b578f267
EN
1294;; Tests --
1295;; - Add and Find -
1296;; (add-completion-to-head "banana") --> ("banana" 0 nil 0)
1297;; (find-exact-completion "banana") --> ("banana" 0 nil 0)
1298;; (find-exact-completion "bana") --> nil
1299;; (car (find-cmpl-prefix-entry "ban")) --> (("banana" ...))
1300;; (cdr (find-cmpl-prefix-entry "ban")) --> (("banana" ...))
1301;; (add-completion-to-head "banish") --> ("banish" 0 nil 0)
1302;; (find-exact-completion "banish") --> ("banish" 0 nil 0)
1303;; (car (find-cmpl-prefix-entry "ban")) --> (("banish" ...) ("banana" ...))
1304;; (cdr (find-cmpl-prefix-entry "ban")) --> (("banana" ...))
1305;; (add-completion-to-head "banana") --> ("banana" 0 nil 0)
1306;; (car (find-cmpl-prefix-entry "ban")) --> (("banana" ...) ("banish" ...))
1307;; (cdr (find-cmpl-prefix-entry "ban")) --> (("banish" ...))
1308;;
1309;; - Deleting -
1310;; (add-completion-to-head "banner") --> ("banner" 0 nil 0)
71296446 1311;; (delete-completion "banner")
b578f267
EN
1312;; (find-exact-completion "banner") --> nil
1313;; (car (find-cmpl-prefix-entry "ban")) --> (("banana" ...) ("banish" ...))
1314;; (cdr (find-cmpl-prefix-entry "ban")) --> (("banish" ...))
71296446
JB
1315;; (add-completion-to-head "banner") --> ("banner" 0 nil 0)
1316;; (delete-completion "banana")
b578f267
EN
1317;; (car (find-cmpl-prefix-entry "ban")) --> (("banner" ...) ("banish" ...))
1318;; (cdr (find-cmpl-prefix-entry "ban")) --> (("banish" ...))
71296446
JB
1319;; (delete-completion "banner")
1320;; (delete-completion "banish")
b578f267
EN
1321;; (find-cmpl-prefix-entry "ban") --> nil
1322;; (delete-completion "banner") --> error
1323;;
1324;; - Tail -
1325;; (add-completion-to-tail-if-new "banana") --> ("banana" 0 nil 0)
1326;; (car (find-cmpl-prefix-entry "ban")) --> (("banana" ...))
1327;; (cdr (find-cmpl-prefix-entry "ban")) --> (("banana" ...))
1328;; (add-completion-to-tail-if-new "banish") --> ("banish" 0 nil 0)
1329;; (car (find-cmpl-prefix-entry "ban")) -->(("banana" ...) ("banish" ...))
1330;; (cdr (find-cmpl-prefix-entry "ban")) -->(("banish" ...))
1331;;
59ca07b5
RS
1332
1333\f
b578f267
EN
1334;;---------------------------------------------------------------------------
1335;; Database Update :: Interface level routines
1336;;---------------------------------------------------------------------------
71296446 1337;;
b578f267
EN
1338;; These lie on top of the database ref. functions but below the standard
1339;; user interface level
59ca07b5
RS
1340
1341
1342(defun interactive-completion-string-reader (prompt)
1343 (let* ((default (symbol-under-or-before-point))
1344 (new-prompt
1345 (if default
1346 (format "%s: (default: %s) " prompt default)
d2c49fd8
DL
1347 (format "%s: " prompt)))
1348 (read (completing-read new-prompt cmpl-obarray)))
59ca07b5 1349 (if (zerop (length read)) (setq read (or default "")))
d2c49fd8 1350 (list read)))
59ca07b5
RS
1351
1352(defun check-completion-length (string)
a7a2b1f6 1353 (if (< (length string) completion-min-length)
136f8f67 1354 (error "The string `%s' is too short to be saved as a completion"
59ca07b5
RS
1355 string)
1356 (list string)))
1357
1358(defun add-completion (string &optional num-uses last-use-time)
a7a2b1f6 1359 "Add STRING to completion list, or move it to head of list.
71296446 1360The completion is altered appropriately if num-uses and/or last-use-time is
59ca07b5
RS
1361specified."
1362 (interactive (interactive-completion-string-reader "Completion to add"))
1363 (check-completion-length string)
1364 (let* ((current-completion-source (if (interactive-p)
1365 cmpl-source-interactive
1366 current-completion-source))
1367 (entry (add-completion-to-head string)))
71296446 1368
59ca07b5
RS
1369 (if num-uses (set-completion-num-uses entry num-uses))
1370 (if last-use-time
d2c49fd8 1371 (set-completion-last-use-time entry last-use-time))))
59ca07b5
RS
1372
1373(defun add-permanent-completion (string)
a7a2b1f6 1374 "Add STRING if it isn't already listed, and mark it permanent."
59ca07b5
RS
1375 (interactive
1376 (interactive-completion-string-reader "Completion to add permanently"))
1377 (let ((current-completion-source (if (interactive-p)
1378 cmpl-source-interactive
d2c49fd8
DL
1379 current-completion-source)))
1380 (add-completion string nil t)))
59ca07b5
RS
1381
1382(defun kill-completion (string)
1383 (interactive (interactive-completion-string-reader "Completion to kill"))
1384 (check-completion-length string)
d2c49fd8 1385 (delete-completion string))
59ca07b5
RS
1386
1387(defun accept-completion ()
a7a2b1f6 1388 "Accepts the pending completion in `completion-to-accept'.
71296446 1389This bumps num-uses. Called by `add-completion-to-head' and
a7a2b1f6 1390`completion-search-reset'."
59ca07b5
RS
1391 (let ((string completion-to-accept)
1392 ;; if this is added afresh here, then it must be a cdabbrev
1393 (current-completion-source cmpl-source-cdabbrev)
d2c49fd8 1394 entry)
59ca07b5
RS
1395 (setq completion-to-accept nil)
1396 (setq entry (add-completion-to-head string))
1397 (set-completion-num-uses entry (1+ (completion-num-uses entry)))
d2c49fd8 1398 (setq cmpl-completions-accepted-p t)))
59ca07b5
RS
1399
1400(defun use-completion-under-point ()
a7a2b1f6
RS
1401 "Add the completion symbol underneath the point into the completion buffer."
1402 (let ((string (and enable-completion (symbol-under-point)))
59ca07b5
RS
1403 (current-completion-source cmpl-source-cursor-moves))
1404 (if string (add-completion-to-head string))))
71296446 1405
59ca07b5 1406(defun use-completion-before-point ()
a7a2b1f6
RS
1407 "Add the completion symbol before point into the completion buffer."
1408 (let ((string (and enable-completion (symbol-before-point)))
59ca07b5
RS
1409 (current-completion-source cmpl-source-cursor-moves))
1410 (if string (add-completion-to-head string))))
1411
1412(defun use-completion-under-or-before-point ()
a7a2b1f6
RS
1413 "Add the completion symbol before point into the completion buffer."
1414 (let ((string (and enable-completion (symbol-under-or-before-point)))
59ca07b5
RS
1415 (current-completion-source cmpl-source-cursor-moves))
1416 (if string (add-completion-to-head string))))
1417
1418(defun use-completion-before-separator ()
a7a2b1f6 1419 "Add the completion symbol before point into the completion buffer.
c2ced5d8 1420Completions added this way will automatically be saved if
a7a2b1f6
RS
1421`completion-on-separator-character' is non-nil."
1422 (let ((string (and enable-completion (symbol-before-point)))
59ca07b5
RS
1423 (current-completion-source cmpl-source-separator)
1424 entry)
1425 (cmpl-statistics-block
d2c49fd8 1426 (note-separator-character string))
59ca07b5
RS
1427 (cond (string
1428 (setq entry (add-completion-to-head string))
136f8f67 1429 (if (and completion-on-separator-character
59ca07b5 1430 (zerop (completion-num-uses entry)))
136f8f67
RS
1431 (progn
1432 (set-completion-num-uses entry 1)
d2c49fd8 1433 (setq cmpl-completions-accepted-p t)))))))
59ca07b5 1434
b578f267
EN
1435;; Tests --
1436;; - Add and Find -
71296446 1437;; (add-completion "banana" 5 10)
b578f267 1438;; (find-exact-completion "banana") --> ("banana" 5 10 0)
71296446 1439;; (add-completion "banana" 6)
b578f267
EN
1440;; (find-exact-completion "banana") --> ("banana" 6 10 0)
1441;; (add-completion "banish")
1442;; (car (find-cmpl-prefix-entry "ban")) --> (("banish" ...) ("banana" ...))
1443;;
1444;; - Accepting -
1445;; (setq completion-to-accept "banana")
71296446 1446;; (accept-completion)
b578f267
EN
1447;; (find-exact-completion "banana") --> ("banana" 7 10)
1448;; (car (find-cmpl-prefix-entry "ban")) --> (("banana" ...) ("banish" ...))
1449;; (setq completion-to-accept "banish")
71296446 1450;; (add-completion "banner")
b578f267
EN
1451;; (car (find-cmpl-prefix-entry "ban"))
1452;; --> (("banner" ...) ("banish" 1 ...) ("banana" 7 ...))
1453;;
1454;; - Deleting -
71296446 1455;; (kill-completion "banish")
b578f267 1456;; (car (find-cmpl-prefix-entry "ban")) --> (("banner" ...) ("banana" ...))
59ca07b5
RS
1457
1458\f
b578f267
EN
1459;;---------------------------------------------------------------------------
1460;; Searching the database
1461;;---------------------------------------------------------------------------
1462;; Functions outside this block must call completion-search-reset followed
1463;; by calls to completion-search-next or completion-search-peek
1464;;
1465
1466;; Status variables
59ca07b5
RS
1467;; Commented out to improve loading speed
1468(defvar cmpl-test-string "")
1469;; "The current string used by completion-search-next."
1470(defvar cmpl-test-regexp "")
71296446 1471;; "The current regexp used by completion-search-next.
59ca07b5
RS
1472;; (derived from cmpl-test-string)"
1473(defvar cmpl-last-index 0)
1474;; "The last index that completion-search-next was called with."
1475(defvar cmpl-cdabbrev-reset-p nil)
1476;; "Set to t when cdabbrevs have been reset."
1477(defvar cmpl-next-possibilities nil)
1478;; "A pointer to the element BEFORE the next set of possible completions.
1479;; cadr of this is the cmpl-next-possibility"
1480(defvar cmpl-starting-possibilities nil)
1481;; "The initial list of starting possibilities."
1482(defvar cmpl-next-possibility nil)
1483;; "The cached next possibility."
1484(defvar cmpl-tried-list nil)
1485;; "A downcased list of all the completions we have tried."
1486
1487
1488(defun completion-search-reset (string)
a7a2b1f6
RS
1489 "Set up the for completion searching for STRING.
1490STRING must be longer than `completion-prefix-min-length'."
59ca07b5
RS
1491 (if completion-to-accept (accept-completion))
1492 (setq cmpl-starting-possibilities
1493 (cmpl-prefix-entry-head
46f950ca
RS
1494 (find-cmpl-prefix-entry
1495 (downcase (substring string 0 completion-prefix-min-length))))
59ca07b5
RS
1496 cmpl-test-string string
1497 cmpl-test-regexp (concat (regexp-quote string) "."))
d2c49fd8 1498 (completion-search-reset-1))
59ca07b5
RS
1499
1500(defun completion-search-reset-1 ()
1501 (setq cmpl-next-possibilities cmpl-starting-possibilities
1502 cmpl-next-possibility nil
1503 cmpl-cdabbrev-reset-p nil
1504 cmpl-last-index -1
d2c49fd8 1505 cmpl-tried-list nil))
59ca07b5
RS
1506
1507(defun completion-search-next (index)
a7a2b1f6
RS
1508 "Return the next completion entry.
1509If INDEX is out of sequence, reset and start from the top.
1510If there are no more entries, try cdabbrev and returns only a string."
59ca07b5
RS
1511 (cond
1512 ((= index (setq cmpl-last-index (1+ cmpl-last-index)))
1513 (completion-search-peek t))
136f8f67 1514 ((< index 0)
59ca07b5
RS
1515 (completion-search-reset-1)
1516 (setq cmpl-last-index index)
1517 ;; reverse the possibilities list
1518 (setq cmpl-next-possibilities (reverse cmpl-starting-possibilities))
1519 ;; do a "normal" search
1520 (while (and (completion-search-peek nil)
136f8f67 1521 (< (setq index (1+ index)) 0))
d2c49fd8 1522 (setq cmpl-next-possibility nil))
59ca07b5
RS
1523 (cond ((not cmpl-next-possibilities))
1524 ;; If no more possibilities, leave it that way
1525 ((= -1 cmpl-last-index)
71296446 1526 ;; next completion is at index 0. reset next-possibility list
59ca07b5
RS
1527 ;; to start at beginning
1528 (setq cmpl-next-possibilities cmpl-starting-possibilities))
1529 (t
1530 ;; otherwise point to one before current
1531 (setq cmpl-next-possibilities
1532 (nthcdr (- (length cmpl-starting-possibilities)
1533 (length cmpl-next-possibilities))
d2c49fd8 1534 cmpl-starting-possibilities)))))
59ca07b5
RS
1535 (t
1536 ;; non-negative index, reset and search
1537 ;;(prin1 'reset)
1538 (completion-search-reset-1)
1539 (setq cmpl-last-index index)
1540 (while (and (completion-search-peek t)
136f8f67 1541 (not (< (setq index (1- index)) 0)))
d2c49fd8 1542 (setq cmpl-next-possibility nil))))
59ca07b5
RS
1543 (prog1
1544 cmpl-next-possibility
d2c49fd8 1545 (setq cmpl-next-possibility nil)))
71296446 1546
59ca07b5
RS
1547
1548(defun completion-search-peek (use-cdabbrev)
7975cb9f 1549 "Return the next completion entry without actually moving the pointers.
71296446 1550Calling this again or calling `completion-search-next' results in the same
a7a2b1f6
RS
1551string being returned. Depends on `case-fold-search'.
1552If there are no more entries, try cdabbrev and then return only a string."
59ca07b5
RS
1553 (cond
1554 ;; return the cached value if we have it
1555 (cmpl-next-possibility)
1556 ((and cmpl-next-possibilities
1557 ;; still a few possibilities left
1558 (progn
1559 (while
1560 (and (not (eq 0 (string-match cmpl-test-regexp
1561 (completion-string (car cmpl-next-possibilities)))))
d2c49fd8
DL
1562 (setq cmpl-next-possibilities (cdr cmpl-next-possibilities))))
1563 cmpl-next-possibilities))
59ca07b5
RS
1564 ;; successful match
1565 (setq cmpl-next-possibility (car cmpl-next-possibilities)
1566 cmpl-tried-list (cons (downcase (completion-string cmpl-next-possibility))
1567 cmpl-tried-list)
d2c49fd8 1568 cmpl-next-possibilities (cdr cmpl-next-possibilities))
59ca07b5
RS
1569 cmpl-next-possibility)
1570 (use-cdabbrev
1571 ;; unsuccessful, use cdabbrev
1572 (cond ((not cmpl-cdabbrev-reset-p)
1573 (reset-cdabbrev cmpl-test-string cmpl-tried-list)
d2c49fd8
DL
1574 (setq cmpl-cdabbrev-reset-p t)))
1575 (setq cmpl-next-possibility (next-cdabbrev)))
59ca07b5
RS
1576 ;; Completely unsuccessful, return nil
1577 ))
1578
b578f267
EN
1579;; Tests --
1580;; - Add and Find -
71296446
JB
1581;; (add-completion "banana")
1582;; (completion-search-reset "ban")
b578f267
EN
1583;; (completion-search-next 0) --> "banana"
1584;;
1585;; - Discrimination -
71296446
JB
1586;; (add-completion "cumberland")
1587;; (add-completion "cumberbund")
1588;; cumbering
b578f267
EN
1589;; (completion-search-reset "cumb")
1590;; (completion-search-peek t) --> "cumberbund"
1591;; (completion-search-next 0) --> "cumberbund"
1592;; (completion-search-peek t) --> "cumberland"
1593;; (completion-search-next 1) --> "cumberland"
1594;; (completion-search-peek nil) --> nil
1595;; (completion-search-next 2) --> "cumbering" {cdabbrev}
1596;; (completion-search-next 3) --> nil or "cumming"{depends on context}
1597;; (completion-search-next 1) --> "cumberland"
1598;; (completion-search-peek t) --> "cumbering" {cdabbrev}
1599;;
1600;; - Accepting -
1601;; (completion-search-next 1) --> "cumberland"
1602;; (setq completion-to-accept "cumberland")
1603;; (completion-search-reset "foo")
1604;; (completion-search-reset "cum")
1605;; (completion-search-next 0) --> "cumberland"
1606;;
1607;; - Deleting -
1608;; (kill-completion "cumberland")
71296446 1609;; cummings
b578f267
EN
1610;; (completion-search-reset "cum")
1611;; (completion-search-next 0) --> "cumberbund"
1612;; (completion-search-next 1) --> "cummings"
1613;;
1614;; - Ignoring Capitalization -
1615;; (completion-search-reset "CuMb")
1616;; (completion-search-next 0) --> "cumberbund"
59ca07b5
RS
1617
1618
1619\f
b578f267
EN
1620;;-----------------------------------------------
1621;; COMPLETE
1622;;-----------------------------------------------
59ca07b5
RS
1623
1624(defun completion-mode ()
d2c49fd8 1625 "Toggle whether or not to add new words to the completion database."
59ca07b5 1626 (interactive)
a7a2b1f6 1627 (setq enable-completion (not enable-completion))
d2c49fd8 1628 (message "Completion mode is now %s." (if enable-completion "ON" "OFF")))
71296446 1629
59ca07b5
RS
1630(defvar cmpl-current-index 0)
1631(defvar cmpl-original-string nil)
1632(defvar cmpl-last-insert-location -1)
1633(defvar cmpl-leave-point-at-start nil)
1634
1635(defun complete (&optional arg)
71296446 1636 "Fill out a completion of the word before point.
eb8c3be9 1637Point is left at end. Consecutive calls rotate through all possibilities.
59ca07b5 1638Prefix args ::
71296446 1639 control-u :: leave the point at the beginning of the completion rather
59ca07b5
RS
1640 than at the end.
1641 a number :: rotate through the possible completions by that amount
1642 `-' :: same as -1 (insert previous completion)
a7a2b1f6 1643 {See the comments at the top of `completion.el' for more info.}"
59ca07b5
RS
1644 (interactive "*p")
1645 ;;; Set up variables
1646 (cond ((eq last-command this-command)
1647 ;; Undo last one
1648 (delete-region cmpl-last-insert-location (point))
1649 ;; get next completion
d2c49fd8 1650 (setq cmpl-current-index (+ cmpl-current-index (or arg 1))))
59ca07b5
RS
1651 (t
1652 (if (not cmpl-initialized-p)
1653 (initialize-completions)) ;; make sure everything's loaded
1654 (cond ((consp current-prefix-arg) ;; control-u
1655 (setq arg 0)
d2c49fd8 1656 (setq cmpl-leave-point-at-start t))
59ca07b5 1657 (t
d2c49fd8 1658 (setq cmpl-leave-point-at-start nil)))
59ca07b5
RS
1659 ;; get string
1660 (setq cmpl-original-string (symbol-before-point-for-complete))
1661 (cond ((not cmpl-original-string)
1662 (setq this-command 'failed-complete)
136f8f67 1663 (error "To complete, point must be after a symbol at least %d character long"
a7a2b1f6 1664 completion-prefix-min-length)))
71296446 1665 ;; get index
59ca07b5
RS
1666 (setq cmpl-current-index (if current-prefix-arg arg 0))
1667 ;; statistics
1668 (cmpl-statistics-block
1669 (note-complete-entered-afresh cmpl-original-string))
1670 ;; reset database
1671 (completion-search-reset cmpl-original-string)
1672 ;; erase what we've got
d2c49fd8 1673 (delete-region cmpl-symbol-start cmpl-symbol-end)))
59ca07b5
RS
1674
1675 ;; point is at the point to insert the new symbol
1676 ;; Get the next completion
1677 (let* ((print-status-p
a7a2b1f6 1678 (and (>= baud-rate completion-prompt-speed-threshold)
7975cb9f 1679 (not (window-minibuffer-p (selected-window)))))
59ca07b5
RS
1680 (insert-point (point))
1681 (entry (completion-search-next cmpl-current-index))
d2c49fd8 1682 string)
59ca07b5
RS
1683 ;; entry is either a completion entry or a string (if cdabbrev)
1684
1685 ;; If found, insert
1686 (cond (entry
1687 ;; Setup for proper case
1688 (setq string (if (stringp entry)
1689 entry (completion-string entry)))
1690 (setq string (cmpl-merge-string-cases
1691 string cmpl-original-string))
1692 ;; insert
1693 (insert string)
1694 ;; accept it
1695 (setq completion-to-accept string)
1696 ;; fixup and cache point
1697 (cond (cmpl-leave-point-at-start
1698 (setq cmpl-last-insert-location (point))
1699 (goto-char insert-point))
1700 (t;; point at end,
d2c49fd8 1701 (setq cmpl-last-insert-location insert-point)))
59ca07b5
RS
1702 ;; statistics
1703 (cmpl-statistics-block
1704 (note-complete-inserted entry cmpl-current-index))
1705 ;; Done ! cmpl-stat-complete-successful
1706 ;;display the next completion
1707 (cond
1708 ((and print-status-p
1709 ;; This updates the display and only prints if there
1710 ;; is no typeahead
a7a2b1f6 1711 (sit-for 0)
59ca07b5
RS
1712 (setq entry
1713 (completion-search-peek
a7a2b1f6 1714 completion-cdabbrev-prompt-flag)))
59ca07b5
RS
1715 (setq string (if (stringp entry)
1716 entry (completion-string entry)))
1717 (setq string (cmpl-merge-string-cases
1718 string cmpl-original-string))
d2c49fd8 1719 (message "Next completion: %s" string))))
71296446 1720 (t;; none found, insert old
59ca07b5
RS
1721 (insert cmpl-original-string)
1722 ;; Don't accept completions
1723 (setq completion-to-accept nil)
1724 ;; print message
23b97eb9
RS
1725 ;; This used to call cmpl19-sit-for, an undefined function.
1726 ;; I hope that sit-for does the right thing; I don't know -- rms.
1727 (if (and print-status-p (sit-for 0))
59ca07b5
RS
1728 (message "No %scompletions."
1729 (if (eq this-command last-command) "more " "")))
1730 ;; statistics
1731 (cmpl-statistics-block
1732 (record-complete-failed cmpl-current-index))
1733 ;; Pretend that we were never here
d2c49fd8 1734 (setq this-command 'failed-complete)))))
59ca07b5 1735\f
b578f267
EN
1736;;---------------------------------------------------------------------------
1737;; Parsing definitions from files into the database
1738;;---------------------------------------------------------------------------
59ca07b5 1739
b578f267
EN
1740;;-----------------------------------------------
1741;; Top Level functions ::
1742;;-----------------------------------------------
59ca07b5 1743
b578f267 1744;; User interface
59ca07b5 1745(defun add-completions-from-file (file)
d2c49fd8 1746 "Parse possible completions from a FILE and add them to data base."
59ca07b5 1747 (interactive "fFile: ")
a7a2b1f6 1748 (setq file (expand-file-name file))
59ca07b5 1749 (let* ((buffer (get-file-buffer file))
d2c49fd8 1750 (buffer-already-there-p buffer))
136f8f67
RS
1751 (if (not buffer-already-there-p)
1752 (let ((completions-merging-modes nil))
1753 (setq buffer (find-file-noselect file))))
59ca07b5
RS
1754 (unwind-protect
1755 (save-excursion
1756 (set-buffer buffer)
d2c49fd8 1757 (add-completions-from-buffer))
136f8f67
RS
1758 (if (not buffer-already-there-p)
1759 (kill-buffer buffer)))))
59ca07b5
RS
1760
1761(defun add-completions-from-buffer ()
1762 (interactive)
1763 (let ((current-completion-source cmpl-source-file-parsing)
1764 (start-num
1765 (cmpl-statistics-block
1766 (aref completion-add-count-vector cmpl-source-file-parsing)))
d2c49fd8 1767 mode)
59ca07b5
RS
1768 (cond ((memq major-mode '(emacs-lisp-mode lisp-mode))
1769 (add-completions-from-lisp-buffer)
d2c49fd8 1770 (setq mode 'lisp))
59ca07b5
RS
1771 ((memq major-mode '(c-mode))
1772 (add-completions-from-c-buffer)
d2c49fd8 1773 (setq mode 'c))
59ca07b5 1774 (t
136f8f67 1775 (error "Cannot parse completions in %s buffers"
d2c49fd8 1776 major-mode)))
59ca07b5
RS
1777 (cmpl-statistics-block
1778 (record-cmpl-parse-file
1779 mode (point-max)
1780 (- (aref completion-add-count-vector cmpl-source-file-parsing)
d2c49fd8 1781 start-num)))))
59ca07b5 1782
b578f267 1783;; Find file hook
59ca07b5 1784(defun cmpl-find-file-hook ()
a7a2b1f6 1785 (cond (enable-completion
59ca07b5 1786 (cond ((and (memq major-mode '(emacs-lisp-mode lisp-mode))
d2c49fd8 1787 (memq 'lisp completions-merging-modes))
59ca07b5
RS
1788 (add-completions-from-buffer))
1789 ((and (memq major-mode '(c-mode))
d2c49fd8
DL
1790 (memq 'c completions-merging-modes))
1791 (add-completions-from-buffer))))))
59ca07b5 1792
b578f267
EN
1793;;-----------------------------------------------
1794;; Tags Table Completions
1795;;-----------------------------------------------
59ca07b5
RS
1796
1797(defun add-completions-from-tags-table ()
1798 ;; Inspired by eero@media-lab.media.mit.edu
a7a2b1f6 1799 "Add completions from the current tags table."
59ca07b5
RS
1800 (interactive)
1801 (visit-tags-table-buffer) ;this will prompt if no tags-table
1802 (save-excursion
1803 (goto-char (point-min))
1804 (let (string)
1805 (condition-case e
1806 (while t
1807 (search-forward "\177")
1808 (backward-char 3)
1809 (and (setq string (symbol-under-point))
1810 (add-completion-to-tail-if-new string))
d2c49fd8
DL
1811 (forward-char 3))
1812 (search-failed)))))
59ca07b5
RS
1813
1814\f
b578f267
EN
1815;;-----------------------------------------------
1816;; Lisp File completion parsing
1817;;-----------------------------------------------
1818;; This merely looks for phrases beginning with (def.... or
1819;; (package:def ... and takes the next word.
1820;;
1821;; We tried using forward-lines and explicit searches but the regexp technique
1822;; was faster. (About 100K characters per second)
1823;;
59ca07b5
RS
1824(defconst *lisp-def-regexp*
1825 "\n(\\(\\w*:\\)?def\\(\\w\\|\\s_\\)*\\s +(*"
d2c49fd8 1826 "A regexp that searches for Lisp definition form.")
59ca07b5 1827
b578f267
EN
1828;; Tests -
1829;; (and (string-match *lisp-def-regexp* "\n(defun foo") (match-end 0)) -> 8
1830;; (and (string-match *lisp-def-regexp* "\n(si:def foo") (match-end 0)) -> 9
1831;; (and (string-match *lisp-def-regexp* "\n(def-bar foo")(match-end 0)) -> 10
1832;; (and (string-match *lisp-def-regexp* "\n(defun (foo") (match-end 0)) -> 9
59ca07b5 1833
71296446 1834;; Parses all the definition names from a Lisp mode buffer and adds them to
b578f267 1835;; the completion database.
59ca07b5 1836(defun add-completions-from-lisp-buffer ()
59ca07b5
RS
1837 ;;; Benchmarks
1838 ;;; Sun-3/280 - 1500 to 3000 lines of lisp code per second
1839 (let (string)
1840 (save-excursion
1841 (goto-char (point-min))
1842 (condition-case e
1843 (while t
1844 (re-search-forward *lisp-def-regexp*)
1845 (and (setq string (symbol-under-point))
d2c49fd8
DL
1846 (add-completion-to-tail-if-new string)))
1847 (search-failed)))))
59ca07b5
RS
1848
1849\f
b578f267
EN
1850;;-----------------------------------------------
1851;; C file completion parsing
1852;;-----------------------------------------------
1853;; C :
1854;; Looks for #define or [<storage class>] [<type>] <name>{,<name>}
1855;; or structure, array or pointer defs.
1856;; It gets most of the definition names.
1857;;
1858;; As you might suspect by now, we use some symbol table hackery
1859;;
1860;; Symbol separator chars (have whitespace syntax) --> , ; * = (
1861;; Opening char --> [ {
1862;; Closing char --> ] }
1863;; opening and closing must be skipped over
1864;; Whitespace chars (have symbol syntax)
1865;; Everything else has word syntax
59ca07b5 1866
a7a2b1f6 1867(defun cmpl-make-c-def-completion-syntax-table ()
32168d16 1868 (let ((table (make-syntax-table))
59ca07b5 1869 (whitespace-chars '(? ?\n ?\t ?\f ?\v ?\r))
eb8c3be9 1870 ;; unfortunately the ?( causes the parens to appear unbalanced
d2c49fd8 1871 (separator-chars '(?, ?* ?= ?\( ?\;))
136f8f67 1872 i)
59ca07b5 1873 ;; default syntax is whitespace
136f8f67
RS
1874 (setq i 0)
1875 (while (< i 256)
1876 (modify-syntax-entry i "w" table)
1877 (setq i (1+ i)))
3f429351 1878 (dolist (char whitespace-chars)
59ca07b5 1879 (modify-syntax-entry char "_" table))
3f429351 1880 (dolist (char separator-chars)
59ca07b5
RS
1881 (modify-syntax-entry char " " table))
1882 (modify-syntax-entry ?\[ "(]" table)
1883 (modify-syntax-entry ?\{ "(}" table)
1884 (modify-syntax-entry ?\] ")[" table)
1885 (modify-syntax-entry ?\} "){" table)
1886 table))
1887
a7a2b1f6 1888(defconst cmpl-c-def-syntax-table (cmpl-make-c-def-completion-syntax-table))
59ca07b5 1889
b578f267 1890;; Regexps
59ca07b5
RS
1891(defconst *c-def-regexp*
1892 ;; This stops on lines with possible definitions
1893 "\n[_a-zA-Z#]"
1894 ;; This stops after the symbol to add.
1895 ;;"\n\\(#define\\s +.\\|\\(\\(\\w\\|\\s_\\)+\\b\\s *\\)+[(;,[*{=]\\)"
1896 ;; This stops before the symbol to add. {Test cases in parens. below}
1897 ;;"\n\\(\\(\\w\\|\\s_\\)+\\s *(\\|\\(\\(#define\\|auto\\|extern\\|register\\|static\\|int\\|long\\|short\\|unsigned\\|char\\|void\\|float\\|double\\|enum\\|struct\\|union\\|typedef\\)\\s +\\)+\\)"
1898 ;; this simple version picks up too much extraneous stuff
1899 ;; "\n\\(\\w\\|\\s_\\|#\\)\\B"
d2c49fd8 1900 "A regexp that searches for a definition form.")
59ca07b5
RS
1901;
1902;(defconst *c-cont-regexp*
1903; "\\(\\w\\|\\s_\\)+\\b\\s *\\({\\|\\(\\[[0-9\t ]*\\]\\s *\\)*,\\(*\\|\\s \\)*\\b\\)"
1904; "This regexp should be used in a looking-at to parse for lists of variables.")
1905;
1906;(defconst *c-struct-regexp*
1907; "\\(*\\|\\s \\)*\\b"
1908; "This regexp should be used to test whether a symbol follows a structure definition.")
1909
1910;(defun test-c-def-regexp (regexp string)
1911; (and (eq 0 (string-match regexp string)) (match-end 0))
1912; )
1913
b578f267
EN
1914;; Tests -
1915;; (test-c-def-regexp *c-def-regexp* "\n#define foo") -> 10 (9)
1916;; (test-c-def-regexp *c-def-regexp* "\nfoo (x, y) {") -> 6 (6)
1917;; (test-c-def-regexp *c-def-regexp* "\nint foo (x, y)") -> 10 (5)
1918;; (test-c-def-regexp *c-def-regexp* "\n int foo (x, y)") -> nil
1919;; (test-c-def-regexp *c-cont-regexp* "oo, bar") -> 4
1920;; (test-c-def-regexp *c-cont-regexp* "oo, *bar") -> 5
1921;; (test-c-def-regexp *c-cont-regexp* "a [5][6], bar") -> 10
1922;; (test-c-def-regexp *c-cont-regexp* "oo(x,y)") -> nil
1923;; (test-c-def-regexp *c-cont-regexp* "a [6] ,\t bar") -> 9
1924;; (test-c-def-regexp *c-cont-regexp* "oo {trout =1} my_carp;") -> 14
1925;; (test-c-def-regexp *c-cont-regexp* "truct_p complex foon") -> nil
1926
71296446 1927;; Parses all the definition names from a C mode buffer and adds them to the
b578f267 1928;; completion database.
59ca07b5 1929(defun add-completions-from-c-buffer ()
59ca07b5
RS
1930 ;; Benchmark --
1931 ;; Sun 3/280-- 1250 lines/sec.
1932
1933 (let (string next-point char
d2c49fd8 1934 (saved-syntax (syntax-table)))
59ca07b5
RS
1935 (save-excursion
1936 (goto-char (point-min))
1937 (catch 'finish-add-completions
1938 (unwind-protect
1939 (while t
1940 ;; we loop here only when scan-sexps fails
1941 ;; (i.e. unbalance exps.)
1942 (set-syntax-table cmpl-c-def-syntax-table)
1943 (condition-case e
1944 (while t
1945 (re-search-forward *c-def-regexp*)
1946 (cond
1947 ((= (preceding-char) ?#)
1948 ;; preprocessor macro, see if it's one we handle
1949 (setq string (buffer-substring (point) (+ (point) 6)))
1950 (cond ((or (string-equal string "define")
d2c49fd8 1951 (string-equal string "ifdef "))
59ca07b5
RS
1952 ;; skip forward over definition symbol
1953 ;; and add it to database
1954 (and (forward-word 2)
1955 (setq string (symbol-before-point))
1956 ;;(push string foo)
d2c49fd8 1957 (add-completion-to-tail-if-new string)))))
59ca07b5
RS
1958 (t
1959 ;; C definition
1960 (setq next-point (point))
1961 (while (and
1962 next-point
1963 ;; scan to next separator char.
d2c49fd8 1964 (setq next-point (scan-sexps next-point 1)))
59ca07b5
RS
1965 ;; position the point on the word we want to add
1966 (goto-char next-point)
1967 (while (= (setq char (following-char)) ?*)
1968 ;; handle pointer ref
1969 ;; move to next separator char.
1970 (goto-char
d2c49fd8 1971 (setq next-point (scan-sexps (point) 1))))
59ca07b5
RS
1972 (forward-word -1)
1973 ;; add to database
1974 (if (setq string (symbol-under-point))
1975 ;; (push string foo)
1976 (add-completion-to-tail-if-new string)
1977 ;; Local TMC hack (useful for parsing paris.h)
1978 (if (and (looking-at "_AP") ;; "ansi prototype"
1979 (progn
1980 (forward-word -1)
1981 (setq string
d2c49fd8
DL
1982 (symbol-under-point))))
1983 (add-completion-to-tail-if-new string)))
59ca07b5
RS
1984 ;; go to next
1985 (goto-char next-point)
1986 ;; (push (format "%c" (following-char)) foo)
1987 (if (= (char-syntax char) ?\()
1988 ;; if on an opening delimiter, go to end
1989 (while (= (char-syntax char) ?\()
1990 (setq next-point (scan-sexps next-point 1)
d2c49fd8 1991 char (char-after next-point)))
59ca07b5
RS
1992 (or (= char ?,)
1993 ;; Current char is an end char.
d2c49fd8 1994 (setq next-point nil)))))))
59ca07b5 1995 (search-failed ;;done
d2c49fd8 1996 (throw 'finish-add-completions t))
59ca07b5
RS
1997 (error
1998 ;; Check for failure in scan-sexps
136f8f67 1999 (if (or (string-equal (nth 1 e)
59ca07b5 2000 "Containing expression ends prematurely")
136f8f67 2001 (string-equal (nth 1 e) "Unbalanced parentheses"))
59ca07b5
RS
2002 ;; unbalanced paren., keep going
2003 ;;(ding)
2004 (forward-line 1)
136f8f67 2005 (message "Error parsing C buffer for completions--please send bug report")
d2c49fd8
DL
2006 (throw 'finish-add-completions t)))))
2007 (set-syntax-table saved-syntax))))))
59ca07b5
RS
2008
2009\f
b578f267
EN
2010;;---------------------------------------------------------------------------
2011;; Init files
2012;;---------------------------------------------------------------------------
59ca07b5 2013
b578f267 2014;; The version of save-completions-to-file called at kill-emacs time.
59ca07b5 2015(defun kill-emacs-save-completions ()
136f8f67
RS
2016 (if (and save-completions-flag enable-completion cmpl-initialized-p)
2017 (cond
2018 ((not cmpl-completions-accepted-p)
2019 (message "Completions database has not changed - not writing."))
2020 (t
2021 (save-completions-to-file)))))
59ca07b5 2022
1add72b5
RS
2023;; There is no point bothering to change this again
2024;; unless the package changes so much that it matters
2025;; for people that have saved completions.
2026(defconst completion-version "11")
2027
59ca07b5
RS
2028(defconst saved-cmpl-file-header
2029 ";;; Completion Initialization file.
b578f267
EN
2030;; Version = %s
2031;; Format is (<string> . <last-use-time>)
2032;; <string> is the completion
2033;; <last-use-time> is the time the completion was last used
2034;; If it is t, the completion will never be pruned from the file.
2035;; Otherwise it is in hours since origin.
59ca07b5
RS
2036\n")
2037
2038(defun completion-backup-filename (filename)
2039 (concat filename ".BAK"))
2040
2041(defun save-completions-to-file (&optional filename)
a7a2b1f6
RS
2042 "Save completions in init file FILENAME.
2043If file name is not specified, use `save-completions-file-name'."
59ca07b5 2044 (interactive)
a7a2b1f6 2045 (setq filename (expand-file-name (or filename save-completions-file-name)))
136f8f67
RS
2046 (if (file-writable-p filename)
2047 (progn
2048 (if (not cmpl-initialized-p)
2049 (initialize-completions));; make sure everything's loaded
2050 (message "Saving completions to file %s" filename)
2051
2052 (let* ((delete-old-versions t)
2053 (kept-old-versions 0)
2054 (kept-new-versions completions-file-versions-kept)
2055 last-use-time
2056 (current-time (cmpl-hours-since-origin))
2057 (total-in-db 0)
2058 (total-perm 0)
2059 (total-saved 0)
d2c49fd8 2060 (backup-filename (completion-backup-filename filename)))
71296446 2061
136f8f67
RS
2062 (save-excursion
2063 (get-buffer-create " *completion-save-buffer*")
2064 (set-buffer " *completion-save-buffer*")
2065 (setq buffer-file-name filename)
2066
2067 (if (not (verify-visited-file-modtime (current-buffer)))
2068 (progn
2069 ;; file has changed on disk. Bring us up-to-date
2070 (message "Completion file has changed. Merging. . .")
2071 (load-completions-from-file filename t)
2072 (message "Merging finished. Saving completions to file %s" filename)))
2073
2074 ;; prepare the buffer to be modified
2075 (clear-visited-file-modtime)
2076 (erase-buffer)
2077 ;; (/ 1 0)
2078 (insert (format saved-cmpl-file-header completion-version))
3f429351 2079 (dolist (completion (list-all-completions))
136f8f67
RS
2080 (setq total-in-db (1+ total-in-db))
2081 (setq last-use-time (completion-last-use-time completion))
2082 ;; Update num uses and maybe write completion to a file
2083 (cond ((or;; Write to file if
2084 ;; permanent
2085 (and (eq last-use-time t)
2086 (setq total-perm (1+ total-perm)))
2087 ;; or if
2088 (if (> (completion-num-uses completion) 0)
2089 ;; it's been used
2090 (setq last-use-time current-time)
2091 ;; or it was saved before and
2092 (and last-use-time
2093 ;; save-completions-retention-time is nil
2094 (or (not save-completions-retention-time)
2095 ;; or time since last use is < ...retention-time*
2096 (< (- current-time last-use-time)
d2c49fd8 2097 save-completions-retention-time)))))
136f8f67
RS
2098 ;; write to file
2099 (setq total-saved (1+ total-saved))
2100 (insert (prin1-to-string (cons (completion-string completion)
d2c49fd8 2101 last-use-time)) "\n"))))
71296446 2102
136f8f67
RS
2103 ;; write the buffer
2104 (condition-case e
2105 (let ((file-exists-p (file-exists-p filename)))
2106 (if file-exists-p
2107 (progn
2108 ;; If file exists . . .
2109 ;; Save a backup(so GNU doesn't screw us when we're out of disk)
2110 ;; (GNU leaves a 0 length file if it gets a disk full error!)
71296446 2111
136f8f67
RS
2112 ;; If backup doesn't exit, Rename current to backup
2113 ;; {If backup exists the primary file is probably messed up}
2114 (or (file-exists-p backup-filename)
2115 (rename-file filename backup-filename))
2116 ;; Copy the backup back to the current name
2117 ;; (so versioning works)
2118 (copy-file backup-filename filename t)))
2119 ;; Save it
2120 (save-buffer)
2121 (if file-exists-p
2122 ;; If successful, remove backup
2123 (delete-file backup-filename)))
2124 (error
2125 (set-buffer-modified-p nil)
d2c49fd8 2126 (message "Couldn't save completion file `%s'" filename)))
136f8f67 2127 ;; Reset accepted-p flag
d2c49fd8 2128 (setq cmpl-completions-accepted-p nil) )
136f8f67 2129 (cmpl-statistics-block
d2c49fd8 2130 (record-save-completions total-in-db total-perm total-saved))))))
59ca07b5 2131
4e0c8650 2132;;(defun auto-save-completions ()
b578f267
EN
2133;; (if (and save-completions-flag enable-completion cmpl-initialized-p
2134;; *completion-auto-save-period*
2135;; (> cmpl-emacs-idle-time *completion-auto-save-period*)
2136;; cmpl-completions-accepted-p)
2137;; (save-completions-to-file)))
59ca07b5 2138
4e0c8650 2139;;(add-hook 'cmpl-emacs-idle-time-hooks 'auto-save-completions)
59ca07b5
RS
2140
2141(defun load-completions-from-file (&optional filename no-message-p)
d2c49fd8 2142 "Load a completion init file FILENAME.
a7a2b1f6 2143If file is not specified, then use `save-completions-file-name'."
59ca07b5 2144 (interactive)
a7a2b1f6 2145 (setq filename (expand-file-name (or filename save-completions-file-name)))
59ca07b5 2146 (let* ((backup-filename (completion-backup-filename filename))
d2c49fd8 2147 (backup-readable-p (file-readable-p backup-filename)))
136f8f67
RS
2148 (if backup-readable-p (setq filename backup-filename))
2149 (if (file-readable-p filename)
2150 (progn
2151 (if (not no-message-p)
2152 (message "Loading completions from %sfile %s . . ."
2153 (if backup-readable-p "backup " "") filename))
2154 (save-excursion
2155 (get-buffer-create " *completion-save-buffer*")
2156 (set-buffer " *completion-save-buffer*")
2157 (setq buffer-file-name filename)
2158 ;; prepare the buffer to be modified
2159 (clear-visited-file-modtime)
2160 (erase-buffer)
71296446 2161
136f8f67
RS
2162 (let ((insert-okay-p nil)
2163 (buffer (current-buffer))
2164 (current-time (cmpl-hours-since-origin))
2165 string num-uses entry last-use-time
2166 cmpl-entry cmpl-last-use-time
2167 (current-completion-source cmpl-source-init-file)
2168 (start-num
2169 (cmpl-statistics-block
2170 (aref completion-add-count-vector cmpl-source-file-parsing)))
d2c49fd8 2171 (total-in-file 0) (total-perm 0))
136f8f67
RS
2172 ;; insert the file into a buffer
2173 (condition-case e
2174 (progn (insert-file-contents filename t)
2175 (setq insert-okay-p t))
2176
71296446 2177 (file-error
136f8f67
RS
2178 (message "File error trying to load completion file %s."
2179 filename)))
71296446 2180 ;; parse it
136f8f67
RS
2181 (if insert-okay-p
2182 (progn
2183 (goto-char (point-min))
2184
2185 (condition-case e
2186 (while t
2187 (setq entry (read buffer))
2188 (setq total-in-file (1+ total-in-file))
2189 (cond
2190 ((and (consp entry)
2191 (stringp (setq string (car entry)))
2192 (cond
2193 ((eq (setq last-use-time (cdr entry)) 'T)
2194 ;; handle case sensitivity
2195 (setq total-perm (1+ total-perm))
2196 (setq last-use-time t))
2197 ((eq last-use-time t)
2198 (setq total-perm (1+ total-perm)))
d2c49fd8 2199 ((integerp last-use-time))))
136f8f67
RS
2200 ;; Valid entry
2201 ;; add it in
2202 (setq cmpl-last-use-time
2203 (completion-last-use-time
2204 (setq cmpl-entry
d2c49fd8 2205 (add-completion-to-tail-if-new string))))
71296446 2206 (if (or (eq last-use-time t)
136f8f67
RS
2207 (and (> last-use-time 1000);;backcompatibility
2208 (not (eq cmpl-last-use-time t))
2209 (or (not cmpl-last-use-time)
2210 ;; more recent
d2c49fd8 2211 (> last-use-time cmpl-last-use-time))))
136f8f67 2212 ;; update last-use-time
d2c49fd8 2213 (set-completion-last-use-time cmpl-entry last-use-time)))
136f8f67
RS
2214 (t
2215 ;; Bad format
2216 (message "Error: invalid saved completion - %s"
2217 (prin1-to-string entry))
2218 ;; try to get back in sync
d2c49fd8 2219 (search-forward "\n("))))
136f8f67 2220 (search-failed
d2c49fd8 2221 (message "End of file while reading completions."))
136f8f67
RS
2222 (end-of-file
2223 (if (= (point) (point-max))
2224 (if (not no-message-p)
2225 (message "Loading completions from file %s . . . Done."
2226 filename))
d2c49fd8 2227 (message "End of file while reading completions."))))))
59ca07b5 2228
136f8f67
RS
2229 (cmpl-statistics-block
2230 (record-load-completions
2231 total-in-file total-perm
2232 (- (aref completion-add-count-vector cmpl-source-init-file)
2233 start-num)))
d2c49fd8 2234))))))
59ca07b5
RS
2235
2236(defun initialize-completions ()
a7a2b1f6 2237 "Load the default completions file.
7975cb9f 2238Also sets up so that exiting Emacs will automatically save the file."
59ca07b5
RS
2239 (interactive)
2240 (cond ((not cmpl-initialized-p)
d2c49fd8
DL
2241 (load-completions-from-file)))
2242 (setq cmpl-initialized-p t))
59ca07b5 2243\f
b578f267
EN
2244;;-----------------------------------------------
2245;; Kill region patch
2246;;-----------------------------------------------
59ca07b5 2247
a7a2b1f6 2248(defun completion-kill-region (&optional beg end)
59ca07b5
RS
2249 "Kill between point and mark.
2250The text is deleted but saved in the kill ring.
2251The command \\[yank] can retrieve it from there.
2252/(If you want to kill and then yank immediately, use \\[copy-region-as-kill].)
2253
2254This is the primitive for programs to kill text (as opposed to deleting it).
0c53eb03 2255Supply two arguments, character positions indicating the stretch of text
59ca07b5
RS
2256 to be killed.
2257Any command that calls this function is a \"kill command\".
2258If the previous command was also a kill command,
2259the text killed this time appends to the text killed last time
2260to make one entry in the kill ring.
2261Patched to remove the most recent completion."
71296446 2262 (interactive "r")
a7a2b1f6 2263 (cond ((eq last-command 'complete)
59ca07b5
RS
2264 (delete-region (point) cmpl-last-insert-location)
2265 (insert cmpl-original-string)
2266 (setq completion-to-accept nil)
2267 (cmpl-statistics-block
a7a2b1f6 2268 (record-complete-failed)))
59ca07b5 2269 (t
a7a2b1f6 2270 (kill-region beg end))))
59ca07b5 2271
a7a2b1f6 2272\f
b578f267
EN
2273;;-----------------------------------------------
2274;; Patches to self-insert-command.
2275;;-----------------------------------------------
59ca07b5 2276
b578f267
EN
2277;; Need 2 versions: generic separator chars. and space (to get auto fill
2278;; to work)
59ca07b5 2279
b578f267
EN
2280;; All common separators (eg. space "(" ")" """) characters go through a
2281;; function to add new words to the list of words to complete from:
2282;; COMPLETION-SEPARATOR-SELF-INSERT-COMMAND (arg).
71296446 2283;; If the character before this was an alpha-numeric then this adds the
b578f267 2284;; symbol before point to the completion list (using ADD-COMPLETION).
59ca07b5
RS
2285
2286(defun completion-separator-self-insert-command (arg)
2287 (interactive "p")
2288 (use-completion-before-separator)
d2c49fd8 2289 (self-insert-command arg))
59ca07b5
RS
2290
2291(defun completion-separator-self-insert-autofilling (arg)
2292 (interactive "p")
2293 (use-completion-before-separator)
2294 (self-insert-command arg)
a7263218 2295 (and auto-fill-function
d2c49fd8 2296 (funcall auto-fill-function)))
59ca07b5 2297
b578f267
EN
2298;;-----------------------------------------------
2299;; Wrapping Macro
2300;;-----------------------------------------------
59ca07b5 2301
71296446 2302;; Note that because of the way byte compiling works, none of
b578f267 2303;; the functions defined with this macro get byte compiled.
59ca07b5
RS
2304
2305(defmacro def-completion-wrapper (function-name type &optional new-name)
c2ced5d8
CZ
2306 "Add a call to update the completion database before function execution.
2307TYPE is the type of the wrapper to be added. Can be :before or :under."
d2c49fd8 2308 (cond ((eq type :separator)
a7a2b1f6
RS
2309 (list 'put (list 'quote function-name) ''completion-function
2310 ''use-completion-before-separator))
d2c49fd8 2311 ((eq type :before)
a7a2b1f6
RS
2312 (list 'put (list 'quote function-name) ''completion-function
2313 ''use-completion-before-point))
d2c49fd8 2314 ((eq type :backward-under)
a7a2b1f6
RS
2315 (list 'put (list 'quote function-name) ''completion-function
2316 ''use-completion-backward-under))
d2c49fd8 2317 ((eq type :backward)
a7a2b1f6
RS
2318 (list 'put (list 'quote function-name) ''completion-function
2319 ''use-completion-backward))
d2c49fd8 2320 ((eq type :under)
a7a2b1f6
RS
2321 (list 'put (list 'quote function-name) ''completion-function
2322 ''use-completion-under-point))
d2c49fd8 2323 ((eq type :under-or-before)
a7a2b1f6
RS
2324 (list 'put (list 'quote function-name) ''completion-function
2325 ''use-completion-under-or-before-point))
d2c49fd8 2326 ((eq type :minibuffer-separator)
a7a2b1f6
RS
2327 (list 'put (list 'quote function-name) ''completion-function
2328 ''use-completion-minibuffer-separator))))
2329
2330(defun use-completion-minibuffer-separator ()
2331 (let ((cmpl-syntax-table cmpl-standard-syntax-table))
2332 (use-completion-before-separator)))
2333
2334(defun use-completion-backward-under ()
2335 (use-completion-under-point)
2336 (if (eq last-command 'complete)
2337 ;; probably a failed completion if you have to back up
2338 (cmpl-statistics-block (record-complete-failed))))
2339
2340(defun use-completion-backward ()
2341 (if (eq last-command 'complete)
2342 ;; probably a failed completion if you have to back up
2343 (cmpl-statistics-block (record-complete-failed))))
2344
2345(defun completion-before-command ()
76e91049
RS
2346 (funcall (or (and (symbolp this-command)
2347 (get this-command 'completion-function))
a7a2b1f6 2348 'use-completion-under-or-before-point)))
bb310d1e 2349\f
b578f267 2350;; C mode diffs.
603715b0
RS
2351
2352(defvar c-mode-map)
2353
32168d16
RS
2354(defun completion-c-mode-hook ()
2355 (def-completion-wrapper electric-c-semi :separator)
2356 (define-key c-mode-map "+" 'completion-separator-self-insert-command)
2357 (define-key c-mode-map "*" 'completion-separator-self-insert-command)
2358 (define-key c-mode-map "/" 'completion-separator-self-insert-command))
2359;; Do this either now or whenever C mode is loaded.
2360(if (featurep 'cc-mode)
2361 (completion-c-mode-hook)
2362 (add-hook 'c-mode-hook 'completion-c-mode-hook))
59ca07b5 2363
b578f267 2364;; FORTRAN mode diffs. (these are defined when fortran is called)
603715b0
RS
2365
2366(defvar fortran-mode-map)
2367
59ca07b5
RS
2368(defun completion-setup-fortran-mode ()
2369 (define-key fortran-mode-map "+" 'completion-separator-self-insert-command)
2370 (define-key fortran-mode-map "-" 'completion-separator-self-insert-command)
2371 (define-key fortran-mode-map "*" 'completion-separator-self-insert-command)
d2c49fd8 2372 (define-key fortran-mode-map "/" 'completion-separator-self-insert-command))
bb310d1e
RS
2373\f
2374;;; Enable completion mode.
71296446 2375
bb310d1e
RS
2376;;;###autoload
2377(defun dynamic-completion-mode ()
2378 "Enable dynamic word-completion."
2379 (interactive)
1a80bcd1 2380 (add-hook 'find-file-hook 'cmpl-find-file-hook)
bb310d1e
RS
2381 (add-hook 'pre-command-hook 'completion-before-command)
2382
2383 ;; Install the appropriate mode tables.
2384 (add-hook 'lisp-mode-hook
99d0735f 2385 (lambda ()
bb310d1e
RS
2386 (setq cmpl-syntax-table cmpl-lisp-syntax-table)))
2387 (add-hook 'c-mode-hook
99d0735f 2388 (lambda ()
bb310d1e
RS
2389 (setq cmpl-syntax-table cmpl-c-syntax-table)))
2390 (add-hook 'fortran-mode-hook
99d0735f 2391 (lambda ()
bb310d1e
RS
2392 (setq cmpl-syntax-table cmpl-fortran-syntax-table)
2393 (completion-setup-fortran-mode)))
2394
2395 ;; "Complete" Key Keybindings.
2396
2397 (global-set-key "\M-\r" 'complete)
2398 (global-set-key [?\C-\r] 'complete)
2399 (define-key function-key-map [C-return] [?\C-\r])
2400
2401 ;; Tests -
2402 ;; (add-completion "cumberland")
2403 ;; (add-completion "cumberbund")
2404 ;; cum
2405 ;; Cumber
2406 ;; cumbering
2407 ;; cumb
2408
2409 ;; Save completions when killing Emacs.
2410
2411 (add-hook 'kill-emacs-hook
99d0735f 2412 (lambda ()
bb310d1e
RS
2413 (kill-emacs-save-completions)
2414 (cmpl-statistics-block
2415 (record-cmpl-kill-emacs))))
2416
2417 ;; Patches to standard keymaps insert completions
2418 (substitute-key-definition 'kill-region 'completion-kill-region
2419 global-map)
2420
2421 ;; Separators
2422 ;; We've used the completion syntax table given as a guide.
2423 ;;
2424 ;; Global separator chars.
2425 ;; We left out <tab> because there are too many special cases for it. Also,
2426 ;; in normal coding it's rarely typed after a word.
2427 (global-set-key " " 'completion-separator-self-insert-autofilling)
2428 (global-set-key "!" 'completion-separator-self-insert-command)
2429 (global-set-key "%" 'completion-separator-self-insert-command)
2430 (global-set-key "^" 'completion-separator-self-insert-command)
2431 (global-set-key "&" 'completion-separator-self-insert-command)
2432 (global-set-key "(" 'completion-separator-self-insert-command)
2433 (global-set-key ")" 'completion-separator-self-insert-command)
2434 (global-set-key "=" 'completion-separator-self-insert-command)
2435 (global-set-key "`" 'completion-separator-self-insert-command)
2436 (global-set-key "|" 'completion-separator-self-insert-command)
2437 (global-set-key "{" 'completion-separator-self-insert-command)
2438 (global-set-key "}" 'completion-separator-self-insert-command)
2439 (global-set-key "[" 'completion-separator-self-insert-command)
2440 (global-set-key "]" 'completion-separator-self-insert-command)
2441 (global-set-key ";" 'completion-separator-self-insert-command)
2442 (global-set-key "\"" 'completion-separator-self-insert-command)
2443 (global-set-key "'" 'completion-separator-self-insert-command)
2444 (global-set-key "#" 'completion-separator-self-insert-command)
2445 (global-set-key "," 'completion-separator-self-insert-command)
2446 (global-set-key "?" 'completion-separator-self-insert-command)
2447
2448 ;; We include period and colon even though they are symbol chars because :
2449 ;; - in text we want to pick up the last word in a sentence.
2450 ;; - in C pointer refs. we want to pick up the first symbol
2451 ;; - it won't make a difference for lisp mode (package names are short)
2452 (global-set-key "." 'completion-separator-self-insert-command)
2453 (global-set-key ":" 'completion-separator-self-insert-command)
2454
2455 ;; Lisp Mode diffs
2456 (define-key lisp-mode-map "!" 'self-insert-command)
2457 (define-key lisp-mode-map "&" 'self-insert-command)
2458 (define-key lisp-mode-map "%" 'self-insert-command)
2459 (define-key lisp-mode-map "?" 'self-insert-command)
2460 (define-key lisp-mode-map "=" 'self-insert-command)
2461 (define-key lisp-mode-map "^" 'self-insert-command)
2462
2463 ;; Avoid warnings.
2464 (defvar c-mode-map)
2465 (defvar fortran-mode-map)
2466
2467 ;;-----------------------------------------------
2468 ;; End of line chars.
2469 ;;-----------------------------------------------
2470 (def-completion-wrapper newline :separator)
2471 (def-completion-wrapper newline-and-indent :separator)
2472 (def-completion-wrapper comint-send-input :separator)
2473 (def-completion-wrapper exit-minibuffer :minibuffer-separator)
2474 (def-completion-wrapper eval-print-last-sexp :separator)
2475 (def-completion-wrapper eval-last-sexp :separator)
2476 ;;(def-completion-wrapper minibuffer-complete-and-exit :minibuffer)
2477
2478 ;;-----------------------------------------------
2479 ;; Cursor movement
2480 ;;-----------------------------------------------
2481
2482 (def-completion-wrapper next-line :under-or-before)
2483 (def-completion-wrapper previous-line :under-or-before)
2484 (def-completion-wrapper beginning-of-buffer :under-or-before)
2485 (def-completion-wrapper end-of-buffer :under-or-before)
2486 (def-completion-wrapper beginning-of-line :under-or-before)
2487 (def-completion-wrapper end-of-line :under-or-before)
2488 (def-completion-wrapper forward-char :under-or-before)
2489 (def-completion-wrapper forward-word :under-or-before)
2490 (def-completion-wrapper forward-sexp :under-or-before)
2491 (def-completion-wrapper backward-char :backward-under)
2492 (def-completion-wrapper backward-word :backward-under)
2493 (def-completion-wrapper backward-sexp :backward-under)
2494
2495 (def-completion-wrapper delete-backward-char :backward)
2496 (def-completion-wrapper delete-backward-char-untabify :backward)
2497
2498 ;; Tests --
2499 ;; foobarbiz
71296446
JB
2500 ;; foobar
2501 ;; fooquux
bb310d1e 2502 ;; fooper
59ca07b5 2503
bb310d1e
RS
2504 (cmpl-statistics-block
2505 (record-completion-file-loaded))
59ca07b5 2506
bb310d1e 2507 (initialize-completions))
c0274f38 2508
7975cb9f 2509(mapc (lambda (x) (add-to-list 'debug-ignored-errors x))
d2c49fd8
DL
2510 '("^To complete, the point must be after a symbol at least [0-9]* character long\\.$"
2511 "^The string \".*\" is too short to be saved as a completion\\.$"))
2512
1aa323ac
RS
2513(provide 'completion)
2514
ab5796a9 2515;;; arch-tag: 6990dafe-4abd-4a1f-8c42-ffb25e120f5e
c0274f38 2516;;; completion.el ends here