Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/andyleejordan/.emacs.d

:keyboard: My Emacs configurations.
https://github.com/andyleejordan/.emacs.d

dotfiles emacs emacs-lisp

Last synced: 20 days ago
JSON representation

:keyboard: My Emacs configurations.

Awesome Lists containing this project

README

        

#+TITLE: Andy Jordan's Emacs configurations
[[https://travis-ci.org/andschwa/.emacs.d][https://travis-ci.org/andschwa/.emacs.d.svg?branch=master]]

Utilizes [[https://github.com/jwiegley/use-package][jwiegley's use-package]] macro to cleanly and quickly require,
install via [[https://github.com/raxod502/straight.el][straight.el]], and setup various extensions. Tries to get
back to the basics.

These configurations work a lot better with at least Emacs 26,
although Emacs 25 should be supported, and I tend to build from source
so I can apply my [[https://github.com/emacs-mirror/emacs/commit/48ff4c0b2f78f1812fa12e3a56ee5f2a0bc712f7#diff-3b23fdba3dbc1527e9de42e7d7f14bbc][patch]].

This readme is currently going through a rewrite.

* Using Emacs

Much of what I know about using Emacs I learned over a decade, but I
highly recommend reading the book [[https://masteringemacs.org/][Mastering Emacs]] by Mickey Petersen.
Xah Lee's [[http://ergoemacs.org/emacs/emacs.html][Practial Emacs Tutorial]] is also fantastic.

** Syntactic movements

See [[https://masteringemacs.org/article/effective-editing-movement][Effective Editing Movement]] for more.

*** Characters and words

Moving forward a character is =C-f=, backward is =C-b=, and deleting
is =C-d=. I mention this because the next syntactic movement is by
word. The keys are symmetric to the character movements, just with
meta instead of control: forward is =M-f=, backward is =M-b=, and
deleting is =M-d=. You can also mark a word with =M-@= (which explains
why =C-@= is another binding for =set-mark-command=). My configuration
enables =subword-mode=, indicated by a comma in the mode line, which
turns =CamelCase= into two words instead of one.

*** Expressions

Now combine control and meta, and you can move by "s-expression," or
=sexp=: forward is =C-M-f= and backward is =C-M-b=. However, delete is
different as it is =C-M-k= (for "kill"). This is because you can move
through nested expressions with up =C-M-u= and down =C-M-d=. Marking
should be familiar on =C-M-SPC= (and is also on =C-M-@= for symmetry).
Honestly, moving by sexp is usually much better than by word.

*** Lines and sentences

Similar to =C-a= to move to the beginning of the line, =C-e= to move
to the end, and =C-k= to kill, sentence movement is =M-a=, =M-e=, and
=M-k=. Marking a sentence is =M-h=. Sentences are more useful than
they would seem, as modes are free to define a sentence how they see
fit. For instance, in the C and C++ modes, a sentence is defined to be
a language statement.

There is also a special command to move "back to indentation" on
=M-m=. This places the point at the first non-whitespace text on the
line, which is a nice shortcut.

*** Functions

Movement by function (or =defun=), is similar to lines and sentences,
but with control and meta. Move to the beginning is =C-M-a=, end is
=C-M-e=, and mark is =C-M-h=. In some modes, like that for Emacs Lisp,
you can also evaluate a =defun= with =C-M-x=.

*** Buffers

Buffer movement only has a commands: move to the beginning is bound to
=M-<=, move to the end is =M->=, and mark the whole buffer is =C-x h=.

That last binding makes sense in the context of =kill-buffer= on =C-x
k=, =save-some-buffers= on =C-x s=, =switch-buffer= on =C-x b=, and
=list-buffers= on =C-x C-b=. [[#buffers][See more.]]

*** Searching

Using =C-s= to incrementally search within a buffer must become second
nature. This command is =isearch=. Using [[#isearch][isearch]] to move within a
buffer is probably the most powerful syntactic movement, as it is
precise and easy to do. You can search in /reverse/ with =C-r=.

After typing =C-s= or =C-r=, you can restart your last search by
pressing it again, or you can yank successive words from the point
onward with =C-w=. While searching for something, move forward through
the matches with =C-s= and backward with =C-r=.

You can cancel a search with =M-g=, which will drop you back to your
starting point, or you can finish a search with =RET=. Finishing a
search will push your starting location onto the [[#mark-ring][mark ring]] and drop
you at the current match. You can jump right back with =C-u C-SPC=,
which pops the mark ring.

*** Going places

Two bindings that are conspicuously missing are =M-n= and =M-p=, but
in fact these are usually specific to the mode. In a [[#packages][Magit]] status
buffer, for example, they move between sections; in an [[#occur][Occur]] buffer
they move between occurrences; and in a compilation buffer they move
between errors. They can be accessed from the original buffer with the
prefix =M-g=, so =M-g M-n= will take you to the next occurrence
without having to switch to the Occur buffer.

That last prefix mentioned, =M-g=, is actually a binding for the
entire =goto-map=. Going to a specific line is done with =M-g M-g=, a
specific character is =M-g c=, and a specific column (character on the
current line) is =M-g TAB=.

As Mickey Petersen points out in Effective Editing Movement, a handy
use of the universal argument for =goto-line= is to switch from a
source buffer to some other buffer that has a line number
corresponding to that source, then =C-u M-g M-g= will take the number
at point and go to that line in the previous buffer. Considering how
many tools emit line numbers (like compilers, linters, search tools,
etc.), this can be quite useful.

*** Paragraphs

When writing blocks of text, such as documentation or notes,
paragraphs become a useful syntactic movement. Moving forward a
paragraph is =M-{= and backward is =M-}=. Wrapping a paragraph is done
with =fill-paragraph= on =M-q=, which can also justify text when given
a prefix argument. My configuration includes the package =unfill=
which makes =M-q= undo itself when repeated.

** Cut and paste

Or in Emacs parlance, kill and yank. In addition to the syntactic kill
commands, you can also kill a region with =C-w=. Yanking text is done
with =C-y=. Follow it up with =M-y= repeatedly to cycle through the
kill ring until you have yanked what you want.

Before killing text, you can use =C-M-w= to append the next kill to
the previous kill. This is useful when killing pieces of text
throughout the buffer, to be yanked all at once elsewhere.

You can "zap" text with =M-z [char]=. This is equivalent to vi's
=df[char]=. It kills from the point to (and including) the next
instance of the given character. I actually prefer the semantics of
=dt[char]=, which kills to (but excluding) the character. So my
configuration remaps =zap-to-char= to =zap-up-to-char=.

** Prefix arguments

Negative and numeric arguments can be prefixed to other commands in
order to perform actions (similar to vi's composable grammar). That
is, =3dd= in vi is equivalent to =C-3 C-k=, and =3k= is =C-3 C-p=. I
am not sure if vi has an equivalent to the negative argument: it is
used to do things backwards, that is, =M-- M-l= will downcase the word
_before_ the point instead of after, and =C-M-- C-M-SPC= will mark the
previous sexp instead of the next.

As you may have noticed, the negative and numeric arguments are bound
to control, meta, and control-meta so that they can be easily combined
with any other binding. You can type any number as a numeric argument.
For example, =C-SPC C-1 C-3 C-n= marks the next 13 lines.

In my opinion, the only real difference between the two grammars is
that in vi, you have to explicitly change modes with =ESC=, and with
Emacs, you temporarily change modes with modifier key chords (control
and alt/meta).

*** Universal argument

The negative and numeric argument bindings are truly just shortcuts
for the "universal" argument =C-u=, which begins a numeric argument
sequence (and remember, numbers can be negative). An example is the
combined command =M-- M-6 M-d=, which kills the last six words, and is
equivalent to =C-u - 6 M-d=.

More interesting is that =C-u= has a default numeric value of four. So
if it is used alone as in =C-u C-f= it will move forward four
characters. While this has some value, it is more useful in the
context of alternative modes of operation for interactive functions. I
will be honest, I usually use it after reading the documentation of a
function, and then promptly forget it. One example I can think of is
=C-u C-SPC=: a single prefix argument to =set-mark-command= causes it
to pop the local mark ring (jump back to last marked spot in the
buffer, like =C-x C-SPC= but not global).

Note that unlike the numeric and negative arguments, the universal
argument is only on =C-u=. That is, =M-u= and =C-M-u= are bound to
completely different commands.

See [[http://ergoemacs.org/emacs_manual/emacs/Arguments.html][ErgoEmacs]].

** Repeating commands

While numeric arguments can repeat a command N times, you have to
specify it before calling the command. Often you realize _after_
calling a command that it needs to be repeated, which you can do with
=C-x z= (bound to =repeat=). This is equivalent to vi's =.= command.
After the first invocation, =z= can be used for more repetitions. It
also repeats the arguments used originally.

More complex commands are repeatable with =repeat-complex-command=,
annoyingly bound to =C-x M-:=. Complex commands are those used in the
minibuffer which take interactive input (like =query-replace=).

See [[https://masteringemacs.org/article/repeating-commands-emacs][Mastering Emacs]].

** Keyboard macros

When a more advanced action needs to be repeated, Emacs [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Keyboard-Macros.html][keyboard
macros]] are awesome! To start recording a macro, use =C-x (=, to finish
recording a macro, use =C-x )=, and to run the last recorded macro,
use =C-x e=. That last command will also automatically finish
recording a macro, and can be repeated with just =e=.

The rest of the useful =kmacro= functions are bound to the prefix =C-x
C-k=. If =C-x (= is annoying, =C-x C-k s= is also bound and is a bit
more mnemonic ("execute kmacro start").

When recording a macro, be careful not to quit by accident or with
=C-g=, as this cancels the recording! I usually run into this when
trying to cancel an =isearch=, and then have to start recording again.
Instead, use =RET= to end (not quit) the search, and then use =C-u
C-SPC= to pop the mark back to where you were. It is also a problem
when deactivating a marked region. Instead of =C-g=, use =C-SPC C-SPC=
to set and then deactivate the mark.

If a mistake is made when recording, use =C-/= to undo. It will work
just fine when applying the macro.

Writing useful macros means using syntactic movements instead of
characters, so that the macro works regardless of textual differences.
The most useful movements are =C-s=, =C-a=, and =C-e=, but also useful
are word and expression commands.

To apply a macro to all lines in a region, use =C-x C-k r=. To
repeatedly apply a macro until an error occurs (like reaching the end
of the buffer, or no more search results), use =C-0 C-x e=.

Macros can be saved by naming them with =C-x C-k n= and then saved
permanently by writing their lisp code with =insert-kbd-macro= (or
just view the last macro with =kmacro-view-macro=).

See [[http://ergoemacs.org/emacs/emacs_macro_example.html][ErgoEmacs]].

** Mark rings
:PROPERTIES:
:CUSTOM_ID: mark-ring
:END:

The mark rings are used for recording positions in buffers. The global
mark ring records the latest mark for each buffer, and each buffer's
local mark ring records the marks for that buffer. So the global mark
ring essentially records your buffer switching history (with the
helpful context of _where_ in the buffer you were), and the local mark
ring records your position history in each buffer.

Setting the mark command is done with =C-SPC= (aptly named
=set-mark-command=). This sets the mark at the point and pushes the
last location onto the local mark ring.

Use =C-u C-SPC= (which internally calls =pop-to-mark-command=) to pop
the local mark after jumping around in a buffer, such as when using
=C-s=. Note that while typing text moves the _point_ (or cursor)
forward, it does not move the mark. Instead, this happens with
commands that "jump," or with =C-SPC C-SPC= to manually set and then
deactivate the mark. Think of the mark as a bookmark of the point, but
not the point itself.

Use =C-x C-SPC= (=pop-global-mark=) to go back after jumping into
another buffer, such as when finding a definition with =M-.=, although
there is also a mark ring for =xref= which you can pop with =M-,=.

When =set-mark-command-repeat-pop= is enabled, the mark can be
repeatedly popped by hitting =C-SPC= after first popping the global or
local mark ring.

An obscure but useful command is =C-x C-x=, which exchanges the point
and mark. When a region is marked, =C-x C-x= moves between the
beginning and end of that region. If the region is not yet marked, it
will mark the region between the point and previous mark. You can
avoid marking the region and instead only move the point with the
prefix argument, so =C-u C-x C-x=. This command is super useful when
using the =rectangle= commands (on =C-x r=) as the exact region
matters.

My configuration turns on =transient-mark-mode= and enables
=set-mark-command-repeat-pop=.

** Deleting whitespace

Delete all horizontal whitespace around the point on the current line
with =M-\=. Use =M-- M-\= to only delete the space backwards.

When a single space is desired (often the case after deleting some
words), use =M-SPC=. The negative argument will delete newlines too,
and numeric arguments keep N spaces. So =M-- M-SPC= is really useful
to join text below the point separated by whitespace to the point on
the same line after a space.

My configuration actually rebinds =M-SPC= to =cycle-spacing=, which is
an enhanced version of =just-one-space=. On the first call it operates
the same; on the second it deletes all spaces (like =M-\=); and on the
third it restores the original whitespace.

You can delete blank lines (vertical whitespace) with =C-x C-o=, which
is mnemonic since =C-o= inserts a newline. Use it on a non-blank line
to join text below the point separated by whitespace, but with a
newline in between instead of on the same line. Use it on a blank line
to keep just one line (like =M-SPC= but for lines). Use it again on a
single blank line to delete it.

You can join text at the point to the _line above the point_ with
=M-^=, which calls =delete-indentation=, so named because it also
fixes up the whitespace at the join. The negative argument instead
joins to the line below the point, essentially turning it into the
commands above. I do not find this command as useful as the others.

** Writing comments

Probably one of my most used commands is =comment-dwim=, or "comment
Do What I Mean," on =M-;=. Given a region, it comments it (or
uncomments it). This is best combined with syntactic mark commands.
Otherwise it starts a new comment, and with a prefix, kills a comment.
To turn the current line into a comment, use =C-x C-;=.

Note that the key =C-;= is not a valid character in a terminal, so it
is baffling that it is used as a default binding. Thus when using
Emacs in a terminal typing =C-x C-;= translates to =C-x ;= which calls
=comment-set-column=, a confusing situation indeed! Instead of finding
a new mapping, I just select the line and use =M-;=.

While writing a multi-line comment, use =M-j= to insert a newline and
comment syntax. This will also indent such as when you are writing to
the side of a block of code. Its counterpart =C-j= inserts a newline
and indents (without commenting). I should use these more.

** Adjusting case

Words can be UPPERCASED with =M-u=, lowercased with =M-l=, and
Capitalized with =M-u=. I find that I run these with the negative
argument more often than not so that I can fix the case of a word just
written.

My configuration remaps the Do What I Mean versions of the above so
that they work on regions too. Otherwise the region versions are =C-x
C-u= and =C-x C-l=, with =capitalize-region= conspicuously unbound.
There is also an obscure version of the last one called
=upcase-initials-region=, which specifically only alters the initial
characters.

** Transposing

I did not use the transpose commands until Mickey explained that they
"pull" characters (and words and sexps) to the right. I cannot explain
this as well he did, so just go read Mastering Emacs. Transposing a
character is =C-t= (useful after an immediate typo), a word is =M-t=,
a sexp is =C-M-t=, and a line is =C-x C-t=.

** Help!

The only help command you need to know is =C-h h=, which gets help for
the help system. It brings up a buffer describing all the possible
other help systems and shortcuts to get there. The other helpful
commands are:

- =C-h e= to view the messages buffers
- =C-h k= to get help for a binding
- =C-h b= to list and search bindings
- =C-h w= to ask =where-is= a function bound
- =C-h f= to get help for a function
- =C-h v= to get help for a variable
- =C-h m= to list help for the current modes
- =C-h l= to view lossage (history of keystrokes)

That last one is for curious people to figure out what keys they are
using too often.

** Quoting characters

Sometimes you need to insert a character whose key usually triggers an
action. An example is typing a lone open parenthesis or quotation mark
when electric modes would otherwise type the whole pair. You can do
this by "quoting" the character with =C-q=, such =C-q (=.

Another example is typing a newline in a query replacement, where
hitting enter would accept the input instead of inserting a newline.
However, =C-q RET= inserts =^M=, which is a carriage return, not a
newline. You actually want =C-q C-j=. But why is that?

Similarly, you often need to insert Unicode characters and Emacs has
an amazing facility with the prefix =C-x 8=. For example, the
copyright symbol © is =C-x 8 C=, and the Euro symbol € is =C-x 8 * E=.
Smart quotes can be found on =[= / =]= for =‘= / =’=, and ={= / =}=
for =“= / =”=, but also see see =electric-quote-mode=. Use =C-x 8 C-h=
to find the rest.

*** Emacs syntax explained

The answer goes all the way back to the ASCII table and the notion of
Unix line endings. You might be familiar with line endings being
"CRLF" on Windows and just "LF" on Linux. The "LF" is "line feed" (or
=^J=, read as "control J," just like =C-j=) and the "CR" is "carriage
return" (or =^M=). The caret in those notations is for control (as in
the key), because the ASCII standard represents these characters as
the combination of control followed by a letter. The letter
corresponds to the position of the character on the ASCII table. Since
line feed is the tenth ASCII character, and "J" is the tenth letter,
=^J= is its notation. Hence Emacs literally interprets =C-j= as a line
feed. Similarly, =C-i= is for horizontal tab, =C-m= is for carriage
return, =C-[= is for escape, etc. See [[http://ergoemacs.org/emacs/keystroke_rep.html][ErgoEmacs]] for more.

This explains why setting =flyspell-use-meta-tab= to nil unbinds
=C-M-i= because it is interpreted as =M-TAB=. This is because =C-i=
/is/ horizontal tab according to the ASCII standard. I mention this
because this default binding is really annoying on Windows where
=M-TAB= (or "alt-tab") switches windows.

** Arranging buffers
:PROPERTIES:
:CUSTOM_ID: buffers
:END:

Emacs is old, so old that it existed before windowing systems. Because
of this, it does not use the now commonplace terminology of "tabs" and
"windows." An operating system window is, to Emacs, a "frame," and
within a frame each portion is a "window" (Mickey Petersen likens it
to window panes in a physical frame). These windows display buffers
(usually an open file, but also any other set of text like
=*Messages*= or =*Help*=), and they are similar to tabs in younger
editors.

Switch buffers with =C-x b=, and [[#ibuffer][list them]] with =C-x C-b=.

Splitting a window horizontally is bound to =C-x 2=, and splitting
vertically is =C-x 3=. Closing a window is =C-x 0=, and closing all
/other/ windows is =C-x 1= (kind of like "maximize this window"). The
other window commands are on the =C-x 4= keymap. What is handy is that
most of these commands are reflective of the =C-x= commands, just
applied to the "other" window. So while =C-x b= switches the current
window's buffer, =C-x 4 b= switches to the other window and then
switches buffers (it will split the current frame to open the other
window if it needs to). You can find a file with =C-x 4 f=, and open
Dired with =C-x 4 d=.

I often find myself with windows split horizontally but I want them
split vertically. Fixing this with vanilla Emacs is an annoying
combination of closing and opening windows. With the
=transpose-frame.el= package, it becomes a simple matter of calling
=transpose-frame=, which I have bound to =C-x 4 r=. This package
provides many other potentially useful functions depending on your
windowing needs, so check it out.

Finally, if you need to deal with frames, all the bindings are under
=C-x 5=, with the important ones being close on =C-x 5 0=, close
others on =C-x 5 1=, and create on =C-x 5 2= (these should be familiar
now as they are symmetric to the basic frame bindings).

** Advanced searching
:PROPERTIES:
:CUSTOM_ID: isearch
:END:

As mentioned earlier, =isearch= is /incredible/ incremental searching.

In =isearch=, switch to regular expression mode with =M-s r=. You can
also initiate a regex search directly with =C-M-s= and =C-M-r=, but
this introduces us to the =isearch= prefix binding, =M-s=.

Other useful bindings in this map are =M-s _= which starts a search in
symbol mode (use =M-s .= to start searching for the symbol at point),
and =M-s w= which starts a word search (that is, search for a sequence
without regard to the separating characters). If a search is already
in progress, these same bindings toggle the search semantics, in
addition to many other toggles available under =M-s=. Check them out
the next time you need to narrow or expand your search.

Also handy is that calling =query-replace= with =M-%= while searching
will use your current search string as the input. This lets you figure
out your exact match string and then immediately replace it.

** Occur
:PROPERTIES:
:CUSTOM_ID: occur
:END:

One of the neatest features of Emacs is the command =occur=, bound to
=M-s o=. Essentially, it is =grep= within Emacs. Calling it alone
prompts for a regular expression, but you can also call it during an
[[#isearch][isearch]]. It lists all the occurrences of the search in an overview
buffer (in fact, =list-matching-lines= is an alias for =occur=).
Selecting an occurrence with =RET= jumps you to it in the original
buffer (=C-o= does the same but leaves the point in the Occur buffer),
and typing =e= switches us to =occur-edit-mode=.

This last command is awesome. It makes the Occur buffer editable: any
changes you make will be made to the original buffer when you finish
with =C-c C-c=. In this way, you can edit matching lines (and
additional context lines by customizing
=list-matching-lines-default-context-lines=) in an overview. I find
this to be a much friendlier way of making changes than slowly going
through a =query-replace=.

Occur is made even better by the ability to run it across multiple
buffers, with the interactive =multi-occur=, or the filtered
=multi-occur-in-matching-buffers=.

** Listing buffers
:PROPERTIES:
:CUSTOM_ID: ibuffer
:END:

My configuration remaps =C-x C-b= to =ibuffer=, a much improved buffer
listing. Frankly, I should use this more than I currently do, but
usually I just switch buffers with =C-x b=. You can group and filter
(with =/=) all your buffers, and once marked (individually with =m= or
all with =t=), apply operations to them.

Instead of using =multi-occur=, you can select your buffers in
=ibuffer= and hit =O= to run Occur across them as a group. You can
also start a query replace with =Q=, and setup a =multi-isearch= with
=M-s a C-s=. Hit =h= to see all the other options with =ibuffer=.

** Common unbound commands
- align
- align-regexp
- customize-group
- desktop-clear
- delete-matching-lines
- delete-non-matching-lines
- eval-buffer
- eval-region
- find-lisp-find-dired
- revert-buffer
- sort-lines
- straight-pull-all
- toggle-debug-on-error
- toggle-theme
- visual-line-mode
- whitespace-cleanup
- whitespace-mode

** Future sections

- ripgrep / wgrep
- wgrep
- compilation
- eshell
- rectangle
- raise and surround
*** dired
=C-0 w= runs =dired-copy-filename-as-kill= with full path
* Notable packages
:PROPERTIES:
:CUSTOM_ID: packages
:END:

This is not an exhaustive list, just the ones I have found the most
useful.

- [[https://github.com/jscheid/dtrt-indent][dtrt-indent]] intelligently guesses indentation rules
- [[https://github.com/raxod502/selectrum][selectrum]] for enhanced command completions
- [[https://github.com/magit/magit][magit]] is the best way to interact with Git, see [[https://emacsair.me/2017/09/01/magit-walk-through/][the walk-through]]
- [[https://github.com/tarsius/hl-todo][hl-todo]] highlights TODOs in source code
- [[https://github.com/Malabarba/smart-mode-line/][smart-mode-line]] makes the mode readable and useful
- [[https://github.com/bbatsov/solarized-emacs][solarized-emacs]] is the color theme
- [[https://github.com/jwiegley/use-package][use-package]] organizes =init.el= and manages packages
- [[https://github.com/justbur/emacs-which-key][which-key]] makes keybindings actually discoverable
- [[https://github.com/lewang/ws-butler][whitespace-butler]] unobtrusively cleans up whitespace

* Emacs Lisp programming notes

** Interactive Emacs Lisp Mode

Unsurprisingly, Emacs comes with an Emacs Lisp REPL, =ielm=, or the
Interactive Emacs Lisp Mode. Use this when testing lots of Emacs Lisp.

The scratch buffer defaults to Emacs Lisp mode so that it is kind of a
REPL. It can be used as such because =C-M-x= evaluates the current
function, =C-x C-e= evaluates the last sexp, and =C-j= will evaluate
/and print/ the last sexp.

Use =M-:= to evaluate an expression queried from the minibuffer.

See [[https://masteringemacs.org/article/evaluating-elisp-emacs][Mastering Emacs]] for more.

** Common functions

- =add-hook= and =eval-after-load= for conditional execution
- =expand-file-name= and =f-expand= for filename expansion
- =file-name-basename= and =file-name-nondirectory= etc.
- =file-remote-p= will return the connection prefix (remote root)
- =message= and =princ= for printing
- =concat= and =format= for strings
- =get-buffer-create= for buffers
- =add-to-list= and =append= for lists
- =mapcar= with list of results
- =mapconcat= for string of results
- =dolist= for =mapc= with implicit bind
- =cadr= for last item of pair, as in, =(car (cdr foo))=
- =cons= to append without copying
- =remove= to filter items from list
- =getenv=, =setenv=, =compilation-environment= for env
- =executable-find= for binaries
- =nth= and =elt= for indexing a list
- =cond= is better than =if= / =else=
- =let= and =let*= for local variables
- =symbol-function= to find an alias
- =where-is-internal= to get bindings
- =save-excursion= to restore point
- =replace-regexp-in-string=
- =shell-command-to-string=
- =thing-at-point= to get things at point
- [[https://github.com/magnars/dash.el][dash.el]] modern list library
- =run-with-idle-timer= to schedule functions to run when idle
- =list-timers= to view (and use ‘c’ to cancel) existing timers

** Custom faces

This was particularly annoying to get right, so here is how to set a
custom face that varies with the background type.

#+begin_src elisp
(use-package ivy
:custom-face
(ivy-current-match
((((class color) (background light))
:background "#fdf6e3" :underline (:color "#859900"))
(((class color) (background dark))
:background "#002b36" :underline (:color "#859900")))))
#+end_src

** Partially evaluate list elements

The backquote is like a normal quote except it evaluates elements
marked with commas. [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Backquote.html][See the manual]].

#+begin_src elisp
(add-to-list 'somelist `(symbol . ,(expression to be evaluated)))
#+end_src

** Capture all regexp matches

Captures all non-terminals in Bison grammar.

#+begin_src elisp
(save-excursion
(while (re-search-forward "^\\([a-z_]+\\):" nil t)
(princ (format "%s " (match-string 1)) (get-buffer-create "matches"))))
#+end_src

** Build regexps etc. with elisp
- =rx= for building regexp from sexps
- =re-builder= for interactively writing regexp
- =find-cmd= for building find command from sexps

* Building from source
- Clone =git clone -b emacs-27 https://github.com/emacs-mirror/emacs.git=
- See =system-configuration-features= for available features
- See =system-configuration-options= for configure times
- [[http://www.x.org/releases/X11R7.7/doc/xorg-docs/fonts/fonts.html][XFT]] is the X11 font system, and is required.
- [[http://jmason.org/howto/subpixel.html][Sub-pixel rendering]]
** macOS script
#+begin_src bash
#!/bin/bash

set -o errexit
set -o pipefail

brew install autoconf gnu-sed texinfo pkg-config gnutls libxml2 jansson

export PATH="/usr/local/opt/texinfo/bin:$PATH"
export PATH="/usr/local/opt/gnu-sed/libexec/gnubin:$PATH"
export PKG_CONFIG_PATH="/usr/local/opt/libxml2/lib/pkgconfig"

./autogen.sh
./configure --with-ns --without-x --with-gnutls --with-json --with-xml2 --without-dbus
make -j $(nproc) all info doc

./src/emacs -Q
make install
# Copy ‘nextstep/Emacs.app’ to /Applications
#+end_src
** Ubuntu 19.10 script with X
#+begin_src bash
#!/bin/bash

set -o errexit
set -o pipefail

sudo apt install pkg-config texinfo libgtk-3-dev libncurses-dev libgnutls28-dev libjansson-dev libxpm-dev libxml2-dev

./autogen.sh
./configure --with-x-toolkit=gtk3 --with-gnutls --with-json --with-xml2
make -j $(nproc) all info doc

./src/emacs -Q
sudo make install install-info install-doc
#+end_src
** Ubuntu 20.04 script without X
#+begin_src bash
#!/bin/bash

set -o errexit
set -o pipefail

sudo apt install pkg-config texinfo libncurses-dev libgnutls28-dev libjansson-dev libxpm-dev libxml2-dev libsystemd-dev libz-dev build-essential aspell
# Consider: git, ripgrep, sshguard, and htop

./autogen.sh
./configure --with-gnutls --with-json --with-xml2 --with-libsystemd --with-x-toolkit=no --with-jpeg=ifavailable --with-png=ifavailable --with-gif=ifavailable --with-tiff=ifavailable | less
make -j $(nproc) all info doc

./src/emacs -Q
sudo make install install-info install-doc
#+end_src
* Bugs
** icomplete uses wrong default value
[[https://debbugs.gnu.org/cgi/bugreport.cgi?bug=42101][GNU Bug Report #42101]]
Disable this expression from =icomplete--sorted-completions=:
#+begin_src elisp
,(lambda (comp)
(string-prefix-p minibuffer-default comp))
#+end_src
** Buffer content invisible when tunneling X
[[https://debbugs.gnu.org/cgi/bugreport.cgi?bug=25474][GNU Bug Report #25474]]
#+begin_src lisp
(setq default-frame-alist
(append default-frame-alist '((inhibit-double-buffering . t))))
#+end_src

** =derived-mode-p= broken for aliased parents
[[https://debbugs.gnu.org/cgi/bugreport.cgi?bug=32795][GNU Bug Report #32795]]
#+begin_src lisp
(defun provided-mode-derived-p (mode &rest modes)
"Non-nil if MODE is derived from one of MODES or their aliases.
Uses the `derived-mode-parent' property of the symbol to trace backwards.
If you just want to check `major-mode', use `derived-mode-p'."
(while
(and
(not (memq mode modes))
(let* ((parent (get mode 'derived-mode-parent))
(parentfn (symbol-function parent)))
(setq mode (if (and parentfn (symbolp parentfn)) parentfn parent)))))
mode)
#+end_src

** Installing =org-mode= with =straight.el=

There is a [[https://github.com/raxod502/straight.el#installing-org-with-straightel][known bug]] when installing =org-mode= with =straight.el=. I
have not applied the workaround because the bug is pretty much just
cosmetic.

* Unfiled

Everything in this section is yet to be rewritten and refiled.

** Install package fork with Quelpa
#+begin_src elisp
(quelpa '(eglot :repo "andschwa/eglot" :fetcher github :branch "fix-capf-use-from-minibuffer"))
#+end_src
** Markdown dwim header =C-c C-t h=
** Narrowing: =C-x n= region =n= defun =d= widen =w=
https://www.gnu.org/software/emacs/manual/html_node/emacs/Narrowing.html
** Selective display: = C-x $=
** Surround with parentheses: =M-(= on region or with numeric arg
** The opposite of =C-l= is =M-r= recenter-positions
** Reposition window to see comment/function: =C-M-l=
** Set fill prefix: =C-x .=
[[https://www.gnu.org/software/emacs/manual/html_node/emacs/Fill-Prefix.html][Fill-Prefix]] with point after prefix
** Set fill column: =C-x f=
** Toggle read-only =C-x C-q=
** =file-name-shadow-mode=
#+begin_src emacs-lisp
(setq file-name-shadow-properties
'(invisible t))
#+end_src
** Writable modes
*** occur with =e= exit
*** wgrep with =C-c C-p=
*** wdired with =C-x C-q=
*** ivy occur with =C-c C-o= then follows wgrep
See [[https://oremacs.com/2016/04/26/ivy-0.8.0/][=ivy-occur-mode=]]

** Tricks and tips
*** Automatic alignment with =align-current=
Fall back to =align-regexp=. Prefix that for complex mode.
*** Replace =uniq= with =delete-duplicate-lines=
**** also =flush-lines= and =keep-lines=
*** Delete blank lines =M-x flush-lines RET ^$ RET=
https://masteringemacs.org/article/removing-blank-lines-buffer
*** Using quote marks within verbatim/code markup in org-mode
- Unicode: /xe2/x80/x8b ZERO WIDTH SPACE
- Insert using: (C-x 8 RET 200b RET)
*** Quickly insert =#+begin_src= with == and =C-c C-, s=
- http://orgmode.org/org.html#Easy-Templates
- =org-insert-structure-template=
#+begin_src emacs-lisp
(require 'org-tempo)
(add-args-to-list 'org-structure-template-alist
'(("el" . "src emacs-lisp")
("sh" . "src sh")))
#+end_src
*** Sudo mode using Tramp =C-x C-f /ssh:you@host|sudo:host:/file=
- http://www.emacswiki.org/emacs/TrampMode
*** Replace in files
From [[https://stackoverflow.com/a/271136][StackOverflow]]:

1. =M-x find-name-dired=: you will be prompted for a root directory and
a filename pattern: =-name "*.py" -not -path "./.archive/*"=

2. Press t to "toggle mark" for all files found.

3. Press Q for "Query-Replace in Files...": you will be prompted for
query/substitution regexps.

4. Proceed as with query-replace-regexp: SPACE to replace and move to
next match, n to skip a match, etc.

5. Press Y to finish replacing in all buffers.

6. C-x C-s ! to save all buffers.

*** Replace with capture regexp
- use regex groups like =ab\(c\)= where the parentheses are escaped
because Emacs
- refer to prior capture groups by =\N= where N is 1-indexed on the
captured groups (e.g. back reference)
*** Renumber with regexp
- see [[http://www.emacswiki.org/emacs/RenumberList][Wiki]]; the comma indicates elisp code to evaluate
- e.g. =[0-9]+= -> =\,(+ 257 \#)=
- or by 8 starting at 10 =\,(+ 10 (* 8 \#))=
*** Replace reStructuredText headers
- Find ~~~ etc. =^\(~+\)$=
- Replace with ^^^ =\,(make-string (length \1) ?^)=
*** regexp-builder for replace
- Use =C-c C-i= and choose the "string" syntax
- Copy the regexp without the surrounding quotes
- Use =C-c C-q= to close regexp-builder
*** Set directory local variable =eval= to execute arbitrary code
*** Use =(hack-dir-local-variables-non-file-buffer)= to re-evaluate dir local
*** See current faces =list-faces-display=