diff options
author | Thierry Volpiatto <thierry.volpiatto@gmail.com> | 2014-09-04 10:49:56 -0400 |
---|---|---|
committer | Stefan Monnier <monnier@iro.umontreal.ca> | 2014-09-04 10:49:56 -0400 |
commit | e77bcfa34d3dfd0efb6ffb40e4035374e22143fc (patch) | |
tree | edbf705069b7b6797c0280c9d1aea445128cf5ec | |
parent | baff67fcd5d64af9d218204111d2566ae408c967 (diff) |
* 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
-rw-r--r-- | lisp/ChangeLog | 6 | ||||
-rw-r--r-- | lisp/emacs-lisp/eldoc.el | 72 |
2 files changed, 62 insertions, 16 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index d8c48287c1..78d3cf5632 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -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> * progmodes/which-func.el (which-func-ff-hook): Obey pre-existing diff --git a/lisp/emacs-lisp/eldoc.el b/lisp/emacs-lisp/eldoc.el index 0b8304af29..acb1bdc32e 100644 --- a/lisp/emacs-lisp/eldoc.el +++ b/lisp/emacs-lisp/eldoc.el @@ -369,9 +369,16 @@ or elsewhere, return a 1-line docstring." (defun eldoc-highlight-function-argument (sym args index) "Highlight argument INDEX in ARGS list for function SYM. 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) (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 ;; 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. (when (string-match "&key" args) (let* (case-fold-search + key-have-value + (sym-name (symbol-name sym)) (cur-w (current-word)) + (args-lst-ak (cdr (member "&key" args-lst))) (limit (save-excursion - (when (re-search-backward (symbol-name sym) nil t) + (when (re-search-backward sym-name nil t) (match-end 0)))) - (cur-a (if (string-match ":\\([^ ()]*\\)" cur-w) + (cur-a (if (and cur-w (string-match ":\\([^ ()]*\\)" cur-w)) (substring cur-w 1) (save-excursion - (when (re-search-backward ":\\([^ ()\n]*\\)" limit t) - (match-string 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 - (string-match (concat "\\_<" (upcase cur-a) "\\_>") args)) - (setq index nil ; Skip next block based on positional args. - start (match-beginning 0) - end (match-end 0))))) + (let (split) + (when (re-search-backward ":\\([^()\n]*\\)" limit t) + (setq split (split-string (match-string 1) " " t)) + (prog1 (car split) + (when (cdr split) + (setq key-have-value t)))))))) + ;; If `cur-a' is not one of `args-lst-ak' + ;; assume user is entering an unknow key + ;; referenced in last position in signature. + (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. (while (and index (>= index 1)) (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") ;; All the rest arguments are the same. (setq index 1)) - ((string= argument "&optional")) ; Skip. + ((string= argument "&optional")) ; Skip. ((string= argument "&allow-other-keys")) ; Skip. ;; Back to index 0 in ARG1 ARG2 ARG2 ARG3 etc... ;; like in `setq'. - ((or (string-match-p "\\.\\.\\.$" argument) - (and (string-match-p "\\.\\.\\.)?$" args) + ((or (and (string-match-p "\\.\\.\\.$" argument) + (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))) (setq index 0)) (t |