mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-23 13:05:12 +00:00
LibLine: Implement searching via up/down arrow keys
This commit is contained in:
parent
58912994ab
commit
42f06fc305
Notes:
sideshowbarker
2024-07-19 07:26:30 +09:00
Author: https://github.com/alimpfard Commit: https://github.com/SerenityOS/serenity/commit/42f06fc305e Pull-request: https://github.com/SerenityOS/serenity/pull/1884 Reviewed-by: https://github.com/awesomekling
2 changed files with 79 additions and 44 deletions
|
@ -68,6 +68,7 @@ void Editor::clear_line()
|
|||
fflush(stdout);
|
||||
m_buffer.clear();
|
||||
m_cursor = 0;
|
||||
m_inline_search_cursor = m_cursor;
|
||||
}
|
||||
|
||||
void Editor::insert(const String& string)
|
||||
|
@ -82,12 +83,14 @@ void Editor::insert(const char ch)
|
|||
if (m_cursor == m_buffer.size()) {
|
||||
m_buffer.append(ch);
|
||||
m_cursor = m_buffer.size();
|
||||
m_inline_search_cursor = m_cursor;
|
||||
return;
|
||||
}
|
||||
|
||||
m_buffer.insert(m_cursor, ch);
|
||||
++m_chars_inserted_in_the_middle;
|
||||
++m_cursor;
|
||||
m_inline_search_cursor = m_cursor;
|
||||
}
|
||||
|
||||
void Editor::register_character_input_callback(char ch, Function<bool(Editor&)> callback)
|
||||
|
@ -195,50 +198,67 @@ String Editor::get_line(const String& prompt)
|
|||
case InputState::ExpectFinal:
|
||||
switch (ch) {
|
||||
case 'A': // up
|
||||
if (m_history_cursor > 0)
|
||||
--m_history_cursor;
|
||||
if (m_history_cursor < m_history.size()) {
|
||||
auto& line = m_history[m_history_cursor];
|
||||
m_buffer.clear();
|
||||
for (auto& c : line)
|
||||
m_buffer.append(c);
|
||||
m_cursor = m_buffer.size();
|
||||
m_refresh_needed = true;
|
||||
{
|
||||
m_searching_backwards = true;
|
||||
auto inline_search_cursor = m_inline_search_cursor;
|
||||
String search_phrase { m_buffer.data(), inline_search_cursor };
|
||||
if (search(search_phrase, true, true)) {
|
||||
++m_search_offset;
|
||||
} else {
|
||||
insert(search_phrase);
|
||||
}
|
||||
m_inline_search_cursor = inline_search_cursor;
|
||||
m_state = InputState::Free;
|
||||
continue;
|
||||
}
|
||||
case 'B': // down
|
||||
if (m_history_cursor < m_history.size())
|
||||
++m_history_cursor;
|
||||
if (m_history_cursor < m_history.size()) {
|
||||
auto& line = m_history[m_history_cursor];
|
||||
{
|
||||
auto inline_search_cursor = m_inline_search_cursor;
|
||||
String search_phrase { m_buffer.data(), inline_search_cursor };
|
||||
auto search_changed_directions = m_searching_backwards;
|
||||
m_searching_backwards = false;
|
||||
if (m_search_offset > 0) {
|
||||
m_search_offset -= 1 + search_changed_directions;
|
||||
if (!search(search_phrase, true, true)) {
|
||||
insert(search_phrase);
|
||||
}
|
||||
} else {
|
||||
m_search_offset = 0;
|
||||
m_cursor = 0;
|
||||
m_buffer.clear();
|
||||
for (auto& c : line)
|
||||
m_buffer.append(c);
|
||||
m_cursor = m_buffer.size();
|
||||
insert(search_phrase);
|
||||
m_refresh_needed = true;
|
||||
}
|
||||
m_inline_search_cursor = inline_search_cursor;
|
||||
m_state = InputState::Free;
|
||||
continue;
|
||||
}
|
||||
case 'D': // left
|
||||
if (m_cursor > 0) {
|
||||
--m_cursor;
|
||||
}
|
||||
m_inline_search_cursor = m_cursor;
|
||||
m_state = InputState::Free;
|
||||
continue;
|
||||
case 'C': // right
|
||||
if (m_cursor < m_buffer.size()) {
|
||||
++m_cursor;
|
||||
}
|
||||
m_inline_search_cursor = m_cursor;
|
||||
m_search_offset = 0;
|
||||
m_state = InputState::Free;
|
||||
continue;
|
||||
case 'H':
|
||||
m_cursor = 0;
|
||||
m_inline_search_cursor = m_cursor;
|
||||
m_search_offset = 0;
|
||||
m_state = InputState::Free;
|
||||
continue;
|
||||
case 'F':
|
||||
m_cursor = m_buffer.size();
|
||||
m_state = InputState::Free;
|
||||
m_inline_search_cursor = m_cursor;
|
||||
m_search_offset = 0;
|
||||
continue;
|
||||
case 'Z': // shift+tab
|
||||
reverse_tab = true;
|
||||
|
@ -252,6 +272,7 @@ String Editor::get_line(const String& prompt)
|
|||
}
|
||||
m_buffer.remove(m_cursor);
|
||||
m_refresh_needed = true;
|
||||
m_search_offset = 0;
|
||||
m_state = InputState::ExpectTerminator;
|
||||
continue;
|
||||
default:
|
||||
|
@ -278,6 +299,8 @@ String Editor::get_line(const String& prompt)
|
|||
}
|
||||
}
|
||||
|
||||
m_search_offset = 0; // reset search offset on any key
|
||||
|
||||
if (ch == '\t' || reverse_tab) {
|
||||
if (!on_tab_complete_first_token || !on_tab_complete_other_token)
|
||||
continue;
|
||||
|
@ -379,6 +402,7 @@ String Editor::get_line(const String& prompt)
|
|||
for (size_t i = m_next_suggestion_invariant_offset; i < shown_length; ++i)
|
||||
m_buffer.remove(actual_offset);
|
||||
m_cursor = actual_offset;
|
||||
m_inline_search_cursor = m_cursor;
|
||||
m_refresh_needed = true;
|
||||
}
|
||||
m_last_shown_suggestion = m_suggestions[m_next_suggestion_index];
|
||||
|
@ -525,6 +549,7 @@ String Editor::get_line(const String& prompt)
|
|||
}
|
||||
m_buffer.remove(m_cursor - 1);
|
||||
--m_cursor;
|
||||
m_inline_search_cursor = m_cursor;
|
||||
// we will have to redraw :(
|
||||
m_refresh_needed = true;
|
||||
};
|
||||
|
@ -580,34 +605,7 @@ String Editor::get_line(const String& prompt)
|
|||
m_search_editor = make<Editor>(true); // Has anyone seen 'Inception'?
|
||||
m_search_editor->initialize();
|
||||
m_search_editor->on_display_refresh = [this](Editor& search_editor) {
|
||||
int last_matching_offset = -1;
|
||||
|
||||
// do not search for empty strings
|
||||
if (search_editor.buffer().size() > 0) {
|
||||
size_t search_offset = m_search_offset;
|
||||
StringView search_term { search_editor.buffer().data(), search_editor.buffer().size() };
|
||||
for (size_t i = m_history_cursor; i > 0; --i) {
|
||||
if (m_history[i - 1].contains(search_term)) {
|
||||
last_matching_offset = i - 1;
|
||||
if (search_offset == 0)
|
||||
break;
|
||||
--search_offset;
|
||||
}
|
||||
}
|
||||
|
||||
if (last_matching_offset == -1) {
|
||||
fputc('\a', stdout);
|
||||
fflush(stdout);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_buffer.clear();
|
||||
m_cursor = 0;
|
||||
if (last_matching_offset >= 0)
|
||||
insert(m_history[last_matching_offset]);
|
||||
// always needed
|
||||
m_refresh_needed = true;
|
||||
search(StringView { search_editor.buffer().data(), search_editor.buffer().size() });
|
||||
refresh_display();
|
||||
return;
|
||||
};
|
||||
|
@ -691,6 +689,40 @@ String Editor::get_line(const String& prompt)
|
|||
}
|
||||
}
|
||||
|
||||
bool Editor::search(const StringView& phrase, bool allow_empty, bool from_beginning)
|
||||
{
|
||||
|
||||
int last_matching_offset = -1;
|
||||
|
||||
// do not search for empty strings
|
||||
if (allow_empty || phrase.length() > 0) {
|
||||
size_t search_offset = m_search_offset;
|
||||
for (size_t i = m_history_cursor; i > 0; --i) {
|
||||
auto contains = from_beginning ? m_history[i - 1].starts_with(phrase) : m_history[i - 1].contains(phrase);
|
||||
if (contains) {
|
||||
last_matching_offset = i - 1;
|
||||
if (search_offset == 0)
|
||||
break;
|
||||
--search_offset;
|
||||
}
|
||||
}
|
||||
|
||||
if (last_matching_offset == -1) {
|
||||
fputc('\a', stdout);
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
m_buffer.clear();
|
||||
m_cursor = 0;
|
||||
if (last_matching_offset >= 0) {
|
||||
insert(m_history[last_matching_offset]);
|
||||
}
|
||||
// always needed
|
||||
m_refresh_needed = true;
|
||||
return last_matching_offset >= 0;
|
||||
}
|
||||
|
||||
void Editor::recalculate_origin()
|
||||
{
|
||||
// changing the columns can affect our origin if
|
||||
|
|
|
@ -160,6 +160,7 @@ private:
|
|||
|
||||
Style find_applicable_style(size_t offset) const;
|
||||
|
||||
bool search(const StringView&, bool allow_empty = false, bool from_beginning = false);
|
||||
inline void end_search()
|
||||
{
|
||||
m_is_searching = false;
|
||||
|
@ -222,6 +223,7 @@ private:
|
|||
bool m_is_searching { false };
|
||||
bool m_reset_buffer_on_search_end { true };
|
||||
size_t m_search_offset { 0 };
|
||||
bool m_searching_backwards { true };
|
||||
size_t m_pre_search_cursor { 0 };
|
||||
Vector<char, 1024> m_pre_search_buffer;
|
||||
|
||||
|
@ -229,6 +231,7 @@ private:
|
|||
ByteBuffer m_pending_chars;
|
||||
size_t m_cursor { 0 };
|
||||
size_t m_drawn_cursor { 0 };
|
||||
size_t m_inline_search_cursor { 0 };
|
||||
size_t m_chars_inserted_in_the_middle { 0 };
|
||||
size_t m_times_tab_pressed { 0 };
|
||||
size_t m_num_columns { 0 };
|
||||
|
|
Loading…
Add table
Reference in a new issue