.emacs.d

My Emacs configurations.

GPL-3.0 License

Stars
31
Committers
2

#+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 =<s = 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=