简体   繁体   中英

In Emacs, how can I use imenu more sensibly with C#?

I've used emacs for a long time, but I haven't been keeping up with a bunch of features. One of these is speedbar , which I just briefly investigated now. Another is imenu . Both of these were mentioned in in-emacs-how-can-i-jump-between-functions-in-the-current-file?

Using imenu, I can jump to particular methods in the module I'm working in. But there is a parse hierarchy that I have to negotiate before I get the option to choose (with autocomplete) the method name.

It goes like this. I type Mx imenu and then I get to choose Using or Types . The Using choice allows me to jump to any of the using statements at the top level of the C# file (something like imports statements in a Java module, for those of you who don't know C#). Not super helpful. I choose Types. Then I have to choose a namespace and a class, even though there is just one of each in the source module. At that point I can choose between variables, types, and methods. If I choose methods I finally get the list of methods to choose from. The hierarchy I traverse looks like this;

Using
Types
  Namespace
    Class
      Types
      Variables
      Methods
         method names

Only after I get to the 5th level do I get to select the thing I really want to jump to: a particular method.

Imenu seems intelligent about the source module, but kind of hard to use. Am I doing it wrong?

The CEDET tools at http://cedet.sf.net includes a C# parser in the 'contrib' area that can parse C# code. CEDET then supports specialized interfaces for both speedbar and imenu, that will shape your menu constructs in a way that code organized, not tag type organized. In c++, for example, code like this:

namespace foo {
   class bar {
       int somemethod();
   }
}

would give you a tree that had "bar" under "foo", and "somemethod" under "bar", so if you know your structure, you just need to unwind by name to the tag you want.

I use the following function, which will use ido and just prompt for the symbols you can jump to. Just call it instead of imenu:

(defun ido-goto-symbol ()
  "Will update the imenu index and then use ido to select a symbol to navigate to"
  (interactive)
  (imenu--make-index-alist)
  (let ((name-and-pos '())
        (symbol-names '()))
    (flet ((addsymbols (symbol-list)
                       (when (listp symbol-list)
                         (dolist (symbol symbol-list)
                           (let ((name nil) (position nil))
                             (cond
                              ((and (listp symbol) (imenu--subalist-p symbol))
                               (addsymbols symbol))
                              ((listp symbol)
                               (setq name (car symbol))
                               (setq position (cdr symbol)))
                              ((stringp symbol)
                               (setq name symbol)
                               (setq position (get-text-property 1 'org-imenu-marker symbol))))
                             (unless (or (null position) (null name))
                               (add-to-list 'symbol-names name)
                               (add-to-list 'name-and-pos (cons name position))))))))
      (addsymbols imenu--index-alist)
      (let* ((symbol-at-point (symbol-name (symbol-at-point)))
             (selected-symbol (ido-completing-read
                               "Symbol? "
                               (if (member symbol-at-point symbol-names)
                                   (cons symbol-at-point (remove-if (lambda (x) (string-equal x symbol-at-point))
                                                                    symbol-names))
                                 symbol-names)))
             (position (cdr (assoc selected-symbol name-and-pos))))
        (if (markerp position)
             (goto-char position) (goto-char (overlay-start position)))))))
  (goto-char position) (goto-char (overlay-start position)))))))

In case it helps anybody, i made my own code following the instructions at imenu emacs documentation . You should be able to add this to your init.el (or in my case to my .spacemacs file under dotspacemacs/user-config)

  (setq csharp-imenu-functions
    '(("Variables" "^\\s-*[a-zA-Z0-9._ ]* \\([a-zA-Z0-9_]*\\)\\( = \\sw*\\|\\s-*\\);$" 1)
      ("Functions" "^\\s-*[^/]* \\([a-zA-Z0-9_]+\\)(.*)\\(\\s-*.*\n\\|\\ *\\)\\s-*{" 1)
      ("Classes" "^\\s-*\\(.*\\)class +\\([a-zA-Z0-9_]+\\)" 2)
      ("Namespaces" "^namespace +\\([a-z0-9_]*\\)" 1)))

  (add-hook 'csharp-mode-hook
            (lambda()
              (setq imenu-generic-expression csharp-imenu-functions)))

I'll try to keep this up to date if I make any changes. Right now it recognizes "using" statements as variables. No other bugs that I'm aware.

PS I have not tried @Eric's solution, maybe its much better than mine.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM