Fix completion pager not rendering after <a-semicolon> in prompt

Usually, the prompt resets "m_line_changed" after invoking the
change handler:

	if (m_line_changed)
	{
	    m_callback(m_line_editor.line(), PromptEvent::Change, context());
	    m_line_changed = false;
	}

but with

	prompt '' '' -on-change %{ execute-keys <a-semicolon>vl } -shell-script-candidates %{ seq 100 }

the change handler pushes a normal mode with "<a-semicolon>" and then
hands back control to the event loop. Later when the normal mode is
popped we run "Prompt::on_enabled()" but don't actually redraw the
completion pager.
Since the <a-semicolon> excursion by definition did not change our
prompt state, we don't need to recompute completions, only render them.
Do that.

This helps commands that use preview the selected completion via a
"prompt -on-change" handler.
This commit is contained in:
Johannes Altmanninger 2023-06-24 23:22:16 +02:00
parent 70e96c272e
commit cac2a32ba2

View File

@ -34,8 +34,8 @@ public:
void handle_key(Key key, bool synthesized) { RefPtr<InputMode> keep_alive{this}; on_key(key, synthesized); } void handle_key(Key key, bool synthesized) { RefPtr<InputMode> keep_alive{this}; on_key(key, synthesized); }
virtual void paste(StringView content); virtual void paste(StringView content);
virtual void on_enabled() {} virtual void on_enabled(bool from_pop) {}
virtual void on_disabled(bool temporary) {} virtual void on_disabled(bool from_push) {}
bool enabled() const { return &m_input_handler.current_mode() == this; } bool enabled() const { return &m_input_handler.current_mode() == this; }
Context& context() const { return m_input_handler.context(); } Context& context() const { return m_input_handler.context(); }
@ -227,7 +227,7 @@ public:
m_state(single_command ? State::SingleCommand : State::Normal) m_state(single_command ? State::SingleCommand : State::Normal)
{} {}
void on_enabled() override void on_enabled(bool from_pop) override
{ {
if (m_state == State::PopOnEnabled) if (m_state == State::PopOnEnabled)
return pop_mode(); return pop_mode();
@ -248,12 +248,12 @@ public:
} }
} }
void on_disabled(bool temporary) override void on_disabled(bool from_push) override
{ {
m_idle_timer.disable(); m_idle_timer.disable();
m_fs_check_timer.disable(); m_fs_check_timer.disable();
if (not temporary and m_hooks_disabled) if (not from_push and m_hooks_disabled)
{ {
context().hooks_disabled().unset(); context().hooks_disabled().unset();
m_hooks_disabled = false; m_hooks_disabled = false;
@ -1117,21 +1117,10 @@ private:
line.byte_count_to(m_line_editor.cursor_pos())); line.byte_count_to(m_line_editor.cursor_pos()));
if (not context().has_client()) if (not context().has_client())
return; return;
show_completions();
if (m_completions.candidates.empty())
return context().client().menu_hide();
Vector<DisplayLine> items;
for (auto& candidate : m_completions.candidates)
items.push_back({ candidate, {} });
const auto menu_style = (m_flags & PromptFlags::Search) ? MenuStyle::Search : MenuStyle::Prompt;
context().client().menu_show(std::move(items), {}, menu_style);
const bool menu = (bool)(m_completions.flags & Completions::Flags::Menu); const bool menu = (bool)(m_completions.flags & Completions::Flags::Menu);
if (menu) if (menu)
context().client().menu_select(0); context().client().menu_select(0);
auto prefix = line.substr(m_completions.start, m_completions.end - m_completions.start); auto prefix = line.substr(m_completions.start, m_completions.end - m_completions.start);
if (not menu and not contains(m_completions.candidates, prefix)) if (not menu and not contains(m_completions.candidates, prefix))
{ {
@ -1144,6 +1133,19 @@ private:
} catch (runtime_error&) {} } catch (runtime_error&) {}
} }
void show_completions()
{
if (m_completions.candidates.empty())
return context().client().menu_hide();
Vector<DisplayLine> items;
for (auto& candidate : m_completions.candidates)
items.push_back({ candidate, {} });
const auto menu_style = (m_flags & PromptFlags::Search) ? MenuStyle::Search : MenuStyle::Prompt;
context().client().menu_show(std::move(items), {}, menu_style);
}
void clear_completions() void clear_completions()
{ {
m_current_completion = -1; m_current_completion = -1;
@ -1163,18 +1165,31 @@ private:
context().print_status(display_line); context().print_status(display_line);
} }
void on_enabled() override void on_enabled(bool from_pop) override
{ {
display(); display();
m_line_changed = true; if (from_pop)
{
if (context().has_client())
{
show_completions();
const bool menu = (bool)(m_completions.flags & Completions::Flags::Menu);
if (m_current_completion != -1)
context().client().menu_select(m_current_completion);
else if (menu)
context().client().menu_select(0);
}
}
else
m_line_changed = true;
if (not (context().flags() & Context::Flags::Draft)) if (not (context().flags() & Context::Flags::Draft))
m_idle_timer.set_next_date(Clock::now() + get_idle_timeout(context())); m_idle_timer.set_next_date(Clock::now() + get_idle_timeout(context()));
} }
void on_disabled(bool temporary) override void on_disabled(bool from_push) override
{ {
if (not temporary) if (not from_push)
context().print_status({}); context().print_status({});
m_idle_timer.disable(); m_idle_timer.disable();
@ -1274,17 +1289,17 @@ public:
prepare(mode, count); prepare(mode, count);
} }
void on_enabled() override void on_enabled(bool from_pop) override
{ {
if (not (context().flags() & Context::Flags::Draft)) if (not (context().flags() & Context::Flags::Draft))
m_idle_timer.set_next_date(Clock::now() + get_idle_timeout(context())); m_idle_timer.set_next_date(Clock::now() + get_idle_timeout(context()));
} }
void on_disabled(bool temporary) override void on_disabled(bool from_push) override
{ {
m_idle_timer.disable(); m_idle_timer.disable();
if (not temporary) if (not from_push)
{ {
last_insert().recording.unset(); last_insert().recording.unset();
@ -1625,7 +1640,7 @@ InputHandler::InputHandler(SelectionList selections, Context::Flags flags, Strin
: m_context(*this, std::move(selections), flags, std::move(name)) : m_context(*this, std::move(selections), flags, std::move(name))
{ {
m_mode_stack.emplace_back(new InputModes::Normal(*this)); m_mode_stack.emplace_back(new InputModes::Normal(*this));
current_mode().on_enabled(); current_mode().on_enabled(false);
} }
InputHandler::~InputHandler() = default; InputHandler::~InputHandler() = default;
@ -1636,7 +1651,7 @@ void InputHandler::push_mode(InputMode* new_mode)
current_mode().on_disabled(true); current_mode().on_disabled(true);
m_mode_stack.emplace_back(new_mode); m_mode_stack.emplace_back(new_mode);
new_mode->on_enabled(); new_mode->on_enabled(false);
context().hooks().run_hook(Hook::ModeChange, format("push:{}:{}", prev_name, new_mode->name()), context()); context().hooks().run_hook(Hook::ModeChange, format("push:{}:{}", prev_name, new_mode->name()), context());
} }
@ -1651,7 +1666,7 @@ void InputHandler::pop_mode(InputMode* mode)
current_mode().on_disabled(false); current_mode().on_disabled(false);
m_mode_stack.pop_back(); m_mode_stack.pop_back();
current_mode().on_enabled(); current_mode().on_enabled(true);
context().hooks().run_hook(Hook::ModeChange, format("pop:{}:{}", prev_name, current_mode().name()), context()); context().hooks().run_hook(Hook::ModeChange, format("pop:{}:{}", prev_name, current_mode().name()), context());
} }