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.
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.)
Do you get any completion from eglot
, like function names in the same file?
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.
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
.
(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
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 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.
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.
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.
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
.
I use doom emacs with emacs-mac-app installed via MacPorts, one of the choices listed in the doom emacs macos install docs.
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
and config.el
, 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.
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
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.
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
.)
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:
(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,
(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
?

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.

Perhaps is
julia-repl
included injulia-mode
?
There was a repl implementation in earlier julia-mode
versions, but my guess would be that you are somehow loading julia-repl
.

I don’t know what works and what doesn’t. I’m in the process of figuring these out
The usage section in the readme should be a good starting point.