(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!