(Re)generate: (find-rstdoc-intro)
Source code:  (find-efunction 'find-rstdoc-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.


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!

