(Re)generate: (find-strange-functions-intro) Source code: (find-efunction 'find-strange-functions-intro) More intros: (find-eev-quick-intro) (find-eev-intro) (find-eepitch-intro) This buffer is _temporary_ and _editable_. It is meant as both a tutorial and a sandbox. Prerequisites: (find-elisp-intro) TODO: update this: http://anggtwu.net/2024-find-lgreps.html Note: this is a work in progress! Both this intro and the HTML page above are unfinished!1. Introduction: videos
We saw in (find-eev-quick-intro "9.1. `code-c-d'") (find-eev-quick-intro "9.1. `code-c-d'" "find-code-c-d") that each call to `code-c-d' defines several functions, and we can use a `find-code-c-d' to display the code that the corresponding `code-c-d' would run. I will refer to the functions defined by a call to `code-c-d' as "functions defined in strange ways", or, to abbreviate, as "strange functions". Here is an another example. This a sexp whose "head" is a strange function, and that plays a certain video: (find-2024gitvideo "00:34") It was defined by a call to `code-1stclassvideo'. Try the `find-code-1stclassvideo' below: ;; (find-code-1stclassvideo "2024git") (code-1stclassvideo "2024git") It defines three associated functions - `find-2024gitvideo', that plays the video, and `find-2024githsubs' and `find-2024gitlsubs', that display the subtitles of the video in different formats. Sometimes we want a quick way to start by one of the sexps below and produce one of the other two, (find-2024gitvideo "00:34") (find-2024githsubs "00:34") (find-2024gitlsubs "00:34") and sometimes we want a way to jump to the place in which these `find-2024git*' functions were defined... note that the three `find-efunctionpp's below do work, (find-efunctionpp 'find-2024gitvideo) (find-efunctionpp 'find-2024githsubs) (find-efunctionpp 'find-2024gitlsubs) (find-efunction 'find-2024gitvideo) (find-efunction 'find-2024githsubs) (find-efunction 'find-2024gitlsubs) but the `find-efunction's don't - they open the file in which the `find-2024git*'s were defined, but they can't find the exact point in which the `code-1stclassvideo' was run.2. Here
This is a sexp that starts with a strange function - or, to abbreviate, a "strange sexp": (find-2024gitvideo "00:34") If you type `M-h M-s' on the line above the `M-h M-s' will display a lot of information about the "strange sexp here". It will run this, (find-sf-links '(find-2024gitvideo "00:34")) and that will display a temporary buffer with the variants of that sexp, some information about the video "2024git", the definitions of the (strange) functions `find-2024gitvideo', `find-2024gitlsubs', and `find-2024githsubs', and a few other things. At this moment only a few kinds of strange sexps are supported. Try: (find-sf-links '(find-2024gitvideo "00:34")) (find-sf-links '(find-eev "eev-strange-functions.el")) and: (code-pdf-page "livesofanimals" "~/Coetzee99.pdf") (code-pdf-text "livesofanimals" "~/Coetzee99.pdf" -110) (find-sf-links '(find-livesofanimalspage (+ -110 113) "LECTURE I.")) (find-sf-links '(find-livesofanimalstext (+ -110 113) "LECTURE I.")) and try using `M-h M-s' on the two sexps below: (find-eev "eev-strange-functions.el") (find-livesofanimalspage (+ -110 113) "LECTURE I.")3. Debugging
Remember that both `M-h M-h' and f8 treat a prefix argument as a request to enter a kind of debugging mode: (find-here-links-intro "8. Debugging") (find-eev "eepitch.el" "debug") `M-h M-s' follows the same convention. Try `M-1 M-h M-s' on the sexp below: (find-2024gitvideo "00:34") You will get the same temporary buffer that you get with: (find-sf-debug-links '(find-2024gitvideo "00:34")) It shows the values of several variables and has several links to the source code. For example, this one, (find-evariable 'ee-hprog-for-sf) that shows the "hprogram" that that `M-h M-s' uses to detect which kind of strange sexp we have "here".4. The load-history
Try `M-h M-s' on these sexps again: (find-2024gitvideo "00:34") (find-eev "eev-strange-functions.el") You will see that the temporary buffers have blocks like these ones: ;; Source and location in the load-history: ;; (find-efunctionlgrep 'find-2024gitvideo "2024git") ;; (find-eloadhistory-for 'find-2024gitvideo) ;; (find-eloadhistory-for 'find-2024gitvideo 2 " find-2024gitvideo)") ;; Source and location in the load-history: ;; (find-efunctionlgrep 'find-eevfile 'eev) ;; (find-eloadhistory-for 'find-eevfile) ;; (find-eloadhistory-for 'find-eevfile 2 " ee-eevfile)") Each of the hyperlinks with `find-eloadhistory-for' displays one entry in the load-history in a pretty-printed format, and a header with help at the top. For example, (find-eloadhistory-for 'find-eevfile 2 " ee-eevfile)") shows the entry in the load-history for the file in which `find-eevfile' was defined, and it jumps to the first defun in this block: ee-eevfile (defun . ee-eevfile) (defun . find-eevfile) (defun . find-eevsh) (defun . find-eevsh0) (defun . find-eevsh00) (defun . find-eevgrep) (defun . find-eev) These are exactly the functions that were defined by this call to `code-c-d', ;; (find-code-c-d "eev" ee-eev-source-directory :anchor) (code-c-d "eev" ee-eev-source-directory :anchor) that appears here: (find-eev "eev-code.el" "code-c-d-s" "\"eev\"") We can use that to see which functions and variables were defined just before and just after the function that we are looking for. [TODO: explain this:] (find-efunctionlgrep 'cl-struct-p--cmacro 'cl-struct-p)4.1. `find-efunctionlgrep'
This hyperlink (find-efunctionlgrep 'find-eevfile 'eev) tries to find the exact point in which the function `find-eevfile' was defined using another method: it first converts the stem in the second argument, "eev", into a regexp that means: search for either "eev" between double quotes, or for "eev" surrounded by certain other characters, like whitespace, a single quote, or parentheses and then it searches for that regexp, using lgrep, in the file in which the function `find-eevfile' was defined. Try it again: (find-efunctionlgrep 'find-eevfile 'eev) it returns four lines that can be the place in which `find-eevfile' was defined - and three of them are false positives. The best way to understand the technical details of `find-efunctionlgrep' is to try the tests in the source code: (find-eev "eev-plinks.el" "find-efunctionlgrep")5. Defuns, recreated
[Explain why we can't always trust the defuns block] [An example with code-c-d:] (find-eev "eev-code.el" "code-c-d-s") (find-eev "eev-code.el" "code-c-d-s" "eli") [compare:] (find-2a ' (find-code-c-d "eli" ee-emacs-lisp-directory "eintr" :gz) ' (find-sf-links '(find-elinode "Top")) )6. Macros
[TODO: explain that in recent versions of Emacs `find-efunction' can find most functions defined by cl macros, but not all...] Emacs comes with lots of strange functions; most (or all?) of them are created by macros. Here is an example: `cl-struct-p' is a function defined in a normal way, but `cl-struct-p--cmacro' is a function defined in a strange way: ok: (find-efunction 'cl-struct-p) fails: (find-efunction 'cl-struct-p--cmacro) bytecomp: (find-efunctionpp 'cl-struct-p) bytecomp: (find-efunctionpp 'cl-struct-p--cmacro) The `find-efunctionpp's are not very helpful because these two functions are byte-compiled, and the (find-efunction 'cl-struct-p--cmacro) fails. But if we try this, (find-efunction-links 'cl-struct-p--cmacro) (eek "M-h M-f cl-struct-p--cmacro") one of the blocks that appears in the temporary buffer is this one: # (find-efunctionlgrep 'cl-struct-p--cmacro) # (find-efunctionlgrep 'cl-struct-p--cmacro 'cl-struct-p--cmacro) # (find-eloadhistory-for 'cl-struct-p--cmacro) # (find-eloadhistory-for 'cl-struct-p--cmacro 2 " cl-struct-p--cmacro)") The second argument to `find-efunctionlgrep' is a stem. In this case the `find-efunction-links' has guessed the stem incorrectly - it guessed the stem as being the name of the original function, for simplicity -, but if we duplicate that line and experiment a bit we can find a stem that works: # (find-efunctionlgrep 'cl-struct-p--cmacro 'cl-struct-p--cmacro) # (find-efunctionlgrep 'cl-struct-p--cmacro 'cl-struct-p) The second `find-efunctionlgrep' above shows three good guesses for places that can be the sexps that define `cl-struct-p--cmacro', but I find the code very hard to understand... the first guess points to a sexp that is several lines long, the second guess points to this sexp, that is just one line: (cl-assert (cl-struct-p (cl--find-class 'cl-structure-class))) We can try to run macroexpand and macroexpand-all on that sexp and pretty-print the results, with `find-eppm' and `find-eppma', (find-eppm ' (cl-assert (cl-struct-p (cl--find-class 'cl-structure-class))) ) (find-eppma ' (cl-assert (cl-struct-p (cl--find-class 'cl-structure-class))) ) and do the same with the other guesses. I tried this with the three sexps - the three "guesses" - and examined the two expansions for each one, and I couldn't find any mentions to `cl-struct-p--cmacro'... so in this case this `find-efunctionlgrep' (find-efunctionlgrep 'cl-struct-p--cmacro 'cl-struct-p) didn't help me to understand where, and how, `cl-struct-p--cmacro', was defined... bleh =(. [TODO: explain this:] (find-egrep "grep --color=auto -nH --null -e --cmacro *.el */*.el") (find-efunction 'cl-define-compiler-macro) (find-efunction 'cl-define-compiler-macro "\"--cmacro\"") [TODO: delete most of the old stuff below, reuse a few parts...] The easiest, and most high-level, way to inspect strange functions uses a kind of "here". If you type `M-h M-s' with the point on the line below, (find-2024githsubs "00:34") then `M-x sf' will first move the point to the end of the line and then it will do some interesting things with the "sexp before point", just like `M-e'. The "here" in that case will be that sexp, whose "head" is a strange function. So the `sf' in `M-x sf' is an abbreviation for: do things with the strange function here, or rather, with the "sexp here", that starts with a strange function, where the "sexp here" is the sexp before the end of line, and a "strange function" is a "function defined in a strange way". And "do things" means: display in a temporary buffer variants of that sexp and lots of other information.4. The load-history
The function `find-eev2021video' is known - try: (find-eev2021video "00:40") (find-efunctionpp 'find-eev2021video) but `find-efunction' can't find its definition... try: (find-efunction 'find-eev2021video) it finds the file in which that function was defined, but it can't find its "defun". That's because `find-eev2021video' is a "function defined in a strange way", or, to abbreviate, a "strange function". _Most_ strange functions defined by eev are defined by calls to `code-c-d' and friends - see: (find-eev-quick-intro "9.1. `code-c-d'") (find-eev-quick-intro "9.1. `code-c-d'" "find-code-c-d") `find-eev2021' was defined by a call to `code-1stclassvideo', like this one, ;; (find-code-1stclassvideo "eev2021") (code-1stclassvideo "eev2021") that defines `find-eev2021video', that plays a video, and two "variants" of `find-eev2021video', that access the subtitles of that video. Try: (find-eev2021video "00:40") (find-eev2021hsubs "00:40") (find-eev2021lsubs "00:40") Sometimes we want to start with a sexp like the ones above, and generate its variants; sometimes we want to start with one of the sexps above and display a lot of information about the "strange function" at the car of its sexp; and sometimes we want to start with one of the sexps above and display a lot of information about the video that it points to. We can do all that with `M-x sf', that: does lots of things with the <S>trange <F>unction in the current line. More precisely, it acts at the sexp at the end of the line, like `M-e', but if that sexp starts with a strange function it does lots of things with that sexp. Try it on the sexps above! [Only a few families of strange functions are supported at this moment] [Describe M-x sf - how to load it, how to test it]1. Introduction
Sometimes `find-efunction' can't find the place in which a function was defined. Try the sexps below: (find-efunction 'cl-struct-p) (find-efunction 'cl-struct-p--cmacro) (find-efunctionpp 'cl-struct-p) (find-efunctionpp 'cl-struct-p--cmacro) (find-function-noselect 'cl-struct-p) ;; --> (#<buffer cl-preloaded.el> . 14565) (find-function-noselect 'cl-struct-p--cmacro) ;; --> (#<buffer cl-preloaded.el>) In `cl-struct-p' everything works, but in `cl-struct-p--cmacro' `find-efuction' only does half of its expected job: it finds the file in which `cl-struct-p--cmacro' was defined, but not its "point of definition" - and it fails with an obscure error. Take a look at the docstrings and the source of `find-efunction' and `find-function-noselect': (find-efunctiondescr 'find-efunction) (find-efunction 'find-efunction) (find-efunctiondescr 'find-function-noselect) (find-efunction 'find-function-noselect) The docstring of `find-function-noselect' explains that it: Return(s) a pair (BUFFER . POINT) pointing to the definition of FUNCTION. Finds the source file containing the definition of FUNCTION in a buffer and the point of the definition. The buffer is not selected. If the function definition can't be found in the buffer, returns (BUFFER). The hard work is done by `find-function-search-for-symbol': (find-efunction 'find-function-search-for-symbol) One of the comments in its source is this one: ;; `regexp' matches definitions using known forms like ;; `defun', or `defvar'. But some functions/variables ;; are defined using special macros (or functions), so ;; if `regexp' can't find the definition, we look for ;; something of the form "(SOMETHING <symbol> ...)". ;; This fails to distinguish function definitions from ;; variable declarations (or even uses thereof), but is ;; a good pragmatic fallback. Sometimes these fallbacks in `find-function-search-for-symbol' are not enough - they don't work for some macros, like `cl-struct-p--cmacro', and they don't work for functions defined by `code-c-d' and its friends. Here's one example: (find-efunction 'find-eetcfile) (find-efunctionpp 'find-eetcfile) But these sexp hyperlinks work, (find-efunctionlgrep 'cl-struct-p--cmacro 'cl-struct-p) (find-efunctionlgrep 'find-eetcfile 'eetc) because they first go to the files in which `cl-struct-p--cmacro' and `find-eetcfile', and then they search for their stems - cl-struct-p--cmacro \---------/\------/ stem suffix find-eetcfile \---/\--/\--/ prefix stem suffix surrounded by certain delimiter characters.