diff --git a/Libraries/LibLine/Editor.cpp b/Libraries/LibLine/Editor.cpp index 815b33ee39..5626892033 100644 --- a/Libraries/LibLine/Editor.cpp +++ b/Libraries/LibLine/Editor.cpp @@ -867,38 +867,42 @@ void Editor::handle_read_event() } } -bool Editor::search(const StringView& phrase, bool allow_empty, bool from_beginning) +bool Editor::search(const StringView& phrase, bool allow_empty) { int last_matching_offset = -1; + bool found = false; // 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); + auto contains = m_history[i - 1].starts_with(phrase); if (contains) { last_matching_offset = i - 1; - if (search_offset == 0) + if (search_offset == 0) { + found = true; break; + } --search_offset; } } - if (last_matching_offset == -1) { + if (!found) { fputc('\a', stderr); fflush(stderr); } } - m_buffer.clear(); - m_cursor = 0; - if (last_matching_offset >= 0) { + if (found) { + m_buffer.clear(); + m_cursor = 0; insert(m_history[last_matching_offset]); + // Always needed, as we have cleared the buffer above. + m_refresh_needed = true; } - // Always needed, as we have cleared the buffer above. - m_refresh_needed = true; - return last_matching_offset >= 0; + + return found; } void Editor::recalculate_origin() diff --git a/Libraries/LibLine/Editor.h b/Libraries/LibLine/Editor.h index 2774ab3901..82c3b5b299 100644 --- a/Libraries/LibLine/Editor.h +++ b/Libraries/LibLine/Editor.h @@ -300,7 +300,7 @@ private: Style find_applicable_style(size_t offset) const; - bool search(const StringView&, bool allow_empty = false, bool from_beginning = false); + bool search(const StringView&, bool allow_empty = false); inline void end_search() { m_is_searching = false; @@ -323,6 +323,8 @@ private: m_cursor = 0; m_drawn_cursor = 0; m_inline_search_cursor = 0; + m_search_offset = 0; + m_search_offset_state = SearchOffsetState::Unbiased; m_old_prompt_metrics = m_cached_prompt_metrics; set_origin(0, 0); m_prompt_lines_at_suggestion_initiation = 0; @@ -404,7 +406,11 @@ 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 }; + enum class SearchOffsetState { + Unbiased, + Backwards, + Forwards, + } m_search_offset_state { SearchOffsetState::Unbiased }; size_t m_pre_search_cursor { 0 }; Vector m_pre_search_buffer; diff --git a/Libraries/LibLine/InternalFunctions.cpp b/Libraries/LibLine/InternalFunctions.cpp index 83b93e3c80..f949ef2053 100644 --- a/Libraries/LibLine/InternalFunctions.cpp +++ b/Libraries/LibLine/InternalFunctions.cpp @@ -48,40 +48,45 @@ Function Editor::find_internal_function(const StringView& name) void Editor::search_forwards() { - auto inline_search_cursor = m_inline_search_cursor; + ScopedValueRollback inline_search_cursor_rollback { m_inline_search_cursor }; StringBuilder builder; - builder.append(Utf32View { m_buffer.data(), inline_search_cursor }); + builder.append(Utf32View { m_buffer.data(), m_inline_search_cursor }); String search_phrase = builder.to_string(); - auto search_changed_directions = m_searching_backwards; - m_searching_backwards = false; + if (m_search_offset_state == SearchOffsetState::Backwards) + --m_search_offset; if (m_search_offset > 0) { - m_search_offset -= 1 + search_changed_directions; - if (!search(search_phrase, true, true)) { - insert(search_phrase); + ScopedValueRollback search_offset_rollback { m_search_offset }; + --m_search_offset; + if (search(search_phrase, true)) { + m_search_offset_state = SearchOffsetState::Forwards; + search_offset_rollback.set_override_rollback_value(m_search_offset); + } else { + m_search_offset_state = SearchOffsetState::Unbiased; } } else { - m_search_offset = 0; + m_search_offset_state = SearchOffsetState::Unbiased; m_cursor = 0; m_buffer.clear(); insert(search_phrase); m_refresh_needed = true; } - m_inline_search_cursor = inline_search_cursor; } void Editor::search_backwards() { - m_searching_backwards = true; - auto inline_search_cursor = m_inline_search_cursor; + ScopedValueRollback inline_search_cursor_rollback { m_inline_search_cursor }; StringBuilder builder; - builder.append(Utf32View { m_buffer.data(), inline_search_cursor }); + builder.append(Utf32View { m_buffer.data(), m_inline_search_cursor }); String search_phrase = builder.to_string(); - if (search(search_phrase, true, true)) { + if (m_search_offset_state == SearchOffsetState::Forwards) + ++m_search_offset; + if (search(search_phrase, true)) { + m_search_offset_state = SearchOffsetState::Backwards; ++m_search_offset; } else { - insert(search_phrase); + m_search_offset_state = SearchOffsetState::Unbiased; + --m_search_offset; } - m_inline_search_cursor = inline_search_cursor; } void Editor::cursor_left_word() @@ -239,7 +244,10 @@ void Editor::enter_search() m_search_editor->on_display_refresh = [this](Editor& search_editor) { StringBuilder builder; builder.append(Utf32View { search_editor.buffer().data(), search_editor.buffer().size() }); - search(builder.build()); + if (!search(builder.build())) { + m_buffer.clear(); + m_cursor = 0; + } refresh_display(); };