Merge branch 'configurable-protocols-to-match-in-url-mode'

Closes #531
This commit is contained in:
Daniel Eklöf 2021-05-22 14:51:15 +02:00
commit 458dd66135
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
7 changed files with 236 additions and 70 deletions

View file

@ -40,9 +40,12 @@
* Unicode 13 characters U+1FB70 - U+1FB8B to list of box drawing
characters rendered by foot itself (rather than using font glyphs)
(https://codeberg.org/dnkl/foot/issues/471).
* Dedicated bell section in config, supporting multiple actions and
a new `command` action to run an arbitrary command.
* Dedicated `[bell]` section to config, supporting multiple actions
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
@ -83,7 +86,14 @@
### Deprecated
* **bell** option in `foot.ini`; set actions in **[bell]** section instead.
* `bell` option in `foot.ini`; set actions in the `[bell]` section
instead.
* `url-launch` option in `foot.ini`; use `launch` in the `[url]`
section instead.
* `jump-label-letters` option in `foot.ini`; use `label-letters` in
the `[url]` section instead.
* `osc8-underline` option in `foot.ini`; use `osc8-underline` in the
`[url]` section instead.
### Removed

176
config.c
View file

@ -530,6 +530,26 @@ str_to_spawn_template(struct config *conf,
return true;
}
static void
deprecated_url_option(struct config *conf,
const char *old_name, const char *new_name,
const char *path, unsigned lineno)
{
LOG_WARN(
"deprecated: %s:%d: [default]: %s: use '%s' in section '[url]' instead",
path, lineno, old_name, new_name);
const char fmt[] =
"%s:%d: \033[1m%s\033[22m, use \033[1m%s\033[22m in the \033[1m[url]\033[22m section instead";
char *text = xasprintf(fmt, path, lineno, old_name, new_name);
struct user_notification deprecation = {
.kind = USER_NOTIFICATION_DEPRECATED,
.text = text,
};
tll_push_back(conf->notifications, deprecation);
}
static bool
parse_section_main(const char *key, const char *value, struct config *conf,
const char *path, unsigned lineno)
@ -773,14 +793,17 @@ parse_section_main(const char *key, const char *value, struct config *conf,
}
else if (strcmp(key, "jump-label-letters") == 0) {
deprecated_url_option(
conf, "jump-label-letters", "label-letters", path, lineno);
wchar_t *letters;
if (!str_to_wchars(value, &letters, conf, path, lineno,
"default", "jump-label-letters"))
"default", "label-letters"))
{
return false;
}
free(conf->jump_label_letters);
conf->jump_label_letters = letters;
free(conf->url.label_letters);
conf->url.label_letters = letters;
}
else if (strcmp(key, "notify") == 0) {
@ -792,7 +815,10 @@ parse_section_main(const char *key, const char *value, struct config *conf,
}
else if (strcmp(key, "url-launch") == 0) {
if (!str_to_spawn_template(conf, value, &conf->url_launch, path, lineno,
deprecated_url_option(
conf, "url-launch", "launch", path, lineno);
if (!str_to_spawn_template(conf, value, &conf->url.launch, path, lineno,
"default", "url-launch"))
{
return false;
@ -822,10 +848,13 @@ parse_section_main(const char *key, const char *value, struct config *conf,
}
else if (strcmp(key, "osc8-underline") == 0) {
deprecated_url_option(
conf, "osc8-underline", "osc8-underline", path, lineno);
if (strcmp(value, "url-mode") == 0)
conf->osc8_underline = OSC8_UNDERLINE_URL_MODE;
conf->url.osc8_underline = OSC8_UNDERLINE_URL_MODE;
else if (strcmp(value, "always") == 0)
conf->osc8_underline = OSC8_UNDERLINE_ALWAYS;
conf->url.osc8_underline = OSC8_UNDERLINE_ALWAYS;
else {
LOG_AND_NOTIFY_ERR(
"%s:%u: [default]: %s: invalid 'osc8-underline'; "
@ -938,6 +967,99 @@ parse_section_scrollback(const char *key, const char *value, struct config *conf
return true;
}
static bool
parse_section_url(const char *key, const char *value, struct config *conf,
const char *path, unsigned lineno)
{
if (strcmp(key, "launch") == 0) {
if (!str_to_spawn_template(conf, value, &conf->url.launch, path, lineno,
"url", "launch"))
{
return false;
}
}
else if (strcmp(key, "label-letters") == 0) {
wchar_t *letters;
if (!str_to_wchars(value, &letters, conf, path, lineno, "url", "letters"))
return false;
free(conf->url.label_letters);
conf->url.label_letters = letters;
}
else if (strcmp(key, "osc8-underline") == 0) {
if (strcmp(value, "url-mode") == 0)
conf->url.osc8_underline = OSC8_UNDERLINE_URL_MODE;
else if (strcmp(value, "always") == 0)
conf->url.osc8_underline = OSC8_UNDERLINE_ALWAYS;
else {
LOG_AND_NOTIFY_ERR(
"%s:%u: [url]: %s: invalid 'osc8-underline'; "
"must be one of 'url-mode', or 'always'", path, lineno, value);
return false;
}
}
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, ","))
{
/* Strip leading whitespace */
while (isspace(*prot))
prot++;
/* Strip trailing whitespace */
size_t len = strlen(prot);
while (len > 0 && isspace(prot[len - 1]))
prot[--len] = '\0';
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"://");
chars += 3; /* Include the "://" */
if (chars > conf->url.max_prot_len)
conf->url.max_prot_len = chars;
}
free(copy);
}
else {
LOG_AND_NOTIFY_ERR("%s:%d: [url]: %s: invalid key", path, lineno, key);
return false;
}
return true;
}
static bool
parse_section_colors(const char *key, const char *value, struct config *conf,
const char *path, unsigned lineno)
@ -1962,6 +2084,7 @@ parse_config_file(FILE *f, struct config *conf, const char *path, bool errors_ar
SECTION_MAIN,
SECTION_BELL,
SECTION_SCROLLBACK,
SECTION_URL,
SECTION_COLORS,
SECTION_CURSOR,
SECTION_MOUSE,
@ -1986,6 +2109,7 @@ parse_config_file(FILE *f, struct config *conf, const char *path, bool errors_ar
[SECTION_MAIN] = {&parse_section_main, "main"},
[SECTION_BELL] = {&parse_section_bell, "bell"},
[SECTION_SCROLLBACK] = {&parse_section_scrollback, "scrollback"},
[SECTION_URL] = {&parse_section_url, "url"},
[SECTION_COLORS] = {&parse_section_colors, "colors"},
[SECTION_CURSOR] = {&parse_section_cursor, "cursor"},
[SECTION_MOUSE] = {&parse_section_mouse, "mouse"},
@ -2301,7 +2425,6 @@ config_load(struct config *conf, const char *conf_path,
.title = xstrdup("foot"),
.app_id = xstrdup("foot"),
.word_delimiters = xwcsdup(L",│`|:\"'()[]{}<>"),
.jump_label_letters = xwcsdup(L"sadfjklewcmpgh"),
.size = {
.type = CONF_SIZE_PX,
.width = 700,
@ -2331,6 +2454,10 @@ config_load(struct config *conf, const char *conf_path,
},
.command_focused = false,
},
.url = {
.label_letters = xwcsdup(L"sadfjklewcmpgh"),
.osc8_underline = OSC8_UNDERLINE_URL_MODE,
},
.scrollback = {
.lines = 1000,
.indicator = {
@ -2403,8 +2530,6 @@ config_load(struct config *conf, const char *conf_path,
.argv = NULL,
},
.osc8_underline = OSC8_UNDERLINE_URL_MODE,
.tweak = {
.fcft_filter = FCFT_SCALING_FILTER_LANCZOS3,
.allow_overflowing_double_width_glyphs = true,
@ -2450,8 +2575,29 @@ config_load(struct config *conf, const char *conf_path,
"notify-send -a foot -i foot ${title} ${body}");
tokenize_cmdline(conf->notify.raw_cmd, &conf->notify.argv);
conf->url_launch.raw_cmd = xstrdup("xdg-open ${url}");
tokenize_cmdline(conf->url_launch.raw_cmd, &conf->url_launch.argv);
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);
@ -2557,11 +2703,9 @@ config_free(struct config conf)
free(conf.title);
free(conf.app_id);
free(conf.word_delimiters);
free(conf.jump_label_letters);
free_spawn_template(&conf.bell.command);
free(conf.scrollback.indicator.text);
free_spawn_template(&conf.notify);
free_spawn_template(&conf.url_launch);
for (size_t i = 0; i < ALEN(conf.fonts); i++) {
tll_foreach(conf.fonts[i], it) {
config_font_destroy(&it->item);
@ -2570,6 +2714,12 @@ config_free(struct config conf)
}
free(conf.server_socket_path);
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);

View file

@ -65,7 +65,6 @@ struct config {
char *title;
char *app_id;
wchar_t *word_delimiters;
wchar_t *jump_label_letters;
bool login_shell;
bool no_wait;
@ -128,6 +127,19 @@ struct config {
double multiplier;
} scrollback;
struct {
wchar_t *label_letters;
struct config_spawn_template launch;
enum {
OSC8_UNDERLINE_URL_MODE,
OSC8_UNDERLINE_ALWAYS,
} osc8_underline;
wchar_t **protocols;
size_t prot_count;
size_t max_prot_len;
} url;
struct {
uint32_t fg;
uint32_t bg;
@ -213,12 +225,6 @@ struct config {
} selection_target;
struct config_spawn_template notify;
struct config_spawn_template url_launch;
enum {
OSC8_UNDERLINE_URL_MODE,
OSC8_UNDERLINE_ALWAYS,
} osc8_underline;
struct {
enum fcft_scaling_filter fcft_filter;

View file

@ -216,10 +216,6 @@ in this order:
text. Note that whitespace characters are _always_ word
delimiters, regardless of this setting. Default: _,│`|:"'()[]{}<>_
*jump-label-letters*
String of characters that will be when generating key sequences
for URL jump labels. Default: _sadfjklewcmpgh_.
*notify*
Command to execute to display a notification. _${title}_ and
_${body}_ will be replaced with the notification's actual _title_
@ -234,10 +230,6 @@ in this order:
Default: _notify-send -a foot -i foot ${title} ${body}_.
*url-launch*
Command to execute when opening URLs. _${url}_ will be replaced
with the actual URL. Default: _xdg-open ${url}_.
*selection-target*
Clipboard target to automatically copy selected text to. One of
*none*, *primary*, *clipboard* or *both*. Default: _primary_.
@ -248,19 +240,6 @@ in this order:
(including SMT). Note that this is not always the best value. In
some cases, the number of physical _cores_ is better.
*osc8-underline*
When to underline OSC-8 URLs. Possible values are *url-mode* and
*always*.
When set to *url-mode*, OSC-8 URLs are only highlighted in URL
mode, just like auto-detected URLs.
When set to *always*, OSC-8 URLs are always highlighted,
regardless of their other attributes (bold, italic etc). Note that
this does _not_ make them clickable.
Default: _url-mode_
# SECTION: bell
@ -321,6 +300,37 @@ in this order:
*indicator-position=none*. Default: _empty string_.
# SECTION: url
*launch*
Command to execute when opening URLs. _${url}_ will be replaced
with the actual URL. Default: _xdg-open ${url}_.
*osc8-underline*
When to underline OSC-8 URLs. Possible values are *url-mode* and
*always*.
When set to *url-mode*, OSC-8 URLs are only highlighted in URL
mode, just like auto-detected URLs.
When set to *always*, OSC-8 URLs are always highlighted,
regardless of their other attributes (bold, italic etc). Note that
this does _not_ make them clickable.
Default: _url-mode_
*label-letters*
String of characters to use when generating key sequences for URL
jump labels. Default: _sadfjklewcmpgh_.
*protocols*
Comma separated 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
@ -360,6 +370,7 @@ applications can change these at runtime.
Default: _font underline thickness_.
# SECTION: mouse
*hide-when-typing*

View file

@ -22,15 +22,12 @@
# resize-delay-ms=100
# notify=notify-send -a foot -i foot ${title} ${body}
# url-launch=xdg-open ${url}
# bold-text-in-bright=no
# bell=none
# word-delimiters=,│`|:"'()[]{}<>
# jump-label-letters=sadfjklewcmpgh
# selection-target=primary
# workers=<number of logical CPUs>
# osc8-underline=url-mode
[bell]
# urgent=no
@ -44,6 +41,12 @@
# indicator-position=relative
# indicator-format=
[url]
# 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

View file

@ -3089,7 +3089,7 @@ term_osc8_close(struct terminal *term)
struct row *row = term->grid->rows[r];
switch (term->conf->osc8_underline) {
switch (term->conf->url.osc8_underline) {
case OSC8_UNDERLINE_ALWAYS:
for (int c = start_col; c <= end_col; c++)
row->cells[c].attrs.url = true;

View file

@ -93,7 +93,7 @@ activate_url(struct seat *seat, struct terminal *term, const struct url *url)
}
if (spawn_expand_template(
&term->conf->url_launch, 1,
&term->conf->url.launch, 1,
(const char *[]){"url"},
(const char *[]){url_string},
&argc, &argv))
@ -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];
@ -405,7 +391,7 @@ osc8_uris(const struct terminal *term, enum url_action action, url_list_t *urls)
{
bool dont_touch_url_attr = false;
switch (term->conf->osc8_underline) {
switch (term->conf->url.osc8_underline) {
case OSC8_UNDERLINE_URL_MODE:
dont_touch_url_attr = false;
break;
@ -484,7 +470,7 @@ static void
generate_key_combos(const struct config *conf,
size_t count, wchar_t *combos[static count])
{
const wchar_t *alphabet = conf->jump_label_letters;
const wchar_t *alphabet = conf->url.label_letters;
const size_t alphabet_len = wcslen(alphabet);
size_t hints_count = 1;