summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2020-07-21 17:32:58 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2020-07-21 17:32:58 +0300
commitd623d42d937d8e7f90deda3f49fe1eb680a7b15e (patch)
treef0d917942765701ce1a8b374994a640e96b079cc
parent2fe3ce64df1924f13a9292e4df013c55e06e3ad1 (diff)
DocumentWidget: Fetching URL contents
-rw-r--r--.clang-format107
-rw-r--r--src/app.c2
-rw-r--r--src/ui/command.c2
-rw-r--r--src/ui/documentwidget.c118
-rw-r--r--src/ui/documentwidget.h2
5 files changed, 229 insertions, 2 deletions
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 00000000..0563a742
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,107 @@
1Language: Cpp
2# BasedOnStyle: Mozilla
3AccessModifierOffset: -4
4AlignAfterOpenBracket: Align
5AlignConsecutiveAssignments: true
6AlignConsecutiveDeclarations: true
7AlignEscapedNewlines: Right
8AlignOperands: true
9AlignTrailingComments: true
10AllowAllParametersOfDeclarationOnNextLine: false
11AllowShortBlocksOnASingleLine: false
12AllowShortCaseLabelsOnASingleLine: false
13AllowShortFunctionsOnASingleLine: Inline
14AllowShortIfStatementsOnASingleLine: true
15AllowShortLoopsOnASingleLine: false
16AlwaysBreakAfterDefinitionReturnType: None
17AlwaysBreakAfterReturnType: None
18AlwaysBreakBeforeMultilineStrings: false
19AlwaysBreakTemplateDeclarations: false
20BinPackArguments: false
21BinPackParameters: true
22BraceWrapping:
23 AfterClass: false
24 AfterControlStatement: false
25 AfterEnum: false
26 AfterFunction: false
27 AfterNamespace: false
28 AfterObjCDeclaration: false
29 AfterStruct: false
30 AfterUnion: false
31 BeforeCatch: true
32 BeforeElse: true
33 IndentBraces: false
34 SplitEmptyFunction: true
35 SplitEmptyRecord: false
36 SplitEmptyNamespace: true
37BreakBeforeBinaryOperators: None
38BreakBeforeBraces: Custom
39BreakBeforeInheritanceComma: true
40BreakBeforeTernaryOperators: true
41BreakConstructorInitializersBeforeComma: true
42BreakConstructorInitializers: BeforeComma
43BreakAfterJavaFieldAnnotations: false
44BreakStringLiterals: true
45ColumnLimit: 100
46CommentPragmas: '^ IWYU pragma:'
47CompactNamespaces: true
48ConstructorInitializerAllOnOneLineOrOnePerLine: false
49ConstructorInitializerIndentWidth: 4
50ContinuationIndentWidth: 4
51Cpp11BracedListStyle: false
52DerivePointerAlignment: false
53DisableFormat: false
54ExperimentalAutoDetectBinPacking: false
55FixNamespaceComments: true
56ForEachMacros:
57 - foreach
58 - Q_FOREACH
59 - BOOST_FOREACH
60#IncludeBlocks: Preserve
61IncludeCategories:
62 - Regex: '^"(llvm|llvm-c|clang|clang-c)/'
63 Priority: 2
64 - Regex: '^(<|"(gtest|gmock|isl|json)/)'
65 Priority: 3
66 - Regex: '.*'
67 Priority: 1
68IncludeIsMainRegex: '(Test)?$'
69IndentCaseLabels: true
70#IndentPPDirectives: AfterHash
71IndentWidth: 4
72IndentWrappedFunctionNames: false
73JavaScriptQuotes: Leave
74JavaScriptWrapImports: true
75KeepEmptyLinesAtTheStartOfBlocks: true
76MacroBlockBegin: ''
77MacroBlockEnd: ''
78MaxEmptyLinesToKeep: 1
79NamespaceIndentation: None
80ObjCBlockIndentWidth: 2
81ObjCSpaceAfterProperty: true
82ObjCSpaceBeforeProtocolList: false
83PenaltyBreakAssignment: 2
84PenaltyBreakBeforeFirstCallParameter: 19
85PenaltyBreakComment: 300
86PenaltyBreakFirstLessLess: 120
87PenaltyBreakString: 1000
88PenaltyExcessCharacter: 1000000
89PenaltyReturnTypeOnItsOwnLine: 200
90PointerAlignment: Right
91ReflowComments: true
92SortIncludes: true
93SortUsingDeclarations: true
94SpaceAfterCStyleCast: true
95SpaceAfterTemplateKeyword: true
96SpaceBeforeAssignmentOperators: true
97SpaceBeforeParens: ControlStatements
98SpaceInEmptyParentheses: false
99SpacesBeforeTrailingComments: 1
100SpacesInAngles: false
101SpacesInContainerLiterals: true
102SpacesInCStyleCastParentheses: false
103SpacesInParentheses: false
104SpacesInSquareBrackets: false
105Standard: Cpp11
106TabWidth: 4
107UseTab: Never
diff --git a/src/app.c b/src/app.c
index 019308be..20c9a399 100644
--- a/src/app.c
+++ b/src/app.c
@@ -101,7 +101,7 @@ static void loadPrefs_App_(iApp *d) {
101 iRangecc line = iNullRange; 101 iRangecc line = iNullRange;
102 while (nextSplit_Rangecc(&src, "\n", &line)) { 102 while (nextSplit_Rangecc(&src, "\n", &line)) {
103 iString cmd; 103 iString cmd;
104 initRange_String(&cmd, &line); 104 initRange_String(&cmd, line);
105 if (equal_Command(cstr_String(&cmd), "uiscale")) { 105 if (equal_Command(cstr_String(&cmd), "uiscale")) {
106 /* Must be handled before the window is created. */ 106 /* Must be handled before the window is created. */
107 setUiScale_Window(get_Window(), argf_Command(cstr_String(&cmd))); 107 setUiScale_Window(get_Window(), argf_Command(cstr_String(&cmd)));
diff --git a/src/ui/command.c b/src/ui/command.c
index 16a0d948..71228784 100644
--- a/src/ui/command.c
+++ b/src/ui/command.c
@@ -64,7 +64,7 @@ const iString *string_Command(const char *cmd, const char *label) {
64 iRangecc val = { valuePtr_Command(cmd, label), NULL }; 64 iRangecc val = { valuePtr_Command(cmd, label), NULL };
65 if (val.start) { 65 if (val.start) {
66 for (val.end = val.start; *val.end && !isspace(*val.end); val.end++) {} 66 for (val.end = val.start; *val.end && !isspace(*val.end); val.end++) {}
67 return collect_String(newRange_String(&val)); 67 return collect_String(newRange_String(val));
68 } 68 }
69 return collectNew_String(); 69 return collectNew_String();
70} 70}
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index 31c1a14c..e8a0ded9 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -1,20 +1,136 @@
1#include "documentwidget.h" 1#include "documentwidget.h"
2#include "paint.h" 2#include "paint.h"
3 3
4#include <the_Foundation/regexp.h>
5#include <the_Foundation/tlsrequest.h>
6
7enum iDocumentState {
8 blank_DocumentState,
9 fetching_DocumentState,
10 layout_DocumentState,
11 ready_DocumentState,
12};
13
4struct Impl_DocumentWidget { 14struct Impl_DocumentWidget {
5 iWidget widget; 15 iWidget widget;
16 enum iDocumentState state;
17 iString *url;
18 iString *source;
19 int statusCode;
20 iTlsRequest *request;
6}; 21};
7 22
23iDeclareType(Url)
24
25struct Impl_Url {
26 iRangecc protocol;
27 iRangecc host;
28 iRangecc port;
29 iRangecc path;
30 iRangecc query;
31};
32
33void init_Url(iUrl *d, const iString *text) {
34 iRegExp *pattern = new_RegExp("(.+)://([^/:?]+)(:[0-9]+)?([^?]*)(\\?.*)?", caseInsensitive_RegExpOption);
35 iRegExpMatch m;
36 if (matchString_RegExp(pattern, text, &m)) {
37 capturedRange_RegExpMatch(&m, 1, &d->protocol);
38 capturedRange_RegExpMatch(&m, 2, &d->host);
39 capturedRange_RegExpMatch(&m, 3, &d->port);
40 if (!isEmpty_Range(&d->port)) {
41 /* Don't include the colon. */
42 d->port.start++;
43 }
44 capturedRange_RegExpMatch(&m, 4, &d->path);
45 capturedRange_RegExpMatch(&m, 5, &d->query);
46 }
47 else {
48 iZap(*d);
49 }
50 iRelease(pattern);
51}
52
8iDefineObjectConstruction(DocumentWidget) 53iDefineObjectConstruction(DocumentWidget)
9 54
10void init_DocumentWidget(iDocumentWidget *d) { 55void init_DocumentWidget(iDocumentWidget *d) {
11 iWidget *w = as_Widget(d); 56 iWidget *w = as_Widget(d);
12 init_Widget(w); 57 init_Widget(w);
13 setBackgroundColor_Widget(w, gray25_ColorId); 58 setBackgroundColor_Widget(w, gray25_ColorId);
59 d->state = blank_DocumentState;
60 d->url = new_String();
61 d->statusCode = 0;
62 d->source = new_String();
63 d->request = NULL;
64
65 setUrl_DocumentWidget(d, collectNewCStr_String("gemini.circumlunar.space/"));
14} 66}
15 67
16void deinit_DocumentWidget(iDocumentWidget *d) { 68void deinit_DocumentWidget(iDocumentWidget *d) {
69 delete_String(d->source);
70 delete_String(d->url);
71}
72
73void setSource_DocumentWidget(iDocumentWidget *d, const iString *source) {
74 /* TODO: lock source during update */
75 set_String(d->source, source);
76 printf("%s\n", cstr_String(d->source));
77 d->state = layout_DocumentState;
78}
79
80static iRangecc getLine_(iRangecc text) {
81 iRangecc line = { text.start, text.start };
82 for (; *line.end != '\n' && line.end != text.end; line.end++) {}
83 return line;
84}
85
86static void requestFinished_DocumentWidget_(iAnyObject *obj) {
87 iDocumentWidget *d = obj;
88 iBlock *response = readAll_TlsRequest(d->request);
89 iRangecc responseRange = { constBegin_Block(response), constEnd_Block(response) };
90 iRangecc respLine = getLine_(responseRange);
91 responseRange.start = respLine.end + 1;
92 /* First line is the status code. */ {
93 iString *line = newRange_String(respLine);
94 trim_String(line);
95 printf("response: %s\n", cstr_String(line));
96 delete_String(line);
97 }
98 setSource_DocumentWidget(d, collect_String(newRange_String(responseRange)));
99 delete_Block(response);
100 iReleaseLater(d->request);
101 d->request = NULL;
102 fflush(stdout);
103}
104
105static void fetch_DocumentWidget_(iDocumentWidget *d) {
106 iAssert(!d->request);
107 d->state = fetching_DocumentState;
108 d->statusCode = 0;
109 iUrl url;
110 init_Url(&url, d->url);
111 d->request = new_TlsRequest();
112 uint16_t port = toInt_String(collect_String(newRange_String(url.port)));
113 if (port == 0) {
114 port = 1965; /* default Gemini port */
115 }
116 setUrl_TlsRequest(d->request, collect_String(newRange_String(url.host)), port);
117 /* The request string is an UTF-8 encoded absolute URL. */
118 iString *content = collectNew_String();
119 append_String(content, d->url);
120 appendCStr_String(content, "\r\n");
121 setContent_TlsRequest(d->request, utf8_String(content));
122 iConnect(TlsRequest, d->request, finished, d, requestFinished_DocumentWidget_);
123 submit_TlsRequest(d->request);
124}
17 125
126void setUrl_DocumentWidget(iDocumentWidget *d, const iString *url) {
127 clear_String(d->url);
128 if (indexOfCStr_String(url, "://") == iInvalidPos && !startsWithCase_String(url, "gemini:")) {
129 /* Prepend default protocol. */
130 setCStr_String(d->url, "gemini://");
131 }
132 append_String(d->url, url);
133 fetch_DocumentWidget_(d);
18} 134}
19 135
20static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *ev) { 136static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *ev) {
@@ -25,6 +141,8 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
25static void draw_DocumentWidget_(const iDocumentWidget *d) { 141static void draw_DocumentWidget_(const iDocumentWidget *d) {
26 const iWidget *w = constAs_Widget(d); 142 const iWidget *w = constAs_Widget(d);
27 draw_Widget(w); 143 draw_Widget(w);
144 if (d->state != ready_DocumentState) return;
145 /* TODO: lock source during draw */
28} 146}
29 147
30iBeginDefineSubclass(DocumentWidget, Widget) 148iBeginDefineSubclass(DocumentWidget, Widget)
diff --git a/src/ui/documentwidget.h b/src/ui/documentwidget.h
index e03e08e4..02b75e69 100644
--- a/src/ui/documentwidget.h
+++ b/src/ui/documentwidget.h
@@ -4,3 +4,5 @@
4 4
5iDeclareWidgetClass(DocumentWidget) 5iDeclareWidgetClass(DocumentWidget)
6iDeclareObjectConstruction(DocumentWidget) 6iDeclareObjectConstruction(DocumentWidget)
7
8void setUrl_DocumentWidget (iDocumentWidget *d, const iString *url);