emacs.d/README.org

4497 lines
192 KiB
Org Mode
Raw Normal View History

2021-11-29 13:14:56 +01:00
#+title: Emacs setup for use with LaTeX, Org, and Python
#+author: Gerard Vermeulen
#+latex_class: article-local
#+latex_class_options: [11pt,a4paper,english,svgnames,tables]
#+macro: kbd (eval (by-backend-kbd-org-macro $1))
#+property: header-args:emacs-lisp :exports code :results silent :tangle init.el
#+property: header-args:org :tangle include.org
#+startup: showeverything
#+include: "include.org"
2021-11-29 13:14:56 +01:00
* Quick start
:PROPERTIES:
:CUSTOM_ID: sec:quick-start
:END:
Backup your =user-emacs-directory= (defaults often to =~/.emacs.d= on =Linux=,
=Unix=, or =Darwin=) directory and execute the commands in listing
2022-01-09 15:39:14 +01:00
[[lst:prepare-user-emacs-directory]]. After invoking Emacs interactively (in
interactive mode, neither in batch mode, nor in server mode), Emacs will ask you
to install a selected set of packages. Quit Emacs and invoke Emacs again.
#+caption[Prepare the user-emacs-directory]:
#+caption: Clone and initialize the user-emacs-directory.
2021-12-28 08:48:03 +01:00
#+name: lst:prepare-user-emacs-directory
#+begin_src shell :noeval :tangle no
cd ~
git clone ccdr@mercury.grenoble.cnrs.fr:SERVER/emacs.d.git .emacs.d
make --directory=.emacs.d init
emacs &
#+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)
illustrates three methods in my work-flow:
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=,
=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.
The [[https://github.com/bdarcus/citar][citar]] extension package provides quick filtering and selecting of
bibliographic entries, and the option to run different commands on those
selections. [[https://github.com/bdarcus/citar][Citar]] requires [[info:org#Top][Org-9.5 (info)]], which is already part of Emacs-28.1.
[[https://github.com/bdarcus/citar][Citar]] exploits the enhancements of Emacs' builtin selection mechanism provided
by the extension packages [[https://github.com/minad/vertico][vertico]], [[https://github.com/oantolin/orderless][orderless]], [[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]]. [[https://github.com/citation-style-language/styles#readme][Citation style language: style repository]]
links to a curated repository of CSL styles.
2021-11-29 13:14:56 +01:00
The [[https://github.com/vedang/pdf-tools][pdf-tools]] extension package renders [[https://en.wikipedia.org/wiki/PDF][PDF]] file with the possibility to
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
2021-11-29 13:14:56 +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:
execute the commands ~pdf-tools-install~, ~org-babel-tangle~,
~org-latex-export-latex-to-latex~, and ~compile~. This sets up an infinite
[[https://www.latex-project.org/][LaTeX]] compilation loop to update and redisplay the [[https://en.wikipedia.org/wiki/PDF][PDF]] file after excution of
the ~org-latex-export-latex-to-latex~ command in this buffer.
Here follows a list of interesting Emacs configurations:
2021-12-05 16:25:38 +01:00
1. [[https://github.com/alhassy/emacs.d][Musa Al-hassy's configuration]] is an impressive example of producing the Emacs
initialization files and other files by tangling an [[info:org#Top][org]] file. His methodology
is impressive, as his [[https://alhassy.github.io/ElispCheatSheet/][Elisp Cheat Sheet]] and [[https://alhassy.github.io/org-special-block-extras/][org-special-block-extra package]]
show. To me, this is a configuration to admire, but his methodology is way
over my head.
2022-03-26 15:35:35 +01:00
2. [[https://github.com/oantolin/emacs-config][Omar Antolin Camarena's configuration]] exploits built-in packages, Omar's own
2021-12-05 16:25:38 +01:00
small packages, and large external packages. Omar is the author of [[https://github.com/oantolin/orderless][orderless]]
and [[https://github.com/oantolin/embark][embark]]. I have stolen his idea of using ~custom-set-variables~ instead
of the customize interface although that is [[https://www.masteringemacs.org/article/bad-emacs-advice][bad Emacs advice]] for new users.
2021-12-05 16:25:38 +01:00
3. [[https://gitlab.com/ambrevar/dotfiles][Pierre Neirhardt's configuration]] implements lazy loading without help of
2021-11-29 13:14:56 +01:00
external packages. I have stolen his approach of using lazy loading to
silently ignore the setup stanzas of uninstalled extension packages.
2021-12-05 16:25:38 +01:00
4. [[https://sachachua.com/dotemacs/][Sacha Chua's configuration]] is a practical example of producing the Emacs
2021-11-29 13:14:56 +01:00
initialization files by tangling an [[info:org#Top][org]] file. It gives me the impression
that she is a very practical person trying to achieve her goals by the most
2022-06-30 18:07:06 +02:00
efficient means.
2021-12-07 05:39:02 +01:00
5. [[https://github.com/purcell/emacs.d][Steve Purcell's configuration]] is well organized, a showcase of readable code,
as well helpful commit and issue histories. See for instance the discussion
on [[https://github.com/purcell/emacs.d/issues/778][the correctness of order of company candidates in Emacs lisp mode]].
2021-11-29 13:14:56 +01:00
Here follows a list of links on how to use Emacs and Elisp:
2022-03-23 08:01:02 +01:00
1. [[https://www.youtube.com/watch?v=lkIicfzPBys][A guided tour of Emacs]] is a link to a video tour pointing how [[info:emacs#Buffers][buffers (info)]],
[[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.
2. [[https://www.youtube.com/watch?v=6ZWp05OW1c0][Emergency Emacs]] is a link to a video on fundamental editing features and
principles with focus on [[info:ediff#Top][ediff (info)]], [[info:emacs#Undo][undo (info)]], [[info:emacs#Moving Point][moving point (info)]],
[[info:emacs#Erasing][erasing (info)]], and [[info:emacs#Dynamic Abbrevs][dynamic abbreviations (info)]].
2. [[https://endlessparentheses.com/][Endless Parentheses]] is a blog with many mindblowing code snippets.
3. [[https://protesilaos.com/codelog/2022-01-31-learning-emacs/][Learning Emacs and Elisp]] is a link to a video tutorial with a transcript on
the best approach to learn Emacs and Elisp.
4. [[https://www.masteringemacs.org/][Mastering Emacs]] is a link to a blog with many interesting posts that promotes
a book on how to become a proficient Emacs user.
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.
#+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
2021-11-29 13:14:56 +01:00
#+begin_src emacs-lisp :tangle early-init.el
;;; early-init.el --- user early-init file -*- lexical-binding: t -*-
;;; Commentary:
;;; Code:
(setq load-prefer-newer t)
(require 'no-littering nil 'noerror)
2021-11-29 13:14:56 +01:00
(provide 'early-init)
;; Emacs looks for "Local variables:" after the last "?\n?\f".
2021-11-29 13:14:56 +01:00
;; Local Variables:
;; indent-tabs-mode: nil
;; End:
;;; earl-init.el ends here
#+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:
1. src_emacs-lisp{(describe-variable #'load-prefer-newer t)}
2. src_emacs-lisp{(apropos-library "no-littering")}
3. src_emacs-lisp{(find-function #'hack-local-variables)}
2022-01-07 16:33:40 +01:00
to execute the code between the curly braces for access to help. This shows
that *Emacs is a self-documenting editor.*
2021-12-07 05:39:02 +01:00
2021-11-29 13:14:56 +01:00
* [[info:emacs#Init File][Init File (info)]] header
:PROPERTIES:
:CUSTOM_ID: sec:init-file-header
:END:
The =user-init-file= header requires =cl-lib= and customizes Emacs variables.
It consists of four parts in listing [[lst:1st-custom-set-variables-call]],
[[lst:2nd-custom-set-variables-call]], [[lst:3rd-custom-set-variables-call]], and
[[lst:4th-custom-set-variables-call]] in order to limit the length of the listings
for exporting to LaTeX.
The [[info:elisp#Quoting][quoting (info)]] and the [[info:elisp#Backquote][backquote (info)]] pages explain how to understand the
~'~ (quote), ~`~ (backquote), ~,~ (substitute) and ~@,~ (splice) in the
~custom-set-variables~ function calls in listing
[[lst:1st-custom-set-variables-call]], [[lst:2nd-custom-set-variables-call]],
[[lst:3rd-custom-set-variables-call]], and [[lst:4th-custom-set-variables-call]]. A
tutorial of how to use those reader macros is the [[https://mullikine.github.io/posts/macro-tutorial/][didactic emacs-lisp macro
example]].
The [[info:emacs#Init File][init file (info)]] does not load the ~custom-file~ as [[info:emacs#Saving Customizations][saving customizations
(info)]] recommends because of the ~custom-set-variables~ function calls.
#+caption[Customize the first set of Emacs variables]:
#+caption: Customize the first set of Emacs variables.
2021-12-28 08:48:03 +01:00
#+name: lst:1st-custom-set-variables-call
2021-11-29 13:14:56 +01:00
#+begin_src emacs-lisp
;;; init.el --- user init file -*- lexical-binding: t -*-
;;; Commentary:
;;; Code:
(require 'cl-lib)
(custom-set-variables
'(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"))
2021-11-29 13:14:56 +01:00
'(epg-pinentry-mode 'loopback)
'(global-hl-line-mode t)
'(global-hl-line-sticky-flag t)
'(history-delete-duplicates t)
'(history-length 500)
2021-11-29 13:14:56 +01:00
'(indent-tabs-mode nil)
'(inhibit-startup-buffer-menu t)
'(inhibit-startup-screen t)
'(initial-buffer-choice t)
'(initial-scratch-message "")
`(insert-directory-program ,(or (executable-find "gls")
(executable-find "ls")))
'(kill-ring-max 300))
#+end_src
#+caption[Customize the second set of Emacs variables]:
#+caption: Customize the second set of Emacs variables.
2021-12-28 08:48:03 +01:00
#+name: lst:2nd-custom-set-variables-call
#+begin_src emacs-lisp
(custom-set-variables
'(package-archives '(("gnu" . "https://elpa.gnu.org/packages/")
("gnu-devel" . "https://elpa.gnu.org/devel/")
("melpa" . "https://melpa.org/packages/")
("nongnu" . "https://elpa.nongnu.org/nongnu/")))
;; Pin packages to GNU ELPA for info or stability.
'(package-pinned-packages '((auctex . "gnu")
(compat . "gnu")
(consult . "gnu")
2022-05-22 15:15:51 +02:00
(engrave-faces . "gnu")
(marginalia . "gnu")
(org . "gnu-devel")
(python . "gnu-devel")
(queue . "gnu")
(rainbow-mode . "gnu")
(spinner . "gnu")
(xr . "gnu")
(vertico . "gnu"))))
#+end_src
#+caption[Customize the third set of Emacs variables]:
#+caption: Customize the third set of Emacs variables.
#+name: lst:3rd-custom-set-variables-call
#+begin_src emacs-lisp
(custom-set-variables
'(package-selected-packages
'(async ; asynchroneous processing
auctex ; Aalborg University Center TeX
company ; complete anything
magit ; Git Text-based User Interface
no-littering ; keep `user-emacs-directory' clean
orderless ; Emacs completion style
org ; thought organizer
python ; major mode to edit Python files
vertico ; VERTical Interactive Completion
wgrep ; open a writable grep buffer
2022-05-21 17:27:31 +02:00
xr))) ; undo rx to grok regular expressions
#+end_src
#+caption[Customize the fourth set of Emacs variables]:
#+caption: Customize the fourth set of Emacs variables.
#+name: lst:4th-custom-set-variables-call
#+begin_src emacs-lisp
(custom-set-variables
2021-11-29 13:14:56 +01:00
'(recentf-mode t)
'(save-place-mode t)
'(scroll-bar-mode nil)
'(tab-always-indent 'complete)
'(tab-width 8)
'(tool-bar-mode nil)
'(url-cookie-trusted-urls nil)
'(url-cookie-untrusted-urls '(".*"))
'(use-dialog-box nil)
'(view-read-only t))
2022-04-09 16:13:10 +02:00
(when (version< "28.0" emacs-version)
(custom-set-variables
'(mode-line-compact 'long)
'(next-error-message-highlight t)
'(use-short-answers t)))
2021-11-29 13:14:56 +01:00
(when (eq system-type 'darwin)
(custom-set-variables
'(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)))
#+end_src
* [[info:emacs#Package Installation][Install the selected packages (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:install-selected-packages
:END:
[[info:emacs#Package Installation][Emacs installs packages]] from archives on the internet. This setup uses three
archives:
1. The [[https://elpa.gnu.org/][GNU Emacs Lisp Package Archive]]
2. The [[https://elpa.nongnu.org/][NonGNU Emacs Lisp Package Archive]].
3. The [[https://melpa.org/#/][Milkypostman's Emacs Lisp Package Archive (MELPA)]].
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:
1. It installs and loads [[https://github.com/emacscollective/no-littering][no-littering]] after ensuring refreshing of the
contents of available packages.
2. It installs [[https://elpa.gnu.org/devel/org.html][Org (GNU-devel ELPA archive)]] early to shadow the built-in package
while preventing collisions between the snapshot and built-in packages.
2022-06-30 18:07:06 +02:00
3. It calls src_emacs-lisp{(package-install-selected-packages)} to check the
installation status of all packages in
src_emacs-lisp{package-selected-packages} and to install the missing packages
after the user has agreed to its prompt.
2022-06-30 18:07:06 +02:00
4. It defines a function to ensure the installation of packages in other source
blocks. This allows skipping installation in sections with a =:noexport:=
tag by disallowing tangling.
In case of normal Emacs usage, src_emacs-lisp{(package-list-packages)} refreshes
the contents of packages and allows to update packages to the latest version.
#+caption[Install the selected packages]:
#+caption: Install the selected packages.
#+name: lst:install-selected-packages
#+begin_src emacs-lisp
(unless noninteractive
(unless (require 'no-littering nil 'noerror)
(unless (bound-and-true-p package-archive-contents)
(package-refresh-contents))
;; Install and require `no-littering'.
(package-install 'no-littering)
(require 'no-littering)
;; https://emacs.stackexchange.com/a/45939 answers
2022-05-21 14:23:38 +02:00
;; "How to shadow automatically a built-in package by installing it?"
(defun shadow-builtin-by-install (pkg)
(when-let ((desc (cadr (assq pkg package-archive-contents))))
(package-install desc 'dont-select)))
;; Shadow built-in `org' by installing `org'.
2022-05-21 14:23:38 +02:00
(shadow-builtin-by-install 'org)
;; Shadow built-in `python' by installing `python'.
(shadow-builtin-by-install 'python)
;; Install the selected packages.
(package-install-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))
(if (package-installed-p package)
(when (bound-and-true-p package-selected-packages)
(cl-pushnew package package-selected-packages))
(setq ok nil)))
ok))
#+end_src
2022-05-22 23:24:12 +02:00
* [[info:emacs#Faces][Text faces or styles (info)]]
:PROPERTIES:
2022-05-22 23:24:12 +02:00
:CUSTOM_ID: sec:text-faces-or-styles
:END:
2022-05-22 23:24:12 +02:00
This setup does not configure [[info:emacs#Custom Themes][custom themes (info)]] in order to prevent endless
useless tweaking. See the [[https://protesilaos.com/codelog/2020-09-05-emacs-note-mixed-font-heights/][note on mixed font heights in Emacs]] for how to setup
fonts properly. It boils down to two rules:
1. The height of the default face must be an integer number to make the height a
physical quantity.
2. The heights of all other faces must be real numbers to scale those heights
with respect to the height of the face (those heights default to 1.0 for no
scaling).
The code in listing [[lst:configure-face-attributes]] source implements those rules.
Listing [[lst:set-default-face-height]] shows that font scaling is easy in case of
proper initialization of all face heigths. Listing
[[lst:fix-gtk-color-for-invert-default-face]] and listing [[lst:shadow-font-lock-faces]]
show a few tweaks to improve visibility without theming:
1. Fixing the =gtk= background color of the already loaded =region= face.
2. Toggling between a dark and light background by means of
2022-05-22 23:24:12 +02:00
src_emacs-lisp{(invert-default-face)}.
3. Shadowing the definition of faces before loading. The last item in the page
on [[https://orgmode.org/worg/org-contrib/babel/examples/fontify-src-code-blocks.html#org5c4406f][fontifying Org mode source code blocks]] describes this method.
#+caption[Configure =face-attributes=]:
#+caption: Configure =face-attributes=.
#+name: lst:configure-face-attributes
#+begin_src emacs-lisp
(with-eval-after-load 'emacs
;; Set face attributes.
(cond
((eq system-type 'darwin)
(set-face-attribute 'default nil :family "Hack" :height 120)
(set-face-attribute 'fixed-pitch nil :family "Hack")
(set-face-attribute 'variable-pitch nil :family "FiraGo"))
((eq system-type 'gnu/linux)
(set-face-attribute 'default nil :family "Hack" :height 110)
(set-face-attribute 'fixed-pitch nil :family "Hack")
(set-face-attribute 'variable-pitch nil :family "FiraGo"))
(t
(set-face-attribute 'default nil :family "Hack" :height 110)
(set-face-attribute 'fixed-pitch nil :family "Hack")
(set-face-attribute 'variable-pitch nil :family "DejaVu Sans"))))
#+end_src
#+caption[Implement =set-default-face-height=]:
#+caption: Implement =set-default-face-height=.
#+name: lst:set-default-face-height
#+begin_src emacs-lisp
(with-eval-after-load 'emacs
(defun set-default-face-height ()
"Set the default face height in all current and future frames.
Scale all other faces with a height that is a real number."
(interactive)
(let* ((prompt (format "face heigth (%s): "
(face-attribute 'default :height)))
(choices (mapcar #'number-to-string
(number-sequence 50 200 10)))
(height (string-to-number
(completing-read prompt choices nil 'require-match))))
(message "Setting the height of the default face to %s" height)
(set-face-attribute 'default nil :height height))))
#+end_src
#+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
2022-07-12 18:51:07 +02:00
#+begin_src emacs-lisp
;; Use proportional font faces in current buffer
(defun set-buffer-variable-pitch-face ()
"Set a variable width (proportional) font in current buffer."
(interactive)
(setq buffer-face-mode-face 'variable-pitch)
(buffer-face-mode))
;; Use monospaced font faces in current buffer
(defun set-buffer-fixed-pitch-face ()
"Set a fixed width (monospace) font in current buffer."
(interactive)
(setq buffer-face-mode-face 'fixed-pitch)
(buffer-face-mode))
(add-hook 'magit-mode-hook #'set-buffer-fixed-pitch-face)
2022-07-12 18:51:07 +02:00
(add-hook 'prog-mode-hook #'set-buffer-fixed-pitch-face)
#+end_src
2022-05-22 23:24:12 +02:00
#+caption[Fix a `gtk' color and implement =invert-default-face=]:
#+caption: Fix a `gtk' color and implement =invert-default-face=.
#+name: lst:fix-gtk-color-for-invert-default-face
#+begin_src emacs-lisp
(with-eval-after-load 'emacs
2022-05-22 23:24:12 +02:00
(defun fix-gtk-region-face-background-color ()
(when (featurep 'gtk)
(set-face-attribute
'region nil
:background (cdr (assoc (face-attribute 'default :background)
'(("white" . "LightGoldenrod2")
("black" . "blue3")))))))
(defun invert-default-face ()
"Invert the default face."
(interactive)
(invert-face 'default)
2022-05-22 23:24:12 +02:00
(fix-gtk-region-face-background-color))
(fix-gtk-region-face-background-color))
#+end_src
2022-05-22 23:24:12 +02:00
#+caption[Shadow font-lock faces to improve the readability]:
#+caption: Shadow font-lock faces to improve the readability.
#+name: lst:shadow-font-lock-faces
#+begin_src emacs-lisp
(with-eval-after-load 'emacs
2022-05-28 15:36:07 +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 various blocks.
It is always used for source blocks. You can refine what face
should be used depending on the source block language by setting,
`org-src-block-faces', which takes precedence.
When `org-fontify-quote-and-verse-blocks' is not nil, text inside
verse and quote blocks are fontified using the `org-verse' and
2022-05-22 23:24:12 +02:00
`org-quote' faces, which inherit from `org-block'.")
2022-05-28 15:36:07 +02:00
(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.")
;; 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."))
#+end_src
* [[info:elisp#Advising Functions][Advising Functions (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:advising-function
:END:
2022-05-01 17:35:18 +02:00
#+caption[Tools for advising functions]:
#+caption: Tools for advising functions.
#+name: lst:advising-tools
#+begin_src emacs-lisp
(with-eval-after-load 'emacs
(defun toggle-advice (symbol where function &optional props)
"Toggle between states after `advice-remove' and `advice-add'."
(let ((how "%s `%s' advice `%s' %s `%s'"))
(if (advice-member-p function symbol)
(progn
(message how "Removal of" where function "from" symbol)
(advice-remove symbol function))
(message how "Addition of" where function "to" symbol)
(advice-add symbol where function props)))))
#+end_src
* [[info:emacs#Dired][Dired: directory editor as file manager (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:file-manager
:END:
[[info:emacs#Dired][Dired (info)]] and the [[https://github.com/ranger/ranger#readme][ranger]] file manager offer similar capabilities for copying,
deleting, opening, renaming, and viewing files and directories, but the
integration of [[info:emacs#Dired][dired (info)]] in Emacs is obviously much better than the
integration of [[https://github.com/ranger/ranger#readme][ranger]] in Emacs.
For instance, this setup allows to insert an =org-mode= link to an poorly
identified file containing a specific image into an =org-mode= buffer by means
of the facilities of [[info:emacs#Dired][dired (info)]] as follows:
1. Type {{{kbd(C-x d)}}} to open the directory containing the pooly identified
file with the specific image in a =dired-mode= buffer.
2. Start searching for the specific image by navigating to the name of any image
file.
3. Type {{{kbd(v)}}} to switch to view the file in an =image-mode= buffer.
4. In the =image-mode= buffer, continue searching for the specific image by
typing:
- {{{kbd(n)}}} to view the next image in the =dired-mode= buffer,
- {{{kbd(p)}}} to view the previous image in the =dired-mode= buffer, and
- {{{kbd(q)}}} to quit the =image-mode= buffer and to go back to the
=dired-mode= buffer.
5. After finding the specific image, use {{{kbd(C-c l)}}} in the =image-mode=
buffer or the =dired-mode= buffer to store the =org-link=.
6. Switch to the =org-mode= buffer and use {{{kbd(C-c C-l)}}} to insert the
=org-link= into the buffer.
Listing [[lst:customize-dired]] makes the directory editor sort entries
alphabetically after grouping the directories before grouping the files by
extension.
#+caption[Customize =dired=]:
#+caption: Customize =dired=.
#+name: lst:customize-dired
#+begin_src emacs-lisp
(with-eval-after-load 'dired
(custom-set-variables
'(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)))
(with-eval-after-load 'files
(custom-set-variables
;; Ensure the use of `GNU-ls' from `coreutils' on darwin.
'(insert-directory-program (or (executable-find "gls")
(executable-find "ls")))))
(with-eval-after-load 'wdired
(custom-set-variables
'(wdired-allow-to-change-permissions t)))
#+end_src
2022-03-28 09:45:27 +02:00
Listing [[lst:extra-dired-key-bindings]] adds new key bindings to =dired-mode-map= to:
1. Open files with the [[https://en.wikipedia.org/wiki/Eww_(web_browser)][Emacs Web Wowser]] inside Emacs.
2. Let [[https://en.wikipedia.org/wiki/Rsync][rsync]] copy marked files outside Emacs to a local or remote directory.
The link [[https://truongtx.me/tmtxt-dired-async.html][asynchoronous execution library for Emacs Dired]] is the original source
for the idea of using [[https://en.wikipedia.org/wiki/Rsync][rsync]] and the blog articles [[https://oremacs.com/2016/02/24/dired-rsync/][using rsync in dired]] and
[[https://vxlabs.com/2018/03/30/asynchronous-rsync-with-emacs-dired-and-tramp/][asynchronous rsync with Emacs, dired and tramp]] are vivid recommendations written
by experienced Emacs users.
#+caption[Extra =dired= key bindings]:
#+caption: Extra =dired= key bindings.
#+name: lst:extra-dired-key-bindings
#+begin_src emacs-lisp
(with-eval-after-load 'dired
(defun dired-eww-open-file ()
"In Dired, open the regular file named on this line with eww"
(interactive)
(let ((file (dired-get-file-for-visit)))
(if (file-regular-p file)
(eww-open-file file)
(error "Eww rejects `%s', since it is not a regular file" file))))
;; https://truongtx.me/tmtxt-dired-async.html
(defun dired-rsync (target)
"Copy marked files with `rsync' to TARGET directory."
(interactive
(list (expand-file-name
(read-file-name "Rsync to:" (dired-dwim-target-directory)))))
;; Store all marked files into the `files' list and intialize
;; the `rsync-command'.
(let ((files (dired-get-marked-files nil current-prefix-arg))
(rsync-command "rsync -av --progress "))
;; Add all marked files as arguments to the `rsync-command'.
(dolist (file files)
(setq rsync-command
(concat rsync-command
(if (string-match "^/ssh:\\(.*\\)$" file)
(format " -e ssh %s" (match-string 1 file))
(shell-quote-argument file)) " ")))
;; Append the destination directory to the `rsync-command'.
(setq rsync-command
(concat rsync-command
(if (string-match "^/ssh:\\(.*\\)$" target)
(format " -e ssh %s" (match-string 1 target))
(shell-quote-argument target))))
;; Run the async shell command.
(async-shell-command rsync-command)
;; Finally, switch to that window.
(other-window 1)))
(define-key dired-mode-map (kbd "E") #'dired-eww-open-file)
(define-key dired-mode-map (kbd "Y") #'dired-rsync))
#+end_src
* [[info:elisp#Processes][Processes (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:processes
:END:
Listing [[lst:process-utilities]] defines a function to run a (command-line) program
with arguments and to obtain a list with its numeric exit status as well as its
output to =stdout=.
#+caption[Process utilities]:
#+caption: Process utilities.
#+name: lst:process-utilities
#+begin_src emacs-lisp
;; https://gitlab.com/howardabrams/spacemacs.d/blob/master/layers/ha-org/funcs.el#L418
(defun shell-command-with-exit-code (program &rest args)
"Run PROGRAM with ARGS and return exit-code and output in a list."
(with-temp-buffer
(list (apply 'call-process program nil (current-buffer) nil args)
(buffer-string))))
#+end_src
* [[info:emacs#Help][Help (info)]]
2022-01-06 19:32:36 +01:00
:PROPERTIES:
:CUSTOM_ID: sec:help
:END:
Table [[tab:help-key-bindings]] lists a number of key bindings to start playing with
the help facilities of Emacs.
#+attr_latex: :booktabs yes :float table
#+caption[Help key bindings]:
#+caption: Help key bindings.
#+name: tab:help-key-bindings
|------------------------------+----------+------------------|
| 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)}}} |
|------------------------------+----------+------------------|
** [[info:emacs#Name Help][Shortdoc-display-group (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:shortdoc-display-group
:END:
Listing [[lst:configure-shortdoc]] binds {{{kbd(C-h y)}}} to
=short-doc-display-group= and defines a short documentation group for functions
defined in this Org file.
#+caption[Configure =shortdoc=]:
#+caption: Configure =shortdoc=.
#+name: lst:configure-shortdoc
#+begin_src emacs-lisp
(when (fboundp 'shortdoc-display-group)
(define-key help-map (kbd "y") #'shortdoc-display-group)
(with-eval-after-load 'shortdoc
;; Ensure defining the functions before documenting them.
(define-short-documentation-group init
"Advice"
(toggle-advice :no-manual t)
"Face"
(invert-default-face :no-manual t)
(set-default-face-height :no-manual t)
2022-05-27 06:52:27 +02:00
"Interaction"
(enable-this-command :no-manual t)
(narrow-or-widen-dwim :no-manual t)
(org-narrow-to-table :no-manual t)
(toggle-ilog-timer-function-after :no-manual)
"LaTeX"
(TeX-brace-count-line-override :no-manual t)
(biber-delete-cache :no-manual t)
(toggle-TeX-brace-count-line-override :no-manual t)
(update-lualatex-opentype-font-name-database :no-manual t)
"Org"
(by-backend :no-manual t)
(by-backend-kbd-org-macro :no-manual t)
(org-babel-execute:latex-extra-header :no-manual t)
(org-babel-execute:latex-header :no-manual t)
(org-electric-dollar :no-manual t)
(org-eval-emacs-lisp-setup-blocks :no-manual t)
(org-eval-python-setup-blocks :no-manual t)
(org-eval-infixed-blocks :no-manual t)
(org-syntax-convert-keyword-case-to-lower :no-manual t)
2022-05-27 06:52:27 +02:00
(toggle-org-babel-python-format-session-value-override :no-manual t))))
#+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-04-04 18:27:58 +02:00
Listing [[lst:configure-info]] adds a path in my home directory 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
#+begin_src emacs-lisp
(with-eval-after-load 'info
;; Emacs should find my "python.info" file.
2022-01-06 19:32:36 +01:00
(add-to-list 'Info-directory-list
(expand-file-name "~/.local/share/info")))
#+end_src
2022-01-18 07:26:09 +01:00
* [[info:emacs#Key Bindings][Key bindings (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:key-bindings
:END:
#+attr_latex: :booktabs yes :float table
#+caption[Basic key bindings]:
#+caption: Basic key bindings.
#+name: tab:basic-key-bindings
|--------------------+------------+------------------------|
| 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-01-18 07:26:09 +01:00
** [[info:emacs#Disabling][Disabling Commands (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:enable-disabled-commands
:END:
Execute src_emacs-lisp{(find-library "novice")} to see how Emacs prevents new
users from shooting themselves in the feet. Listing
[[lst:configure-disabled-command-function]] enables [[https://www.emacswiki.org/emacs/DisabledCommands][disabled commands on the fly]].
#+caption[Configure the =disabled-command-function=]:
#+caption: Configure the =disabled-command-function=.
#+name: lst:configure-disabled-command-function
#+begin_src emacs-lisp
(with-eval-after-load 'emacs
(setq disabled-command-function
(defun enable-this-command (&rest _args)
"Called when a disabled command is executed.
2022-01-18 07:26:09 +01:00
Enable it and re-execute it."
(put this-command 'disabled nil)
(message "You typed %s. %s was disabled until now."
(key-description (this-command-keys)) this-command)
(sit-for 0)
(call-interactively this-command))))
2022-01-18 07:26:09 +01:00
#+end_src
2022-05-13 04:00:02 +02:00
** [[https://github.com/michael-heerdegen/interaction-log.el#readme][Interaction-log]]
:PROPERTIES:
:CUSTOM_ID: sec:interaction-log
:END:
#+caption[Configure =interaction-log=]:
#+caption: Configure =interaction-log=.
#+name: lst:configure-interaction-log
#+begin_src emacs-lisp
(when (and (ensure-package-installation 'interaction-log)
(require 'interaction-log nil 'noerror))
;; https://www.skybert.net/emacs/show-shortcuts-when-giving-presentations/
2022-05-13 04:00:02 +02:00
(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)))
2022-05-13 04:00:02 +02:00
(display-buffer (get-buffer ilog-buffer-name))))
2022-05-27 06:52:27 +02:00
(define-key help-map (kbd "C-l") #'interaction-log-mode))
(with-eval-after-load 'emacs
2022-05-13 04:00:02 +02:00
(defun toggle-ilog-timer-function-after ()
"Toggle `ilog-timer-function' advice."
(interactive)
(toggle-advice 'ilog-timer-function :after #'ilog-ensure-ilog-buffer-window))
2022-05-27 06:52:27 +02:00
(toggle-ilog-timer-function-after))
2022-05-13 04:00:02 +02:00
#+end_src
** [[https://github.com/tarsius/keycast#readme][Keycast]] :noexport:
:PROPERTIES:
:CUSTOM_ID: sec:keycast
2022-05-13 04:00:02 +02:00
:header-args:emacs-lisp: :tangle no
:END:
Listing [[lst:configure-keycast]] configures =keycast=.
#+caption[Configure =keycast=]:
#+caption: Configure =keycast=.
#+name: lst:configure-keycast
#+begin_src emacs-lisp
;; Make `keycast-log-update-buffer' use a buffer similar to the
;; control buffer `ediff-setup-windows-plain' returns.
2022-05-13 04:00:02 +02:00
(when (and (ensure-package-installation 'keycast)
(require 'keycast nil 'noerror))
(custom-set-variables
'(keycast-mode-line-window-predicate 'keycast-bottom-right-window-p))
(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)))))))
(defun toggle-keycast-log-update-buffer-override ()
"Toggle `keycast-log-update-buffer' advice."
(interactive)
(toggle-advice 'keycast-log-update-buffer
:override #'keycast-log-update-buffer-plain))
(toggle-keycast-log-update-buffer-override))
#+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
command =emacsclient=. Section [[#sec:latexmk-save-compile-display-loop]] and
[[#sec:qutebrowser-userscript]] show how to use ~emacsclient~ to:
1. Install an asynchronous (or background) loop of saving a LaTeX file,
compiling it, and redisplaying the output in Emacs.
2. Make [[https://qutebrowser.org][qutebrowser]] send html links with document titles to Emacs.
The code in listing [[lst:start-emacs-server]] starts the Emacs server.
2021-11-29 13:14:56 +01:00
#+caption[Start the Emacs server]:
#+caption: Start the Emacs server.
2021-12-28 08:48:03 +01:00
#+name: lst:start-emacs-server
2021-11-29 13:14:56 +01:00
#+begin_src emacs-lisp
(when window-system
(unless (or noninteractive (daemonp))
(add-hook 'after-init-hook #'server-start)))
#+end_src
** Latexmk save-compile-display loop
2021-11-29 13:14:56 +01:00
:PROPERTIES:
:CUSTOM_ID: sec:latexmk-save-compile-display-loop
2021-11-29 13:14:56 +01:00
:END:
The =latexmk= resource file in the next source code block shows how to use
=emacsclient= to (re)display the PDF file in Emacs after each succesful
(re)compilation on condition that the settings of the ~compile-command~ local
variable in section are compatible. The local variable ~compile-command~ in the
2021-12-05 16:39:07 +01:00
[[#sec:local-variables][local variables]] section (only visible in =org= files, but not in =html= and
=pdf= files) shows how to use the =latexmkrc= file.
2021-11-29 13:14:56 +01:00
#+attr_latex: :options breaklines
#+caption[Tangle the Latexmk resource file]:
#+caption: Tangle the Latexmk resource file.
2021-12-28 08:48:03 +01:00
#+name: lst:latexmkrc
2021-11-30 18:04:16 +01:00
#+begin_src perl :tangle latexmkrc :comments none
# pdf creator
$pdf_mode = 4; # 4 means lualatex
2021-11-29 13:14:56 +01:00
# pdf previewer and update pdf previewer
$pdf_previewer = "emacsclient -e '(find-file-other-window %S)'";
$pdf_update_method = 4; # 4 runs a 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' );
$clean_ext .= " acr acn alg bbl dvi glo gls glg ist lol nav run.xml snm synctex.gz";
2021-11-29 13:14:56 +01:00
sub makeglossaries {
my ($name, $path) = fileparse( $$Psource );
return system "makeglossaries -d '$path' '$name'";
}
# Emacs looks for "Local variables:" after the last "newline-formfeed".
2021-11-29 13:14:56 +01:00
# Local Variables:
# mode: perl
# End:
#+end_src
** [[https://qutebrowser.org/doc/userscripts.html][Qutebrowser userscript]]
2021-12-05 16:39:07 +01:00
:PROPERTIES:
:CUSTOM_ID: sec:qutebrowser-userscript
:END:
2021-11-29 13:14:56 +01:00
The next block contains an userscript that sends a [[info:org#The store-link protocol][store-link org-protocol]]
message with the url and the title from [[https://qutebrowser.org][qutebrowser]] to =emacsclient=. The
function =urlencode= translates the url and the title for the message. The
[[info:python#Examples<22>][Python urllib examples]] show how to use =urlencode=. The final =execvp= call
deals with a [[https://qutebrowser.org][qutebrowser]] userscript requirement: the =emacsclient= process must
get the PID of the userscript that must kill itself after the take-over.
Termination of the =emacsclient= process hands control back to [[https://qutebrowser.org][qutebrowser]].
On a [[https://en.wikipedia.org/wiki/POSIX][POSIX]] system, you can run the userscript from [[https://qutebrowser.org][qutebrowser]] or from a
terminal to see whether it works. In case you try to run it from Emacs, Emacs
may hang or die.
#+caption[Tangle a qutebrowser userscript]:
#+caption: Tangle a qutebrowser userscript.
2021-11-29 13:14:56 +01:00
#+header: :comments none
#+header: :tangle-mode (identity #o755)
2021-12-28 08:48:03 +01:00
#+name: lst:qutebrowser-userscript
2021-11-29 13:14:56 +01:00
#+begin_src python :noeval :tangle org-store-link
#!/usr/bin/env python
from urllib.parse import urlencode
from os import environ, execvp
url = environ.get("QUTE_URL", "https://orgmode.org")
title = environ.get("QUTE_TITLE", "Org Mode")
parameters = urlencode({"url": url, "title": title})
print(payload := f"org-protocol://store-link?{parameters}")
execvp("emacsclient", ("-n", payload))
#+end_src
** TODO Look into: org-protocol handling with other browser on Darwin
:PROPERTIES:
:CUSTOM_ID: sec:org-protocol-darwin
:END:
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]]
#+caption[Ensure =applescript-mode= installation]:
#+caption: Ensure =applescript-mode= installation.
#+name: lst:ensure-applescript-mode-installation
#+begin_src emacs-lisp
(when (ensure-package-installation 'applescript-mode))
#+end_src
#+caption[Applescript code to register =org-protocol= on Darwin]:
#+caption: Applescript code to register =org-protocol= on Darwin.
#+name: lst:applescript-org-protocol
#+begin_src applescript :tangle no
on emacsclient(input)
do shell script "/usr/local/bin/emacsclient -n -c '" & input & "'"
tell application "Emacs" to activate
end emacsclient
on open location input
emacsclient(input)
end open location
on open inputs
repeat with raw_input in inputs
set input to POSIX path of raw_input
emacsclient(input)
end repeat
end open
on run
do shell script emacsclient("")
end run
#+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:
2021-12-05 16:40:20 +01:00
1. [[info:orderless#Top][Orderless (info)]] for an advanced completion style,
2. [[info:embark#Top][Embark (info)]] for minibuffer actions with context menus,
3. [[info:marginalia#Top][Marginalia (info)]] for rich annotations in the minibuffer, and
4. [[info:consult#Top][Consult (info)]] for useful search and navigation commands,
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
Finally, [[https://company-mode.github.io/][company: a modular complete-anything framework for Emacs]] provides
completion in any buffer and [[#sec:minibuffer-history-completion][minibuffer-history-completion]] provides completion
on previous input in the minibuffer.
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
Listing [[lst:enable-vertico-mode]] configures and enables =savehist-mode= and
enables =vertico-mode=. The documentation src_emacs-lisp{(describe-function
'savehist-mode)} why it is best to turn on =savehist-mode= in the Emacs init
file.
#+caption[Enable =savehist-mode= and =vertico-mode=]:
#+caption: Enable =savehist-mode= and =vertico-mode=.
2021-12-28 08:48:03 +01:00
#+name: lst:enable-vertico-mode
2021-11-29 13:14:56 +01:00
#+begin_src emacs-lisp
(when (fboundp 'savehist-mode)
(savehist-mode +1)
(custom-set-variables
'(savehist-additional-variables
'(eww-history
kill-ring
regexp-search-string
search-ring
search-string))))
(when (fboundp 'vertico-mode)
(vertico-mode +1))
(with-eval-after-load 'vertico
(define-key vertico-map (kbd "RET") #'vertico-directory-enter)
(define-key vertico-map (kbd "DEL") #'vertico-directory-delete-char)
(define-key vertico-map (kbd "M-DEL") #'vertico-directory-delete-word))
2021-11-29 13:14:56 +01:00
#+end_src
#+attr_latex: :booktabs yes :float table
#+caption[Vertico key map bindings]:
#+caption: Vertico key map bindings.
#+name: tab:vertico-keymap-bindings
|-------------------------------+----------------------------------+---------------------|
| command | remap | keys |
|-------------------------------+----------------------------------+---------------------|
| vertico-directory-delete-char | | {{{kbd(DEL)}}} |
| vertico-directory-delete-word | | {{{kbd(M-DEL)}}} |
| vertico-directory-enter | | {{{kbd(RET)}}} |
| vertico-exit | exit-minibuffer | {{{kbd(C-j)}}} |
| vertico-exit-input | | {{{kbd(C-RET)}}} |
| vertico-first | beginning-of-buffer | {{{kbd(M-<)}}} |
| vertico-first | minibuffer-beginning-of-buffer | {{{kbd(M-<)}}} |
| vertico-insert | | {{{kbd(TAB)}}} |
| vertico-last | end-of-buffer | {{{kbd(M->)}}} |
| vertico-next-group | forward-paragraph | {{{kbd(C-<down>)}}} |
| vertico-next | next-line-or-history-element | {{{kbd(<down>)}}} |
| vertico-next | next-line | {{{kbd(C-n)}}} |
| vertico-previous-group | backward-paragraph | {{{kbd(C-<up>)}}} |
| vertico-previous | previous-line-or-history-element | {{{kbd(<up>)}}} |
| vertico-previous | previous-line | {{{kbd(C-p)}}} |
| vertico-save | kill-ring-save | {{{kbd(M-w)}}} |
| vertico-scroll-down | scroll-down-command | {{{kbd(M-v)}}} |
| vertico-scroll-up | scroll-up-command | {{{kbd(C-v)}}} |
|-------------------------------+----------------------------------+---------------------|
2021-12-05 16:40:20 +01:00
** [[info:orderless#Top][Orderless (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:orderless-configuration
:END:
Listing [[lst:configure-orderless]] configures [[info:orderless#Company][orderless for company (info)]].
#+caption[Configure =orderless=]:
#+caption: Configure =orderless=.
2021-12-28 08:48:03 +01:00
#+name: lst:configure-orderless
2021-12-05 16:40:20 +01:00
#+begin_src emacs-lisp
(when (ensure-package-installation 'marginalia)
(with-eval-after-load 'orderless
(custom-set-variables
'(orderless-component-separator " +"))
(defun just-one-face (fn &rest args)
(let ((orderless-match-faces [completions-common-part]))
(apply fn args)))
(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:
2022-04-20 05:35:28 +02:00
Listing [[lst:configure-embark]] configures =embark= key bindings:
1. =embark-act= prompts the user for an action and performs it.
2. Except for highlighting of email and web URLs, =embark-dwim= englobes the
2022-04-20 05:35:28 +02:00
functionality of src_emacs-lisp{(find-library "goto-addr")} that activates
mail and web URLs to turn them into clickable buttons. Since =embark-dwim=
acts on a superset of target types, it renders =goto-addr= superfluous. See:
1. [[info:emacs#Goto Address mode][Goto Address mode (info)]].
2. [[info:embark#The default action on a target][The default (embark-dwim) action on a target (info)]].
3. =embark-bindings= allows to explore all current command key bindings in the
minibuffer.
4. The initialization src_emacs-lisp{(setq prefix-help-command
#'embark-prefix-help-command)} enables minibuffer help after a prefix key
(for instance {{{kbd(C-x)}}} or {{{kbd(C-c)}}}) as typing {{{kbd(C-x C-h)}}}
or {{{kbd(C-c C-h)}}} shows.
#+caption[Configure =embark=]:
#+caption: Configure =embark=.
2021-12-28 08:48:03 +01:00
#+name: lst:configure-embark
2021-12-05 16:40:20 +01:00
#+begin_src emacs-lisp
(when (ensure-package-installation 'embark)
(when (fboundp 'embark-act)
(global-set-key (kbd "C-,") #'embark-act))
(when (fboundp 'embark-dwim)
(global-set-key (kbd "C-:") #'embark-dwim))
(when (fboundp 'embark-bindings)
(global-set-key (kbd "C-h B") #'embark-bindings))
(when (fboundp 'embark-prefix-help-command)
(setq prefix-help-command #'embark-prefix-help-command)))
2021-12-05 16:40:20 +01:00
#+end_src
** [[info:marginalia#Top][Marginalia (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:marginalia-configuration
:END:
2021-11-29 13:14:56 +01:00
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
2021-11-29 13:14:56 +01:00
#+begin_src emacs-lisp
(when (and (ensure-package-installation 'marginalia)
(fboundp 'marginalia-mode))
(marginalia-mode +1))
2021-11-29 13:14:56 +01:00
#+end_src
2021-12-05 16:40:20 +01:00
** [[info:consult#Top][Consult (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:consult-configuration
:END:
2021-11-29 13:14:56 +01:00
Consult provides practical commands based on the Emacs minibuffer completion
function [[info:elisp#Minibuffer Completion][completing-read]]. Listing [[lst:configure-consult]] configures =consult=.
#+attr_latex: :booktabs yes :float table
#+caption[Configuration specific key bindings]:
#+caption: Configuration specific key-bindings.
#+name: tab:configuration-specific-key-bindings
|-----------------------------+----------------------+---------------------|
| command | key map | keys |
|-----------------------------+----------------------+---------------------|
| consult-apropos | help-map | {{{kbd(<help> a)}}} |
| consult-bookmark | ctl-x-r-keymap | {{{kbd(C-x r b)}}} |
| consult-buffer-other-frame | ctl-x-5-keymap | {{{kbd(C-x 5 b)}}} |
| consult-buffer-other-window | ctl-x-4-keymap | {{{kbd(C-x 4 b)}}} |
| consult-buffer | ctl-x-keymap | {{{kbd(C-x b)}}} |
| consult-compile-error | goto-map | {{{kbd(M-g e)}}} |
| consult-complex-command | ctl-x-keymap | {{{kbd(C-x M-:)}}} |
| consult-find | search-map | {{{kbd(M-s f)}}} |
| consult-focus-lines | search-map | {{{kbd(M-s u)}}} |
| consult-git-grep | search-map | {{{kbd(M-s g)}}} |
| consult-global-mark | goto-map | {{{kbd(M-g k)}}} |
| consult-goto-line | goto-map | {{{kbd(M-g M-g)}}} |
| consult-goto-line | goto-map | {{{kbd(M-g g)}}} |
| consult-history | global-map | {{{kbd(C-c h)}}} |
| consult-imenu | goto-map | {{{kbd(M-g i)}}} |
| consult-keep-lines | search-map | {{{kbd(M-s k)}}} |
| consult-line | search-map | {{{kbd(M-s l)}}} |
| consult-mark | goto-map | {{{kbd(M-g m)}}} |
| consult-mode-command | global-map | {{{kbd(C-c m)}}} |
| consult-multi-occur | search-map | {{{kbd(M-s m)}}} |
| consult-outline | goto-map | {{{kbd(M-g o)}}} |
| consult-register | ctl-x-r-keymap | {{{kbd(C-x r x)}}} |
| consult-yank-pop | global-map | {{{kbd(M-y)}}} |
|-----------------------------+----------------------+---------------------|
| deadgrep | search-map | {{{kbd(M-s d)}}} |
| elfeed | global-map | {{{kbd(C-x w)}}} |
| embark-act | global-map | {{{kbd(C-\,)}}} |
| embark-bindings | global-map | {{{kbd(C-h B)}}} |
| embark-dwim | global-map | {{{kbd(C-:)}}} |
| iedit-mode | global-map | {{{kbd(C-;)}}} |
| minibuffer-complete-history | minibuffer-local-map | {{{kbd(C-<tab>)}}} |
| narrow-or-widen-dwim | ctl-x-keymap | {{{kbd(C-x C-n)}}} |
| org-agenda | global-map | {{{kbd(C-c a)}}} |
| org-capture | global-map | {{{kbd(C-c c)}}} |
| org-cite | org-mode-map | {{{kbd(C-c b)}}} |
| org-insert-link-global | global-map | {{{kbd(C-c C-l)}}} |
| org-narrow-to-table | ctl-x-keymap | {{{kbd(C-x n t)}}} |
| org-store-link | global-map | {{{kbd(C-c l)}}} |
|-----------------------------+----------------------+---------------------|
#+caption[Configure =consult=]:
#+caption: Configure =consult=.
#+name: lst:configure-consult
2021-11-29 13:14:56 +01:00
#+begin_src emacs-lisp
(when (ensure-package-installation 'consult)
(custom-set-variables
2022-07-13 05:12:17 +02:00
'(consult-project-function #'(lambda (_) (vc-root-dir))))
2022-04-17 16:11:05 +02:00
;; C-c bindings (current-global-map)
(global-set-key (kbd "C-c h") #'consult-history)
(global-set-key (kbd "C-c m") #'consult-mode-command)
2022-04-17 16:11:05 +02:00
;; C-h bindings (help-map)
(define-key help-map (kbd "a") #'consult-apropos)
;; C-x bindings (ctl-x-map)
(define-key ctl-x-map (kbd "M-:") #'consult-complex-command)
(define-key ctl-x-map (kbd "b") #'consult-buffer)
(define-key ctl-x-4-map (kbd "b") #'consult-buffer-other-window)
(define-key ctl-x-5-map (kbd "b") #'consult-buffer-other-frame)
(define-key ctl-x-r-map (kbd "x") #'consult-register)
(define-key ctl-x-r-map (kbd "b") #'consult-bookmark)
;; M-g bindings (goto-map)
(define-key goto-map (kbd "g") #'consult-goto-line)
(define-key goto-map (kbd "M-g") #'consult-goto-line)
(define-key goto-map (kbd "o") #'consult-outline)
(define-key goto-map (kbd "m") #'consult-mark)
(define-key goto-map (kbd "k") #'consult-global-mark)
2022-07-13 05:12:17 +02:00
(define-key goto-map (kbd "i") #'consult-imenu)
(define-key goto-map (kbd "e") #'consult-compile-error)
;; M-s bindings (search-map)
(define-key search-map (kbd "g") #'consult-git-grep)
(define-key search-map (kbd "f") #'consult-find)
(define-key search-map (kbd "k") #'consult-keep-lines)
(define-key search-map (kbd "l") #'consult-line)
(define-key search-map (kbd "m") #'consult-multi-occur)
(define-key search-map (kbd "u") #'consult-focus-lines)
2022-04-17 16:11:05 +02:00
;; Other bindings (current-global-map)
2022-07-13 05:12:17 +02:00
(global-set-key (kbd "M-y") #'consult-yank-pop))
2021-11-29 13:14:56 +01:00
#+end_src
2021-12-05 16:40:20 +01:00
** [[https://company-mode.github.io/][Company: a modular complete anything framework for Emacs]]
:PROPERTIES:
:CUSTOM_ID: sec:company-configuration
:END:
2021-11-29 13:14:56 +01:00
Listing [[lst:configure-company]] configures =company=.
#+caption[Configure =company=]:
#+caption: Configure =company=.
2021-12-28 08:48:03 +01:00
#+name: lst:configure-company
2021-11-29 13:14:56 +01:00
#+begin_src emacs-lisp
(when (fboundp 'company-mode)
(custom-set-variables
;; https://github.com/purcell/emacs.d/issues/778
'(company-transformers '(company-sort-by-occurrence)))
(dolist (hook '(LaTeX-mode-hook
org-mode-hook
emacs-lisp-mode-hook
lisp-interaction-mode-hook
lisp-mode-hook
python-mode-hook
ielm-mode-hook
sly-mrepl-mode-hook))
(add-hook hook #'company-mode)))
2021-11-29 13:14:56 +01:00
#+end_src
2021-12-29 14:05:03 +01:00
** [[https://lists.gnu.org/archive/html/emacs-devel/2021-12/msg00802.html][Minibuffer history completion]]
:PROPERTIES:
:CUSTOM_ID: sec:minibuffer-history-completion
:END:
See [[https://lists.gnu.org/archive/html/emacs-devel/2021-12/msg00802.html][Juri Linkov (Emacs Developer mailing list)]] for how to allow completion on
previous input in the minibuffer. Listing
[[lst:enable-minibuffer-history-completion]] enables minibuffer history completion.
#+caption[Enable =minibuffer-history-completion=]:
#+caption: Enable =minibuffer-history-completion=.
2021-12-28 08:48:03 +01:00
#+name: lst:enable-minibuffer-history-completion
#+begin_src emacs-lisp
(with-eval-after-load 'minibuffer
;; https://github.com/oantolin/emacs-config/blob/master/init.el#L333
(custom-set-variables
'(completion-category-defaults nil)
'(completion-category-overrides '((file (styles basic partial-completion))))
'(completion-ignore-case t)
'(completion-styles '(orderless basic partial-completion)))
(defun minibuffer-setup-history-completions ()
(unless (or minibuffer-completion-table minibuffer-completion-predicate)
(setq-local minibuffer-completion-table
(symbol-value minibuffer-history-variable))))
(add-hook 'minibuffer-setup-hook 'minibuffer-setup-history-completions)
;; Stolen from Emacs-28.1 for Emacs-27.2:
(unless (fboundp 'minibuffer--completion-prompt-end)
(defun minibuffer--completion-prompt-end ()
(let ((end (minibuffer-prompt-end)))
(if (< (point) end)
(user-error "Can't complete in prompt")
end))))
;; Adapted from minibuffer-complete:
(defun minibuffer-complete-history ()
"Allow minibuffer completion on previous input."
(interactive)
(completion-in-region (minibuffer--completion-prompt-end) (point-max)
(symbol-value minibuffer-history-variable)
nil))
(define-key minibuffer-local-map (kbd "C-<tab>") #'minibuffer-complete-history))
#+end_src
2022-02-27 14:13:45 +01:00
* [[info:emacs#Search][Search and replace (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:search-replace
:END:
** [[https://github.com/Wilfred/deadgrep#readme][Deadgrep]]
:PROPERTIES:
:CUSTOM_ID: sec:deadgrep
:END:
[[https://github.com/Wilfred/deadgrep#readme][Deadgrep]] uses [[https://github.com/BurntSushi/ripgrep#readme][ripgrep]] for superfast text searching in the default directory or
the current [[https://en.wikipedia.org/wiki/Version_control][VCS]] directory tree. Listing [[lst:configure-deadgrep]] binds =deadgrep=
to {{{kbd(M-s d)}}} and =deadgrep-edit-mode= to {{{kbd(C-c C-w)}}}.
2022-02-27 14:13:45 +01:00
#+caption[Configure =deadgrep=]:
#+caption: Configure =deadgrep=.
#+name: lst:configure-deadgrep
#+begin_src emacs-lisp
2022-05-21 14:51:33 +02:00
(when (and (ensure-package-installation 'deadgrep)
(fboundp 'deadgrep))
(define-key search-map (kbd "d") #'deadgrep)
(with-eval-after-load 'deadgrep
(define-key deadgrep-mode-map (kbd "C-c C-w") #'deadgrep-edit-mode)))
2022-02-27 14:13:45 +01:00
#+end_src
2022-08-10 06:49:55 +02:00
** [[https://www.genivia.com/get-ugrep.html][Ugrep]]
:PROPERTIES:
:CUSTOM_ID: sec:ugrep
:END:
[[https://www.genivia.com/get-ugrep.html][Ugrep]] is an ultra fast grep with interactive query UI and fuzzy search. The
pages [[https://github.com/Genivia/ugrep#emacs][Using ugrep within Emacs]] and [[https://manueluberti.eu/emacs/2022/08/07/emacs-ugrep/][Ugrep in Emacs]] show how to make Emacs use it
with [[info:emacs#Grep Searching][lgrep]] and [[info:emacs#Xref][xref]]. Listing [[lst:use-ugrep]] shows my implementation of the
suggestions in those pages.
#+caption[Use =ugrep= when available]:
#+caption: Use =ugrep= when available.
#+name: lst:use-ugrep
#+begin_src emacs-lisp
(when (executable-find "ugrep")
(with-eval-after-load 'grep
(custom-set-variables
`(grep-template ,(string-join '("ugrep"
"--color=always"
"--ignore-binary"
"--ignore-case"
"--include=\"<F>\""
"--line-number"
"--null"
"--recursive"
"--regexp=<R>")
" "))))
(with-eval-after-load 'xref
(custom-set-variables
'(xref-search-program-alist
'((grep
. "xargs -0 grep <C> --null -snHE -e <R>")
(ripgrep
. "xargs -0 rg <C> --null -nH --no-heading --no-messages -g '!*/' -e <R>")
(ugrep
. "xargs -0 ugrep <C> --null -ns -e <R>")))
'(xref-search-program 'ugrep))))
#+end_src
* [[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]].
Listing [[lst:configure-ediff]] configures =ediff= to display all its buffers in a
single frame and to make all text visible prior to ediffing Org buffers.
#+caption[Configure =ediff=]:
#+caption: Configure =ediff=.
#+name: lst:configure-ediff
#+begin_src emacs-lisp
(with-eval-after-load 'emacs
(custom-set-variables
'(ediff-merge-split-window-function #'split-window-horizontally)
'(ediff-split-window-function #'split-window-horizontally)
'(ediff-window-setup-function #'ediff-setup-windows-plain)))
(with-eval-after-load 'org
;; https://github.com/oantolin/emacs-config#readme
(defun ediff-with-org-show-all ()
"Expand all headings prior to ediffing org buffers."
(add-hook 'ediff-prepare-buffer-hook #'org-show-all nil t))
(add-hook 'org-mode-hook #'ediff-with-org-show-all))
#+end_src
2021-11-29 13:14:56 +01:00
* Reading
:PROPERTIES:
:CUSTOM_ID: sec:reading
:END:
2022-02-27 14:13:45 +01:00
** Reading [[https://en.wikipedia.org/wiki/DjVu][DjVu]] files
:PROPERTIES:
:CUSTOM_ID: sec:reading-djvu-files
:END:
This setup relies on [[info:emacs#Document View][Document View (info)]] to facilitate reading [[https://en.wikipedia.org/wiki/DjVu][DjVu]] files.
Reading the code shown by src_emacs-lisp{(find-function
'doc-view-djvu->tiff-converter-ddjvu)} shows that reading [[https://en.wikipedia.org/wiki/DjVu][DjVu]] files requires
the command line [[https://en.wikipedia.org/wiki/DjVu][DjVu]] decoder =ddjvu= from the [[http://djvu.sourceforge.net/][DjVuLibre]] utilities.
** Reading EPUB files
:PROPERTIES:
:CUSTOM_ID: sec:reading-epub-files
:END:
2021-11-29 13:14:56 +01: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
#+caption[Configure =nov=]:
#+caption: Configure =nov=.
#+name: lst:configure-nov
2021-11-29 13:14:56 +01:00
#+begin_src emacs-lisp
2022-05-21 14:23:38 +02:00
(when (and (ensure-package-installation 'nov)
(fboundp 'nov-mode))
(add-to-list 'auto-mode-alist `(,(rx ".epub" eos) . nov-mode)))
2021-11-29 13:14:56 +01:00
#+end_src
** 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]]
files produced with LaTeX to the original LaTeX sources. The [[https://github.com/nicolaisingh/saveplace-pdf-view#readme][saveplace-pdf-view]]
package saves =pdf-view= and =doc-view= places.
2021-11-29 13:14:56 +01:00
2022-02-17 13:14:51 +01:00
In order to use [[https://github.com/vedang/pdf-tools][pdf-tools]], you have to type {{{kbd(M-x pdf-tools-install)}}} after
2021-12-07 08:19:59 +01:00
installation of [[https://github.com/vedang/pdf-tools][pdf-tools]] from [[https://melpa.org/][MELPA]] or after each update of [[https://github.com/freedesktop/poppler][poppler]] to build or
rebuild the =epdfinfo= executable that serves the [[https://en.wikipedia.org/wiki/PDF][PDF]] files to Emacs.
2021-11-29 13:14:56 +01:00
#+caption[Configure =pdf-tools=]:
#+caption: Configure =pdf-tools=.
#+name: lst:configure-pdf-tools
2021-11-29 13:14:56 +01:00
#+begin_src emacs-lisp
2022-05-21 14:51:33 +02:00
(when (and (ensure-package-installation 'pdf-tools 'saveplace-pdf-view)
(fboundp 'pdf-loader-install))
;; `pdf-loader-install' is the lazy equivalent of `pdf-tools-install':
;; see the README file.
(pdf-loader-install)
2021-12-07 05:45:38 +01:00
(with-eval-after-load 'pdf-outline
;; Unmask the `image-save' key binding in `pdf-view-mode-map' and
;; in `image-mode-map' (by parenthood).
(define-key pdf-outline-minor-mode-map (kbd "o") nil)
(define-key pdf-outline-minor-mode-map (kbd "O") #'pdf-outline))
(with-eval-after-load 'pdf-view
(custom-set-variables
'(pdf-view-display-size 'fit-page)
`(pdf-view-use-scaling ,(eq system-type 'darwin)))
(require 'saveplace-pdf-view nil 'noerror)))
2021-11-29 13:14:56 +01:00
#+end_src
* Writing
:PROPERTIES:
:CUSTOM_ID: sec:writing
:END:
2021-11-29 13:14:56 +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
[[https://en.wikipedia.org/wiki/AUCTeX][AUCTeX]]. For instance, 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=,
Emacs will complain that ~TeX-master~ is no safe local variable in case it reads
a LaTeX file that sets ~TeX-master~. Listing [[lst:require-auctex]] initializes
[[https://en.wikipedia.org/wiki/AUCTeX][AUCTeX]] properly for LuaTeX or LuaLaTeX. In case the output of =LuaLaTeX= has
missing fonts, listing [[lst:update-lualatex-opentype-font-name-database]] defines a
function to update the =OpenType Font= name database for =LuaLaTeX=. Finally,
out of the box, [[https://en.wikipedia.org/wiki/AUCTeX][AUCTeX]] does not indent text between square brackets. The code
in listing [[lst:configure-auctex]] corrects this by advising to override
~TeX-brace-count-line~ with ~TeX-brace-count-line-advice~.
2021-11-29 13:14:56 +01:00
#+caption[Require =AUCTeX=]:
#+caption: Require =AUCTeX=.
2021-12-28 08:48:03 +01:00
#+name: lst:require-auctex
2021-11-29 13:14:56 +01:00
#+begin_src emacs-lisp
;; Use `require' to make `TeX-master' a safe local variable.
2021-11-29 13:14:56 +01:00
(when (require 'tex nil 'noerror)
(custom-set-variables
'(TeX-auto-save t)
'(TeX-engine 'luatex)
'(TeX-install-font-lock #'font-latex-setup)
'(TeX-parse-self t)
;; Disable `TeX-electric-math' to prevent collisions with `smartparens'.
'(TeX-electric-math nil)))
#+end_src
#+caption[Update the =LuaLaTeX OpenType Font= name database]:
#+caption: Update the =LuaLaTeX= =OpenType Font= name database.
#+name: lst:update-lualatex-opentype-font-name-database
#+begin_src emacs-lisp
(with-eval-after-load 'emacs
(defun update-lualatex-opentype-font-name-database ()
"Update the \"OpenType Font\" name database for \"LuaLaTeX\"."
(interactive)
(cl-destructuring-bind (exit-code output)
(shell-command-with-exit-code
"luaotfload-tool" "-vv" "--update" "--force")
(if (= 0 exit-code) (message "%s" (string-trim output))
(error "%s" (string-trim output))))))
#+end_src
#+caption[Configure =AUCTeX=]:
#+caption: Configure =AUCTeX=.
#+name: lst:configure-auctex
#+begin_src emacs-lisp
(when (require 'tex nil 'noerror)
;; https://emacs.stackexchange.com/a/35507 answers:
;; How to indent between square brackets?
(defun TeX-brace-count-line-override ()
"Count number of open/closed braces."
(save-excursion
(let ((count 0) (limit (line-end-position)) char)
(while (progn
(skip-chars-forward "^{}[]\\\\" limit)
(when (and (< (point) limit) (not (TeX-in-comment)))
(setq char (char-after))
(forward-char)
(cond ((eq char ?\{)
(setq count (+ count TeX-brace-indent-level)))
((eq char ?\})
(setq count (- count TeX-brace-indent-level)))
((eq char ?\[)
(setq count (+ count TeX-brace-indent-level)))
((eq char ?\])
(setq count (- count TeX-brace-indent-level)))
((eq char ?\\)
(when (< (point) limit)
(forward-char) t))))))
count)))
(defun toggle-TeX-brace-count-line-override ()
"Toggle `TeX-brace-count-line-override' advice."
(interactive)
(toggle-advice 'TeX-brace-count-line :override #'TeX-brace-count-line-override))
(toggle-TeX-brace-count-line-override))
#+end_src
Listing [[lst:configure-bibtex]] configures the Emacs =bibtex= library to use the
LaTeX =BiBTeX= dialect for backwards compatibility. Listing
[[lst:configure-font-latex]] disables font scaling of section titles. Listing
[[lst:configure-latex]] configures =latex= for a full featured
=LaTeX-section-command=.
#+caption[Configure =bibtex=]:
#+caption: Configure =bibtex=.
2021-12-28 08:48:03 +01:00
#+name: lst:configure-bibtex
#+begin_src emacs-lisp
(with-eval-after-load 'bibtex
(custom-set-variables '(bibtex-dialect 'BibTeX)))
#+end_src
#+caption[Configure =font-latex=]:
#+caption: Configure =font-latex=.
2021-12-28 08:48:03 +01:00
#+name: lst:configure-font-latex
#+begin_src emacs-lisp
(with-eval-after-load 'font-latex
(custom-set-variables
'(font-latex-fontify-sectioning 1.0)))
#+end_src
#+caption[Configure =latex=]:
#+caption: Configure =latex=.
2021-12-28 08:48:03 +01:00
#+name: lst:configure-latex
#+begin_src emacs-lisp
(with-eval-after-load 'latex
2021-12-07 17:22:31 +01:00
(custom-set-variables
'(LaTeX-electric-left-right-brace t)
2021-12-07 17:22:31 +01:00
'(LaTeX-section-hook '(LaTeX-section-heading
LaTeX-section-title
LaTeX-section-toc
LaTeX-section-section
LaTeX-section-label))))
#+end_src
2022-05-18 07:12:32 +02:00
*** [[https://gitlab.com/matsievskiysv/math-preview/-/blob/master/README.md][Math-preview]]
:PROPERTIES:
:CUSTOM_ID: sec:math-preview
:END:
2022-05-18 07:12:32 +02:00
[[https://gitlab.com/matsievskiysv/math-preview/-/blob/master/README.md][Math-preview]] uses [[https://docs.mathjax.org/en/latest/][Mathjax-3]] to display [[https://www.latex-project.org/][LaTeX]], [[https://www.w3.org/Math/][MathML]],and [[http://asciimath.org/][asciimath]] in Emacs
buffers with help of an external [[https://nodejs.org][node.js]] program.
#+caption[Configure =math-preview=]:
#+caption: Configure =math-preview=.
#+name: lst:configure-math-preview
#+begin_src emacs-lisp
(when (ensure-package-installation 'math-preview)
(with-eval-after-load 'math-preview
2022-05-18 07:12:32 +02:00
;; https://docs.mathjax.org/en/latest/input/tex/extensions/physics.html
(let ((physics (split-string "
abs absolutevalue acomm acos acosecant acosine acot acotangent
acsc admat anticommutator antidiagonalmatrix arccos arccosecant
arccosine arccot arccotangent arccsc arcsec arcsecant arcsin
arcsine arctan arctangent asec asecant asin asine atan atangent
bmqty bqty Bqty bra braket comm commutator cos cosecant cosh
cosine cot cotangent coth cp cross crossproduct csc csch curl dd
derivative det determinant diagonalmatrix diffd differential div
divergence dmat dotproduct dv dyad erf ev eval evaluated exp
expectationvalue exponential expval fderivative fdv flatfrac
functionalderivative grad gradient gradientnabla hypcosecant
hypcosine hypcotangent hypsecant hypsine hyptangent
identitymatrix Im imaginary imat innerproduct ip ket ketbra
laplacian ln log logarithm matrixdeterminant matrixel
matrixelement matrixquantity mdet mel mqty naturallogarithm norm
op order outerproduct partialderivative paulimatrix pb
pderivative pdv pmat pmqty Pmqty poissonbracket pqty Pr
principalvalue Probability pv PV qall qand qas qassume qc qcc
qcomma qelse qeven qfor qgiven qif qin qinteger qlet qodd qor
qotherwise qq qqtext qsince qthen qty quantity qunless qusing
rank Re real Res Residue sbmqty sec secant sech sin sine sinh
smallmatrixquantity smdet smqty spmqty sPmqty svmqty tan tangent
tanh tr Tr trace Trace va var variation vb vdot vectorarrow
vectorbold vectorunit vmqty vnabla vqty vu xmat xmatrix
zeromatrix zmat")))
(cl-pushnew `("physics" . ,physics)
math-preview-tex-packages-autoload-packages))
(setq math-preview-raise 0.5
math-preview-scale 1
math-preview-tex-default-packages '("autoload" "ams" "physics"))
(let ((command (executable-find "~/node_modules/.bin/math-preview")))
(if command
2022-05-18 07:12:32 +02:00
(setq math-preview-command command)
;; https://stackoverflow.com/a/17509764 answers:
;; How to install an npm package from github directly?
2022-05-18 07:12:32 +02:00
(unless (file-directory-p "~/node_modules")
(make-directory "~/node_modules"))
(cl-destructuring-bind (exit-code output)
(shell-command-with-exit-code
"npm" "install" "git+https://gitlab.com/matsievskiysv/math-preview.git")
(if (= 0 exit-code) (message "%s" (string-trim output))
(error "%s" (string-trim output))))))))
#+end_src
2021-12-11 12:19:35 +01:00
*** TODO Improve the AUCTeX configuration slowly
:PROPERTIES:
:CUSTOM_ID: sec:configure-auctex-slowly
:END:
2021-12-11 12:19:35 +01:00
[[https://github.com/thisirs/dotemacs/blob/master/lisp/init-auctex.el][AUCTeX setup of an experienced user]]
** Writing Org files
:PROPERTIES:
:CUSTOM_ID: sec:writing-org-files
:END:
2021-11-29 13:14:56 +01:00
*** [[info:org#Activation][Org activation (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:activate-org
:END:
2021-11-29 13:14:56 +01:00
#+caption[Activate =Org=]:
#+caption: Activate =Org=.
2021-12-28 08:48:03 +01:00
#+name: lst:activate-org
2021-11-29 13:14:56 +01:00
#+begin_src emacs-lisp
(when (cl-every #'fboundp '(org-agenda org-capture))
(global-set-key (kbd "C-c a") #'org-agenda)
(global-set-key (kbd "C-c c") #'org-capture)
(with-eval-after-load 'ol
(global-set-key (kbd "C-c l") #'org-store-link)
(global-set-key (kbd "C-c C-l") #'org-insert-link-global)))
2021-11-29 13:14:56 +01:00
#+end_src
*** Org customization
:PROPERTIES:
:CUSTOM_ID: sec:customize-org
:END:
2021-11-29 13:14:56 +01:00
Listing [[lst:customize-org-babel]], [[lst:customize-org]], [[lst:customize-org-link]] does
basic customization of [[https://orgmode.org/][Org-mode]] variables. Listing
[[lst:customize-org-for-lualatex-export]], and
[[lst:customize-ox-latex-for-lualatex-export]] configure [[https://orgmode.org/][Org-mode]] for export to
LuaLaTeX. Listing [[lst:customize-ob-python]] allows to pretty-print Python session
source block values with [[https://github.com/psf/black#readme][black]] instead of [[https://docs.python.org/3/library/pprint.html][pprint]]. Listing
[[lst:customize-org-link]] configures =org-link= to use relative file path links.
Listing [[lst:customize-org-latex-classes]] defines [[info:org#LaTeX specific export settings][org-latex-classes (info)]] for
backward compatibility. See table [[tab:org-latex-class-tag-placeholder]] and type
{{{kbd(C-h v org-latex-classes)}}} for an explanation of the code in listing
[[lst:customize-org-latex-classes]].
#+attr_latex: :booktabs yes :float table
#+caption[The relation tag-placeholder in listing [[lst:customize-org-latex-classes]]]:
#+caption: The relation tag-placeholder in listing [[lst:customize-org-latex-classes]].
#+name: tab:org-latex-class-tag-placeholder
| tag | placeholder |
|-----+-----------------------|
| +1 | [DEFAULT-PACKAGES] |
| +2 | [PACKAGES] |
| +3 | [EXTRA] |
| -1 | [NO-DEFAULT-PACKAGES] |
| -2 | [NO-PACKAGES] |
| -3 | [NO-EXTRA] |
#+caption[Customize =org-babel=]:
#+caption: Customize =org-babel=.
2021-12-28 08:48:03 +01:00
#+name: lst:customize-org-babel
2021-11-29 13:14:56 +01:00
#+begin_src emacs-lisp
(with-eval-after-load 'ob-core
(custom-set-variables
'(org-confirm-babel-evaluate nil)))
2022-01-04 13:11:21 +01:00
(with-eval-after-load 'ob-latex
(custom-set-variables
'(org-babel-latex-preamble
(lambda (_)
"\\documentclass[preview]{standalone}\n"))
'(org-babel-latex-begin-env
(lambda (_)
"\\begin{document}\n"))
'(org-babel-latex-end-env
(lambda (_)
"\\end{document}\n"))))
(with-eval-after-load 'ob-lisp
(with-eval-after-load 'sly
(custom-set-variables
'(org-babel-lisp-eval-fn #'sly-eval))))
2022-05-27 06:52:27 +02:00
(with-eval-after-load 'ob-python
(custom-set-variables
'(org-babel-python-command
"ipython3 --simple-prompt --HistoryAccessor.enabled=False")))
#+end_src
2022-04-23 14:26:59 +02:00
#+caption[Customize =ob-python=]:
#+caption: Customize =ob-python=.
#+name: lst:customize-ob-python
#+begin_src emacs-lisp
2022-04-23 14:26:59 +02:00
(with-eval-after-load 'ob-python
(defun org-babel-python-format-session-value-override
(src-file result-file result-params)
"Return Python code to evaluate SRC-FILE and write result to RESULT-FILE.
Use `black' instead of `pprint' when \"pp\" is a member of RESULT-PARAMS."
(format "\
import ast
with open('%s') as __org_babel_python_tmpfile:
__org_babel_python_ast = ast.parse(__org_babel_python_tmpfile.read())
__org_babel_python_final = __org_babel_python_ast.body[-1]
if isinstance(__org_babel_python_final, ast.Expr):
__org_babel_python_ast.body = __org_babel_python_ast.body[:-1]
exec(compile(__org_babel_python_ast, '<string>', 'exec'))
__org_babel_python_final = eval(
compile(ast.Expression(__org_babel_python_final.value), '<string>', 'eval')
)
with open('%s', 'w') as __org_babel_python_tmpfile:
if %s:
import black
__org_babel_python_tmpfile.write(
black.format_str(repr(__org_babel_python_final), mode=black.Mode())
)
else:
__org_babel_python_tmpfile.write(str(__org_babel_python_final))
else:
exec(compile(__org_babel_python_ast, '<string>', 'exec'))
__org_babel_python_final = None"
(org-babel-process-file-name src-file 'noquote)
(org-babel-process-file-name result-file 'noquote)
2022-05-27 06:52:27 +02:00
(if (member "pp" result-params) "True" "False"))))
2022-05-27 06:52:27 +02:00
(with-eval-after-load 'emacs
(defun toggle-org-babel-python-format-session-value-override ()
"Toggle `org-babel-python-format-session-value' advice."
(interactive)
(toggle-advice 'org-babel-python-format-session-value
:override #'org-babel-python-format-session-value-override))
(toggle-org-babel-python-format-session-value-override))
2021-11-29 13:14:56 +01:00
#+end_src
#+caption[Customize =Org=]:
#+caption: Customize =Org=.
2021-12-28 08:48:03 +01:00
#+name: lst:customize-org
#+begin_src emacs-lisp
(with-eval-after-load 'org
(custom-set-variables
'(org-babel-load-languages '((C . t)
(calc . t)
(dot . t)
(emacs-lisp . t)
(eshell . t)
(fortran . t)
(gnuplot . t)
2022-07-01 10:02:53 +02:00
(js . t)
(latex . t)
(lisp . t)
(maxima . t)
(org . t)
(perl . t)
(python . t)
(shell . t)))
2022-01-05 17:38:01 +01:00
'(org-export-backends '(ascii beamer html icalendar latex odt texinfo))
'(org-file-apps '((auto-mode . emacs)
(directory . emacs)
("\\.mm\\'" . default)
("\\.x?html?\\'" . default)
("\\.pdf\\'" . emacs)))
'(org-modules '(ol-bibtex
ol-doi
ol-eww
ol-info
org-id
org-protocol
org-tempo))
'(org-structure-template-alist '(("a" . "export ascii")
("c" . "center")
("C" . "comment")
("e" . "example")
("E" . "export")
("h" . "export html")
("l" . "export latex")
("q" . "quote")
("s" . "src")
("p" . "src python :session")
("v" . "verse")))))
#+end_src
#+caption[Configure =org-mode-map=]:
#+caption: Configure =org-mode-map=.
#+name: lst:configure-org-mode-map
#+begin_src emacs-lisp
(with-eval-after-load 'emacs
;; From: "Nicolas Richard" <theonewiththeevillook@yahoo.fr>
;; Date: Fri, 08 Mar 2013 16:23:02 +0100 [thread overview]
;; Message-ID: <87vc913oh5.fsf@yahoo.fr> (raw)
(defun org-electric-dollar ()
"When called once, insert \\(\\) and leave point in between.
When called twice, replace the previously inserted \\(\\) by one $."
(interactive)
(if (and (looking-at "\\\\)") (looking-back "\\\\(" (- (point) 2)))
(progn (delete-char 2)
(delete-char -2)
(insert "$"))
(insert "\\(\\)")
(backward-char 2)))
(with-eval-after-load 'org
(define-key org-mode-map (kbd "$") #'org-electric-dollar)
2022-06-30 18:07:06 +02:00
(define-key org-mode-map (kbd "M-q") #'org-fill-paragraph)))
#+end_src
#+caption[Customize =org-link=]:
#+caption: Customize =org-link=.
#+name: lst:customize-org-link
#+begin_src emacs-lisp
(with-eval-after-load 'ol
(custom-set-variables
'(org-link-file-path-type 'relative)))
#+end_src
#+caption[Customize =org-export=]:
#+caption: Customize =org-export=.
2021-12-28 08:48:03 +01:00
#+name: lst:customize-org-export
#+begin_src emacs-lisp
(with-eval-after-load 'ox
(custom-set-variables
'(org-export-dispatch-use-expert-ui t)))
#+end_src
#+caption[Customize =org= for export to LuaLaTeX]:
#+caption: Customize =org= for export to LuaLaTeX.
#+name: lst:customize-org-for-lualatex-export
#+begin_src emacs-lisp
(with-eval-after-load 'org
;; https://list.orgmode.org/87o84fd4oi.fsf@posteo.net/
(add-to-list
'org-preview-latex-process-alist
'(luamagick
:programs ("lualatex" "convert")
:description "pdf > png"
:message "you need to install lualatex and imagemagick."
:image-input-type "pdf"
:image-output-type "png"
:image-size-adjust (1.0 . 1.0)
:post-clean nil
:latex-header nil
:latex-compiler ("lualatex -interaction nonstopmode -output-directory %o %f")
:image-converter ("convert -density %D -trim -antialias %f -quality 100 %O")))
(custom-set-variables
'(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[Customize =ox-latex= for export to LuaLaTeX]:
#+caption: Customize =ox-latex= for export to LuaLaTeX.
#+name: lst:customize-ox-latex-for-lualatex-export
#+begin_src emacs-lisp
(with-eval-after-load 'ox-latex
(custom-set-variables
'(org-latex-pdf-process
;; https://tecosaur.github.io/emacs-config/#compiling
("latexmk -f -pdf -%latex -interaction=nonstopmode -shell-escape -outdir=%o %f"))
'(org-latex-compiler "lualatex")
'(org-latex-hyperref-template "\\hypersetup{
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,
}\n")
'(org-latex-listings 'minted)
'(org-latex-minted-langs '((cc "c++")
(conf "text")
(cperl "perl")
(diff "diff")
(shell-script "bash")
(json "json")
(org "text")
(toml "toml")))
'(org-latex-minted-options '(("bgcolor" "LightGoldenrodYellow")))
2021-12-28 08:48:03 +01:00
`(org-latex-logfiles-extensions
',(cl-union '("lof" "lot") org-latex-logfiles-extensions :test #'equal))
'(org-latex-prefer-user-labels t)
'(org-latex-subtitle-separate t)))
#+end_src
#+caption[Customize =org-latex-classes= for backwards compatibility]:
#+caption: Customize =org-latex-classes= for backwards compatibility.
#+name: lst:customize-org-latex-classes
#+begin_src emacs-lisp
(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}")))))))
#+end_src
*** [[https://github.com/bdarcus/citar][Citar: citing bibliography]] with [[https://orgmode.org/][Org Mode]]
2021-12-05 16:40:20 +01:00
:PROPERTIES:
:CUSTOM_ID: sec:citing-bibliography
2021-12-05 16:40:20 +01:00
:END:
[[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
support. In combination with vertico, orderless, embark, marginalia, and
consult, [[https://github.com/bdarcus/citar][Citar]] provides quick filtering and selecting of bibliographic entries
from the minibuffer, as well as the option to run different commands on those
selections. The article [[https://kristofferbalintona.me/posts/202206141852/][Citations in org-mode: Org-cite and Citar]] tries to walk
you from understanding the general context (bibliography producer, text
processor, text to product convertor) to an Emacs setup. Listing
[[lst:configure-oc-cite+citar]] shows my =org-cite=, =citar=, and =org=
configuration.
#+caption[Configure =org-cite= with =citar=]:
#+caption: Configure =oc-cite= with =citar=.
2021-12-28 08:48:03 +01:00
#+name: lst:configure-oc-cite+citar
#+begin_src emacs-lisp
(with-eval-after-load 'oc
2022-07-13 06:11:45 +02:00
;; Org-9.5 needs the requirements, but Org-9.6 does not.
(require 'oc-biblatex)
2022-07-13 06:11:45 +02:00
(require 'oc-csl))
(with-eval-after-load 'org
2022-07-13 06:11:45 +02:00
(define-key org-mode-map (kbd "C-c b") #'org-cite-insert))
(when (ensure-package-installation 'citar 'citar-embark)
(with-eval-after-load 'embark
(when (fboundp 'citar-embark-mode)
(citar-embark-mode +1)))
2022-07-13 06:11:45 +02:00
(with-eval-after-load 'oc
(custom-set-variables
'(org-cite-export-processors '((latex biblatex)
(t csl)))
2022-07-13 06:11:45 +02:00
'(org-cite-global-bibliography '("~/VCS/research/refs.bib")))
(when (require 'citar nil 'noerror)
(custom-set-variables
'(org-cite-activate-processor 'citar)
'(org-cite-follow-processor 'citar)
'(org-cite-insert-processor 'citar))))
(with-eval-after-load 'org
(when (require 'citar nil 'noerror)
(custom-set-variables
'(citar-bibliography '("~/VCS/research/refs.bib"))
'(citar-library-file-extensions '("djvu" "pdf"))
'(citar-library-paths '("~/VCS/research/papers/"))))))
#+end_src
Ref. [cite:@Schulte.MCSE.2011.41] shows that [[https://orgmode.org/][Org-mode]] is a simple, plain-text
markup language for hierarchical documents allowing intermingling of data, code,
and prose. It serves as an example link to to show how to use [[https://github.com/bdarcus/citar][Citar]] within this
setup, provided that =citar-bibliography= and =citar-library-paths= point to
valid directories and files. In an [[https://orgmode.org/][Org-mode]] buffer this setup allows to:
2022-07-13 05:16:00 +02:00
1. Insert one or more [[https://orgmode.org/][Org-mode]] cite links:
1. Type {{{kbd(C-c b)}}} or {{{kbd(M-x org-cite-insert)}}}.
2022-07-13 05:16:00 +02:00
2. Navigate to a bibliographic entry to insert:
1. Select it with {{{kbd(TAB)}}} to select more entries.
2. Select it with {{{kbd(RET)}}} to select the last entry.
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.
*** 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]]
#+caption[Delete =Biber= cache to get rid of =Biber= exit code 2]:
#+caption: Delete =Biber= cache to get rid of =Biber= exit code 2.
#+name: lst:delete-biber-cache
#+begin_src emacs-lisp
(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."
(cl-destructuring-bind (exit-code output)
(shell-command-with-exit-code "rm" "-rf" "$(biber --cache)")
(if (= 0 exit-code) (message "%s") (string-trim output)
(error "%s" (string-trim output))))))
#+end_src
*** [[https://github.com/tecosaur/engrave-faces#readme][Engrave Faces]]
:PROPERTIES:
:CUSTOM_ID: sec:engrave-faces
:END:
This package aims to produce a versatile generic core which can process a
fontified buffer and pass the data to any number of backends to deal with
specific output formats.
I have tried to configure [[info:org#Source blocks in LaTeX export][Org source block export to LaTeX (info)]] setting
=org-latex-src-block-backend= to =engraved= instead of =minted=, but the LaTeX
backend chokes on multi-line documentation strings.
#+caption[Ensure installation of =engrave= for experimentation]:
#+caption: Ensure installation of =engrave= for experimentation.
#+name: lst:ensure-engrave-installation
#+begin_src emacs-lisp
(when (ensure-package-installation 'engrave-faces)
(message "Engrave-faces chokes on multi-line documentation strings."))
#+end_src
*** [[info:org#Adding Hyperlink Types][Making Org hyperlink types (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:making-org-hyperlink-types
:END:
Listing [[lst:org-ref-like-org-link-types]] defines =org-link= types for backwards
compatibility with [[https://github.com/jkitchin/org-ref][org-ref]]. 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]]. Finally, listing
[[lst:patch-org-info-link-type]] patches the function =org-info-export= 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.
#+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
#+begin_src emacs-lisp
(with-eval-after-load 'ol
(org-link-set-parameters
"ac*" :export (lambda (path _desc backend _info)
(pcase backend
(`latex (format "\\gls*{%s}" path))
(_ path))))
(org-link-set-parameters
"cite" :export (lambda (path _desc backend _info)
(pcase backend
(`latex (format "\\cite{%s}" path))
(_ path))))
(org-link-set-parameters
"eqref" :export (lambda (path _desc backend _info)
(pcase backend
(`latex (format "\\eqref{%s}" path))
(_ path))))
2021-12-16 17:44:55 +01:00
(org-link-set-parameters
"hyperlink" :export (lambda (path desc backend _info)
(pcase backend
(`latex (format "\\hyperlink{%s}{%s}" path desc))
(_ path))))
(org-link-set-parameters
"label" :export (lambda (path _desc backend _info)
(pcase backend
(`latex (format "\\label{%s}" path))
(_ path))))
(org-link-set-parameters
"ref" :export (lambda (path _desc backend _info)
(pcase backend
(`latex (format "\\ref{%s}" path))
(_ path)))))
#+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=.
#+name: lst:define-org-pdfview-link-type
#+begin_src emacs-lisp
(with-eval-after-load 'ol
(autoload 'pdf-view-goto-page "pdf-view" nil t)
(org-link-set-parameters "pdfview"
:follow #'org-pdfview-open
:export #'org-pdfview-export
:store #'org-pdfview-store-link)
(defun org-pdfview-export (link description backend _)
"Export a \"pdfview\" type link.
The paths of the links export as file relative paths in order to
facilate moving single directories or whole directory trees."
(let ((path (if (string-match "\\(.+\\)::.+" link)
(match-string 1 link)
link))
(desc (or description link)))
(when (stringp path)
(setq path (file-relative-name path))
(pcase backend
(`html (format "<a href=\"%s\">%s</a>" path desc))
(`latex (format "\\href{%s}{%s}" path desc))
(`ascii (format "%s (%s)" desc path))
(_ path)))))
(defun org-pdfview-open (link _)
"Open a \"pdfview\" type link."
(string-match "\\(.*?\\)\\(?:::\\([0-9]+\\)\\)?$" link)
(let ((path (match-string 1 link))
(page (and (match-beginning 2)
(string-to-number (match-string 2 link)))))
;; Let Org mode open the file (in-emacs = 1) to ensure
;; org-link-frame-setup is respected.
(org-open-file path 1)
(when page (pdf-view-goto-page page))))
(defun org-pdfview-store-link ()
"Store a \"pdfview\" type link."
(when (eq major-mode 'pdf-view-mode)
(let* ((path buffer-file-name)
(page (pdf-view-current-page))
2022-02-07 18:24:31 +01:00
(link (concat "pdfview:" path "::" (number-to-string page))))
(org-link-store-props
2022-02-16 07:46:40 +01:00
:type "pdfview"
:link link
:description path)))))
#+end_src
2021-12-05 16:40:20 +01:00
#+caption[Patch =ol-info=]:
#+caption: Patch =ol-info=.
#+name: lst:patch-org-info-link-type
#+begin_src emacs-lisp :exports code :results silent
(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)))))
#+end_src
2022-07-01 10:02:05 +02:00
#+attr_latex: :options breaklines
#+caption[Patch buffer local =ol-info=]:
#+caption: Patch buffer local =ol-info=.
#+name: lst:emacs-lisp-setup-buffer-local-ol-info
#+begin_src emacs-lisp :exports code :silent :tangle no
(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")
("marginalia" . "https://github.com/minad/marginalia")
2022-07-01 10:02:05 +02:00
("maxima" . "https://maxima.sourceforge.io/docs/manual/maxima_singlepage.html")
("org" . "https://orgmode.org/org.html")
("orderless" . "https://github.com/oantolin/orderless")
("sly" . "https://joaotavora.github.io/sly/")
("vertico" . "https://github.com/minad/vertico"))
org-info-other-documents :test #'equal)))
2021-12-05 16:40:20 +01:00
#+end_src
2022-07-01 10:02:05 +02:00
*** [[https://tecosaur.github.io/emacs-config/#translate-capital-keywords][Translate capital keywords (old) to lower case (new)]]
:PROPERTIES:
:CUSTOM_ID: sec:convert-upper-to-lower-case-keywords
:END:
2021-11-29 13:14:56 +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
2021-11-29 13:14:56 +01:00
#+begin_src emacs-lisp
(with-eval-after-load 'emacs
;; https://tecosaur.github.io/emacs-config/#translate-capital-keywords
2021-11-29 13:14:56 +01:00
(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]]
: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]]
#+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
2021-11-29 13:14:56 +01:00
#+begin_src emacs-lisp
(with-eval-after-load 'emacs
2022-05-09 07:21:12 +02:00
(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)
2022-05-09 07:21:12 +02:00
(org-eval-named-blocks-with-infix "emacs-lisp-setup"))
(defun org-eval-python-setup-blocks ()
"Evaluate all source blocks having \"python-setup\" in their name."
(interactive)
2022-05-09 07:21:12 +02:00
(org-eval-named-blocks-with-infix "python-setup"))
;; 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
*** [[info:org#LaTeX header and sectioning][Easy LaTeX preamble editing]]
:PROPERTIES:
:CUSTOM_ID: sec:easy-latex-preamble-editing
:END:
There are at least two ways (new and old) to edit the LateX preamble
=latex_header= and =latex-extra_header= export options easily in LaTeX source or
export blocks. This [[info:org#Top][Org (info)]] file uses the new way, but keeps the old way for
backwards compatibility.
The new way -- exploiting an idea of [[https://www.matem.unam.mx/~omar/][Omar Antolin Camarena]] -- is to code new
[[info:org#Editing Source Code][<LANGUAGE>-modes]] allowing to edit in LaTeX mode and to export to LaTeX code with
[[info:org#LaTeX specific export settings][correct LaTeX preamble export setting prefixes]]. Here, are links to three posts
exposing his idea:
1. [[https://www.reddit.com/r/orgmode/comments/7u2n0h/tip_for_defining_latex_macros_for_use_in_both/][Export LaTeX macros to LaTeX and HTML/MathJax preambles (reddit)]],
2. [[https://www.reddit.com/r/orgmode/comments/5bi6ku/tip_for_exporting_javascript_source_block_to/][Export JavaScript source blocks to script tags in HTML (reddit)]],
3. [[https://emacs.stackexchange.com/questions/28301/export-javascript-source-block-to-script-tag-in-html-when-exporting-org-file-to][Export JavaScript source blocks to script tags in HTML (SX)]].
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=.
#+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
#+begin_src emacs-lisp :exports code :silent
(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.
This function is called by `org-babel-execute-src-block' and
prefixes all lines with \"#+latex_extra_header: \"."
(prefix-all-lines "#+latex_extra_header: " body))
(defun org-babel-execute:latex-header (body _params)
"Execute a block of LaTeX header lines with org-babel.
2022-01-05 17:38:01 +01:00
This function is called by `org-babel-execute-src-block' and
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
(custom-set-variables
'(org-src-window-setup 'current-window))
(add-to-list 'org-src-lang-modes '("toml" . conf-toml))
(add-to-list 'org-src-lang-modes '("latex-header" . latex))
(add-to-list 'org-src-lang-modes '("latex-extra-header" . latex))))
#+end_src
The old way is to use a special export attribute as in the function
=org-latex-header-blocks-filter= in [[https://git.sr.ht/~bzg/org-contrib/tree/master/item/lisp/ox-extra.el][ox-extra.el]]. Apparently, nobody is using
this broken function (broken, since it relies on support only in org-mode before
2021-12-29 14:05:03 +01:00
=2014-11-11=). Listing [[lst:org-latex-header-blocks-filter]] proposes a fix for
=org-latex-header-blocks-filter=.
#+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
2021-12-14 10:15:39 +01:00
#+begin_src emacs-lisp
(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.\"."
2021-11-29 13:14:56 +01:00
(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)
2021-12-06 08:30:31 +01:00
;; Set point to where to insert LaTeX header lines
;; after deleting the block.
2021-11-29 13:14:56 +01:00
(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")))))
2021-12-06 08:30:31 +01:00
;; Reverse to go upwards to avoid wrecking the list of
;; block positions in the file that would occur in case
;; of going downwards.
(reverse blocks)))))
;; Push the filter on the hook.
(cl-pushnew #'org-latex-header-blocks-filter
org-export-before-parsing-hook))
2021-12-14 10:15:39 +01:00
#+end_src
2021-11-29 13:14:56 +01:00
2021-12-29 14:05:03 +01:00
This file uses the new way, while keeping the old way for backwards
compatibility, because the new way feels less hackish than the old way. A
practical difference is that new way source blocks (contrary to old way export
blocks) do not work in [[info:org#Export Settings][#+SETUPFILE: <FILE>]], but only in [[info:org#Export Settings][#+INCLUDE: <FILE>]] files.
2021-11-29 13:14:56 +01:00
*** [[info:org#Export Settings][#+INCLUDE: <FILE> (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:include-file-usage
:END:
Evaluation of the source block in listing
[[lst:make-source-block-with-export-keyword-settings]] produces the source block
that exports to listing [[lst:source-file-export-keyword-settings]] in order to show
the first nine lines of this [[file:README.org]] file. The last line shows that
[[file:include.org][include.org]] is the argument for [[info:org#Export Settings][#+INCLUDE: <FILE>]].
#+caption[Make setup and include file export keyword settings source block]:
#+caption: The shell script to make the source block containing the export
#+caption: keyword settings.
#+name: lst:make-source-block-with-export-keyword-settings
#+begin_src shell :exports both :results drawer
echo "#+caption[Source file export keyword settings]:"
echo "#+caption: The first nine lines of README.org containing the export"
echo "#+caption: keyword settings."
echo "#+name: lst:source-file-export-keyword-settings"
echo "#+begin_src org :tangle no"
head -n 9 README.org
echo -n "#+end_src"
#+end_src
#+RESULTS: lst:make-source-block-with-export-keyword-settings
:results:
2021-12-29 14:05:03 +01:00
#+caption[Source file export keyword settings]:
#+caption: The first nine lines of README.org containing the export
#+caption: keyword settings.
2021-12-29 14:05:03 +01:00
#+name: lst:source-file-export-keyword-settings
#+begin_src org :tangle no
#+title: Emacs setup for use with LaTeX, Org, and Python
#+author: Gerard Vermeulen
#+latex_class: article-local
#+latex_class_options: [11pt,a4paper,english,svgnames,tables]
#+macro: kbd (eval (by-backend-kbd-org-macro $1))
#+property: header-args:emacs-lisp :exports code :results silent :tangle init.el
#+property: header-args:org :tangle include.org
2022-08-20 15:19:02 +02:00
#+startup: showeverything
#+include: "include.org"
2021-12-29 14:05:03 +01:00
#+end_src
:end:
2021-12-29 14:05:03 +01:00
Listing [[lst:by-backend-kbd-org-macro]] defines the tools for the definition of the
[[https://orgmode.org/][Org mode]] =kbd= macro on the fifth line of listing
[[lst:source-file-export-keyword-settings]].
#+attr_latex: :options breaklines
#+caption[Define the tools of the =Org-mode= =kbd= macro]:
#+caption: Define the tools for the =Org-mode= =kbd= macro.
#+name: lst:by-backend-kbd-org-macro
#+begin_src emacs-lisp
(with-eval-after-load 'emacs
2022-05-22 14:36:55 +02:00
(when (ensure-package-installation 'htmlize)
(autoload 'htmlize-protect-string "htmlize" nil t))
;; https://orgmode.org/worg/org-contrib/babel/languages/ob-doc-LaTeX.html#orge5c50fd
(defmacro by-backend (&rest body)
"Help for org-export backend dependent execution."
`(cl-case ',(bound-and-true-p org-export-current-backend) ,@body))
(defun by-backend-kbd-org-macro (keys)
"Help for an org-export backend dependent \"#+macro: kbd\"."
(by-backend
(html (format "@@html:<kbd>%s</kbd>@@" (htmlize-protect-string keys)))
(latex (format "@@latex:\\colorbox{PowderBlue}{\\texttt{%s}}@@" keys)))))
#+end_src
Listing [[lst:use-latex-header-1]], [[lst:use-latex-header-2]], [[lst:use-latex-header-3]],
[[lst:use-latex-header-4]], and [[lst:use-latex-header-5]] tangle into the
[[file:include.org][include.org]] file in order to create the [[https://www.latex-project.org/][LaTeX]] preamble.
#+caption[LaTeX preamble: replacing the =Org-mode= default packages]:
#+caption: LaTeX preamble: replacing the =Org-mode= default packages.
#+name: lst:use-latex-header-1
#+begin_src org
,#+begin_src latex-header
% 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
}
}
\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_src
#+end_src
#+caption[LaTeX preamble: language, lists and floats]:
#+caption: LaTeX preamble: language, lists and floats.
#+name: lst:use-latex-header-2
#+begin_src org
,#+begin_src latex-header
% 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_src
#+end_src
#+caption[LaTeX preamble: page layout]:
#+caption: LaTeX preamble: page layout.
#+name: lst:use-latex-header-3
#+begin_src org
,#+begin_src latex-header
% PAGE LAYOUT:
\usepackage{fancyhdr}
\usepackage{lastpage}
\usepackage[
headheight=20mm,
top=40mm,
bottom=20mm,
left=60pt,
right=60pt,
heightrounded,
verbose,
]{geometry}
% TECHNICS:
\usepackage{siunitx}
\usepackage{tikz}
,#+end_src
#+end_src
#+caption[LaTeX preamble: float barriers]:
#+caption: LaTeX preamble: float barriers.
#+name: lst:use-latex-header-4
#+begin_src org
,#+begin_src latex-header
% 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
}%
}
\makeatother
,#+end_src
#+end_src
#+caption[LaTeX preamble: fancy headers and footers]:
#+caption: LaTeX preamble: fancy headers and footers.
#+name: lst:use-latex-header-5
#+begin_src org
,#+begin_src latex-header
% FANCY HEADERS AND FOOTERS:
% Add fancy headers and footers to normal pages.
\pagestyle{fancy}
\fancyhf{}
\renewcommand{\footrulewidth}{0.4pt}
\fancyfoot[C]{\emph{
Emacs setup for use with \LaTeX{}, Org, and Python -- Gerard Vermeulen}}
\renewcommand{\headrulewidth}{0.4pt}
\fancyhead[L]{\includegraphics[height=1.8cm]{Org-mode-unicorn.png}}
\fancyhead[C]{
Page: \thepage/\pageref{LastPage} \\
\text{ } \\
\text{ } \\
DRAFT
}
\fancyhead[R]{\includegraphics[height=1.8cm]{Emacs-logo.png}}
% Add fancy header and footer to custom titlepage.
% https://tex.stackexchange.com/questions/506102/
% adding-header-and-footer-to-custom-titlepage
\fancypagestyle{titlepage}{%
\fancyhf{}
\renewcommand{\footrulewidth}{0.4pt}
\fancyfoot[C]{\emph{
Emacs setup for use with \LaTeX{}, Org, and Python -- Gerard Vermeulen}}
\renewcommand{\headrulewidth}{0.4pt}
\fancyhead[L]{\includegraphics[height=1.8cm]{Org-mode-unicorn.png}}
\fancyhead[C]{
\pageref{LastPage} pages \\
\text{ } \\
\text{ } \\
DRAFT
}
\fancyhead[R]{\includegraphics[height=1.8cm]{Emacs-logo.png}}
}
% #+latex_header: END.
,#+end_src
#+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:
Listing [[lst:ox-latex-emacs-lisp-setup]] initializes the buffer local variables
=org-latex-classes=, =org-latex-title-command=, =org-latex-toc-command=, and
=org-latex-subtitle-format=. Listing [[lst/title-page]] is a template to initialize
=org-latex-title-command=. Type {{{kbd(M-x org-latex-classes)}}}, {{{kbd(M-x
org-latex-subtitle-format)}}}, {{{kbd(M-x org-latex-title-command)}}}, and
{{{kbd(M-x org-latex-toc-command)}}} to read how those variables control
exporting from Org-mode to LaTeX.
2021-12-29 14:05:03 +01:00
#+caption[Define buffer local =ox-latex= variables]:
#+caption: Define buffer local =-ox-latex= variables.
#+header: :var title-page=lst/title-page
#+name: lst:ox-latex-emacs-lisp-setup
#+begin_src emacs-lisp :results silent :tangle no
(when (require 'ox-latex nil 'noerror)
;; https://emacs.stackexchange.com/questions/47347/
;; customizing-org-latex-title-command-to-edit-title-page
(make-variable-buffer-local 'org-latex-classes)
(cl-pushnew '("article-local"
"\\documentclass[11pt]{article}
2021-12-29 14:05:03 +01:00
[NO-DEFAULT-PACKAGES]
[PACKAGES]
[EXTRA]"
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}")
("\\paragraph{%s}" . "\\paragraph*{%s}")
("\\subparagraph{%s}" . "\\subparagraph*{%s}"))
org-latex-classes :key #'car :test #'equal)
(make-variable-buffer-local 'org-latex-title-command)
(setq org-latex-title-command (concat title-page))
(make-variable-buffer-local 'org-latex-toc-command)
2022-02-23 17:07:03 +01:00
(setq org-latex-toc-command "
\\tableofcontents\\label{toc}
\\listoftables
\\listoffigures
\\newpage
")
(make-variable-buffer-local 'org-latex-subtitle-format)
(setq org-latex-subtitle-format ""))
2021-12-29 14:05:03 +01:00
#+end_src
#+caption[Show a title-page example for =org-latex-title-command=]:
#+caption: Show a title-page example for =org-latex-title-command=.
#+name: lst/title-page
#+begin_src latex :exports code :results silent :tangle no
\begin{titlepage}
%% https://tex.stackexchange.com/questions/506102/
%% adding-header-and-footer-to-custom-titlepage
\thispagestyle{titlepage}
\begin{center}
%% Title
\begin{Huge}
{\bf %t} \\
\vspace{1em}
\end{Huge}
%% Author
\begin{Large}
{\bf %a} \\
\vspace{1em}
\end{Large}
\end{center}
\end{titlepage}
#+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
#+begin_src emacs-lisp
(with-eval-after-load 'org-element
(when (require 'pp nil 'noerror)
2022-01-17 07:56:55 +01:00
(defconst grok-org-output
"*Grok Org Element Output*"
"Grok Org output buffer name.")
(defun grok-org-element-at-point ()
(interactive)
(pp-display-expression
(org-element-at-point) grok-org-output))
(defun grok-org-element-context ()
(interactive)
(pp-display-expression
(org-element-context) grok-org-output))
(defun grok-org-element-parse-buffer ()
(interactive)
(let ((what (completing-read
"granularity: "
'(headline element greater-element object)
nil 'require-match)))
(pp-display-expression
(org-element-parse-buffer what) grok-org-output)))
(defun grok-org-heading-components ()
(interactive)
(pp-display-expression
(org-heading-components) grok-org-output))))
#+end_src
** Grammar, spelling, and style tools
:PROPERTIES:
:CUSTOM_ID: sec:writing-tools
:END:
*** [[info:emacs#Abbrevs][Abbrevs (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:writing-abbreviations
:END:
[[https://www.masteringemacs.org/article/correcting-typos-misspellings-abbrev][Correcting Typos and Misspellings with Abbrev]] is an interesting post by [[https://www.masteringemacs.org/][Mickey
Peterson]] showing how to use [[info:emacs#Keyboard Macros][Keyboard Macros (info)]] to exploit the [[https://en.wikipedia.org/wiki/Wikipedia:Lists_of_common_misspellings/For_machines][Wikipedia
list of common misspellings for machines]]. Listing [[lst:misspellings-abbrev]]
defines his keyboard macro under the name =misspellings-abrev=.
#+caption[Definition of the =misspellings-abbrev= keyboard macro]:
#+caption: Definition of the =misspellings-abbrev= keyboard macro.
#+name: lst:misspellings-abbrev
#+begin_src emacs-lisp
(with-eval-after-load 'emacs
(fset 'misspellings-abbrev
(kmacro-lambda-form
[?\C-s ?- ?> return backspace backspace ?\C-k ?\C-x ?a ?i ?g ?\C-y return]
0 "%d"))
(setq-default abbrev-mode t))
#+end_src
2022-05-22 14:54:12 +02:00
*** [[https://github.com/tecosaur/lexic#readme][Emacs LEXICal information viewer]]
:PROPERTIES:
:CUSTOM_ID: sec:writing-lexic
:END:
The [[https://github.com/tecosaur/lexic#readme][Emacs LEXICal information viewer]] is a front-end for offline dictionary,
etymology, or thesaurus back-ends (current limited to [[https://en.wikipedia.org/wiki/Sdcv][sdcv]]). Listing
[[lst:configure-lexic]] configures [[https://github.com/tecosaur/lexic#readme][lexic]].
#+attr_latex: :options breaklines
2022-05-22 14:54:12 +02:00
#+caption[Configure =lexic=]:
#+caption: Configure =lexic=.
#+name: lst:configure-lexic
#+begin_src emacs-lisp
(when (ensure-package-installation 'lexic)
;; http://download.huzheng.org/fr/
;; https://polyglotte.tuxfamily.org/doku.php?id=donnees:dicos_bilingues
2022-05-22 14:54:12 +02:00
;; http://download.huzheng.org/dict.org/stardict-dictd-web1913-2.4.2.tar.bz2
;; http://download.huzheng.org/dict.org/stardict-dictd_www.dict.org_gcide-2.4.2.tar.bz2
(with-eval-after-load 'lexic
(if-let ((lpp (executable-find "sdcv")))
(custom-set-variables
'(lexic-program-path lpp)
'(lexic-dictionary-alist '(("full" . t)))
;; sdcv --data-dir .local/share -l
'(lexic-dictionary-list
'("Webster's Revised Unabridged Dictionary (1913)"
"dictd_www.dict.org_gcide"))
'(lexic-dictionary-path "~/.local/share"))
(message "`lexic' fails to find the `sdcv' executable"))))
#+end_src
*** [[https://wordnet.princeton.edu/][Wordnet]]
:PROPERTIES:
:CUSTOM_ID: sec:writing-wordnet
:END:
The [[https://github.com/gromnitsky/wordnut#readme][wordnut]] package is a major mode interface to [[https://wordnet.princeton.edu/][Wordnet]], a lexical database for
the English language. Listing [[lst:check-wordnut]] checks whether the system meets
the [[https://github.com/gromnitsky/wordnut#readme][wordnut]] prerequisites.
#+caption[System check for =wordnut=]:
#+caption: System check for =wordnut=.
#+name: lst:check-wordnut
#+begin_src emacs-lisp
(when (ensure-package-installation 'wordnut)
(with-eval-after-load 'wordnut
(if-let ((wn (executable-find "wn")))
(custom-set-variables
'(wordnut-cmd wn))
(message "`wordnut' fails to find the `wn' executable"))))
#+end_src
*** [[https://github.com/bnbeckwith/writegood-mode#readme][Writegood mode]]
:PROPERTIES:
:CUSTOM_ID: sec:writing-writegood-mode
:END:
2022-07-27 07:01:43 +02:00
[[https://github.com/bnbeckwith/writegood-mode#readme][Writegood mode]] is a minor mode to aid in finding common writing problems. The post
[[http://matt.might.net/articles/shell-scripts-for-passive-voice-weasel-words-duplicates/][Matt Might's "My Ph.D. advisor rewrote himself in bash" scripts]] inspired this mode.
Listing [[lst:configure-writegood-mode]] configures [[https://github.com/bnbeckwith/writegood-mode#readme][writegood mode]].
#+caption[Configure =writegood-mode=]:
#+caption: Configure =writegood-mode=.
#+name: lst:configure-writegood-mode
#+begin_src emacs-lisp
2022-05-21 14:23:38 +02:00
(when (and (ensure-package-installation 'writegood-mode)
(fboundp 'writegood-mode))
(global-set-key (kbd "C-c g") #'writegood-mode))
#+end_src
* Programming Tools
:PROPERTIES:
:CUSTOM_ID: sec:programming-tools
:END:
2022-07-27 09:12:02 +02:00
** [[https://github.com/joaotavora/eglot][Eglot]]
:PROPERTIES:
:CUSTOM_ID: sec:eglot
:END:
[[https://github.com/joaotavora/eglot#readme][Emacs polyGLOT (eglot)]] is an Emacs language-server-protocol client that stays
out of the way. The following listings contribute to a programming language
mode independent [[https://github.com/joaotavora/eglot][eglot]] configuration:
1. Listing [[lst:ensure-eglot-installation]] ensures installation of [[https://github.com/joaotavora/eglot][eglot]] with
minimal configuration.
2. Listing [[lst:help-setup-org-src-mode-for-eglot]] and
[[lst:setup-python-org-src-mode-for-eglot]] try to prepare any =org-src-mode=
buffers for use with [[https://github.com/joaotavora/eglot][eglot]]. They are a refactored implementation of the post
[[https://www.reddit.com/r/emacs/comments/w4f4u3/using_rustic_eglot_and_orgbabel_for_literate/][Using rustic, eglot, and org-babel with LSP support in Emacs]] for my use with
Python.
3. Listing [[lst:narrow-format-all-python]] defines a function to format only the
narrowed region of Python =org-src-mode= blocks prepared by means of the code
in listing [[lst:setup-python-org-src-mode-for-eglot]]. *Do not use*
=format-all-buffer= *on such buffers*, since =format-all-buffer= does not
handle the narrowing.
4. Listing [[lst:eglot-maybe-ensure]] starts [[https://github.com/joaotavora/eglot][eglot]] in case of proper programming
modes and proper directory local variables (meaning in presence of a proper
file [[info:emacs#Directory Variables][.dir-locals.el]] in the root directory of any project using proper
programming modes).
#+caption[Ensure =eglot= installation]:
#+caption: Ensure =eglot= installation.
#+name: lst:ensure-eglot-installation
#+begin_src emacs-lisp
(when (ensure-package-installation 'eglot)
;; (defvar eglot-server-programs
;; `((python-mode . ("pylsp" "-vvv")))
;; "Shadow the definition of `eglot-server-programs' in `eglot'.")
(with-eval-after-load 'eglot
(define-key eglot-mode-map (kbd "C-c n") #'flymake-goto-next-error)
(define-key eglot-mode-map (kbd "C-c p") #'flymake-goto-prev-error)
(define-key eglot-mode-map (kbd "C-c r") 'eglot-rename)))
#+end_src
#+caption[Help to setup any =org-src-mode= buffers for =eglot=]:
#+caption: Help to setup any =org-src-mode= buffers for =eglot=.
#+name: lst:help-setup-org-src-mode-for-eglot
#+begin_src emacs-lisp
(when (fboundp 'eglot-ensure)
(defcustom eglot-maybe-ensure-modes '(python-mode)
"Modes where maybe `eglot-ensure' should be or has been called.
This may be in the case of proper directory local variables or in
the case of proper `org-src-mode' buffers.")
;; https://www.reddit.com/r/emacs/comments/w4f4u3
;; /using_rustic_eglot_and_orgbabel_for_literate/
(defun eglot-org-babel-edit-prep (info)
"Try to setup and `org-mode-src' buffer to make `eglot-ensure' succeed.
INFO has a form similar to the return value of
`org-babel-get-src-block-info'. Try to load the tangled file
into the `org-src-mode' buffer as well as to narrow the region to
the Org-mode source block code before calling `eglot-ensure'."
(unless (bound-and-true-p org-src-mode)
(user-error "Buffer %s is no `org-src-mode' buffer" (buffer-name)))
(let ((mark (point))
(body (nth 1 info))
(filename (expand-file-name (cdr (assq :tangle (nth 2 info))))))
(unless (file-readable-p filename)
(user-error "Tangled file %s is not readible" filename))
(with-temp-buffer
(insert-file-contents filename 'visit nil nil 'replace)
(unless (search-forward body nil 'noerror)
(user-error "Org source block does not occur in tangled file %s"
filename))
(when (search-forward body nil 'noerror)
(user-error "Org source block occurs twice or more in tangled file %s"
filename)))
(goto-char (point-min))
(insert-file-contents filename 'visit nil nil 'replace)
(let ((max-point (search-forward body))
(min-point (search-backward body)))
(narrow-to-region min-point max-point))
(goto-char mark)
(eglot-ensure))))
#+end_src
#+caption[Setup Python =org-src-mode= buffers for =eglot=]:
#+caption: Setup Python =org-src-mode= buffers for =eglot=.
#+name: lst:setup-python-org-src-mode-for-eglot
#+begin_src emacs-lisp
(when (fboundp 'eglot-ensure)
;; https://www.reddit.com/r/emacs/comments/w4f4u3
;; /using_rustic_eglot_and_orgbabel_for_literate/
(defun undo-eglot-org-babel-edit-prep()
"Undo the `eglot' setup by deleting the text hidden by narrowing.
This is to advice `org-edit-src-exit' and `org-edit-src-save'."
(when (and (bound-and-true-p org-src-mode)
(buffer-file-name)
(apply #'derived-mode-p eglot-maybe-ensure-modes))
(save-excursion
(goto-char (point-min))
(save-restriction
(widen)
(delete-region (point-min) (point)))
(goto-char (point-max))
(save-restriction
(widen)
(delete-region (point) (point-max))))))
(defun org-babel-edit-prep:python (info)
(eglot-org-babel-edit-prep info))
(advice-add 'org-edit-src-exit :before #'undo-eglot-org-babel-edit-prep)
(advice-add 'org-edit-src-save :before #'undo-eglot-org-babel-edit-prep))
#+end_src
#+caption[Experimental =narrow-format-all:python=]:
#+caption: Experimental =narrow-format-all:python=.
#+name: lst:narrow-format-all-python
#+begin_src emacs-lisp
(when (and (fboundp 'eglot-ensure)
(fboundp 'format-all-buffer))
(defun narrow-format-all:python ()
"Format narrowed Python `org-src-mode' buffers correctly.
Use this function instead of `format-all-buffer' on `org-babel-edit-prep:python'
prepared buffers."
(interactive)
(when (eq major-mode 'python-mode)
(let ((source-min (point-min))
(source-max (point-max))
(source (current-buffer))
(target (get-buffer-create "*narrow-format-all:python*")))
(with-current-buffer target
(barf-if-buffer-read-only)
(erase-buffer)
(save-excursion
(insert-buffer-substring-no-properties
source source-min source-max))
(python-mode)
(setq-local format-all-formatters '(("Python" black)))
(format-all-buffer)
(let ((target-min (point-min))
(target-max (point-max)))
(with-current-buffer source
(erase-buffer)
(save-excursion
(insert-buffer-substring-no-properties
target target-min target-max)))))))))
#+end_src
#+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
#+begin_src emacs-lisp
(when (fboundp 'eglot-ensure)
(defun eglot-maybe-ensure ()
(when (and (apply #'derived-mode-p eglot-maybe-ensure-modes)
(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))
#+end_src
** [[https://github.com/lassik/emacs-format-all-the-code#readme][Format-all]]
:PROPERTIES:
:CUSTOM_ID: sec:format-all
:END:
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.
#+caption[Configure =format-all=]:
#+caption: Configure =format-all=.
#+name: lst:configure-format-all
#+begin_src emacs-lisp
;; https://github.com/lassik/emacs-format-all-the-code#readme
;; https://ianyepan.github.io/posts/format-all/
;; https://jamesaimonetti.com/posts/formatting-tangled-output-in-org-mode/
(when (ensure-package-installation 'format-all)
;; (with-eval-after-load 'prog-mode
;; (when (autoload 'format-all-ensure-formatter "format-all")
;; (add-hook 'prog-mode-hook #'format-all-ensure-formatter)))
(with-eval-after-load 'ob-tangle
(add-hook
'org-babel-post-tangle-hook
(defun format-all-org-babel-post-tangle ()
(when (derived-mode-p 'python-mode)
(setq-local format-all-formatters '(("Python" black)))
(format-all-buffer)
(save-buffer)
(message "Saved reformatted tangled buffer `%s'" (buffer-file-name)))))))
#+end_src
** [[info:flymake#Top][Flymake (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:flymake
:END:
Flymake is an universal on-the-fly syntax checker for Emacs. It is a requirement
of [[https://github.com/joaotavora/eglot][eglot]], but you can use it without [[https://github.com/joaotavora/eglot][eglot]] for instance in [[https://git.savannah.gnu.org/cgit/emacs.git/tree/lisp/progmodes/python.el][python-mode]] buffers
that do not visit a file.
* Programming Modes
:PROPERTIES:
:CUSTOM_ID: sec:programming-languages
:END:
** [[https://dept-info.labri.fr/~strandh/Teaching/PFS/Common/Strandh-Tutorial/Dir-symbolic.html][Common Lisp programming]]
:PROPERTIES:
:CUSTOM_ID: sec:common-lisp-programming
: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 ensures the [[info:sly#Auto-SLY][automatic connection to the lisp server (info)]] when opening a
Common Lisp file.
3. It configures searching documentation in the [[http://www.lispworks.com/documentation/HyperSpec/Front/][Common Lisp HyperSpec]] according
to the [[info:sly#Basic customization][basic customization (info)]] manual.
Finally, listing [[lst:configure-sly]] uses a technique to [[info:sly#Loading Slynk faster][load Slynk faster (info)]]
by means of a custom core file in src_emacs-lisp{no-littering-var-directory}.
Listing [[lst:sbcl-core-for-sly]] tangles to a script to dump such a [[http://www.sbcl.org/][SBCL]] core.
#+caption[Configure =sly=]:
#+caption: Configure =sly=.
#+name: lst:configure-sly
#+begin_src emacs-lisp
(when (ensure-package-installation 'sly)
(with-eval-after-load 'sly
(custom-set-variables
;; Customize `sly-default-lisp' instead of `inferior-lisp-program',
;; because `sly' uses `inferior-lisp-program' only as a backwards
;; compatibility fallback option.
'(sly-default-lisp 'sbcl)
`(sly-lisp-implementations
'((sbcl (,(executable-find "sbcl")
"--core"
,(no-littering-expand-var-file-name "sbcl.core-for-sly"))))))
(add-hook 'sly-mode-hook
(defun on-sly-mode-hook ()
(unless (sly-connected-p)
(save-excursion (sly)))))
(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")))
(define-key sly-prefix-map (kbd "M-h") #'sly-documentation-lookup)))
#+end_src
#+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
#+begin_src shell :noeval :tangle ~/bin/sbcl.core-for-sly
#!/bin/sh
sbcl <<EOF
(mapc 'require '(sb-bsd-sockets sb-posix sb-introspect sb-cltl2 asdf))
(save-lisp-and-die "sbcl.core-for-sly")
EOF
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# sh-basic-offset: 2
# End:
#+end_src
*** [[https://courses.cs.northwestern.edu/325/][CS 325 AI Programming]]
:PROPERTIES:
:CUSTOM_ID: sec:cs-325-ai-programming
:END:
2022-08-05 07:21:13 +02:00
The [[https://courses.cs.northwestern.edu/325/][CS 325 AI Programming]] course allows to learn Common Lisp by self-study and
the page [[https://courses.cs.northwestern.edu/325/admin/lisp-setup.php][CS 325: Setting up Lisp]] gives instructions how to:
1. [[https://courses.cs.northwestern.edu/325/admin/lisp-setup.php#lisp][Download and install common lisp]].
2. [[https://courses.cs.northwestern.edu/325/admin/lisp-setup.php#quicklisp][Install Quicklisp]].
3. [[https://courses.cs.northwestern.edu/325/admin/lisp-setup.php#install-325][Install the CS325 library]].
*** [[https://www.quicklisp.org/][Quicklisp]]
:PROPERTIES:
:CUSTOM_ID: sec:quicklisp
:END:
2022-08-05 07:21:13 +02:00
[[https://www.quicklisp.org/][Quicklisp]] is a library manager for Common Lisp. Listing
[[lst:download+verify-quicklisp]] downloads the [[https://www.quicklisp.org/][Quicklisp]] file and verifies its
signature to prevent tampering. Listing [[lst:bootstrap-quicklisp]] tangles to a
shell script allowing to bootstrap [[https://www.quicklisp.org/][Quicklisp]] with [[http://www.sbcl.org/][SBCL]]. Listing
[[lst:quicklisp-sbclrc-file]] tangles to the a [[http://www.sbcl.org/][SBCL]] resource file with [[https://www.quicklisp.org/][Quicklisp]]
support.
#+caption[Download and verify =quicklisp=]:
#+caption: Download and verify =quicklisp=.
#+name: lst:download+verify-quicklisp
#+begin_src shell :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
#+begin_src shell :noeval :tangle ~/bin/quicklisp-sbcl-bootstrap
#!/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[A =quicklisp= sbclrc file]:
#+caption: A =quicklisp= sbclrc file.
#+name: lst:quicklisp-sbclrc-file
#+begin_src lisp :tangle ~/.sbclrc
;;; Hey Emacs, this is my -*- lisp -*- .sbclrc file.
#-quicklisp
(let ((quicklisp-init (merge-pathnames "quicklisp/setup.lisp"
(user-homedir-pathname))))
(when (probe-file quicklisp-init)
(load quicklisp-init)))
#+end_src
2022-01-27 09:50:39 +01:00
** [[info:eintr#Top][Emacs Lisp Programming (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:emacs-lisp-programming
:END:
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-07-01 10:02:05 +02:00
** [[info:maxima#Top][Maxima Programming (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:maxima-programming
:END:
2022-07-01 14:11:48 +02:00
Listing [[lst:configure-maxima]] configures [[https://gitlab.com/sasanidas/maxima][Maxima Mode]]. The following list contains
more information:
1. [[https://gitlab.com/sasanidas/maxima][Maxima Mode]] is an Emacs interface to the computer algebra system [[https://en.wikipedia.org/wiki/Maxima_(software)][Maxima]].
2. [[https://orgmode.org/worg/org-contrib/babel/languages/ob-doc-maxima.html][Maxima Source Code Blocks in Org Mode]] shows how to use [[https://en.wikipedia.org/wiki/Maxima_(software)][Maxima]] in [[https://orgmode.org/][Org Mode]].
3. [[https://home.csulb.edu/~woollett/mbe.html][Maxima By Example]] is a tutorial for [[https://en.wikipedia.org/wiki/Maxima_(software)][Maxima]].
Listing [[lst:maxima-example]] is a minimal example of how to use how to use [[https://en.wikipedia.org/wiki/Maxima_(software)][Maxima]]
in [[https://orgmode.org/][Org Mode]].
2022-07-01 10:02:05 +02:00
#+caption[Configure =maxima=]:
#+caption: Configure =maxima=.
#+name: lst:configure-maxima
#+begin_src emacs-lisp
(when (ensure-package-installation 'maxima 'company-maxima)
(add-hook 'maxima-mode-hook #'maxima-hook-function)
(add-hook 'maxima-inferior-mode-hook #'maxima-hook-function)
(add-to-list 'auto-mode-alist
(cons "\\.mac\\'" 'maxima-mode))
(add-to-list 'interpreter-mode-alist
(cons "maxima" 'maxima-mode)))
#+end_src
2022-07-01 14:11:48 +02:00
#+caption[Maxima example]:
#+caption: Maxima example.
#+name: lst:maxima-example
#+begin_src maxima :exports both :results output
2022-07-01 10:02:05 +02:00
print(1+1);
#+end_src
2022-07-01 14:11:48 +02:00
#+RESULTS: lst:maxima-example
2022-07-01 10:02:05 +02:00
: 2
** [[https://www.seas.upenn.edu/~chaoliu/2017/09/01/python-programming-in-emacs/][Python programming]]
:PROPERTIES:
:CUSTOM_ID: sec:python-programming
:END:
The [[https://www.emacswiki.org/emacs/PythonProgrammingInEmacs][Python Programming in Emacs]] wiki page lists options to enhance Emacs's
built-in ~python-mode~. Here, the focus is on three packages:
1. [[https://github.com/joaotavora/eglot][Eglot - Emacs polyGLOT: an Emacs LSP client that stays out of your way]]. The
maintainer also contributes to Emacs itself and has a deep understanding of
[[https://sheer.tj/the_way_of_emacs.html][the Way of Emacs]]. He refuses to add new features without seeing how they fit
into [[https://sheer.tj/the_way_of_emacs.html][the Way of Emacs]] as this discussion on [[https://github.com/joaotavora/eglot/issues/523][org-mode source code blocks]]
shows.
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.
3. [[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]].
Here are links covering how to integrate Emacs, Python and a Python LSP
server, before plunging into the configuration steps:
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]]
*** [[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
Listing [[lst:configure-python]] configures [[https://git.savannah.gnu.org/cgit/emacs.git/tree/lisp/progmodes/python.el][python-mode]] to use [[https://flake8.pycqa.org/en/latest/][flake8]] as style
checker and [[https://ipython.org/][IPython]] as shell interpreter. The [[https://github.com/pythonic-emacs/pythonic#readme][pythonic]] and [[https://github.com/jorgenschaefer/pyvenv#readme][pyvenv]] packages
provide support 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]]) and tweak the
environment variables and restart the relevant Python child processes (in case
of [[https://github.com/jorgenschaefer/pyvenv#readme][pyvenv]]). Therefore, this setup replaces those packages with listing
[[lst:manage-pyenv]] to manage [[https://github.com/pyenv/pyenv#readme][pyenv]] from within Emacs and listing
[[lst:setting-python-shell-virtualenv-root]] to set =python-shell-virtualenv-root=.
#+caption[Configure =python=]:
#+caption: Configure =python=.
#+name: lst:configure-python
2022-01-04 13:10:26 +01:00
#+begin_src emacs-lisp
(with-eval-after-load 'python
(custom-set-variables
2022-07-15 17:15:29 +02:00
`(python-check-command ,(executable-find "flake8"))
`(python-flymake-command '(,(executable-find "flake8") "-"))
'(python-indent-guess-indent-offset nil)
'(python-shell-completion-native-disabled-interpreters '("ipython3" "pypy"))
'(python-shell-interpreter "ipython3")
'(python-shell-interpreter-args
"--simple-prompt --HistoryAccessor.enabled=False")))
#+end_src
#+caption[Manage =pyenv=]:
#+caption: Manage =pyenv=.
#+name: lst:manage-pyenv
#+begin_src emacs-lisp
(when (executable-find "pyenv")
(defun pyenv-full-path (version)
"Return the full path for VERSION."
(unless (string= version "system")
(concat (pyenv-root) (file-name-as-directory "versions") version)))
(defun pyenv-root ()
"Return \"pyenv root\" as a directory."
(cl-destructuring-bind (exit-code output)
(shell-command-with-exit-code "pyenv" "root")
(if (= 0 exit-code) (file-name-as-directory (string-trim output))
(error "%s" (string-trim output)))))
(defun pyenv-version-name ()
"Return \"pyenv version-name\"."
(cl-destructuring-bind (exit-code output)
(shell-command-with-exit-code "pyenv" "version-name")
(if (= 0 exit-code) (string-trim output)
(error "%s" (string-trim output)))))
(defun pyenv-versions ()
"Return \"pyenv versions --bare --skip-aliases\" as a list.
Complete the result with \"system\"."
(cl-destructuring-bind (exit-code output)
(shell-command-with-exit-code
"pyenv" "versions" "--bare" "--skip-aliases")
(if (= 0 exit-code) (cons "system" (split-string output))
(error "%s" (string-trim output)))))
(defun pyenv-virtualenvs ()
"Return \"pyenv virtualenvs --bare --skip-aliases\" as a list."
(cl-destructuring-bind (exit-code output)
(shell-command-with-exit-code
"pyenv" "virtualenvs" "--bare" "--skip-aliases")
(if (= 0 exit-code) (split-string output)
(error "%s" (string-trim output))))))
#+end_src
#+caption[Setting =python-shell-virtualenv-root=]:
#+caption: Setting =python-shell-virtualenv-root=.
#+name: lst:setting-python-shell-virtualenv-root
2022-01-04 13:10:26 +01:00
#+begin_src emacs-lisp
(with-eval-after-load 'python
(when (cl-every #'fboundp '(pyenv-full-path
pyenv-version-name
pyenv-versions
pyenv-virtualenvs))
(setq python-shell-virtualenv-root
(pyenv-full-path (or (car `(,(pyenv-version-name)))
(car (pyenv-virtualenvs))
(car (pyenv-versions)))))
(message "Now `python-shell-virtualenv-root' equals \"%s\""
python-shell-virtualenv-root)
(defun set-python-shell-virtualenv-root-to-pyenv-version ()
"Set `python-shell-virtual-env-root' to a pyenv version."
(interactive)
(let* ((version-name (pyenv-version-name))
(prompt (format "pyenv version (%s): " version-name))
(choices (pyenv-versions))
(version (completing-read prompt choices nil 'require-match)))
(unless (string= version-name version)
(setq python-shell-virtualenv-root (pyenv-full-path version))
(setenv "PYENV_VERSION" version))
(message "Now `python-shell-virtualenv-root' equals \"%s\""
python-shell-virtualenv-root)))
(defun set-python-shell-virtualenv-root-to-pyenv-virtualenv ()
"Set `python-shell-virtual-env-root' to a pyenv virtualenv."
(interactive)
(let* ((version-name (pyenv-version-name))
(prompt (format "pyenv virtualenv (%s): " version-name))
(choices (pyenv-virtualenvs))
(version (completing-read prompt choices nil 'require-match)))
(unless (string= version-name version)
(setq python-shell-virtualenv-root (pyenv-full-path version))
(setenv "PYENV_VERSION" version))
(message "Now `python-shell-virtualenv-root' equals \"%s\""
python-shell-virtualenv-root)))))
2022-01-04 13:10:26 +01:00
#+end_src
*** [[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:
:CUSTOM_ID: sec:eglot-python
2022-01-04 13:10:26 +01:00
:END:
2022-08-05 07:21:13 +02:00
Listing [[lst:configure-eglot+python-lsp-server-for-python]] 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]]. In order to enable all builtin
[[https://github.com/python-lsp/python-lsp-server][python-lsp-server]] capabilities, ensure installation of 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]], [[https://github.com/python-lsp/python-lsp-server][python-lsp-server]], [[https://github.com/python-rope/rope#readme][rope]], and [[https://github.com/google/yapf#readme][yapf]]. In
addition, install the [[https://github.com/emanspeaks/pyls-flake8#readme][pyls-flake8]] plugin to let [[https://github.com/python-lsp/python-lsp-server][python-lsp-server]] use [[https://github.com/PyCQA/flake8][flake8]].
The latest [[https://github.com/python-lsp/python-lsp-server#readme][python-lsp-server]] documentation tells to let it use [[https://github.com/PyCQA/flake8][flake8]] as in
[[lst:broken-configure-eglot+python-lsp-server-for-python]], but it does not work.
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
according to the configuration in listing [[lst:eglot-maybe-ensure]].
2022-01-07 16:34:21 +01:00
#+caption[Configure =eglot= with =python-lsp-server= for Python]:
#+caption: Configure =eglot= with =python-lsp-server= for Python.
#+name: lst:configure-eglot+python-lsp-server-for-python
#+begin_src emacs-lisp
(with-eval-after-load 'eglot
(setq-default
eglot-workspace-configuration
'(;; Disable the `:pyls_flake8' plugin to fall back to pycodestyle.
(:pylsp . (:plugins (:pyls_flake8 (:enabled t))))
(:pylsp . (:plugins (:jedi (:auto_import_modules ["numpy"]))))
(:pylsp . (:plugins (:jedi_completion (:cache_for ["astropy"])))))))
2022-01-07 16:34:21 +01:00
#+end_src
#+caption[Broken configure =eglot= with =python-lsp-server= for Python]:
#+caption: Broken configure =eglot= with =python-lsp-server= for Python.
#+name: lst:broken-configure-eglot+python-lsp-server-for-python
#+begin_src emacs-lisp :tangle no
(with-eval-after-load 'eglot
(setq-default
eglot-workspace-configuration
'(;; To use flake8 instead of pycodestyle, see:
;; https://github.com/python-lsp/python-lsp-server#configuration
(:pylsp . (:configurationSources ["flake8"]))
(:pylsp . (:plugins (:pycodestyle (:enabled :json-false))))
(:pylsp . (:plugins (:mccabe (:enabled :json-false))))
(:pylsp . (:plugins (:pyflakes (:enabled :json-false))))
(:pylsp . (:plugins (:flake8 (:enabled t))))
(:pylsp . (:plugins (:jedi (:auto_import_modules ["numpy"]))))
(:pylsp . (:plugins (:jedi_completion (:cache_for ["astropy"])))))))
#+end_src
#+caption[Propose =directory-variables= to launch =eglot=]:
#+caption: Propose =directory-variables= in the root of any Python project to
#+caption: launch =eglot=.
#+name: lst:eglot-directory-variables-for-python
#+begin_src emacs-lisp :tangle dir-locals.el
;; Proposal for a .dir-locals.el file in the root of any Python project.
((python-mode
. ((eglot-workspace-configuration
. (;; Disable the `:pyls_flake8' plugin to fall back to pycodestyle.
(:pylsp . (:plugins (:pyls_flake8 (:enabled t))))
(:pylsp . (:plugins (:jedi (:auto_import_modules ["numpy"]))))
(:pylsp . (:plugins (:jedi_completion (:cache_for ["astropy"])))))))))
#+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
|-------------------------+----------------+------------------|
| 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
Listing [[lst:pyproject-toml-kick-off]] and [[lst:setup-cfg-kick-off]] implement the
rules in [[https://black.readthedocs.io/en/stable/guides/using_black_with_other_tools.html][using black with other tools]] in order to make [[https://flake8.pycqa.org/en/latest/][flake8]] or [[https://pycodestyle.pycqa.org/en/latest/][pycodestyle]]
agree with [[https://black.readthedocs.io/en/stable/index.html][black's uncompromising style]].
#+caption[Kick starting a =pyproject.toml= file]:
#+caption: Kick starting a =pyproject.toml= file.
#+name: lst:pyproject-toml-kick-off
#+begin_src toml :tangle pyproject.toml
[build-system]
requires = ["setuptools", "wheel"]
build-backend = "setuptools.build_meta"
[tool.black]
line-length = 88
# Local Variables:
# mode: conf-toml
# End:
#+end_src
#+caption[Kick starting a =setup.cfg= file]:
#+caption: Kick starting a =setup.cfg= file.
#+name: lst:setup-cfg-kick-off
#+begin_src toml :tangle setup.cfg
[flake8]
max-line-length = 88
extend-ignore = E203
[pycodestyle]
ignore = E203
max-line-length = 88
# Local Variables:
# mode: conf-toml
# End:
#+end_src
[[https://jedi.readthedocs.io/en/latest/][Jedi]] provides grammar checking and completion candidates to [[https://github.com/python-lsp/python-lsp-server][python-lsp-server]].
Only [[https://jedi.readthedocs.io/en/latest/docs/changelog.html][jedi-0.18.1]] works with for instance [[https://numpy.org/][numpy-1.23.0]] in the sense that it does
not choke on universal functions provided that [[https://jedi.readthedocs.io/en/latest/][jedi]] does not parse but imports
[[https://numpy.org/][numpy-1.23.1]] (see [[https://github.com/davidhalter/jedi/issues/1744][jedi issue #1744]], [[https://github.com/davidhalter/jedi/issues/1745][#1745]], and [[https://github.com/davidhalter/jedi/issues/1746][#1746]]). Since the universal
functions are neither builtin methods nor data instances but a kind of "callable
instances", the [[https://docs.python.org/3/library/inspect.html][Python inspect]] module also fails to handle the universal
functions properly.
Listing [[lst:make-pylsp-server-patch]] generates and listing
[[lst:echo-pylsp-server-patch]] echos the patch in listing
[[lst:show-pylsp-server-patch]] to make [[https://jedi.readthedocs.io/en/latest/][jedi]] import [[https://numpy.org/][numpy-1.22.2]] in order to serve
the information to [[https://github.com/python-lsp/python-lsp-server][python-lsp-server]] allowing it to handle universal functions.
#+caption[Make =pylsp-auto-import-modules.patch= listing]:
#+caption: Make =pylsp-auto-import-modules.patch= listing.
#+name: lst:make-pylsp-server-patch
#+begin_src shell :exports code :results none
git -C $HOME/VCS/python-lsp-server diff >pylsp-auto-import-modules.patch
#+end_src
#+caption[Echo =pylsp-auto-import-modules.patch= listing]:
#+caption: Echo =pylsp-auto-import-modules.patch= listing.
#+name: lst:echo-pylsp-server-patch
#+begin_src shell :exports both :results drawer
echo "#+attr_latex: :options breaklines"
echo "#+caption[Show =pylsp-auto-import-modules.patch=]:"
echo "#+caption: Show =pylsp-auto-import-modules.patch=."
echo "#+name: lst:show-pylsp-server-patch"
echo "#+begin_src diff :tangle no"
cat pylsp-auto-import-modules.patch
echo -n "#+end_src"
#+end_src
#+RESULTS: lst:echo-pylsp-server-patch
:results:
#+attr_latex: :options breaklines
#+caption[Show =pylsp-auto-import-modules.patch=]:
#+caption: Show =pylsp-auto-import-modules.patch=.
#+name: lst:show-pylsp-server-patch
#+begin_src diff :tangle no
diff --git a/pylsp/config/schema.json b/pylsp/config/schema.json
index 4443780..a19972b 100644
--- a/pylsp/config/schema.json
+++ b/pylsp/config/schema.json
@@ -87,6 +87,14 @@
"uniqueItems": true,
"description": "List of errors and warnings to enable."
},
+ "pylsp.plugins.jedi.auto_import_modules": {
+ "type": "array",
+ "default": ["numpy", "gi"],
+ "items": {
+ "type": "string"
+ },
+ "description": "List of module names for jedi to import (jedi.settings.auto_import_modules)."
+ },
"pylsp.plugins.jedi.extra_paths": {
"type": "array",
"default": [],
diff --git a/pylsp/workspace.py b/pylsp/workspace.py
2022-01-07 16:34:21 +01:00
index bf312f6..4758b53 100644
--- a/pylsp/workspace.py
+++ b/pylsp/workspace.py
@@ -14,6 +14,8 @@ from . import lsp, uris, _utils
log = logging.getLogger(__name__)
2022-01-07 16:34:21 +01:00
+DEFAULT_AUTO_IMPORT_MODULES = ["numpy", "gi"]
+
# TODO: this is not the best e.g. we capture numbers
RE_START_WORD = re.compile('[A-Za-z_0-9]*$')
RE_END_WORD = re.compile('^[A-Za-z_0-9]*')
@@ -252,6 +254,8 @@ class Document:
if self._config:
jedi_settings = self._config.plugin_settings('jedi', document_path=self.path)
+ jedi.settings.auto_import_modules = jedi_settings.get('auto_import_modules',
+ DEFAULT_AUTO_IMPORT_MODULES)
environment_path = jedi_settings.get('environment')
extra_paths = jedi_settings.get('extra_paths') or []
env_vars = jedi_settings.get('env_vars')
#+end_src
:end:
*** [[https://jedi.readthedocs.io/en/latest/][Jedi]]
:PROPERTIES:
:CUSTOM_ID: sec:jedi
:END:
2022-08-05 07:21:13 +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
with [[https://github.com/joaotavora/eglot][eglot]] works when coding for instance [[https://numpy.org/][numpy]] universal functions.
#+caption[Tangle the =example.py= file]:
#+caption: Tangle the =example.py= file.
#+name: lst:example-py
#+begin_src python :tangle example.py
import numpy
import astropy.units as apu
a = numpy.arange(0, 11)
a = numpy.linspace(0, 10, num=11)
a = numpy.arccos(a)
q = apu.Quantity(a, apu.meter)
print(q)
#+end_src
2022-02-23 07:43:57 +01:00
*** [[https://github.com/astoff/code-cells.el#readme][Code-cells]]
:PROPERTIES:
2022-03-26 15:11:32 +01:00
:CUSTOM_ID: sec:code-cells
2022-02-23 07:43:57 +01:00
:END:
[[https://github.com/astoff/code-cells.el#readme][Code-cells]] allows to edit [[https://ipython.org/notebook.html][IPython or Jupyter notebooks]] in Emacs with help from
either [[https://github.com/mwouts/jupytext][Jupytext]] or [[https://pandoc.org/][Pandoc]] to translate between the [[https://nbformat.readthedocs.io/en/latest/][ipynb]] format and different
plain text formats. Sofar, I have used [[https://github.com/astoff/code-cells.el#readme][code-cells]] to open [[https://nbformat.readthedocs.io/en/latest/][ipynb]] notebooks with
{{{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
#+begin_src emacs-lisp
(when (ensure-package-installation 'code-cells)
(with-eval-after-load 'code-cells
(let ((map code-cells-mode-map))
(define-key map (kbd "M-p") #'code-cells-backward-cell)
(define-key map (kbd "M-n") #'code-cells-forward-cell)
(define-key map (kbd "C-c C-c") #'code-cells-eval))))
#+end_src
2022-02-23 07:43:57 +01:00
*** TODO Look into: editing facilities
1. [[https://github.com/douglasdavis/numpydoc.el/blob/main/numpydoc.el][Emacs extension to insert numpy style docstrings in function definitions]]
* [[https://github.com/emacs-tw/awesome-emacs#library][Libraries]]
:PROPERTIES:
:CUSTOM_ID: sec:libraries
:END:
2022-08-05 07:21:13 +02: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
processing API of [[info:cl#Top][cl]]. It is a requirement of several 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
[[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
#+begin_src emacs-lisp
(when (fboundp #'global-dash-fontify-mode)
(global-dash-fontify-mode))
(when (fboundp #'dash-register-info-lookup)
(with-eval-after-load 'info-look
(dash-register-info-lookup)))
#+end_src
** [[https://github.com/rejeep/f.el][Library f.el]]
:PROPERTIES:
:CUSTOM_ID: sec:f-library
:END:
2022-08-05 07:21:13 +02:00
The library [[https://github.com/rejeep/f.el][f.el]] positions itself as a modern API for working with files and
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.
** [[https://github.com/magnars/s.el][Library s.el]]
:PROPERTIES:
:CUSTOM_ID: sec:s-library
:END:
The library [[https://github.com/magnars/s.el][s.el]] positions itself as the long lost Emacs string manipulation
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-17 07:56:55 +01:00
* [[info:emacs#Minor Modes][Minor Modes (info)]]
:PROPERTIES:
2022-01-17 07:56:55 +01:00
:CUSTOM_ID: sec:minor-modes
: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
#+caption[Enable =iedit=]:
#+caption: Enable =iedit=.
2021-12-28 08:48:03 +01:00
#+name: lst:enable-iedit
2021-11-29 13:14:56 +01:00
#+begin_src emacs-lisp
2022-05-21 14:23:38 +02:00
(when (ensure-package-installation 'iedit)
(require 'iedit nil 'noedit))
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
#+caption[Configure =ws-butler=]:
#+caption: Configure =ws-butler=.
2021-12-28 08:48:03 +01:00
#+name: lst:configure-ws-butler
2021-11-29 13:14:56 +01:00
#+begin_src emacs-lisp
2022-05-21 14:23:38 +02:00
(when (and (ensure-package-installation 'ws-butler)
(require 'ws-butler nil 'noerror))
(custom-set-variables
'(ws-butler-keep-whitespace-before-point nil))
(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
** [[https://countvajhula.com/2021/09/25/the-animated-guide-to-symex/][Structural editing]]
:PROPERTIES:
2021-12-29 10:05:06 +01:00
:CUSTOM_ID: sec:structural-editing
: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
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
a 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
while the strict mode does not. Therefore, the strict mode is more for code
editing since it never breaks programming language rules and the normal mode is
more for text editing where structure is a matter of convention instead of
programming language rules.
For instance, the strict mode in Python allows to delete entire lists, tuples,
or the arguments after the cursor (what Emacs calls =point=) in a function call
without breaking the character pair balance. In order to repair a broken
character pair balance, insert a single character by prefixing it with "C-q"
bound to =quoted-insert=.
The [[https://smartparens.readthedocs.io/en/latest/index.html][smartparens documentation]] targets experienced Emacs users. The
following links show how to put the documentation to practical use:
1. [[https://gist.github.com/oantolin][Omar Antolin's gist "my-smartparens-config.el"]] is the first place to look for
how to tweak [[https://github.com/Fuco1/smartparens][smartparens]]. However, the gist may be partially obsolete, since
it is not part of his current [[https://github.com/oantolin/emacs-config][Emacs configuration]].
2. [[https://lists.gnu.org/archive/html/help-gnu-emacs/2014-07/msg00135.html][How to enable smartparens in the minibuffer after eval-expression]] explains
how the machinery after the first and after later usages of =eval-expression=
differ and discusses options how to handle those differences.
Listing [[lst:configure-smartparens]] aims to configure [[https://github.com/Fuco1/smartparens][smartparens]] for Elisp,
LaTeX, Org, and Python.
Despite the provocative post [[https://andreyorst.gitlab.io/posts/2022-02-20-what-if-structural-editing-was-a-mistake/]["What if structural editing was a mistake?"]],
[[https://github.com/Fuco1/smartparens][smartparens]] is one of my favorite packages. In particular, [[https://github.com/Fuco1/smartparens][smartparens]] handles
matching pairs in Org-mode files with export and source blocks for multiple
formats and languages correctly. Therefore, [[https://smartparens.readthedocs.io/en/latest/index.html?highlight=show-smartparens-mode#getting-started][show-smartparens-mode]] highlights
matching pairs immediately in front or after point in such files correctly,
contrary to for instance [[https://github.com/Fanael/rainbow-delimiters#readme][rainbow-delimiters]].
#+caption[Configure =smartparens=]:
#+caption: Configure =smartparens=.
2021-12-28 08:48:03 +01:00
#+name: lst:configure-smartparens
2021-11-29 13:14:56 +01:00
#+begin_src emacs-lisp
2022-05-21 17:27:31 +02:00
(when (and (ensure-package-installation 'smartparens)
;; Require `smartparens-config' instead of `smartparens' to
;; disable pairing of the quote character for lisp modes.
(require 'smartparens-config nil 'noerror))
(custom-set-variables
'(sp-base-key-bindings 'sp)
'(sp-override-key-bindings '(("C-(" . sp-backward-barf-sexp)
("C-)" . sp-forward-slurp-sexp))))
2021-11-29 13:14:56 +01:00
2022-05-21 17:27:31 +02:00
(dolist (hook '(prog-mode-hook text-mode-hook))
(add-hook hook #'smartparens-mode))
2022-05-21 17:27:31 +02:00
(dolist (hook '(emacs-lisp-mode-hook
ielm-mode-hook
lisp-data-mode-hook
2022-05-21 17:27:31 +02:00
lisp-mode-hook
python-mode-hook
sly-mrepl-mode-hook))
(add-hook hook #'smartparens-strict-mode))
2021-11-29 13:14:56 +01:00
2022-05-21 17:27:31 +02: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-05-21 17:27:31 +02: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-05-21 17:27:31 +02:00
(show-smartparens-global-mode +1))
2021-11-29 13:14:56 +01:00
#+end_src
2022-01-09 15:39:14 +01:00
** [[https://github.com/davidshepherd7/electric-operator#readme][Electric operators]]
2021-12-06 08:32:39 +01:00
:PROPERTIES:
:CUSTOM_ID: sec:electric-operators
:END:
2021-11-29 13:14:56 +01:00
Listing [[lst:configure-electric-operator]] configures =electric-operator-mode=
2021-12-29 10:05:06 +01:00
to add spaces around operators for compatibility with for instance the [[https://black.readthedocs.io/en/stable/][Black
code formatter for Python]].
#+caption[Configure =electric-operator=]:
#+caption: Configure =electric-operator=.
#+name: lst:configure-electric-operator
2021-11-29 13:14:56 +01:00
#+begin_src emacs-lisp
2022-05-21 14:23:38 +02:00
(when (and (ensure-package-installation 'electric-operator)
(fboundp 'electric-operator-mode))
(add-hook 'c-mode-common #'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]]
:PROPERTIES:
:CUSTOM_ID: sec:smart-snippets
:END:
2021-11-29 13:14:56 +01:00
#+caption[Enable =yas-global-mode=]:
#+caption: Enable =yas-global-mode=.
2021-12-28 08:48:03 +01:00
#+name: lst:enable-yas-global-mode
2021-11-29 13:14:56 +01:00
#+begin_src emacs-lisp
2022-08-05 07:41:27 +02:00
(when (ensure-package-installation 'yasnippet)
2021-11-29 13:14:56 +01:00
(custom-set-variables
2022-08-05 07:41:27 +02:00
;; Set `yas-alias-to-yas/prefix-p' before loading `yasnippet'.
2021-11-29 13:14:56 +01:00
'(yas-alias-to-yas/prefix-p nil))
2022-08-05 07:41:27 +02:00
(when (require 'yasnippet nil 'noerror)
(yas-global-mode +1)))
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
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
#+begin_src emacs-lisp
(with-eval-after-load 'emacs
(autoload 'org-at-table-p "org-table")
(defun org-narrow-to-table ()
"Narrow buffer to table at point."
(interactive)
(if (org-at-table-p)
(narrow-to-region (org-table-begin) (org-table-end))
(user-error "Not in a table")))
(defun narrow-or-widen-dwim (p)
"Widen if buffer is narrowed, narrow \"Do What I Mean\" otherwise.
DWIM means: region, Org table, Org source block, Org block, Org
subtree, LaTeX environment, TeX group, or defun, whichever
applies first. Narrowing to org-src-block actually calls
`org-edit-src-code'.
With prefix P, don't widen, just narrow even if buffer is already
narrowed."
(interactive "P")
(declare (interactive-only))
(cond ((and (buffer-narrowed-p) (not p))
(widen))
((and (bound-and-true-p org-src-mode) (not p))
(org-edit-src-exit))
((region-active-p)
(narrow-to-region (region-beginning) (region-end)))
((derived-mode-p 'org-mode)
(or (with-demoted-errors "DWIM: %S" (org-narrow-to-table) t)
(with-demoted-errors "DWIM: %S" (org-edit-src-code) t)
(with-demoted-errors "DWIM: %S" (org-narrow-to-block) t)
(org-narrow-to-subtree)))
((derived-mode-p 'latex-mode)
(LaTeX-narrow-to-environment))
((derived-mode-p 'tex-mode)
(TeX-narrow-to-group))
(t
(narrow-to-defun))))
(define-key ctl-x-map (kbd "n t") #'org-narrow-to-table)
(define-key ctl-x-map (kbd "C-n") #'narrow-or-widen-dwim))
2022-01-17 07:56:55 +01:00
#+end_src
2021-12-29 14:05:03 +01:00
** [[https://jblevins.org/log/rainbow-mode][Visualize color codes and names]]
2022-01-09 15:39:14 +01:00
:PROPERTIES:
:CUSTOM_ID: sec:rainbow-mode
:END:
2021-12-29 14:05:03 +01:00
Listing [[lst:enable-rainbow-mode]] enables =rainbow-mode= to colorize color codes
and names in buffers for debugging.
#+caption[Enable =rainbow-mode=]:
#+caption: Enable =rainbow-mode=.
#+name: lst:enable-rainbow-mode
#+begin_src emacs-lisp
2022-05-21 14:23:38 +02:00
(when (and (ensure-package-installation 'rainbow-mode)
(fboundp 'rainbow-mode))
(custom-set-variables
'(rainbow-x-colors-major-mode-list
'(c++-mode
c-mode
emacs-lisp-mode
inferior-emacs-lisp-mode
java-mode
lisp-interaction-mode
org-mode
python-mode)))
(rainbow-mode +1))
#+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
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
2021-11-29 13:14:56 +01:00
#+begin_src emacs-lisp
;; Ensure loading `pulse' with the dynamic variables `pulse-delay' and
;; `pulse-iterations' before masking them lexically instead of after
;; to prevent the warning triggered by lazy loading.
(when (require 'pulse nil 'noerror)
2021-11-29 13:14:56 +01:00
;; https://karthinks.com/software/batteries-included-with-emacs/
;; https://www.reddit.com/r/emacs/comments/jwhr6g/batteries_included_with_emacs/
(defun flash-line-around-point (&rest _)
"Flash the line around point."
2021-11-29 13:14:56 +01:00
(let ((pulse-iterations 16)
(pulse-delay 0.1))
(pulse-momentary-highlight-one-line (point))))
2021-11-29 13:14:56 +01:00
(dolist (command '(scroll-up-command
scroll-down-command
recenter-top-bottom
other-window))
(advice-add command :after #'flash-line-around-point)))
2021-11-29 13:14:56 +01:00
#+end_src
* Applications
2022-01-09 15:39:14 +01:00
:PROPERTIES:
:CUSTOM_ID: sec:applications
:END:
2021-11-29 13:14:56 +01:00
** [[info:emacs#Hyperlinking][Hyperlinking and Web Navigation Features (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:hyperlinking-web-navigating
:END:
*** [[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
#+caption[Configure =browse-url=]:
#+caption: Configure =browse-url=.
#+name: lst:configure-browse-url
#+begin_src emacs-lisp
(with-eval-after-load 'browse-url
(defun browse-url-mpv (url &optional _)
(start-process "mpv" nil "mpv" url))
(defconst browse-url-mpv-regexp
(rx bos
(or "http://" "https://")
(or (or "www.youtube.com/" "youtu.be/" "soundcloud.com/")
(seq (+? nonl) (or ".mp4" ".webm") eos)))
"Match hyperlinks to browse with mpv.")
(if (version< emacs-version "28.0")
(custom-set-variables
'(browse-url-browser-function
`((,browse-url-mpv-regexp . browse-url-mpv)
("." . eww-browse-url))))
(custom-set-variables
'(browse-url-handlers
`((,browse-url-mpv-regexp . browse-url-mpv)
("." . eww-browse-url)))))
(custom-set-variables
`(browse-url-generic-program ,(or (when (eq system-type 'darwin) "open")
(executable-find "firefox")))))
#+end_src
*** [[https://en.wikipedia.org/wiki/Eww_(web_browser)][Emacs Web Wowser]]
:PROPERTIES:
:CUSTOM_ID: sec:emacs-web-wowser
:END:
#+caption[Configure =eww= URLs]:
#+caption: Configure =eww= URLs.
#+name: lst:configure-eww-urls
#+begin_src emacs-lisp
(when (fboundp 'eww-browse-url)
(defun eww-subreddit ()
"Read a subreddit in Emacs."
(interactive)
(eww-browse-url (format "www.reddit.com/r/%s/.mobile"
(completing-read "subreddit: "
'("emacs"
"i3wm"
"orgmode")
nil t)))))
#+end_src
#+caption[Configure =eww= rendering]:
#+caption: Configure =eww= rendering.
#+name: lst:configure-eww-rendering
#+begin_src emacs-lisp
(with-eval-after-load 'eww
(defun eww-rename-buffer ()
"Rename the buffer using title or url."
(let* ((title (plist-get eww-data :title))
(name (or (and (eq "" title) (plist-get eww-data :url)) title)))
(rename-buffer (format "*%s # eww*" name) t)))
2022-04-09 17:14:24 +02:00
(add-hook 'eww-after-render-hook #'eww-rename-buffer))
#+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
#+begin_src org :tangle ~/.mailcap
# https://emacs.stackexchange.com/a/24502 answers the question:
# How to use pdf-tools (pdf-view-mode) in emacs?
application/pdf; emacsclient %s
#+end_src
*** [[https://www.emacswiki.org/emacs/WebJump][Webjump]]
:PROPERTIES:
:CUSTOM_ID: sec:webjump
:END:
Listing [[lst:configure-webjump]] binds {{{kbd(C-c j)}}} to =webjump= and
initializes a list of =webjump-sites=.
2022-04-18 08:26:40 +02:00
#+attr_latex: :options breaklines
#+caption[Configure =webjump=]:
#+caption: Configure =webjump=.
#+name: lst:configure-webjump
#+begin_src emacs-lisp
(when (fboundp 'webjump)
(global-set-key (kbd "C-c j") 'webjump)
(with-eval-after-load 'webjump
(custom-set-variables
'(webjump-sites
'(("CS 325 AI Programming" . "courses.cs.northwestern.edu/325")
2022-04-06 07:07:22 +02:00
("Emacs News" . "sachachua.com/blog/category/emacs-news")
("Planet Emacs Life" . "planet.emacslife.com")
2022-05-29 14:40:28 +02:00
("Worg - Org Mode Community" . "orgmode.org/worg")
("Git: Emacs" . "git.savannah.gnu.org/cgit/emacs.git")
("Git: Emacs Core Python Mode" .
"git.savannah.gnu.org/cgit/emacs.git/log/lisp/progmodes/python.el")
("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")
2022-03-23 07:53:20 +01:00
("Asian Pacific Journal Japan Focus" . "apjjf.org")
("Counterpunch" . "www.counterpunch.org")
("Dictionary EN" . [simple-query "thefreedictionary.com"
"thefreedictionary.com/" ""])
2022-06-05 14:54:25 +02:00
("Dictionary FR" . [simple-query "www.cnrtl.fr"
"www.cnrtl.fr/definition/" ""])
("Dictionary NL" . [simple-query "www.woorden.org"
"www.woorden.org/woord/" ""])
2022-05-22 14:39:43 +02:00
("Merriam-Webster" . [simple-query
"www.merriam-webster.com"
"www.merriam-webster.com/dictionary/" ""])
("Webster" . [simple-query
"www.webster-dictionary.org"
"www.webster-dictionary.org/definition/" ""])
2022-05-27 11:04:26 +02:00
("Wiktionary EN" . [simple-query "en.wiktionary.org/"
"en.wiktionary.org/wiki/" ""])
("Wiktionary FR" . [simple-query "fr.wiktionary.org/"
"fr.wiktionary.org/wiki/" ""])
("Wiktionary NL" . [simple-query "nl.wiktionary.org/"
"nl.wiktionary.org/wiki/" ""])
("Le Figaro" . "www.lefigaro.fr")
("Le Monde" . "www.lemonde.fr")
("Libération" . "www.liberation.fr")
("Monde Diplomatique" . "www.monde-diplomatique.fr")
("NRC". "www.nrc.nl")
2022-04-09 17:13:48 +02:00
("The Guardian" . "www.theguardian.com/international")
("Trouw" . "www.trouw.nl")
("Volkskrant" . "www.volkskrant.nl"))))))
#+end_src
2022-07-08 10:01:57 +02:00
** [[info:emacs#Sending Mail][Sending Mail (info)]]
:PROPERTIES:
:CUSTOM_ID: sec:sending-mail
:END:
1. [[https://macowners.club/posts/email-emacs-mu4e-macos/][Email setup in Emacs with Mu4e on macOS]]
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-07-08 10:01:57 +02:00
#+caption[Configure =message=]:
#+caption: Configure =message=.
#+name: lst:configure-message
#+begin_src emacs-lisp
(custom-set-variables
'(user-full-name "Gerard Vermeulen")
'(user-mail-address "gerard.vermeulen@neel.cnrs.fr"))
(with-eval-after-load 'message
(custom-set-variables
'(message-sendmail-envelope-from 'header)))
#+end_src
#+caption[Configure =sendmail=]:
#+caption: Configure =sendmail=.
#+name: lst:configure-sendmail
#+begin_src emacs-lisp
(with-eval-after-load 'sendmail
(custom-set-variables
'(mail-specify-envelope-from t)
'(mail-envelope-from 'header)
2022-07-11 12:08:17 +02:00
'(send-mail-function #'sendmail-send-it)
2022-07-10 13:24:46 +02:00
`(sendmail-program ,(executable-find "msmtp"))))
2022-07-08 10:01:57 +02:00
#+end_src
#+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")
#+begin_src conf
# 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:
#+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")
#+begin_src conf
# 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:
#+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
Listing [[lst:configure-elfeed]] configures =elfeed= and makes a minimal attempt to
enable =emms=.
2022-04-18 08:26:40 +02:00
#+attr_latex: :options breaklines
#+caption[Configure =elfeed=]:
#+caption: Configure =elfeed=.
#+name: lst:configure-elfeed
2021-11-29 13:14:56 +01:00
#+begin_src emacs-lisp
2022-05-21 14:23:38 +02:00
(when (and (ensure-package-installation 'elfeed)
(fboundp 'elfeed))
(global-set-key (kbd "C-x w") #'elfeed)
2021-11-29 13:14:56 +01:00
2022-04-18 08:26:40 +02:00
(with-eval-after-load 'elfeed
(custom-set-variables
'(elfeed-feeds
'(("http://www.howardism.org/index.xml" h-abrams)
("https://emacshorrors.com/feed.atom" v-schneidermann)
("https://emacsninja.com/emacs.atom" v-schneidermann)
("https://feeds.feedburner.com/InterceptedWithJeremyScahill" j-scahill)
("https://frame.work/fr/fr/blog.rss" framework)
("https://nullprogram.com/feed/" c-wellons)
("https://oremacs.com/atom.xml" o-krehel)
("https://planet.emacslife.com/atom.xml" planet-emacs)
("https://protesilaos.com/codelog.xml" p-stavrou)
("https://sachachua.com/blog/category/emacs/feed" s-chua)
("https://sciencescitoyennes.org/feed/" sciences)
("https://updates.orgmode.org/feed/updates" org-updates)
("https://www.bof.nl/rss/" bof)
("https://www.democracynow.org/podcast-video.xml" dn)
("https://www.laquadrature.net/fr/rss.xml" lqdn)
("https://www.lemonde.fr/blog/huet/feed/" sciences)))))
(with-eval-after-load 'elfeed-show
2022-07-15 14:17:36 +02:00
(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
using =emms= with =elfeed=. Listing [[lst:configure-emms]] configures =emms=.
2022-04-18 08:26:40 +02:00
#+caption[Configure =emms=]:
#+caption: Configure =emms=.
#+name: lst:configure-emms
2021-11-29 13:14:56 +01:00
#+begin_src emacs-lisp
(when (ensure-package-installation 'emms)
(with-eval-after-load 'emms
(custom-set-variables
2022-07-15 14:17:36 +02:00
'(emms-player-list '(emms-player-mpd emms-player-mpv)))
(emms-all))
(with-eval-after-load 'emms-mode-line
(custom-set-variables
'(emms-mode-line-format "")))
(with-eval-after-load 'emms-player-mpd
(custom-set-variables
`(emms-player-mpd-music-directory ,(expand-file-name "~/Music"))
'(emms-player-mpd-server-name "localhost")
'(emms-player-mpd-server-port "6600")
'(emms-player-mpd-verbose t)))
(with-eval-after-load 'emms-player-mpv
(custom-set-variables
'(emms-player-mpv-ipc-method 'ipc-server)
'(emms-player-mpv-update-metadata t)))
2022-04-19 04:03:39 +02:00
(with-eval-after-load 'emms-playing-time
(custom-set-variables
'(emms-playing-time-display-format " %s ")))
(with-eval-after-load 'emms-playlist-mode
(custom-set-variables
'(emms-playlist-mode-center-when-go t)))
(with-eval-after-load 'emms-streams
(custom-set-variables
`(emms-streams-file
2022-07-15 14:17:36 +02:00
,(no-littering-expand-etc-file-name "emms/streams.emms")))))
2021-11-29 13:14:56 +01:00
#+end_src
*** Taming spurious buffers
:PROPERTIES:
:CUSTOM_ID: sec:taming-spurious-buffers
:END:
When =emms-player-mpd= opens a connection to =mpd=, =mpd= responds with a
message of the form "OK MPD 0.23.5". Neither =emms-player-mpd= nor its support
library =tq= anticipate the "OK MPD 0.23.5" message, but send such messages to a
new intrusive buffer called =*spurious*=. Listing [[lst:taming-spurious-buffers]]
makes those =*spurious*= buffers less intrusive. See:
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.
#+caption[Taming =*spurious*= buffers]:
#+caption: Taming =*spurious*= buffers.
#+name: lst:taming-spurious-buffers
#+begin_src emacs-lisp
(with-eval-after-load 'emms-player-mpd
;; https://stackoverflow.com/a/47587185 answers:
;; How to avoid pop-up of *Async Shell Command* buffers in Emacs?
;; Avoid popping up of `*spurious*' buffers:
(add-to-list 'display-buffer-alist
'("\\*spurious\\*.*"
(display-buffer-at-bottom)
(window-height . fit-window-to-buffer))))
#+end_src
2022-07-15 17:12:53 +02:00
*** [[https://www.musicpd.org/][Music Player Daemon]] configuration
:PROPERTIES:
:CUSTOM_ID: sec:mpd-configuration-file
:END:
Listing [[lst:make-mpd-conf]] proposes a [[https://www.musicpd.org/][Music Player Daemon]] configuration file that
keeps each new connection for a day in order to reduce the rate of =*spurious*=
generation.
#+Caption[A Music Player Daemon configuration file proposal]:
#+caption: A Music Player Daemon configuration file proposal.
#+name: lst:make-mpd-conf
#+begin_src shell :results silent
case "$(uname -s)" in
Darwin)
cat <<EOF > ~/.mpd/mpd.conf
music_directory "~/Music"
playlist_directory "~/.mpd/playlists"
db_file "~/.mpd/mpd.db"
log_file "~/.mpd/mpd.log"
pid_file "~/.mpd/mpd.pid"
state_file "~/.mpd/mpdstate"
follow_outside_symlinks "yes"
follow_inside_symlinks "yes"
bind_to_address "localhost"
port "6600"
connection_timeout "86400"
audio_output {
type "osx"
name "CoreAudio"
mixer_type "software"
}
EOF
;;
esac
#+end_src
2021-11-29 13:14:56 +01:00
* [[info:emacs#Init File][Init File (info)]] footer
:PROPERTIES:
:CUSTOM_ID: sec:user-init-file-footer
2021-11-29 13:14:56 +01:00
:END:
#+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
2021-11-29 13:14:56 +01:00
#+begin_src emacs-lisp
(provide 'init)
;; Emacs looks for "Local variables:" after the last "newline-formfeed".
2021-11-29 13:14:56 +01:00
;; Local Variables:
;; indent-tabs-mode: nil
;; End:
;;; init.el ends here
#+end_src
* Local variables linking to [[#sec:latexmk-save-compile-display-loop][Latexmk save-compile-display-loop]]
2021-11-29 13:14:56 +01:00
:PROPERTIES:
:CUSTOM_ID: sec:local-variables
2021-11-29 13:14:56 +01:00
:END:
Only the [[info:org#Top][Org]] source file shows the local variables footer.
2021-11-29 13:14:56 +01:00
\printbibliography
# Emacs looks for "Local variables:" after the last "newline-formfeed".
2021-11-29 13:14:56 +01:00
# Local Variables:
# eval: (org-eval-emacs-lisp-setup-blocks)
2021-11-29 13:14:56 +01:00
# compile-command: "latexmk -interaction=nonstopmode -lualatex -pvc -shell-escape README.tex"
# fill-column: 80
# End: