mirror of
https://github.com/RGBCube/serenity
synced 2025-07-24 22:17:42 +00:00
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:
parent
c8cf465174
commit
238e87de4e
4 changed files with 81 additions and 38 deletions
|
@ -407,6 +407,55 @@ void Editor::initialize()
|
||||||
m_initialized = true;
|
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>
|
auto Editor::get_line(const String& prompt) -> Result<String, Editor::Error>
|
||||||
{
|
{
|
||||||
initialize();
|
initialize();
|
||||||
|
@ -454,8 +503,9 @@ auto Editor::get_line(const String& prompt) -> Result<String, Editor::Error>
|
||||||
add_child(*m_notifier);
|
add_child(*m_notifier);
|
||||||
|
|
||||||
m_notifier->on_ready_to_read = [&] {
|
m_notifier->on_ready_to_read = [&] {
|
||||||
if (m_was_interrupted)
|
if (m_was_interrupted) {
|
||||||
handle_interrupt_event();
|
handle_interrupt_event();
|
||||||
|
}
|
||||||
|
|
||||||
handle_read_event();
|
handle_read_event();
|
||||||
|
|
||||||
|
@ -464,28 +514,12 @@ auto Editor::get_line(const String& prompt) -> Result<String, Editor::Error>
|
||||||
|
|
||||||
refresh_display();
|
refresh_display();
|
||||||
|
|
||||||
if (m_finish) {
|
if (m_finish)
|
||||||
m_finish = false;
|
really_quit_event_loop();
|
||||||
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);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
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 };
|
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;
|
m_was_interrupted = false;
|
||||||
|
|
||||||
if (!m_buffer.is_empty())
|
auto cb = m_key_callbacks.get(ctrl('C'));
|
||||||
fprintf(stderr, "^C");
|
if (cb.has_value()) {
|
||||||
|
if (!cb.value()->callback(*this)) {
|
||||||
|
// Oh well.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
m_buffer.clear();
|
if (!m_buffer.is_empty()) {
|
||||||
m_cursor = 0;
|
fprintf(stderr, "^C");
|
||||||
|
fflush(stderr);
|
||||||
|
}
|
||||||
|
|
||||||
if (on_interrupt_handled)
|
if (on_interrupt_handled)
|
||||||
on_interrupt_handled();
|
on_interrupt_handled();
|
||||||
|
|
||||||
m_refresh_needed = true;
|
if (m_buffer.is_empty())
|
||||||
refresh_display();
|
return;
|
||||||
|
|
||||||
|
m_buffer.clear();
|
||||||
|
m_cursor = 0;
|
||||||
|
|
||||||
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Editor::handle_read_event()
|
void Editor::handle_read_event()
|
||||||
|
|
|
@ -196,13 +196,7 @@ public:
|
||||||
|
|
||||||
// FIXME: we will have to kindly ask our instantiators to set our signal handlers,
|
// 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)
|
// since we can not do this cleanly ourselves. (signal() limitation: cannot give member functions)
|
||||||
void interrupted()
|
void interrupted();
|
||||||
{
|
|
||||||
if (m_is_editing) {
|
|
||||||
m_was_interrupted = true;
|
|
||||||
handle_interrupt_event();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void resized()
|
void resized()
|
||||||
{
|
{
|
||||||
m_was_resized = true;
|
m_was_resized = true;
|
||||||
|
@ -277,6 +271,11 @@ private:
|
||||||
|
|
||||||
static VTState actual_rendered_string_length_step(StringMetrics&, size_t& length, u32, u32, VTState);
|
static VTState actual_rendered_string_length_step(StringMetrics&, size_t& length, u32, u32, VTState);
|
||||||
|
|
||||||
|
enum LoopExitCode {
|
||||||
|
Exit = 0,
|
||||||
|
Retry
|
||||||
|
};
|
||||||
|
|
||||||
// ^Core::Object
|
// ^Core::Object
|
||||||
virtual void save_to(JsonObject&) override;
|
virtual void save_to(JsonObject&) override;
|
||||||
|
|
||||||
|
@ -336,6 +335,7 @@ private:
|
||||||
|
|
||||||
void refresh_display();
|
void refresh_display();
|
||||||
void cleanup();
|
void cleanup();
|
||||||
|
void really_quit_event_loop();
|
||||||
|
|
||||||
void restore()
|
void restore()
|
||||||
{
|
{
|
||||||
|
|
|
@ -168,6 +168,7 @@ void Editor::finish_edit()
|
||||||
if (!m_always_refresh) {
|
if (!m_always_refresh) {
|
||||||
m_input_error = Error::Eof;
|
m_input_error = Error::Eof;
|
||||||
finish();
|
finish();
|
||||||
|
really_quit_event_loop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -238,10 +238,6 @@ int main(int argc, char** argv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
editor->on_interrupt_handled = [&] {
|
|
||||||
editor->finish();
|
|
||||||
};
|
|
||||||
|
|
||||||
shell->add_child(*editor);
|
shell->add_child(*editor);
|
||||||
|
|
||||||
Core::EventLoop::current().post_event(*shell, make<Core::CustomEvent>(Shell::ShellEventType::ReadLine));
|
Core::EventLoop::current().post_event(*shell, make<Core::CustomEvent>(Shell::ShellEventType::ReadLine));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue