summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2020-07-29 16:40:07 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2020-07-29 16:40:19 +0300
commit72e095cf987d6bb2bc2212035a8c5498f3b6d329 (patch)
tree75e1191db056794d252ff6c6384f3763f2a0ad4b
parent67750111c420fcf97e31289bb4770cb7f69c426e (diff)
Moved History to its own type
-rw-r--r--CMakeLists.txt2
-rw-r--r--src/app.c150
-rw-r--r--src/app.h6
-rw-r--r--src/gmdocument.h1
-rw-r--r--src/history.c158
-rw-r--r--src/history.h41
-rw-r--r--src/ui/documentwidget.c8
-rw-r--r--src/ui/text.c7
8 files changed, 226 insertions, 147 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 43260264..5048360e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -42,6 +42,8 @@ set (SOURCES
42 src/gmrequest.h 42 src/gmrequest.h
43 src/gmutil.c 43 src/gmutil.c
44 src/gmutil.h 44 src/gmutil.h
45 src/history.c
46 src/history.h
45 src/stb_image.h 47 src/stb_image.h
46 src/stb_truetype.h 48 src/stb_truetype.h
47 # User interface: 49 # User interface:
diff --git a/src/app.c b/src/app.c
index 2629ff84..8d037828 100644
--- a/src/app.c
+++ b/src/app.c
@@ -1,5 +1,6 @@
1#include "app.h" 1#include "app.h"
2#include "embedded.h" 2#include "embedded.h"
3#include "history.h"
3#include "ui/command.h" 4#include "ui/command.h"
4#include "ui/window.h" 5#include "ui/window.h"
5#include "ui/inputwidget.h" 6#include "ui/inputwidget.h"
@@ -29,21 +30,6 @@
29#endif 30#endif
30 31
31iDeclareType(App) 32iDeclareType(App)
32iDeclareType(HistoryItem)
33
34struct Impl_HistoryItem {
35 iTime when;
36 iString url;
37};
38
39void init_HistoryItem(iHistoryItem *d) {
40 initCurrent_Time(&d->when);
41 init_String(&d->url);
42}
43
44void deinit_HistoryItem(iHistoryItem *d) {
45 deinit_String(&d->url);
46}
47 33
48#if defined (iPlatformApple) 34#if defined (iPlatformApple)
49static const char *dataDir_App_ = "~/Library/Application Support/fi.skyjake.Lagrange"; 35static const char *dataDir_App_ = "~/Library/Application Support/fi.skyjake.Lagrange";
@@ -57,16 +43,13 @@ static const char *dataDir_App_ = "~/.config/lagrange";
57static const char *prefsFileName_App_ = "prefs.cfg"; 43static const char *prefsFileName_App_ = "prefs.cfg";
58static const char *historyFileName_App_ = "history.txt"; 44static const char *historyFileName_App_ = "history.txt";
59 45
60static const size_t historyMax_App_ = 100;
61
62struct Impl_App { 46struct Impl_App {
63 iCommandLine args; 47 iCommandLine args;
64 iBool running; 48 iBool running;
65 iWindow * window; 49 iWindow * window;
66 iSortedArray tickers; 50 iSortedArray tickers;
67 iBool pendingRefresh; 51 iBool pendingRefresh;
68 iArray history; 52 iHistory history;
69 size_t historyPos; /* zero at the latest item */
70 /* Preferences: */ 53 /* Preferences: */
71 iBool retainWindowSize; 54 iBool retainWindowSize;
72 float uiScale; 55 float uiScale;
@@ -156,71 +139,16 @@ static void savePrefs_App_(const iApp *d) {
156 delete_String(cfg); 139 delete_String(cfg);
157} 140}
158 141
159static void saveHistory_App_(const iApp *d) {
160 iFile *f = new_File(historyFileName_());
161 if (open_File(f, writeOnly_FileMode | text_FileMode)) {
162 iString *line = new_String();
163 iConstForEach(Array, i, &d->history) {
164 const iHistoryItem *item = i.value;
165 iDate date;
166 init_Date(&date, &item->when);
167 format_String(line,
168 "%04d-%02d-%02dT%02d:%02d:%02d %s\n",
169 date.year,
170 date.month,
171 date.day,
172 date.hour,
173 date.minute,
174 date.second,
175 cstr_String(&item->url));
176 writeData_File(f, cstr_String(line), size_String(line));
177 }
178 delete_String(line);
179 }
180 iRelease(f);
181}
182
183static void loadHistory_App_(iApp *d) {
184 iFile *f = new_File(historyFileName_());
185 if (open_File(f, readOnly_FileMode | text_FileMode)) {
186 iString *src = newBlock_String(collect_Block(readAll_File(f)));
187 const iRangecc range = range_String(src);
188 iRangecc line = iNullRange;
189 while (nextSplit_Rangecc(&range, "\n", &line)) {
190 int y, m, D, H, M, S;
191 sscanf(line.start, "%04d-%02d-%02dT%02d:%02d:%02d", &y, &m, &D, &H, &M, &S);
192 if (!y) break;
193 iHistoryItem item;
194 init_HistoryItem(&item);
195 init_Time(
196 &item.when,
197 &(iDate){ .year = y, .month = m, .day = D, .hour = H, .minute = M, .second = S });
198 initCStrN_String(&item.url, line.start + 20, size_Range(&line) - 20);
199 pushBack_Array(&d->history, &item);
200 }
201 delete_String(src);
202 }
203 iRelease(f);
204}
205
206static void clearHistory_App_(iApp *d) {
207 iForEach(Array, i, &d->history) {
208 deinit_HistoryItem(i.value);
209 }
210 clear_Array(&d->history);
211}
212
213static void init_App_(iApp *d, int argc, char **argv) { 142static void init_App_(iApp *d, int argc, char **argv) {
214 init_CommandLine(&d->args, argc, argv); 143 init_CommandLine(&d->args, argc, argv);
215 init_SortedArray(&d->tickers, sizeof(iTicker), cmp_Ticker_); 144 init_SortedArray(&d->tickers, sizeof(iTicker), cmp_Ticker_);
216 init_Array(&d->history, sizeof(iHistoryItem));
217 d->historyPos = 0;
218 d->running = iFalse; 145 d->running = iFalse;
219 d->window = NULL; 146 d->window = NULL;
220 d->retainWindowSize = iTrue; 147 d->retainWindowSize = iTrue;
221 d->pendingRefresh = iFalse; 148 d->pendingRefresh = iFalse;
149 init_History(&d->history);
222 loadPrefs_App_(d); 150 loadPrefs_App_(d);
223 loadHistory_App_(d); 151 load_History(&d->history, historyFileName_());
224#if defined (iHaveLoadEmbed) 152#if defined (iHaveLoadEmbed)
225 /* Load the resources from a file. */ { 153 /* Load the resources from a file. */ {
226 if (!load_Embed( 154 if (!load_Embed(
@@ -238,9 +166,8 @@ static void init_App_(iApp *d, int argc, char **argv) {
238 166
239static void deinit_App(iApp *d) { 167static void deinit_App(iApp *d) {
240 savePrefs_App_(d); 168 savePrefs_App_(d);
241 saveHistory_App_(d); 169 save_History(&d->history, historyFileName_());
242 clearHistory_App_(d); 170 deinit_History(&d->history);
243 deinit_Array(&d->history);
244 deinit_SortedArray(&d->tickers); 171 deinit_SortedArray(&d->tickers);
245 delete_Window(d->window); 172 delete_Window(d->window);
246 d->window = NULL; 173 d->window = NULL;
@@ -393,32 +320,6 @@ static iBool handlePrefsCommands_(iWidget *d, const char *cmd) {
393 return iFalse; 320 return iFalse;
394} 321}
395 322
396static iHistoryItem *historyItem_App_(iApp *d, size_t pos) {
397 if (isEmpty_Array(&d->history)) return NULL;
398 return &value_Array(&d->history, size_Array(&d->history) - 1 - pos, iHistoryItem);
399}
400
401static const iString *historyUrl_App_(iApp *d, size_t pos) {
402 const iHistoryItem *item = historyItem_App_(d, pos);
403 if (item) {
404 return &item->url;
405 }
406 return collectNew_String();
407}
408
409static void printHistory_App_(const iApp *d) {
410#if 0
411 iConstForEach(Array, i, &d->history) {
412 const size_t idx = index_ArrayConstIterator(&i);
413 printf("%s[%zu]: %s\n",
414 d->historyPos == size_Array(&d->history) - idx - 1 ? "->" : " ",
415 idx,
416 cstr_String(&((const iHistoryItem *) i.value)->url));
417 }
418 fflush(stdout);
419#endif
420}
421
422iBool handleCommand_App(const char *cmd) { 323iBool handleCommand_App(const char *cmd) {
423 iApp *d = &app_; 324 iApp *d = &app_;
424 iWidget *root = d->window->root; 325 iWidget *root = d->window->root;
@@ -427,37 +328,16 @@ iBool handleCommand_App(const char *cmd) {
427 if (!argLabel_Command(cmd, "history")) { 328 if (!argLabel_Command(cmd, "history")) {
428 if (argLabel_Command(cmd, "redirect")) { 329 if (argLabel_Command(cmd, "redirect")) {
429 /* Update in the history. */ 330 /* Update in the history. */
430 iHistoryItem *item = historyItem_App_(d, d->historyPos); 331 iHistoryItem *item = item_History(&d->history);
431 if (item) { 332 if (item) {
432 set_String(&item->url, url); 333 set_String(&item->url, url);
433 } 334 }
434 } 335 }
435 else { 336 else {
436 /* Cut the trailing history items. */ 337 addUrl_History(&d->history, url);
437 if (d->historyPos > 0) {
438 for (size_t i = 0; i < d->historyPos - 1; i++) {
439 deinit_HistoryItem(historyItem_App_(d, i));
440 }
441 removeN_Array(
442 &d->history, size_Array(&d->history) - d->historyPos, iInvalidSize);
443 d->historyPos = 0;
444 }
445 /* Insert new item. */
446 const iHistoryItem *lastItem = historyItem_App_(d, 0);
447 if (!lastItem || cmpString_String(&lastItem->url, url) != 0) {
448 iHistoryItem item;
449 init_HistoryItem(&item);
450 set_String(&item.url, url);
451 pushBack_Array(&d->history, &item);
452 /* Don't make it too long. */
453 if (size_Array(&d->history) > historyMax_App_) {
454 deinit_HistoryItem(front_Array(&d->history));
455 remove_Array(&d->history, 0);
456 }
457 }
458 } 338 }
459 } 339 }
460 printHistory_App_(d); 340 print_History(&d->history);
461 setUrl_DocumentWidget(findChild_Widget(root, "document"), url); 341 setUrl_DocumentWidget(findChild_Widget(root, "document"), url);
462 } 342 }
463 else if (equal_Command(cmd, "document.request.cancelled")) { 343 else if (equal_Command(cmd, "document.request.cancelled")) {
@@ -499,19 +379,11 @@ iBool handleCommand_App(const char *cmd) {
499 return iFalse; 379 return iFalse;
500 } 380 }
501 else if (equal_Command(cmd, "navigate.back")) { 381 else if (equal_Command(cmd, "navigate.back")) {
502 if (d->historyPos < size_Array(&d->history) - 1) { 382 goBack_History(&d->history);
503 d->historyPos++;
504 postCommandf_App("open history:1 url:%s",
505 cstr_String(historyUrl_App_(d, d->historyPos)));
506 }
507 return iTrue; 383 return iTrue;
508 } 384 }
509 else if (equal_Command(cmd, "navigate.forward")) { 385 else if (equal_Command(cmd, "navigate.forward")) {
510 if (d->historyPos > 0) { 386 goForward_History(&d->history);
511 d->historyPos--;
512 postCommandf_App("open history:1 url:%s",
513 cstr_String(historyUrl_App_(d, d->historyPos)));
514 }
515 return iTrue; 387 return iTrue;
516 } 388 }
517 else if (equal_Command(cmd, "navigate.home")) { 389 else if (equal_Command(cmd, "navigate.home")) {
diff --git a/src/app.h b/src/app.h
index af0b6134..43de8b5a 100644
--- a/src/app.h
+++ b/src/app.h
@@ -3,6 +3,7 @@
3/* Application core: event loop, base event processing, audio synth. */ 3/* Application core: event loop, base event processing, audio synth. */
4 4
5#include <the_Foundation/string.h> 5#include <the_Foundation/string.h>
6#include <the_Foundation/time.h>
6 7
7iDeclareType(Window) 8iDeclareType(Window)
8 9
@@ -20,11 +21,12 @@ const iString *execPath_App (void);
20 21
21int run_App (int argc, char **argv); 22int run_App (int argc, char **argv);
22void processEvents_App (enum iAppEventMode mode); 23void processEvents_App (enum iAppEventMode mode);
24iBool handleCommand_App (const char *cmd);
23void refresh_App (void); 25void refresh_App (void);
24 26
27iTime urlVisitTime_App (const iString *url);
25iAny * findWidget_App (const char *id); 28iAny * findWidget_App (const char *id);
26void addTicker_App (void (*ticker)(iAny *), iAny *context); 29void addTicker_App (void (*ticker)(iAny *), iAny *context);
27
28void postRefresh_App (void); 30void postRefresh_App (void);
29void postCommand_App (const char *command); 31void postCommand_App (const char *command);
30void postCommandf_App (const char *command, ...); 32void postCommandf_App (const char *command, ...);
@@ -32,5 +34,3 @@ void postCommandf_App (const char *command, ...);
32iLocalDef void postCommandString_App(const iString *command) { 34iLocalDef void postCommandString_App(const iString *command) {
33 postCommand_App(cstr_String(command)); 35 postCommand_App(cstr_String(command));
34} 36}
35
36iBool handleCommand_App (const char *cmd);
diff --git a/src/gmdocument.h b/src/gmdocument.h
index c353c733..4997398b 100644
--- a/src/gmdocument.h
+++ b/src/gmdocument.h
@@ -20,6 +20,7 @@ enum iGmLinkFlags {
20 imageFileExtension_GmLinkFlag = iBit(6), 20 imageFileExtension_GmLinkFlag = iBit(6),
21 audioFileExtension_GmLinkFlag = iBit(7), 21 audioFileExtension_GmLinkFlag = iBit(7),
22 content_GmLinkFlag = iBit(8), /* content visible below */ 22 content_GmLinkFlag = iBit(8), /* content visible below */
23 visited_GmLinkFlag = iBit(9), /* in the history */
23}; 24};
24 25
25iDeclareType(GmImageInfo) 26iDeclareType(GmImageInfo)
diff --git a/src/history.c b/src/history.c
new file mode 100644
index 00000000..94b88677
--- /dev/null
+++ b/src/history.c
@@ -0,0 +1,158 @@
1#include "history.h"
2#include "app.h"
3
4#include <the_Foundation/file.h>
5
6static const size_t maxSize_History_ = 5000;
7
8void init_HistoryItem(iHistoryItem *d) {
9 initCurrent_Time(&d->when);
10 init_String(&d->url);
11}
12
13void deinit_HistoryItem(iHistoryItem *d) {
14 deinit_String(&d->url);
15}
16
17void init_History(iHistory *d) {
18 init_Array(&d->history, sizeof(iHistoryItem));
19 d->historyPos = 0;
20}
21
22void deinit_History(iHistory *d) {
23 clear_History(d);
24 deinit_Array(&d->history);
25}
26
27void save_History(const iHistory *d, const iString *path) {
28 iFile *f = new_File(path);
29 if (open_File(f, writeOnly_FileMode | text_FileMode)) {
30 iString *line = new_String();
31 iConstForEach(Array, i, &d->history) {
32 const iHistoryItem *item = i.value;
33 iDate date;
34 init_Date(&date, &item->when);
35 format_String(line,
36 "%04d-%02d-%02dT%02d:%02d:%02d %s\n",
37 date.year,
38 date.month,
39 date.day,
40 date.hour,
41 date.minute,
42 date.second,
43 cstr_String(&item->url));
44 writeData_File(f, cstr_String(line), size_String(line));
45 }
46 delete_String(line);
47 }
48 iRelease(f);
49}
50
51void load_History(iHistory *d, const iString *path) {
52 iFile *f = new_File(path);
53 if (open_File(f, readOnly_FileMode | text_FileMode)) {
54 iString *src = newBlock_String(collect_Block(readAll_File(f)));
55 const iRangecc range = range_String(src);
56 iRangecc line = iNullRange;
57 while (nextSplit_Rangecc(&range, "\n", &line)) {
58 int y, m, D, H, M, S;
59 sscanf(line.start, "%04d-%02d-%02dT%02d:%02d:%02d", &y, &m, &D, &H, &M, &S);
60 if (!y) break;
61 iHistoryItem item;
62 init_HistoryItem(&item);
63 init_Time(
64 &item.when,
65 &(iDate){ .year = y, .month = m, .day = D, .hour = H, .minute = M, .second = S });
66 initRange_String(&item.url, (iRangecc){ line.start + 20, line.end });
67 pushBack_Array(&d->history, &item);
68 }
69 delete_String(src);
70 }
71 iRelease(f);
72}
73
74void clear_History(iHistory *d) {
75 iForEach(Array, i, &d->history) {
76 deinit_HistoryItem(i.value);
77 }
78 clear_Array(&d->history);
79}
80
81iHistoryItem *itemAtPos_History(iHistory *d, size_t pos) {
82 if (isEmpty_Array(&d->history)) return NULL;
83 return &value_Array(&d->history, size_Array(&d->history) - 1 - pos, iHistoryItem);
84}
85
86const iString *url_History(iHistory *d, size_t pos) {
87 const iHistoryItem *item = itemAtPos_History(d, pos);
88 if (item) {
89 return &item->url;
90 }
91 return collectNew_String();
92}
93
94void addUrl_History(iHistory *d, const iString *url ){
95 /* Cut the trailing history items. */
96 if (d->historyPos > 0) {
97 for (size_t i = 0; i < d->historyPos - 1; i++) {
98 deinit_HistoryItem(itemAtPos_History(d, i));
99 }
100 removeN_Array(
101 &d->history, size_Array(&d->history) - d->historyPos, iInvalidSize);
102 d->historyPos = 0;
103 }
104 /* Insert new item. */
105 const iHistoryItem *lastItem = itemAtPos_History(d, 0);
106 if (!lastItem || cmpString_String(&lastItem->url, url) != 0) {
107 iHistoryItem item;
108 init_HistoryItem(&item);
109 set_String(&item.url, url);
110 pushBack_Array(&d->history, &item);
111 /* Don't make it too long. */
112 if (size_Array(&d->history) > maxSize_History_) {
113 deinit_HistoryItem(front_Array(&d->history));
114 remove_Array(&d->history, 0);
115 }
116 }
117}
118
119iBool goBack_History(iHistory *d) {
120 if (d->historyPos < size_Array(&d->history) - 1) {
121 d->historyPos++;
122 postCommandf_App("open history:1 url:%s",
123 cstr_String(url_History(d, d->historyPos)));
124 return iTrue;
125 }
126 return iFalse;
127}
128
129iBool goForward_History(iHistory *d) {
130 if (d->historyPos > 0) {
131 d->historyPos--;
132 postCommandf_App("open history:1 url:%s",
133 cstr_String(url_History(d, d->historyPos)));
134 return iTrue;
135 }
136 return iFalse;
137}
138
139iTime urlVisitTime_History(const iHistory *d, const iString *url) {
140 iTime when;
141 iZap(when);
142
143 return when;
144}
145
146void print_History(const iHistory *d) {
147#if 0
148 iConstForEach(Array, i, &d->history) {
149 const size_t idx = index_ArrayConstIterator(&i);
150 printf("%s[%zu]: %s\n",
151 d->historyPos == size_Array(&d->history) - idx - 1 ? "->" : " ",
152 idx,
153 cstr_String(&((const iHistoryItem *) i.value)->url));
154 }
155 fflush(stdout);
156#endif
157}
158
diff --git a/src/history.h b/src/history.h
new file mode 100644
index 00000000..15a179d6
--- /dev/null
+++ b/src/history.h
@@ -0,0 +1,41 @@
1#pragma once
2
3#include <the_Foundation/array.h>
4#include <the_Foundation/string.h>
5#include <the_Foundation/time.h>
6
7iDeclareType(History)
8iDeclareType(HistoryItem)
9
10struct Impl_HistoryItem {
11 iTime when;
12 iString url;
13};
14
15iDeclareTypeConstruction(HistoryItem)
16
17struct Impl_History {
18 iArray history;
19 size_t historyPos; /* zero at the latest item */
20};
21
22iDeclareTypeConstruction(History)
23
24void clear_History (iHistory *);
25
26void load_History (iHistory *, const iString *path);
27void save_History (const iHistory *, const iString *path);
28
29iHistoryItem * itemAtPos_History (iHistory *, size_t pos);
30const iString * url_History (iHistory *, size_t pos);
31iTime urlVisitTime_History(const iHistory *, const iString *url);
32void print_History (const iHistory *);
33
34iLocalDef iHistoryItem *item_History(iHistory *d) {
35 return itemAtPos_History(d, d->historyPos);
36}
37
38void addUrl_History (iHistory *, const iString *url);
39
40iBool goBack_History (iHistory *);
41iBool goForward_History (iHistory *);
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index e908f090..52628143 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -903,10 +903,10 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) {
903 /* Text markers. */ 903 /* Text markers. */
904 fillRange_DrawContext_(d, run, teal_ColorId, d->widget->foundMark, &d->inFoundMark); 904 fillRange_DrawContext_(d, run, teal_ColorId, d->widget->foundMark, &d->inFoundMark);
905 fillRange_DrawContext_(d, run, brown_ColorId, d->widget->selectMark, &d->inSelectMark); 905 fillRange_DrawContext_(d, run, brown_ColorId, d->widget->selectMark, &d->inSelectMark);
906 if (run->linkId) { 906 if (run->linkId && !isEmpty_Rect(run->bounds)) {
907 fg = linkColor_GmDocument(doc, run->linkId); 907 fg = white_ColorId;
908 if (isHover && ~linkFlags_GmDocument(doc, run->linkId) & content_GmLinkFlag) { 908 if (isHover || linkFlags_GmDocument(doc, run->linkId) & content_GmLinkFlag) {
909 fg = white_ColorId; 909 fg = linkColor_GmDocument(doc, run->linkId);
910 } 910 }
911 } 911 }
912 drawString_Text(run->font, visPos, fg, &text); 912 drawString_Text(run->font, visPos, fg, &text);
diff --git a/src/ui/text.c b/src/ui/text.c
index 12255fdb..ad1c37c8 100644
--- a/src/ui/text.c
+++ b/src/ui/text.c
@@ -298,6 +298,11 @@ static iChar nextChar_(const char **chPos, const char *end) {
298 298
299int enableHalfPixelGlyphs_Text = iTrue; 299int enableHalfPixelGlyphs_Text = iTrue;
300 300
301iLocalDef iBool isWrapBoundary_(iChar a, iChar b) {
302 if (b == '/' || b == '-') return iTrue;
303 return !isSpace_Char(a) && isSpace_Char(b);
304}
305
301static iInt2 run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLen, iInt2 pos, 306static iInt2 run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLen, iInt2 pos,
302 int xposLimit, const char **continueFrom_out, int *runAdvance_out) { 307 int xposLimit, const char **continueFrom_out, int *runAdvance_out) {
303 iInt2 size = zero_I2(); 308 iInt2 size = zero_I2();
@@ -364,7 +369,7 @@ static iInt2 run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLe
364 } 369 }
365 xpos += glyph->advance; 370 xpos += glyph->advance;
366 xposMax = iMax(xposMax, xpos); 371 xposMax = iMax(xposMax, xpos);
367 if (mode == measureNoWrap_RunMode || (!isSpace_Char(prevCh) && isSpace_Char(ch))) { 372 if (mode == measureNoWrap_RunMode || isWrapBoundary_(prevCh, ch)) {
368 lastWordEnd = chPos; 373 lastWordEnd = chPos;
369 } 374 }
370 /* Check the next character. */ 375 /* Check the next character. */