* lisp/emacs-lisp/eldoc.el (eldoc-highlight-function-argument): Handle the

case where we're currently providing part of the &rest arg after some
&key args, as in define-ibuffer-op.

Fixes: debbugs:18048
This commit is contained in:
Thierry Volpiatto 2014-09-04 10:49:56 -04:00 committed by Stefan Monnier
parent baff67fcd5
commit e77bcfa34d
2 changed files with 62 additions and 16 deletions

View file

@ -1,3 +1,9 @@
2014-09-04 Thierry Volpiatto <thierry.volpiatto@gmail.com>
* emacs-lisp/eldoc.el (eldoc-highlight-function-argument): Handle the
case where we're currently providing part of the &rest arg after some
&key args, as in define-ibuffer-op (bug#18048).
2014-09-03 Stefan Monnier <monnier@iro.umontreal.ca> 2014-09-03 Stefan Monnier <monnier@iro.umontreal.ca>
* progmodes/which-func.el (which-func-ff-hook): Obey pre-existing * progmodes/which-func.el (which-func-ff-hook): Obey pre-existing

View file

@ -369,9 +369,16 @@ or elsewhere, return a 1-line docstring."
(defun eldoc-highlight-function-argument (sym args index) (defun eldoc-highlight-function-argument (sym args index)
"Highlight argument INDEX in ARGS list for function SYM. "Highlight argument INDEX in ARGS list for function SYM.
In the absence of INDEX, just call `eldoc-docstring-format-sym-doc'." In the absence of INDEX, just call `eldoc-docstring-format-sym-doc'."
;; FIXME: This should probably work on the list representation of `args'
;; rather than its string representation.
;; FIXME: This function is much too long, we need to split it up!
(let ((start nil) (let ((start nil)
(end 0) (end 0)
(argument-face 'eldoc-highlight-function-argument)) (argument-face 'eldoc-highlight-function-argument)
(args-lst (mapcar (lambda (x)
(replace-regexp-in-string
"\\`[(]\\|[)]\\'" "" x))
(split-string args))))
;; Find the current argument in the argument string. We need to ;; Find the current argument in the argument string. We need to
;; handle `&rest' and informal `...' properly. ;; handle `&rest' and informal `...' properly.
;; ;;
@ -385,23 +392,53 @@ In the absence of INDEX, just call `eldoc-docstring-format-sym-doc'."
;; position in ARGS based on this current arg. ;; position in ARGS based on this current arg.
(when (string-match "&key" args) (when (string-match "&key" args)
(let* (case-fold-search (let* (case-fold-search
key-have-value
(sym-name (symbol-name sym))
(cur-w (current-word)) (cur-w (current-word))
(args-lst-ak (cdr (member "&key" args-lst)))
(limit (save-excursion (limit (save-excursion
(when (re-search-backward (symbol-name sym) nil t) (when (re-search-backward sym-name nil t)
(match-end 0)))) (match-end 0))))
(cur-a (if (string-match ":\\([^ ()]*\\)" cur-w) (cur-a (if (and cur-w (string-match ":\\([^ ()]*\\)" cur-w))
(substring cur-w 1) (substring cur-w 1)
(save-excursion (save-excursion
(when (re-search-backward ":\\([^ ()\n]*\\)" limit t) (let (split)
(match-string 1)))))) (when (re-search-backward ":\\([^()\n]*\\)" limit t)
;; If `cur-a' is nil probably cursor is on a positional arg (setq split (split-string (match-string 1) " " t))
;; before `&key', in this case, exit this block and determine (prog1 (car split)
;; position with `index'. (when (cdr split)
(when (and cur-a (setq key-have-value t))))))))
(string-match (concat "\\_<" (upcase cur-a) "\\_>") args)) ;; If `cur-a' is not one of `args-lst-ak'
(setq index nil ; Skip next block based on positional args. ;; assume user is entering an unknow key
start (match-beginning 0) ;; referenced in last position in signature.
end (match-end 0))))) (other-key-arg (and (stringp cur-a)
args-lst-ak
(not (member (upcase cur-a) args-lst-ak))
(upcase (car (last args-lst-ak))))))
(unless (string= cur-w sym-name)
;; The last keyword have already a value
;; i.e :foo a b and cursor is at b.
;; If signature have also `&rest'
;; (assume it is after the `&key' section)
;; go to the arg after `&rest'.
(if (and key-have-value
(save-excursion
(not (re-search-forward ":.*" (point-at-eol) t)))
(string-match "&rest \\([^ ()]*\\)" args))
(setq index nil ; Skip next block based on positional args.
start (match-beginning 1)
end (match-end 1))
;; If `cur-a' is nil probably cursor is on a positional arg
;; before `&key', in this case, exit this block and determine
;; position with `index'.
(when (and cur-a ; A keyword arg (dot removed) or nil.
(or (string-match
(concat "\\_<" (upcase cur-a) "\\_>") args)
(string-match
(concat "\\_<" other-key-arg "\\_>") args)))
(setq index nil ; Skip next block based on positional args.
start (match-beginning 0)
end (match-end 0)))))))
;; Handle now positional arguments. ;; Handle now positional arguments.
(while (and index (>= index 1)) (while (and index (>= index 1))
(if (string-match "[^ ()]+" args end) (if (string-match "[^ ()]+" args end)
@ -412,12 +449,15 @@ In the absence of INDEX, just call `eldoc-docstring-format-sym-doc'."
(cond ((string= argument "&rest") (cond ((string= argument "&rest")
;; All the rest arguments are the same. ;; All the rest arguments are the same.
(setq index 1)) (setq index 1))
((string= argument "&optional")) ; Skip. ((string= argument "&optional")) ; Skip.
((string= argument "&allow-other-keys")) ; Skip. ((string= argument "&allow-other-keys")) ; Skip.
;; Back to index 0 in ARG1 ARG2 ARG2 ARG3 etc... ;; Back to index 0 in ARG1 ARG2 ARG2 ARG3 etc...
;; like in `setq'. ;; like in `setq'.
((or (string-match-p "\\.\\.\\.$" argument) ((or (and (string-match-p "\\.\\.\\.$" argument)
(and (string-match-p "\\.\\.\\.)?$" args) (string= argument (car (last args-lst))))
(and (string-match-p "\\.\\.\\.$"
(substring args 1 (1- (length args))))
(= (length (remove "..." args-lst)) 2)
(> index 1) (cl-oddp index))) (> index 1) (cl-oddp index)))
(setq index 0)) (setq index 0))
(t (t