(Re)generate: (find-here-links-intro) Source code: (find-efunction 'find-here-links-intro) More intros: (find-eev-quick-intro) (find-eev-intro) (find-refining-intro) This buffer is _temporary_ and _editable_. It is meant as both a tutorial and a sandbox. This intro will be merged with (find-refining-intro) at some point... Eev's central idea is that you can keep "executable logs" of what you do, in a format that is reasonably readable and that is easy to "play back" later, step by step and in any order. We call these executable logs, or executable notes, "e-scripts". [Video links:] (find-eev2019hsubs "05:24" "e-scripts") (find-eev2019video "05:24" "e-scripts") (find-eev2019hsubs "12:54" "A demo") (find-eev2019video "12:54" "A demo")1. Alternating between "task" and "notes"
In the old days log books were always made of paper, and there was nothing automatic in taking notes with them. We would have to decide what to write and how to write it, and we would have to alternate between the "task" and "taking notes". After many years of practice _some_ people would learn how to take notes without distracting themselves much from the task at hand, and they would learn how to make their notes at the same time concise and readable enough. Nowadays, with computers, there are _some_ ways to write logs automatically - for example, most shells record the commands given to them - but the output is of low quality. Eev takes an intermediate stance between "notes by hand" and "automatic notes". It is possible to do "task"+"notes" with just a few more keystrokes than for doing just "task", but that requires learning some tricks, and having some practice.1.1. Reading and writing
Learning eev is like learning to read and write. We first learn _how to read_, and we learn _how to write_ in a second stage, when we have read a lot and we are able to read what we write. Learning eev is also like learning to use paper notebooks. It is much easier to understand the notes and ideas what we wrote ourselves in our notebooks than to understand what other people wrote in their notebooks... when we go back to what _we_ wrote we are able to reconnect with what we were thinking, even when our notes are quite terse because we did not write down all details - and we can't do that with other people's notes. So: we have to first learn how to _read_ executable notes in order to be able to _write_ our own executable notes, but after learning the basics we will usually find it much easier to read our own executable notes than to read other people's notes... This is very similar to what happens in programming. Programmers usually takes years, and a lot of effort, to learn to write code and comments that other people find readable, and what they do after that is not that they write super-readable code all the time - instead they _adjust_ the level of readability of their code depending on the situation: they write the code that will be used and read by other people in a cleaner, more readable style with lots of comments, and they write "throwaway code" that they will only run once in a very terse, and often messy, style. Most of my executable notes are written - or rather, "appear" - when I am learning something and I am switching rather mindlessly between "task" and "notes" as I explained in the previous section. What I write looks like throwaway code, only worse - because I usually leave lots of unfinished parts intermixed with the parts that run, without marking clearly which are which... but when I go through my notes about a task again I usually clean my notes a bit. For me going through my executable notes about a task again always involves a bit of _rewriting_ - which is something that programmers often do with their own code, but that we don't do much with paper notebooks. Anyway: be prepared to create executable notes that are almost unreadable, even by you when you go back to them a few hours later - that's normal, that's how things are, and you can, and WILL, rewrite the most useful parts... Note that this "intro" is about writing elisp hyperlinks. The tricks for writing eepitch blocks and index-anchor pairs are discussed elsewhere.2. "Here"
In this tutorial we will learn the basic technique for creating an elisp hyperlink to "here" and copying it to our notes. "Here" means the current Emacs buffer; we saw in the main tutorial that elisp hyperlinks like (find-eev-quick-intro "4. Creating Elisp Hyperlinks") (find-emacs-keys-intro "3. Cutting & pasting") (find-fline "~/") (find-eevfile "") (find-eevfile "eev-blinks.el") (find-efunctiondescr 'find-file) (find-enode "Modes") (find-elnode "Defining Functions" "(defun foo () 5)") (find-man "date") open eev tutorials (`find-xxx-intro's), directories, files, descriptions of emacs functions, sections of manuals in "info" format, and manpages. All the elisp hyperlinks above are of the kind described in the first paragraphs of this section of the main tutorial: (find-eev-quick-intro "3. Elisp hyperlinks") They (usually) create a new buffer, and it is possible to "go back" from that buffer with `M-k' of `M-K': (find-eval-intro "5. Going back") [Video links:] (find-eev2020video "2:25" "variants that were better behaved") (find-eev2020video "2:36" "in the same window as before")3. `find-here-links'
Eev has a function, called `find-here-links' and bound to `M-h M-h', that is able to distinguish several kinds of "here"s. When we run it it creates a temporary buffer with lots of elisp hyperlinks, and when we have enough practice we can spot in a second which of its hyperlinks is the "hyperlink to here" that we want to copy to our notes. This tutorial is about a _variant_ of `find-here-links' that is more suitable for beginners.4. `find-here-links-3'
Suppose that you are in a buffer with something interesting - "here" -, and you want to generate a hyperlink to it and copy that hyperlink to your notes. Some terminology: 1. The target of that hyperlink will be the "here" buffer, so let's call the "here" buffer the "target buffer" from now on. 2. `find-here-links' creates a temporary buffer with several elisp hyperlinks - let's call that buffer the "elinks buffer". 3. Beginners start by putting all their (executable) notes in a single file, "~/TODO"; remember that `M-1 M-j' jumps to that file. The "notes buffer" is a buffer visiting the file "~/TODO". The key sequence `M-h M-3' saves the current window configuration in a variable called `ee-window-configuration-before-M-h-M-3', creates a 3-window setting like this, _____________________ | | | | | elinks | | | buffer | | target |__________| | buffer | | | | notes | | | buffer | |__________|__________| and puts the cursor at the elinks buffer.5. `find-here-links-1'
After creating the three windows described above we will usually want to select a line from the elinks buffer - the right one, i.e., the one with a hyperlink to the target buffer - and copy it to the notes buffer; the next section explains how to do this. After copying the hyperlink - or after deciding that we don't want to copy it - we want to restore the original window configuration that we had before typing `M-h M-3'. We can do that by typing `M-h M-1' (`find-here-links-1'); I chose to use the suffix "1" because in most cases the original window configuration has a single window with the target buffer in it, and the "1" is a reference to this: (find-emacs-keys-intro "6. Windows" "C-x 1") Note that `M-h M-1' undoes what `M-h M-3' did. In a figure: _______________ _____________________ ________________ | | | | | | | | | | | elinks | | | | | | | buffer | | | | target | M-h M-3 | target |__________| M-h M-1 | target | | buffer | ------> | buffer | | ------> | buffer | | | | | notes | | | | | | | buffer | | | |_______________| |__________|__________| |________________| [Video links:] (find-eevfherelhsubs "04:40" "2. The beginner's way") (find-eevfherelvideo "04:40" "2. The beginner's way") (find-eevfherelhsubs "04:40" "2.1. The 3-window setting - and going back from it") (find-eevfherelvideo "04:40" "2.1. The 3-window setting - and going back from it") (find-eevfherelhsubs "06:47" "`M-h M-3': three windows; `M-h M-1' goes back") (find-eevfherelvideo "06:47" "`M-h M-3': three windows; `M-h M-1' goes back") (find-eevfherelhsubs "07:26" "the original configuration can be anything") (find-eevfherelvideo "07:26" "the original configuration can be anything")6. Copying the hyperlink
When you are a beginner, the easiest way to copy an elisp hyperlink from the elinks buffer to the notes buffer is to put the cursor on the line with the hyperlink, then type `M-h M-w' (`ee-copy-this-line-to-kill-ring'), and then go to the notes buffer and copy it to there with `C-y' or with the entry "Edit -> Paste" in the menu bar. Note that in the three-window setting copying a hyperlink from the elinks buffer to the notes buffer means copying it from the upper right window to the lower right window: _____________________ | | | | | elinks | | | buffer | | target |____||____| | buffer | \/ | | | notes | | | buffer | |__________|__________| When you become a slightly more advanced user the easiest way is the one with the key sequences described here: (find-eev-quick-intro "5.2. Cutting and pasting") [Video links:] (find-eevfherelvideo "08:56" "2.2. Copying one link") (find-eevfherelvideo "08:56" "2.2. Copying one link")7. Refining your hyperlinks
After learning the technique above, that was based on the keys: M-h M-3 -- find-here-links-3 M-h M-w -- ee-copy-this-line-to-kill-ring C-y -- yank, i.e., paste; see: (find-enode "Kill Ring") M-h M-1 -- find-here-links-1 The next steps are to learn how: a) Refine hyperlinks. See: (find-refining-intro "1. Pos-spec-lists") (find-refining-intro "2. Refining hyperlinks") b) Work with a single window. See: (find-refining-intro "3. Three buffers") c) Use other keys that create buffers with hyperlinks. See: (find-emacs-keys-intro "Some other keys that create")8. Debugging
The best way to understand the innards of `find-here-links' is to call it in "debug mode" - or, more precisely, to call it with a prefix argument. When we run `find-here-links' _without_ a prefix argument it displays a header and then the links to "here"; _with_ a prefix argument it displays the header and then a lot of internal information about "here". For example, if you run (eek "M-h M-h ;; find-here-links") then "here" is this intro, and `find-here-links' displays a header and then a "body" that is the result of running (ee-find-intro-links). You can inspect the header and the body separately with: (find-elinks (ee-find-here-links-header)) (find-elinks (ee-find-here-links)) (find-elinks (ee-find-intro-links)) If you run `find-here-links' with a prefix argument, as in this `eek' sexp, (eek "M-0 M-h M-h ;; M-0 find-here-links") then `find-here-links' will display the same header as before and then a lot of information on how `(ee-find-here-links)' decided that "here" was an intro - this one - and then selected `(ee-find-intro-links)' as the right lower-level function to use to generate the body. You can inspect the header and the body of that buffer separately with: (find-elinks (ee-find-here-links-header)) (ee-detect-here) (find-elinks (ee-find-here-debug-links)) You can also try these tests: (find-eev "eev-htests.el" "tests") Each test tests a kind of "here", and generates a 3-window setting of one of these two forms: ______________________ ______________________ | | | | | | | | One kind | | | One kind | | | of here | | | of here | | Tests |____________| | Tests |____________| | | | | | | | | links to | | | one link | | | here | | | to here | |_________|____________| |_________|____________| They are explained in: (find-eev "eev-htests.el" "find-tlh")9. The hlang
The original implementation of `find-here-links' was simple but was hard to debug - its core used a big `cond' and it didn't keep a lot of information on how it detected the kind of "here". See: (find-eev "eev-hlinks.el" "ee-find-here-links-old") Then in 2021-2023 I rewrote it several times, and now `ee-detect-here' runs a program that looks like this: (find-eev "eev-hlinks.el" "hprog") (find-eev "eev-hlinks.el" "ee-hprog-find-here-links") The variable `ee-hprog-find-here-links' contains an "hprogram", that is a program written in the "hlang", that is a little language that is used mostly for deciding what is "here" and keeping track of some information on how that decision was made. The hlang is defined in the link below. To understand how it works read its docstrings, (find-eev "eev-hlinks.el" "hlang") and try these examples: (ee-hlang-:lisp '(+ 20 3) '(+ 40 5)) (ee-hlang-:or '(:lisp nil) '(:lisp nil) '(:lisp 42) '(:lisp 99)) (ee-hlang-:if '(< 1 2) '(list 'lt)) (ee-hlang-:if '(> 1 2) '(list 'gt)) (ee-hlang-eval '(:lisp (+ 20 3) (+ 40 5))) (ee-hlang-eval '(:or (:lisp nil) (:lisp nil) (:lisp 42) (:lisp 99))) (ee-hlang-eval '(:if (< 1 2) (list 'lt))) (ee-hlang-eval '(:if (> 1 2) (list 'gt))) (ee-hlang-eval '(:or (:if (< 1 2) (list 'lt)) (:if (> 1 2) (list 'gt)))) (ee-hlang-eval '(:or (:if (> 1 2) (list 'gt)) (:if (< 1 2) (list 'lt)))) Note this: (find-efunction 'ee-hlang-:if) (find-efunction 'ee-hlang-:if "d) we DO NOT evaluate SEXP2") (find-efunction 'ee-find-here-links) (find-efunction 'ee-find-here-links "(eval ee-hlang-sexp2)") When we are in debug mode we don't eval the "then" part of an (:if ...)! Check this low-level example to understand the details: (ee-hlang-eval '(:or (:if nil (error 1)) (:if t (error 2)) (:if t (error 3)) (:if nil (error 4)))) (eval ee-hlang-sexp2)9.1. A historical note
My main motivation for the hlang was my frustration with Org and Hyperbole. They are infinitely more popular then eev, probably because they look very user-friendly, but when I tried to learn them I stumbled on their hacker-unfriendliness... Both Org and Hyperbole have cases in which they have to inspect what we have "here", "around point", or "in a link", and then they have to classify what they found into several different cases, and act in a different way for each different case. Let me call the function that classifies and acts accordingly a "dispatcher". I tried to add new hyperlink types to Org ages ago, when the way to do that was not as well-documented as it is now. The current way is explained here: (find-orgnode "External Links") (find-orgnode "Adding Hyperlink Types") and when I tried to understand how Org's code blocks "really work" my experience was so painful that I made a video about it: Page: http://anggtwu.net/2021-org-for-non-users.html Info: (find-1stclassvideo-links "2021orgfornonusers") Play: (find-2021orgfornonusersvideo "00:00") Subs: (find-2021orgfornonuserslsubs "00:00") ...but that was nothing in comparison with Hyperbole! I spent a lot of time trying to build a bridge between eev and Hyperbole that would make them easy to use together, but each one of my questions about the innards of Hyperbole - for example, my questions about the dispatchers for button types - was treated as The Wrong Question... and in the end Hyperbole got my Eternal Hate. See: (find-es "hyperbole") Then I decided that ok, I will never be able to make eev look as user-friendly as Org or as Hyperbole, but at least I can make eev more hacker-friendly than them... and if tinkering with the innards of Org and Hyperbole is so unfun then I can make the innards of eev more fun to play with - and then I rewrote `find-here-links', that at that point was the part of eev whose code was worst.