summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--res/about/version.gmi2
-rw-r--r--src/app.c17
-rw-r--r--src/app.h1
-rw-r--r--src/gmutil.c15
-rw-r--r--src/gmutil.h1
-rw-r--r--src/prefs.c2
-rw-r--r--src/prefs.h1
-rw-r--r--src/ui/util.c7
-rw-r--r--src/ui/window.c14
9 files changed, 54 insertions, 6 deletions
diff --git a/res/about/version.gmi b/res/about/version.gmi
index c255e533..ba94f7e2 100644
--- a/res/about/version.gmi
+++ b/res/about/version.gmi
@@ -8,7 +8,9 @@
8 8
9## 1.2 9## 1.2
10* Help is opened on first run instead of the "About Lagrange" page to make it easier to discover important Gemini links like the FAQ. 10* Help is opened on first run instead of the "About Lagrange" page to make it easier to discover important Gemini links like the FAQ.
11* Added search engine support: non-URL text entered in the navbar is passed onto the configured search query URL (Preferences > Network).
11* Short pages are centered vertically on actual page content excluding the top banner. 12* Short pages are centered vertically on actual page content excluding the top banner.
13* Added user preference for aligning all pages to the top of the window.
12* Shift+Insert can be used for pasting clipboard contents into input fields. 14* Shift+Insert can be used for pasting clipboard contents into input fields.
13* Added keybinding (F11) for toggling fullscreen mode. On macOS, the shortcut is ⌃⌘F as before. 15* Added keybinding (F11) for toggling fullscreen mode. On macOS, the shortcut is ⌃⌘F as before.
14* Added keybinding for finding text on page. 16* Added keybinding for finding text on page.
diff --git a/src/app.c b/src/app.c
index 3d3dc6f8..b5eb5688 100644
--- a/src/app.c
+++ b/src/app.c
@@ -227,6 +227,7 @@ static iString *serializePrefs_App_(const iApp *d) {
227 appendFormat_String(str, "proxy.gopher address:%s\n", cstr_String(&d->prefs.gopherProxy)); 227 appendFormat_String(str, "proxy.gopher address:%s\n", cstr_String(&d->prefs.gopherProxy));
228 appendFormat_String(str, "proxy.http address:%s\n", cstr_String(&d->prefs.httpProxy)); 228 appendFormat_String(str, "proxy.http address:%s\n", cstr_String(&d->prefs.httpProxy));
229 appendFormat_String(str, "downloads path:%s\n", cstr_String(&d->prefs.downloadDir)); 229 appendFormat_String(str, "downloads path:%s\n", cstr_String(&d->prefs.downloadDir));
230 appendFormat_String(str, "searchurl address:%s\n", cstr_String(&d->prefs.searchUrl));
230 return str; 231 return str;
231} 232}
232 233
@@ -937,6 +938,8 @@ static iBool handlePrefsCommands_(iWidget *d, const char *cmd) {
937 isSelected_Widget(findChild_Widget(d, "prefs.ostheme"))); 938 isSelected_Widget(findChild_Widget(d, "prefs.ostheme")));
938 postCommandf_App("decodeurls arg:%d", 939 postCommandf_App("decodeurls arg:%d",
939 isSelected_Widget(findChild_Widget(d, "prefs.decodeurls"))); 940 isSelected_Widget(findChild_Widget(d, "prefs.decodeurls")));
941 postCommandf_App("searchurl address:%s",
942 cstr_String(text_InputWidget(findChild_Widget(d, "prefs.searchurl"))));
940 postCommandf_App("cachesize.set arg:%d", 943 postCommandf_App("cachesize.set arg:%d",
941 toInt_String(text_InputWidget(findChild_Widget(d, "prefs.cachesize")))); 944 toInt_String(text_InputWidget(findChild_Widget(d, "prefs.cachesize"))));
942 postCommandf_App("proxy.gemini address:%s", 945 postCommandf_App("proxy.gemini address:%s",
@@ -1122,6 +1125,15 @@ iBool willUseProxy_App(const iRangecc scheme) {
1122 return schemeProxy_App(scheme) != NULL; 1125 return schemeProxy_App(scheme) != NULL;
1123} 1126}
1124 1127
1128const iString *searchQueryUrl_App(const iString *queryStringUnescaped) {
1129 iApp *d = &app_;
1130 if (isEmpty_String(&d->prefs.searchUrl)) {
1131 return collectNew_String();
1132 }
1133 const iString *escaped = urlEncode_String(queryStringUnescaped);
1134 return collectNewFormat_String("%s?%s", cstr_String(&d->prefs.searchUrl), cstr_String(escaped));
1135}
1136
1125iBool handleCommand_App(const char *cmd) { 1137iBool handleCommand_App(const char *cmd) {
1126 iApp *d = &app_; 1138 iApp *d = &app_;
1127 if (equal_Command(cmd, "config.error")) { 1139 if (equal_Command(cmd, "config.error")) {
@@ -1292,6 +1304,10 @@ iBool handleCommand_App(const char *cmd) {
1292 } 1304 }
1293 return iTrue; 1305 return iTrue;
1294 } 1306 }
1307 else if (equal_Command(cmd, "searchurl")) {
1308 setCStr_String(&d->prefs.searchUrl, suffixPtr_Command(cmd, "address"));
1309 return iTrue;
1310 }
1295 else if (equal_Command(cmd, "proxy.gemini")) { 1311 else if (equal_Command(cmd, "proxy.gemini")) {
1296 setCStr_String(&d->prefs.geminiProxy, suffixPtr_Command(cmd, "address")); 1312 setCStr_String(&d->prefs.geminiProxy, suffixPtr_Command(cmd, "address"));
1297 return iTrue; 1313 return iTrue;
@@ -1474,6 +1490,7 @@ iBool handleCommand_App(const char *cmd) {
1474 setText_InputWidget(findChild_Widget(dlg, "prefs.cachesize"), 1490 setText_InputWidget(findChild_Widget(dlg, "prefs.cachesize"),
1475 collectNewFormat_String("%d", d->prefs.maxCacheSize)); 1491 collectNewFormat_String("%d", d->prefs.maxCacheSize));
1476 setToggle_Widget(findChild_Widget(dlg, "prefs.decodeurls"), d->prefs.decodeUserVisibleURLs); 1492 setToggle_Widget(findChild_Widget(dlg, "prefs.decodeurls"), d->prefs.decodeUserVisibleURLs);
1493 setText_InputWidget(findChild_Widget(dlg, "prefs.searchurl"), &d->prefs.searchUrl);
1477 setText_InputWidget(findChild_Widget(dlg, "prefs.proxy.gemini"), &d->prefs.geminiProxy); 1494 setText_InputWidget(findChild_Widget(dlg, "prefs.proxy.gemini"), &d->prefs.geminiProxy);
1478 setText_InputWidget(findChild_Widget(dlg, "prefs.proxy.gopher"), &d->prefs.gopherProxy); 1495 setText_InputWidget(findChild_Widget(dlg, "prefs.proxy.gopher"), &d->prefs.gopherProxy);
1479 setText_InputWidget(findChild_Widget(dlg, "prefs.proxy.http"), &d->prefs.httpProxy); 1496 setText_InputWidget(findChild_Widget(dlg, "prefs.proxy.http"), &d->prefs.httpProxy);
diff --git a/src/app.h b/src/app.h
index efaf0a3e..54c60d10 100644
--- a/src/app.h
+++ b/src/app.h
@@ -75,6 +75,7 @@ iBool forceSoftwareRender_App(void);
75enum iColorTheme colorTheme_App (void); 75enum iColorTheme colorTheme_App (void);
76const iString * schemeProxy_App (iRangecc scheme); 76const iString * schemeProxy_App (iRangecc scheme);
77iBool willUseProxy_App (const iRangecc scheme); 77iBool willUseProxy_App (const iRangecc scheme);
78const iString * searchQueryUrl_App (const iString *queryStringUnescaped);
78 79
79typedef void (*iTickerFunc)(iAny *); 80typedef void (*iTickerFunc)(iAny *);
80 81
diff --git a/src/gmutil.c b/src/gmutil.c
index 0e0cccc5..32bf356f 100644
--- a/src/gmutil.c
+++ b/src/gmutil.c
@@ -272,6 +272,21 @@ const iString *absoluteUrl_String(const iString *d, const iString *urlMaybeRelat
272 return absolute; 272 return absolute;
273} 273}
274 274
275iBool isLikelyUrl_String(const iString *d) {
276 /* Guess whether a human intends the string to be an URL. This is supposed to be fuzzy;
277 not completely per-spec: a) begins with a scheme; b) has something that looks like a
278 hostname */
279 iRegExp *pattern = new_RegExp("^([a-z]+:)?//.*|"
280 "^(//)?([^/?#: ]+)([/?#:].*)$|"
281 "^(\\w+(\\.\\w+)+|localhost)$",
282 caseInsensitive_RegExpOption);
283 iRegExpMatch m;
284 init_RegExpMatch(&m);
285 const iBool likelyUrl = matchString_RegExp(pattern, d, &m);
286 iRelease(pattern);
287 return likelyUrl;
288}
289
275static iBool equalPuny_(const iString *d, iRangecc orig) { 290static iBool equalPuny_(const iString *d, iRangecc orig) {
276 if (!endsWith_String(d, "-")) { 291 if (!endsWith_String(d, "-")) {
277 return iFalse; /* This is a sufficient condition? */ 292 return iFalse; /* This is a sufficient condition? */
diff --git a/src/gmutil.h b/src/gmutil.h
index 1caf2445..26385c02 100644
--- a/src/gmutil.h
+++ b/src/gmutil.h
@@ -104,6 +104,7 @@ void init_Url (iUrl *, const iString *text);
104iRangecc urlScheme_String (const iString *); 104iRangecc urlScheme_String (const iString *);
105iRangecc urlHost_String (const iString *); 105iRangecc urlHost_String (const iString *);
106const iString * absoluteUrl_String (const iString *, const iString *urlMaybeRelative); 106const iString * absoluteUrl_String (const iString *, const iString *urlMaybeRelative);
107iBool isLikelyUrl_String (const iString *);
107void punyEncodeUrlHost_String(iString *); 108void punyEncodeUrlHost_String(iString *);
108void stripDefaultUrlPort_String(iString *); 109void stripDefaultUrlPort_String(iString *);
109const iString * urlFragmentStripped_String(const iString *); 110const iString * urlFragmentStripped_String(const iString *);
diff --git a/src/prefs.c b/src/prefs.c
index a8f34b02..f9186ab3 100644
--- a/src/prefs.c
+++ b/src/prefs.c
@@ -51,9 +51,11 @@ void init_Prefs(iPrefs *d) {
51 init_String(&d->gopherProxy); 51 init_String(&d->gopherProxy);
52 init_String(&d->httpProxy); 52 init_String(&d->httpProxy);
53 init_String(&d->downloadDir); 53 init_String(&d->downloadDir);
54 initCStr_String(&d->searchUrl, "gemini://gus.guru/search");
54} 55}
55 56
56void deinit_Prefs(iPrefs *d) { 57void deinit_Prefs(iPrefs *d) {
58 deinit_String(&d->searchUrl);
57 deinit_String(&d->geminiProxy); 59 deinit_String(&d->geminiProxy);
58 deinit_String(&d->gopherProxy); 60 deinit_String(&d->gopherProxy);
59 deinit_String(&d->httpProxy); 61 deinit_String(&d->httpProxy);
diff --git a/src/prefs.h b/src/prefs.h
index dcda695f..1889c338 100644
--- a/src/prefs.h
+++ b/src/prefs.h
@@ -48,6 +48,7 @@ struct Impl_Prefs {
48 iBool hoverLink; 48 iBool hoverLink;
49 iBool smoothScrolling; 49 iBool smoothScrolling;
50 iBool loadImageInsteadOfScrolling; 50 iBool loadImageInsteadOfScrolling;
51 iString searchUrl;
51 /* Network */ 52 /* Network */
52 iBool decodeUserVisibleURLs; 53 iBool decodeUserVisibleURLs;
53 int maxCacheSize; /* MB */ 54 int maxCacheSize; /* MB */
diff --git a/src/ui/util.c b/src/ui/util.c
index 9a98d07b..553d9078 100644
--- a/src/ui/util.c
+++ b/src/ui/util.c
@@ -1175,6 +1175,10 @@ iWidget *makePreferences_Widget(void) {
1175 } 1175 }
1176 /* Network. */ { 1176 /* Network. */ {
1177 appendTwoColumnPage_(tabs, "Network", '5', &headings, &values); 1177 appendTwoColumnPage_(tabs, "Network", '5', &headings, &values);
1178 addChild_Widget(headings, iClob(makeHeading_Widget("Search URL:")));
1179 setId_Widget(addChild_Widget(values, iClob(new_InputWidget(0))), "prefs.searchurl");
1180 addChild_Widget(headings, iClob(makeHeading_Widget("Decode URLs:")));
1181 addChild_Widget(values, iClob(makeToggle_Widget("prefs.decodeurls")));
1178 addChild_Widget(headings, iClob(makeHeading_Widget("Cache size:"))); 1182 addChild_Widget(headings, iClob(makeHeading_Widget("Cache size:")));
1179 iWidget *cacheGroup = new_Widget(); { 1183 iWidget *cacheGroup = new_Widget(); {
1180 iInputWidget *cache = new_InputWidget(4); 1184 iInputWidget *cache = new_InputWidget(4);
@@ -1183,8 +1187,6 @@ iWidget *makePreferences_Widget(void) {
1183 addChildFlags_Widget(cacheGroup, iClob(new_LabelWidget("MB", NULL)), frameless_WidgetFlag); 1187 addChildFlags_Widget(cacheGroup, iClob(new_LabelWidget("MB", NULL)), frameless_WidgetFlag);
1184 } 1188 }
1185 addChildFlags_Widget(values, iClob(cacheGroup), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag); 1189 addChildFlags_Widget(values, iClob(cacheGroup), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag);
1186 addChild_Widget(headings, iClob(makeHeading_Widget("Decode URLs:")));
1187 addChild_Widget(values, iClob(makeToggle_Widget("prefs.decodeurls")));
1188 makeTwoColumnHeading_("PROXIES", headings, values); 1190 makeTwoColumnHeading_("PROXIES", headings, values);
1189 addChild_Widget(headings, iClob(makeHeading_Widget("Gemini proxy:"))); 1191 addChild_Widget(headings, iClob(makeHeading_Widget("Gemini proxy:")));
1190 setId_Widget(addChild_Widget(values, iClob(new_InputWidget(0))), "prefs.proxy.gemini"); 1192 setId_Widget(addChild_Widget(values, iClob(new_InputWidget(0))), "prefs.proxy.gemini");
@@ -1201,6 +1203,7 @@ iWidget *makePreferences_Widget(void) {
1201 resizeToLargestPage_Widget(tabs); 1203 resizeToLargestPage_Widget(tabs);
1202 arrange_Widget(dlg); 1204 arrange_Widget(dlg);
1203 /* Set input field sizes. */ { 1205 /* Set input field sizes. */ {
1206 expandInputFieldWidth_(findChild_Widget(tabs, "prefs.searchurl"));
1204 expandInputFieldWidth_(findChild_Widget(tabs, "prefs.downloads")); 1207 expandInputFieldWidth_(findChild_Widget(tabs, "prefs.downloads"));
1205 expandInputFieldWidth_(findChild_Widget(tabs, "prefs.proxy.gemini")); 1208 expandInputFieldWidth_(findChild_Widget(tabs, "prefs.proxy.gemini"));
1206 expandInputFieldWidth_(findChild_Widget(tabs, "prefs.proxy.gopher")); 1209 expandInputFieldWidth_(findChild_Widget(tabs, "prefs.proxy.gopher"));
diff --git a/src/ui/window.c b/src/ui/window.c
index cd813acb..563d57ae 100644
--- a/src/ui/window.c
+++ b/src/ui/window.c
@@ -47,6 +47,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
47 47
48#include <the_Foundation/file.h> 48#include <the_Foundation/file.h>
49#include <the_Foundation/path.h> 49#include <the_Foundation/path.h>
50#include <the_Foundation/regexp.h>
50#include <SDL_hints.h> 51#include <SDL_hints.h>
51#include <SDL_timer.h> 52#include <SDL_timer.h>
52#include <SDL_syswm.h> 53#include <SDL_syswm.h>
@@ -419,9 +420,14 @@ static iBool handleNavBarCommands_(iWidget *navBar, const char *cmd) {
419 !isFocused_Widget(findWidget_App("lookup"))) { 420 !isFocused_Widget(findWidget_App("lookup"))) {
420 iString *newUrl = copy_String(text_InputWidget(url)); 421 iString *newUrl = copy_String(text_InputWidget(url));
421 trim_String(newUrl); 422 trim_String(newUrl);
422 postCommandf_App( 423 if (!isEmpty_String(&prefs_App()->searchUrl) && !isLikelyUrl_String(newUrl)) {
423 "open url:%s", 424 postCommandf_App("open url:%s", cstr_String(searchQueryUrl_App(newUrl)));
424 cstr_String(absoluteUrl_String(&iStringLiteral(""), collect_String(newUrl)))); 425 }
426 else {
427 postCommandf_App(
428 "open url:%s",
429 cstr_String(absoluteUrl_String(&iStringLiteral(""), collect_String(newUrl))));
430 }
425 return iTrue; 431 return iTrue;
426 } 432 }
427 } 433 }
@@ -1168,7 +1174,7 @@ static iBool handleWindowEvent_Window_(iWindow *d, const SDL_WindowEvent *ev) {
1168 //updateRootSize_Window_(d, iTrue); 1174 //updateRootSize_Window_(d, iTrue);
1169 invalidate_Window_(d); 1175 invalidate_Window_(d);
1170 d->isMinimized = iFalse; 1176 d->isMinimized = iFalse;
1171 //printf("restored %d\n", snap_Window(d)); fflush(stdout); 1177 printf("restored %d\n", snap_Window(d)); fflush(stdout);
1172 return iTrue; 1178 return iTrue;
1173 case SDL_WINDOWEVENT_MINIMIZED: 1179 case SDL_WINDOWEVENT_MINIMIZED:
1174 d->isMinimized = iTrue; 1180 d->isMinimized = iTrue;