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