From c106451daf76ce05592fa6f8226df9002ab531c0 Mon Sep 17 00:00:00 2001 From: Linus Groh Date: Sat, 11 Apr 2020 19:35:39 +0100 Subject: [PATCH] LibLine: Cycle backward through suggestions using Shift+Tab --- Libraries/LibLine/Editor.cpp | 37 +++++++++++++++++++++++++++++++++--- Libraries/LibLine/Editor.h | 6 ++++++ 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/Libraries/LibLine/Editor.cpp b/Libraries/LibLine/Editor.cpp index 15ee4c9b04..d01d8addd5 100644 --- a/Libraries/LibLine/Editor.cpp +++ b/Libraries/LibLine/Editor.cpp @@ -159,6 +159,7 @@ String Editor::get_line(const String& prompt) exit(2); } + auto reverse_tab = false; auto do_delete = [&] { if (m_cursor == m_buffer.size()) { fputc('\a', stdout); @@ -167,6 +168,14 @@ String Editor::get_line(const String& prompt) } m_buffer.remove(m_cursor); }; + auto increment_suggestion_index = [&] { + m_next_suggestion_index = (m_next_suggestion_index + 1) % m_suggestions.size(); + }; + auto decrement_suggestion_index = [&] { + if (m_next_suggestion_index == 0) + m_next_suggestion_index = m_suggestions.size(); + m_next_suggestion_index--; + }; for (ssize_t i = 0; i < nread; ++i) { char ch = keybuf[i]; if (ch == 0) @@ -229,6 +238,10 @@ String Editor::get_line(const String& prompt) m_cursor = m_buffer.size(); m_state = InputState::Free; continue; + case 'Z': // shift+tab + reverse_tab = true; + m_state = InputState::Free; + break; case '3': do_delete(); m_state = InputState::ExpectTerminator; @@ -257,11 +270,13 @@ String Editor::get_line(const String& prompt) } } - if (ch == '\t') { + if (ch == '\t' || reverse_tab) { if (!on_tab_complete_first_token || !on_tab_complete_other_token) continue; bool is_empty_token = m_cursor == 0 || m_buffer[m_cursor - 1] == ' '; + + // reverse tab can count as regular tab here m_times_tab_pressed++; int token_start = m_cursor - 1; @@ -290,6 +305,19 @@ String Editor::get_line(const String& prompt) m_suggestions = on_tab_complete_other_token(token); } + // Adjust already incremented / decremented index when switching tab direction + if (reverse_tab && m_tab_direction != TabDirection::Backward) { + decrement_suggestion_index(); + decrement_suggestion_index(); + m_tab_direction = TabDirection::Backward; + } + if (!reverse_tab && m_tab_direction != TabDirection::Forward) { + increment_suggestion_index(); + increment_suggestion_index(); + m_tab_direction = TabDirection::Forward; + } + reverse_tab = false; + auto current_suggestion_index = m_next_suggestion_index; if (m_next_suggestion_index < m_suggestions.size()) { if (!m_last_shown_suggestion.is_null()) { @@ -301,7 +329,10 @@ String Editor::get_line(const String& prompt) } m_last_shown_suggestion = m_suggestions[m_next_suggestion_index]; insert(m_last_shown_suggestion.substring_view(m_next_suggestion_invariant_offset, m_last_shown_suggestion.length() - m_next_suggestion_invariant_offset)); - m_next_suggestion_index = (m_next_suggestion_index + 1) % m_suggestions.size(); + if (m_tab_direction == TabDirection::Forward) + increment_suggestion_index(); + else + decrement_suggestion_index(); } else { m_next_suggestion_index = 0; } @@ -406,7 +437,7 @@ String Editor::get_line(const String& prompt) m_refresh_needed = true; continue; } - if (ch == 0xc) { // ^L + if (ch == 0xc) { // ^L printf("\033[3J\033[H\033[2J"); // Clear screen. vt_move_absolute(1, 1); m_origin_x = 1; diff --git a/Libraries/LibLine/Editor.h b/Libraries/LibLine/Editor.h index 187ae7ac09..a5817c83dc 100644 --- a/Libraries/LibLine/Editor.h +++ b/Libraries/LibLine/Editor.h @@ -200,6 +200,12 @@ private: size_t m_next_suggestion_index { 0 }; size_t m_next_suggestion_invariant_offset { 0 }; + enum class TabDirection { + Forward, + Backward, + }; + TabDirection m_tab_direction { TabDirection::Forward }; + HashMap> m_key_callbacks; // TODO: handle signals internally