Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 271
Cheeso Avatar asked Feb 10 '10 21:02

Cheeso


3 Answers

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.

like image 131
Eric Avatar answered Nov 20 '22 06:11

Eric


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)))))))
like image 31
Nathaniel Flath Avatar answered Nov 20 '22 05:11

Nathaniel Flath


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.

like image 1
Rodrigo Sebastian Mendoza Teja Avatar answered Nov 20 '22 07:11

Rodrigo Sebastian Mendoza Teja