Emacs-based workflow

emacs

#1

I’m trying to set-up an (efficient) Emacs-based workflow to develop Julia code (on a linux system).

Currently, here is what I’m using:

  • I have a live Julia REPL in an ansi-term buffer, which uses Revise to update the Julia code as I edit source files. I’m currently using my own isend-mode package to interact with this buffer and evaluate Julia code blocks, but am thinking of trying @Tamas_Papp’s julia-repl instead1.

  • In order to search for something in the documentation, I use zeal and zeal-at-point. But I don’t like spawning an external process (and window), especially when most of this documentation (and more) is available from Julia itself in a form that could easily be browsed within Emacs (but I haven’t found any readily-available tool to do this).

  • In order to search for and (jump to) function definitions, I’m using InteractiveCodeSearch.jl. Again, I’d like to streamline the process of looking for the definition of the function at point (which I don’t think would be too difficult; I might try to develop a package to do it if I get around to it…)

Some of the points bothering me might very well be fixed by LanguageServer and lsp-mode, but I haven’t been able to successfully set these up yet. I had difficulties installing LanguageServer, and then had some trouble with lsp-julia2. In your opinion, is it worth to invest some time to make it work?


On another note, one thing I lack is the ability to quickly run tests. In most other languages (like C++ or Python), I would set up compilation commands to build and/or test my program, and bind them to a single key so that I can speed-up development cycles. In Julia, I use the same technique to run thorough tests (as in julia -O3 --project runtests.jl), but long startup times prevent me from running these too often. Most of the time, I simply go to the REPL and hit upRET. But I don’t like this process very much, since it sometimes interferes with other experiments I made in the REPL (and e.g. the last command is not what I thought it would be).


Have I blatantly missed anything? Do you (Emacs users) have entirely different workflows? Are you facing some of the same issues?



1 in particular, julia-repl's use of bracketed paste might solve some quirks I have with isend-mode when sending indented blocks.

2 I tried to use @gdkrmr’s fork of lsp-julia (which seemed to be the most up-to-date) and had strange Emacs errors. At first sight, it looked like these might be due to incompatibilities between recent lsp-mode versions and my outdated Emacs-25; I’ll have to investigate.


#2

I’ve been using this interface to jupyter for my Julia REPL for the past several months, and it’s been lovely. There’s actually some julia-specific code in the repo to make Julia’s REPL a bit more friendly rather than just a generic jupyter prompt like provided by e.g. ob-ipython.

I hope to update my fork some time in the coming few weeks and then maybe even publish to Melpa; just fyi.

Startup times for just Julia have gotten pretty darn fast. It’s re-precompiling the package that probably takes all the time. But this would be no different than running ] test in the REPL, so if you find that sufficient other than messing up your REPL session, binding running tests with the Julia binary to a key shouldn’t be any worse (as long as it’s an async command).


#3

Thanks, I’ll definitely try this!

Yes, sorry if I was unclear. I do run extensive tests (like the full test suite) from a M-x (re)compile command, and it is as fast to run them this way (with a fresh julia process) as from ] test. And I usually don’t care about how long it takes Julia to re-compile the necessary modules, since the tests themselves are long and there is potentially many of them.

What I meant is that when I’m working on a single function (o small part of the code), I like having a small test case to see whether I’m improving things or not (and at that time, I’m not necessarily interested in knowing whether I broke something else, which is what the full test suite is useful for). This “small test” is usually a single expression like

@btime myfun($testArg)

and I like to be able to run it right away (for now, in a “hot” REPL, relying on Revise to ensure that an up-to-date version of the code is run).

One thing I have in mind would be to have an “interactive” REPL open in a terminal where I can interact at will, and another REPL in a hidden/buried terminal buffer for “automated” interactions. I would not type directly in that second terminal, but would rather have small commands (bound to readily accessible keys) to send some pre-defined expression to the REPL. But that sounds an awful lot like I would then be re-inventing a poor-man’s LSP :confused:


#4

I also get error messages in the *Message* buffer, but they are not fatal, you can see a discussion here

I am using spacemacs with the julia-layer and everything works pretty well. There are currently some issues:

  • There was no LanguageServer.jl release for Julia 1.0. Solved with release v0.5.0.
  • There are breaking changes in the last release of lsp-mode and you have to figure out which version to use.
  • The julia-layer is not yet updated to work with the new version of lsp-mode, see the link above.

With julia-repl you can just do C-c C-d (or K in spacemacs) on a symbol and the repl will print the documentation.

This would be a nice addition, ESS has a shortcut for this. If I am working on a single test, most of the times it is sufficient to run that test(-set) interactively until it works and then run the entire suite just to check.

+1


#5

Thanks, I’ll try this.


I’ve never used ESS; I’ll have to look at what it does exactly. But would you find it useful if I submitted a PR to julia-repl, so that a user-specified command could be sent to the REPL in one key press?


#6

julia-repl is probably the best place for this. I would ask @Tamas_Papp about this.

You would probably do something like here to locate the project folder.


#7

I use ctags/etags for this. Works pretty well.


#8

I just use emacs with julia-mode and some terminals for REPL and running test scripts. I like this zeal thing, though. That’s great!


#9

Thanks, I did not know one could index julia files using ctags. I wonder if you index only Julia itself (and maybe the installed packages), or also your own code (in order to navigate within your sources as you’re developing them). In the latter case, do you have any way to automatically update the index as your sources evolve?


#10

I only have it setup for Julia 0.6 at the moment. In .emacs I have:

;; CTAGS ETAGS
; https://www.emacswiki.org/emacs/EtagsTable
(require 'etags-table)
(setq etags-table-alist
      '(
        (".*\\.jl$" "~/julia/julia-0.6/TAGS"  "~/.julia/v0.6/TAGS")
        ))
(setq tags-case-fold-search nil) ; case sensitive search

then I bulild the tags with:

~ >> cat julia/julia-0.6/build-ctags.sh 
#!/bin/sh
ctags -R -e --options=contrib/ctags --languages=julia --totals=yes base
~ >> cat .julia/v0.6/build-ctags.sh  
#!/bin/sh
ctags -R -e --options=/home/mauro/julia/julia-0.6/contrib/ctags --totals=yes --exclude=.* --exclude=.git --languages=julia

.i.e. I build a ctags file for julia-base and the installed packages (which also include (most of) my personal package/code).

Navigation is pretty nice with M-. jumping to a function def and M-, back. If there are several methods, they will show in a window to select (which is ok for a few methods but not so useful when there are 10+)

For Julia 1.0, the julia-0.6/contrib/ctags file has been moved to https://github.com/JuliaEditorSupport/julia-ctags.


#11

julia-repl is a quick & dirty effort to take advantage of ansi terminal features in Julia. I hope that code introspection (docstrings, function argument lookup) will improve as LanguageServer interfaces stabilize, which is why I am not making a huge effort to develop a parallel solution, as that would imply a fundamental redesign. In the meantime, C-c C-d is a stopgap (in particular, it won’t use module names, eg Foo.bar will look up Main.bar, that is a bug).

For quickly running something without interrupting your main work, consider using a buffer suffix (C-c C-s). This will send code to another *julia-suffix* buffer. You can use different versions, too (C-c C-v).

I look at LanguageServer from time to time, but found it not ready the last time I did that (about 3 months ago). If someone things it is ready for regular use and there is anything I can do on the julia-repl side to make it easier, please let me know. I know some open issues have been around for a long time, but I always try to fix them if I get a break from other things.