(Re)generate: (find-eejump-intro) Source code: (find-eev "eev-intro.el" "find-eejump-intro") More intros: (find-eev-quick-intro) (find-eval-intro) (find-eepitch-intro) This buffer is _temporary_ and _editable_. It is meant as both a tutorial and a sandbox. Note: this intro needs to be rewritten! Ideally it should _complement_ the material in: (find-eev-quick-intro "7.1. `eejump'") See the comments in: (find-eev "eejump.el")
1. The problemSuppose that we have several files that we are working on, and we want a quick way to jump to (i.e., to visit) any of them with very few keystrokes; moreover, 1) we want our list of files to be preserved between one Emacs session and another, 2) we know that each "visit a file" command will correspond to an elisp hyperlink. One quick solution would be to put the list of elisp hyperlinks in a file, and make the key `M-j' open that file. But then jumping to a file in that list becomes a two-step process: type `M-j', move the point to the right line, type `M-e'. This would be similar to what happens when we use one of the `find-e*' commands, for example `find-efunction': (find-efunction 'find-efunction) (eek "M-h M-f find-efunction") Those intermediate steps - seeing the list, locating visually the right line, moving to it - are distracting, so we want to add new items to our wishlist: 3) it should be possible to jump straight to any of the files in the list, and with very few keystrokes, 4) the list should be stored in a format that lets us see quickly which are the keystrokes for accessing each item - so that we won't need to memorize anything, 5) the list should be easy to modify, 6) it should be possible to assign shorter key sequences to files we visit more often, 7) the source code must be very simple.
2. A miniatureMy original solution was this: I used only one keybinding, `M-j', that acted differently when invoked with different numeric prefixes; when invoked as `M-1 M-j' it opened a certain file, when invoked with `M-2 M-j' it opened another, and so on, and when it was invoked with an unrecognized prefix or with no prefix it jumped to its definition in my ~/.emacs. Its code was like this (**NOTE: do not execute these defuns**): ;; eejump-simplified (`M-j'): ;; M-1 M-j opens a certain file, ;; M-2 M-j opens another file, ;; when the argument is 11, 22, 33 or 44 do something special, ;; like changing the font; ;; with no argument or with an unrecognized argument jump to the ;; definition of eejump in ~/.emacs; then we can see which numbers ;; correspond to which actions (the source is the documentation!), and ;; we can change the definition if needed - just run `M-e' at the ;; right place to make the changes apply. ;; (global-set-key (kbd "M-j") 'eejump-simplified) (defun eejump-simplified (arg) (interactive "P") (cond ((eq arg 1) (find-file "~/NOTES")) ((eq arg 2) (find-file "~/otherfile.txt")) ;; ((eq arg 11) (set-frame-font "fixed")) ((eq arg 22) (set-frame-font "terminus-16")) ((eq arg 33) (set-frame-font "terminus-bold-16")) ((eq arg 44) (set-frame-font "10x20")) (t (find-function 'eejump-simplified)))) except that my definition became huge with time as I added to it more entries for files (and other actions!) that I used often, and also entries that were used not so often... All the "options" - i.e., all the `(eq arg nnn)' lines - had to be together in a single very big defun, and there was no way to add new options temporarily...
3. FamiliesLet's use a shorthand for key sequences: for example, `M-123j' instead of `M-1 M-2 M-3 M-j'. I tend to assign related numbers to related files. For example, I use the prefix "5" for things that are Emacs-related: `M-5j' visits my .emacs, `M-555j' visits the directory with all of eev's elisp files, and `M-51j', `M-52j', etc, visit specific eev source files that I happen to be working on. Also, I use the prefix "7" for things related to LaTeX. So, the "5*" family is composed of Emacs-related files, and the "7*" family of LaTex-related files. The definition of `eejump-simplified' given above does not satisfy these two (new!) wishlist items: 8) it should be possible to jump to the definition of the "5*" family by typing something like `M-5678j', where "5678" is a non-assigned number that starts with the "5*" prefix, 9) it should be possible to convert a number/hyperlink pair very easily into to the code that assigns that elisp hyperlink as the desired behavior for that number - and it should be possible to do that both permanently (think in changing the definition of `eejump-simplified' in your .emacs) and temporarily (i.e., for the current Emacs session only).
4. `eejump'The definition of `eejump' that comes with eev is a bit more complex than the one given above, and it will not be shown here (it involves a tricky recursive function) but it satisfies the 9 wishlist items above. It works in this way: if you type, say, `M-123j', then: a) if `eejump-123' is defined, then execute it; b) otherwise, if `eejump-12*' is defined, execute it; c) otherwise, if `eejump-1*' is defined, execute it; d) otherwise, if `eejump-*' is defined, execute it, and if `eejump-*' also is not defined, you get an error. Here is a block of "defun"s that defines (trivial) meanings for "91", "92", "991", and "992", plus targets for the "9*" family and for the "99*" family; it also has two tests in comments that will be very important for an explanation below. Let's refer as that, in this section and the next ones, as "the block of six defuns (plus four tests)". (defun eejump-9* () (find-efunction 'eejump-9*)) (defun eejump-91 () (message "M-91j")) (defun eejump-92 () (message "M-92j")) (defun eejump-99* () (find-efunction 'eejump-99*)) (defun eejump-991 () (message "M-991j")) (defun eejump-992 () (message "M-992j")) ;; (find-function-noselect 'eejump-9*) ;; (find-function-noselect 'eejump-99*) ;; (find-efunction 'eejump-9*) ;; (find-efunction 'eejump-99*) Try to evaluate each of the sexps above with `M-e', then try to run things like `M-92j' and `M-992j' - they should work - and then something like `M-99876j'; that will not work, you'll get an error like "Don't know where `eejump-99*' is defined"...
5. eejump blocksLet's a call a sequence of defuns for eejumps with the same prefix, like this, starting with a `(defun eejump-<prefix>* ...)', (defun eejump-99* () (find-efunction 'eejump-99*)) (defun eejump-991 () (message "M-991j")) (defun eejump-992 () (message "M-992j")) an "eejump block". There are two sample eejump blocks in eejump.el, for the prefixes "" and "5", starting at: (find-eev "eejump.el" "eejump-*") (find-eev "eejump.el" "eejump-5*") You should probably copy them to your .emacs, and then start modifying them.
6. Making an `eejump-nn*' workIf you execute a line like (defun eejump-9* () (find-efunction 'eejump-9*)) then Emacs will only record that `eejump-9*' has been defined in this buffer - and thus will be able to jump to its definition when you type something like `M-987j' - if two conditions are met: a) the defun is executed with `M-x eval-region', `M-x eval-buffer', or some variant of `load' or `require' (`M-e' will not do!), b) the buffer with the definition is associated to a file; see these two pages of the Emacs manuals (find-enode "Buffers" "visiting") (find-elnode "Buffer File Name") if that concept is not totally familiar to you. So, as an experiment, copy the block with six defuns and four tests above to some buffer associated to a file, mark it, and execute it with `M-x eval-region'. Now the tests should work - and key sequences like `M-987j' should also work, and should jump to the right places. See also: (find-elnode "Where Defined")
7. Producing `eejump-nnn's and `eejump-nnn*'sLook again to the block of six "defun"s above. Now type `M-J' on each of the six lines below: 9 91 (message "M-91j") 92 (message "M-92j") 99 991 (message "M-991j") 992 (message "M-992j") you will notice that you've just generated a block of defuns like the one in the previous section! `M-J' works like this: it tries to split the current line into "words" separated by whitespace, but producing a maximum of two "words" (the 2nd, 3rd, etc "words" as treated as a single "word"); if the second word is empty, then `M-J' produces a definition for an `eejump-nnn*'; if it is not empty, then `M-J' produces a definition for an `eejump-nnn', treating the second "word" as a sexp. Note that `M-J' is quite dumb - it doesn't check if the first "word" is a number, nor if the second is a sexp. Use it with care! Try using `M-J' on the "a b ..." lines below - you will get useless definitons. a b c d a b c a b a
8. Permanent and temporaryIf you create a block like the block of six defuns above in your .emacs file then you'll be attributing a "permanent" meaning to `M-91j', ..., `M-992j', and if you create it in a file that is not evaluated in every Emacs session (and execute it, of course), then you'll be attributing just a "temporary" meaning to `M-91j', ..., `M-992j'.