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

Add config for keeping menu always open #821

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

HKalbasi
Copy link
Contributor

fix #820

@fdncred
Copy link
Collaborator

fdncred commented Aug 24, 2024

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
Copy link
Contributor Author

Sure! This PR adds some configs to menus:

  • activate_on_start: if true, menu will be activated at the start of every prompt, when the editor is empty.
  • keep_active_after_accept: Keeps the menu enabled even when it's suggestion is accepted.

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:

  • ReedlineEvent::MenuAccept: a Submit like event specific to menus, which keys like Tab can bound it.
  • treat_submit_as_accept menu config: if true (which is the default), Submit and Enter events accept the menu suggestion.

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
Copy link
Collaborator

fdncred commented Aug 29, 2024

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

@fdncred fdncred marked this pull request as draft August 29, 2024 14:19
@HKalbasi
Copy link
Contributor Author

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
Copy link
Collaborator

fdncred commented Aug 30, 2024

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
Copy link
Contributor Author

HKalbasi commented Sep 4, 2024

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

@fdncred
Copy link
Collaborator

fdncred commented Sep 6, 2024

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
Copy link
Contributor

andylokandy commented Oct 5, 2024

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

@HKalbasi
Copy link
Contributor Author

HKalbasi commented Oct 5, 2024

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
Copy link
Contributor

andylokandy commented Oct 5, 2024

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
Copy link
Contributor Author

HKalbasi commented Oct 5, 2024

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

@andylokandy
Copy link
Contributor

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

@HKalbasi
Copy link
Contributor Author

HKalbasi commented Oct 6, 2024

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

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

Successfully merging this pull request may close these issues.

Keeping completion menu always open
3 participants