* lisp/minibuffer.el (completion--done): New fun.
(completion--do-completion): Use it. New arg `expect-exact'.
(minibuffer-complete, minibuffer-complete-word): Don't output message,
since completion--do-completion does it for us now.
(minibuffer-force-complete): Use completion--done and
completion--replace. Handle sole-completion case with more care.
(minibuffer-complete-and-exit): Use new `expect-exact' arg.
(completion-extra-properties): New var.
(completion-annotate-function): Make obsolete.
(minibuffer-completion-help): Adjust accordingly.
Use completion-list-insert-choice-function.
(completion-at-point, completion-help-at-point):
Bind completion-extra-properties.
(completion-pcm-word-delimiters): Add | (for uniquify, for example).
* lisp/simple.el (completion-list-insert-choice-function): New var.
(completion-setup-function): Preserve it.
(choose-completion): Pay attention to it, shuffle the code a bit.
(choose-completion-string): New arg `insert-function'.
* lisp/textmodes/bibtex.el: Convert to lexical binding.
(bibtex-mode-map): Use completion-at-point.
(bibtex-mode): Use define-derived-mode&completion-at-point-functions.
(bibtex-completion-at-point-function): New fun, from bibtex-complete.
(bibtex-complete): Define as obsolete alias.
(bibtex-complete-internal): Remove.
(bibtex-format-entry): Remove unused sub-group in regexp.
* lisp/shell.el (shell--command-completion-data)
(shell-environment-variable-completion):
* lisp/pcomplete.el (pcomplete-completions-at-point):
* lisp/comint.el (comint--complete-file-name-data): Use :exit-function
instead of completion-table-with-terminator so it also works for
choose-completion.
\f
* Changes in Emacs 24.1
-** Completion in a non-minibuffer now tries to detect the end of completion
-and pops down the *Completions* buffer accordingly.
-
** emacsclient changes
*** New emacsclient argument --parent-id ID can be used to open a
*** If emacsclient shuts down as a result of Emacs signalling an
error, its exit status is 1.
-** Completion can cycle, depending on completion-cycle-threshold.
+** Completion
+*** Many packages have been changed to use completion-at-point rather than
+their own completion code.
+
+*** Completion in a non-minibuffer now tries to detect the end of completion
+and pops down the *Completions* buffer accordingly.
+
+*** Completion can cycle, depending on completion-cycle-threshold.
-** `completing-read' can be customized using the new variable
+*** New completion style `substring'.
+
+*** `completing-read' can be customized using the new variable
`completing-read-function'.
** auto-mode-case-fold is now enabled by default.
\f
* Lisp changes in Emacs 24.1
+** Completion
+*** New variable completion-extra-properties used to specify extra properties
+of the current completion:
+- :annotate-function, same as the old completion-annotate-function.
+- :exit-function, function to call after completion took place.
+
+*** Functions on completion-at-point-functions can return any of the properties
+valid for completion-extra-properties.
+
+*** completion-annotate-function is obsolete.
+
** `glyphless-char-display' can now distinguish between graphical and
text terminal display, via a char-table entry that is a cons cell.
** buffer-substring-filters is obsoleted by filter-buffer-substring-functions.
-** New completion style `substring'.
-
** `facemenu-read-color' is now an alias for `read-color'.
The command `read-color' now requires a match for a color name or RGB
triplet, instead of signalling an error if the user provides a invalid
+2011-05-24 Stefan Monnier <monnier@iro.umontreal.ca>
+
+ Add an :exit-function for completion-at-point.
+
+ * minibuffer.el (completion--done): New fun.
+ (completion--do-completion): Use it. New arg `expect-exact'.
+ (minibuffer-complete, minibuffer-complete-word): Don't output message,
+ since completion--do-completion does it for us now.
+ (minibuffer-force-complete): Use completion--done and
+ completion--replace. Handle sole-completion case with more care.
+ (minibuffer-complete-and-exit): Use new `expect-exact' arg.
+ (completion-extra-properties): New var.
+ (completion-annotate-function): Make obsolete.
+ (minibuffer-completion-help): Adjust accordingly.
+ Use completion-list-insert-choice-function.
+ (completion-at-point, completion-help-at-point):
+ Bind completion-extra-properties.
+ (completion-pcm-word-delimiters): Add | (for uniquify, for example).
+ * simple.el (completion-list-insert-choice-function): New var.
+ (completion-setup-function): Preserve it.
+ (choose-completion): Pay attention to it, shuffle the code a bit.
+ (choose-completion-string): New arg `insert-function'.
+
+ * textmodes/bibtex.el: Convert to lexical binding.
+ (bibtex-mode-map): Use completion-at-point.
+ (bibtex-mode): Use define-derived-mode&completion-at-point-functions.
+ (bibtex-completion-at-point-function): New fun, from bibtex-complete.
+ (bibtex-complete): Define as obsolete alias.
+ (bibtex-complete-internal): Remove.
+ (bibtex-format-entry): Remove unused sub-group in regexp.
+ * shell.el (shell--command-completion-data)
+ (shell-environment-variable-completion):
+ * pcomplete.el (pcomplete-completions-at-point):
+ * comint.el (comint--complete-file-name-data): Use :exit-function
+ instead of completion-table-with-terminator so it also works for
+ choose-completion.
+
2011-05-23 Stefan Monnier <monnier@iro.umontreal.ca>
* <lots-of-files>.el: Don't quote lambda expressions with `quote'.
#'comint--table-subvert
#'completion-file-name-table
(cdr prefixes) (car prefixes)))))
- (list
- filename-beg filename-end
- (lambda (string pred action)
- (let ((completion-ignore-case read-file-name-completion-ignore-case)
- (completion-ignored-extensions comint-completion-fignore))
- (if (zerop (length filesuffix))
- (complete-with-action action table string pred)
- ;; Add a space at the end of completion. Use a terminator-regexp
- ;; that never matches since the terminator cannot appear
- ;; within the completion field anyway.
- (completion-table-with-terminator
- (cons filesuffix "\\`a\\`")
- table string pred action)))))))
+ (nconc
+ (list
+ filename-beg filename-end
+ (lambda (string pred action)
+ (let ((completion-ignore-case read-file-name-completion-ignore-case)
+ (completion-ignored-extensions comint-completion-fignore))
+ (complete-with-action action table string pred))))
+ (unless (zerop (length filesuffix))
+ (list :exit-function
+ (lambda (_s finished)
+ (when (memq finished '(sole finished))
+ (if (looking-at (regexp-quote filesuffix))
+ (goto-char (match-end 0))
+ (insert filesuffix)))))))))
(defun comint-dynamic-complete-as-filename ()
"Dynamically complete at point as a filename.
;;; Todo:
+;; - for M-x, cycle-sort commands that have no key binding first.
;; - Make things like icomplete-mode or lightning-completion work with
;; completion-in-region-mode.
-;; - completion-insert-complete-hook (called after inserting a complete
-;; completion), typically used for "complete-abbrev" where it would expand
-;; the abbrev. Tho we'd probably want to provide it from the
-;; completion-table.
;; - extend `boundaries' to provide various other meta-data about the
;; output of `all-completions':
;; - preferred sorting order when displayed in *Completions*.
;; - indicate how to turn all-completion's output into
;; try-completion's output: e.g. completion-ignored-extensions.
;; maybe that could be merged with the "quote" operation above.
-;; - completion hook to run when the completion is
-;; selected/inserted (maybe this should be provided some other
-;; way, e.g. as text-property, so `try-completion can also return it?)
-;; both for when it's inserted via TAB or via choose-completion.
;; - indicate that `all-completions' doesn't do prefix-completion
;; but just returns some list that relates in some other way to
;; the provided string (as is the case in filecache.el), in which
;; \n into something else, add special boundaries between
;; completions). E.g. when completing from the kill-ring.
-;; - make partial-completion-mode obsolete:
-;; - (?) <foo.h> style completion for file names.
-;; This can't be done identically just by tweaking completion,
-;; because partial-completion-mode's behavior is to expand <string.h>
-;; to /usr/include/string.h only when exiting the minibuffer, at which
-;; point the completion code is actually not involved normally.
-;; Partial-completion-mode does it via a find-file-not-found-function.
-;; - special code for C-x C-f <> to visit the file ref'd at point
-;; via (require 'foo) or #include "foo". ffap seems like a better
-;; place for this feature (supplemented with major-mode-provided
-;; functions to find the file ref'd at point).
-
;; - case-sensitivity currently confuses two issues:
;; - whether or not a particular completion table should be case-sensitive
;; (i.e. whether strings that differ only by case are semantically
(if completion-show-inline-help
(minibuffer-message msg)))
-(defun completion--do-completion (&optional try-completion-function)
+(defun completion--do-completion (&optional try-completion-function
+ expect-exact)
"Do the completion and return a summary of what happened.
M = completion was performed, the text was Modified.
C = there were available Completions.
100 4 ??? impossible
101 5 ??? impossible
110 6 some completion happened
- 111 7 completed to an exact completion"
+ 111 7 completed to an exact completion
+
+TRY-COMPLETION-FUNCTION is a function to use in place of `try-completion'.
+EXPECT-EXACT, if non-nil, means that there is no need to tell the user
+when the buffer's text is already an exact match."
(let* ((beg (field-beginning))
(end (field-end))
(string (buffer-substring beg end))
(minibuffer--bitset nil nil nil))
((eq t comp)
(minibuffer-hide-completions)
- (goto-char (field-end))
+ (goto-char end)
+ (completion--done string 'finished
+ (unless expect-exact "Sole completion"))
(minibuffer--bitset nil nil t)) ;Exact and unique match.
(t
;; `completed' should be t if some completion was done, which doesn't
;; whether this is a unique completion or not, so try again using
;; the real case (this shouldn't recurse again, because the next
;; time try-completion will return either t or the exact string).
- (completion--do-completion try-completion-function)
+ (completion--do-completion try-completion-function expect-exact)
;; It did find a match. Do we match some possibility exactly now?
(let ((exact (test-completion completion
- minibuffer-completion-table
- minibuffer-completion-predicate))
+ minibuffer-completion-table
+ minibuffer-completion-predicate))
(comps
;; Check to see if we want to do cycling. We do it
;; here, after having performed the normal completion,
;; We could also decide to refresh the completions,
;; if they're displayed (and assuming there are
;; completions left).
- (minibuffer-hide-completions))
+ (minibuffer-hide-completions)
+ (if exact
+ ;; If completion did not put point at end of field,
+ ;; it's a sign that completion is not finished.
+ (completion--done completion
+ (if (< comp-pos (length completion))
+ 'exact 'unknown))))
;; Show the completion table, if requested.
((not exact)
(if (case completion-auto-help
;; If the last exact completion and this one were the same, it
;; means we've already given a "Complete, but not unique" message
;; and the user's hit TAB again, so now we give him help.
- ((eq this-command last-command)
- (if completion-auto-help (minibuffer-completion-help))))
+ (t
+ (if (and (eq this-command last-command) completion-auto-help)
+ (minibuffer-completion-help))
+ (completion--done completion 'exact
+ (unless expect-exact
+ "Complete, but not unique"))))
(minibuffer--bitset completed t exact))))))))
t)
(t (case (completion--do-completion)
(#b000 nil)
- (#b001 (completion--message "Sole completion")
- t)
- (#b011 (completion--message "Complete, but not unique")
- t)
(t t)))))
(defun completion--flush-all-sorted-completions (&rest _ignore)
;; Prefer recently used completions.
;; FIXME: Additional sorting ideas:
;; - for M-x, prefer commands that have no key binding.
- (let ((hist (symbol-value minibuffer-history-variable)))
- (setq all (sort all (lambda (c1 c2)
- (> (length (member c1 hist))
- (length (member c2 hist)))))))
+ (when (minibufferp)
+ (let ((hist (symbol-value minibuffer-history-variable)))
+ (setq all (sort all (lambda (c1 c2)
+ (> (length (member c1 hist))
+ (length (member c2 hist))))))))
;; Cache the result. This is not just for speed, but also so that
;; repeated calls to minibuffer-force-complete can cycle through
;; all possibilities.
;; ~/src/emacs/trunk/ and throws away lisp/minibuffer.el.
(let* ((start (field-beginning))
(end (field-end))
- (all (completion-all-sorted-completions)))
- (if (not (consp all))
+ (all (completion-all-sorted-completions))
+ (base (+ start (or (cdr (last all)) 0))))
+ (cond
+ ((not (consp all))
(completion--message
- (if all "No more completions" "No completions"))
+ (if all "No more completions" "No completions")))
+ ((not (consp (cdr all)))
+ (let ((mod (equal (car all) (buffer-substring-no-properties base end))))
+ (if mod (completion--replace base end (car all)))
+ (completion--done (buffer-substring-no-properties start (point))
+ 'finished (unless mod "Sole completion"))))
+ (t
(setq completion-cycling t)
- (goto-char end)
- (insert (car all))
- (delete-region (+ start (cdr (last all))) end)
+ (completion--replace base end (car all))
+ (completion--done (buffer-substring-no-properties start (point)) 'sole)
;; If completing file names, (car all) may be a directory, so we'd now
;; have a new set of possible completions and might want to reset
;; completion-all-sorted-completions to nil, but we prefer not to,
;; through the previous possible completions.
(let ((last (last all)))
(setcdr last (cons (car all) (cdr last)))
- (setq completion-all-sorted-completions (cdr all))))))
+ (setq completion-all-sorted-completions (cdr all)))))))
(defvar minibuffer-confirm-exit-commands
'(minibuffer-complete minibuffer-complete-word PC-complete PC-complete-word)
(t
;; Call do-completion, but ignore errors.
(case (condition-case nil
- (completion--do-completion)
+ (completion--do-completion nil 'expect-exact)
(error 1))
((#b001 #b011) (exit-minibuffer))
(#b111 (if (not minibuffer-completion-confirm)
(interactive)
(case (completion--do-completion 'completion--try-word-completion)
(#b000 nil)
- (#b001 (completion--message "Sole completion")
- t)
- (#b011 (completion--message "Complete, but not unique")
- t)
(t t)))
(defface completions-annotations '((t :inherit italic))
(run-hooks 'completion-setup-hook)))
nil)
+(defvar completion-extra-properties nil
+ "Property list of extra properties of the current completion job.
+These include:
+`:annotation-function': Function to add annotations in the completions buffer.
+ The function takes a completion and should either return nil, or a string
+ that will be displayed next to the completion. The function can access the
+ completion data via `minibuffer-completion-table' and related variables.
+`:exit-function': Function to run after completion is performed.
+ The function takes at least 2 parameters (STRING and STATUS) where STRING
+ is the text to which the field was completed and STATUS indicates what
+ kind of operation happened: if text is now complete it's `finished', if text
+ cannot be further completed but completion is not finished, it's `sole', if
+ text is a valid completion but may be further completed, it's `exact', and
+ other STATUSes may be added in the future.")
+
(defvar completion-annotate-function
nil
;; Note: there's a lot of scope as for when to add annotations and
will be displayed next to the completion. The function can access the
completion table and predicates via `minibuffer-completion-table' and related
variables.")
+(make-obsolete-variable 'completion-annotate-function
+ 'completion-extra-properties "24.1")
+
+(defun completion--done (string &optional finished message)
+ (let* ((exit-fun (plist-get completion-extra-properties :exit-function))
+ (pre-msg (and exit-fun (current-message))))
+ (assert (memq finished '(exact sole finished unknown)))
+ ;; FIXME: exit-fun should receive `finished' as a parameter.
+ (when exit-fun
+ (when (eq finished 'unknown)
+ (setq finished
+ (if (eq (try-completion string
+ minibuffer-completion-table
+ minibuffer-completion-predicate)
+ t)
+ 'finished 'exact)))
+ (funcall exit-fun string finished))
+ (when (and message
+ ;; Don't output any message if the exit-fun already did so.
+ (equal pre-msg (and exit-fun (current-message))))
+ (completion--message message))))
(defun minibuffer-completion-help ()
"Display a list of possible completions of the current minibuffer contents."
minibuffer-completion-predicate
(- (point) (field-beginning)))))
(message nil)
- (if (and completions
- (or (consp (cdr completions))
- (not (equal (car completions) string))))
- (let* ((last (last completions))
- (base-size (cdr last))
- ;; If the *Completions* buffer is shown in a new
- ;; window, mark it as softly-dedicated, so bury-buffer in
- ;; minibuffer-hide-completions will know whether to
- ;; delete the window or not.
- (display-buffer-mark-dedicated 'soft))
- (with-output-to-temp-buffer "*Completions*"
- ;; Remove the base-size tail because `sort' requires a properly
- ;; nil-terminated list.
- (when last (setcdr last nil))
- (setq completions (sort completions 'string-lessp))
- (when completion-annotate-function
- (setq completions
- (mapcar (lambda (s)
- (let ((ann
- (funcall completion-annotate-function s)))
- (if ann (list s ann) s)))
- completions)))
- (with-current-buffer standard-output
- (set (make-local-variable 'completion-base-position)
- (list (+ start base-size)
- ;; FIXME: We should pay attention to completion
- ;; boundaries here, but currently
- ;; completion-all-completions does not give us the
- ;; necessary information.
- end)))
- (display-completion-list completions)))
-
- ;; If there are no completions, or if the current input is already the
- ;; only possible completion, then hide (previous&stale) completions.
- (minibuffer-hide-completions)
- (ding)
- (minibuffer-message
- (if completions "Sole completion" "No completions")))
+ (if (or (null completions)
+ (and (not (consp (cdr completions)))
+ (equal (car completions) string)))
+ (progn
+ ;; If there are no completions, or if the current input is already
+ ;; the sole completion, then hide (previous&stale) completions.
+ (minibuffer-hide-completions)
+ (ding)
+ (minibuffer-message
+ (if completions "Sole completion" "No completions")))
+
+ (let* ((last (last completions))
+ (base-size (cdr last))
+ (prefix (unless (zerop base-size) (substring string 0 base-size)))
+ (global-af (or (plist-get completion-extra-properties
+ :annotation-function)
+ completion-annotate-function))
+ ;; If the *Completions* buffer is shown in a new
+ ;; window, mark it as softly-dedicated, so bury-buffer in
+ ;; minibuffer-hide-completions will know whether to
+ ;; delete the window or not.
+ (display-buffer-mark-dedicated 'soft))
+ (with-output-to-temp-buffer "*Completions*"
+ ;; Remove the base-size tail because `sort' requires a properly
+ ;; nil-terminated list.
+ (when last (setcdr last nil))
+ (setq completions (sort completions 'string-lessp))
+ (setq completions
+ (cond
+ (global-af
+ (mapcar (lambda (s)
+ (let ((ann (funcall global-af s)))
+ (if ann (list s ann) s)))
+ completions))
+ (t completions)))
+
+ (with-current-buffer standard-output
+ (set (make-local-variable 'completion-base-position)
+ (list (+ start base-size)
+ ;; FIXME: We should pay attention to completion
+ ;; boundaries here, but currently
+ ;; completion-all-completions does not give us the
+ ;; necessary information.
+ end))
+ (set (make-local-variable 'completion-list-insert-choice-function)
+ (let ((ctable minibuffer-completion-table)
+ (cpred minibuffer-completion-predicate)
+ (cprops completion-extra-properties))
+ (lambda (start end choice)
+ (unless
+ (or (zerop (length prefix))
+ (equal prefix
+ (buffer-substring-no-properties
+ (max (point-min) (- start (length prefix)))
+ start)))
+ (message "*Completions* out of date"))
+ ;; FIXME: Use `md' to do quoting&terminator here.
+ (completion--replace start end choice)
+ (let* ((minibuffer-completion-table ctable)
+ (minibuffer-completion-predicate cpred)
+ (completion-extra-properties cprops)
+ (result (concat prefix choice))
+ (bounds (completion-boundaries
+ result ctable cpred "")))
+ ;; If the completion introduces a new field, then
+ ;; completion is not finished.
+ (completion--done result
+ (if (eq (car bounds) (length result))
+ 'exact 'finished)))))))
+
+ (display-completion-list completions))))
nil))
(defun minibuffer-hide-completions ()
START and END delimit the entity to complete and should include point,
COLLECTION is the completion table to use to complete it, and
PROPS is a property list for additional information.
-Currently supported properties are:
- `:predicate' a predicate that completion candidates need to satisfy.
- `:annotation-function' the value to use for `completion-annotate-function'.")
+Currently supported properties are all the properties that can appear in
+`completion-extra-properties' plus:
+ `:predicate' a predicate that completion candidates need to satisfy.")
(defvar completion--capf-misbehave-funs nil
"List of functions found on `completion-at-point-functions' that misbehave.")
(pcase res
(`(,_ . ,(and (pred functionp) f)) (funcall f))
(`(,hookfun . (,start ,end ,collection . ,plist))
- (let* ((completion-annotate-function
- (or (plist-get plist :annotation-function)
- completion-annotate-function))
+ (let* ((completion-extra-properties plist)
(completion-in-region-mode-predicate
(lambda ()
;; We're still in the same completion field.
(`(,hookfun . (,start ,end ,collection . ,plist))
(let* ((minibuffer-completion-table collection)
(minibuffer-completion-predicate (plist-get plist :predicate))
- (completion-annotate-function
- (or (plist-get plist :annotation-function)
- completion-annotate-function))
+ (completion-extra-properties plist)
(completion-in-region-mode-predicate
(lambda ()
;; We're still in the same completion field.
(defun completion-pcm--prepare-delim-re (delims)
(setq completion-pcm--delim-wild-regex (concat "[" delims "*]")))
-(defcustom completion-pcm-word-delimiters "-_./: "
+(defcustom completion-pcm-word-delimiters "-_./:| "
"A string of characters treated as word delimiters for completion.
Some arcane rules:
If `]' is in this string, it must come first.
(funcall pcomplete-norm-func
(directory-file-name f))
pcomplete-seen)))))))
- (unless (zerop (length pcomplete-termination-string))
- ;; Add a space at the end of completion. Use a terminator-regexp
- ;; that never matches since the terminator cannot appear
- ;; within the completion field anyway.
- (setq table
- (apply-partially #'completion-table-with-terminator
- (cons pcomplete-termination-string
- "\\`a\\`")
- table)))
(when pcomplete-ignore-case
(setq table
(apply-partially #'completion-table-case-fold table)))
- (list beg (point) table :predicate pred))))))
+ (list beg (point) table
+ :predicate pred
+ :exit-function
+ (unless (zerop (length pcomplete-termination-string))
+ (lambda (_s finished)
+ (when (memq finished '(sole finished))
+ (if (looking-at
+ (regexp-quote pcomplete-termination-string))
+ (goto-char (match-end 0))
+ (insert pcomplete-termination-string)))))))))))
;; I don't think such commands are usable before first setting up buffer-local
;; variables to parse args, so there's no point autoloading it.
(list
start end
(lambda (string pred action)
- (completion-table-with-terminator
- " " (lambda (string pred action)
- (if (string-match "/" string)
- (completion-file-name-table string pred action)
- (complete-with-action action completions string pred)))
- string pred action)))))
+ (if (string-match "/" string)
+ (completion-file-name-table string pred action)
+ (complete-with-action action completions string pred)))
+ :exit-function
+ (lambda (_string finished)
+ (when (memq finished '(sole finished))
+ (if (looking-at " ")
+ (goto-char (match-end 0))
+ (insert " ")))))))
;; (defun shell-dynamic-complete-as-command ()
;; "Dynamically complete at point as a command.
(substring x 0 (string-match "=" x)))
process-environment))
(suffix (case (char-before start) (?\{ "}") (?\( ")") (t ""))))
- (list
- start end
- (apply-partially
- #'completion-table-with-terminator
- (cons (lambda (comp)
- (concat comp
- suffix
- (if (file-directory-p
- (comint-directory (getenv comp)))
- "/")))
- "\\`a\\`")
- variables))))))
+ (list start end variables
+ :exit-function
+ (lambda (s finished)
+ (when (memq finished '(sole finished))
+ (let ((suf (concat suffix
+ (if (file-directory-p
+ (comint-directory (getenv s)))
+ "/"))))
+ (if (looking-at (regexp-quote suf))
+ (goto-char (match-end 0))
+ (insert suf))))))))))
(defun shell-c-a-p-replace-by-expanded-directory ()
where the completion should be inserted and END (if non-nil) is the end
of the text to replace. If END is nil, point is used instead.")
+(defvar completion-list-insert-choice-function #'completion--replace
+ "Function to use to insert the text chosen in *Completions*.
+Called with 3 arguments (BEG END TEXT), it should replace the text
+between BEG and END with TEXT. Expected to be set buffer-locally
+in the *Completions* buffer.")
+
(defvar completion-base-size nil
"Number of chars before point not involved in completion.
This is a local variable in the completion list buffer.
;; In case this is run via the mouse, give temporary modes such as
;; isearch a chance to turn off.
(run-hooks 'mouse-leave-buffer-hook)
- (let (buffer base-size base-position choice)
- (with-current-buffer (window-buffer (posn-window (event-start event)))
- (setq buffer completion-reference-buffer)
- (setq base-size completion-base-size)
- (setq base-position completion-base-position)
- (save-excursion
- (goto-char (posn-point (event-start event)))
- (let (beg end)
- (if (and (not (eobp)) (get-text-property (point) 'mouse-face))
- (setq end (point) beg (1+ (point))))
- (if (and (not (bobp)) (get-text-property (1- (point)) 'mouse-face))
- (setq end (1- (point)) beg (point)))
- (if (null beg)
- (error "No completion here"))
- (setq beg (previous-single-property-change beg 'mouse-face))
- (setq end (or (next-single-property-change end 'mouse-face)
- (point-max)))
- (setq choice (buffer-substring-no-properties beg end)))))
-
- (let ((owindow (selected-window)))
+ (with-current-buffer (window-buffer (posn-window (event-start event)))
+ (let ((buffer completion-reference-buffer)
+ (base-size completion-base-size)
+ (base-position completion-base-position)
+ (insert-function completion-list-insert-choice-function)
+ (choice
+ (save-excursion
+ (goto-char (posn-point (event-start event)))
+ (let (beg end)
+ (cond
+ ((and (not (eobp)) (get-text-property (point) 'mouse-face))
+ (setq end (point) beg (1+ (point))))
+ ((and (not (bobp))
+ (get-text-property (1- (point)) 'mouse-face))
+ (setq end (1- (point)) beg (point)))
+ (t (error "No completion here")))
+ (setq beg (previous-single-property-change beg 'mouse-face))
+ (setq end (or (next-single-property-change end 'mouse-face)
+ (point-max)))
+ (buffer-substring-no-properties beg end))))
+ (owindow (selected-window)))
+
+ (unless (buffer-live-p buffer)
+ (error "Destination buffer is dead"))
(select-window (posn-window (event-start event)))
(if (and (one-window-p t 'selected-frame)
(window-dedicated-p (selected-window)))
(or (window-dedicated-p (selected-window))
(bury-buffer)))
(select-window
- (or (and (buffer-live-p buffer)
- (get-buffer-window buffer 0))
- owindow)))
-
- (choose-completion-string
- choice buffer
- (or base-position
- (when base-size
- ;; Someone's using old completion code that doesn't know
- ;; about base-position yet.
- (list (+ base-size (with-current-buffer buffer (field-beginning)))))
- ;; If all else fails, just guess.
- (with-current-buffer buffer
- (list (choose-completion-guess-base-position choice)))))))
+ (or (get-buffer-window buffer 0)
+ owindow))
+
+ (with-current-buffer buffer
+ (choose-completion-string
+ choice buffer
+ (or base-position
+ (when base-size
+ ;; Someone's using old completion code that doesn't know
+ ;; about base-position yet.
+ (list (+ base-size (field-beginning))))
+ ;; If all else fails, just guess.
+ (list (choose-completion-guess-base-position choice)))
+ insert-function)))))
;; Delete the longest partial match for STRING
;; that can be found before POINT.
If all functions in the list return nil, that means to use
the default method of inserting the completion in BUFFER.")
-(defun choose-completion-string (choice &optional buffer base-position)
+(defun choose-completion-string (choice &optional
+ buffer base-position insert-function)
"Switch to BUFFER and insert the completion choice CHOICE.
BASE-POSITION, says where to insert the completion."
;; If BUFFER is a minibuffer, barf unless it's the currently
;; active minibuffer.
(if (and mini-p
- (or (not (active-minibuffer-window))
- (not (equal buffer
+ (not (and (active-minibuffer-window)
+ (equal buffer
(window-buffer (active-minibuffer-window))))))
(error "Minibuffer is not active for completion")
;; Set buffer so buffer-local choose-completion-string-functions works.
;; and indeed unused. The last used to be `base-size', so we
;; keep it to try and avoid breaking old code.
choice buffer base-position nil)
+ ;; This remove-text-properties should be unnecessary since `choice'
+ ;; comes from buffer-substring-no-properties.
+ ;;(remove-text-properties 0 (lenth choice) '(mouse-face nil) choice)
;; Insert the completion into the buffer where it was requested.
- (delete-region (or (car base-position) (point))
- (or (cadr base-position) (point)))
- (insert choice)
- (remove-text-properties (- (point) (length choice)) (point)
- '(mouse-face nil))
- ;; Update point in the window that BUFFER is showing in.
+ (funcall (or insert-function completion-list-insert-choice-function)
+ (or (car base-position) (point))
+ (or (cadr base-position) (point))
+ choice)
+ ;; Update point in the window that BUFFER is showing in.
(let ((window (get-buffer-window buffer t)))
(set-window-point window (point)))
;; If completing for the minibuffer, exit it with this choice.
0 (or completion-base-size 0)))))))
(with-current-buffer standard-output
(let ((base-size completion-base-size) ;Read before killing localvars.
- (base-position completion-base-position))
+ (base-position completion-base-position)
+ (insert-fun completion-list-insert-choice-function))
(completion-list-mode)
(set (make-local-variable 'completion-base-size) base-size)
- (set (make-local-variable 'completion-base-position) base-position))
+ (set (make-local-variable 'completion-base-position) base-position)
+ (set (make-local-variable 'completion-list-insert-choice-function)
+ insert-fun))
(set (make-local-variable 'completion-reference-buffer) mainbuf)
(if base-dir (setq default-directory base-dir))
;; Maybe insert help string.
-;;; bibtex.el --- BibTeX mode for GNU Emacs
+;;; bibtex.el --- BibTeX mode for GNU Emacs -*- lexical-binding: t -*-
;; Copyright (C) 1992, 1994-1999, 2001-2011 Free Software Foundation, Inc.
(const entry-class)
(const t)))
(put 'bibtex-maintain-sorted-entries 'safe-local-variable
- '(lambda (a) (memq a '(nil t plain crossref entry-class))))
+ (lambda (a) (memq a '(nil t plain crossref entry-class))))
(defcustom bibtex-sort-entry-class
'(("String")
(modify-syntax-entry ?\" "\"" st)
(modify-syntax-entry ?$ "$$ " st)
(modify-syntax-entry ?% "< " st)
- (modify-syntax-entry ?' "w " st)
+ (modify-syntax-entry ?' "w " st) ;FIXME: Not allowed in @string keys.
(modify-syntax-entry ?@ "w " st)
(modify-syntax-entry ?\\ "\\" st)
(modify-syntax-entry ?\f "> " st)
;; The Key `C-c&' is reserved for reftex.el
(define-key km "\t" 'bibtex-find-text)
(define-key km "\n" 'bibtex-next-field)
- (define-key km "\M-\t" 'bibtex-complete)
+ (define-key km "\M-\t" 'completion-at-point)
(define-key km "\C-c\"" 'bibtex-remove-delimiters)
(define-key km "\C-c{" 'bibtex-remove-delimiters)
(define-key km "\C-c}" 'bibtex-remove-delimiters)
;; remove delimiters from purely numerical fields
(when (and (memq 'numerical-fields format)
(progn (goto-char beg-text)
- (looking-at "\\(\"[0-9]+\"\\)\\|\\({[0-9]+}\\)")))
+ (looking-at "\"[0-9]+\"\\|{[0-9]+}")))
(goto-char end-text)
(delete-char -1)
(goto-char beg-text)
(content (bibtex-text-in-field field bibtex-autokey-use-crossref))
case-fold-search)
(unless content (setq content ""))
- (dolist (pattern change-list content)
+ (dolist (pattern change-list)
(setq content (replace-regexp-in-string (car pattern)
(cdr pattern)
- content t)))))
+ content t)))
+ content))
(defun bibtex-autokey-get-names ()
"Get contents of the name field of the current entry.
(bibtex-sort-ignore-string-entries t)
bounds)
(bibtex-map-entries
- (lambda (key beg end)
+ (lambda (key _beg end)
(if (and abortable
(input-pending-p))
;; user has aborted by typing a key: return `aborted'
(message "No BibTeX buffers defined")))
buffer-list))
-(defun bibtex-complete-internal (completions)
- "Complete word fragment before point to longest prefix of COMPLETIONS.
-COMPLETIONS is an alist of strings. If point is not after the part
-of a word, all strings are listed. Return completion."
- ;; Return value is used by cleanup functions.
- ;; Code inspired by `lisp-complete-symbol'.
- (let ((beg (save-excursion
- (re-search-backward "[ \t{\"]")
- (forward-char)
- (point)))
- (end (point)))
- (when (completion-in-region beg end completions)
- (buffer-substring beg (point)))))
-
(defun bibtex-complete-string-cleanup (str compl)
"Cleanup after inserting string STR.
Remove enclosing field delimiters for STR. Display message with
;; Interactive Functions:
;;;###autoload
-(defun bibtex-mode ()
+(define-derived-mode bibtex-mode nil "BibTeX"
"Major mode for editing BibTeX files.
General information on working with BibTeX mode:
Some features of BibTeX mode are available only by setting the variable
`bibtex-maintain-sorted-entries' to non-nil. However, then BibTeX mode
-works only with buffers containing valid (syntactical correct) and sorted
+works only with buffers containing valid (syntactically correct) and sorted
entries. This is usually the case, if you have created a buffer completely
with BibTeX mode and finished every new entry with \\[bibtex-clean-entry].
\\[bibtex-remove-delimiters] removes the double-quotes or braces around the text of the current field.
\\[bibtex-empty-field] replaces the text of the current field with the default \"\" or {}.
\\[bibtex-find-text] moves point to the end of the current field.
-\\[bibtex-complete] completes word fragment before point according to context.
+\\[completion-at-point] completes word fragment before point according to context.
The command \\[bibtex-clean-entry] cleans the current entry, i.e. it removes OPT/ALT
from the names of all non-empty optional or alternative fields, checks that
if that value is non-nil.
\\{bibtex-mode-map}"
- (interactive)
- (kill-all-local-variables)
- (use-local-map bibtex-mode-map)
- (setq major-mode 'bibtex-mode)
- (setq mode-name "BibTeX")
- (set-syntax-table bibtex-mode-syntax-table)
+ (add-hook 'completion-at-point-functions
+ 'bibtex-completion-at-point-function nil 'local)
(make-local-variable 'bibtex-buffer-last-parsed-tick)
;; Install stealthy parse function if not already installed
(unless bibtex-parse-idle-timer
(set (make-local-variable 'defun-prompt-regexp) "^[ \t]*@[[:alnum:]]+[ \t]*")
(set (make-local-variable 'outline-regexp) "[ \t]*@")
(set (make-local-variable 'fill-paragraph-function) 'bibtex-fill-field)
- (set (make-local-variable 'fill-prefix) (make-string (+ bibtex-entry-offset
- bibtex-contline-indentation)
- ?\s))
+ (set (make-local-variable 'fill-prefix)
+ (make-string (+ bibtex-entry-offset bibtex-contline-indentation) ?\s))
(set (make-local-variable 'font-lock-defaults)
'(bibtex-font-lock-keywords
nil t ((?$ . "\"")
(setq imenu-generic-expression
(list (list nil bibtex-entry-head bibtex-key-in-head))
imenu-case-fold-search t)
- (make-local-variable 'choose-completion-string-functions)
;; XEmacs needs `easy-menu-add', Emacs does not care
(easy-menu-add bibtex-edit-menu)
- (easy-menu-add bibtex-entry-menu)
- (run-mode-hooks 'bibtex-mode-hook))
+ (easy-menu-add bibtex-entry-menu))
(defun bibtex-field-list (entry-type)
"Return list of allowed fields for entry ENTRY-TYPE.
(bibtex-sort-ignore-string-entries (not count-string-entries)))
(save-restriction
(if mark-active (narrow-to-region (region-beginning) (region-end)))
- (bibtex-map-entries (lambda (key beg end) (setq number (1+ number)))))
+ (bibtex-map-entries (lambda (_key _beg _end) (setq number (1+ number)))))
(message "%s contains %d entries."
(if mark-active "Region" "Buffer")
number)))
(unless (local-variable-p 'bibtex-sort-entry-class-alist)
(set (make-local-variable 'bibtex-sort-entry-class-alist)
(let ((i -1) alist)
- (dolist (class bibtex-sort-entry-class alist)
+ (dolist (class bibtex-sort-entry-class)
(setq i (1+ i))
(dolist (entry class)
;; All entry types should be downcase (for ease of comparison).
(push (cons (if (stringp entry) (downcase entry) entry) i)
- alist)))))))
+ alist)))
+ alist))))
(defun bibtex-lessp (index1 index2)
"Predicate for sorting BibTeX entries with indices INDEX1 and INDEX2.
(let (previous current key-list)
(bibtex-progress-message "Checking for duplicate keys")
(bibtex-map-entries
- (lambda (key beg end)
+ (lambda (key _beg _end)
(bibtex-progress-message)
(setq current (bibtex-entry-index))
(cond ((not previous))
"Checking required fields and month fields")
(let ((bibtex-sort-ignore-string-entries t))
(bibtex-map-entries
- (lambda (key beg end)
+ (lambda (_key beg _end)
(bibtex-progress-message)
(let* ((entry-list (assoc-string (bibtex-type-in-head)
bibtex-entry-field-alist t))
(if (memq 'realign bibtex-entry-format)
(bibtex-realign))
(bibtex-progress-message "Formatting" 1)
- (bibtex-map-entries (lambda (key beg end)
+ (bibtex-map-entries (lambda (_key _beg _end)
(bibtex-progress-message)
(bibtex-clean-entry reformat-reference-keys t)))
(bibtex-progress-message 'done))
(goto-char (point-max))
(message "Buffer is now parsable. Please save it.")))
-(defun bibtex-complete ()
- "Complete word fragment before point according to context.
-If point is inside key or crossref field perform key completion based on
-`bibtex-reference-keys'. Inside a month field perform key completion
-based on `bibtex-predefined-month-strings'. Inside any other field
-\(including a String or Preamble definition) perform string completion
-based on `bibtex-strings'.
-An error is signaled if point is outside key or BibTeX field."
- (interactive)
+(define-obsolete-function-alias 'bibtex-complete 'completion-at-point "24.1")
+(defun bibtex-completion-at-point-function ()
(let ((pnt (point))
(case-fold-search t)
+ (beg (save-excursion
+ (re-search-backward "[ \t{\"]")
+ (forward-char)
+ (point)))
+ (end (point))
bounds name compl)
(save-excursion
(if (and (setq bounds (bibtex-enclosing-field nil t))
(setq compl 'key)))))
(cond ((eq compl 'key)
- ;; key completion: no cleanup needed
- (setq choose-completion-string-functions nil)
- (let (completion-ignore-case)
- (bibtex-complete-internal (bibtex-global-key-alist))))
+ ;; Key completion: no cleanup needed.
+ (list beg end
+ (lambda (s p a)
+ (let (completion-ignore-case)
+ (complete-with-action a (bibtex-global-key-alist) s p)))))
((eq compl 'crossref-key)
- ;; crossref key completion
- ;;
- ;; If we quit the *Completions* buffer without requesting
- ;; a completion, `choose-completion-string-functions' is still
- ;; non-nil. Therefore, `choose-completion-string-functions' is
- ;; always set (either to non-nil or nil) when a new completion
- ;; is requested.
- (let (completion-ignore-case)
- (setq choose-completion-string-functions
- (lambda (choice buffer base-position &rest ignored)
- (setq choose-completion-string-functions nil)
- (choose-completion-string choice buffer base-position)
- (bibtex-complete-crossref-cleanup choice)
- t)) ; needed by choose-completion-string-functions
- (bibtex-complete-crossref-cleanup
- (bibtex-complete-internal (bibtex-global-key-alist)))))
+ ;; Crossref key completion.
+ (let* ((buf (current-buffer)))
+ (list beg end
+ (lambda (s p a)
+ (cond
+ ((eq a 'metadata) `(metadata (category . bibtex-key)))
+ (t (let ((completion-ignore-case nil))
+ (complete-with-action
+ a (bibtex-global-key-alist) s p)))))
+ :exit-function
+ (lambda (string status)
+ (when (memq status '(exact sole finished))
+ (let ((summary
+ (with-current-buffer buf
+ (save-excursion
+ (if (bibtex-search-entry string)
+ (funcall bibtex-summary-function))))))
+ (when summary
+ (message "%s %s" string summary))))))))
((eq compl 'string)
- ;; string key completion: no cleanup needed
- (setq choose-completion-string-functions nil)
- (let ((completion-ignore-case t))
- (bibtex-complete-internal bibtex-strings)))
+ ;; String key completion: no cleanup needed.
+ (list beg end
+ (lambda (s p a)
+ (let ((completion-ignore-case t))
+ (complete-with-action a bibtex-strings s p)))))
(compl
- ;; string completion
- (let ((completion-ignore-case t))
- (setq choose-completion-string-functions
- `(lambda (choice buffer base-position &rest ignored)
- (setq choose-completion-string-functions nil)
- (choose-completion-string choice buffer base-position)
- (bibtex-complete-string-cleanup choice ',compl)
- t)) ; needed by `choose-completion-string-functions'
- (bibtex-complete-string-cleanup (bibtex-complete-internal compl)
- compl)))
-
- (t (setq choose-completion-string-functions nil)
- (error "Point outside key or BibTeX field")))))
+ ;; String completion.
+ (list beg end
+ (lambda (s p a)
+ (cond
+ ((eq a 'metadata) `(metadata (category . bibtex-string)))
+ (t (let ((completion-ignore-case t))
+ (complete-with-action a compl s p)))))
+ :exit-function
+ (lambda (string status)
+ (when (memq status '(exact finished sole))
+ (let ((abbr (cdr (assoc-string string compl t))))
+ (when abbr
+ (message "%s = abbreviation for `%s'" string abbr))))
+ (when (eq status 'finished)
+ (save-excursion (bibtex-remove-delimiters)))))))))
(defun bibtex-Article ()
"Insert a new BibTeX @Article entry; see also `bibtex-entry'."
;; Make BibTeX a Feature
(provide 'bibtex)
-
;;; bibtex.el ends here