LibLine: Handle Ctrl-C and Ctrl-D in a way similar to other line editors

Makes C-c print "^C" and continue prompting on a new line.
Also fixes a problem where an interrupted get_line() would need more
read()'s than required to update the display.
This commit is contained in:
AnotherTest 2020-08-20 20:04:55 +04:30 committed by Andreas Kling
parent c8cf465174
commit 238e87de4e
4 changed files with 81 additions and 38 deletions

View file

@ -407,6 +407,55 @@ void Editor::initialize()
m_initialized = true;
}
void Editor::interrupted()
{
if (!m_is_editing)
return;
m_was_interrupted = true;
handle_interrupt_event();
if (!m_finish)
return;
m_finish = false;
reposition_cursor(true);
if (m_suggestion_display->cleanup())
reposition_cursor();
cleanup();
fprintf(stderr, "\n");
fflush(stderr);
m_buffer.clear();
m_is_editing = false;
restore();
m_notifier->set_event_mask(Core::Notifier::None);
deferred_invoke([this](auto&) {
remove_child(*m_notifier);
m_notifier = nullptr;
Core::EventLoop::current().quit(Retry);
});
}
void Editor::really_quit_event_loop()
{
m_finish = false;
reposition_cursor(true);
fprintf(stderr, "\n");
fflush(stderr);
auto string = line();
m_buffer.clear();
m_is_editing = false;
restore();
m_returned_line = string;
m_notifier->set_event_mask(Core::Notifier::None);
deferred_invoke([this](auto&) {
remove_child(*m_notifier);
m_notifier = nullptr;
Core::EventLoop::current().quit(Exit);
});
}
auto Editor::get_line(const String& prompt) -> Result<String, Editor::Error>
{
initialize();
@ -454,8 +503,9 @@ auto Editor::get_line(const String& prompt) -> Result<String, Editor::Error>
add_child(*m_notifier);
m_notifier->on_ready_to_read = [&] {
if (m_was_interrupted)
if (m_was_interrupted) {
handle_interrupt_event();
}
handle_read_event();
@ -464,28 +514,12 @@ auto Editor::get_line(const String& prompt) -> Result<String, Editor::Error>
refresh_display();
if (m_finish) {
m_finish = false;
reposition_cursor(true);
fprintf(stderr, "\n");
fflush(stderr);
auto string = line();
m_buffer.clear();
m_is_editing = false;
restore();
m_returned_line = string;
m_notifier->set_event_mask(Core::Notifier::None);
deferred_invoke([this](auto&) {
remove_child(*m_notifier);
m_notifier = nullptr;
Core::EventLoop::current().quit(0);
});
}
if (m_finish)
really_quit_event_loop();
};
loop.exec();
if (loop.exec() == Retry)
return get_line(prompt);
return m_input_error.has_value() ? Result<String, Editor::Error> { m_input_error.value() } : Result<String, Editor::Error> { m_returned_line };
}
@ -512,17 +546,29 @@ void Editor::handle_interrupt_event()
{
m_was_interrupted = false;
if (!m_buffer.is_empty())
fprintf(stderr, "^C");
auto cb = m_key_callbacks.get(ctrl('C'));
if (cb.has_value()) {
if (!cb.value()->callback(*this)) {
// Oh well.
return;
}
}
m_buffer.clear();
m_cursor = 0;
if (!m_buffer.is_empty()) {
fprintf(stderr, "^C");
fflush(stderr);
}
if (on_interrupt_handled)
on_interrupt_handled();
m_refresh_needed = true;
refresh_display();
if (m_buffer.is_empty())
return;
m_buffer.clear();
m_cursor = 0;
finish();
}
void Editor::handle_read_event()

View file

@ -196,13 +196,7 @@ public:
// FIXME: we will have to kindly ask our instantiators to set our signal handlers,
// since we can not do this cleanly ourselves. (signal() limitation: cannot give member functions)
void interrupted()
{
if (m_is_editing) {
m_was_interrupted = true;
handle_interrupt_event();
}
}
void interrupted();
void resized()
{
m_was_resized = true;
@ -277,6 +271,11 @@ private:
static VTState actual_rendered_string_length_step(StringMetrics&, size_t& length, u32, u32, VTState);
enum LoopExitCode {
Exit = 0,
Retry
};
// ^Core::Object
virtual void save_to(JsonObject&) override;
@ -336,6 +335,7 @@ private:
void refresh_display();
void cleanup();
void really_quit_event_loop();
void restore()
{

View file

@ -168,6 +168,7 @@ void Editor::finish_edit()
if (!m_always_refresh) {
m_input_error = Error::Eof;
finish();
really_quit_event_loop();
}
}

View file

@ -238,10 +238,6 @@ int main(int argc, char** argv)
return 1;
}
editor->on_interrupt_handled = [&] {
editor->finish();
};
shell->add_child(*editor);
Core::EventLoop::current().post_event(*shell, make<Core::CustomEvent>(Shell::ShellEventType::ReadLine));