summaryrefslogtreecommitdiff
path: root/src/ui/lookupwidget.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/lookupwidget.c')
-rw-r--r--src/ui/lookupwidget.c69
1 files changed, 57 insertions, 12 deletions
diff --git a/src/ui/lookupwidget.c b/src/ui/lookupwidget.c
index c1c52708..74f394e6 100644
--- a/src/ui/lookupwidget.c
+++ b/src/ui/lookupwidget.c
@@ -27,6 +27,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
27#include "util.h" 27#include "util.h"
28#include "command.h" 28#include "command.h"
29#include "bookmarks.h" 29#include "bookmarks.h"
30#include "visited.h"
30#include "gmutil.h" 31#include "gmutil.h"
31#include "app.h" 32#include "app.h"
32 33
@@ -38,11 +39,13 @@ iDeclareType(LookupJob)
38 39
39struct Impl_LookupJob { 40struct Impl_LookupJob {
40 iRegExp *term; 41 iRegExp *term;
42 iTime now;
41 iPtrArray results; 43 iPtrArray results;
42}; 44};
43 45
44static void init_LookupJob(iLookupJob *d) { 46static void init_LookupJob(iLookupJob *d) {
45 d->term = NULL; 47 d->term = NULL;
48 initCurrent_Time(&d->now);
46 init_PtrArray(&d->results); 49 init_PtrArray(&d->results);
47} 50}
48 51
@@ -102,7 +105,7 @@ static void draw_LookupItem_(iLookupItem *d, iPaint *p, iRect rect, const iListW
102 const iInt2 size = measure_Text(d->font, cstr_String(&d->text)); 105 const iInt2 size = measure_Text(d->font, cstr_String(&d->text));
103 iInt2 pos = init_I2(left_Rect(rect) + 3 * gap_UI, mid_Rect(rect).y - size.y / 2); 106 iInt2 pos = init_I2(left_Rect(rect) + 3 * gap_UI, mid_Rect(rect).y - size.y / 2);
104 if (d->listItem.isSeparator) { 107 if (d->listItem.isSeparator) {
105 pos.y = bottom_Rect(rect) - lineHeight_Text(d->font) - gap_UI; 108 pos.y = bottom_Rect(rect) - lineHeight_Text(d->font);
106 } 109 }
107 drawRange_Text(d->font, pos, fg, range_String(&d->text)); 110 drawRange_Text(d->font, pos, fg, range_String(&d->text));
108} 111}
@@ -147,18 +150,31 @@ static float bookmarkRelevance_LookupJob_(const iLookupJob *d, const iBookmark *
147 return h + iMax(p, t) + 2 * g; /* extra weight for tags */ 150 return h + iMax(p, t) + 2 * g; /* extra weight for tags */
148} 151}
149 152
153static float visitedRelevance_LookupJob_(const iLookupJob *d, const iVisitedUrl *vis) {
154 iUrl parts;
155 init_Url(&parts, &vis->url);
156 const float h = scoreMatch_(d->term, parts.host);
157 const float p = scoreMatch_(d->term, parts.path);
158 const double age = secondsSince_Time(&d->now, &vis->when) / 3600.0 / 24.0; /* days */
159 return iMax(h, p) / (age + 1); /* extra weight for recency */
160}
161
150static iBool matchBookmark_LookupJob_(void *context, const iBookmark *bm) { 162static iBool matchBookmark_LookupJob_(void *context, const iBookmark *bm) {
151 return bookmarkRelevance_LookupJob_(context, bm) > 0; 163 return bookmarkRelevance_LookupJob_(context, bm) > 0;
152} 164}
153 165
154static void searchBookmarks_LookupJob_(iLookupJob *d) { 166static void searchBookmarks_LookupJob_(iLookupJob *d) {
155 /* Note: Called in a background thread. */ 167 /* Note: Called in a background thread. */
168 /* TODO: Thread safety! What if a bookmark gets deleted while its being accessed here? */
156 iConstForEach(PtrArray, i, list_Bookmarks(bookmarks_App(), NULL, matchBookmark_LookupJob_, d)) { 169 iConstForEach(PtrArray, i, list_Bookmarks(bookmarks_App(), NULL, matchBookmark_LookupJob_, d)) {
157 const iBookmark *bm = i.ptr; 170 const iBookmark *bm = i.ptr;
158 iLookupResult * res = new_LookupResult(); 171 iLookupResult * res = new_LookupResult();
159 res->type = bookmark_LookupResultType; 172 res->type = bookmark_LookupResultType;
160 res->relevance = bookmarkRelevance_LookupJob_(d, bm); 173 res->relevance = bookmarkRelevance_LookupJob_(d, bm);
161 set_String(&res->label, &bm->title); 174 appendChar_String(&res->label, bm->icon);
175 appendChar_String(&res->label, ' ');
176 append_String(&res->label, &bm->title);
177// set_String(&res->label, &bm->title);
162// appendFormat_String(&res->label, " (%f)", res->relevance); 178// appendFormat_String(&res->label, " (%f)", res->relevance);
163 set_String(&res->url, &bm->url); 179 set_String(&res->url, &bm->url);
164 res->when = bm->when; 180 res->when = bm->when;
@@ -166,6 +182,24 @@ static void searchBookmarks_LookupJob_(iLookupJob *d) {
166 } 182 }
167} 183}
168 184
185static void searchVisited_LookupJob_(iLookupJob *d) {
186 /* Note: Called in a background thread. */
187 /* TODO: Thread safety! Visited URLs may be deleted while being accessed here. */
188 iConstForEach(PtrArray, i, list_Visited(visited_App(), 0)) {
189 const iVisitedUrl *vis = i.ptr;
190 const float relevance = visitedRelevance_LookupJob_(d, vis);
191 if (relevance > 0) {
192 iLookupResult *res = new_LookupResult();
193 res->type = history_LookupResultType;
194 res->relevance = relevance;
195 set_String(&res->label, &vis->url);
196 set_String(&res->url, &vis->url);
197 res->when = vis->when;
198 pushBack_PtrArray(&d->results, res);
199 }
200 }
201}
202
169static iThreadResult worker_LookupWidget_(iThread *thread) { 203static iThreadResult worker_LookupWidget_(iThread *thread) {
170 iLookupWidget *d = userData_Thread(thread); 204 iLookupWidget *d = userData_Thread(thread);
171 printf("[LookupWidget] worker is running\n"); fflush(stdout); 205 printf("[LookupWidget] worker is running\n"); fflush(stdout);
@@ -193,7 +227,6 @@ static iThreadResult worker_LookupWidget_(iThread *thread) {
193 isFirst = iFalse; 227 isFirst = iFalse;
194 } 228 }
195 iAssert(!isEmpty_String(pattern)); 229 iAssert(!isEmpty_String(pattern));
196// printf("{%s}\n", cstr_String(pattern));
197 job->term = new_RegExp(cstr_String(pattern), caseInsensitive_RegExpOption); 230 job->term = new_RegExp(cstr_String(pattern), caseInsensitive_RegExpOption);
198 delete_String(pattern); 231 delete_String(pattern);
199 } 232 }
@@ -201,6 +234,7 @@ static iThreadResult worker_LookupWidget_(iThread *thread) {
201 unlock_Mutex(d->mtx); 234 unlock_Mutex(d->mtx);
202 /* Do the lookup. */ { 235 /* Do the lookup. */ {
203 searchBookmarks_LookupJob_(job); 236 searchBookmarks_LookupJob_(job);
237 searchVisited_LookupJob_(job);
204 } 238 }
205 /* Submit the result. */ 239 /* Submit the result. */
206 lock_Mutex(d->mtx); 240 lock_Mutex(d->mtx);
@@ -226,7 +260,7 @@ void init_LookupWidget(iLookupWidget *d) {
226 setId_Widget(w, "lookup"); 260 setId_Widget(w, "lookup");
227 setFlags_Widget(w, focusable_WidgetFlag | resizeChildren_WidgetFlag, iTrue); 261 setFlags_Widget(w, focusable_WidgetFlag | resizeChildren_WidgetFlag, iTrue);
228 d->list = addChild_Widget(w, iClob(new_ListWidget())); 262 d->list = addChild_Widget(w, iClob(new_ListWidget()));
229 setItemHeight_ListWidget(d->list, lineHeight_Text(default_FontId) * 2); 263 setItemHeight_ListWidget(d->list, lineHeight_Text(uiContent_FontId) * 1.25f);
230 d->cursor = iInvalidPos; 264 d->cursor = iInvalidPos;
231 d->work = new_Thread(worker_LookupWidget_); 265 d->work = new_Thread(worker_LookupWidget_);
232 setUserData_Thread(d->work, d); 266 setUserData_Thread(d->work, d);
@@ -321,23 +355,34 @@ static void presentResults_LookupWidget_(iLookupWidget *d) {
321 iLookupItem *item = new_LookupItem(NULL); 355 iLookupItem *item = new_LookupItem(NULL);
322 item->listItem.isSeparator = iTrue; 356 item->listItem.isSeparator = iTrue;
323 item->fg = uiHeading_ColorId; 357 item->fg = uiHeading_ColorId;
324 item->font = default_FontId; 358 item->font = uiLabel_FontId;
325 format_String(&item->text, "%s", cstr_LookupResultType(res->type)); 359 format_String(&item->text, "%s", cstr_LookupResultType(res->type));
326 addItem_ListWidget(d->list, item); 360 addItem_ListWidget(d->list, item);
327 iRelease(item); 361 iRelease(item);
328 lastType = res->type; 362 lastType = res->type;
329 } 363 }
330 iLookupItem *item = new_LookupItem(res); 364 iLookupItem *item = new_LookupItem(res);
365 const char *url = cstr_String(&res->url);
366 if (startsWithCase_String(&res->url, "gemini://")) {
367 url += 9;
368 }
331 switch (res->type) { 369 switch (res->type) {
332 case bookmark_LookupResultType: { 370 case bookmark_LookupResultType: {
333 item->fg = uiTextStrong_ColorId; 371 item->fg = uiTextStrong_ColorId;
334 item->font = default_FontId; 372 item->font = uiLabel_FontId;
335 const char *url = cstr_String(&res->url); 373 format_String(&item->text,
336 if (startsWithCase_String(&res->url, "gemini://")) { 374 "%s %s\u2014 %s",
337 url += 9; 375 cstr_String(&res->label),
338 } 376 uiText_ColorEscape,
339 format_String(&item->text, "%s\n%s Open %s", cstr_String(&res->label), 377 url);
340 uiText_ColorEscape, url); 378 format_String(&item->command, "open url:%s", cstr_String(&res->url));
379 break;
380 }
381 case history_LookupResultType: {
382 item->fg = uiText_ColorId;
383 item->font = uiContent_FontId;
384 format_String(&item->text, "%s \u2014 ", url);
385 append_String(&item->text, collect_String(format_Time(&res->when, "%b %d, %Y")));
341 format_String(&item->command, "open url:%s", cstr_String(&res->url)); 386 format_String(&item->command, "open url:%s", cstr_String(&res->url));
342 break; 387 break;
343 } 388 }