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