My Helix-editor + Julia + LaTeX setup
I have been using the Helix editor for the last year. I really like this "post-modern", modal editor. It sure is a bit of a change after decades of Emacs but as the dude says "to keep my mind, you know, uh, limber". One of the promises of Helix is that it needs very little configuration and works mostly just out of the box. Whilst my config is certainly lots smaller than the one of Emacs, I sure spent some time to get everything running as I like.
My install is Arch Linux with the following packages:
- Helix editor
- Wez's Terminal Emulator
- Vale language server for spell checking
Julia setup
When I work on a Julia script I like to have a Julia REPL open into which I can evaluate parts of the open script (line, regions, function definitions). Depending on your workflow that may not be necessary, but for me it sure is. Here a session with an example from the WhereTheWaterFlows.jl package using KittyTerminalImages.jl:

First things first though: the setup of the language server and code formatter which lives in ~/.config/helix/languages.toml
:
[[language]] name = "julia" language-servers = ["julia-lsp", "vale"] # Install LanguageServer.jl with # julia --project=@lsp --startup-file=no -e 'using Pkg; Pkg.add("LanguageServer")'i # update with # julia --project=@lsp --startup-file=no -e 'using Pkg; Pkg.update()' [language-server.julia-lsp] command = "julia" timeout = 60 args = [ "--startup-file=no", "--history-file=no", "--quiet", "--project=@lsp", "-e", "using LanguageServer; runserver()", ] # Formatting # https://github.com/domluna/JuliaFormatter.jl/issues/868 # install JuliaFormatter.jl with # julia --project=@juliaformatter --startup-file=no -e 'using Pkg; Pkg.add("JuliaFormatter")' # update with # julia --project=@juliaformatter --startup-file=no -e 'using Pkg; Pkg.update()' [language.formatter] args = [ "--startup-file=no", "--history-file=no", "--project=@juliaformatter", "--quiet", "-e", "using JuliaFormatter; print(format_text(read(stdin, String); Dict{Symbol,Any}(Symbol(k) => v for (k, v) in JuliaFormatter.find_config_file(realpath(\".\")))...))" ] timeout = 60 command = "julia"
Of note is that:
- the language server should just work, see the Helix manual for details on how to make use of it.
- to format the buffer run
:fmt
- I install the LanguageServer.jl and the JuliaFormatter.jl into their own environments. See the comments in above code-snippet on how to do that. Note that to call to them also requires specifying their environment, e.g.,
"project=@lsp"
. - the LanguageServer takes some time to start up (and shut down too). In particular the first time.
- to check the outputs and errors of the LanguageServer, look at
~/.cache/helix/helix.log
. - the JuliaFormatter call took a bit of finicking to make sure the configuration in the
.JuliaFormatter.toml
gets read, thus it is a bit longer. - more advanced setups are possible, for instance here Julia-system image creation is described which would allow for a faster startup of the LanguageServer.jl.
Next, the setup to evaluate code from Julia scripts in a REPL. This is setup is in ~/.config/helix/config.toml
:
[keys.normal] ## REPL interaction stuff # - start repl (note that a terminal pane can be started by hand too. As long as it is on the pane on the right) "A-s" = ":noop %sh{helix-repl-start.sh %{buffer_name}}" # - execute line and move cursor to next line A-ret = ["extend_to_line_bounds", ":pipe-to xargs -0 wezterm cli send-text --pane-id $(wezterm cli get-pane-direction right)", "move_visual_line_down", "goto_line_start"] # - execute line and keep cursor location "A-\\" = "@<C-s><A-ret><C-o>" # exectue function A-f = "@<C-s>maf<A-ret><C-o>" # exectue paragraph (block of code without spaces) A-P = "@<C-s>map<A-ret><C-o>" # execute file (Julia only) A-I = [":write", ":sh wezterm cli send-text --no-paste --pane-id $(wezterm cli get-pane-direction right) \"include(\\\"%{buffer_name}\\\")\n\""] [keys.select] # execute selection A-ret = [":pipe-to xargs -0 wezterm cli send-text --pane-id $(wezterm cli get-pane-direction right)", ":sh wezterm cli send-text --no-paste --pane-id $(wezterm cli get-pane-direction right) \"\n\""]
Thus this defines the following key bindings:
- Alt+s to start a REPL in a new pane on the right
- Alt+enter to execute the current line or selection and move the cursor to the next line (multi-cursors do not work)
- Alt+\ to execute the line without moving the cursor
- Alt+f to execute the current function
- Alt+P to execute the current paragraph, i.e. the section of code surrounded by the next blank lines
- Alt+I to execute (include) the whole script (Julia only)
All commands but the last one work on other buffers than Julia-scripts too. In particular Python and Matlab REPLs are also started automatically, alternatively just a terminal is opened.
The bash scrip executed on Alt+s to start the REPL in a new pane on the right is (put it on your $PATH
):
#!/bin/bash # # Script to start a terminal (and maybe a REPL within) in a pane to the right. Needs wezterm. # Looks at the file extention of the passed in ARG and starts Julia, Python or Matlab if it # is a file of that type, otherwise just a terminal. filename="$1" shift # Remove filename from args list # Extract the file extension extension="${filename##*.}" # Convert extension to lowercase for comparison extension=$(echo "$extension" | tr '[:upper:]' '[:lower:]') # Launch appropriate interpreter based on extension case "$extension" in "jl") echo "Starting Julia..." wezterm cli split-pane --right bash -i -c "julia --project; exec bash" ;; "py") echo "Starting Python..." wezterm cli split-pane --right bash -i -c "ipython; exec bash" ;; "m") echo "Starting MATLAB..." wezterm cli split-pane --right bash -i -c "matlab -nosplash -nodesktop; exec bash" ;; *) echo "Starting shell" wezterm cli split-pane --right ;; esac
Thus this will start, depending on the current file, a Julia, Python or Matlab REPL, or otherwise just a terminal.
I'm pretty happy with this setup which mirrors my previous setup on Emacs quite closely. Albeit, I haven't written tons of code with it yet… I really should write more code.
Soon, a plugin system for Helix will land which presumably would pave the way for much more fancy integrations. But this is definitely 90% there already.
LaTeX setup
With LaTeX, I want to have:
- easy and fast compilation
- forward and inverse search between editor and PDF
Additionally install the following Arch packages (or equivalent):
- texlab language server
- tectonic LaTeX engine which automatically runs latex, bibtex, etc. until a document is fully compiled
- Zathura pdf viewer
This setup then compiles the tex-document on save, opens the pdf viewer (if needed) and highlights the current line in the pdf. Here the section of the ~/.config/helix/languages.toml
which defines the LaTeX setup:
## LaTex # # If the document viewer does not show, then something is amiss. Try manual compile: # tectonic -X compile --synctex --keep-logs --keep-intermediates --outdir=build your.tex [[language]] name = "latex" soft-wrap.enable = true language-servers = ["texlab", "vale"] # https://github.com/helix-editor/helix/issues/340#issuecomment-1167200354 [language-server.texlab.config.texlab.chktex] onOpenAndSave = true onEdit = true # Zathura as viewer # see also settings in ~/.config/zathura/zathurarc [language-server.texlab.config.texlab.forwardSearch] executable = "zathura" args = [ "--synctex-forward", "%l:1:%f", "%p" ] # https://github.com/latex-lsp/texlab/wiki/Tectonic [language-server.texlab.config.texlab.build] forwardSearchAfter = true onSave = true # Tectonic auxDirectory = "build" logDirectory = "build" pdfDirectory = "build" executable = "helix-tectonic.sh" args = [ "%f" ]
with the helix-tectonic.sh
shell-script (on your $PATH
):
#!/bin/sh # # Run tectonic to compile LaTeX. Intended for use in Helix. # Creates a build/ directory if needed. mkdir -p build tectonic -X compile --synctex --keep-logs --keep-intermediates --outdir=build --only-cached $1