#+title: On Emacs #+rss_title: On Emacs This post is a short love letter to emacs, the text editor that has changed the way I do my daily computing for a few years now. You can find my config [[https://github.com/neeasade/emacs.d][here]]. Disclaimer: At the end of the day, a text editor is just a preference, just like mechanical keyboards, vim bindings, window managers and what have you. ** [[#h-8e4f945a-37c2-4d42-be79-a975cade36f9][Programmable state]] :PROPERTIES: :CUSTOM_ID: h-8e4f945a-37c2-4d42-be79-a975cade36f9 :END: Emacs state is a long running emacs lisp repl, with all variable and function assignments tracked in a global environment. This has a few negatives, such as the naming conflict potential of all elisp code, and that any running elisp can affect emacs state (say, freeze the entire experience). However, the benefit of being able to peek and tweak any elisp code live is huge. You can connect or fix elisp packages together in ways not imagined by the authors through that global repl, and see changes instantly, with a very low bar for hackery. The resulting footgun is both the best and worst computing experience I think I'll have for quite awhile. ** [[#h-13fbbde3-2f8f-46bc-be50-2cacd057a744][Blended environment]] :PROPERTIES: :CUSTOM_ID: h-13fbbde3-2f8f-46bc-be50-2cacd057a744 :END: Emacs can be thought of as a toolkit for integrating textual data into a higher level interface, with an API for shaping that data into emacs primitives. Things like buffers, windows, the point, overlays, and major modes are all programmatically available in the expressive emacs lisp language. Combine this with the programmable global state in emacs and you get a very 'flowey' feeling when you switch between different interfaces all using the same UI primitives. I like to contrast this to the rise of many TUI tools for doing things in the terminal in recent years -- having to learn different keybinds and mental models for each of them (=ncmpcpp=, =tig=, =mutt=, =ranger=, =weechat=, ...) is more overhead for me than using the emacs equivalents and getting the benefit of a consistent interface. ** [[#h-97a67f51-b0b7-49c7-be42-83a026b58043][Emacs lisp]] :PROPERTIES: :CUSTOM_ID: h-97a67f51-b0b7-49c7-be42-83a026b58043 :END: Emacs lisp is the first lisp I've used for more than 10 seconds, because you're forced to if you want to configure emacs. Having used it for a few years within emacs now, the expressive nature of lisp has grown on me to the extent it shapes how I program in most other languages (possibly in danger of being a [[http://wiki.c2.com/?SmugLispWeenie][smug lisp weenie]]). The semantic nature of lisp means you can always reshape things to get a better view of the problem you are trying to solve, and macros allow you to do so cheaply. ** [[#h-525c8289-7b42-4e7c-a08f-101994ca8066][Fun things I've done with emacs]] :PROPERTIES: :CUSTOM_ID: h-525c8289-7b42-4e7c-a08f-101994ca8066 :END: *** [[#h-fadca8cd-9f0e-404d-a820-a892afd4dc7c][Shell stuff]] :PROPERTIES: :CUSTOM_ID: h-fadca8cd-9f0e-404d-a820-a892afd4dc7c :END: **** [[#h-c641f262-63ae-40c1-847b-f32801e1b447][=shell-mode= as my terminal, with a staged shell buffer]] :PROPERTIES: :CUSTOM_ID: h-c641f262-63ae-40c1-847b-f32801e1b447 :END: When I first start emacs, I create an 'on-deck' staged shell buffer with an interactive shell. Then when I 'spawn a terminal', what I'm actually doing is: - making a new emacs frame - picking up the staged shell buffer and renaming it - staging the next shell buffer for a future pickup This means there is no startup time or delay on the part of the shell for me to get going. It also means I can pickup the staged shell from other contexts, like =dired= (spawn a shell in the current directory from the existing staged buffer). **** [[#h-c158a52f-4538-4a23-a7a5-1c4e714d7e19][Shell $CWD history]] :PROPERTIES: :CUSTOM_ID: h-c158a52f-4538-4a23-a7a5-1c4e714d7e19 :END: Everytime my prompt prints, it prints a key string for emacs shell to pickup, setting the current directory of the emacs shell buffer sync'd from the bash shell. These values are tracked in a persisent list, so that I can jump to any folder location I've ever been using ivy. Sorting order keeps frequently picked folders near the top with the help of [[https://github.com/raxod502/prescient.el][ivy-prescient]]. **** [[#h-b176dd54-5955-4d01-8ad3-7e8a1ec8a21f][Scripts and functions]] :PROPERTIES: :CUSTOM_ID: h-b176dd54-5955-4d01-8ad3-7e8a1ec8a21f :END: An =elisp= script that obfuscates the details of connecting to the running emacs server to interact with it, allowing me to peek at emacs state or do things in emacs from a script or shell: #+begin_src sh $ elisp '(message "hello from the shell")' #+end_src A function =shellshot= that lets me take a 'text screenshot' of the current shell window contents for pastebins or sharing output: #+begin_src text $ uname -a Linux bridge 4.19.86 #1-NixOS SMP Sun Nov 24 07:21:09 UTC 2019 x86_64 GNU/Linux $ ps PID TTY TIME CMD 7217 pts/19 00:00:00 bash 7538 pts/19 00:00:00 ps $ emacs --version GNU Emacs 26.3 Copyright (C) 2019 Free Software Foundation, Inc. GNU Emacs comes with ABSOLUTELY NO WARRANTY. You may redistribute copies of GNU Emacs under the terms of the GNU General Public License. For more information about these matters, see the file named COPYING. $ shellshot #+end_src A script =fzf= that intercepts [[https://github.com/junegunn/fzf][fzf]] calls and redirects them to be emacs ivy-read calls #+begin_src text $ echo $ESHELL true $ mpc listall | fzf import/Vapor Memory/Windows彡96 - Gradient Horizont.opus #+end_src *** [[#h-a90f40d3-9b7a-4072-ba55-79706612e385][Org pomodoro status]] :PROPERTIES: :CUSTOM_ID: h-a90f40d3-9b7a-4072-ba55-79706612e385 :END: Org mode is a markup format deeply integrated into emacs (the elisp code is the reference implementation). It's what I'm writing the post in. At it's core, org-mode is about headings and metadata around headings. I have a bind to toggle an 'active' heading, and with org-pomodoro I can toggle commands to signal pomodoro breaks, or query the current state in a script for my panel: #+begin_src text $ org_task Write 'On Emacs' ■■■□□□□□□□ #+end_src *** [[#h-b7164713-2ccc-4516-88b3-e9e9d0cc5280][Contextual inline eval for lisps]] :PROPERTIES: :CUSTOM_ID: h-b7164713-2ccc-4516-88b3-e9e9d0cc5280 :END: I have a lisp eval function that will have different targets in different situations. When on an empty line, it will eval the last s expression. When on a not-empty line, it will eval the top s expression. And if there is anything highlighted, it will eval the region. This means I have just one eval keybind to mash. And with [[https://github.com/xiongtx/eros][eros]] I get sexy inline eval results!: {{{image(eros.png)}}} *** [[#h-47ae41c2-5ecb-442f-b142-2e8c8cb05f0e][IRC + highlight buffer]] :PROPERTIES: :CUSTOM_ID: h-47ae41c2-5ecb-442f-b142-2e8c8cb05f0e :END: I created a derived text mode for irc highlights that allows me to jump to mentions. {{{image(circe.png)}}} *** [[#h-91a68a46-e5fc-485f-a1cb-f6464acec9fd][Meta file switcher]] :PROPERTIES: :CUSTOM_ID: h-91a68a46-e5fc-485f-a1cb-f6464acec9fd :END: I created a 'goto file' function that combines: - recent files - files in current project (or optionally files in all open projects) - open files And then I just have to fuzzy type to get to a matching file. *** [[#h-67f8078e-b949-4c42-a763-169d8f0e05a7][Meta GOTO thing]] :PROPERTIES: :CUSTOM_ID: h-67f8078e-b949-4c42-a763-169d8f0e05a7 :END: I have a function that will follow 'thing' at point, handling: - urls - filepaths (relative or absolute, and jump to line number) - definitions for various languages (see [[https://github.com/jojojames/smart-jump][smart jump]]) ** [[#h-068ed8fe-fa21-43df-96e4-1360d1684886][Other]] :PROPERTIES: :CUSTOM_ID: h-068ed8fe-fa21-43df-96e4-1360d1684886 :END: https://nixers.net/showthread.php?tid=2216&pid=19558#pid19558