From 67aa257da88fa5aa64cc632c5a54b35cb54ed574 Mon Sep 17 00:00:00 2001 From: Humdinger Date: Wed, 21 May 2025 14:16:49 +0200 Subject: [PATCH] TextSearch: Add keyboard navigation to history Move back and forth in the search history with CursorUp/Down. Entering a search text will reset the current history index (fCurrentHistoryIndex = -1), and you'll be back to the first history item next time you CursorUp. Change-Id: Id45a47756b4732ae6e22e5373c4db5249c8df198 Reviewed-on: https://review.haiku-os.org/c/haiku/+/9303 Reviewed-by: waddlesplash Tested-by: Commit checker robot --- src/apps/text_search/GrepWindow.cpp | 87 +++++++++++++++++++++++++++++ src/apps/text_search/GrepWindow.h | 2 +- src/apps/text_search/Model.cpp | 17 ++++++ src/apps/text_search/Model.h | 3 + 4 files changed, 108 insertions(+), 1 deletion(-) diff --git a/src/apps/text_search/GrepWindow.cpp b/src/apps/text_search/GrepWindow.cpp index 6e1a1a63e1..61e4821781 100644 --- a/src/apps/text_search/GrepWindow.cpp +++ b/src/apps/text_search/GrepWindow.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -71,6 +72,48 @@ static const bigtime_t kChangesPulseInterval = 150000; #endif // TRACE_FUNCTIONS +class HistoryInputFilter : public BMessageFilter { +public: + HistoryInputFilter(BHandler* target) + : BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE, B_KEY_DOWN), + fTarget(target) + { + } + + virtual filter_result Filter(BMessage* message, BHandler** _target) + { + const char* bytes; + int32 modifiers; + if (message->FindString("bytes", &bytes) != B_OK) + return B_DISPATCH_MESSAGE; + + message->FindInt32("modifiers", &modifiers); + if (modifiers & (B_SHIFT_KEY | B_OPTION_KEY | B_COMMAND_KEY | B_CONTROL_KEY)) + return B_DISPATCH_MESSAGE; + + switch (bytes[0]) { + case B_UP_ARROW: + { + fTarget.SendMessage(new BMessage(MSG_PREV_HISTORY)); + return B_SKIP_MESSAGE; + } break; + + case B_DOWN_ARROW: + { + fTarget.SendMessage(new BMessage(MSG_NEXT_HISTORY)); + return B_SKIP_MESSAGE; + } break; + + default: + return B_DISPATCH_MESSAGE; + } + } + + private: + BMessenger fTarget; +}; + + GrepWindow::GrepWindow(BMessage* message) : BWindow(BRect(0, 0, 525, 430), NULL, B_DOCUMENT_WINDOW, B_AUTO_UPDATE_SIZE_LIMITS), @@ -115,6 +158,7 @@ GrepWindow::GrepWindow(BMessage* message) fChangesIterator(NULL), fChangesPulse(NULL), + fCurrentHistoryIndex(-1), fFilePanel(NULL) { if (fModel == NULL) @@ -233,6 +277,7 @@ void GrepWindow::MessageReceived(BMessage* message) break; case MSG_SEARCH_TEXT: + fCurrentHistoryIndex = -1; // reset on user input _OnSearchText(); break; @@ -244,6 +289,46 @@ void GrepWindow::MessageReceived(BMessage* message) _OnHistoryItem(message); break; + case MSG_PREV_HISTORY: + { + if (fCurrentHistoryIndex == HISTORY_LIMIT - 1) + break; + + fCurrentHistoryIndex++; + BString text = fModel->GetHistoryItem(fCurrentHistoryIndex); + if (text != NULL) { + fSearchText->SetModificationMessage(NULL); + fSearchText->SetText(text); + fSearchText->SetModificationMessage(new BMessage(MSG_SEARCH_TEXT)); + } else + fCurrentHistoryIndex--; + + _OnSearchText(); + break; + } + case MSG_NEXT_HISTORY: + { + if (fCurrentHistoryIndex <= 0) { + fCurrentHistoryIndex = -1; + fSearchText->SetText(""); + _OnSearchText(); + break; + } + + fCurrentHistoryIndex--; + BString text = fModel->GetHistoryItem(fCurrentHistoryIndex); + if (text != NULL) { + fSearchText->SetModificationMessage(NULL); + fSearchText->SetText(text); + fSearchText->SetModificationMessage(new BMessage(MSG_SEARCH_TEXT)); + } else { + fCurrentHistoryIndex--; + fSearchText->SetText(""); + } + + _OnSearchText(); + break; + } case MSG_START_CANCEL: _OnStartCancel(); break; @@ -549,6 +634,7 @@ GrepWindow::_CreateViews() "SearchText", NULL, NULL, NULL, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_NAVIGABLE); + fSearchText->TextView()->AddFilter(new HistoryInputFilter(this)); fSearchText->TextView()->SetMaxBytes(1000); fSearchText->SetModificationMessage(new BMessage(MSG_SEARCH_TEXT)); @@ -754,6 +840,7 @@ GrepWindow::_OnStartCancel() fSearchText->SetModificationMessage(NULL); fGlobText->SetModificationMessage(NULL); + fCurrentHistoryIndex = -1; fFileMenu->SetEnabled(false); fActionMenu->SetEnabled(false); diff --git a/src/apps/text_search/GrepWindow.h b/src/apps/text_search/GrepWindow.h index d74fbdbd44..a625586b30 100644 --- a/src/apps/text_search/GrepWindow.h +++ b/src/apps/text_search/GrepWindow.h @@ -129,7 +129,7 @@ private: ChangesIterator* fChangesIterator; BMessageRunner* fChangesPulse; - + int32 fCurrentHistoryIndex; BFilePanel* fFilePanel; }; diff --git a/src/apps/text_search/Model.cpp b/src/apps/text_search/Model.cpp index 9fbe8cbc0b..8eb9e037e7 100644 --- a/src/apps/text_search/Model.cpp +++ b/src/apps/text_search/Model.cpp @@ -225,6 +225,23 @@ Model::FillHistoryMenu(BMenu* menu) const } +BString +Model::GetHistoryItem(int32 index) +{ + BList items; + if (!_LoadHistory(items)) + return NULL; + + int32 itemCount = items.CountItems() - 1; + if (index > itemCount) + return NULL; + + // latest entry is at the end of the BList + BString* itemtext = static_cast(items.ItemAt(itemCount - index)); + + return itemtext->String(); +} + // #pragma mark - private diff --git a/src/apps/text_search/Model.h b/src/apps/text_search/Model.h index d330efc875..b6d9ee3ac8 100644 --- a/src/apps/text_search/Model.h +++ b/src/apps/text_search/Model.h @@ -31,6 +31,8 @@ enum { MSG_SEARCH_GLOB_FILTER, MSG_INVOKE_ITEM, MSG_SELECT_HISTORY, + MSG_PREV_HISTORY, + MSG_NEXT_HISTORY, MSG_NODE_MONITOR_PULSE, MSG_START_NODE_MONITORING, @@ -69,6 +71,7 @@ public: void AddToHistory(const char* text); void FillHistoryMenu(BMenu* menu) const; + BString GetHistoryItem(int32 index); public: // The directory we were invoked from.