Package for writing Elisp code as Doom Emacs Evil User

I am using Doom Emacs for almost 6 months. During my usage I have realized I must know elisp to be more productive and not just copy paste code but be able to edit code myself.
However writing elisp is wierd, dealing with parenthesis is a nightmare.
I know there are packages eg. smartparen , lispy, paredit that allow you to write but I am confused which one would work with doom emacs with evil mode.

I would appreciate , if any EVIL doom user can share their experience.

I wonder where was that ban button. Don’t they have it here on Discourse?

1 Like

Maybe I choose the wrong words and should not have written it but the intention was not to bash about elisp or be disrespectful.
It is that have never written elisp and that I don’t have dev setup which makes writing elisp easier.
I have gone through web to find relevant tutorial for EVIL or doom emacs but they seems overly complex.

This forum has been very supportive in term of helping beginners and I though people might guide me.
Again my apologies it offended anyone in the forum.

I don’t use Evil so I don’t see the intricacies of the issues you may be experiencing in coding Elisp. I started coding Elisp only about a year ago, but it might be OK for me to say I’m intermediate after producing my packages like these: org-transclusion, org-marginalia, and md-roam.

If this background could give you any useful idea, here is what I do. It’s minimal but for me enough and effective. I don’t think I would need any more at this stage – I believe these are mostly built-in functions.

(show-paren-mode 1)
(electric-pair-mode 1)

I then just use:

  • emacs-lisp-mode in coding
  • edebug to review how code behaves in runtime and for debugging.
  • help documentation for functions and variables (C-h f and C-h v)
  • in-system documentation with C-h i (then go to Elisp docuementation)
  • M-. (xref-find-definitions) to jump to the definition of functions and variables,
  • M-, (xref-pop-marker-stack) to go back where I jumped from
  • Aligning parentheses is not a problem – indentation and messages in minibuffer help me a lot.
  • flycheck-mode: I use it sparingly (not always on) to list warning and errors with C-! l (flycheck-list-errors) – EDIT: not built-in

My naive sense is that you can easily translate and adapt parts of this to Evil (vim keybindings) as you see fit.

You can totally ignore what I am saying as I’m no Evil user.

EDIT: Forgot to mention Company mode. For in-line (in-buffer) completion — a kind of Emacs “intellisense”. It’s a MELPA package

1 Like

I’d suggest heading over to the Doom Emacs discord for questions about Doom. Doom has a lot of stuff going on and it can be a bit hard for people that are unfamiliar with it to help you properly. I personally use lispy and love it. There is a lispy module in Doom so you can just uncomment that and run doom sync and test it out. You can read the docs for the doom module with SPC h d m lispy and for lispy at There are many keybindings but those I recommend starting with are [,],<,>.

Re: parenthesis, lisp doesn’t really have more parenthesis than other languages, it’s just that it uses () where many others use {}.

Your apologies accepted, thank you.

I will just repeat what @Zetagon wrote. Enable the lispy module under the :editor section in your init.el and make sure that the default evil, emacs-lisp, syntax and electric modules are enabled too and you are done. These modules configure several packages that help in editing Elisp and other Lisp files:

  • smartparens package is enabled in Doom core and cannot be disabled. You may want to make sure that the default +smartparens flag is set on the default module in the :config section - it adds a few additional perks. The smartparens package helps to deal with all kinds of parentheses, including but not limited to () {} [] "" '', in any mode.
  • evil module enables Evil keybindings. You don’t need an Evil tutorial to get started. If you have some experience with Vi/Vim, you’ll find yourself at home. If you don’t have such experience, take better the Vim tutorial, it’s good.
  • Not surprisingly, Emacs has a good support for Elisp out of the box. Doom’s emacs-lisp module additionally configures several helpful packages:
    • elisp-def for jumping to symbol definitions;
    • elisp-demo that adds code demos to many common functions when you look them up with C-h f (or Doom’s SPC h f); remember, C-h f and C-h v are your best friends to learn Elisp;
    • highlight-quoted adds additional syntax highlighting;
    • macrostep allows for easy inline macro expansions;
    • a few others for Elisp testing toolkits, you’ll probably won’t need them right away, but they are there;
  • syntax module configures the built-in flycheck package to check your code, including Elisp, for errors.
  • electric module configures the built-in electric package for automatic indentation when you rearrange your code.
  • lispy module enables the lispy package, which makes it easy to navigate through “nightmarish” s-expressions and quickly rearrange them.
    • If you have evil enabled, lispy will additionally configure the lispyville package that adds Evil keybindings to lispy.

Basically, Doom in its default setup is already a very well configured Elisp IDE, much enhanced over the default Emacs. You don’t need any external packages such as paredit, which is anyway covered by smartparens. The only other good thing, which is shipped with Doom but is not enabled by default, is lispy.

Unfortunately, there is no easy way to learn things. To learn something, you must invest efforts in learning and practicing it. If it seems “overly complex” then question yourself whether you are really interested in learning it.


Now you have expert advice directly relevant for Doom and Evil from @Zetagon and @mshevchuk , I might throw in my key but very basic learnings from writing in Elisp. They are very elementary and you could laugh at me saying they were key for me :slight_smile:

I’m OK to be laughed at for this. Just for what it’s worth.

  1. Elisp functions do not have return (!).
    Elisp functions automatically return the value of the last expression evaluated. It took me very long to learn this. I think I found a clear statement in the Elisp documentation, after which everything became much easier.

That has been the single most important haha :sweat_smile: . My lessions learned 2 and 3 below are much less important.

  1. Indent defun correctly.
    edebug seems to care about the column number where defun starts; if it’s not in the first column, edebug-defun behaves unexpectedly

  2. Think function, not object and method
    (unless you specifically want to code Elisp in an object-oriented way with EIEIO). I am no professional developer, and it’s probably Day 1 of Computer Science 101. But personally for me, it helps me write cleaner code * if I diligently force myself to think about “what I want my code to do” in terms of:

  • input (args): What input values does the function need to produce the output I want?
  • process (function): What does function need to do to produce the output values I want?
  • output (returned values): What output values do I want? – if I don’t want any particular output values, what computer “side-effect” do I want?

*: I define “clean code” as “code I can easily write a docstring for, to tell my future-self an easy explanation of what this code does and why this code exists”. If I struggle to write a helpful docstring, think again.


This is a very good point about writing Elisp. I often start designing a new function by writing its docstring first. If I can clearly describe in human language what the function does, then the Elisp implementation is often trivial.

1 Like

Thank you @mshevchuk @Zetagon for your advice on doom emacs and @nobiot for sharing you experience and great advice on writing “clean code”.

You suggestion are really helpful. I got a lot to learn.
Especially, I didn’t knew there are xref-find-definitions and xref-find-references.
with Spc h v and Spc h f, I think any documentation I need, I would rarely have to go to browser to lookup on it.

Yesterday night, I tried again to configure the elisp modules. Finally got a working setup.
I used symex github which is on based lispy, paredit and evil-parens in contrast of lispyville whose readme I found difficult to follow.

It is the first time I have been introduced to concept Structured editing and how lisp code is inherently a tree, then editing code just becomes modifying tree.
Again every language has a parse tree, but lisp is more explicit due its use parenthesis and therefore easier to manipulate directly in code. To me, it also explains why people say it is easier to write in lisp.


Surprisingly true :slight_smile:

1 Like

Yeah, this is so true. Structured editing is really nice!

Lispyville feels a bit out of place to me. lispy brings another mode, “lisp mode” if you will, and then normal mode is more for textual editing which makes for a nice clean distinction.


Welcome on board! In fact, Lisp code is a “parse tree”. Further reading: defmacro - The Nature of Lisp.

1 Like

This is true and easy to forget. Let the investments begin!

1 Like

Apologies for the double post. I accidentally deleted my previous one.

In brief, @mschevchuk’s post on learning elisp in doom emacs is a goldmine for a learner such as me (one year in). Would make a very useful pinned post or a sticky. Not sure for this forum but somewhere. Perhaps over at the doom discourse once it’s up and running.

Anyway, I do appreciate the guidance.

@kohlworks, thank you. Unfortunately, it’s not exhaustive and may not be very accurate. For instance, it looks like smartparens, paredit and lispy share common functionality for editing s-expressions. I don’t have experience with paredit and with a glance on its documentation I’d now say it’s more comparable to lispy because they both target Lisp editing. Also, the symex package mentioned by @jio32 currently uses paredit as a backend. The smartparens package, although it does provide some functionality for Lisp editing, has a more general goal of balancing any kind of paired delimiters in any mode. This is perhaps the reason why smartparens is built into Doom’s core, while lispy is made available for those wanting a very fine specialized support for Lisps.

I would also caution against blindly installing external packages such as paredit or symex that share common functionality with Doom’s built-in packages (really any package, not just those for editing parentheses), unless one is able and ready to go into hassle of debugging if somethings goes wrong. In my opinion, it’s better to start with what is available - it’s been made available for a particular reason by people who are arguable more experienced - and only look for alternatives after one has learned what they need and what they lack. While I personally a year ago initially didn’t agree with a few of the Doom’s choices, I’ve now learned to live with them and can’t really remember now what was that that bothered me. It just isn’t worth to invest my personal time into the things that other people have already invested in enough of their time.


I could have saved a ton of time had I followed such counsel to refrain from filling up packages.el with functionality redundant to what’s built into doom. Equally, doom’s maintainer is quite transparent about why he makes the decisions he makes regarding what packages to include or not. I don’t have enough experience to make anything approaching an informed counter-argument, so why not just trust that some very smart people have already figured this out and learn from them? A lesson that extends far beyond the current context.

I also had a palm-to-forehead moment when I read programmers (actual programmers, unlike me) doom configs and saw how few external packages they added. I was working waaay harder than necessary.

A recent case in point. As I’m learning clojure, instead of reading all over the interwebs about to set up a clojure IDE, I just enabled the :lang clojure module, jacked into a repl, and got to work on the main task at hand which is… learning clojure. Doom makes that so wonderfully convenient.

All in all an excellent learning experience. I now have perhaps six external packages total and three of them are related to screenwriting (my job).

Okay, enough of my rambling. Thanks again for your valuable contributions.


I tried using lispy yesterday, without reading the docs, and I got so frustrated trying to type things in lisp code and having something totally unexpected happen that I had to disable it for now. Next time, I will read the docs you linked to before trying again :slight_smile:

Aha. Now I get the Doom Emacs one-liner that lispy is “vim for lisp, for people who don’t like vim”