Skip to content

Commit

Permalink
LibLine: Handle Ctrl-C and Ctrl-D in a way similar to other line editors
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
alimpfard authored and awesomekling committed Aug 21, 2020
1 parent c8cf465 commit 238e87d
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 38 deletions.
100 changes: 73 additions & 27 deletions Libraries/LibLine/Editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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();

Expand All @@ -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 };
}
Expand All @@ -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()
Expand Down
14 changes: 7 additions & 7 deletions Libraries/LibLine/Editor.h
Original file line number Diff line number Diff line change
Expand Up @@ -196,13 +196,7 @@ class Editor : public Core::Object {

// 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;
Expand Down Expand Up @@ -277,6 +271,11 @@ class Editor : public Core::Object {

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;

Expand Down Expand Up @@ -336,6 +335,7 @@ class Editor : public Core::Object {

void refresh_display();
void cleanup();
void really_quit_event_loop();

void restore()
{
Expand Down
1 change: 1 addition & 0 deletions Libraries/LibLine/InternalFunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ void Editor::finish_edit()
if (!m_always_refresh) {
m_input_error = Error::Eof;
finish();
really_quit_event_loop();
}
}

Expand Down
4 changes: 0 additions & 4 deletions Shell/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down

0 comments on commit 238e87d

Please sign in to comment.