RFC: Action for jumping to the REPL

39 views
Skip to first unread message

Colin Fleming

unread,
Jan 31, 2017, 2:35:18 AM1/31/17
to cur...@googlegroups.com
Hi everyone,

One thing that gets requested a lot is the ability to jump to the REPL with a keystroke. There’s a workaround for this described here: You can assign a toolwindow number to the REPL toolwindow, say Ctrl-9, or Cmd-9 on the Mac. Most of the existing toolwindows have equivalent numbers assigned to them. This number will be displayed on the toolwindow button. You can then use this key to jump to the toolwindow, and ESC to jump back. In IntelliJ, ESC always jumps back to the editor from any tool window.

This has some issues - if the REPL pane is already open and selected when you try to jump to it, it will be closed instead. I’m considering adding an explicit action to do this and make it reliable, i.e. open the REPL pane if it’s closed and select it, and do nothing if you’re already there. 

Some users have also requested the ability to have the caret active in the output pane and to be able to switch there with a key, so they can copy and paste without using the mouse. I’ve enabled the caret, but I’m not sure how the keybindings should work. I can think of a couple of obvious options:

1. A single action which cycles around all 3 (editor, REPL, output).
2. Actions which cycle Editor<->REPL, REPL<->Output, and perhaps Output<->Editor.
3. Absolute actions (Jump to last Editor, Jump to REPL, Jump to Output).

Presumably jumping to and from the REPL is much more common than jumping to the output pane, so that would suggest that #2 or #3 would be preferable. For #3, ESC currently works for jumping back to the editor but that may change - currently IntelliJ’s UI rule that ESC in tool windows should always jump back to the main editor is very difficult for IdeaVim users, since ESC no longer works for switching modes in the REPL. I’m considering patching IdeaVim such that Cursive could override the ESC behaviour for the REPL editor, and in that case an explicit “Jump back to Editor” action would be required.

Opinions?

Thanks,
Colin

Camille Troillard

unread,
Jan 31, 2017, 2:35:53 AM1/31/17
to cur...@googlegroups.com
Hi Colin,

I really appreciate the proposal for switching between the REPL and the Editor, I missed that.

Now, about being able to control the carte in the output pane. My advice: look at existing Lisp IDEs. Emacs, LispWorks, AllegroCL, DrRacket… no REPL has this dichotomy between input and output: both inputs and outputs are in the same buffer.


Best,
Cam

Colin Fleming

unread,
Jan 31, 2017, 2:36:28 AM1/31/17
to cur...@googlegroups.com
Hi Camille,

Thanks for the feedback.

The issue is that in IntelliJ, the editors are strongly typed. So in order to get all the functionality in the REPL editor, it is created as a Clojure editor. The problem with combining the two panes is that the REPL output is not valid Clojure code, so it would have a lot of warnings and general complaining that the contents are not valid code. 

Cheers,
Colin

Camille Troillard

unread,
Jan 31, 2017, 2:37:03 AM1/31/17
to cur...@googlegroups.com
On Apr 30, 2016, at 12:45 PM, Colin Fleming <cur...@cursive-ide.com> wrote:

The issue is that in IntelliJ, the editors are strongly typed. So in order to get all the functionality in the REPL editor, it is created as a Clojure editor. The problem with combining the two panes is that the REPL output is not valid Clojure code, so it would have a lot of warnings and general complaining that the contents are not valid code. 

I see… thanks for the details.

Personnaly, I would really prefer one keystroke to cycle through the code editor and the REPL editor. Cycle through the code editor, the REPL input and the REPL output is not IHMO the most efficient use-case.

For the REPL output, I feel that being able to copy the last evaluation result to the clipboard would be sufficient for a start. Then, maybe a solution to unify both buffers will become available. It seems less risky than implementing required functionality to control the caret in the output buffer.

James Elliott

unread,
Jan 31, 2017, 2:37:44 AM1/31/17
to cur...@googlegroups.com
Whoops, this bounced because when I sent it last night it went out from the wrong email address. And now Colin has already replied with information that is more definitive and useful, but I thought I would weigh in anyway.

On Apr 30, 2016, at 03:05, Camille Troillard <c...@wildora.com> wrote:
> Now, about being able to control the carte in the output pane. My advice: look at existing Lisp IDEs. Emacs, LispWorks, AllegroCL, DrRacket… no REPL has this dichotomy between input and output: both inputs and outputs are in the same buffer.

Hmm, that seems to me to be a historical legacy from the days of serial-line terminals when there was no such thing as multiple actual windows. I love CIDER and Emacs and spend most of my Clojure time in there, but the way that input and output end up in the same buffer *often* leads to messes and bad state from which it is difficult to recover, especially if output is happening at a rapid pace and preventing you from entering and evaluating a form that would make the madness stop. The fact that Cursive lives in a modern, GUI IDE environment and can avoid that problem is one of its advantages, in my opinion.

-James

signature.asc

Vincent Pizzo

unread,
Jan 31, 2017, 2:38:20 AM1/31/17
to cur...@googlegroups.com
Just my two cents. I currently have a custom keybinding to show the REPL as many do. As noted by others, if the output window previously had focus, pressing esc to go to the editor and going back to the REPL keeps focus on the output window rather than the REPL console. I would love the following:

1) A custom shortcut option to copy the last command’s output to your clipboard. I feel that this is something quite common that people would like to do.
2) I would have a shortcut to navigate directly to the REPL console (and not close the REPL toolbar if it is already open)
3) I would have a shortcut to navigate to the REPL output (and not close the REPL toolbar if it is already open)

I would like to note that #3 would only really be useful if you could navigate the output without a mouse (for text selection and whatnot). I realize there are probably challenges with this, but I find it cumbersome that I’m forced to use the mouse in the REPL output window (and currently copy is broken :) ).

Vince

Bill Kennedy

unread,
Jan 31, 2017, 2:38:56 AM1/31/17
to cur...@googlegroups.com


For me the most attractive combination is a key to switch Editor<->REPL and a key to copy the last command output.

Usually if I’m doing something more complicated in the output window it involves using Find and then copying with the mouse, so a key to switch Editor<->Output is not as interesting.

Thanks, Colin!

Timothy Pratley

unread,
Jan 31, 2017, 2:39:44 AM1/31/17
to cur...@googlegroups.com
Hi Colin,


As a data point, I use CMD+3 and it works for my purposes. When I do
want to use the Cursive REPL, I find the send to REPL and sync
functions preferable to typing in the REPL box.

I understand that REPL switching sounds nice, but I want to make a
case for reload integration being more valuable than REPL (or at least
worthy of equal consideration).

There are three mature code reload workflows in Clojure:
* Figwheel
* Ring reload middleware
* Test-refresh

They all watch files and reload code. The trigger for code evaluation
is when we save a file, which is usually the right punctuation point
in our workflow. Saving files works with any editor with no special
plugins or keystrokes. The model is easy to understand and think
about.

I love tmux, emacs, and vim... but when it comes to REPL integration,
things get pretty complicated. It feels productive to have key combos
to execute code, run tests, switch buffers, splice in results and all
sorts of great stuff. However I end up spending a lot of time
switching window focus, sending code to the REPL, finding tests to
run, forgetting to eval my function or file, and generally being busy
interacting with the REPL. I make many mistakes, and blame myself for
not being able to keep it all straight in my head.

In contrast, when I use a reload workflow with any editor, life is
simple. There is my code and there is the log of what happens when it
reloads. From this simplicity flows productivity because I can focus
on my code. My primary brain function is thinking about the program,
not managing my REPL. REPL integration destroys programming flow. The
more awesome keystrokes you add to give ultimate power to the
programmer end up burdening me with having to spend more time thinking
about keystrokes instead of programming. My code lives in multiple
places and I need to keep track of what is loaded where.

Cursive is especially good to me because it can detect errors without
REPL integration.

But, Cursive could be even more awesome to me if the output of those
refresh processes could be actioned directly in Cursive.

What should reload integration look like in Cursive?

When something goes wrong, I'd like to be directed to the source of
the problem with minimal ceremony. Right now that ceremony consists of
me reading a stack trace and opening the file and line number.

If I sync a file in the REPL using ctrl-shift-p it gives me a lovely
href link that I can click on to go directly to the source of any
compilation error. I love that. But I don't love having to remember to
sync my code.

If I start test-refresh from inside a Cursive REPL, it loads the
changes but does not link me to the code:


(use 'com.jakemccrary.test-refresh)
=> nil
(monitor-project ["test" "src"] {})
*************** Running tests ***************
Passed all tests
*************** Running tests ***************
:reloading (pirates.server.ticker-tests)
:error-while-loading pirates.server.ticker-tests

Error refreshing environment: java.lang.ClassCastException:
java.lang.String cannot be cast to java.lang.Number,
compiling:(pirates/server/ticker_tests.clj:29:1)


As you can see, the output shows exactly where the problem is, but I
can't click on it.

If I start test-refresh from a terminal inside Intellij:


tim:pirates timothypratley$ lein test-refresh
*************** Running tests ***************
FAIL in (foo) (ticker_tests.clj:57)

expected: ((fn test-it [x] (not (and (+ 1 2) (+ 3 4) (or (= 1 2) (= 1 1))))) {})
actual: (not true)

Ran 3 tests containing 3 assertions.
1 failures, 0 errors.

Failed 1 of 3 assertions
Finished at 16:40:33.499 (run time: 6.708s)

Error refreshing environment: java.lang.ClassCastException:
java.lang.String cannot be cast to java.lang.Number,
compiling:(pirates/server/ticker_tests.clj:29:1)


Again I can see where tests are failing or where compilation fails,
but I can't navigate there.

What I would like is instead for figwheel/ring-reload/test-reload all
to be able to notify Cursive about problems (test-refresh is the most
valuable out of the 3 if I have to choose). The problems that they
notify me about are all very regular: A filename and a line number. So
I think a generic interface would be straight forward. Perhaps there
doesn't even need to be an interface at all if Cursive can just parse
the text output.

As for what Cursive does with that info, ideally I'd like to just see
it in the current output window and be able to click on it. I don't
see the need for anything more complicated.

How?

Ultimately its all just Clojure running in a REPL, I just need a way
to tell Cursive "Hey, link me to this file please!"

Easy right?

Well I'm not sure where to start, is it even something I can do
myself, or would it have to be implemented as part of Cursive itself?


Regards,
Timothy

Brian Guthrie

unread,
Jan 31, 2017, 2:40:18 AM1/31/17
to cur...@googlegroups.com
Hi Colin,

Thanks for the proposal; this is a (minor) pain point for me. For what it's worth, #2 seems fine; I mostly bounce between the editor and the REPL, and the existing IntelliJ solution is less than ideal for the reasons you mentioned.

Brian

Gökhan Özcan

unread,
Jan 31, 2017, 2:41:32 AM1/31/17
to cur...@googlegroups.com
It may be slightly off topic but +1 to Timothy. Couldn't have said it better myself. Experiencing reload on save on the client side with figwheel ruins everything else.

On another note, thanks for all your the effort Colin. Cursive is awesome!

Cheers.

Colin Fleming

unread,
Jan 31, 2017, 2:51:28 AM1/31/17
to cur...@googlegroups.com
Hi Timothy,

Thanks as always for the detailed feedback, and sorry it’s taken so long to reply - I took a while to think about it and then got distracted.

I’m actually starting to agree about refresh-based workflows, I almost never send individual forms from the editor to the REPL when I’m defining things. I do it a lot for evaluating test forms from comment blocks and so on, but they are generally forms that test the results of my definitions. The definitions are almost exclusively loaded file by file. Combined with the transitive dep loading, I find it’s much harder for the REPL to get into a state that I no longer understand, and it has a few additional benefits like ensuring that line numbers for forms from later in the file are still correct.

When I’m working like this, I generally use Load file in REPL or Sync files in REPL rather than file watching due to the unusual way IntelliJ saves files, but the principle is the same - you have some action which you perform which updates your runtime. I actually like this model more, since it feels like I have an explicit “update everything” command rather than having that be a side effect of files being saved.

I’ll actually be adding a proper IntelliJ test runner soon, and that will have refresh-like functionality. I’ll also be integrating Figwheel so that the Figwheel errors come out in the IDE rather than the browser. It’s interesting to think about the jumping-to-error case. It seems like the simplest solution would be for Cursive to correctly link files (see #331), which it should definitely do - if it doesn’t, that’s a bug which deserves an issue. I know there are CLJS issues with this right now that I need to fix. One question on that issue I didn’t get an answer to - in your case, is pirates/server/ticker_tests.clj relative to a source root, or to the REPL CWD? I’m assuming it’s a source root, i.e. that path is basically relative to the classpath, but it would be good to get confirmation of that.

However this still requires you to use the mouse, and in the case of a test runner will probably involve some clicking since it likes to collapse individual tests under test suites. IntelliJ already has a “Jump to next error” function, and it seems like this is what you’d want. I’ll check how extensible it is - generally it works for errors in the same editor, I’m not sure if it will also jump to errors across files. It seems like you’d want to be able to step through those errors using F2 or whatever, no matter where they are. That might involve having those errors painted in the editor too, but I’m guessing that would be a good thing anyway.

Does that sound like what you’re after?

Cheers,
Colin
Reply all
Reply to author
Forward
0 new messages