~keith's Web site

Emacs stuff

I've recently switched to Emacs as my text editor and IDE. Specifically, with the Doom Emacs framework, because it was easy to get set up with, but isn't too different from vanilla Emacs. Anyways, here's some of my Emacs Lisp fuckery. I hope you'll find it useful.

Text-mode indentation fix

Emacs has some really weird opinions about indentation in text-mode. In literally every other text editor in existence, the Tab key, you know, inserts a tab. Not Emacs, though! Instead, it inserts any number of spaces or tabs based on... how RMS is feeling at that exact moment? I don't know.

Regardless, I find that behaviour annoying, so here's the little hack I wrote to fix it:

;; HACK make text-mode tab behaviour normal (insert actual tabs, not random fucking spaces)
(defun indent-by-leading-whitespace (&optional first-only unindented-ok)
  (interactive "P")
  (let (leading-whitespace)
    (save-excursion
      (beginning-of-line)
      (forward-line -1)
      (setq leading-whitespace (thing-at-point 'whitespace))
      (unless (not leading-whitespace) (setq leading-whitespace
        (replace-regexp-in-string "\n" "" leading-whitespace)))
      ;(message (format "whitespace: %S, first-only: %S, unindented-ok: %S, flag: %S"
      ;  leading-whitespace first-only unindented-ok indent-fix-hack-flag))
    )
    (if (not (or (> (current-column) 0) (not leading-whitespace) (string= "" leading-whitespace)))
      (unless (and (> (current-column) 0) first-only) (insert leading-whitespace))
      (if indent-fix-hack-flag (tab-to-tab-stop))
    )
  )
)

;; Fix the issue where Tab doesn't indent the 1st time
(defvar-local indent-fix-hack-flag nil "Flag indicates if a tab-indent is occuring")
(defun indent-fix-hack-wrapper (orig-fun &rest args)
  (setq indent-fix-hack-flag t)
  (let ((res (apply orig-fun args)))
    (setq indent-fix-hack-flag nil)
    res))
(advice-add 'indent-for-tab-command :around #'indent-fix-hack-wrapper)

(add-hook! text-mode
  (setq indent-line-function #'indent-by-leading-whitespace))

Text-mode's smart indentation is actually kind of nice visually, though. I might try revisiting it later - maybe I could make it change the width of tabs, rather than inserting different numbers of spaces?

Mixed-pitch font height scaling

I use mixed-pitch-mode for Markdown and org-mode documents, but the proportional font I use needs to be set to a larger height value than my monospace font to appear the same size. Mixed-pitch-mode does have a built-in option for that (mixed-pitch-set-height), but it conflicts with header scaling (or any other underlying size adjustments), so I use this little snippet instead:

;; HACK Apply relative height scale to fixed-pitch faces
(setq mixed-pitch-set-height nil)
(defvar-local mixed-pitch-hack-remaps nil)
(add-hook! mixed-pitch-mode
  (if mixed-pitch-mode
      (let ((var-height (face-attribute mixed-pitch-face :height))
            (fix-height (face-attribute 'fixed-pitch :height))
            to-fix-scale)
        (setq to-fix-scale (/ (float fix-height) (float var-height)))
        (setq mixed-pitch-hack-remaps nil)
        (add-to-list 'mixed-pitch-hack-remaps (face-remap-add-relative 'default :height var-height))
        (dolist (face mixed-pitch-fixed-pitch-faces)
          (add-to-list 'mixed-pitch-hack-remaps (face-remap-add-relative face :height to-fix-scale))))
    (progn
      (dolist (remap mixed-pitch-hack-remaps) (face-remap-remove-relative remap))
      (setq mixed-pitch-hack-remaps nil))))