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

3

9

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 M-x 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?

Procrustean answered 10/2, 2010 at 21:3 Comment(3)
It would be a lot more work, but if you're serious about improving Emacs' C# support (which it seems to desparately need), the most complete and powerful way of doing it is with Semantic (cedet.sourceforge.net/semantic.shtml). This involves writing a full-on parser, but gives you the benefits of having such a parser. If you're looking for something quick, it's overkill, though.Stingy
Your question inspired me to send a patch for a similar problem in makefile-mode: it used to have two top-level menus, "Dependencies" and "Macro assignments", but with my patch they're merged into a flat list (I just replaced the heading strings with nil). Doing the same for the C# mode shouldn't be hard.Drucill
My patch: debbugs.gnu.org/cgi/bugreport.cgi?bug=5582Drucill
O
2

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.

Olnee answered 13/2, 2010 at 1:49 Comment(0)
C
1

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)))))))
Chordate answered 10/2, 2010 at 22:37 Comment(0)
D
1

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.

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

Dismantle answered 13/1, 2022 at 23:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.