diff options
author | AnotherTest <ali.mpfard@gmail.com> | 2020-08-20 20:04:55 +0430 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-08-21 16:10:51 +0200 |
commit | 238e87de4e0b805caad470c70acef989e493b810 (patch) | |
tree | 68991d85a82c62257feeceb05ee607d675adbb85 /Libraries | |
parent | c8cf4651742053e11b72d736bb59a6714e89d8c7 (diff) | |
download | serenity-238e87de4e0b805caad470c70acef989e493b810.zip |
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.
Diffstat (limited to 'Libraries')
-rw-r--r-- | Libraries/LibLine/Editor.cpp | 100 | ||||
-rw-r--r-- | Libraries/LibLine/Editor.h | 14 | ||||
-rw-r--r-- | Libraries/LibLine/InternalFunctions.cpp | 1 |
3 files changed, 81 insertions, 34 deletions
diff --git a/Libraries/LibLine/Editor.cpp b/Libraries/LibLine/Editor.cpp index 7c97447c9f..61508f6fe0 100644 --- a/Libraries/LibLine/Editor.cpp +++ b/Libraries/LibLine/Editor.cpp @@ -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() diff --git a/Libraries/LibLine/Editor.h b/Libraries/LibLine/Editor.h index 7fb7f88d40..01640777dd 100644 --- a/Libraries/LibLine/Editor.h +++ b/Libraries/LibLine/Editor.h @@ -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() { diff --git a/Libraries/LibLine/InternalFunctions.cpp b/Libraries/LibLine/InternalFunctions.cpp index 680bd62d0a..83b93e3c80 100644 --- a/Libraries/LibLine/InternalFunctions.cpp +++ b/Libraries/LibLine/InternalFunctions.cpp @@ -168,6 +168,7 @@ void Editor::finish_edit() if (!m_always_refresh) { m_input_error = Error::Eof; finish(); + really_quit_event_loop(); } } |