10

Throughout the day I am constantly using C-h f or C-h v (describe-function and describe-variable) to look up documentation for functions and variables. More often than not, if I don't get all the information I need, I will click on the file link at the end of:

some-random-command is an interactive compiled Lisp function in `some-mode.el'.

and navigate to the source code. This works for installed packages, but doesn't seem to work for built-in ones. For example, at the top of the help page for the command describe-function all I get is:

describe-function is an interactive compiled Lisp function.

with no link to the source code. Is there any way to quickly navigate to the source code of a built in package?

I know I can find source code in e.g., /usr/share/emacs/24.5/lisp, and come up with any number of ways to access that directory quickly, but I am curious if there is a quick and easy way to navigate to a built-in function/variable definition in the source code. Thank you!

elethan
  • 4,755
  • 3
  • 29
  • 56
  • 5
    `M-x find-function`; `M-x find-variable`; `M-x find-face`; `M-x find-library`. I always use a full installation of Emacs so that I have access to everything, and just after building my own Emacs I copy over the C-source code and set its location so that I can find C-Source code definitions also. See the variable `find-function-C-source-directory` to set the location of the C-source code after you copy it over. – lawlist Jan 06 '16 at 05:31
  • 1
    Using the master branch of Emacs, I get the following with `M-x describe-function`: **describe-function is an interactive autoloaded compiled Lisp function in ‘help-fns.el’.** And from there I can click on (or press enter on) `help-fns.el` and am then transported to the applicable section of the code. Perhaps you have multiple Emacs versions, and the one your using at the moment doesn't have all the source code installed? – lawlist Jan 06 '16 at 05:48
  • If you get that behavior when you start Emacs using `emacs -Q` (no init file), or if you can repro it with a recipe that starts with `emacs -Q` (e.g. saying what libraries you load and how you load them etc.), then please consider filing a bug report: **`M-x report-emacs-bug`**. – Drew Jan 06 '16 at 07:19
  • 4
    n.b. IIRC, the Emacs packages for Debian (maybe other OSs as well) separate out the `.el` files (treated as optional) from the `.elc` files (mandatory), such that you need to install one or more additional packages to get them. If you obtained Emacs from your OS package manager, perhaps this explains it. – phils Jan 06 '16 at 09:59
  • @lawlist whenever I run into this problem, the function I am looking up still works properly (i.e., I can't navigate to the source for `describe-function`, but `M-x describe-function` still works, so I don't think it is the case that the version I am using at the moment doesn't have all the source code installed. However, it still might be related to multiple versions as you suggest, so I will investigate in that direction when I get home. Also, thanks for bringing the `find-*` commands to my attention. If I just want to go right to source, these are great (but still need to try at home)! – elethan Jan 06 '16 at 15:31
  • `.elc` files do contain docstrings, so lacking source code would be consistent with the symptoms you describe. – npostavs Jan 06 '16 at 18:48
  • @npostavs maybe I am misunderstanding something then. If the source code were missing, wouldn't the command defined in that code not work? – elethan Jan 06 '16 at 18:50
  • It could still work and still be described if it's defined in an `.elc` file produced by byte-compiling the original source code. – npostavs Jan 06 '16 at 19:00
  • @lawlist Do you know of a good way to tell if I have multiple versions of Emacs installed? – elethan Jan 07 '16 at 03:18
  • 1
    You could do a grep (or other search utility) for the name of the binaries (with executable permissions) -- **emacs** or **emacsclient** -- and see where they are on your hard drive. I store mine entirely separately in their own dedicated folder. For example, I have the version that shipped with my operating system -- `/usr/bin/emacs` and `/usr/bin/emacsclient`, and I have a version nicely packaged in an OSX application folder ending in .app -- i.e., `/Applications/Emacs.app` (inside that Emacs.app, are the binaries and all the source-code files). – lawlist Jan 07 '16 at 03:28

2 Answers2

7

The reason you sometimes see “interactive compiled Lisp function” (or likewise for variables) with no file name is that the function was loaded from a byte-compiled file and the corresponding Elisp source file is not present. In order to show you the source code, Emacs has to be able to find the source code.

Many distributions ship Lisp source files in a separate package, because not every user wants them and they're bulky. For example, on Debian and derivatives, install emacs24-el. If you build Emacs from source, make install copies the Elisp sources.

If you want to see the source code of primitives (subroutines and special forms), Emacs needs to be able to find the C sources. Those are not normally available unless you installed from source.

Emacs looks for the Lisp sources in the directories in load-path. For a function or variable loaded from foo.elc, the file can be foo.el or foo.el.gz. Emacs looks for C sources under source-directory, and prompts you for a different directory if it doesn't find the source file.

  • Although I could have sworn that I built this version of Emacs from source, when I call `M-x emacs-version` it says "modified by Debian" at the end, which would indicate that I am using a version from my OS's (Ubuntu's) package manager, right? – elethan Jan 07 '16 at 03:19
  • @elethan If it says “modified by Debian” then you installed or at least built the Ubuntu package. You may have built it from source (maybe because you wanted a newer version than the one in your Ubuntu release). Are you running `/usr/bin/emacs` or `/usr/local/bin/emacs`? – Gilles 'SO- stop being evil' Jan 07 '16 at 12:33
3

If you're looking for ways to quickly jump to source code, there are also find-function-at-point and find-variable-at-point which will jump to the definition of the symbol under the cursor - you could bind them to C-h C-f and C-h C-v, for instance.

Or you could try elisp-slime-nav, which uses M-. to jump to a symbol's definition, and M-, to return - it navigates to variables, functions, libraries, and faces - https://github.com/purcell/elisp-slime-nav/

Brian Burns
  • 1,577
  • 14
  • 15