From: Lennart Poettering Date: Thu, 19 Apr 2018 15:48:53 +0000 (+0200) Subject: terminal: add internal API to format URLs for display in capable terminals X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=15f9c17dd3ccf9dc21ceb795feb27a6b6dee1b1f;p=elogind.git terminal: add internal API to format URLs for display in capable terminals Newer terminals (in particular gnome-terminal) understand special escape sequence for formatting clickable links. Let's support that to make our tool output more clickable where that's appropriate. For details see this: https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda The one big issue is that 'less' currently doesn't grok this, and doesn't ignore sequence like regular terminal implementations do if they don't support it. Hence for now, let's disable URL output if a pager is used. We should revisit that though as soon as less added support for it and enough time passed for it to enter various distributions. --- diff --git a/man/elogind.xml b/man/elogind.xml index 9fee8d105..6dce20386 100644 --- a/man/elogind.xml +++ b/man/elogind.xml @@ -947,6 +947,15 @@ + + $SYSTEMD_URLIFY + + The value must be a boolean. Controls whether clickable links should be generated in the output + for terminal emulators supporting this. This can be specified to override the decision that + systemd makes based on $TERM and other conditions. + + + $LISTEN_PID $LISTEN_FDS diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c index a0ebb86cd..ac7598971 100644 --- a/src/basic/terminal-util.c +++ b/src/basic/terminal-util.c @@ -8,21 +8,22 @@ #include #include #include +//#include +//#include +//#include +//#include +//#include #include #include #include #include #include +//#include #include #include #include -#include -#include -#include -#include -#include -#include #include +//#include #include #include @@ -34,6 +35,7 @@ #include "io-util.h" #include "log.h" #include "macro.h" +//#include "pager.h" #include "parse-util.h" //#include "path-util.h" //#include "proc-cmdline.h" @@ -1288,3 +1290,94 @@ int vt_reset_keyboard(int fd) { return 0; } + +static bool urlify_enabled(void) { + static int cached_urlify_enabled = -1; + + /* Unfortunately 'less' doesn't support links like this yet 😭, hence let's disable this as long as there's a + * pager in effect. Let's drop this check as soon as less got fixed a and enough time passed so that it's safe + * to assume that a link-enabled 'less' version has hit most installations. */ + + if (cached_urlify_enabled < 0) { + int val; + + val = getenv_bool("SYSTEMD_URLIFY"); + if (val >= 0) + cached_urlify_enabled = val; + else + cached_urlify_enabled = colors_enabled() && !pager_have(); + } + + return cached_urlify_enabled; +} + +int terminal_urlify(const char *url, const char *text, char **ret) { + char *n; + + assert(url); + + /* Takes an URL and a pretty string and formats it as clickable link for the terminal. See + * https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda for details. */ + + if (isempty(text)) + text = url; + + if (urlify_enabled()) + n = strjoin("\x1B]8;;", url, "\a", text, "\x1B]8;;\a"); + else + n = strdup(text); + if (!n) + return -ENOMEM; + + *ret = n; + return 0; +} + +int terminal_urlify_path(const char *path, const char *text, char **ret) { + _cleanup_free_ char *absolute = NULL; + struct utsname u; + const char *url; + int r; + + assert(path); + + /* Much like terminal_urlify() above, but takes a file system path as input, and turns it into a properl + * file:// URL first. */ + + if (isempty(path)) + return -EINVAL; + + if (isempty(text)) + text = path; + + if (!urlify_enabled()) { + char *n; + + n = strdup(text); + if (!n) + return -ENOMEM; + + *ret = n; + return 0; + } + + if (uname(&u) < 0) + return -errno; + + if (!path_is_absolute(path)) { + r = path_make_absolute_cwd(path, &absolute); + if (r < 0) + return r; + + path = absolute; + } + + /* As suggested by https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda, let's include the local + * hostname here. Note that we don't use gethostname_malloc() or gethostname_strict() since we are interested + * in the raw string the kernel has set, whatever it may be, under the assumption that terminals are not overly + * careful with validating the strings either. */ + + url = strjoina("file://", u.nodename, path); + + return terminal_urlify(url, text, ret); +} diff --git a/src/basic/terminal-util.h b/src/basic/terminal-util.h index 1aa5ccc72..b5e755eba 100644 --- a/src/basic/terminal-util.h +++ b/src/basic/terminal-util.h @@ -174,3 +174,6 @@ int open_terminal_in_namespace(pid_t pid, const char *name, int mode); int vt_default_utf8(void); int vt_reset_keyboard(int fd); + +int terminal_urlify(const char *url, const char *text, char **ret); +int terminal_urlify_path(const char *path, const char *text, char **ret);