summaryrefslogtreecommitdiff
path: root/Libraries/LibLine
diff options
context:
space:
mode:
authorAnotherTest <ali.mpfard@gmail.com>2020-08-20 20:04:55 +0430
committerAndreas Kling <kling@serenityos.org>2020-08-21 16:10:51 +0200
commit238e87de4e0b805caad470c70acef989e493b810 (patch)
tree68991d85a82c62257feeceb05ee607d675adbb85 /Libraries/LibLine
parentc8cf4651742053e11b72d736bb59a6714e89d8c7 (diff)
downloadserenity-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/LibLine')
-rw-r--r--Libraries/LibLine/Editor.cpp100
-rw-r--r--Libraries/LibLine/Editor.h14
-rw-r--r--Libraries/LibLine/InternalFunctions.cpp1
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();
}
}