summaryrefslogtreecommitdiff
path: root/src/bookmarks.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/bookmarks.c')
-rw-r--r--src/bookmarks.c135
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
51iBool hasTag_Bookmark(const iBookmark *d, const char *tag) { 53iBool 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
61void addTag_Bookmark(iBookmark *d, const char *tag) { 63void 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
79static struct {
80 uint32_t bit;
81 const char *tag;
82 iRegExp * pattern;
83 iRegExp * oldPattern;
84}
85specialTags_[] = {
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
96static 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
110static 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
133static 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
152static 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
76iDefineTypeConstruction(Bookmark) 165iDefineTypeConstruction(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
293void save_Bookmarks(const iBookmarks *d, const char *dirPath) { 387void 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
470iBool 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
562iBool filterHomepage_Bookmark(void *d, const iBookmark *bm) {
563 iUnused(d);
564 return (bm->flags & homepage_BookmarkFlag) != 0;
474} 565}
475 566
476static iBool matchUrl_(void *url, const iBookmark *bm) { 567static iBool matchUrl_(void *url, const iBookmark *bm) {
@@ -618,7 +709,7 @@ const iString *bookmarkListPage_Bookmarks(const iBookmarks *d, enum iBookmarkLis
618 709
619static iBool isRemoteSource_Bookmark_(void *context, const iBookmark *d) { 710static 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
624void remoteRequestFinished_Bookmarks_(iBookmarks *d, iGmRequest *req) { 715void 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++;