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
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.
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.
I would say that loss of expertise in emacs-lisp is a significant loss, even if there continues to exist C-expertise globally.
Warning (files): Missing ‘lexical-binding’ cookie in "~/.emacs.d/custom.el". You can add one with ‘M-x elisp-enable-lexical-binding RET’. See ‘(elisp)Selecting Lisp Dialect’ and ‘(elisp)Converting to Lexical Binding’ for more information.
I am still trying to figure out what to do! The manual is quite verbose and I haven't had the patience to go through it yet.
M-x elisp-enable-lexical-binding RET
It will add a cookie (lexical-binding) to the top of the file. If you want to do it manually put this: ;; -*- lexical-binding: nil; -*-
or this: ;; -*- lexical-binding: t; -*-
at the top of your custom.el file. They want it to be explicit now because eventually lexical will be the default. If you put in the former then when lexical becomes the default, the file will still use the current dynamic bindings. And if you use the latter, if there are issues you'll discover them now before the default changes and you're surprised by it.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.
Claude, the ultimate REPL.
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.
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.
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.
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.
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.
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.I use agent-shell and I love the ecosystem that's being created there:
https://github.com/xenodium/agent-shell
And for claude interacting back with emacs:
Some folks like having an MCP package. I agree that gives you a bit more control. But I live dangerously and run emacs in daemon mode and tell claude to just run emacsclient to execute elisp as needed. It works amazingly well. Claude has full visibility into my editor and together we can pretty much do anything.
In fact, I increasingly think of emacs as just a live lisp machine. It's a surface that I and the agents can interact against. It acts as a document store, database, control surface, etc.
Maybe the solution is that I should just be running the entire thing in a sandbox in any case.
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.