💾 Archived View for idiomdrottning.org › on-top-of-emacs-god-mode captured on 2021-12-04 at 18:04:22. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2021-12-03)
➡️ Next capture (2023-01-29)
-=-=-=-=-=-=-
I’ve been using god-mode for a few years. It’s an Emacs mode that’s sort of like if Control was held down all the time. The key sequence C-c C-s C-p becomes just csp and C-x n n becomes x nn. I’ve built some cruft on top of it and today I finally ironed out some long-standing bugs so I decided to post this stuff!
Let’s start with the unusualest stuff first:
(define-key god-local-mode-map (kbd "o") 'insert-one-character) (define-key god-local-mode-map (kbd "O") 'spacer) (define-key god-local-mode-map (kbd "h") 'my-dumb-del) (define-key god-local-mode-map (kbd "i") 'incarnate)
C-q already existed, so if you want to insert one character you could already use q. The difference between q and o is how they deal with prefix arguments, where q will insert more of the same while o will listen that amount of times. If you want to insert three hyphens, 3q-. If you want to insert the word “and”, 3oand. Or 5o and if you want spaces.
This was one of the three changes I made today: I had a bug where it would only work on ASCII clean characters. (That was a bug I introduced, can’t blame anyone else for that.) I lived with that for years! Having to remember to use incarnate (as described later) when I needed to insert words with non-ASCII stuff, which is often.
But now it works great:
(defun insert-one-character (times) (interactive "p") (dotimes (x times) (quoted-insert 1)))
Often enough I just wanna insert a space. This one does work like q, in that the prefix sets the number of spaces you get.
(defun spacer (times) (interactive "p") (dotimes (x times) (insert " ")))
Then, for my-dumb-del, it’s just a way to make h work as a backspace in god-mode. I use F1 as a help key.
(defun my-dumb-del () (interactive) (setq unread-command-events (listify-key-sequence "\C-\?")))
Now, let’s talk about incarnate.
What it used to do was switch out of god-mode, except that RET returned me to god-mode. Great when I just wanna insert just a handful of words, so I don’t need to toggle out of god-mode completely, but it’s more than I wanna bother to count so the prefix and o solution isn’t the best. I just hit i, type some words, then RET. (And then one more RET if I actually want the newline, too.)
However, now that I’m on Atreus, it’s easier to just toggle back into god-mode since Escape is so easily accessible (I can just tap Alt) while RET is cumbersome (I have it bound to C-m).
On HHKB, even if Esc is unusually accessible there (it’s placed to the left of 1, where grave tilde normally is), I still got some use out of incarnate since RET was easier still. But the primary use for incarnate is when I’m on the tablet using an on-screen keyboard. Switching in and out of god-mode is cumbersome there since I want to use the SSH Esc for other, well, for normal Emacs stuff.
So, now what it does is that it uses (display-graphic-p) to try to guess if I’m on SSH or if I’m on the desktop. If I’m on SSH, it works like it always did: incarnates so I can type a few words until I hit RET. If I’m on the desktop using the Atreus, but still press i out of long-ingrained habit, it just toggles me out of god-mode since it’s easy enough to return there when I want to.
My god-mode cursor is a red box, my normal cursor is a black box, and my incarnate cursor is a black bar.
(define-minor-mode incarnate-mode "As normal but toggle to God mode on RET" :lighter " God-Inc" :keymap '(("\r" . unincarnate))) (defun unincarnate () (interactive) (incarnate-mode -1) (god-mode)) (defun incarnate () (interactive) (god-mode) (unless (display-graphic-p) (set-cursor-color "black") (setq cursor-type 'bar) (incarnate-mode)))
OK, now let’s talk about the third and final change I did today.
One long-standing gripe with god-mode is how badly it works with input methods, which… input methods is like the number one reason I even use Emacs in the first place!
For a while, I had it turn off input methods when entering god-mode and turning on the default input method when leaving it. This sucked because I sometimes type in English (where I don’t want any input method) and sometimes type in all kinds of weird languages, so I want to use all kinds of weird input methods.
So what I then did was that when entering god-mode, I turn off any input methods. Since I mostly use god-mode on the tablet anyway, where the on-screen keyboard has its own easy way to enter those non-ASCII chars, this was mostly fine. But this meant that on the desktop I was mostly using god-mode for code, for English, or for editing very late drafts of pretty-much finished texts in other languages.
Only today I finally got my proverbial in gear and implemented the obvious solution: Stash away any input methods when entering god-mode and restore them when leaving it. Duh. I can’t believe I didn’t think of that.
Also sets the cursor.
(defvar old-inp current-input-method) (defun my-update-cursor () (if god-local-mode (progn (incarnate-mode -1) (set-cursor-color "red") (setq cursor-type 'box) (setq old-inp current-input-method) (deactivate-input-method)) (progn (incarnate-mode -1) (set-cursor-color "black") (setq cursor-type 'box) (when old-inp (activate-input-method old-inp))))) (add-hook 'god-mode-enabled-hook 'my-update-cursor) (add-hook 'god-mode-disabled-hook 'my-update-cursor)
OK, that was it for the new and interesting things. For completeness sake, I’ll write up the rest of what I have even though it’s what probably every god-mode user has.
I’m OK with using the recommended Escape for this on the desktop. I used to do Esc for many uses of meta, like I’d be more likely to hit Esc x than M-x, so it took some getting used to, but by know I’ve used it enough that Esc gx is easy enough to type, or just gx when I already am in god-mode. (I forgot to say earlier that god-mode uses g as a meta prefix.)
On SSH that doesn’t work great so I’ve added some other characters. What I most often use there is actually ğ. It’s a letter I rarely use but that’s easy enough to get to on the on-screen keyboard (it’s a few layers deep, though). That’s why I rely so heavily on incarnate mode when I’m using that interface—because it’s such a hassle to actually get into actual god-mode otherwise!
(global-set-key (kbd "<escape>") 'god-mode) (global-set-key (kbd "M-~") 'god-mode) (global-set-key (kbd "M-`") 'god-mode) (global-set-key (kbd "Äź") 'god-mode) (global-set-key (kbd "Č©") 'god-mode)
Since I use C-z so heavily (I have it set to toggle a shell buffer), I use comma for repeat instead:
(define-key god-local-mode-map (kbd ",") 'repeat)
The recommendadion from the god-mode docs is to have both C-x
2 and C-x C-2' do the same thing ongod-modesince the latter is
easier. (The former isx 2and the latter isx2` without the space.)
For me on Atreus I also added ',. as synonyms for 123 in this context so I don’t have to layer switch to my number layer. (Implementing that was a huge tipping point in getting me to closer to liking this keyboard.)
Actually, here we might have something that’s interesting to other peeps. Window splitting! The default on Emacs (same as on Blender) is that you get two copies of the same buffer and if you want them to be different, you change one of them out.
What I do instead now is that I get two different buffers and if I want them to be the same, I have to change it back. This took some getting used to and I often enough do want a second copy of the same buffer so I’m not sure this is the right call, but generally it’s been great. It’s great because I don’t even notice it when it works; it’s just one less step I don’t have to take.
(defun split-window-func-with-other-buffer (split-function) (lexical-let ((s-f split-function)) (lambda () (interactive) (funcall s-f) (set-window-buffer (next-window) (other-buffer))))) (global-set-key (kbd "C-x C-1") 'delete-other-windows) (global-set-key (kbd "C-x C-'") 'delete-other-windows) (global-set-key (kbd "C-x '") 'delete-other-windows) (global-set-key (kbd "C-x C-o") 'other-window) (global-set-key (kbd "C-x C-2") (split-window-func-with-other-buffer 'split-window-vertically)) (global-set-key (kbd "C-x C-,") (split-window-func-with-other-buffer 'split-window-vertically)) (global-set-key (kbd "C-x ,") (split-window-func-with-other-buffer 'split-window-vertically)) (global-set-key (kbd "C-x C-3") (split-window-func-with-other-buffer 'split-window-horizontally)) (global-set-key (kbd "C-x C-.") (split-window-func-with-other-buffer 'split-window-horizontally)) (global-set-key (kbd "C-x .") (split-window-func-with-other-buffer 'split-window-horizontally)) (global-set-key (kbd "C-x 2") (split-window-func-with-other-buffer 'split-window-vertically)) (global-set-key (kbd "C-x 3") (split-window-func-with-other-buffer 'split-window-horizontally)) (global-set-key (kbd "C-x C-0") 'delete-window)
Finally, here are the modes I currently have exempt from god-mode:
(add-to-list 'god-exempt-major-modes 'Buffer-Selection-Menu-mode) (add-to-list 'god-exempt-major-modes 'notmuch-search-mode) (add-to-list 'god-exempt-major-modes 'notmuch-show-mode) (add-to-list 'god-exempt-major-modes 'Info-mode)
Entering and exiting out of isearch is a hassle so why not let a timer do that?
(defun leap-skele (proc) (run-with-idle-timer .5 nil (lambda () (when (= 0 (length isearch-string)) (message "")) (isearch-done))) (funcall proc)) (defun leap-back () (interactive) (leap-skele 'isearch-backward)) (defun leap-forward () (interactive) (leap-skele 'isearch-forward)) (global-set-key (kbd "C-r") 'leap-back) (global-set-key (kbd "C-s") 'leap-forward)
This inspires me to do the same for inserting text from god-mode:
(defun type-something-quickly () (interactive) (run-with-idle-timer (if (display-graphic-p) .5 3) nil 'god-mode) (god-mode))
Not sure if it belongs on o or on i yet, and what time is good. Half a second felt perfect for searching; not so sure about typing. Going to have to experiment.