Remix.run Logo
▲ jwr 7 hours ago

I have been using Emacs for more than 30 years now. Other editors have come and gone, Emacs stayed. Parts of my configuration are more than 30 years old.

There were better and worse times in Emacs history. Recent times, however, are really good. Emacs is maintained and developed actively and there are many external packages which are impressive. Magit and ghostel are good examples of packages that I use on a daily basis to get my work done.

Recently, AI completely changed how I use Emacs, and in a very good way. I now treat AI as a fairy that can fulfill any wish. I describe how I want my editor to work, and boom! it works that way.

Examples: window and tab management, difftastic integration, markdown previews with beautifully rendered tables, markdown previews as PDFs, and many more.

What is most important, however, goes back to Stallman's original ideas. I am in control of my editor and my environment. I decide how it will look and behave. No corporation decides for me. No corporation builds in a new AI assistant. Nobody introduces ads or tracking. This is something I've learned to appreciate over the years.

▲TFNA 6 hours ago | parent | next [-]

On one hand, AI boosts Emacs development. On the other hand, as an Emacs user of 30 years, I have always felt that the number of people who deeply grasp Emacs Lisp and Emacs' internals is really small against the population of people merely using Emacs and lightly hacking their own setup, and I worry AI is not going to encourage any growth in that small elite that seems kinda important for Emacs' long-term future.

▲cyrialize 5 hours ago | parent | next [-]

This is a good point, but I do want to mention that I feel like in the past 5 years we've had lots of extremely popular packages that hook into Emacs internals instead of rolling out their own architecture.

For example, corfu [0] versus company [1]. Company works with capf, but you can also write your own backends for it (specific to company). Corfu also works with capf, but all backends are capf functions instead of a corfu specific backend.

Another good example is eglot [2] versus lsp-mode [3]. Eglot is actually packaged with Emacs now.

There's also other stuff, like vertico [4] (and others that are recommended to download) versus helm/ivy.

I also want to mention that packages that hook into Emacs more don't necessarily mean that they're better. From my POV it's more like you get a lot more things for free and the documentation you dive into will be Emacs specific instead of package specific. It all comes down to preference.

Vertico/Counsel/Orderless is very nice, but Helm and Ivy are fully featured (I always forget how much Helm has for you).

I use corfu, eglot, and vertico now. I have thought about going back to helm and company, especially since I was very familiar with company's backends for a long time.

[0]: https://github.com/minad/corfu

[1]: https://github.com/company-mode/company-mode

[2]: https://github.com/joaotavora/eglot

[3]: https://github.com/emacs-lsp/lsp-mode

[4]: https://github.com/minad/vertico

▲seanw444 3 hours ago | parent [-]

I was using Helm, lsp-mode, yasnippet, and the like for a long time. I switched to Eglot/Corfu/Vertico/Tempel. I much prefer the new wave.

▲bluGill 6 hours ago | parent | prev | next [-]

> the population of people merely using Emacs and lightly hacking their own setup

This is a good thing. Custom environments should be either minimal or upstream. Anybody should be able to sit down next to you and help you hack out a change. The more unusual/custom your environment is the less productive that is, and this more than balances out any possible gain you can make from custom setups. (don't forget to account for your cost to learn elisp and then make the changes!)

Somebody needs to make the correct setups. However most of us have better things to do.

▲TFNA 6 hours ago | parent [-]

I'm not advocating for making all (or even most) users spend so much time on internals that they don't get productivity gains. Rather, I'm concerned about maintaining, ensuring generational turnover, and healthily boosting the elite that the product depends on. It is no secret that a number of Emacs ecosystem core devs are middle-aged, and so the project is a few heart attacks or whatever away from losing the experience and competence that has sustained it so well.

▲skydhash 6 hours ago | parent [-]

Most of emacs is lisp. The actual C part is quite small considering the capabilities of the system. Lisp being what it is, it’s moslty about domain knowledge than language expertise.

▲jupitr 5 hours ago | parent [-]

I feel the lisp constructed on top needs significant language expertise. Lispy constructs of defvar, defconst, defcustom, alist, cl-loop etc. are quite extensively used in emacs - and need an understanding quite unique to Lisp. Of course, the domain then builds on top of this shared understanding of the contructs themselves.

I would say that loss of expertise in emacs-lisp is a significant loss, even if there continues to exist C-expertise globally.

▲skydhash 4 hours ago | parent [-]

There's a wealth of packages and the documentation for emacs-lisp is quite extensive. It's not some esoteric language. But what I'm talking about is that the code for the packages can be quite simple and readable.

▲iLemming 41 minutes ago | parent | prev | next [-]

> AI is not going to encourage any growth in that small elite

In practice we're seeing the biggest waves of development in years. r/emacs gets daily, daily! announcements of new packages. Many of them, if not most, are not some AI-sloped trash - they are very useful. Some package makers go above and beyond - even though vibe-coded, they still show good design decisions, proper tests, hand-written documentation. Canvas stuff most likely wouldn't be possible without LLMs.

▲torben-friis 6 hours ago | parent | prev | next [-]

>and I worry AI is not going to encourage any growth in that small elite

I wouldn't dismiss the help of lower friction of entry. Lots of recent Linux and neovim users due to how easy it is to debug an issue or edit a config now.

The larger the regular userbase, the more chances people gradually go deeper into the system.

▲hirvi74 6 hours ago | parent | prev [-]

I think that is part of the beauty of Emacs -- it is what one makes of it.

▲gpderetta 5 hours ago | parent | prev | next [-]

It is is unreal how I can ask claude, from within emacs, to implement an extension for me on the fly, inject it into the running process, have it observe the results, and quickly iterate to a working solution.

Claude, the ultimate REPL.

▲tetraodonpuffer 5 hours ago | parent [-]

I am also a member of the 30+ year emacs club (with a detour to jetbrains some years back due to java) and it has been crazy how good claude is at implementing/debugging emacs extensions, I have it set up so it has emacs in its container and it is able to basically use it headless to debug whatever.

Saying "I want my editor to do X" and have it happen basically realtime on an editor I fully control is incredible. I have written elisp in the past, but it's definitely one of my weakest languages, so being able to leverage claude to do this is great.

▲LoganDark 4 hours ago | parent [-]

Curious, is elisp particularly good at that (editing a process while it's running)? I've never experienced a system like that before, so I'm curious.

▲a_e_k 3 minutes ago | parent | next [-]

If you've read Pratchett's Discworld, I like to think of Emacs as an Igor: it's a loyal servant that can swap out, share its own parts, and rebuild itself on the fly.

But to answer your question, It's not just elisp itself, but rather that Emacs is basically a live elisp interpreter process with an editor UI on top, and the design is something of a ball-of-mud with few boundaries.

With typical systems you have plugins and they have fairly narrow interfaces. If you want to do something that's not covered by the plugin API, you're pretty much out of luck.

With Emacs, everything is open as a free-for-all to extend or redefine, so you can monkey-patch pretty much anything. Here's an example from my init.el:

    (define-key global-map [remap move-beginning-of-line] 'move-beginning-of-line-dwim)
    (defun move-beginning-of-line-dwim ()
      "Cycles between the beginning of text on the line, the actual
    beginning of the line, and the beginning of the body of a comment
    on the line.  If not in one of those three places, it starts at
    the beginning of the text.  Basically, it's a smarter HOME
    command."
      (interactive "^")
      (comment-normalize-vars t)
      (unless (and (bolp) (comment-search-forward (pos-eol) t))
        (let ((cur (point)))
          (beginning-of-line-text)
          (if (= cur (point))
              (beginning-of-line)))))
By default, the HOME key and Ctrl-a are bound to the `move-beginning-of-line` (defined in `simple.el`, one of the elisp source files that comprises vanilla Emacs). That `define-key` with the `remap` tells Emacs that everywhere in the global keymap that it sees the default `move-beginning-of-line`, it should replace it with my custom `move-beginning-of-line-dwim`.

Alternatively, I could have just done `(defun move-beginning-of-line ...)` and simply redefined `move-beginning-of-line` wholesale and it would probably have worked fine. But this is a little cleaner, IMO. Either way, now when I hit HOME key it cycles between column 0, the first non-whitespace character, and the first character in the body of a trailing comment.

On top of that, I don't need to have a formal plugin or anything. I can take the above code, paste it into an elisp buffer somewhere, put the cursor somewhere in or after the `(defun ...), hit Ctrl-x Ctrl-e and now that function is defined within Emacs (and callable by other functions). Same thing with the `(define-key ...)`: put the cursor on it, Ctrl-x Ctrl-e, and the binding is updated. No ceremony.

And for testing, I can edit the function freely, hit Ctrl-x Ctrl-e and now my edited version is the live one in the running Emacs process. It's a lot like a scripting language REPL except within the editor UI.

And in addition, Ctrl-h Ctrl-f tells you about any function that Emacs knows, defaulting to whatever function name the cursor is on. So if I put the cursor on `move-beginning-of-line-dwim` and hit Ctrl-h Ctrl-f RETURN, I get:

    <home> runs the command move-beginning-of-line-dwim (found in global-map),
    which is an interactive interpreted-function.

    It is bound to C-a and <home>.

    (move-beginning-of-line-dwim)

    Cycles between the beginning of text on the line, the actual
    beginning of the line, and the beginning of the body of a comment
    on the line.  If not in one of those three places, it starts at
    the beginning of the text.  Basically, it’s a smarter HOME
    command.

    [back]
Same thing for Ctrl-h Ctrl-v for variables and settings. The documentation that it shows is generated directly from the doc strings and live editor state. Ctrl-h Ctrl-k will prompt for a key and show me a key binding, so Ctrl-h Ctrl-k HOME will give me the above documentation now too. Ctrl-h Ctrl-b shows all applicable keybindings, etc.

Now I'd mentioned that you can monkey-patch anything. In practice that could cause chaos if you don't take care. A pretty common idiom in Emacs to do this more cooperatively are "hooks". These are just variables that some package, internal or external, defines to hold a list of functions to callback. The package iterates the list and calls them whenever the given event happens and you can add or remove your own function to the list to get that call. Think signals and slots, if you seen that design before. And these are pretty ubiquitous. As an example from my init.el:

    (add-hook 'font-lock-mode-hook 'font-lock-mode-setup)
    (defun font-lock-mode-setup ()
      "Make fixme tags standout."
      (unless (derived-mode-p 'special-mode)                      ; Don't break list-{faces,colors}-display
        (font-lock-add-keywords nil
         '(("\\<\\(?:AEK\\|NOTE\\|FIXME\\|TODO\\|XXX\\)\\>\\(?:([a-z]+)\\)?:?" 0 'font-lock-warning-face prepend)))))
So whenever syntax highlighting is started up in a buffer, it calls the font-lock-mode-hook callbacks, and that runs my code to register a regexp to highlight my initials and other fixme tags.

And if all that's not enough, Emacs also has an "advice" system which lets you register code to run before, after, around, etc., any existing function. (And then later unregister it if you wish.) There's also a built-in elisp debugger to break into a function and step through it.

So basically, the key I'd say is that there's no real privileged code in Emacs. You can redefine pretty much anything to taste, and do so without even having to reload Emacs. The downside is that it's up to you to decide what to trust. It's on you to avoid breaking it, and you probably want to be choosy about the packages you run.

▲Karrot_Kream 25 minutes ago | parent | prev | next [-]

Elisp is homoiconic and has a strong culture of REPL development, but really the thing that makes elisp so nice is that it has decades of use to iterate on an editor. There's an attempt to do this with Common Lisp that's quite cool, called Lem, but the sheer amount of person-years that have gone into making emacs and elisp a conjoined system makes it a pleasure to use and iterate on. Lem, in comparison, is building up all the UX associated with a "live programming environment" that just comes out of the box with elisp (though I, personally, prefer Common Lisp as a language/environment.)

Pre-LLM I used to spend the occasional afternoon at work when I was a bit demotivated just adding new features to my emacs or fixing small papercuts in the environment. Now I largely have the LLM work on it for me, though I separate out LLM code from my own by loading them separately in my config.

▲iLemming 2 hours ago | parent | prev | next [-]

Any Lisp is good at editing live process, you just need to give it a REPL. Because of homoiconic nature of Lisp, every step in Read-Eval-Print-Loop differs. Lispers sometimes refer to Lisp REPL as the "true REPL", because non-homoiconic REPLs are rather "interactive shells" in comparison.

Clojurescripters for example can use nbb with the connected REPL and build web-scrapers while interactively "clicking" on buttons and exploring DOM directly from the editor.

In case of Emacs, it is not [just] an editor, technically it is a Lisp REPL loop with a built-in text editor. That's why you can virtually change any aspect of it on the fly, without ever having to restart it.

What's crazy that this allows to have pretty much anything "programmable". Even keyboard macros in Emacs are just series of Lisp instructions. You can compose a macro and then look at its underlying code, modify it and execute it.

▲drob518 20 minutes ago | parent | prev | next [-]

I do this everyday with Emacs live editing a Clojure process.

▲jerf 4 hours ago | parent | prev | next [-]

There are a number of environments and languages that have the capability to reload things extensively at runtime. elisp is mostly nice because it is polished, but it isn't necessarily the "best". Erlang has a claim on being better at it, probably. And while most scripting languages are capable of it, that doesn't mean you can just drop one in and go necessarily. It helps to have an environment where that sort of interactivity is first-class and in constant use and testing, which is where the polish comes from.

▲fmbb 4 hours ago | parent [-]

Erlang the runtime sure. But Emacs is an application with these properties. There is no editor like Emacs for Erlang (some small clones I am sure) and no other user application utilizing this feature.

Smalltalk is a development environment and an applications platform. The development tools are as extensible and user customizable as Emacs. And like Erlang it is also a runtime you can package software for. Any GUI or server software. For Emacs you can probably do the same, but I’m not convince many users would find the GUI familiar.

▲knome 4 hours ago | parent | prev | next [-]

you can replace or wrap arbitrary functions or update values freely in emacs. most of the editor is written in elisp. only the primitives are in c.

you can write (arbitrary (lisp)) and then just put the cursor after the end parenthesis and hit `Ctrl-x Ctrl-e` to evaluate it. It works just like you had typed out something in a python repl, only you can inspect, add, or update anything inside of your running copy of emacs.

As an example, I've had a chunk in my ~/.emacs for 15+ years that rewrites a few builtin functions to prefix all of the backup files emacs makes with a `.` because I don't like to see them in `ls` listings but still want them local to where they were made should I want to diff them against the current version. (the default is just a ~ suffix, and there's a common directory relocation many people use to pile them all in a backups directory somewhere)

As another, I wanted to be able to punch a button and drop the current datetime into a file, for files where I keep records and the like, so I added this:

    (defun my-date-insert ()
      (interactive)
      (insert (substring (shell-command-to-string "date") 0 -1 ))
      )
    
    (global-set-key [f9] 'my-date-insert)
Albeit, you needn't shell out to get a date in emacs, I dropped in in their years ago on a whim and just used what I knew at that time to toss it together.
▲a_e_k an hour ago | parent [-]

`(insert (format-time-string "%c"))` should do the trick, though you might need to change the format string to taste.

▲tetraodonpuffer 4 hours ago | parent | prev [-]

well if you're in emacs you can C-x C-e evaluate whatever, and if you eval an edited version of whatever function emacs is calling, it just works as emacs calls the thing by symbol name; conceptually it's basically your editor is an elisp repl, so everything can be changed at any time (in general, things like defvar you'd need to setq and so on)

▲zavec 4 hours ago | parent | prev | next [-]

I've been getting into emacs somewhat recently and really enjoying it so far, though I do worry a bit about how much it can do and whether it will lead to any sort of "oops, you opened a project that had a thing that autoexecs or exploits a parser and now you're pwned". I know that's not a unique problem to emacs, but it feels like the enormous amount of things emacs can do gives it a bigger attack surface for that (and I don't know my way around it well enough yet to be confident that I've looked at all the places that might happen)

Maybe the solution is that I should just be running the entire thing in a sandbox in any case.

▲_doctor_love 4 hours ago | parent | prev | next [-]

I am too young to be in the 30 year club but Emacs has served me well for more than a decade. I don't use it as a daily driver anymore but it holds a special place in my heart.

Using magit made me believe again that really good software can exist and that there are really great designers still among us.

Also super agree that Stallman's original ideas are only ever more increasingly valid. I will generously say that Stallman has been an imperfect messenger but the core message has always been solid. I have not regretted my FSF membership over the years.

▲taf2 5 hours ago | parent | prev [-]

[flagged]