Compare commits

...

9 Commits

1 changed files with 212 additions and 52 deletions

View File

@ -152,6 +152,9 @@ Here follows a list of links on how to use Emacs and Elisp:
the best approach to learn Emacs and Elisp.
5. [[https://www.masteringemacs.org/][Mastering Emacs]] is a link to a blog with many interesting posts that promotes
a book on how to become a proficient Emacs user.
6. [[https://www2.lib.uchicago.edu/keith/emacs/][Use GNU Emacs: The Plain Text Computing Environment]] explains the fundamentals
of the Emacs abstractions before showing how to exploit those abstractions
interactively. It targets a similar audience as the [[https://www.masteringemacs.org/][Mastering Emacs]] book.
* [[info:emacs#Early Init File][Early Init File (info)]]
:PROPERTIES:
@ -2054,6 +2057,7 @@ list detailing and motivating each listing:
(gnuplot . ,(fboundp 'gnuplot-mode))
(js . t)
(latex . t)
(lilypond . ,(fboundp 'lilypond-mode))
(lisp . t)
(lua . ,(fboundp 'lua-mode))
(maxima . ,(fboundp 'maxima-mode))
@ -2074,18 +2078,7 @@ list detailing and motivating each listing:
ol-info
org-id
org-protocol
org-tempo)
org-structure-template-alist '(("a" . "export ascii")
("c" . "center")
("C" . "comment")
("e" . "example")
("E" . "export")
("h" . "export html")
("l" . "export latex")
("q" . "quote")
("s" . "src")
("p" . "src python -n -i :session")
("v" . "verse"))))
org-tempo)))
#+end_src
#+caption[Setup =org-babel=]:
@ -2417,7 +2410,7 @@ else:
#+caption: Find valid entries for =org-babel-load-languages=.
#+name: lst:valid-org-babel-load-languages-entries
#+header: :wrap "src emacs-lisp :results silent :tangle no"
#+begin_src emacs-lisp :exports both :results value pp :exports both
#+begin_src emacs-lisp :exports both :results value pp
(defun all-org-babel-execute-fns ()
"Find `ob-LANGUAGE' files in Org defining `org-babel-execute:LANGUAGE'.
@ -4532,6 +4525,96 @@ src_emacs-lisp{(describe-function 'inferior-emacs-lisp-mode)}.
(setopt ielm-dynamic-return nil))
#+end_src
*** [[https://emacs.stackexchange.com/questions/2129/why-is-let-faster-with-lexical-scope][Disassemble dynamical and lexical scope]]
:PROPERTIES:
:CUSTOM_ID: sec:disassemble-dynamical-lexical-scope
:header-args:emacs-lisp: :exports code :tangle no
:END:
Listing [[lst:disassemble-lexical-scope][lexical scope disassembly]] and [[lst:disassemble-dynamical-scope][dynamical scope disassembly]] disassemble
identical code in case of respectively lexical and dynamical scope. Listing
[[lst:disassemble-lexical-scope-results][lexical scope disassembly results]] and [[lst:disassemble-dynamical-scope-results][dynamical scope disassembly results]] show
the respective results.
The link [[https://emacs.stackexchange.com/questions/61754/how-can-i-enable-lexical-binding-for-elisp-code-in-org-mode][how to enable lexical scope for Emacs Lisp in org-mode source blocks]]
explains all possibilities of disabling or enabling lexical scope.
#+caption[Disassemble lexical scope]:
#+caption: Disassemble lexical scope.
#+name: lst:disassemble-lexical-scope
#+header: :wrap "src text -n"
#+begin_src emacs-lisp -n :exports both :lexical t :results value
(with-temp-buffer
(disassemble (lambda (n)
"Demonstrate lexical scope."
(let* ((lower most-negative-fixnum)
(upper most-positive-fixnum)
(sum (+ lower upper)))
(expt sum n)))
(current-buffer))
(buffer-substring-no-properties (point-min) (point-max)))
#+end_src
#+caption[Disassemble lexical scope results]:
#+caption: Disassemble lexical scope results.
#+name: lst:disassemble-lexical-scope-results
#+RESULTS: lst:disassemble-lexical-scope
#+begin_src text -n
byte code:
doc: Demonstrate lexical scope. ...
args: (arg1)
0 varref most-negative-fixnum
1 varref most-positive-fixnum
2 stack-ref 1
3 stack-ref 1
4 plus
5 constant expt
6 stack-ref 1
7 stack-ref 5
8 call 2
9 return
#+end_src
#+caption[Disassemble dynamical scope]:
#+caption: Disassemble dynamical scope.
#+name: lst:disassemble-dynamical-scope
#+header: :wrap "src text -n"
#+begin_src emacs-lisp -n :exports both :results value
(with-temp-buffer
(disassemble (lambda (n)
"Demonstrate lexical scope."
(let* ((lower most-negative-fixnum)
(upper most-positive-fixnum)
(sum (+ lower upper)))
(expt sum n)))
(current-buffer))
(buffer-substring-no-properties (point-min) (point-max)))
#+end_src
#+caption[Disassemble dynamical scope results]:
#+caption: Disassemble dynamical scope results.
#+name: lst:disassemble-dynamical-scope-results
#+RESULTS: lst:disassemble-dynamical-scope
#+begin_src text -n
byte code:
doc: Demonstrate lexical scope.
args: (n)
0 varref most-negative-fixnum
1 varbind lower
2 varref most-positive-fixnum
3 varbind upper
4 varref lower
5 varref upper
6 plus
7 varbind sum
8 constant expt
9 varref sum
10 varref n
11 call 2
12 unbind 3
13 return
#+end_src
** [[https://fennel-lang.org/][Fennel Programming]]
:PROPERTIES:
:CUSTOM_ID: sec:fennel-programming
@ -4977,9 +5060,14 @@ ruff "$@" | cat
:header-args: :eval never-export
:END:
Listing [[lst:shell-pip-list-outdated]] and [[lst:shell-pip-index-versions]] are two
examples of invoking [[https://pip.pypa.io/en/stable/][pip]] in =org-mode= =shell= source blocks with the respective
results in listing [[lst:shell-pip-list-outdated-results]] and
[[lst:shell-pip-index-versions-results]].
#+caption[Show how to use =pip list --outdated=]:
#+caption: Show how to use =pip list --outdated=.
#+header: :wrap src text
#+header: :wrap "src text -n"
#+name: lst:shell-pip-list-outdated
#+begin_src shell :exports both :results verbatim
# WARNING: "pip index" is currently an experimental command.
@ -4988,12 +5076,13 @@ pip list --outdated
#+caption[The result of =pip list --outdated=]:
#+caption: The result of =pip list --outdated=.
#+name: lst:shell-pip-list-outdated-results
#+RESULTS: lst:shell-pip-list-outdated
#+begin_src text
#+begin_src text -n
Package Version Latest Type
------------------- ------- ------ -----
aiofiles 22.1.0 23.1.0 wheel
jupyter_server_ydoc 0.6.1 0.7.0 wheel
jupyter_server_ydoc 0.6.1 0.8.0 wheel
jupyter-ydoc 0.2.2 0.3.4 wheel
y-py 0.5.9 0.6.0 wheel
ypy-websocket 0.8.2 0.8.4 wheel
@ -5001,7 +5090,7 @@ ypy-websocket 0.8.2 0.8.4 wheel
#+caption[Show how to use =pip index versions=]:
#+caption: Show how to use =pip index versions=.
#+header: :wrap src text
#+header: :wrap "src text -n"
#+name: lst:shell-pip-index-versions
#+begin_src shell :exports both :results verbatim
# WARNING: "pip index" is currently an experimental command.
@ -5010,8 +5099,9 @@ pip index versions circular-buffer --no-color
#+caption[The result of =pip index versions=]:
#+caption: The result of =pip index versions=.
#+name: lst:shell-pip-index-versions-results
#+RESULTS: lst:shell-pip-index-versions
#+begin_src text
#+begin_src text -n
circular-buffer (0.2.0)
Available versions: 0.2.0, 0.1.1, 0.1.0
#+end_src
@ -5037,6 +5127,7 @@ Available versions: 0.2.0, 0.1.1, 0.1.0
(string-replace "_" "-" (alist-get 'name (car alists))))
(setq alists (cdr alists))))
(kill-buffer)
(describe-variable 'pip-outdated-packages)
(message "Calling `%S' succeeded" #'pip-list-outdated))))
(defun pip-list-outdated ()
@ -5057,14 +5148,22 @@ This invokes an asynchonous process and finishes with a message."
#+caption: Emacs interface to upgrade outdated unfrozen Python packages.
#+name: lst:pip-upgrade-maybe
#+begin_src emacs-lisp -n :results silent
(defcustom pip-frozen-packages '("aiofiles"
"jupyter-server-ydoc"
"jupyter-ydoc"
"y-py"
"ypy-websocket")
"Frozen Python packages (until jupyterlab-4.0.0)"
(defgroup pip nil
"Client for accessing the \"Package Installer for Python\" and \"PyPI\"."
:group 'applications)
(defcustom pip-frozen-packages nil
"Frozen Python packages."
:group 'pip
:type '(repeat string))
;; Frozen until the release of jupyterlab-4.0.0.
(setopt pip-frozen-packages '("aiofiles"
"jupyter-server-ydoc"
"jupyter-ydoc"
"y-py"
"ypy-websocket"))
(defun pip--upgrade-maybe-sentinel (process event)
(when (and (eq (process-status process) 'exit)
(buffer-live-p (process-buffer process)))
@ -5096,16 +5195,72 @@ buffer to check whether upgrading has made the dependencies incompatible."
#+caption[Emacs interface to the =PyPI= simple =JSON= =API=]:
#+caption: Emacs interface to the =PyPI= simple =JSON= =API=.
#+name: lst:pip-pypi-simple-json-apip
#+begin_src emacs-lisp -n :results silent
(defun pip-simple-json-project-details (name)
(let ((url (format "https://pypi.org/simple/%s" name))
(url-request-method "GET")
(url-mime-accept-string "application/vnd.pypi.simple.latest+json"))
(url-retrieve url
(lambda (status) (switch-to-buffer (current-buffer))))))
#+name: lst:pip-pypi-simple-json-api
#+begin_src emacs-lisp -n :lexical t :results silent
;; https://emacs.stackexchange.com/questions/61754/
;; "How can I enable lexical binding for elisp code in Org mode?"
(defun pip-simple-json-project-list ()
(defvar pip--simple-details-cache (make-hash-table :test 'equal)
"Cache for PyPI project details")
(defun pip-simple-get-json ()
(save-excursion
(goto-char (point-min))
(and (re-search-forward "^HTTP/.+ 200 OK$" nil (line-end-position))
(search-forward "\n\n" nil t)
(json-parse-buffer :array-type 'list))))
(defun pip-simple-details-retrieve (name callback &optional cbargs)
(pip--simple-details-prune-cache)
(if-let ((cached (gethash name pip--simple-details-cache)))
(apply callback (cdr cached) cbargs)
(let ((url (format "https://pypi.org/simple/%s" name))
(url-request-method "GET")
(url-mime-accept-string "application/vnd.pypi.simple.latest+json"))
(url-retrieve
url
(lambda (status)
(let ((details (and (not (plist-get status :error))
(pip-simple-get-json))))
(when details
(setf (gethash name pip--simple-details-cache)
(cons (time-convert nil 'integer) details)))
(prog1
(apply callback (or details 'error) cbargs)
(kill-buffer))))
nil t))))
(defun pip--simple-details-prune-cache ()
(let ((expired nil)
(time (- (time-convert nil 'integer)
;; Ten minutes
(* 10 60))))
(maphash (lambda (key val)
(when (< (car val) time)
(push key expired)))
pip--simple-details-cache)
(dolist (key expired)
(remhash key pip--simple-details-cache))))
#+end_src
#+caption[Using the Emacs interface to the =PyPI= simple =JSON= =API=]:
#+caption: Using the Emacs interface to the =PyPI= simple =JSON= =API=.
#+name: lst:using-pip-pypi-simple-json-api
#+begin_src emacs-lisp -n :lexical t :results silent
;; https://emacs.stackexchange.com/questions/61754/
;; "How can I enable lexical binding for elisp code in Org mode?"
(defun pip-simple-project-versions (name)
"Return the versions of Python package NAME."
(interactive "sPython package name: ")
(pip-simple-details-retrieve
name
(lambda (details)
(when-let ((versions (reverse (cdr (gethash "versions" details)))))
(message "`%s' versions: %S" name versions)))))
(defun pip-simple-project-list ()
"Get the Python package project list (PEP-691 and PEP-700)."
(interactive)
(let ((url-request-method "GET")
(url-mime-accept-string "application/vnd.pypi.simple.latest+json"))
@ -5501,9 +5656,9 @@ contrary to for instance [[https://github.com/Fanael/rainbow-delimiters#readme][
:CUSTOM_ID: sec:electric-operators
:END:
Listing [[lst:configure-electric-operator]] configures =electric-operator-mode=
to add spaces around operators for compatibility with for instance the [[https://black.readthedocs.io/en/stable/][Black
code formatter for Python]].
Listing [[lst:configure-electric-operator]] configures =electric-operator-mode= to
add spaces around operators for compatibility with for instance the [[https://black.readthedocs.io/en/stable/][Black code
formatter for Python]].
#+caption[Configure =electric-operator=]:
#+caption: Configure =electric-operator=.
@ -5555,7 +5710,7 @@ Listing [[lst:configure-tempo-latex-completing-read]] shows how to combine =temp
#+caption: Configure =tempo= user-interface.
#+name: lst:configure-tempo-ui
#+begin_src emacs-lisp -n :results silent
(with-eval-after-load 'tempo
(when (require 'tempo nil 'noerror)
(setopt tempo-interactive t)
(with-eval-after-load 'marginalia
@ -5589,31 +5744,30 @@ Allows `tempo' expansion by typing <SPC> after a complete `tempo' tag."
(unless (abbrev-symbol (car tag) abbrev-table)
(define-abbrev abbrev-table
(car tag) 1 'abbrev-tempo-expand-if-complete)))))
(with-eval-after-load 'org
(add-hook 'org-mode-hook 'setup-local-tempo-key-bindings))
#+end_src
*** Tempo for =AUCTeX='s =LaTeX-mode=
:PROPERTIES:
:CUSTOM_ID: sec:tempo-latex
:END:
#+caption[Configure =tempo= for =latex= with =completing-read=]:
#+caption: Configure =tempo= for =latex= with =completing-read=.
#+name: lst:configure-tempo-latex-completing-read
#+begin_src emacs-lisp -n :results silent
(with-eval-after-load 'latex
(unless (featurep 'tempo)
(require 'tempo))
(require 'tempo nil 'noerror)
(defun tempo-latex-environment-handler (element)
(when-let ((ok (eq element 'latex-environment))
(environment
(completing-read "LaTeX environment: "
(LaTeX-environment-list)
#'always 'require-match)))
`(l "\\begin{" ,environment "}" > n > r n "\\end{" ,environment "}" >)))
(when (eq element 'latex-environment)
(let ((environment (completing-read "LaTeX environment: "
(LaTeX-environment-list)
#'always 'require-match)))
`(l "\\begin{" ,environment "}" > n > r n "\\end{" ,environment "}" >))))
(cl-pushnew 'tempo-latex-environment-handler tempo-user-elements)
(defun setup-tempo-latex ()
(setup-local-tempo-key-bindings)
(defvar latex-tempo-tags nil)
(tempo-define-template
@ -5624,18 +5778,24 @@ Allows `tempo' expansion by typing <SPC> after a complete `tempo' tag."
'latex-tempo-tags)
(tempo-use-tag-list 'latex-tempo-tags)
(add-tempo-tags-to-abbrev-table latex-tempo-tags latex-mode-abbrev-table))
(add-tempo-tags-to-abbrev-table latex-tempo-tags latex-mode-abbrev-table)
(setup-local-tempo-key-bindings))
(add-hook 'LaTeX-mode-hook 'setup-tempo-latex))
#+end_src
*** Tempo for =python-mode=
:PROPERTIES:
:CUSTOM_ID: sec:tempo-python
:END:
#+caption[Configure =tempo= for =python-mode=]:
#+caption: Configure =tempo= for =python-mode=.
#+name: lst:setup-python-tempo
#+begin_src emacs-lisp -n :results silent
(with-eval-after-load 'python
(unless (featurep 'tempo)
(require 'tempo))
(require 'tempo nil 'noerror)
(defun setup-tempo-python ()
(defvar python-tempo-tags nil)