Keybaord
noctuid/general.el: More convenient key definitions in emacs, is a critical package for my usage of Emacs.
One of the features of Emacs is the keybindings that are usable in the program. Keybindings is another way of saying keyboard commands. The base program comes with its own keybindings. Every time you add a package to the program, it comes with it’s own keybindings or it asks you to set keybindings for its important functions. You write a function in elisp and it is more useful if you assign a keybinding to it. Soon you are swimming in keybindings and you can’t remember them. There are several ways to solve this problem. Extensive transient menus is one of them. kickingvegas/casual-suite: Casual Suite - An umbrella package to support a single install point for all Casual user interfaces. is an attempt to do that. I am going to write about that in a future article. Another solution is general.el.
I am going to tackle my solution to the problem by using general.el.
Keybindings and the Problems With Them
I love keybindings. It is easier to use a program if you know the keybindings which let you perform functions. You don’t have to mouse over to a menu or search for a command when you know the keybindings. Makes your hands not move from the keyboard. Jeff Raskin said in defense of keeping his hands on the keyboard, “You shouldn’t have to live, a hand to mouse existence.” The problem is that there are too many of them and since they are set by someone else, it is difficult to remember them.
I wanted a system which lets me set my own keybindings for my often used commands. The reasoning is that if I am setting my own keybindings, then it is more likely that I will remember them. General.el lets me do that.
Setting Up the Usual Markdown Commands
#+begin_src emacs-lisp
(general-define-key
:keymaps 'markdown-mode-map
:prefix "s-o"
"b" '(markdown-insert-bold :which-key "md bold")
"q" '(markdown-insert-blockquote :which-key "md blockquote")
"c" '(markdown-insert-code :which-key "md code")
"i" '(markdown-insert-italic :which-key "md italic")
"j" '(markdown-move-list-item-down :which-key "md list dn")
"k" '(markdown-move-list-item-up :which-key "md list up")
"l" '(markdown-insert-link :which-key "md link")
"f" '(markdown-insert-footnote :which-key "md footnote")
"p" '(md-capture :which-key "md capture")
"t" '(markdown-insert-table :which-key "md table")
"u" '(markdown-move-subtree-up :which-key "md item up")
"d" '(markdown-move-subtree-down :which-key "md item down"))
#+end_src
Wanted to standardize on a leader key. In my case, it made sense to use s-o. In the Emacs world on macOS s is the ⌘key. I type the leader key and then another key to achieve the function assigned to it. Thus if I want to bold something, I can type s-o b and Emacs puts in four asterisks with the cursor between the four asterisks. Or, I can select something which I want to be bold, press the keyboard command s-o b and it gets the syntax of two asterisks surrounding the selected text. I have a whole list of commands tied to Markdown mode assigned to the s-o leader key. Since they follow a pattern and they are chosen by me. It is easier to remember them.
Setting Up the Usual Org-mode Commands
Org-mode is where I spend all my time, and it does a whole lot. The Org-mode commands are broken up into a few sections. These are the usual syntax commands. You have to specify them first, like,
#+begin_src emacs-lisp
;; general.el
(defun my/org-bold () (interactive) (org-emphasize ?*))
(defun my/org-code () (interactive) (org-emphasize ?~))
(defun my/org-italic () (interactive) (org-emphasize ?/))
(defun my/org-clear () (interactive) (org-emphasize ? ))
(defun my/org-strikethrough () (interactive) (org-emphasize ?+))
(defun my/org-underline () (interactive) (org-emphasize ?_))
(defun my/org-verbatim () (interactive) (org-emphasize ?=))
#+end_src
and,
#+begin_src emacs-lisp
(general-define-key
:keymaps 'org-mode-map
:prefix "s-o"
"a" '(org-agenda :which-key "org agenda")
"b" '(my/org-bold :which-key "org bold")
"C" '(org-capture :which-key "org capture")
"c" '(my/org-code :which-key "org code")
"i" '(my/org-italic :which-key "org italic")
"e" '(org-emphasize :which-key "org emph")
"l" '(my/org-insert-link-dwim :which-key "org ins link")
"s" '(org-schedule :which-key "org sch")
"t" '(org-todo :which-key "org todo"))
#+end_src
Because I use Org-mode extensively this list includes a few commands that are not syntax related (agenda, capture, schedule and todo). They are commands I use all the time and the s-o leader key is convenient. This is a list of syntax commands and four function commands which get extensive use in Org-mode.
Navigation Commands
These are commands which let me move between headers in Org-mode:
#+begin_src emacs-lisp
(general-define-key
:keymaps 'org-mode-map
"M-n" 'org-next-visible-heading
"M-p" 'org-previous-visible-heading)
#+end_src
There are additional navigation commands which get used for every mode:
#+begin_src emacs-lisp
(general-define-key
;; Move to beginning/end of buffer
"s-<up>" 'beginning-of-buffer
"s-<down>" 'end-of-buffer
;; Move to beginning/end of line
"s-<left>" 'beginning-of-line
"s-<right>" 'end-of-line)
#+end_src
Commands Which Deal With Emacs
Now we come to the bulk of the commands that I have set in general.el. These have to be assigned to a leader key. I chose M-o since the right option key and the o are readily accessible. There are many keys assigned to this leader-key. Firstly, a set of keys which are accessed regularly.
#+begin_src emacs-lisp
(general-create-definer my-leader-def
:prefix "M-o"
:non-normal-prefix "M-o")
(my-leader-def
;; Top level functions
"." '(find-file :which-key "find file")
";" '(consult-recent-file :which-key "recent files")
"/" '(bufferfile-rename :which-key "rename file")
"TAB" '(switch-to-prev-buffer :which-key "previous buffer")
"r" '(repeat :which-key "repeat")
"g" '(avy-goto-char-timer :which-key "avy char timer")
"p" '(org-capture :which-key "org-capture")
"x" '(execute-extended-command :which-key "execute command")
"+" '(tab-bar-new-tab :which-key "tab new")
"-" '(tab-close :which-key "tab close")
"1" '(tab-previous :which-key "tab previous")
"2" '(tab-next :which-key "tab next")
"9" '(my/scroll-up-half-page :which-key "scroll up")
"0" '(my/scroll-down-half-page :which-key "scroll down")
"<up>" '(push-mark-command :which-key "push mark")
"<left>" '(backward-forward-previous-location :which-key "previous location")
"<right>" '(backward-forward-next-location :which-key "next location")
#+end_src
This group went through changes initially. I was trying to see how often they got used. I keep a close watch on the frequency of use to get an idea of its utility. This group changes often.
#+begin_src emacs-lisp
;; Applications
"a" '(nil :which-key "applications")
"ao" '(org-agenda :which-key "org-agenda")
"ac" '(org-capture :which-key "org-capture")
"ab" '(nil :which-key "browse url")
"abc" '(browse-url-chrome :which-key "chrome")
"av" '(nil :which-key "avy")
"avc" '(avy-goto-char-2 :which-key "avy goto char")
"avp" '(avy-goto-parens :which-key "avy goto parens")
"ad" '(dired :which-key "dired")
#+end_src
A set of keys assigned to “applications.” Thus M-o a and then a key to call the function.
#+begin_src emacs-lisp
;; Buffers
"b" '(nil :which-key "buffer")
"bb" '(switch-to-buffer :which-key "switch-to-buffer")
"bc" '(consult-buffer :which-key "consult-buffer")
"bd" '(kill-buffer :which-key "kill-buffer")
"be" '(my/kill-other-buffers :which-key "kill other buffers")
"bf" '(my/copy-buffer-file-path-to-clipboard :which-key "copy file path")
"bi" '(ibuffer :which-key "ibuffer")
"bk" '(my/save-and-close-this-buffer :which-key "save-kill-buffer")
"bm" '(nil :which-key "bookmark")
"bmd" '(bookmark-delete :which-key "bookmark delete")
"bmj" '(bookmark-jump :which-key "bookmark jump")
"bms" '(bookmark-set :which-key "bookmark set")
"bn" '(next-buffer :which-key "next-buffer")
"bo" '(org-switchb :which-key "org-switchb")
"bp" '(previous-buffer :which-key "previous-buffer")
"bR" '(revert-buffer :which-key "revert-buffer")
"br" '(bufferfile-rename :which-key "rename buffer")
"bs" '(scratch :which-key "scratch")
#+end_src
A set of keys assigned to M-o b and then a key. Buffer related. Except the ones for bookmarks. It was mnemonically consistent to have them here.
#+begin_src emacs-lisp
;;Consult
"c" '(nil :which-key "consult")
"cd" '(consult-dir :which-key "con dir")
"cg" '(consult-grep :which-key "con grep")
"ch" 'consult-org-heading :which-key "con org heading"
"cl" '(consult-line :which-key "con line")
"cn" '(consult-notes :which-key "con notes")
"co" '(consult-outline :which-key "con outline")
"cy" '(consult-yasnippet :which-key "con yasnippet")
"cb" '(nil :which-key "bookmark/buffer")
"cbo" '(consult-bookmark :which-key "con bookmark")
"cbu" '(consult-buffer :which-key "con buffer")
;;Consult-register
"cr" '(nil :which-key "consult-register")
"crr" '(consult-register :which-key "con register")
"crs" '(consult-register-store :which-key "con reg store")
#+end_src
These are the keys set for minad/consult: :mag: consult.el - Search and navigate via completing-read. M-o c and then the relevant key. This group gets used a lot every day. I love consult. Thank you Howard Melman for pointing me to it.
#+begin_src emacs-lisp
;; Denote
"d" '(nil :which-key "denote")
"dd" '(denote-sort-dired :which-key "denote-sort-dired")
"dl" '(denote-link :which-key "denote-link")
"dL" '(denote-add-links :which-key "denote-add-links")
"dn" '(nil :which-key "denote")
"dno" '(denote :which-key "denote")
"dnc" '(my/denote-create-note :which-key "denote choose")
"db" '(denote-backlinks :which-key "denote-backlinks")
"dr" '(denote-rename-file :which-key "denote-rename-file")
"dR" '(denote-rename-file-using-front-matter :which-key "denote-rename-file-using-front-matter")
"ds" '(denote-subdirectory :which-key "denote-subdir")
"dt" '(denote-type :which-key "denote-type")
#+end_src
Assigned to M-o d this is my Denote (denote.el) | Protesilaos Stavrou group. I rely on this for all my note-taking. Thank you Prot. You are special.
#+begin_src emacs-lisp
;;Elfeed
"e" '(nil :which-key "elfeed")
"ee" '(elfeed :which-key "elfeed")
"eu" '(elfeed-update :which-key "elfeed-update")
#+end_src
This is the skeeto/elfeed: An Emacs web feeds client group. I love reading my feeds in Emacs.
#+begin_src emacs-lisp
;; Files
"f" '(nil :which-key "files")
"fb" '(my-list-blog :which-key "blogwriting")
"fn" '(my-list-notes :which-key "notes")
"fo" '(my/open-buffer-file-mac :which-key "open buffer in macOS")
"fm" '(my-list-markdown :which-key "markdown files")
"ff" '(find-file :which-key "find file")
"fs" '(save-buffer :which-key "save buffer")
"fS" '(write-file :which-key "write file")
"fd" '(dired :which-key "dired")
"fo" '(reveal-in-osx-finder :which-key "reveal in finder")
"fr" '(consult-recent-file :which-key "recent files")
"fR" '(bufferfile-rename :which-key "rename buffer")
#+end_src
This section deals with file operations. Goes to directories, finds files and other assorted tasks.
#+begin_src emacs-lisp
;; Help/emacs
"h" '(nil :which-key "help/emacs")
"hv" '(describe-variable :which-key "des. variable")
"hb" '(describe-bindings :which-key "des. bindings")
"hM" '(describe-mode :which-key "des. mode")
"hf" '(describe-function :which-key "des. func")
"hF" '(describe-face :which-key "des. face")
"hk" '(describe-key :which-key "des. key")
#+end_src
This is the help section. Gets used multiple times a day.
#+begin_src emacs-lisp
;;set-mode
"hm" '(nil :which-key "which-mode")
"hme" '(emacs-lisp-mode :which-key "elisp mode")
"hmo" '(org-mode :which-key "org mode")
"hmm" '(markdown-mode :which-key "markdown mode")
"hmt" '(text-mode :which-key "text mode")
#+end_src
Usually automatic, I use this group rarely. Not sure that I need it but it is here for the time being.
#+begin_src emacs-lisp
;; Jumps
"j" '(nil :which-key "jumps")
"jr" '(jump-to-register :which-key "registers")
"jb" '(bookmark-jump :which-key "bookmark jump")
#+end_src
Jumps to the registers and the bookmarks. I do these several times a day and they are repeated commands. Usually achieve this through consult. These are the in built Emacs commands. Might get rid of these.
#+begin_src emacs-lisp
;; kirigami
"k" '(nil :which-key "kirigami")
"kc" '(kirigami-close-folds :which-key "close all")
"ko" '(kirigami-open-folds :which-key "open all")
"kt" '(kirigami-toggle-fold :which-key "toggle folds")
#+end_src
These are the commands for jamescherti/kirigami.el: kirigami.el, a unified method to fold and unfold text in Emacs: outline, outline-indent, org-mode, markdown-mode, gfm-mode, vdiff, hideshow, fold-this, ts-fold, treesit-fold, vimish-fold…. Useful for long documents, and I have a few of those. Love this developer and this package.
#+begin_src emacs-lisp
;; Lisp
"l" '(nil :which-key "lisp")
"lb" '(eval-buffer :which-key "eval buffer")
"ld" '(eval-defun :which-key "eval defun")
"le" '(eval-expression :which-key "eval expression")
"lr" '(eval-region :which-key "eval region")
"ls" '(eval-sexp :which-key "eval sexp")
#+end_src
Learning elisp, this is important.
#+begin_src emacs-lisp
;;package
"hp" '(nil :which-key "package")
"hpr" '(package-refresh-contents)
"hpi" '(package-install)
"hpd" '(package-delete)
"hps" '(straight-pull-all)
#+end_src
Package management in Emacs. Useful sometimes.
#+begin_src emacs-lisp
;; Search
"s" '(nil :which-key "search")
"sa" '(avy-goto-char-2 :which-key "avy-goto-char-2")
"ss" '(isearch-forward :which-key "isearch-forward")
"sr" '(isearch-backward :which-key "isearch-backward")
"sp" '(project-search :which-key "project search")
"si" '(consult-imenu :which-key "consult-imenu")
"sm" '(consult-mark :which-key "jump to marker")
"sl" '(consult-goto-line :which-key "Go to line")
#+end_src
Search. Gets used multiple times every day. Useful bunch of commands. Fond of consult-goto-line.
#+begin_src emacs-lisp
;;System
"m" '(nil :which-key "system")
"m1" '(restart-emacs :which-key "restart emacs")
"m+" '(tab-bar-new-tab :which-key "tab new")
"m-" '(tab-close :which-key "tab close")
"ma" '(read-abbrev-file :which-key "read abbrev file")
"mc" '(hrm-load-current-lisp-file :which-key "load lisp file")
"mf" '(my/resources-visit :which-key "visit resources")
"mr" '(nil :which-key "region")
"mre" '(er/expand-region :which-key "expand region")
"mrc" '(er/contract-region :which-key "contract region")
"mp" '(nil :which-key "palimpsest")
"mpb" '(palimpsest-move-region-to-bottom :which-key "pal move bottom")
"mpt" '(palimpsest-move-region-to-top :which-key "pal move top")
"mm" '(nil :which-key "mark")
"mml" '(my/mark-line :which-key "mark line")
"mmb" '(my/mark-block :which-key "mark block")
"mw" '(writegood-mode :which-key "writegood toggle")
#+end_src
The classification is iffy. This is not all system related. The mnemonic is not useful. However these are a set of commands which get used a lot. I have meshed them into my fingers.
#+begin_src emacs-lisp
;; Org-mode
"o" '(nil :which-key "org-mode")
"oa" '(org-agenda :which-key "org-agenda")
"oc" '(org-capture :which-key "org-capture")
"on" '(recursive-narrow-or-widen-dwim :which-key "narrow")
"or" '(org-refile :which-key "refile")
"ot" '(org-todo :which-key "DONE")
"ou" '(my/org-jump-to-heading-beginning :which-key "jump to heading")
;; More Org
"ol" '(nil :which-key "line/link")
"olb" '(org-beginning-of-line :which-key "begin of line")
"ole" '(org-end-of-line :which-key "end of line")
"oli" '(org-insert-link :which-key "org insert link")
"olh" '(denote-org-link-to-heading :which-key "org link to heading")
"ols" '(org-store-link :which-key "org store link")
;; Yet More org
"," '(nil :which-key "more-org")
",c" '(org-cycle :which-key "org-cycle")
",m" '(my/yank-markdown-as-org :which-key "yank md>org")
",n" '(outline-next-visible-heading :which-key "next-heading")
",p" '(outline-previous-visible-heading :which-key "previous-heading")
",t" '(org-set-tags-command :which-key "set-tags")
",u" '(outline-up-heading :which-key "up-heading")
#+end_src
I write primarily in Org-mode and there are a host of things Org can do for you. Not all of these get used all the time. They are Org features which make it better than any other markup language for me.
#+begin_src emacs-lisp
;; text
"t" '(nil :which-key "text")
"ti" '(indent-whole-buffer :which-key "indent whole buffer")
"tr" '(isearch-query-replace :which-key "find and replace")
"ts" '(yas-insert-snippet :which-key "insert yasnippet")
"tR" '(replace-regexp :which-key "replace-regexp")
"tt" '(titlecase-dwim :which-key "titlecase")
"t/" '(my/comment-or-uncomment :which-key "comment")
;; date/time
"td" '(nil :which-key "stamp date/time")
"tdt" '(my/time-stamp-short :which-key "time-stamp-short")
"tdd" '(my/date-stamp :which-key "date-stamp")
;; word
"tw" '(nil :which-key "word")
"twc" '(my/copy-whole-word :which-key "copy whole word")
"twk" '(my/kill-inner-word :which-key "kill inner word")
"two" '(copy-as-format-org-mode :which-key "copy as org mode")
"twm" '(copy-as-format-markdown :which-key "copy as markdown mode")
"twi" '(org-web-tools-insert-web-page-as-entry :which-key "insert web page as entry")
"tww" '(org-web-tools-insert-link-for-url :which-key "insert link for url")
"twl" '(dictionary-lookup-definition :which-key "dictionary lookup")
"twp" '(my/lookup-word-at-point :which-key "lookup word at point")
#+end_src
This is a collection of things which are text related. Functions which make working with text easier in Emacs. I am always using these. They are critical.
#+begin_src emacs-lisp
;; Windows
"w" '(nil :which-key "window")
"wl" '(windmove-right :which-key "windmove-right")
"wh" '(windmove-left :which-key "windmove-left")
"wk" '(windmove-up :which-key "windmove-up")
"wj" '(windmove-down :which-key "windmove-down")
"wd" '(delete-window :which-key "delete-window")
"wr" '(hsplit-last-buffer :which-key "split-window-right")
"wb" '(vsplit-last-buffer :which-key "split-window-below")
"ww" '(appine-open-web-split :which-key "appine-web")
"wf" '(appine-open-file-split :which-key "appine-file")
#+end_src
Windows management related keyboard commands. I use these several times every day.
#+begin_src emacs-lisp
;; Visual
"v" '(nil :which-key "visual")
"vm" '(view-mode :which-key "view-mode")
"vt" '(consult-theme :which-key "load theme")
"vR" '(read-only-mode :which-key "read only mode"))
#+end_src
This is a strange bunch of commands which don’t get used all that often. I use read-only-mode when the document is critical and needs deliberate editing.
Some of the functions are repeated several times in the setup. Those are important to my use and I am trying to figure out which is the easiest way to get to them. This is going to get cleaned up over time.
I love general.el. It has made it possible to define, remember, and use my own keyboard commands in Emacs. Thank you to the developer.
macosxguru at the gmail thingie.
Thanks: Photo by cottonbro studio: https://www.pexels.com/photo/white-apple-keyboard-on-white-table-5082571/