rhysd / tui-textarea

Simple yet powerful multi-line text editor widget for ratatui and tui-rs
https://crates.io/crates/tui-textarea
MIT License
341 stars 63 forks source link

add os clipboard support #50

Closed pm100 closed 8 months ago

pm100 commented 1 year ago

Today the copy and paste functions only work within TTA to and from its private paste buffer.

It would be very useful to copy to and from the system clipboard.

Maybe should be a feature

I intend to do a PR for this

pm100 commented 1 year ago

Investigated a bit

Its actually a very lightweight change so probably doesnt need to be a feature

Maybe a set_clip_mode function so that the app can say if it wants to use the clipboard or the yank buffer (or both?)

rhysd commented 1 year ago

This would be a desired feature. But I guess you can implement it to your app without modifying this library.

When ctrl+c or ctrl+x is input, how about getting the text via TextArea::yank_text and transfering it to OS clipboard?

rhysd commented 1 year ago

It might be a good idea to add new clipboard feature to this crate. When it is enabled, a system clipboard is used instead of YankedText.

The discussion points are:

For implementation, this crate looks great. It is used for implementation of Alacritty.

https://crates.io/crates/copypasta

EDIT: copypasta was not suitable since its clipboard-win dependency was too old and maintainers were not willing to upgrade it.

pm100 commented 1 year ago

After some thought it seems simple thing is not that simple (easy to implement, not clear on functinality)

First , the users expectation for the clipboard in general is that things only get put there via explicit request - ie cut or copy short cut or menu click.

So should things that simply delete text load data into the clipboard? - no IMO. I think the user would be surprised by that. I would.

I also think that the yank / clipboard behavior can / might be changed by the select PR. Before that there was no way for a user to mark text for yanking/clipping. Only the delete verbs did it. Now there is the option to select (including using all the line, word navigation options) and then chose cut or copy. Should yank/clip still be done in those delete cases?

Here you see that since vim is doing private stuff, not messing with shared resource, it is happy to yank. vscode does not.

My vote would be that if clipboard is enabled then only the copy and cut calls / keys load the clipboard.

But now we have an oddity. What does paste do? Does it use yank or clip? if delete word loads yank then paste needs to read yank, but in other cases it needs to read clipboard.

Here is what I would do if clipboard is turned on - however that is done

This also resolves another strangeness: ctrl-v behavior. In many terminal environments ctrl-v is captured by the system and it converts it into simply typing the clipboard into the terminal. This is great for apps that don't support paste themselves (like the command line). But sucks for code like tta. crossterm's raw mode cannot suppress this behavior on windows, I have not looked into other environments yet. (I have raised this with the windows terminal project, other have to)

So if the user types ctrl-v in many places they get the clipboard regardless of what the tta code does. The current default key binding for tta paste is ctrl-y. I find it hard to remember to use ctrl-y rather than ctrl-v, and end up getting the clipboard rather than the yank. This again suggests that yank buffer should be suppressed. [BTW ctrl-y is a strange choice -> it implies yank, but thats not what is does]

I used cli-clipboard for my test, trivial to use. Error handling - write to the log :-) Seriously, the API verbs that can fail (copy and paste here) are new in select PR and can be made to return Result. The input function can ignore the result but if the caller uses the API directly then they will get the Result

joshka commented 1 year ago

Doesn't bracketed paste work in windows terminal? https://github.com/microsoft/terminal/issues/395

As a macOS user, I expect that when I select text using my mouse, that text is automatically copied to the clipboard without having to press anything (this is often the default behavior in unix terminal apps too).

pm100 commented 1 year ago

whats bracket paste - the link explaining it in the link that you linked to is dead

rhysd commented 1 year ago

Bracketed paste is a terminal's feature to notify pasted text from clipboard to the process running on the terminal.

https://en.wikipedia.org/wiki/Bracketed-paste

When pasting a text to terminal, terminal sends the text to its shell process as if a user types it. This is a problem for the program running in the shell since it cannot know the input text was sent via clipboard or a user really typed the text by keyboard.

For example, termwiz crate handles bracket paste as InputEvent::Paste if my understanding is correct.

rhysd commented 1 year ago

As a macOS user, I expect that when I select text using my mouse, that text is automatically copied to the clipboard without having to press anything (this is often the default behavior in unix terminal apps too).

That's depending on terminal. Since I'm not using mouse usually, I'm not sure famous terminals (Terminal.app or iTerm2.app) support it.

And I think selecting by mouse is not a perfect solution because:

image
pm100 commented 1 year ago

And mouse support is a whole other rabbit hole to disappear down :)

pm100 commented 12 months ago

This would be a desired feature. But I guess you can implement it to your app without modifying this library.

When ctrl+c or ctrl+x is input, how about getting the text via TextArea::yank_text and transfering it to OS clipboard?

Yes but then why have any key mapping? The app can interpret all keys themselves. (See other thread)

Plus it requires the author to work out how to do clipboard stuff.

joshka commented 12 months ago

Plus it requires the author to work out how to do clipboard stuff.

I suspect that's a good thing. Clipboard handling is more of a cross cutting concern than one that makes sense on each widget. Put another way, implementing copy-paste to the OS in this widget leaves all the other widgets that make up an app lacking that functionality (or having functionality that is incompatible or subtly different). There are already crates for handling the OS clipboard ... https://crates.io/search?q=clipboard

So IMO, the right way to handle this is hooks to support copy and paste, but leave the OS clipboard handling to the app.

@rhysd wrote

That's depending on terminal. Since I'm not using mouse usually, I'm not sure famous terminals (Terminal.app or iTerm2.app) support it.

Terminal.app doesn't support it, iTerm2 does. Most Unix window managers support it at the OS level (though it's been a while since I've used desktop Linux)

And I think selecting by mouse is not a perfect solution because:

  • When selecting text via mouse, terminal doesn't understand what widgets are put in the screen. When widgets are put horizontally, copying multiple lines of text in one of the widgets would not work as the following screenshot shows

Definitely, but if an app is able to handle mouse mode properly and widgets were to somehow present selectable areas, then we could have some way to handle wrapping of the selection in a way that works nice. iTerm2 has an option that makes this just work:

Edit > Selection Respects Soft Boundaries

When enabled, vertical lines of pipe characters | will be interpreted as pane dividers (as in vim or emacs) and selection will wrap at them.

@rhsyd also wrote:

  • Terminal users don't like to use mouse. Selecting the text within the textarea and directly sending the selected text to their clipboard would be desired

Personally use the mouse in the terminal all the time (scrolling, selection, etc.). I suspect that it is fairly common that users embrace multi-modal input when it's available.

pm100 commented 12 months ago

Why not add clipboard support to the editor sample. That's the most sophisticated sample, it would be a good addition

rhysd commented 12 months ago

Why not add clipboard support to the editor sample. That's the most sophisticated sample, it would be a good addition

I think this feature should be implemented in this crate rather than example. I've not implemented it yet just because I didn't have enough time to implement it. I prioritized to fix bugs around CRLF and release v0.4.0.

rhysd commented 12 months ago

So IMO, the right way to handle this is hooks to support copy and paste, but leave the OS clipboard handling to the app.

I undestand that making copy/paste pluggable is a good option. However I'm not sure such flexibility is actually necessary. I believe there are only two use cases; textarea-internal clipboard or global system clipboard.

I'm planning to implement this as clipboard feature of this crate. Users can select it at build time. Pros are:

rhysd commented 11 months ago

I implemented this at the following branch. Document needs to be updated but you can try the implementation.

https://github.com/rhysd/tui-textarea/tree/clipboard

rhysd commented 11 months ago

I updated the document as well: d78e9aaacb6a447afed74d849f9bcc9e4dedc324

pm100 commented 11 months ago

tested on windows 11 - fine tested on WSL (my main linux env) - no. Will investigate

still to do mac and 'real' linux

pm100 commented 11 months ago

Heres what works vs does not

For WSL this is one of those places where WSL command line is different from plain vanilla gui ubuntu. There is no clipboard in Liniux, it belongs to the x server, command line wsl has no xserver. The user expectation is that it reads and writes the windows clipboard, but thats mainly done via the terminal windows simply copying and pasting, not via the app. WIll investigate further to see what other rust folks have done

The linux failure is probably due to a missing dependency at the OS level. I will investigate.

Functionality wise this is what I find:

I did not try all the emacs like delete operations (delete word back, forward,.....) but I suspect they are all the same, delte and copy to clipboard. I am surprised by this, the user expectation is that the clipboard gets overwritten by explicit copy or cut operations. I get that its intended to be consistent with the current yank buffer behavior but I am sure you will get issues raised on this

pm100 commented 11 months ago

The wsl clipboard issue is resolved here https://github.com/rgwood/clipboard-anywhere. A simple wrapper on top of arboard. Or the code simply be lifted from it - its very simple.

My linux issue seems to have gone away - dont like things that go away by themsleves, they come back by themselves. This will spur me to set up a 'normal' linux machine (raspian is a bit odd)

Update: Ubuntu 22 VM - works fine

I think the default configuration should support ctrl-v as paste. It doesnt work on windows (Windows intercepts it before it gets to any app) but it would work fine on Linux

rhysd commented 11 months ago

Thank you for confirming that. I think the WSL issue should be solved by upstream (arboard) rather than adding hack to this crate. Since the implementation is quite simple, it would be easy to send a patch. But the problem is that I don't have WSL environment.

EDIT:

I did not try all the emacs like delete operations (delete word back, forward,.....) but I suspect they are all the same

Yeah, it is not necessary to try all functionalities. Just checking copy/paste should be enough because they all use the same interface Clipboard::set_contenst and Clipboard::get_contents.

I think the default configuration should support ctrl-v as paste.

That cannot be changed easily and is being discussed in #51.

rhysd commented 11 months ago

@pm100 I installed WSL (Ubuntu) following the guide and tried arboard crate on it. It seems that arboard works fine on my machine.

use std::error::Error;

fn main() -> Result<(), Box<dyn Error>> {
    let text = "hello, world";
    let mut c = arboard::Clipboard::new()?;
    assert_ne!(c.get_text()?, text);
    c.set_text(text)?;
    assert_eq!(c.get_text()?, text);
    Ok(())
}

WSL supports X11 and Wayland: https://learn.microsoft.com/en-us/windows/wsl/tutorials/gui-apps

Clipboard contents seem to be synced between Linux and Windows automatically. Do you still use quite old WSL (perhaps WSL1)? I don't think supporting such old WSL environment is reasonable.

EDIT:

I also confimred cargo run --example minimal --features=clipboard worked on WSL.

pm100 commented 11 months ago

@rhysd I do not use old WSL. But the non GUI version of WSL is the most common use case (it was the only one till recently). This is why there is that fix for the clipboard in clipboard-anywhere

pm100 commented 11 months ago

@rhysd - you did not respond to my comment about delete-word etc placing data in the system clipboard. I think this is the wrong behavior, I did not test them all to see if they work, I am sure they do. But I assume they all load the clipboard, which IMO is incorrect.

rhysd commented 11 months ago

But the non GUI version of WSL is the most common use case (it was the only one till recently). This is why there is that fix for the clipboard in clipboard-anywhere

Even if using non-GUI version of WSL, wsl --install automatically installs X11 as far as following the guide.

you did not respond to my comment about delete-word etc placing data in the system clipboard. I think this is the wrong behavior

That's because deleting word yanks the deleted text. Since clipboard uses system clipboard instead of its internal yank buffer, it is intended. And I don't think it is wrong behavior. For example, Vim stores deleted word with dw to system clipboard when :set clipboard=unnamed. How do you determine it is the wrong behavior? Since you don't describe any detailed interface and behavior in your brain, there is no way to know what is the correct behavior.

pm100 commented 11 months ago

@rhysd I just tried vscode and notepad++. On both, ctrl-backspace is 'delete word left' (as an example of 'complex' delete operations that they both support). Neither of them copy to the clipboard.

You could at least make it an option (set_yank_mode or something like that), I can do a PR for it

pm100 commented 8 months ago

@rhysd I have worked out that its pretty easy to make os clipboard support without any changes to tta.

I just added arbound to gitui (or whatever product), and after I call tta.cut or copy I copy the yank to the clipboard, and before I call tta.paste I copy the clipboard to the yank buffer (which is nicely exposed by tta). So lets close this