comparison lisp/packages/completion.el @ 0:376386a54a3c r19-14

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