Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove Emacs-like shortcuts from TextArea::input #51

Open
rhysd opened this issue Nov 11, 2023 · 11 comments
Open

Remove Emacs-like shortcuts from TextArea::input #51

rhysd opened this issue Nov 11, 2023 · 11 comments
Labels
enhancement New feature or request

Comments

@rhysd
Copy link
Owner

rhysd commented Nov 11, 2023

The problem

Currently TextArea::input supports Emacs-like keyboard shortcuts. This was a good idea when tui-textarea had less features. However, now tui-textarea supports more features and adds more default key shortcuts and running out key combinations. And now it causes some conflicts.

  • C-a is used for moving to head of line in Emacs, but usually it is used for selecting all text in normal textarea
  • C-v is used for moving to the next page in Emacs, but usually it is used for pasting yanked text

Current default key shortcuts can be found here: https://github.com/rhysd/tui-textarea#minimal-usage

Emacs solves the problem by key sequence (like C-x b) but tui-textarea doesn't have the functionality (and should not have for avoiding complexity).

tui-textarea aims to be something like <textarea> element in HTML as described in the first sentence of README.md. So the default shortcuts should be intuitive and kept simple.

The solution

Remove Emacs-like shortcuts from TextArea::input and add TextArea::input_with_emacs_shortcuts instead.

Supported key shortcuts are as follows.

TextArea::input

Mappings Description
Ctrl+H, Backspace Delete one character before cursor
Delete Delete one character next to cursor
Enter Insert newline
Alt+Backspace Delete one word before cursor
Alt+Delete Delete one word next to cursor
Ctrl+Z Undo
Alt+Z Redo
Ctrl+C Copy selected text
Ctrl+X Cut selected text
Ctrl+V Paste yanked text
Ctrl+A Select all text
Ctrl+F, Move cursor forward by one character
Ctrl+B, Move cursor backward by one character
Ctrl+P, Move cursor up by one line
Ctrl+N, Move cursor down by one line
Ctrl+→ Move cursor forward by word
Ctrl+← Move cursor backward by word
Ctrl+↑ Move cursor up by paragraph
Ctrl+↓ Move cursor down by paragraph
End, Ctrl+Alt+→ Move cursor to the end of line
Home, Ctrl+Alt+← Move cursor to the head of line
Ctrl+Alt+↑ Move cursor to top of lines
Ctrl+Alt+↓ Move cursor to bottom of lines
PageDown Scroll down by page
PageUp Scroll up by page

Note: Alt+Z is unusual, but Ctrl+Shift+Z cannot be detected due to limitation of the terminal escape sequence.

Note: Ctrl+N, Ctrl+P, Ctrl+F, Ctrl+B, Ctrl+H remain because they are supported on macOS by default key shortcuts.

TextArea::input_with_emacs_shortcuts

Mappings Description
Ctrl+H, Backspace Delete one character before cursor
Ctrl+D, Delete Delete one character next to cursor
Ctrl+M, Enter Insert newline
Ctrl+K Delete from cursor until the end of line
Ctrl+J Delete from cursor until the head of line
Ctrl+W, Alt+H Delete one word before cursor
Alt+D Delete one word next to cursor
Ctrl+U Undo
Ctrl+R Redo
Ctrl+Y Paste yanked text
Ctrl+Space Start selection
Ctrl+W Cut selected text
Alt+W Copy selected text
Ctrl+G Cancel selection
Ctrl+F, Move cursor forward by one character
Ctrl+B, Move cursor backward by one character
Ctrl+P, Move cursor up by one line
Ctrl+N, Move cursor down by one line
Alt+F Move cursor forward by word
Atl+B Move cursor backward by word
Alt+], Alt+P Move cursor up by paragraph
Alt+[, Alt+N Move cursor down by paragraph
Ctrl+E, End, Ctrl+Alt+F Move cursor to the end of line
Ctrl+A, Home, Ctrl+Alt+B Move cursor to the head of line
Alt+<, Ctrl+Alt+P, Move cursor to top of lines
Alt+>, Ctrl+Alt+N, Move cursor to bottom of lines
Ctrl+V, PageDown Scroll down by page
Alt+V, PageUp Scroll up by page
@rhysd rhysd added the enhancement New feature or request label Nov 11, 2023
@pm100
Copy link
Contributor

pm100 commented Nov 11, 2023

I certainly think that ctrlz,ctrlx,ctrlc,ctrlv should be standard. And ctrla. I added ctrlc and ctrlx in the select PR

BTW - I am working on a table lookup key dispatch mechanism making it much easier for the caller to change the key mappings. At present I have basically had to copy and paste the entire input function into my gitui code just to tweak a few keys

@joshka
Copy link
Contributor

joshka commented Nov 11, 2023

I think most CLI users would expect Emacs key bindings to work as a default (I actually use Ctrl+A/E/U/etc. everywhere in macOS as there's an OS level switch for turning on the shortcuts), and Ctrl+C to always mean SIGINT rather than copy. Strong preference for keeping that the default so that apps built with tui-textarea generally "just work", and instead making the non-emacs mode the opt-in / configurable approach.

@pm100
Copy link
Contributor

pm100 commented Nov 11, 2023

Ctrlc does not always equal sigint . Raw mode passes it through as a plain ol keystroke. Interestingly this is bound to the other new issue about clipboard etc

@joshka
Copy link
Contributor

joshka commented Nov 15, 2023

Sure - but IMO your app should probably do something reasonable with that rather than treating it as copy at least in the default situation.

@pm100
Copy link
Contributor

pm100 commented Nov 15, 2023

It is up to the app author to decide what ctrlc should do. If they pass that keystroke to tta rather than acting on it themselves then doing a copy is reasonable. The app I am working on exits cleanly on ctrlc but if tta has focus then it will pass it to tta

@joshka
Copy link
Contributor

joshka commented Nov 15, 2023

I see your point that its the app creator that decides, but I'd caution that there's a problem with that approach. It leads to building apps that all act slightly inconsistently with respect to how they handle keystrokes. For the most part I find it jarring when an application changes widely held conventions. Ctrl+C is basically never copy on macOS (that's Cmd+C). So my point isn't that the shortcuts shouldn't be customizable - it should be. My point is that out of the box the defaults should respect and be consistent with the operating system defaults.

P.S. if you're interested, there's some discussion about how to design keybinding more generally at ratatui/ratatui#627. It would be worth feeding some ideas about how libs can take advantage of something like that.

@rhysd
Copy link
Owner Author

rhysd commented Nov 15, 2023

Sorry for the delay in response. I was working on refactorying and bug fix.

@pm100

I am working on a table lookup key dispatch mechanism making it much easier for the caller to change the key mappings.

It would be useful as a separate crate. For me, match statement is powerful enough to define basic key bindings and don't want more flexibility. I saw some discussion about key bindings implementation in the forum of ratatui repository as @joshka pointed. You may be interested in it.

@joshka

everywhere in macOS as there's an OS level switch for turning on the shortcuts), and Ctrl+C to always mean SIGINT rather than copy. Strong preference for keeping that the default so that apps built with tui-textarea generally "just work", and instead making the non-emacs mode the opt-in / configurable approach.

Ah, nice point. I've not thought about C-c sends signal. Is it common sense for general ratatui applications? demo example in ratatui does not stop on C-c. I would expect C-c to stop the process when the application is non-interactive. But I'm not sure the expectation can be applied to interactive applications.


General TUI app users' expectations would be:

  • They would expect basic Emacs shortcuts like C-f, C-b, ... since many language REPLs provide them
  • They would not expect Emacs's copy/paste shortcuts (C-Space for starting selection, C-w for cut, and C-y for copy)

I'd like to enable both Emacs shortcuts and copy/paste/undo/redo shortcuts in general textarea in browser. The problem is C-a.

@rhysd
Copy link
Owner Author

rhysd commented Nov 15, 2023

It might be a good idea to follow key bindings of micro text editor:

https://github.com/zyedidia/micro/blob/master/runtime/help/keybindings.md#default-keybinding-configuration

Using Alt for Emacs-like shortcuts may be another option:

Mappings Description
Alt+H, Backspace Delete one character before cursor
Alt+D, Delete Delete one character next to cursor
Enter Insert newline
Alt+Backspace Delete one word before cursor
Alt+Delete Delete one word next to cursor
Ctrl+Z Undo
Alt+Z Redo
Ctrl+C Copy selected text
Ctrl+X Cut selected text
Ctrl+V Paste yanked text
Ctrl+A Select all text
Alt+F, Move cursor forward by one character
Alt+B, Move cursor backward by one character
Alt+P, Move cursor up by one line
Alt+N, Move cursor down by one line
Ctrl+→ Move cursor forward by word
Ctrl+← Move cursor backward by word
Ctrl+↑ Move cursor up by paragraph
Ctrl+↓ Move cursor down by paragraph
Alt+E, End, Ctrl+Alt+→ Move cursor to the end of line
Alt+A, Home, Ctrl+Alt+← Move cursor to the head of line
Ctrl+Alt+↑ Move cursor to top of lines
Ctrl+Alt+↓ Move cursor to bottom of lines
Alt+V, PageDown Scroll down by page
PageUp Scroll up by page
Alt+K Delete from cursor until the end of line

@joshka
Copy link
Contributor

joshka commented Nov 15, 2023

Ah, nice point. I've not thought about C-c sends signal. Is it common sense for general ratatui applications? demo example in ratatui does not stop on C-c. I would expect C-c to stop the process when the application is non-interactive. But I'm not sure the expectation can be applied to interactive applications.

I'm not 100% sure what the general rule for this should be, but probably a TUI that's just a display type UI should stop running when Ctrl+C is pressed, editor type TUIs are probably a bit different. Ctrl+Z should put the app into the background rather than being undo (try it in vim).

Using Alt for Emacs-like shortcuts may be another option:

This brings me back to the comment about respecting the conventions of the operating system / environment. For that reason, I'd suggest avoiding this option.

@pm100
Copy link
Contributor

pm100 commented Nov 16, 2023

My 10cents

The key dispatch logic in input should not be in tta. tta should be an API driven component, Many real uses require a complete replacement of that input code, my use of it involved basically copying and pasting that huge chunk of logic and tweaking it.

I would

  • make it more table driven
  • have multiple starter tables (emacs like, ctrlzxcv, ....)

You need to make sure that if I have my own input interpreter it has the same features that the in box one has - ie no secret hooks into tta. You could argue that the input interpreter should be separate sample / crate.

@rhysd
Copy link
Owner Author

rhysd commented Nov 17, 2023

probably a TUI that's just a display type UI should stop running when Ctrl+C is pressed, editor type TUIs are probably a bit different. Ctrl+Z should put the app into the background rather than being undo (try it in vim)

I tried tig and I confirmed both C-c and C-z are working as you said. I need more consideration. Thank you for the point.

Many real uses require a complete replacement of that input code

Yes, that's what I assume. Key shortcuts are very application specific. TextArea::input is just a convenient method for casual use. APIs are more fundamental.

You could argue that the input interpreter should be separate sample / crate.

I would suggest to create separate crate for this.

use your_crate::InputState;

// Input state such as current pending key sequence and table of key shortcuts
let mut input_state = InputState::default();

// event loop
loop {
    let input: Input = crossterm::event::read()?.into();

    // Receive new single input and modify textarea state if necessary
    input_state.apply(input, &mut textarea);

    // ...
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants