diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ad6b871..0474fe3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,8 @@ and a new `command` action to run an arbitrary command. (https://codeberg.org/dnkl/foot/pulls/483) * Dedicated `[url]` section to config. +* `[url].protocols` option to `foot.ini` + (https://codeberg.org/dnkl/foot/issues/531). * Support for setting the full 256 color palette in foot.ini (https://codeberg.org/dnkl/foot/issues/489) * XDG activation support, will be used by `[bell].urgent` when diff --git a/config.c b/config.c index 80f944b5..08446e7d 100644 --- a/config.c +++ b/config.c @@ -1001,6 +1001,47 @@ parse_section_url(const char *key, const char *value, struct config *conf, } } + else if (strcmp(key, "protocols") == 0) { + for (size_t i = 0; i < conf->url.prot_count; i++) + free(conf->url.protocols[i]); + free(conf->url.protocols); + + conf->url.max_prot_len = 0; + conf->url.prot_count = 0; + conf->url.protocols = NULL; + + char *copy = xstrdup(value); + + for (char *prot = strtok(copy, " "); + prot != NULL; + prot = strtok(NULL, " ")) + { + size_t chars = mbstowcs(NULL, prot, 0); + if (chars == (size_t)-1) { + LOG_AND_NOTIFY_ERRNO( + "%s:%u: [url]: protocols: invalid protocol name: %s", + path, lineno, prot); + return false; + } + + conf->url.prot_count++; + conf->url.protocols = xrealloc( + conf->url.protocols, + conf->url.prot_count * sizeof(conf->url.protocols[0])); + + size_t idx = conf->url.prot_count - 1; + conf->url.protocols[idx] = xmalloc((chars + 1 + 3) * sizeof(wchar_t)); + mbstowcs(conf->url.protocols[idx], prot, chars + 1); + wcscpy(&conf->url.protocols[idx][chars], L"://"); + + size_t len = chars + 3; /* Include the "://" */ + if (len > conf->url.max_prot_len) + conf->url.max_prot_len = len; + } + + free(copy); + } + else { LOG_AND_NOTIFY_ERR("%s:%d: [url]: %s: invalid key", path, lineno, key); return false; @@ -2527,6 +2568,27 @@ config_load(struct config *conf, const char *conf_path, conf->url.launch.raw_cmd = xstrdup("xdg-open ${url}"); tokenize_cmdline(conf->url.launch.raw_cmd, &conf->url.launch.argv); + static const wchar_t *url_protocols[] = { + L"http://", + L"https://", + L"ftp://", + L"ftps://", + L"file://", + L"gemini://", + L"gopher://", + }; + conf->url.protocols = xmalloc( + ALEN(url_protocols) * sizeof(conf->url.protocols[0])); + conf->url.prot_count = ALEN(url_protocols); + conf->url.max_prot_len = 0; + + for (size_t i = 0; i < ALEN(url_protocols); i++) { + size_t len = wcslen(url_protocols[i]); + if (len > conf->url.max_prot_len) + conf->url.max_prot_len = len; + conf->url.protocols[i] = xwcsdup(url_protocols[i]); + } + tll_foreach(*initial_user_notifications, it) { tll_push_back(conf->notifications, it->item); tll_remove(*initial_user_notifications, it); @@ -2644,6 +2706,10 @@ config_free(struct config conf) free(conf.url.label_letters); free_spawn_template(&conf.url.launch); + for (size_t i = 0; i < conf.url.prot_count; i++) + free(conf.url.protocols[i]); + free(conf.url.protocols); + key_binding_list_free(&conf.bindings.key); key_binding_list_free(&conf.bindings.search); key_binding_list_free(&conf.bindings.url); diff --git a/config.h b/config.h index 69fb8f07..95083e6c 100644 --- a/config.h +++ b/config.h @@ -135,6 +135,9 @@ struct config { OSC8_UNDERLINE_ALWAYS, } osc8_underline; + wchar_t **protocols; + size_t prot_count; + size_t max_prot_len; } url; struct { diff --git a/doc/foot.ini.5.scd b/doc/foot.ini.5.scd index f6a91b8a..f224c957 100644 --- a/doc/foot.ini.5.scd +++ b/doc/foot.ini.5.scd @@ -323,6 +323,13 @@ in this order: String of characters to use when generating key sequences for URL jump labels. Default: _sadfjklewcmpgh_. +*protocols* + List of protocols (schemes) that should be recognized in URL + mode. Note that only auto-detected URLs are affected by this + option. OSC-8 URLs are always enabled, regardless of + protocol. Default: _http https ftp ftps file gemini gopher_. + + # SECTION: cursor This section controls the cursor style and color. Note that diff --git a/foot.ini b/foot.ini index d6ad17ed..c4f786a9 100644 --- a/foot.ini +++ b/foot.ini @@ -45,6 +45,8 @@ # launch=xdg-open ${url} # label-letters=sadfjklewcmpgh # osc8-underline=url-mode +# protocols = http https ftp ftps file gemini gopher + [cursor] # style=block # color=111111 dcdccc diff --git a/url-mode.c b/url-mode.c index fc1812ae..dc63ebbe 100644 --- a/url-mode.c +++ b/url-mode.c @@ -212,23 +212,9 @@ static void auto_detected(const struct terminal *term, enum url_action action, url_list_t *urls) { - static const wchar_t *const prots[] = { - L"http://", - L"https://", - L"ftp://", - L"ftps://", - L"file://", - L"gemini://", - L"gopher://", - }; - - size_t max_prot_len = 0; - for (size_t i = 0; i < ALEN(prots); i++) { - size_t len = wcslen(prots[i]); - if (len > max_prot_len) - max_prot_len = len; - } + const struct config *conf = term->conf; + size_t max_prot_len = conf->url.max_prot_len; wchar_t proto_chars[max_prot_len]; struct coord proto_start[max_prot_len]; size_t proto_char_count = 0; @@ -266,15 +252,15 @@ auto_detected(const struct terminal *term, enum url_action action, proto_start[max_prot_len - 1] = (struct coord){c, r}; proto_char_count++; - for (size_t i = 0; i < ALEN(prots); i++) { - size_t prot_len = wcslen(prots[i]); + for (size_t i = 0; i < conf->url.prot_count; i++) { + size_t prot_len = wcslen(conf->url.protocols[i]); if (proto_char_count < prot_len) continue; const wchar_t *proto = &proto_chars[max_prot_len - prot_len]; - if (wcsncasecmp(prots[i], proto, prot_len) == 0) { + if (wcsncasecmp(conf->url.protocols[i], proto, prot_len) == 0) { state = STATE_URL; start = proto_start[max_prot_len - prot_len];