1149 lines
47 KiB
Org Mode
1149 lines
47 KiB
Org Mode
|
#+startup: content
|
|||
|
#+title: Emacs setup for use with LaTeX, Org, and Python
|
|||
|
#+author: Gerard Vermeulen
|
|||
|
#+babel: :cache no
|
|||
|
#+property: header-args :tangle init.el :comments link
|
|||
|
#+property: header-args:emacs-lisp :results silent
|
|||
|
#+latex_class: article
|
|||
|
#+latex_class_options: [11pt,a4paper,svgnames]
|
|||
|
#+latex_header: \hypersetup{
|
|||
|
#+latex_header: citecolor=blue,
|
|||
|
#+latex_header: colorlinks=true,
|
|||
|
#+latex_header: filecolor=blue,
|
|||
|
#+latex_header: hyperfootnotes=false,
|
|||
|
#+latex_header: linkcolor=blue,
|
|||
|
#+latex_header: unicode=true,
|
|||
|
#+latex_header: urlcolor=blue
|
|||
|
#+latex_header: }
|
|||
|
#+latex_header: \usepackage{minted}
|
|||
|
#+latex_header: \usemintedstyle{xcode}
|
|||
|
#+latex_header: \usepackage[
|
|||
|
#+latex_header: headheight=20mm,
|
|||
|
#+latex_header: top=40mm,
|
|||
|
#+latex_header: bottom=20mm,
|
|||
|
#+latex_header: left=0.1\paperwidth,
|
|||
|
#+latex_header: right=0.1\paperwidth,
|
|||
|
#+latex_header: heightrounded,
|
|||
|
#+latex_header: verbose,
|
|||
|
#+latex_header: ]{geometry}
|
|||
|
|
|||
|
* 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 my work-flow by showing:
|
|||
|
1. How tangle (or export) source blocks from [[info:org#Top][org]] files. This file contains the
|
|||
|
files =early-init.el=, =init.el=, =latexmkrc=, =org-store-link=, and
|
|||
|
=example.py= for tangling.
|
|||
|
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]].
|
|||
|
|
|||
|
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 file that link back to the
|
|||
|
original [[https://www.latex-project.org/][LaTeX]] file of a document. An example of my work-flow are the steps how
|
|||
|
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.
|
|||
|
|
|||
|
[[info:emacs#Top][Emac (info)]]
|
|||
|
|
|||
|
|
|||
|
Here follows a list of interesting Emacs configurations:
|
|||
|
1. [[https://github.com/oantolin/emacs-config][Omar Antolín Camarena's configuration]]
|
|||
|
2. [[https://gitlab.com/ambrevar/dotfiles][Pierre Neirhardt's configuration]] implements lazy loading without help of
|
|||
|
external packages. I have stolen his approach of using lazy loading to
|
|||
|
silently ignore the setup stanzas of uninstalled extension packages.
|
|||
|
3. [[https://sachachua.com/dotemacs/][Sacha Chua's configuration]] is an example of producing the Emacs
|
|||
|
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
|
|||
|
efficient means. I have stolen her idea of using [[https://github.com/quelpa/quelpa][quelpa]] to install packages
|
|||
|
from any source.
|
|||
|
4. [[https://github.com/purcell/emacs.d][Steve Purcell's configuration]] is well organized and a show-case of readable
|
|||
|
[[info:elisp#Top][Emacs lisp (info)]] code. I have stolen his idea of versioning the
|
|||
|
~package-user-dir~ variable to prevent clashes between the byte-compiler
|
|||
|
output of different Emacs versions.
|
|||
|
5. [[https://github.com/tecosaur/emacs-config][Timothy E. Chapman]]
|
|||
|
|
|||
|
* [[info:emacs#Early Init File][Early Init File (info)]]
|
|||
|
:PROPERTIES:
|
|||
|
:CUSTOM_ID: sec:early-init-file
|
|||
|
:END:
|
|||
|
|
|||
|
The err
|
|||
|
[[#sec:package-bootstrapping][Package Bootstrapping]]
|
|||
|
|
|||
|
qLF FF
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+begin_src emacs-lisp :tangle early-init.el
|
|||
|
;;; early-init.el --- user early-init file -*- lexical-binding: t -*-
|
|||
|
;;; Commentary:
|
|||
|
;;; Code:
|
|||
|
(setq package-enable-at-startup nil)
|
|||
|
(setq-default load-prefer-newer t)
|
|||
|
|
|||
|
(provide 'early-init)
|
|||
|
;; Emacs looks for "Local variables:" after the last "C-q C-j C-q C-l".
|
|||
|
|
|||
|
;; Local Variables:
|
|||
|
;; indent-tabs-mode: nil
|
|||
|
;; End:
|
|||
|
;;; earl-init.el ends here
|
|||
|
#+end_src
|
|||
|
|
|||
|
* [[info:emacs#Init File][Init File (info)]] header
|
|||
|
:PROPERTIES:
|
|||
|
:CUSTOM_ID: sec:init-file-header
|
|||
|
:END:
|
|||
|
|
|||
|
The [[info:elisp#Quoting][quoting (info)]] and the [[info:elisp#Backquote][backquote (info)]] pages explain how to understand the
|
|||
|
reader macros ~'~ (quote), ~`~ (backquote), ~,~ (substitute) and ~@,~ (splice)
|
|||
|
in the ~custom-set-variable~ function call below.
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+begin_src emacs-lisp
|
|||
|
;;; init.el --- user init file -*- lexical-binding: t -*-
|
|||
|
;;; Commentary:
|
|||
|
;;; Code:
|
|||
|
(require 'cl-lib)
|
|||
|
|
|||
|
;; https://with-emacs.com/posts/tutorials/almost-all-you-need-to-know-about-variables/
|
|||
|
(defmacro csetq (sym val)
|
|||
|
`(funcall (or (get ',sym 'custom-set) 'set-default) ',sym ,val))
|
|||
|
|
|||
|
(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
|
|||
|
(format "custom-%s.%s.el" emacs-major-version emacs-minor-version)))
|
|||
|
'(epg-pinentry-mode 'loopback)
|
|||
|
'(global-hl-line-mode t)
|
|||
|
'(global-hl-line-sticky-flag t)
|
|||
|
'(history-delete-duplicates t)
|
|||
|
'(history-length 500)
|
|||
|
'(indent-tabs-mode nil)
|
|||
|
'(inhibit-startup-buffer-menu t)
|
|||
|
'(inhibit-startup-screen t)
|
|||
|
'(initial-buffer-choice t)
|
|||
|
'(initial-scratch-message "")
|
|||
|
`(insert-directory-program ,(or (executable-find "gls")
|
|||
|
(executable-find "ls")))
|
|||
|
'(kill-ring-max 300)
|
|||
|
'(package-archive-priorities '(("gnu" . 1)
|
|||
|
("nongnu" . 1)))
|
|||
|
'(package-archives '(("gnu" . "https://elpa.gnu.org/packages/")
|
|||
|
("nongnu" . "https://elpa.nongnu.org/nongnu/")
|
|||
|
("melpa" . "https://melpa.org/packages/")))
|
|||
|
`(package-user-dir
|
|||
|
,(locate-user-emacs-file
|
|||
|
(format "elpa-%s.%s" emacs-major-version emacs-minor-version)))
|
|||
|
'(recentf-mode t)
|
|||
|
'(save-place-mode t)
|
|||
|
'(savehist-additional-variables
|
|||
|
'(eww-history
|
|||
|
kill-ring
|
|||
|
regexp-search-string
|
|||
|
search-ring
|
|||
|
search-string))
|
|||
|
'(savehist-mode t)
|
|||
|
'(savehist-save-minibuffer-history 1)
|
|||
|
'(scroll-bar-mode nil)
|
|||
|
'(tab-always-indent 'complete)
|
|||
|
'(tab-width 8)
|
|||
|
'(tool-bar-mode nil)
|
|||
|
'(url-cookie-trusted-urls nil)
|
|||
|
'(url-cookie-untrusted-urls '(".*"))
|
|||
|
'(use-dialog-box nil)
|
|||
|
'(use-short-answer t)
|
|||
|
'(view-read-only t))
|
|||
|
|
|||
|
(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
|
|||
|
|
|||
|
* Package bootstrapping
|
|||
|
:PROPERTIES:
|
|||
|
:CUSTOM_ID: sec:package-bootstrapping
|
|||
|
:END:
|
|||
|
|
|||
|
[[info:emacs#Package Installation][Emacs installs packages]] from archives on the internet.
|
|||
|
This setup uses three archives in two decreasing levels of priority:
|
|||
|
1. The [[https://elpa.gnu.org/][GNU Emacs Lisp Package Archive]] or the [[https://elpa.nongnu.org/][NonGNU Emacs Lisp Package Archive]].
|
|||
|
3. The [[https://melpa.org/#/][MELPA - Milkypostman’s Emacs Lisp Package Archive]].
|
|||
|
Finally, the [[https://github.com/quelpa/quelpa][quelpa]] tool allows to fetch code from any source and build a
|
|||
|
package on your computer before installation. It allows to install a package
|
|||
|
from [[https://melpa.org/#/][MELPA]] instead of [[https://elpa.gnu.org/][GNU ELPA]] or [[https://elpa.nongnu.org/][NonGNU ELPA]], breaking the priority order.
|
|||
|
|
|||
|
The output of the byte-compiler may change with each new Emacs release.
|
|||
|
Therefore, in order to prevent collisions between different Emacs versions, the
|
|||
|
package-user-directory has a suffix containing the major- and minor-version
|
|||
|
numbers of Emacs.
|
|||
|
|
|||
|
The order of the next 1nd, 2nd, and 3rd package-bootstrapping blocks matters
|
|||
|
because each of those blocks prepares Emacs for the next block.
|
|||
|
|
|||
|
If present, the package [[https://github.com/emacscollective/no-littering][no-littering]] helps to keep =~/.emacs.d= clean.
|
|||
|
|
|||
|
The code assumes that the package system is in a *virgin* state in case the
|
|||
|
package [[https://github.com/emacscollective/no-littering][no-littering]] is not present. Refreshing the contents of available
|
|||
|
packages at least once is a requirement in order to be able to install and load
|
|||
|
any packages, hence also [[https://github.com/emacscollective/no-littering][no-littering]].
|
|||
|
|
|||
|
You have to refresh the list of available packages yourself before updating
|
|||
|
the installed packages.
|
|||
|
|
|||
|
Finally, ~my-install-packages~ ensures installation of all packages in a list of
|
|||
|
packages.
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+begin_src emacs-lisp
|
|||
|
;; The is the 1st package bootstrapping block.
|
|||
|
(require 'package)
|
|||
|
(package-initialize)
|
|||
|
|
|||
|
(unless (require 'no-littering nil 'noerror)
|
|||
|
(package-refresh-contents)
|
|||
|
(package-install 'no-littering)
|
|||
|
(require 'no-littering))
|
|||
|
|
|||
|
(defun my-install-packages (packages)
|
|||
|
"Ensure installation of all packages in PACKAGES."
|
|||
|
(dolist (package packages)
|
|||
|
(unless (package-installed-p package)
|
|||
|
(package-install package))))
|
|||
|
#+end_src
|
|||
|
|
|||
|
Install the basic packages and in case this is Emacs-27.2, upgrade [[https://orgmode.org/][Org Mode]] for
|
|||
|
compatibility with Emacs-28.1. The [[info:elisp#Backquote][info:backquote]] page explains how to read the
|
|||
|
~`~ and ~,@~ in the definition of ~my-packages~ variable below.
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+begin_src emacs-lisp
|
|||
|
;; The is the 2nd package bootstrapping block.
|
|||
|
(defvar my-packages
|
|||
|
`(
|
|||
|
,@(when (version< emacs-version "28.0")
|
|||
|
'(org)) ; plain text thought organizer
|
|||
|
auctex ; Aalborg University Center TeX
|
|||
|
blacken ; Black Python-code formatter client
|
|||
|
citar ; bibliography handling
|
|||
|
citeproc ; bibliography handling
|
|||
|
consult ; consult completing-read
|
|||
|
;; eglot ; Emacs polyGLOT LSP client
|
|||
|
elpy ; Python development environment
|
|||
|
embark ; act on any buffer selection
|
|||
|
htmlize ; convert buffer contents to HTML
|
|||
|
leuven-theme ; beautiful color theme
|
|||
|
;; lsp-mode ; Language Server Protocol client
|
|||
|
marginalia ; minibuffer margin notes
|
|||
|
orderless ; Emacs completion style
|
|||
|
pdf-tools ; interactive docview replacement
|
|||
|
pyenv-mode ; Python environment selector
|
|||
|
quelpa ; install Emacs packages from source
|
|||
|
vertico) ; VERTical Interactive Completion
|
|||
|
"List of packages required packages.")
|
|||
|
|
|||
|
(my-install-packages my-packages)
|
|||
|
#+end_src
|
|||
|
|
|||
|
Install the following packages with [[https://github.com/quelpa/quelpa][quelpa]]:
|
|||
|
1. ~lisp-ui~ (including ~lisp-mode~), because ~lisp-ui~ is yet available from
|
|||
|
[[https://elpa.gnu.org/][GNU ELPA]], [[https://elpa.nongnu.org/][NonGNU ELPA]], or [[https://melpa.org/#/][MELPA]].
|
|||
|
2. ~eglot~ to get the latest version from [[https://melpa.org/#/][MELPA]].
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+begin_src emacs-lisp
|
|||
|
;; This is the 3rd package bootstrapping block.
|
|||
|
(when (package-installed-p 'quelpa)
|
|||
|
(defun my-install-sources (sources)
|
|||
|
(mapc (lambda (source)
|
|||
|
(unless (package-installed-p (car source))
|
|||
|
(quelpa source)))
|
|||
|
sources))
|
|||
|
(my-install-sources
|
|||
|
'((lsp-ui :fetcher github :repo "emacs-lsp/lsp-ui")
|
|||
|
(eglot :fetcher github :repo "joaotavora/eglot"))))
|
|||
|
#+end_src
|
|||
|
|
|||
|
Install the optional packages.
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+begin_src emacs-lisp
|
|||
|
;; The is the 4th package bootstrapping block.
|
|||
|
(defvar my-optional-packages
|
|||
|
`(
|
|||
|
,@(when (version< emacs-version "28.0")
|
|||
|
'(modus-themes)) ; high foreground/background contrast themes
|
|||
|
async ; asynchroneous processing
|
|||
|
company ; complete anything
|
|||
|
electric-operator ; automatic spacing around operators
|
|||
|
elfeed ; web feed reader
|
|||
|
emms ; Emacs Multi-Media System
|
|||
|
iedit ; simultaneous multi-entity editing
|
|||
|
laas ; LaTeX Auto-Activating Snippets
|
|||
|
magit ; Git Text-based User Interface
|
|||
|
nov ; EPUB reader
|
|||
|
smartparens ; smart editing of character pairs
|
|||
|
wgrep ; open a writable grep buffer
|
|||
|
which-key ; on the fly key-binding help
|
|||
|
wordnut ; WordNet lexical database
|
|||
|
writegood-mode ; bullshit and weasel-word detector
|
|||
|
ws-butler ; remove trailing whitespace
|
|||
|
xr ; undo rx to grok regular expressions
|
|||
|
yasnippet)) ; code or text template expansion
|
|||
|
|
|||
|
(defun my-install-optional-packages ()
|
|||
|
(interactive)
|
|||
|
(my-install-packages my-optional-packages))
|
|||
|
#+end_src
|
|||
|
|
|||
|
* [[info:emacs#Emacs Server][Emacs Server (info)]]
|
|||
|
|
|||
|
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=.
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+begin_src emacs-lisp
|
|||
|
(when window-system
|
|||
|
(unless (or noninteractive (daemonp))
|
|||
|
(add-hook 'after-init-hook #'server-start)))
|
|||
|
#+end_src
|
|||
|
|
|||
|
** [[https://www.personal.psu.edu/jcc8/latexmk/][Usage: latexmk compilation loop]]
|
|||
|
:PROPERTIES:
|
|||
|
:CUSTOM_ID: sec:latexmk-compilation-loop
|
|||
|
: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 [[#sec:compile-with-latexmk][compile with latexmk]] are compatible.
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+begin_src perl :tangle latexmkrc
|
|||
|
# 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 glo gls glg run.xml";
|
|||
|
sub makeglossaries {
|
|||
|
my ($name, $path) = fileparse( $$Psource );
|
|||
|
return system "makeglossaries -d '$path' '$name'";
|
|||
|
}
|
|||
|
# Emacs looks for "Local variables:" after the last "C-q C-j C-q C-l".
|
|||
|
|
|||
|
# Local Variables:
|
|||
|
# mode: perl
|
|||
|
# End:
|
|||
|
#+end_src
|
|||
|
|
|||
|
** [[https://qutebrowser.org/doc/userscripts.html][Usage: qutebrowser userscript]]
|
|||
|
|
|||
|
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.
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+header: :comments none
|
|||
|
#+header: :tangle-mode (identity #o755)
|
|||
|
#+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
|
|||
|
|
|||
|
* 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
|
|||
|
circumstances. Vertico integrates well with fully supported complementary
|
|||
|
packages to enrich the completion UI:
|
|||
|
1. [[info:marginalia#Top][Marginalia (info)]] for rich annotations in the minibuffer.
|
|||
|
2. [[info:consult#Top][Consult (info)]] for useful search and navigation commands.
|
|||
|
3. [[info:embark#Top][Embark (info)]] for minibuffer actions with context menus.
|
|||
|
4. [[info:orderless#Top][Orderless (info)]] for an advanced completion style.
|
|||
|
|
|||
|
[[https://cestlaz.github.io/post/using-emacs-80-vertico/][Using Vertico, Marginalia, Consult, and Embark]]
|
|||
|
|
|||
|
[[info:vertico#Configuration][Vertico configuration (link)]]
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+begin_src emacs-lisp
|
|||
|
(unless noninteractive
|
|||
|
(when (fboundp 'vertico-mode)
|
|||
|
(vertico-mode +1)))
|
|||
|
#+end_src
|
|||
|
|
|||
|
[[info:marginalia#Top][Marginalia (info)]] adds marginalia (margin annotations) to minibuffer
|
|||
|
completions.
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+begin_src emacs-lisp
|
|||
|
(unless noninteractive
|
|||
|
(when (fboundp 'marginalia-mode)
|
|||
|
(marginalia-mode +1)))
|
|||
|
#+end_src
|
|||
|
|
|||
|
Consult provides practical commands based on the Emacs completion
|
|||
|
function.
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+begin_src emacs-lisp
|
|||
|
(unless noninteractive
|
|||
|
(when (fboundp 'consult-apropos)
|
|||
|
(custom-set-variables
|
|||
|
'(consult-project-root-function #'vc-root-dir))
|
|||
|
;; C-c bindings (mode-specific-map)
|
|||
|
(global-set-key (kbd "C-c h") #'consult-history)
|
|||
|
(global-set-key (kbd "C-c m") #'consult-mode-command)
|
|||
|
;; C-x bindings (ctl-x-map)
|
|||
|
(global-set-key (kbd "C-x M-:") #'consult-complex-command)
|
|||
|
(global-set-key (kbd "C-x b") #'consult-buffer)
|
|||
|
(global-set-key (kbd "C-x 4 b") #'consult-buffer-other-window)
|
|||
|
(global-set-key (kbd "C-x 5 b") #'consult-buffer-other-frame)
|
|||
|
(global-set-key (kbd "C-x r x") #'consult-register)
|
|||
|
(global-set-key (kbd "C-x r b") #'consult-bookmark)
|
|||
|
;; M-g bindings (goto-map)
|
|||
|
(global-set-key (kbd "M-g g") #'consult-goto-line)
|
|||
|
(global-set-key (kbd "M-g M-g") #'consult-goto-line)
|
|||
|
(global-set-key (kbd "M-g o") #'consult-outline)
|
|||
|
(global-set-key (kbd "M-g m") #'consult-mark)
|
|||
|
(global-set-key (kbd "M-g k") #'consult-global-mark)
|
|||
|
(global-set-key (kbd "M-g i") #'consult-imenu-project)
|
|||
|
(global-set-key (kbd "M-g e") #'consult-error)
|
|||
|
;; M-s bindings (search-map)
|
|||
|
(global-set-key (kbd "M-s g") #'consult-git-grep)
|
|||
|
(global-set-key (kbd "M-s f") #'consult-find)
|
|||
|
(global-set-key (kbd "M-s k") #'consult-keep-lines)
|
|||
|
(global-set-key (kbd "M-s l") #'consult-line)
|
|||
|
(global-set-key (kbd "M-s m") #'consult-multi-occur)
|
|||
|
(global-set-key (kbd "M-s u") #'consult-focus-lines)
|
|||
|
;; Other bindings
|
|||
|
(global-set-key (kbd "M-y") #'consult-yank-pop)
|
|||
|
(global-set-key (kbd "<help> a") #'consult-apropos)
|
|||
|
;; Tweak functions
|
|||
|
(advice-add 'completing-read-multiple
|
|||
|
:override #'consult-completing-read-multiple)
|
|||
|
(fset 'multi-occur #'consult-multi-occur)))
|
|||
|
#+end_src
|
|||
|
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+begin_src emacs-lisp
|
|||
|
(unless noninteractive
|
|||
|
(when (cl-every #'fboundp '(embark-act embark-bindings embark-dwim))
|
|||
|
(global-set-key (kbd "C-,") #'embark-act)
|
|||
|
(global-set-key (kbd "C-:") #'embark-dwim)
|
|||
|
(global-set-key (kbd "C-h B") #'embark-bindings)))
|
|||
|
#+end_src
|
|||
|
|
|||
|
[[info:orderless#Top][Orderless (info)]]
|
|||
|
|
|||
|
#+begin_src emacs-lisp
|
|||
|
(unless noninteractive
|
|||
|
(when (fboundp 'orderless-filter)
|
|||
|
(custom-set-variables
|
|||
|
;; https://github.com/purcell/emacs.d/issues/778
|
|||
|
'(completion-styles '(basic completion-partial orderless))
|
|||
|
'(completion-category-defaults nil)
|
|||
|
'(completion-category-overrides
|
|||
|
'((file (styles partial-completion)))))
|
|||
|
(add-hook 'minibuffer-setup-hook
|
|||
|
(defun my-on-minibuffer-setup-hook()
|
|||
|
(setq-default completion-styles '(substring orderless))))))
|
|||
|
#+end_src
|
|||
|
|
|||
|
[[https://company-mode.github.io/][company-mode: modular in-buffer completion framework for Emacs]]
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+begin_src emacs-lisp
|
|||
|
(unless noninteractive
|
|||
|
(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
|
|||
|
python-mode-hook
|
|||
|
ielm-mode-hook))
|
|||
|
(add-hook hook #'company-mode))))
|
|||
|
#+end_src
|
|||
|
|
|||
|
* Reading
|
|||
|
|
|||
|
** EPUB files
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+begin_src emacs-lisp
|
|||
|
(when (fboundp 'nov-mode)
|
|||
|
(add-to-list 'auto-mode-alist `(,(rx ".epub" eos) . nov-mode)))
|
|||
|
#+end_src
|
|||
|
|
|||
|
** PDF files
|
|||
|
|
|||
|
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.
|
|||
|
|
|||
|
In order to use [[https://github.com/vedang/pdf-tools][pdf-tools]], you have to type =M-x pdf-tools-install= after
|
|||
|
installation of [[https://github.com/vedang/pdf-tools][pdf-tools]] from [[https://melpa.org/][MELPA]] or after each update of [[https://github.com/freedesktop/poppler][poppler]] to build
|
|||
|
or rebuild the =epdfinfo= executable that serves the [[https://en.wikipedia.org/wiki/PDF][PDF]] files to Emacs.
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+begin_src emacs-lisp
|
|||
|
(when (fboundp 'pdf-tools-install)
|
|||
|
(autoload 'pdf-view-mode "pdf-view")
|
|||
|
(add-to-list 'magic-mode-alist '("%PDF" . pdf-view-mode)))
|
|||
|
#+end_src
|
|||
|
|
|||
|
* Writing
|
|||
|
|
|||
|
** LaTeX
|
|||
|
|
|||
|
Loading =tex.el= immediately instead of lazily ensures proper initialization of
|
|||
|
the [[https://en.wikipedia.org/wiki/AUCTeX][AUCTeX]]. For instance, the ~TeX-master~ safe local variable in the =tex.el=
|
|||
|
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~.
|
|||
|
|
|||
|
Out of the box, [[https://en.wikipedia.org/wiki/AUCTeX][AUCTeX]] does not indent text between square brackets. The code
|
|||
|
below corrects this by advising to override ~TeX-brace-count-line~ with
|
|||
|
~my-TeX-brace-count-line~.
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+begin_src emacs-lisp
|
|||
|
;; Try to get the `safe-local-variable` predicate for `TeX-master`
|
|||
|
(when (require 'tex nil 'noerror)
|
|||
|
;; https://emacs.stackexchange.com/questions/17396/indentation-in-square-brackets
|
|||
|
(defun my-TeX-brace-count-line ()
|
|||
|
"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)))
|
|||
|
(advice-add 'TeX-brace-count-line :override #'my-TeX-brace-count-line))
|
|||
|
#+end_src
|
|||
|
|
|||
|
** Org-mode
|
|||
|
|
|||
|
*** [[info:org#Activation][Activation (info)]]
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+begin_src emacs-lisp
|
|||
|
;; Inspect:
|
|||
|
;; function with "C-h f"
|
|||
|
;; symbols with "C-h o"
|
|||
|
;; variables with "C-h v"
|
|||
|
|
|||
|
(global-set-key (kbd "C-c a") #'org-agenda)
|
|||
|
(global-set-key (kbd "C-c c") #'org-capture)
|
|||
|
(global-set-key (kbd "C-c l") #'org-store-link)
|
|||
|
(global-set-key (kbd "C-c C-l") #'org-insert-link-global)
|
|||
|
#+end_src
|
|||
|
|
|||
|
*** Customization
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+begin_src emacs-lisp
|
|||
|
(custom-set-variables
|
|||
|
'(org-babel-python-command "python -E")
|
|||
|
'(org-babel-load-languages '((C . t)
|
|||
|
(calc . t)
|
|||
|
(dot . t)
|
|||
|
(emacs-lisp . t)
|
|||
|
(eshell . t)
|
|||
|
(fortran . t)
|
|||
|
(gnuplot . t)
|
|||
|
(latex . t)
|
|||
|
(lisp . t)
|
|||
|
(maxima . t)
|
|||
|
(org . t)
|
|||
|
(perl . t)
|
|||
|
(python . t)
|
|||
|
(scheme . t)
|
|||
|
(shell . t)))
|
|||
|
'(org-cite-export-processors '((latex biblatex)
|
|||
|
(t csl)))
|
|||
|
'(org-cite-global-bibliography '("~/VCS/research/refs.bib"))
|
|||
|
'(org-file-apps '((auto-mode . emacs)
|
|||
|
(directory . emacs)
|
|||
|
("\\.mm\\'" . default)
|
|||
|
("\\.x?html?\\'" . default)
|
|||
|
("\\.pdf\\'" . emacs)))
|
|||
|
'(org-confirm-babel-evaluate nil)
|
|||
|
'(org-latex-compiler "lualatex")
|
|||
|
'(org-latex-hyperref-template nil)
|
|||
|
'(org-latex-listings 'minted)
|
|||
|
'(org-latex-logfiles-extensions '("blg" "lof" "log" "lot" "out" "toc"))
|
|||
|
'(org-latex-prefer-user-labels t)
|
|||
|
'(org-modules '(ol-bibtex
|
|||
|
ol-doi
|
|||
|
ol-eww
|
|||
|
ol-info
|
|||
|
org-id
|
|||
|
org-protocol
|
|||
|
org-tempo))
|
|||
|
'(org-src-fontify-natively t)
|
|||
|
'(org-src-window-setup 'current-window)
|
|||
|
'(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 :async")
|
|||
|
("v" . "verse"))))
|
|||
|
#+end_src
|
|||
|
|
|||
|
*** [[info:org#Citation export processors][Citation export processors (info)]]
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+begin_src emacs-lisp
|
|||
|
(with-eval-after-load 'oc
|
|||
|
(require 'oc-biblatex)
|
|||
|
(require 'oc-csl))
|
|||
|
#+end_src
|
|||
|
|
|||
|
*** [[https://tecosaur.github.io/emacs-config/#translate-capital-keywords][Translate capital keywords (old) to lower case (new)]]
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+begin_src emacs-lisp
|
|||
|
(with-eval-after-load 'org
|
|||
|
(defun org-syntax-convert-keyword-case-to-lower ()
|
|||
|
"Convert all #+KEYWORDS to #+keywords."
|
|||
|
(interactive)
|
|||
|
(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)))))
|
|||
|
#+end_src
|
|||
|
|
|||
|
*** [[info:org#Advanced Export Configuration][Advanced Export Configuration (info)]]
|
|||
|
|
|||
|
Stolen from [[https://git.sr.ht/~bzg/org-contrib/tree/master/item/lisp/ox-extra.el][ox-extra.el]]
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+begin_src emacs-lisp
|
|||
|
(with-eval-after-load 'ox
|
|||
|
(defun my-org-latex-header-blocks-filter (backend)
|
|||
|
(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))))))
|
|||
|
;; Set point to where to insert LaTeX header lines after
|
|||
|
;; deleting the block.
|
|||
|
(mapc (lambda (block)
|
|||
|
(goto-char (org-element-property :post-affiliated block))
|
|||
|
(let ((lines
|
|||
|
(split-string (org-element-property :value block) "\n")))
|
|||
|
(delete-region (org-element-property :begin block)
|
|||
|
(org-element-property :end block))
|
|||
|
(dolist (line lines)
|
|||
|
(insert (concat "#+latex_header: "
|
|||
|
(replace-regexp-in-string "\\` *" "" line)
|
|||
|
"\n")))))
|
|||
|
;; Reverse to go upwards to avoid wrecking the numeric
|
|||
|
;; positions earlier in the file.
|
|||
|
(reverse blocks)))))
|
|||
|
|
|||
|
(add-hook 'org-latex-header-blocks-filter #'my-org-latex-header-blocks-filter))
|
|||
|
#+end_src
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+begin_src emacs-lisp
|
|||
|
(with-eval-after-load 'ox-latex
|
|||
|
(mapc (lambda (item)
|
|||
|
(add-to-list 'org-latex-classes item))
|
|||
|
'(;; The postfixes +1, +2, +3, -1, -2, and -3 denote:
|
|||
|
;; +1 => [DEFAULT-PACKAGES]
|
|||
|
;; +2 => [PACKAGES]
|
|||
|
;; +3 => [EXTRA]
|
|||
|
;; -1 => [NO-DEFAULT-PACKAGES]
|
|||
|
;; -2 => [NO-PACKAGES]
|
|||
|
;; -3 => [NO-EXTRA]
|
|||
|
("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
|
|||
|
|
|||
|
*** Evaluate source blocks on loading
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+begin_src emacs-lisp
|
|||
|
(defun my-org-eval-blocks-named (name)
|
|||
|
"Evaluate all source blocks named NAME."
|
|||
|
(when (eq major-mode 'org-mode)
|
|||
|
(let ((blocks
|
|||
|
(org-element-map
|
|||
|
(org-element-parse-buffer 'greater-element nil) 'src-block
|
|||
|
(lambda (block)
|
|||
|
(when (string= name (org-element-property :name block))
|
|||
|
block)))))
|
|||
|
(dolist (block blocks)
|
|||
|
(goto-char (org-element-property :begin block))
|
|||
|
(org-babel-execute-src-block)))))
|
|||
|
|
|||
|
;; Emacs looks for "Local variables:" after the last "C-q C-j C-q C-l".
|
|||
|
(add-to-list 'safe-local-eval-forms
|
|||
|
'(apply 'my-org-eval-blocks-named '("elisp-setup")))
|
|||
|
(add-to-list 'safe-local-eval-forms
|
|||
|
'(apply 'my-org-eval-blocks-named '("python-setup")))
|
|||
|
#+end_src
|
|||
|
|
|||
|
** Citing bibliography
|
|||
|
:PROPERTIES:
|
|||
|
:CUSTOM_ID: sec:citing-bibliography
|
|||
|
:END:
|
|||
|
|
|||
|
[[https://github.com/bdarcus/citar][Citar]] provides a completing-read front-end to browse and act on BibTeX,
|
|||
|
BibLaTeX, and CSL JSON bibliographic data, and LaTeX, markdown, and org-cite
|
|||
|
editing support.
|
|||
|
|
|||
|
[[https://github.com/bdarcus/citar][Citar]] -- in combination with vertico, embark, and marginalia -- provides quick
|
|||
|
filtering and selecting of bibliographic entries from the minibuffer, and the
|
|||
|
option to run different commands on those selections.
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+begin_src emacs-lisp
|
|||
|
(when (cl-every #'fboundp '(citar-insert-citation
|
|||
|
citar-insert-preset
|
|||
|
citar-org-activate
|
|||
|
citar-org-follow
|
|||
|
citar-org-insert))
|
|||
|
(custom-set-variables
|
|||
|
'(org-cite-activate-processor 'citar)
|
|||
|
'(org-cite-follow-processor 'citar)
|
|||
|
'(org-cite-insert-processor 'citar))
|
|||
|
(global-set-key (kbd "C-c b") #'citar-insert-citation)
|
|||
|
(define-key minibuffer-local-map (kbd "M-b") #'citar-insert-preset))
|
|||
|
#+end_src
|
|||
|
|
|||
|
* Editing
|
|||
|
|
|||
|
** Synchronal multiple-region editing
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+begin_src emacs-lisp
|
|||
|
(unless noninteractive
|
|||
|
(require 'iedit nil 'noerror))
|
|||
|
#+end_src
|
|||
|
|
|||
|
** Extraneous whitespace trimming
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+begin_src emacs-lisp
|
|||
|
(unless noninteractive
|
|||
|
(when (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)))
|
|||
|
#+end_src
|
|||
|
|
|||
|
** Smart character-pair handling
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+begin_src emacs-lisp
|
|||
|
(unless noninteractive
|
|||
|
(when (require 'smartparens-config nil 'noerror)
|
|||
|
;; Requiring smartparens-config disables pairing of the quote
|
|||
|
;; character for lisp modes, contrary to requiring smartparens.
|
|||
|
(custom-set-variables
|
|||
|
'(sp-base-key-bindings 'sp)
|
|||
|
'(sp-override-key-bindings '(("C-(" . sp-backward-barf-sexp)
|
|||
|
("C-)" . sp-forward-slurp-sexp))))
|
|||
|
|
|||
|
(add-hook 'LaTeX-mode-hook #'turn-off-smartparens-mode)
|
|||
|
(add-hook 'prog-mode-hook #'turn-on-smartparens-mode)
|
|||
|
(add-hook 'text-mode-hook #'turn-on-smartparens-mode)
|
|||
|
|
|||
|
(add-hook 'emacs-lisp-mode-hook #'turn-on-smartparens-strict-mode)
|
|||
|
(add-hook 'ielm-mode-hook #'turn-on-smartparens-strict-mode)
|
|||
|
(add-hook 'python-mode-hook #'turn-on-smartparens-strict-mode)
|
|||
|
|
|||
|
;; 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))
|
|||
|
|
|||
|
(sp-local-pair 'prog-mode "(" nil :post-handlers '((indent-between-pair "RET")))
|
|||
|
(sp-local-pair 'prog-mode "[" nil :post-handlers '((indent-between-pair "RET")))
|
|||
|
(sp-local-pair 'prog-mode "{" nil :post-handlers '((indent-between-pair "RET")))
|
|||
|
|
|||
|
(show-smartparens-global-mode +1)))
|
|||
|
#+end_src
|
|||
|
|
|||
|
** Operators
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+begin_src emacs-lisp
|
|||
|
(when (fboundp 'electric-operator-mode)
|
|||
|
(add-hook 'c-mode-common #'electric-operator-mode)
|
|||
|
(add-hook 'python-mode-hook #'electric-operator-mode))
|
|||
|
#+end_src
|
|||
|
|
|||
|
** Smart snippets
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+begin_src emacs-lisp
|
|||
|
(when (require 'yasnippet nil 'noerror)
|
|||
|
(custom-set-variables
|
|||
|
'(yas-alias-to-yas/prefix-p nil))
|
|||
|
(yas-global-mode +1))
|
|||
|
#+end_src
|
|||
|
|
|||
|
* Coding
|
|||
|
|
|||
|
#+begin_src emacs-lisp
|
|||
|
(with-eval-after-load 'eglot
|
|||
|
(add-to-list 'eglot-server-programs '(python-mode "pylsp")))
|
|||
|
#+end_src
|
|||
|
|
|||
|
** Python coding
|
|||
|
|
|||
|
Here, the focus is on three ways to extend Emacs's built-in ~python-mode~ out of
|
|||
|
the options listed on the [[https://www.emacswiki.org/emacs/PythonProgrammingInEmacs][Python Programming in Emacs]] wiki page:
|
|||
|
1. [[https://elpy.readthedocs.io/en/latest/][Elpy]] is an opinionated Python integrated development environment with its own
|
|||
|
Python server and its own server protocol. Its main disadvantages are:
|
|||
|
1. It requires a high number of Elisp and Python packages.
|
|||
|
2. It imposes its way making it hard to do otherwise for beginners.
|
|||
|
3. It requires a new maintainer, because the current maintainer has no time
|
|||
|
anymore for adding new features or squashing hard bugs.
|
|||
|
Its main advantages are:
|
|||
|
1. Its usability out of the box.
|
|||
|
2. Its documentation quality.
|
|||
|
3. Its compatibility with the Org source block editing mode.
|
|||
|
2. [[https://emacs-lsp.github.io/lsp-mode/][LSP Mode - Language Server Protocol support for Emacs]] with its [[https://emacs-lsp.github.io/lsp-ui/][LSP-UI]] user
|
|||
|
interface extensions. According to [[https://github.com/emacs-lsp/lsp-mode/blob/master/docs/manual-language-docs/lsp-org.md][Literate programming using LSP and
|
|||
|
org-mode(alpha)]], this package tries to be compatible with the Org source
|
|||
|
block editing mode, but it is not ready for daily usage.
|
|||
|
3. [[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 at [[https://github.com/joaotavora/eglot/issues/523][Eglot github issue: org-mode
|
|||
|
source code blocks]] shows.
|
|||
|
|
|||
|
[[https://emacs.stackexchange.com/questions/45164/does-org-have-any-inverse-tangle-operations-e-g-for-collaborating-with-non-or][Does org have any "inverse-tangle" operations e.g. for collaborating with non-org users?]]
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+begin_src python :tangle example.py :comments link
|
|||
|
import numpy
|
|||
|
import astropy.units as apu
|
|||
|
|
|||
|
a = numpy.linspace(0, 10, num=11)
|
|||
|
q = apu.Quantity(a, apu.meter)
|
|||
|
print(q)
|
|||
|
#+end_src
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+begin_src emacs-lisp
|
|||
|
(custom-set-variables
|
|||
|
'(python-shell-interpreter-args "-i -E"))
|
|||
|
(when (and (executable-find "pyenv")
|
|||
|
(require 'pyenv-mode nil 'noerror))
|
|||
|
(pyenv-mode +1)
|
|||
|
(pyenv-mode-set "3.9.8/envs/python-3.9.8"))
|
|||
|
#+end_src
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+begin_src emacs-lisp
|
|||
|
(with-eval-after-load 'info
|
|||
|
(add-to-list 'Info-directory-list
|
|||
|
(expand-file-name "~/.local/share/info")))
|
|||
|
#+end_src
|
|||
|
|
|||
|
Look into:
|
|||
|
1. [[https://github.com/douglasdavis/numpydoc.el/blob/main/numpydoc.el][Emacs extension to insert numpy style docstrings in function definitions]]
|
|||
|
|
|||
|
* Appearance
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+begin_src emacs-lisp
|
|||
|
(unless noninteractive
|
|||
|
;; 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
|
|||
|
|
|||
|
This setup prefers the ~leuven~ and ~leuven-dark~ themes from [[https://melpa.org/#/][MELPA]], because the
|
|||
|
very popular ~modus-operandi~ and ~modus-vivendi~ themes feel quirky: for
|
|||
|
instance those themes fail to display ~hl-line-mode~ with Emacs-27.2 on Darwin.
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+begin_src emacs-lisp
|
|||
|
(unless noninteractive
|
|||
|
;; Try to detect `leuven-theme` from MELPA.
|
|||
|
(when (fboundp 'leuven-scale-font)
|
|||
|
(custom-set-variables
|
|||
|
'(leuven-scale-org-agenda-structure nil)
|
|||
|
'(leuven-scale-org-document-title nil)
|
|||
|
'(leuven-scale-outline-headlines nil)
|
|||
|
'(leuven-scale-volatile-highlight nil)))
|
|||
|
(load-theme 'leuven 'no-confirm nil))
|
|||
|
#+end_src
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+begin_src emacs-lisp :tangle no
|
|||
|
(unless noninteractive
|
|||
|
(custom-set-variables
|
|||
|
'(modus-themes-hl-line 'underline)
|
|||
|
'(modus-themes-intense-markup 't))
|
|||
|
(when (and (version< emacs-version "28.0")
|
|||
|
(require 'modus-themes nil 'noerror))
|
|||
|
(modus-themes-load-themes)))
|
|||
|
#+end_src
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+begin_src emacs-lisp
|
|||
|
(unless noninteractive
|
|||
|
;; https://karthinks.com/software/batteries-included-with-emacs/
|
|||
|
;; https://www.reddit.com/r/emacs/comments/jwhr6g/batteries_included_with_emacs/
|
|||
|
(defun my-pulse-one-line (&rest _)
|
|||
|
"Pulse the current line."
|
|||
|
(let ((pulse-iterations 16)
|
|||
|
(pulse-delay 0.1))
|
|||
|
(pulse-momentary-highlight-one-line (point))))
|
|||
|
(dolist (command '(scroll-up-command
|
|||
|
scroll-down-command
|
|||
|
recenter-top-bottom
|
|||
|
other-window))
|
|||
|
(advice-add command :after #'my-pulse-one-line)))
|
|||
|
#+end_src
|
|||
|
|
|||
|
* Applications
|
|||
|
|
|||
|
** Feed reader
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+begin_src emacs-lisp
|
|||
|
(autoload 'elfeed "elfeed" nil t)
|
|||
|
(global-set-key (kbd "C-x w") #'elfeed)
|
|||
|
|
|||
|
(with-eval-after-load 'elfeed
|
|||
|
(custom-set-variables
|
|||
|
'(elfeed-feeds
|
|||
|
'(("http://www.howardism.org/index.xml" h-abrams)
|
|||
|
("https://ambrevar.xyz/atom.xml" p-neirhardt)
|
|||
|
("https://emacshorrors.com/feed.atom" v-schneidermann)
|
|||
|
("https://emacsninja.com/emacs.atom" v-schneidermann)
|
|||
|
("https://feeds.feedburner.com/InterceptedWithJeremyScahill" j-scahill)
|
|||
|
("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.aclu.org/taxonomy/feed-term/2152/feed" aclu)
|
|||
|
("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)))))
|
|||
|
#+end_src
|
|||
|
|
|||
|
** Multi-media system
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+begin_src emacs-lisp
|
|||
|
(custom-set-variables
|
|||
|
'(emms-mode-line-format "")
|
|||
|
'(emms-player-list '(emms-player-mpd emms-player-mpv))
|
|||
|
`(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)
|
|||
|
'(emms-playing-time-display-format " %s ")
|
|||
|
'(emms-playlist-mode-center-when-go t))
|
|||
|
|
|||
|
(defun my-emms-print-metadata-find ()
|
|||
|
(require 'find-func)
|
|||
|
(locate-file
|
|||
|
"emms-print-metadata"
|
|||
|
(expand-file-name
|
|||
|
"src"
|
|||
|
(file-name-directory (find-library-name "emms")))
|
|||
|
exec-suffixes #'file-executable-p))
|
|||
|
|
|||
|
(with-eval-after-load 'emms
|
|||
|
(require 'emms-info-libtag)
|
|||
|
(let ((emms-print-metadata (my-emms-print-metadata-find)))
|
|||
|
(when emms-print-metadata
|
|||
|
(custom-set-variables
|
|||
|
'(emms-info-functions nil)
|
|||
|
`(emms-info-libtag-program-name ,emms-print-metadata))
|
|||
|
(add-hook 'emms-info-functions #'emms-info-libtag))))
|
|||
|
|
|||
|
(with-eval-after-load 'elfeed-show
|
|||
|
(when (require 'emms-setup nil 'noerror)
|
|||
|
(emms-all)))
|
|||
|
|
|||
|
(autoload 'emms-streams "emms-streams" nil 'interactive)
|
|||
|
(with-eval-after-load 'emms-streams (emms-all))
|
|||
|
#+end_src
|
|||
|
|
|||
|
* [[info:emacs#Init File][Init File (info)]] footer
|
|||
|
:PROPERTIES:
|
|||
|
:CUSTOM_ID: sec:init-file-footer
|
|||
|
:END:
|
|||
|
|
|||
|
#+attr_latex: :options bgcolor=LightGoldenrodYellow
|
|||
|
#+begin_src emacs-lisp
|
|||
|
(provide 'init)
|
|||
|
|
|||
|
;; Emacs looks for "Local variables:" after the last "C-q C-j C-q C-l".
|
|||
|
|
|||
|
;; Local Variables:
|
|||
|
;; indent-tabs-mode: nil
|
|||
|
;; End:
|
|||
|
;;; init.el ends here
|
|||
|
#+end_src
|
|||
|
|
|||
|
* Compile with [[https://www.personal.psu.edu/jcc8/latexmk/][latexmk]]
|
|||
|
:PROPERTIES:
|
|||
|
:CUSTOM_ID: sec:compile-with-latexmk
|
|||
|
:END:
|
|||
|
|
|||
|
The local variable ~compile-command~ (only visible in =org= files, but not in
|
|||
|
=html= and =pdf= files) below shows how to use the =latexmkrc= file in section
|
|||
|
[[#sec:latexmk-compilation-loop][usage: latexmk compilation loop]].
|
|||
|
|
|||
|
# Emacs looks for "Local variables:" after the last "C-q C-j C-q C-l".
|
|||
|
|
|||
|
# Local Variables:
|
|||
|
# compile-command: "latexmk -interaction=nonstopmode -lualatex -pvc -shell-escape README.tex"
|
|||
|
# fill-column: 80
|
|||
|
# End:
|