2024-01-21 18:51:41 +01:00
#+title : Emacs setup for use with LaTeX, Lisp, Org, and Python
2021-11-29 13:14:56 +01:00
#+author : Gerard Vermeulen
2024-01-22 13:22:36 +01:00
#+latex_class : article
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))
2023-07-06 07:33:58 +02:00
#+options : ^:{} timestamp:nil
2024-01-24 14:58:34 +01:00
#+property : header-args:emacs-lisp :exports code :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:
2024-01-21 18:51:11 +01:00
This README contains my Emacs setup for use with LaTeX, Lisp, Org, and Python.
2024-05-08 15:12:03 +02:00
Copyright \copy 2021-2024 Gerard Vermeulen.
2022-11-16 07:09:25 +01:00
#+BEGIN_QUOTE
2023-06-29 19:56:30 +02:00
All Org-mode source blocks with function definitions in this document are free
software: you can redistribute it and/or modify it under the terms of the GNU
General Public License as published by the Free Software Foundation, either
version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/ >.
#+END_QUOTE
#+BEGIN_QUOTE
Permission is granted to copy, distribute and/or modify the other parts
of this document under the terms of the GNU Free Documentation License,
2022-11-16 07:09:25 +01:00
Version 1.3 or any later version published by the Free Software
Foundation; with no Invariant Sections, with no Front-Cover Texts,
2024-01-21 18:51:11 +01:00
and with no Back-Cover Texts. You should have received a copy of the GNU
Free Documentation License with the source file of this document. If not,
see <https://www.gnu.org/licenses/ >.
2022-11-16 07:09:25 +01:00
#+END_QUOTE
2021-11-30 09:35:15 +01:00
* Quick start
:PROPERTIES:
:CUSTOM_ID: sec:quick-start
:END:
2023-09-26 15:06:50 +02:00
This setup requires at least Emacs-30. The installation procedure starts with:
1. Backup the =user-emacs-directory= which defaults often to =~/.emacs.d= .
2. Run the listing [[lst:prepare-user-emacs-directory-with-https ][prepare the =user-emacs-directory= without =ssh= access ]] or
the listing [[lst:prepare-user-emacs-directory-with-ssh ][prepare the =user-emacs-directory= with =ssh= access ]] commands.
After invoking Emacs interactively, Emacs will ask you to install a selected set
of packages. Quit Emacs and invoke Emacs again.
2023-01-03 21:04:52 +01:00
#+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-06-25 14:00:01 +02:00
#+begin_src shell -n :eval never :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-06-25 14:00:01 +02:00
#+begin_src shell -n :eval never :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
2024-01-29 09:41:51 +01:00
[[https://www.latex-project.org/ ][LaTeX ]] compilation loop to update and redisplay the [[https://en.wikipedia.org/wiki/PDF ][PDF ]] file after execution of
2021-11-29 13:14:56 +01:00
the ~org-latex-export-latex-to-latex~ command in this buffer.
2022-02-01 07:57:33 +01:00
Here follows a list of links on how to use Emacs and Elisp:
2024-01-26 10:01:12 +01:00
1. [[https://www.masteringemacs.org/ ][Mastering Emacs ]] is a link to a blog with interesting posts that promotes a
book on how to become a proficient Emacs user.
2023-03-16 17:19:11 +01:00
2. [[https://www2.lib.uchicago.edu/keith/emacs/ ][Use GNU Emacs: The Plain Text Computing Environment ]] explains the fundamentals
of the Emacs abstractions before showing how to exploit those abstractions
interactively. It targets a similar audience as the [[https://www.masteringemacs.org/ ][Mastering Emacs ]] book.
3. [[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.
2023-03-16 17:19:11 +01:00
4. [[https://www.youtube.com/watch?v=6ZWp05OW1c0 ][Emergency Emacs ]] is a link to a video on fundamental editing features and
2022-03-27 19:16:06 +02:00
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) ]].
2024-01-26 10:01:12 +01:00
5. [[https://endlessparentheses.com/ ][Endless Parentheses ]] is a blog with mindblowing code snippets.
2023-03-16 17:19:11 +01:00
6. [[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
2022-09-18 08:50:24 +02:00
[[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.
2023-03-16 17:19:11 +01:00
7. [[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.
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
2024-01-25 10:37:09 +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:
2023-03-16 17:18:32 +01:00
;;; early-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:
2024-06-15 12:11:45 +02:00
1. src_emacs-lisp[:results none]{(describe-variable 'load-prefer-newer)}
2024-01-25 14:22:36 +01:00
2. src_emacs-lisp[:results none]{(apropos-library "no-littering")}
2021-12-23 15:29:03 +01:00
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
2023-05-17 16:55:19 +02:00
consists of three parts in listing [[lst:1st-setopt-call ]], [[lst:2nd-setopt-call ]], and
[[lst:2nd-setopt-call ]] in order to limit the length of the listings for exporting
to LaTeX.
2023-01-12 21:28:18 +01:00
2024-02-14 09:40:11 +01:00
The [[info:emacs#Init File ][init file (info) ]] does load the ~custom-file~ according to the recommendation
of [[info:emacs#Saving Customizations ][saving customizations (info) ]].
2023-01-12 21:28:18 +01:00
#+caption[Set the first set of Emacs options]:
#+caption : Set the first set of Emacs options.
#+name : lst:1st-setopt-call
2024-01-25 10:37:09 +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:
2023-07-05 03:47:22 +02:00
2022-11-07 11:50:17 +01:00
(require 'cl-lib)
2023-09-26 15:06:50 +02:00
(when (< emacs-major-version 30)
(error "This `init.el' requires at least Emacs-30"))
2023-01-12 21:28:18 +01:00
(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")
2023-06-13 18:12:11 +02:00
;; Known problem: EasyPG fails to save files encrypted with GnuPG v2.4.1.
;; Darwin: brew install gnupg@2.2
2023-01-12 21:28:18 +01:00
epg-pinentry-mode 'loopback
global-hl-line-mode t
global-hl-line-sticky-flag t
history-delete-duplicates t
2024-06-17 12:33:20 +02:00
history-length 200
2023-01-12 21:28:18 +01:00
indent-tabs-mode nil
inhibit-startup-buffer-menu t
inhibit-startup-screen t
initial-scratch-message ""
2023-05-18 10:01:58 +02:00
isearch-lazy-count t
2023-01-12 21:28:18 +01:00
kill-ring-max 300
2023-05-18 10:01:58 +02:00
lazy-count-prefix-format nil
lazy-count-suffix-format " (%s/%s)"
2023-06-06 07:01:34 +02:00
lazy-highlight-initial-delay 1.0
2023-12-30 13:46:33 +01:00
mode-line-compact t
2023-01-12 21:28:18 +01:00
next-error-message-highlight t
2023-12-30 13:46:33 +01:00
recentf-max-saved-items 100
2023-01-12 21:28:18 +01:00
recentf-mode t
2024-06-05 17:45:10 +02:00
save-place-mode t
2024-06-17 12:33:20 +02:00
savehist-additional-variables nil ; Docstring is not OK!
2024-06-14 11:10:41 +02:00
savehist-mode t
2023-01-12 21:28:18 +01:00
scroll-bar-mode nil
tab-always-indent 'complete
tool-bar-mode nil
2024-02-20 14:19:16 +01:00
tooltip-mode nil
2023-01-12 21:28:18 +01:00
url-cookie-trusted-urls nil
url-cookie-untrusted-urls '(".*")
use-dialog-box nil
use-short-answers t
2024-06-12 13:07:44 +02:00
view-read-only t
winner-mode t)
2023-05-18 10:01:58 +02:00
#+end_src
2022-04-09 16:13:10 +02:00
2023-05-18 10:01:58 +02:00
#+caption[Set the second set of Emacs options: pin packages to archives]:
#+caption : Set the second set of Emacs options: pin packages to archives.
#+name : lst:2nd-setopt-call
2024-01-25 10:37:09 +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/ ")
2023-03-16 13:39:08 +01:00
("melpa-stable" . "https://stable.melpa.org/packages/ ")
2023-01-12 21:28:18 +01:00
("nongnu" . "https://elpa.nongnu.org/nongnu/ "))
2024-04-29 10:17:34 +02:00
package-install-upgrade-built-in nil
2023-07-25 10:29:52 +02:00
;; Pin packages to GNU ELPA or to MELPA STABLE for info and/or stability.
2023-01-12 21:28:18 +01:00
package-pinned-packages '((auctex . "gnu")
2023-07-25 06:55:14 +02:00
(citar . "melpa-stable")
(citar-embark . "melpa-stable")
2023-01-12 21:28:18 +01:00
(compat . "gnu")
2024-01-25 12:13:52 +01:00
(consult . "gnu")
2023-07-25 10:29:52 +02:00
(dash . "melpa-stable")
2024-03-12 10:24:52 +01:00
(debbugs . "gnu")
2024-03-25 09:22:32 +01:00
(denote . "gnu")
2024-01-25 12:13:52 +01:00
(embark . "gnu")
(embark-consult . "gnu")
(emms . "gnu")
2023-01-12 21:28:18 +01:00
(engrave-faces . "gnu-devel")
2023-07-25 10:29:52 +02:00
(f . "melpa-stable")
2024-01-25 14:17:42 +01:00
(forge . "melpa-stable")
2023-07-25 10:29:52 +02:00
(git-commit . "nongnu")
2023-12-05 12:01:40 +01:00
(keycast . "nongnu")
2023-07-25 10:29:52 +02:00
(magit . "nongnu")
(magit-section . "nongnu")
2024-01-25 12:13:52 +01:00
(marginalia . "gnu")
(osm . "gnu")
2023-03-16 13:39:08 +01:00
(parsebib . "melpa-stable")
2023-01-12 21:28:18 +01:00
(queue . "gnu")
(rainbow-mode . "gnu")
2024-06-11 18:50:35 +02:00
(realgud . "melpa")
2023-07-25 10:29:52 +02:00
(s . "melpa-stable")
2023-01-12 21:28:18 +01:00
(xr . "gnu")
2024-01-25 12:13:52 +01:00
(vertico . "gnu")
(with-editor . "nongnu")
(yasnippet . "gnu"))
2024-06-12 15:27:10 +02:00
package-selected-packages '(no-littering))
2023-05-17 16:55:19 +02:00
#+end_src
2024-05-05 16:43:04 +02:00
#+caption[Set the third set of Emacs options: final tweaks]:
#+caption : Set the third set of Emacs options: final tweaks.
2023-05-17 16:55:19 +02:00
#+name : lst:3rd-setopt-call
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2024-01-12 10:52:32 +01:00
;; To use different Org git repositories (org or gro):
2024-06-10 09:01:55 +02:00
;; (push (expand-file-name "~/VCS/org-mode/lisp") load-path)
;; Postpone loading Org after shadowing Org and sh-script faces below.
2023-12-13 17:36:08 +01:00
2024-02-01 15:54:51 +01:00
(when (eq system-type 'darwin)
2024-05-09 08:23:05 +02:00
;; Failed to initialize color list unarchiver: ...
;; BUG#32854 and BUG#70836: rm ~/Library/Colors/Emacs.clr
2024-05-09 20:06:26 +02:00
;; INSTALL file: '--without-dbus --without-gconf --without-gsettings'.
2024-02-01 15:54:51 +01:00
(setopt ns-alternate-modifier nil
ns-command-modifier 'meta
ns-right-command-modifier 'super))
(when (eq window-system 'ns)
(add-to-list 'initial-frame-alist '(height . 51))
(add-to-list 'initial-frame-alist '(width . 180)))
2023-01-12 21:28:18 +01:00
2024-02-14 09:28:39 +01:00
(when (file-exists-p custom-file)
(load custom-file))
2023-06-01 16:22:00 +02:00
#+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:
2023-05-17 16:55:19 +02:00
[[info:emacs#Package Installation ][Emacs installs packages ]] from archives on the internet. This setup uses five
2022-05-21 12:50:47 +02:00
archives:
2023-05-17 16:55:19 +02:00
1. The [[https://elpa.gnu.org/ ][GNU Emacs Lisp Package Archive ]].
2. The [[https://elpa.gnu.org/devel/index.html ][Development Emacs Lisp Package Archive ]].
3. The [[https://elpa.nongnu.org/ ][NonGNU Emacs Lisp Package Archive ]].
4. The [[https://melpa.org/#/ ][Milkypostman's Emacs Lisp Package Archive (MELPA) ]] with its official
2022-10-16 07:15:58 +02:00
[[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.
2023-05-17 16:55:19 +02:00
5. The [[https://stable.melpa.org/#/getting-started ][Stable Milkypostman's Emacs Lisp Package Archive ]].
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.
2024-03-03 16:09:37 +01:00
2. It calls src_emacs-lisp[:results silent]{(package-install-selected-packages)}
to check the installation status of all packages in src_emacs-lisp[:results
silent]{package-selected-packages} and to install the missing packages after
the user has agreed to its prompt.
2024-03-03 15:41:41 +01:00
3. It defines a function to ensure the installation of packages in other source
blocks.
2024-03-03 16:09:37 +01:00
In case of normal Emacs usage, src_emacs-lisp[:results silent]{(list-packages)}
refreshes the contents of packages and allows to update packages to the latest
version.
2022-05-21 12:50:47 +02:00
#+caption[Install the selected packages]:
#+caption : Install the selected packages.
#+name : lst:install-selected-packages
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2024-04-18 17:03:25 +02:00
(defvar package-selected-packages)
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)
;; 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-05-28 14:19:21 +02:00
Mickey Peterson's post [[https://www.masteringemacs.org/article/how-to-get-started-tree-sitter?utm_source=newsletter&utm_medium=rss ][How To Get Started with Tree-Sitter ]] explains how to use
2023-07-25 10:37:22 +02:00
=tree-sitter= in Emacs-29.1. Listing [[lst:setup-treesit-sources ][Setup =treesit= grammar sources ]] configures
where to find the different =tree-sitter= grammar sources for different
languages. Listing [[lst:setup-go ][Setup Go programming ]] shows how to configure ~tab-width~ for
~go-ts-mod~ and ~go-mode-ts-mode~ .
2023-05-28 14:19:21 +02:00
#+caption[Setup =treesit= grammar sources]:
#+caption : Setup =treesit= grammar sources.
#+name : lst:setup-treesit-sources
2024-01-25 10:37:09 +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-04-25 20:56:10 +02:00
;; go-ts-mode requires libtree-sitter-go and libtree-sitter-gomode.
2023-01-20 20:13:31 +01:00
(go "https://github.com/tree-sitter/tree-sitter-go" "master" "src")
2023-04-25 20:56:10 +02:00
(gomod "https://github.com/camdencheek/tree-sitter-go-mod" "main" "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-09-16 16:06:33 +02:00
(lua "https://github.com/MunifTanjim/tree-sitter-lua" "main" "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-05-15 14:05:56 +02:00
(yaml "https://github.com/ikatyang/tree-sitter-yaml" "master" "src"))))
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:
2024-05-05 11:18:19 +02:00
This setup does not use [[info:emacs#Custom Themes ][custom themes (info) ]], but it does a minimal setup of
fonts and faces. 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).
2024-01-15 14:20:22 +01:00
The code in listing [[lst:configure-face-attributes ]] implements those rules.
2024-03-14 10:49:05 +01:00
Listing [[lst:face-setting-functions ]] shows that font scaling is easy in case of
proper initialization of all face heights in a frame. To adjust the font size
in windows, invoke src_emacs-lisp{(set-default-face-height)}. To adjust the
2024-03-14 15:37:42 +01:00
font size in the current buffer, type {{{kbd(s-=)}}} or {{{kbd(s-+)}}} to invoke
src_emacs-lisp[:results silent]{(text-scale-adjust +1)} before making further
adjustments as displayed. Listing [[lst:face-setting-functions ]],
[[lst:shadow-org-font-lock-faces ]], and [[lst:shadow-emacs-font-lock-faces ]] show tweaks
to improve visibility without theming:
2024-03-15 08:47:37 +01:00
1. Toggling between a dark and light background by means of
2022-05-22 23:24:12 +02:00
src_emacs-lisp{(invert-default-face)}.
2024-03-15 08:47:37 +01:00
2. Shadowing the definition of faces before loading. The last item in the page
2022-05-22 23:24:12 +02:00
on [[https://orgmode.org/worg/org-contrib/babel/examples/fontify-src-code-blocks.html#org5c4406f ][fontifying Org mode source code blocks ]] describes this method.
2024-01-15 14:20:22 +01:00
Listing [[lst:use-buffer-face-mode-for-fixed-or-variable-pitch-face ]] contains
functions to set a fixed or variable pitch face in the current buffer and
2024-03-15 08:47:37 +01:00
selects a fixed pitch face for =magit-mode= and =progmode= buffers. Type
2024-06-08 09:27:32 +02:00
{{{kbd(M-x describe-text-properties)}}} to inspect faces at point. Listing
[[lst:disable-mac-mouse-change-font-size ]] tries to disable accidental changing of
the font size with the mouse on Darwin. Listing [[lst:setup-visual-line-mode ]]
configures =visual-line-mode= .
2022-05-22 23:24:12 +02:00
#+caption[Configure =face-attributes= ]:
#+caption : Configure =face-attributes=.
#+name : lst:configure-face-attributes
2024-01-25 10:37:09 +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)
2023-12-31 11:51:08 +01:00
(set-face-attribute 'default nil :family "Hack" :height 120)
2022-11-07 11:50:17 +01:00
(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
2024-03-14 10:49:05 +01:00
#+caption[Implement =face= setting functions]:
#+caption : Implement =face= setting functions.
#+name : lst:face-setting-functions
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'emacs
2024-03-14 10:49:05 +01:00
;; Neither `set-default-face-height' nor `text-scale-adjust' work well.
2022-11-07 11:50:17 +01:00
(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)
2024-01-29 09:41:51 +01:00
(let* ((prompt (format "face height (%s): "
2022-11-07 11:50:17 +01:00
(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)
2024-03-14 10:49:05 +01:00
(set-face-attribute 'default nil :height height)))
2022-11-07 11:50:17 +01:00
(defun invert-default-face ()
"Invert the default face."
(interactive)
2024-03-14 10:49:05 +01:00
(invert-face 'default)))
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-12-10 15:00:01 +01:00
#+begin_src emacs-lisp -n
2024-06-09 11:54:44 +02:00
;; 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 blocks.
2022-11-07 11:50:17 +01:00
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
2023-09-26 16:25:53 +02:00
`org-quote' faces, which inherit from `org-block'."
2024-06-09 11:54:44 +02:00
:group 'org-faces)
(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."
:group 'org-faces)
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-12-10 15:00:01 +01:00
#+begin_src emacs-lisp -n
2024-06-09 11:54:44 +02:00
;; 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."
:group 'sh-indentation)
2022-01-25 11:28:05 +01:00
#+end_src
2024-01-15 14:20:22 +01: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
#+begin_src emacs-lisp -n
;; Use proportional font faces in current buffer
(defun set-buffer-variable-pitch-face ()
"Set a variable width (proportional) font in current buffer."
(interactive)
2024-03-14 11:25:49 +01:00
(setq-local buffer-face-mode-face 'variable-pitch)
(buffer-face-mode))
2024-01-15 14:20:22 +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)
2024-03-14 11:25:49 +01:00
(setq-local buffer-face-mode-face 'fixed-pitch)
(buffer-face-mode))
2024-01-15 14:20:22 +01:00
(add-hook 'magit-mode-hook #'set-buffer-fixed-pitch-face)
(add-hook 'prog-mode-hook #'set-buffer-fixed-pitch-face)
#+end_src
2024-06-08 09:27:32 +02:00
#+caption[Disable changing font size with mouse on Darwin]:
#+caption : Disable changing font size with mouse on Darwin.
#+name : lst:disable-mac-mouse-change-font-size
#+begin_src emacs-lisp -n :results silent
(when (eq system-type 'darwin)
;; https://lmno.lol/alvaro/hey-mouse-dont-mess-with-my-emacs-font-size
;; Hint: reset font size with "C-u 0 M-x text-scale-adjust".
2024-06-09 12:06:27 +02:00
;; GAV: how to explain undefined "C-<wheel-left >" and "C-<wheel-right >"?
2024-06-08 09:27:32 +02:00
(global-set-key (kbd "<pinch >") 'ignore)
(global-set-key (kbd "<C-wheel-up >") 'ignore)
(global-set-key (kbd "<C-wheel-down >") 'ignore))
#+end_src
2024-01-27 17:24:21 +01:00
#+caption[Setup ~visual-line-mode~ ]:
#+caption : Setup ~visual-line-mode~.
#+name : lst:setup-visual-line-mode
#+begin_src emacs-lisp -n :results silent
(when (fboundp 'visual-wrap-prefix-mode)
(add-hook 'visual-line-mode-hook 'visual-wrap-prefix-mode))
#+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
2024-06-12 13:07:44 +02:00
window placement. Listing [[lst:1st-window-management ]] and
[[lst:2nd-window-management ]] implement a selection of his recommendations. See:
2024-05-05 08:52:02 +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 ]]
for technical information.
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-12-10 15:00:01 +01:00
#+begin_src emacs-lisp -n
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."
2024-04-18 17:03:25 +02:00
(lambda (buf-name _action)
(with-current-buffer buf-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
#+caption[Window management variables]:
#+caption : Window management variables.
2024-06-12 13:07:44 +02:00
#+name : lst:2nd-window-management
2024-05-05 08:52:02 +02:00
#+begin_src emacs-lisp -n :results none
2024-05-07 15:28:42 +02:00
;; (info "(elisp) Displaying Buffers")
;; (info "(emacs) Window Choice")
;; (describe-function 'display-buffer)
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'emacs
;; https://www.masteringemacs.org/article/demystifying-emacs-window-manager
2024-05-05 08:52:02 +02:00
(setopt switch-to-buffer-obey-display-actions t)
2022-11-07 11:50:17 +01:00
(add-to-list 'display-buffer-alist
2024-05-07 15:28:42 +02:00
`(,(rx (or "*Apropos* " "*Dictionary* "))
2022-11-07 11:50:17 +01:00
(display-buffer-reuse-window display-buffer-pop-up-window)
(inhibit-same-window . nil)))
2024-05-07 15:28:42 +02:00
(add-to-list 'display-buffer-alist
`(,(rx (or "*Help* " "*info* "))
display-buffer-pop-up-window
(inhibit-same-window . t)))
2022-11-07 11:50:17 +01:00
(add-to-list 'display-buffer-alist
2024-05-05 08:52:02 +02:00
`(,(rx (or "*Occur* " "*grep* " "*xref* "))
2022-11-07 11:50:17 +01:00
display-buffer-reuse-window
(inhibit-same-window . nil)))
2024-05-05 08:52:02 +02:00
;; BUG#70773: Eli tells `(setq delayed-warnings-hook nil)' is better.
2024-05-07 08:40:25 +02:00
;; BUG#70795: Inconsistent `warning-display-at-bottom' behavior.
;; https://lists.gnu.org/archive/html/bug-gnu-emacs/2024-05/msg00359.html
;; Works now always as after setting `warnings-display-at-bottom' to `nil'.
2022-11-07 11:50:17 +01:00
(add-to-list 'display-buffer-alist
2024-05-05 11:16:30 +02:00
`(,(rx (or "*Warnings* " "*compilation* "))
2022-11-07 11:50:17 +01:00
display-buffer-no-window
2024-04-12 10:29:56 +02:00
(allow-no-window . t))))
2022-09-01 03:54:05 +02:00
#+end_src
2022-10-31 13:46:31 +01:00
2023-07-06 08:03:42 +02:00
* [[info:emacs#Bookmarks][Bookmarks (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:bookmarks
:END:
2023-12-11 12:18:12 +01:00
Listing [[lst:setup-bookmark ][bookmark setup ]] preserves bookmark history in [[./var/bookmark-default.el ][bookmark-default.el ]]. Table
[[tab:bookmark-commands-and-bindings ]] lists all =bookmark= commands with working
2024-01-25 10:37:09 +01:00
key bindings. Not all key bindings in src_emacs-lisp[:results
silent]{(describe-variable 'bookmark-map)} are operational for different
reasons.
2023-12-11 12:18:12 +01:00
2023-12-09 10:59:32 +01:00
BUG: The virtual buffers of the ~consult-buffer~ command do not seem to work.
Therefore, ~consult-buffer~ is no means to access the bookmark history (contrary
to claims in [[info:consult#Top ][consult (info) ]]).
2024-01-26 10:01:12 +01:00
#+caption[Let Emacs save bookmarks when killed]:
#+caption : Let Emacs save bookmarks when killed.
2023-07-06 08:03:42 +02:00
#+name : lst:setup-bookmark
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2023-07-06 08:03:42 +02:00
(with-eval-after-load 'bookmark
2023-12-09 10:59:32 +01:00
(setopt bookmark-save-flag 1)
(setf bookmark-exit-hook 'bookmark-unload-function))
2023-07-06 08:03:42 +02:00
#+end_src
2023-12-11 12:18:12 +01:00
#+attr_latex : :booktabs yes :float table
#+caption[Bookmark commands with key bindings]:
#+caption : Bookmark commands with key bindings.
#+name : tab:bookmark-commands-and-bindings
|------------------------------+--------------------|
| command | key binding |
|------------------------------+--------------------|
| *bookmark-delete* | |
| *bookmark-delete-all* | |
| *bookmark-insert* | {{{kbd(C-x r i)}}} |
| *bookmark-insert-location* | |
| *bookmark-jump* | {{{kbd(C-x r j)}}} |
| *bookmark-jump-other-frame* | |
| *bookmark-jump-other-window* | |
| *bookmark-load* | |
| *bookmark-rename* | |
| *bookmark-save* | |
| *bookmark-set* | {{{kbd(C-x r m)}}} |
| *bookmark-set-no-overwrite* | {{{kbd(C-x r M)}}} |
| *bookmark-write* | |
| *consult-bookmark* | {{{kbd(C-x r b)}}} |
| *list-bookmarks* | |
|------------------------------+--------------------|
* [[info:emacs#Registers][Registers (info)]]
2023-12-11 08:38:43 +01:00
:PROPERTIES:
:CUSTOM_ID: sec:registers
:END:
2023-12-16 17:14:53 +01:00
Listing [[lst:register-separator-usage-example ][register separator usage example ]] shows how to use a register
{{{kbd(+)}}} as register separator when appending regions to text registers.
Listing [[lst:setup-register ][setup register usage ]] prepares my preferred register usage. Table
[[tab:register-commands-and-bindings ]] lists all =register= commands with working
2023-12-11 12:18:12 +01:00
key bindings. The =desktop= library allows to preserve the =register= history
between Emacs sessions.
2023-12-11 08:38:43 +01:00
2023-12-16 17:14:53 +01:00
#+caption[Register separator usage example]:
#+caption : Register separator usage example.
#+name : lst:register-separator-usage-example
#+begin_src text -n :exports code
When I set register ?+ to
(set-register ?+ "\n*REGISTER SEPARATOR* \n")
to test append-to-register on two regions like
Mark this line without new-line as region 1
Mark this line without new-line as region 2
The correct result of
"C-x r s T" with region 1 marked
"C-x r + T" with region 2 marked
"C-x r i T"
is:
Mark this line without new-line as region 1
*REGISTER SEPARATOR*
Mark this line without new-line as region 2
#+end_src
2023-12-11 08:38:43 +01:00
#+caption[Setup register usage]:
#+caption : Setup register usage.
#+name : lst:setup-register
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2023-12-11 08:38:43 +01:00
(with-eval-after-load 'register
2023-12-16 17:14:53 +01:00
;; Register `?+' serves as register separator when using `append-to-register':
(set-register ?+ "\n")
2023-12-11 12:18:12 +01:00
;; https://emacs.stackexchange.com/a/52290
(defun delete-all-registers ()
"Delete all registers."
(interactive)
(setq register-alist nil)))
2023-12-11 08:38:43 +01:00
#+end_src
2023-12-11 12:18:12 +01:00
#+attr_latex : :booktabs yes :float table
#+caption[Register commands with key bindings]:
#+caption : Register commands with key bindings.
#+name : tab:register-commands-and-bindings
|------------------------------------+------------------------|
| command | key binding |
|------------------------------------+------------------------|
| *append-to-register* | |
| *copy-rectangle-to-register* | {{{kbd(C-x r r)}}} |
| *copy-to-register* | {{{kbd(C-x r s)}}} |
| *frameset-to-register* | {{{kbd(C-x r f)}}} |
| *increment-register* | {{{kbd(C-x r +)}}} |
| *insert-register* | {{{kbd(C-x r i)}}} |
| *jump-to-register* | {{{kbd(C-x r j)}}} |
| *kmacro-to-register* | {{{kbd(C-x C-k x)}}} |
| *number-to-register* | {{{kbd(C-x r n)}}} |
| *point-to-register* | {{{kbd(C-x r <SPC>)}}} |
| *prepend-to-register* | |
| *set-register* | |
| *window-configuration-to-register* | {{{kbd(C-x r w)}}} |
|------------------------------------+------------------------|
2023-12-11 08:38:43 +01:00
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.
2024-04-17 10:24:28 +02:00
For instance, this setup allows to insert an =org-mode= link to a 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 file with the
specific image in a =dired-mode= buffer.
2022-02-06 13:03:59 +01:00
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
2024-01-25 10:37:09 +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 '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
2024-01-22 13:07:17 +01:00
Listing [[lst:extra-dired-key-bindings ]] adds a new key binding to =dired-mode-map=
2024-03-03 14:52:45 +01:00
to open files with the [[https://en.wikipedia.org/wiki/Eww_(web_browser) ][Emacs Web Wowser ]] inside Emacs.
2022-02-06 13:03:59 +01:00
#+caption[Extra =dired= key bindings]:
#+caption : Extra =dired= key bindings.
#+name : lst:extra-dired-key-bindings
2024-01-25 10:37:09 +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))))
2024-01-22 13:07:17 +01:00
(keymap-set dired-mode-map "E" #'dired-eww-open-file))
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
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2024-06-12 09:17:05 +02:00
(with-eval-after-load 'minibuffer
2022-12-12 08:09:19 +01:00
;; 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-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
2024-06-17 19:35:23 +02:00
with arguments and to obtain a =cons= of its numeric return code as well as its
2022-02-13 15:09:26 +01:00
output to =stdout= .
#+caption[Process utilities]:
#+caption : Process utilities.
#+name : lst:process-utilities
2024-01-25 10:37:09 +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
2024-06-17 19:31:20 +02:00
(defun get-program-code-output (program &rest args)
"Run PROGRAM with ARGS and return the `cons' of return-code and output."
2022-11-07 11:50:17 +01:00
(with-temp-buffer
2024-06-17 19:31:20 +02:00
(cons (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:
2024-03-25 10:21:00 +01:00
Listing [[lst:setup-help ]] enriches the help buffer. Table [[tab:help-key-bindings ]]
lists a number of key bindings to start playing with the help facilities of
Emacs. Try {{{kbd(C-h o)}}} instead of {{{kbd(C-h f)}}} or {{{kbd(C-h v)}}} .
#+caption[Setup =help= ]:
#+caption : Setup =help=.
#+name : lst:setup-help
#+begin_src emacs-lisp -n :results silent
(with-eval-after-load 'help-fns
2024-06-12 10:27:44 +02:00
;; ChatGPT recommends to require `shortdoc' contrary to the
;; `shortdoc-help-fns-examples-function' documentation string.
2024-06-15 12:19:48 +02:00
;; BUG#71537: "emacs -Q" works with a simpler `add-hook' form. Note:
2024-06-14 11:08:03 +02:00
;; `add-hook' should append `shortdoc-help-fns-examples-function' to
;; `help-fns-describe-function-functions'.
2024-03-25 10:21:00 +01:00
(add-hook 'help-fns-describe-function-functions
2024-06-14 11:08:03 +02:00
#'shortdoc-help-fns-examples-function 'append)
2024-03-25 10:21:00 +01:00
(setopt help-enable-symbol-autoload t))
#+end_src
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
** [[info:emacs#Name Help][Shortdoc-display-group (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:shortdoc-display-group
:END:
2024-06-12 09:16:29 +02:00
Listing [[lst:setup-shortdoc ]] binds {{{kbd(C-h y)}}} to =shortdoc-display-group= .
2022-04-17 17:45:42 +02:00
2024-06-12 09:16:29 +02:00
#+caption[Setup =shortdoc= ]:
#+caption : Setup =shortdoc=.
#+name : lst:setup-shortdoc
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(when (fboundp 'shortdoc-display-group)
2024-06-11 11:04:59 +02:00
(keymap-set help-map "y" #'shortdoc-display-group))
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
2024-01-25 10:37:09 +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)))
2023-08-17 11:30:30 +02:00
;; Make Emacs find the git Org info files.
2024-06-10 09:01:55 +02:00
;; (push (expand-file-name "~/VCS/org-mode/doc") Info-directory-list)
2024-05-12 11:03:21 +02:00
;; Make Emacs find Python info files.
(push (expand-file-name "~/.local/share/info") Info-directory-list))
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:
2024-06-12 10:58:48 +02:00
Execute src_emacs-lisp[:results none]{(find-library "novice")} to see how Emacs
prevents new users from shooting themselves in the feet. Listing
2022-01-18 07:26:09 +01:00
[[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
2024-01-25 10:37:09 +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)
2024-02-16 11:02:34 +01:00
"Called when executing a disabled command.
2022-11-07 11:50:17 +01:00
Enable it and re-execute it."
(put this-command 'disabled nil)
2024-02-16 11:02:34 +01:00
(message "You typed %s. Emacs enabled %s."
2022-11-07 11:50:17 +01:00
(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
2024-01-25 10:37:09 +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
2023-12-05 12:01:40 +01:00
** [[https://github.com/tarsius/keycast#readme][Keycast]]
2022-05-01 07:29:03 +02:00
:PROPERTIES:
:CUSTOM_ID: sec:keycast
:END:
Listing [[lst:configure-keycast ]] configures =keycast= .
#+caption[Configure =keycast= ]:
#+caption : Configure =keycast=.
#+name : lst:configure-keycast
2024-01-25 10:37:09 +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.
2023-12-05 12:01:40 +01:00
(when (ensure-package-installation 'keycast)
(setopt keycast-log-newest-first t
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
2024-06-16 20:04:36 +02:00
command =emacsclient= . Section [[#sec:latexmk-save-compile-display-loop ]] explains
how to use ~emacsclient~ to install an asynchronous (or background) loop of
saving a LaTeX file, compiling it, and redisplaying the output in Emacs.
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
2024-01-25 10:37:09 +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:
2024-06-16 20:07:17 +02:00
The =latexmk= resource file in listing [[lst:latexmkrc ]] 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
2024-03-06 14:49:48 +01:00
** TODO Org-protocol handling with other browser on Darwin :noexport:
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 ]]
2024-03-11 18:11:35 +01:00
* [[info:emacs#Calendar/Diary][Calendar, Diary, and Time (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:time
:END:
#+caption[Set =world-clock= options]:
#+caption : Set =world-clock= options.
#+name : lst:set-world-clock-options
#+begin_src emacs-lisp -n :results silent
(with-eval-after-load 'time
(setopt world-clock-list
'(("America/Los_Angeles" "Seattle")
("America/New_York" "New York")
("Europe/London" "London")
2024-03-12 10:23:30 +01:00
("Europe/Moscow" "Moscow")
2024-03-11 18:11:35 +01:00
("Europe/Paris" "Paris")
("Europe/Istanbul" "Istanbul")
2024-03-12 10:23:30 +01:00
("Africa/Cairo" "Cairo")
2024-03-11 18:11:35 +01:00
("Asia/Jerusalem" "Jerusalem")
("Asia/Singapore" "Singapore")
("Asia/Tokyo" "Tokyo"))
world-clock-time-format "%a %d %b %R %z"))
#+end_src
2023-12-17 14:00:21 +01:00
* Tools to handle buffers and modes
:PROPERTIES:
:CUSTOM_ID: sec:buffer-mode-tools
:END:
#+caption[Tools to handle buffers and modes]:
#+caption : Tools to handl buffers and modes.
#+name : lst:buffer-mode-tools
#+begin_src emacs-lisp -n :results silent
(defun set-all-buffers-with-modes (minor-mode value modes)
"Set MINOR-MODE to VALUE for all buffers with a mode derived from MODES."
(dolist (buffer (buffer-list))
(with-current-buffer buffer
(when (and (derived-mode-p modes) (buffer-file-name))
(funcall minor-mode value)))))
(defun enable-ro-all-org-mode-buffers ()
"Enable `buffer-read-only' of all `org-mode' buffers."
(interactive)
(set-all-buffers-with-modes #'read-only-mode +1 '(org-mode))
(message "Enabled `buffer-read-only' of all `org-mode' buffers."))
(defun disable-ro-all-org-mode-buffers ()
"Disable `buffer-read-only' of all `org-mode' buffers."
(interactive)
(set-all-buffers-with-modes #'read-only-mode -1 '(org-mode))
(message "Disabled `buffer-read-only' of all `org-mode' buffers."))
(defun active-major-modes ()
"Return a list of active major modes found by iterating over all buffers."
(let (result)
(dolist (buffer (buffer-list))
(with-current-buffer buffer
(let ((mode major-mode))
(push mode result))))
2024-06-17 16:09:11 +02:00
(sort (cl-remove-duplicates result))))
2023-12-17 14:00:21 +01: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
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
2024-06-15 14:29:44 +02:00
See the [[yt:hPwDbx--Waw ][Vertico extensions for Emacs ]] video for an overview. Listing
[[lst:setup-vertico-mode ]] sets up =vertico-mode= without using the
=vertico-directory= extension (less is better!). Listing
2024-06-15 11:40:42 +02:00
[[lst:prune-file-name-history ]] allows to prune non-existing files from the file
2024-06-15 14:29:44 +02:00
name history.
NOTE: Play with =vertico-buffer-mode= , =vertico-flat-mode= , =vertico-grid-mode= ,
=vertico-indexed-mode= , =vertico-mouse-mode= (not easy to use with my trackpad),
=vertico-reverse-mode= .
NOTE: The src_emacs-lisp{(describe-function 'savehist-mode)} documentation
explains why it is best to turn on =savehist-mode= in =user-init-file= .
BUG: Adding ~kill-ring~ to ~savehist-additional-variables~ does not save
~kill-ring~ from an Emacs session to the next session, contrary to the
src_emacs-lisp{(describe-variable 'savehist-additional-variables)}
2024-06-15 11:40:42 +02:00
documentation.
2024-06-15 14:29:44 +02:00
#+caption[Setup =vertico-mode= ]:
#+caption : Setup =vertico-mode=.
2024-06-15 11:40:42 +02:00
#+name : lst:setup-vertico-mode
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2024-06-15 11:40:42 +02:00
(when (ensure-package-installation 'vertico)
2024-06-15 14:29:44 +02:00
;; GAV: Builtin `fido-mode' may fix `find-file' completion when
;; using `vertico-directory' functions which confuse `find-file'.
2024-06-16 10:49:30 +02:00
;; GAV: Builtin `fido-mode' has more down than up sides: ChatGPT
;; bullshits on enhancing `vertico-mode' completion.
2024-06-15 14:29:44 +02:00
(vertico-mode +1))
2021-11-29 13:14:56 +01:00
#+end_src
2024-06-14 11:10:41 +02:00
#+caption[Prune non-existing files from =file-name-history= ]:
#+caption : Prune non-existing files from =file-name-history=.
#+name : lst:prune-file-name-history
#+begin_src emacs-lisp -n :results silent
(defun prune-file-name-history ()
"Prune non-existing files from `file-name-history'."
(interactive)
(let ((old (length file-name-history)) ok)
(dolist (name file-name-history)
(when (file-exists-p name)
(push name ok)))
(setq file-name-history (nreverse ok))
(message "Pruned `file-name-history' from `%S' to `%S' files"
old (length file-name-history))))
#+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-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
2024-01-25 10:37:09 +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:
2024-04-29 09:55:26 +02:00
1. =embark-act= prompts the user for an action and performs it. GAV: ~org-mode~
and ~embark~ do not play together nicely.
2022-04-20 06:10:56 +02:00
2. Except for highlighting of email and web URLs, =embark-dwim= englobes the
2024-06-12 10:58:48 +02:00
functionality of src_emacs-lisp[:results none]{(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:
2022-04-20 05:35:28 +02:00
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.
2024-01-25 10:37:09 +01:00
4. The initialization of =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
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2024-06-15 15:32:39 +02:00
;; GAV: `org-mode' and `embark' do not play together nicely.
;; GAV: `embark' is a dependency of `citar-embark' and `embark-consult'.
2024-04-29 09:55:26 +02:00
(when (ensure-package-installation 'embark-consult)
2024-06-15 15:32:39 +02:00
(keymap-global-set "C-," #'embark-act)
(keymap-global-set "C-:" #'embark-dwim)
(keymap-global-set "C-h B" #'embark-bindings)
(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
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2024-06-15 15:32:39 +02:00
(when (ensure-package-installation 'marginalia)
2022-11-07 11:50:17 +01:00
(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.
2024-03-22 09:05:57 +01:00
Consult usage tips are:
1. Add a buffer position to the mark ring by means of {{{kbd(C-SPACE C-SPACE)}}}
and jump to one of the marks in the ring by means of {{{kbd(M-x
consult-mark)}}} or {{{kbd(M-g m)}}} . See [[https://arialdomartini.github.io//emacs-mark-ring ][Emacs: Mark Ring ]].
2. {{{kbd(M-x consult-org-heading)}}} or {{{kbd(C-c C-h)}}} is an alternative to
{{{kbd(M-x org-goto)}}} or {{{kbd(C-c C-j)}}} .
2024-06-15 15:31:17 +02:00
#+caption[Bind =consult= commands]:
#+caption : Bind =consult= commands.
#+name : lst:bind-consult-commands
#+begin_src emacs-lisp -n :results silent
(when (ensure-package-installation 'consult)
;; C-c bindings (current-global-map)
(keymap-global-set "C-c h" #'consult-history)
(keymap-global-set "C-c m" #'consult-mode-command)
;; C-x bindings (ctl-x-map)
(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)
;; M-g bindings (goto-map)
(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)
(with-eval-after-load 'org
(keymap-set org-mode-map "C-c C-h" #'consult-org-heading))
;; M-s bindings (search-map)
(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)
;; Other bindings (current-global-map)
(keymap-global-set "M-y" #'consult-yank-pop))
#+end_src
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)}}} |
2024-02-05 19:17:28 +01:00
| consult-org-heading | org-mode-map | {{{kbd(C-c C-h)}}} |
2023-02-15 06:44:36 +01:00
| 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)}}} |
|-----------------------------+----------------------+--------------------|
| 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)}}} |
2024-02-05 19:17:28 +01:00
| org-goto | org-goto | {{{kbd(C-c C-j)}}} |
2023-02-15 06:44:36 +01:00
| 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-12-05 09:56:39 +01:00
** [[https://company-mode.github.io/][Company (info)]]
2021-12-05 16:40:20 +01:00
: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-12-05 09:56:39 +01:00
[[info:company#Top ][Company (info) ]] is a modular completion framework and listing [[lst:setup-company ]]
configures =company= after ensuring the =company= installation.
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
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2024-06-15 16:08:37 +02:00
(when (ensure-package-installation 'company)
2023-01-12 21:28:18 +01:00
;; https://github.com/purcell/emacs.d/issues/778
(setopt company-transformers '(company-sort-by-occurrence))
2024-06-15 16:08:37 +02:00
(add-hook 'LaTeX-mode-hook #'company-mode)
(add-hook 'org-mode-hook #'company-mode)
(add-hook 'emacs-lisp-mode-hook #'company-mode)
(add-hook 'lisp-interaction-mode-hook #'company-mode)
(add-hook 'lisp-mode-hook #'company-mode)
(add-hook 'python-mode-hook #'company-mode)
(add-hook 'ielm-mode-hook #'company-mode)
(add-hook 'sly-mrepl-mode-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:
2024-01-29 09:41:51 +01:00
Executing {{{kbd(M-x replace-regexp)}}} prompts for 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:
2022-09-11 07:37:26 +02:00
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 ]].
2024-01-29 09:41:51 +01:00
Table [[tab:replace-regexp-tranform ]] tabulates how to perform example tasks by
means of {{{kbd(M-x replace-regexp)}}} using =(regular-expression transform)=
pairs.
2022-09-11 07:37:26 +02:00
#+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+ \#)._= |
|-----------------------------+---------------------------------+---------------|
2024-03-05 14:52:47 +01:00
** [[info:emacs#Incremental Search][Incremental Search (info)]] and [[info:emacs#Other Repeating Search][Other Search and Loop Commands (info)]]
2023-05-07 17:05:46 +02:00
:PROPERTIES:
2024-03-05 14:52:47 +01:00
:CUSTOM_ID: sec:search
2023-05-07 17:05:46 +02:00
:END:
#+caption[Define =multi-occur-in-this-mode= ]:
#+caption : Define =multi-occur-in-this-mode=.
#+name : lst:multi-occur-in-this-mode
2023-12-10 15:00:01 +01:00
#+begin_src emacs-lisp -n
2024-03-05 14:52:47 +01:00
;; https://www.masteringemacs.org/article/searching-buffers-occur-mode
2023-05-07 17:05:46 +02:00
(defun get-buffers-matching-mode (mode)
"Return a list of buffers whose major-mode is equal to MODE."
(let ((buffer-mode-matches '()))
(dolist (buf (buffer-list))
(with-current-buffer buf
(when (eq mode major-mode)
(push buf buffer-mode-matches))))
buffer-mode-matches))
(defun multi-occur-in-this-mode ()
"Show all lines matching REGEXP in buffers with this major mode."
(interactive)
(multi-occur
(get-buffers-matching-mode major-mode)
(car (occur-read-primary-args))))
#+end_src
2024-03-05 14:52:47 +01:00
#+caption[Use =consult-line= from =isearch= ]:
#+caption : Use =consult-line= from =isearch=.
#+name : lst:consult-line-from-isearch
#+begin_src emacs-lisp -n :results silent
;; https://blog.chmouel.com/posts/emacs-isearch/
(when (package-installed-p 'consult)
(defun consult-line-from-isearch ()
"Invoke `consult-line' from isearch."
(interactive)
(let ((query (if isearch-regexp
isearch-string
(regexp-quote isearch-string))))
(isearch-update-ring isearch-string isearch-regexp)
(let (search-nonincremental-instead)
(ignore-errors (isearch-done t t)))
(consult-line query)))
(keymap-set isearch-mode-map "C-l" #'consult-line-from-isearch))
#+end_src
#+caption[Use =occur= and =project-find-regexp= from =isearch= ]:
#+caption : Use =occur= and =project-find-regexp= from =isearch=.
#+name : lst:occur-and-project-find-regexp-from-isearch
#+begin_src emacs-lisp -n :results silent
;; https://blog.chmouel.com/posts/emacs-isearch/
(defun occur-from-isearch ()
"Invoke `occur' from isearch."
(interactive)
(let ((query (if isearch-regexp
isearch-string
(regexp-quote isearch-string))))
(isearch-update-ring isearch-string isearch-regexp)
(let (search-nonincremental-instead)
(ignore-errors (isearch-done t t)))
(occur query)))
(defun project-find-regexp-from-isearch ()
"Invoke `project-find-regexp' from isearch."
(interactive)
(let ((query (if isearch-regexp
isearch-string
(regexp-quote isearch-string))))
(isearch-update-ring isearch-string isearch-regexp)
(let (search-nonincremental-instead)
(ignore-errors (isearch-done t t)))
(project-find-regexp query)))
(keymap-set isearch-mode-map "C-o" #'occur-from-isearch)
(keymap-set isearch-mode-map "C-f" #'project-find-regexp-from-isearch)
#+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
2023-07-14 08:28:56 +02:00
implementation of the suggestions on those pages. *To do* :
1. None of the commands listed in [[info:emacs#Grep Searching ][Searching with Grep under Emacs (info) ]]
works on my system with the exception of ~lgrep~ when using [[https://www.genivia.com/get-ugrep.html ][ugrep ]].
2. None of the ~grep~ , ~agrep~ , ~egrep~ , ~fgrep~ , and ~glimpse~ builtins listed
in [[info:eshell#Built-ins ][Eshell builtins (info) ]] works.
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
2024-01-25 10:37:09 +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 >")
2023-05-19 10:58:15 +02:00
" ")
grep-command "ugrep --color=always --null -nH -e "
grep-use-null-device nil))
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"
2023-05-18 16:02:51 +02:00
" --no-heading --no-messages -g '!*/' -e <R >"))
2023-01-12 21:28:18 +01:00
(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
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2024-06-15 17:01:51 +02:00
(ensure-package-installation 'xr)
2023-01-09 13:00:17 +01:00
#+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
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2024-04-18 17:03:25 +02:00
(with-eval-after-load 'ediff-wind
(when (fboundp 'ediff-setup-windows-plain)
(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
2024-04-18 17:03:25 +02:00
(add-hook 'org-mode-hook
(defun ediff-with-org-show-all ()
"Expand all headings prior to ediffing org buffers."
(add-hook 'ediff-prepare-buffer-hook #'org-fold-show-all nil t))))
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:
2024-03-16 08:48: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. Magit usage tips are:
1. [[https://stackoverflow.com/questions/tagged/magit?tab=Votes ][Most upvoted Magit questions on Stack Overflow ]].
2. [[https://stackoverflow.com/a/33644270 ][Abort an active rebase ]] by pressing {{{kbd(r a)}}} .
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)}.
#+caption[Ensure =Magit= installation]:
#+caption : Ensure =Magit= installation
#+name : lst:ensure-magit-installation
#+begin_src emacs-lisp -n :results silent
(ensure-package-installation 'magit)
2022-10-23 10:31:11 +02:00
#+end_src
2024-02-07 18:45:50 +01:00
*** Github quick setup
:PROPERTIES:
:CUSTOM_ID: sec:github-quick-setup
:END:
#+caption[Make a new repository on the command line]:
#+caption : Make a new repository on the command line.
#+name : lst:make-new-git-repo
#+begin_src shell -n :eval never
2024-03-16 08:48:02 +01:00
echo "# oglot" >> README.md
2024-02-07 18:45:50 +01:00
git init
git add README.md
git commit -m "first commit"
git branch -M main
2024-03-16 08:48:02 +01:00
git remote add origin git@github.com:gav451/oglot.git
2024-02-07 18:45:50 +01:00
git push -u origin main
#+end_src
#+caption[Push an old git repository on the command line]:
#+caption : Push an old git repository on the command line.
#+name : lst:push-old-git-repo
#+begin_src shell -n :eval never
2024-03-16 08:48:02 +01:00
git remote add origin git@github.com:gav451/oglot.git
2024-02-07 18:45:50 +01:00
git branch -M main
git push -u origin main
#+end_src
*** Learn git
:PROPERTIES:
:CUSTOM_ID: sec:learn-git
:END:
2024-01-29 09:44:03 +01:00
Useful [[https://git-scm.com/book/en/v2 ][Git ]] links are:
- [[https://sentry.io/answers/abort-a-merge-in-git/ ][Abort a merge in Git ]]
- [[https://sentry.io/answers/change-the-uri-for-a-git-remote/ ][Change the URI for a Git remote ]]
- [[https://sentry.io/answers/check-out-a-remote-branch-in-git/ ][Check out a remote branch in Git ]]
- [[https://sentry.io/answers/clone-a-git-repository-to-a-specific-folder/ ][Clone a Git repository to a specific folder ]]
- [[https://sentry.io/answers/clone-a-specific-git-repository-branch/ ][Clone a specific Git repository branch ]]
- [[https://sentry.io/answers/create-a-new-git-branch-from-an-existing-branch/ ][Create a new Git branch from an existing branch ]]
- [[https://sentry.io/answers/create-a-remote-branch-in-git/ ][Create a remote branch in Git ]]
- [[https://sentry.io/answers/delete-a-commit-from-a-branch-in-git/ ][Delete a commit from a branch in Git ]]
- [[https://sentry.io/answers/delete-a-file-from-a-git-repository/ ][Delete a file from a Git repository ]]
- [[https://sentry.io/answers/delete-a-git-branch-locally-and-remotely/ ][Delete a Git branch locally and remotely ]]
- [[https://sentry.io/answers/determine-the-origin-of-a-cloned-git-repository/ ][Determine the origin of a cloned Git repository ]]
- [[https://sentry.io/answers/undo-the-most-recent-local-git-commits/ ][Undo the most recent local Git commits ]]
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
2024-03-16 08:48:02 +01:00
git -C ~/VCS/oglot 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
2024-03-16 08:48:02 +01:00
: * main
: remotes/origin/main
2023-01-06 20:45:02 +01:00
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:
2024-01-25 13:29:06 +01:00
[[info:emacs#Document View ][Document View (info) ]] allows to read [[https://en.wikipedia.org/wiki/DjVu ][DjVu ]] files on condition that it can use the
command line [[https://en.wikipedia.org/wiki/DjVu ][DjVu ]] decoder =ddjvu= from the [[http://djvu.sourceforge.net/ ][DjVuLibre ]] utilities as shown by the
code of src_emacs-lisp{(find-function 'doc-view-djvu->tiff-converter-ddjvu)}.
Use {{{kbd(+)}}} or {{{kbd(-)}}} to enlarge or shrink what =doc-view-mode=
displays and use {{{kbd(SPC)}}} or {{{kbd(S-SPC)}}} to scroll down or up through
when pages are larger than the =doc-view-mode= window.
2022-02-27 10:37:22 +01:00
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
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2024-06-15 17:01:51 +02:00
(when (ensure-package-installation 'nov)
2022-11-07 11:50:17 +01:00
(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 ]]
2023-12-12 11:10:28 +01:00
files produced with LaTeX to the original LaTeX sources. In order to use
[[https://github.com/vedang/pdf-tools ][pdf-tools ]], you have to type {{{kbd(M-x pdf-tools-install)}}} after 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
2024-02-07 11:03:11 +01:00
=epdfinfo= executable that serves the [[https://en.wikipedia.org/wiki/PDF ][PDF ]] files to Emacs. Table
2024-04-17 10:25:27 +02:00
[[tab:pdf-view-mode-commands-and-bindings ]] lists important local map key bindings
in ~pdf-view-mode~ . Note: ~image-save~ saves the page under point to a ~png~
file.
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
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2024-06-15 17:01:51 +02:00
(when (ensure-package-installation 'pdf-tools)
2024-04-17 10:25:27 +02:00
;; Use `pdf-loader-install' for faster startup than with `pdf-tools-install'.
2022-11-07 11:50:17 +01:00
(pdf-loader-install)
(with-eval-after-load 'pdf-view
2023-01-12 21:28:18 +01:00
(setopt pdf-view-display-size 'fit-page
2023-12-12 11:10:28 +01:00
pdf-view-use-scaling (eq system-type 'darwin))))
2021-11-29 13:14:56 +01:00
#+end_src
2024-02-07 11:03:11 +01:00
#+attr_latex : :booktabs yes :float table
2024-04-17 10:25:27 +02:00
#+caption[Commands with local key bindings in ~pdf-view-mode~ ]:
#+caption : Commands with local key bindings in ~pdf-view-mode~.
#+name : tab:pdf-view-mode-commands-and-bindings
|---------------------------------+----------------|
| command | key binding |
|---------------------------------+----------------|
| *image-save* | {{{kbd(i o)}}} |
| *pdf-outline* | {{{kbd(o)}}} |
| *pdf-view-fit-height-to-window* | {{{kbd(H)}}} |
| *pdf-view-fit-width-to-window* | {{{kbd(W)}}} |
|---------------------------------+----------------|
2024-02-07 11:03:11 +01:00
2024-05-09 09:36:17 +02:00
** Reading outline files
:PROPERTIES:
:CUSTOM_ID: sec:reading-outline-files
:END:
#+caption[Enable ~read-only-mode~ for some files in ~outline-mode~ ]:
#+caption : Enable ~read-only-mode~ for some files in ~outline-mode~.
#+name : lst:maybe-read-only-in-outline-mode
#+begin_src emacs-lisp -n :results silent
(defun maybe-read-only-in-outline-mode ()
;; GAV: Should be a toplevel function to call `message' here.
(let ((fnsd (buffer-file-name)))
;; GAV: `fnsd' is nil during Org export to LaTeX.
(when fnsd
(setq fnsd (file-name-nondirectory fnsd))
2024-06-11 09:38:28 +02:00
;; These are files from the EMACS and ORG git repositories.
(when (member fnsd '("EGLOT-NEWS" "NEWS" "ORG-NEWS" "PROBLEMS"
"org.org" "org-guide.org" "org-manual.org"))
2024-05-09 09:36:17 +02:00
(message "Visit `%s' in `read-only-mode'" fnsd)
(read-only-mode +1)))))
(add-hook 'outline-mode-hook #'maybe-read-only-in-outline-mode)
#+end_src
2021-11-29 13:14:56 +01:00
* 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= .
2023-06-06 08:06:59 +02:00
2. Listing [[lst:set-tex-options ]] also enables *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-06-06 08:06:59 +02:00
4. Listing [[lst:set-bibtex-options ]] configures the Emacs =bibtex= library to use
the 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
2024-01-25 10:37:09 +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-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
2024-01-25 10:37:09 +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)
2024-06-17 19:31:20 +02:00
(let* ((pair (get-program-code-output
"luaotfload-tool" "-vv" "--update" "--force"))
(return-code (car pair))
(output (cdr pair)))
(if (= 0 return-code)
2022-11-07 11:50:17 +01:00
(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
2024-01-25 10:37:09 +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
2024-01-25 10:37:09 +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
2024-01-25 10:37:09 +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-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
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2024-04-18 17:03:25 +02:00
(when (ensure-package-installation 'markdown-mode) t)
2022-10-12 06:05:19 +02:00
#+end_src
2024-03-23 15:09:26 +01:00
** Writing [[info:org#Top][Org (info)]] files and [[info:org#Activation][Org activation (info)]]
2021-12-23 15:29:03 +01:00
:PROPERTIES:
:CUSTOM_ID: sec:writing-org-files
:END:
2021-11-29 13:14:56 +01:00
2024-03-23 15:09:26 +01:00
Listing [[lst:bind-org-commands ]] activates [[info:org#Top ][Org (info) ]] by means of global key
bindings.
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
2024-01-25 10:37:09 +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)
2024-03-16 15:01:21 +01:00
(global-set-key (kbd "C-c l") #'org-store-link))
2021-11-29 13:14:56 +01:00
#+end_src
2024-03-23 15:09:26 +01:00
Links to Org-mode videos are:
1. [[yt:o6rE18Mxu9U ][Analyze Your Time with Org Mode Clocktables ]]
2. [[yt:EgOBBiomfGo ][Basic Task Management with Org: Checklists, TODOs, and Org-Agenda ]]
3. [[yt:oJTwQvgfgMM ][Emacs Org-mode: a system for note-taking and project planning ]]
4. [[yt:SzA2YODtgK4 ][Getting Started With Org Mode ]]
5. [[yt:zqAYHWv36X0 ][Org Mode Time and Task Tools ]]
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
2024-03-23 15:13:24 +01:00
:ID: 0D725DA1-7431-40BD-85FF-EFF4F7E4EC95
2021-12-23 15:29:03 +01:00
:END:
2021-11-29 13:14:56 +01:00
2024-06-16 19:23:53 +02:00
I have split the initial [[https://orgmode.org/ ][Org-mode ]] setup over eleven listings. Here, follows a
2023-01-12 21:28:18 +01:00
list detailing and motivating each listing:
1. Listing [[lst:set-org-options ]] handles basic [[https://orgmode.org/ ][Org-mode ]] options.
2024-03-23 15:13:24 +01:00
2. Listing [[lst:org-capture-templates ]] initializes a simple capture template.
2024-04-30 12:29:10 +02:00
3. Listing [[lst:setup-org-babel ]] sets ~ob-core~ , ~ob-latex~ , and ~ob-lisp~ options.
2024-02-02 14:42:36 +01:00
See [[info:org#Working with Source Code ][working with source code (info) ]] for Org Babel information.
2024-06-11 10:11:26 +02:00
4. Listing [[lst:looking-at-org-id ]] enables recent ~org-id~ features.
5. Listing [[lst:setup-org-mode-map-1 ]] and [[lst:setup-org-mode-map-2 ]] extend the
2024-01-21 17:27:22 +01:00
=org-mode-map= with useful key-bindings.
2024-06-11 10:11:26 +02:00
6. Listing [[lst:setup-org-src ]] facilitates [[info:org#Editing Source Code ][editing source code blocks ]], and it
2024-01-17 12:23:17 +01:00
provides functions to change the indentation of all =org-src-mode= blocks.
2024-06-11 10:11:26 +02:00
7. Listing [[lst:setup-ob-python ]] allows to pretty-print Python session source
2024-04-30 12:29:10 +02:00
block values with [[https://github.com/psf/black#readme ][black ]] instead of [[https://docs.python.org/3/library/pprint.html ][pprint ]]. This snippet may break in the
future, because it sets =org-babel-python--def-format-value= which is a
constant declared "private" by two dashes in its name!
2024-06-11 10:11:26 +02:00
8. Listing [[lst:set-org-export-options ]] selects the =non-intrusive= expert user
2024-06-10 19:55:26 +02:00
interface for export dispatching.
2024-06-11 10:11:26 +02:00
9. Listing [[lst:setup-org-for-lualatex-export ]] and
[[lst:set-ox-latex-options-for-lualatex-export ]] configure [[https://orgmode.org/ ][Org-mode ]] to generate
output for the LuaLaTeX compiler.
2024-06-16 19:23:53 +02:00
# 10. Listing [[lst:setup-org-latex-classes]] defines [[info:org#LaTeXspecificexportsettings][org-latex-classes (info)]] for
# backward compatibility. For an explanation of the code in listing
# [[lst:setup-org-latex-classes]], type {{{kbd(C-h v 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
2024-01-25 10:37:09 +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
2024-03-11 18:10:28 +01:00
org-agenda-files '("gerard.org")
org-agenda-include-diary t
org-babel-load-languages `((calc . t)
(dot . ,(fboundp 'grapviz-dot-mode))
(emacs-lisp . t)
(eshell . t)
(fortran . t)
(gnuplot . ,(fboundp 'gnuplot-mode))
(latex . t)
(lilypond . ,(fboundp 'lilypond-mode))
(lisp . t)
(lua . ,(fboundp 'lua-mode))
(org . t)
(perl . t)
;; Beware of circular Python dependencies.
(python . t)
(ruby . ,(fboundp 'ruby-mode))
(shell . t))
org-directory "~/org"
2024-02-27 18:14:26 +01:00
org-export-backends '(ascii beamer html icalendar latex md odt texinfo)
2023-01-12 21:28:18 +01:00
org-file-apps '((auto-mode . emacs)
(directory . emacs)
("\\.mm\\'" . default)
("\\.x?html?\\'" . default)
("\\.pdf\\'" . emacs))
2024-06-11 10:11:26 +02:00
;; Set `org-link-descriptive' interactively by `org-toggle-link-display'.
org-link-descriptive t
org-link-file-path-type 'adaptive
org-modules (list 'ol-bibtex 'ol-doi 'ol-eww 'ol-info
'org-id 'org-protocol 'org-tempo)
2023-06-22 17:34:55 +02:00
org-use-property-inheritance t))
2023-01-12 21:28:18 +01:00
#+end_src
2024-03-23 15:13:24 +01:00
#+caption[Setup =org-capture-templates= ]:
#+caption : Setup =org-capture-templates=.
#+name : lst:org-capture-templates
#+begin_src emacs-lisp -n :results silent
(with-eval-after-load 'org-capture
(setopt org-capture-templates
'(("f" "Flat capture database" entry (file "flat.org")
"* %^{Prompt}t %?
%a"))))
#+end_src
2024-02-02 14:42:36 +01:00
#+caption[Set =org-babel= options]:
#+caption : Set =org-babel= options.
2023-01-17 08:07:15 +01:00
#+name : lst:setup-org-babel
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-10 06:58:33 +01:00
(with-eval-after-load 'ob-core
2024-02-11 13:47:39 +01:00
(setopt org-confirm-babel-evaluate nil))
2024-01-24 15:08:36 +01:00
2024-02-02 14:42:36 +01:00
(with-eval-after-load 'ob-latex
(setopt org-babel-latex-preamble
(lambda (_)
"\\documentclass[preview]{standalone}\n")))
(with-eval-after-load 'ob-lisp
2024-06-15 17:01:51 +02:00
(when (package-installed-p 'sly)
2024-02-02 14:42:36 +01:00
(setopt org-babel-lisp-eval-fn #'sly-eval)))
#+end_src
2024-03-06 14:26:55 +01:00
#+caption[Looking at =org-id= ]:
#+caption : Looking at =org-id=.
#+name : lst:looking-at-org-id
#+begin_src emacs-lisp -n :results silent
(with-eval-after-load 'org-id
(setopt org-id-link-to-org-use-id t
org-id-track-globally t)
;; https://stackoverflow.com/a/16247032 answers
;; "How to assign IDs to all entries in a buffer."
(defun org-id-add-ids-to-headlines-in-buffer ()
"Add slowly ID properties to all headlines without such an ID property.
Undo this by means of `org-delete-property-globally'."
(interactive)
(org-map-entries #'org-id-get-create)))
#+end_src
2024-01-21 17:27:22 +01:00
#+caption[Setup =org-mode-map= 1]:
#+caption : Setup =org-mode-map= 1.
#+name : lst:setup-org-mode-map-1
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2024-04-18 17:03:25 +02:00
;; 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.
2022-11-07 11:50:17 +01:00
When called twice, replace the previously inserted \\(\\) by one $."
2024-04-18 17:03:25 +02:00
(interactive)
(if (and (looking-at "\\\\)") (looking-back "\\\\(" (- (point) 2)))
2024-06-11 09:52:57 +02:00
(progn (delete-char 2) (delete-char -2) (insert "$"))
2024-04-18 17:03:25 +02:00
(insert "\\(\\)")
(backward-char 2)))
(with-eval-after-load 'org
(setopt org-return-follows-link t)
(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
2024-01-21 17:27:22 +01:00
#+caption[Setup =org-mode-map= 2]:
#+caption : Setup =org-mode-map= 2.
#+name : lst:setup-org-mode-map-2
2024-02-16 10:37:33 +01:00
#+begin_src emacs-lisp -n :results silent
2024-04-18 17:03:25 +02:00
;; Stolen from `org-insert-structure-template'.
;; Note: `org-tempo' does not require `tempo' at all.
(defcustom org-insert-source-block-defaults
'("calc -n :results silent"
"emacs-lisp -n :results silent"
"latex -n"
"lisp -n :results silent :package :cs325-user"
"org -n"
"python -i -n :results silent")
"Default values for `org-insert-source-block'."
:group 'org
:type '(repeat string))
(defun org-insert-source-block ()
"Insert a source block #+begin_src/SPEC/BODY/ #+end_src.
2024-01-21 17:27:22 +01:00
Prompt for the source block SPEC. With an active region, the
region becomes the block BODY. Otherwise, insert an empty block."
2024-04-18 17:03:25 +02:00
(interactive)
(let* ((spec (completing-read
"Block spec: " org-insert-source-block-defaults nil 'confirm))
(region? (use-region-p))
(region-start (and region? (region-beginning)))
(region-end (and region? (copy-marker (region-end)))))
(when region? (goto-char region-start))
(let ((column (current-indentation)))
(if (save-excursion (skip-chars-backward " \t") (bolp))
(forward-line 0)
(insert "\n"))
(save-excursion
(indent-to column)
(insert (format "#+begin_src %s\n" spec))
(when region?
(org-escape-code-in-region (point) region-end)
(goto-char region-end)
(skip-chars-backward " \n\t\r")
(end-of-line))
(unless (bolp) (insert "\n"))
(indent-to column)
(insert "#+end_src")
(if (looking-at "[ \t]*$") (replace-match "") (insert "\n"))
(when (and (eobp) (not (bolp))) (insert "\n")))
(end-of-line))))
2024-01-21 17:27:22 +01:00
(with-eval-after-load 'org
2024-02-11 16:19:39 +01:00
(keymap-set org-mode-map "C-c C-;" #'org-insert-source-block))
2024-01-21 17:27:22 +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
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2024-06-14 22:29:19 +02:00
(with-eval-after-load 'org-src
;; https://list.orgmode.org/c3cc4ff1fcfb3bc741df89a3f45be30e@posteo.net/
(setopt org-edit-src-content-indentation 0
org-src-preserve-indentation nil
org-src-window-setup 'current-window)
(defun org-left-shift-block ()
"Left-shift the block at point using `org-indent-block'."
(interactive)
(let ((org-adapt-indentation nil)
(org-edit-src-content-indentation 0)
(org-src-preserve-indentation nil))
(org-indent-block)))
2022-11-10 06:58:33 +01:00
2024-01-17 12:23:17 +01:00
(defun org-right-shift-block (&optional arg)
"Right-shift the block at point 4 spaces.
With prefix argument ARG, prompt for the number of spaces."
(interactive "P")
(let ((spaces 4)
(start (org-babel-where-is-src-block-head)))
(if (not start) (message "Not at block")
(when arg
(setq spaces (read-number "Number of spaces: ")))
;; The `SUBEXP' of the block body is 5.
(goto-char (match-end 5))
(forward-line -1)
(string-insert-rectangle
(match-beginning 5) (point) (make-string spaces ?\s)))))
2022-11-10 06:58:33 +01:00
(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= ]:
2023-08-24 10:43:26 +02:00
#+caption : Setup =ob-python=. This snippet may break in the future!
2023-01-12 21:28:18 +01:00
#+name : lst:setup-ob-python
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-09 12:16:59 +01:00
(with-eval-after-load 'ob-python
2023-08-24 10:43:26 +02:00
(setq org-babel-python--def-format-value "\
def __org_babel_python_format_value(result, result_file, result_params):
with open(result_file, 'w') as f:
if 'graphics' in result_params:
result.savefig(result_file)
elif 'pp' in result_params:
2022-11-09 12:16:59 +01:00
import black
2023-08-24 10:43:26 +02:00
f.write(black.format_str(repr(result), mode=black.Mode()))
elif 'list' in result_params and isinstance(result, dict):
f.write(str(['{} :: {}'.format(k, v) for k, v in result.items()]))
2022-11-09 12:16:59 +01:00
else:
2023-08-24 10:43:26 +02:00
if not set(result_params).intersection(\
['scalar', 'verbatim', 'raw']):
def dict2table(res):
if isinstance(res, dict):
return [(k, dict2table(v)) for k, v in res.items()]
elif isinstance(res, list) or isinstance(res, tuple):
return [dict2table(x) for x in res]
else:
return res
if 'table' in result_params:
result = dict2table(result)
try:
import pandas
except ImportError:
pass
else:
if isinstance(result, pandas.DataFrame) and 'table' in result_params:
result = [[result.index.name or ''] + list(result.columns)] + \
[None] + [[i] + list(row) for i, row in result.iterrows()]
elif isinstance(result, pandas.Series) and 'table' in result_params:
result = list(result.items())
try:
import numpy
except ImportError:
pass
else:
if isinstance(result, numpy.ndarray):
if 'table' in result_params:
result = result.tolist()
else:
result = repr(result)
f.write(str(result))"))
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
2024-01-25 10:37:09 +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
2024-01-25 10:37:09 +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
2024-02-16 10:36:42 +01:00
: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
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2024-02-02 14:42:36 +01:00
(when (require 'ox-latex nil 'noerror) ;; To use the safe file local variables!
2023-01-12 21:28:18 +01:00
(setopt
org-latex-compiler "lualatex"
2023-07-06 07:33:58 +02:00
org-latex-compiler-file-string
2024-02-09 10:20:16 +01:00
"%% -*- LaTeX -* -\n%% Intended LaTeX compiler: %s\n"
2023-01-12 21:28:18 +01:00
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-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"))
2024-02-10 09:39:10 +01:00
org-latex-prefer-user-labels t)
(put 'org-latex-toc-command 'safe-local-variable 'stringp))
2023-01-12 21:28:18 +01:00
#+end_src
#+caption[Setup =org-latex-classes= for backwards compatibility]:
#+caption : Setup =org-latex-classes= for backwards compatibility.
#+name : lst:setup-org-latex-classes
2024-06-16 19:23:53 +02:00
#+begin_src emacs-lisp -n :exports none :results silent :tangle no
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
2024-01-21 17:29:41 +01:00
*** [[info:org#In-buffer Settings][Buffer properties]]
:PROPERTIES:
:CUSTOM_ID: sec:buffer-properties
:END:
2024-02-24 16:06:48 +01:00
#+caption[Buffer properties]:
#+caption : Buffer properties.
#+name : lst:buffer-properties
#+begin_src emacs-lisp -n :results silent
(with-eval-after-load 'org
2024-01-21 17:29:41 +01:00
(defun org-get-buffer-properties ()
"Get all properties in buffer."
(org-element-map (org-element-parse-buffer) 'keyword
(lambda (el)
(and ;; Use (upcase "property"), else it fails.
(string= (org-element-property :key el) "PROPERTY")
(let* ((strings (split-string (org-element-property :value el)))
(value (string-join (cdr strings) " "))
(name (car strings)))
(cons name value)))))))
#+end_src
2023-04-26 12:09:45 +02:00
*** Org introspection
2023-02-26 14:55:12 +01:00
:PROPERTIES:
2023-04-26 12:09:45 +02:00
:CUSTOM_ID: sec:org-introspection
2023-02-26 14:55:12 +01:00
:END:
2024-06-11 10:31:36 +02:00
1. Listing [[lst:org-babel-active-languages ]] produces a list containing language
2024-03-10 15:44:16 +01:00
names that have ~org-babel-execute:LANGUAGE~ functions.
2024-06-11 10:31:36 +02:00
2. Listing [[lst:get-in-buffer-settings ]] and [[lst:get-in-buffer-settings-result ]] show
2024-03-10 15:44:16 +01:00
how to access [[info:org#In-buffer Settings ][In-buffer Settings (info) ]].
2023-04-26 12:09:45 +02:00
#+caption[Find active Org Babel languages]:
#+caption : Find active Org Babel languages.
#+name : lst:org-babel-active-languages
2023-07-05 04:29:34 +02:00
#+header : :wrap "src emacs-lisp -n :eval never :tangle no"
2023-07-05 04:19:23 +02:00
#+begin_src emacs-lisp -n :exports both :results value pp :tangle no
2023-04-26 12:09:45 +02:00
(defun org-babel-active-languages ()
2024-02-11 12:13:53 +01:00
(let (result)
2023-04-26 12:09:45 +02:00
(mapatoms
(lambda (x)
(when (and
(string-prefix-p "org-babel-execute:" (symbol-name x))
2023-05-11 20:37:56 +02:00
;; Get rid of all sub-modes in `ob-shell':
(not (eq 'org-babel-shell-initialize (get x 'definition-name)))
;; Get rid of aliases:
(not (eq 'symbol (type-of (symbol-function x)))))
2023-04-26 12:09:45 +02:00
(when (symbol-file x)
(push (string-remove-prefix "org-babel-execute:" (symbol-name x))
result)))))
result))
2024-06-17 16:09:11 +02:00
(mapcar #'list (sort (org-babel-active-languages)))
2023-04-26 12:09:45 +02:00
#+end_src
#+caption[Active Org Babel languages]:
#+caption : Active Org Babel languages.
#+RESULTS : lst:org-babel-active-languages
2023-07-05 04:29:34 +02:00
#+begin_src emacs-lisp -n :eval never :tangle no
2024-06-15 18:19:32 +02:00
(("calc") ("emacs-lisp") ("eshell") ("fortran") ("latex") ("lisp")
("org") ("perl") ("python") ("ruby") ("shell"))
2023-04-26 12:09:45 +02:00
#+end_src
2024-03-10 15:44:16 +01:00
#+caption[Get "in-buffer" settings]:
#+caption : Get "in-buffer" settings.
#+name : lst:get-in-buffer-settings
#+header : :wrap "src emacs-lisp -n :eval never :tangle no"
#+begin_src emacs-lisp -n :exports both :results value pp :tangle no
(org-collect-keywords '("title" "author" "latex_class"))
#+end_src
#+caption[Get "in-buffer" settings result]:
#+caption : Get "in-buffer" settings result.
#+name : lst:get-in-buffer-settings-result
#+RESULTS : lst:get-in-buffer-settings
#+begin_src emacs-lisp -n :eval never :tangle no
(("TITLE" "Emacs setup for use with LaTeX, Lisp, Org, and Python")
("AUTHOR" "Gerard Vermeulen") ("LATEX_CLASS" "article"))
#+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
2024-01-29 09:41:51 +01:00
processor, text to product converter) to an Emacs setup. Listing
2024-01-22 17:15:03 +01:00
[[lst:set-oc+citar-options ]] shows the =oc= and =citar= setup with binding of
{{{kbd(C-c b)}}} to src_emacs-lisp{(call-interactively 'org-cite-insert)} in
=org-mode-map= .
2021-12-23 15:29:03 +01:00
2024-01-22 17:15:03 +01:00
#+caption[Set =oc= and =citar= options]:
#+caption : Set =oc= and =citar= options.
#+name : lst:set-oc+citar-options
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
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-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"))
2024-01-22 17:15:03 +01:00
(if (not (require 'citar nil 'noerror))
(user-error "Fails to require `citar' and to setup `citar' and `oc'")
;; Synchronize the two involved bibliographies.
(setopt citar-bibliography org-cite-global-bibliography
citar-library-file-extensions '("djvu" "pdf")
;; Here are the `.djvu' and `.pdf' files.
citar-library-paths '("~/VCS/research/papers/ "))
2023-01-12 21:28:18 +01:00
(setopt org-cite-activate-processor 'citar
org-cite-follow-processor 'citar
2024-01-22 17:15:03 +01:00
org-cite-insert-processor 'citar)
(with-eval-after-load 'org
(keymap-set org-mode-map "C-c b" #'org-cite-insert)))))
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,
2024-01-26 10:01:12 +01:00
and prose. It serves as an example link to show how to use [[https://github.com/bdarcus/citar ][Citar ]] within this
2022-02-17 13:15:30 +01:00
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)}}} .
2024-01-22 17:15:03 +01:00
2. Choose one or multiple citations from the bibliography:
1. by navigating to an item and selecting it with {{{kbd(RET)}}}
2. by repeatingly navigating to an item and preselecting it with
{{{kbd(TAB)}}} . Select all preselected items with {{{kbd(RET)}}} .
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.
2024-01-22 17:15:03 +01:00
4. The following =citar= functions may be useful too:
1. src_emacs-lisp{(call-interactively 'citar-insert-citation)}.
2024-01-25 10:37:09 +01:00
2. src_emacs-lisp[:results silent]{(call-interactively 'citar-open)}.
2022-02-17 13:15:30 +01:00
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
2024-01-25 10:37:09 +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)
2024-06-17 19:31:20 +02:00
(let* ((pair (get-program-code-output "rm" "-rf" "$(biber --cache)"))
(return-code (car pair))
(output (cdr pair)))
(if (= 0 return-code)
2022-11-07 11:50:17 +01:00
(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
2024-01-25 10:37:09 +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)
2023-09-26 16:25:53 +02:00
"Replace \"Code\" with \"Breakable\" in non-floating DATA environments.
2022-11-07 11:50:17 +01:00
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)
2024-02-10 10:30:34 +01:00
(user-error
"`org-latex-engraved-preamble' defines no `Breakable' environment"))
2022-11-07 11:50:17 +01:00
(when (eq org-latex-src-block-backend 'engraved)
2024-02-10 10:20:10 +01:00
;; Transform only blocks matching at position 0. Therefore, do
;; not transform blocks that are listing environments.
(when (string-match "\\`\\\\begin{Code}\n" data)
(setq data (replace-match "\\begin{Breakable}\n" t 'literal data))
(if (string-match "^\\\\end{Code}\n" data)
(setq data (replace-match "\\end{Breakable}\n" t 'literal data))
(error "Match `^\\\\end{Code}' failure")))))
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
2024-01-25 10:37:09 +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}}
2024-01-31 20:42:05 +01:00
% Do not rely on an eventual call to `engrave-faces-latex-gen-preamble'.
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-04-18 18:03:33 +02:00
#+begin_src emacs-lisp -n :exports code :results none :tangle no
2023-06-21 10:50:45 +02:00
(with-eval-after-load 'ox-latex
2024-01-31 20:43:24 +01:00
(make-local-variable 'org-export-filter-src-block-functions)
2022-11-07 11:50:17 +01:00
(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
2023-12-05 09:20:47 +01:00
*** [[https://github.com/flexibeast/org-vcard#org-vcard---org-mode-support-for-vcard-export-and-import][Org-mode support for vCard import and export]] :noexport:
2023-06-23 18:28:00 +02:00
:PROPERTIES:
:CUSTOM_ID: sec:org-vcard
2023-12-05 09:20:47 +01:00
:header-args:emacs-lisp: :tangle no
2023-06-23 18:28:00 +02:00
:END:
Import/export =vcf= files (Android phones) from/to Org-mode linear (level 1)
headline lists with the data in property drawers.
#+caption[Install =org-vcard= to read =vcf= files=]:
#+caption : Install =org-vcard= to read =vcf= files=.
2024-03-03 15:43:14 +01:00
#+name : lst:org-vcard
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2023-06-23 18:28:00 +02:00
(ensure-package-installation 'org-vcard)
#+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
2024-01-25 10:37:09 +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
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2024-04-18 17:03:25 +02:00
(declare-function pdf-view-current-page "pdf-macs" (&optional window))
(declare-function pdf-view-goto-page "pdf-view" (page &optional window))
(defun org-pdfview-export (link description backend _)
"Export LINK as a \"pdfview\" type link using DESCRIPTION and export BACKEND.
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 LINK as 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 to respect org-link-frame-setup.
(org-open-file path 1)
(when page (pdf-view-goto-page page))))
2024-05-09 20:07:32 +02:00
(defun org-pdfview-store-link (&optional _interactive?)
2024-04-18 17:03:25 +02:00
"Store a \"pdfview\" type link."
(when (eq major-mode 'pdf-view-mode)
(let* ((path buffer-file-name)
(page (pdf-view-current-page))
2024-05-09 20:07:32 +02:00
(text (concat "pdfview:" path "::" (number-to-string page))))
2024-04-18 17:03:25 +02:00
(org-link-store-props
:type "pdfview"
2024-05-09 20:07:32 +02:00
:link text
2024-04-18 17:03:25 +02:00
:description path))))
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'ol
(org-link-set-parameters "pdfview"
:follow #'org-pdfview-open
:export #'org-pdfview-export
2024-04-18 17:03:25 +02:00
:store #'org-pdfview-store-link))
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
2024-04-18 17:03:25 +02:00
(declare-function org-info-map-html-url "ol-info" (filename))
(declare-function org-info--expand-node-name "ol-info" (node))
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-04-18 18:03:33 +02:00
#+begin_src emacs-lisp -n :exports code :results none :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")
("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:
2024-06-16 14:07:33 +02:00
Listing [[lst:define-org-yt-link-type ]] implements code to open the link to the
following YouTube video [[yt:eaZUZCzaIgw ][Extending org-mode to handle YouTube links ]] modifying
code from the following [[https://raw.githubusercontent.com/bitspook/spookmax.d/master/readme.org ][Emacs setup ]].
2023-05-07 16:57:17 +02:00
2024-06-16 14:07:33 +02:00
Opening [[yt:eaZUZCzaIgw ][Extending org-mode to handle YouTube links ]] may fail due to an old
(fixed) bug in =mpv= . However, the link [[yt:48JlgiBpw_I ][Absolute Beginner's Guide to Emacs ]]
works always.
NOTE: Listing [[lst:define-org-yt-link-type ][define org-yt-link type ]] does only implement normal =html= links
instead of embedded video links, but listing [[lst:howto-embed-yt ]] shows a working
=html= example of how to embed a YouTube video in an inline frame element.
2022-12-22 19:15:34 +01:00
#+caption[Define an =org-link= type for =YouTube= ]:
#+caption : Define an =org-link= type for =YouTube=.
#+name : lst:define-org-yt-link-type
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2024-06-15 19:09:53 +02:00
(when (ensure-package-installation 'emms)
;; https://bitspook.in/blog/extending-org-mode-to-handle-youtube-paths/
(defun org-yt-emms-open (path)
"Open an \"YouTube\" PATH link with `emms' using \"mpv\"."
(let ((link (format "https://www.youtube.com/watch?v=%s" path)))
(require 'emms nil 'noerror)
(emms-add-url link)
(with-current-emms-playlist
(save-excursion
(emms-playlist-last)
(emms-playlist-mode-play-current-track)))))
(defun org-yt-url-browse-open (path)
"Open an \"YouTube\" PATH link with `url-browse'."
(let ((link (format "https://www.youtube.com/watch?v=%s" path)))
(browse-url link)))
(defun org-yt-export (path desc backend _)
"Export an \"YouTube\" PATH link according to DESC and BACKEND."
(pcase backend
(`ascii
(format "[%s] <https://www.youtube.com/watch?v=%s >" desc path))
(`html
(format "<a href=\"https://www.youtube.com/watch?v=%s\" >%s</a >" path desc))
(`latex
(format "\\href{https://www.youtube.com/watch?v=%s}{%s}" path desc))
(_ path)))
2022-12-22 19:15:34 +01:00
2024-06-15 19:09:53 +02:00
(with-eval-after-load 'ol
(org-link-set-parameters
"yt" :follow #'org-yt-emms-open :export #'org-yt-export)))
2022-12-22 19:15:34 +01:00
#+end_src
2024-06-16 14:07:33 +02:00
#+caption[How to embed a =YouTube= video in =HTML= ]:
#+caption : How to embed a =YouTube= video in =HTML=.
#+name : lst:howto-embed-yt
#+begin_src html -n :exports code :tangle yegge.html
<!DOCTYPE html >
<html lang="en" >
<head >
<meta charset="UTF-8" >
<meta name="viewport" content="width=device-width, initial-scale=1.0" >
<title >ChatGPT: How to embed a YouTube video in HTML</title >
</head >
<body >
<h1 >Steve Yegge embedded YouTube video</h1 >
<iframe width="630" height= "420"
src="https://www.youtube.com/embed/lkIicfzPBys"
allowfullscreen></iframe >
</body >
</html >
#+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
2024-01-25 10:37:09 +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
2024-01-25 10:37:09 +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
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
2024-01-25 10:37:09 +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
2024-01-26 09:59:27 +01:00
(ascii (format "`kbd(%s)'" keys))
2022-11-07 11:50:17 +01:00
(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
2024-05-15 15:15:29 +02:00
*** Handle Python exceptions in ~ob-python~
:PROPERTIES:
:CUSTOM_ID: sec:handle-python-exceptions
:END:
Python exceptions are never visible while executing Python ~org-src-mode~
blocks. Redirecting Python exceptions is a way to make them visible. Listing
[[lst:redirect-python-exceptions ]] redirects Python exceptions to the file
~stderr.arm~ , listing [[lst:open-python-exceptions ]] opens the file ~stderr.arm~ in
~auto-revert-mode~ , and listing [[lst:demo-python-exceptions ]] demonstrates the
redirection of Python exceptions to the file ~stderr.arm~ .
#+caption[Redirect Python exceptions to a file]:
#+caption : Redirect Python exceptions to a file:
#+name : lst:redirect-python-exceptions
#+begin_src python -i -n :results silent :session :tangle no
import sys
file = open("stderr.arm", "w")
sys.stderr = file
#+end_src
#+caption[Open the redirected file in ~auto-revert-mode~ ]:
#+caption : Open the redirected file in ~auto-revert-mode~.
#+name : lst:open-python-exceptions
#+begin_src emacs-lisp -n :results silent :tangle no
(find-file "stderr.arm")
(auto-revert-mode)
#+end_src
#+caption[Demonstrate the redirection of Python exceptions to a file]:
#+caption : Demonstrate the redirectio of Python exceptions to a file.
#+name : lst:demo-python-exceptions
#+begin_src python -i -n :results silent :session :tangle no
variable
#+end_src
2024-01-17 12:56:00 +01:00
*** [[https://orgmode.org/worg/org-tests/index.html][Testing Org]]
:PROPERTIES:
:CUSTOM_ID: sec:testing-org
:END:
2024-01-22 12:13:01 +01:00
Listing [[lst:batch-org-testing ]] shows the recommended way: use =make test= in a
2024-05-16 11:47:20 +02:00
clean Org git repository. In addition, on my weird Darwin system, I do =ln -sf
VCS/org-mode/lisp= and =ln -sf VCS/org-mode/testing= to fix the command =make
repro=.
2024-01-22 12:13:01 +01:00
#+caption[Batch Org testing]:
#+caption : Batch Org testing: obligatory before mailing a patch.
#+name : lst:batch-org-testing
#+begin_src shell -n :eval never :tangle no
make test > out.txt 2>&1
#+end_src
2024-01-17 12:56:00 +01:00
2024-01-22 12:57:41 +01:00
*** LaTex preamble editing using [[info:org#Noweb Reference Syntax][Noweb (info)]]
2022-11-06 15:53:39 +01:00
: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
2024-01-20 00:21:47 +01:00
contain the LaTeX preamble. All LaTeX listings in this section *can be and are*
handled by [[info:org#Noweb Reference Syntax ][noweb (info) ]].
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{
2024-01-21 18:51:41 +01:00
Emacs for \LaTeX{}, Lisp, Org, and Python -- Gerard Vermeulen
2022-11-07 11:50:17 +01:00
}
}
\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{
2024-01-21 18:51:41 +01:00
Emacs for \LaTeX{}, Lisp, Org, and Python -- Gerard Vermeulen
2023-05-06 10:39:42 +02:00
}
}
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
2024-06-14 22:29:19 +02:00
*** [[info:org#LaTeX header and sectioning][Deprecated LaTeX preamble editing methods]] :noexport:
2023-06-02 17:12:00 +02:00
:PROPERTIES:
:CUSTOM_ID: sec:easy-latex-preamble-editing
2024-06-17 13:48:16 +02:00
:header-args:emacs-lisp: :tangle no
2023-06-02 17:12:00 +02:00
:END:
2024-01-22 12:57:41 +01:00
*NOTE:* This [[info:org#Top ][Org (info) ]] file uses the recommended method of noweb trickery in
Section [[#sec:file-inclusion-and-noweb ]].
There are at least two deprecated (old and historic) ways to edit the Org
=#+latex_header:= and =#+latex_extra_header:= keywords easily
for export to LaTeX, see [[info:org#LaTeX header and sectioning ][LaTeX header and sectioning (info) ]].
2023-06-02 17:12:00 +02:00
The old 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) ]].
Listing [[lst:org-babel-latex-header-blocks ]] implements this way by means of two
new [[info:org#Editing Source Code ][<LANGUAGE>-modes ]]: =latex-header= and =latex-extra-header= .
2024-01-22 12:57:41 +01:00
The old way is to define two Org Babel languages (=latex-extra-header= and
=latex-header= ) as done in Listing [[lst:org-babel-latex-header-blocks ]]. The
historic 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
=2014-11-11= ). Listing [[lst:org-latex-header-blocks-filter ]] proposes a fix for
=org-latex-header-blocks-filter= . This setup keeps the deprecated ways for
backwards compatibility. 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.
2023-06-02 17:12:00 +02:00
#+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.
#+name : lst:org-babel-latex-header-blocks
2024-06-17 13:48:16 +02:00
#+begin_src emacs-lisp -n :exports code :results silent
2023-06-02 17:12:00 +02: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)))
(defun org-babel-execute:latex-extra-header (body _params)
"Execute a block of LaTeX extra header lines with org-babel.
2024-01-28 14:29:59 +01:00
Calling `org-babel-execute-src-block' calls this function and
2023-06-02 17:12:00 +02:00
prefixes all lines with \"#+latex_extra_header: \"."
(prefix-all-lines "#+latex_extra_header: " body))
(defun org-babel-execute:latex-header (body _params)
"Execute a block of LaTeX header lines with org-babel.
2024-01-28 14:29:59 +01:00
Calling `org-babel-execute-src-block' calls this function and
2023-06-02 17:12:00 +02:00
prefixes all lines with \"#+latex_header: \"."
(prefix-all-lines "#+latex_header: " body))
(defvar org-babel-default-header-args:latex-extra-header
'((:exports . "results") (:results . "raw")))
(defvar org-babel-default-header-args:latex-header
'((:exports . "results") (:results . "raw")))
(with-eval-after-load 'org-src
(add-to-list 'org-src-lang-modes '("latex-header" . latex))
(add-to-list 'org-src-lang-modes '("latex-extra-header" . latex))))
#+end_src
#+caption[Convert marked LaTeX export blocks to LaTeX header lines]:
#+caption : Convert marked LaTeX export blocks to LaTeX header lines.
#+name : lst:org-latex-header-blocks-filter
2024-06-17 13:48:16 +02:00
#+begin_src emacs-lisp -n :results silent
2023-06-02 17:12:00 +02: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
2023-09-26 16:25:53 +02:00
org-export-before-parsing-functions))
2023-06-02 17:12:00 +02:00
#+end_src
2023-07-08 07:02:55 +02:00
*** [[info:org#HTML Export][HTML export (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:html-export
:END:
The code label and link feature in [[info:Org#Literal Examples ][Literal Examples (info) ]] does not integrate
with LaTeX export.
#+caption[Set HTML export options]:
#+caption : Set HTML export options.
#+name : lst:set-html-export-options
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2023-07-08 07:02:55 +02:00
(with-eval-after-load 'ox-html
;; (Info-find-node "Org" "Literal Examples")
2024-06-16 15:10:22 +02:00
(setopt org-html-head-include-scripts t))
2023-07-08 07:02:55 +02: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
2024-05-02 13:19:46 +02:00
=org-latex-subtitle-format= . Read the documentation strings to understand how
those variables control 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
#+name : lst:ox-latex-emacs-lisp-setup
2023-04-18 18:03:33 +02:00
#+begin_src emacs-lisp -n :exports code :results none :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
2024-05-02 14:53:33 +02:00
;; https://tex.stackexchange.com/questions/506102/
;; adding-header-and-footer-to-custom-titlepage
2024-02-11 16:19:02 +01:00
(make-local-variable 'org-latex-classes)
2022-11-07 11:50:17 +01:00
(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)
2024-05-02 13:19:46 +02:00
(setq-local org-latex-title-command "\\begin{titlepage}
2024-05-02 14:53:33 +02:00
%% https://emacs.stackexchange.com/questions/47347/
%% customizing-org-latex-title-command-to-edit-title-page
2024-05-02 13:19:46 +02:00
%% 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}")
2024-02-11 16:19:02 +01:00
(setq-local org-latex-toc-command "
2022-11-07 11:50:17 +01:00
\\tableofcontents\\label{toc}
\\listoflistings
\\listoftables
\\newpage
")
2024-02-11 16:19:02 +01:00
(setq-local org-latex-subtitle-format ""))
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
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'org-element
2024-06-13 09:02:05 +02:00
(defconst grok-org-output
"*Grok Org Element Output* "
"Grok Org output buffer name.")
2022-01-17 07:56:55 +01:00
2024-06-13 09:02:05 +02:00
(defun grok-org-element-at-point ()
"Call `org-element-at-point' interactively and pretty-print."
(interactive)
(pp-display-expression
(org-element-at-point) grok-org-output))
2022-11-07 11:50:17 +01:00
2024-06-13 09:02:05 +02:00
(defun grok-org-element-context ()
"Call `org-element-context' interactively and pretty-print."
(interactive)
(pp-display-expression
(org-element-context) grok-org-output))
(defun grok-org-element-parse-buffer ()
"Call `org-element-parse-buffer' interactively and pretty-print."
(interactive)
(let ((what (completing-read
"granularity: "
'(headline element greater-element object)
nil 'require-match)))
2022-11-07 11:50:17 +01:00
(pp-display-expression
2024-06-13 09:02:05 +02:00
(org-element-parse-buffer what) grok-org-output)))
2022-11-07 11:50:17 +01:00
2024-06-13 09:02:05 +02:00
(defun grok-org-element-parse-whole-buffer ()
"Like `grok-org-element-parse-buffer' from point 1 and sans granularity."
(interactive)
(org-with-point-at 1
(pp-display-expression (org-element-parse-buffer) grok-org-output)))
2023-06-29 06:43:20 +02:00
2024-06-13 09:02:05 +02:00
(defun grok-org-heading-components ()
"Call `org-heading-components' interactively and pretty-print."
(interactive)
(pp-display-expression
(org-heading-components) grok-org-output))
2023-06-23 11:38:37 +02:00
2024-06-13 09:02:05 +02:00
(defun grok-org-element-lineage ()
"Call `org-element-lineage' interactively and pretty-print."
(interactive)
(org-load-modules-maybe)
(pp-display-expression
(org-element-lineage (org-element-context) nil t) 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
2024-01-25 10:37:09 +01:00
misspellings for machines]]. Listing [[lst:misspellings-abbrev ]] defines his keyboard
macro under the name =misspellings-abrev= . I have used those directions to
define src_emacs-lisp[:results silent]{(describe-variable 'global-abbrev-table)}
2024-06-12 10:58:48 +02:00
and to store it in src_emacs-lisp[:results none]{(describe-variable
2024-01-25 10:37:09 +01:00
'abbrev-file-name)} to manage its changes with git. I can change the
2022-09-11 14:34:03 +02:00
abbreviation definitions in this file by means of:
2024-01-25 10:37:09 +01:00
1. Execute src_emacs-lisp[:results silent]{(edit-abbrevs)} to alter abbreviation
definitions by editing an =*Abbrevs*= buffer.
2022-09-11 14:34:03 +02:00
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
2024-01-25 10:37:09 +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
2023-07-06 08:18:57 +02:00
*** TODO [[https://dict.org/bin/Dict][DICT.org]] local server fails on Darwin
2022-10-12 06:08:27 +02:00
: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
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:
2024-01-26 13:09:42 +01: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. Listing [[lst:configure-writegood-mode ]] configures [[https://github.com/bnbeckwith/writegood-mode#readme ][writegood mode ]] and
2024-01-26 19:22:09 +01:00
enables =writegood-mode= for =text-mode= buffers. Therefore, the best way use
it for this buffer is by typing {{{kbd(C-c C-e t U)}}} to export the it to a
=text-mode= buffer where the =writegood-mode= faces are more visible.
2022-04-30 09:55:37 +02:00
#+caption[Configure =writegood-mode= ]:
#+caption : Configure =writegood-mode=.
#+name : lst:configure-writegood-mode
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2024-06-15 17:01:51 +02:00
(when (ensure-package-installation 'writegood-mode)
2024-01-26 19:22:09 +01:00
(add-hook 'after-init-hook
(defun on-after-change-mode-hook-enable-writegood-mode ()
(add-hook 'after-change-major-mode-hook
(defun enable-writegood-mode ()
2024-04-18 17:03:25 +02:00
(when (derived-mode-p '(org-mode text-mode))
2024-01-26 19:22:09 +01:00
(writegood-mode +1)))))
'depth)
(global-set-key (kbd "C-c g") #'writegood-mode))
2022-04-30 09:55:37 +02:00
#+end_src
2024-02-05 19:16:09 +01:00
** [[info:emacs#Which Function][Which-function-mode (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:which-function-mode
:END:
2024-02-07 13:15:50 +01:00
Listing [[lst:setup-which-function-mode ]] sets ~which-function-mode~ options. The
post [[https://codelearn.me/2024/02/02/emacs-which-function-mode.html ][Emacs: which-function-mode ]] claims that ~which-function-mode~ works in
2024-02-06 09:24:56 +01:00
~org-mode~ . This is true in case all document headlines are simple, but is not
true in case document headlines contain links. The code in listing
2024-02-07 13:15:50 +01:00
[[lst:define-for-which-func-functions ]] has stolen ideas from the following links:
2024-02-05 19:16:09 +01:00
- [[https://list.orgmode.org/20240205.141235.268481480563517065.teika@gmx.com/ ][Show current org-mode headline in frame header ]].
- [[https://emacs.stackexchange.com/questions/30894/ ][Show current org-mode headline in modeline ]].
#+caption[Setup ~which-function-mode~ ]:
#+caption : Setup ~which-function-mode~.
#+name : lst:setup-which-function-mode
#+begin_src emacs-lisp -n :results silent
2024-02-07 18:47:11 +01:00
(with-eval-after-load 'which-func
2024-06-15 17:01:51 +02:00
(setopt which-func-modes '(emacs-lisp-mode org-mode pdf-view-mode)))
2024-02-07 13:15:50 +01:00
#+end_src
#+caption[Define functions for ~which-func-functions~ ]:
#+caption : Define functions for ~which-func-functions~.
#+name : lst:define-for-which-func-functions
#+begin_src emacs-lisp -n :results silent
;; https://emacs.stackexchange.com/questions/30894/
2024-04-18 17:03:25 +02:00
(declare-function pdf-info-outline "pdf-info" (&optional file-or-buffer))
(declare-function org-element-type-p "org-element-ast" (node types))
2024-02-05 19:16:09 +01:00
(defvar which-func-functions nil)
2024-02-06 09:24:56 +01:00
(defun which-func-org-function ()
2024-02-05 19:16:09 +01:00
"Return level and title of the current headline.
Return the document title when point is above the first headline."
2024-02-06 09:24:56 +01:00
(interactive) ;; Keep this function interactive for fixing.
2024-02-05 19:16:09 +01:00
(when (eq major-mode 'org-mode)
(let (text)
2024-02-06 09:24:56 +01:00
;; Handle point eventually above the first headline.
2024-02-05 19:16:09 +01:00
(unless (org-at-heading-p)
(save-excursion
(org-previous-visible-heading 1)
(let ((eap (org-element-at-point)))
(when (org-element-type-p eap 'keyword)
(setq text (format "0|%s" (org-element-property :value eap)))))))
2024-02-06 09:24:56 +01:00
;; Handle point anywhere else.
2024-02-05 19:16:09 +01:00
(unless text
(let* ((chain (org-get-outline-path t))
(count (length chain)))
(setq text (format "%s|%s" count (nth (1- count) chain)))))
text)))
2024-02-06 09:24:56 +01:00
(add-to-list 'which-func-functions 'which-func-org-function)
2024-02-05 19:16:09 +01:00
2024-02-06 09:24:56 +01:00
(defun which-func-pdf-view-function ()
2024-02-05 19:16:09 +01:00
"Return the title of the current headline.
2024-02-07 18:47:11 +01:00
Return \"Front Matter\" when current page is above the first headline."
2024-02-06 09:24:56 +01:00
(interactive) ;; Keep this function interactive for fixing.
2024-02-05 19:16:09 +01:00
(when (eq major-mode 'pdf-view-mode)
(let* ((current-page (pdf-view-current-page))
(outline (pdf-info-outline (current-buffer)))
(hl-count (length outline))
(hl-index 0)
(hl-page 0)
(old-title "Front Matter")
(new-title old-title))
2024-02-07 11:01:34 +01:00
;; Return the first headline on a page which is better than nothing.
;; I can't do better, since `pdf-view-mode' has no notion of point.
2024-02-05 19:16:09 +01:00
(while (and (< hl-index hl-count) (< hl-page current-page))
(setq old-title new-title)
(setq hl-page (alist-get 'page (nth hl-index outline)))
(setq new-title (alist-get 'title (nth hl-index outline)))
(cl-incf hl-index))
(if (< current-page hl-page) old-title new-title))))
2024-02-06 09:24:56 +01:00
(add-to-list 'which-func-functions 'which-func-pdf-view-function)
2024-02-05 19:16:09 +01:00
#+end_src
2024-02-01 16:20:04 +01:00
* [[info:emacs#Saving Emacs Sessions][Saving Emacs sessions (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:desktop
:END:
Listing [[lst:desktop-setup ][setup desktop ]] makes Emacs save its state between closing its session to
opening the next session.
2024-06-16 10:30:38 +02:00
#+caption[Setup =desktop= to save Emacs sessions]:
#+caption : Setup =desktop= to save Emacs sessions.
2024-02-01 16:20:04 +01:00
#+name : lst:desktop-setup
#+begin_src emacs-lisp -n :results silent
(with-eval-after-load 'emacs
2024-06-16 10:30:38 +02:00
;; GAV: I fail to implement the idea of ChatGPT on how to reload
;; `eww' pages automatically while restoring the desktop (idea is to
;; add save and restore handlers to `desktop-buffer-mode-handlers').
;; GAV: (setopt eww-restore-desktop t) fails and starts hesitantly.
;; GAV: I fail to code a function for setting the
;; `desktop-buffers-not-to-save-function' option.
2024-02-01 16:20:04 +01:00
(setopt desktop-buffers-not-to-save
(rx bos (or "*Apropos" "compilation* "))
desktop-modes-not-to-save
2024-06-16 10:30:38 +02:00
'(emacs-lisp-mode image-mode tags-table-mode))
2024-02-01 16:20:04 +01:00
2024-06-16 10:30:38 +02:00
(desktop-save-mode t))
#+end_src
2024-02-01 16:20:04 +01:00
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-07-25 10:37:22 +02:00
out of your way. [[info:eglot#Top ][Eglot (info) ]] is a builtin since Emacs-29.1. The following
2023-01-13 17:49:43 +01:00
listings contribute to a programming language mode independent [[https://github.com/joaotavora/eglot ][Eglot ]]
configuration:
2023-07-29 17:20:22 +02:00
1. Listing [[lst:minimal-eglot-setup ][minimal Eglot setup ]] adds key bindings to =eglot-mode-keymap= .
2024-06-11 19:56:24 +02:00
2. Listing [[lst:setup-oglot ]] uses [[https://github.com/gav451/oglot# ][oglot ]] to enable using [[https://github.com/joaotavora/eglot ][Eglot ]] in =org-src-mode=
Python buffers (and not for Julia buffers).
3. 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).
2024-06-11 19:56:24 +02:00
4. Listing [[lst:whiten-black ]] defines Emacs Lisp functions to undo (whiten) some
2024-01-25 10:37:09 +01:00
output of [[https://black.readthedocs.io/en/stable/ ][Black ]] after src_emacs-lisp[:results silent]{(org-babel-tangle)}.
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
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
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
2024-06-11 19:56:24 +02:00
#+caption : Setup ~oglot~ for ~python-mode~.
2024-03-19 21:16:46 +01:00
#+name : lst:setup-oglot
#+begin_src emacs-lisp -n :results silent
2024-06-17 08:52:24 +02:00
(unless (package-installed-p 'oglot)
2024-06-16 17:24:22 +02:00
(package-vc-install '(oglot :url "https://github.com/gav451/oglot.git")))
2024-06-17 08:52:24 +02:00
(when (require 'oglot nil 'noerror)
(setopt oglot-maybe-ensure-modes '(python-mode)))
2024-03-19 21:16:46 +01:00
#+end_src
2024-01-17 21:29:53 +01: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
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2024-02-23 11:17:46 +01:00
(defun eglot-maybe-ensure ()
2024-04-18 17:03:25 +02:00
"Call `eglot-ensure' under favorable conditions."
2024-02-24 16:06:48 +01:00
(when (and (apply #'derived-mode-p '(python-mode))
2024-02-23 11:17:46 +01:00
(assoc 'eglot-workspace-configuration dir-local-variables-alist))
(eglot-ensure)))
;; 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)
2023-12-10 15:13:49 +01:00
#+end_src
2024-01-21 17:30:56 +01:00
#+caption[Whiten Black]:
#+caption : Whiten Black
#+name : lst:whiten-black
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2024-01-21 17:30:56 +01:00
(with-eval-after-load 'emacs
(defun black-python-sequence ()
"Try to find a Blackened Python sequence to whiten."
(interactive)
(if (derived-mode-p 'python-mode)
(re-search-forward "[[(][ \t]*$" nil t)
(org-narrow-to-block)
(re-search-forward "[[(][ \t]*$" nil t)
(widen)))
(defun whiten--python-sequence ()
"Whiten a Blackened Python sequence without narrowing.
Call `widen' after an `user-error'."
(if (not (and (looking-at-p "[ \t]*$")))
(user-error "Call `widen': not seeing `new-line'")
(skip-chars-backward " \t\\[\\(")
(if (not (looking-at-p "[ \t]*[[(][ \t]* $"))
(user-error "Call `widen': not seeing `[' or `(' before `new-line'")
(fixup-whitespace)
(skip-chars-forward " \\[\\(")
(kill-line)
(fixup-whitespace)
(move-end-of-line 1)
(while (and (eq ?\, (char-before)))
(kill-line)
(fixup-whitespace)
(move-end-of-line 1))
(save-excursion
(when (memq (char-before) '(?\) ?\]))
(goto-char (1- (point)))
(delete-char -1))))))
(defun whiten-python-sequence ()
"Whiten a Blackened Python sequence. Call `widen' after an `user-error'."
(interactive)
(if (derived-mode-p 'python-mode)
(whiten--python-sequences)
(org-narrow-to-block)
(whiten--python-sequence)
(widen))))
#+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
2024-01-25 10:37:09 +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)
2023-07-29 17:20:22 +02:00
;; `format-all' defines `format-all-buffer' as an autoloaded command.
2022-11-07 11:50:17 +01:00
(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
2024-01-21 18:25:03 +01:00
that do not visit a file. Listing [[lst:configure-flymake ]] aliases =list-errors=
(new) to =flymake-show-buffer-diagnostics= (old).
#+caption[Configure =Flymake= ]:
#+caption : Configure =Flymake=
#+name : lst:configure-flymake
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2024-01-21 18:25:03 +01:00
(with-eval-after-load 'flymake
(defalias 'list-errors #'flymake-show-buffer-diagnostics
2024-04-18 12:59:41 +02:00
"Show a list of Flymake diagnostics for current buffer.")
(keymap-set flymake-mode-map "M-n" 'flymake-goto-next-error)
(keymap-set flymake-mode-map "M-p" 'flymake-goto-prev-error))
2024-01-21 18:25:03 +01:00
#+end_src
2022-07-17 20:10:17 +02:00
* 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
2023-05-28 11:48:25 +02:00
Links to Common Lisp books and posts are:
2023-05-28 10:08:24 +02:00
1. [[https://lisp-lang.org/ ][Common Lisp ]]
2. [[https://kvardek-du.kerno.org/ ][Kvardek Du - Luis Oliveira ]]
3. [[https://redirect.cs.umbc.edu/courses/331/resources/lisp/ ][Lisp Resources ]]
4. [[https://redirect.cs.umbc.edu/courses/331/resources/lisp/onLisp/ ][On Lisp - Paul Graham ]]
5. [[https://dept-info.labri.fr/~strandh/Teaching/Programmation-Symbolique/Common/Book/HTML/programmation.html ][Traité de Programmation en Common Lisp ]]
2023-05-15 14:07:59 +02:00
*** [[https://joaotavora.github.io/sly/][Sly]]
:PROPERTIES:
:CUSTOM_ID: sec:sly
:END:
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
~sly~ documentation string instead of in the [[info:sly#Multiple Lisps ][multiple lisps (info) ]] manual.
2. It does not ensure the [[info:sly#Auto-SLY ][automatic connection to the lisp server (info) ]] when
opening a Common Lisp file because it does not play well with =ob-lisp= .
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.
Listing [[lst:slink-sel ]] allows to set or get the Sly string elision length.
Finally, listing [[lst:configure-sly ]] uses a technique to [[info:sly#Loading Slynk faster ][load Slynk faster (info) ]]
2024-01-25 10:37:09 +01:00
by means of a custom core file in src_emacs-lisp[:results
2024-06-12 10:58:48 +02:00
none]{(describe-variable 'no-littering-var-directory)}. Listing
2024-01-25 10:37:09 +01:00
[[lst:sbcl-core-for-sly ]] tangles to a script to dump such a [[http://www.sbcl.org/ ][SBCL ]] core.
2023-05-15 14:07:59 +02:00
2022-01-23 11:56:37 +01:00
#+caption[Configure =sly= ]:
#+caption : Configure =sly=.
#+name : lst:configure-sly
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2023-05-28 10:04:33 +02:00
(when (ensure-package-installation 'sly 'sly-macrostep 'sly-named-readtables)
2022-11-07 11:50:17 +01:00
(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'.
2023-03-28 08:15:11 +02:00
(setopt sly-db-initial-restart-limit 10
sly-default-lisp 'sbcl
2023-01-12 21:28:18 +01:00
sly-lisp-implementations
2023-04-07 13:49:25 +02:00
`((ccl (,(executable-find "ccl64")))
(sbcl (,(executable-find "sbcl")
2023-01-12 21:28:18 +01:00
"--core"
,(no-littering-expand-var-file-name "sbcl.core-for-sly")))))
2022-11-07 11:50:17 +01:00
2023-04-02 07:17:08 +02: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
2023-05-15 14:07:59 +02:00
#+caption[Get/set Sly ~slynk:*string-elision-length*~ functionality]:
#+caption : Get/set Sly ~slynk:*string-elision-length*~ functionality.
#+name : lst:slink-sel
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2023-05-15 14:07:59 +02:00
(with-eval-after-load 'sly
(defconst slynk-command-get-sel
"(cdr (assoc 'slynk:*string-elision-length* slynk:*slynk-pprint-bindings* ))"
"Slynk \"string elision length\" getter command.")
2024-03-20 14:11:14 +01:00
(defun slynk-command-set-sel (length)
"Slynk LENGTH \"string elision length\" setter command.
LENGTH values must be positive integers to enable or `nil' to disable elision."
(format "(setf %s %s)" slynk-command-get-sel length))
2023-05-15 14:07:59 +02:00
(defun slynk-get-sel ()
"Get the Slynk \"string-elision-length\"."
(cadr (sly-eval `(slynk:eval-and-grab-output ,slynk-command-get-sel))))
2024-03-20 14:11:14 +01:00
;; Most useful for Org source blocks.
(defun slynk-set-sel (length)
"Set the Slynk \"string-elision-length\" LENGTH.
LENGTH values must be positive integers to enable or `nil' to disable elision."
(cadr
(sly-eval `(slynk:eval-and-grab-output ,(slynk-command-set-sel length)))))
2023-05-15 14:07:59 +02:00
2024-03-20 14:11:14 +01:00
;; Most useful for interactive use.
2023-05-15 14:07:59 +02:00
(defun slynk-eval-sel-command (string)
"Evaluate the Slynk \"string-elision-length\" command STRING."
(unless (sly-connected-p)
(user-error "Slynk connection is not open: \"M-x sly\"?"))
(message "Slynk string elision length is %S"
(read (cadr (sly-eval `(slynk:eval-and-grab-output ,string))))))
(defun slynk-get-string-elision-length ()
"Get the Slynk \"string-elision-length\"."
(interactive)
(slynk-eval-sel-command slynk-command-get-sel))
2024-03-20 14:11:14 +01:00
(defun slynk-set-string-elision-length (&optional length)
"Set the Slynk \"string-elision-length\" LENGTH.
Valid LENGTH values are positive integers to set or `nil' to reset."
(interactive "X\ Slink string elision length: ")
(unless (or (null length) (and (integerp length) (> length 0)))
2023-05-15 14:07:59 +02:00
(user-error
2024-03-20 14:11:14 +01:00
"Slynk `length' must be `nil' or a positive integer (got `%S')" length))
(slynk-eval-sel-command (slynk-command-set-sel length))))
2023-05-15 14:07:59 +02: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-06-25 14:00:01 +02:00
#+begin_src shell -n :eval never :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-05-15 14:07:59 +02:00
*** [[https://courses.cs.northwestern.edu/325/][CS 325 AI Programming]]
:PROPERTIES:
:CUSTOM_ID: sec:cs-325-ai-programming
:END:
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:
[[https://www.quicklisp.org/ ][Quicklisp ]] is a library manager for Common Lisp. Listing
[[lst:download+verify-quicklisp ]] downloads the [[https://www.quicklisp.org/ ][Quicklisp ]] installation 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. Listing [[lst:clone-local-projects ]] shows how to make local projects out
of unpackaged projects and listing [[lst:register-load-local-projects ]] shows how to
register local projects in order to load those unpackaged projects in the same
way as packaged projects.
#+caption[Download and verify =quicklisp= ]:
#+caption : Download and verify =quicklisp=.
#+name : lst:download+verify-quicklisp
#+begin_src shell -n :dir ~ :results none :tangle no
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
#+end_src
#+caption[Bootstrap =quicklisp= ]:
#+caption : Bootstrap =quicklisp=.
#+header : :tangle-mode (identity #o755)
#+name : lst:bootstrap-quicklisp
2023-06-25 14:00:01 +02:00
#+begin_src shell -n :eval never :tangle ~/bin/quicklisp-sbcl-bootstrap
2023-05-15 14:07:59 +02:00
#!/bin/sh
sbcl --load ~/quicklisp.lisp <<EOF
(quicklisp-quickstart:install)
(quit)
EOF
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# sh-basic-offset: 2
# End:
#+end_src
#+caption[Clone local =quicklisp= projects]:
#+caption : Clone local =quicklisp= projects.
#+name : lst:clone-local-projects
#+begin_src shell -n :dir ~/quicklisp/local-projects :results none :tangle no
git clone https://gitlab.com/criesbeck/cs325.git
git clone git@github.com:ageldama/cl-state-machine.git
#+end_src
#+caption[Register and load local =quicklisp= projects with dependencies]:
#+caption : Register and load local =quicklisp= projects with dependencies.
#+name : lst:register-load-local-projects
#+begin_src lisp -n :eval never-export :results none :tangle no
;; SBCL on Darwin fails to run cl-cffi-gtk:
;; https://lisp-journey.gitlab.io/blog/gui-programming-in-common-lisp-part-3-of-5-gtk3/
;; https://www.crategus.com/books/cl-cffi-gtk/
;; https://www.crategus.com/books/cl-gtk/gtk-tutorial.html
(defun probe--local-project-directory (name)
(some #'identity (mapcar (lambda (x)
(let ((*default-pathname-defaults* x))
(probe-file name)))
ql:*local-project-directories* )))
(when (probe--local-project-directory "cs325")
(ql:register-local-projects)
(ql:quickload "cs325")
(ql:quickload "meta")
(ql:quickload '("named-readtables" "try")) ;; testing requires "try".
#-:clozure
(ql:quickload "nodgui") ;; requires https://www.tcl.tk/software/tklib/
(ql:quickload '("rutils" "rutilsx"))
(ql:quickload "ucons"))
(when (probe--local-project-directory "cl-state-machine")
(ql:quickload '("cl-state-machine" "cl-state-machine-examples"
"cl-state-machine-graphing" "cl-state-machine-test")))
#+end_src
#+caption : A =quicklisp= sbclrc file.
#+name : lst:quicklisp-sbclrc-file
#+begin_src lisp -n :eval never :tangle ~/.sbclrc
;;; Hey Emacs, this is my -*- lisp -* - .sbclrc file.
;;; The following lines added by ql:add-to-init-file:
#-quicklisp
(let ((quicklisp-init (merge-pathnames "quicklisp/setup.lisp"
(user-homedir-pathname))))
(when (probe-file quicklisp-init)
(load quicklisp-init)))
;;; Load cs325.lisp to create the cs325 package.
;; (eval-when (:compile-toplevel :load-toplevel :execute)
;; (ql:quickload "cs325")
;; (setq *package* (find-package :cs325-user)))
#+end_src
** [[https://www.n16f.net/blog/custom-font-lock-configuration-in-emacs/][Lisp mode custom font locking for Common Lisp]]
:PROPERTIES:
:CUSTOM_ID: sec:lisp-custom-font-locking
:END:
2023-05-28 10:04:03 +02:00
This section implements the code described in the [[https://www.n16f.net/blog/custom-font-lock-configuration-in-emacs/ ][Emacs Common Lisp Font Locking ]]
post.
2023-05-15 14:07:59 +02:00
*** [[https://www.n16f.net/blog/custom-font-lock-configuration-in-emacs/][Initialize Common Lisp custom font locking]]
:PROPERTIES:
:CUSTOM_ID: sec:cl-custom-font-locking-start
2023-02-26 21:44:42 +01:00
: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
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2023-02-26 13:30:20 +01:00
;;; 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-03-22 17:55:26 +01:00
#+caption[Define a =Common Lisp= function to find standard symbol names]:
#+caption : Define a =Common Lisp= function to find standard symbol names.
#+name : lst:standard-symbol-names
2023-07-05 05:41:32 +02:00
#+begin_src lisp -n :eval never-export :results silent :tangle no
2023-02-26 13:30:20 +01:00
(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-05-15 14:07:59 +02:00
#+caption[Set Sly ~slynk:*string-elision-length*~ ]:
#+caption : Set Sly ~slynk:*string-elision-length*~.
#+name : lst:set-sly-sel
#+header : :wrap "src text -n"
#+begin_src emacs-lisp -n :eval never-export :exports both :tangle no
(when (and (fboundp 'sly-connected-p) (sly-connected-p))
(and (fboundp 'slynk-set-sel) (slynk-set-sel (ash 1 14))))
#+end_src
#+caption[Set Sly ~slynk:*string-elision-length*~ result]:
#+caption : Set Sly ~slynk:*string-elision-length*~ result.
#+name : lst:set-sly-sel-result
#+RESULTS : lst:set-sly-sel
#+begin_src text -n
16384 (15 bits, #x4000)
#+end_src
*** [[https://www.n16f.net/blog/custom-font-lock-configuration-in-emacs/][Collect standard symbol function names]]
:PROPERTIES:
:CUSTOM_ID: sec:cl-function-names
:END:
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
2024-01-25 10:37:09 +01:00
#+header : :wrap "src emacs-lisp -n :results silent"
2023-02-26 21:44:42 +01:00
#+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
2024-01-25 10:37:09 +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-05-15 14:07:59 +02:00
*** [[https://www.n16f.net/blog/custom-font-lock-configuration-in-emacs/][Collect standard symbol value names]]
:PROPERTIES:
:CUSTOM_ID: sec:cl-value-names
:END:
2023-02-26 21:44:42 +01:00
#+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
2024-01-25 10:37:09 +01:00
#+header : :wrap "src emacs-lisp -n :results silent"
2023-02-26 21:44:42 +01:00
#+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
2024-01-25 10:37:09 +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-05-15 14:07:59 +02:00
*** [[https://www.n16f.net/blog/custom-font-lock-configuration-in-emacs/][Finalize Common Lisp custom font locking]]
:PROPERTIES:
:CUSTOM_ID: sec:cl-custom-font-locking-final
:END:
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
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2023-02-26 13:30:20 +01:00
(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 ()
2023-09-26 16:25:53 +02:00
"Hook to initialize Common Lisp font locking."
2023-02-26 13:30:20 +01:00
(setq font-lock-defaults cl-font-lock-defaults))
(add-hook 'lisp-mode-hook 'cl-init-lisp-font-lock)
#+end_src
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
2024-04-29 09:55:26 +02:00
important Emacs Lisp idioms.
2022-11-06 15:53:39 +01:00
2024-05-08 13:13:09 +02:00
*** [[info:emacs#Bug Reference][Bug Reference Mode (info)]]
2023-11-22 13:15:20 +01:00
:PROPERTIES:
2024-05-08 13:13:09 +02:00
:CUSTOM_ID: sec:bug-reference-mode
2023-11-22 13:15:20 +01:00
:END:
2024-05-08 13:13:09 +02:00
Listing [[lst:bug-reference-mode ]] configures ~bug-reference-mode~ for use with the
[[https://debbugs.gnu.org/ ][GNU Bug Tracker ]].
2023-11-22 13:15:20 +01:00
2024-05-08 13:13:09 +02:00
#+caption[Setup ~bug-reference-mode~ ]:
#+caption : Setup ~bug-reference-mode~.
#+name : lst:bug-reference-mode
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2024-05-09 08:21:32 +02:00
;; (info "(debbugs) Top")
2024-05-08 13:13:09 +02:00
;; (info "(emacs) Bug Reference")
2024-05-09 08:21:32 +02:00
(ensure-package-installation 'debbugs)
2024-05-08 13:13:09 +02:00
(defvar bug-reference-url-format
"https://debbugs.gnu.org/cgi/bugreport.cgi?bug=%s"
2024-06-14 11:06:46 +02:00
"Format to use `gnu-debbugs' URL.")
2024-06-14 14:20:26 +02:00
(put 'bug-reference-mode 'safe-local-variable 'booleanp)
2023-11-22 13:15:20 +01:00
#+end_src
*** [[info:elisp#Debugging][Debugging Emacs Lisp (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:debugging
:END:
2024-05-08 13:13:09 +02:00
GAV: I fail to instrument the functions from the [[https://www.emacswiki.org/emacs/SourceLevelDebugger ][source level debugger (edebug) ]]
wiki entry as in [[info:elisp#Edebug ][Edebug (info) ]].
2023-11-22 13:15:20 +01:00
2024-05-08 13:13:09 +02:00
*** [[https://www.masteringemacs.org/article/evaluating-elisp-emacs][Evaluating Elisp in Emacs]]
2023-03-05 10:55:27 +01:00
:PROPERTIES:
2024-05-08 13:13:09 +02:00
:CUSTOM_ID: sec:elisp-evaluation
2023-03-05 10:55:27 +01:00
:END:
2024-05-08 13:13:09 +02:00
Listing [[lst:setup-ielm ][setup ielm ]] configures the [[https://wikemacs.org/wiki/IELM ][Interactive Emacs Lisp Mode ]] for better
interoperability with [[https://smartparens.readthedocs.io/en/latest/ ][smartparens ]]: get help on the key bindings by means of
2024-06-12 10:58:48 +02:00
src_emacs-lisp[:results none]{(describe-function 'ielm)}.
2023-03-05 10:55:27 +01:00
2024-05-08 13:13:09 +02:00
#+caption[Setup =ielm= ]:
#+caption : Setup =ielm=.
#+name : lst:setup-ielm
#+begin_src emacs-lisp -n :results silent
(with-eval-after-load 'ielm
(setopt ielm-dynamic-return nil))
2023-03-05 10:55:27 +01:00
#+end_src
2024-04-19 11:40:48 +02:00
*** [[http://yummymelon.com/devnull/writing-better-elisp-docstrings.html][Writing Better Elisp Docstrings]]
:PROPERTIES:
:CUSTOM_ID: sec:describe-function-at-point
:END:
#+caption[Describe Elisp function at point]:
#+caption : Describe Elisp function at point.
#+name : lst:describe-function-at-point
#+begin_src emacs-lisp -n :results silent
;; Stolen from Charles Choi:
;; http://yummymelon.com/devnull/writing-better-elisp-docstrings.html
;; GAV: Org changes the semantics of calling `beginning-of-defun'.
(defun describe-function-at-point ()
"Call `describe-function' on the Elisp function at point.
Switch temporarily from `org-mode' to `text-mode', since `org-mode'
changes the semantics of calling `beginning-of-defun'."
(interactive)
(let ((mode major-mode))
(when (eq major-mode 'org-mode)
(text-mode))
(save-excursion
(beginning-of-defun)
(forward-char)
(forward-sexp 2)
(let ((end-point (point)))
(backward-sexp)
(let* ((fn-name (buffer-substring (point) end-point))
(interned (intern-soft fn-name)))
(if interned
(describe-function interned)
(message "Can't find function at point")))))
(when (eq mode 'org-mode)
(org-mode))))
(with-eval-after-load 'org-mode
(keymap-set org-mode-map "C-c d" #'describe-function-at-point))
(with-eval-after-load 'emacs-lisp-mode
(keymap-set emacs-lisp-mode-map "C-c d" #'describe-function-at-point))
#+end_src
2023-04-26 11:30:06 +02:00
** [[https://go.dev/][Go Programming]]
2022-10-02 07:22:00 +02:00
:PROPERTIES:
2023-04-26 11:30:06 +02:00
:CUSTOM_ID: sec:go-programming
2022-10-02 07:22:00 +02:00
:END:
2024-02-26 19:15:11 +01:00
Links for further investigation are:
1. [[https://gobyexample.com/ ][Go by example ]] is a showcase of short examples with explanations.
2022-10-02 07:22:00 +02:00
2023-05-15 14:05:56 +02:00
#+caption[Setup Go programming]:
#+caption : Setup Go programming.
#+name : lst:setup-go
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2023-05-15 14:05:56 +02:00
(when (featurep 'treesit)
(setopt go-ts-mode-indent-offset 2)
2024-06-14 19:05:26 +02:00
(add-hook 'go-ts-mode-hook (lambda ()
(setq-local tab-width 2)))
2023-05-15 14:05:56 +02:00
(add-to-list 'auto-mode-alist `(,(rx ".go" eos) . go-ts-mode)))
#+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
2024-06-04 13:52:27 +02:00
built-in ~python-mode~ . Here, the focus is on one Emacs package and three Python
2023-01-13 17:49:43 +01:00
packages:
2024-02-22 14:04:29 +01:00
1. [[#sec:eglot ][Eglot - Emacs polyGLOT: a builtin LSP client since Emacs-29.1 ]] and its author
(who is a prolific Common Lisp and Emacs Lisp programmer) has also
contributed to other parts of Emacs.
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.
2024-01-26 10:01:12 +01:00
3. Nowadays, [[https://github.com/charliermarsh/ruff#readme ][Ruff ]] is the fastest 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
2023-01-13 17:49:43 +01:00
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.
2024-06-04 13:52:27 +02:00
# 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
# from either [[https://github.com/mwouts/jupytext][Jupytext]] or [[https://pandoc.org/][Pandoc]].
2022-07-26 20:13:43 +02:00
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-05-28 10:03:11 +02:00
Here are links to Python programming background videos:
2024-02-22 14:07:15 +01:00
1. [[yt:T-TwcmT6Rcw ][Dataclasses: The Code Generator to End All Code Generators - Raymond Hettinger ]]
2. [[yt:p33CVV29OG8 ][Modern Dictionaries - Raymond Hettinger ]]
3. [[yt:HTLu2DFOdTg ][Python's Class Development Kit - Raymond Hettinger ]]
4. [[yt:uL_kmagVKFQ ][The Big Leap of Python-3.13 - Lukasz Langa ]]
5. [[yt:UANN2Eu6ZnM ][The Mental Game of Python - Raymond Hettinger ]]
6. [[yt:Bv25Dwe84g0 ][Thinking about Concurrency - Raymond Hettinger ]]
7. [[yt:0kXaLh8Fz3k ][Thinking outside the GIL with AsyncIO and MultiProcessing - John Reese ]]
8. [[yt:bZAsSzzk0E ][What can't WebAssembly do? - Katie Bell ]]
2023-02-26 14:55:12 +01:00
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
2023-12-11 17:13:55 +01:00
Listing [[lst:setup-python-mode ][setup Python mode ]] selects a common Python interpreter in a virtual
environment for use in =python-mode= and =ob-python= . 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.
2022-12-24 16:36:10 +01:00
2023-12-27 10:08:50 +01:00
Install [[https://github.com/PyCQA/isort#readme ][isort ]] and [[https://github.com/PyCQA/pyflakes#readme ][pyflakes ]] to enable adding, removing, sorting, and fixing
import statements in [[https://git.savannah.gnu.org/cgit/emacs.git/tree/lisp/progmodes/python.el ][Python-mode ]], see the end of the commentary
2024-06-12 10:58:48 +02:00
src_emacs-lisp[:results none]{(find-library "python")} section.
2023-12-27 10:08:50 +01:00
2022-12-24 16:36:10 +01:00
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
2024-06-07 14:01:02 +02:00
Finally, listing [[lst:ruff-nocolor ][ruff-nocolor ]] pipes the =stdout= output of the [[https://pypi.org/project/ruff/ ][ruff ]] executable
through =cat= to remove escape sequences.
2022-12-24 16:36:10 +01:00
2023-05-15 16:10:51 +02:00
#+caption[Setup Python mode with =ob-python= ]:
#+caption : Setup Python mode with =ob-python=.
2023-01-10 19:04:39 +01:00
#+name : lst:setup-python-mode
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2023-05-15 16:10:51 +02:00
(with-eval-after-load 'ob-python
(setopt org-babel-python-command (concat (or (executable-find "python3")
(executable-find "python"))
" -E")))
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"
2023-05-15 16:10:51 +02:00
"pypy")
python-shell-interpreter (or (executable-find "python3")
(executable-find "python"))
python-shell-interpreter-args "-E -i"
python-check-command (executable-find "ruff-nocolor")
python-flymake-command (list (executable-find "ruff-nocolor")
"--stdin-filename" "stdin" "-")))
2023-01-10 19:04:39 +01:00
#+end_src
2022-12-24 16:36:10 +01:00
#+caption[Access =pyenv= ]:
#+caption : Access =pyenv=.
#+name : lst:access-pyenv
2024-01-25 10:37:09 +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."
2024-06-17 16:09:11 +02:00
(concat (pyenv-root) (file-name-as-directory "versions") version))
2022-11-07 11:50:17 +01:00
(defun pyenv-root ()
"Return \"pyenv root\" as a directory."
2024-06-17 19:31:20 +02:00
(let* ((pair (get-program-code-output "pyenv" "root"))
(return-code (car pair))
(output (cdr pair)))
(if (= 0 return-code)
2022-11-07 11:50:17 +01:00
(file-name-as-directory (string-trim output))
(error "%s" (string-trim output)))))
(defun pyenv-version-name ()
"Return \"pyenv version-name\"."
2024-06-17 19:31:20 +02:00
(let* ((pair (get-program-code-output "pyenv" "version-name"))
(return-code (car pair))
(output (cdr pair)))
(if (= 0 return-code)
2022-11-07 11:50:17 +01:00
(string-trim output)
(error "%s" (string-trim output)))))
(defun pyenv-versions ()
2024-06-17 16:09:11 +02:00
"Return \"pyenv versions --bare --skip-aliases\" as a list."
2024-06-17 19:31:20 +02:00
(let* ((pair (get-program-code-output
"pyenv" "versions" "--bare" "--skip-aliases"))
(return-code (car pair))
(output (cdr pair)))
(if (= 0 return-code)
2024-06-17 16:09:11 +02:00
(split-string output)
2022-11-07 11:50:17 +01:00
(error "%s" (string-trim output)))))
(defun pyenv-virtualenvs ()
"Return \"pyenv virtualenvs --bare --skip-aliases\" as a list."
2024-06-17 19:31:20 +02:00
(let* ((pair (get-program-code-output
"pyenv" "virtualenvs" "--bare" "--skip-aliases"))
(return-code (car pair))
(output (cdr pair)))
(if (= 0 return-code)
2022-11-07 11:50:17 +01:00
(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
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'python
2024-06-17 16:09:11 +02:00
(when (and (fboundp 'pyenv-full-path)
(fboundp 'pyenv-version-name)
(fboundp 'pyenv-versions)
(fboundp 'pyenv-virtualenvs))
2022-11-07 11:50:17 +01:00
(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 ()
2024-06-17 16:09:11 +02:00
"Set `python-shell-virtualenv-root' to a pyenv version."
2022-11-07 11:50:17 +01:00
(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 ()
2024-06-17 16:09:11 +02:00
"Set `python-shell-virtualenv-root' to a pyenv virtualenv."
2022-11-07 11:50:17 +01:00
(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-12-30 13:48:47 +01:00
# See:
# https://docs.astral.sh/ruff/configuration/
# https://pycqa.github.io/isort/docs/configuration/black_compatibility.html
# https://setuptools.pypa.io/en/latest/userguide/pyproject_config.html
2022-12-24 16:36:10 +01:00
[tool.black]
line-length = 88
2023-12-30 13:48:47 +01:00
[tool.isort]
profile = "black"
2022-12-24 16:36:10 +01:00
[tool.ruff]
line-length = 88
2024-06-16 17:27:04 +02:00
[tool.ruff.lint]
2022-12-24 16:36:10 +01:00
select = [
2024-06-16 17:27:04 +02:00
"ARG", # flake8-unused-arguments
"B", # flake8-bugbear
"C", # mccabe
"C4", # flake8-comprehensions
"E", # pycodestyle
"D", # pydocstyle
"F", # pyflakes
"UP", # pyupgrade
"W", # pycodestyle
"NPY201", # numpy-2.0 upgrade guide
]
2022-12-24 16:36:10 +01:00
ignore = [
2023-01-05 14:51:19 +01:00
"B905", # `zip()` without an explicit `strict=` parameter
2023-12-30 13:48:47 +01:00
"D202", # no blank lines allowed after function docstring
2022-12-24 16:36:10 +01:00
]
2024-06-16 17:27:04 +02:00
[tool.ruff.lint.mccabe]
2022-12-24 16:36:10 +01:00
max-complexity = 15
2024-06-16 17:27:04 +02:00
[tool.ruff.lint.pydocstyle]
2022-12-29 12:22:44 +01:00
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[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-06-25 14:00:01 +02:00
#+begin_src shell -n :eval never :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:
2024-06-12 13:53:49 +02:00
Listing [[lst:shell-pip-index-versions ]] are is an example of invoking [[https://pip.pypa.io/en/stable/ ][pip ]] in an
=org-mode= =shell= source block with its results in listing
[[lst:shell-pip-index-versions-results ]]. Listing [[lst:pip-pypi-options ]],
[[lst:pip-list-outdated ]], [[lst:pip-upgrade-maybe ]] allow to upgrade outdated Python
packages.
2023-02-26 14:04:44 +01:00
#+caption[Show how to use =pip index versions= ]:
#+caption : Show how to use =pip index versions=.
2023-03-08 11:15:56 +01:00
#+header : :wrap "src text -n"
2023-02-26 14:04:44 +01:00
#+name : lst:shell-pip-index-versions
2023-05-14 07:08:25 +02:00
#+begin_src shell -n :exports both :results verbatim
2023-02-26 14:04:44 +01:00
# 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
2023-03-08 11:15:56 +01:00
#+begin_src text -n
2023-02-26 14:04:44 +01:00
circular-buffer (0.2.0)
Available versions: 0.2.0, 0.1.1, 0.1.0
#+end_src
2023-03-12 18:06:40 +01:00
#+caption[Emacs client "Package Installer for Python" and "PyPI" options]:
#+caption : Emacs client "Package Installer for Python" and "PyPI" options.
#+name : lst:pip-pypi-options
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2023-03-12 18:06:40 +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
:type '(repeat string))
2023-05-21 10:15:37 +02:00
;; Updating "docutils" may require a compatible "Sphinx" release.
2024-02-09 16:06:40 +01:00
;; (setopt pip-frozen-packages '("docutils"))
2023-03-12 18:06:40 +01:00
#+end_src
2023-02-26 14:04:44 +01:00
#+caption[Emacs interface to list outdated Python packages]:
#+caption : Emacs interface to list outdated Python packages.
#+name : lst:pip-list-outdated
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2023-02-26 14:04:44 +01:00
(defvar pip-outdated-packages nil
"Outdated Python packages.")
2023-09-26 16:25:53 +02:00
(defun pip--list-outdated-sentinel (process _event)
"Sentinel function for when the `pip-list-outdated' PROCESS succeeds."
2023-02-26 14:04:44 +01:00
(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)
2023-03-08 11:19:50 +01:00
(describe-variable 'pip-outdated-packages)
2023-02-26 14:04:44 +01:00
(message "Calling `%S' succeeded" #'pip-list-outdated))))
(defun pip-list-outdated ()
2023-09-26 16:25:53 +02:00
"Save the outdated Python packages in `pip-outdated-packages'.
2023-02-26 14:04:44 +01:00
2024-01-29 09:41:51 +01:00
This invokes an asynchronous process and finishes with a message."
2023-02-26 14:04:44 +01:00
(interactive)
2024-06-12 13:58:19 +02:00
(let ((content '("pip" "list" "--outdated" "--format" "json")))
2023-02-26 14:04:44 +01:00
(make-process
:name "pip-list-outdated"
:buffer (generate-new-buffer-name "*pip-list-outdated-output* ")
2024-06-12 13:58:19 +02:00
:command content
2023-02-26 14:04:44 +01:00
:sentinel #'pip--list-outdated-sentinel)
2024-06-13 08:12:02 +02:00
(message "Running `%s' asynchronously" (string-join content " "))))
2023-02-26 14:04:44 +01:00
#+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
2023-03-12 18:06:40 +01:00
#+begin_src emacs-lisp :results silent
2023-09-26 16:25:53 +02:00
(defun pip--upgrade-maybe-sentinel (process _event)
"Sentinel function for when the `pip-upgrade-maybe' PROCESS succeeds."
2023-02-26 14:04:44 +01:00
(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.
2024-01-29 09:41:51 +01:00
This invokes an asynchronous process and finishes with displaying the process
2023-02-26 14:04:44 +01:00
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)
2024-06-12 13:58:19 +02:00
(let ((content
2023-02-26 14:04:44 +01:00
`("pip" "install" "--progress-bar" "off" ,@(nreverse found))))
(make-process
:name "pip-upgrade-maybe"
:buffer (generate-new-buffer-name "*pip-upgrade-maybe* ")
2024-06-12 13:58:19 +02:00
:command content
2023-02-26 14:04:44 +01:00
:sentinel #'pip--upgrade-maybe-sentinel)
2024-06-13 08:12:02 +02:00
(message "Running `%s' asynchronously" (string-join content " ")))
2023-02-26 14:04:44 +01:00
(message "`pip-upgrade-maybe' found no packages to install"))))
#+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=
2024-06-12 10:58:48 +02:00
representation of src_emacs-lisp[:results none]{(describe-variable
2024-06-06 19:09:24 +02:00
'eglot-workspace-configuration)} 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
2024-01-25 10:37:09 +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
2024-06-06 16:09:37 +02:00
;; Enable the `:pylsp_ruff' plugin and ensure to uninstall 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)
: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
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :eval never :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.
2024-06-06 16:09:37 +02:00
;; Ensure to enable the pylsp_ruff plugin.
;; Ensure to uninstall the flake8, mccabe, and pycodestyle Python packages.
2022-11-07 11:50:17 +01:00
((nil ;; nil, since Emacs-29.1 filters out irrelevant variable names.
. ((eglot-workspace-configuration
. (:pylsp (:plugins
2022-12-24 16:36:10 +01:00
(:pylsp_ruff
2022-11-07 11:50:17 +01:00
(:enabled t)
: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-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
2024-06-04 13:52:27 +02:00
*** [[https://github.com/astoff/code-cells.el#readme][Code-cells]] :noexport:
2022-02-23 07:43:57 +01:00
:PROPERTIES:
2022-03-26 15:11:32 +01:00
:CUSTOM_ID: sec:code-cells
2024-06-17 13:48:16 +02:00
:header-args:emacs-lisp: :tangle no
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
2024-06-17 13:48:16 +02: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
2024-06-01 12:49:53 +02:00
*** [[https://stackoverflow.com/questions/2324758/debugging-python-programs-in-emacs][Debugging Python programs in Emacs]]
:PROPERTIES:
:CUSTOM_ID: sec:debug-python
:END:
2024-06-12 15:27:10 +02:00
[[https://github.com/realgud/realgud ][RealGUD ]] is the best option and in case of defaulting to {{{kbd(M-x pdb)}}}
debugging may work better with =tool-bar-mode= enabled. Listing
[[lst:ensure-realgud ]] ensures the installation of =realgud= . Listing [[lst:pdb-numpy ]]
is a debugging start by means of =pdb= or =realgud:pdb= . Links of interest are:
2024-06-11 18:50:35 +02:00
- [[https://github.com/realgud/realgud ][RealGUD ]] provides a nice interface to PDB by means of {{{kbd(M-x
2024-06-12 13:09:22 +02:00
realgud:pdb)}}} that also works well with =tool-bar-mode= disabled.
- [[https://realpython.com/python-debugging-pdb/ ][Python Debugging with PDB ]]
2024-06-01 12:49:53 +02:00
- [[https://docs.python.org/3/library/pdb.html ][The Python Debugger ]]
- [[yt:vfPtGsSJldg ][Introduction to PDB (Python-2.7 YouTube video) ]]
2024-06-01 15:32:03 +02:00
- [[https://stackoverflow.com/questions/7668979/how-do-you-watch-a-variable-in-pdb ][How do you watch a variable in PDB? (Python-2.7) ]]
- [[https://stackoverflow.com/questions/51349074/in-python-3-7-does-the-opcode-event-from-sys-settrace-give-any-information-ab ][How to use the opcode event (Python-3.7, GAV: why does it fail)? ]]
2024-06-06 12:40:34 +02:00
- [[https://pypi.org/project/pdbpp/ ][PDB++ ]] looks incompatible with Python>3.10: see [[https://github.com/pdbpp/pdbpp/issues/516 ][Python-3.11 breaks PDBPP ]].
- [[https://python-scientific-lecture-notes.developpez.com/tutoriel/notes-cours/python-debugging-code/#L3-1 ][Debugging Python with IPDB under IPython or with PDB in a terminal ]].
2024-06-07 11:37:01 +02:00
- [[https://docs.spyder-ide.org/current/panes/debugging.html ][Spyder Python debugging using IPDB ]].
2024-06-06 16:09:37 +02:00
- [[https://docs.python.org/3/howto/gdb_helpers.html ][Debugging C API extensions and CPython Internals with GDB ]]. Making this work
with =pyenv= is an unresolved issue: see [[https://github.com/pyenv/pyenv/issues/1190 ][Install python-gdb.py ]].
2024-06-07 11:37:01 +02:00
Python info links of interest are:
- [[info:python#Debugging C API extensions and CPython Internals with GDB ][Debugging C API extensions and CPython Internals with GDB (info) ]].
2024-06-12 15:27:10 +02:00
- [[info:python#Debugging and Profiling ][Debugging and Profiling (info) ]].
2024-06-01 12:49:53 +02:00
2024-06-12 15:27:10 +02:00
#+caption[Ensure =realgud= installation]:
#+caption : Ensure =realgud= installation.
#+name : lst:ensure-realgud
#+begin_src emacs-lisp -n :results silent
(ensure-package-installation 'realgud)
2024-06-01 12:49:53 +02:00
#+end_src
2024-06-06 12:40:34 +02:00
#+caption[PDB NumPy example: =python -m pdb .emacs.d/nuggy.py= ]:
#+caption : PDB NumPy example: =python -m pdb .emacs.d/nuggy.py=.
#+name : lst:pdb-numpy
#+begin_src python -i -n :results silent
def buggy():
from numpy import array, matrix
from numpy.linalg import inv
a = matrix(array([[1.0, 1.0], [1.0, 1.0]]))
# Use "display", "p", or "pp" to inspect "a".
2024-06-12 15:27:10 +02:00
# PDB: A series of "s" does not raise the exception here, contrary to "c".
2024-06-06 12:40:34 +02:00
b = inv(a)
return b
if __name__ == "__main__":
b = buggy()
2024-06-12 15:27:10 +02:00
# PDB: The series of "s" says only here "Uncaught exception".
2024-06-06 12:40:34 +02:00
#+end_src
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
2024-01-26 10:01:12 +01:00
processing API of [[info:cl#Top ][cl ]]. It is a requirement of important packages in this 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
2024-01-25 10:37:09 +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:
2024-06-06 16:09:37 +02:00
2022-01-21 06:56:03 +01:00
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
2024-01-25 10:37:09 +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
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2024-06-12 16:54:43 +02:00
(when (ensure-package-installation 'ws-butler)
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:
2023-07-21 13:54:53 +02:00
1. The [[https://gist.github.com/pvik/8eb5755cc34da0226e3fc23a320a3c95 ][smartparens cheatsheet ]] demonstrates its usage visually.
2. [[https://gist.github.com/oantolin ][Omar Antolin's gist "my-smartparens-config.el" ]] is the first place to look for
2021-12-16 09:00:35 +01:00
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 ]].
2023-07-21 13:54:53 +02:00
3. [[https://lists.gnu.org/archive/html/help-gnu-emacs/2014-07/msg00135.html ][How to enable smartparens in the minibuffer after eval-expression ]] explains
2021-12-16 09:00:35 +01:00
how the machinery after the first and after later usages of =eval-expression=
differ and discusses options how to handle those differences.
2024-06-14 21:06:13 +02:00
Listing [[lst:setup-smartparens ]] aims to setup [[https://github.com/Fuco1/smartparens ][smartparens ]] for Go, LaTeX, Lisp
dialects, Org, and Python. Execute src_emacs-lisp[:results
2024-06-12 10:58:48 +02:00
none]{(sp-cheat-sheet)} for short documentation taking into account the
2024-06-14 21:06:13 +02:00
overridden key bindings in listing [[lst:setup-smartparens ]]. Table
2024-01-25 10:37:09 +01:00
[[tab:smartparens-commands-and-bindings ]] lists commands with key bindings taken in
2024-06-12 10:58:48 +02:00
order from src_emacs-lisp[:results none]{(sp-cheat-sheet)} that takes the
2024-06-14 21:06:13 +02:00
overrides of listing [[lst:setup-smartparens ]] into account. Finally, listing
[[lst:sp-eval-expression ]] defines an alternative to =eval-expression= enabling
=smartparens-strict-mode= and =font-lock-mode= .
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
2023-12-31 11:43:48 +01:00
formats and languages almost (exceptions are due to ~Search failed~ errors
inside source blocks) 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 ]].
2022-02-23 07:44:29 +01:00
2024-06-14 21:06:13 +02:00
#+caption[Setup =smartparens= ]:
#+caption : Setup =smartparens=.
#+name : lst:setup-smartparens
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2024-06-14 21:06:13 +02:00
(when (ensure-package-installation 'smartparens)
;; GAV: Documentation says to require `smartparens-config'.
(require 'smartparens-config)
2023-01-12 21:28:18 +01:00
(setopt sp-base-key-bindings 'sp
2023-12-31 11:43:48 +01:00
sp-override-key-bindings '(("C-(" . sp-backward-slurp-sexp)
2023-07-21 13:54:53 +02:00
("C-)" . sp-forward-slurp-sexp)
("C-M-(" . sp-backward-barf-sexp)
2023-12-31 11:43:48 +01:00
("C-M-)" . sp-forward-barf-sexp)))
2021-11-29 13:14:56 +01:00
2024-06-14 21:06:13 +02:00
(add-hook 'conf-toml-mode-hook #'smartparens-mode)
(add-hook 'prog-mode-hook #'smartparens-mode)
(add-hook 'text-mode-hook #'smartparens-mode)
(add-hook 'emacs-lisp-mode-hook #'smartparens-strict-mode)
(add-hook 'go-ts-mode-hook #'smartparens-strict-mode)
(add-hook 'ielm-mode-hook #'smartparens-strict-mode)
(add-hook 'inferior-python-mode-hook #'smartparens-strict-mode)
(add-hook 'lisp-data-mode-hook #'smartparens-strict-mode)
(add-hook 'lisp-mode-hook #'smartparens-strict-mode)
(add-hook 'python-mode-hook #'smartparens-strict-mode)
(add-hook 'sly-mrepl-mode-hook #'smartparens-strict-mode)
2021-11-29 13:14:56 +01:00
2023-04-26 10:20:10 +02:00
(when (fboundp 'go-ts-mode)
;; Stolen from `smartparens-go':
(sp-with-modes 'go-ts-mode
(sp-local-pair "{" nil :post-handlers '(("||\n[i]" "RET")))
(sp-local-pair "/*" "*/ " :post-handlers '(("| " "SPC")
("* ||\n[i]" "RET"))))
;; Go has no sexp suffices. This fixes slurping:
;; (|foo).bar -> (foo.bar)
2024-02-12 09:45:17 +01:00
(add-to-list 'sp-sexp-suffix (list #'go-ts-mode 'regexp "")))
2023-04-26 10:20:10 +02: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
2023-12-31 14:10:43 +01:00
#+attr_latex : :booktabs yes :float table
#+caption[Smartparens commands with key bindings in this setup]:
#+caption : Smartparens commands with key bindings in this setup.
#+name : tab:smartparens-commands-and-bindings
|--------------------------------+----------------------------+----------|
| command | keys | status |
|--------------------------------+----------------------------+----------|
| sp-forward-sexp | {{{kbd(C-M-f)}}} | |
| sp-backward-sexp | {{{kbd(C-M-b)}}} | |
| sp-next-sexp | {{{kbd(C-M-n)}}} | |
| sp-prev-sexp | {{{kbd(C-M-p)}}} | |
| sp-down-sexp | {{{kbd(C-M-d)}}} | shadowed |
| sp-backward-down-sexp | {{{kbd(C-M-a)}}} | |
| sp-beginning-of-sexp | {{{kbd(C-S-d)}}} | |
| sp-end-of-sexp | {{{kbd(C-S-a)}}} | |
| sp-up-sexp | {{{kbd(C-M-e)}}} | |
| sp-backward-up-sexp | {{{kbd(C-M-u)}}} | |
| sp-kill-sexp | {{{kbd(C-M-k)}}} | |
| sp-copy-sexp | {{{kbd(C-M-w)}}} | |
| sp-forward-slurp-sexp | {{{kbd(C-))}}} | override |
| sp-backward-slurp-sexp | {{{kbd(C-()}}} | override |
| sp-forward-barf-sexp | {{{kbd(C-M-))}}} | override |
| sp-backward-barf-sexp | {{{kbd(C-M-()}}} | override |
| sp-forward-symbol | {{{kbd(M-F)}}} | |
| sp-backward-symbol | {{{kbd(M-B)}}} | |
| sp-unwrap-sexp | {{{kbd(M-<delete>)}}} | shadowed |
| sp-backward-unwrap-sexp | {{{kbd(M-<backspace>)}}} | |
| sp-splice-sexp | {{{kbd(M-D)}}} | |
| sp-splice-killing-backward | {{{kbd(C-M-<backspace>)}}} | |
| sp-splice-sexp-killing-forward | {{{kbd(C-M-<delete>)}}} | shadowed |
| sp-select-next-thing | {{{kbd(C-M-])}}} | |
| sp-select-next-thing-exchange | {{{kbd(C-])}}} | |
| sp-mark-sexp | {{{kbd(C-M-SPC)}}} | |
|--------------------------------+----------------------------+----------|
2024-06-14 21:06:13 +02:00
#+caption[Define =sp-eval-expression= with =smartparens= support]:
#+caption : Define =sp-eval-expression= enabling =smartparens-strict-mode=
#+caption : and =font-lock-mode=.
#+name : lst:sp-eval-expression
#+begin_src emacs-lisp -n :results silent
(with-eval-after-load 'smartparens
;; https://lists.gnu.org/archive/html/help-gnu-emacs/2014-07/msg00135.html
;; GAV: Reuse `read--expresssion-map' instead of defining my own map.
(defun sp--read-expression (prompt &optional initial-contents)
(let ((minibuffer-completing-symbol t))
(minibuffer-with-setup-hook
(lambda ()
(emacs-lisp-mode) ; Enables `smartparens-strict-mode' too.
(use-local-map read--expression-map)
(font-lock-mode t))
(read-from-minibuffer prompt initial-contents
read--expression-map nil
'read-expression-history))))
(defun sp-eval-expression (expression &optional arg)
"Evaluate EXPRESSION with `smartparens' support."
(interactive (list (read (sp--read-expression "SP eval: "))
current-prefix-arg))
(if arg
(insert (pp-to-string (eval expression lexical-binding)))
(pp-display-expression (eval expression lexical-binding)
2024-06-16 11:13:37 +02:00
"*SP Eval Output* ")))
;; Do not change the "M-ESC :" `eval-expression' key binding.
(keymap-global-set "M-:" #'sp-eval-expression))
2024-06-14 21:06:13 +02:00
#+end_src
2023-12-31 14:10:43 +01:00
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
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2024-06-15 15:32:39 +02:00
(when (ensure-package-installation 'electric-operator)
(add-hook 'c-mode-common-hook #'electric-operator-mode)
(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
2024-06-14 21:02:31 +02:00
#+caption[Setup =yasnippet= ]:
#+caption : Setup =yasnippet=.
#+name : lst:setup-yasnippet
2024-01-25 10:37:09 +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)
2024-06-14 21:02:31 +02:00
(add-hook 'LaTeX-mode-hook #'yas-minor-mode)
(add-hook 'org-mode-hook #'yas-minor-mode)
(add-hook 'python-mode-hook #'yas-minor-mode))
2021-11-29 13:14:56 +01: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
2024-01-25 10:37:09 +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)
2024-01-26 10:01:12 +01:00
"Widen a narrowed buffer, narrow \"Do What I Mean\" otherwise.
2022-11-07 11:50:17 +01:00
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."
2024-04-18 17:03:25 +02:00
(declare (interactive-only t))
2022-11-07 11:50:17 +01:00
(interactive "P")
(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
2024-06-12 16:35:43 +02:00
Listing [[lst:setup-rainbow-mode ]] configures =rainbow-mode= to colorize color codes
2021-12-29 14:05:03 +01:00
and names in buffers for debugging.
2021-12-13 12:41:06 +01:00
2024-06-12 16:35:43 +02:00
#+caption[Setup =rainbow-mode= ]:
#+caption : Setup =rainbow-mode=.
#+name : lst:setup-rainbow-mode
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2024-06-12 16:35:43 +02:00
(when (ensure-package-installation 'rainbow-mode)
2024-06-14 21:04:11 +02:00
;; GAV: Do not add `rainbow-mode' to any programming language hook,
;; since that interferes at least with Org export to LaTeX.
2024-06-12 16:35:43 +02:00
(setopt rainbow-x-colors-major-mode-list
(list 'c++-mode 'c-mode 'emacs-lisp-mode 'inferior-emacs-lisp-mode
2024-06-14 21:04:11 +02:00
'lisp-interaction-mode 'org-mode 'python-mode)))
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
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2024-06-12 16:43:12 +02:00
;; https://karthinks.com/software/batteries-included-with-emacs/
;; https://github.com/karthink/ .emacs.d/blob/master/init.el#L2077
2024-06-14 14:26:34 +02:00
;; BUG#71537: Using `let' in `flash-line-around-point' implies
;; requiring `pulse'.
(require 'pulse)
2024-06-12 16:43:12 +02:00
(defun flash-line-around-point (&rest _)
"Flash the line around point."
2024-06-14 14:26:34 +02:00
(let ((pulse-iterations 16)
(pulse-delay 0.1))
(pulse-momentary-highlight-one-line (point))))
2024-06-12 16:43:12 +02:00
2024-06-14 21:02:31 +02:00
(advice-add 'scroll-up-command :after #'flash-line-around-point)
(advice-add 'scroll-down-command :after #'flash-line-around-point)
(advice-add 'recenter-top-bottom :after #'flash-line-around-point)
(advice-add 'other-window :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
2024-01-25 10:37:09 +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:
2024-06-17 12:26:23 +02:00
#+caption[Display =pdf= links properly in =eww= ]:
#+caption : Display =pdf= links properly in =eww=.
#+name : lst:display-pdf-links-in-eww
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2022-11-07 11:50:17 +01:00
(with-eval-after-load 'eww
2024-06-17 12:26:23 +02:00
;; GAV: Renaming `eww' buffers conflicts with `desktop-save-mode'.
;; GAV: Setting `eww-restore-desktop' to something else fails too.
(setopt eww-restore-desktop nil)
2022-11-07 11:50:17 +01:00
(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
(advice-add 'eww-display-pdf :around #'eww-display-pdf-as-binary))
2022-03-21 07:52:06 +01:00
#+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-03-19 20:40:21 +01:00
*** [[https://github.com/minad/osm#readme][Open Street Map viewer for Emacs]]
:PROPERTIES:
:CUSTOM_ID: sec:open-street-map
:END:
2023-11-20 10:29:17 +01:00
[[https://github.com/minad/osm#readme ][Open Street Map ]] is a tile-based map viewer with a responsive movable and
zoomable display and with a list of multiple preconfigured tile servers.
2023-12-24 11:38:18 +01:00
Listing [[lst:ensure-osm-installation ]] ensures the installation of ~osm~ and
listing [[lst:using-osm-example ]] is a minimal example of how to use ~osm~ . Inside
2024-02-12 09:44:40 +01:00
~osm-mode~ buffers, the key binding for the command
src_emacs-lisp{(osm-bookmark-set)} is {{{kbd(C-x r b)}}} allowing to bookmark
such buffers. Outside ~osm-mode~ buffers, the key binding for the command
src_emacs-lisp{(call-interactively 'consult-bookmark)} is {{{kbd(C-x r b)}}} .
2023-11-20 10:29:17 +01:00
2023-12-24 11:38:18 +01:00
#+caption[Ensure "osm" installation]:
#+caption : Ensure ~osm~ installation.
#+name : lst:ensure-osm-installation
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2023-11-20 10:29:17 +01:00
(ensure-package-installation 'osm)
2023-03-19 20:40:21 +01:00
#+end_src
2023-12-24 11:38:18 +01:00
#+caption[Using "osm" example]:
#+caption : Using ~osm~ example.
#+name : lst:using-osm-example
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent :tangle no
2023-12-24 11:38:18 +01:00
(osm "Tower of London")
#+end_src
2024-03-27 14:17:43 +01:00
*** [[info:url#Top][URL (info)]] :noexport:
:PROPERTIES:
:CUSTOM_ID: sec:url
2024-06-17 13:48:16 +02:00
:header-args:emacs-lisp: :tangle no
2024-03-27 14:17:43 +01:00
:END:
[[https://lists.gnu.org/archive/html/emacs-devel/2024-03/msg00670.html ][How to retrieve only URL metadata ]]
#+caption[Make an URL HEAD request]:
#+caption : Make an URL HEAD request.
#+name : lst:url-head-request
#+header : :wrap "src text -n :eval no"
2024-06-17 13:48:16 +02:00
#+begin_src emacs-lisp -n :eval never-export :exports both
2024-03-27 14:17:43 +01:00
(with-current-buffer
(let ((url-request-method "HEAD"))
(url-retrieve-synchronously "https://www.gnu.org/ "))
(buffer-string))
#+end_src
#+caption[URL HEAD request result]:
#+caption : URL HEAD request result.
#+name : lst:url-head-request-result
#+RESULTS : lst:url-head-request
#+begin_src text -n :eval no
HTTP/1.1 200 OK
Date: Wed, 27 Mar 2024 07:40:07 GMT
Server: Apache/2.4.29
Content-Location: home.html
Vary: negotiate,accept-language,Accept-Encoding
TCN: choice
Strict-Transport-Security: max-age=63072000
X-Frame-Options: sameorigin
X-Content-Type-Options: nosniff
Access-Control-Allow-Origin: (null)
Accept-Ranges: bytes
Cache-Control: max-age=0
Expires: Wed, 27 Mar 2024 07:40:07 GMT
Content-Length: 9803
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html
Content-Language: en
#+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
2024-01-25 10:37:09 +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")
("Worg - Org Mode Community" . "orgmode.org/worg")
("Git: Emacs" . "git.savannah.gnu.org/cgit/emacs.git")
2023-02-08 08:07:27 +01:00
("Git: Emacs MultiMedia System" .
"https://git.savannah.gnu.org/cgit/emms.git")
2023-07-20 12:30:15 +02:00
("Git: GNU AUCTeX" . "git.savannah.gnu.org/cgit/auctex.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/ ")
("Counterpunch" . "www.counterpunch.org")
("Dictionary FR" . [simple-query "www.cnrtl.fr"
"www.cnrtl.fr/definition/ " ""])
("Dictionary NL" . [simple-query "www.woorden.org"
2024-02-09 10:22:02 +01:00
"www.woorden.org/woord/ " ""])))))
2022-03-21 07:52:06 +01:00
#+end_src
2024-03-06 14:49:48 +01:00
** [[info:gnus#Top][Reading News and Mail (info)]] :noexport:
2022-09-04 18:57:53 +02:00
:PROPERTIES:
:CUSTOM_ID: sec:reading-news-mail
2024-03-06 14:49:48 +01:00
:header-args:emacs-lisp: :tangle no
2022-09-04 18:57:53 +02:00
:END:
2023-06-25 14:00:01 +02:00
Reading news and mail:
2022-09-04 18:57:53 +02:00
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 ]]
2023-06-25 14:00:01 +02:00
Password management:
2022-11-13 14:26:06 +01:00
1. [[https://www.passwordstore.org/ ][Pass: the standard unix password manager ]]
2023-06-25 14:00:01 +02:00
2. [[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 ]]
3. [[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
2024-01-25 10:37:09 +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
2024-03-06 14:49:48 +01:00
** [[info:emacs#Sending Mail][Sending Mail (info)]] :noexport:
2022-07-08 10:01:57 +02:00
:PROPERTIES:
:CUSTOM_ID: sec:sending-mail
2024-03-06 14:49:48 +01:00
:header-args:emacs-lisp: :tangle no
2022-07-08 10:01:57 +02:00
: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
2024-01-25 10:37:09 +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
2024-01-25 10:37:09 +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
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
2024-01-25 10:37:09 +01:00
#+begin_src emacs-lisp -n :results silent
2024-06-10 11:56:51 +02:00
(when (ensure-package-installation '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
2024-06-16 15:11:55 +02:00
(setopt elfeed-feeds
'(("https://frame.work/fr/fr/blog.rss" framework)
("https://nullprogram.com/feed/ " c-wellons)
("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://updates.orgmode.org/feed/updates" org-updates)
("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-07-28 11:41:17 +02:00
using ~emms~ with ~elfeed~ . Listing [[lst:set-emms-options ]] configures ~emms~
for ~mpv~ while eliminating use of ~mpd~ .
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
2024-01-25 10:37:09 +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
2024-06-16 14:05:31 +02:00
(emms-all) ;; Restrict now to `emms-player-mpd' use only.
2023-05-07 16:41:58 +02:00
(setopt emms-player-list '(emms-player-mpv)))
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-11-07 11:50:17 +01:00
(with-eval-after-load 'emms-player-mpv
2024-06-16 14:05:31 +02:00
(setopt emms-player-mpv-update-metadata t
emms-player-mpv-parameters
(append emms-player-mpv-parameters
'("--ytdl-format=best" "--config=no" "--fullscreen"))))
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-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
* [[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
2024-01-25 10:37:09 +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
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:
2024-06-14 11:06:46 +02:00
# bug-reference-mode: t
2021-11-29 13:14:56 +01:00
# compile-command: "latexmk -interaction=nonstopmode -lualatex -pvc -shell-escape README.tex"
# fill-column: 80
2024-01-31 20:44:50 +01:00
# org-edit-src-content-indentation: 0
2024-02-11 11:53:49 +01:00
# org-latex-src-block-backend: engraved
2024-01-31 20:44:50 +01:00
# eval: (org-eval-emacs-lisp-setup-blocks)
2021-11-29 13:14:56 +01:00
# End: