mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-03-04 01:40:21 -05:00
url-mode+config: wip: add url.regex option
This commit is contained in:
parent
e76d8dd7af
commit
d41b28bd02
5 changed files with 76 additions and 54 deletions
60
config.c
60
config.c
|
|
@ -1234,6 +1234,26 @@ parse_section_url(struct context *ctx)
|
||||||
(int *)&conf->url.osc8_underline);
|
(int *)&conf->url.osc8_underline);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (streq(key, "regex")) {
|
||||||
|
const char *regex = ctx->value;
|
||||||
|
regex_t preg;
|
||||||
|
|
||||||
|
int r = regcomp(&preg, regex, REG_EXTENDED);
|
||||||
|
if (r != 0) {
|
||||||
|
char err_buf[128];
|
||||||
|
regerror(r, &preg, err_buf, sizeof(err_buf));
|
||||||
|
LOG_CONTEXTUAL_ERR("invalid regex: %s", err_buf);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
regfree(&conf->url.preg);
|
||||||
|
free(conf->url.regex);
|
||||||
|
|
||||||
|
conf->url.regex = xstrdup(regex);
|
||||||
|
conf->url.preg = preg;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
LOG_CONTEXTUAL_ERR("not a valid option: %s", key);
|
LOG_CONTEXTUAL_ERR("not a valid option: %s", key);
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -3241,6 +3261,42 @@ config_load(struct config *conf, const char *conf_path,
|
||||||
tokenize_cmdline("--action ${action-name}=${action-label}", &conf->desktop_notifications.command_action_arg.argv.args);
|
tokenize_cmdline("--action ${action-name}=${action-label}", &conf->desktop_notifications.command_action_arg.argv.args);
|
||||||
tokenize_cmdline("xdg-open ${url}", &conf->url.launch.argv.args);
|
tokenize_cmdline("xdg-open ${url}", &conf->url.launch.argv.args);
|
||||||
|
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Based on https://gist.github.com/gruber/249502, but modified:
|
||||||
|
* - Do not allow {} at all
|
||||||
|
* - Do allow matched []
|
||||||
|
*/
|
||||||
|
const char *url_regex_string =
|
||||||
|
"("
|
||||||
|
"[a-z][[:alnum:]-]+:" // protocol
|
||||||
|
"("
|
||||||
|
"/{1,3}|[a-z0-9%]" // slashes (what's the OR part for?)
|
||||||
|
")"
|
||||||
|
"|"
|
||||||
|
"www[:digit:]{0,3}[.]"
|
||||||
|
//"|"
|
||||||
|
//"[a-z0-9.\\-]+[.][a-z]{2,4}/" /* "looks like domain name followed by a slash" - remove? */
|
||||||
|
")"
|
||||||
|
"("
|
||||||
|
"[^[:space:](){}<>]+"
|
||||||
|
"|"
|
||||||
|
"\\(([^[:space:](){}<>]+|(\\([^[:space:](){}<>]+\\)))*\\)"
|
||||||
|
"|"
|
||||||
|
"\\[([^]\\[[:space:](){}<>]+|(\\[[^]\\[[:space:](){}<>]+\\]))*\\]"
|
||||||
|
")+"
|
||||||
|
"("
|
||||||
|
"\\(([^[:space:](){}<>]+|(\\([^[:space:](){}<>]+\\)))*\\)"
|
||||||
|
"|"
|
||||||
|
"\\[([^]\\[[:space:](){}<>]+|(\\[[^]\\[[:space:](){}<>]+\\]))*\\]"
|
||||||
|
"|"
|
||||||
|
"[^]\\[[:space:]`!(){};:'\".,<>?«»“”‘’]"
|
||||||
|
")"
|
||||||
|
;
|
||||||
|
int r = regcomp(&conf->url.preg, url_regex_string, REG_EXTENDED);
|
||||||
|
xassert(r == 0);
|
||||||
|
conf->url.regex = xstrdup(url_regex_string);
|
||||||
|
}
|
||||||
|
|
||||||
tll_foreach(*initial_user_notifications, it) {
|
tll_foreach(*initial_user_notifications, it) {
|
||||||
tll_push_back(conf->notifications, it->item);
|
tll_push_back(conf->notifications, it->item);
|
||||||
|
|
@ -3476,6 +3532,8 @@ config_clone(const struct config *old)
|
||||||
|
|
||||||
conf->url.label_letters = xc32dup(old->url.label_letters);
|
conf->url.label_letters = xc32dup(old->url.label_letters);
|
||||||
spawn_template_clone(&conf->url.launch, &old->url.launch);
|
spawn_template_clone(&conf->url.launch, &old->url.launch);
|
||||||
|
conf->url.regex = xstrdup(old->url.regex);
|
||||||
|
regcomp(&conf->url.preg, conf->url.regex, REG_EXTENDED);
|
||||||
|
|
||||||
key_binding_list_clone(&conf->bindings.key, &old->bindings.key);
|
key_binding_list_clone(&conf->bindings.key, &old->bindings.key);
|
||||||
key_binding_list_clone(&conf->bindings.search, &old->bindings.search);
|
key_binding_list_clone(&conf->bindings.search, &old->bindings.search);
|
||||||
|
|
@ -3556,6 +3614,8 @@ config_free(struct config *conf)
|
||||||
|
|
||||||
free(conf->url.label_letters);
|
free(conf->url.label_letters);
|
||||||
spawn_template_free(&conf->url.launch);
|
spawn_template_free(&conf->url.launch);
|
||||||
|
regfree(&conf->url.preg);
|
||||||
|
free(conf->url.regex);
|
||||||
|
|
||||||
free_key_binding_list(&conf->bindings.key);
|
free_key_binding_list(&conf->bindings.key);
|
||||||
free_key_binding_list(&conf->bindings.search);
|
free_key_binding_list(&conf->bindings.search);
|
||||||
|
|
|
||||||
6
config.h
6
config.h
|
|
@ -1,7 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <regex.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <uchar.h>
|
#include <uchar.h>
|
||||||
|
|
||||||
#include <xkbcommon/xkbcommon.h>
|
#include <xkbcommon/xkbcommon.h>
|
||||||
|
|
@ -219,6 +220,9 @@ struct config {
|
||||||
OSC8_UNDERLINE_URL_MODE,
|
OSC8_UNDERLINE_URL_MODE,
|
||||||
OSC8_UNDERLINE_ALWAYS,
|
OSC8_UNDERLINE_ALWAYS,
|
||||||
} osc8_underline;
|
} osc8_underline;
|
||||||
|
|
||||||
|
char *regex;
|
||||||
|
regex_t preg;
|
||||||
} url;
|
} url;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
|
|
||||||
|
|
@ -782,6 +782,11 @@ xdgtoken=95ebdfe56e4f47ddb5bba9d7dc3a2c35
|
||||||
|
|
||||||
Default: _sadfjklewcmpgh_.
|
Default: _sadfjklewcmpgh_.
|
||||||
|
|
||||||
|
*regex*
|
||||||
|
URL regex to use when auto-detecting URLs. The format is
|
||||||
|
"POSIX-Extended Regular Expressions".
|
||||||
|
|
||||||
|
Default: _TODO_
|
||||||
|
|
||||||
# SECTION: cursor
|
# SECTION: cursor
|
||||||
|
|
||||||
|
|
|
||||||
2
foot.ini
2
foot.ini
|
|
@ -69,6 +69,8 @@
|
||||||
# launch=xdg-open ${url}
|
# launch=xdg-open ${url}
|
||||||
# label-letters=sadfjklewcmpgh
|
# label-letters=sadfjklewcmpgh
|
||||||
# osc8-underline=url-mode
|
# osc8-underline=url-mode
|
||||||
|
# regex=TODO
|
||||||
|
|
||||||
|
|
||||||
[cursor]
|
[cursor]
|
||||||
# style=block
|
# style=block
|
||||||
|
|
|
||||||
57
url-mode.c
57
url-mode.c
|
|
@ -380,54 +380,7 @@ regex_detected(const struct terminal *term, enum url_action action, url_list_t *
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
const regex_t *preg = &term->conf->url.preg;
|
||||||
* Based on https://gist.github.com/gruber/249502, but modified:
|
|
||||||
* - Do not allow {} at all
|
|
||||||
* - Do allow matched []
|
|
||||||
*/
|
|
||||||
regex_t preg;
|
|
||||||
const char *regex_string =
|
|
||||||
"("
|
|
||||||
"[a-z][[:alnum:]-]+:" // protocol
|
|
||||||
"("
|
|
||||||
"/{1,3}|[a-z0-9%]" // slashes (what's the OR part for?)
|
|
||||||
")"
|
|
||||||
"|"
|
|
||||||
"www[:digit:]{0,3}[.]"
|
|
||||||
"|"
|
|
||||||
"[a-z0-9.\\-]+[.][a-z]{2,4}/"
|
|
||||||
")"
|
|
||||||
"("
|
|
||||||
"[^[:space:](){}<>]+"
|
|
||||||
"|"
|
|
||||||
"\\(([^[:space:](){}<>]+|(\\([^[:space:](){}<>]+\\)))*\\)"
|
|
||||||
"|"
|
|
||||||
"\\[([^]\\[[:space:](){}<>]+|(\\[[^]\\[[:space:](){}<>]+\\]))*\\]"
|
|
||||||
")+"
|
|
||||||
"("
|
|
||||||
"\\(([^[:space:](){}<>]+|(\\([^[:space:](){}<>]+\\)))*\\)"
|
|
||||||
"|"
|
|
||||||
"\\[([^]\\[[:space:](){}<>]+|(\\[[^]\\[[:space:](){}<>]+\\]))*\\]"
|
|
||||||
"|"
|
|
||||||
"[^]\\[[:space:]`!(){};:'\".,<>?«»“”‘’]"
|
|
||||||
")"
|
|
||||||
;
|
|
||||||
|
|
||||||
int r = regcomp(&preg, regex_string, REG_EXTENDED);
|
|
||||||
|
|
||||||
if (r != 0) {
|
|
||||||
char err_buf[1024];
|
|
||||||
regerror(r, &preg, err_buf, sizeof(err_buf));
|
|
||||||
LOG_ERR("failed to compile regular expression: %s", err_buf);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < ALEN(vlines); i++) {
|
|
||||||
const struct vline *v = &vlines[i];
|
|
||||||
free(v->utf8);
|
|
||||||
free(v->map);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < ALEN(vlines); i++) {
|
for (size_t i = 0; i < ALEN(vlines); i++) {
|
||||||
const struct vline *v = &vlines[i];
|
const struct vline *v = &vlines[i];
|
||||||
|
|
@ -436,9 +389,8 @@ regex_detected(const struct terminal *term, enum url_action action, url_list_t *
|
||||||
|
|
||||||
const char *search_string = v->utf8;
|
const char *search_string = v->utf8;
|
||||||
while (true) {
|
while (true) {
|
||||||
|
regmatch_t matches[preg->re_nsub + 1];
|
||||||
regmatch_t matches[preg.re_nsub + 1];
|
int r = regexec(preg, search_string, preg->re_nsub + 1, matches, 0);
|
||||||
r = regexec(&preg, search_string, preg.re_nsub + 1, matches, 0);
|
|
||||||
|
|
||||||
if (r == REG_NOMATCH)
|
if (r == REG_NOMATCH)
|
||||||
break;
|
break;
|
||||||
|
|
@ -470,9 +422,8 @@ regex_detected(const struct terminal *term, enum url_action action, url_list_t *
|
||||||
free(v->utf8);
|
free(v->utf8);
|
||||||
free(v->map);
|
free(v->map);
|
||||||
}
|
}
|
||||||
|
|
||||||
regfree(&preg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
osc8_uris(const struct terminal *term, enum url_action action, url_list_t *urls)
|
osc8_uris(const struct terminal *term, enum url_action action, url_list_t *urls)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue