emacs-devel
[Top][All Lists]
Advanced

[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))




reply via email to

[Prev in Thread] Current Thread [Next in Thread]