diff --git a/config.c b/config.c index 0ea45b02..74cff1f3 100644 --- a/config.c +++ b/config.c @@ -75,6 +75,7 @@ static const char *const binding_action_map[] = { [BIND_ACTION_PIPE_SCROLLBACK] = "pipe-scrollback", [BIND_ACTION_PIPE_VIEW] = "pipe-visible", [BIND_ACTION_PIPE_SELECTED] = "pipe-selected", + [BIND_ACTION_SHOW_URLS_COPY] = "show-urls-copy", [BIND_ACTION_SHOW_URLS_LAUNCH] = "show-urls-launch", /* Mouse-specific actions */ diff --git a/doc/foot.ini.5.scd b/doc/foot.ini.5.scd index fe158279..727b81f1 100644 --- a/doc/foot.ini.5.scd +++ b/doc/foot.ini.5.scd @@ -500,6 +500,11 @@ e.g. *search-start=none*. a jump label with a key sequence that will open the URL. Default: _Control+Shift+U_. +*show-urls-copy* + Enters URL mode, where all currently visible URLs are tagged with + a jump label with a key sequence that will place the URL in the + clipboard. Default: _none_. + # SECTION: search-bindings diff --git a/foot.ini b/foot.ini index 692eac4f..4ed3d64b 100644 --- a/foot.ini +++ b/foot.ini @@ -98,6 +98,7 @@ # pipe-scrollback=[sh -c "xurls | bemenu | xargs -r firefox"] none # pipe-selected=[xargs -r firefox] none # show-urls-launch=Control+Shift+U +# show-urls-copy=none [search-bindings] # cancel=Control+g Escape diff --git a/input.c b/input.c index dfbf4fa3..65670aa3 100644 --- a/input.c +++ b/input.c @@ -272,12 +272,18 @@ execute_binding(struct seat *seat, struct terminal *term, return true; } - case BIND_ACTION_SHOW_URLS_LAUNCH: + case BIND_ACTION_SHOW_URLS_COPY: + case BIND_ACTION_SHOW_URLS_LAUNCH: { xassert(!urls_mode_is_active(term)); - urls_collect(term); + enum url_action url_action = action == BIND_ACTION_SHOW_URLS_COPY + ? URL_ACTION_COPY + : URL_ACTION_LAUNCH; + + urls_collect(term, url_action); render_refresh_urls(term); return true; + } case BIND_ACTION_SELECT_BEGIN: selection_start( diff --git a/terminal.h b/terminal.h index 24183c7b..b58cd137 100644 --- a/terminal.h +++ b/terminal.h @@ -223,12 +223,14 @@ enum term_surface { typedef tll(struct ptmx_buffer) ptmx_buffer_list_t; +enum url_action { URL_ACTION_COPY, URL_ACTION_LAUNCH }; struct url { wchar_t *url; wchar_t *text; wchar_t key[4]; struct coord start; struct coord end; + enum url_action action; }; struct terminal { diff --git a/url-mode.c b/url-mode.c index 78291685..79c6c17c 100644 --- a/url-mode.c +++ b/url-mode.c @@ -7,6 +7,7 @@ #define LOG_ENABLE_DBG 1 #include "log.h" #include "grid.h" +#include "selection.h" #include "spawn.h" #include "terminal.h" #include "util.h" @@ -88,24 +89,38 @@ urls_input(struct seat *seat, struct terminal *term, uint32_t key, size_t chars = wcstombs(NULL, match->url, 0); if (chars != (size_t)-1) { - char url_utf8[chars + 1]; + char *url_utf8 = malloc(chars + 1); wcstombs(url_utf8, match->url, chars + 1); - size_t argc; - char **argv; + switch (match->action) { + case URL_ACTION_COPY: + if (text_to_clipboard(seat, term, url_utf8, seat->kbd.serial)) { + /* Now owned by our clipboard “manager” */ + url_utf8 = NULL; + } + break; - if (spawn_expand_template( - &term->conf->url_launch, 1, - (const char *[]){"url"}, - (const char *[]){url_utf8}, - &argc, &argv)) - { - spawn(term->reaper, term->cwd, argv, -1, -1, -1); + case URL_ACTION_LAUNCH: { + size_t argc; + char **argv; - for (size_t i = 0; i < argc; i++) - free(argv[i]); - free(argv); + if (spawn_expand_template( + &term->conf->url_launch, 1, + (const char *[]){"url"}, + (const char *[]){url_utf8}, + &argc, &argv)) + { + spawn(term->reaper, term->cwd, argv, -1, -1, -1); + + for (size_t i = 0; i < argc; i++) + free(argv[i]); + free(argv); + } + break; } + } + + free(url_utf8); } urls_reset(term); @@ -120,7 +135,7 @@ urls_input(struct seat *seat, struct terminal *term, uint32_t key, IGNORE_WARNING("-Wpedantic") static void -auto_detected(struct terminal *term) +auto_detected(struct terminal *term, enum url_action action) { static const wchar_t *const prots[] = { L"http://", @@ -274,7 +289,8 @@ auto_detected(struct terminal *term) .url = xwcsdup(url), .text = xwcsdup(L""), .start = start, - .end = end})); + .end = end, + .action = action})); state = STATE_PROTOCOL; len = 0; @@ -290,10 +306,10 @@ auto_detected(struct terminal *term) UNIGNORE_WARNINGS void -urls_collect(struct terminal *term) +urls_collect(struct terminal *term, enum url_action action) { xassert(tll_length(term->urls) == 0); - auto_detected(term); + auto_detected(term, action); size_t count = tll_length(term->urls); diff --git a/url-mode.h b/url-mode.h index 150a0222..94c1e675 100644 --- a/url-mode.h +++ b/url-mode.h @@ -11,7 +11,7 @@ static inline bool urls_mode_is_active(const struct terminal *term) return tll_length(term->urls) > 0; } -void urls_collect(struct terminal *term); +void urls_collect(struct terminal *term, enum url_action action); void urls_reset(struct terminal *term); void urls_input(struct seat *seat, struct terminal *term, uint32_t key, diff --git a/wayland.h b/wayland.h index 3ad7b862..3c160b7c 100644 --- a/wayland.h +++ b/wayland.h @@ -49,6 +49,7 @@ enum bind_action_normal { BIND_ACTION_PIPE_SCROLLBACK, BIND_ACTION_PIPE_VIEW, BIND_ACTION_PIPE_SELECTED, + BIND_ACTION_SHOW_URLS_COPY, BIND_ACTION_SHOW_URLS_LAUNCH, /* Mouse specific actions - i.e. they require a mouse coordinate */