(Re)generate: (find-rstdoc-intro)
Source code:  (find-efunction 'find-rstdoc-intro)
More intros:  (find-eev-quick-intro)
This buffer is _temporary_ and _editable_.
It is meant as both a tutorial and a sandbox.

This intro corresponds to one of my presentations at
the EmacsConf2022. It page and its video are here:
   Page:  http://anggtwu.net/emacsconf2022-py.html
   Info:  (find-1stclassvideo-links "eev2022py")
   Play:  (find-eev2022pyvideo "00:00")
   HSubs: (find-eev2022pyhsubs "00:00")

0. Preparation

Many examples in this intro will suppose that you have run this, (ee-rstdoc-default-defuns) that can't be run by default because it defines three functions with atypical names: `pdk', `sdk', and `mdk', that will be explained in the section 5. So run the sexp above now!

1. Introduction

The eepitch block below contains a small Python program and five links that point to Python docs: * (eepitch-python) * (eepitch-kill) * (eepitch-python) # (find-pydoc "reference/datamodel#object.__init__") # (find-pydoc "reference/datamodel#object.__str__") # (find-pydoc "reference/datamodel#emulating-numeric-types") # (find-pydocw "reference/datamodel#emulating-numeric-types") # (find-pydocr "reference/datamodel" "_numeric-types:") class MyVector: def __init__(v, x, y): v.x = x v.y = y def __str__(v): return '(%d,%d)' % (v.x, v.y) def __add__(v, w): return MyVector(v.x+w.x, v.y+w.y) print(MyVector(20,30)) print(MyVector(20,30)+MyVector(4,5)) If you are on Debian Stable then all the `find-pydoc*'s above should work out of the box. The first three `find-pydoc's will open these local URLs using a browser, file:///usr/share/doc/python3.9-doc/html/reference/datamodel.html#object.__init__ file:///usr/share/doc/python3.9-doc/html/reference/datamodel.html#object.__str__ file:///usr/share/doc/python3.9-doc/html/reference/datamodel.html#emulating-numeric-types the `find-pydocw' will open this URL - the suffix `w' means "use the web instead of the local copies", https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types and in the last link, (find-pydocr "reference/datamodel" "_numeric-types:") the suffix `r' means "open the source in .rst instead of the HTML version"; it opens this file /usr/share/doc/python3.9/html/_sources/reference/datamodel.rst.txt and searches for the first occurrence of the string "_numeric-types:" in it.

2. Expansion

The functions `find-pydoc', `find-pydocw', and `find-pydocr' expand their arguments in different ways. You can see that by trying: (find-pydoc "tutorial/modules#the-module-search-path") (find-pydocw "tutorial/modules#the-module-search-path") (find-pydocr "tutorial/modules#the-module-search-path") (find-pydoc-expand "tutorial/modules#the-module-search-path") (find-pydocw-expand "tutorial/modules#the-module-search-path") (find-pydocr-expand "tutorial/modules#the-module-search-path") The functions that end with `-expand' above simply return a string.

3. `code-rstdoc'

The six functions of the previous section are all part of the same family - they are associated to the the keyword `:py', and they were defined by running a function called `code-rstdoc', that is similar to `code-c-d' - see: (find-eev-quick-intro "9.1. `code-c-d'") Remember that `code-c-d' generates some code and executes it, and `find-code-c-d' generates the same code and displays it instead of executing it. It's the same thing with `code-rstdoc', and we can understand how a `code-rstdoc' works by running a `find-code-rstdoc'. In the pair of sexps below ;; (find-code-rstdoc :py) (code-rstdoc :py) the six `find-pydoc*' functions were generated by running (code-rstdoc :py) and we can use the ;; (find-code-rstdoc :py) in comments to understand what the `(code-rstdoc ...)' does. Try it now - you will see that: 1. it generates a temporary buffer with lots of comments at the top. Some of these comments are links to docs, and some are tests; 2. The paths that are used in the expansion - for example, the "file:///usr/share/doc/python3.9-doc/html/" do not appear there... they are defined elsewhere, in a variable called `ee-rstdoc-:py'.

4. `ee-rstdoc-:py' and friends

The functions `find-pydoc', `find-pydocw', and `find-pydocr' use fields of the variable `ee-rstdoc-:py' to determine how they will expand their arguments. You can inspect `ee-rstdoc-:py' with: (find-eev "eev-rstdoc.el" "ee-rstdoc-:py") (find-evariable 'ee-rstdoc-:py) (find-eppp ee-rstdoc-:py) (find-code-rstdoc :py) The file eev-rstdoc.el defines three families of `find-*doc*' functions: `:py', for Python itself, `:sympy', for SymPy, and `:mpl' for MatPlotLib. You can inspect `ee-rstdoc-:sympy' and `ee-rstdoc-:mpl' with: (find-eev "eev-rstdoc.el" "ee-rstdoc-:sympy") (find-evariable 'ee-rstdoc-:sympy) (find-eppp ee-rstdoc-:sympy) (find-code-rstdoc :sympy) (find-eev "eev-rstdoc.el" "ee-rstdoc-:mpl") (find-evariable 'ee-rstdoc-:mpl) (find-eppp ee-rstdoc-:mpl) (find-code-rstdoc :mpl) These `ee-rstdoc-:*'s contain plists. We can access some of their fields - the ones that are easier to understand - with: (plist-get ee-rstdoc-:py :base-html) (plist-get ee-rstdoc-:py :base-web) (plist-get ee-rstdoc-:py :base-rst) and with the functions in: (find-eev "eev-rstdoc.el" "basic-ops") The fields `:base-html', `:base-web', and `:base-html' are used in expansions. What are the other fields?

5. Shortening and killing

The documentation of Python in intended to be read in a browser. Suppose that we start here, (find-pydocw "tutorial/classes") https://docs.python.org/3/tutorial/classes.html and we navigate the docs a bit, and we find this other section that we want to keep a link to: https://docs.python.org/3/tutorial/controlflow.html#lambda-expressions Try this: put the point on the URL above and type `M-x pdk' - for "Python doc kill". The `pdk' will interpret the URL above as something that points to the Python docs, in the sense that it is related to the family defined by `ee-rstdoc-:py', not the ones for SymPy or MatPlotLib - and it will show this message in the echo area: Copied to the kill ring: # (find-pydoc "tutorial/controlflow#lambda-expressions") What happened here was that `pdk' "shortened" the URL above by deleting all the parts in it that are not the "stem" or the "hashanchor", https://docs.python.org/3/tutorial/controlflow.html#lambda-expressions \------------------/ \-----------------/ stem hashanchor then it produced this sexp, (find-pydoc "tutorial/controlflow#lambda-expressions") \/ \------------------/\-----------------/ kw stem hashanchor using the "py" from the keyword `:py', the stem, and the hashanchor, and then it "killed it" - i.e., it copied it to the kill rings. The definition of `ee-rstdoc-:py' in eev-rstdoc.el is this one: ;; From: (find-eev "eev-rstdoc.el" "ee-rstdoc-:py") ;; (find-evariable 'ee-rstdoc-:py) (defvar ee-rstdoc-:py '(:base "index" :base-web "https://docs.python.org/3/" :base-html "file:///usr/share/doc/python3.9-doc/html/" :base-rst "/usr/share/doc/python3.9/html/_sources/" :rst ".rst.txt" :res ("#.*$" "\\?.*$" ".html$" ".txt$" ".rst$" "^file://" "^https://docs.python.org/3/" "^/usr/share/doc/python[0-9.]*-doc/html/") :kill pdk ) "See: (find-code-rstdoc :py)") and the field `:res' controls how the shortening should work - the value of the `:res' field is a list of regexps, and during the shortening each occurrence of each one of these regexps is replaced by the empty string. The field `:kill' in `ee-rstdoc-:py' determines the name of the killing function for the `:py' family. Take a look at the temporary buffer generated by the `find-code-rstdoc' below: ;; (find-code-rstdoc :py) (code-rstdoc :py) The last thing in that temporary buffer is a `(defun pdk ...)' that defines `pdk' "in the right way".

6. A workflow

Let's suppose that you have just copied this URL from your browser to your notes: https://docs.python.org/3/tutorial/controlflow.html#lambda-expressions Run `M-x pdk' on it, go to the next line, and insert the sexp. You should get something like this: https://docs.python.org/3/tutorial/controlflow.html#lambda-expressions # (find-pydoc "tutorial/controlflow#lambda-expressions") Usually what I do then is that I test the sexp to see if it works as expected, and if it does I delete the URL. So my workflow is: 1. copy an URL from the browser, 2. run `M-x pdk' (or `M-x sdk', or `M-x mdk') on it, 3. go to the next line, 4. insert the sexp, 5. test the sexp, 6. delete the URL. I tried to keep the code as simple as possible, so there isn't a "smarter" way with fewer steps - yet. Sometimes I also do this: 7. duplicate the sexp with `M-h M-2', 8. add a `w' or a `r' to the new sexp, 9. adjust the `find-pydocr' sexp. The "adjust" step is because the "#lambda-expressions" part in the second sexp below doesn't work, and I don't know a way to convert it - the "hashanchor" part - into a string to search for; so I convert the second sexp below into the third by hand, by trial and error. Try: # (find-pydoc "tutorial/controlflow#lambda-expressions") # (find-pydocr "tutorial/controlflow#lambda-expressions") # (find-pydocr "tutorial/controlflow" "_tut-lambda:") The documentation for Python has lots of code snippets. The most obvious way to convert them into executable notes - like this: * (eepitch-python) * (eepitch-kill) * (eepitch-python) def make_incrementor(n): return lambda x: x + n f = make_incrementor(42) f(0) f(1) is by using cut-and-paste from the browser to Emacs, but I find it much easier to open the .rst file and do cut-and-paste from it to my notes.

7. `find-rstdoc-links'

The easiest way to define new families is by using `find-rstdoc-links'. Compare the temporary buffers generated by the two sexps below: (find-2a ' (find-rstdoc-links :py) ' (find-rstdoc-links :foo) ) The `(find-rstdoc-links :foo)' shows lots of strings like "BASE-WEB", "BASE-HTML", "BASE-RST", and "{kil}", that indicate that `find-rstdoc-links' couldn't find good guesses for those parts of the template. In `(find-rstdoc-links :foo)' those "holes" don't exist, but compare: (find-2a ' (find-eev "eev-rstdoc.el" "ee-rstdoc-:py") ' (find-rstdoc-links :py) ) The `defvar' in (find-eev "eev-rstdoc.el" "ee-rstdoc-:py") uses some regexps that are smarter than the ones that were generated by the `find-rstdoc-links'... TODO: explain how to edit the defvars/setqs and how to test the fields step by step!