From c7b55f3d2ead592e110a1a1fb219bcb5a9009b37 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Mon, 7 Sep 2020 14:50:09 +0300 Subject: LookupWidget: Working on history content search --- src/app.c | 15 ++++++++++-- src/app.h | 2 ++ src/history.c | 42 +++++++++++++++++++++++++++++++-- src/history.h | 6 ++++- src/ui/lookupwidget.c | 64 +++++++++++++++++++++++++++++++++++++++++++-------- 5 files changed, 114 insertions(+), 15 deletions(-) diff --git a/src/app.c b/src/app.c index a7aceb19..6b78f2e4 100644 --- a/src/app.c +++ b/src/app.c @@ -254,13 +254,24 @@ static iBool loadState_App_(iApp *d) { return iFalse; } +iObjectList *listDocuments_App(void) { + iObjectList *docs = new_ObjectList(); + const iWidget *tabs = findWidget_App("doctabs"); + iForEach(ObjectList, i, children_Widget(findChild_Widget(tabs, "tabs.pages"))) { + if (isInstance_Object(i.object, &Class_DocumentWidget)) { + pushBack_ObjectList(docs, i.object); + } + } + return docs; +} + static void saveState_App_(const iApp *d) { + iUnused(d); iFile *f = newCStr_File(concatPath_CStr(dataDir_App_, stateFileName_App_)); if (open_File(f, writeOnly_FileMode)) { writeData_File(f, magicState_App_, 4); write32_File(f, 0); /* version */ - iWidget *tabs = findChild_Widget(d->window->root, "doctabs"); - iConstForEach(ObjectList, i, children_Widget(findChild_Widget(tabs, "tabs.pages"))) { + iConstForEach(ObjectList, i, iClob(listDocuments_App())) { if (isInstance_Object(i.object, &Class_DocumentWidget)) { writeData_File(f, magicTabDocument_App_, 4); write8_File(f, document_App() == i.object ? 1 : 0); diff --git a/src/app.h b/src/app.h index 09d84f19..da86c37e 100644 --- a/src/app.h +++ b/src/app.h @@ -24,6 +24,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* Application core: event loop, base event processing, audio synth. */ +#include #include #include @@ -64,6 +65,7 @@ iGmCerts * certs_App (void); iVisited * visited_App (void); iBookmarks * bookmarks_App (void); iDocumentWidget * document_App (void); +iObjectList * listDocuments_App (void); iDocumentWidget * document_Command (const char *cmd); iDocumentWidget * newTab_App (const iDocumentWidget *duplicateOf); diff --git a/src/history.c b/src/history.c index 63fa1104..57e556f7 100644 --- a/src/history.c +++ b/src/history.c @@ -67,8 +67,10 @@ void init_History(iHistory *d) { } void deinit_History(iHistory *d) { - clear_History(d); - deinit_Array(&d->recent); + iGuardMutex(d->mtx, { + clear_History(d); + deinit_Array(&d->recent); + }); delete_Mutex(d->mtx); } @@ -249,3 +251,39 @@ void setCachedResponse_History(iHistory *d, const iGmResponse *response) { } unlock_Mutex(d->mtx); } + +const iStringArray *searchContents_History(const iHistory *d, const iRegExp *pattern) { + iStringArray *urls = iClob(new_StringArray()); + lock_Mutex(d->mtx); + iConstForEach(Array, i, &d->recent) { + const iRecentUrl *url = i.value; + const iGmResponse *resp = url->cachedResponse; + if (resp && category_GmStatusCode(resp->statusCode) == categorySuccess_GmStatusCode) { + if (indexOfCStrSc_String(&resp->meta, "text/", &iCaseInsensitive) == iInvalidPos) { + continue; + } + iRegExpMatch m; + init_RegExpMatch(&m); + if (matchRange_RegExp(pattern, range_Block(&resp->body), &m)) { + iString entry; + init_String(&entry); + iRangei cap = m.range; + cap.start = iMax(cap.start - 4, 0); + cap.end = iMin(cap.end + 10, (int) size_Block(&resp->body)); + iString content; + initRange_String(&content, (iRangecc){ m.subject + cap.start, m.subject + cap.end }); + /* This needs cleaning up; highlight the matched word. */ { + + } + format_String(&entry, "match len:%zu str:%s", size_String(&content), cstr_String(&content)); + deinit_String(&content); + //appendRange_String(&entry, ); + appendFormat_String(&entry, " url:%s", cstr_String(&url->url)); + pushBack_StringArray(urls, &entry); + deinit_String(&entry); + } + } + } + unlock_Mutex(d->mtx); + return urls; +} diff --git a/src/history.h b/src/history.h index 22fe8bf8..41005d02 100644 --- a/src/history.h +++ b/src/history.h @@ -24,8 +24,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "gmrequest.h" -#include +#include +#include #include +#include #include iDeclareType(RecentUrl) @@ -55,6 +57,8 @@ iRecentUrl *recentUrl_History (iHistory *, size_t pos); iRecentUrl *mostRecentUrl_History (iHistory *); iRecentUrl *findUrl_History (iHistory *, const iString *url); +const iStringArray * searchContents_History (const iHistory *, const iRegExp *pattern); /* chronologically ascending */ + const iString * url_History (const iHistory *, size_t pos); const iRecentUrl * diff --git a/src/ui/lookupwidget.c b/src/ui/lookupwidget.c index 74f394e6..52f3d864 100644 --- a/src/ui/lookupwidget.c +++ b/src/ui/lookupwidget.c @@ -21,12 +21,14 @@ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "lookupwidget.h" +#include "documentwidget.h" #include "lookup.h" #include "listwidget.h" #include "inputwidget.h" #include "util.h" #include "command.h" #include "bookmarks.h" +#include "history.h" #include "visited.h" #include "gmutil.h" #include "app.h" @@ -40,12 +42,14 @@ iDeclareType(LookupJob) struct Impl_LookupJob { iRegExp *term; iTime now; + iObjectList *docs; iPtrArray results; }; static void init_LookupJob(iLookupJob *d) { d->term = NULL; initCurrent_Time(&d->now); + d->docs = NULL; init_PtrArray(&d->results); } @@ -54,6 +58,7 @@ static void deinit_LookupJob(iLookupJob *d) { delete_LookupResult(i.ptr); } deinit_PtrArray(&d->results); + iRelease(d->docs); iRelease(d->term); } @@ -125,7 +130,8 @@ struct Impl_LookupWidget { iThread * work; iCondition jobAvailable; /* wakes up the work thread */ iMutex * mtx; - iString nextJob; + iString pendingTerm; + iObjectList *pendingDocs; iLookupJob * finishedJob; }; @@ -200,13 +206,37 @@ static void searchVisited_LookupJob_(iLookupJob *d) { } } +static void searchHistory_LookupJob_(iLookupJob *d) { + /* Note: Called in a background thread. */ + size_t index = 0; + iForEach(ObjectList, i, d->docs) { + iConstForEach(StringArray, j, + searchContents_History(history_DocumentWidget(i.object), d->term)) { + const char *match = cstr_String(j.value); + const size_t matchLen = argLabel_Command(match, "len"); + iRangecc text; + text.start = strstr(match, " str:") + 5; + text.end = text.start + matchLen; + const char *url = strstr(text.end, " url:") + 5; + iLookupResult *res = new_LookupResult(); + res->type = content_LookupResultType; + res->relevance = ++index; /* most recent comes last */ + setCStr_String(&res->label, "..."); + appendRange_String(&res->label, text); + appendCStr_String(&res->label, "..."); + setCStr_String(&res->url, url); + pushBack_PtrArray(&d->results, res); + } + } +} + static iThreadResult worker_LookupWidget_(iThread *thread) { iLookupWidget *d = userData_Thread(thread); printf("[LookupWidget] worker is running\n"); fflush(stdout); lock_Mutex(d->mtx); for (;;) { wait_Condition(&d->jobAvailable, d->mtx); - if (isEmpty_String(&d->nextJob)) { + if (isEmpty_String(&d->pendingTerm)) { break; /* Time to quit. */ } iLookupJob *job = new_LookupJob(); @@ -214,7 +244,7 @@ static iThreadResult worker_LookupWidget_(iThread *thread) { iString *pattern = new_String(); iRangecc word = iNullRange; iBool isFirst = iTrue; - while (nextSplit_Rangecc(range_String(&d->nextJob), " ", &word)) { + while (nextSplit_Rangecc(range_String(&d->pendingTerm), " ", &word)) { if (isEmpty_Range(&word)) continue; if (!isFirst) appendChar_String(pattern, '|'); for (const char *ch = word.start; ch != word.end; ch++) { @@ -230,11 +260,14 @@ static iThreadResult worker_LookupWidget_(iThread *thread) { job->term = new_RegExp(cstr_String(pattern), caseInsensitive_RegExpOption); delete_String(pattern); } - clear_String(&d->nextJob); + clear_String(&d->pendingTerm); + job->docs = d->pendingDocs; + d->pendingDocs = NULL; unlock_Mutex(d->mtx); /* Do the lookup. */ { searchBookmarks_LookupJob_(job); searchVisited_LookupJob_(job); + searchHistory_LookupJob_(job); } /* Submit the result. */ lock_Mutex(d->mtx); @@ -266,7 +299,8 @@ void init_LookupWidget(iLookupWidget *d) { setUserData_Thread(d->work, d); init_Condition(&d->jobAvailable); d->mtx = new_Mutex(); - init_String(&d->nextJob); + init_String(&d->pendingTerm); + d->pendingDocs = NULL; d->finishedJob = NULL; start_Thread(d->work); } @@ -274,23 +308,26 @@ void init_LookupWidget(iLookupWidget *d) { void deinit_LookupWidget(iLookupWidget *d) { /* Stop the worker. */ { iGuardMutex(d->mtx, { - clear_String(&d->nextJob); + iReleasePtr(&d->pendingDocs); + clear_String(&d->pendingTerm); signal_Condition(&d->jobAvailable); }); join_Thread(d->work); iRelease(d->work); } delete_LookupJob(d->finishedJob); - deinit_String(&d->nextJob); + deinit_String(&d->pendingTerm); delete_Mutex(d->mtx); deinit_Condition(&d->jobAvailable); } void submit_LookupWidget(iLookupWidget *d, const iString *term) { iGuardMutex(d->mtx, { - set_String(&d->nextJob, term); - trim_String(&d->nextJob); - if (!isEmpty_String(&d->nextJob)) { + set_String(&d->pendingTerm, term); + trim_String(&d->pendingTerm); + iReleasePtr(&d->pendingDocs); + if (!isEmpty_String(&d->pendingTerm)) { + d->pendingDocs = listDocuments_App(); /* holds reference to all open tabs */ signal_Condition(&d->jobAvailable); } else { @@ -386,6 +423,13 @@ static void presentResults_LookupWidget_(iLookupWidget *d) { format_String(&item->command, "open url:%s", cstr_String(&res->url)); break; } + case content_LookupResultType: { + item->fg = uiText_ColorId; + item->font = uiContent_FontId; + format_String(&item->text, "%s \u2014 %s", cstr_String(&res->label), url); + format_String(&item->command, "open url:%s", cstr_String(&res->url)); + break; + } } addItem_ListWidget(d->list, item); iRelease(item); -- cgit v1.2.3