Skip to content

Latest commit

 

History

History
2569 lines (2001 loc) · 88.7 KB

init.org

File metadata and controls

2569 lines (2001 loc) · 88.7 KB

Emacs Init

To try

  • Tree-sitter modes.
  • LSP, with lsp-mode or eglot. Would be nice to try texlab for LaTeX.

LaTeX export options

I may try to fancy up the LaTeX export so I can read it all like an article.

Commentary

In March 2021 I moved my Emacs config into an Org file, but did it in bulk, so many small comments are yet to be done. I’ll expand all this as I refine it.

Using Org for Emacs management

Diego Zamboni’s Literate Configuration is relevant and I should read it.

Org inits I looked at:

To try?

  • Sacha Chua’s subed for editing video subtitles
  • Should I stop using Projectile, and use Emacs built-in project stuff, such as C-x p p? How to make that divide projects nicely in C-x C-b?

Warning!

;; DO NOT EDIT THIS FILE DIRECTLY
;; It is generated from an Org file.
;;
;; You should make any changes there and regenerate it with C-c C-v t

Early init

The early init file “is loaded before the package system and GUI is initialized, so in it you can customize variables that affect frame appearance as well as the package initialization process.”

;; DO NOT EDIT THIS FILE DIRECTLY
;; It is generated from an Org file.
;;
;; You should make any changes there and regenerate it with C-c C-v t

Turn off these interface features early in startup to avoid momentary display.

;; (menu-bar-mode 1)
(tool-bar-mode -1)
(tab-line-mode -1)
;; (scroll-bar-mode 1)

Turn off the startup screen.

(setq inhibit-startup-message t)

Go full screen!

(when (fboundp 'toggle-frame-maximized)
  (toggle-frame-maximized))

I don’t have a “file containing site-wide run-time initializations.”

(setq site-run-file nil)

And finally, don’t garbage clean so often.

(setq gc-cons-threshold 8000000) ;; 8 MB

Everything from here on is in the regular init file.

Debugging (when needed)

When I need to debug something, I can turn on debugging (uncomment debug-on-error) and change warning levels.

;; (setq debug-on-error t)
(setq warning-minimum-level :emergency) ;; :emergency, :error, :warning, :debug

For more investigation, this minimal customization (as documented in the manual) might be necessary. First, turn on debugging.

(setq debug-on-error t
      debug-on-signal nil
      debug-on-quit nil)

Then load up Org from where I have it, and tell Org it can run R and shell scripts.

(add-to-list 'load-path (expand-file-name "/usr/local/src/org-mode/lisp"))

(org-babel-do-load-languages 'org-babel-load-languages '(
     (R . t)
     (shell . t)
     ))

For R, define where ESS is (change path as appropriate).

(add-to-list 'load-path "~/.emacs.d/elpa/ess-20221121.1627") ;;  "/usr/local/src/ESS/lisp"
(require 'ess-r-mode)

Then run emacs -Q -l ~/.emacs.d/minimal-org.el and take it from there. See the documentation for how to generate useful backtraces.

Starting up

Note that user-emacs-directory is ~/.emacs.d/.

Packages

First, set up the MELPA archive.

(require 'package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
(setq package-archive-priorities '(("melpa" . 20) ("gnu" . 10)))

I use John Wiegley’s great use-package everywhere I can to handle the packages I want. It’s now a part of core Emacs. diminish and bind-key go with it, because I diminish mode line indicators and use :bind in places.

(require 'use-package)
(use-package diminish)
(use-package bind-key)

If I want a package, install it automatically.

(setq use-package-always-ensure t)

Garbage Collection Magic Hack.

(use-package gcmh
  :diminish gcmh-mode
  :config
  (gcmh-mode 1)
  :custom
  (setq gcmh-verbose t) ;; t to see what it's doing
  )

Emacs server

Run the server; now I can load any file into Emacs with emacsclient file (or, as I have it aliased, e file.)

(server-mode)

Internals and technical stuff

Disable byte-compile warnings, which I don’t care about.

(setq byte-compile-warnings '(not nresolved
                                  free-vars
                                  callargs
                                  redefine
                                  obsolete
                                  noruntime
                                  cl-functions
                                  interactive-only
                                  ))

Keep custom settings in separate file. If custom.el doesn’t exist, create an empty file (for starting from scratch).

(setq custom-file "~/.custom.el")
(unless (file-exists-p custom-file)
  (write-region "" nil custom-file))
(load custom-file)

Install async, which some packages need.

(use-package async
  :defer t
  :config
  (dired-async-mode 1)
  )

Help

which-key “is a minor mode for Emacs that displays the key bindings following your currently entered incomplete command (a prefix) in a popup.” Very handy: start a command and wait a second and it will show you all the possible completions.

(use-package which-key
  :diminish which-key-mode
  :config
  (which-key-mode)
  )

Minor one-line customizations

Sentences do not need double spaces to end. But it’s better when they do, of course.

(set-default 'sentence-end-double-space nil)

Calendar weeks start on Monday.

(setq calendar-week-start-day 1)

I don’t want to type in “yes” or “no”—I want y/n.

;; (fset 'yes-or-no-p 'y-or-n-p)
(setq use-short-answers t)

Lower the time to echo keystrokes.

(setq echo-keystrokes 0.1)

Never use an X dialog box; use the minibuffer instead.

(setq use-dialog-box nil)

Hide commands in M-x which do not work in the current mode.

(setq read-extended-command-predicate #'command-completion-default-include-p)

Appearance

General

Proper line wrapping.

(global-visual-line-mode 1)

Add a little space (measured in pixels) between lines.

(setq-default line-spacing 2)

When selecting a region that wraps from one to the other, don’t highlight to the edge of the buffer.

(set-face-attribute 'region nil :extend nil)

Subtly highlight the current line.

(global-hl-line-mode 1)
;; And set its colour
;; (set-face-background hl-line-face "#efefef")

Set whether the underline line is at the baseline (just below an x) or the descent line (just below a y). I used want it at the descent line but now I don’t, so I don’t tangle this, meaning the default of the baseline is used.

(setq x-underline-at-descent-line t)

Protesilaos Stavrou’s spacious-padding mode makes things look comfortably nicer.

(use-package spacious-padding
  :config
  (spacious-padding-mode)
  )

Pointer

Make the cursor a thin horizontal bar, not a block. It can be =’bar= or =’box= or =’(hbar . 3)= etc. I like it blinking so I don’t disable blink-cursor-mode.

(set-default 'cursor-type '(bar . 2))

Change the pointer colour. Why boring old plain white?

(set-cursor-color "DarkGoldenrod")

Faces, fonts and pitches

My home and work machines have different screen resolutions, so the font height needs to be different. It’s measured in 0.1 points, so 130 is 13 pt. I need it a little bigger on my work machine.

(setq wtd-fixed-pitch-height
      (cond ((string= (system-name) "ochre") 130)
	    ((string= (system-name) "helium") 130)
	    (t 120))
      )

I’m going to try, yet again, using variable pitch for regular text. I try it every now and then and have always reverted back, but maybe it will be different this time.

First, set the default, which is fixed pitch, or monospaced. I now use the DejaVu fonts, so for this it’s DejaVu Sans Mono. I also use this in terminal windows, so everything looks the same. (Before, I used Ubuntu Mono, and I tried Fira Code for a little while. I might try Victor Mono one day.)

Where Fontconfig is used, running fc-list : family | sort will list all available fonts.

(set-face-attribute 'default nil :font "DejaVu Sans Mono" :height wtd-fixed-pitch-height)

Using mixed-pitch makes it easy to have both variable and fixed pitches. For variable pitch I use DejaVu Serif, which goes well with its Mono version, of course. I was using DejaVu Sans, but saw serif used in the Mono theme and wanted to try it again. I had tried Baskerville as the variable pitch, but while it’s one of my favourites in print, on screen it didn’t suit me. (On Ubuntu I ran sudo apt install fonts-adf-baskervald to install it.)

The variable-pitch face may need to be sized larger than the fixed one: if it’s the same height it may look small in comparison. Setting mixed-pitch-set-height to true is necessary to allow this.

(use-package mixed-pitch
  :diminish
  :hook
  (text-mode . mixed-pitch-mode)
  ;; (org-mode markdown-mode)
  :config
  (setq mixed-pitch-set-height t)
  (set-face-attribute 'fixed-pitch nil :inherit 'default)
  ;; (set-face-attribute 'variable-pitch nil :family "Baskervald ADF Std" :height 1.2)
  ;; (set-face-attribute 'variable-pitch nil :family "DejaVu Sans" :height 1.1)
  (set-face-attribute 'variable-pitch nil :family "DejaVu Serif" :height 1.2)
  ;; (setq left-margin-width 10)
  ;; (setq right-margin-width 10)
  )

This could help improve performance with Unicode symbols.

(setq inhibit-compacting-font-caches t)

Always do font-locking.

(setq font-lock-maximum-decoration t)

Unicode and UTF-8

list-unicode-display “provides a command which searches for Unicode characters by name, and displays a list of matching characters with their names in a buffer.”

(use-package list-unicode-display)

UTF-8 everywhere (surely this is overkill?).

(set-language-environment "UTF-8")
(setq locale-coding-system 'utf-8)
(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)
(set-selection-coding-system 'utf-8)
(prefer-coding-system 'utf-8)

Parentheses

Use smartparens to handle parentheses? Right now, no. I’m going to try not having any fancy parentheses (or quote, or whatever) handling, so I have to type it all in myself.

(use-package smartparens
  :diminish smartparens-mode
  :init
  (require 'smartparens-config)
  :config
  (smartparens-global-mode t)
  (show-smartparens-global-mode t)
  (setq sp-show-pair-from-inside t)
  :custom-face
  (sp-show-pair-match-face ((t (:foreground "White")))) ;; Could also have :background "Colour" in there.
  ;; (sp-show-pair-match-content-face ((t (:foreground "White")))) ;; Highlight all the enclosed content
  (sp-show-pair-mismatch-face ((t (:foreground "Red"))))
  )

I do want a bit of basic help with these, however. (I wish the blink highlight were more obvious—how can I make it flash reverse, or something like that?)

(show-paren-mode t)
(setq blink-matching-paren t)

Indenting

Tabs have four spaces. Eight is wrong.

(setq tab-width 4)

I don’t turn on the built-in electric-indent-mode because I use aggressive-indent-mode, which is indeed aggressive, but very handy.

(use-package aggressive-indent
  :diminish aggressive-indent-mode ;; "→"
  :config
  (global-aggressive-indent-mode 1)
  (add-to-list 'aggressive-indent-excluded-modes 'html-mode)
  )

I was trying out highlight-indent-guides (after using indent-guide before) but I disabled it to see if I miss it. (Watch out for the ESS hook.)

(use-package highlight-indent-guides
  :diminish
  :config
  (setq highlight-indent-guides-method 'character
	highlight-indent-guides-character ?\|)
  :hook
  (prog-mode . highlight-indent-guides-mode)
  )

Solarized theme

Bozhidar Batsov’s Solarized theme for Emacs is smooth and easy on the eye.

(setq my-solarized-theme
      (cond ((string= (system-name) "helium") 'solarized-light)
	    (t 'solarized-dark)))

(use-package solarized-theme
  :config
  ;; Stop the theme from messing up Org headlines and using variable pitch everywhere.
  (setq solarized-use-variable-pitch nil
	solarized-scale-org-headlines nil
	solarized-high-contrast-mode-line t
	solarized-use-more-italic t)
  ;; (load-theme 'solarized-light t)
  (load-theme my-solarized-theme t)
  )

Mode line

Include the size of the file in the mode line.

(size-indication-mode t)

Also show which column I’m in.

(column-number-mode t)

I used to use powerline, but went back to just the default. I’ll leave the old invocation here for a while.

(use-package powerline
  :config
  (powerline-default-theme)
  )

I don’t like a crowded mode line, and for most modes I don’t want it to show the mode is active, so I use :diminish when packages are installed with use-package. That doesn’t get everything, so I need to specify some here.

(diminish 'abbrev-mode)
(diminish 'emacs-lisp-d-mode "")

And here’s a list of various other modes I hide a different way.

(eval-after-load "autorevert" '(diminish 'auto-revert-mode))
(eval-after-load "eldoc" '(diminish 'eldoc-mode))
;; (eval-after-load "flymake" '(diminish 'flymake-mode))
(eval-after-load "flyspell" '(diminish 'flyspell-mode ""))
;;(eval-after-load "magit" '(diminish 'magit-auto-revert-mode))
(eval-after-load "org-indent" '(diminish 'org-indent-mode)) ;; →
(eval-after-load "outline" '(diminish 'outline-minor-mode))
(eval-after-load "rainbow-mode" '(diminish 'rainbow-mode))
(eval-after-load "subword" '(diminish 'subword-mode))

Prettifying symbols

Use prettify-symbols-mode everywhere.

(global-prettify-symbols-mode 1)

The mode reveals what’s really there when the pointer is on the symbol, and this makes it also show the real text when the pointer is just to the right.

(setq prettify-symbols-unprettify-at-point 'right-edge)

I don’t think I should be setting this variable like this, but there’s no other way I can figure out to get prettification working in Ruby and other modes that don’t have the right stuff built in (unlike the mode for Python).

Nevertheless, this doesn’t work. Why don’t more programming modes support this mode?

(setq-default prettify-symbols-alist '(("->" . ?→)
 				       ("<-" . ?←)
                                       ("->>" . ?↠)
                                       ("->>" . ?↞)
                                       ("=>" . ?⇒)
                                       ("!=" . ?≠)
                                       ("==" . ?≡)
                                       ("<=" . ?≤)
                                       (">=" . ?≥)
				       ))

Further customizations are set up by language.

Sessions, buffers, windows and projects

Regions

I’m old enough to be able to use narrow-to-region.

(put 'narrow-to-region 'disabled nil)

This is another borrowing from Arthur Malabarba. C-x w narrows or widens the region, as appropriate. This is beautiful magic in Org.

(defun narrow-or-widen-dwim (p)
  "Widen if buffer is narrowed, narrow-dwim otherwise.
Dwim means: region, org-src-block, org-subtree, 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))
        ((region-active-p)
         (narrow-to-region (region-beginning) (region-end)))
        ((derived-mode-p 'org-mode)
         ;; `org-edit-src-code' is not a real narrowing
         ;; command. Remove this first conditional if you
         ;; don't want it.
         (cond ((ignore-errors (org-edit-src-code))
                (delete-other-windows))
               ((ignore-errors (org-narrow-to-block) t))
               (t (org-narrow-to-subtree))))
        ((derived-mode-p 'latex-mode)
         (LaTeX-narrow-to-environment))
        (t (narrow-to-defun))))

(define-key ctl-x-map "w" #'narrow-or-widen-dwim)
(eval-after-load 'latex '(define-key LaTeX-mode-map "\C-xw" nil))

wrap-region to wrap regions in * or / etc. Extra lines taken from Wrap text in custom characters.

(use-package wrap-region
  :defer t
  :diminish wrap-region-mode
  :config
  ;; (wrap-region-mode t)
  (wrap-region-add-wrappers
   '(("*" "*" nil org-mode)
     ("~" "~" nil org-mode)
     ("/" "/" nil org-mode)
     ("=" "=" "+" org-mode)
     ("_" "_" nil org-mode)
     ("$" "$" nil (org-mode latex-mode))))
  :init
  (add-hook 'org-mode-hook 'wrap-region-mode)
  (add-hook 'latex-mode-hook 'wrap-region-mode)
  )

Expand-region is kind of magical. C-= successively expands the region with great intelligence.

(use-package expand-region
  :defer t
  :init
  (global-set-key (kbd "C-=") 'er/expand-region)
  )

Buffers

Remember all (well, almost) the buffers I have open.

(desktop-save-mode 1)
(setq history-length 50)
(setq desktop-buffers-not-to-save
      (concat "\\("
	      "^nn\\.a[0-9]+\\|\\.log\\|(ftp)\\|^tags\\|^TAGS"
	      "\\|\\.emacs.*\\|\\.diary\\|elpa\/*\\|\\.bbdb"
	      "\\)$"))
(add-to-list 'desktop-modes-not-to-save 'dired-mode)
(add-to-list 'desktop-modes-not-to-save 'Info-mode)
(add-to-list 'desktop-modes-not-to-save 'info-lookup-mode)
(add-to-list 'desktop-modes-not-to-save 'fundamental-mode)

Add parts of each file’s directory to the buffer name if not unique.

(require 'uniquify)
(setq uniquify-buffer-name-style 'forward)

A few things about the scratch buffer. By default it’s in lisp-interaction-mode by default, but I use Org more, so make it that.

(setq initial-major-mode 'org-mode)
(setq initial-scratch-message "")

Use C-c b to create a new scratch buffer.

(defun create-scratch-buffer nil
  "Create a new scratch buffer to work in (could be *scratch* - *scratchX*)."
  (interactive)
  (let ((n 0)
	bufname)
    (while (progn
	     (setq bufname (concat "*scratch"
				   (if (= n 0) "" (int-to-string n))
				   "*"))
	     (setq n (1+ n))
	     (get-buffer bufname)))
    (switch-to-buffer (get-buffer-create bufname))
    (org-mode)))
;; (global-set-key (kbd "C-c b") 'create-scratch-buffer)
(keymap-global-set "C-c b" 'create-scratch-buffer)

When I want to kill a buffer, it’s always the current one, so don’t ask. (Source.)

(defun wtd/kill-this-buffer ()
  "Kill the current buffer."
  (interactive)
  (kill-buffer (current-buffer)))

;; (global-set-key (kbd "C-x k") 'wtd/kill-this-buffer)
(keymap-global-set "C-x k" 'wtd/kill-this-buffer)

ibuffer is a nicer way of showing the buffer list (C-x C-b). It’s built in. Alias the usual buffer list command to ibuffer.

(defalias 'list-buffers 'ibuffer)

Set up some default groups so that files are grouped by type (or location).

(setq ibuffer-saved-filter-groups
      (quote (("default"
 	       ("dired" (mode . dired-mode))
 	       ("emacs" (or
 			 (name . "^\\*scratch\\*$")
 			 (name . "^\\*Messages\\*$")))
	       ))))

Windows

Split the window horizontally, not vertically (I prefer side-by-side with wider screens).

(setq split-height-threshold nil)
(setq split-width-threshold 0)

Make window splitting easier: C-x 2 for vertical split, C-x 3 for horizontal.

(defun wtd/vsplit-last-buffer (PREFIX)
  "Split the window vertically and display the previous buffer.
   By default, switch to that new window; with PREFIX, stay where you are."
  (interactive "p")
  (split-window-vertically)
  (other-window 1 nil)
  (unless prefix
    (switch-to-next-buffer)))

(defun wtd/hsplit-last-buffer (PREFIX)
  "Split the window horizontally and display the previous buffer.
   By default, switch to that new window; with PREFIX, stay where you are."
  (interactive "p")
  (split-window-horizontally)
  (other-window 1 nil)
  (unless prefix (switch-to-next-buffer)))

;; (global-set-key (kbd "C-x 2") 'wtd/vsplit-last-buffer)
;; (global-set-key (kbd "C-x 3") 'wtd/hsplit-last-buffer)
(keymap-global-set "C-x 2" 'wtd/vsplit-last-buffer)
(keymap-global-set "C-x 3" 'wtd/hsplit-last-buffer)

Use C-c left or C-c right to go back and forth in window configurations.

(winner-mode t)

Or use M-o as a shortcut for other-window instead of the default C-x o, which is too long. This makes it much easier to toggle between windows.

;; (global-set-key (kbd "M-o") 'other-window)
(keymap-global-set "M-o" 'other-window)

I could use eyebrowse to manage window configurations, but I never did, so I took out the code. I’ll leave this note here in case I want to go back.

Sessions

When I close a session, save exactly where I was in the files.

(require 'saveplace)
(setq save-place-file (expand-file-name ".places" user-emacs-directory))
(save-place-mode)

Projects

Trying the built-in projects features.

(setq project-vc-extra-root-markers '(".project.el" ".projectile" ))
(use-package ibuffer-project
  :hook (ibuffer . (lambda ()
                     "Group ibuffer's list by project."
                     (setq ibuffer-filter-groups (ibuffer-project-generate-filter-groups))
                     (unless (eq ibuffer-sorting-mode 'project-file-relative)
                       (ibuffer-do-sort-by-project-file-relative))))
  :init (setq ibuffer-project-use-cache t)
  )
(use-package projectile
  :config
  (projectile-mode)
  (define-key projectile-mode-map (kbd "C-c p") 'projectile-command-map)
  (setq projectile-mode-line-function '(lambda () (format " ᴨ[%s]" (projectile-project-name))))
  )
(use-package ibuffer-projectile
  :defer t
  :init
  (add-hook 'ibuffer-hook
	    (lambda ()
	      (ibuffer-projectile-set-filter-groups)
	      (unless (eq ibuffer-sorting-mode 'alphabetic)
		(ibuffer-do-sort-by-alphabetic))))
  )

Completion and the minibuffer

In January 2023 I moved from the Ivy-Swiper-Counsel system (which served me well for many years) to Vertico and its friends.

Vertico

First, set up Vertico (VErtical Interactive COmpletion), a “minimalistic vertical completion UI based on the default completion system.”

(use-package vertico
  :init
  (vertico-mode)
  (vertico-multiform-mode)
  :config
  (add-to-list 'vertico-multiform-categories '(embark-keybinding grid))
)

This adds some extra features for navigating directories with find-file.

(use-package vertico-directory
  :after vertico
  :ensure nil
  ;; More convenient directory navigation commands
  :bind (:map vertico-map
              ("RET" . vertico-directory-enter)
              ("DEL" . vertico-directory-delete-char)
              ("M-DEL" . vertico-directory-delete-word))
  ;; Tidy shadowed file names
  :hook (rfn-eshadow-update-overlay . vertico-directory-tidy))

Orderless

Orderless “provides an orderless completion style that divides the pattern into space-separated components, and matches candidates that match all of the components in any order.” It relies on savehist for suggestions based on history.

(use-package savehist
  :init
  (savehist-mode)
  )
(use-package orderless
  :init
  (setq completion-styles '(orderless basic)
	completion-category-defaults nil
	completion-category-overrides '((file (styles partial-completion))))
  )

Marginalia

Marginalia “adds marginalia to the minibuffer completions” such as file details, command definitions and so on. This is really handy.

(use-package marginalia
  ;; Bind `marginalia-cycle' locally in the minibuffer.  To make the binding
  ;; available in the *Completions* buffer, add it to the
  ;; `completion-list-mode-map'.
  :bind (:map minibuffer-local-map
	      ("M-A" . marginalia-cycle))

  :init
  (marginalia-mode)
  )

Consult

And Consult is a big one, it “provides search and navigation commands based on the Emacs completion function completing-read. Completion allows you to quickly select an item from a list of candidates.” I’ve overwritten some key bindings so the Consult version replaces the built-in version. I’ve also left a lot of suggested bindings in place here that I don’t use right now, but might.

(use-package consult
  ;; Replace bindings. Lazily loaded due by `use-package'.
  :bind (;; C-c bindings in `mode-specific-map'
	 ;; First, settings I customized.
         ("C-s" . consult-line) ;; The most important.
         ([remap goto-line] . consult-goto-line)
         ([remap imenu] . consult-imenu)
         ("M-i" . consult-imenu)
	 ;; The rest are copied from the suggested config.
         ("C-c M-x" . consult-mode-command)
         ("C-c h" . consult-history)
         ("C-c k" . consult-kmacro)
         ("C-c m" . consult-man)
         ("C-c i" . consult-info)
         ([remap Info-search] . consult-info)
         ;; C-x bindings in `ctl-x-map'
         ("C-x M-:" . consult-complex-command)     ;; orig. repeat-complex-command
         ("C-x b" . consult-buffer)                ;; orig. switch-to-buffer
         ("C-x 4 b" . consult-buffer-other-window) ;; orig. switch-to-buffer-other-window
         ("C-x 5 b" . consult-buffer-other-frame)  ;; orig. switch-to-buffer-other-frame
         ("C-x t b" . consult-buffer-other-tab)    ;; orig. switch-to-buffer-other-tab
         ("C-x r b" . consult-bookmark)            ;; orig. bookmark-jump
         ("C-x p b" . consult-project-buffer)      ;; orig. project-switch-to-buffer
         ;; Custom M-# bindings for fast register access
         ("M-#" . consult-register-load)
         ("M-'" . consult-register-store)          ;; orig. abbrev-prefix-mark (unrelated)
         ("C-M-#" . consult-register)
         ;; Other custom bindings
         ("M-y" . consult-yank-pop)                ;; orig. yank-pop
         ;; M-g bindings in `goto-map'
         ("M-g e" . consult-compile-error)
         ("M-g f" . consult-flymake)               ;; Alternative: consult-flycheck
         ("M-g o" . consult-outline)               ;; Alternative: consult-org-heading
         ("M-g m" . consult-mark)
         ("M-g k" . consult-global-mark)
         ("M-g I" . consult-imenu-multi)
         ;; M-s bindings in `search-map'
         ("M-s d" . consult-find)                  ;; Alternative: consult-fd
         ("M-s c" . consult-locate)
         ("M-s g" . consult-grep)
         ("M-s G" . consult-git-grep)
         ("M-s r" . consult-ripgrep)
         ("M-s L" . consult-line-multi)
         ("M-s k" . consult-keep-lines)
         ("M-s u" . consult-focus-lines)
         ;; Isearch integration
         ("M-s e" . consult-isearch-history)
         :map isearch-mode-map
         ("M-e" . consult-isearch-history)         ;; orig. isearch-edit-string
         ("M-s e" . consult-isearch-history)       ;; orig. isearch-edit-string
         ("M-s l" . consult-line)                  ;; needed by consult-line to detect isearch
         ("M-s L" . consult-line-multi)            ;; needed by consult-line to detect isearch
         ;; Minibuffer history
         :map minibuffer-local-map
         ("M-s" . consult-history)                 ;; orig. next-matching-history-element
         ("M-r" . consult-history))                ;; orig. previous-matching-history-element

  ;; Enable automatic preview at point in the *Completions* buffer. This is
  ;; relevant when you use the default completion UI.
  :hook (completion-list-mode . consult-preview-at-point-mode)

  ;; The :init configuration is always executed (Not lazy)
  :init

  ;; Optionally configure the register formatting. This improves the register
  ;; preview for `consult-register', `consult-register-load',
  ;; `consult-register-store' and the Emacs built-ins.
  (setq register-preview-delay 0.5
        register-preview-function #'consult-register-format)

  ;; Optionally tweak the register preview window.
  ;; This adds thin lines, sorting and hides the mode line of the window.
  (advice-add #'register-preview :override #'consult-register-window)

  ;; Use Consult to select xref locations with preview
  (setq xref-show-xrefs-function #'consult-xref
        xref-show-definitions-function #'consult-xref)

  :config

  ;; Optionally configure preview. The default value
  ;; is 'any, such that any key triggers the preview.
  ;; (setq consult-preview-key 'any)
  ;; (setq consult-preview-key "M-.")
  ;; (setq consult-preview-key '("S-<down>" "S-<up>"))
  ;; For some commands and buffer sources it is useful to configure the
  ;; :preview-key on a per-command basis using the `consult-customize' macro.
  (consult-customize
   consult-theme :preview-key '(:debounce 0.5 any)
   consult-ripgrep consult-git-grep consult-grep
   consult-bookmark consult-recent-file consult-xref
   consult--source-bookmark consult--source-file-register
   consult--source-recent-file consult--source-project-recent-file
   ;; :preview-key "M-."
   :preview-key '(:debounce 0.4 any))

  ;; Optionally configure the narrowing key.
  ;; Both < and C-+ work reasonably well.
  (setq consult-narrow-key "<") ;; "C-+"

  ;; Optionally make narrowing help available in the minibuffer.
  ;; You may want to use `embark-prefix-help-command' or which-key instead.
  ;; (define-key consult-narrow-map (vconcat consult-narrow-key "?") #'consult-narrow-help)

  ;; By default `consult-project-function' uses `project-root' from project.el.
  ;; Optionally configure a different project root function.
  ;;;; 1. project.el (the default)
  ;; (setq consult-project-function #'consult--default-project--function)
  ;;;; 2. vc.el (vc-root-dir)
  ;; (setq consult-project-function (lambda (_) (vc-root-dir)))
  ;;;; 3. locate-dominating-file
  ;; (setq consult-project-function (lambda (_) (locate-dominating-file "." ".git")))
  ;;;; 4. projectile.el (projectile-project-root)
  ;; (autoload 'projectile-project-root "projectile")
  ;; (setq consult-project-function (lambda (_) (projectile-project-root)))
  ;;;; 5. No project support
  ;; (setq consult-project-function nil)
)

I don’t want to see previews of any remote files (perhaps bookmarked with Tramp), so I’m using this snippet from the Consult wiki. Unfortunately it doesn’t work, and something about it messes up the rest of the configuration, so I’m not tangling it until this is sorted out.

(defun consult-buffer-state-no-tramp ()
  "Buffer state function that doesn't preview Tramp buffers."
  (let ((orig-state (consult--buffer-state))
        (filter (lambda (action cand)
                  (if (and cand
                           (or (eq action 'return)
                               (let ((buffer (get-buffer cand)))
                                 (and buffer
                                      (not (file-remote-p (buffer-local-value 'default-directory buffer)))))))
                      cand
                    nil))))
    (lambda (action cand)
      (funcall orig-state action (funcall filter action cand)))))

(setq consult--source-buffer
      (plist-put consult--source-buffer :state #'consult-buffer-state-no-tramp))

Prescient

Prescient makes M-x listings and suggestions better by remembering what you’ve run before.

(use-package vertico-prescient
  :after vertico
  :init
  (vertico-prescient-mode)
  (prescient-persist-mode)
  )

Embark

I didn’t get what Embark does until I tried it, and I’m not sure yet how best to use it. If the point is on something interesting, embark-act (bound to C-.) will pop up a list of actions that can be taken on what’s at the point: “You can think of embark-act as a keyboard-based version of a right-click contextual menu.” It’s context-dependent, so it acts differently for Org source blocks, URLs, and so on. M-. runs embark-dwim and performs the default action, which might not be what I want, so I should always check first.

(use-package embark
  :ensure t
  :bind
  (("C-." . embark-act)
   ("M-." . embark-dwim)
   ("C-h B" . embark-bindings)) ;; alternative for `describe-bindings'
  :init
  ;; Optionally replace the key help with a completing-read interface
  (setq prefix-help-command #'embark-prefix-help-command)

  ;; Show the Embark target at point via Eldoc. You may adjust the
  ;; Eldoc strategy, if you want to see the documentation from
  ;; multiple providers. Beware that using this can be a little
  ;; jarring since the message shown in the minibuffer can be more
  ;; than one line, causing the modeline to move up and down:

  ;; (add-hook 'eldoc-documentation-functions #'embark-eldoc-first-target)
  ;; (setq eldoc-documentation-strategy #'eldoc-documentation-compose-eagerly)

  :config
 (setq prefix-help-command #'embark-prefix-help-command)
 (add-to-list 'vertico-multiform-categories '(embark-keybinding grid))
 (setq embark-indicators
       '(embark-mixed-indicator
         embark-highlight-indicator
         embark-isearch-highlight-indicator))
  ;; Hide the mode line of the Embark live/completions buffers
  (add-to-list 'display-buffer-alist
               '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
                 nil
                 (window-parameters (mode-line-format . none))))
  )

This connects Embark and Consult.

;; Consult users will also want the embark-consult package.
(use-package embark-consult
  :ensure t ; only need to install it, embark loads it after consult if found
  :after embark consult
  :hook
  (embark-collect-mode . consult-preview-at-point-mode)
  )

Corfu

Connected to all the above is Corfu, which is “the minimalistic in-buffer completion counterpart” of Vertico.

(use-package corfu
  :custom
  (corfu-cycle t)
  (corfu-quit-at-boundary 'separator)
  (corfu-echo-documentation 0.25)
  ;; :hook ((prog-mode . corfu-mode))
  :init
  (global-corfu-mode)
  :bind
  (:map corfu-map
	("<escape>" . corfu-quit)
	)
  )

Small tweaks

(setq tab-always-indent 'complete) ;; Try to indent current line; if already indented, try to complete the thing at point.

Command launchers

These key mappings (C-x l something) make it easier to run common things. I learned about this from Arthur Malabarba’s Launcher keymap for standalone features.

(define-prefix-command 'launcher-map)
(define-key ctl-x-map "l" 'launcher-map)
(define-key launcher-map "c" #'calculator) ; calc is too much
(define-key launcher-map "g" #'magit-status)
(define-key launcher-map "l" #'goto-line)
(define-key launcher-map "m" #'mc/edit-lines)
(define-key launcher-map "p" #'list-packages)
(define-key launcher-map "s" #'eshell)
(define-key launcher-map "u" #'magit-pull-from-upstream)
(define-key launcher-map "w" #'count-words-region)

Editing

Scrolling

Scroll by one line at a time.

(setq scroll-conservatively 10000)

A tip found on Stack Exchange to stop scrolling from slowing things down.

(setq auto-window-vscroll nil)

Whitespace

Remove trailing whitespace (at the end of a file) automatically.

(add-hook 'before-save-hook 'delete-trailing-whitespace)

But it should end with a newline, so if there isn’t one there, add it.

(setq require-final-newline t)

But down-arrow at the end of a file shouldn’t add in a new line.

(setq next-line-add-newlines nil)

If there are any empty lines at the end of a buffer, show them (but they will disappear on saving, because of the above).

(set-default 'indicate-empty-lines t)

Colours

Rainbow-mode is a handy little helper. “All strings representing colors will be highlighted with the color they represent.”

(use-package rainbow-mode
  :init
  (add-hook 'prog-mode-hook 'rainbow-mode)
  :config
  (rainbow-mode t) ;; #0af
  )

Other editing

Let me upcase or downcase a region, which is disabled by default.

(put 'downcase-region 'disabled nil)
(put 'upcase-region 'disabled nil)

With iedit I can edit multiple occurrences of the same text all at once (see Mickey Petersen’s post about it).

(use-package iedit
  :bind
  (("C-:" . iedit-mode))
  )

I don’t use multiple cursors … but I could.

(use-package multiple-cursors)

Open a new line above or below the current one, even if the cursor is mid-sentence. (January 2024: don’t tangle; I don’t use this.)

(defun open-line-below ()
  (interactive)
  (end-of-line)
  (newline)
  (indent-for-tab-command))

(defun open-line-above ()
  (interactive)
  (beginning-of-line)
  (newline)
  (forward-line -1)
  (indent-for-tab-command))

(global-set-key (kbd "<C-return>") 'open-line-below)
(global-set-key (kbd "<C-S-return>") 'open-line-above)

Move an entire line up or down with C-S-up or C-S-down. (January 2024: don’t tangle; I was hitting this by accident, and never used it intentionally.)

(defun move-line-down ()
  (interactive)
  (let ((col (current-column)))
    (save-excursion
      (forward-line)
      (transpose-lines 1))
    (forward-line)
    (move-to-column col)))

(defun move-line-up ()
  (interactive)
  (let ((col (current-column)))
    (save-excursion
      (forward-line)
      (transpose-lines -1))
    (move-to-column col)))

(global-set-key (kbd "<C-S-down>") 'move-line-down)
(global-set-key (kbd "<C-S-up>") 'move-line-up)

Join the following line onto this one. Good for reformatting. (January 2024: Use unfill-region instead.)

(global-set-key (kbd "M-j")
            (lambda ()
                  (interactive)
                  (join-line -1)))

Steve Purcell’s unfill gives unfill-region and unfill-paragraph, which are opposites of the built-in fill functions.

(use-package unfill
  :init
  (global-set-key (kbd "<f9>") 'unfill-toggle)
)

Searching

Make searches case insensitive.

(setq case-fold-search nil)

Turn on highlighting for search strings.

(setq search-highlight t)

Anzu-mode provides a “minor mode which display current point and total matched in various search mode.”

(use-package anzu
  :diminish anzu-mode
  :config
  (global-anzu-mode t)
  (global-set-key (kbd "M-%") 'anzu-query-replace)
  (global-set-key (kbd "C-M-%") 'anzu-query-replace-regexp)
  )

I was getting errors about exceeding the defaults on both of these.

(setq max-specpdl-size 50000)
(setq max-lisp-eval-depth 25000)

Copying and pasting

Highlight marked text.

(transient-mark-mode t)

Remove text in active region if inserting text.

(delete-selection-mode 1)

The volatile-highlights mode temporarily highlights what you’ve just pasted in. When you move the pointer, it disappears.

(use-package volatile-highlights
  :init (volatile-highlights-mode t)
  :diminish volatile-highlights-mode
  :config
  (vhl/define-extension 'undo-tree 'undo-tree-yank 'undo-tree-move)
  (vhl/install-extension 'undo-tree)
  )

Enable cutting/pasting and putting results into the X clipboard. (January 2024: don’t tangle; I don’t think I ever use this.)

(global-set-key [(shift delete)] 'clipboard-kill-region)
(global-set-key [(control insert)] 'clipboard-kill-ring-save)
(global-set-key [(shift insert)] 'clipboard-yank)

Allow pasting selection outside of Emacs.

(setq select-enable-clipboard t)

M-backspace is backward-word-kill, and C-backspace is bound to that by default. Change that to backword-kill-line so it deletes from the point to the beginning of the line.

(global-set-key (kbd "C-<backspace>") (lambda ()
					(interactive)
					(kill-line 0)))

Spelling

Usually I invoke M-x ispell to check spelling, or M-$ on a word to deal with it, but I’m going to try flyspell-correct and see how that helps. C-; to jump back to the first misspelled word before the point, then jump back to where you were. Good for very easily fixing a mistake a few words back. (Use M-o to see the options for saving or ignoring a word.)

By default flyspell binds C-. but I want Embark to be able to use that. A helpful Stack Overflow answer showed me how to arrange this.

(eval-after-load "flyspell" '(define-key flyspell-mode-map (kbd "C-.") nil))
(use-package flyspell-correct
  :after flyspell
  :bind (:map flyspell-mode-map ("C-;" . flyspell-correct-wrapper)))

Use Flyspell for spell-checking in comments in programs.

(add-hook 'prog-mode-hook 'flyspell-prog-mode)

Expansions and abbreviations

Abbrevs

Abbrevs are words or letter combinations that when typed expand into longer words or phrases. New ones can be added with define-global-abbrev or define-mode-abbrev for a particular mode.

(setq-default abbrev-mode t)

The abbrevs are saved in this file. “The abbrevs are saved in the form of a Lisp program to define the same abbrev tables with the same contents.”

(setq abbrev-file-name "~/.emacs.d/abbrev_defs")

Yasnippet

Yet Another Snippet Extension.

(use-package yasnippet
  :diminish yas-minor-mode
  :config
  (use-package yasnippet-snippets)
  (yas-global-mode 1)
  )

Undoing

undo-tree gives a nice visualization of changes to the file.

(use-package undo-tree
  :diminish undo-tree-mode
  :config
  (global-undo-tree-mode)
  (setq undo-tree-auto-save-history nil) ;; If t then big dot files start accumulating
  :custom
  (undo-tree-visualizer-timestamps t)
  (undo-tree-visualizer-diff t)
  )

File management

Keep a list of recently opened files

(require 'recentf)
(recentf-mode 1)
(setq recentf-save-file "~/.recentf")

Rebind FFAP’s find-file-at-point so it goes with C-x f (usually find-file), so I don’t have to use C-x C-f (its default binding). Saves time.

(global-set-key (kbd "C-x f") 'find-file-at-point)

Refresh buffers when files change. But don’t worry: “Auto Revert will not revert a buffer if it has unsaved changes, or if its file on disk is deleted or renamed.”

(global-auto-revert-mode t)

Dired

Auto refresh dired, but be quiet about it.

(setq global-auto-revert-non-file-buffers t)

Tell dired how to handle some file types.

(setq dired-guess-shell-alist-user
      '(("\\.pdf\\'" "evince")
	("\\.tex\\'" "pdflatex")
	("\\.ods\\'\\|\\.xlsx?\\'\\|\\.docx?\\'\\|\\.csv\\'" "libreoffice")))

C-x C-j (M-x dired-jump) instantly goes to the current file’s position in a dired buffer. No need to open up a dired buffer and move the pointer.

(require 'dired-x)

I want the long (like ls -l )format in file listings.

(setq diredp-hide-details-initially-flag nil)

“In Dired, visit this file or directory instead of the Dired buffer.” Prevents buffers littering up things when moving around in Dired.

(put 'dired-find-alternate-file 'disabled nil)

Reuse the current buffer when moving into a new directory.

(setq dired-kill-when-opening-new-dired-buffer t)

Make it easier to move and copy files across windows.

(setq dired-dwim-target t)

dired+ has got some wild colours by default. This turns that off, but leaves the settings at maximum (the default) for everything else.

(setq font-lock-maximum-decoration (quote ((dired-mode) (t . t))))

Rename or delete the current buffer and its file

A file management shortcut from Bodil Stokke’s setup, and something that she also had done but is now handled by a built-in function.

  • C-x C-k to delete the file being edited and kill the buffer
  • C-x C-r to rename the file being edited and the current buffer
(defun wtd/delete-current-buffer-file ()
  "Delete file connected to current buffer and kill buffer."
  (interactive)
  (let ((filename (buffer-file-name))
        (buffer (current-buffer))
        (name (buffer-name)))
    (if (not (and filename (file-exists-p filename)))
        (ido-kill-buffer)
      (when (yes-or-no-p "Are you sure you want to delete this file? ")
        (delete-file filename)
        (kill-buffer buffer)
        (message "File '%s' successfully removed" filename)))))
;;(global-set-key (kbd "C-x C-k") 'wtd/delete-current-buffer-file)
(keymap-global-set "C-x C-k" 'wtd/delete-current-buffer-file)
;; (global-set-key (kbd "C-x C-r") 'rename-visited-file)
(keymap-global-set "C-x C-r" 'rename-visited-file)

File types

CSV

I love CSV files, but I’d rather load them into Org or R then edit them directly. Still …

(use-package csv-mode)

JSON

JSON-mode.

(use-package json-mode)

Markdown

(use-package markdown-mode
  :commands (markdown-mode gfm-mode)
  :mode (
	 ("README\\.md\\'" . gfm-mode)
	 )
  :init
  ;; (setq markdown-command "multimarkdown")
  (setq markdown-hide-urls t
	markdown-hide-markup t
	markdown-url-compose-char ""
	markdown-header-scaling t
	)
  :hook
  'turn-on-visual-line-mode
  )

PDF

(May 2022: Turned this off because of a problem with the required tablist package, which wouldn’t go in; and anyways I wasn’t using it. November 2023: turned it back on again.)

PDF Tools allows commenting on PDFs, not just viewing. I took this snippet from Pragmatic Emacs and tweaked it.

(use-package pdf-tools
  :pin melpa ;; melpa to get it to install, maybe change to manual if need be?
  :config
  (pdf-tools-install)
  (setq-default pdf-view-display-size 'fit-page) ;; Use H, W or P to scale.
  (setq pdf-annot-activate-created-annotations t) ;; Automatically annotate highlights.
  (define-key pdf-view-mode-map (kbd "C-s") 'isearch-forward);; Use normal isearch because Swiper doesn't do PDFs.
  :hook
  (pdf-view-mode . (lambda() (linum-mode -1))) ;; linum-mode doesn't work well with PDF Tools, apparently.
  (pdf-view-mode . pdf-view-themed-minor-mode)
 )

XML

nXML mode is for XML files.

(add-to-list 'auto-mode-alist
	     (cons (concat "\\." (regexp-opt '("xml" "xsd" "sch" "rng" "xslt" "svg" "rss") t) "\\'")
		   'nxml-mode))

Adding this Hideshow minor mode hook means I can fold or hide chunks of XML with C-c SPC h (while sitting on the opening tag).

(add-to-list 'hs-special-modes-alist
	     '(nxml-mode
               "<!--\\|<[^/>]*[^/]>"
               "-->\\|</[^/>]*[^/]>"
               "<!--"
               sgml-skip-tag-forward
               nil))

(add-hook 'nxml-mode-hook 'hs-minor-mode)

Define the actual keystroke now that the rest has been set up. The default is longer and confusing.

(with-eval-after-load "nxml-mode"
  (define-key nxml-mode-map "\C-c h" 'hs-toggle-hiding))

YAML

YAML-mode seems to be a small package, and not maintained much any more, but it works.

(use-package yaml-mode
  :init
  (add-to-list 'auto-mode-alist '("\\.yml$" . yaml-mode))
  )

Git

Magit will install with-editor when it goes in.

(use-package magit
  ;; :config
  )

git-gutter.

(use-package git-gutter-fringe
  :diminish git-gutter-mode
  :config
  (global-git-gutter-mode t)
  (setq git-gutter-fr:side 'right-fringe)
  )

Org

A note I made on 16 April 2013: “Started using org-mode … I could really get into this.”

Some things I might try:

Manage and configure with use-package

The use-package syntax here is messy. All of the hooks should go under :hook and the appearance teaks under :custom-face, but I don’t know how to do that yet.

Deep in there I use set-face-attribute on org-verbatim and org-code faces to make them more noticeable. Instead of being shadowed out verbatim text has a slight wavy underline and code is in a box. Both are fixed pitch, of course. I’ll try this out for a while and see how I like it. See the face attributes documentation for more.

(use-package org
  ;; Use Org's current development branch, pulled down with Git.  See https://orgmode.org/org.html#Installation.
  :pin manual
  :load-path "/usr/local/src/org-mode/lisp"
  :init
  (setq
   org-agenda-skip-scheduled-if-done t;; Don't show DONE tasks in agenda view
   org-blank-before-new-entry '((heading . never) (plain-list-item . auto))
   org-confirm-babel-evaluate nil ;; Evaluate Babel blocks without asking for confirmation
   org-cycle-separator-lines 0 ;; Never show blank lines in condensed view
   org-display-inline-images t ;; Embed an image with [[file:foo.png]] and then C-c C-x C-v to view
   org-ditaa-jar-path "/usr/share/ditaa/ditaa.jar" ;; External dependency: ditaa
   org-ellipsis "" ;; ⤵ ↴  Change the ellipsis that indicates hidden content
   org-export-backends (quote (ascii html latex md odt)) ;; Exporting: I will see these export options after C-c C-e ;; beamer reveal
   ;; org-export-date-timestamp-format "%d %m %Y" ;; Date format on exports
   org-export-with-smart-quotes t ;; Turn plain quotes into posh (I can't include examples in here or it breaks paren matching!)
   org-fold-catch-invisible-edits 'smart
   org-fontify-quote-and-verse-blocks t ;; Add a special face to #+begin_quote and #+begin_verse block.
   org-fontify-whole-heading-line t
   org-footnote-auto-adjust nil ;; Don't resort or adjust them without my saying so.
   org-footnote-section nil ;; Define footnotes nearby when I use C-c C-x f
   org-hide-emphasis-markers t ;; Hide the /italics/ and *bold* markers
   org-hide-macro-markers t ;; Hide {{{macro}}} curly brackets; see also wtd/toggle-org-macro-markers
   org-highlight-latex-and-related nil ;; '(script entities) ;; Highlight inline LaTeX. Was '(latex) but in Feb 2024 that started breaking large files.  Could also be nil.
   org-id-link-to-org-use-id 'use-existing
   org-image-max-width nil ;; nil means "do not limit image width"
   org-image-actual-width nil ;; nil means "try to get the width from an #+ATTR.* keyword and fall back on the original width if none is found."
   org-list-allow-alphabetical t ;; Allow a b c lists
   org-pretty-entities t ;; org-entities displays \alpha etc. as Unicode characters.
   org-return-follows-link t ;; Hit return on a link to open it in a browser
   org-special-ctrl-a/e t ;; Make C-a and C-e understand how headings and tags work
   org-src-fontify-natively t ;; Fontify Babel blocks nicely
   org-src-preserve-indentation t ;; Preserve indentation when tangling source blocks (important for makefiles)
   org-src-window-setup 'current-window ;; How to rearrange things when I edit a source block.  Default is regorganize-frame.
   org-startup-indented t ;; Visually indent everything nicely, but leave the raw file left-aligned
   org-startup-with-inline-images t ;; Show images on startup
   org-support-shift-select t ;; Shift and arrow keys to select text works a bit differently in Org.
   org-tags-column 0 ;; Right-align tags to an indent from the right margin, could use 120 or (- 50 (window-width))
   org-use-speed-commands t ;; Allow speed commands
   )

  ;; Define my own link abbreviations
  (setq org-link-abbrev-alist
	'(
	  ("DOI" . "http://dx.doi.org/%s")                        ;; Thus [[DOI:10.1108/07378831111138189]]
	  ("WP"  . "https://en.wikipedia.org/wiki/%s")            ;; Thus [[WP:Toronto, Ontario]]
	  ("YUL" . "https://ocul-yor.primo.exlibrisgroup.com/permalink/01OCUL_YOR/1jocqcq/%s") ;; Thus [[YUL:alma991029590289705164]] for Omni
	  )
	)

  ;; Clocking
  (setq org-clock-out-remove-zero-time-clocks t) ;; Remove the clock line when the resulting time is zero.
  (setq org-clock-persist 'history)
  (org-clock-persistence-insinuate)

  ;; Agendas and tag inheritance
  (setq org-agenda-files '("~/york/shared/projects/projects.org" "~/york/shared/work-diaries/work-diary.org" "~/york/shared/work-diaries/work-diary-2023-2024.org"))
  (setq org-complete-tags-always-offer-all-agenda-tags t)

  ;; Automatically refresh inline images that are generated from Babel blocks
  (add-hook 'org-babel-after-execute-hook 'org-redisplay-inline-images)

  ;; Display images when a file is loaded (I can always toggle them off if I don't want them)
  (add-hook 'org-mode-hook (lambda () (org-toggle-inline-images)))

  ;; Use LaTeX spell-check
  (add-hook 'org-mode-hook (lambda () (setq ispell-parser 'tex)))

  ;; Hooks for prettify-symbols-mode
  ;; See also https://pank.eu/blog/pretty-babel-src-blocks.html for some cool stuff
  ;; And https://github.com/zzamboni/dot-emacs/blob/master/init.org#source-code-blocks
  ;; for some stuff I tried out but decided was a bit too much for me.
  (add-hook 'org-mode-hook
 	    (lambda ()
 	      (push '("<=" . ?≤) prettify-symbols-alist)
 	      (push '(">=" . ?≥) prettify-symbols-alist)
 	      (push '("|>" . ?▷) prettify-symbols-alist)
 	      (push '("#+BEGIN_SRC" . ?⎡) prettify-symbols-alist) ;;  ⎡ ➤ ➟ ➤ ✎
 	      (push '("#+END_SRC" . ?⎣) prettify-symbols-alist) ;; ⎣ ✐
 	      (push '("#+begin_src" . ?⎡) prettify-symbols-alist)
 	      (push '("#+end_src" . ?⎣) prettify-symbols-alist)
 	      (push '("#+BEGIN_QUOTE" . ?❝) prettify-symbols-alist)
 	      (push '("#+END_QUOTE" . ?❞) prettify-symbols-alist)
 	      (push '("#+begin_quote" . ?❝) prettify-symbols-alist)
 	      (push '("#+end_quote" . ?❞) prettify-symbols-alist)
 	      ;; (push '("[ ]" . ?☐) prettify-symbols-alist)
 	      ;; (push '("[X]" . ?☒) prettify-symbols-alist)
 	      ))

  :config
  (global-set-key "\C-cl" 'org-store-link)

  ;; In 25 Org started opening exported PDFs in docview, but I prefer seeing them externally.
  ;; (delete '("\\.pdf\\'" . default) org-file-apps)
  ;; (add-to-list 'org-file-apps '("\\.pdf\\'" . "evince %s"))

  ;; Active Babel languages (http://orgmode.org/org.html#Languages)
  (org-babel-do-load-languages 'org-babel-load-languages '(
							   (ditaa . t)
							   (dot . t)
							   (latex . t)
							   (lilypond . t)
							   (python . t)
							   (R . t)
							   (ruby . t)
							   (shell . t)
							   (sql . t)
							   (sqlite . t)
							   ))

  (set-face-attribute 'org-link nil :foreground "Steel Blue" :weight 'normal)
  (set-face-attribute 'org-footnote nil :height 0.9)

  ;; Necessary when using mixed-pitch, because I want these fixed.
  (set-face-attribute 'org-special-keyword nil :inherit 'fixed-pitch)
  (set-face-attribute 'org-drawer nil :inherit 'fixed-pitch)
  (set-face-attribute 'org-date nil :inherit 'fixed-pitch)

  ;; Code and verbatim text.
  (set-face-attribute 'org-verbatim nil :family "Ubuntu Mono" :height wtd-fixed-pitch-height :inherit 'fixed-pitch) ;; :underline '(:color "dim gray") :style wave))
  (set-face-attribute 'org-code nil :family "Ubuntu Mono" :height wtd-fixed-pitch-height :foreground 'unspecified :box '(:color "dim gray")) ;; was #586e75

  ;; Source code block appearance
  (set-face-attribute 'org-block-begin-line nil :underline nil)
  (set-face-attribute 'org-block-end-line nil :overline nil)

  (set-face-attribute 'org-ellipsis nil :underline nil)

  (set-face-attribute 'org-tag nil :height 0.8 :foreground "dim gray")

  ;; Make LOGBOOK and such fainter.  Default bold is too loud.
  ;; (face-spec-set 'org-drawer '((t (:foreground "dim gray" :weight normal :height 0.9)))) ;; Worked in dark look
  ;; (face-spec-set 'org-special-keyword '((t (:foreground "dim gray" :weight normal :height 0.9)))) ;; Worked in dark look
  (face-spec-set 'org-drawer '((t (:weight extra-light :height 0.9))))
  (face-spec-set 'org-special-keyword '((t (:weight extra-light :height 0.9))))
  (face-spec-set 'org-property-value '((t (:weight normal :height 0.9))))

  ;; Make completed items in a checkbox list less noticeable
  ;; https://fuco1.github.io/2017-05-25-Fontify-done-checkbox-items-in-org-mode.html
  (set-face-attribute 'org-headline-done nil :foreground "#586e75") ;; Aug 2023: Had to set this after some appearance changes.
  (font-lock-add-keywords
   'org-mode
   `(("^[ \t]*\\(?:[-+*]\\|[0-9]+[).]\\)[ \t]+\\(\\(?:\\[@\\(?:start:\\)?[0-9]+\\][ \t]*\\)?\\[\\(?:X\\|\\([0-9]+\\)/\\2\\)\\][^\n]*\n\\)" 1 'org-headline-done prepend))
   'append)

  ;; Headline sizes
  (face-spec-set 'org-level-1 '((t (:height 1.3))))
  (face-spec-set 'org-level-2 '((t (:height 1.1))))
  ;; (face-spec-set 'org-level-3 '((t (:height 1.0))))

  :hook
  (
   (org-mode . wrap-region-mode)
   (org-mode . turn-on-flyspell) ;; Use flyspell to check spelling as I go
   )
  )

Set up a global key binding for org-agenda.

(global-set-key (kbd "C-c a") #'org-agenda)

To reveal markup there is visibility-mode, which can be toggled on or off for the whole file, but org-appear “provides a way to toggle visibility of hidden elements such as emphasis markers, links, etc. by customizing specific variables.” (November 2022: This seems to be making Org freeze on large tables, so I’m turning it off for now.)

(use-package org-appear
  :config
  :hook (org-mode . org-appear-mode)
  )

That doesn’t work on the {{{ curly brackets }}} that define macros, though, so it’s nice to have a way of toggling them. (Note there should be no space before the name of the macro, or else hiding the braces doesn’t work.)

(defun wtd/toggle-org-macro-markers ()
  "Toggle visibility of {{{macro}}} markers"
  (interactive)
  (setq org-hide-macro-markers (not org-hide-macro-markers))
  (font-lock-mode)
  (font-lock-mode))

Some links about Org appearance and variable pitch:

Some helper functions

Use C-c d to close all the open drawers in a file.

(defun wtd/add-org-close-all-drawers-key ()
  (local-set-key (kbd "C-c d") (lambda () (interactive) (org-cycle-hide-drawers 'all))))
(add-hook 'org-mode-hook 'wtd/add-org-close-all-drawers-key)

Since I’m using C-x n to narrow and widen source blocks (see narrow-or-widen-dwim) I don’t need to use C-c ` to enter and leave them, so I can use C-x C-s to save and exit them, which is nice. Source.

(eval-after-load 'org-src
  '(define-key org-src-mode-map
     "\C-x\C-s" #'org-edit-src-exit))

Replace a link with just the descriptive text.

(defun wtd/org-link-delete-link ()
  "Remove the link from an Org link at point and keep only the description."
  (interactive)
  (let ((elem (org-element-context)))
    (if (eq (car elem) 'link)
        (let* ((content-begin (org-element-property :contents-begin elem))
               (content-end  (org-element-property :contents-end elem))
               (link-begin (org-element-property :begin elem))
               (link-end (org-element-property :end elem)))
          (if (and content-begin content-end)
              (let ((content (buffer-substring-no-properties content-begin content-end)))
                (delete-region link-begin link-end)
                (insert content)))))))

Use C-c t to toggle “:eval no|yes” status in source blocks.

(defun org-toggle-src-eval-no ()
  "Toggle ':eval no' on the src block begin line."
  (defun in-src-block-p ()
    "Returns t when the point is inside a source code block"
    (string= "src" (org-in-block-p '("src"))))
  (defun beginning-src ()
    "Find the beginning of the src block"
    (let ((case-fold-search t)) (search-backward "#+BEGIN_SRC")))
  (defun toggle-eval-no ()
    "Handles the toggling of ' :eval no'"
    (save-excursion
      (end-of-line)
      (let ((case-fold-search t)) (search-backward "#+BEGIN_SRC")
	   (if (search-forward " :eval no" (line-end-position) "f")
	       (replace-match "")
	     (insert " :eval no")
	     ))))
  (if (in-src-block-p) (toggle-eval-no)))
(defun add-org-toggle-src-key ()
  (local-set-key (kbd "C-c t") (lambda () (interactive) (org-toggle-src-eval-no))))
(add-hook 'org-mode-hook 'add-org-toggle-src-key)

Stop ispell from looking where it shouldn’t.

(defun wtd/org-ispell ()
  "Configure `ispell-skip-region-alist' for `org-mode'."
  (make-local-variable 'ispell-skip-region-alist)
  (add-to-list 'ispell-skip-region-alist '(org-property-drawer-re))
  (add-to-list 'ispell-skip-region-alist '("~" "~"))
  (add-to-list 'ispell-skip-region-alist '("=" "="))
  (add-to-list 'ispell-skip-region-alist '("^#\\+BEGIN_SRC" . "^#\\+END_SRC"))
  (add-to-list 'ispell-skip-region-alist '("^#\\+begin_src" . "^#\\+end_src"))
  (add-to-list 'ispell-skip-region-alist '("^#\\+BEGIN_EXAMPLE ". "#\\+END_EXAMPLE"))
  )
(add-hook 'org-mode-hook #'wtd/org-ispell)

So I can use Memoir as a document class in Org (but I don’t).

(with-eval-after-load 'ox-latex
  (add-to-list 'org-latex-classes
	       '("memoir-blocked"
		 "\\documentclass{memoir}
	       [NO-DEFAULT-PACKAGES]
	       [NO-PACKAGES]
	       [NO-EXTRA]"
               ("\\chapter{%s}" . "\\chapter*{%s}")
               ("\\section{%s}" . "\\section*{%s}")
               ("\\subsection{%s}" . "\\subsection*{%s}")
               ("\\subsubsection{%s}" . "\\subsubsection*{%s}")))
  (add-to-list 'org-latex-classes
               '("letter" "\\documentclass{letter}"))
  (add-to-list 'org-latex-classes
               '("memoir"
                 "\\documentclass{memoir}"
                 ("\\book{%s}" . "\\book*{%s}")
                 ("\\part{%s}" . "\\part*{%s}")
                 ("\\chapter{%s}" . "\\chapter*{%s}")
                 ("\\section{%s}" . "\\section*{%s}")
                 ("\\subsection{%s}" . "\\subsection*{%s}")
                 ("\\subsubsection{%s}" . "\\subsubsection*{%s}")))
  (add-to-list 'org-latex-classes
               '("memoir-chapter+"
                 "\\documentclass{memoir}"
                 ("\\chapter{%s}" . "\\chapter*{%s}")
                 ("\\section{%s}" . "\\section*{%s}")
                 ("\\subsection{%s}" . "\\subsection*{%s}")
                 ("\\subsubsection{%s}" . "\\subsubsection*{%s}")))
  )

Exporting formatted source code blocks with minted

This sets up a function that makes it easy to use minted when I want exported code blocks to look nice.

minted uses Pygments, so make sure that’s installed. To compile PDFs that use minted I need to use pdflatex -shell-escape (actually, I would use pdflatex -shell-escape -interaction=nonstopmode) because pdflatex needs to make an external call to Pygments to do the formatting, and it needs to be specially permitted to do so.

Originally, I had the following, which first adds minted to the default list of packages in LaTeX exports (in a way that keeps LaTeX preview fragments working; see the bottom of this explanation of LaTeX exports for more) and next says that source code listings should be formatted with minted (this has to be set this way, there is no way to change it in-buffer).

(add-to-list 'org-latex-packages-alist '("" "minted" nil))
(setq org-latex-src-block-backend 'minted)

But I don’t want minted to be one of the included packages in every LaTeX export, because then I always have to run pdflatex -shell-escape, even if there are no source blocks. Instead, I use this function (based on a tip from Xah Lee) to toggle those settings on or off. When I’m working on a file that I want to export using minted, I run M-x wtd/org-toggle-minted to turn things on. When I’m done, I run it again to turn things off. (There would be a way to tweak org-latex-pdf-process also, to handle the shell escape option, but I’m happy to do it by hand.)

(defun wtd/org-toggle-minted ()
  "Toggle whether or not Org should use minted for LaTeX."
  (interactive)
  (if (get 'wtd-org-minted-on-or-off 'state)
      (progn
	(setq org-latex-packages-alist (delete '("" "minted" nil) org-latex-packages-alist))
	(setq org-latex-src-block-backend 'verbatim)
	(put 'wtd-org-minted-on-or-off 'state nil)
	(message "Minted is off")
	)
    (progn
      (add-to-list 'org-latex-packages-alist '("" "minted" nil))
      (setq org-latex-src-block-backend 'minted)
      (put 'wtd-org-minted-on-or-off 'state t)
      (message "Minted is on; use pdflatex -shell-escape -interaction=nonstopmode")
      )
    )
  )

Minted has all sorts of options. They can be set here, in an association list, that will be passed to every source block. However, this takes precedence over everything else in the file, so it’s very strong. I prefer to define options with \setminted{} added with latex_header at the top of the document. I’ll set it up it that every source block exported has lines to the left (the options are: none, leftline, topline, bottomline, lines, single), but then I won’t export this, so it won’t take effect.

(setq org-latex-minted-options
      '(("frame" "leftline")
	))

Bullets

Prettify the headings and such with better bullets thanks to org-superstar-mode.

(use-package org-superstar
  :config
  (setq org-superstar-headline-bullets-list '("" "ǁ" "ǀ" "" "" "")) ;; ǂ ⋮
  :hook
  (org-mode . (lambda () (org-superstar-mode 1)))
  )

Possible: org-modern

Perhaps try org-modern one day.

(use-package org-modern
  :hook org-mode
  )

Org stuff I don’t use right now

Programming

General stuff

I sometimes use CamelCase in Ruby and R.

(add-hook 'prog-mode-hook 'subword-mode)

Make script files executable automatically

(add-hook 'after-save-hook 'executable-make-buffer-file-executable-if-script-p)

Comint

Settings for command interpreter modes, which I use mostly for R and Ruby.

(setq ansi-color-for-comint-mode 'filter
      comint-scroll-to-bottom-on-input t
      comint-scroll-to-bottom-on-output t
      comint-move-point-for-output t
 )
;;(setq comint-prompt-read-only t)

Colourise the comint buffer.

(setq ansi-color-for-comint-mode 'filter)

Syntax checking

Flycheck for syntax checking.

(use-package flycheck
  :diminish flycheck-mode
  :config
  (global-flycheck-mode)
  (setq flycheck-global-modes '(not org-mode)) ;; Could also set :modes to list where I want it.
  )

Linting

Flycheck and lintr.

(setq-default flycheck-lintr-linters
              (concat "with_defaults(line_length_linter(120), "
                      "absolute_paths_linter = NULL, "
		      ;; "camel_case_linter = NULL, "
		      ;; "snake_case_linter = NULL, "
		      "commented_code_linter = NULL)"))

R and ESS

ESS.

(use-package ess
  :commands R
  :config
  (setq
   ess-use-flymake nil ;; Don't run flymake on these buffers
   ess-help-own-frame 'nil ;; Make all help buffers go into one frame
   ess-plain-first-buffername 'nil ;; Call the first process R:1, not just R
   ess-startup-directory 'default-directory ;; "Always start the process in the directory of the current file" (not in project home directory)
   ess-ask-for-ess-directory nil ;; Start in the current directory
   ess-history-file nil ;; No history files
   ;; ess-local-process-name "R" ;; What does this do?
   ess-R-font-lock-keywords (quote ;; Be more colourful!
			     ((ess-R-fl-keyword:modifiers . t)
			      (ess-R-fl-keyword:fun-defs . t)
			      (ess-R-fl-keyword:keywords . t)
			      (ess-R-fl-keyword:assign-ops . t)
			      (ess-R-fl-keyword:constants . t)
			      (ess-fl-keyword:fun-calls . t)
			      (ess-fl-keyword:numbers . t)
			      (ess-fl-keyword:operators . t)
			      (ess-fl-keyword:delimiters . t)
			      (ess-fl-keyword:=)
			      (ess-R-fl-keyword:F&T)))
   )
  :init
  ;; (add-hook 'ess-mode-hook 'highlight-indent-guides-mode) ;; indent-guide ... very nice
  ;; (add-hook 'ess-mode-hook (lambda () (flycheck-mode t)))
  ;; (add-hook 'ess-R-post-run-hook 'ess-execute-screen-options) ;; MESSES THINGS UP.  Use the full width of the Emacs frame.  Messes up R in Org, I found.
  ;; Display %>% as |, and |> as ▷.
  (add-hook 'inferior-ess-mode-hook
	    (lambda ()
	      (push '("%>%" . ?|) prettify-symbols-alist)
 	      (push '("|>" . ?▷) prettify-symbols-alist)
	      ))
  (add-hook 'ess-mode-hook
	    (lambda ()
	      (push '("%>%" . ?|) prettify-symbols-alist)
 	      (push '("|>" . ?▷) prettify-symbols-alist)
	      ))
  (add-hook 'ess-mode-hook
	    ;; This stops comments from flying all the way over to the right, and makes %>% chains indent nicely (if the newline is after the pipe).
	    (lambda ()
	      (setq ess-indent-offset 4
		    ess-offset-continued 2
		    ess-offset-continued 'straight
		    ess-brace-offset -4
		    ess-expression-offset 4
		    ess-else-offset 0
		    ess-close-brace-offset 0
		    ess-brace-imaginary-offset 0
		    ess-continued-brace-offset 0
		    ess-indent-from-lhs 4
		    ess-offset-arguments-newline '(4)
		    )))
)

Ruby

This doesn’t work. Why not?

(add-hook 'ruby-mode-hook
	  (lambda ()
	    (push '("!=" . ?≠) prettify-symbols-alist)
	    ;; (push '("&&" . ?∧) prettify-symbols-alist)
 	    ;; (push '("||" . ?∨) prettify-symbols-alist)
	    ))

I use rbenv, so Emacs needs to know about it.

(use-package rbenv
  :hook (ruby-mode . global-rbenv-mode)
  :config
  (setq rbenv-show-active-ruby-in-modeline nil
	rbenv-modeline-function 'rbenv--modeline-plain
   )
  (rbenv-use-global)
  )

Open up irb with M-x inf-ruby or C-c C-s from a Ruby buffer.

(use-package inf-ruby
  :hook (ruby-mode . inf-ruby-minor-mode)
  :config
  (autoload 'inf-ruby "inf-ruby" "Run an inferior Ruby process" t)
  (add-to-list 'inf-ruby-implementations' ("pry". "pry"))
  (setq inf-ruby-default-implementation "pry")
  )

Avoid ridiculous Ruby indentation.

(setq ruby-deep-indent-paren nil)

Don’t put the UTF-8 encoding comment at the top.

(setq ruby-insert-encoding-magic-comment nil)

Parentheses.

(require 'smartparens-ruby)

“Finds all the URLs in the buffer, highlights them, and turns them into clickable buttons.” Use C-c RET to follow a link.

TODO Make Org’s C-c C-o more general and follow these links too.

(add-hook 'ruby-mode-hook #'goto-address-mode)

Rubocop is a huge help when writing Ruby.

(use-package rubocop
  :diminish rubocop-mode
  :hook (ruby-mode . rubocop-mode)
  )

I tried using Robe for documentation lookup and such, but never used it.

Jekyll

My personal web site is built on Jekyll. I use these three commands a lot:

  • C-c j n: create new draft post
  • C-c j p: publish the post
  • C-c j t: update the timestamp in the post

I wrote this timestamp function myself. It’s the most complex Lisp thing I’ve ever written!

(defun jekyll-timestamp ()
  "Update existing date: timestamp on a Jekyll page or post."
  (interactive)
  (save-excursion (
		   goto-char 1)
		  (re-search-forward "^date:")
		  (let ((beg (point)))
		    (end-of-line)
		    (delete-region beg (point)))
		  (insert (concat " " (format-time-string "%Y-%m-%d %H:%M:%S %z"))))
  )

I got all this from a web site that no longer exists. Such is the way of the internet.

(global-set-key (kbd "C-c j n") 'jekyll-draft-post)
(global-set-key (kbd "C-c j p") 'jekyll-publish-post)
(global-set-key (kbd "C-c j t") 'jekyll-timestamp)
(global-set-key (kbd "C-c j o") (lambda () (interactive) (find-file "~/web/")))

(defvar jekyll-directory "~/web/" "Path to Jekyll blog.")
(defvar jekyll-drafts-dir "_drafts/" "Relative path to drafts directory.")
(defvar jekyll-posts-dir "_posts/" "Relative path to posts directory.")
(defvar jekyll-post-ext ".md"  "File extension of Jekyll posts.")
(defvar jekyll-post-template "---\nlayout: post\ntitle: %s\ntags:\ndate: \n---\n"
  "Default template for Jekyll posts. %s will be replace by the post title.")

(defun jekyll-make-slug (s) "Turn string S into a slug."
       (replace-regexp-in-string " " "-"  (downcase (replace-regexp-in-string "[^A-Za-z0-9 ]" "" s))))

(defun jekyll-yaml-escape (s) "Escape string S for YAML."
       (if (or (string-match ":" s) (string-match "\"" s)) (concat "\"" (replace-regexp-in-string "\"" "\\\\\"" s) "\"") s))

(defun jekyll-draft-post (title) "Create a new Jekyll blog post with title TITLE."
       (interactive "sPost Title: ")
       (let ((draft-file (concat jekyll-directory jekyll-drafts-dir
				 (jekyll-make-slug title)
				 jekyll-post-ext)))
	 (if (file-exists-p draft-file)
             (find-file draft-file)
	   (find-file draft-file)
	   (insert (format jekyll-post-template (jekyll-yaml-escape title))))))

(defun jekyll-publish-post () "Move a draft post to the posts directory, and rename it to include the date."
       (interactive)
       (cond
	((not (equal
               (file-name-directory (buffer-file-name (current-buffer)))
               (expand-file-name (concat jekyll-directory jekyll-drafts-dir))))
	 (message "This is not a draft post.")
	 (insert (file-name-directory (buffer-file-name (current-buffer))) "\n"
		 (concat jekyll-directory jekyll-drafts-dir)))
	((buffer-modified-p)
	 (message "Can't publish post; buffer has modifications."))
	(t
	 (let ((filename
		(concat jekyll-directory jekyll-posts-dir
			(format-time-string "%Y-%m-%d-")
			(file-name-nondirectory
			 (buffer-file-name (current-buffer)))))
               (old-point (point)))
	   (rename-file (buffer-file-name (current-buffer))
			filename)
	   (kill-buffer nil)
	   (find-file filename)
	   (set-window-point (selected-window) old-point)))))

LaTeX

Except: auto-completion in Auctex is turned on elsewhere.

Remember: when editing tables, use M-x align-current.

Good reading:

(add-hook 'LaTeX-mode-hook #'outline-minor-mode)

Auctex is amazingly powerful.

(use-package auctex
  :defer t
  :diminish auctex
  )

Always use visual-line-mode.

(add-hook 'LaTeX-mode-hook 'turn-on-visual-line-mode)

Turn on spell-checking.

(add-hook 'LaTeX-mode-hook 'flyspell-mode)

Use pdflatex to make PDFs.

(setq latex-run-command "pdflatex")
;; Use pdflatex to make PDFs
;; For some reason this value isn't respected and I had to set
;; it through Custom. Don't know why.
;; TEMP
(setq TeX-PDF-mode t)
; (customize-set-variable 'org-latex-pdf-process '("latexmk -f -pdf -%latex -interaction=nonstopmode -output-directory=%o %f"))

If a buffer is showing a PDF and the PDF is regenerated, I don’t want to be asked if the buffer should revert. (If I ever want to treat another file type this way, I’ll need to append to the list, I guess.)

(setq revert-without-query '(".pdf"))

Bibliographies.

(setq biblatex-dialect "biblatex")

Automatically activate TeX-fold-mode. C-c C-o C-b is necessary to hide everything (or see LaTeX | Show/Hide)

(add-hook 'TeX-mode-hook (lambda () (TeX-fold-mode 1)))

Use wrap-region.

(add-hook 'latex-mode-hook 'wrap-region-mode)

Indent lists by 2 (default is -2).

(setq LaTeX-item-indent 0)

Let me do some narrowing in LaTeX documents … but narrow-or-widen-dwim (C-x w) doesn’t focus on a section or subsection?!

(put 'LaTeX-narrow-to-environment 'disabled nil)
(put 'TeX-narrow-to-group 'disabled nil)

RefTeX. (December 2023: I don’t think I ever use this, so I’m not tangling it.)

(add-hook 'LaTeX-mode-hook 'turn-on-reftex)
(setq reftex-plug-into-AUCTeX t)
(eval-after-load "reftex" '(diminish 'reftex-mode))
(setq reftex-bibliography-commands '("bibliography" "nobibliography" "addbibresource"))

From Stack Overflow, as usual.

(eval-after-load 'reftex-vars
  '(progn
     ;; (also some other reftex-related customizations)
     (setq reftex-cite-format
           '((?\C-m . "\\cite[]{%l}")
             (?f . "\\footcite[][]{%l}")
             (?t . "\\textcite[]{%l}")
             (?p . "\\parencite[]{%l}")
             (?o . "\\citepr[]{%l}")
             (?n . "\\nocite{%l}")))))

Zotero

To connect with Zotero, use zotxt-emacs (which requires the zotxt Zotero plugin).

(use-package zotxt
  :defer t
  :diminish zotxt
  )

Citations

Testing out some citation stuff.

(use-package citeproc
  :defer t
  :diminish citeproc
  )

Polymode (not in use)

Polymode, for Markdown + R + Yaml etc.

I don’t use this right now—it would mess up headers in YAML files—but maybe I’ll come back to it. For now, it’s not tangled.

(use-package polymode)

;; Polymode is nice everywhere, except I do not want it in Org.

(use-package poly-markdown
  :config
  (add-to-list 'auto-mode-alist '("\\.md$" . poly-markdown-mode))
  (setq markdown-hide-urls t)
  (setq markdown-hide-markup t)
  (setq markdown-url-compose-char "")
  (setq markdown-header-scaling t)
  (add-hook 'markdown-mode-hook 'turn-on-visual-line-mode)
  )

(use-package poly-R
  :config
  (add-to-list 'auto-mode-alist '("\\.Rmd$" . poly-markdown+r-mode))
  )

(use-package poly-noweb)

Esonify (not in use)

Esonify is “an Emacs extension that sonifies your code.” M-x esonify-mode to toggle on/off.

(use-package esonify)

Noted for later

(defun wtd/add-cite (beg end)
  "Wrap selected text in HTML cite tags."
  (interactive "r")
  (save-excursion
    (narrow-to-region beg end)
    (set-mark nil)
    (goto-char (point-min))
    (insert "<cite>")
    (goto-char (point-max))
    (insert "</cite>")
    (widen)))