nushell / reedline

A feature-rich line editor - powering Nushell
https://docs.rs/reedline/
MIT License
549 stars 154 forks source link

Add config for keeping menu always open #821

Open HKalbasi opened 3 months ago

HKalbasi commented 3 months ago

fix #820

fdncred commented 3 months ago

Would be nice to see a gif/video of what this looks like and a better description so that reviewers don't have to jump around figuring out what this PR is supposed to do.

HKalbasi commented 3 months ago

Sure! This PR adds some configs to menus:

By enabling these configs, menu will be open on start and remain open unless user manually close it with ESC or something similar. The problem is that now it is impossible to actually submit the prompt without manually closing the menu since the menu always capture the Enter event. So I added two other things:

All together, we can keep completion menu always open while accepting prompts at the same time with Enter: Recording 2024-08-24 at 12 17 43

It is not very clear in the video, but I don't press any key for activating the menu and it is always enabled. I use completion with Tab and submit prompts with Enter. I added the change into the example ide_completions so you can execute it yourself if the video is not clear enough. Also I can create another example if you want to keep that example unchanged or remove it if it is not desired.

fdncred commented 2 months ago

This is an interesting feature and a good start but I'm getting a panic somewhere when accepting an entry. image

It's also weird that I can't use Enter to accept an item in the list. I'm not sure Tab will be a good "accept" since it's used to complete things.

All very interesting and it reminds me of pwsh's menu, which I just love. image

HKalbasi commented 2 months ago

I'm getting a panic somewhere when accepting an entry.

I'm not able to reproduce the panic. Can you give me the stack trace of it or some way to reproduce it? Does it happen when you do some specific thing?

It's also weird that I can't use Enter to accept an item in the list. I'm not sure Tab will be a good "accept" since it's used to complete things.

It is configurable and can be disabled, but without it, user needs to manually close the menu with ESC before submitting the prompt.

Another way to address this problem is how prompt_toolkit python library does: in prompt toolkit, the completion menu is always open, but it doesn't select any item, and when an item is selected, it is implicitly accepted and user don't need to press anything to accept the suggestion and can just continue the typing:

Recording 2024-08-30 at 15 27 04

In this way, the Enter key is free for submitting the prompt, and Tab is used for switching between the menu items. I can add configuration for this as well if desired.

fdncred commented 2 months ago

I'm not able to reproduce the panic. Can you give me the stack trace of it or some way to reproduce it? Does it happen when you do some specific thing?

It's some combination of hitting tab, backspace or tab, enter, backspace.

❯ cargo r --example ide_completions                                                                         10:27:34 AM
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.19s
     Running `target\debug\examples\ide_completions.exe`
~\source\repos\reedline| hello another very large option for hello word that will force one column08/30/2024 10:28:01 AM
We processed: hello another very large option for hello word that will force one column
~\source\repos\reedline| hello another very large option for hello word that will force one columnthread 'main' panicked at /rustc/051478957371ee0084a7c0913941d2a8c4757bb9\library\core\src\str\mod.rs:659:21:
byte index 72 is out of bounds of `hello another very large option for hello word ...`
stack backtrace:
   0:     0x7ff76579ecad - std::backtrace_rs::backtrace::dbghelp64::trace
                               at /rustc/051478957371ee0084a7c0913941d2a8c4757bb9/library\std\src\..\..\backtrace\src\backtrace\dbghelp64.rs:91
   1:     0x7ff76579ecad - std::backtrace_rs::backtrace::trace_unsynchronized
                               at /rustc/051478957371ee0084a7c0913941d2a8c4757bb9/library\std\src\..\..\backtrace\src\backtrace\mod.rs:66
   2:     0x7ff76579ecad - std::sys_common::backtrace::_print_fmt
                               at /rustc/051478957371ee0084a7c0913941d2a8c4757bb9/library\std\src\sys_common\backtrace.rs:68
   3:     0x7ff76579ecad - std::sys_common::backtrace::_print::impl$0::fmt
                               at /rustc/051478957371ee0084a7c0913941d2a8c4757bb9/library\std\src\sys_common\backtrace.rs:44
   4:     0x7ff7657b8099 - core::fmt::rt::Argument::fmt
                               at /rustc/051478957371ee0084a7c0913941d2a8c4757bb9/library\core\src\fmt\rt.rs:165
   5:     0x7ff7657b8099 - core::fmt::write
                               at /rustc/051478957371ee0084a7c0913941d2a8c4757bb9/library\core\src\fmt\mod.rs:1168
   6:     0x7ff76579b341 - std::io::Write::write_fmt<std::sys::pal::windows::stdio::Stderr>
                               at /rustc/051478957371ee0084a7c0913941d2a8c4757bb9/library\std\src\io\mod.rs:1835
   7:     0x7ff76579ea86 - std::sys_common::backtrace::print
                               at /rustc/051478957371ee0084a7c0913941d2a8c4757bb9/library\std\src\sys_common\backtrace.rs:34
   8:     0x7ff7657a0bf8 - std::panicking::default_hook::closure$1
                               at /rustc/051478957371ee0084a7c0913941d2a8c4757bb9/library\std\src\panicking.rs:271
   9:     0x7ff7657a08a6 - std::panicking::default_hook
                               at /rustc/051478957371ee0084a7c0913941d2a8c4757bb9/library\std\src\panicking.rs:298
  10:     0x7ff7657a1128 - std::panicking::rust_panic_with_hook
                               at /rustc/051478957371ee0084a7c0913941d2a8c4757bb9/library\std\src\panicking.rs:795
  11:     0x7ff7657a0fe7 - std::panicking::begin_panic_handler::closure$0
                               at /rustc/051478957371ee0084a7c0913941d2a8c4757bb9/library\std\src\panicking.rs:664
  12:     0x7ff76579f61f - std::sys_common::backtrace::__rust_end_short_backtrace<std::panicking::begin_panic_handler::closure_env$0,never$>
                               at /rustc/051478957371ee0084a7c0913941d2a8c4757bb9/library\std\src\sys_common\backtrace.rs:171
  13:     0x7ff7657a0c98 - std::panicking::begin_panic_handler
                               at /rustc/051478957371ee0084a7c0913941d2a8c4757bb9/library\std\src\panicking.rs:652
  14:     0x7ff7657beed4 - core::panicking::panic_fmt
                               at /rustc/051478957371ee0084a7c0913941d2a8c4757bb9/library\core\src\panicking.rs:72
  15:     0x7ff7657ba1c4 - core::str::slice_error_fail_rt
                               at /rustc/051478957371ee0084a7c0913941d2a8c4757bb9/library\core\src\str\mod.rs:112
  16:     0x7ff7657bf5f8 - core::str::slice_error_fail
                               at /rustc/051478957371ee0084a7c0913941d2a8c4757bb9/library\core\src\str\mod.rs:89
  17:     0x7ff7656fd43d - core::str::impl$0::split_at
                               at /rustc/051478957371ee0084a7c0913941d2a8c4757bb9\library\core\src\str\mod.rs:659
  18:     0x7ff7656b366a - reedline::menu::ide_menu::IdeMenu::create_value_string
                               at C:\Users\fdncred\source\repos\reedline\src\menu\ide_menu.rs:518
  19:     0x7ff765721838 - reedline::menu::ide_menu::impl$6::menu_string::closure$0
                               at C:\Users\fdncred\source\repos\reedline\src\menu\ide_menu.rs:865
  20:     0x7ff7656fe93e - core::iter::adapters::map::map_fold::closure$0<tuple$<usize,ref$<reedline::completion::base::Suggestion> >,alloc::string::String,tuple$<>,reedline::menu::ide_menu::impl$6::menu_string::closure_env$0,core::iter::traits::iterator::Iterator::for_each::call::c
                               at /rustc/051478957371ee0084a7c0913941d2a8c4757bb9\library\core\src\iter\adapters\map.rs:89
  21:     0x7ff7656f89b6 - core::iter::adapters::enumerate::impl$1::fold::enumerate::closure$0<ref$<reedline::completion::base::Suggestion>,tuple$<>,core::iter::adapters::map::map_fold::closure_env$0<tuple$<usize,ref$<reedline::completion::base::Suggestion> >,alloc::string::String,t
                               at /rustc/051478957371ee0084a7c0913941d2a8c4757bb9\library\core\src\iter\adapters\enumerate.rs:108
  22:     0x7ff76570543c - core::iter::adapters::take::impl$10::spec_fold<core::iter::adapters::skip::Skip<core::slice::iter::Iter<reedline::completion::base::Suggestion> >,tuple$<>,core::iter::adapters::enumerate::impl$1::fold::enumerate::closure_env$0<ref$<reedline::completion::ba
                               at /rustc/051478957371ee0084a7c0913941d2a8c4757bb9\library\core\src\iter\adapters\take.rs:307
  23:     0x7ff765703ba9 - core::iter::adapters::take::impl$1::fold<core::iter::adapters::skip::Skip<core::slice::iter::Iter<reedline::completion::base::Suggestion> >,tuple$<>,core::iter::adapters::enumerate::impl$1::fold::enumerate::closure_env$0<ref$<reedline::completion::base::Su
                               at /rustc/051478957371ee0084a7c0913941d2a8c4757bb9\library\core\src\iter\adapters\take.rs:110
  24:     0x7ff7656f8817 - core::iter::adapters::enumerate::impl$1::fold<core::iter::adapters::take::Take<core::iter::adapters::skip::Skip<core::slice::iter::Iter<reedline::completion::base::Suggestion> > >,tuple$<>,core::iter::adapters::map::map_fold::closure_env$0<tuple$<usize,ref
                               at /rustc/051478957371ee0084a7c0913941d2a8c4757bb9\library\core\src\iter\adapters\enumerate.rs:114
  25:     0x7ff7656fd681 - core::iter::adapters::map::impl$2::fold<alloc::string::String,core::iter::adapters::enumerate::Enumerate<core::iter::adapters::take::Take<core::iter::adapters::skip::Skip<core::slice::iter::Iter<reedline::completion::base::Suggestion> > > >,reedline::menu:
                               at /rustc/051478957371ee0084a7c0913941d2a8c4757bb9\library\core\src\iter\adapters\map.rs:129
  26:     0x7ff7656fe4b8 - core::iter::traits::iterator::Iterator::for_each<core::iter::adapters::map::Map<core::iter::adapters::enumerate::Enumerate<core::iter::adapters::take::Take<core::iter::adapters::skip::Skip<core::slice::iter::Iter<reedline::completion::base::Suggestion> > >
                               at /rustc/051478957371ee0084a7c0913941d2a8c4757bb9\library\core\src\iter\traits\iterator.rs:818
  27:     0x7ff7656ec30a - alloc::vec::Vec<alloc::string::String,alloc::alloc::Global>::extend_trusted<alloc::string::String,alloc::alloc::Global,core::iter::adapters::map::Map<core::iter::adapters::enumerate::Enumerate<core::iter::adapters::take::Take<core::iter::adapters::skip::Sk
                               at /rustc/051478957371ee0084a7c0913941d2a8c4757bb9\library\alloc\src\vec\mod.rs:3096
  28:     0x7ff7656f137e - alloc::vec::spec_extend::impl$1::spec_extend<alloc::string::String,core::iter::adapters::map::Map<core::iter::adapters::enumerate::Enumerate<core::iter::adapters::take::Take<core::iter::adapters::skip::Skip<core::slice::iter::Iter<reedline::completion::bas
                               at /rustc/051478957371ee0084a7c0913941d2a8c4757bb9\library\alloc\src\vec\spec_extend.rs:26
  29:     0x7ff7656ea0e2 - alloc::vec::spec_from_iter_nested::impl$1::from_iter<alloc::string::String,core::iter::adapters::map::Map<core::iter::adapters::enumerate::Enumerate<core::iter::adapters::take::Take<core::iter::adapters::skip::Skip<core::slice::iter::Iter<reedline::complet
                               at /rustc/051478957371ee0084a7c0913941d2a8c4757bb9\library\alloc\src\vec\spec_from_iter_nested.rs:62
  30:     0x7ff7656f1551 - alloc::vec::spec_from_iter::impl$0::from_iter<alloc::string::String,core::iter::adapters::map::Map<core::iter::adapters::enumerate::Enumerate<core::iter::adapters::take::Take<core::iter::adapters::skip::Skip<core::slice::iter::Iter<reedline::completion::ba
                               at /rustc/051478957371ee0084a7c0913941d2a8c4757bb9\library\alloc\src\vec\spec_from_iter.rs:33
  31:     0x7ff7656f10b7 - alloc::vec::impl$15::from_iter<alloc::string::String,core::iter::adapters::map::Map<core::iter::adapters::enumerate::Enumerate<core::iter::adapters::take::Take<core::iter::adapters::skip::Skip<core::slice::iter::Iter<reedline::completion::base::Suggestion>
                               at /rustc/051478957371ee0084a7c0913941d2a8c4757bb9\library\alloc\src\vec\mod.rs:2970
  32:     0x7ff7656fe441 - core::iter::traits::iterator::Iterator::collect<core::iter::adapters::map::Map<core::iter::adapters::enumerate::Enumerate<core::iter::adapters::take::Take<core::iter::adapters::skip::Skip<core::slice::iter::Iter<reedline::completion::base::Suggestion> > >
                               at /rustc/051478957371ee0084a7c0913941d2a8c4757bb9\library\core\src\iter\traits\iterator.rs:2005
  33:     0x7ff7656b576a - reedline::menu::ide_menu::impl$6::menu_string
                               at C:\Users\fdncred\source\repos\reedline\src\menu\ide_menu.rs:855
  34:     0x7ff765707bf6 - reedline::menu::impl$4::menu_string
                               at C:\Users\fdncred\source\repos\reedline\src\menu\mod.rs:484
  35:     0x7ff76570df4c - reedline::painting::painter::Painter::print_menu
                               at C:\Users\fdncred\source\repos\reedline\src\painting\painter.rs:307
  36:     0x7ff76570e7b4 - reedline::painting::painter::Painter::print_small_buffer
                               at C:\Users\fdncred\source\repos\reedline\src\painting\painter.rs:359
  37:     0x7ff76570d4ea - reedline::painting::painter::Painter::repaint_buffer
                               at C:\Users\fdncred\source\repos\reedline\src\painting\painter.rs:234
  38:     0x7ff7656c15aa - reedline::engine::Reedline::buffer_paint
                               at C:\Users\fdncred\source\repos\reedline\src\engine.rs:1842
  39:     0x7ff7656c02ed - reedline::engine::Reedline::repaint
                               at C:\Users\fdncred\source\repos\reedline\src\engine.rs:1544
  40:     0x7ff7656ba63a - reedline::engine::Reedline::read_line_helper
                               at C:\Users\fdncred\source\repos\reedline\src\engine.rs:805
  41:     0x7ff7656b9c73 - reedline::engine::Reedline::read_line
                               at C:\Users\fdncred\source\repos\reedline\src\engine.rs:649
  42:     0x7ff7656a1f02 - ide_completions::main
                               at C:\Users\fdncred\source\repos\reedline\examples\ide_completions.rs:123
  43:     0x7ff7656a10ab - core::ops::function::FnOnce::call_once<enum2$<core::result::Result<tuple$<>,std::io::error::E~\source\repos\reedline| hello another very large option for hello word that will force one columerror: process didn't exit successfully: `target\debug\examples\ide_completions.exe` (exit code: 101)
~\source\repos\reedline> [keep-menu-always-open]
HKalbasi commented 2 months ago

The panic also happens in the main branch. I will fix it in a separate PR.

fdncred commented 2 months ago

now that the bug is out of the way, i'm thinking about this "implicit acceptance" you demonstrated above. i'm wondering what the most ergonomic way is to interact with a menu that is open all the time.

andylokandy commented 1 month ago

Very appealing feature! Is it still working in process? I can help if any.

HKalbasi commented 1 month ago

The problem here is to find the best ergonomic way for accepting when the menu is still open. I'm open to implement the prompt toolkit way if desired, and I think since this feature is opt-in we can merge this PR for now and wait for people to use the feature and come with more ideas.

andylokandy commented 1 month ago

FYI: my use case is to pop up the menu when a key is pressed. Maybe we can provide a custom event hook which can rewrite to edit action or discard an input event.

HKalbasi commented 1 month ago

Can you check if this PR as its current state satisfy your needs?

andylokandy commented 1 month ago

I'd like to close the menu when the cursor is right after a whitespace. Can this PR achieve that?

HKalbasi commented 1 month ago

I think you can set an event for the space key to do that, but I'm not sure.