# Emacs and Julia: how to

**URL:** <https://discourse.julialang.org/t/emacs-and-julia-how-to/123623>\
**Category:** Tooling\
**Tags:** emacs\
**Created:** [December 9, 2024, 3:05pm UTC](https://discourse.julialang.org/t/emacs-and-julia-how-to/123623 "2024-12-09T15:05:54Z")\
**Posts on this page:** 20\
**Page:** 3

<div class="post-metadata">

**Author:** ![g-gundam](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/g-gundam/32/47593_2.png) [@g-gundam](https://discourse.julialang.org/u/g-gundam)\
**Post date:** [January 13, 2025, 4:26pm UTC](https://discourse.julialang.org/t/emacs-and-julia-how-to/123623/41 "2025-01-13T16:26:22Z")

</div>

- [GitHub - ffevotte/isend-mode.el: Interactively send parts of an Emacs buffer to an interpreter](https://github.com/ffevotte/isend-mode.el)

That’s really nice. I’m glad you took the time to come up with a generalized and language-agnostic solution to this. I had no idea this existed.

---

<div class="post-metadata">

**Author:** ![ryofurue](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ryofurue/32/24531_2.png) [@ryofurue](https://discourse.julialang.org/u/ryofurue)\
**Post date:** [July 12, 2025, 5:53am UTC](https://discourse.julialang.org/t/emacs-and-julia-how-to/123623/42 "2025-07-12T05:53:42Z")

</div>

Could somebody care to show their lisp code for `init.el` ?

Currently, I just copied a set of lisp lines from a blog post of somebody (`julia-mode` + `eglot-jl` + `julia-repl`). It’s working okay but I’m not getting completion (or perhaps I don’t know how to invoke completion? Isn’t it just Tab?). I want to see the API of the library function I’m calling.

By the way, I keep hearing about `vterm` but for a long time the emacs package manager has failed to compile the `vterm` binary (written in C++?) on my Macs and so I’ve given it up for some time. Does somebody know what’s wrong? (When this problem first hit me, I did some search on the Net but didn’t find a solution.)

---

<div class="post-metadata">

**Author:** ![linwaytin](https://avatars.discourse-cdn.com/v4/letter/l/898d66/32.png) [@linwaytin](https://discourse.julialang.org/u/linwaytin)\
**Post date:** [July 12, 2025, 10:35pm UTC](https://discourse.julialang.org/t/emacs-and-julia-how-to/123623/43 "2025-07-12T22:35:44Z")

</div>

Do you get any completion from `eglot`, like function names in the same file?

---

<div class="post-metadata">

**Author:** ![ryofurue](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ryofurue/32/24531_2.png) [@ryofurue](https://discourse.julialang.org/u/ryofurue)\
**Post date:** [July 13, 2025, 5:14pm UTC](https://discourse.julialang.org/t/emacs-and-julia-how-to/123623/44 "2025-07-13T17:14:26Z")

</div>

Yes, not only functions in the same file but also standard library functions.

At least I see a list of candidates by pressing the Tab key. Unlike with the “normal” completion (e.g., zsh), though, I don’t know how to select from the list.

In any case, I realize “completion” may have been a misnomer. What I meant was: When you have typed the name of a library function and the opening parenthesis, its API (potential argument list) would show up.

. . . Maybe such a feature isn’t available in the emacs environment.

---

<div class="post-metadata">

**Author:** ![ffevotte](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ffevotte/32/6587_2.png) [@ffevotte](https://discourse.julialang.org/u/ffevotte)\
**Post date:** [July 13, 2025, 6:44pm UTC](https://discourse.julialang.org/t/emacs-and-julia-how-to/123623/45 "2025-07-13T18:44:42Z")

</div>

Since the config file of long time emacs users tends to end up being a few thousand lines of elisp setting up interdependent packages, I find it difficult enough to isolate what’s relevant for a specific topic (like Julia here).

Nevertheless, here is a (very) minimalistic snippet which sets up `julia-mode`, `eglot-jl` and completion with `company`. I personally don’t use `julia-repl`.

```elisp
(use-package julia-mode
  :ensure t
  :config
  (add-hook 'julia-mode-hook 'eglot-jl-init)
  (add-hook 'julia-mode-hook 'eglot-ensure))

(use-package eglot-jl
  :ensure t
  :config
  (setq eglot-sync-connect 1
        eglot-connect-timeout 120))

(use-package company
  :ensure t
  :config
  (global-company-mode 1))

```

> **The same snippet, in standalone form**
>
> Here is the same snippet, put as [testable, standalone init.el](https://gonewest818.github.io/2020/03/a-standalone-init.el-for-emacs-package-debugging/)
> 
> ```elisp
> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> ;; copy this file somewhere, then test it with:
> ;; emacs -q -l /path/to/your/copy/of/this/init.el
> 
> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> ;; set user-emacs-directory to the directory where this file lives
> ;; do not read or write anything in $HOME/.emacs.d
> 
> (setq user-init-file (or load-file-name (buffer-file-name)))
> (setq user-emacs-directory (file-name-directory user-init-file))
> 
> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> ;; set custom-file to write into a separate place
> 
> (setq custom-file (concat user-emacs-directory ".custom.el"))
> (when (file-readable-p custom-file) (load custom-file))
> 
> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> ;; configure melpa (and other repos if needed)
> 
> (require 'package)
> (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
> (setq package-enable-at-startup nil)
> (package-initialize)
> (when (not package-archive-contents)
> (package-refresh-contents))
> 
> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> ;; install and configure packages
> 
> (use-package julia-mode
> :ensure t
> :config
> (add-hook 'julia-mode-hook 'eglot-jl-init)
> (add-hook 'julia-mode-hook 'eglot-ensure))
> 
> (use-package eglot-jl
> :ensure t
> :config
> (setq eglot-sync-connect 1
> eglot-connect-timeout 120))
> 
> (use-package company
> :ensure t
> :config
> (global-company-mode 1))
> 
> ```

Even with such a bare-bones setup, a lot of features work out of the box. The screenshots below are taken while editing the main source file of Example.jl

**Completion** (in the sense of completing function/variable name). Note that available completions appear as you type, you don’t have to press TAB or anything.

 ![Screenshot from 2025-07-13 20-24-24](https://global.discourse-cdn.com/julialang/original/3X/9/1/91bb35928a7bb7456fd5ddf168b0a98f9cf16eef.png)

**Documentation** of function arguments (what you refer to as “API completion” IIUC). Again, no need to press anything, the doc appears automatically in the echo area.

 ![Screenshot from 2025-07-13 20-24-44](https://global.discourse-cdn.com/julialang/original/3X/2/4/245b1be7755e01afbfad495a57c3f4f3e1153a47.png)

**LSP diagnostics** for errors, unused variables, etc. These also appear automatically in the echo area. You can also hover over a squiggly line to see the message.

 ![Screenshot from 2025-07-13 20-25-22](https://global.discourse-cdn.com/julialang/original/3X/6/8/682f09e353c7eca9194060796b6926a5e8332e0f.png)

---

<div class="post-metadata">

**Author:** ![linwaytin](https://avatars.discourse-cdn.com/v4/letter/l/898d66/32.png) [@linwaytin](https://discourse.julialang.org/u/linwaytin)\
**Post date:** [July 13, 2025, 7:02pm UTC](https://discourse.julialang.org/t/emacs-and-julia-how-to/123623/46 "2025-07-13T19:02:09Z")

</div>

For names defined in libraries, as far as I know, you need to set up a julia pacakge. You can read the first paragraph in Eglot-jl.

If you only have a single script file, LSP does not work automatically with the included libraries. This is my impression.

Since you are using Emacs, I suggest you also check `julia-snail`.

---

<div class="post-metadata">

**Author:** ![George9000](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/george9000/32/23619_2.png) [@George9000](https://discourse.julialang.org/u/George9000)\
**Post date:** [July 13, 2025, 7:06pm UTC](https://discourse.julialang.org/t/emacs-and-julia-how-to/123623/47 "2025-07-13T19:06:56Z")

</div>

I use [doom emacs](https://github.com/doomemacs/doomemacs) with emacs-mac-app installed via MacPorts, one of the choices listed in the doom emacs [macos install docs](https://github.com/doomemacs/doomemacs/blob/master/docs/getting_started.org#with-macports).

`sudo port install emacs-mac-app-devel +metal +nativecomp +rsvg +treesitter +imagemagick`

I also use MacPorts to install vterm, which is needed by doom emacs. I’m sure you could do the same with Homebrew.

`sudo port install libvterm`

Here are portions of my [doom `init.el`](https://gist.github.com/George9000/dedc56fc9667f64c04e56fcf955bbd2d) and [`config.el`](https://gist.github.com/George9000/7c2b99945e74b492df5832e86eb1c6b4), which should be placed in `~/.config/doom/`

Then install doom according to directions at its github site.

After the install completes (note: give time on first launch for it to compile all initial functions), quit, run `doom sync.`

Relaunch, run `M-x vterm.` Reply yes to question about compiling vterm. Then `M-x treesit-install-language-grammar` and choose julia, an option already in the `config.el` gist above.

The quit, doom sync, relaunch.

When you now open a Julia file, `SPC-c-d` for Jump to definition and `SPC-c-k` for Jump to documentation are both usesful. Docs appear in split window below Julia file. Signature of functions also appear in echo area.

---

<div class="post-metadata">

**Author:** ![ryofurue](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ryofurue/32/24531_2.png) [@ryofurue](https://discourse.julialang.org/u/ryofurue)\
**Post date:** [July 15, 2025, 6:49am UTC](https://discourse.julialang.org/t/emacs-and-julia-how-to/123623/48 "2025-07-15T06:49:13Z")

</div>

Thank you all for your inputs. I’ve just copied @ffevotte’s settings and started to use it.

It’s working well, but I have a lot of things to figure out, like what’s the shortcut to send the buffer to a Julia REPL, how to display the docstring of the function I’m calling, how to jump to the line that caused error in the REPL, how to vertically scroll in the REPL buffer (C-p goes back in the history, not moves cursor upward) . . . off the top of my head right now.

By the way, are “simpler” function signatures available from emacs? The “correct” function signatures are unreadable, such as `findfirst(::Base.#iszero, a::Union{Base.CodeUnits,Core.Array,Core.Array, . . . `.

For most library functions, “unofficial” signatures like

```julia
findfirst(array)
findfirst(predicate, array)

```

would be best for use on the IDE.

Anyway, I’ll report back as I get familiar with this workflow in due course.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [July 15, 2025, 7:02am UTC](https://discourse.julialang.org/t/emacs-and-julia-how-to/123623/49 "2025-07-15T07:02:52Z")

</div>

> [@ryofurue](#):
>
> what’s the shortcut to send the buffer to a Julia REPL, how to display the docstring of the function I’m calling, how to jump to the line that caused error in the REPL

Note that these are all solved by `julia-repl` and `julia-snail`. Unless you have a strong reason to roll your own solution, I would recommend either of those. (Disclaimer: I am the main author of `julia-repl`.)

---

<div class="post-metadata">

**Author:** ![ryofurue](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ryofurue/32/24531_2.png) [@ryofurue](https://discourse.julialang.org/u/ryofurue)\
**Post date:** [July 15, 2025, 8:22am UTC](https://discourse.julialang.org/t/emacs-and-julia-how-to/123623/50 "2025-07-15T08:22:09Z")

</div>

> [@Tamas\_Papp](#):
>
> > [@ryofurue](#):
> >
> > what’s the shortcut to send the buffer to a Julia REPL, how to display the docstring of the function I’m calling, how to jump to the line that caused error in the REPL
> 
> Note that these are all solved by `julia-repl` and `julia-snail`.

Thanks for the info. Can you elaborate? Interaction with REPL seems to be already implemented even when `julia-repl` isn’t used.

Initially I started out with @ffevotte’s setting:

```julia
(use-package julia-mode
  :ensure t
  :config
  (add-hook 'julia-mode-hook 'eglot-jl-init)
  (add-hook 'julia-mode-hook 'eglot-ensure)
  )

(use-package eglot-jl
  :ensure t
  :config
  (setq eglot-sync-connect 1
        eglot-connect-timeout 120))

(use-package company
  :ensure t
  :config
  (global-company-mode 1))

```

Then, `julia-repl-send-buffer` already does that (invoke the REPL and send the buffer to it).

When I added,

```julia
(use-package julia-repl
  :ensure t
)

```

but I didn’t know what change this new package brought about. Perhaps is `julia-repl` included in `julia-mode`?

> [@Tamas\_Papp](#):
>
> Unless you have a strong reason to roll your own solution, I would recommend either of those.

Of course. In addition, I don’t have the skill even if I have a strong reason.

Currently, I even don’t know whether I have a reason to deviate from what `julia-repl` offers or not, because I don’t know what works and what doesn’t. I’m in the process of figuring these out.

By the way, I was surprised by the `company` mode. It works not only in Julia source code, but also in English text. So, I’ve moved it to the main part of my `init.el` out of my computer-language-specific sections.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [July 15, 2025, 8:32am UTC](https://discourse.julialang.org/t/emacs-and-julia-how-to/123623/51 "2025-07-15T08:32:28Z")

</div>

> [@ryofurue](#):
>
> Perhaps is `julia-repl` included in `julia-mode`?

There was a repl implementation in earlier `julia-mode` versions, but my guess would be that you are somehow loading `julia-repl`.

> [@ryofurue](#):
>
> I don’t know what works and what doesn’t. I’m in the process of figuring these out

The [usage](https://github.com/tpapp/julia-repl/?tab=readme-ov-file#usage) section in the readme should be a good starting point.

---

<div class="post-metadata">

**Author:** ![csvance](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/csvance/32/218927_2.png) [@csvance](https://discourse.julialang.org/u/csvance)\
**Post date:** [November 29, 2025, 12:33am UTC](https://discourse.julialang.org/t/emacs-and-julia-how-to/123623/52 "2025-11-29T00:33:12Z")

</div>

Both julia-repl and julia-snail are excellent options, I tried them both. Make sure you use vterm or otherwise many emacs key combinations wont be registered inside of the REPL. Each one works with remote development, julia-repl over SSH and julia-snail via Tramp. In the end I ended up building ontop of snail since it handles plotting. I’m actually starting to send plot buffers off to an external application that is written in Julia so I can toggle between images, zoom, scroll etc with decent performance. Much better than what is possible with elisp. I need this working in the area of medical image analysis.

I don’t find LSP to be that useful in Julia as things stand currently, even for the most basic of tasks. Too many false positives and crashes. Maybe when JETLS is production ready it will be worth using an option to go the LSP route, but as it stands now you are better off using Claude Code for many of the things LSP can provide. Claude Code has amazing support in emacs via claude-code and monet.

---

<div class="post-metadata">

**Author:** ![csvance](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/csvance/32/218927_2.png) [@csvance](https://discourse.julialang.org/u/csvance)\
**Post date:** [November 30, 2025, 3:53pm UTC](https://discourse.julialang.org/t/emacs-and-julia-how-to/123623/53 "2025-11-30T15:53:10Z")

</div>

Going to have to eat my words about LSP not being useful 😅

 ![image](https://global.discourse-cdn.com/julialang/original/3X/b/8/b89a030e2670fbf4d9d9ade063cc6d8fdcbb9d95.png)

If you want to use [ReLint.jl](https://github.com/RelationalAI-oss/ReLint.jl) in emacs as a minimal linting only LSP server, full instructions are here: [Neovim editor configuration · Issue #65 · RelationalAI-oss/ReLint.jl · GitHub](https://github.com/RelationalAI-oss/ReLint.jl/issues/65#issuecomment-3592708535)

In my limited testing it works quite well and doesn’t slow things down. Thanks to the ReLint.jl devs for the package and engon for the the LSP server. Hopefully all of this stuff will move to registered packages in the near future.

Here is the recent talk from JuliaCon about [ReLint.jl](https://github.com/RelationalAI-oss/ReLint.jl) if anyone is interested: [https://www.youtube.com/watch?v=H69bGbT0ZNQ](https://www.youtube.com/watch?v=H69bGbT0ZNQ)

---

<div class="post-metadata">

**Author:** ![indymnv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/indymnv/32/212594_2.png) [@indymnv](https://discourse.julialang.org/u/indymnv)\
**Post date:** [January 27, 2026, 4:15am UTC](https://discourse.julialang.org/t/emacs-and-julia-how-to/123623/54 "2026-01-27T04:15:24Z")

</div>

The easiest one for me to use has been Julia-snail, I would like a Common Lisp Slime like experience for Julia in Emacs, so this package offer you something like that, the only problem that I see, is that you need to use Vterm or Eat, which is fine if you are not working  
on Windows, but It would be nice to have a tool that rely on Emacs internals only.

---

<div class="post-metadata">

**Author:** ![mahmah](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mahmah/32/214326_2.png) [@mahmah](https://discourse.julialang.org/u/mahmah)\
**Post date:** [August 3, 2026, 6:00am UTC](https://discourse.julialang.org/t/emacs-and-julia-how-to/123623/55 "2026-08-03T06:00:52Z")

</div>

I think this is a related issue (I opened a topic but didn’t get replies); how do you make emacs and julia coexist given that we want julia to persist and emacs may need to be restarted every now and then? Do you use tmux + vterm or is there anything better?

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [August 26, 2026, 12:06pm UTC](https://discourse.julialang.org/t/emacs-and-julia-how-to/123623/56 "2026-08-26T12:06:02Z")

</div>

> [@mahmah](#):
>
> how do you make emacs and julia coexist given that we want julia to persist and emacs may need to be restarted every now and then?

I restart Julia much more often (multiple times a day) than Emacs (once every month or so).

Anyhow, I visited this topic to share what I learned about `subword-mode`. It is built into Emacs, and makes `CamelCaseVariables` much easier to navigate and edit, `capitalize-word`, `right-word`, etc just work as they should.

---

<div class="post-metadata">

**Author:** ![mahmah](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mahmah/32/214326_2.png) [@mahmah](https://discourse.julialang.org/u/mahmah)\
**Post date:** [August 26, 2026, 1:36pm UTC](https://discourse.julialang.org/t/emacs-and-julia-how-to/123623/57 "2026-08-26T13:36:22Z")

</div>

Sounds very cool! Regarding my question, after setting the default org-agenda view to today, things feel much faster and I don’t feel the need to restart emacs all the time. I also got rid of auto completion, I think it was collecting too much information and adding further delay. Do you use Julia-snail btw?

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [August 26, 2026, 1:37pm UTC](https://discourse.julialang.org/t/emacs-and-julia-how-to/123623/58 "2026-08-26T13:37:20Z")

</div>

No, I use julia-repl (I am its maintainer).

---

<div class="post-metadata">

**Author:** ![mahmah](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mahmah/32/214326_2.png) [@mahmah](https://discourse.julialang.org/u/mahmah)\
**Post date:** [August 26, 2026, 1:58pm UTC](https://discourse.julialang.org/t/emacs-and-julia-how-to/123623/59 "2026-08-26T13:58:39Z")

</div>

Apologies! I think I saw you contributing to both, hence the confusion 🙂

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [August 26, 2026, 2:09pm UTC](https://discourse.julialang.org/t/emacs-and-julia-how-to/123623/60 "2026-08-26T14:09:54Z")

</div>

No worries! `julia-snail` is a fine tool, especially if you like SLIME/CIDER and want to have the introspection tools tightly integrated with Emacs.

[Previous page](https://discourse.julialang.org/t/emacs-and-julia-how-to/123623.md?page=2)

[Next page](https://discourse.julialang.org/t/emacs-and-julia-how-to/123623.md?page=4)
