2021-11-29 13:14:56 +01:00
#+title : Emacs setup for use with LaTeX, Org, and Python
#+author : Gerard Vermeulen
2022-02-22 07:58:33 +01:00
#+latex_class : article-local
2022-09-18 11:08:04 +02:00
#+latex_class_options : [11pt,a4paper,english,svgnames]
2022-03-02 06:36:12 +01:00
#+macro : kbd (eval (by-backend-kbd-org-macro $1))
2022-10-12 06:06:56 +02:00
#+options : ^:{}
2022-03-02 06:36:12 +01:00
#+property : header-args:emacs-lisp :exports code :results silent :tangle init.el
2022-04-29 06:19:40 +02:00
#+startup : showeverything
2022-11-06 15:53:39 +01:00
#+begin_src latex :noweb yes :results raw
2022-11-07 11:50:17 +01:00
,#+latex_header: <<latex-header-1 >>
,#+latex_header: <<latex-header-2 >>
,#+latex_header: <<latex-header-3 >>
,#+latex_header: <<latex-header-4 >>
,#+latex_header: <<latex-header-5 >>
2022-11-06 15:53:39 +01:00
#+end_src
2021-11-29 13:14:56 +01:00
2022-11-16 07:09:25 +01:00
* Copying
:PROPERTIES:
:CUSTOM_ID: sec:copying
:END:
This README contains my Emacs setup for use with LaTeX, Org, and Python.
2023-01-01 13:42:14 +01:00
Copyright \copy 2021-2023 Gerard Vermeulen.
2022-11-16 07:09:25 +01:00
#+BEGIN_QUOTE
Permission is granted to copy, distribute and/or modify this
document under the terms of the GNU Free Documentation License,
Version 1.3 or any later version published by the Free Software
Foundation; with no Invariant Sections, with no Front-Cover Texts,
and with no Back-Cover Texts. A copy of the license is included in
the section entitled "GNU Free Documentation License".
#+END_QUOTE
2021-11-30 09:35:15 +01:00
* Quick start
:PROPERTIES:
:CUSTOM_ID: sec:quick-start
:END:
2023-01-12 21:28:18 +01:00
This setup requires at least Emacs-29.0.60. Backup the =user-emacs-directory=
(defaults often to =~/.emacs.d= on =Linux= , =Unix= , or =Darwin= ) and execute the
commands in listing [[lst:prepare-user-emacs-directory-with-https ][prepare the =user-emacs-directory= without =ssh= access ]] or
in listing [[lst:prepare-user-emacs-directory-with-ssh ][prepare the =user-emacs-directory= with =ssh= access ]]. After invoking
Emacs interactively (in interactive mode, neither in batch mode, nor in server
mode), Emacs will ask you to install a selected set of packages. Quit Emacs and
invoke Emacs again.
2021-12-11 12:48:46 +01:00
2023-01-03 21:04:52 +01:00
# #+caption[Prepare the user-emacs-directory]:
# #+caption: Clone and initialize the user-emacs-directory.
# #+name: lst:prepare-user-emacs-directory
2023-01-24 07:41:16 +01:00
# #+begin_src shell -n :noeval :tangle no
2023-01-03 21:04:52 +01:00
# cd ~
# git clone ccdr@mercury.grenoble.cnrs.fr:SERVER/emacs.d.git .emacs.d
# make --directory=.emacs.d init
# emacs &
# #+end_src
#+caption[Prepare the user-emacs-directory without =ssh= access]:
#+caption : Clone and initialize the user-emacs-directory without =ssh= access.
#+name : lst:prepare-user-emacs-directory-with-https
2023-01-24 07:41:16 +01:00
#+begin_src shell -n :noeval :tangle no
2023-01-03 21:04:52 +01:00
cd ~
2023-01-09 12:32:48 +01:00
git clone https://forge.chapril.org/gav451/emacs.d.git .emacs.d
2023-01-03 21:04:52 +01:00
make --directory=.emacs.d init
emacs &
#+end_src
#+caption[Prepare the =user-emacs-directory= with =ssh= access]:
#+caption : Clone and initialize the user-emacs-directory with =ssh= access.
#+name : lst:prepare-user-emacs-directory-with-ssh
2023-01-24 07:41:16 +01:00
#+begin_src shell -n :noeval :tangle no
2022-11-07 11:50:17 +01:00
cd ~
2023-01-09 12:32:48 +01:00
git clone ssh://gitea@forge.chapril.org:222/gav451/emacs.d.git .emacs.d
2022-11-07 11:50:17 +01:00
make --directory=.emacs.d init
emacs &
2021-11-30 09:35:15 +01:00
#+end_src
2021-11-29 13:14:56 +01:00
* Introduction
:PROPERTIES:
:CUSTOM_ID: sec:introduction
:END:
This Emacs setup aims to install automatically a minimal set of extension
packages that allows to handle my reports and presentations. The file format of
the reports is [[https://orgmode.org/ ][Org Mode ]] plain text with [[https://www.python.org/ ][Python ]] source code blocks and the file
format of the presentations is [[https://www.latex-project.org/ ][LaTeX ]].
This [[info:org#Top ][org ]] file (more precisely the original [[info:org#Top ][org ]] source file of this file)
2021-12-23 15:29:03 +01:00
illustrates three methods in my work-flow:
2021-11-30 09:35:15 +01:00
1. How to tangle (or export) source blocks from [[info:org#Top ][org ]] files. This file contains
2022-01-09 15:39:14 +01:00
source blocks to produce the files =early-init.el= , =init.el= , =latexmkrc= ,
2021-11-30 09:35:15 +01:00
=org-store-link= , and =example.py= by tangling.
2021-11-29 13:14:56 +01:00
2. How to export [[info:org#Top ][org ]] files to other formats such as [[https://en.wikipedia.org/wiki/HTML ][HTML ]], [[https://www.latex-project.org/ ][LaTeX ]], and [[https://en.wikipedia.org/wiki/PDF ][PDF ]].
3. How [[info:org#Hyperlinks ][org hyperlinks (info) ]] allow to link inside and outside [[info:org#Top ][Org Mode ]]: hover
over or click on the links to experiment.
The [[https://en.wikipedia.org/wiki/AUCTeX ][AUCTeX - Aalborg University Center TeX ]] extension package provides a
powerful [[https://en.wikipedia.org/wiki/Text-based_user_interface ][Text-based User Interface (TUI) ]] environment to edit the [[https://www.latex-project.org/ ][LaTeX ]]
presentations.
2022-11-16 07:09:25 +01:00
The [[https://github.com/bdarcus/citar ][Citar ]] extension package provides quick filtering and selecting of
2021-11-29 13:14:56 +01:00
bibliographic entries, and the option to run different commands on those
2023-01-12 21:28:18 +01:00
selections. [[https://github.com/bdarcus/citar ][Citar ]] exploits the extension packages [[https://github.com/minad/vertico ][Vertico ]], [[https://github.com/oantolin/embark ][Embark ]], [[https://github.com/minad/marginalia ][Marginalia ]],
and [[https://github.com/minad/consult ][Consult ]]. The [[https://github.com/andras-simonyi/citeproc-el ][CiteProc ]] extension package provides [[https://citationstyles.org/ ][CSL: citation style
language]] processing capabilities to [[https://github.com/bdarcus/citar ][Citar ]] and [[https://orgmode.org/ ][Org Mode ]]. A curated repository
of CSL styles is the [[https://github.com/citation-style-language/styles#readme ][citation style language repository ]].
The [[https://github.com/vedang/pdf-tools ][PDF-Tools ]] extension package renders [[https://en.wikipedia.org/wiki/PDF ][PDF ]] file with the possibility to
2021-11-30 09:35:15 +01:00
annotate the file or to click on anchors in the [[https://en.wikipedia.org/wiki/PDF ][PDF ]] file that link back to the
original [[https://www.latex-project.org/ ][LaTeX ]] file of the document. An example of my work-flow are the steps
2023-01-12 21:28:18 +01:00
to convert this [[info:org#Top ][org ]] file to [[https://en.wikipedia.org/wiki/PDF ][PDF ]] and to see the result with [[HTTPS://github.com/vedang/pdf-tools ][PDF-Tools ]] in Emacs:
2021-11-29 13:14:56 +01:00
execute the commands ~pdf-tools-install~ , ~org-babel-tangle~ ,
~org-latex-export-latex-to-latex~ , and ~compile~ . This sets up an infinite
[[https://www.latex-project.org/ ][LaTeX ]] compilation loop to update and redisplay the [[https://en.wikipedia.org/wiki/PDF ][PDF ]] file after excution of
the ~org-latex-export-latex-to-latex~ command in this buffer.
Here follows a list of interesting Emacs configurations:
2021-12-05 16:25:38 +01:00
1. [[https://github.com/alhassy/emacs.d ][Musa Al-hassy's configuration ]] is an impressive example of producing the Emacs
initialization files and other files by tangling an [[info:org#Top ][org ]] file. His methodology
is impressive, as his [[https://alhassy.github.io/ElispCheatSheet/ ][Elisp Cheat Sheet ]] and [[https://alhassy.github.io/org-special-block-extras/ ][org-special-block-extra package ]]
show. To me, this is a configuration to admire, but his methodology is way
over my head.
2022-03-26 15:35:35 +01:00
2. [[https://github.com/oantolin/emacs-config ][Omar Antolin Camarena's configuration ]] exploits built-in packages, Omar's own
2021-12-05 16:25:38 +01:00
small packages, and large external packages. Omar is the author of [[https://github.com/oantolin/orderless ][orderless ]]
2023-01-12 21:28:18 +01:00
and [[https://github.com/oantolin/embark ][embark ]]. My use =setopt= to set Emacs options instead of the customize
interface comes from his idea of using =custom-set-variables= although that
is [[https://www.masteringemacs.org/article/bad-emacs-advice ][bad Emacs advice ]] for new users.
2021-12-05 16:25:38 +01:00
3. [[https://gitlab.com/ambrevar/dotfiles ][Pierre Neirhardt's configuration ]] implements lazy loading without help of
2021-11-29 13:14:56 +01:00
external packages. I have stolen his approach of using lazy loading to
silently ignore the setup stanzas of uninstalled extension packages.
2021-12-05 16:25:38 +01:00
4. [[https://sachachua.com/dotemacs/ ][Sacha Chua's configuration ]] is a practical example of producing the Emacs
2021-11-29 13:14:56 +01:00
initialization files by tangling an [[info:org#Top ][org ]] file. It gives me the impression
that she is a very practical person trying to achieve her goals by the most
2022-06-30 18:07:06 +02:00
efficient means.
2022-10-16 07:14:44 +02:00
5. [[https://github.com/purcell/emacs.d ][Steve Purcell's configuration ]] is well organized and a showcase of readable
code. Its commit and issue histories are also helpful: see for instance the
discussion [[https://github.com/purcell/emacs.d/issues/778 ][The order of company candidates is incorrect in Emacs lisp mode ]].
2021-11-29 13:14:56 +01:00
2022-02-01 07:57:33 +01:00
Here follows a list of links on how to use Emacs and Elisp:
2022-03-23 08:01:02 +01:00
1. [[https://www.youtube.com/watch?v=lkIicfzPBys ][A guided tour of Emacs ]] is a link to a video tour pointing how [[info:emacs#Buffers ][buffers (info) ]],
2022-03-13 11:36:07 +01:00
[[info:emacs#Dired ][dired (info) ]], [[info:emacs#Help ][documentation (info) ]], [[info:elisp#Top ][elisp (info) ]], [[info:elisp#Debugging ][elisp debugging (info) ]],
[[info:eshell#Top ][eshell (info) ]], and [[info:emacs#Keyboard Macros ][keyboard macros (info) ]] turn Emacs in an powerful coding
and editing environment.
2022-03-27 19:16:06 +02:00
2. [[https://www.youtube.com/watch?v=6ZWp05OW1c0 ][Emergency Emacs ]] is a link to a video on fundamental editing features and
principles with focus on [[info:ediff#Top ][ediff (info) ]], [[info:emacs#Undo ][undo (info) ]], [[info:emacs#Moving Point ][moving point (info) ]],
[[info:emacs#Erasing ][erasing (info) ]], and [[info:emacs#Dynamic Abbrevs ][dynamic abbreviations (info) ]].
2022-03-13 11:36:07 +01:00
2. [[https://endlessparentheses.com/ ][Endless Parentheses ]] is a blog with many mindblowing code snippets.
2022-09-18 08:50:24 +02:00
3. [[https://www.murilopereira.com/how-to-open-a-file-in-emacs/ ][How to open a file in Emacs ]] looks into [[info:elisp#Top ][elisp (info) ]] and
[[info:elisp#Debugging ][elisp debugging (info) ]] and then compares Emacs, [[https://www.vim.org/ ][Vim ]],
[[https://neovim.io/ ][Neovim ]], and [[https://code.visualstudio.com/ ][Visual Studio Code ]] with respect to values and technology.
4. [[https://protesilaos.com/codelog/2022-01-31-learning-emacs/ ][Learning Emacs and Elisp ]] is a link to a video tutorial with a transcript on
2022-02-01 07:57:33 +01:00
the best approach to learn Emacs and Elisp.
2022-09-18 08:50:24 +02:00
5. [[https://www.masteringemacs.org/ ][Mastering Emacs ]] is a link to a blog with many interesting posts that promotes
2022-02-01 07:57:33 +01:00
a book on how to become a proficient Emacs user.
2021-11-29 13:14:56 +01:00
* [[info:emacs#Early Init File][Early Init File (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:early-init-file
:END:
2021-12-07 08:19:59 +01:00
Try to load [[https://github.com/emacscollective/no-littering ][no-littering ]] as early as possible, since it helps to keep
=~/.emacs.d= clean.
2021-12-23 15:29:03 +01:00
#+caption[Tangle the early-init-file]:
#+caption : Tangle the early-init-file.
2021-12-28 08:48:03 +01:00
#+name : lst:tangle-early-init-file
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent :tangle early-init.el
2022-11-07 11:50:17 +01:00
;;; early-init.el --- user early-init file -*- lexical-binding: t -* -
;;; Commentary:
;;; Code:
(setq load-prefer-newer t)
2021-12-06 18:35:33 +01:00
2022-11-07 11:50:17 +01:00
(require 'no-littering nil 'noerror)
2021-11-29 13:14:56 +01:00
2022-11-07 11:50:17 +01:00
(provide 'early-init)
;; Emacs looks for "Local variables:" after the last "?\n?\f".
;; Local Variables:
;; indent-tabs-mode: nil
;; End:
;;; earl-init.el ends here
2021-11-29 13:14:56 +01:00
#+end_src
2021-12-07 05:39:02 +01:00
In order to get help in understanding the code block above in a buffer showing
2022-01-09 15:39:14 +01:00
the original [[info:org#Top ][Org ]] source file, type {{{kbd(C-c C-c)}}} after moving
point (or cursor) to one of the items of the list:
2021-12-23 15:29:03 +01:00
1. src_emacs-lisp{(describe-variable #'load-prefer-newer t)}
2. src_emacs-lisp{(apropos-library "no-littering")}
3. src_emacs-lisp{(find-function #'hack-local-variables)}
2022-01-07 16:33:40 +01:00
to execute the code between the curly braces for access to help. This shows
that *Emacs is a self-documenting editor.*
2021-12-07 05:39:02 +01:00
2021-11-29 13:14:56 +01:00
* [[info:emacs#Init File][Init File (info)]] header
:PROPERTIES:
:CUSTOM_ID: sec:init-file-header
:END:
2023-01-12 21:28:18 +01:00
The =user-init-file= header requires =cl-lib= and sets Emacs options. It
consists of two parts in listing [[lst:1st-setopt-call ]], and [[lst:2nd-setopt-call ]] in
order to limit the length of the listings for exporting to LaTeX.
2022-04-20 04:56:39 +02:00
The [[info:elisp#Quoting ][quoting (info) ]] and the [[info:elisp#Backquote ][backquote (info) ]] pages explain how to understand the
2023-01-12 21:28:18 +01:00
~'~ (quote), ~`~ (backquote), ~,~ (substitute) and ~@,~ (splice) in in listing
[[lst:1st-setopt-call ]] and [[lst:2nd-setopt-call ]]. A tutorial of how to use those
reader macros is the [[https://mullikine.github.io/posts/macro-tutorial/ ][didactic emacs-lisp macro example ]].
The [[info:emacs#Init File ][init file (info) ]] does not load the ~custom-file~ in spite of the
recommendation of [[info:emacs#Saving Customizations ][saving customizations (info) ]].
#+caption[Set the first set of Emacs options]:
#+caption : Set the first set of Emacs options.
#+name : lst:1st-setopt-call
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
;;; init.el --- user init file -*- lexical-binding: t -* -
;;; Commentary:
;;; Code:
(require 'cl-lib)
2023-01-12 21:28:18 +01:00
(when (version< emacs-version "29.0.60")
(error "This `init.el' requires at least Emacs-29.0.60"))
(setopt
after-save-hook #'executable-make-buffer-file-executable-if-script-p
column-number-mode t
cursor-type 'box
custom-file (locate-user-emacs-file "custom.el")
epg-pinentry-mode 'loopback
global-hl-line-mode t
global-hl-line-sticky-flag t
history-delete-duplicates t
history-length 500
indent-tabs-mode nil
inhibit-startup-buffer-menu t
inhibit-startup-screen t
initial-buffer-choice t
initial-scratch-message ""
insert-directory-program (or (executable-find "gls")
(executable-find "ls"))
kill-ring-max 300
mode-line-compact 'long
next-error-message-highlight t
recentf-mode t
save-place-mode t
scroll-bar-mode nil
tab-always-indent 'complete
tab-width 8
tool-bar-mode nil
url-cookie-trusted-urls nil
url-cookie-untrusted-urls '(".*")
use-dialog-box nil
use-short-answers t
view-read-only t)
2022-04-09 16:13:10 +02:00
2022-11-07 11:50:17 +01:00
(when (eq system-type 'darwin)
2023-01-12 21:28:18 +01:00
(setopt ns-alternate-modifier nil
ns-command-modifier 'meta
ns-right-command-modifier 'super))
2021-11-29 13:14:56 +01:00
2022-11-07 11:50:17 +01:00
(when (eq window-system 'ns)
(add-to-list 'initial-frame-alist '(height . 51))
(add-to-list 'initial-frame-alist '(width . 180)))
2021-11-29 13:14:56 +01:00
#+end_src
2023-01-12 21:28:18 +01:00
#+caption[Set the second set of Emacs options]:
#+caption : Set the second set of Emacs options.
#+name : lst:2nd-setopt-call
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2023-01-12 21:28:18 +01:00
(setopt
;; See https://github.com/melpa/melpa#mirrors for official Melpa mirrors.
;; ("melpa" . "https://www.mirrorservice.org/sites/melpa.org/packages/ ")
package-archives '(("gnu" . "https://elpa.gnu.org/packages/ ")
("gnu-devel" . "https://elpa.gnu.org/devel/ ")
("melpa" . "https://melpa.org/packages/ ")
("nongnu" . "https://elpa.nongnu.org/nongnu/ "))
;; Pin packages to GNU ELPA for info or stability.
package-pinned-packages '((auctex . "gnu")
(compat . "gnu")
(consult . "gnu-devel")
(embark . "gnu-devel")
(embark-consult . "gnu-devel")
(engrave-faces . "gnu-devel")
(hyperbole . "gnu-devel")
(marginalia . "gnu-devel")
(org . "gnu-devel")
(queue . "gnu")
(rainbow-mode . "gnu")
(spinner . "gnu")
(xr . "gnu")
(vertico . "gnu-devel"))
package-selected-packages '(async ; asynchroneous processing
debbugs ; access the GNU bug tracker
no-littering ; keep `user-emacs-directory' clean
org ; thought organizer
wgrep)) ; open a writable grep buffer
#+end_src
2022-05-21 12:50:47 +02:00
* [[info:emacs#Package Installation][Install the selected packages (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:install-selected-packages
:END:
[[info:emacs#Package Installation ][Emacs installs packages ]] from archives on the internet. This setup uses three
archives:
1. The [[https://elpa.gnu.org/ ][GNU Emacs Lisp Package Archive ]]
2. The [[https://elpa.nongnu.org/ ][NonGNU Emacs Lisp Package Archive ]].
2022-10-16 07:15:58 +02:00
3. The [[https://melpa.org/#/ ][Milkypostman's Emacs Lisp Package Archive (MELPA) ]] with its official
[[https://www.mirrorservice.org/sites/melpa.org/packages/ ][mirror ]] in case [[https://downforeveryoneorjustme.com/melpa.org ][is Melpa.org down? ]] tells [[https://melpa.org/#/ ][MELPA ]] is down for everyone.
2022-06-30 18:07:06 +02:00
The code in listing [[lst:install-selected-packages ]] assumes that the package
system is in a *virgin* state if the package [[https://github.com/emacscollective/no-littering ][no-littering ]] is not present:
2022-05-21 12:50:47 +02:00
1. It installs and loads [[https://github.com/emacscollective/no-littering ][no-littering ]] after ensuring refreshing of the
contents of available packages.
2. It installs [[https://elpa.gnu.org/devel/org.html ][Org (GNU-devel ELPA archive) ]] early to shadow the built-in package
while preventing collisions between the snapshot and built-in packages.
2022-06-30 18:07:06 +02:00
3. It calls src_emacs-lisp{(package-install-selected-packages)} to check the
2022-05-21 12:50:47 +02:00
installation status of all packages in
src_emacs-lisp{package-selected-packages} and to install the missing packages
after the user has agreed to its prompt.
2022-06-30 18:07:06 +02:00
4. It defines a function to ensure the installation of packages in other source
2022-05-21 12:50:47 +02:00
blocks. This allows skipping installation in sections with a =:noexport:=
tag by disallowing tangling.
In case of normal Emacs usage, src_emacs-lisp{(package-list-packages)} refreshes
the contents of packages and allows to update packages to the latest version.
#+caption[Install the selected packages]:
#+caption : Install the selected packages.
#+name : lst:install-selected-packages
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(unless noninteractive
(unless (require 'no-littering nil 'noerror)
(unless (bound-and-true-p package-archive-contents)
(package-refresh-contents))
;; Install and require `no-littering'.
(package-install 'no-littering)
(require 'no-littering)
;; https://emacs.stackexchange.com/a/45939 answers
;; "How to shadow automatically a built-in package by installing it?"
(defun shadow-builtin-by-install (pkg)
(when-let ((desc (cadr (assq pkg package-archive-contents))))
(package-install desc 'dont-select)))
;; Shadow built-in `org' by installing `org'.
(shadow-builtin-by-install 'org)
;; Install the selected packages.
(package-install-selected-packages)))
(defun ensure-package-selection (package)
"Ensure selection of PACKAGE."
(when (and (package-installed-p package)
(bound-and-true-p package-selected-packages))
(cl-pushnew package package-selected-packages)))
(defun ensure-package-installation (&rest packages)
"Ensure installation of all packages in PACKAGES."
(let ((ok t))
(dolist (package packages)
(unless (package-installed-p package)
(package-install package))
(unless (ensure-package-selection package)
(setq ok nil)))
ok))
2022-05-21 12:50:47 +02:00
#+end_src
2022-12-12 08:09:19 +01:00
* [[https://git.savannah.gnu.org/cgit/emacs.git/tree/admin/notes/tree-sitter/starter-guide?h=feature/tree-sitter][Emacs Tree-sitter]]
:PROPERTIES:
:CUSTOM_ID: sec:emacs-tree-sitter
:END:
2023-01-12 21:28:18 +01:00
#+caption[Setup Emacs Tree-sitter]:
#+caption : Setup Emacs Tree-sitter.
#+name : lst:setup-emacs-tree-sitter
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2023-01-09 19:04:33 +01:00
(when (require 'treesit nil 'noerror)
2023-01-20 20:13:31 +01:00
(setopt
treesit-language-source-alist
'((bash "https://github.com/tree-sitter/tree-sitter-bash" "master" "src")
(c "https://github.com/tree-sitter/tree-sitter-c" "master" "src")
2023-01-21 10:04:14 +01:00
(cmake "https://github.com/uyha/tree-sitter-cmake" "master" "src")
2023-01-20 20:13:31 +01:00
(cpp "https://github.com/tree-sitter/tree-sitter-cpp" "master" "src")
(css "https://github.com/tree-sitter/tree-sitter-css" "master" "src")
2023-01-21 10:04:14 +01:00
(glsl "https://github.com/theHamsta/tree-sitter-glsl" "master" "src")
2023-01-20 20:13:31 +01:00
(go "https://github.com/tree-sitter/tree-sitter-go" "master" "src")
2023-01-21 10:04:14 +01:00
(html "https://github.com/tree-sitter/tree-sitter-html" "master" "src")
2023-01-20 20:13:31 +01:00
(java "https://github.com/tree-sitter/tree-sitter-java" "master" "src")
2023-01-24 07:41:16 +01:00
(javascript "https://github.com/tree-sitter/tree-sitter-javascript"
"master" "src")
2023-01-20 20:13:31 +01:00
(json "https://github.com/tree-sitter/tree-sitter-json" "master" "src")
(julia "https://github.com/tree-sitter/tree-sitter-julia" "master" "src")
2023-01-21 10:04:14 +01:00
(make "https://github.com/alemuller/tree-sitter-make" "main" "src")
(perl "https://github.com/ganezdragon/tree-sitter-perl" "master" "src")
2023-01-20 20:13:31 +01:00
(python "https://github.com/tree-sitter/tree-sitter-python" "master" "src")
(ruby "https://github.com/tree-sitter/tree-sitter-ruby" "master" "src")
(rust "https://github.com/tree-sitter/tree-sitter-rust" "master" "src")
(scala "https://github.com/tree-sitter/tree-sitter-scala" "master" "src")
2023-01-21 10:04:14 +01:00
(sql "https://github.com/m-novikov/tree-sitter-sql" "main" "src")
(swift "https://github.com/tree-sitter/tree-sitter-swift" "master" "src")
2023-01-20 20:13:31 +01:00
(toml "https://github.com/tree-sitter/tree-sitter-toml" "master" "src")
2023-01-24 07:41:16 +01:00
(tsx "https://github.com/tree-sitter/tree-sitter-typescript"
"master" "tsx/src")
(typescript "https://github.com/tree-sitter/tree-sitter-typescript"
"master" "typescript/src")
2023-01-21 10:04:14 +01:00
(yaml "https://github.com/ikatyang/tree-sitter-yaml" "master" "src")))
2023-01-20 20:13:31 +01:00
(add-to-list 'auto-mode-alist
`(,(rx ".py" (opt (any "iw")) eos) . python-ts-mode)))
2022-12-12 08:09:19 +01:00
#+end_src
2022-05-22 23:24:12 +02:00
* [[info:emacs#Faces][Text faces or styles (info)]]
2022-01-25 11:28:05 +01:00
:PROPERTIES:
2022-05-22 23:24:12 +02:00
:CUSTOM_ID: sec:text-faces-or-styles
2022-01-25 11:28:05 +01:00
:END:
2023-01-12 21:28:18 +01:00
This setup does not use [[info:emacs#Custom Themes ][custom themes (info) ]] to avoid endless tweaking, but it
does a minimal setup of fonts and faces. See the [[https://protesilaos.com/codelog/2020-09-05-emacs-note-mixed-font-heights/ ][note on mixed font heights in
Emacs]] for how to setup fonts properly. It boils down to two rules:
2022-05-22 23:24:12 +02:00
1. The height of the default face must be an integer number to make the height a
physical quantity.
2. The heights of all other faces must be real numbers to scale those heights
with respect to the height of the face (those heights default to 1.0 for no
scaling).
The code in listing [[lst:configure-face-attributes ]] source implements those rules.
Listing [[lst:set-default-face-height ]] shows that font scaling is easy in case of
proper initialization of all face heigths. Listing
2022-10-08 20:25:17 +02:00
[[lst:fix-gtk-color-for-invert-default-face ]], [[lst:shadow-org-font-lock-faces ]], and
[[lst:shadow-org-font-lock-faces ]] show a few tweaks to improve visibility without
theming:
2022-05-22 23:24:12 +02:00
1. Fixing the =gtk= background color of the already loaded =region= face.
2022-03-26 15:41:37 +01:00
2. Toggling between a dark and light background by means of
2022-05-22 23:24:12 +02:00
src_emacs-lisp{(invert-default-face)}.
3. Shadowing the definition of faces before loading. The last item in the page
on [[https://orgmode.org/worg/org-contrib/babel/examples/fontify-src-code-blocks.html#org5c4406f ][fontifying Org mode source code blocks ]] describes this method.
#+caption[Configure =face-attributes= ]:
#+caption : Configure =face-attributes=.
#+name : lst:configure-face-attributes
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'emacs
;; Set face attributes.
(cond
((eq system-type 'darwin)
(set-face-attribute 'default nil :family "Hack" :height 120)
(set-face-attribute 'fixed-pitch nil :family "Hack")
(set-face-attribute 'variable-pitch nil :family "FiraGo"))
((eq system-type 'gnu/linux)
(set-face-attribute 'default nil :family "Hack" :height 110)
(set-face-attribute 'fixed-pitch nil :family "Hack")
(set-face-attribute 'variable-pitch nil :family "FiraGo"))
(t
(set-face-attribute 'default nil :family "Hack" :height 110)
(set-face-attribute 'fixed-pitch nil :family "Hack")
(set-face-attribute 'variable-pitch nil :family "DejaVu Sans"))))
2022-05-22 23:24:12 +02:00
#+end_src
#+caption[Implement =set-default-face-height= ]:
#+caption : Implement =set-default-face-height=.
#+name : lst:set-default-face-height
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'emacs
(defun set-default-face-height ()
"Set the default face height in all current and future frames.
2022-05-22 23:24:12 +02:00
2022-11-07 11:50:17 +01:00
Scale all other faces with a height that is a real number."
(interactive)
(let* ((prompt (format "face heigth (%s): "
(face-attribute 'default :height)))
(choices (mapcar #'number-to-string
(number-sequence 50 200 10)))
(height (string-to-number
(completing-read prompt choices nil 'require-match))))
(message "Setting the height of the default face to %s" height)
(set-face-attribute 'default nil :height height))))
2022-05-22 23:24:12 +02:00
#+end_src
2022-01-25 11:28:05 +01:00
2022-07-13 07:15:52 +02:00
#+caption[Use =buffer-face-mode= to set fixed or variable pitch face]:
#+caption : Use =buffer-face-mode= to set fixed or variable pitch face.
#+name : lst:use-buffer-face-mode-for-fixed-or-variable-pitch-face
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
;; Use proportional font faces in current buffer
(defun set-buffer-variable-pitch-face ()
"Set a variable width (proportional) font in current buffer."
(interactive)
(setq buffer-face-mode-face 'variable-pitch)
(buffer-face-mode))
2022-07-12 18:51:07 +02:00
2022-11-07 11:50:17 +01:00
;; Use monospaced font faces in current buffer
(defun set-buffer-fixed-pitch-face ()
"Set a fixed width (monospace) font in current buffer."
(interactive)
(setq buffer-face-mode-face 'fixed-pitch)
(buffer-face-mode))
2022-07-12 18:51:07 +02:00
2022-11-07 11:50:17 +01:00
(add-hook 'magit-mode-hook #'set-buffer-fixed-pitch-face)
(add-hook 'prog-mode-hook #'set-buffer-fixed-pitch-face)
2022-07-12 18:51:07 +02:00
#+end_src
2022-05-22 23:24:12 +02:00
#+caption[Fix a `gtk' color and implement =invert-default-face= ]:
#+caption : Fix a `gtk' color and implement =invert-default-face=.
#+name : lst:fix-gtk-color-for-invert-default-face
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'emacs
(defun fix-gtk-region-face-background-color ()
(when (featurep 'gtk)
(set-face-attribute
'region nil
:background (cdr (assoc (face-attribute 'default :background)
'(("white" . "LightGoldenrod2")
("black" . "blue3")))))))
(defun invert-default-face ()
"Invert the default face."
(interactive)
(invert-face 'default)
2022-05-22 23:24:12 +02:00
(fix-gtk-region-face-background-color))
2022-11-07 11:50:17 +01:00
(fix-gtk-region-face-background-color))
2022-03-26 15:41:37 +01:00
#+end_src
2022-10-08 20:25:17 +02:00
#+caption[Shadow Org font-lock faces to improve the readability]:
#+caption : Shadow Org font-lock faces to improve the readability.
#+name : lst:shadow-org-font-lock-faces
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'emacs
;; Shadow two definitions in org-faces.el:
(defface org-block
;; https://emacs.stackexchange.com/a/9604 answers:
;; How to override a defined face for light and dark backgrounds?
`((((background dark))
:inherit (fixed-pitch)
,@(and (>= emacs-major-version 27) '(:extend t))
:background "#444444")
(t
:inherit (fixed-pitch)
,@(and (>= emacs-major-version 27) '(:extend t))
:background "#FFFFD0"))
"My face used for text inside various blocks.
It is always used for source blocks. You can refine what face
should be used depending on the source block language by setting,
`org-src-block-faces', which takes precedence.
When `org-fontify-quote-and-verse-blocks' is not nil, text inside
verse and quote blocks are fontified using the `org-verse' and
`org-quote' faces, which inherit from `org-block'.")
(defface org-table
;; https://emacs.stackexchange.com/a/9604 answers:
;; How to override a defined face for light and dark backgrounds?
`((((background dark))
:inherit (fixed-pitch)
,@(and (>= emacs-major-version 27) '(:extend t))
:background "#444444")
(t
:inherit (fixed-pitch)
,@(and (>= emacs-major-version 27) '(:extend t))
:background "#FFFFD0"))
"My face for tables."))
2022-10-08 20:25:17 +02:00
#+end_src
2022-05-28 15:36:07 +02:00
2022-10-08 20:25:17 +02:00
#+caption[Shadow Emacs font-lock faces to improve the readability]:
#+caption : Shadow Emacs font-lock faces to improve the readability.
#+name : lst:shadow-emacs-font-lock-faces
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'emacs
;; Shadow one definition in sh-script.el:
(defface sh-heredoc
'((((class color) (background dark))
(:foreground "yellow"))
(((class color) (background light))
(:foreground "magenta"))
(t
(:weight bold)))
"My face to show a here-document."))
2022-01-25 11:28:05 +01:00
#+end_src
2022-09-01 03:54:05 +02:00
* [[info:emacs#Windows][Window management (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:window-management
:END:
Mickey Peterson's post [[https://www.masteringemacs.org/article/demystifying-emacs-window-manager ][Demystifying Emacs's Window Manager ]] invites to improve
2022-09-11 07:38:53 +02:00
window placement. Listing [[lst:1st-window-management ]], [[lst:2nd-window-management ]]
and [[lst:3rd-window-management ]] implement a selection of his recommendations.
2022-09-01 03:54:05 +02:00
2022-09-03 20:17:09 +02:00
#+caption[Window management functions and key bindings]:
#+caption : Window management functions and key bindings.
2022-09-01 03:54:05 +02:00
#+name : lst:1st-window-management
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'emacs
;; https://www.masteringemacs.org/article/demystifying-emacs-window-manager
(defun split-root-below (arg)
"Split window below from the root or from the parent with ARG."
(interactive "P")
2023-01-12 21:28:18 +01:00
(split-window (if arg
(window-parent (selected-window))
2022-11-07 11:50:17 +01:00
(frame-root-window))
nil 'below nil))
(defun split-root-right (arg)
"Split window right from the root or from the parent with ARG."
(interactive "P")
2023-01-12 21:28:18 +01:00
(split-window (if arg
(window-parent (selected-window))
2022-11-07 11:50:17 +01:00
(frame-root-window))
nil 'right nil))
(defun toggle-window-dedication ()
"Toggles window dedication in the selected window."
(interactive)
(set-window-dedicated-p
(selected-window) (not (window-dedicated-p (selected-window)))))
2022-09-02 06:32:35 +02:00
2022-11-07 11:50:17 +01:00
(defun make-display-buffer-matcher-function (major-modes)
"Return a lambda function to match a list of MAJOR-MODES."
(lambda (buffer-name action)
(with-current-buffer buffer-name (apply #'derived-mode-p major-modes))))
2022-09-03 20:17:09 +02:00
2023-02-26 14:37:33 +01:00
(keymap-global-set "M-o" #'other-window))
2022-09-01 03:54:05 +02:00
#+end_src
2022-09-11 07:38:53 +02:00
#+caption[Window management modes]:
#+caption : Window management modes.
#+name : lst:2nd-window-management
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'emacs
(winner-mode +1))
2022-09-11 07:38:53 +02:00
#+end_src
2022-09-01 03:54:05 +02:00
#+caption[Window management variables]:
#+caption : Window management variables.
2022-09-11 07:38:53 +02:00
#+name : lst:3rd-window-management
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'emacs
;; https://www.masteringemacs.org/article/demystifying-emacs-window-manager
2023-01-12 21:28:18 +01:00
(when (version< "29.0.0" emacs-version)
(setopt switch-to-buffer-in-dedicated-window 'pop
switch-to-buffer-obey-display-actions t))
2022-11-07 11:50:17 +01:00
(add-to-list 'display-buffer-alist
`(,(rx (or "*Apropos* "
"*Help* "
"*info"))
(display-buffer-reuse-window display-buffer-pop-up-window)
(inhibit-same-window . nil)))
(add-to-list 'display-buffer-alist
`(,(rx (or "*Occur* "
"*grep* "
"*xref* "))
display-buffer-reuse-window
(inhibit-same-window . nil)))
(add-to-list 'display-buffer-alist
'("\\*compilation\\* "
display-buffer-no-window
(allow-no-window . t)))
(add-to-list 'display-buffer-alist
'("^\\*Dictionary\\* " display-buffer-in-side-window
(side . left)
(window-width . 70))))
2022-09-01 03:54:05 +02:00
#+end_src
2022-10-31 13:46:31 +01:00
* [[info:elisp#Advising Functions][Advising functions (info)]]
2022-05-21 12:50:47 +02:00
:PROPERTIES:
:CUSTOM_ID: sec:advising-function
:END:
2022-05-01 17:35:18 +02:00
2022-10-31 13:46:31 +01:00
#+caption[Toggle any advice]:
#+caption : Toggle any advice.
#+name : lst:toggle-any-advice
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'emacs
(defun advice-toggle (symbol where function &optional props)
"Toggle between states after `advice-remove' and `advice-add'."
(let ((how "%s `%s' advice `%s' %s `%s'"))
(if (advice-member-p function symbol)
(progn
(message how "Removal of" where function "from" symbol)
(advice-remove symbol function))
(message how "Addition of" where function "to" symbol)
(advice-add symbol where function props)))))
2022-05-01 17:35:18 +02:00
#+end_src
2022-10-31 13:46:31 +01:00
#+caption[Toggle specific advice]:
#+caption : Toggle specific advice.
#+name : lst:toggle-specific-advice
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'emacs
2023-01-21 10:26:24 +01:00
(defun toggle-eww-display-pdf-around ()
"Toggle `eww-display-advice' advice."
(interactive)
(advice-toggle 'eww-display-pdf :around #'eww-display-pdf-as-binary))
(defun toggle-ilog-timer-function-after ()
"Toggle `ilog-timer-function' advice."
(interactive)
(advice-toggle 'ilog-timer-function :after #'ilog-ensure-ilog-buffer-window))
(defun toggle-keycast-log-update-buffer-override ()
"Toggle `keycast-log-update-buffer' advice."
(interactive)
(advice-toggle 'keycast-log-update-buffer
:override #'keycast-log-update-buffer-plain))
(defun toggle-org-babel-python-format-session-value-override ()
"Toggle `org-babel-python-format-session-value' advice."
(interactive)
(advice-toggle 'org-babel-python-format-session-value
:override #'org-babel-python-format-session-value-override)))
2022-10-31 13:46:31 +01:00
#+end_src
2022-05-21 12:50:47 +02:00
* [[info:emacs#Dired][Dired: directory editor as file manager (info)]]
2022-02-05 14:04:41 +01:00
:PROPERTIES:
:CUSTOM_ID: sec:file-manager
:END:
2022-02-06 13:03:59 +01:00
[[info:emacs#Dired ][Dired (info) ]] and the [[https://github.com/ranger/ranger#readme ][ranger ]] file manager offer similar capabilities for copying,
deleting, opening, renaming, and viewing files and directories, but the
integration of [[info:emacs#Dired ][dired (info) ]] in Emacs is obviously much better than the
integration of [[https://github.com/ranger/ranger#readme ][ranger ]] in Emacs.
For instance, this setup allows to insert an =org-mode= link to an poorly
identified file containing a specific image into an =org-mode= buffer by means
of the facilities of [[info:emacs#Dired ][dired (info) ]] as follows:
1. Type {{{kbd(C-x d)}}} to open the directory containing the pooly identified
file with the specific image in a =dired-mode= buffer.
2. Start searching for the specific image by navigating to the name of any image
file.
3. Type {{{kbd(v)}}} to switch to view the file in an =image-mode= buffer.
4. In the =image-mode= buffer, continue searching for the specific image by
typing:
- {{{kbd(n)}}} to view the next image in the =dired-mode= buffer,
- {{{kbd(p)}}} to view the previous image in the =dired-mode= buffer, and
- {{{kbd(q)}}} to quit the =image-mode= buffer and to go back to the
=dired-mode= buffer.
5. After finding the specific image, use {{{kbd(C-c l)}}} in the =image-mode=
buffer or the =dired-mode= buffer to store the =org-link= .
6. Switch to the =org-mode= buffer and use {{{kbd(C-c C-l)}}} to insert the
=org-link= into the buffer.
2023-01-12 21:28:18 +01:00
Listing [[lst:set-dired-options ]] makes the directory editor sort entries
2022-02-05 14:04:41 +01:00
alphabetically after grouping the directories before grouping the files by
extension.
2023-01-12 21:28:18 +01:00
#+caption[Set =dired= options]:
#+caption : Set =dired= options.
#+name : lst:set-dired-options
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'dired
2023-01-12 21:28:18 +01:00
(setopt dired-dwim-target t
;; | switch | action |
;; |--------+----------------------------------------|
;; | -a | also list hidden entries |
;; | -l | use a long listing format |
;; | -X | sort alphabetically by entry extension |
;; | -G | skip long listing format group names |
;; | -1 | list one entry per line |
dired-listing-switches "-alGX1 --group-directories-first"
dired-recursive-copies 'always
dired-recursive-deletes 'always))
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'files
2023-01-12 21:28:18 +01:00
;; Ensure the use of `GNU-ls' from `coreutils' on darwin.
(setopt insert-directory-program (or (executable-find "gls")
(executable-find "ls"))))
2022-02-06 13:03:59 +01:00
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'wdired
2023-01-12 21:28:18 +01:00
(setopt wdired-allow-to-change-permissions t))
2022-02-05 14:04:41 +01:00
#+end_src
2022-03-28 09:45:27 +02:00
Listing [[lst:extra-dired-key-bindings ]] adds new key bindings to =dired-mode-map= to:
2022-02-06 13:03:59 +01:00
1. Open files with the [[https://en.wikipedia.org/wiki/Eww_(web_browser) ][Emacs Web Wowser ]] inside Emacs.
2. Let [[https://en.wikipedia.org/wiki/Rsync ][rsync ]] copy marked files outside Emacs to a local or remote directory.
The link [[https://truongtx.me/tmtxt-dired-async.html ][asynchoronous execution library for Emacs Dired ]] is the original source
for the idea of using [[https://en.wikipedia.org/wiki/Rsync ][rsync ]] and the blog articles [[https://oremacs.com/2016/02/24/dired-rsync/ ][using rsync in dired ]] and
[[https://vxlabs.com/2018/03/30/asynchronous-rsync-with-emacs-dired-and-tramp/ ][asynchronous rsync with Emacs, dired and tramp ]] are vivid recommendations written
by experienced Emacs users.
#+caption[Extra =dired= key bindings]:
#+caption : Extra =dired= key bindings.
#+name : lst:extra-dired-key-bindings
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'dired
(defun dired-eww-open-file ()
"In Dired, open the regular file named on this line with eww"
(interactive)
(let ((file (dired-get-file-for-visit)))
(if (file-regular-p file)
(eww-open-file file)
(error "Eww rejects `%s', since it is not a regular file" file))))
;; https://truongtx.me/tmtxt-dired-async.html
(defun dired-rsync (target)
"Copy marked files with `rsync' to TARGET directory."
(interactive
(list (expand-file-name
(read-file-name "Rsync to:" (dired-dwim-target-directory)))))
;; Store all marked files into the `files' list and intialize
;; the `rsync-command'.
(let ((files (dired-get-marked-files nil current-prefix-arg))
(rsync-command "rsync -av --progress "))
;; Add all marked files as arguments to the `rsync-command'.
(dolist (file files)
2022-05-03 09:34:20 +02:00
(setq rsync-command
(concat rsync-command
2022-11-07 11:50:17 +01:00
(if (string-match "^/ssh:\\(.*\\)$" file)
(format " -e ssh %s" (match-string 1 file))
(shell-quote-argument file)) " ")))
;; Append the destination directory to the `rsync-command'.
(setq rsync-command
(concat rsync-command
(if (string-match "^/ssh:\\(.*\\)$" target)
(format " -e ssh %s" (match-string 1 target))
(shell-quote-argument target))))
;; Run the async shell command.
(async-shell-command rsync-command)
;; Finally, switch to that window.
(other-window 1)))
2023-02-26 14:37:33 +01:00
(keymap-set dired-mode-map "E" #'dired-eww-open-file)
(keymap-set dired-mode-map "Y" #'dired-rsync))
2022-02-06 13:03:59 +01:00
#+end_src
2022-02-13 15:09:26 +01:00
2022-12-12 08:09:19 +01:00
* [[info:emacs#Completion Styles][Minibuffer completion styles (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:minibuffer-completion-styles
:END:
2023-01-12 21:28:18 +01:00
Listing [[lst:set-minibuffer-options ][set minibuffer options ]] implements ideas of the post [[https://www.masteringemacs.org/article/understanding-minibuffer-completion][Understanding
minibuffer completion]].
2022-12-12 08:09:19 +01:00
2023-01-12 21:28:18 +01:00
#+caption[Set =minibuffer= options]:
#+caption : Set =minibuffer= options.
#+name : lst:set-minibuffer-options
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-12-12 08:09:19 +01:00
(when (require 'minibuffer nil 'noerror)
;; https://www.masteringemacs.org/article/understanding-minibuffer-completion
2023-01-12 21:28:18 +01:00
(setopt
completion-category-overrides '((file (styles basic substring)))
completion-ignore-case nil
completion-styles '(basic flex partial-completion substring)))
2022-12-12 08:09:19 +01:00
#+end_src
2022-05-21 12:50:47 +02:00
* [[info:elisp#Processes][Processes (info)]]
2022-02-13 15:09:26 +01:00
:PROPERTIES:
:CUSTOM_ID: sec:processes
:END:
Listing [[lst:process-utilities ]] defines a function to run a (command-line) program
with arguments and to obtain a list with its numeric exit status as well as its
output to =stdout= .
#+caption[Process utilities]:
#+caption : Process utilities.
#+name : lst:process-utilities
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
;; https://gitlab.com/howardabrams/spacemacs.d/blob/master/layers/ha-org/funcs.el#L418
(defun shell-command-with-exit-code (program &rest args)
"Run PROGRAM with ARGS and return exit-code and output in a list."
(with-temp-buffer
(list (apply 'call-process program nil (current-buffer) nil args)
2023-02-26 10:01:26 +01:00
(buffer-substring-no-properties (point-min) (point-max)))))
2022-02-13 15:09:26 +01:00
#+end_src
2022-04-17 17:45:42 +02:00
* [[info:emacs#Help][Help (info)]]
2022-01-06 19:32:36 +01:00
:PROPERTIES:
2022-04-17 17:45:42 +02:00
:CUSTOM_ID: sec:help
:END:
Table [[tab:help-key-bindings ]] lists a number of key bindings to start playing with
2022-09-23 07:33:33 +02:00
the help facilities of Emacs. Try {{{kbd(C-h o)}}} instead of {{{kbd(C-h f)}}}
or {{{kbd(C-h v)}}} .
2022-04-17 17:45:42 +02:00
#+attr_latex : :booktabs yes :float table
#+caption[Help key bindings]:
#+caption : Help key bindings.
#+name : tab:help-key-bindings
2022-07-17 21:05:46 +02:00
|------------------------------+----------+------------------|
| command | key map | keys |
|------------------------------+----------+------------------|
| Info-goto-emacs-command-node | help-map | {{{kbd(C-h F)}}} |
| describe-function | help-map | {{{kbd(C-h f)}}} |
| describe-key | help-map | {{{kbd(C-h k)}}} |
| describe-symbol | help-map | {{{kbd(C-h o)}}} |
| describe-variable | help-map | {{{kbd(C-h v)}}} |
| info | help-map | {{{kbd(C-h i)}}} |
|------------------------------+----------+------------------|
2022-04-17 17:45:42 +02:00
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent :tangle no
2023-01-12 21:28:18 +01:00
(defun org-key-binding-macro (cmd)
(let* ((sym (intern-soft cmd))
(keys (and (commandp sym) (where-is-internal sym nil 'first-only)))
(prefix (seq-take keys (1- (length keys))))
(keymap (key-binding prefix 'accept-default)))
(format "%s %s %s {{{kbd(%s)}}} "
cmd keymap (help--binding-locus keys nil) (key-description keys))))
(org-key-binding-macro 'consult-buffer)
#+end_src
2022-09-02 17:28:15 +02:00
2022-04-17 17:45:42 +02:00
** [[info:emacs#Name Help][Shortdoc-display-group (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:shortdoc-display-group
:END:
Listing [[lst:configure-shortdoc ]] binds {{{kbd(C-h y)}}} to
=short-doc-display-group= and defines a short documentation group for functions
defined in this Org file.
#+caption[Configure =shortdoc= ]:
#+caption : Configure =shortdoc=.
#+name : lst:configure-shortdoc
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(when (fboundp 'shortdoc-display-group)
2023-02-26 14:37:33 +01:00
(keymap-set help-map "y" #'shortdoc-display-group)
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'shortdoc
;; Ensure defining the functions before documenting them.
(define-short-documentation-group init
"Advice"
(advice-toggle :no-manual t)
(toggle-eww-display-pdf-around :no-manual t)
(toggle-ilog-timer-function-after :no-manual t)
(toggle-keycast-log-update-buffer-override :no-manual t)
(toggle-org-babel-python-format-session-value-override :no-manual t)
"Face"
(invert-default-face :no-manual t)
(set-default-face-height :no-manual t)
"Interaction"
(enable-this-command :no-manual t)
(narrow-or-widen-dwim :no-manual t)
(org-narrow-to-table :no-manual t)
"LaTeX"
(biber-delete-cache :no-manual t)
(update-lualatex-opentype-font-name-database :no-manual t)
"Org"
(by-backend :no-manual t)
(by-backend-kbd-org-macro :no-manual t)
(org-active-current-time-stamp :nomanual t)
(org-babel-execute:latex-extra-header :no-manual t)
(org-babel-execute:latex-header :no-manual t)
(org-electric-dollar :no-manual t)
(org-eval-emacs-lisp-setup-blocks :no-manual t)
(org-eval-python-setup-blocks :no-manual t)
(org-eval-infixed-blocks :no-manual t)
(org-latex-engraved-source-block-filter :no-manual t)
(org-inactive-current-time-stamp :nomanual t)
(org-syntax-convert-keyword-case-to-lower :no-manual t)
(smart-latex-engrave-org-source-blocks :no-manual t)
2022-11-09 12:16:59 +01:00
(zero-all-org-src-blocks-indentation :no-manual t)
2022-11-07 11:50:17 +01:00
"Python"
2023-01-10 21:08:55 +01:00
(choose-common-python-interpreter :no-manual t)
(choose-common-python-linter :no-manual t))))
2022-04-17 17:45:42 +02:00
#+end_src
** [[info:info#Top][Info (info)]]
:PROPERTIES:
2022-04-20 05:34:35 +02:00
:CUSTOM_ID: sec:info
2022-01-06 19:32:36 +01:00
:END:
2022-09-02 17:28:15 +02:00
Listing [[lst:configure-info ]] adds the required paths to the places where =info=
looks for files.
2022-01-06 19:32:36 +01:00
#+caption[Configure =info= ]:
#+caption : Configure =info=.
#+name : lst:configure-info
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'info
2022-12-10 16:56:54 +01:00
;; Make Emacs find ALL "*.info" files in `package-user-dir' on Gentoo Linux.
(when (eq system-type 'gnu/linux)
(dolist (path
(nreverse
(mapcar
(lambda (name)
(expand-file-name (file-name-directory name)))
(directory-files-recursively package-user-dir "\\.info\\'"))))
(add-to-list 'Info-directory-list path nil #'file-equal-p)))
2022-11-07 11:50:17 +01:00
;; Make Emacs find my "python.info" file.
(add-to-list 'Info-directory-list
(expand-file-name "~/.local/share/info")))
2022-01-06 19:32:36 +01:00
#+end_src
2022-01-18 07:26:09 +01:00
* [[info:emacs#Key Bindings][Key bindings (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:key-bindings
:END:
2022-03-28 09:46:04 +02:00
#+attr_latex : :booktabs yes :float table
2022-04-17 17:45:42 +02:00
#+caption[Basic key bindings]:
#+caption : Basic key bindings.
#+name : tab:basic-key-bindings
2022-07-17 21:05:46 +02:00
|--------------------+------------+------------------------|
| command | key map | keys |
|--------------------+------------+------------------------|
| undo | global-map | {{{kbd(s-z)}}} |
| backward-kill-word | global-map | {{{kbd(C-backspace)}}} |
| backward-char | global-map | {{{kbd(C-b)}}} |
| forward-char | global-map | {{{kbd(C-f)}}} |
| backward-word | global-map | {{{kbd(M-b)}}} |
| forward-word | global-map | {{{kbd(M-f)}}} |
| backward-sentence | global-map | {{{kbd(M-a)}}} |
| forward-sentence | global-map | {{{kbd(M-e)}}} |
|--------------------+------------+------------------------|
2022-03-28 09:46:04 +02:00
2022-01-18 07:26:09 +01:00
** [[info:emacs#Disabling][Disabling Commands (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:enable-disabled-commands
:END:
Execute src_emacs-lisp{(find-library "novice")} to see how Emacs prevents new
users from shooting themselves in the feet. Listing
[[lst:configure-disabled-command-function ]] enables [[https://www.emacswiki.org/emacs/DisabledCommands ][disabled commands on the fly ]].
#+caption[Configure the =disabled-command-function= ]:
#+caption : Configure the =disabled-command-function=.
#+name : lst:configure-disabled-command-function
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'emacs
(setq disabled-command-function
(defun enable-this-command (&rest _args)
"Called when a disabled command is executed.
Enable it and re-execute it."
(put this-command 'disabled nil)
(message "You typed %s. %s was disabled until now."
(key-description (this-command-keys)) this-command)
(sit-for 0)
(call-interactively this-command))))
2022-01-18 07:26:09 +01:00
#+end_src
2022-05-13 04:00:02 +02:00
** [[https://github.com/michael-heerdegen/interaction-log.el#readme][Interaction-log]]
:PROPERTIES:
:CUSTOM_ID: sec:interaction-log
:END:
#+caption[Configure =interaction-log= ]:
#+caption : Configure =interaction-log=.
#+name : lst:configure-interaction-log
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(when (and (ensure-package-installation 'interaction-log)
(require 'interaction-log nil 'noerror))
2022-05-13 04:00:02 +02:00
2022-11-07 11:50:17 +01:00
;; https://www.skybert.net/emacs/show-shortcuts-when-giving-presentations/
(defun ilog-ensure-ilog-buffer-window ()
"Ensure the visibility of the `ilog' buffer, when it exists."
(when (and (get-buffer ilog-buffer-name)
(not (get-buffer-window ilog-buffer-name)))
(display-buffer (get-buffer ilog-buffer-name))))
2022-05-13 04:00:02 +02:00
2023-02-26 14:37:33 +01:00
(keymap-set help-map "C-l" #'interaction-log-mode)
2022-11-07 11:50:17 +01:00
(advice-add 'ilog-timer-function :after #'ilog-ensure-ilog-buffer-window))
2022-05-13 04:00:02 +02:00
#+end_src
** [[https://github.com/tarsius/keycast#readme][Keycast]] :noexport:
2022-05-01 07:29:03 +02:00
:PROPERTIES:
:CUSTOM_ID: sec:keycast
2023-01-01 14:56:22 +01:00
:header-args:emacs-lisp: :tangle no :eval never-export
2022-05-01 07:29:03 +02:00
:END:
Listing [[lst:configure-keycast ]] configures =keycast= .
#+caption[Configure =keycast= ]:
#+caption : Configure =keycast=.
#+name : lst:configure-keycast
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
;; Make `keycast-log-update-buffer' use a buffer similar to the
;; control buffer `ediff-setup-windows-plain' returns.
(when (and (ensure-package-installation 'keycast)
(require 'keycast nil 'noerror))
2023-01-12 21:28:18 +01:00
(setopt keycast-mode-line-window-predicate 'keycast-bottom-right-window-p)
2022-11-07 11:50:17 +01:00
(defun keycast-log-update-buffer-plain ()
(let ((buffer (get-buffer keycast-log-buffer-name)))
(unless (buffer-live-p buffer)
(setq buffer (get-buffer-create keycast-log-buffer-name))
(with-current-buffer buffer
(setq buffer-read-only t)))
(unless (get-buffer-window buffer)
(display-buffer buffer '(display-buffer-at-bottom
(dedicated . t)
(window-height . 10))))
(when-let ((output (keycast--format keycast-log-format)))
(with-current-buffer buffer
(goto-char (if keycast-log-newest-first (point-min) (point-max)))
(let ((inhibit-read-only t))
(when (and (> keycast--command-repetitions 0)
(string-match-p "%[rR]" keycast-log-format))
(unless keycast-log-newest-first
(backward-char))
(ignore-errors
(delete-region (line-beginning-position)
(1+ (line-end-position)))))
(insert output))
(goto-char (if keycast-log-newest-first (point-min) (point-max)))))))
(advice-add 'keycast-log-update-buffer
:override #'keycast-log-update-buffer-plain))
2022-05-01 07:29:03 +02:00
#+end_src
2021-12-05 16:39:07 +01:00
* [[info:emacs#Emacs Server][Using Emacs as a server (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:using-emacs-server
:END:
2021-11-29 13:14:56 +01:00
Emacs can act as a server that listens to a socket to share its state (for
instance buffers and command history) with other programs by means of a shell
2021-12-23 15:29:03 +01:00
command =emacsclient= . Section [[#sec:latexmk-save-compile-display-loop ]] and
[[#sec:qutebrowser-userscript ]] show how to use ~emacsclient~ to:
1. Install an asynchronous (or background) loop of saving a LaTeX file,
compiling it, and redisplaying the output in Emacs.
2. Make [[https://qutebrowser.org ][qutebrowser ]] send html links with document titles to Emacs.
The code in listing [[lst:start-emacs-server ]] starts the Emacs server.
2021-11-29 13:14:56 +01:00
2021-12-23 15:29:03 +01:00
#+caption[Start the Emacs server]:
#+caption : Start the Emacs server.
2021-12-28 08:48:03 +01:00
#+name : lst:start-emacs-server
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(when window-system
(unless (or noninteractive (daemonp))
(add-hook 'after-init-hook #'server-start)))
2021-11-29 13:14:56 +01:00
#+end_src
2021-12-23 15:29:03 +01:00
** Latexmk save-compile-display loop
2021-11-29 13:14:56 +01:00
:PROPERTIES:
2021-12-23 15:29:03 +01:00
:CUSTOM_ID: sec:latexmk-save-compile-display-loop
2021-11-29 13:14:56 +01:00
:END:
The =latexmk= resource file in the next source code block shows how to use
2023-01-12 21:28:18 +01:00
=emacsclient= to (re)display the PDF file in Emacs after each successful
(re)compilation on condition that the local ~compile-command~ variable is
correct. The local ~compile-command~ variable in the [[#sec:local-variables ][local variables ]] section
(only visible in =org= files, but not in =html= and =pdf= files) shows how to
make use of the =latexmkrc= file.
2021-11-29 13:14:56 +01:00
2022-01-12 20:19:22 +01:00
#+attr_latex : :options breaklines
2022-08-21 13:48:09 +02:00
#+caption[Tangle the =Latexmk= resource file]:
#+caption : Tangle the =Latexmk= resource file.
2021-12-28 08:48:03 +01:00
#+name : lst:latexmkrc
2023-01-24 07:41:16 +01:00
#+begin_src perl -n :tangle latexmkrc :comments no
2022-11-07 11:50:17 +01:00
# pdf creator
$pdf_mode = 4; # 4 means lualatex
# pdf previewer and update pdf previewer
$pdf_previewer = "emacsclient -e '(find-file-other-window %S)'";
$pdf_update_method = 4; # 4 runs $pdf_update_command to force the update
$pdf_update_command = "emacsclient -e '(with-current-buffer (find-buffer-visiting %S) (pdf-view-revert-buffer nil t))'";
# see for instance glossary.latexmkrc
add_cus_dep( 'acn', 'acr', 0, 'makeglossaries' );
add_cus_dep( 'glo', 'gls', 0, 'makeglossaries' );
# use ".=" to append to $clean_ext
$clean_ext .= " acr acn alg bbl dvi glo gls glg ist lol lst";
$clean_ext .= " nav run.xml snm synctex.gz";
sub makeglossaries {
my ($name, $path) = fileparse( $$Psource );
return system "makeglossaries -d '$path' '$name'";
}
# Emacs looks for "Local variables:" after the last "newline-formfeed".
# Local Variables:
# mode: perl
# End:
2021-11-29 13:14:56 +01:00
#+end_src
2021-11-30 09:35:15 +01:00
** [[https://qutebrowser.org/doc/userscripts.html][Qutebrowser userscript]]
2021-12-05 16:39:07 +01:00
:PROPERTIES:
:CUSTOM_ID: sec:qutebrowser-userscript
:END:
2021-11-29 13:14:56 +01:00
The next block contains an userscript that sends a [[info:org#The store-link protocol ][store-link org-protocol ]]
message with the url and the title from [[https://qutebrowser.org ][qutebrowser ]] to =emacsclient= . The
function =urlencode= translates the url and the title for the message. The
[[info:python#Examples<22> ][Python urllib examples ]] show how to use =urlencode= . The final =execvp= call
deals with a [[https://qutebrowser.org ][qutebrowser ]] userscript requirement: the =emacsclient= process must
get the PID of the userscript that must kill itself after the take-over.
Termination of the =emacsclient= process hands control back to [[https://qutebrowser.org ][qutebrowser ]].
On a [[https://en.wikipedia.org/wiki/POSIX ][POSIX ]] system, you can run the userscript from [[https://qutebrowser.org ][qutebrowser ]] or from a
terminal to see whether it works. In case you try to run it from Emacs, Emacs
may hang or die.
2021-12-23 15:29:03 +01:00
#+caption[Tangle a qutebrowser userscript]:
#+caption : Tangle a qutebrowser userscript.
2022-11-04 07:08:38 +01:00
#+header : :comments no
2021-11-29 13:14:56 +01:00
#+header : :tangle-mode (identity #o755)
2021-12-28 08:48:03 +01:00
#+name : lst:qutebrowser-userscript
2023-01-24 07:41:16 +01:00
#+begin_src python -n :noeval :tangle org-store-link
2022-11-07 11:50:17 +01:00
#!/usr/bin/env python
from urllib.parse import urlencode
from os import environ, execvp
2021-11-29 13:14:56 +01:00
2022-11-07 11:50:17 +01:00
url = environ.get("QUTE_URL", "https://orgmode.org")
title = environ.get("QUTE_TITLE", "Org Mode")
parameters = urlencode({"url": url, "title": title})
print(payload := f"org-protocol://store-link?{parameters}")
execvp("emacsclient", ("-n", payload))
2021-11-29 13:14:56 +01:00
#+end_src
2021-12-08 04:59:07 +01:00
** TODO Look into: org-protocol handling with other browser on Darwin
2022-04-30 12:07:34 +02:00
:PROPERTIES:
:CUSTOM_ID: sec:org-protocol-darwin
:END:
2021-12-08 04:59:07 +01:00
1. [[http://rwx.io/posts/osx-uri-protocol-handler/ ][Patrick Goddi: macOS URI protocol handler ]] and his [[https://github.com/fooqri/uri-handler ][URI-Handler ]].
2. [[https://www.hammerspoon.org/ ][Hammerspoon ]]
3. [[https://vritser.github.io/posts/capture-anywhere/ ][Emacs Capture Anywhere ]]
2022-10-28 06:40:08 +02:00
** [[https://en.wikipedia.org/wiki/AppleScript][AppleScript]] :noexport:
:PROPERTIES:
:CUSTOM_ID: sec:applescript
:header-args:emacs-lisp: :tangle no
:END:
2022-04-30 10:47:17 +02:00
#+caption[Ensure =applescript-mode= installation]:
#+caption : Ensure =applescript-mode= installation.
#+name : lst:ensure-applescript-mode-installation
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(when (ensure-package-installation 'applescript-mode))
2022-04-30 10:47:17 +02:00
#+end_src
2022-04-30 12:07:34 +02:00
#+caption[Applescript code to register =org-protocol= on Darwin]:
#+caption : Applescript code to register =org-protocol= on Darwin.
#+name : lst:applescript-org-protocol
#+begin_src applescript :tangle no
2022-11-07 11:50:17 +01:00
on emacsclient(input)
do shell script "/usr/local/bin/emacsclient -n -c '" & input & "'"
tell application "Emacs" to activate
end emacsclient
on open location input
emacsclient(input)
end open location
on open inputs
repeat with raw_input in inputs
set input to POSIX path of raw_input
2022-04-30 12:07:34 +02:00
emacsclient(input)
2022-11-07 11:50:17 +01:00
end repeat
end open
2022-04-30 12:07:34 +02:00
2022-11-07 11:50:17 +01:00
on run
do shell script emacsclient("")
end run
2022-04-30 12:07:34 +02:00
#+end_src
2021-11-29 13:14:56 +01:00
* Completion
:PROPERTIES:
:CUSTOM_ID: sec:completion
:END:
[[info:vertico#Top ][Vertico (info) ]] provides a performant and minimalistic vertical completion UI
based on the default completion system and behaves therefore correctly under all
2021-12-05 16:40:20 +01:00
circumstances. [[https://cestlaz.github.io/post/using-emacs-80-vertico/ ][Using Vertico, Marginalia, Consult, and Embark ]] links to a video
demonstration. Vertico integrates well with fully supported complementary
2021-11-29 13:14:56 +01:00
packages to enrich the completion UI:
2022-10-27 07:06:55 +02:00
1. [[info:embark#Top ][Embark (info) ]] for minibuffer actions with context menus,
2. [[info:marginalia#Top ][Marginalia (info) ]] for rich annotations in the minibuffer, and
3. [[info:consult#Top ][Consult (info) ]] for useful search and navigation commands,
2021-12-05 16:40:20 +01:00
where the order is that of [[https://github.com/bdarcus/citar#installation ][enhancing citar's experience ]] and the configuration
steps below.
2021-11-29 13:14:56 +01:00
2021-12-23 15:29:03 +01:00
Finally, [[https://company-mode.github.io/ ][company: a modular complete-anything framework for Emacs ]] provides
2022-12-12 08:09:19 +01:00
completion in any buffer.
2021-11-29 13:14:56 +01:00
2023-01-06 20:45:02 +01:00
** [[info:company#Top][Company (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:company
:END:
[[info:company#Top ][Company (info) ]] is a modular completion framework and the the snippet [[lst:ensure-company-installation ][below ]]
ensures its installation.
#+caption[Ensure =company= installation]:
#+caption : Ensure =company= installation.
#+name : lst:ensure-company-installation
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2023-01-06 20:45:02 +01:00
(ensure-package-installation 'company)
#+end_src
2021-12-05 16:40:20 +01:00
** [[info:vertico#Top][Vertico (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:vertico-configuration
:END:
2021-11-29 13:14:56 +01:00
2021-12-23 15:29:03 +01:00
Listing [[lst:enable-vertico-mode ]] configures and enables =savehist-mode= and
enables =vertico-mode= . The documentation src_emacs-lisp{(describe-function
'savehist-mode)} why it is best to turn on =savehist-mode= in the Emacs init
file.
#+caption[Enable =savehist-mode= and =vertico-mode= ]:
#+caption : Enable =savehist-mode= and =vertico-mode=.
2021-12-28 08:48:03 +01:00
#+name : lst:enable-vertico-mode
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2023-01-12 21:28:18 +01:00
(when (require 'savehist nil 'noerror)
(setopt savehist-additional-variables '(eww-history
kill-ring
regexp-search-string
search-ring
search-string))
2022-12-10 13:31:06 +01:00
(savehist-mode +1))
2023-01-06 20:45:02 +01:00
(when (and (ensure-package-installation 'vertico)
(fboundp 'vertico-mode))
2022-11-07 11:50:17 +01:00
(vertico-mode +1))
(with-eval-after-load 'vertico
2023-02-26 14:37:33 +01:00
(keymap-set vertico-map "RET" #'vertico-directory-enter)
(keymap-set vertico-map "DEL" #'vertico-directory-delete-char)
(keymap-set vertico-map "M-DEL" #'vertico-directory-delete-word))
2021-11-29 13:14:56 +01:00
#+end_src
2022-01-10 08:47:45 +01:00
#+attr_latex : :booktabs yes :float table
#+caption[Vertico key map bindings]:
#+caption : Vertico key map bindings.
#+name : tab:vertico-keymap-bindings
2022-07-17 21:05:46 +02:00
|-------------------------------+----------------------------------+---------------------|
| command | remap | keys |
|-------------------------------+----------------------------------+---------------------|
| vertico-directory-delete-char | | {{{kbd(DEL)}}} |
| vertico-directory-delete-word | | {{{kbd(M-DEL)}}} |
| vertico-directory-enter | | {{{kbd(RET)}}} |
| vertico-exit | exit-minibuffer | {{{kbd(C-j)}}} |
| vertico-exit-input | | {{{kbd(C-RET)}}} |
| vertico-first | beginning-of-buffer | {{{kbd(M-<)}}} |
| vertico-first | minibuffer-beginning-of-buffer | {{{kbd(M-<)}}} |
| vertico-insert | | {{{kbd(TAB)}}} |
| vertico-last | end-of-buffer | {{{kbd(M->)}}} |
| vertico-next-group | forward-paragraph | {{{kbd(C-<down>)}}} |
| vertico-next | next-line-or-history-element | {{{kbd(<down>)}}} |
| vertico-next | next-line | {{{kbd(C-n)}}} |
| vertico-previous-group | backward-paragraph | {{{kbd(C-<up>)}}} |
| vertico-previous | previous-line-or-history-element | {{{kbd(<up>)}}} |
| vertico-previous | previous-line | {{{kbd(C-p)}}} |
| vertico-save | kill-ring-save | {{{kbd(M-w)}}} |
| vertico-scroll-down | scroll-down-command | {{{kbd(M-v)}}} |
| vertico-scroll-up | scroll-up-command | {{{kbd(C-v)}}} |
|-------------------------------+----------------------------------+---------------------|
2022-01-10 08:47:45 +01:00
2022-10-27 00:50:24 +02:00
** [[info:orderless#Top][Orderless (info)]] :noexport:
2021-12-05 16:40:20 +01:00
:PROPERTIES:
:CUSTOM_ID: sec:orderless-configuration
2022-10-27 00:50:24 +02:00
:header-args:emacs-lisp: :tangle no
2021-12-05 16:40:20 +01:00
:END:
2022-10-27 19:31:48 +02:00
Listing [[lst:configure-orderless ]] configures [[info:orderless#Company ][orderless for company (info) ]]. Note:
*Python editing is orders of magnitude faster after removal of Orderless* .
2021-12-23 15:29:03 +01:00
#+caption[Configure =orderless= ]:
#+caption : Configure =orderless=.
2021-12-28 08:48:03 +01:00
#+name : lst:configure-orderless
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(when (ensure-package-installation 'marginalia)
(with-eval-after-load 'orderless
2023-01-12 21:28:18 +01:00
(setopt orderless-component-separator " +")
2022-04-17 21:04:03 +02:00
2022-11-07 11:50:17 +01:00
(defun just-one-face (fn &rest args)
(let ((orderless-match-faces [completions-common-part]))
(apply fn args)))
2022-04-17 21:04:03 +02:00
2022-11-07 11:50:17 +01:00
(advice-add 'company-capf--candidates :around #'just-one-face)))
2021-12-05 16:40:20 +01:00
#+end_src
2021-12-29 10:05:06 +01:00
** [[info:embark#Top][Embark (info)]]
2021-12-05 16:40:20 +01:00
:PROPERTIES:
:CUSTOM_ID: sec:embark-configuration
:END:
2023-01-12 21:28:18 +01:00
Listing [[lst:bind-embark-commands ][bind =embark= commands ]] binds =embark= commands to the global key map:
2022-04-20 06:10:56 +02:00
1. =embark-act= prompts the user for an action and performs it.
2. Except for highlighting of email and web URLs, =embark-dwim= englobes the
2022-04-20 05:35:28 +02:00
functionality of src_emacs-lisp{(find-library "goto-addr")} that activates
mail and web URLs to turn them into clickable buttons. Since =embark-dwim=
acts on a superset of target types, it renders =goto-addr= superfluous. See:
1. [[info:emacs#Goto Address mode ][Goto Address mode (info) ]].
2. [[info:embark#The default action on a target ][The default (embark-dwim) action on a target (info) ]].
2022-04-20 06:10:56 +02:00
3. =embark-bindings= allows to explore all current command key bindings in the
minibuffer.
4. The initialization src_emacs-lisp{(setq prefix-help-command
#'embark-prefix-help-command)} enables minibuffer help after a prefix key
(for instance {{{kbd(C-x)}}} or {{{kbd(C-c)}}} ) as typing {{{kbd(C-x C-h)}}}
or {{{kbd(C-c C-h)}}} shows.
2021-12-23 15:29:03 +01:00
2023-01-12 21:28:18 +01:00
#+caption[Bind =embark= commands globally]:
#+caption : Bind =embark= commands globally.
#+name : lst:bind-embark-commands
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-16 07:33:17 +01:00
(when (ensure-package-installation 'embark 'embark-consult)
2022-11-07 11:50:17 +01:00
(when (fboundp 'embark-act)
2023-02-26 14:37:33 +01:00
(keymap-global-set "C-," #'embark-act))
2022-11-07 11:50:17 +01:00
(when (fboundp 'embark-dwim)
2023-02-26 14:37:33 +01:00
(keymap-global-set "C-:" #'embark-dwim))
2022-11-07 11:50:17 +01:00
(when (fboundp 'embark-bindings)
2023-02-26 14:37:33 +01:00
(keymap-global-set "C-h B" #'embark-bindings))
2022-11-07 11:50:17 +01:00
(when (fboundp 'embark-prefix-help-command)
(setq prefix-help-command #'embark-prefix-help-command)))
2021-12-05 16:40:20 +01:00
#+end_src
** [[info:marginalia#Top][Marginalia (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:marginalia-configuration
:END:
2021-11-29 13:14:56 +01:00
2021-12-23 15:29:03 +01:00
Listing [[lst:enable-marginalia-mode ]] enables =marginalia-mode= .
#+caption[Enable =marginalia-mode= ]:
#+caption : Enable =marginalia-mode=.
2021-12-28 08:48:03 +01:00
#+name : lst:enable-marginalia-mode
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(when (and (ensure-package-installation 'marginalia)
(fboundp 'marginalia-mode))
(marginalia-mode +1))
2021-11-29 13:14:56 +01:00
#+end_src
2021-12-05 16:40:20 +01:00
** [[info:consult#Top][Consult (info)]]
:PROPERTIES:
2023-01-12 21:28:18 +01:00
:CUSTOM_ID: sec:consult-setup
2021-12-05 16:40:20 +01:00
:END:
2021-11-29 13:14:56 +01:00
2023-01-12 21:28:18 +01:00
[[info:consult#Top ][Consult (info) ]] provides practical commands based on the Emacs minibuffer
completion function [[info:elisp#Minibuffer Completion ][completing-read ]]. Listing [[lst:bind-consult-commands ][bind =consult= commands ]] binds
=consult= commands to different key maps.
2021-12-23 15:29:03 +01:00
2021-12-28 08:38:29 +01:00
#+attr_latex : :booktabs yes :float table
2022-01-10 08:47:45 +01:00
#+caption[Configuration specific key bindings]:
2021-12-28 08:38:29 +01:00
#+caption : Configuration specific key-bindings.
#+name : tab:configuration-specific-key-bindings
2023-02-15 06:44:36 +01:00
|-----------------------------+----------------------+--------------------|
| command | key map | keys |
|-----------------------------+----------------------+--------------------|
| consult-bookmark | ctl-x-r-keymap | {{{kbd(C-x r b)}}} |
| consult-buffer-other-frame | ctl-x-5-keymap | {{{kbd(C-x 5 b)}}} |
| consult-buffer-other-window | ctl-x-4-keymap | {{{kbd(C-x 4 b)}}} |
| consult-buffer | ctl-x-keymap | {{{kbd(C-x b)}}} |
| consult-compile-error | goto-map | {{{kbd(M-g e)}}} |
| consult-complex-command | ctl-x-keymap | {{{kbd(C-x M-:)}}} |
| consult-find | search-map | {{{kbd(M-s f)}}} |
| consult-focus-lines | search-map | {{{kbd(M-s u)}}} |
| consult-git-grep | search-map | {{{kbd(M-s g)}}} |
| consult-global-mark | goto-map | {{{kbd(M-g k)}}} |
| consult-goto-line | goto-map | {{{kbd(M-g M-g)}}} |
| consult-goto-line | goto-map | {{{kbd(M-g g)}}} |
| consult-history | global-map | {{{kbd(C-c h)}}} |
| consult-imenu | goto-map | {{{kbd(M-g i)}}} |
| consult-keep-lines | search-map | {{{kbd(M-s k)}}} |
| consult-line | search-map | {{{kbd(M-s l)}}} |
| consult-mark | goto-map | {{{kbd(M-g m)}}} |
| consult-mode-command | global-map | {{{kbd(C-c m)}}} |
| consult-multi-occur | search-map | {{{kbd(M-s m)}}} |
| consult-outline | goto-map | {{{kbd(M-g o)}}} |
| consult-register | ctl-x-r-keymap | {{{kbd(C-x r x)}}} |
| consult-yank-pop | global-map | {{{kbd(M-y)}}} |
|-----------------------------+----------------------+--------------------|
| deadgrep | search-map | {{{kbd(M-s d)}}} |
| elfeed | global-map | {{{kbd(C-x w)}}} |
| embark-act | global-map | {{{kbd(C-\,)}}} |
| embark-bindings | global-map | {{{kbd(C-h B)}}} |
| embark-dwim | global-map | {{{kbd(C-:)}}} |
| iedit-mode | global-map | {{{kbd(C-;)}}} |
| minibuffer-complete-history | minibuffer-local-map | {{{kbd(C-<tab>)}}} |
| narrow-or-widen-dwim | ctl-x-keymap | {{{kbd(C-x C-n)}}} |
| org-agenda | global-map | {{{kbd(C-c a)}}} |
| org-capture | global-map | {{{kbd(C-c c)}}} |
| org-cite | org-mode-map | {{{kbd(C-c b)}}} |
| org-insert-link-global | global-map | {{{kbd(C-c C-l)}}} |
| org-narrow-to-table | ctl-x-keymap | {{{kbd(C-x n t)}}} |
| org-store-link | global-map | {{{kbd(C-c l)}}} |
|-----------------------------+----------------------+--------------------|
2021-12-28 08:38:29 +01:00
2023-01-12 21:28:18 +01:00
#+caption[Bind =consult= commands]:
#+caption : Bind =consult= commands.
#+name : lst:bind-consult-commands
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(when (ensure-package-installation 'consult)
;; C-c bindings (current-global-map)
2023-02-26 14:37:33 +01:00
(keymap-global-set "C-c h" #'consult-history)
(keymap-global-set "C-c m" #'consult-mode-command)
2022-11-07 11:50:17 +01:00
;; C-x bindings (ctl-x-map)
2023-02-26 14:37:33 +01:00
(keymap-set ctl-x-map "M-:" #'consult-complex-command)
(keymap-set ctl-x-map "b" #'consult-buffer)
(keymap-set ctl-x-4-map "b" #'consult-buffer-other-window)
(keymap-set ctl-x-5-map "b" #'consult-buffer-other-frame)
(keymap-set ctl-x-r-map "x" #'consult-register)
(keymap-set ctl-x-r-map "b" #'consult-bookmark)
2022-11-07 11:50:17 +01:00
;; M-g bindings (goto-map)
2023-02-26 14:37:33 +01:00
(keymap-set goto-map "g" #'consult-goto-line)
(keymap-set goto-map "M-g" #'consult-goto-line)
(keymap-set goto-map "o" #'consult-outline)
(keymap-set goto-map "m" #'consult-mark)
(keymap-set goto-map "k" #'consult-global-mark)
(keymap-set goto-map "i" #'consult-imenu)
(keymap-set goto-map "e" #'consult-compile-error)
2022-11-07 11:50:17 +01:00
;; M-s bindings (search-map)
2023-02-26 14:37:33 +01:00
(keymap-set search-map "g" #'consult-git-grep)
(keymap-set search-map "f" #'consult-find)
(keymap-set search-map "k" #'consult-keep-lines)
(keymap-set search-map "l" #'consult-line)
(keymap-set search-map "m" #'consult-multi-occur)
(keymap-set search-map "u" #'consult-focus-lines)
2022-11-07 11:50:17 +01:00
;; Other bindings (current-global-map)
2023-02-26 14:37:33 +01:00
(keymap-global-set "M-y" #'consult-yank-pop))
2021-11-29 13:14:56 +01:00
#+end_src
2021-12-05 16:40:20 +01:00
** [[https://company-mode.github.io/][Company: a modular complete anything framework for Emacs]]
:PROPERTIES:
2023-01-12 21:28:18 +01:00
:CUSTOM_ID: sec:company-setup
2021-12-05 16:40:20 +01:00
:END:
2021-11-29 13:14:56 +01:00
2023-01-12 21:28:18 +01:00
Listing [[lst:setup-company ]] configures =company= .
2021-12-23 15:29:03 +01:00
2023-01-12 21:28:18 +01:00
#+caption[Setup =company= ]:
#+caption : Setup =company=.
#+name : lst:setup-company
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(when (fboundp 'company-mode)
2023-01-12 21:28:18 +01:00
;; https://github.com/purcell/emacs.d/issues/778
(setopt company-transformers '(company-sort-by-occurrence))
2022-11-07 11:50:17 +01:00
(dolist (hook '(LaTeX-mode-hook
org-mode-hook
emacs-lisp-mode-hook
lisp-interaction-mode-hook
lisp-mode-hook
python-mode-hook
ielm-mode-hook
sly-mrepl-mode-hook))
(add-hook hook #'company-mode)))
2021-11-29 13:14:56 +01:00
#+end_src
2022-02-27 14:13:45 +01:00
* [[info:emacs#Search][Search and replace (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:search-replace
:END:
2022-09-11 07:37:26 +02:00
** [[info:emacs#Regexp Replace][Regexp Replace (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:regexp-replace
:END:
Executing {{{kbd(M-x replace-regexp)}}} prompts fo a regular expression =REGEXP=
and a substitution =NEWSTRING= to replace =REGEXP= with =NEWSTRING= . The tools
in section [[#sec:narrowing ][Narrowing ]] allow to limit the scope of {{{kbd(M-x replace-regexp)}}} .
A list pointing to relevant documentation is:
1. [[info:emacs#Regexp Replace ][Regexp Replace (info) ]] explains how the substitution handles references to
regular expression groups and lisp expressions.
2. [[info:emacs#Regexps ][Syntax of Regular Expressions (info) ]] describes regular expression features
for users.
3. [[info:elisp#Regular Expressions ][Emacs Lisp Regular Expressions (info) ]] describes regular expression features
for programmers.
4. [[https://www.emacswiki.org/ ][Emacs Wiki ]] has an article on [[https://www.emacswiki.org/emacs/ReplaceRegexpWithLispExpressions ][replacing regexp with lisp expressions ]].
Table [[tab:replace-regexp-tranform ]] tabulates how to perfom example tasks by means
of {{{kbd(M-x replace-regexp)}}} using =(regular-expression transform)= pairs.
#+attr_latex : :booktabs yes :float table
#+caption[Example =replace-regexp= (regular-expression substitution) pairs]:
#+caption : Example =replace-regexp= (regular-expression substitution) pairs.
#+name : tab:replace-regexp-tranform
| task | regular expression | substitution |
|-----------------------------+---------------------------------+---------------|
| move dot two digits forward | =0\.\([[:digit:]][[:digit:]]\)= | =0\1.= |
| move dot two digits forward | =0\.\([0-9][0-9]\)= | =0\1.= |
| renumber grep/occur matches | =\(.+:\)= | =\,(1+ \#)._= |
|-----------------------------+---------------------------------+---------------|
2022-02-27 14:13:45 +01:00
** [[https://github.com/Wilfred/deadgrep#readme][Deadgrep]]
:PROPERTIES:
:CUSTOM_ID: sec:deadgrep
:END:
[[https://github.com/Wilfred/deadgrep#readme ][Deadgrep ]] uses [[https://github.com/BurntSushi/ripgrep#readme ][ripgrep ]] for superfast text searching in the default directory or
2023-01-12 21:28:18 +01:00
the current [[https://en.wikipedia.org/wiki/Version_control ][VCS ]] directory tree. Listing [[lst:bind-deadgrep-commands ][setup =deadgrep= commands ]] binds
=deadgrep= globally to {{{kbd(M-s d)}}} and =deadgrep-edit-mode= locally to
{{{kbd(C-c C-w)}}} .
2022-02-27 14:13:45 +01:00
2023-01-12 21:28:18 +01:00
#+caption[Bind =deadgrep= commands]:
#+caption : Bind =deadgrep= commands.
#+name : lst:bind-deadgrep-commands
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(when (and (ensure-package-installation 'deadgrep)
(fboundp 'deadgrep))
2023-02-26 14:37:33 +01:00
(keymap-set search-map "d" #'deadgrep)
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'deadgrep
2023-02-26 14:37:33 +01:00
(keymap-set deadgrep-mode-map "C-c C-w" #'deadgrep-edit-mode)))
2022-02-27 14:13:45 +01:00
#+end_src
2022-08-10 06:49:55 +02:00
** [[https://www.genivia.com/get-ugrep.html][Ugrep]]
:PROPERTIES:
:CUSTOM_ID: sec:ugrep
:END:
[[https://www.genivia.com/get-ugrep.html ][Ugrep ]] is an ultra fast grep with interactive query UI and fuzzy search. The
pages [[https://github.com/Genivia/ugrep#emacs ][Using ugrep within Emacs ]] and [[https://manueluberti.eu/emacs/2022/08/07/emacs-ugrep/ ][Ugrep in Emacs ]] show how to make Emacs use it
2023-01-12 21:28:18 +01:00
with [[info:emacs#Grep Searching ][lgrep ]] and [[info:emacs#Xref ][xref ]]. Listing [[lst:set-grep+xref-options ][set =grep= and =xref= options ]] shows my
implementation of the suggestions on those pages.
2022-08-10 06:49:55 +02:00
2023-01-12 21:28:18 +01:00
#+caption[Set =grep= and =xref= options to use =ugrep= when available]:
#+caption : Set =grep= and =xref= options to use =ugrep= when available.
#+name : lst:set-grep+xref-options
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(when (executable-find "ugrep")
(with-eval-after-load 'grep
2023-01-12 21:28:18 +01:00
(setopt grep-template (string-join '("ugrep"
"--color=always"
"--decompress"
"--ignore-binary"
"--ignore-case"
"--include=\"<F >\""
"--line-number"
"--null"
"--recursive"
"--regexp=<R >")
" ")))
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'xref
2023-01-12 21:28:18 +01:00
(setopt
xref-search-program 'ugrep
xref-search-program-alist
`((grep . "xargs -0 grep <C > --null -snHE -e <R >")
(ripgrep . ,(concat "xargs -0 rg <C > --null -nH"
" --no-heading --no-messages -g '!*/' -e <R >"))
(ugrep . "xargs -0 ugrep <C > --null -ns -e <R >")))))
2022-08-10 06:49:55 +02:00
#+end_src
2023-01-09 13:00:17 +01:00
** [[https://github.com/mattiase/xr#readme][XR - Emacs regexp parser and analyzer]]
:PROPERTIES:
:CUSTOM_ID: sec:ensure-xr-installation
:END:
[[https://github.com/mattiase/xr#readme ][XR ]] converts Emacs regular expressions to the structured =rx= form, thus being an
inverse of =rx= . It can also find mistakes and questionable constructs inside
regexp strings.
#+caption[Ensure =xr= installation]:
#+caption : Ensure =xr= installation.
#+name : lst:ensure-xr-installation
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2023-01-09 13:00:17 +01:00
(when (ensure-package-installation 'xr))
#+end_src
2022-03-28 09:47:05 +02:00
* [[info:emacs#Version Control][Version Control (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:version-control
:END:
** [[info:ediff#Top][Ediff (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:ediff
:END:
Video links to complete the [[info:ediff#Top ][ediff (info) ]] manual are:
1. [[https://www.youtube.com/watch?v=6ZWp05OW1c0 ][Emergency Emacs ]].
2. [[https://protesilaos.com/codelog/2020-04-10-emacs-smerge-ediff/ ][Use =smerge= and =ediff= to resolve file conflicts ]].
2023-01-12 21:28:18 +01:00
Listing [[lst:setup-ediff ]] configures =ediff= to display all its buffers in a
2022-03-28 09:47:05 +02:00
single frame and to make all text visible prior to ediffing Org buffers.
2023-01-12 21:28:18 +01:00
#+caption[Setup =ediff= ]:
#+caption : Setup =ediff=.
#+name : lst:setup-ediff
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'emacs
2023-01-12 21:28:18 +01:00
(setopt ediff-merge-split-window-function #'split-window-horizontally
ediff-split-window-function #'split-window-horizontally
ediff-window-setup-function #'ediff-setup-windows-plain))
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'org
;; https://github.com/oantolin/emacs-config#readme
(defun ediff-with-org-show-all ()
"Expand all headings prior to ediffing org buffers."
2023-01-12 21:28:18 +01:00
(add-hook 'ediff-prepare-buffer-hook #'org-fold-show-all nil t))
2022-11-07 11:50:17 +01:00
(add-hook 'org-mode-hook #'ediff-with-org-show-all))
2022-03-28 09:47:05 +02:00
#+end_src
2022-10-23 10:31:11 +02:00
** [[https://git-scm.com/book/en/v2][Git]]
:PROPERTIES:
:CUSTOM_ID: sec:git
:END:
2022-10-23 14:19:18 +02:00
[[https://www.theserverside.com/blog/Coffee-Talk-Java-News-Stories-and-Opinions/git-push-new-branch-remote-github-gitlab-upstream-example ][How to push new branches to remote repositories on Github or Gitlab ]] explains how
to do this from the command line. Listing
[[lst:forking-and-branching-remote-repositories ]] shows an example work flow of
command line =git= and =nano= invocations. I did yet not figure out how to do
this by means of [[info:magit#Top ][Magit (info) ]]: I still have to understand [[info:magit#Pushing ][Magit pushing (info) ]]
and to figure out how to use src_emacs-lisp{(magit-push-current-to-pushremote)}
or src_emacs-lisp{(magit-push-current-to-upstream)}.
2022-10-23 10:31:11 +02:00
#+caption[Forking and branching on Github or Gitlab]:
#+caption : Forking and branching on Github or Gitlab.
#+name : lst:forking-and-branching-remote-repositories
2023-01-24 07:41:16 +01:00
#+begin_src shell -n :noeval
2022-11-07 11:50:17 +01:00
# Clone the repository
git clone git@github.com:gav451/engrave-faces engrave-faces-fork
cd engrave-face-fork
# Handle 1st branch:
# - Create and switch to a new branch with either:
git switch -c latex-engrave-symbolic-color-names
# or: git checkout -b latex-engrave-symbolic-color-names
# - Use "--set-upstream origin" as a 1st-time branch push:
git push --set-upstream origin latex-engrave-symbolic-color-names
# - Create, add, and commit, and push changes in this branch:
nano engrave-faces-latex.el
git add engrave-faces-latex.el
git commit -m 'Commit latex-engrave-dont-symbolic-color-names changes'
git push
# - Switch to master branch:
git checkout master
# Handle 2nd branch:
# - Create and switch to a new branch with either:
git switch -c latex-engrave-dont-wrap-white-space
# - or: git checkout -b latex-engrave-dont-wrap-white-space
# - Use "--set-upstream origin" as a 1st-time branch push:
git push --set-upstream origin latex-engrave-dont-wrap-white-space
# - Create, add, commit, and push changes in this branch:
nano engrave-faces-latex.el
git add engrave-faces-latex.el
git commit -m 'Commit latex-engrave-dont-wrap-white-space changes'
git push
# - Switch to master branch:
git checkout master
2022-10-23 10:31:11 +02:00
#+end_src
2022-10-23 14:19:18 +02:00
*** [[https://www.theserverside.com/blog/Coffee-Talk-Java-News-Stories-and-Opinions/git-push-new-branch-remote-github-gitlab-upstream-example][List all Git branches]]
:PROPERTIES:
:CUSTOM_ID: sec:list-all-git-branches
:END:
#+caption[List all =git= branches]:
#+caption : List all =git= branches.
#+name : lst:list-all-git-branches
2023-01-24 07:41:16 +01:00
#+begin_src shell -n :exports both :results verbatim
2022-11-07 11:50:17 +01:00
git -C ~/VCS/engrave-faces-fork branch -a
2022-10-23 10:31:11 +02:00
#+end_src
2022-10-23 14:19:18 +02:00
#+RESULTS : lst:list-all-git-branches
2022-11-05 13:30:21 +01:00
: * gav
2022-10-23 10:31:11 +02:00
: latex-engrave-dont-wrap-white-space
: latex-engrave-symbolic-color-names
2022-11-05 13:30:21 +01:00
: master
2022-10-23 10:31:11 +02:00
: remotes/origin/HEAD -> origin/master
2022-11-05 13:30:21 +01:00
: remotes/origin/gav
2022-10-23 10:31:11 +02:00
: remotes/origin/latex-engrave-dont-wrap-white-space
: remotes/origin/latex-engrave-symbolic-color-names
: remotes/origin/master
2023-01-06 20:45:02 +01:00
*** [[info:magit#Top][Magit (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:magit
:END:
[[info:magit#Top ][Magit (info) ]] is an Emacs interface to the version control system [[https://git-scm.com/book/en/v2 ][Git ]] and the
snippet [[lst:ensure-magit-installation ][below ]] ensures its installation.
#+caption[Ensure =Magit= installation]:
#+caption : Ensure =Magit= installation
#+name : lst:ensure-magit-installation
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2023-01-06 20:45:02 +01:00
(ensure-package-installation 'magit)
#+end_src
2021-11-29 13:14:56 +01:00
* Reading
2021-12-23 15:29:03 +01:00
:PROPERTIES:
:CUSTOM_ID: sec:reading
:END:
2022-02-27 14:13:45 +01:00
** Reading [[https://en.wikipedia.org/wiki/DjVu][DjVu]] files
2022-02-27 10:37:22 +01:00
:PROPERTIES:
:CUSTOM_ID: sec:reading-djvu-files
:END:
This setup relies on [[info:emacs#Document View ][Document View (info) ]] to facilitate reading [[https://en.wikipedia.org/wiki/DjVu ][DjVu ]] files.
Reading the code shown by src_emacs-lisp{(find-function
'doc-view-djvu->tiff-converter-ddjvu)} shows that reading [[https://en.wikipedia.org/wiki/DjVu ][DjVu ]] files requires
the command line [[https://en.wikipedia.org/wiki/DjVu ][DjVu ]] decoder =ddjvu= from the [[http://djvu.sourceforge.net/ ][DjVuLibre ]] utilities.
2021-12-23 15:29:03 +01:00
** Reading EPUB files
:PROPERTIES:
:CUSTOM_ID: sec:reading-epub-files
:END:
2021-11-29 13:14:56 +01:00
2022-04-30 18:59:01 +02:00
The package [[https://depp.brause.cc/nov.el/ ][nov.el ]] provides a major mode for reading EPUB files in Emacs.
Listing [[lst:configure-nov ]] configures [[https://depp.brause.cc/nov.el/ ][nov.el ]].
2021-11-29 13:14:56 +01:00
2022-04-30 18:59:01 +02:00
#+caption[Configure =nov= ]:
#+caption : Configure =nov=.
#+name : lst:configure-nov
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(when (and (ensure-package-installation 'nov)
(fboundp 'nov-mode))
(add-to-list 'auto-mode-alist `(,(rx ".epub" eos) . nov-mode)))
2021-11-29 13:14:56 +01:00
#+end_src
2021-12-23 15:29:03 +01:00
** Reading PDF files
:PROPERTIES:
:CUSTOM_ID: sec:reading-pdf-files
:END:
2021-11-29 13:14:56 +01:00
The [[https://github.com/vedang/pdf-tools ][pdf-tools ]] package exploits the [[https://github.com/freedesktop/poppler ][poppler ]] library to render and to let you
annotate [[https://en.wikipedia.org/wiki/PDF ][PDF ]] files. It also exploits the [[https://wiki.contextgarden.net/SyncTeX ][SyncTeX ]] library to link anchors in [[https://en.wikipedia.org/wiki/PDF ][PDF ]]
2022-04-15 07:59:23 +02:00
files produced with LaTeX to the original LaTeX sources. The [[https://github.com/nicolaisingh/saveplace-pdf-view#readme ][saveplace-pdf-view ]]
package saves =pdf-view= and =doc-view= places.
2021-11-29 13:14:56 +01:00
2022-02-17 13:14:51 +01:00
In order to use [[https://github.com/vedang/pdf-tools ][pdf-tools ]], you have to type {{{kbd(M-x pdf-tools-install)}}} after
2021-12-07 08:19:59 +01:00
installation of [[https://github.com/vedang/pdf-tools ][pdf-tools ]] from [[https://melpa.org/ ][MELPA ]] or after each update of [[https://github.com/freedesktop/poppler ][poppler ]] to build or
rebuild the =epdfinfo= executable that serves the [[https://en.wikipedia.org/wiki/PDF ][PDF ]] files to Emacs.
2021-11-29 13:14:56 +01:00
2023-01-12 21:28:18 +01:00
#+caption[Setup =pdf-tools= ]:
#+caption : Setup =pdf-tools=.
#+name : lst:setup-pdf-tools
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(when (and (ensure-package-installation 'pdf-tools 'saveplace-pdf-view)
(fboundp 'pdf-loader-install))
;; `pdf-loader-install' is the lazy equivalent of `pdf-tools-install':
;; see the README file.
(pdf-loader-install)
(with-eval-after-load 'pdf-outline
;; Unmask the `image-save' key binding in `pdf-view-mode-map' and
;; in `image-mode-map' (by parenthood).
2023-02-26 14:37:33 +01:00
(keymap-set pdf-outline-minor-mode-map "o" nil)
(keymap-set pdf-outline-minor-mode-map "O" #'pdf-outline))
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'pdf-view
2023-01-12 21:28:18 +01:00
(setopt pdf-view-display-size 'fit-page
pdf-view-use-scaling (eq system-type 'darwin))
2022-11-07 11:50:17 +01:00
(require 'saveplace-pdf-view nil 'noerror)))
2021-11-29 13:14:56 +01:00
#+end_src
* Writing
2021-12-23 15:29:03 +01:00
:PROPERTIES:
:CUSTOM_ID: sec:writing
:END:
2021-11-29 13:14:56 +01:00
2021-12-23 15:29:03 +01:00
** Writing LaTeX files
:PROPERTIES:
:CUSTOM_ID: sec:writing-latex-files
:END:
2021-11-29 13:14:56 +01:00
Loading =tex.el= immediately instead of lazily ensures proper initialization of
2022-11-05 13:32:57 +01:00
[[https://en.wikipedia.org/wiki/AUCTeX ][AUCTeX ]]. In particular, the ~TeX-master~ safe local variable in the =tex.el=
2021-11-29 13:14:56 +01:00
elisp library file has no autoload cookie. Without prior loading of =tex.el= ,
2021-12-26 11:53:40 +01:00
Emacs will complain that ~TeX-master~ is no safe local variable in case it reads
2022-11-05 13:32:57 +01:00
a LaTeX file that sets ~TeX-master~ . The list below summarizes the main [[https://en.wikipedia.org/wiki/AUCTeX ][AUCTeX ]]
configuration objectives:
2023-01-12 21:28:18 +01:00
1. Listing [[lst:set-tex-options ]] ensures installation of [[https://en.wikipedia.org/wiki/AUCTeX ][AUCTeX ]] and initializes
[[https://en.wikipedia.org/wiki/AUCTeX ][AUCTeX ]] properly for =LuaTeX= or =LuaLaTeX= .
2. Listing [[lst:set-tex-options ]] also enables [[https://git.savannah.gnu.org/cgit/auctex.git/patch/?id=f464242eab092e610dda6b654e6fd197ef649d3eAA ][indenting between square brackets ]]
2022-11-05 13:32:57 +01:00
which is a recent feature.
3. Listing [[lst:update-lualatex-opentype-font-name-database ]] defines a function to
update the =OpenType Font= name database for =LuaLaTeX= when the output of
=LuaLaTeX= shows missing fonts.
2023-01-12 21:28:18 +01:00
4. Listing [[lst:set-bibtex-options ]] configures the Emacs =bibtex= library to use the
2022-11-05 13:32:57 +01:00
LaTeX =BiBTeX= dialect for backwards compatibility.
2023-01-12 21:28:18 +01:00
5. Listing [[lst:set-font-latex-options ]] disables font scaling of section titles.
6. Listing [[lst:set-latex-options ]] configures =latex= for a full featured
2022-11-05 13:32:57 +01:00
=LaTeX-section-command= .
2023-01-12 21:28:18 +01:00
#+caption[Ensure =AUCTeX= installation and set =TeX= option]:
#+caption : Ensure =AUCTeX= installation and set =TeX= option.
#+name : lst:set-tex-options
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2023-01-09 13:00:17 +01:00
(when (ensure-package-installation 'auctex)
;; Use `require' to make `TeX-master' a safe local variable.
(when (require 'tex nil 'noerror)
2023-01-12 21:28:18 +01:00
(setopt
TeX-auto-save t
TeX-engine 'luatex
TeX-indent-close-delimiters "]"
TeX-indent-open-delimiters "["
TeX-install-font-lock #'font-latex-setup
TeX-parse-self t
2023-01-09 13:00:17 +01:00
;; Disable `TeX-electric-math' to prevent collisions with `smartparens'.
2023-01-12 21:28:18 +01:00
TeX-electric-math nil)))
2022-04-22 06:34:58 +02:00
#+end_src
2022-05-08 09:58:53 +02:00
#+caption[Update the =LuaLaTeX OpenType Font= name database]:
#+caption : Update the =LuaLaTeX= =OpenType Font= name database.
#+name : lst:update-lualatex-opentype-font-name-database
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'emacs
(defun update-lualatex-opentype-font-name-database ()
"Update the \"OpenType Font\" name database for \"LuaLaTeX\"."
(interactive)
(cl-destructuring-bind (exit-code output)
(shell-command-with-exit-code
"luaotfload-tool" "-vv" "--update" "--force")
(if (= 0 exit-code)
(message "%s" (string-trim output))
(error "%s" (string-trim output))))))
2022-05-08 09:58:53 +02:00
#+end_src
2023-01-12 21:28:18 +01:00
#+caption[Set =bibtex= options]:
#+caption : Set =bibtex= options.
#+name : lst:set-bibtex-options
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'bibtex
2023-01-12 21:28:18 +01:00
(setopt bibtex-dialect 'BibTeX))
2021-12-23 15:29:03 +01:00
#+end_src
2023-01-12 21:28:18 +01:00
#+caption[Set =font-latex= options]:
#+caption : Set =font-latex= options.
#+name : lst:set-font-latex-options
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'font-latex
2023-01-12 21:28:18 +01:00
(setopt font-latex-fontify-sectioning 1.0))
2021-12-23 15:29:03 +01:00
#+end_src
2023-01-12 21:28:18 +01:00
#+caption[Set =latex= options]:
#+caption : Set =latex= options.
#+name : lst:set-latex-options
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'latex
2023-01-12 21:28:18 +01:00
(setopt LaTeX-electric-left-right-brace t
LaTeX-section-hook '(LaTeX-section-heading
LaTeX-section-title
LaTeX-section-toc
LaTeX-section-section
LaTeX-section-label)))
2021-12-23 15:29:03 +01:00
#+end_src
2022-05-18 07:12:32 +02:00
*** [[https://gitlab.com/matsievskiysv/math-preview/-/blob/master/README.md][Math-preview]]
2022-02-27 10:41:31 +01:00
:PROPERTIES:
:CUSTOM_ID: sec:math-preview
:END:
2022-05-18 07:12:32 +02:00
[[https://gitlab.com/matsievskiysv/math-preview/-/blob/master/README.md ][Math-preview ]] uses [[https://docs.mathjax.org/en/latest/ ][Mathjax-3 ]] to display [[https://www.latex-project.org/ ][LaTeX ]], [[https://www.w3.org/Math/ ][MathML ]],and [[http://asciimath.org/ ][asciimath ]] in Emacs
buffers with help of an external [[https://nodejs.org ][node.js ]] program.
2023-01-12 21:28:18 +01:00
#+caption[Setup =math-preview= ]:
#+caption : Setup =math-preview=.
#+name : lst:setup-math-preview
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(when (ensure-package-installation 'math-preview)
(with-eval-after-load 'math-preview
;; https://docs.mathjax.org/en/latest/input/tex/extensions/physics.html
(let ((physics (split-string "
abs absolutevalue acomm acos acosecant acosine acot acotangent
acsc admat anticommutator antidiagonalmatrix arccos arccosecant
arccosine arccot arccotangent arccsc arcsec arcsecant arcsin
arcsine arctan arctangent asec asecant asin asine atan atangent
bmqty bqty Bqty bra braket comm commutator cos cosecant cosh
cosine cot cotangent coth cp cross crossproduct csc csch curl dd
derivative det determinant diagonalmatrix diffd differential div
divergence dmat dotproduct dv dyad erf ev eval evaluated exp
expectationvalue exponential expval fderivative fdv flatfrac
functionalderivative grad gradient gradientnabla hypcosecant
hypcosine hypcotangent hypsecant hypsine hyptangent
identitymatrix Im imaginary imat innerproduct ip ket ketbra
laplacian ln log logarithm matrixdeterminant matrixel
matrixelement matrixquantity mdet mel mqty naturallogarithm norm
op order outerproduct partialderivative paulimatrix pb
pderivative pdv pmat pmqty Pmqty poissonbracket pqty Pr
principalvalue Probability pv PV qall qand qas qassume qc qcc
qcomma qelse qeven qfor qgiven qif qin qinteger qlet qodd qor
qotherwise qq qqtext qsince qthen qty quantity qunless qusing
rank Re real Res Residue sbmqty sec secant sech sin sine sinh
smallmatrixquantity smdet smqty spmqty sPmqty svmqty tan tangent
tanh tr Tr trace Trace va var variation vb vdot vectorarrow
vectorbold vectorunit vmqty vnabla vqty vu xmat xmatrix
zeromatrix zmat")))
(cl-pushnew `("physics" . ,physics)
math-preview-tex-packages-autoload-packages))
(setq math-preview-raise 0.5
math-preview-scale 1
math-preview-tex-default-packages '("autoload" "ams" "physics"))
(let ((command (executable-find "~/node_modules/ .bin/math-preview")))
(if command
(setq math-preview-command command)
;; https://stackoverflow.com/a/17509764 answers:
;; How to install an npm package from github directly?
(unless (file-directory-p "~/node_modules")
(make-directory "~/node_modules"))
(cl-destructuring-bind (exit-code output)
(shell-command-with-exit-code
"npm" "install"
"git+https://gitlab.com/matsievskiysv/math-preview.git")
(if (= 0 exit-code)
(message "%s" (string-trim output))
(error "%s" (string-trim output))))))))
2022-02-27 10:41:31 +01:00
#+end_src
2021-12-11 12:19:35 +01:00
*** TODO Improve the AUCTeX configuration slowly
2022-02-27 10:41:31 +01:00
:PROPERTIES:
2023-01-12 21:28:18 +01:00
:CUSTOM_ID: sec:setup-auctex-slowly
2022-02-27 10:41:31 +01:00
:END:
2021-12-11 12:19:35 +01:00
[[https://github.com/thisirs/dotemacs/blob/master/lisp/init-auctex.el ][AUCTeX setup of an experienced user ]]
2022-10-12 06:05:19 +02:00
** Writing [[https://www.markdownguide.org/][Markdown]] files
:PROPERTIES:
:CUSTOM_ID: sec:writing-markdown-files
:END:
#+caption[Configure =markdown-mode= ]:
#+caption : Configure =markdown-mode=.
#+name : lst:configure-markdown-mode
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(when (ensure-package-installation 'markdown-mode))
2022-10-12 06:05:19 +02:00
#+end_src
2022-11-10 06:58:33 +01:00
** Writing [[info:org#Top][Org (info)]] files
2021-12-23 15:29:03 +01:00
:PROPERTIES:
:CUSTOM_ID: sec:writing-org-files
:END:
2021-11-29 13:14:56 +01:00
2022-11-10 06:58:33 +01:00
The [[https://org-babel.readthedocs.io/en/latest/ ][Org Babel reference card ]] complements section [[info:org#Working with Source Code ][Working with Source Code (info) ]]
of the [[info:org#Top ][Org (info) ]] manual.
2021-12-23 15:29:03 +01:00
*** [[info:org#Activation][Org activation (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:activate-org
:END:
2021-11-29 13:14:56 +01:00
2023-01-12 21:28:18 +01:00
#+caption[Bind =Org= commands globally]:
#+caption : Bind =Org= commands globally.
#+name : lst:bind-org-commands
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2023-01-12 21:28:18 +01:00
(with-eval-after-load 'emacs
2022-11-07 11:50:17 +01:00
(global-set-key (kbd "C-c a") #'org-agenda)
(global-set-key (kbd "C-c c") #'org-capture)
(with-eval-after-load 'ol
(global-set-key (kbd "C-c l") #'org-store-link)
(global-set-key (kbd "C-c C-l") #'org-insert-link-global)))
2021-11-29 13:14:56 +01:00
#+end_src
2023-01-12 21:28:18 +01:00
*** Setup Org
2021-12-23 15:29:03 +01:00
:PROPERTIES:
2023-01-12 21:28:18 +01:00
:CUSTOM_ID: sec:setup-org
2021-12-23 15:29:03 +01:00
:END:
2021-11-29 13:14:56 +01:00
2023-01-12 21:28:18 +01:00
I have split the initial [[https://orgmode.org/ ][Org-mode ]] setup over several listings. Here, follows a
list detailing and motivating each listing:
1. Listing [[lst:set-org-options ]] handles basic [[https://orgmode.org/ ][Org-mode ]] options.
2023-01-20 07:06:51 +01:00
2. Listing [[lst:setup-org-babel ]] handles basic [[https://orgmode.org/ ][Org-mode ]] options specific to
[[info:org#Working with Source Code ][work with source code (info) ]].
2023-01-12 21:28:18 +01:00
3. Listing [[lst:set-org-link-options ]] handles [[https://orgmode.org/ ][Org-mode ]] options specific to
[[info:org#Hyperlinks ][hyperlinks (info) ]].
4. Listing [[lst:setup-org-mode-map ]] extends the =org-mode-map= with useful
2022-11-10 06:58:33 +01:00
key-bindings.
2023-01-12 21:28:18 +01:00
5. Listing [[lst:setup-org-src ]] facilitates [[info:org#Editing Source Code ][editing Python source code blocks ]],
2022-11-10 06:58:33 +01:00
and it provides a function to remove the indentation of all =org-src-mode=
blocks without =-i= switch.
2023-01-12 21:28:18 +01:00
6. Listing [[lst:setup-ob-python ]] allows to pretty-print Python session source
2022-11-10 06:58:33 +01:00
block values with [[https://github.com/psf/black#readme ][black ]] instead of [[https://docs.python.org/3/library/pprint.html ][pprint ]].
2023-01-12 21:28:18 +01:00
7. Listing [[lst:set-org-export-options ]] selects the =non-intrusive= expert user
2022-11-10 06:58:33 +01:00
interface for export dispatching.
2023-01-12 21:28:18 +01:00
8. Listing [[lst:setup-org-for-lualatex-export ]] and
[[lst:set-ox-latex-options-for-lualatex-export ]] configure [[https://orgmode.org/ ][Org-mode ]] to generate
2022-11-10 06:58:33 +01:00
output for the LuaLaTeX compiler.
2023-01-12 21:28:18 +01:00
9. Listing [[lst:setup-org-latex-classes ]] defines [[info:org#LaTeXspecificexportsettings ][org-latex-classes (info) ]] for
2022-11-10 06:58:33 +01:00
backward compatibility. See table [[tab:org-latex-class-tag-placeholder ]] and
type {{{kbd(C-hv org-latex-classes)}}} for an explanation of the code in
2023-01-12 21:28:18 +01:00
listing [[lst:setup-org-latex-classes ]].
2022-04-23 14:26:59 +02:00
2023-01-12 21:28:18 +01:00
#+caption[Set basic =Org= options]:
#+caption : Set basic =Org= options.
#+name : lst:set-org-options
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'org
2023-01-12 21:28:18 +01:00
(setopt
2023-01-13 16:57:56 +01:00
org-babel-load-languages
`((C . t)
(calc . t)
(dot . ,(fboundp 'grapviz-dot-mode))
(emacs-lisp . t)
2023-03-04 06:46:55 +01:00
(eshell . t)
2023-01-13 16:57:56 +01:00
(fortran . t)
(gnuplot . ,(fboundp 'gnuplot-mode))
(js . t)
(latex . t)
2023-03-06 13:18:46 +01:00
(lilypond . ,(fboundp 'lilypond-mode))
2023-01-13 16:57:56 +01:00
(lisp . t)
2023-03-04 06:46:55 +01:00
(lua . ,(fboundp 'lua-mode))
2023-01-13 16:57:56 +01:00
(maxima . ,(fboundp 'maxima-mode))
(org . t)
(perl . t)
2023-01-20 07:06:51 +01:00
;; Postpone Python activation to prevent calling still unbound functions.
(python . nil)
2023-01-13 16:57:56 +01:00
(shell . t))
2023-01-12 21:28:18 +01:00
org-export-backends '(ascii beamer html icalendar latex odt texinfo)
org-file-apps '((auto-mode . emacs)
(directory . emacs)
("\\.mm\\'" . default)
("\\.x?html?\\'" . default)
("\\.pdf\\'" . emacs))
org-modules '(ol-bibtex
ol-doi
ol-eww
ol-info
org-id
org-protocol
2023-03-06 13:18:46 +01:00
org-tempo)))
2023-01-12 21:28:18 +01:00
#+end_src
2023-01-17 08:07:15 +01:00
#+caption[Setup =org-babel= ]:
#+caption : Setup =org-babel=.
#+name : lst:setup-org-babel
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-10 06:58:33 +01:00
(with-eval-after-load 'ob-core
2023-01-12 21:28:18 +01:00
(setopt org-confirm-babel-evaluate nil))
2022-11-10 06:58:33 +01:00
(with-eval-after-load 'ob-latex
2023-01-12 21:28:18 +01:00
(setopt
org-babel-latex-preamble (lambda (_)
"\\documentclass[preview]{standalone}\n")
org-babel-latex-begin-env (lambda (_)
"\\begin{document}\n")
org-babel-latex-end-env (lambda (_)
"\\end{document}\n")))
2022-11-10 06:58:33 +01:00
(with-eval-after-load 'ob-lisp
(with-eval-after-load 'sly
2023-01-12 21:28:18 +01:00
(setopt org-babel-lisp-eval-fn #'sly-eval)))
2022-11-10 06:58:33 +01:00
2023-01-20 07:06:51 +01:00
(with-eval-after-load 'emacs
(defun set-org-babel-language-activity (lang active)
"Set the `org-babel' activity of language LANG to ACTIVE.
Let `org-babel-do-load-languages' load ob-LANG when ACTIVE is t or
unbind the `org-babel' interface functions when ACTIVE is nil."
(if (locate-library (format "ob-%s" lang))
(or (org-babel-do-load-languages
'org-babel-load-languages
(cons (cons lang active)
(assq-delete-all
lang (default-toplevel-value 'org-babel-load-languages))))
org-babel-load-languages)
(warn "Can't locate `ob-%s', hence don't set `%s' activity" lang lang)))
(defun activate-org-babel-language (lang)
"Activate LANG for `org-babel'."
(interactive "SActivate language: ")
(if (set-org-babel-language-activity lang t)
(message "Did activate `%s' for `org-babel'" lang)
(message "Can't activate `%s' for `org-babel'" lang)))
(defun deactivate-org-babel-language (lang)
"Activate LANG for `org-babel'."
(interactive "SDeactivate language: ")
(if (set-org-babel-language-activity lang nil)
(message "Did deactivate `%s' for `org-babel'" lang)
2023-03-04 10:57:04 +01:00
(message "Can't deactivate `%s' for `org-babel'" lang))))
2022-11-10 06:58:33 +01:00
#+end_src
2022-11-09 12:16:59 +01:00
2023-01-12 21:28:18 +01:00
#+caption[Set =org-link= options]:
#+caption : Set =org-link= options.
#+name : lst:set-org-link-options
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-09 12:16:59 +01:00
(with-eval-after-load 'ol
2023-01-12 21:28:18 +01:00
(setopt org-link-file-path-type 'relative))
2022-11-09 12:16:59 +01:00
#+end_src
2023-01-12 21:28:18 +01:00
#+caption[Setup =org-mode-map= ]:
#+caption : Setup =org-mode-map=.
#+name : lst:setup-org-mode-map
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'emacs
;; From: "Nicolas Richard" <theonewiththeevillook@yahoo.fr >
;; Date: Fri, 08 Mar 2013 16:23:02 +0100 [thread overview]
;; Message-ID: <87vc913oh5.fsf@yahoo.fr > (raw)
(defun org-electric-dollar ()
"When called once, insert \\(\\) and leave point in between.
When called twice, replace the previously inserted \\(\\) by one $."
(interactive)
(if (and (looking-at "\\\\)") (looking-back "\\\\(" (- (point) 2)))
(progn (delete-char 2)
(delete-char -2)
(insert "$"))
(insert "\\(\\)")
(backward-char 2)))
(defun org-active-current-time-stamp ()
"Insert an active date-time stamp of the current time."
(interactive)
(if (fboundp 'org-insert-time-stamp)
(org-insert-time-stamp (current-time) 'with-hm)
(let ((stamp (format-time-string "<%Y-%m-%d %a %H:%M >" (current-time))))
(insert stamp)
stamp)))
(defun org-inactive-current-time-stamp ()
"Insert an inactive date-time stamp of the current time."
(interactive)
(if (fboundp 'org-insert-time-stamp)
(org-insert-time-stamp (current-time) 'with-hm 'inactive)
(let ((stamp (format-time-string "[%Y-%m-%d %a %H:%M]" (current-time))))
(insert stamp)
stamp)))
2022-09-02 15:02:51 +02:00
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'org
2023-01-20 07:03:52 +01:00
(setopt org-return-follows-link t)
2023-02-26 14:37:33 +01:00
(keymap-set org-mode-map "C-c <SPC >" #'org-inactive-current-time-stamp)
(keymap-set org-mode-map "C-c C-<SPC >" #'org-active-current-time-stamp)
(keymap-set org-mode-map "$" #'org-electric-dollar)
(keymap-set org-mode-map "M-q" #'org-fill-paragraph)))
2021-12-23 15:29:03 +01:00
#+end_src
2023-01-12 21:28:18 +01:00
#+caption[Setup =org-src= ]:
#+caption : Setup =org-src=.
#+name : lst:setup-org-src
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-10 06:58:33 +01:00
(with-eval-after-load 'emacs
2022-11-17 03:27:07 +01:00
(with-eval-after-load 'org-src
2023-01-12 21:28:18 +01:00
(setopt org-src-preserve-indentation t))
2022-11-10 06:58:33 +01:00
(declare-function org-babel-map-src-blocks "ext:ob-core" (file &rest body))
(declare-function org-do-remove-indentation "ext:org-macs" (n skip-fl))
(defun zero-all-org-src-blocks-indentation ()
"Remove the indentation of all `org-src-mode' blocks without `-i' switch."
(interactive)
(when (derived-mode-p 'org-mode)
(save-excursion
(org-babel-map-src-blocks
nil
(unless (or (string-match "-i " switches)
(string-match (rx (or bos bol) graph) body))
(when-let ((new (with-temp-buffer
(insert body)
(org-do-remove-indentation)
(buffer-string))))
(goto-char beg-body)
(delete-region beg-body end-body)
(insert new))))))))
#+end_src
2023-01-12 21:28:18 +01:00
#+caption[Setup =ob-python= ]:
#+caption : Setup =ob-python=.
#+name : lst:setup-ob-python
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-09 12:16:59 +01:00
(with-eval-after-load 'ob-python
(defun org-babel-python-format-session-value-override
(src-file result-file result-params)
"Return Python code to evaluate SRC-FILE and write result to RESULT-FILE.
Use `black' instead of `pprint' when \"pp\" is a member of RESULT-PARAMS."
(format "\
import ast
with open('%s') as __org_babel_python_tmpfile:
__org_babel_python_ast = ast.parse(__org_babel_python_tmpfile.read())
__org_babel_python_final = __org_babel_python_ast.body[-1]
if isinstance(__org_babel_python_final, ast.Expr):
__org_babel_python_ast.body = __org_babel_python_ast.body[:-1]
exec(compile(__org_babel_python_ast, '<string >', 'exec'))
__org_babel_python_final = eval(
compile(ast.Expression(__org_babel_python_final.value), '<string >', 'eval')
)
with open('%s', 'w') as __org_babel_python_tmpfile:
if %s:
import black
__org_babel_python_tmpfile.write(
black.format_str(repr(__org_babel_python_final), mode=black.Mode())
)
else:
__org_babel_python_tmpfile.write(str(__org_babel_python_final))
else:
exec(compile(__org_babel_python_ast, '<string >', 'exec'))
__org_babel_python_final = None"
(org-babel-process-file-name src-file 'noquote)
(org-babel-process-file-name result-file 'noquote)
(if (member "pp" result-params) "True" "False")))
(advice-add 'org-babel-python-format-session-value
:override #'org-babel-python-format-session-value-override))
2022-05-03 08:13:39 +02:00
#+end_src
2023-01-12 21:28:18 +01:00
#+caption[Set =org-export= options]:
#+caption : Set =org-export= options.
#+name : lst:set-org-export-options
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'ox
2023-01-12 21:28:18 +01:00
(setopt org-export-dispatch-use-expert-ui t))
2022-05-03 08:13:39 +02:00
#+end_src
2023-01-12 21:28:18 +01:00
#+caption[Setup =org= for export to LuaLaTeX]:
#+caption : Setup =org= for export to LuaLaTeX.
#+name : lst:setup-org-for-lualatex-export
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'org
;; https://list.orgmode.org/87o84fd4oi.fsf@posteo.net/
(add-to-list
'org-preview-latex-process-alist
'(luamagick
:programs ("lualatex" "convert")
:description "pdf > png"
:message "you need to install lualatex and imagemagick."
:image-input-type "pdf"
:image-output-type "png"
:image-size-adjust (1.0 . 1.0)
:post-clean nil
:latex-header nil
:latex-compiler ("lualatex -interaction nonstopmode -output-directory %o %f")
:image-converter ("convert -density %D -trim -antialias %f -quality 100 %O")))
2023-01-12 21:28:18 +01:00
(setopt
org-preview-latex-default-process 'luamagick
org-latex-default-packages-alist '(("" "fontspec" t ("lualatex"))
("AUTO" "inputenc" t ("pdflatex"))
("T1" "fontenc" t ("pdflatex"))
("" "graphicx" t)
("" "longtable" nil)
("" "wrapfig" nil)
("" "rotating" nil)
("normalem" "ulem" t)
("" "amsmath" t)
("" "amssymb" t)
("" "capt-of" nil)
("" "hyperref" nil))))
#+end_src
#+caption[Set =ox-latex= options for export to LuaLaTeX]:
#+caption : Set =ox-latex= options for export to LuaLaTeX.
#+name : lst:set-ox-latex-options-for-lualatex-export
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'ox-latex
2023-01-12 21:28:18 +01:00
(setopt
org-latex-compiler "lualatex"
org-latex-hyperref-template "\\hypersetup{
2022-11-07 11:50:17 +01:00
pdfauthor={%a},
pdftitle={%t},
pdfkeywords={%k},
pdfsubject={%d},
pdfcreator={%c},
pdflang={%L},
citecolor=blue,
colorlinks=true,
filecolor=blue,
hyperfootnotes=false,
linkcolor=blue,
unicode=true,
urlcolor=blue,
2023-01-12 21:28:18 +01:00
}\n"
org-latex-src-block-backend 'minted
org-latex-minted-langs '((cc "c++")
(conf "text")
(cperl "perl")
(diff "diff")
(shell-script "bash")
(json "json")
(org "text")
(toml "toml"))
org-latex-minted-options '(("bgcolor" "LightGoldenrodYellow"))
org-latex-logfiles-extensions
(cl-union '("lof" "lot") org-latex-logfiles-extensions :test #'equal)
;; https://tecosaur.github.io/emacs-config/ #compiling
org-latex-pdf-process (list (concat "latexmk -f -pdf -%latex"
" -interaction=nonstopmode"
" -shell-escape -outdir=%o %f"))
org-latex-prefer-user-labels t
org-latex-subtitle-separate t))
#+end_src
#+caption[Setup =org-latex-classes= for backwards compatibility]:
#+caption : Setup =org-latex-classes= for backwards compatibility.
#+name : lst:setup-org-latex-classes
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'ox-latex
(mapc (function (lambda (element)
(add-to-list 'org-latex-classes element)))
(nreverse
(quote (("elsarticle-1+2+3" ; Elsevier journals
"\\documentclass{elsarticle}
[NO-DEFAULT-PACKAGES]
[PACKAGES]
[EXTRA]"
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}")
("\\paragraph{%s}" . "\\paragraph*{%s}")
("\\subparagraph{%s}" . "\\subparagraph*{%s}"))
("article-1+2+3"
"\\documentclass{article}
[NO-DEFAULT-PACKAGES]
[PACKAGES]
[EXTRA]"
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}")
("\\paragraph{%s}" . "\\paragraph*{%s}")
("\\subparagraph{%s}" . "\\subparagraph*{%s}"))
("report-1+2+3"
"\\documentclass[11pt]{report}
[NO-DEFAULT-PACKAGES]
[PACKAGES]
[EXTRA]"
("\\part{%s}" . "\\part*{%s}")
("\\chapter{%s}" . "\\chapter*{%s}")
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}"))
("book-1+2+3"
"\\documentclass[11pt]{book}
[NO-DEFAULT-PACKAGES]
[PACKAGES]
[EXTRA]"
("\\part{%s}" . "\\part*{%s}")
("\\chapter{%s}" . "\\chapter*{%s}")
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}")))))))
2022-02-18 06:58:14 +01:00
#+end_src
2022-11-10 06:58:33 +01:00
#+attr_latex : :booktabs yes :float table
2023-01-12 21:28:18 +01:00
#+caption[The relation tag-placeholder in listing [[lst:setup-org-latex-classes ]]]:
#+caption : The relation tag-placeholder in listing [[lst:setup-org-latex-classes]].
2022-11-10 06:58:33 +01:00
#+name : tab:org-latex-class-tag-placeholder
| tag | placeholder |
|-----+-----------------------|
| +1 | [DEFAULT-PACKAGES] |
| +2 | [PACKAGES] |
| +3 | [EXTRA] |
| -1 | [NO-DEFAULT-PACKAGES] |
| -2 | [NO-PACKAGES] |
| -3 | [NO-EXTRA] |
2023-02-26 14:55:12 +01:00
*** Debug setting =org-babel-load-languages= options
:PROPERTIES:
:CUSTOM_ID: sec:setopt-org-babel-load-languages
:header-args:emacs-lisp: :exports code :tangle no
:END:
#+caption[Find valid entries for =org-babel-load-languages= ]:
#+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"
2023-03-05 10:48:03 +01:00
#+begin_src emacs-lisp :exports both :results value pp
2023-02-26 14:55:12 +01:00
(defun all-org-babel-execute-fns ()
"Find `ob-LANGUAGE' files in Org defining `org-babel-execute:LANGUAGE'.
Return a list of items where the filename is the `car' of each item and the
`cdr' of each item lists the `org-babel-execute:LANGUAGE' functions."
(let* ((dir (file-name-parent-directory (locate-library "org")))
(names (directory-files dir t (rx "ob-" (+ print) ".el" eos))))
(cl-loop for name in names
for found = (has-org-babel-execute-fn name)
when found collect found)))
(defun has-org-babel-execute-fn (name)
(let* ((buffer (find-file-noselect name))
(base (file-name-base (buffer-file-name buffer)))
(regexp (rx "defun" (+ blank) "org-babel-execute:" (group (+ graphic))))
(matches))
(save-match-data
(save-excursion
(with-current-buffer buffer
(save-restriction
(widen)
(goto-char 1)
(while (re-search-forward regexp nil t 1)
(push (match-string-no-properties 1) matches))))))
(when matches
`(,base ,@matches))))
(all-org-babel-execute-fns)
#+end_src
#+caption[Org Babel libraries with =org-babel-execute:language= functions]:
#+caption : Org Babel libraries with =org-babel-execute:language= functions.
#+RESULTS : lst:valid-org-babel-load-languages-entries
#+begin_src emacs-lisp :results silent :tangle no
(("ob-C" "C" "D" "C++" "cpp")
("ob-R" "R")
("ob-awk" "awk")
("ob-calc" "calc")
("ob-clojure" "clojurescript" "clojure")
("ob-css" "css")
("ob-ditaa" "ditaa")
("ob-dot" "dot")
("ob-emacs-lisp" "emacs-lisp")
("ob-eshell" "eshell")
("ob-forth" "forth")
("ob-fortran" "fortran")
("ob-gnuplot" "gnuplot")
("ob-groovy" "groovy")
("ob-haskell" "haskell")
("ob-java" "java")
("ob-js" "js")
("ob-julia" "julia")
("ob-latex" "latex")
("ob-lilypond" "lilypond")
("ob-lisp" "lisp")
("ob-lua" "lua")
("ob-makefile" "makefile")
("ob-maxima" "maxima")
("ob-ocaml" "ocaml")
("ob-octave" "octave" "matlab")
("ob-org" "org")
("ob-perl" "perl")
("ob-plantuml" "plantuml")
("ob-processing" "processing")
("ob-python" "python")
("ob-ruby" "ruby")
("ob-sass" "sass")
("ob-scheme" "scheme")
("ob-screen" "screen")
("ob-sed" "sed")
("ob-shell" "shell")
("ob-sql" "sql")
("ob-sqlite" "sqlite"))
#+end_src
2021-12-23 15:29:03 +01:00
*** [[https://github.com/bdarcus/citar][Citar: citing bibliography]] with [[https://orgmode.org/][Org Mode]]
2021-12-05 16:40:20 +01:00
:PROPERTIES:
2021-12-23 15:29:03 +01:00
:CUSTOM_ID: sec:citing-bibliography
2021-12-05 16:40:20 +01:00
:END:
2021-12-23 15:29:03 +01:00
[[https://github.com/bdarcus/citar ][Citar ]] is a completing-read front-end to browse and act on BibTeX, BibLaTeX, as
well as CSL JSON bibliographic data with LaTeX, markdown, and org-cite editing
2022-10-27 07:06:55 +02:00
support. In combination with vertico, embark, marginalia, and consult, [[https://github.com/bdarcus/citar ][Citar ]]
provides quick filtering and selecting of bibliographic entries from the
2023-01-12 21:28:18 +01:00
minibuffer as well as the option to run different commands on those
2022-06-30 18:07:44 +02:00
selections. The article [[https://kristofferbalintona.me/posts/202206141852/ ][Citations in org-mode: Org-cite and Citar ]] tries to walk
you from understanding the general context (bibliography producer, text
processor, text to product convertor) to an Emacs setup. Listing
2023-01-12 21:28:18 +01:00
[[lst:set-org-cite+citar-options ]] shows my =org-cite= , =citar= , and =org= setup.
2021-12-23 15:29:03 +01:00
2023-01-12 21:28:18 +01:00
#+caption[Set =org-cite= and =citar= options]:
#+caption : Set =org-cite= and =citar= options.
#+name : lst:set-org-cite+citar-options
2023-01-24 07:41:16 +01:00
#+begin_src emacs-lisp -n
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'oc
;; Org-9.5 needs the requirements, but Org-9.6 does not.
2023-01-12 21:28:18 +01:00
(when (version< (org-version) "9.6")
2022-11-07 11:50:17 +01:00
(require 'oc-biblatex)
(require 'oc-csl)))
2021-12-23 15:29:03 +01:00
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'org
2023-02-26 14:37:33 +01:00
(keymap-set org-mode-map "C-c b" #'org-cite-insert))
2022-07-13 06:11:45 +02:00
2022-11-07 11:50:17 +01:00
(when (ensure-package-installation 'citar 'citar-embark)
(with-eval-after-load 'embark
(when (fboundp 'citar-embark-mode)
(citar-embark-mode +1)))
2021-12-23 15:29:03 +01:00
2022-11-20 12:15:32 +01:00
(when (require 'citar nil 'noerror)
2023-01-12 21:28:18 +01:00
(setopt citar-bibliography '("~/VCS/research/refs.bib")
citar-library-file-extensions '("djvu" "pdf")
citar-library-paths '("~/VCS/research/papers/ ")))
2022-11-20 12:15:32 +01:00
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'oc
2023-01-12 21:28:18 +01:00
(setopt org-cite-export-processors '((latex biblatex)
(t csl))
org-cite-global-bibliography '("~/VCS/research/refs.bib"))
2022-10-31 14:39:13 +01:00
2022-11-07 11:50:17 +01:00
(when (require 'citar nil 'noerror)
2023-01-12 21:28:18 +01:00
(setopt org-cite-activate-processor 'citar
org-cite-follow-processor 'citar
org-cite-insert-processor 'citar))))
2021-12-23 15:29:03 +01:00
#+end_src
2022-02-17 13:15:30 +01:00
Ref. [cite:@Schulte.MCSE.2011.41] shows that [[https://orgmode.org/ ][Org-mode ]] is a simple, plain-text
markup language for hierarchical documents allowing intermingling of data, code,
and prose. It serves as an example link to to show how to use [[https://github.com/bdarcus/citar ][Citar ]] within this
setup, provided that =citar-bibliography= and =citar-library-paths= point to
valid directories and files. In an [[https://orgmode.org/ ][Org-mode ]] buffer this setup allows to:
2022-07-13 05:16:00 +02:00
1. Insert one or more [[https://orgmode.org/ ][Org-mode ]] cite links:
2022-02-17 13:15:30 +01:00
1. Type {{{kbd(C-c b)}}} or {{{kbd(M-x org-cite-insert)}}} .
2022-07-13 05:16:00 +02:00
2. Navigate to a bibliographic entry to insert:
1. Select it with {{{kbd(TAB)}}} to select more entries.
2. Select it with {{{kbd(RET)}}} to select the last entry.
2022-02-17 13:15:30 +01:00
2. View an electronic copy of an [[https://orgmode.org/ ][Org-mode ]] cite link:
1. Move point to the [[https://orgmode.org/ ][Org-mode ]] cite link.
2. Type {{{kbd(C-:)}}} or {{{kbd(M-x embark-dwim)}}} .
3. Navigate to the corresponding library file.
4. Select it.
3. Open the DOI of an [[https://orgmode.org/ ][Org-mode ]] cite link:
1. Move point to the [[https://orgmode.org/ ][Org-mode ]] cite link.
2. Type {{{kbd(C-:)}}} or {{{kbd(M-x embark-dwim)}}} .
3. Navigate to the corresponding link.
4. Select it.
2021-12-23 15:29:03 +01:00
*** TODO Compare bibtex and biblatex
1. [[https://www.economics.utoronto.ca/osborne/latex/BIBTEX.HTM ][Using bibtex: a short guide ]]
2. [[https://www.tug.org/texlive//devsrc/Master/texmf-dist/doc/latex/biblatex/biblatex.pdf ][The biblatex package ]]
3. [[https://github.com/yuchenlin/rebiber ][Rebiber: A tool for normalizing bibtex with official info ]]
4. [[https://github.com/josephwright/biblatex-phys ][A biblatex implementation of the AIP and APS bibliography style ]]
2022-09-18 12:41:52 +02:00
#+caption[Delete =Biber= cache when =Biber= fails to make a bibliography]:
#+caption : Delete =Biber= cache when =Biber= fails to make a bibliography.
2022-05-10 08:20:48 +02:00
#+name : lst:delete-biber-cache
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'emacs
;; https://tex.stackexchange.com/a/579356 answers
;; "How to solve Biber exiting with error code 2 but no error messages?"
(defun biber-delete-cache ()
"Delete the `Biber' cache to get rid of `Biber' exit code 2."
(interactive)
(cl-destructuring-bind (exit-code output)
(shell-command-with-exit-code "rm" "-rf" "$(biber --cache)")
(if (= 0 exit-code)
(message "%s" (string-trim output))
(error "%s" (string-trim output))))))
2022-05-10 08:20:48 +02:00
#+end_src
2022-08-18 20:22:04 +02:00
*** [[https://github.com/tecosaur/engrave-faces#readme][Engrave Faces]]
:PROPERTIES:
:CUSTOM_ID: sec:engrave-faces
:END:
2023-01-01 13:43:44 +01:00
This package has a front-end that processes fontified buffers and pipes its
output into one of three back-ends for export to LaTeX, HTML and text with ANSI
escape codes. It is an alternative to =minted= in case of LaTeX export or to
2023-01-02 14:58:26 +01:00
=htmlized= in case of HTML export.
2023-01-21 10:26:24 +01:00
The listings below work around one issue with spacing in the =pdf= output
2023-01-02 14:58:26 +01:00
resulting from use of the =engraved= source block back-end during =LaTeX=
2023-01-21 10:26:24 +01:00
export. They increase the quality of the export results of this [[file:README.org ][README.org ]] and
the user-friendliness of this facility to a level acceptable for my workflow:
2022-10-16 18:55:12 +02:00
1. The default Org export configuration for engraving listings produces =pdf=
2023-01-02 14:58:26 +01:00
output with a non-equidistant interline spacing in floating listings (those
2023-01-02 20:31:17 +01:00
with captions) and equidistant interline spacing in non-floating =tcolorbox=
2023-01-02 14:58:26 +01:00
environments (those without captions). I have traced the non-equidistant
interline spacing back to the =breakable= option of =Code= environments
inside =listing= environments. However, =tcolorbox= requires =breakable= for
listings that do not fit on a page. The filter
2023-01-01 13:43:44 +01:00
=org-latex-engraved-source-block-filter= in listing
2022-09-20 20:03:27 +02:00
[[lst:org-latex-engraved-source-block-filter ]] and the
2022-08-21 13:48:09 +02:00
=org-latex-engraved-preamble= customization in listing
[[lst:smart-latex-engrave-org-source-blocks ]] allow to engrave =org-mode= source
2023-01-01 13:43:44 +01:00
blocks to "floating unbreakable with caption" or "non-floating breakable
without caption" LaTeX environments. This is a partial work-around, but part
of my workflow.
2023-01-21 10:26:24 +01:00
2. Listing [[lst:ox-engraved-emacs-lisp-setup ]] shows how to use this configuration.
2022-08-20 15:22:55 +02:00
#+caption[Engrave to floating unbreakable or non-floating breakable environments]:
#+caption : Define an =org-export= filter function to engrave =org-src-mode=
#+caption : blocks to floating unbreakable LaTeX environments or non-floating
#+caption : breakable LaTeX environments.
2022-09-20 20:03:27 +02:00
#+name : lst:org-latex-engraved-source-block-filter
2023-01-24 07:41:16 +01:00
#+begin_src emacs-lisp -n :results silent
2023-01-06 20:45:02 +01:00
(ensure-package-installation 'engrave-faces)
2022-11-07 11:50:17 +01:00
(defun org-latex-engraved-source-block-filter (data _backend _info)
"Replace \"Code\" with \"Breakable\" in non-floating environments.
2023-01-12 21:28:18 +01:00
Set `org-latex-engraved-preamble' to define a Breakable (non-floating)
2022-11-07 11:50:17 +01:00
environment and an unbreakable Code (floating) environment."
(unless (string-match "^\\\\DeclareTColorBox\\[\\]{Breakable}"
org-latex-engraved-preamble)
(user-error "`org-latex-engraved-preamble' defines no `Breakable' environment"))
(when (eq org-latex-src-block-backend 'engraved)
(let ((enter "^\\\\begin{Code}\n\\\\begin{Verbatim}")
(leave "^\\\\end{Verbatim}\n\\\\end{Code}"))
;; Transform only blocks matching the enter regexp at position 0.
;; Do not transform blocks that are listing environments.
(when (and (string-match enter data) (eql 0 (match-beginning 0)))
(setq data (replace-match
"\\begin{Breakable}\n\\begin{Verbatim}" t t data))
(when (string-match leave data (match-end 0))
2022-08-20 15:22:55 +02:00
(setq data (replace-match
2022-11-07 11:50:17 +01:00
"\\end{Verbatim}\n\\end{Breakable}" t t data))
(when (string-match enter data)
(user-error "The `enter' regexp `%s' should not match" enter))
(when (string-match leave data)
(user-error "The `leave' regexp `%s' should not match" leave))
data)))))
2022-08-20 15:22:55 +02:00
#+end_src
2022-08-18 20:22:04 +02:00
2022-10-16 18:55:12 +02:00
#+caption[Smart LaTeX engraving of =org-src-mode= blocks]:
#+caption : Smart LaTeX engraving of =org-src-mode= blocks.
2022-08-20 15:22:55 +02:00
#+name : lst:smart-latex-engrave-org-source-blocks
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(defun smart-latex-engrave-org-source-blocks ()
"Enable smart LaTeX engraving of `org-src-mode' blocks.
2022-08-20 15:22:55 +02:00
2022-11-07 11:50:17 +01:00
Sets backend and preamble locally to support floating unbreakable LaTeX
environments and non-floating breakable LaTeX environments by means of
`org-latex-engraved-source-block-filter'."
(interactive)
(when (require 'ox-latex nil 'noerror)
(setq-local org-latex-src-block-backend 'engraved
org-latex-engraved-preamble "\\usepackage{fvextra}
[FVEXTRA-SETUP]
% Make code and line numbers normalsize. Make line numbers grey.
\\renewcommand\\theFancyVerbLine{
\\normalsize\\color{black!40!white}\\arabic{FancyVerbLine}}
% In case engrave-faces-latex-gen-preamble has not been run.
2023-01-17 08:02:11 +01:00
\\usepackage{xcolor}
2022-11-07 11:50:17 +01:00
\\providecolor{EfD}{HTML}{f7f7f7}
\\providecolor{EFD}{HTML}{28292e}
% To use \\DeclareTColorBox from the tcolorbox package:
\\usepackage[breakable,xparse]{tcolorbox}
% Define a Breakable environment to fontify code outside floats.
\\DeclareTColorBox[]{Breakable}{o}{
colback=EfD, colframe=EFD, colupper=EFD,
fontupper=\\normalsize\\setlength{\\fboxsep}{0pt},
IfNoValueTF={#1}{
boxsep=1pt, arc=1pt, outer arc=1pt, boxrule=0.5pt,
}{
boxsep=1pt, arc=0pt, outer arc=0pt, boxrule=0pt, leftrule=1pt
},
left=2pt, right=2pt, top=1pt, bottom=1pt, breakable
}
% Define an unbreakable Code environment to fontify code inside floats.
\\DeclareTColorBox[]{Code}{o}{
colback=EfD, colframe=EFD, colupper=EFD,
fontupper=\\normalsize\\setlength{\\fboxsep}{0pt},
IfNoValueTF={#1}{
boxsep=1pt, arc=1pt, outer arc=1pt, boxrule=0.5pt
}{
boxsep=1pt, arc=0pt, outer arc=0pt, boxrule=0pt, leftrule=1pt
},
2023-01-20 07:13:09 +01:00
left=2pt, right=2pt, top=1pt, bottom=1pt
2022-11-07 11:50:17 +01:00
}
[LISTINGS-SETUP]")))
2022-08-18 20:22:04 +02:00
#+end_src
2022-08-21 13:48:09 +02:00
#+caption[Emacs setup to use =engrave-faces-latex= in =org-mode= smartly]:
#+caption : Emacs setup to use =engrave-faces-latex= in =org-mode= smartly.
2022-09-20 20:03:27 +02:00
#+name : lst:ox-engraved-emacs-lisp-setup
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent :tangle no
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'ox
(make-variable-buffer-local 'org-export-filter-src-block-functions)
(add-to-list 'org-export-filter-src-block-functions
'org-latex-engraved-source-block-filter)
(when (fboundp 'smart-latex-engrave-org-source-blocks)
(smart-latex-engrave-org-source-blocks)))
2022-08-21 13:48:09 +02:00
#+end_src
2021-12-23 15:29:03 +01:00
*** [[info:org#Adding Hyperlink Types][Making Org hyperlink types (info)]]
:PROPERTIES:
2022-12-22 19:15:34 +01:00
:CUSTOM_ID: sec:make-org-hyperlink-types
2021-12-23 15:29:03 +01:00
:END:
2022-12-22 19:15:34 +01:00
The listings below implement or reimplement three groups of =org-link= types:
2022-09-25 20:37:08 +02:00
1. Listing [[lst:org-ref-like-org-link-types ]] defines =org-link= types for
backwards compatibility with [[https://github.com/jkitchin/org-ref ][org-ref ]].
2. Listing [[lst:define-org-pdfview-link-type ]] uses ideas from the definition of
=docview-org-link= and =doi-org-link= types to define an =pdfview-org-link=
type for use with [[https://github.com/vedang/pdf-tools ][pdf-tools ]].
2022-12-22 19:15:34 +01:00
3. Listing [[lst:patch-org-info-link-type ]] patches the function =org-info-export=
2022-09-25 20:37:08 +02:00
and listing [[lst:emacs-lisp-setup-buffer-local-ol-info ]] sets the constants
~org-info-emacs-documents~ and ~org-info-other-documents~ as buffer local
variables in order to export the =info-org-link= types in this document to
=html= and LaTeX correctly.
2021-12-23 15:29:03 +01:00
2022-02-03 19:10:05 +01:00
#+caption[Define =org-link= types for backwards compatibility with =org-ref= ]:
#+caption : Define =org-link= types for backwards compatibility with =org-ref=.
#+name : lst:org-ref-like-org-link-types
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'ol
(org-link-set-parameters "ac*" :export #'org-ref-ac* -export)
(org-link-set-parameters "cite" :export #'org-ref-cite-export)
(org-link-set-parameters "eqref" :export #'org-ref-eqref-export)
(org-link-set-parameters "hyperlink" :export #'org-ref-hyperlink-export)
(org-link-set-parameters "label" :export #'org-ref-label-export)
(org-link-set-parameters "ref" :export #'org-ref-ref-export)
(defun org-ref-ac*-export (path _desc backend _info)
(pcase backend
(`latex (format "\\gls*{%s}" path))
(_ path)))
(defun org-ref-cite-export (path _desc backend _info)
(pcase backend
(`latex (format "\\cite{%s}" path))
(_ path)))
(defun org-ref-eqref-export (path _desc backend _info)
(pcase backend
(`latex (format "\\eqref{%s}" path))
(_ path)))
(defun org-ref-hyperlink-export (path desc backend _info)
(pcase backend
(`latex (format "\\hyperlink{%s}{%s}" path desc))
(_ path)))
(defun org-ref-label-export (path _desc backend _info)
(pcase backend
(`latex (format "\\label{%s}" path))
(_ path)))
(defun org-ref-ref-export (path _desc backend _info)
(pcase backend
(`latex (format "\\ref{%s}" path))
(_ path))))
2021-12-06 12:59:24 +01:00
#+end_src
2022-02-12 09:22:34 +01:00
#+caption[Define an =org-link= type for =pdf-tools= ]:
#+caption : Define an =org-link= type for =pdf-tools=.
2022-02-03 19:10:05 +01:00
#+name : lst:define-org-pdfview-link-type
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'ol
(autoload 'pdf-view-goto-page "pdf-view" nil t)
(org-link-set-parameters "pdfview"
:follow #'org-pdfview-open
:export #'org-pdfview-export
:store #'org-pdfview-store-link)
(defun org-pdfview-export (link description backend _)
"Export a \"pdfview\" type link.
The paths of the links export as file relative paths in order to
facilate moving single directories or whole directory trees."
(let ((path (if (string-match "\\(.+\\)::.+ " link)
(match-string 1 link)
link))
(desc (or description link)))
(when (stringp path)
(setq path (file-relative-name path))
(pcase backend
(`html (format "<a href=\"%s\" >%s</a >" path desc))
(`latex (format "\\href{%s}{%s}" path desc))
(`ascii (format "%s (%s)" desc path))
(_ path)))))
(defun org-pdfview-open (link _)
"Open a \"pdfview\" type link."
(string-match "\\(.*?\\)\\(?:::\\([0-9]+\\)\\)?$" link)
(let ((path (match-string 1 link))
(page (and (match-beginning 2)
(string-to-number (match-string 2 link)))))
;; Let Org mode open the file (in-emacs = 1) to ensure
;; org-link-frame-setup is respected.
(org-open-file path 1)
(when page (pdf-view-goto-page page))))
(defun org-pdfview-store-link ()
"Store a \"pdfview\" type link."
(when (eq major-mode 'pdf-view-mode)
(let* ((path buffer-file-name)
(page (pdf-view-current-page))
(link (concat "pdfview:" path "::" (number-to-string page))))
(org-link-store-props
:type "pdfview"
:link link
:description path)))))
2022-02-03 19:10:05 +01:00
#+end_src
2021-12-05 16:40:20 +01:00
2021-12-23 15:29:03 +01:00
#+caption[Patch =ol-info= ]:
#+caption : Patch =ol-info=.
2022-08-02 14:07:15 +02:00
#+name : lst:patch-org-info-link-type
2023-01-24 07:41:16 +01:00
#+begin_src emacs-lisp -n :exports code :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'ol-info
(defun org-info-export (path desc format)
"Export an info link.
See `org-link-parameters' for details about PATH, DESC and FORMAT."
(let* ((parts (split-string path "#\\|::"))
(manual (car parts))
(node (or (nth 1 parts) "Top")))
(pcase format
(`html
(format "<a href=\"%s#%s\" >%s</a >"
(org-info-map-html-url manual)
(org-info--expand-node-name node)
(or desc path)))
(`latex
(format "\\href{%s\\#%s}{%s}"
(org-info-map-html-url manual)
(org-info--expand-node-name node)
(or desc path)))
(`texinfo
(let ((title (or desc "")))
(format "@ref{%s,%s,,%s,}" node title manual)))
(_ nil)))))
2022-02-27 16:58:24 +01:00
#+end_src
2021-12-23 15:29:03 +01:00
2022-07-01 10:02:05 +02:00
#+attr_latex : :options breaklines
2022-02-27 16:58:24 +01:00
#+caption[Patch buffer local =ol-info= ]:
#+caption : Patch buffer local =ol-info=.
#+name : lst:emacs-lisp-setup-buffer-local-ol-info
2023-01-24 07:41:16 +01:00
#+begin_src emacs-lisp -n :exports code :results silent :tangle no
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'ol-info
(make-variable-buffer-local 'org-info-emacs-documents)
(setq org-info-emacs-documents (delete "org" org-info-emacs-documents))
(make-variable-buffer-local 'org-info-other-documents)
(setq org-info-other-documents
(cl-union
'(("consult" . "https://github.com/minad/consult")
("embark" . "https://github.com/oantolin/embark")
("magit" . "https://magit.vc/manual/magit.html")
("marginalia" . "https://github.com/minad/marginalia")
("maxima" .
"https://maxima.sourceforge.io/docs/manual/maxima_singlepage.html")
("org" . "https://orgmode.org/org.html")
("orderless" . "https://github.com/oantolin/orderless")
("sly" . "https://joaotavora.github.io/sly/ ")
("vertico" . "https://github.com/minad/vertico"))
org-info-other-documents :test #'equal)))
2021-12-05 16:40:20 +01:00
#+end_src
2022-07-01 10:02:05 +02:00
2022-12-22 19:15:34 +01:00
*** [[https://bitspook.in/blog/extending-org-mode-to-handle-youtube-links/][Extending org-mode to handle YouTube links]]
:PROPERTIES:
:CUSTOM_ID: sec:make-org-yt-link-type
:END:
Listing [[lst:define-org-yt-link-type ][define org-yt-link type ]] implements code to open the link to the
following YouTube video [[yt:eaZUZCzaIgw#6s#10s ][Extending org-mode to handle YouTube links. ]]
The following posts provide programming information:
1. [[https://developers.google.com/youtube/v3/docs ][YouTube API reference ]].
2. [[https://developers.google.com/youtube/iframe_api_reference ][YouTube Player API reference for iframe embeds ]].
3. [[https://www.alphr.com/how-to-link-specific-timestamp-youtube/ ][How to link to a specific timestamp in a YouTube video ]].
2023-01-24 07:41:16 +01:00
#+begin_src emacs-lisp -n :exports none :tangle no
2022-12-22 19:15:34 +01:00
;; https://www.youtube.com/embed/M03bTkQxVUg?start=30&end=120
(org-yt-seconds-to-hms (+ (* 3600 120) (* 60 9) 7))
(org-yt-seconds-to-hms 3661)
(org-yt-time-to-seconds "")
(org-yt-time-to-seconds "1")
(org-yt-time-to-seconds "1:1")
(org-yt-time-to-seconds "1:1:1")
(org-yt-time-to-seconds "1h1m1s")
(org-yt-time-to-seconds "1mX")
(org-yt-time-to-seconds "1h")
(org-yt-time-to-seconds "1H1m")
(org-yt-time-to-seconds "1h1s")
(org-yt-time-to-seconds "1m1s")
(org-yt-time-to-seconds "1h1s")
(org-yt-time-to-seconds "1h1M1s")
(org-yt-format-open-url "WKwZHSbHmPg" "")
(org-yt-format-open-url "WKwZHSbHmPg" nil)
(org-yt-format-open-url "WKwZHSbHmPg" '("1m1s"))
(org-yt-format-open-url "WKwZHSbHmPg" '("0:2:44" "0:2:50"))
(org-yt-open "WKwZHSbHmPg#0:2:44#0:2:50" t)
(org-yt-export "WKwZHSbHmPg#0:2:44#0:2:50" "Title" 'html nil)
(org-yt-export "WKwZHSbHmPg#0h2m40s#0h2m50s" "Title" 'html nil)
(org-yt-export "WKwZHSbHmPg#2M40S#2M50S" "Title" 'html nil)
(org-yt-export "WKwZHSbHmPg#0:2:44#0:2:50" "Title" 'latex nil)
(org-yt-export "WKwZHSbHmPg#0h2m40s#0h2m50s" "Title" 'latex nil)
(org-yt-export "WKwZHSbHmPg#2M40S#2M50S" "Title" 'latex nil)
#+end_src
#+caption[Parsing function for the =org-yt= link type]:
#+caption : Parsing function for the =org-yt= link type.
#+name : lst:org-yt-parsing
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-12-22 19:15:34 +01:00
(defun org-yt-time-to-seconds (text)
"Convert TEXT of the form `12:34:56' or `12h34m56s' to seconds as integers."
(let* ((case-fold-search t)
(hms (< (length (split-string text "[:]"))
(length (split-string text "[HhMmSs]"))))
(regexp (if hms
(rx (opt (group (+ digit) "h"))
(opt (group (+ digit) "m"))
(opt (group (+ digit) "s")))
(rx (opt (group (+ digit)))
(opt ":" (group (+ digit)))
(opt ":" (group (+ digit))))))
(_ (string-match regexp text))
(md (match-data))
(found (substring text (pop md) (pop md)))
(seconds 0)
lot)
(if (string< found text)
(user-error "Found `%s' which is a prefix of `%s'" found text)
(if hms
(while md
(setq lot (substring text (or (pop md) 0) (or (pop md) 0)))
(cond
((or (string-suffix-p "h" lot) (string-suffix-p "H" lot))
(setq seconds (+ seconds (* 3600 (string-to-number lot)))))
((or (string-suffix-p "m" lot) (string-suffix-p "M" lot))
(setq seconds (+ seconds (* 60 (string-to-number lot)))))
((or (string-suffix-p "s" lot) (string-suffix-p "S" lot))
(setq seconds (+ seconds (string-to-number lot))))))
(while md (push (string-to-number
(substring text (or (pop md) 0) (or (pop md) 0)))
lot))
(cond
((length= lot 1) (setq seconds (car lot)))
((length= lot 2) (setq seconds (+ (* 60 (cadr lot))
(car lot))))
((length= lot 3) (setq seconds (+ (* 3600 (caddr lot))
(* 60 (cadr lot))
(car lot)))))))
seconds))
#+end_src
#+caption[Formatting functions to open =org-yt= links]:
#+caption : Formatting functions to open =org-yt= links.
#+name : lst:org-yt-open-formatting
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-12-22 19:15:34 +01:00
(defun org-yt-seconds-to-hms (seconds)
"Convert seconds as integers to text of the form `12h34m56s'."
(let ((h (/ seconds 3600))
(m (/ (% seconds 3600) 60))
(s (% seconds 60)))
(concat (and (> h 0) (format "%dh" h))
(if (> h 0)
(format "%02dm" m)
(and (> m 0) (format "%dm" m)))
(if (or (> h 0) (> m 0))
(format "%02ds" s)
(format "%ds" s)))))
(defconst org-yt-start
"https://www.youtube.com/watch?v=%s&t= %s"
"Format string for `org-yt-format-open-url' to fill in ID and TIMING.")
(defconst org-yt-chunk
"https://www.youtube.com/embed/ %s?autoplay=1&start= %d&end=%d"
"Format string for `org-yt-format-open-url' to fill in ID and TIMING.")
(defun org-yt-format-open-url (id timing)
"Convert an \"yt\" type link to an URL for opening."
(cond
((not timing)
(format org-yt-start id "0s"))
((length= timing 1)
(format org-yt-start id
(org-yt-seconds-to-hms (org-yt-time-to-seconds (car timing)))))
((length= timing 2)
(format org-yt-chunk id
(org-yt-time-to-seconds (car timing))
(org-yt-time-to-seconds (cadr timing))))))
#+end_src
#+caption[Formatting function for HTML export of =org-yt= links]:
#+caption : Formatting function for HTML export of =org-yt= links.
#+name : lst:org-yt-html-export-formatting
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-12-22 19:15:34 +01:00
(defconst org-yt-iframe
"<iframe
frameborder=\"0\" width= \"600\" height=\"450\"
src=\"https://www.youtube.com/embed/ %s%s\"
title=\"%s\"
allowfullscreen></iframe >"
"Format string for `org-yt-iframe' to fill in ID, TIMING, and TITLE.")
(defun org-yt-format-iframe (id timing title)
"Convert an \"yt\" type link to an inline frame element for export to HTML."
(format org-yt-iframe id
(cond
((not timing) "")
((length= timing 1)
(format "?start=%d" id (org-yt-time-to-seconds (car timing))))
((length= timing 2)
(format "?start=%d&end= %d"
(org-yt-time-to-seconds (car timing))
(org-yt-time-to-seconds (cadr timing)))))
title))
#+end_src
#+caption[Define an =org-link= type for =YouTube= ]:
#+caption : Define an =org-link= type for =YouTube=.
#+name : lst:define-org-yt-link-type
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-12-22 19:15:34 +01:00
(defun org-yt-open (path prefix)
"Open an \"yt\" type link with `browse-url', `emms', or \"mpv\".
PATH is a string containing the video ID and optional timing information.
Open the link with `browse-url' if PREFIX else with `emms' or \"mpv\"."
(let* ((parts (split-string path "[#]+" t))
(id (car parts))
(timing (cdr parts))
(url (org-yt-format-open-url id timing)))
(cond
(prefix
(browse-url url))
((require 'emms nil 'noerror)
(emms-add-url url)
(with-current-emms-playlist
(save-excursion
(emms-playlist-last)
(emms-playlist-mode-play-current-track))))
((executable-find "mpv")
(let ((display-buffer-alist
`((,shell-command-buffer-name-async . (display-buffer-no-window)))))
(async-shell-command (format "\"%s\" \"%s\"" url)))
(message "Launched mpv with \"%s\"" url))
(t
(user-error "Can't open `%s': install `emms' and/or `mpv'" url)))))
(defun org-yt-export (path desc backend _)
"Export an \"yt\" type link."
(let* ((parts (split-string path "[#]+" t))
(id (car parts))
(timing (cdr parts)))
(pcase backend
(`html
(org-yt-format-iframe id timing desc))
(`latex
(format "\\href{%s}{%s}" (org-yt-format-open-url id timing) desc))
(_ id))))
(with-eval-after-load 'ol
;; https://bitspook.in/blog/extending-org-mode-to-handle-youtube-paths/
(org-link-set-parameters "yt"
:follow #'org-yt-open
:export #'org-yt-export))
#+end_src
2021-12-05 17:34:56 +01:00
*** [[https://tecosaur.github.io/emacs-config/#translate-capital-keywords][Translate capital keywords (old) to lower case (new)]]
2021-12-23 15:29:03 +01:00
:PROPERTIES:
:CUSTOM_ID: sec:convert-upper-to-lower-case-keywords
:END:
2021-11-29 13:14:56 +01:00
2021-12-23 15:29:03 +01:00
#+caption[Convert upper to lower case keywords]:
#+caption : Convert upper to lower case keywords.
2021-12-28 08:48:03 +01:00
#+name : lst:convert-upper-to-lower-case-keywords
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'emacs
;; https://tecosaur.github.io/emacs-config/ #translate-capital-keywords
(defun org-syntax-convert-keyword-case-to-lower ()
"Convert all #+KEYWORDS to #+keywords."
(interactive)
(when (derived-mode-p 'org-mode)
(save-excursion
(goto-char (point-min))
(let ((count 0)
(case-fold-search nil))
(while (re-search-forward "^[ \t]*#\\+[A-Z_]+ " nil t)
(unless (s-matches-p "RESULTS" (match-string 0))
(replace-match (downcase (match-string 0)) t)
(setq count (1+ count))))
(message "Replaced %d keywords" count))))))
2021-11-29 13:14:56 +01:00
#+end_src
2021-12-29 14:05:03 +01:00
*** [[https://lists.gnu.org/archive/html/emacs-orgmode/2016-07/msg00394.html][Evaluate specific source blocks at load-time]]
2021-12-23 15:29:03 +01:00
:PROPERTIES:
:CUSTOM_ID: sec:load-time-specific-source-block-evaluation
:END:
2021-11-29 13:14:56 +01:00
2021-12-29 14:05:03 +01:00
[[https://emacs.stackexchange.com/questions/12938/how-can-i-evaluate-elisp-in-an-orgmode-file-when-it-is-opened ][How to do load time source block evaluation ]]
2021-12-23 15:29:03 +01:00
#+caption[Evaluate specific source blocks at load-time]:
#+caption : Evaluate specific source blocks at load-time.
2021-12-28 08:48:03 +01:00
#+name : lst:load-time-specific-source-block-evaluation
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'emacs
(defun org-eval-named-blocks-with-infix (infix)
"Evaluate all source blocks having INFIX in their name."
(when (eq major-mode 'org-mode)
(let ((blocks
(org-element-map
(org-element-parse-buffer 'greater-element nil) 'src-block
(lambda (block)
(when-let ((name (org-element-property :name block)))
(when (string-match-p infix name) block))))))
(dolist (block blocks)
(goto-char (org-element-property :begin block))
(org-babel-execute-src-block)))))
(defun org-eval-emacs-lisp-setup-blocks ()
"Evaluate all source blocks having \"emacs-lisp-setup\" in their name."
(interactive)
(org-eval-named-blocks-with-infix "emacs-lisp-setup"))
2022-04-17 19:05:06 +02:00
2022-11-07 11:50:17 +01:00
(defun org-eval-python-setup-blocks ()
"Evaluate all source blocks having \"python-setup\" in their name."
(interactive)
(org-eval-named-blocks-with-infix "python-setup"))
2022-04-17 19:05:06 +02:00
2022-11-07 11:50:17 +01:00
;; Emacs looks for "Local variables:" after the last "newline-formfeed".
(add-to-list 'safe-local-eval-forms '(org-eval-emacs-lisp-setup-blocks))
(add-to-list 'safe-local-eval-forms '(org-eval-python-setup-blocks)))
2021-12-14 10:15:39 +01:00
#+end_src
2021-12-13 21:01:08 +01:00
2021-12-28 08:32:51 +01:00
*** [[info:org#LaTeX header and sectioning][Easy LaTeX preamble editing]]
2021-12-23 15:29:03 +01:00
:PROPERTIES:
2021-12-28 08:32:51 +01:00
:CUSTOM_ID: sec:easy-latex-preamble-editing
2021-12-23 15:29:03 +01:00
:END:
2021-12-28 08:32:51 +01:00
There are at least two ways (new and old) to edit the LateX preamble
=latex_header= and =latex-extra_header= export options easily in LaTeX source or
export blocks. This [[info:org#Top ][Org (info) ]] file uses the new way, but keeps the old way for
backwards compatibility.
2021-12-23 15:29:03 +01:00
2021-12-28 08:32:51 +01:00
The new way -- exploiting an idea of [[https://www.matem.unam.mx/~omar/ ][Omar Antolin Camarena ]] -- is to code new
[[info:org#Editing Source Code ][<LANGUAGE>-modes ]] allowing to edit in LaTeX mode and to export to LaTeX code with
[[info:org#LaTeX specific export settings ][correct LaTeX preamble export setting prefixes ]]. Here, are links to three posts
exposing his idea:
1. [[https://www.reddit.com/r/orgmode/comments/7u2n0h/tip_for_defining_latex_macros_for_use_in_both/ ][Export LaTeX macros to LaTeX and HTML/MathJax preambles (reddit) ]],
2. [[https://www.reddit.com/r/orgmode/comments/5bi6ku/tip_for_exporting_javascript_source_block_to/ ][Export JavaScript source blocks to script tags in HTML (reddit) ]],
3. [[https://emacs.stackexchange.com/questions/28301/export-javascript-source-block-to-script-tag-in-html-when-exporting-org-file-to ][Export JavaScript source blocks to script tags in HTML (SX) ]].
2022-08-02 14:07:15 +02:00
Listing [[lst:org-babel-latex-header-blocks ]] implements this way by means of two
2021-12-28 08:32:51 +01:00
new [[info:org#Editing Source Code ][<LANGUAGE>-modes ]]: =latex-header= and =latex-extra-header= .
#+caption[New =<LANGUAGE>-modes= to edit the LaTeX preamble easily]:
#+caption : Add =latex-header= and =latex-extra-header= language modes to edit
#+caption : LaTeX preamble =latex_header= and =latex_extra_header= export options
#+caption : easily.
2022-08-02 14:07:15 +02:00
#+name : lst:org-babel-latex-header-blocks
2023-01-24 07:41:16 +01:00
#+begin_src emacs-lisp -n :exports code :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'emacs
(defun prefix-all-lines (prefix body)
(with-temp-buffer
(insert body)
(string-insert-rectangle (point-min) (point-max) prefix)
(buffer-string)))
2021-12-28 08:32:51 +01:00
2022-11-07 11:50:17 +01:00
(defun org-babel-execute:latex-extra-header (body _params)
"Execute a block of LaTeX extra header lines with org-babel.
This function is called by `org-babel-execute-src-block' and
prefixes all lines with \"#+latex_extra_header: \"."
(prefix-all-lines "#+latex_extra_header: " body))
2021-12-28 08:32:51 +01:00
2022-11-07 11:50:17 +01:00
(defun org-babel-execute:latex-header (body _params)
"Execute a block of LaTeX header lines with org-babel.
This function is called by `org-babel-execute-src-block' and
prefixes all lines with \"#+latex_header: \"."
(prefix-all-lines "#+latex_header: " body))
2021-12-26 11:53:40 +01:00
2022-11-07 11:50:17 +01:00
(defvar org-babel-default-header-args:latex-extra-header
'((:exports . "results") (:results . "raw")))
2021-12-26 11:53:40 +01:00
2022-11-07 11:50:17 +01:00
(defvar org-babel-default-header-args:latex-header
'((:exports . "results") (:results . "raw")))
2022-04-17 19:06:34 +02:00
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'org-src
2023-01-12 21:28:18 +01:00
(setopt org-src-window-setup 'current-window)
2022-05-01 07:54:35 +02:00
2022-11-07 11:50:17 +01:00
(add-to-list 'org-src-lang-modes '("toml" . conf-toml))
(add-to-list 'org-src-lang-modes '("latex-header" . latex))
(add-to-list 'org-src-lang-modes '("latex-extra-header" . latex))))
2021-12-26 11:53:40 +01:00
#+end_src
2021-12-28 08:32:51 +01:00
The old way is to use a special export attribute as in the function
=org-latex-header-blocks-filter= in [[https://git.sr.ht/~bzg/org-contrib/tree/master/item/lisp/ox-extra.el ][ox-extra.el ]]. Apparently, nobody is using
this broken function (broken, since it relies on support only in org-mode before
2021-12-29 14:05:03 +01:00
=2014-11-11= ). Listing [[lst:org-latex-header-blocks-filter ]] proposes a fix for
=org-latex-header-blocks-filter= .
2021-12-26 11:53:40 +01:00
2021-12-23 15:29:03 +01:00
#+caption[Convert marked LaTeX export blocks to LaTeX header lines]:
#+caption : Convert marked LaTeX export blocks to LaTeX header lines.
2021-12-28 08:32:51 +01:00
#+name : lst:org-latex-header-blocks-filter
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'ox
(defun org-latex-header-blocks-filter (backend)
"Convert marked LaTeX export blocks to \"#+latex_header: \" lines.
The marker is a line \"#+header: :header yes\" preceding the block.
For instance, the LaTeX export block
,#+header: :header yes
,#+begin_export latex
% This line converts to a LaTeX header line.
,#+end_export
converts to
\"#+latex_header: % This line converts to a LaTeX header line.\"."
(when (org-export-derived-backend-p backend 'latex)
(let ((blocks
(org-element-map
(org-element-parse-buffer 'greater-element nil) 'export-block
(lambda (block)
(let ((type (org-element-property :type block))
(header (org-export-read-attribute :header block :header)))
(when (and (string= type "LATEX") (string= header "yes"))
block))))))
(mapc (lambda (block)
;; Set point to where to insert LaTeX header lines
;; after deleting the block.
(goto-char (org-element-property :post-affiliated block))
(let ((lines
(split-string (org-element-property :value block) "\n")))
(delete-region (org-element-property :begin block)
(org-element-property :end block))
(dolist (line lines)
(insert (concat "#+latex_header: "
(replace-regexp-in-string "\\` *" "" line)
"\n")))))
;; Reverse to go upwards to avoid wrecking the list of
;; block positions in the file that would occur in case
;; of going downwards.
(reverse blocks)))))
;; Push the filter on the hook.
(cl-pushnew #'org-latex-header-blocks-filter
org-export-before-parsing-hook))
2021-12-14 10:15:39 +01:00
#+end_src
2021-11-29 13:14:56 +01:00
2021-12-29 14:05:03 +01:00
This file uses the new way, while keeping the old way for backwards
compatibility, because the new way feels less hackish than the old way. A
practical difference is that new way source blocks (contrary to old way export
blocks) do not work in [[info:org#Export Settings ][#+SETUPFILE: <FILE> ]], but only in [[info:org#Export Settings ][#+INCLUDE: <FILE> ]] files.
2021-11-29 13:14:56 +01:00
2022-11-06 15:53:39 +01:00
*** [[info:org#Macro Replacement][Org-mode macro utilities]]
2021-12-28 14:08:56 +01:00
:PROPERTIES:
2022-11-06 15:53:39 +01:00
:CUSTOM_ID: sec:org-macro-utilities
2021-12-28 14:08:56 +01:00
:END:
2022-11-06 15:53:39 +01:00
Listing [[lst:by-backend-kbd-org-macro ]] defines the Emacs Lisp utilities to
define the [[https://orgmode.org/ ][Org mode ]] =kbd= macro in listing
2022-03-02 06:36:12 +01:00
[[lst:source-file-export-keyword-settings ]].
2021-12-29 10:05:43 +01:00
2022-04-18 10:39:08 +02:00
#+attr_latex : :options breaklines
2022-11-06 15:53:39 +01:00
#+caption[Define Emacs Lisp utilities to define the =Org-mode= =kbd= macro]:
#+caption : Define Emacs Lisp utilities to define the =Org-mode= =kbd= macro.
2022-01-09 19:20:15 +01:00
#+name : lst:by-backend-kbd-org-macro
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'emacs
(when (ensure-package-installation 'htmlize)
(autoload 'htmlize-protect-string "htmlize" nil t))
2022-01-09 19:20:15 +01:00
2022-11-07 11:50:17 +01:00
;; https://orgmode.org/worg/org-contrib/babel/languages/ob-doc-LaTeX.html
(defmacro by-backend (&rest body)
"Help for org-export backend dependent execution."
`(cl-case ',(bound-and-true-p org-export-current-backend) ,@body))
2022-01-09 19:20:15 +01:00
2022-11-07 11:50:17 +01:00
(defun by-backend-kbd-org-macro (keys)
"Help for an org-export backend dependent \"#+macro: kbd\"."
(by-backend
(html (format "@@html:<kbd >%s</kbd >@@" (htmlize-protect-string keys)))
(latex (format "@@latex:\\colorbox{PowderBlue}{\\texttt{%s}}@@" keys)))))
2022-01-09 19:20:15 +01:00
#+end_src
2022-11-06 15:53:39 +01:00
*** [[info:org#Export Settings][File inclusion (info)]] and [[info:org#Noweb Reference Syntax][Noweb (info)]] trickery
:PROPERTIES:
:CUSTOM_ID: sec:file-inclusion-and-noweb
:END:
2022-01-09 19:20:15 +01:00
2022-11-13 14:26:06 +01:00
Note: [[https://list.orgmode.org/87sfisf31o.fsf@posteo.net/ ][How to include LaTeX packages in a LaTeX export block ]].
2022-11-06 15:53:39 +01:00
Listing [[lst:source-file-export-keyword-settings ]] shows the preamble lines of this
[[file:README.org ]] file. It lists the export keyword settings, the definition of
the [[https://orgmode.org/ ][Org mode ]] =kbd= macro and the source block that generates part of the LaTeX
preamble. Listing [[lst:latex-header-1 ]], [[lst:latex-header-2 ]], [[lst:latex-header-3 ]],
[[lst:latex-header-4 ]], and [[lst:latex-header-5 ]] show the LaTeX source blocks that
generate the LaTeX preamble. All listings in this section exists thanks to [[info:org#Export Settings][file
inclusion (info)]] and [[info:org#Noweb Reference Syntax ][noweb (info) ]] trickery.
2021-12-29 10:05:43 +01:00
2022-11-06 15:53:39 +01:00
#+caption[Source file export keyword settings]:
#+caption : The preamble lines of README.org containing the export keyword
#+caption : settings, the definition of the Org-mode =kbd= macro, and the
#+caption : source block that generates part of the LaTeX preamble.
#+name : lst:source-file-export-keyword-settings
2023-01-24 07:41:16 +01:00
#+include : "README.org" src org -n :lines "1-17"
2022-11-06 15:53:39 +01:00
#+name : latex-header-1
2023-01-24 07:41:16 +01:00
#+begin_src latex -n :exports none
2022-11-07 11:50:17 +01:00
% Begin of the LaTeX preamble:
% See: https://list.orgmode.org/87o807r7fr.fsf@posteo.net/
% From: "Juan Manuel Macías" <maciaschain@posteo.net >
% To: orgmode <emacs-orgmode@gnu.org >
% Subject: [tip] Insert arbitrary LaTeX code at the beginning of any float environment
% Date: Sun, 08 May 2022 22:22:16 +0000
% Message-ID: <87o807r7fr.fsf@posteo.net >
% LuaLaTeX-, PdfLaTeX-, or XeTeX-COMPILER COMPATIBILITY:
% Prevent collisions by using font packages before compiler specific packages.
\usepackage{ifthen,ifluatex,ifxetex}
\ifthenelse{\boolean{luatex}}{
\usepackage{fontspec} % lualatex
}{\ifthenelse{\boolean{xetex}}{
\usepackage{mathspec} % xetex
}{
\usepackage[T1]{fontenc} % pdflatex
\usepackage[utf8]{inputenc} % pdflatex
2022-11-06 15:53:39 +01:00
}
2022-11-07 11:50:17 +01:00
}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{pifont} % check mark (\ding{52}) and cross mark (\ding{56})
\usepackage{textcomp} % \texttimes
\usepackage{wasysym} % \diameter
% Org-mode REQUIREMENTS:
\usepackage{graphicx}
\usepackage{longtable}
\usepackage{wrapfig}
\usepackage{rotating}
\usepackage[normalem]{ulem}
\usepackage{capt-of}
\usepackage{hyperref}
% End of the 1st LaTeX header block.
2022-11-06 15:53:39 +01:00
#+end_src
2022-02-21 15:56:27 +01:00
2022-11-06 15:53:39 +01:00
#+caption[LaTeX preamble: replacing the =Org-mode= default packages]:
#+caption : LaTeX preamble: replacing the =Org-mode= default packages.
#+name : lst:latex-header-1
2023-01-24 07:41:16 +01:00
#+begin_src latex -n :exports code :noweb yes
2022-11-07 11:50:17 +01:00
<<latex-header-1 >>
2022-11-06 15:53:39 +01:00
#+end_src
#+name : latex-header-2
2023-01-24 07:41:16 +01:00
#+begin_src latex -n :exports none
2022-11-07 11:50:17 +01:00
% LANGUAGE:
\usepackage{babel}
\usepackage{fvextra}
\usepackage{csquotes}
% LISTS:
\usepackage{enumitem}
\setlist{noitemsep}
% LISTINGS:
% Section 2.6 of caption-eng.pdf (texdoc caption) explains that the sign
% of "skip" depends on the assumption "position=above" or "position=below".
% The assumption should match the real caption position in the LaTeX code.
\usepackage{caption}
\usepackage[newfloat]{minted}
\captionsetup[listing]{position=below,skip=0em}
\usemintedstyle{xcode}
% TABLES:
% https://tex.stackexchange.com/questions/341205/
% what-is-the-difference-between-tabular-tabular-and-tabularx-environments
% https://emacs.stackexchange.com/questions/26179/
% change-org-mode-table-style-just-for-latex-export
% https://tex.stackexchange.com/questions/468585/
% table-formatting-using-siunitx
\usepackage{booktabs}
\usepackage{colortbl}
\usepackage{tabularx} % DANGER: beware of Org table :width and :align options!
% End of the 2nd LaTeX header block.
2022-02-21 15:56:27 +01:00
#+end_src
#+caption[LaTeX preamble: language, lists and floats]:
#+caption : LaTeX preamble: language, lists and floats.
2022-11-06 15:53:39 +01:00
#+name : lst:latex-header-2
2023-01-24 07:41:16 +01:00
#+begin_src latex -n :exports code :noweb yes
2022-11-07 11:50:17 +01:00
<<latex-header-2 >>
2022-11-06 15:53:39 +01:00
#+end_src
#+name : latex-header-3
2023-01-24 07:41:16 +01:00
#+begin_src latex -n :exports none
2022-11-07 11:50:17 +01:00
% PAGE LAYOUT:
\usepackage{fancyhdr}
\usepackage{lastpage}
\usepackage[
headheight=20mm,
top=40mm,
bottom=20mm,
left=0.1\paperwidth,
right=0.1\paperwidth,
heightrounded,
verbose,
]{geometry}
% TECHNICS:
\usepackage{siunitx}
\usepackage{tikz}
% End of the 3rd LaTeX header block.
2022-11-06 15:53:39 +01:00
#+end_src
#+caption[LaTeX preamble: page layout and technics]:
2021-12-29 10:05:43 +01:00
#+caption : LaTeX preamble: page layout.
2022-11-06 15:53:39 +01:00
#+name : lst:latex-header-3
2023-01-24 07:41:16 +01:00
#+begin_src latex -n :exports code :noweb yes
2022-11-07 11:50:17 +01:00
<<latex-header-3 >>
2022-11-06 15:53:39 +01:00
#+end_src
#+name : latex-header-4
2023-01-24 07:41:16 +01:00
#+begin_src latex -n :exports none
2022-11-07 11:50:17 +01:00
% FLOAT BARRIERS:
% https://tex.stackexchange.com/questions/118662/use-placeins-for-subsections
% Make section an implicit float barrier:
\usepackage[section]{placeins}
% Make subsection an implicit float barrier:
\makeatletter
\AtBeginDocument{%
\expandafter\renewcommand\expandafter\subsection\expandafter{%
\expandafter\@fb@secFB\subsection
}%
}
\makeatother
% Make subsubsection an implicit float barrier:
\makeatletter
\AtBeginDocument{%
\expandafter\renewcommand\expandafter\subsubsection\expandafter{%
\expandafter\@fb@secFB\subsubsection
}%
}
% End of the 4th LaTeX header block.
2021-12-29 10:05:43 +01:00
#+end_src
#+caption[LaTeX preamble: float barriers]:
#+caption : LaTeX preamble: float barriers.
2022-11-06 15:53:39 +01:00
#+name : lst:latex-header-4
2023-01-24 07:41:16 +01:00
#+begin_src latex -n :exports code :noweb yes
2022-11-07 11:50:17 +01:00
<<latex-header-4 >>
2022-11-06 15:53:39 +01:00
#+end_src
#+name : latex-header-5
2023-01-24 07:41:16 +01:00
#+begin_src latex -n :exports none
2022-11-07 11:50:17 +01:00
% FANCY HEADERS AND FOOTERS:
% Add fancy headers and footers to normal pages.
\pagestyle{fancy}
\fancyhf{}
\renewcommand{\footrulewidth}{0.4pt}
\fancyfoot[C]{\emph{
Emacs setup for use with \LaTeX{}, Org, and Python -- Gerard Vermeulen
}
}
\renewcommand{\headrulewidth}{0.4pt}
\fancyhead[L]{\includegraphics[height=1.8cm]{Org-mode-unicorn.png}}
\fancyhead[C]{
Page: \thepage/\pageref{LastPage} \\
\text{ } \\
\text{ } \\
DRAFT
}
\fancyhead[R]{\includegraphics[height=1.8cm]{Emacs-logo.png}}
% Add fancy header and footer to custom titlepage.
% https://tex.stackexchange.com/questions/506102/
% adding-header-and-footer-to-custom-titlepage
\fancypagestyle{titlepage}{%
2022-11-06 15:53:39 +01:00
\fancyhf{}
\renewcommand{\footrulewidth}{0.4pt}
\fancyfoot[C]{\emph{
2022-11-07 11:50:17 +01:00
Emacs setup for use with \LaTeX{}, Org, and Python -- Gerard Vermeulen}}
2022-11-06 15:53:39 +01:00
\renewcommand{\headrulewidth}{0.4pt}
\fancyhead[L]{\includegraphics[height=1.8cm]{Org-mode-unicorn.png}}
\fancyhead[C]{
2022-11-07 11:50:17 +01:00
\pageref{LastPage} pages \\
2022-11-06 15:53:39 +01:00
\text{ } \\
\text{ } \\
DRAFT
}
\fancyhead[R]{\includegraphics[height=1.8cm]{Emacs-logo.png}}
2022-11-07 11:50:17 +01:00
}
% End of the 5th and last LaTeX header block.
2022-11-06 15:53:39 +01:00
#+end_src
2021-12-29 10:05:43 +01:00
2022-11-06 15:53:39 +01:00
#+caption[LaTeX preamble: fancy headers and footers]:
#+caption : LaTeX preamble: fancy headers and footers.
#+name : lst:latex-header-5
2023-01-24 07:41:16 +01:00
#+begin_src latex -n :exports code :noweb yes
2022-11-07 11:50:17 +01:00
<<latex-header-5 >>
2021-12-28 14:08:56 +01:00
#+end_src
2021-12-29 14:05:03 +01:00
*** [[info:org#LaTeX specific export settings][Advanced LaTeX export settings]]
:PROPERTIES:
:CUSTOM_ID: sec:advanced-latex-export-settings
:END:
2022-02-22 07:58:33 +01:00
Listing [[lst:ox-latex-emacs-lisp-setup ]] initializes the buffer local variables
=org-latex-classes= , =org-latex-title-command= , =org-latex-toc-command= , and
=org-latex-subtitle-format= . Listing [[lst/title-page ]] is a template to initialize
2022-09-18 07:38:29 +02:00
=org-latex-title-command= . Type {{{kbd(C-h v org-latex-classes)}}} , {{{kbd(C-h
v org-latex-subtitle-format)}}}, {{{kbd(C-h v org-latex-title-command)}}} , and
{{{kbd(C-h v org-latex-toc-command)}}} to read how those variables control
2022-02-22 07:58:33 +01:00
exporting from Org-mode to LaTeX.
2021-12-29 14:05:03 +01:00
2022-02-22 07:58:33 +01:00
#+caption[Define buffer local =ox-latex= variables]:
2022-12-21 17:48:54 +01:00
#+caption : Define buffer local =ox-latex= variables.
2022-02-22 07:58:33 +01:00
#+header : :var title-page=lst/title-page
#+name : lst:ox-latex-emacs-lisp-setup
2023-01-24 07:41:16 +01:00
#+begin_src emacs-lisp -n :results silent :tangle no
2022-11-07 11:50:17 +01:00
(when (require 'ox-latex nil 'noerror)
;; https://emacs.stackexchange.com/questions/47347/
;; customizing-org-latex-title-command-to-edit-title-page
(make-variable-buffer-local 'org-latex-classes)
(cl-pushnew '("article-local"
"\\documentclass[11pt]{article}
[NO-DEFAULT-PACKAGES]
[PACKAGES]
[EXTRA]"
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}")
("\\paragraph{%s}" . "\\paragraph*{%s}")
("\\subparagraph{%s}" . "\\subparagraph*{%s}"))
org-latex-classes :key #'car :test #'equal)
(make-variable-buffer-local 'org-latex-title-command)
(setq org-latex-title-command (concat title-page))
(make-variable-buffer-local 'org-latex-toc-command)
(setq org-latex-toc-command "
\\tableofcontents\\label{toc}
\\listoflistings
\\listoftables
\\newpage
")
(make-variable-buffer-local 'org-latex-subtitle-format)
(setq org-latex-subtitle-format ""))
2021-12-29 14:05:03 +01:00
#+end_src
#+caption[Show a title-page example for =org-latex-title-command= ]:
#+caption : Show a title-page example for =org-latex-title-command=.
#+name : lst/title-page
2023-01-24 07:41:16 +01:00
#+begin_src latex -n :exports code :results silent :tangle no
2022-11-07 11:50:17 +01:00
\begin{titlepage}
%% https://tex.stackexchange.com/questions/506102/
%% adding-header-and-footer-to-custom-titlepage
\thispagestyle{titlepage}
\begin{center}
%% Title
\begin{Huge}
{\bf %t} \\
\vspace{1em}
\end{Huge}
%% Author
\begin{Large}
{\bf %a} \\
\vspace{1em}
\end{Large}
\end{center}
\end{titlepage}
2021-12-29 14:05:03 +01:00
#+end_src
2022-01-17 07:56:55 +01:00
*** [[https://orgmode.org/worg/dev/org-syntax-edited.html][Org Syntax]]
:PROPERTIES:
:CUSTOM_ID: sec:org-syntax
:END:
Two tools to grok how [[https://orgmode.org/worg/dev/org-element-api.html ][Org mode parsing ]] works are the [[https://orgmode.org/worg/dev/org-syntax-edited.html ][Org Syntax ]] specification
and the [[http://xahlee.info/emacs/emacs/elisp_parse_org_mode.html ][Org mode parser tutorial ]]. The [[https://orgmode.org/worg/dev/org-element-api.html ][Org element parsing API ]] boils down to three
functions:
1. The function [[https://orgmode.org/worg/dev/org-element-api.html#global ][~org-element-parse-buffer~ ]] implements a fully recursive buffer
parser that returns an abstract syntax tree.
2. The functions [[https://orgmode.org/worg/dev/org-element-api.html#local ][~org-element-at-point~ and ~org-element-context~ ]] return
information on the document structure around point either at the element
level or at the object level in case of ~org-element-context~ .
Listing [[lst:grok-org-element-tree ]] improves the [[http://xahlee.info/emacs/emacs/elisp_parse_org_mode.html ][Org mode parser tutorial ]] by
defining interactive wrappers that pretty print the results of those
non-interactive =org-element= functions to an =Emacs-lisp= buffer.
#+caption[Grok how =org-element= parses your document]:
#+caption : Grok how =org-element= parses your document.
#+name : lst:grok-org-element-tree
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'org-element
(when (require 'pp nil 'noerror)
(defconst grok-org-output
"*Grok Org Element Output* "
"Grok Org output buffer name.")
2022-01-17 07:56:55 +01:00
2022-11-07 11:50:17 +01:00
(defun grok-org-element-at-point ()
(interactive)
(pp-display-expression
(org-element-at-point) grok-org-output))
(defun grok-org-element-context ()
(interactive)
(pp-display-expression
(org-element-context) grok-org-output))
(defun grok-org-element-parse-buffer ()
(interactive)
(let ((what (completing-read
"granularity: "
'(headline element greater-element object)
nil 'require-match)))
2022-01-17 07:56:55 +01:00
(pp-display-expression
2022-11-07 11:50:17 +01:00
(org-element-parse-buffer what) grok-org-output)))
(defun grok-org-heading-components ()
(interactive)
(pp-display-expression
(org-heading-components) grok-org-output))))
2022-01-17 07:56:55 +01:00
#+end_src
2022-04-29 06:16:12 +02:00
** Grammar, spelling, and style tools
:PROPERTIES:
2022-04-30 12:06:45 +02:00
:CUSTOM_ID: sec:writing-tools
2022-04-29 06:16:12 +02:00
:END:
2022-06-05 11:59:13 +02:00
*** [[info:emacs#Abbrevs][Abbrevs (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:writing-abbreviations
:END:
2022-09-11 07:40:22 +02:00
[[https://www.masteringemacs.org/ ][Mickey Peterson ]] has posted [[https://www.masteringemacs.org/article/correcting-typos-misspellings-abbrev ][Correcting Typos and Misspellings with Abbrev ]] showing
how to use [[info:emacs#Keyboard Macros ][Keyboard Macros (info) ]] to exploit [[https://en.wikipedia.org/wiki/Wikipedia:Lists_of_common_misspellings/For_machines][Wikipedia's list of common
misspellings for machines]]. Listing [[lst:misspellings-abbrev ]] defines his
2022-09-11 14:34:03 +02:00
keyboard macro under the name =misspellings-abrev= . I have used those
directions to define src_emacs-lisp{global-abbrev-table} and to store it in
src_emacs-lisp{abbrev-file-name} for git management. I can change the
abbreviation definitions in this file by means of:
1. Execute src_emacs-lisp{(edit-abbrevs)} to alter abbreviation definitions by
editing an =*Abbrevs*= buffer.
2. Add, edit, or remove definitions of the form ="source" 1 "target"= under the
global or a mode-specific table.
3. Execute src_emacs-lisp{(abbrev-edit-save-buffer)} to save all user
abbreviation definitions in the current buffer.
2022-06-05 11:59:13 +02:00
#+caption[Definition of the =misspellings-abbrev= keyboard macro]:
#+caption : Definition of the =misspellings-abbrev= keyboard macro.
#+name : lst:misspellings-abbrev
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'emacs
(defun browse-common-misspellings ()
"Open the Wikipedia page of common misspellings for machines in EWW."
(interactive)
(eww (concat "https://en.wikipedia.org/wiki/Wikipedia"
":Lists_of_common_misspellings/For_machines")))
2022-11-07 12:19:35 +01:00
(fset 'misspellings-abbrev
(kmacro-lambda-form
[?\C-s ?- ?> return backspace backspace ?\C-k ?\C-x ?a ?i ?g ?\C-y return]
0 "%d"))
2022-11-07 11:50:17 +01:00
2022-11-07 12:19:35 +01:00
(setq-default abbrev-mode t))
2022-09-18 12:47:54 +02:00
#+end_src
2022-11-07 12:19:35 +01:00
Listing [[lst:word-games ]] defines the =anagram-p= function that migth be used games.
2022-09-12 07:01:03 +02:00
#+caption[Word games]:
#+caption : Word games.
#+name : lst:word-games
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
;; https://funcall.blogspot.com/2022/07/lets-play-wordle.html
;; https://github.com/tabatkins/wordle-list
(defun anagram-p (evil vile)
"Check whether strings EVIL and VILE are anagrams of each other."
(if (string= evil vile)
nil
(string= (cl-sort evil #'<) (cl-sort vile #'<))))
;; https://funcall.blogspot.com/2020/01/palindromes-redux-and-sufficiently.html
;; https://irreal.org/blog/ ?p=8570
(defun palindrome-p (word)
"Check whether the string WORD is a palindrome."
(cl-do ((head 0 (1+ head))
(tail (1- (length word)) (1- tail))
(ok t))
((or (not ok) (>= head tail) ok)
(setq ok (= (aref word head) (aref word tail))))))
2022-09-12 07:01:03 +02:00
#+end_src
2022-10-12 06:08:27 +02:00
*** [[https://dict.org/bin/Dict][DICT.org]]
:PROPERTIES:
:CUSTOM_ID: sec:writing-dict
:END:
Evaluating src_emacs-lisp{(dictionary)} connects to a local or remote =dictd=
server. The following links explain how to configure and use =dictd= :
1. [[https://jpmens.net/2020/03/08/looking-up-words-with-dict/ ][Looking up words with DICT ]]
2. [[https://www.rfc-editor.org/rfc/rfc2229.html ][RFC 2229: A Dictionary Server Protocol ]]
3. [[https://www.masteringemacs.org/article/wordsmithing-in-emacs ][Wordsmithing in Emacs ]]
I am using the following Debian Bullseye dictionaries on Darwin and Gentoo:
2022-11-06 19:45:57 +01:00
1. [[http://ftp.fr.debian.org/debian/pool/main/d/dict-devil/dict-devil_1.0-13.1_all.deb ][dict-devil_1.0-13.1_all.deb ]]
2. [[http://ftp.fr.debian.org/debian/pool/main/d/dict-foldoc/dict-foldoc_20201018-1_all.deb ][dict-foldoc_20201018-1_all.deb ]]
3. [[http://ftp.fr.debian.org/debian/pool/main/d/dict-gcide/dict-gcide_0.48.5+nmu1_all.deb ][dict-gcide_0.48.5+nmu1_all.deb ]]
2022-10-12 06:08:27 +02:00
4. [[http://ftp.fr.debian.org/debian/pool/main/d/dict-jargon/dict-jargon_4.4.7-3.1_all.deb ][dict-jargon_4.4.7-3.1_all.deb ]]
5. [[http://ftp.fr.debian.org/debian/pool/main/v/vera/dict-vera_1.24-1_all.deb ][dict-vera_1.24-1_all.deb ]]
6. [[http://ftp.fr.debian.org/debian/pool/main/w/wordnet/dict-wn_3.0-36_all.deb ][dict-wn_3.0-36_all.deb ]]
#+caption[Resource file for =dict= on =Darwin= ]:
#+caption : Resource file for =dict= on =Darwin=.
#+name : lst:darwin-dict-resource-file
#+header : :tangle (if (eq 'darwin system-type) "~/.dictrc" "no")
2023-01-24 07:41:16 +01:00
#+begin_src conf -n
2022-11-07 11:50:17 +01:00
# https://jpmens.net/2020/03/08/looking-up-words-with-dict/
server 127.0.0.1 {
port 2628
}
# Local Variables:
# mode: conf-unix
# End:
2022-10-12 06:08:27 +02:00
#+end_src
#+caption[Make a configuration file for =dictd= on =Darwin= ]:
#+caption : Make a configuration file for =dictd= on =Darwin=.
#+name : lst:dictd-configuration-file
2023-01-24 07:41:16 +01:00
#+begin_src shell -n :eval (if (eq 'darwin system-type) "yes" "never") :results silent
2022-11-07 11:50:17 +01:00
cat > ~/.dictd.conf <<EOF
# https://www.masteringemacs.org/article/wordsmithing-in-emacs
database devil {
data "${HOME}/.local/share/dictd/devil.dict.dz"
index "${HOME}/.local/share/dictd/devil.index"
}
database foldoc {
data "${HOME}/.local/share/dictd/foldoc.dict.dz"
index "${HOME}/.local/share/dictd/foldoc.index"
}
database gcide {
data "${HOME}/.local/share/dictd/gcide.dict.dz"
index "${HOME}/.local/share/dictd/gcide.index"
}
database jargon {
data "${HOME}/.local/share/dictd/jargon.dict.dz"
index "${HOME}/.local/share/dictd/jargon.index"
}
database vera {
data "${HOME}/.local/share/dictd/vera.dict.dz"
index "${HOME}/.local/share/dictd/vera.index"
}
database wn {
data "${HOME}/.local/share/dictd/wn.dict.dz"
index "${HOME}/.local/share/dictd/wn.index"
}
EOF
2022-10-12 06:08:27 +02:00
#+end_src
#+caption[Run =dictd= in debug mode on =Darwin= ]:
#+caption : Run =dictd= in debug mode on =Darwin=.
#+name : lst:darwin-dictd-launch
2023-01-24 07:41:16 +01:00
#+begin_src shell -n :eval never :tangle no
2022-11-07 11:50:17 +01:00
# https://jpmens.net/2020/03/08/looking-up-words-with-dict/
/usr/local/sbin/dictd \
--config .dictd.conf \
--verbose \
--logfile .dictd.log \
-d nodetach
2022-10-12 06:08:27 +02:00
#+end_src
*** [[https://github.com/tecosaur/lexic#readme][Emacs LEXICal information viewer]] :noexport:
2022-05-22 14:54:12 +02:00
:PROPERTIES:
:CUSTOM_ID: sec:writing-lexic
2022-10-12 06:08:27 +02:00
:header-args:emacs-lisp: :tangle no
2022-05-22 14:54:12 +02:00
:END:
The [[https://github.com/tecosaur/lexic#readme ][Emacs LEXICal information viewer ]] is a front-end for offline dictionary,
2022-10-12 06:08:27 +02:00
etymology, or thesaurus back-ends (currently limited to [[https://en.wikipedia.org/wiki/Sdcv ][sdcv ]]). Listing
2022-05-22 14:54:12 +02:00
[[lst:configure-lexic ]] configures [[https://github.com/tecosaur/lexic#readme ][lexic ]].
2022-07-01 07:38:53 +02:00
#+attr_latex : :options breaklines
2022-05-22 14:54:12 +02:00
#+caption[Configure =lexic= ]:
#+caption : Configure =lexic=.
#+name : lst:configure-lexic
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(when (ensure-package-installation 'lexic)
;; http://download.huzheng.org/fr/
;; https://polyglotte.tuxfamily.org/doku.php?id=donnees:dicos_bilingues
;; http://download.huzheng.org/dict.org/stardict-dictd-web1913-2.4.2.tar.bz2
;; http://download.huzheng.org/dict.org/stardict-dictd_www.dict.org_gcide-2.4.2.tar.bz2
(with-eval-after-load 'lexic
(if-let ((lpp (executable-find "sdcv")))
2023-01-12 21:28:18 +01:00
(setopt
lexic-program-path lpp
lexic-dictionary-alist '(("full" . t))
2022-11-07 11:50:17 +01:00
;; sdcv --data-dir .local/share -l
2023-01-12 21:28:18 +01:00
lexic-dictionary-list '("Webster's Revised Unabridged Dictionary (1913)"
"dictd_www.dict.org_gcide")
lexic-dictionary-path "~/.local/share")
(message "`lexic' fails to find the `sdcv' executable"))))
2022-05-22 14:54:12 +02:00
#+end_src
2022-11-06 18:10:47 +01:00
*** [[https://wordnet.princeton.edu/][Wordnet]] :noexport:
2022-04-29 06:16:12 +02:00
:PROPERTIES:
2022-04-30 12:06:45 +02:00
:CUSTOM_ID: sec:writing-wordnet
2022-04-29 06:16:12 +02:00
:END:
The [[https://github.com/gromnitsky/wordnut#readme ][wordnut ]] package is a major mode interface to [[https://wordnet.princeton.edu/ ][Wordnet ]], a lexical database for
the English language. Listing [[lst:check-wordnut ]] checks whether the system meets
the [[https://github.com/gromnitsky/wordnut#readme ][wordnut ]] prerequisites.
#+caption[System check for =wordnut= ]:
#+caption : System check for =wordnut=.
#+name : lst:check-wordnut
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent :tangle no
2022-11-07 11:50:17 +01:00
(when (ensure-package-installation 'wordnut)
(with-eval-after-load 'wordnut
(if-let ((wn (executable-find "wn")))
2023-01-12 21:28:18 +01:00
(setopt wordnut-cmd wn)
2022-11-07 11:50:17 +01:00
(message "`wordnut' fails to find the `wn' executable"))))
2022-04-29 06:16:12 +02:00
#+end_src
2022-04-30 09:55:37 +02:00
*** [[https://github.com/bnbeckwith/writegood-mode#readme][Writegood mode]]
:PROPERTIES:
2022-04-30 12:06:45 +02:00
:CUSTOM_ID: sec:writing-writegood-mode
2022-04-30 09:55:37 +02:00
:END:
2022-07-27 07:01:43 +02:00
[[https://github.com/bnbeckwith/writegood-mode#readme ][Writegood mode ]] is a minor mode to aid in finding common writing problems. The post
[[http://matt.might.net/articles/shell-scripts-for-passive-voice-weasel-words-duplicates/ ][Matt Might's "My Ph.D. advisor rewrote himself in bash" scripts ]] inspired this mode.
2022-04-30 09:55:37 +02:00
Listing [[lst:configure-writegood-mode ]] configures [[https://github.com/bnbeckwith/writegood-mode#readme ][writegood mode ]].
#+caption[Configure =writegood-mode= ]:
#+caption : Configure =writegood-mode=.
#+name : lst:configure-writegood-mode
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(when (and (ensure-package-installation 'writegood-mode)
(fboundp 'writegood-mode))
(global-set-key (kbd "C-c g") #'writegood-mode))
2022-04-30 09:55:37 +02:00
#+end_src
2022-07-17 20:10:17 +02:00
* Programming Tools
2022-01-01 11:42:28 +01:00
:PROPERTIES:
2022-07-17 20:10:17 +02:00
:CUSTOM_ID: sec:programming-tools
2022-01-01 11:42:28 +01:00
:END:
2023-01-13 17:49:43 +01:00
** [[info:eglot#Top][Eglot (info)]]
2022-07-17 20:10:17 +02:00
:PROPERTIES:
:CUSTOM_ID: sec:eglot
:END:
2022-10-31 06:42:27 +01:00
[[https://github.com/joaotavora/eglot#readme ][Emacs polyGLOT (Eglot) ]] is an Emacs language-server-protocol client that stays
2023-01-13 17:49:43 +01:00
out of your way. [[info:eglot#Top ][Eglot (info) ]] is a builtin since Emacs-29.0.60. The following
listings contribute to a programming language mode independent [[https://github.com/joaotavora/eglot ][Eglot ]]
configuration:
2022-12-24 16:36:10 +01:00
1. Listing [[lst:minimal-eglot-setup ][minimal Eglot setup ]] ensures installation of [[https://github.com/joaotavora/eglot ][Eglot ]], shows how to get
debug information from the [[https://github.com/python-lsp/python-lsp-server ][Python LSP server ]], and adds key bindings to
=eglot-mode-keymap= .
2022-07-27 07:00:37 +02:00
2. Listing [[lst:help-setup-org-src-mode-for-eglot ]] and
[[lst:setup-python-org-src-mode-for-eglot ]] try to prepare any =org-src-mode=
2022-10-31 06:42:27 +01:00
buffers for use with [[https://github.com/joaotavora/eglot ][Eglot ]]. They are a refactored implementation of the post
2022-07-27 07:00:37 +02:00
[[https://www.reddit.com/r/emacs/comments/w4f4u3/using_rustic_eglot_and_orgbabel_for_literate/ ][Using rustic, eglot, and org-babel with LSP support in Emacs ]] for my use with
Python.
2022-08-08 06:33:28 +02:00
3. Listing [[lst:narrow-format-all-python ]] defines a function to format only the
narrowed region of Python =org-src-mode= blocks prepared by means of the code
in listing [[lst:setup-python-org-src-mode-for-eglot ]]. *Do not use*
=format-all-buffer= *on such buffers* , since =format-all-buffer= does not
handle the narrowing.
2022-10-31 06:42:27 +01:00
4. Listing [[lst:eglot-maybe-ensure ]] starts [[https://github.com/joaotavora/eglot ][Eglot ]] in case of proper programming
2022-07-26 19:56:24 +02:00
modes and proper directory local variables (meaning in presence of a proper
2022-07-27 07:00:37 +02:00
file [[info:emacs#Directory Variables ][.dir-locals.el ]] in the root directory of any project using proper
2022-07-26 19:56:24 +02:00
programming modes).
2022-07-17 20:10:17 +02:00
2022-12-29 08:52:38 +01:00
#+caption[Ensure =eglot= installation with minimal setup]:
#+caption : Ensure =eglot= installation with minimal setup.
2022-12-24 16:36:10 +01:00
#+name : lst:minimal-eglot-setup
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-12-24 16:36:10 +01:00
(with-eval-after-load 'emacs
;; Replace `nil' with `t' for debugging.
(when nil
2022-12-29 08:52:38 +01:00
(when (require 'eglot nil t)
(setq eglot-server-programs
`(((python-ts-mod python-mode)
. ,(eglot-alternatives
'(("pylsp" "-vv")
2023-01-12 21:28:18 +01:00
("ruff-lsp")))))))))
2022-12-24 16:36:10 +01:00
2023-01-12 21:28:18 +01:00
(with-eval-after-load 'eglot
2023-02-26 14:37:33 +01:00
(keymap-set eglot-mode-map "C-c n" 'flymake-goto-next-error)
(keymap-set eglot-mode-map "C-c p" 'flymake-goto-prev-error)
(keymap-set eglot-mode-map "C-c r" 'eglot-rename))
2022-07-17 20:10:17 +02:00
#+end_src
2022-07-27 07:00:37 +02:00
#+caption[Help to setup any =org-src-mode= buffers for =eglot= ]:
#+caption : Help to setup any =org-src-mode= buffers for =eglot=.
#+name : lst:help-setup-org-src-mode-for-eglot
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2023-01-12 21:28:18 +01:00
(with-eval-after-load 'emacs
2022-11-07 11:50:17 +01:00
(defcustom eglot-maybe-ensure-modes '(python-mode)
"Modes where maybe `eglot-ensure' should be or has been called.
This may be in the case of proper directory local variables or in
the case of proper `org-src-mode' buffers.")
;; https://www.reddit.com/r/emacs/comments/w4f4u3
;; /using_rustic_eglot_and_orgbabel_for_literate/
(defun eglot-org-babel-edit-prep (info)
"Try to setup an `org-mode-src' buffer to make `eglot-ensure' succeed.
INFO has a form similar to the return value of
`org-babel-get-src-block-info'. Try to load the tangled file
into the `org-src-mode' buffer as well as to narrow the region to
the Org-mode source block code before calling `eglot-ensure'."
(unless (bound-and-true-p org-src-mode)
(user-error "Buffer %s is no `org-src-mode' buffer" (buffer-name)))
(let ((mark (point))
(body (nth 1 info))
(filename (cdr (assq :tangle (nth 2 info)))))
(when (string= filename "no")
(user-error "Org source block has no tangled file"))
(setq filename (expand-file-name filename))
(unless (file-readable-p filename)
(user-error "Tangled file %s is not readable" filename))
(with-temp-buffer
2022-07-26 19:56:24 +02:00
(insert-file-contents filename 'visit nil nil 'replace)
2022-11-07 11:50:17 +01:00
(unless (search-forward body nil 'noerror)
(user-error "Org source block does not occur in tangled file %s"
filename))
(when (search-forward body nil 'noerror)
(user-error "Org source block occurs twice or more in tangled file %s"
filename)))
(goto-char (point-min))
(insert-file-contents filename 'visit nil nil 'replace)
(let ((max-point (search-forward body))
(min-point (search-backward body)))
(narrow-to-region min-point max-point))
(goto-char mark)
(eglot-ensure))))
2022-07-27 07:00:37 +02:00
#+end_src
2022-07-26 19:56:24 +02:00
2022-07-27 07:00:37 +02:00
#+caption[Setup Python =org-src-mode= buffers for =eglot= ]:
#+caption : Setup Python =org-src-mode= buffers for =eglot=.
#+name : lst:setup-python-org-src-mode-for-eglot
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2023-01-12 21:28:18 +01:00
(with-eval-after-load 'emacs
2022-11-07 11:50:17 +01:00
;; https://www.reddit.com/r/emacs/comments/w4f4u3
;; /using_rustic_eglot_and_orgbabel_for_literate/
(defun undo-eglot-org-babel-edit-prep()
"Undo the `eglot' setup by deleting the text hidden by narrowing.
This is to advice `org-edit-src-exit' and `org-edit-src-save'."
(when (and (bound-and-true-p org-src-mode)
(buffer-file-name)
(apply #'derived-mode-p eglot-maybe-ensure-modes))
(save-excursion
(goto-char (point-min))
(save-restriction
(widen)
(delete-region (point-min) (point)))
(goto-char (point-max))
(save-restriction
(widen)
(delete-region (point) (point-max))))))
(defun org-babel-edit-prep:python (info)
(eglot-org-babel-edit-prep info))
(advice-add 'org-edit-src-exit :before #'undo-eglot-org-babel-edit-prep)
(advice-add 'org-edit-src-save :before #'undo-eglot-org-babel-edit-prep))
2022-07-17 20:10:17 +02:00
#+end_src
2022-08-08 06:33:28 +02:00
#+caption[Experimental =narrow-format-all:python= ]:
#+caption : Experimental =narrow-format-all:python=.
#+name : lst:narrow-format-all-python
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2023-01-12 21:28:18 +01:00
(when (fboundp 'format-all-buffer)
2022-11-07 11:50:17 +01:00
(defun narrow-format-all:python ()
"Format narrowed Python `org-src-mode' buffers correctly.
Use this function instead of `format-all-buffer' on `org-babel-edit-prep:python'
prepared buffers."
(interactive)
(when (eq major-mode 'python-mode)
(let ((source-min (point-min))
(source-max (point-max))
(source (current-buffer))
(target (get-buffer-create "*narrow-format-all:python* ")))
(with-current-buffer target
(barf-if-buffer-read-only)
(erase-buffer)
(save-excursion
(insert-buffer-substring-no-properties
source source-min source-max))
(python-mode)
(setq-local format-all-formatters '(("Python" black)))
(format-all-buffer)
(let ((target-min (point-min))
(target-max (point-max)))
(with-current-buffer source
(erase-buffer)
(save-excursion
(insert-buffer-substring-no-properties
target target-min target-max)))))))))
2022-08-08 06:33:28 +02:00
#+end_src
2022-07-27 07:00:37 +02:00
#+caption[Start =eglot= in case of a proper =dir-local-variables-alist= ]:
#+caption : Start =eglot= in case of a proper =dir-local-variables-alist=.
#+name : lst:eglot-maybe-ensure
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2023-01-12 21:28:18 +01:00
(with-eval-after-load 'emacs
2022-11-07 11:50:17 +01:00
(defun eglot-maybe-ensure ()
(when (and (apply #'derived-mode-p eglot-maybe-ensure-modes)
(assoc 'eglot-workspace-configuration dir-local-variables-alist))
(eglot-ensure)))
2022-07-27 07:00:37 +02:00
2022-11-07 11:50:17 +01:00
;; The two hooks `after-change-major-mode-hook' and
;; `hack-local-variables-hook' are OK, but language mode hooks like
;; `python-mode-hook' are not.
(add-hook 'after-change-major-mode-hook #'eglot-maybe-ensure))
2022-07-27 07:00:37 +02:00
#+end_src
2022-04-28 20:13:57 +02:00
** [[https://github.com/lassik/emacs-format-all-the-code#readme][Format-all]]
:PROPERTIES:
:CUSTOM_ID: sec:format-all
:END:
2022-05-06 17:19:54 +02:00
Listing [[lst:configure-format-all ]]:
1. Configures [[https://github.com/lassik/emacs-format-all-the-code#readme ][format-all ]] which is a package that provides an universal interface
to code formatters of more than 60 computer languages.
2. Adds =format-all-org-babel-post-tangle= to =org-babel-post-tangle-hook= to
format tangled Python code.
2022-04-28 20:13:57 +02:00
#+caption[Configure =format-all= ]:
#+caption : Configure =format-all=.
#+name : lst:configure-format-all
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
;; https://github.com/lassik/emacs-format-all-the-code#readme
;; https://ianyepan.github.io/posts/format-all/
;; https://jamesaimonetti.com/posts/formatting-tangled-output-in-org-mode/
(when (ensure-package-installation 'format-all)
;; (with-eval-after-load 'prog-mode
;; (when (autoload 'format-all-ensure-formatter "format-all")
;; (add-hook 'prog-mode-hook #'format-all-ensure-formatter)))
(with-eval-after-load 'ob-tangle
(add-hook
'org-babel-post-tangle-hook
(defun format-all-org-babel-post-tangle ()
(when (derived-mode-p 'python-mode)
(setq-local format-all-formatters '(("Python" black)))
(format-all-buffer)
(save-buffer)
2023-01-24 07:41:16 +01:00
(message "Saved reformatted tangled buffer `%s'"
(buffer-file-name)))))))
2022-04-28 20:13:57 +02:00
#+end_src
2022-07-17 20:10:17 +02:00
** [[info:flymake#Top][Flymake (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:flymake
:END:
2022-12-24 16:36:10 +01:00
2022-07-17 20:10:17 +02:00
Flymake is an universal on-the-fly syntax checker for Emacs. It is a requirement
of [[https://github.com/joaotavora/eglot ][eglot ]], but you can use it without [[https://github.com/joaotavora/eglot ][eglot ]] for instance in [[https://git.savannah.gnu.org/cgit/emacs.git/tree/lisp/progmodes/python.el ][python-mode ]] buffers
that do not visit a file.
* Programming Modes
:PROPERTIES:
:CUSTOM_ID: sec:programming-languages
:END:
2022-02-28 08:08:17 +01:00
** [[https://dept-info.labri.fr/~strandh/Teaching/PFS/Common/Strandh-Tutorial/Dir-symbolic.html][Common Lisp programming]]
2022-01-23 11:56:37 +01:00
:PROPERTIES:
:CUSTOM_ID: sec:common-lisp-programming
:END:
2022-12-24 16:36:10 +01:00
2022-01-23 11:56:37 +01:00
Listing [[lst:configure-sly ]] configures the [[info:sly#Top ][Sly (info) ]] Common Lisp IDE for Emacs
for use with [[http://www.sbcl.org/ ][Steel Bank Common Lisp (sbcl) ]]:
1. It configures =sly-default-lisp= and =sly-lisp-implementations= as in the
2022-01-24 04:27:47 +01:00
~sly~ documentation string instead of in the [[info:sly#Multiple Lisps ][multiple lisps (info) ]] manual.
2022-01-23 11:56:37 +01:00
2. It ensures the [[info:sly#Auto-SLY ][automatic connection to the lisp server (info) ]] when opening a
Common Lisp file.
3. It configures searching documentation in the [[http://www.lispworks.com/documentation/HyperSpec/Front/ ][Common Lisp HyperSpec ]] according
to the [[info:sly#Basic customization ][basic customization (info) ]] manual.
2022-01-24 04:27:47 +01:00
Finally, listing [[lst:configure-sly ]] uses a technique to [[info:sly#Loading Slynk faster ][load Slynk faster (info) ]]
by means of a custom core file in src_emacs-lisp{no-littering-var-directory}.
Listing [[lst:sbcl-core-for-sly ]] tangles to a script to dump such a [[http://www.sbcl.org/ ][SBCL ]] core.
2022-01-23 11:56:37 +01:00
#+caption[Configure =sly= ]:
#+caption : Configure =sly=.
#+name : lst:configure-sly
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(when (ensure-package-installation 'sly)
(with-eval-after-load 'sly
2023-01-12 21:28:18 +01:00
;; Set `sly-default-lisp' instead of `inferior-lisp-program',
;; because `sly' uses `inferior-lisp-program' only as a backwards
;; compatibility fallback option.
;; The warning "Value ‘ sbcl’ does not match type function" is due to
;; the buggy `defcustom' type of `sbcl-default-lisp' in `sly.el'.
(setopt sly-default-lisp 'sbcl
sly-lisp-implementations
`((sbcl (,(executable-find "sbcl")
"--core"
,(no-littering-expand-var-file-name "sbcl.core-for-sly")))))
2022-11-07 11:50:17 +01:00
(add-hook 'sly-mode-hook
(defun on-sly-mode-hook ()
(unless (sly-connected-p)
(save-excursion (sly)))))
2022-04-30 18:59:01 +02:00
2022-11-07 11:50:17 +01:00
(cond
((eq system-type 'darwin)
(setq common-lisp-hyperspec-root
"file:///usr/local/share/doc/hyperspec/HyperSpec/ ")
(setq common-lisp-hyperspec-symbol-table
(concat common-lisp-hyperspec-root "Data/Map_Sym.txt")))
((eq system-type 'gnu/linux)
(setq common-lisp-hyperspec-root
"file:///usr/share/doc/hyperspec-7.0/HyperSpec/ "))
(t (message "Default Common Lisp HyperSpec access")))
2022-04-30 18:59:01 +02:00
2023-02-26 14:37:33 +01:00
(keymap-set sly-prefix-map "M-h" #'sly-documentation-lookup)))
2022-01-23 11:56:37 +01:00
#+end_src
2022-01-24 04:27:47 +01:00
#+caption[Script to dump a SBCL core for the Sly Common Lisp IDE]:
#+caption : Script to dump a SBCL core for the Sly Common Lisp IDE.
#+header : :tangle-mode (identity #o755)
#+name : lst:sbcl-core-for-sly
2023-01-24 07:41:16 +01:00
#+begin_src shell -n :noeval :tangle ~/bin/sbcl.core-for-sly
2022-11-07 11:50:17 +01:00
#!/bin/sh
2022-01-24 04:27:47 +01:00
2022-11-07 11:50:17 +01:00
sbcl <<EOF
(mapc 'require '(sb-bsd-sockets sb-posix sb-introspect sb-cltl2 asdf))
(save-lisp-and-die "sbcl.core-for-sly")
EOF
2022-01-24 04:27:47 +01:00
2022-11-07 11:50:17 +01:00
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# sh-basic-offset: 2
# End:
2022-01-24 04:27:47 +01:00
#+end_src
2023-02-26 21:44:42 +01:00
*** [[https://www.n16f.net/blog/custom-font-lock-configuration-in-emacs/][Common Lisp custom font locking]]
:PROPERTIES:
:CUSTOM_ID: sec:cl-custom-font-locking
:END:
#+caption[Define faces for =Common Lisp= custom font locking]:
#+caption : Define faces for =Common Lisp= custom-font-locking.
#+name : lst:cl-custom-font-locking-faces
2023-02-26 13:30:20 +01:00
#+begin_src emacs-lisp -n :results silent
;;; Common Lisp custom font lock configuration.
;;; https://www.n16f.net/blog/custom-font-lock-configuration-in-emacs/
(defface cl-character-face
'((default :inherit font-lock-constant-face))
"The face used to highlight Common Lisp character literals.")
(defface cl-standard-function-face
'((default :inherit font-lock-keyword-face))
"The face used to highlight standard Common Lisp function symbols.")
(defface cl-standard-value-face
'((default :inherit font-lock-variable-name-face))
"The face used to highlight standard Common Lisp value symbols.")
#+end_src
2023-02-26 21:44:42 +01:00
#+caption[Setup =SLY= and =Common Lisp= to find standard symbol names]:
#+caption : Setup =SLY= and =Common Lisp= to find standard symbol names.
#+name : lst:sly-cl-standard-symbol-names
2023-02-26 13:30:20 +01:00
#+begin_src lisp -n :eval never-export :results silent :tangle no
(rplacd (assoc 'slynk:*string-elision-length* slynk:*slynk-pprint-bindings* )
(ash 1 14))
(defun standard-symbol-names (predicate)
(let ((symbols nil))
(do-external-symbols (symbol :common-lisp)
(when (funcall predicate symbol)
(push (string-downcase (symbol-name symbol)) symbols)))
(sort symbols #'string<)))
#+end_src
2023-02-26 21:44:42 +01:00
#+caption[Define the =cl-function-names= variable in an =Emacs Lisp= block]:
#+caption : Use =Common Lisp= to define the =cl-function-names= variable in
#+caption : an =Emacs Lisp= source block for tangling into =user-init-file=.
2023-02-26 13:30:20 +01:00
#+name : lst:define-cl-function-names
2023-02-26 21:44:42 +01:00
#+header : :wrap "src emacs-lisp -n :results silent"
#+begin_src lisp -n :exports both :eval never-export
2023-02-26 13:30:20 +01:00
(format nil "(defvar~% cl-function-names~ % '~S)~ %"
(standard-symbol-names #'fboundp))
#+end_src
#+RESULTS : lst:define-cl-function-names
2023-02-26 21:44:42 +01:00
#+begin_src emacs-lisp -n :results silent
2023-02-26 13:30:20 +01:00
(defvar
cl-function-names
'("*" "+" "-" "/" "/=" "1+ " "1-" "<" "<=" "=" " >" ">=" "abort" "abs" "acons"
"acos" "acosh" "add-method" "adjoin" "adjust-array" "adjustable-array-p"
"allocate-instance" "alpha-char-p" "alphanumericp" "and" "append" "apply"
"apropos" "apropos-list" "aref" "arithmetic-error-operands"
"arithmetic-error-operation" "array-dimension" "array-dimensions"
"array-displacement" "array-element-type" "array-has-fill-pointer-p"
"array-in-bounds-p" "array-rank" "array-row-major-index" "array-total-size"
"arrayp" "ash" "asin" "asinh" "assert" "assoc" "assoc-if" "assoc-if-not"
"atan" "atanh" "atom" "bit" "bit-and" "bit-andc1" "bit-andc2" "bit-eqv"
"bit-ior" "bit-nand" "bit-nor" "bit-not" "bit-orc1" "bit-orc2"
"bit-vector-p" "bit-xor" "block" "boole" "both-case-p" "boundp" "break"
"broadcast-stream-streams" "butlast" "byte" "byte-position" "byte-size"
"caaaar" "caaadr" "caaar" "caadar" "caaddr" "caadr" "caar" "cadaar"
"cadadr" "cadar" "caddar" "cadddr" "caddr" "cadr" "call-method" "car"
"case" "catch" "ccase" "cdaaar" "cdaadr" "cdaar" "cdadar" "cdaddr" "cdadr"
"cdar" "cddaar" "cddadr" "cddar" "cdddar" "cddddr" "cdddr" "cddr" "cdr"
"ceiling" "cell-error-name" "cerror" "change-class" "char" "char-code"
"char-downcase" "char-equal" "char-greaterp" "char-int" "char-lessp"
"char-name" "char-not-equal" "char-not-greaterp" "char-not-lessp"
"char-upcase" "char/=" "char<" "char<= " "char=" "char>" "char>= "
"character" "characterp" "check-type" "cis" "class-name" "class-of"
"clear-input" "clear-output" "close" "clrhash" "code-char" "coerce"
"compile" "compile-file" "compile-file-pathname" "compiled-function-p"
"compiler-macro-function" "complement" "complex" "complexp"
"compute-applicable-methods" "compute-restarts" "concatenate"
"concatenated-stream-streams" "cond" "conjugate" "cons" "consp"
"constantly" "constantp" "continue" "copy-alist" "copy-list"
"copy-pprint-dispatch" "copy-readtable" "copy-seq" "copy-structure"
"copy-symbol" "copy-tree" "cos" "cosh" "count" "count-if" "count-if-not"
"ctypecase" "decf" "declaim" "decode-float" "decode-universal-time"
"defclass" "defconstant" "defgeneric" "define-compiler-macro"
"define-condition" "define-method-combination" "define-modify-macro"
"define-setf-expander" "define-symbol-macro" "defmacro" "defmethod"
"defpackage" "defparameter" "defsetf" "defstruct" "deftype" "defun"
"defvar" "delete" "delete-duplicates" "delete-file" "delete-if"
"delete-if-not" "delete-package" "denominator" "deposit-field" "describe"
"describe-object" "destructuring-bind" "digit-char" "digit-char-p"
"directory" "directory-namestring" "disassemble" "do" "do*"
"do-all-symbols" "do-external-symbols" "do-symbols" "documentation"
"dolist" "dotimes" "dpb" "dribble" "ecase" "echo-stream-input-stream"
"echo-stream-output-stream" "ed" "eighth" "elt" "encode-universal-time"
"endp" "enough-namestring" "ensure-directories-exist"
"ensure-generic-function" "eq" "eql" "equal" "equalp" "error" "etypecase"
"eval" "eval-when" "evenp" "every" "exp" "export" "expt" "fboundp"
"fceiling" "fdefinition" "ffloor" "fifth" "file-author"
"file-error-pathname" "file-length" "file-namestring" "file-position"
"file-string-length" "file-write-date" "fill" "fill-pointer" "find"
"find-all-symbols" "find-class" "find-if" "find-if-not" "find-method"
"find-package" "find-restart" "find-symbol" "finish-output" "first" "flet"
"float" "float-digits" "float-precision" "float-radix" "float-sign"
"floatp" "floor" "fmakunbound" "force-output" "format" "formatter" "fourth"
"fresh-line" "fround" "ftruncate" "funcall" "function" "function-keywords"
"function-lambda-expression" "functionp" "gcd" "gensym" "gentemp" "get"
"get-decoded-time" "get-dispatch-macro-character" "get-internal-real-time"
"get-internal-run-time" "get-macro-character" "get-output-stream-string"
"get-properties" "get-setf-expansion" "get-universal-time" "getf" "gethash"
"go" "graphic-char-p" "handler-bind" "handler-case" "hash-table-count"
"hash-table-p" "hash-table-rehash-size" "hash-table-rehash-threshold"
"hash-table-size" "hash-table-test" "host-namestring" "identity" "if"
"ignore-errors" "imagpart" "import" "in-package" "incf"
"initialize-instance" "input-stream-p" "inspect" "integer-decode-float"
"integer-length" "integerp" "interactive-stream-p" "intern" "intersection"
"invalid-method-error" "invoke-debugger" "invoke-restart"
"invoke-restart-interactively" "isqrt" "keywordp" "labels" "lambda" "last"
"lcm" "ldb" "ldb-test" "ldiff" "length" "let" "let*"
"lisp-implementation-type" "lisp-implementation-version" "list" "list*"
"list-all-packages" "list-length" "listen" "listp" "load"
"load-logical-pathname-translations" "load-time-value" "locally" "log"
"logand" "logandc1" "logandc2" "logbitp" "logcount" "logeqv"
"logical-pathname" "logical-pathname-translations" "logior" "lognand"
"lognor" "lognot" "logorc1" "logorc2" "logtest" "logxor" "long-site-name"
"loop" "loop-finish" "lower-case-p" "machine-instance" "machine-type"
"machine-version" "macro-function" "macroexpand" "macroexpand-1" "macrolet"
"make-array" "make-broadcast-stream" "make-concatenated-stream"
"make-condition" "make-dispatch-macro-character" "make-echo-stream"
"make-hash-table" "make-instance" "make-instances-obsolete" "make-list"
"make-load-form" "make-load-form-saving-slots" "make-package"
"make-pathname" "make-random-state" "make-sequence" "make-string"
"make-string-input-stream" "make-string-output-stream" "make-symbol"
"make-synonym-stream" "make-two-way-stream" "makunbound" "map" "map-into"
"mapc" "mapcan" "mapcar" "mapcon" "maphash" "mapl" "maplist" "mask-field"
"max" "member" "member-if" "member-if-not" "merge" "merge-pathnames"
"method-combination-error" "method-qualifiers" "min" "minusp" "mismatch"
"mod" "muffle-warning" "multiple-value-bind" "multiple-value-call"
"multiple-value-list" "multiple-value-prog1" "multiple-value-setq"
"name-char" "namestring" "nbutlast" "nconc" "nintersection" "ninth"
"no-applicable-method" "no-next-method" "not" "notany" "notevery" "nreconc"
"nreverse" "nset-difference" "nset-exclusive-or" "nstring-capitalize"
"nstring-downcase" "nstring-upcase" "nsublis" "nsubst" "nsubst-if"
"nsubst-if-not" "nsubstitute" "nsubstitute-if" "nsubstitute-if-not" "nth"
"nth-value" "nthcdr" "null" "numberp" "numerator" "nunion" "oddp" "open"
"open-stream-p" "or" "output-stream-p" "package-error-package"
"package-name" "package-nicknames" "package-shadowing-symbols"
"package-use-list" "package-used-by-list" "packagep" "pairlis"
"parse-integer" "parse-namestring" "pathname" "pathname-device"
"pathname-directory" "pathname-host" "pathname-match-p" "pathname-name"
"pathname-type" "pathname-version" "pathnamep" "peek-char" "phase" "plusp"
"pop" "position" "position-if" "position-if-not" "pprint" "pprint-dispatch"
"pprint-exit-if-list-exhausted" "pprint-fill" "pprint-indent"
"pprint-linear" "pprint-logical-block" "pprint-newline" "pprint-pop"
"pprint-tab" "pprint-tabular" "prin1" "prin1-to-string" "princ"
"princ-to-string" "print" "print-not-readable-object" "print-object"
"print-unreadable-object" "probe-file" "proclaim" "prog" "prog*" "prog1"
"prog2" "progn" "progv" "provide" "psetf" "psetq" "push" "pushnew" "quote"
"random" "random-state-p" "rassoc" "rassoc-if" "rassoc-if-not" "rational"
"rationalize" "rationalp" "read" "read-byte" "read-char"
"read-char-no-hang" "read-delimited-list" "read-from-string" "read-line"
"read-preserving-whitespace" "read-sequence" "readtable-case" "readtablep"
"realp" "realpart" "reduce" "reinitialize-instance" "rem" "remf" "remhash"
"remove" "remove-duplicates" "remove-if" "remove-if-not" "remove-method"
"remprop" "rename-file" "rename-package" "replace" "require" "rest"
"restart-bind" "restart-case" "restart-name" "return" "return-from"
"revappend" "reverse" "room" "rotatef" "round" "row-major-aref" "rplaca"
"rplacd" "sbit" "scale-float" "schar" "search" "second" "set"
"set-difference" "set-dispatch-macro-character" "set-exclusive-or"
"set-macro-character" "set-pprint-dispatch" "set-syntax-from-char" "setf"
"setq" "seventh" "shadow" "shadowing-import" "shared-initialize" "shiftf"
"short-site-name" "signal" "signum" "simple-bit-vector-p"
"simple-condition-format-arguments" "simple-condition-format-control"
"simple-string-p" "simple-vector-p" "sin" "sinh" "sixth" "sleep"
"slot-boundp" "slot-exists-p" "slot-makunbound" "slot-missing"
"slot-unbound" "slot-value" "software-type" "software-version" "some"
"sort" "special-operator-p" "sqrt" "stable-sort" "standard-char-p" "step"
"store-value" "stream-element-type" "stream-error-stream"
"stream-external-format" "streamp" "string" "string-capitalize"
"string-downcase" "string-equal" "string-greaterp" "string-left-trim"
"string-lessp" "string-not-equal" "string-not-greaterp" "string-not-lessp"
"string-right-trim" "string-trim" "string-upcase" "string/=" "string<"
"string<=" "string=" "string >" "string>=" "stringp" "sublis" "subseq"
"subsetp" "subst" "subst-if" "subst-if-not" "substitute" "substitute-if"
"substitute-if-not" "subtypep" "svref" "sxhash" "symbol-function"
"symbol-macrolet" "symbol-name" "symbol-package" "symbol-plist"
"symbol-value" "symbolp" "synonym-stream-symbol" "tagbody" "tailp" "tan"
"tanh" "tenth" "terpri" "the" "third" "throw" "time" "trace"
"translate-logical-pathname" "translate-pathname" "tree-equal" "truename"
"truncate" "two-way-stream-input-stream" "two-way-stream-output-stream"
"type-error-datum" "type-error-expected-type" "type-of" "typecase" "typep"
"unbound-slot-instance" "unexport" "unintern" "union" "unless"
"unread-char" "untrace" "unuse-package" "unwind-protect"
"update-instance-for-different-class" "update-instance-for-redefined-class"
"upgraded-array-element-type" "upgraded-complex-part-type" "upper-case-p"
"use-package" "use-value" "user-homedir-pathname" "values" "values-list"
"vector" "vector-pop" "vector-push" "vector-push-extend" "vectorp" "warn"
"when" "wild-pathname-p" "with-accessors" "with-compilation-unit"
"with-condition-restarts" "with-hash-table-iterator"
"with-input-from-string" "with-open-file" "with-open-stream"
"with-output-to-string" "with-package-iterator" "with-simple-restart"
"with-slots" "with-standard-io-syntax" "write" "write-byte" "write-char"
"write-line" "write-sequence" "write-string" "write-to-string" "y-or-n-p"
"yes-or-no-p" "zerop"))
#+end_src
2023-02-26 21:44:42 +01:00
\newpage
#+caption[Define the =cl-variable-names= variable in an =Emacs Lisp= block]:
#+caption : Use =Common Lisp= to define the =cl-variable-names= variable in
#+caption : an =Emacs Lisp= source block for tangling into =user-init-file=.
2023-02-26 13:30:20 +01:00
#+name : lst:define-cl-value-names
2023-02-26 21:44:42 +01:00
#+header : :wrap "src emacs-lisp -n :results silent"
#+begin_src lisp -n :exports both :eval never-export
2023-02-26 13:30:20 +01:00
(format nil "(defvar~% cl-value-names~ % '~S)~ %"
(standard-symbol-names #'boundp))
#+end_src
#+RESULTS : lst:define-cl-value-names
2023-02-26 21:44:42 +01:00
#+begin_src emacs-lisp -n :results silent
2023-02-26 13:30:20 +01:00
(defvar
cl-value-names
'("*" "* *" "* **" "*break-on-signals* " "*compile-file-pathname* "
"*compile-file-truename* " "*compile-print* " "*compile-verbose* "
"*debug-io* " "*debugger-hook* " "*default-pathname-defaults* "
"*error-output* " "*features* " "*gensym-counter* " "*load-pathname* "
"*load-print* " "*load-truename* " "*load-verbose* " "*macroexpand-hook* "
"*modules* " "*package* " "*print-array* " "*print-base* " "*print-case* "
"*print-circle* " "*print-escape* " "*print-gensym* " "*print-length* "
"*print-level* " "*print-lines* " "*print-miser-width* "
"*print-pprint-dispatch* " "*print-pretty* " "*print-radix* "
"*print-readably* " "*print-right-margin* " "*query-io* " "*random-state* "
"*read-base* " "*read-default-float-format* " "*read-eval* " "*read-suppress* "
"*readtable* " "*standard-input* " "*standard-output* " "*terminal-io* "
"*trace-output* " "+" "+ +" "+ ++" "-" "/" "/ /" "/ //" "array-dimension-limit"
"array-rank-limit" "array-total-size-limit" "boole-1" "boole-2" "boole-and"
"boole-andc1" "boole-andc2" "boole-c1" "boole-c2" "boole-clr" "boole-eqv"
"boole-ior" "boole-nand" "boole-nor" "boole-orc1" "boole-orc2" "boole-set"
"boole-xor" "call-arguments-limit" "char-code-limit" "double-float-epsilon"
"double-float-negative-epsilon" "internal-time-units-per-second"
"lambda-list-keywords" "lambda-parameters-limit"
"least-negative-double-float" "least-negative-long-float"
"least-negative-normalized-double-float"
"least-negative-normalized-long-float"
"least-negative-normalized-short-float"
"least-negative-normalized-single-float" "least-negative-short-float"
"least-negative-single-float" "least-positive-double-float"
"least-positive-long-float" "least-positive-normalized-double-float"
"least-positive-normalized-long-float"
"least-positive-normalized-short-float"
"least-positive-normalized-single-float" "least-positive-short-float"
"least-positive-single-float" "long-float-epsilon"
"long-float-negative-epsilon" "most-negative-double-float"
"most-negative-fixnum" "most-negative-long-float"
"most-negative-short-float" "most-negative-single-float"
"most-positive-double-float" "most-positive-fixnum"
"most-positive-long-float" "most-positive-short-float"
"most-positive-single-float" "multiple-values-limit" "nil" "pi"
"short-float-epsilon" "short-float-negative-epsilon" "single-float-epsilon"
"single-float-negative-epsilon" "t"))
#+end_src
2023-02-26 21:44:42 +01:00
#+caption[Finalize =Common Lisp= custom font locking]:
#+caption : Finalize =Common Lisp= custom font locking.
#+name : lst:finalize-cl-custom-font-locking
2023-02-26 13:30:20 +01:00
#+begin_src emacs-lisp -n :results silent
(defvar cl-font-lock-keywords
(let* ((character-re (concat "#\\\\" lisp-mode-symbol-regexp "\\_>"))
(function-re (concat "(" (regexp-opt cl-function-names t) "\\_>"))
(value-re (regexp-opt cl-value-names 'symbols)))
`((,character-re . 'cl-character-face)
(,function-re
(1 'cl-standard-function-face))
(,value-re . 'cl-standard-value-face))))
(defvar cl-font-lock-defaults
'((cl-font-lock-keywords)
nil ; enable syntaxic highlighting
t ; case insensitive highlighting
nil ; use the lisp-mode syntax table
(font-lock-mark-block-function . mark-defun)
(font-lock-extra-managed-props help-echo)
(font-lock-syntactic-face-function
. lisp-font-lock-syntactic-face-function)))
(defun cl-init-lisp-font-lock ()
(setq font-lock-defaults cl-font-lock-defaults))
(add-hook 'lisp-mode-hook 'cl-init-lisp-font-lock)
#+end_src
2022-01-24 04:27:47 +01:00
*** [[https://courses.cs.northwestern.edu/325/][CS 325 AI Programming]]
:PROPERTIES:
2022-02-08 20:37:06 +01:00
:CUSTOM_ID: sec:cs-325-ai-programming
2022-01-24 04:27:47 +01:00
:END:
2022-08-05 07:21:13 +02:00
2022-01-24 04:27:47 +01:00
The [[https://courses.cs.northwestern.edu/325/ ][CS 325 AI Programming ]] course allows to learn Common Lisp by self-study and
the page [[https://courses.cs.northwestern.edu/325/admin/lisp-setup.php ][CS 325: Setting up Lisp ]] gives instructions how to:
1. [[https://courses.cs.northwestern.edu/325/admin/lisp-setup.php#lisp ][Download and install common lisp ]].
2. [[https://courses.cs.northwestern.edu/325/admin/lisp-setup.php#quicklisp ][Install Quicklisp ]].
3. [[https://courses.cs.northwestern.edu/325/admin/lisp-setup.php#install-325 ][Install the CS325 library ]].
*** [[https://www.quicklisp.org/][Quicklisp]]
:PROPERTIES:
:CUSTOM_ID: sec:quicklisp
:END:
2022-08-05 07:21:13 +02:00
2022-01-24 04:27:47 +01:00
[[https://www.quicklisp.org/ ][Quicklisp ]] is a library manager for Common Lisp. Listing
[[lst:download+verify-quicklisp ]] downloads the [[https://www.quicklisp.org/ ][Quicklisp ]] file and verifies its
signature to prevent tampering. Listing [[lst:bootstrap-quicklisp ]] tangles to a
shell script allowing to bootstrap [[https://www.quicklisp.org/ ][Quicklisp ]] with [[http://www.sbcl.org/ ][SBCL ]]. Listing
[[lst:quicklisp-sbclrc-file ]] tangles to the a [[http://www.sbcl.org/ ][SBCL ]] resource file with [[https://www.quicklisp.org/ ][Quicklisp ]]
support.
#+caption[Download and verify =quicklisp= ]:
#+caption : Download and verify =quicklisp=.
#+name : lst:download+verify-quicklisp
2023-01-24 07:41:16 +01:00
#+begin_src shell -n :dir ~ :results none :tangle no
2022-11-07 11:50:17 +01:00
curl -sS -O https://beta.quicklisp.org/quicklisp.lisp
curl -sS -O https://beta.quicklisp.org/quicklisp.lisp.asc
curl -sS -O https://beta.quicklisp.org/release-key.txt
gpg --import release-key.txt
gpg --verify quicklisp.lisp.asc quicklisp.lisp
2022-01-24 04:27:47 +01:00
#+end_src
#+caption[Bootstrap =quicklisp= ]:
#+caption : Bootstrap =quicklisp=.
#+header : :tangle-mode (identity #o755)
#+name : lst:bootstrap-quicklisp
2023-01-24 07:41:16 +01:00
#+begin_src shell -n :noeval :tangle ~/bin/quicklisp-sbcl-bootstrap
2022-11-07 11:50:17 +01:00
#!/bin/sh
2022-01-24 04:27:47 +01:00
2022-11-07 11:50:17 +01:00
sbcl --load ~/quicklisp.lisp <<EOF
(quicklisp-quickstart:install)
(quit)
EOF
2022-01-24 04:27:47 +01:00
2022-11-07 11:50:17 +01:00
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# sh-basic-offset: 2
# End:
2022-01-24 04:27:47 +01:00
#+end_src
#+caption[A =quicklisp= sbclrc file]:
#+caption : A =quicklisp= sbclrc file.
#+name : lst:quicklisp-sbclrc-file
2023-01-24 07:41:16 +01:00
#+begin_src lisp -n :eval never-export :tangle ~/.sbclrc
2022-11-07 11:50:17 +01:00
;;; Hey Emacs, this is my -*- lisp -* - .sbclrc file.
#-quicklisp
(let ((quicklisp-init (merge-pathnames "quicklisp/setup.lisp"
(user-homedir-pathname))))
(when (probe-file quicklisp-init)
(load quicklisp-init)))
2022-01-24 04:27:47 +01:00
#+end_src
2022-01-23 11:56:37 +01:00
2022-01-27 09:50:39 +01:00
** [[info:eintr#Top][Emacs Lisp Programming (info)]]
2022-01-01 11:42:28 +01:00
:PROPERTIES:
:CUSTOM_ID: sec:emacs-lisp-programming
:END:
2022-10-30 09:34:40 +01:00
Here is a list of links describing how to program and debug [[info:elisp#Top ][Emacs Lisp (info) ]] code:
2022-01-27 09:50:39 +01:00
1. [[https://www.masteringemacs.org/article/evaluating-elisp-emacs ][Evaluating Elisp in Emacs ]]
2. [[https://endlessparentheses.com/debugging-emacs-lisp-part-1-earn-your-independence.html ][Debugging Elisp Part 1: Earn your independence ]]
3. [[https://endlessparentheses.com/debugging-elisp-part-2-advanced-topics.html ][Debugging Elisp Part 2: Advanced topics ]]
4. [[http://xahlee.info/talk_show/xah_talk_show_2022-01-20.html ][Xah talk show: Elisp coding: xah-add-space-after-comma ]]
5. [[http://xahlee.info/talk_show/xah_talk_show_2022-01-22.html ][Xah talk show: Elisp coding: narrow-to-region, sort-lines, hilight-unicode ]]
2022-11-06 15:53:39 +01:00
Ref. [cite:@Monnier.ACM-PL.4.1] exposes the evolution of Emacs Lisp and explains
many Emacs Lisp idioms.
2023-01-12 21:28:18 +01:00
Listing [[lst:setup-ielm ][setup ielm ]] configures the [[https://wikemacs.org/wiki/IELM ][Interactive Emacs Lisp Mode ]] for better
2023-01-03 17:17:23 +01:00
interoperability with [[https://smartparens.readthedocs.io/en/latest/ ][Smartparens ]]: get help on the key bindings by means of
2023-01-03 21:03:10 +01:00
src_emacs-lisp{(describe-function 'inferior-emacs-lisp-mode)}.
2023-01-03 17:17:23 +01:00
2023-01-03 21:03:10 +01:00
#+caption[Setup =ielm= ]:
#+caption : Setup =ielm=.
2023-01-03 17:17:23 +01:00
#+name : lst:setup-ielm
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2023-01-03 17:17:23 +01:00
(with-eval-after-load 'ielm
2023-01-10 19:03:26 +01:00
(setopt ielm-dynamic-return nil))
2023-01-03 17:17:23 +01:00
#+end_src
2023-03-05 10:55:27 +01:00
*** [[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
2022-10-02 07:22:00 +02:00
** [[https://fennel-lang.org/][Fennel Programming]]
:PROPERTIES:
:CUSTOM_ID: sec:fennel-programming
:END:
2022-10-30 09:34:40 +01:00
Here is a list of links describing how to install and setup [[https://fennel-lang.org/ ][Fennel ]] and how to
install and use [[https://gitlab.com/andreyorst/ob-fennel ][ob-fennel ]] with the [[https://love2d.org/ ][LÖVE 2D game engine ]]:
1. [[https://fennel-lang.org/ ][The Fennel Programming Language ]]
2. [[https://fennel-lang.org/setup ][Setting up Fennel ]]
3. [[https://gitlab.com/andreyorst/ob-fennel ][Org Babel support for the Fennel language: ob-fennel ]]
4. [[https://andreyorst.gitlab.io/posts/2022-09-26-reproducible-research-with-org-mode-fennel-and-love/ ][Reproducible Research with Org Mode, Fennel, and LÖVE ]]
2022-10-30 18:48:47 +01:00
#+caption[Install =fennel-mode= and =ob-fennel= when =fennel= is an executable]:
#+caption : Install =fennel-mode= and =ob-fennel= when =fennel= is an executable.
2022-10-02 07:22:00 +02:00
#+name : lst:install-ob-fennel-mode
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(when (and (executable-find "fennel")
2023-01-28 11:44:29 +01:00
(ensure-package-installation 'fennel-mode))
2022-11-07 11:50:17 +01:00
(unless (package-installed-p 'ob-fennel)
2023-01-28 11:44:29 +01:00
(package-vc-install "https://gitlab.com/andreyorst/ob-fennel"))
(when (package-installed-p 'ob-fennel)
(ensure-package-installation 'ob-fennel)
2023-01-20 07:06:51 +01:00
(set-org-babel-language-activity 'fennel (fboundp 'fennel-mode))))
2022-10-02 07:22:00 +02:00
#+end_src
#+caption[Fennel example]:
#+caption : Fennel example.
2022-10-08 20:26:46 +02:00
#+header : :var x=10 y=20
2022-10-02 07:22:00 +02:00
#+name : lst:fennel-example
2023-01-24 07:41:16 +01:00
#+begin_src fennel -n :eval never-export :results silent :session fennel
2022-11-07 11:50:17 +01:00
(+ x y)
2022-10-02 07:22:00 +02:00
#+end_src
2022-10-30 18:48:47 +01:00
#+caption[Install =Fennel= with luarocks on Darwin]:
#+caption : Install =Fennel= with luarocks on Darwin.
#+name : lst:install-fennel-on-darwin
2023-01-24 07:41:16 +01:00
#+begin_src shell -n :eval never :results silent :tangle no
2022-11-07 11:50:17 +01:00
luarocks \
install --local readline \
HISTORY_INCDIR=/usr/local/opt/readline/include \
HISTORY_DIR=/usr/local/opt/readline/lib
2022-10-30 18:48:47 +01:00
#+end_src
2022-10-02 07:22:00 +02:00
** [[https://www.lua.org/][Lua Programming]]
:PROPERTIES:
:CUSTOM_ID: sec:lua-programming
:END:
#+caption[Install =lua-mode= in case of =Lua= ]:
#+caption : Install =lua-mode= in case of =Lua=.
#+name : lst:install-lua-mode
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(when (and (executable-find "lua")
(ensure-package-installation 'company-lua 'lua-mode)))
2022-10-02 07:22:00 +02:00
#+end_src
#+caption[Lua example]:
#+caption : Lua example.
#+name : lst:lua-example
2023-01-24 07:41:16 +01:00
#+begin_src lua -n :results silent :var x=10 y=20
2022-11-07 11:50:17 +01:00
return (x+y)
2022-10-02 07:22:00 +02:00
#+end_src
2022-07-01 10:02:05 +02:00
** [[info:maxima#Top][Maxima Programming (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:maxima-programming
:END:
2022-07-01 14:11:48 +02:00
Listing [[lst:configure-maxima ]] configures [[https://gitlab.com/sasanidas/maxima ][Maxima Mode ]]. The following list contains
more information:
1. [[https://gitlab.com/sasanidas/maxima ][Maxima Mode ]] is an Emacs interface to the computer algebra system [[https://en.wikipedia.org/wiki/Maxima_(software) ][Maxima ]].
2. [[https://orgmode.org/worg/org-contrib/babel/languages/ob-doc-maxima.html ][Maxima Source Code Blocks in Org Mode ]] shows how to use [[https://en.wikipedia.org/wiki/Maxima_(software) ][Maxima ]] in [[https://orgmode.org/ ][Org Mode ]].
3. [[https://home.csulb.edu/~woollett/mbe.html ][Maxima By Example ]] is a tutorial for [[https://en.wikipedia.org/wiki/Maxima_(software) ][Maxima ]].
Listing [[lst:maxima-example ]] is a minimal example of how to use how to use [[https://en.wikipedia.org/wiki/Maxima_(software) ][Maxima ]]
in [[https://orgmode.org/ ][Org Mode ]].
2022-07-01 10:02:05 +02:00
#+caption[Configure =maxima= ]:
#+caption : Configure =maxima=.
#+name : lst:configure-maxima
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(when (ensure-package-installation 'maxima 'company-maxima)
(add-hook 'maxima-mode-hook #'maxima-hook-function)
(add-hook 'maxima-inferior-mode-hook #'maxima-hook-function)
(add-to-list 'auto-mode-alist
(cons "\\.mac\\'" 'maxima-mode))
(add-to-list 'interpreter-mode-alist
(cons "maxima" 'maxima-mode)))
2022-07-01 10:02:05 +02:00
#+end_src
2022-07-01 14:11:48 +02:00
#+caption[Maxima example]:
#+caption : Maxima example.
#+name : lst:maxima-example
2023-01-24 07:41:16 +01:00
#+begin_src maxima -n :exports code :results silent
2022-11-07 11:50:17 +01:00
print(1+1);
2022-07-01 10:02:05 +02:00
#+end_src
2022-01-01 11:42:28 +01:00
** [[https://www.seas.upenn.edu/~chaoliu/2017/09/01/python-programming-in-emacs/][Python programming]]
:PROPERTIES:
2022-01-23 11:56:37 +01:00
:CUSTOM_ID: sec:python-programming
2022-01-01 11:42:28 +01:00
:END:
2023-01-13 17:49:43 +01:00
2022-01-01 11:42:28 +01:00
The [[https://www.emacswiki.org/emacs/PythonProgrammingInEmacs ][Python Programming in Emacs ]] wiki page lists options to enhance Emacs's
2023-01-13 17:49:43 +01:00
built-in ~python-mode~ . Here, the focus is on two Emacs packages and four Python
packages:
1. [[#sec:eglot ][Eglot - Emacs polyGLOT: a builtin LSP client since Emacs-29.0.60 ]]. The
2022-01-01 11:42:28 +01:00
maintainer also contributes to Emacs itself and has a deep understanding of
[[https://sheer.tj/the_way_of_emacs.html ][the Way of Emacs ]]. He refuses to add new features without seeing how they fit
into [[https://sheer.tj/the_way_of_emacs.html ][the Way of Emacs ]] as this discussion on [[https://github.com/joaotavora/eglot/issues/523 ][org-mode source code blocks ]]
shows.
2022-07-26 20:13:43 +02:00
2. [[https://jedi.readthedocs.io/en/latest/ ][Jedi ]] is a static analysis tool for Python that is typically used in plugins
for editors or integrated development environments. Jedi has a focus on
autocompletion and object definition lookup functionality.
2023-01-13 17:49:43 +01:00
3. [[https://github.com/charliermarsh/ruff#readme ][Ruff ]] is an extremely fast Python linter and a replacement for [[https://flake8.pycqa.org/en/latest/ ][Flake8 ]] with a
variety of its plugins. [[https://notes.crmarsh.com/ ][Charlie Marsh ]] explains why he started [[https://pypi.org/project/ruff/ ][Ruff ]] in the
post [[https://notes.crmarsh.com/python-tooling-could-be-much-much-faster ][Python tooling could be much faster ]].
4. [[https://github.com/python-lsp/python-lsp-server#readme ][Python LSP Server ]] is in my opinion the most complete [[https://en.wikipedia.org/wiki/Language_Server_Protocol ][Language Server Protocol ]]
implementation for Python and it handles [[https://github.com/charliermarsh/ruff#readme ][Ruff ]] thanks to the [[https://github.com/python-lsp/python-lsp-ruff ][python-lsp-ruff ]]
plugin.
5. [[https://github.com/astoff/code-cells.el#readme ][Code-cells ]] allows to edit [[https://ipython.org/notebook.html ][IPython or Jupyter notebooks ]] in Emacs with help
2022-07-26 20:13:43 +02:00
from either [[https://github.com/mwouts/jupytext ][Jupytext ]] or [[https://pandoc.org/ ][Pandoc ]].
Here are links covering how to integrate Emacs, Python and a Python LSP
server, before plunging into the configuration steps:
2022-01-19 07:47:56 +01:00
1. [[https://taingram.org/blog/emacs-lsp-ide.html ][Building Your Own Emacs IDE with LSP ]]
2. [[https://rgoswami.me/posts/emacs-lang-servers/ ][Doom Emacs and Language Servers ]]
3. [[https://ddavis.io/posts/eglot-python-ide/ ][Eglot based Emacs Python IDE ]]
4. [[https://www.mattduck.com/lsp-python-getting-started.html ][Getting started with lsp-mode for Python ]]
5. [[https://ddavis.io/posts/python-emacs-3/ ][Python & Emacs, Take 3 ]]
6. [[https://ddavis.io/posts/emacs-python-lsp/ ][Python with Emacs: py(v)env and lsp-mode ]]
2022-01-01 11:42:28 +01:00
2023-02-26 14:55:12 +01:00
Videos
1. [[yt:HTLu2DFOdTg ][Python's Class Development Kit - Raymond Hettinger ]]
2.
2022-01-01 11:42:28 +01:00
*** [[https://git.savannah.gnu.org/cgit/emacs.git/tree/lisp/progmodes/python.el][Python-mode]]
2022-01-04 13:10:26 +01:00
:PROPERTIES:
:CUSTOM_ID: sec:python-mode
:END:
2022-08-05 07:21:13 +02:00
2022-12-24 16:36:10 +01:00
Listing [[lst:setup-python-mode ][setup Python mode ]] and [[lst:choose-common-python-interpreter ][choose common Python interpreter ]] select a common
Python interpreter in a virtual environment for use in =python-mode= and
=ob-python= by means of src_emacs-lisp{(choose-common-python-interpreter)}. The
[[https://github.com/pythonic-emacs/pythonic#readme ][pythonic ]], [[https://github.com/jorgenschaefer/pyvenv#readme ][pyvenv ]], and [[https://github.com/jorgenschaefer/pyvenv#readme ][pyvenv ]] packages allow to handle Python virtual
environments within Emacs. The [[https://github.com/pyenv/pyenv ][pyenv ]] package provides support to work with
[[https://github.com/pyenv/pyenv#readme ][pyenv ]] (eventually with [[https://github.com/pyenv/pyenv-virtualenv#readme ][pyenv-virtualenv ]]) to select between different python
versions (eventually each with different environments). In the end, all those
packages do is to set =python-shell-virtualenv-root= (in case of [[https://github.com/pyenv/pyenv#readme ][pyenv ]] and
[[https://github.com/pythonic-emacs/pythonic#readme ][pythonic ]]) or tweak the environment variables and restart the relevant Python
child processes (in case of [[https://github.com/jorgenschaefer/pyvenv#readme ][pyvenv ]]). Therefore, I replace those packages with
listing [[lst:access-pyenv ][access pyenv ]] and [[lst:select-python-virtual-environment ][select a Python interpreter in a virtual environment ]] to
set =python-shell-virtualenv-root= from within Emacs.
Listing [[lst:setup-python-mode ][setup Python mode ]] and [[lst:choose-common-python-linter ][choose common Python linter ]] select a common Python
linter for the =python-check-command= and the =python-flymake-command= by means
of src_emacs-lisp{(choose-common-python-linter)} from:
1. [[https://github.com/PyCQA/pyflakes ][Pyflakes - simple tool which checks Python source files for errors ]].
2. [[https://flake8.pycqa.org/en/latest/ ][Flake8 - your tool for style guide enforcement ]].
3. [[https://github.com/charliermarsh/ruff ][Ruff - an extremely fast Python linter written in Rust ]].
Listing [[lst:pyproject-toml-kickoff ][kickoff pyproject.toml proposal ]] facilitates dropping a [[https://pip.pypa.io/en/stable/reference/build-system/pyproject-toml ][pyproject.toml ]]
file into Python projects which anyhow should switch to using a [[https://pip.pypa.io/en/stable/reference/build-system/pyproject-toml ][pyproject.toml ]]
file as explained in the post [[https://bbc.github.io/cloudfit-public-docs/packaging/this_way_up.html ][This Way Up: A Bottom-Up Look At Python Packaging ]].
2022-12-29 10:04:59 +01:00
The [[https://packaging.python.org/en/latest/tutorials/packaging-projects/ ][packaging Python projects tutorial ]] and the [[https://github.com/pypa/sampleproject ][Python sample project ]] walk you
2022-12-29 12:22:44 +01:00
through the process of writing a [[https://pip.pypa.io/en/stable/reference/build-system/pyproject-toml ][pyproject.toml ]] file. [[https://github.com/charliermarsh/ruff#does-ruff-support-numpy--or-google-style-docstrings ][Ruff docstring setup ]]
explains how to setup documentation string checking in the [[https://pip.pypa.io/en/stable/reference/build-system/pyproject-toml ][pyproject.toml ]] file.
2022-12-24 16:36:10 +01:00
Listing [[lst:setup-cfg-kickoff ][kickoff setup.cfg proposal ]] implements the [[https://black.readthedocs.io/en/stable/guides/using_black_with_other_tools.html ][using black with other tools ]]
rules which make [[https://flake8.pycqa.org/en/latest/ ][flake8 ]] or [[https://pycodestyle.pycqa.org/en/latest/ ][pycodestyle ]] agree with [[https://black.readthedocs.io/en/stable/index.html ][black's uncompromising style ]].
Finally, listing [[lst:flake8-nocolor ][flake8-nocolor ]] and [[lst:ruff-nocolor ][ruff-nocolor ]] pipe the =stdout= output of the
[[https://pypi.org/project/flake8/ ][flake8 ]] and [[https://pypi.org/project/ruff/ ][ruff ]] executables through =cat= to remove escape sequences.
#+caption[Choose a common Python interpreter]:
#+caption : Choose a common Python interpreter for =ob-python= and =python-mode=.
2022-08-28 16:39:43 +02:00
#+name : lst:choose-common-python-interpreter
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-12-24 16:36:10 +01:00
(defun choose-common-python-interpreter (&optional interpreter)
"Let `ob-python' and `python-mode' use the same Python INTERPRETER."
2022-11-07 11:50:17 +01:00
(interactive)
2023-01-20 07:06:51 +01:00
(unless (featurep 'ob-python)
(set-org-babel-language-activity 'python (fboundp 'python-mode)))
2022-11-07 11:50:17 +01:00
(let* ((prompt (format "Choose Python (%s): "
(bound-and-true-p python-shell-interpreter)))
(choices '(ipython python))
2022-12-24 16:36:10 +01:00
(choice (if (member interpreter choices)
(symbol-name interpreter)
2022-11-07 11:50:17 +01:00
(completing-read prompt choices nil t))))
(when (boundp 'org-babel-python-command)
(pcase choice
("python"
2023-01-12 21:28:18 +01:00
(setopt org-babel-python-command
(concat (or (executable-find "python3")
(executable-find "python"))
" -E")))
2022-11-07 11:50:17 +01:00
("ipython"
2023-01-12 21:28:18 +01:00
(setopt org-babel-python-command
(concat (or (executable-find "ipython3")
(executable-find "ipython"))
" --simple-prompt --HistoryAccessor.enabled=False"))))
2022-11-17 03:27:07 +01:00
(message "Now `org-babel-python-command' equals %S"
org-babel-python-command))
2022-11-07 11:50:17 +01:00
(when (boundp 'python-shell-interpreter)
(pcase choice
("python"
2023-01-12 21:28:18 +01:00
(setopt python-shell-interpreter (or (executable-find "python3")
(executable-find "python"))
python-shell-interpreter-args "-E -i"))
2022-11-07 11:50:17 +01:00
("ipython"
2023-01-12 21:28:18 +01:00
(setopt python-shell-interpreter (or (executable-find "ipython3")
(executable-find "ipython"))
python-shell-interpreter-args
"--simple-prompt --HistoryAccessor.enabled=False")))
2022-11-17 03:27:07 +01:00
(message "Now `python-shell-interpreter' equals %S"
python-shell-interpreter))))
2022-01-01 11:42:28 +01:00
#+end_src
2022-12-24 16:36:10 +01:00
#+caption[Choose a common Python linter]:
#+caption : Choose a common Python linter for =python-check-command= and
#+caption : =python-flymake-command=.
#+name : lst:choose-common-python-linter
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-12-24 16:36:10 +01:00
(defun choose-common-python-linter (&optional linter)
"Let `python-check-command' and `python-flymake-command' use the same LINTER."
(interactive)
(let* ((prompt (format "Choose Python checker (%s): "
(bound-and-true-p python-check-command)))
(choices '(flake8-nocolor pyflakes ruff-nocolor))
(choice (if (member linter choices)
(symbol-name linter)
(completing-read prompt choices nil t))))
(when (and (boundp 'python-check-command) (boundp 'python-flymake-command))
(pcase choice
("flake8-nocolor"
2023-01-12 21:28:18 +01:00
(setopt python-check-command (executable-find choice)
python-flymake-command (list (executable-find choice) "-")))
2022-12-24 16:36:10 +01:00
("pyflakes"
2023-01-12 21:28:18 +01:00
(setopt python-check-command (executable-find choice)
python-flymake-command `(,(executable-find choice))))
2022-12-24 16:36:10 +01:00
("ruff-nocolor"
2023-01-12 21:28:18 +01:00
(setopt python-check-command (executable-find choice)
python-flymake-command (list (executable-find choice)
"--stdin-filename" "stdin" "-"))))
2022-12-24 16:36:10 +01:00
(when (bound-and-true-p python-check-custom-command)
(setq python-check-custom-command nil))
(message "Python checker commands are %S and %S"
python-check-command python-flymake-command))))
#+end_src
2023-01-10 19:04:39 +01:00
#+caption[Setup Python mode]:
#+caption : Setup Python mode.
#+name : lst:setup-python-mode
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2023-01-10 19:04:39 +01:00
(with-eval-after-load 'python
2023-01-12 21:28:18 +01:00
(setopt python-indent-guess-indent-offset nil
python-shell-completion-native-disabled-interpreters '("ipython3"
"pypy"))
2023-01-10 19:04:39 +01:00
(choose-common-python-interpreter 'python)
(choose-common-python-linter 'ruff-nocolor))
#+end_src
2022-12-24 16:36:10 +01:00
#+caption[Access =pyenv= ]:
#+caption : Access =pyenv=.
#+name : lst:access-pyenv
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(when (executable-find "pyenv")
(defun pyenv-full-path (version)
"Return the full path for VERSION."
(unless (string= version "system")
(concat (pyenv-root) (file-name-as-directory "versions") version)))
(defun pyenv-root ()
"Return \"pyenv root\" as a directory."
(cl-destructuring-bind (exit-code output)
(shell-command-with-exit-code "pyenv" "root")
(if (= 0 exit-code)
(file-name-as-directory (string-trim output))
(error "%s" (string-trim output)))))
(defun pyenv-version-name ()
"Return \"pyenv version-name\"."
(cl-destructuring-bind (exit-code output)
(shell-command-with-exit-code "pyenv" "version-name")
(if (= 0 exit-code)
(string-trim output)
(error "%s" (string-trim output)))))
(defun pyenv-versions ()
"Return \"pyenv versions --bare --skip-aliases\" as a list.
Complete the result with \"system\"."
(cl-destructuring-bind (exit-code output)
(shell-command-with-exit-code
"pyenv" "versions" "--bare" "--skip-aliases")
(if (= 0 exit-code)
(cons "system" (split-string output))
(error "%s" (string-trim output)))))
(defun pyenv-virtualenvs ()
"Return \"pyenv virtualenvs --bare --skip-aliases\" as a list."
(cl-destructuring-bind (exit-code output)
(shell-command-with-exit-code
"pyenv" "virtualenvs" "--bare" "--skip-aliases")
(if (= 0 exit-code)
(split-string output)
(error "%s" (string-trim output))))))
2022-02-13 15:10:23 +01:00
#+end_src
2022-12-24 16:36:10 +01:00
#+caption[Select the Python virtual environment]:
#+caption : Select the Python virtual environment.
#+name : lst:select-python-virtual-environment
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'python
(when (cl-every #'fboundp '(pyenv-full-path
pyenv-version-name
pyenv-versions
pyenv-virtualenvs))
(setq python-shell-virtualenv-root
2022-11-17 03:27:07 +01:00
(pyenv-full-path (or (pyenv-version-name)
2022-11-07 11:50:17 +01:00
(car (pyenv-virtualenvs))
(car (pyenv-versions)))))
2022-11-17 03:27:07 +01:00
(message "Now `python-shell-virtualenv-root' equals %S"
2022-11-07 11:50:17 +01:00
python-shell-virtualenv-root)
(defun set-python-shell-virtualenv-root-to-pyenv-version ()
"Set `python-shell-virtual-env-root' to a pyenv version."
(interactive)
(let* ((version-name (pyenv-version-name))
(prompt (format "pyenv version (%s): " version-name))
(choices (pyenv-versions))
(version (completing-read prompt choices nil 'require-match)))
(unless (string= version-name version)
(setq python-shell-virtualenv-root (pyenv-full-path version))
(setenv "PYENV_VERSION" version))
2022-11-17 03:27:07 +01:00
(message "Now `python-shell-virtualenv-root' equals %S"
2022-11-07 11:50:17 +01:00
python-shell-virtualenv-root)))
(defun set-python-shell-virtualenv-root-to-pyenv-virtualenv ()
"Set `python-shell-virtual-env-root' to a pyenv virtualenv."
(interactive)
(let* ((version-name (pyenv-version-name))
(prompt (format "pyenv virtualenv (%s): " version-name))
(choices (pyenv-virtualenvs))
(version (completing-read prompt choices nil 'require-match)))
(unless (string= version-name version)
(setq python-shell-virtualenv-root (pyenv-full-path version))
(setenv "PYENV_VERSION" version))
2022-11-17 03:27:07 +01:00
(message "Now `python-shell-virtualenv-root' equals %S"
2022-11-07 11:50:17 +01:00
python-shell-virtualenv-root)))))
2022-01-04 13:10:26 +01:00
#+end_src
2022-01-19 07:47:56 +01:00
2022-12-24 16:36:10 +01:00
#+caption[Kickoff =pyproject.toml= proposal]:
#+caption : Kickoff =pyproject.toml= proposal.
#+name : lst:pyproject-toml-kickoff
2023-01-24 07:41:16 +01:00
#+begin_src toml -n :tangle pyproject.toml
2023-01-05 14:51:19 +01:00
# Use for instance "hatch new" to create or initialize a project.
# See: https://pypi.org/project/hatch
2022-12-24 16:36:10 +01:00
[tool.black]
line-length = 88
[tool.ruff]
line-length = 88
select = [
"ARG", # flake8-unused-arguments
"B", # flake8-bugbear
"C", # mccabe
2023-01-05 14:51:19 +01:00
"C4", # flake8-comprehensions
2022-12-24 16:36:10 +01:00
"E", # pycodestyle
"D", # pydocstyle
"F", # pyflakes
2023-01-05 14:51:19 +01:00
"UP", # pyupgrade
"W", # pycodestyle
2022-12-24 16:36:10 +01:00
]
ignore = [
2023-01-05 14:51:19 +01:00
"B905", # `zip()` without an explicit `strict=` parameter
2022-12-24 16:36:10 +01:00
]
[tool.ruff.mccabe]
max-complexity = 15
2022-12-29 12:22:44 +01:00
[tool.ruff.pydocstyle]
convention = "numpy"
2022-12-24 16:36:10 +01:00
# Local Variables:
2022-12-29 12:22:44 +01:00
# mode: conf-toml-mode
2022-12-24 16:36:10 +01:00
# End:
#+end_src
#+caption[Kickoff =setup.cfg= proposal]:
#+caption : Kickoff =setup.cfg= proposal.
#+name : lst:setup-cfg-kickoff
2023-01-24 07:41:16 +01:00
#+begin_src toml -n :tangle setup.cfg
2022-12-24 16:36:10 +01:00
[flake8]
docstring-convention = numpy
extend-select = B,F,W
extend-ignore = W503
max-complexity = 15
max-line-length = 88
[pycodestyle]
ignore = W503
max-line-length = 88
# Local Variables:
# mode: conf-toml
# End:
#+end_src
#+caption[Wrap =flake8= to remove color from text output]:
#+caption : Wrap =flake8= to remove color from text output.
#+header : :tangle-mode (identity #o755)
#+name : lst:flake8-nocolor
2023-01-24 07:41:16 +01:00
#+begin_src shell -n :noeval :tangle ~/bin/flake8-nocolor
2022-12-24 16:36:10 +01:00
#!/bin/sh
flake8 "$@" | cat
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# sh-basic-offset: 2
# End:
#+end_src
#+caption[Wrap =ruff= to remove color from text output]:
#+caption : Wrap =ruff= to remove color from text output.
#+header : :tangle-mode (identity #o755)
#+name : lst:ruff-nocolor
2023-01-24 07:41:16 +01:00
#+begin_src shell -n :noeval :tangle ~/bin/ruff-nocolor
2022-12-24 16:36:10 +01:00
#!/bin/sh
ruff "$@" | cat
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# sh-basic-offset: 2
# End:
#+end_src
2023-02-26 14:04:44 +01:00
*** [[https://pip.pypa.io/en/stable/][Package Installer for Python]]
:PROPERTIES:
:CUSTOM_ID: sec:pip-python
:header-args: :eval never-export
:END:
2023-03-05 10:53:38 +01:00
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 ]].
2023-02-26 14:04:44 +01:00
#+caption[Show how to use =pip list --outdated= ]:
#+caption : Show how to use =pip list --outdated=.
#+header : :wrap src text
#+name : lst:shell-pip-list-outdated
#+begin_src shell :exports both :results verbatim
# WARNING: "pip index" is currently an experimental command.
pip list --outdated
#+end_src
#+caption[The result of =pip list --outdated= ]:
#+caption : The result of =pip list --outdated=.
2023-03-05 10:53:38 +01:00
#+name : lst:shell-pip-list-outdated-results
2023-02-26 14:04:44 +01:00
#+RESULTS : lst:shell-pip-list-outdated
#+begin_src text
Package Version Latest Type
------------------- ------- ------ -----
aiofiles 22.1.0 23.1.0 wheel
jupyter_server_ydoc 0.6.1 0.7.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
#+end_src
#+caption[Show how to use =pip index versions= ]:
#+caption : Show how to use =pip index versions=.
#+header : :wrap src text
#+name : lst:shell-pip-index-versions
#+begin_src shell :exports both :results verbatim
# WARNING: "pip index" is currently an experimental command.
pip index versions circular-buffer --no-color
#+end_src
#+caption[The result of =pip index versions= ]:
#+caption : The result of =pip index versions=.
2023-03-05 10:53:38 +01:00
#+name : lst:shell-pip-index-versions-results
2023-02-26 14:04:44 +01:00
#+RESULTS : lst:shell-pip-index-versions
#+begin_src text
circular-buffer (0.2.0)
Available versions: 0.2.0, 0.1.1, 0.1.0
#+end_src
#+caption[Emacs interface to list outdated Python packages]:
#+caption : Emacs interface to list outdated Python packages.
#+name : lst:pip-list-outdated
#+begin_src emacs-lisp -n results silent
(defvar pip-outdated-packages nil
"Outdated Python packages.")
(defun pip--list-outdated-sentinel (process event)
(when (and (eq (process-status process) 'exit)
(zerop (process-exit-status process))
(buffer-live-p (process-buffer process)))
(with-current-buffer (process-buffer process)
(goto-char (point-min))
(setq pip-outdated-packages
(json-parse-buffer :array-type 'list :object-type 'alist))
(let ((alists pip-outdated-packages))
(while alists
2023-02-26 18:47:24 +01:00
(setcdr (assq 'name (car alists))
(string-replace "_" "-" (alist-get 'name (car alists))))
2023-02-26 14:04:44 +01:00
(setq alists (cdr alists))))
(kill-buffer)
(message "Calling `%S' succeeded" #'pip-list-outdated))))
(defun pip-list-outdated ()
"Save the outdated Python packages in `pip-outdated-packages'
This invokes an asynchonous process and finishes with a message."
(interactive)
(let ((command '("pip" "list" "--outdated" "--format" "json")))
(make-process
:name "pip-list-outdated"
:buffer (generate-new-buffer-name "*pip-list-outdated-output* ")
:command command
:sentinel #'pip--list-outdated-sentinel)
(message "Running `%s' asynchonously" (string-join command " "))))
#+end_src
#+caption[Emacs interface to upgrade outdated unfrozen Python packages]:
#+caption : Emacs interface to upgrade outdated unfrozen Python packages.
#+name : lst:pip-upgrade-maybe
#+begin_src emacs-lisp -n :results silent
2023-03-05 10:53:38 +01:00
(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
2023-02-26 14:04:44 +01:00
:type '(repeat string))
2023-03-05 10:53:38 +01:00
;; Frozen until the release of jupyterlab-4.0.0.
(setopt pip-frozen-packages '("aiofiles"
"jupyter-server-ydoc"
"jupyter-ydoc"
"y-py"
"ypy-websocket"))
2023-02-26 14:04:44 +01:00
(defun pip--upgrade-maybe-sentinel (process event)
(when (and (eq (process-status process) 'exit)
(buffer-live-p (process-buffer process)))
(display-buffer (process-buffer process))))
(defun pip-upgrade-maybe ()
"Install the latest version of outdated packages unless they are frozen.
This invokes an asynchonous process and finishes with displaying the process
buffer to check whether upgrading has made the dependencies incompatible."
(interactive)
(let (found)
(dolist (alist pip-outdated-packages found)
(let ((name (alist-get 'name alist))
(latest_version (alist-get 'latest_version alist)))
(unless (member name pip-frozen-packages)
(push (format "%s==%s" name latest_version) found))))
(if (consp found)
(let ((command
`("pip" "install" "--progress-bar" "off" ,@(nreverse found))))
(make-process
:name "pip-upgrade-maybe"
:buffer (generate-new-buffer-name "*pip-upgrade-maybe* ")
:command command
:sentinel #'pip--upgrade-maybe-sentinel)
(message "Running `%s' asynchonously" (string-join command " ")))
(message "`pip-upgrade-maybe' found no packages to install"))))
#+end_src
#+caption[Emacs interface to the =PyPI= simple =JSON= =API= ]:
#+caption : Emacs interface to the =PyPI= simple =JSON= =API=.
2023-03-05 10:53:38 +01:00
#+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?"
(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)."
2023-02-26 14:04:44 +01:00
(interactive)
(let ((url-request-method "GET")
(url-mime-accept-string "application/vnd.pypi.simple.latest+json"))
(url-retrieve "https://pypi.org/simple"
(lambda (status) (switch-to-buffer (current-buffer))))))
#+end_src
#+caption[Emacs interface to get the dependency tree of installed packages]:
#+caption : Emacs interface to get the dependency tree of installed packages.
#+name : lst:pip-dependency-tree
#+begin_src emacs-lisp :results silent
(defvar pip-package-dependency-tree nil
"Python package dependency tree.")
(defun pip--dependency-tree-sentinel (process event)
(when (and (eq (process-status process) 'exit)
(zerop (process-exit-status process))
(buffer-live-p (process-buffer process)))
(with-current-buffer (process-buffer process)
(goto-char (point-min))
(setq pip-package-dependency-tree
(json-parse-buffer :array-type 'list :object-type 'alist))
(kill-buffer)
(message "Calling `%S' succeeded" #'pip-dependency-tree))))
(defun pip-dependency-tree ()
"Save the Python package dependency tree in `pip-package-dependency-tree'."
(interactive)
(let ((command '("pipdeptree" "--json-tree")))
(make-process
:name "pip-dependency-tree"
:buffer (generate-new-buffer-name "*pip-dependency-tree-output* ")
:command command
:sentinel #'pip--dependency-tree-sentinel)
(message "Running `%s' asynchonously" (string-join command " "))))
#+end_src
#+caption[Emacs functions to flatten the Python package dependency tree]:
#+caption : Emacs functions to flatten the Python package dependency tree.
#+name : lst:pip-python-interface
#+begin_src emacs-lisp -n :results silent
(defun pip--flatten-dependencies (parents found)
(dolist (parent parents)
(when-let ((children (alist-get 'dependencies parent)))
(setq found (pip--flatten-dependencies children found)))
(if-let* ((pair `(key . ,(alist-get 'key parent)))
(old (cl-loop for alist in found thereis (member pair alist)))
(rvs (split-string (alist-get 'required_version parent) "[,]+")))
(dolist (rv rvs)
(cl-pushnew rv (alist-get 'required_version old) :test #'equal))
(let* ((new (assq-delete-all 'dependencies (copy-alist parent)))
(rvs (split-string (alist-get 'required_version new) "[,]+")))
2023-02-26 18:47:24 +01:00
(setcdr (assq 'required_version new) rvs)
2023-02-26 14:04:44 +01:00
(push new found))))
found)
(defun pip-flatten-package-dependency-tree ()
(let (found)
(dolist (package pip-package-dependency-tree)
(when-let ((children (alist-get 'dependencies package)))
(setq found (pip--flatten-dependencies children found))))
found))
(defconst pip-canonical-version-regexp-alist
'(("^[.]dev$" . -4)
("^a$" . -3)
("^b$" . -2)
("^rc$" . -1)
("^[.]post$" . 1))
"Specify association between canonical \"PEP-440\" version and its priority.")
(defun pip-canonical-version-to-list (version)
(let ((version-regexp-alist pip-canonical-version-regexp-alist))
(version-to-list version)))
;; https://peps.python.org/pep-0440/
(defun pip-pep-440 (clauses)
(let (compatibles exclusions greater-equals less-thans unknowns)
(dolist (clause clauses)
(cond ((string-prefix-p "~=" clause)
(push (substring clause 2) compatibles))
((string-prefix-p "!=" clause)
(push (substring clause 2) exclusions))
((string-prefix-p ">=" clause)
(push (substring clause 2) greater-equals))
((string-prefix-p "<" clause)
(push (substring clause 1) less-thans))
(t (push clause unknowns))))
(list compatibles exclusions greater-equals less-thans unknowns)))
#+end_src
2022-07-17 20:10:17 +02:00
*** [[https://github.com/joaotavora/eglot][Eglot]] for [[https://git.savannah.gnu.org/cgit/emacs.git/tree/lisp/progmodes/python.el][python-mode]]
2022-01-04 13:10:26 +01:00
:PROPERTIES:
2022-07-17 20:10:17 +02:00
:CUSTOM_ID: sec:eglot-python
2022-01-04 13:10:26 +01:00
:END:
2022-08-05 07:21:13 +02:00
2022-12-24 16:36:10 +01:00
Listing [[lst:configure-eglot+pylsp-ruff ]] configures [[https://github.com/joaotavora/eglot ][eglot ]] for [[https://www.python.org ][Python ]] using the
[[https://github.com/python-lsp/python-lsp-server ][python-lsp-server ]] with the [[https://github.com/python-lsp/python-lsp-ruff#readme ][pylsp-ruff ]] plugin for the easiest way to let
2023-02-26 10:05:28 +01:00
[[https://github.com/python-lsp/python-lsp-server ][python-lsp-server ]] use [[https://pypi.org/project/ruff/ ][Ruff ]]. It is better to uninstall the Python packages
[[https://github.com/hhatto/autopep8#readme ][autopep8 ]], [[https://github.com/PyCQA/flake8 ][flake8 ]], [[https://github.com/PyCQA/pydocstyle#readme ][pydocstyle ]], [[https://github.com/PyCQA/pylint#readme ][pylint ]], and [[https://github.com/python-rope/rope#readme ][rope ]].
2022-12-24 16:36:10 +01:00
2022-07-17 20:10:17 +02:00
Listing [[lst:eglot-directory-variables-for-python ]] shows a proper [[info:emacs#Directory Variables ][.dir-locals.el ]]
file in the root directory of any [[https://www.python.org ][Python ]] project to start [[https://github.com/joaotavora/eglot ][eglot ]] automatically
2023-02-26 10:05:28 +01:00
according to the configuration in listing [[lst:eglot-maybe-ensure ]].
Type {{{kbd(M-x eglot-show-workspace-configuration)}}} to dump a =JSON=
2022-09-18 11:14:56 +02:00
representation of src_emacs-lisp{eglot-workspace-configuration} for debugging.
2022-12-24 16:36:10 +01:00
The comment in listing [[lst:minimal-eglot-setup ][minimal Eglot setup ]] also shows how to decrease
or to increase the verbosity of [[https://github.com/python-lsp/python-lsp-server ][Python LSP server ]] log output for debugging.
2022-01-07 16:34:21 +01:00
2022-12-24 16:36:10 +01:00
#+caption[Configure =eglot= with =python-lsp-ruff= ]:
#+caption : Configure =eglot= with =python-lsp-ruff=.
#+name : lst:configure-eglot+pylsp-ruff
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'eglot
(setq-default
eglot-workspace-configuration
2022-12-27 10:47:33 +01:00
;; Enable the `:pylsp_ruff' plugin and ensure to disable the
2022-12-24 16:36:10 +01:00
;; `:flake8', `:mccabe', and `:pycodestye' plugins.
2022-11-07 11:50:17 +01:00
'(:pylsp (:plugins
2022-12-24 16:36:10 +01:00
(:pylsp_ruff
2022-11-07 11:50:17 +01:00
(:enabled t)
2023-02-26 10:05:28 +01:00
:flake8 ;; It is better to uninstall flake8
2022-12-24 16:36:10 +01:00
(:enabled :json-false)
2023-02-26 10:05:28 +01:00
:mccabe ;; It is better to uninstall mccabe
2022-12-24 16:36:10 +01:00
(:enabled :json-false)
2023-02-26 10:05:28 +01:00
:pycodestyle ;; It is better to uninstall pycodestyle
2022-12-24 16:36:10 +01:00
(:enabled :json-false)
2022-11-07 11:50:17 +01:00
:jedi
(:auto_import_modules ["numpy"])
:jedi_completion
(:cache_for ["astropy"]))))))
2022-01-01 11:42:28 +01:00
#+end_src
2022-11-07 10:46:34 +01:00
#+caption[A =.dir-locals.el= proposal to launch =eglot= automatically]:
2022-12-24 16:36:10 +01:00
#+caption : A =.dir-locals.el= file proposal for Python projects or Org-mode
#+caption : projects tangling Python files to launch =eglot= automatically.
2022-01-01 11:42:28 +01:00
#+name : lst:eglot-directory-variables-for-python
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent :tangle dir-locals.el
2022-11-07 11:50:17 +01:00
;; A .dir-locals.el file proposal in the root of any
;; Python project or Org-mode project tangling Python files
;; to launch eglot automatically.
((nil ;; nil, since Emacs-29.1 filters out irrelevant variable names.
. ((eglot-workspace-configuration
2022-12-27 10:47:33 +01:00
;; Enable the `:pylsp_ruff' plugin and ensure to disable the
2022-12-24 16:36:10 +01:00
;; `:flake8', `:mccabe', and `:pycodestye' plugins.
2022-11-07 11:50:17 +01:00
. (:pylsp (:plugins
2022-12-24 16:36:10 +01:00
(:pylsp_ruff
2022-11-07 11:50:17 +01:00
(:enabled t)
2023-02-26 10:05:28 +01:00
:flake8 ;; It is better to uninstall flake8
2022-12-24 16:36:10 +01:00
(:enabled :json-false)
2023-02-26 10:05:28 +01:00
:mccabe ;; It is better to uninstall mccabe
2022-12-24 16:36:10 +01:00
(:enabled :json-false)
2023-02-26 10:05:28 +01:00
:pycodestyle ;; It is better to uninstall pycodestyle
2022-12-24 16:36:10 +01:00
(:enabled :json-false)
2022-11-07 11:50:17 +01:00
:jedi
(:auto_import_modules ["numpy"])
:jedi_completion
(:cache_for ["astropy"]))))))))
2022-01-19 07:47:56 +01:00
#+end_src
2022-02-02 08:37:12 +01:00
#+attr_latex : :booktabs yes :float table
#+caption[Eglot related key bindings]:
#+caption : Eglot related key-bindings.
#+name : tab:eglot-related-key-bindings
2022-07-17 22:27:17 +02:00
|-------------------------+----------------+------------------|
| command | key map | keys |
|-------------------------+----------------+------------------|
| xref-find-definition | global-map | {{{kbd(M-.)}}} |
| xref-pop | global-map | {{{kbd(M-\,)}}} |
| flymake-goto-next-error | eglot-mode-map | {{{kbd(C-c n)}}} |
| flymake-goto-prev-error | eglot-mode-map | {{{kbd(C-c p)}}} |
| eglot-rename | eglot-mode-map | {{{kbd(C-c r)}}} |
| eldoc-doc-buffer | eglot-mode-map | {{{kbd(C-h .)}}} |
|-------------------------+----------------+------------------|
2022-02-02 08:37:12 +01:00
2022-11-04 06:08:39 +01:00
Listing [[lst:make-pylsp-server-patch ]] is useful to propagate eventual patches of
a local fork of [[https://github.com/python-lsp/python-lsp-server ][python-lsp-server ]].
2022-01-12 20:19:22 +01:00
#+caption[Make =pylsp-auto-import-modules.patch= listing]:
#+caption : Make =pylsp-auto-import-modules.patch= listing.
#+name : lst:make-pylsp-server-patch
2023-01-24 07:41:16 +01:00
#+begin_src shell -n :exports code :results none
2022-11-04 06:08:39 +01:00
git -C $HOME/VCS/python-lsp-server diff >pylsp.patch
2022-02-08 13:34:50 +01:00
#+end_src
2022-04-26 05:29:36 +02:00
*** [[https://jedi.readthedocs.io/en/latest/][Jedi]]
:PROPERTIES:
:CUSTOM_ID: sec:jedi
:END:
2022-08-05 07:21:13 +02:00
2022-04-26 05:29:36 +02:00
Listing [[lst:example-py ]] is a [[https://www.python.org ][Python ]] example to test whether [[https://jedi.readthedocs.io/en/latest/ ][jedi ]] in combination
2022-07-26 20:13:43 +02:00
with [[https://github.com/joaotavora/eglot ][eglot ]] works when coding for instance [[https://numpy.org/ ][numpy ]] universal functions.
2022-04-26 05:29:36 +02:00
#+caption[Tangle the =example.py= file]:
#+caption : Tangle the =example.py= file.
#+name : lst:example-py
2023-01-24 07:41:16 +01:00
#+begin_src python -n :tangle example.py
2022-11-07 11:50:17 +01:00
import numpy
import astropy.units as apu
2022-04-26 05:29:36 +02:00
2022-11-07 11:50:17 +01:00
a = numpy.arange(0, 11)
a = numpy.linspace(0, 10, num=11)
a = numpy.arccos(a)
q = apu.Quantity(a, apu.meter)
print(q)
2022-04-26 05:29:36 +02:00
#+end_src
2022-02-23 07:43:57 +01:00
*** [[https://github.com/astoff/code-cells.el#readme][Code-cells]]
:PROPERTIES:
2022-03-26 15:11:32 +01:00
:CUSTOM_ID: sec:code-cells
2022-02-23 07:43:57 +01:00
:END:
[[https://github.com/astoff/code-cells.el#readme ][Code-cells ]] allows to edit [[https://ipython.org/notebook.html ][IPython or Jupyter notebooks ]] in Emacs with help from
either [[https://github.com/mwouts/jupytext ][Jupytext ]] or [[https://pandoc.org/ ][Pandoc ]] to translate between the [[https://nbformat.readthedocs.io/en/latest/ ][ipynb ]] format and different
plain text formats. Sofar, I have used [[https://github.com/astoff/code-cells.el#readme ][code-cells ]] to open [[https://nbformat.readthedocs.io/en/latest/ ][ipynb ]] notebooks with
2022-04-30 09:55:37 +02:00
{{{kbd(C-x C-f)}}} in Emacs for viewing. Listing [[lst:configure-code-cells ]]
configures =code-cells= .
#+caption[Configure =code-cells= ]:
#+caption : Configure =code-cells=.
#+name : lst:configure-code-cells
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(when (ensure-package-installation 'code-cells)
(with-eval-after-load 'code-cells
(let ((map code-cells-mode-map))
2023-02-26 14:37:33 +01:00
(keymap-set map "M-p" #'code-cells-backward-cell)
(keymap-set map "M-n" #'code-cells-forward-cell)
(keymap-set map "C-c C-c" #'code-cells-eval))))
2022-04-30 09:55:37 +02:00
#+end_src
2022-02-23 07:43:57 +01:00
2022-01-01 11:42:28 +01:00
*** TODO Look into: editing facilities
1. [[https://github.com/douglasdavis/numpydoc.el/blob/main/numpydoc.el ][Emacs extension to insert numpy style docstrings in function definitions ]]
2022-01-21 06:56:03 +01:00
* [[https://github.com/emacs-tw/awesome-emacs#library][Libraries]]
:PROPERTIES:
:CUSTOM_ID: sec:libraries
:END:
2022-08-05 07:21:13 +02:00
2022-01-21 06:56:03 +01:00
** [[info:dash.info#Top][Library dash.el (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:dash-library
:END:
2022-08-05 07:21:13 +02:00
The library [[info:dash.info#Top ][dash.el (info) ]] positions itself as a modern alternative for the list
2022-01-21 06:56:03 +01:00
processing API of [[info:cl#Top ][cl ]]. It is a requirement of several important packages in this
2022-05-06 17:20:44 +02:00
Emacs setup (for instance [[https://github.com/andras-simonyi/citeproc-el#readme ][citeproc ]], [[https://github.com/magit/magit#readme ][magit ]], and [[https://github.com/Fuco1/smartparens#readme ][smartparens ]]). Listing
2022-01-21 06:56:03 +01:00
[[lst:configure-dash ]] enables fontification of =dash= macros and makes
=info-lookup-symbol= take into account the =dash= macros.
#+caption[Configure =dash= fontification and info lookup]:
#+caption : Configure =dash= fontification and info lookup.
#+name : lst:configure-dash
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(when (fboundp #'global-dash-fontify-mode)
(global-dash-fontify-mode))
2022-01-21 06:56:03 +01:00
2022-11-07 11:50:17 +01:00
(when (fboundp #'dash-register-info-lookup)
(with-eval-after-load 'info-look
(dash-register-info-lookup)))
2022-01-21 06:56:03 +01:00
#+end_src
** [[https://github.com/rejeep/f.el][Library f.el]]
:PROPERTIES:
2022-02-08 20:37:06 +01:00
:CUSTOM_ID: sec:f-library
2022-01-21 06:56:03 +01:00
:END:
2022-08-05 07:21:13 +02:00
2022-01-21 06:56:03 +01:00
The library [[https://github.com/rejeep/f.el ][f.el ]] positions itself as a modern API for working with files and
2022-05-06 17:20:44 +02:00
directories in Emacs. It is a requirement of the [[https://github.com/andras-simonyi/citeproc-el#readme ][citeproc ]] package in this Emacs
setup and requires no configuration.
2022-01-21 06:56:03 +01:00
** [[https://github.com/magnars/s.el][Library s.el]]
:PROPERTIES:
:CUSTOM_ID: sec:s-library
:END:
The library [[https://github.com/magnars/s.el ][s.el ]] positions itself as the long lost Emacs string manipulation
2022-05-06 17:20:44 +02:00
library. It is a requirement of the [[https://github.com/andras-simonyi/citeproc-el#readme ][citeproc ]] and [[https://github.com/bdarcus/citar#readme ][citar ]] packages in this Emacs
setup and requires no configuration.
2022-01-21 06:56:03 +01:00
2022-01-17 07:56:55 +01:00
* [[info:emacs#Minor Modes][Minor Modes (info)]]
2021-12-06 08:31:40 +01:00
:PROPERTIES:
2022-01-17 07:56:55 +01:00
:CUSTOM_ID: sec:minor-modes
2021-12-06 08:31:40 +01:00
:END:
2022-01-09 15:39:14 +01:00
** [[https://github.com/victorhge/iedit#readme][Synchronal multiple-region editing]]
:PROPERTIES:
:CUSTOM_ID: sec:synchronal-multiple-region-editing
:END:
2021-11-29 13:14:56 +01:00
2021-12-23 15:29:03 +01:00
#+caption[Enable =iedit= ]:
#+caption : Enable =iedit=.
2021-12-28 08:48:03 +01:00
#+name : lst:enable-iedit
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(when (ensure-package-installation 'iedit)
(require 'iedit nil 'noerror))
2021-11-29 13:14:56 +01:00
#+end_src
2022-01-09 15:39:14 +01:00
** [[https://github.com/lewang/ws-butler#readme][Unobtrusive whitespace trimming]]
:PROPERTIES:
:CUSTOM_ID: sec:unobtrusive-whitespace-trimming
:END:
2021-11-29 13:14:56 +01:00
2021-12-23 15:29:03 +01:00
#+caption[Configure =ws-butler= ]:
#+caption : Configure =ws-butler=.
2021-12-28 08:48:03 +01:00
#+name : lst:configure-ws-butler
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(when (and (ensure-package-installation 'ws-butler)
(require 'ws-butler nil 'noerror))
2023-01-12 21:28:18 +01:00
(setopt ws-butler-keep-whitespace-before-point nil)
2022-11-07 11:50:17 +01:00
(add-hook 'prog-mode-hook #'ws-butler-mode)
(add-hook 'text-mode-hook #'ws-butler-mode))
2021-11-29 13:14:56 +01:00
#+end_src
2022-01-01 11:42:28 +01:00
** [[https://countvajhula.com/2021/09/25/the-animated-guide-to-symex/][Structural editing]]
2021-12-16 09:00:35 +01:00
:PROPERTIES:
2021-12-29 10:05:06 +01:00
:CUSTOM_ID: sec:structural-editing
2021-12-16 09:00:35 +01:00
:END:
2021-11-29 13:14:56 +01:00
2021-12-29 10:05:06 +01:00
Structural editing keeps character pairs (for instance parentheses, curly and
2021-12-16 09:00:35 +01:00
square brackets as well as single and double quotes) balanced to leave code (for
instance Lisp and Python) and text (for instance LaTeX and Org) structure
intact. I use [[https://github.com/Fuco1/smartparens ][smartparens ]] which offers a normal mode (=smartparens-mode= ) and a
2022-08-21 13:48:09 +02:00
strict mode (=smartparens-strict-mode= ). Although both modes insert character
2022-01-07 16:32:43 +01:00
pairs, the normal mode allows to delete one of the paired characters easily
2021-12-16 09:00:35 +01:00
while the strict mode does not. Therefore, the strict mode is more for code
editing since it never breaks programming language rules and the normal mode is
more for text editing where structure is a matter of convention instead of
programming language rules.
For instance, the strict mode in Python allows to delete entire lists, tuples,
or the arguments after the cursor (what Emacs calls =point= ) in a function call
without breaking the character pair balance. In order to repair a broken
character pair balance, insert a single character by prefixing it with "C-q"
bound to =quoted-insert= .
The [[https://smartparens.readthedocs.io/en/latest/index.html ][smartparens documentation ]] targets experienced Emacs users. The
following links show how to put the documentation to practical use:
1. [[https://gist.github.com/oantolin ][Omar Antolin's gist "my-smartparens-config.el" ]] is the first place to look for
how to tweak [[https://github.com/Fuco1/smartparens ][smartparens ]]. However, the gist may be partially obsolete, since
it is not part of his current [[https://github.com/oantolin/emacs-config ][Emacs configuration ]].
2. [[https://lists.gnu.org/archive/html/help-gnu-emacs/2014-07/msg00135.html ][How to enable smartparens in the minibuffer after eval-expression ]] explains
how the machinery after the first and after later usages of =eval-expression=
differ and discusses options how to handle those differences.
2021-12-23 15:29:03 +01:00
Listing [[lst:configure-smartparens ]] aims to configure [[https://github.com/Fuco1/smartparens ][smartparens ]] for Elisp,
LaTeX, Org, and Python.
2021-12-15 17:59:15 +01:00
2022-02-23 07:44:29 +01:00
Despite the provocative post [[https://andreyorst.gitlab.io/posts/2022-02-20-what-if-structural-editing-was-a-mistake/ ]["What if structural editing was a mistake?" ]],
[[https://github.com/Fuco1/smartparens ][smartparens ]] is one of my favorite packages. In particular, [[https://github.com/Fuco1/smartparens ][smartparens ]] handles
matching pairs in Org-mode files with export and source blocks for multiple
formats and languages correctly. Therefore, [[https://smartparens.readthedocs.io/en/latest/index.html?highlight=show-smartparens-mode#getting-started ][show-smartparens-mode ]] highlights
matching pairs immediately in front or after point in such files correctly,
contrary to for instance [[https://github.com/Fanael/rainbow-delimiters#readme ][rainbow-delimiters ]].
2021-12-23 15:29:03 +01:00
#+caption[Configure =smartparens= ]:
#+caption : Configure =smartparens=.
2021-12-28 08:48:03 +01:00
#+name : lst:configure-smartparens
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(when (and (ensure-package-installation 'smartparens)
;; Require `smartparens-config' instead of `smartparens' to
;; disable pairing of the quote character for lisp modes.
(require 'smartparens-config nil 'noerror))
2023-01-12 21:28:18 +01:00
(setopt sp-base-key-bindings 'sp
sp-override-key-bindings '(("C-(" . sp-backward-barf-sexp)
("C-)" . sp-forward-slurp-sexp)))
2021-11-29 13:14:56 +01:00
2023-01-05 14:53:22 +01:00
(dolist (hook '(conf-toml-mode-hook prog-mode-hook text-mode-hook))
2022-11-07 11:50:17 +01:00
(add-hook hook #'smartparens-mode))
2022-04-17 19:36:57 +02:00
2022-11-07 11:50:17 +01:00
(dolist (hook '(emacs-lisp-mode-hook
ielm-mode-hook
lisp-data-mode-hook
lisp-mode-hook
python-mode-hook
sly-mrepl-mode-hook))
(add-hook hook #'smartparens-strict-mode))
2021-11-29 13:14:56 +01:00
2022-11-07 11:50:17 +01:00
;; https://xenodium.com/emacs-smartparens-auto-indent/index.html
(defun indent-between-pair (&rest _ignored)
(newline)
(indent-according-to-mode)
(forward-line -1)
(indent-according-to-mode))
2021-11-29 13:14:56 +01:00
2022-11-07 11:50:17 +01:00
(dolist (left '("(" "[" "{"))
(sp-local-pair 'prog-mode left
nil :post-handlers '((indent-between-pair "RET"))))
2021-11-29 13:14:56 +01:00
2022-11-07 11:50:17 +01:00
(show-smartparens-global-mode +1))
2021-11-29 13:14:56 +01:00
#+end_src
2022-01-09 15:39:14 +01:00
** [[https://github.com/davidshepherd7/electric-operator#readme][Electric operators]]
2021-12-06 08:32:39 +01:00
:PROPERTIES:
:CUSTOM_ID: sec:electric-operators
:END:
2021-11-29 13:14:56 +01:00
2023-03-05 10:50:25 +01:00
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]].
2021-12-28 08:44:00 +01:00
2022-04-30 18:59:01 +02:00
#+caption[Configure =electric-operator= ]:
#+caption : Configure =electric-operator=.
#+name : lst:configure-electric-operator
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(when (and (ensure-package-installation 'electric-operator)
(fboundp 'electric-operator-mode))
2022-11-20 12:13:26 +01:00
(add-hook 'c-mode-common-hook #'electric-operator-mode)
2022-11-07 11:50:17 +01:00
(add-hook 'python-mode-hook #'electric-operator-mode))
2021-11-29 13:14:56 +01:00
#+end_src
2022-01-09 15:39:14 +01:00
** [[https://joaotavora.github.io/yasnippet/][Smart snippets]]
2021-12-23 15:29:03 +01:00
:PROPERTIES:
:CUSTOM_ID: sec:smart-snippets
:END:
2021-11-29 13:14:56 +01:00
2021-12-23 15:29:03 +01:00
#+caption[Enable =yas-global-mode= ]:
#+caption : Enable =yas-global-mode=.
2021-12-28 08:48:03 +01:00
#+name : lst:enable-yas-global-mode
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(when (ensure-package-installation 'yasnippet)
2023-01-12 21:28:18 +01:00
;; Set `yas-alias-to-yas/prefix-p' before loading `yasnippet'.
(setopt yas-alias-to-yas/prefix-p nil)
2022-11-07 11:50:17 +01:00
(when (require 'yasnippet nil 'noerror)
(yas-global-mode +1)))
2021-11-29 13:14:56 +01:00
#+end_src
2022-09-18 21:59:11 +02:00
** [[info:autotype#Tempo][Tempo (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:tempo
:END:
The official [[info:autotype#Tempo ][tempo (info) ]] documentation is very short and the following links
are obsolete or do not reveal the full power of [[info:autotype#Tempo ][tempo (info) ]] after its
adaptation to =lexical-binding= :
2023-02-15 06:45:37 +01:00
1. [[https://www.emacswiki.org/emacs/TempoMode ][Tempo (Emacs Wiki) ]].
2. [[https://www.lysator.liu.se/~davidk/elisp/ ][David Kågedal’ s elisp ]].
3. [[https://github.com/yilkalargaw/emacs-native-snippets ][Emacs's Native Snippets ]], [[https://www.reddit.com/r/emacs/comments/wdbk34/emacss_native_templating_and_snippet_fuctionality/ ][Emacs's native templating and snippet functionality ]].
4. [[https://www.n16f.net/blog/templating-in-emacs-with-tempo/ ][Templating in Emacs with Tempo ]].
Listing [[lst:configure-tempo-ui ]] defines a function that inserts major modes
specific tempo templates by means of [[https://github.com/minad/marginalia ][marginalia ]], a function to define local
keybindings and the tools to add =tempo-tags= to abbreviation tables.
Listing [[lst:configure-tempo-latex-completing-read ]] shows how to combine =tempo= ,
=latex= and =completing-read= for the builtin =tempo= package. Listing
[[lst:setup-python-tempo ]] configures =tempo= for =python-mode= .
2022-09-25 11:42:58 +02:00
#+caption[Configure =tempo= user interface]:
#+caption : Configure =tempo= user-interface.
#+name : lst:configure-tempo-ui
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2023-03-06 13:18:46 +01:00
(when (require 'tempo nil 'noerror)
2023-01-12 21:28:18 +01:00
(setopt tempo-interactive t)
2022-09-18 21:59:11 +02:00
2023-02-15 06:45:37 +01:00
(with-eval-after-load 'marginalia
(add-to-list 'marginalia-prompt-categories
'("\\<tempo template\\ >" . command)))
;; https://www.n16f.net/blog/templating-in-emacs-with-tempo/
(defun insert-tempo-template ()
"Insert a major mode specific tempo template."
(interactive)
(let* ((choices (mapcar #'cdr (tempo-build-collection)))
(function-name (completing-read "Tempo template: " choices)))
(funcall (intern function-name))))
2022-11-07 11:50:17 +01:00
(defun setup-local-tempo-key-bindings ()
"Initialize local `tempo' key bindings."
2023-02-15 06:45:37 +01:00
(keymap-local-set "M-n" #'tempo-forward-mark)
(keymap-local-set "M-p" #'tempo-backward-mark)
(keymap-local-set "M-+" #'insert-tempo-template))
2022-09-25 11:42:58 +02:00
2022-11-07 11:50:17 +01:00
(defun abbrev-tempo-expand-if-complete ()
"Hook function for `define-abbrev' with `no-self-insert' property `t'."
(tempo-expand-if-complete))
2022-09-24 20:48:16 +02:00
2022-11-07 11:50:17 +01:00
(put 'abbrev-tempo-expand-if-complete 'no-self-insert t)
2022-09-24 20:48:16 +02:00
2022-11-07 11:50:17 +01:00
(defun add-tempo-tags-to-abbrev-table (tempo-tags abbrev-table)
"Add the tags in TEMPO-TAGS to ABBREV-TABLE.
Allows `tempo' expansion by typing <SPC > after a complete `tempo' tag."
(dolist (tag tempo-tags)
(unless (abbrev-symbol (car tag) abbrev-table)
(define-abbrev abbrev-table
(car tag) 1 'abbrev-tempo-expand-if-complete)))))
2022-09-24 20:48:16 +02:00
#+end_src
#+caption[Configure =tempo= for =latex= with =completing-read= ]:
#+caption : Configure =tempo= for =latex= with =completing-read=.
#+name : lst:configure-tempo-latex-completing-read
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'latex
(unless (featurep 'tempo)
(require 'tempo))
2022-09-23 07:33:33 +02:00
2022-11-07 11:50:17 +01:00
(defun tempo-latex-environment-handler (element)
2023-03-06 13:18:46 +01:00
(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 "}" >))))
2022-09-18 21:59:11 +02:00
2022-11-07 11:50:17 +01:00
(cl-pushnew 'tempo-latex-environment-handler tempo-user-elements)
2022-09-18 21:59:11 +02:00
2022-11-07 11:50:17 +01:00
(defun setup-tempo-latex ()
(setup-local-tempo-key-bindings)
(defvar latex-tempo-tags nil)
2022-09-24 20:48:16 +02:00
2022-11-07 11:50:17 +01:00
(tempo-define-template
"LaTeX-environment"
'('latex-environment)
"env"
"Insert a LaTeX environment"
'latex-tempo-tags)
2022-09-24 20:48:16 +02:00
2022-11-07 11:50:17 +01:00
(tempo-use-tag-list 'latex-tempo-tags)
(add-tempo-tags-to-abbrev-table latex-tempo-tags latex-mode-abbrev-table))
2022-09-24 20:48:16 +02:00
2022-11-07 11:50:17 +01:00
(add-hook 'LaTeX-mode-hook 'setup-tempo-latex))
2022-09-24 20:48:16 +02:00
#+end_src
#+caption[Configure =tempo= for =python-mode= ]:
#+caption : Configure =tempo= for =python-mode=.
#+name : lst:setup-python-tempo
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'python
(unless (featurep 'tempo)
(require 'tempo))
(defun setup-tempo-python ()
(defvar python-tempo-tags nil)
(tempo-define-template
"python-base-class"
'("class " p ":" n >)
"clsb" "Define a base class" 'python-tempo-tags)
(tempo-define-template
"python-derived-class"
'("class " p "(" p "):" n >)
"clsd" "Define a derived class" 'python-tempo-tags)
(tempo-define-template
"python-class-method"
'("@classmethod" > n > "def " p "(cls, " p "):" n >)
"defc" "Define a class method" 'python-tempo-tags)
(tempo-define-template
"python-function"
'("def " p "(" p "):" n >)
"deff" "Define a function" 'python-tempo-tags)
(tempo-define-template
"python-normal-method"
'("def " p "(self, " p "):" n >)
"defm" "Define a normal method" 'python-tempo-tags)
(tempo-define-template
"python-static-method"
'("@staticmethod" > n > "def " p "(" p "):" n >)
"defs" "Define a static method" 'python-tempo-tags)
(tempo-use-tag-list 'python-tempo-tags)
(add-tempo-tags-to-abbrev-table python-tempo-tags python-mode-abbrev-table)
(setup-local-tempo-key-bindings))
(add-hook 'python-mode-hook 'setup-tempo-python))
2022-09-18 21:59:11 +02:00
#+end_src
2022-01-17 07:56:55 +01:00
* [[info:emacs#Display][Display (info)]]
2022-01-09 15:39:14 +01:00
:PROPERTIES:
2022-01-17 07:56:55 +01:00
:CUSTOM_ID: sec:display
2022-01-09 15:39:14 +01:00
:END:
2021-12-29 14:05:03 +01:00
2022-01-17 07:56:55 +01:00
** [[info:emacs#Narrowing][Narrowing]]
:PROPERTIES:
:CUSTOM_ID: sec:narrowing
:END:
Narrowing means focusing in on some portion of the buffer and widening means
focussing out on the whole buffer. This allows to concentrate temporarily on
for instance a particular function or paragraph by removing clutter. The "Do
What I Mean" [[https://endlessparentheses.com/emacs-narrow-or-widen-dwim.html ][narrow-or-widen-dwim ]] function allows to toggle between narrowed and
widened buffer states. Here, the function =narrow-or-widen-dwim= operates also
2022-05-28 17:44:19 +02:00
on any Org table, Org source block, Org block, or Org subtree.
2022-01-17 07:56:55 +01:00
#+caption[Configure =narrow-or-widen-dwim= ]:
#+caption : Configure =narrow-or-widen-dwim=.
#+name : lst:configure-narrow-or-widen-dwim
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'emacs
2023-01-12 21:28:18 +01:00
(declare-function org-at-table-p "org" (&optional table-type))
2022-04-18 12:33:52 +02:00
2022-11-07 11:50:17 +01:00
(defun org-narrow-to-table ()
"Narrow buffer to table at point."
(interactive)
(if (org-at-table-p)
(narrow-to-region (org-table-begin) (org-table-end))
(user-error "Not in a table")))
(defun narrow-or-widen-dwim (p)
"Widen if buffer is narrowed, narrow \"Do What I Mean\" otherwise.
DWIM means: region, Org table, Org source block, Org block, Org
subtree, LaTeX environment, TeX group, or defun, whichever
applies first. Narrowing to org-src-block actually calls
`org-edit-src-code'.
With prefix P, don't widen, just narrow even if buffer is already
narrowed."
(interactive "P")
(declare (interactive-only))
(cond ((and (buffer-narrowed-p) (not p))
(widen))
((and (bound-and-true-p org-src-mode) (not p))
(org-edit-src-exit))
((region-active-p)
(narrow-to-region (region-beginning) (region-end)))
((derived-mode-p 'org-mode)
(or (with-demoted-errors "DWIM: %S" (org-narrow-to-table) t)
(with-demoted-errors "DWIM: %S" (org-edit-src-code) t)
(with-demoted-errors "DWIM: %S" (org-narrow-to-block) t)
(org-narrow-to-subtree)))
((derived-mode-p 'latex-mode)
(LaTeX-narrow-to-environment))
((derived-mode-p 'tex-mode)
(TeX-narrow-to-group))
(t
(narrow-to-defun))))
2023-02-26 14:37:33 +01:00
(keymap-set ctl-x-map "n t" #'org-narrow-to-table)
(keymap-set ctl-x-map "C-n" #'narrow-or-widen-dwim))
2022-01-17 07:56:55 +01:00
#+end_src
2022-03-26 15:41:37 +01:00
2021-12-29 14:05:03 +01:00
** [[https://jblevins.org/log/rainbow-mode][Visualize color codes and names]]
2022-01-09 15:39:14 +01:00
:PROPERTIES:
:CUSTOM_ID: sec:rainbow-mode
:END:
2021-12-29 14:05:03 +01:00
Listing [[lst:enable-rainbow-mode ]] enables =rainbow-mode= to colorize color codes
and names in buffers for debugging.
2021-12-13 12:41:06 +01:00
2021-12-23 15:29:03 +01:00
#+caption[Enable =rainbow-mode= ]:
#+caption : Enable =rainbow-mode=.
2021-12-28 08:42:19 +01:00
#+name : lst:enable-rainbow-mode
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(when (and (ensure-package-installation 'rainbow-mode)
(fboundp 'rainbow-mode))
2023-01-12 21:28:18 +01:00
(setopt rainbow-x-colors-major-mode-list '(c++-mode
c-mode
emacs-lisp-mode
inferior-emacs-lisp-mode
java-mode
lisp-interaction-mode
org-mode
python-mode))
2022-11-07 11:50:17 +01:00
(rainbow-mode +1))
2021-12-13 12:41:06 +01:00
#+end_src
2021-12-29 14:05:03 +01:00
** [[https://karthinks.com/software/batteries-included-with-emacs/][Flash the line around point for visual feedback]]
2022-01-09 15:39:14 +01:00
:PROPERTIES:
:CUSTOM_ID: sec:flash-line-around-point
:END:
2021-12-29 14:05:03 +01:00
2022-04-10 07:23:29 +02:00
Listing [[lst:flash-line-around-point ]] implements flashing of the line around point
for visual feedback after a selection of commands that make it hard to track
point movements visually.
#+caption[Implement =flash-line-around-point= ]:
#+caption : Implement =flash-line-around-point=.
#+name : lst:flash-line-around-point
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
;; Ensure loading `pulse' with the dynamic variables `pulse-delay' and
;; `pulse-iterations' before masking them lexically instead of after
;; to prevent the warning triggered by lazy loading.
(when (require 'pulse nil 'noerror)
;; https://karthinks.com/software/batteries-included-with-emacs/
;; https://github.com/karthink/ .emacs.d/blob/master/init.el#L2077
(defun flash-line-around-point (&rest _)
"Flash the line around point."
(let ((pulse-iterations 16)
(pulse-delay 0.1))
(pulse-momentary-highlight-one-line (point))))
(dolist (command '(scroll-up-command
scroll-down-command
recenter-top-bottom
other-window))
(advice-add command :after #'flash-line-around-point)))
2021-11-29 13:14:56 +01:00
#+end_src
* Applications
2022-01-09 15:39:14 +01:00
:PROPERTIES:
:CUSTOM_ID: sec:applications
:END:
2021-11-29 13:14:56 +01:00
2022-02-13 16:13:13 +01:00
** [[info:emacs#Hyperlinking][Hyperlinking and Web Navigation Features (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:hyperlinking-web-navigating
:END:
2022-03-21 07:52:06 +01:00
*** [[info:emacs#Browse-URL][Browse URL (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:browse-url
:END:
Listing [[lst:configure-browse-url ]] configures =browse-url= .
2022-04-01 12:29:52 +02:00
#+attr_latex : :options breaklines
2022-03-21 07:52:06 +01:00
#+caption[Configure =browse-url= ]:
#+caption : Configure =browse-url=.
#+name : lst:configure-browse-url
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'browse-url
(defun browse-url-mpv (url &optional _)
(start-process "mpv" nil "mpv" url))
(defconst browse-url-mpv-regexp
2022-12-21 17:48:28 +01:00
(rx bos "http" (opt "s") "://"
(or (seq "youtu.be/")
(seq "www.youtube.com/" (or "embed/ " "watch?"))
2022-11-07 11:50:17 +01:00
(seq (+? nonl) (or ".mp4" ".webm") eos)))
2022-12-21 17:48:28 +01:00
"Match hyperlinks to open with mpv.")
2022-11-07 11:50:17 +01:00
2023-01-12 21:28:18 +01:00
(setopt
browse-url-generic-program (or (when (eq system-type 'darwin) "open")
(executable-find "firefox"))
browse-url-handlers `((,browse-url-mpv-regexp . browse-url-mpv)
("." . eww-browse-url))))
2022-03-21 07:52:06 +01:00
#+end_src
*** [[https://en.wikipedia.org/wiki/Eww_(web_browser)][Emacs Web Wowser]]
:PROPERTIES:
:CUSTOM_ID: sec:emacs-web-wowser
:END:
#+caption[Configure =eww= URLs]:
#+caption : Configure =eww= URLs.
#+name : lst:configure-eww-urls
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(when (fboundp 'eww-browse-url)
(defun eww-subreddit ()
"Read a subreddit in Emacs."
(interactive)
(eww-browse-url (format "www.reddit.com/r/ %s/.mobile"
(completing-read "subreddit: "
'("emacs"
"i3wm"
"orgmode")
nil t)))))
2022-03-21 07:52:06 +01:00
#+end_src
2022-10-27 00:49:22 +02:00
#+caption[Rename =eww= buffers and display =pdf= links properly]:
#+caption : Rename =eww= buffers and display =pdf= links properly.
#+name : lst:rename-eww-buffer-display-pdf-links
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'eww
(defun eww-display-pdf-as-binary (fn &rest args)
(let ((buffer-file-coding-system 'binary))
(apply fn args)))
2022-10-27 00:49:22 +02:00
2022-11-07 11:50:17 +01:00
(defun eww-rename-buffer ()
"Rename the buffer using title or url."
(let* ((title (plist-get eww-data :title))
(name (or (and (eq "" title) (plist-get eww-data :url)) title)))
(rename-buffer (format "*%s # eww* " name) t)))
2022-03-21 07:52:06 +01:00
2022-11-07 11:50:17 +01:00
(add-hook 'eww-after-render-hook #'eww-rename-buffer)
(advice-add 'eww-display-pdf :around #'eww-display-pdf-as-binary))
2022-03-21 07:52:06 +01:00
#+end_src
2023-01-01 14:56:22 +01:00
*** [[https://www.gnu.org/software/hyperbole/][GNU Hyperbole]] :noexport:
2022-12-19 09:34:10 +01:00
:PROPERTIES:
:CUSTOM_ID: sec:ensure-hyperbole-installation
2023-01-01 14:56:22 +01:00
:header-args:emacs-lisp: :tangle no :eval never-export
2022-12-19 09:34:10 +01:00
:END:
2022-12-22 14:12:35 +01:00
Listing [[lst:ensure-hyperbole-installation ][ensure Hyperbole installation ]] works around two [[https://www.gnu.org/software/hyperbole/ ][GNU Hyperbole ]] quirks:
1. The [[https://elpa.gnu.org/elpa/hyperbole.html ][GNU ELPA Hyperbole ]] and [[https://elpa.gnu.org/devel/hyperbole.html ][GNU ELPA Hyperbole developer ]] packages ship their
own =hyperbole-autoloads= and =kotl-autoloads= files which are incompatible
with Emacs Lisp packages from "package archives". Consequently, Emacs can
neither autoload nor load the =hyperbole-autoloads= and =kotl-autoloads=
files. Therefore, the predicate loading the =kotl-autoloads= file in the
first =unless= form of listing [[lst:ensure-hyperbole-installation ][ensure Hyperbole installation ]] will fail and
the body of this form will overwrite the =hyperbole-autoloads= file to fix
=load-path= *and* load the =hyperbole-autoloads= and =kotl-autoloads= files.
A next time, Emacs will be able to autoload the new =hyperbole-autoloads=
file but not the =kotl-autoloads= file. However, Emacs will now be able to
load the =kotl-autoloads= file which the predicate in the first =unless= form
of listing [[lst:ensure-hyperbole-installation ][ensure Hyperbole installation ]] does.
2. [[https://www.gnu.org/software/hyperbole/ ][GNU Hyperbole ]] and [[info:vertico#Top ][Vertico (info) ]] do not play well together, since the
=vertico-mode= preselection of the first candidate out of the full candidate
completion list interferes with =hyperbole-mode= expectations where it must
handle a full candidate list. Therefore, the function call
src_emacs-lisp{(either-hyperbole-or-vertico-mode)} handles this conflict by
toggling between =hyperbole-mode= and =vertico-mode= .
2022-12-19 09:34:10 +01:00
#+caption[Ensure Hyperbole installation]:
2022-12-22 14:12:35 +01:00
#+caption : Ensure Hyperbole installation and address two Hyperbole quirks.
2022-12-19 09:34:10 +01:00
#+name : lst:ensure-hyperbole-installation
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-12-19 09:34:10 +01:00
(when (ensure-package-installation 'hyperbole)
2022-12-22 14:12:35 +01:00
(unless (load "kotl-autoloads.el" 'noerror nil nil 'must-suffix)
;; See `package-generate-autoloads' for `loaddefs-generate' usage.
(unless (bound-and-true-p package-archive-contents)
(package-read-all-archive-contents))
(let* ((pkg-desc (cadr (assq 'hyperbole package-archive-contents)))
(pkg-dir (expand-file-name
(package-desc-full-name pkg-desc) package-user-dir))
(hpbl-alf (expand-file-name "hyperbole-autoloads.el" pkg-dir))
(kotl-alf (expand-file-name
(file-name-concat "kotl" "kotl-autoloads.el") pkg-dir))
(extra-data
(concat
(prin1-to-string
'(add-to-list
'load-path
(or (and load-file-name (file-name-directory load-file-name))
(car load-path))))
"\n"
(prin1-to-string
'(add-to-list
'load-path
(expand-file-name
"kotl"
(or (and load-file-name (file-name-directory load-file-name))
(car load-path)))))))
(autoload-timestamps nil)
(version-control 'never))
(loaddefs-generate pkg-dir hpbl-alf nil extra-data nil 'generate-full)
(dolist (alf (list hpbl-alf kotl-alf))
(let ((buf (find-buffer-visiting hpbl-alf)))
(when buf (kill-buffer buf)))
(load alf nil nil nil 'must-suffix))))
2022-12-19 09:34:10 +01:00
(defun either-hyperbole-or-vertico-mode ()
2022-12-22 14:12:35 +01:00
"Toggle between either `hyperbole-mode' or `vertico-mode'."
2022-12-19 09:34:10 +01:00
(interactive)
(when (and (boundp hyperbole-mode) (boundp vertico-mode))
(if hyperbole-mode
(progn
(hyperbole-mode -1)
(vertico-mode +1))
(hyperbole-mode +1)
(vertico-mode -1)))))
#+end_src
2022-03-04 07:49:15 +01:00
*** [[https://en.wikipedia.org/wiki/Media_type#Mailcap][Mailcap]]
:PROPERTIES:
:CUSTOM_ID: sec:mailcap
:END:
Extension packages as [[info:emacs#EWW ][EWW (info) ]], [[info:emacs#Gnus ][Gnus (info) ]], and [[info:org#Top ][Org (info) ]] rely on a [[https://en.wikipedia.org/wiki/Media_type#Mailcap ][mailcap ]]
file to know what application should open a specific media file type. Listing
[[lst:tangle-mailcap-file ]] specifies =emacsclient= as the application to open PDF
files.
#+caption[Tangle =mailcap= file]:
#+caption : Tangle =mailcap= file.
#+name : lst:tangle-mailcap-file
2023-01-24 07:41:16 +01:00
#+begin_src org -n :tangle ~/.mailcap
2022-11-07 11:50:17 +01:00
# https://emacs.stackexchange.com/a/24502 answers the question:
# How to use pdf-tools (pdf-view-mode) in emacs?
application/pdf; emacsclient %s
2022-03-04 07:49:15 +01:00
#+end_src
2023-02-26 13:59:16 +01:00
*** [[https://github.com/pashky/restclient.el#readme][Restclient]]
:PROPERTIES:
:CUSTOM_ID: sec:restclient
:END:
[[https://github.com/pashky/restclient.el#readme ][Restclient ]] is a tool to manually explore and test =HTTP= =REST= webservices. It
runs queries from a plain-text query sheet and displays results as images,
pretty-printed =XML= , and pretty-printed =JSON= .
#+begin_src emacs-lisp -n :silent nil
(ensure-package-installation 'restclient)
#+end_src
#+caption[Explore =PEP-691= and =PEP-700= with =restclient= ]:
#+caption : Explore =PEP-691= and =PEP-700= with =restclient=.
#+name : lst:restclient-pep-691-700
#+begin_src restclient -n :results client
# Get the JSON project list from PyPI using PEP-691 and PEP-700
GET https://pypi.org/simple
Accept: application/vnd.pypi.simple.latest+json
# Get the JSON project details of "circular-buffer" using PEP-691 and PEP-700
GET https://pypi.org/simple/circular-buffer
Accept: application/vnd.pypi.simple.latest+json
# Get the JSON project details of "holygrail" using PEP-691 and PEP-700
GET https://pypi.org/simple/holygrail
Accept: application/vnd.pypi.simple.latest+json
# Get the JSON project details of "pipdeptree" using PEP-691 and PEP-700
GET https://pypi.org/simple/pipdeptree
Accept: application/vnd.pypi.simple.latest+json
# Get the JSON project details of "numpy" using PEP-691 and PEP-700
GET https://pypi.org/simple/numpy
Accept: application/vnd.pypi.simple.latest+json
#+end_src
2022-03-21 07:52:06 +01:00
*** [[https://www.emacswiki.org/emacs/WebJump][Webjump]]
:PROPERTIES:
:CUSTOM_ID: sec:webjump
:END:
2023-01-12 21:28:18 +01:00
Listing [[lst:set-webjump-options ]] binds {{{kbd(C-c j)}}} to =webjump= and
sets the =webjump-sites= option.
2022-03-21 07:52:06 +01:00
2022-04-18 08:26:40 +02:00
#+attr_latex : :options breaklines
2023-01-12 21:28:18 +01:00
#+caption[Set =webjump= options and bind the =webjump= command]:
#+caption : Set =webjump= options and bind the =webjump= command.
#+name : lst:set-webjump-options
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(when (fboundp 'webjump)
2023-02-26 14:37:33 +01:00
(keymap-global-set "C-c j" 'webjump)
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'webjump
2023-01-12 21:28:18 +01:00
(setopt
webjump-sites
'(("CS 325 AI Programming" . "courses.cs.northwestern.edu/325")
("Emacs News" . "sachachua.com/blog/category/emacs-news")
("Mastering Emacs" . "www.masteringemacs.org")
("Planet Emacs Life" . "planet.emacslife.com")
("Real Python" . "realpython.com")
("Worg - Org Mode Community" . "orgmode.org/worg")
("Git: Emacs" . "git.savannah.gnu.org/cgit/emacs.git")
("Git: Emacs Core Python Mode" .
"git.savannah.gnu.org/cgit/emacs.git/log/lisp/progmodes/python.el")
2023-02-08 08:07:27 +01:00
("Git: Emacs MultiMedia System" .
"https://git.savannah.gnu.org/cgit/emms.git")
2023-01-12 21:28:18 +01:00
("Git: GNU ELPA" . "git.savannah.gnu.org/cgit/emacs/elpa.git")
("Git: NonGNU ELPA" . "git.savannah.gnu.org/cgit/emacs/nongnu.git")
("Git: Org Mode" . "git.savannah.gnu.org/cgit/emacs/org-mode.git")
("List: Org Mode" . "list.orgmode.org")
("List: Emacs Developer Archives" .
"lists.gnu.org/archive/html/emacs-devel/ ")
("List: Help GNU Emacs Archives" .
"lists.gnu.org/archive/html/help-gnu-emacs/ ")
("Asian Pacific Journal Japan Focus" . "apjjf.org")
("Counterpunch" . "www.counterpunch.org")
("Dictionary FR" . [simple-query "www.cnrtl.fr"
"www.cnrtl.fr/definition/ " ""])
("Dictionary NL" . [simple-query "www.woorden.org"
"www.woorden.org/woord/ " ""])
("Le Figaro" . "www.lefigaro.fr")
("Le Monde" . "www.lemonde.fr")
("Libération" . "www.liberation.fr")
("Monde Diplomatique" . "www.monde-diplomatique.fr")
("NRC". "www.nrc.nl")
("The Guardian" . "www.theguardian.com/international")
("Trouw" . "www.trouw.nl")
("Volkskrant" . "www.volkskrant.nl")))))
2022-03-21 07:52:06 +01:00
#+end_src
2022-09-04 18:57:53 +02:00
** [[info:gnus#Top][Reading News and Mail (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:reading-news-mail
:END:
1. [[https://www.maketecheasier.com/emacs-usenet-reader-with-gnus/ ][How to use Emacs as a USENET reader with Gnus ]]
2. [[https://github.com/redguardtoo/mastering-emacs-in-one-year-guide/blob/master/gnus-guide-en.org ][A practical guide to Gnus ]]
3. [[https://jao.io/blog/2021-05-17-reading-and-searching-gmane-with-gnus-fast.html ][Fast reading and searching of Gmane.io with Gnus ]]
4. [[https://www.brautaset.org/posts/leafnode-nntp-os-x.html ][Setting up Leafnode on macOS ]]
5. [[https://blog.bitside.pl/posts/gnus/ ][Gnus ]]
2022-09-11 07:39:35 +02:00
6. [[http://www.bobnewell.net/publish/35years/gmailhacks.html ][Stupid GMail hacks for Gnus ]]
7. [[http://www.bobnewell.net/publish/35years/gnuhacks.html ][More stupid Gnus hacks ]]
2022-11-13 14:26:06 +01:00
8. [[https://config.phundrak.com/emacs.html ][See Mu4e section of Phundrak's Emacs configuration ]]
1. [[https://www.passwordstore.org/ ][Pass: the standard unix password manager ]]
1. [[https://www.howtogeek.com/devops/how-to-use-pass-a-command-line-password-manager-for-linux-systems/ ][How to use Pass, a command-line password manager for Unix systems ]]
2. [[https://vitalyparnas.com/guides/pass/ ][Clever uses of pass, the Unix password manager ]]
2022-09-04 18:57:53 +02:00
2022-09-05 03:20:44 +02:00
#+attr_latex : :booktabs yes :float table
#+caption[Gnus key bindings]:
#+caption : Gnus key bindings.
#+name : tab:gnus-key-bindings
| command | map | keys |
|--------------------------------+---------------------+----------------|
| gnus-group-list-active | gnus-group-list-map | {{{kbd(A-A)}}} |
| gnus-group-list-all-groups | gnus-group-mode-map | {{{kbd(L)}}} |
| gnus-group-toggle-subscription | gnus-group-mode-map | {{{kbd(U)}}} |
|--------------------------------+---------------------+----------------|
2022-09-04 18:57:53 +02:00
#+caption[Configure =gnus= ]:
#+caption : Configure =gnus=.
#+name : lst:configure-gnus
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'gnus
2023-01-12 21:28:18 +01:00
(setopt gnus-select-method '(nntp "news.gmane.io")))
2022-12-10 13:31:06 +01:00
(with-eval-after-load 'gnus-start
2023-01-12 21:28:18 +01:00
(setopt gnus-check-bogus-newsgroups nil
gnus-check-new-newsgroups 'ask-server
gnus-read-newsrc-file t
gnus-read-active-file 'some
gnus-save-killed-list t
gnus-save-newsrc-file t
gnus-use-dribble-file t))
2022-12-10 13:31:06 +01:00
(with-eval-after-load 'gnus-sum
2023-01-12 21:28:18 +01:00
(setopt gnus-thread-hide-subtree t))
2022-09-04 18:57:53 +02:00
#+end_src
2022-07-08 10:01:57 +02:00
** [[info:emacs#Sending Mail][Sending Mail (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:sending-mail
:END:
1. [[https://macowners.club/posts/email-emacs-mu4e-macos/ ][Email setup in Emacs with Mu4e on macOS ]]
2022-07-11 12:08:54 +02:00
2. [[https://www.bounga.org/tips/2020/05/03/multiple-smtp-accounts-in-gnus-without-external-tools/ ][Setting up multiple IMAP and SMTP accounts in Gnus ]]
2022-08-05 07:21:13 +02:00
3. [[https://jherrlin.github.io/posts/emacs-on-macos-monterey/ ][Emacs on Macos Monterey ]]
2022-10-08 20:28:02 +02:00
4. [[https://github.com/00riddle00/dotfiles/blob/master/.msmtprc ][Msmtp resource file for posteo.net ]]
2022-11-06 15:53:39 +01:00
5. [[https://www.devdungeon.com/content/gpg-tutorial ][GPG tutorial ]]
6. [[https://en.wikipedia.org/wiki/Key_server_(cryptographic)#Keyserver_examples ][Cryptographic key server examples ]]
2022-11-13 14:26:06 +01:00
7. [[https://rakhim.org/fastmail-setup-with-emacs-mu4e-and-mbsync-on-macos/ ][Fastmail setup with Emacs, mu4e and mbsync on macOS ]]
2022-07-08 10:01:57 +02:00
#+caption[Configure =message= ]:
#+caption : Configure =message=.
#+name : lst:configure-message
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2023-01-12 21:28:18 +01:00
(setopt user-full-name "Gerard Vermeulen"
user-mail-address "gerard.vermeulen@posteo.net")
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'message
2023-01-12 21:28:18 +01:00
(setopt message-sendmail-envelope-from 'header))
2022-07-08 10:01:57 +02:00
#+end_src
#+caption[Configure =sendmail= ]:
#+caption : Configure =sendmail=.
#+name : lst:configure-sendmail
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'sendmail
2023-01-12 21:28:18 +01:00
(setopt mail-specify-envelope-from t
mail-envelope-from 'header
send-mail-function #'sendmail-send-it
sendmail-program (executable-find "msmtp")))
2022-07-08 10:01:57 +02:00
#+end_src
2022-07-17 20:08:01 +02:00
#+attr_latex : :options breaklines
#+caption[Resource file for =msmtp= on =Darwin= ]:
#+caption : Resource file for =msmtp= on =Darwin=.
#+name : lst:darwin-msmpt-resource-file
#+header : :tangle (if (eq 'darwin system-type) "~/.msmtprc" "no")
2023-01-24 07:41:16 +01:00
#+begin_src conf -n
2022-11-07 11:50:17 +01:00
# Set default values for all accounts.
defaults
auth on
tls on
logfile ~/.msmtp.log
# CNRS on Darwin
# security add-generic-password -s cnrs -a gerard.vermeulen@neel.cnrs.fr -w
account cnrs
host smtps.grenoble.cnrs.fr
port 465
tls_starttls off
from gerard.vermeulen@neel.cnrs.fr
user gerard.vermeulen@neel.cnrs.fr
passwordeval security find-generic-password -s cnrs -w
# https://notmuchmail.org/emacstips/#index11h2
# https://wiki.debian.org/msmtp
# https://tushartyagi.com/blog/configure-mu4e-and-msmtp/
# https://www.emacswiki.org/emacs/GnusMSMTP
# https://www.ying-ish.com/essay/emacs-notmuch-mbsync-msmtp-email/
# Local Variables:
# mode: conf-unix
# End:
2022-07-17 20:08:01 +02:00
#+end_src
#+attr_latex : :options breaklines
#+caption[Resource file for =msmtp= on =Linux= ]:
#+caption : Resource file for =msmtp= on =Linux=.
#+name : lst:linux-msmpt-resource-file
#+header : :tangle (if (eq 'gnu/linux system-type) "~/.msmtprc" "no")
2023-01-24 07:41:16 +01:00
#+begin_src conf -n
2022-11-07 11:50:17 +01:00
# Set default values for all accounts.
defaults
auth on
tls on
tls_trust_file /etc/ssl/certs/ca-certificates.crt
logfile ~/.msmtp.log
# CNRS on Linux
# secret-tool store --label=msmtp host smtps.grenoble.cnrs.fr service smtp user gerard.vermeulen@neel.cnrs.fr
account cnrs
host smtps.grenoble.cnrs.fr
port 465
tls_starttls off
from gerard.vermeulen@neel.cnrs.fr
user gerard.vermeulen@neel.cnrs.fr
# https://notmuchmail.org/emacstips/#index11h2
# https://wiki.debian.org/msmtp
# https://tushartyagi.com/blog/configure-mu4e-and-msmtp/
# https://www.emacswiki.org/emacs/GnusMSMTP
# https://www.ying-ish.com/essay/emacs-notmuch-mbsync-msmtp-email/
# Local Variables:
# mode: conf-unix
# End:
2022-07-17 20:08:01 +02:00
#+end_src
2022-01-09 15:39:14 +01:00
** [[https://github.com/skeeto/elfeed#readme][Elfeed: Emacs web feed reader]]
:PROPERTIES:
:CUSTOM_ID: sec:emacs-web-feed-reader
:END:
2021-11-29 13:14:56 +01:00
2023-01-12 21:28:18 +01:00
Listing [[lst:set-elfeed-options ]] sets =elfeed= options, binds the =elfeed=
command, and makes a minimal attempt to enable =emms= .
2022-04-18 08:26:40 +02:00
#+attr_latex : :options breaklines
2023-01-12 21:28:18 +01:00
#+caption[Set =elfeed= options and bind =elfeed= command]:
#+caption : Set =elfeed= options and bind =elfeed= command.
#+name : lst:set-elfeed-options
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(when (and (ensure-package-installation 'elfeed)
(fboundp 'elfeed))
2023-02-26 14:37:33 +01:00
(keymap-global-set "C-x w" #'elfeed)
2021-11-29 13:14:56 +01:00
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'elfeed
2023-01-12 21:28:18 +01:00
(setopt
elfeed-feeds
'(("http://www.howardism.org/index.xml" h-abrams)
("https://bitspook.in/archive/feed.xml" c-singh)
("https://emacshorrors.com/feed.atom" v-schneidermann)
("https://emacsninja.com/emacs.atom" v-schneidermann)
("https://feeds.feedburner.com/InterceptedWithJeremyScahill" j-scahill)
("https://frame.work/fr/fr/blog.rss" framework)
("https://nullprogram.com/feed/ " c-wellons)
("https://oremacs.com/atom.xml" o-krehel)
("https://planet.emacslife.com/atom.xml" planet-emacs)
("https://protesilaos.com/codelog.xml" p-stavrou)
("https://sachachua.com/blog/category/emacs/feed" s-chua)
("https://sciencescitoyennes.org/feed/ " sciences)
("https://tdodge.consulting/blog/rss.xml" t-dodge)
("https://talkpython.fm/episodes/rss" talk-python)
("https://updates.orgmode.org/feed/updates" org-updates)
("https://www.bof.nl/rss/ " bof)
("https://www.democracynow.org/podcast-video.xml" dn)
("https://www.laquadrature.net/fr/rss.xml" lqdn)
("https://www.lemonde.fr/blog/huet/feed/ " sciences))))
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'elfeed-show
(when (fboundp 'emms-all)
(emms-all))))
2021-11-29 13:14:56 +01:00
#+end_src
2022-01-09 15:39:14 +01:00
** [[info:emms#Top][Emacs Multimedia System (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:emacs-multimedia-system
:END:
2021-11-29 13:14:56 +01:00
2022-04-18 08:26:40 +02:00
The link [[https://sqrtminusone.xyz/posts/2021-09-07-emms/ ][my emms and elfeed setup ]] is a nice introduction to configuring and
2023-01-12 21:28:18 +01:00
using =emms= with =elfeed= . Listing [[lst:set-emms-options ]] configures =emms= .
2022-04-18 08:26:40 +02:00
2023-01-12 21:28:18 +01:00
#+caption[Set =emms= options]:
#+caption : Set =emms= options.
#+name : lst:set-emms-options
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(when (ensure-package-installation 'emms)
(with-eval-after-load 'emms
2023-01-12 21:28:18 +01:00
(setopt emms-player-list '(emms-player-mpd emms-player-mpv))
2022-11-07 11:50:17 +01:00
(emms-all))
2022-04-18 06:27:24 +02:00
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'emms-mode-line
2023-01-12 21:28:18 +01:00
(setopt emms-mode-line-format ""))
2022-04-18 06:27:24 +02:00
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'emms-player-mpd
2023-01-12 21:28:18 +01:00
(setopt emms-player-mpd-music-directory (expand-file-name "~/Music")
emms-player-mpd-server-name "localhost"
emms-player-mpd-server-port "6600"
emms-player-mpd-verbose t))
2022-04-18 06:27:24 +02:00
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'emms-player-mpv
2023-01-12 21:28:18 +01:00
(setopt emms-player-mpv-ipc-method 'ipc-server
emms-player-mpv-update-metadata t))
2022-04-19 04:03:39 +02:00
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'emms-playing-time
2023-01-12 21:28:18 +01:00
(setopt emms-playing-time-display-format " %s "))
2022-04-18 06:27:24 +02:00
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'emms-playlist-mode
2023-01-12 21:28:18 +01:00
(setopt emms-playlist-mode-center-when-go t))
2022-04-18 06:27:24 +02:00
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'emms-streams
2023-01-12 21:28:18 +01:00
(setopt emms-streams-file
(no-littering-expand-etc-file-name "emms/streams.emms"))))
2021-11-29 13:14:56 +01:00
#+end_src
2022-09-01 15:47:33 +02:00
*** Hiding spurious buffers
2022-04-24 10:18:32 +02:00
:PROPERTIES:
2022-09-01 15:47:33 +02:00
:CUSTOM_ID: sec:hiding-spurious-buffers
2022-04-24 10:18:32 +02:00
:END:
2022-09-01 15:47:33 +02:00
When =emms-player-mpd= opens a connection to =mpd= and =mpd= is not running,
=mpd= responds with a message of the form "OK MPD 0.23.5". Neither
=emms-player-mpd= nor its support library =tq= anticipate the "OK MPD 0.23.5"
message, but send such messages to a new intrusive buffer called =*spurious*= .
Listing [[lst:hiding-spurious-buffers ]] hides those =*spurious*= buffers, but you
can always switch to them. See:
2022-04-24 10:18:32 +02:00
1. [[info:elisp#The Zen of Buffer Display ][The Zen of Buffer Display (info) ]]
2. [[https://e17i.github.io/articles-emacs-display-1/ ][Configuring the Emacs display system ]]
2022-09-01 03:52:23 +02:00
3. [[https://www.masteringemacs.org/article/demystifying-emacs-window-manager ][Demystifying Emacs's Window Manager ]]
2022-04-24 10:18:32 +02:00
for technical information.
2022-09-01 15:47:33 +02:00
#+caption[Hiding =*spurious*= buffers]:
#+caption : Hiding =*spurious*= buffers.
#+name : lst:hiding-spurious-buffers
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'emms-player-mpd
;; https://www.masteringemacs.org/article/demystifying-emacs-window-manager
;; Hide `*spurious* ' buffers, but you can always switch to them:
(add-to-list 'display-buffer-alist
'("\\*spurious\\* .*" display-buffer-no-window
(allow-no-window . t))))
2022-04-24 10:18:32 +02:00
#+end_src
2022-07-15 17:12:53 +02:00
*** [[https://www.musicpd.org/][Music Player Daemon]] configuration
2022-04-24 10:18:32 +02:00
:PROPERTIES:
:CUSTOM_ID: sec:mpd-configuration-file
:END:
2022-11-06 17:40:56 +01:00
Listing [[lst:darwin-mpd-conf ]] proposes a [[https://www.musicpd.org/ ][Music Player Daemon ]] configuration file on
Darwin that keeps each new connection for a day in order to reduce the rate of
=*spurious*= generation.
#+caption[A Music Player Daemon configuration file on Darwin]:
#+caption : A Music Player Daemon configuration file on Darwin.
#+name : lst:darwin-mpd-conf
2023-01-24 07:41:16 +01:00
#+begin_src conf -n :tangle (if (eq 'darwin system-type) "~/.mpd/mpd.conf" "no")
2022-11-07 11:50:17 +01:00
music_directory "~/Music"
playlist_directory "~/.mpd/playlists"
db_file "~/.mpd/mpd.db"
log_file "~/.mpd/mpd.log"
pid_file "~/.mpd/mpd.pid"
state_file "~/.mpd/mpdstate"
follow_outside_symlinks "yes"
follow_inside_symlinks "yes"
bind_to_address "localhost"
port "6600"
connection_timeout "86400"
audio_output {
type "osx"
name "CoreAudio"
mixer_type "software"
}
2022-04-23 13:01:38 +02:00
#+end_src
2021-11-29 13:14:56 +01:00
* [[info:emacs#Init File][Init File (info)]] footer
:PROPERTIES:
2021-12-23 15:29:03 +01:00
:CUSTOM_ID: sec:user-init-file-footer
2021-11-29 13:14:56 +01:00
:END:
2021-12-23 15:29:03 +01:00
#+caption[Tangle the =user-init-file= footer]:
#+caption : Tangle the =user-init-file= footer.
2021-12-28 08:48:03 +01:00
#+name : lst:tangle-user-init-file-footer
2023-02-07 07:10:26 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(provide 'init)
2021-11-29 13:14:56 +01:00
2022-11-07 11:50:17 +01:00
;; Emacs looks for "Local variables:" after the last "newline-formfeed".
;; Local Variables:
;; indent-tabs-mode: nil
;; End:
;;; init.el ends here
2021-11-29 13:14:56 +01:00
#+end_src
2022-11-16 07:09:25 +01:00
* GNU Free Documentation License
:PROPERTIES:
:CUSTOM_ID: sec:gnu-fdl
:END:
#+include : fdl.org
2021-12-23 15:29:03 +01:00
* Local variables linking to [[#sec:latexmk-save-compile-display-loop][Latexmk save-compile-display-loop]]
2021-11-29 13:14:56 +01:00
:PROPERTIES:
2021-11-30 09:35:15 +01:00
:CUSTOM_ID: sec:local-variables
2021-11-29 13:14:56 +01:00
:END:
2021-11-30 18:44:54 +01:00
Only the [[info:org#Top ][Org ]] source file shows the local variables footer.
2021-11-29 13:14:56 +01:00
2022-11-06 15:53:39 +01:00
#+print_bibliography :
2022-02-17 13:15:30 +01:00
2022-05-17 05:10:55 +02:00
# Emacs looks for "Local variables:" after the last "newline-formfeed".
2021-11-29 13:14:56 +01:00
# Local Variables:
# compile-command: "latexmk -interaction=nonstopmode -lualatex -pvc -shell-escape README.tex"
2022-10-05 14:09:52 +02:00
# eval: (org-eval-emacs-lisp-setup-blocks)
2021-11-29 13:14:56 +01:00
# fill-column: 80
# End: