[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: imenu-level-separator
From: |
Stefan Monnier |
Subject: |
Re: imenu-level-separator |
Date: |
Fri, 19 Apr 2013 01:25:46 -0400 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/24.3.50 (gnu/linux) |
> When reading imenu items from minibuffer I don't like navigating defun
> names by hitting RET, I rather would like completion to be performed on
> a flattened version of the alist separated with dots (in the Python
> case). So as I'm about to implement something like that to python.el,
> perhaps there's interest for this to be added to imenu core itself.
I agree that the minibuffer completion in imenu sucks.
I started down that path some time ago but never got around to
finishing it. See my current local patch below.
Stefan
Using submit branch file:///home/monnier/src/emacs/bzr/trunk/
=== modified file 'lisp/imenu.el'
--- lisp/imenu.el 2013-02-28 17:15:08 +0000
+++ lisp/imenu.el 2013-03-09 17:01:55 +0000
@@ -828,12 +828,85 @@
(concat "\\`" (regexp-quote guess))
(concat (regexp-quote guess) "\\'")
(regexp-quote guess)))
- (dolist (x completions)
- (if (string-match re (car x)) (throw 'found (car x)))))))))
+ (let ((als (list (cons "" completions)))
+ (later ()))
+ (while (or als (prog1 (setq als (nreverse later))
+ (setq later ())))
+ (let ((prefix (caar als))
+ (al (cdar als)))
+ (setq als (cdr als))
+ (dolist (x al)
+ (cond
+ ((imenu--subalist-p x)
+ (push (cons (concat prefix (car x) "/") (cdr x))
+ later))
+ ((string-match re (car x))
+ (throw 'found (concat prefix (car x))))))))))))))
+
+(defun imenu--lookup-index (string index-alist sep-re)
+ (let ((result index-alist)
+ (parts (split-string string sep-re)))
+ (while parts
+ (setq result (assoc (pop parts) (cdr result)))
+ (if (imenu--subalist-p result) (setq result (cdr result))))
+ result))
(defun imenu--completion-buffer (index-alist &optional prompt)
"Let the user select from INDEX-ALIST in a completion buffer with PROMPT.
+Return one of the entries in INDEX-ALIST or nil."
+ ;; Create a list for this buffer only when needed.
+ ;; FIXME: Obey imenu-space-replacement.
+ ;; FIXME: imenu (via imenu--in-alist) already allows matching sub-elements.
+ ;; FIXME: Maybe a better approach is to do "name/type" where /type is only
+ ;; needed in case of ambiguity.
+ (let* ((name (thing-at-point 'symbol))
+ ;; FIXME: what should we do if / appears in one of the entries?
+ (separator "/")
+ (sep-re (regexp-quote separator))
+ (nonsep-re (format "[^%s]*\\'" separator)))
+ (when (stringp name)
+ (setq name (or (imenu-find-default name index-alist) name)))
+ (cond (prompt)
+ ((and name (imenu--in-alist name index-alist))
+ (setq prompt (format "Index item (default %s): " name)))
+ (t (setq prompt "Index item: ")))
+ (minibuffer-with-setup-hook
+ ;; Display the completion buffer.
+ (if imenu-eager-completion-buffer
+ #'minibuffer-completion-help #'ignore)
+ (let* ((table
+ (lambda (string pred action)
+ (string-match nonsep-re string)
+ (let* ((boundary (match-beginning 0))
+ (prefix (substring string 0 boundary))
+ (rest (substring string boundary)))
+ (cond
+ ((eq (car-safe action) 'boundaries)
+ `(boundaries ,boundary
+ ,@(string-match sep-re (cdr action))))
+ (t
+ (let* ((al (if (zerop (length prefix))
+ index-alist
+ ;; Strip final separator.
+ (imenu--lookup-index (substring prefix 0 -1)
+ index-alist sep-re)))
+ (table (mapcar
+ (lambda (x)
+ (if (imenu--subalist-p x)
+ (cons (concat (car x) separator)
+ (cdr x))
+ x))
+ al)))
+ (completion-table-with-context
+ prefix table rest pred action)))))))
+ (name (completing-read prompt table
+ nil t nil 'imenu--history-list name)))
+ (imenu--lookup-index name index-alist sep-re)))))
+
+(defun imenu--completion-buffer-modal (index-alist &optional prompt)
+ "Let the user select from INDEX-ALIST in a completion buffer with PROMPT.
+
Return one of the entries in index-alist or nil."
;; Create a list for this buffer only when needed.
(let ((name (thing-at-point 'symbol))
@@ -908,7 +981,7 @@
(or (framep window) (null window) (select-window window))))
;; Create a list for this buffer only when needed.
(while (eq result t)
- (setq index-alist (if alist alist (imenu--make-index-alist)))
+ (setq index-alist (or alist (imenu--make-index-alist)))
(setq result
(if (and imenu-use-popup-menu
(or (eq imenu-use-popup-menu t) mouse-triggered))