diff options
Diffstat (limited to 'src/bookmarks.c')
-rw-r--r-- | src/bookmarks.c | 135 |
1 files changed, 113 insertions, 22 deletions
diff --git a/src/bookmarks.c b/src/bookmarks.c index d4b20162..2606d975 100644 --- a/src/bookmarks.c +++ b/src/bookmarks.c | |||
@@ -37,6 +37,7 @@ void init_Bookmark(iBookmark *d) { | |||
37 | init_String(&d->url); | 37 | init_String(&d->url); |
38 | init_String(&d->title); | 38 | init_String(&d->title); |
39 | init_String(&d->tags); | 39 | init_String(&d->tags); |
40 | iZap(d->flags); | ||
40 | iZap(d->when); | 41 | iZap(d->when); |
41 | d->parentId = 0; | 42 | d->parentId = 0; |
42 | d->order = 0; | 43 | d->order = 0; |
@@ -48,6 +49,7 @@ void deinit_Bookmark(iBookmark *d) { | |||
48 | deinit_String(&d->url); | 49 | deinit_String(&d->url); |
49 | } | 50 | } |
50 | 51 | ||
52 | #if 0 | ||
51 | iBool hasTag_Bookmark(const iBookmark *d, const char *tag) { | 53 | iBool hasTag_Bookmark(const iBookmark *d, const char *tag) { |
52 | if (!d) return iFalse; | 54 | if (!d) return iFalse; |
53 | iRegExp *pattern = new_RegExp(format_CStr("\\b%s\\b", tag), caseSensitive_RegExpOption); | 55 | iRegExp *pattern = new_RegExp(format_CStr("\\b%s\\b", tag), caseSensitive_RegExpOption); |
@@ -60,7 +62,7 @@ iBool hasTag_Bookmark(const iBookmark *d, const char *tag) { | |||
60 | 62 | ||
61 | void addTag_Bookmark(iBookmark *d, const char *tag) { | 63 | void addTag_Bookmark(iBookmark *d, const char *tag) { |
62 | if (!isEmpty_String(&d->tags)) { | 64 | if (!isEmpty_String(&d->tags)) { |
63 | appendChar_String(&d->tags, ' '); | 65 | appendCStr_String(&d->tags, " "); |
64 | } | 66 | } |
65 | appendCStr_String(&d->tags, tag); | 67 | appendCStr_String(&d->tags, tag); |
66 | } | 68 | } |
@@ -72,6 +74,93 @@ void removeTag_Bookmark(iBookmark *d, const char *tag) { | |||
72 | trim_String(&d->tags); | 74 | trim_String(&d->tags); |
73 | } | 75 | } |
74 | } | 76 | } |
77 | #endif | ||
78 | |||
79 | static struct { | ||
80 | uint32_t bit; | ||
81 | const char *tag; | ||
82 | iRegExp * pattern; | ||
83 | iRegExp * oldPattern; | ||
84 | } | ||
85 | specialTags_[] = { | ||
86 | { homepage_BookmarkFlag, ".homepage" }, | ||
87 | { remoteSource_BookmarkFlag, ".remotesource" }, | ||
88 | { linkSplit_BookmarkFlag, ".linksplit" }, | ||
89 | { userIcon_BookmarkFlag, ".usericon" }, | ||
90 | { subscribed_BookmarkFlag, ".subscribed" }, | ||
91 | { headings_BookmarkFlag, ".headings" }, | ||
92 | { ignoreWeb_BookmarkFlag, ".ignoreweb" }, | ||
93 | /* `remote_BookmarkFlag` not included because it's runtime only */ | ||
94 | }; | ||
95 | |||
96 | static void updatePatterns_(size_t index) { | ||
97 | if (!specialTags_[index].pattern) { | ||
98 | specialTags_[index].pattern = new_RegExp(format_CStr("(?<!\\w)\\%s\\b(?!\\w)", | ||
99 | specialTags_[index].tag), | ||
100 | caseSensitive_RegExpOption); /* never released */ | ||
101 | } | ||
102 | if (!specialTags_[index].oldPattern) { | ||
103 | /* TODO: Get rid of these when compatibility with v1.9 or older is not important. */ | ||
104 | specialTags_[index].oldPattern = | ||
105 | new_RegExp(format_CStr("\\b%s\\b", specialTags_[index].tag + 1), /* dotless */ | ||
106 | caseSensitive_RegExpOption); /* never released */ | ||
107 | } | ||
108 | } | ||
109 | |||
110 | static void normalizeSpacesInTags_(iString *tags) { | ||
111 | iBool wasSpace = iFalse; | ||
112 | iString out; | ||
113 | init_String(&out); | ||
114 | for (const char *ch = constBegin_String(tags); ch != constEnd_String(tags); ch++) { | ||
115 | if (*ch == ' ') { | ||
116 | if (!wasSpace) { | ||
117 | wasSpace = iTrue; | ||
118 | } | ||
119 | else { | ||
120 | continue; | ||
121 | } | ||
122 | } | ||
123 | else { | ||
124 | wasSpace = iFalse; | ||
125 | } | ||
126 | appendData_Block(&out.chars, ch, 1); | ||
127 | } | ||
128 | trim_String(&out); | ||
129 | set_String(tags, &out); | ||
130 | deinit_String(&out); | ||
131 | } | ||
132 | |||
133 | static void unpackDotTags_Bookmark_(iBookmark *d) { | ||
134 | iZap(d->flags); | ||
135 | iForIndices(i, specialTags_) { | ||
136 | updatePatterns_(i); | ||
137 | iRegExpMatch m; | ||
138 | init_RegExpMatch(&m); | ||
139 | iBool isSet = matchString_RegExp(specialTags_[i].pattern, &d->tags, &m); | ||
140 | if (!isSet) { | ||
141 | init_RegExpMatch(&m); | ||
142 | isSet = matchString_RegExp(specialTags_[i].oldPattern, &d->tags, &m); | ||
143 | } | ||
144 | iChangeFlags(d->flags, specialTags_[i].bit, isSet); | ||
145 | if (isSet) { | ||
146 | remove_Block(&d->tags.chars, m.range.start, size_Range(&m.range)); | ||
147 | } | ||
148 | } | ||
149 | normalizeSpacesInTags_(&d->tags); | ||
150 | } | ||
151 | |||
152 | static iString *packedDotTags_Bookmark_(const iBookmark *d) { | ||
153 | iString *withDot = copy_String(&d->tags); | ||
154 | iForIndices(i, specialTags_) { | ||
155 | if (d->flags & specialTags_[i].bit) { | ||
156 | if (!isEmpty_String(withDot)) { | ||
157 | appendCStr_String(withDot, " "); | ||
158 | } | ||
159 | appendCStr_String(withDot, specialTags_[i].tag); | ||
160 | } | ||
161 | } | ||
162 | return withDot; | ||
163 | } | ||
75 | 164 | ||
76 | iDefineTypeConstruction(Bookmark) | 165 | iDefineTypeConstruction(Bookmark) |
77 | 166 | ||
@@ -176,6 +265,7 @@ static void loadOldFormat_Bookmarks(iBookmarks *d, const char *dirPath) { | |||
176 | setRange_String(&bm->title, line); | 265 | setRange_String(&bm->title, line); |
177 | nextSplit_Rangecc(src, "\n", &line); | 266 | nextSplit_Rangecc(src, "\n", &line); |
178 | setRange_String(&bm->tags, line); | 267 | setRange_String(&bm->tags, line); |
268 | unpackDotTags_Bookmark_(bm); | ||
179 | insert_Bookmarks_(d, bm); | 269 | insert_Bookmarks_(d, bm); |
180 | } | 270 | } |
181 | } | 271 | } |
@@ -220,6 +310,10 @@ static void handleKeyValue_BookmarkLoader_(void *context, const iString *table, | |||
220 | } | 310 | } |
221 | else if (!cmp_String(key, "tags") && tv->type == string_TomlType) { | 311 | else if (!cmp_String(key, "tags") && tv->type == string_TomlType) { |
222 | set_String(&bm->tags, tv->value.string); | 312 | set_String(&bm->tags, tv->value.string); |
313 | if (strstr(cstr_String(&bm->tags), "subscribed")) { | ||
314 | printf("a\n"); | ||
315 | } | ||
316 | unpackDotTags_Bookmark_(bm); | ||
223 | } | 317 | } |
224 | else if (!cmp_String(key, "icon") && tv->type == int64_TomlType) { | 318 | else if (!cmp_String(key, "icon") && tv->type == int64_TomlType) { |
225 | bm->icon = (iChar) tv->value.int64; | 319 | bm->icon = (iChar) tv->value.int64; |
@@ -292,7 +386,6 @@ void load_Bookmarks(iBookmarks *d, const char *dirPath) { | |||
292 | 386 | ||
293 | void save_Bookmarks(const iBookmarks *d, const char *dirPath) { | 387 | void save_Bookmarks(const iBookmarks *d, const char *dirPath) { |
294 | lock_Mutex(d->mtx); | 388 | lock_Mutex(d->mtx); |
295 | iRegExp *remotePattern = iClob(new_RegExp("\\bremote\\b", caseSensitive_RegExpOption)); | ||
296 | iFile *f = newCStr_File(concatPath_CStr(dirPath, fileName_Bookmarks_)); | 389 | iFile *f = newCStr_File(concatPath_CStr(dirPath, fileName_Bookmarks_)); |
297 | if (open_File(f, writeOnly_FileMode | text_FileMode)) { | 390 | if (open_File(f, writeOnly_FileMode | text_FileMode)) { |
298 | iString *str = collectNew_String(); | 391 | iString *str = collectNew_String(); |
@@ -300,13 +393,12 @@ void save_Bookmarks(const iBookmarks *d, const char *dirPath) { | |||
300 | writeData_File(f, cstr_String(str), size_String(str)); | 393 | writeData_File(f, cstr_String(str), size_String(str)); |
301 | iConstForEach(Hash, i, &d->bookmarks) { | 394 | iConstForEach(Hash, i, &d->bookmarks) { |
302 | const iBookmark *bm = (const iBookmark *) i.value; | 395 | const iBookmark *bm = (const iBookmark *) i.value; |
303 | iRegExpMatch m; | 396 | if (bm->flags & remote_BookmarkFlag) { |
304 | init_RegExpMatch(&m); | ||
305 | if (matchString_RegExp(remotePattern, &bm->tags, &m)) { | ||
306 | /* Remote bookmarks are not saved. */ | 397 | /* Remote bookmarks are not saved. */ |
307 | continue; | 398 | continue; |
308 | } | 399 | } |
309 | iBeginCollect(); | 400 | iBeginCollect(); |
401 | const iString *packedTags = collect_String(packedDotTags_Bookmark_(bm)); | ||
310 | format_String(str, | 402 | format_String(str, |
311 | "[%d]\n" | 403 | "[%d]\n" |
312 | "url = \"%s\"\n" | 404 | "url = \"%s\"\n" |
@@ -317,7 +409,7 @@ void save_Bookmarks(const iBookmarks *d, const char *dirPath) { | |||
317 | id_Bookmark(bm), | 409 | id_Bookmark(bm), |
318 | cstrCollect_String(quote_String(&bm->url, iFalse)), | 410 | cstrCollect_String(quote_String(&bm->url, iFalse)), |
319 | cstrCollect_String(quote_String(&bm->title, iFalse)), | 411 | cstrCollect_String(quote_String(&bm->title, iFalse)), |
320 | cstrCollect_String(quote_String(&bm->tags, iFalse)), | 412 | cstrCollect_String(quote_String(packedTags, iFalse)), |
321 | bm->icon, | 413 | bm->icon, |
322 | seconds_Time(&bm->when), | 414 | seconds_Time(&bm->when), |
323 | cstrCollect_String(format_Time(&bm->when, "%Y-%m-%d"))); | 415 | cstrCollect_String(format_Time(&bm->when, "%Y-%m-%d"))); |
@@ -397,7 +489,7 @@ iBool updateBookmarkIcon_Bookmarks(iBookmarks *d, const iString *url, iChar icon | |||
397 | const uint32_t id = findUrl_Bookmarks(d, url); | 489 | const uint32_t id = findUrl_Bookmarks(d, url); |
398 | if (id) { | 490 | if (id) { |
399 | iBookmark *bm = get_Bookmarks(d, id); | 491 | iBookmark *bm = get_Bookmarks(d, id); |
400 | if (!hasTag_Bookmark(bm, remote_BookmarkTag) && !hasTag_Bookmark(bm, userIcon_BookmarkTag)) { | 492 | if (~bm->flags & remote_BookmarkFlag && ~bm->flags & userIcon_BookmarkFlag) { |
401 | if (icon != bm->icon) { | 493 | if (icon != bm->icon) { |
402 | bm->icon = icon; | 494 | bm->icon = icon; |
403 | changed = iTrue; | 495 | changed = iTrue; |
@@ -422,19 +514,13 @@ iChar siteIcon_Bookmarks(const iBookmarks *d, const iString *url) { | |||
422 | if (isEmpty_String(url)) { | 514 | if (isEmpty_String(url)) { |
423 | return 0; | 515 | return 0; |
424 | } | 516 | } |
425 | static iRegExp *tagPattern_; | ||
426 | if (!tagPattern_) { | ||
427 | tagPattern_ = new_RegExp("\\b" userIcon_BookmarkTag "\\b", caseSensitive_RegExpOption); | ||
428 | } | ||
429 | const iRangecc urlRoot = urlRoot_String(url); | 517 | const iRangecc urlRoot = urlRoot_String(url); |
430 | size_t matchingSize = iInvalidSize; /* we'll pick the shortest matching */ | 518 | size_t matchingSize = iInvalidSize; /* we'll pick the shortest matching */ |
431 | iChar icon = 0; | 519 | iChar icon = 0; |
432 | lock_Mutex(d->mtx); | 520 | lock_Mutex(d->mtx); |
433 | iConstForEach(Hash, i, &d->bookmarks) { | 521 | iConstForEach(Hash, i, &d->bookmarks) { |
434 | const iBookmark *bm = (const iBookmark *) i.value; | 522 | const iBookmark *bm = (const iBookmark *) i.value; |
435 | iRegExpMatch m; | 523 | if (bm->icon && bm->flags & userIcon_BookmarkFlag) { |
436 | init_RegExpMatch(&m); | ||
437 | if (bm->icon && matchString_RegExp(tagPattern_, &bm->tags, &m)) { | ||
438 | const iRangecc bmRoot = urlRoot_String(&bm->url); | 524 | const iRangecc bmRoot = urlRoot_String(&bm->url); |
439 | if (equalRangeCase_Rangecc(urlRoot, bmRoot)) { | 525 | if (equalRangeCase_Rangecc(urlRoot, bmRoot)) { |
440 | const size_t n = size_String(&bm->url); | 526 | const size_t n = size_String(&bm->url); |
@@ -467,10 +553,15 @@ void reorder_Bookmarks(iBookmarks *d, uint32_t id, int newOrder) { | |||
467 | unlock_Mutex(d->mtx); | 553 | unlock_Mutex(d->mtx); |
468 | } | 554 | } |
469 | 555 | ||
470 | iBool filterTagsRegExp_Bookmarks(void *regExp, const iBookmark *bm) { | 556 | //iBool filterTagsRegExp_Bookmarks(void *regExp, const iBookmark *bm) { |
471 | iRegExpMatch m; | 557 | // iRegExpMatch m; |
472 | init_RegExpMatch(&m); | 558 | // init_RegExpMatch(&m); |
473 | return matchString_RegExp(regExp, &bm->tags, &m); | 559 | // return matchString_RegExp(regExp, &bm->tags, &m); |
560 | //} | ||
561 | |||
562 | iBool filterHomepage_Bookmark(void *d, const iBookmark *bm) { | ||
563 | iUnused(d); | ||
564 | return (bm->flags & homepage_BookmarkFlag) != 0; | ||
474 | } | 565 | } |
475 | 566 | ||
476 | static iBool matchUrl_(void *url, const iBookmark *bm) { | 567 | static iBool matchUrl_(void *url, const iBookmark *bm) { |
@@ -618,7 +709,7 @@ const iString *bookmarkListPage_Bookmarks(const iBookmarks *d, enum iBookmarkLis | |||
618 | 709 | ||
619 | static iBool isRemoteSource_Bookmark_(void *context, const iBookmark *d) { | 710 | static iBool isRemoteSource_Bookmark_(void *context, const iBookmark *d) { |
620 | iUnused(context); | 711 | iUnused(context); |
621 | return hasTag_Bookmark(d, remoteSource_BookmarkTag); | 712 | return (d->flags & remoteSource_BookmarkFlag) != 0; |
622 | } | 713 | } |
623 | 714 | ||
624 | void remoteRequestFinished_Bookmarks_(iBookmarks *d, iGmRequest *req) { | 715 | void remoteRequestFinished_Bookmarks_(iBookmarks *d, iGmRequest *req) { |
@@ -642,7 +733,6 @@ void requestFinished_Bookmarks(iBookmarks *d, iGmRequest *req) { | |||
642 | initCurrent_Time(&now); | 733 | initCurrent_Time(&now); |
643 | iRegExp *linkPattern = new_RegExp("^=>\\s*([^\\s]+)(\\s+(.*))?", 0); | 734 | iRegExp *linkPattern = new_RegExp("^=>\\s*([^\\s]+)(\\s+(.*))?", 0); |
644 | iString src; | 735 | iString src; |
645 | const iString *remoteTag = collectNewCStr_String("remote"); | ||
646 | initBlock_String(&src, body_GmRequest(req)); | 736 | initBlock_String(&src, body_GmRequest(req)); |
647 | iRangecc srcLine = iNullRange; | 737 | iRangecc srcLine = iNullRange; |
648 | while (nextSplit_Rangecc(range_String(&src), "\n", &srcLine)) { | 738 | while (nextSplit_Rangecc(range_String(&src), "\n", &srcLine)) { |
@@ -660,8 +750,9 @@ void requestFinished_Bookmarks(iBookmarks *d, iGmRequest *req) { | |||
660 | if (isEmpty_String(titleStr)) { | 750 | if (isEmpty_String(titleStr)) { |
661 | setRange_String(titleStr, urlHost_String(urlStr)); | 751 | setRange_String(titleStr, urlHost_String(urlStr)); |
662 | } | 752 | } |
663 | const uint32_t bmId = add_Bookmarks(d, absUrl, titleStr, remoteTag, 0x2913); | 753 | const uint32_t bmId = add_Bookmarks(d, absUrl, titleStr, NULL, 0x2913); |
664 | iBookmark *bm = get_Bookmarks(d, bmId); | 754 | iBookmark *bm = get_Bookmarks(d, bmId); |
755 | bm->flags |= remote_BookmarkFlag; | ||
665 | bm->parentId = *(uint32_t *) userData_Object(req); | 756 | bm->parentId = *(uint32_t *) userData_Object(req); |
666 | delete_String(titleStr); | 757 | delete_String(titleStr); |
667 | } | 758 | } |
@@ -690,7 +781,7 @@ void fetchRemote_Bookmarks(iBookmarks *d) { | |||
690 | size_t numRemoved = 0; | 781 | size_t numRemoved = 0; |
691 | iForEach(Hash, i, &d->bookmarks) { | 782 | iForEach(Hash, i, &d->bookmarks) { |
692 | iBookmark *bm = (iBookmark *) i.value; | 783 | iBookmark *bm = (iBookmark *) i.value; |
693 | if (hasTag_Bookmark(bm, remote_BookmarkTag)) { | 784 | if (bm->flags & remote_BookmarkFlag) { |
694 | remove_HashIterator(&i); | 785 | remove_HashIterator(&i); |
695 | delete_Bookmark(bm); | 786 | delete_Bookmark(bm); |
696 | numRemoved++; | 787 | numRemoved++; |