gcv / julia-snail

An Emacs development environment for Julia
GNU General Public License v3.0
231 stars 21 forks source link

Feature request: copy region into terminal #67

Closed nlw0 closed 2 years ago

nlw0 commented 2 years ago

Hope it's ok to make a request. i'm not sure how to implement this myself, and advice would be much appreciated. It would be great to be able to copy-paste and run a region, similar to julia-snail-send-line. I miss being able to see the code and the output at the terminal when I run a region, the same way it happens to a line.

gcv commented 2 years ago

It cannot run the code in the context of the current module, which is why I didn't think it valuable to include in Snail. It's quite easy to write, so here's an implementation:

(defun julia-snail-copy-repl-region ()
  "Copy the region (requires transient-mark) to the Julia REPL and evaluate it.
This is not module-context aware."
  (interactive)
  (if (null (use-region-p))
      (user-error "No region selected")
    (let* ((block-start (region-beginning))
           (block-end (region-end))
           (text (s-trim (buffer-substring-no-properties block-start block-end))))
      (julia-snail--send-to-repl text)
      (julia-snail--flash-region (point-at-bol) (point-at-eol)))))

Give it a try and let me know what you think. I'm open to adding it.

nlw0 commented 2 years ago

Worked great, thanks a lot!! With that I should be able to modify julia-snail-send-dwim, and then it would work like julia-repl, where C-c C-c copies over either a line or a region. I got used to it and I like it, but I suppose it's not everybody's workflow. The point is mostly about being able to make small modifications then run small pieces of the code, and see all the outputs interleaved with the inputs, pretty much like a poor man's notebook I guess!

gcv commented 2 years ago

All right; I'll put this code in the wiki Tips and Tricks section for now.

nlw0 commented 2 years ago

This is great, I've now been able to switch from julia-repl. Thanks a lot! One other suggestion I would give is that the default behavior for julia-snail-send-buffer-file should probably be to save the buffer first, and not give an error/warning message asking if I want to execute a non-saved buffer... That's something I can probably fix by myself, but I would imagine most users would actually want that, no?

gcv commented 2 years ago

This is Emacs, most users want configurability. 😎

Anyway, I don't like the idea of automatically making durable on-disk changes to user data (files). That said, you're probably right that julia-snail-send-buffer-file is annoying (unless you save all the time like I do and therefore don't notice the problem). It should really turn into julia-snail-send-buffer (without the -file suffix) and send buffer contents into the Julia session rather than load an on-disk file. All the moving parts for doing this are actually there (sending Base64-encoded data from Emacs into Julia is already used for the parser), and this should probably happen at some point. I just don't have time right now.

As a quick fix for your annoyance right now, you can write a bit of :before advice for julia-snail-send-buffer-file to save the file. Untested, but (advice-add 'julia-snail-send-buffer-file :before #'save-buffer) might be all you need.

MasonProtter commented 2 years ago

Maybe instead of using something julia-snail-copy-repl-region could there be a nice way to show us the output of of julia-snail-send-region?

That's what I really want, I just want to get some visual indication what that region evaluated to.

gcv commented 2 years ago

@MasonProtter: I just pushed a change which shows the output of julia-snail-send-region in the minibuffer. It was actually always supposed to do that. It’s in MELPA now. Can you give it a try and see if that suffices?

MasonProtter commented 2 years ago

Hm yeah I gave it a try and unfortunately my new problem is that the output is in compact mode. I'm not sure what the right way to handle this would be since the minibuffer really only should be used for small outputs, but also I find this almost worse than no output:

image

I'm not really sure what the right solution is, but it'd be good if there could be a place where the output is shown with it's proper formatting. For not I will probably just use the copy-repl-region function I think.

gcv commented 2 years ago

Yes, that’s pretty terrible. I reverted the change (that should be in MELPA in a couple of hours).

An alternative is to show the result in an overlay at the end of the chunk of code being evaluated. CIDER does this. Pretty-printing it is a different story. I’ll leave that as a TODO for now.

It also looks like the Snail logo emoji doesn’t render in your modeline! That’s weird, what does (char-displayable-p (char-from-name "SNAIL")) return on your system???

MasonProtter commented 2 years ago

An alternative is to show the result in an overlay at the end of the chunk of code being evaluated. CIDER does this. Pretty-printing it is a different story. I’ll leave that as a TODO for now.

What if we just use popup-el? We could simply do on the julia side

result_str = repr("text/plain", result)

and then pass that string to emacs and do

(popup-tip result-str)

I tried to prototype this myself for a PR, but I don't understand elisp well enough to do it unfortunately.

It also looks like the Snail logo emoji doesn’t render in your modeline! That’s weird, what does (char-displayable-p (char-from-name "SNAIL")) return on your system???

Probably the way I've set my fonts if I had to guess. The function you suggest returns unicode.

gcv commented 2 years ago

Interesting! popup-tip looks promising. I’ll have to think about how best to use it. There are times when displaying the output in the source buffer is not helpful, such as for evaluating function (re)definitions, and I want to find a way to distinguish those use cases.

You can turn off the emoji modeline by setting julia-snail-use-emoji-mode-lighter to nil (I suggest doing it in the :custom section of use-package).

gcv commented 2 years ago

Both things discussed in this ticket are now live.

One: julia-snail-send-region now supports a two-prefix arg form (C-u C-u C-c C-r) that copies the region into the REPL. (Related: For consistency, I made julia-snail-send-line no longer copy to the REPL by default; the copying behavior is also available in two-prefix arg form.)

Two: the variable julia-snail-popup-display-eval-results now controls the use of popup.el to show in-line results. It defaults to :command, which keeps the results up until the next Emacs command. It can also be set to :change, which keeps the results up until the buffer changes.