From 7b15f872f23855de59bd06b0ebdbbc47b27b781b Mon Sep 17 00:00:00 2001 From: Christian Couder Date: Fri, 25 Apr 2008 08:24:22 +0200 Subject: [PATCH 1/5] help: use man viewer path from "man..path" config var This patch implements reading values from "man..path" configuration variables, and using these values as pathes to the man viewer s when lauching them. This makes it possible to use different version of the tools than the one on the current PATH, or maybe a custom script. In this patch we also try to launch "konqueror" using "kfmclient" even if a path to a konqueror binary is given in "man.konqueror.path". The "man_viewer_list" becomes a simple string list to simplify things for the following patches. Signed-off-by: Christian Couder Signed-off-by: Junio C Hamano --- help.c | 143 +++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 124 insertions(+), 19 deletions(-) diff --git a/help.c b/help.c index 10298fb0a1..483e1e9c38 100644 --- a/help.c +++ b/help.c @@ -11,10 +11,16 @@ #include "run-command.h" static struct man_viewer_list { - void (*exec)(const char *); struct man_viewer_list *next; + char name[FLEX_ARRAY]; } *man_viewer_list; +static struct man_viewer_info_list { + struct man_viewer_info_list *next; + const char *info; + char name[FLEX_ARRAY]; +} *man_viewer_info_list; + enum help_format { HELP_FORMAT_MAN, HELP_FORMAT_INFO, @@ -49,6 +55,18 @@ static enum help_format parse_help_format(const char *format) die("unrecognized help format '%s'", format); } +static const char *get_man_viewer_info(const char *name) +{ + struct man_viewer_info_list *viewer; + + for (viewer = man_viewer_info_list; viewer; viewer = viewer->next) + { + if (!strcasecmp(name, viewer->name)) + return viewer->info; + } + return NULL; +} + static int check_emacsclient_version(void) { struct strbuf buffer = STRBUF_INIT; @@ -95,56 +113,126 @@ static int check_emacsclient_version(void) return 0; } -static void exec_woman_emacs(const char *page) +static void exec_woman_emacs(const char* path, const char *page) { if (!check_emacsclient_version()) { /* This works only with emacsclient version >= 22. */ struct strbuf man_page = STRBUF_INIT; + + if (!path) + path = "emacsclient"; strbuf_addf(&man_page, "(woman \"%s\")", page); - execlp("emacsclient", "emacsclient", "-e", man_page.buf, NULL); + execlp(path, "emacsclient", "-e", man_page.buf, NULL); + warning("failed to exec '%s': %s", path, strerror(errno)); } } -static void exec_man_konqueror(const char *page) +static void exec_man_konqueror(const char* path, const char *page) { const char *display = getenv("DISPLAY"); if (display && *display) { struct strbuf man_page = STRBUF_INIT; + const char *filename = "kfmclient"; + + /* It's simpler to launch konqueror using kfmclient. */ + if (path) { + const char *file = strrchr(path, '/'); + if (file && !strcmp(file + 1, "konqueror")) { + char *new = xstrdup(path); + char *dest = strrchr(new, '/'); + + /* strlen("konqueror") == strlen("kfmclient") */ + strcpy(dest + 1, "kfmclient"); + path = new; + } + if (file) + filename = file; + } else + path = "kfmclient"; strbuf_addf(&man_page, "man:%s(1)", page); - execlp("kfmclient", "kfmclient", "newTab", man_page.buf, NULL); + execlp(path, filename, "newTab", man_page.buf, NULL); + warning("failed to exec '%s': %s", path, strerror(errno)); } } -static void exec_man_man(const char *page) +static void exec_man_man(const char* path, const char *page) { - execlp("man", "man", page, NULL); + if (!path) + path = "man"; + execlp(path, "man", page, NULL); + warning("failed to exec '%s': %s", path, strerror(errno)); } -static void do_add_man_viewer(void (*exec)(const char *)) +static void do_add_man_viewer(const char *name) { struct man_viewer_list **p = &man_viewer_list; + size_t len = strlen(name); while (*p) p = &((*p)->next); - *p = xmalloc(sizeof(**p)); - (*p)->next = NULL; - (*p)->exec = exec; + *p = xcalloc(1, (sizeof(**p) + len + 1)); + strncpy((*p)->name, name, len); +} + +static int supported_man_viewer(const char *name, size_t len) +{ + return (!strncasecmp("man", name, len) || + !strncasecmp("woman", name, len) || + !strncasecmp("konqueror", name, len)); } static int add_man_viewer(const char *value) { - if (!strcasecmp(value, "man")) - do_add_man_viewer(exec_man_man); - else if (!strcasecmp(value, "woman")) - do_add_man_viewer(exec_woman_emacs); - else if (!strcasecmp(value, "konqueror")) - do_add_man_viewer(exec_man_konqueror); + if (supported_man_viewer(value, strlen(value))) + do_add_man_viewer(value); else warning("'%s': unsupported man viewer.", value); return 0; } +static void do_add_man_viewer_info(const char *name, + size_t len, + const char *value) +{ + struct man_viewer_info_list *new = xcalloc(1, sizeof(*new) + len + 1); + + strncpy(new->name, name, len); + new->info = xstrdup(value); + new->next = man_viewer_info_list; + man_viewer_info_list = new; +} + +static int add_man_viewer_path(const char *name, + size_t len, + const char *value) +{ + if (supported_man_viewer(name, len)) + do_add_man_viewer_info(name, len, value); + else + warning("'%s': path for unsupported man viewer.", name); + + return 0; +} + +static int add_man_viewer_info(const char *var, const char *value) +{ + const char *name = var + 4; + const char *subkey = strrchr(name, '.'); + + if (!subkey) + return error("Config with no key for man viewer: %s", name); + + if (!strcmp(subkey, ".path")) { + if (!value) + return config_error_nonbool(var); + return add_man_viewer_path(name, subkey - name, value); + } + + warning("'%s': unsupported man viewer sub key.", subkey); + return 0; +} + static int git_help_config(const char *var, const char *value) { if (!strcmp(var, "help.format")) { @@ -158,6 +246,9 @@ static int git_help_config(const char *var, const char *value) return config_error_nonbool(var); return add_man_viewer(value); } + if (!prefixcmp(var, "man.")) + return add_man_viewer_info(var, value); + return git_default_config(var, value); } @@ -453,6 +544,20 @@ static void setup_man_path(void) strbuf_release(&new_path); } +static void exec_viewer(const char *name, const char *page) +{ + const char *path = get_man_viewer_info(name); + + if (!strcasecmp(name, "man")) + exec_man_man(path, page); + else if (!strcasecmp(name, "woman")) + exec_woman_emacs(path, page); + else if (!strcasecmp(name, "konqueror")) + exec_man_konqueror(path, page); + else + warning("'%s': unsupported man viewer.", name); +} + static void show_man_page(const char *git_cmd) { struct man_viewer_list *viewer; @@ -461,9 +566,9 @@ static void show_man_page(const char *git_cmd) setup_man_path(); for (viewer = man_viewer_list; viewer; viewer = viewer->next) { - viewer->exec(page); /* will return when unable */ + exec_viewer(viewer->name, page); /* will return when unable */ } - exec_man_man(page); + exec_viewer("man", page); die("no man viewer handled the request"); } From 7e8114c0683e6ecfd400a5a798ae7e2fc91249fb Mon Sep 17 00:00:00 2001 From: Christian Couder Date: Fri, 25 Apr 2008 08:24:41 +0200 Subject: [PATCH 2/5] documentation: help: add "man..path" config variable This patch documents the "man..path" configuration variable. Signed-off-by: Christian Couder Signed-off-by: Junio C Hamano --- Documentation/config.txt | 4 ++++ Documentation/git-help.txt | 9 +++++++++ 2 files changed, 13 insertions(+) diff --git a/Documentation/config.txt b/Documentation/config.txt index 7a24f6e819..138ba9ad8f 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -805,6 +805,10 @@ merge..recursive:: performing an internal merge between common ancestors. See linkgit:gitattributes[5] for details. +man..path:: + Override the path for the given tool that may be used to + display help in the 'man' format. See linkgit:git-help[1]. + mergetool..path:: Override the path for the given tool. This is useful in case your tool is not in the PATH. diff --git a/Documentation/git-help.txt b/Documentation/git-help.txt index be2ae53b90..4c6cb2194c 100644 --- a/Documentation/git-help.txt +++ b/Documentation/git-help.txt @@ -104,6 +104,15 @@ DISPLAY is not set) and in that case emacs' woman mode will be tried. If everything fails the 'man' program will be tried anyway. +man..path +~~~~~~~~~~~~~~~ + +You can explicitly provide a full path to your preferred man viewer by +setting the configuration variable 'man..path'. For example, you +can configure the absolute path to konqueror by setting +'man.konqueror.path'. Otherwise, 'git help' assumes the tool is +available in PATH. + Note about git config --global ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From a26a06afed783cb7cf7207c1bcb2d1781d623d1e Mon Sep 17 00:00:00 2001 From: Christian Couder Date: Fri, 25 Apr 2008 08:24:58 +0200 Subject: [PATCH 3/5] help: use "man..cmd" as custom man viewer command Currently "git help -m GITCMD" is restricted to a set of man viewers defined at compile time. You can subvert the "man..path" to force "git help -m" to use a different man, viewer, but if you have a man viewer whose invocation syntax does not match one of the current tools then you would have to write a wrapper script for it. This patch adds a git config variable "man..cmd" which allows a more flexible man viewer choice. If you run "git help -m GITCMD" with the "man.viewer" config variable set to an unrecognized tool then it will query the "man..cmd" config variable. If this variable exists, then the specified tool will be treated as a custom man viewer and it will be run in a shell with the man page name of the GITCMD added as extra parameter. Signed-off-by: Christian Couder Signed-off-by: Junio C Hamano --- help.c | 58 ++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/help.c b/help.c index 483e1e9c38..af80979fcb 100644 --- a/help.c +++ b/help.c @@ -163,7 +163,15 @@ static void exec_man_man(const char* path, const char *page) warning("failed to exec '%s': %s", path, strerror(errno)); } -static void do_add_man_viewer(const char *name) +static void exec_man_cmd(const char *cmd, const char *page) +{ + struct strbuf shell_cmd = STRBUF_INIT; + strbuf_addf(&shell_cmd, "%s %s", cmd, page); + execl("/bin/sh", "sh", "-c", shell_cmd.buf, NULL); + warning("failed to exec '%s': %s", cmd, strerror(errno)); +} + +static void add_man_viewer(const char *name) { struct man_viewer_list **p = &man_viewer_list; size_t len = strlen(name); @@ -181,16 +189,6 @@ static int supported_man_viewer(const char *name, size_t len) !strncasecmp("konqueror", name, len)); } -static int add_man_viewer(const char *value) -{ - if (supported_man_viewer(value, strlen(value))) - do_add_man_viewer(value); - else - warning("'%s': unsupported man viewer.", value); - - return 0; -} - static void do_add_man_viewer_info(const char *name, size_t len, const char *value) @@ -210,7 +208,23 @@ static int add_man_viewer_path(const char *name, if (supported_man_viewer(name, len)) do_add_man_viewer_info(name, len, value); else - warning("'%s': path for unsupported man viewer.", name); + warning("'%s': path for unsupported man viewer.\n" + "Please consider using 'man..cmd' instead.", + name); + + return 0; +} + +static int add_man_viewer_cmd(const char *name, + size_t len, + const char *value) +{ + if (supported_man_viewer(name, len)) + warning("'%s': cmd for supported man viewer.\n" + "Please consider using 'man..path' instead.", + name); + else + do_add_man_viewer_info(name, len, value); return 0; } @@ -228,6 +242,11 @@ static int add_man_viewer_info(const char *var, const char *value) return config_error_nonbool(var); return add_man_viewer_path(name, subkey - name, value); } + if (!strcmp(subkey, ".cmd")) { + if (!value) + return config_error_nonbool(var); + return add_man_viewer_cmd(name, subkey - name, value); + } warning("'%s': unsupported man viewer sub key.", subkey); return 0; @@ -244,7 +263,8 @@ static int git_help_config(const char *var, const char *value) if (!strcmp(var, "man.viewer")) { if (!value) return config_error_nonbool(var); - return add_man_viewer(value); + add_man_viewer(value); + return 0; } if (!prefixcmp(var, "man.")) return add_man_viewer_info(var, value); @@ -546,16 +566,18 @@ static void setup_man_path(void) static void exec_viewer(const char *name, const char *page) { - const char *path = get_man_viewer_info(name); + const char *info = get_man_viewer_info(name); if (!strcasecmp(name, "man")) - exec_man_man(path, page); + exec_man_man(info, page); else if (!strcasecmp(name, "woman")) - exec_woman_emacs(path, page); + exec_woman_emacs(info, page); else if (!strcasecmp(name, "konqueror")) - exec_man_konqueror(path, page); + exec_man_konqueror(info, page); + else if (info) + exec_man_cmd(info, page); else - warning("'%s': unsupported man viewer.", name); + warning("'%s': unknown man viewer.", name); } static void show_man_page(const char *git_cmd) From 0bb64009586b7fd674b1c3238f041b61c5d03f91 Mon Sep 17 00:00:00 2001 From: Christian Couder Date: Fri, 25 Apr 2008 08:25:35 +0200 Subject: [PATCH 4/5] documentation: help: add info about "man..cmd" config var This patch also describes the current behavior for "konqueror" and how to modify it using "man..cmd" if needed. Signed-off-by: Christian Couder Signed-off-by: Junio C Hamano --- Documentation/config.txt | 5 ++++ Documentation/git-help.txt | 48 ++++++++++++++++++++++++++++++++++---- 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 138ba9ad8f..3b65c07517 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -805,6 +805,11 @@ merge..recursive:: performing an internal merge between common ancestors. See linkgit:gitattributes[5] for details. +man..cmd:: + Specify the command to invoke the specified man viewer. The + specified command is evaluated in shell with the man page + passed as argument. (See linkgit:git-help[1].) + man..path:: Override the path for the given tool that may be used to display help in the 'man' format. See linkgit:git-help[1]. diff --git a/Documentation/git-help.txt b/Documentation/git-help.txt index 4c6cb2194c..bfbba9e235 100644 --- a/Documentation/git-help.txt +++ b/Documentation/git-help.txt @@ -82,22 +82,28 @@ man.viewer ~~~~~~~~~~ The 'man.viewer' config variable will be checked if the 'man' format -is chosen. Only the following values are currently supported: +is chosen. The following values are currently supported: * "man": use the 'man' program as usual, * "woman": use 'emacsclient' to launch the "woman" mode in emacs (this only works starting with emacsclient versions 22), -* "konqueror": use a man KIO slave in konqueror. +* "konqueror": use 'kfmclient' to open the man page in a new konqueror +tab (see 'Note about konqueror' below). -Multiple values may be given to this configuration variable. Their -corresponding programs will be tried in the order listed in the -configuration file. +Values for other tools can be used if there is a corresponding +'man..cmd' configuration entry (see below). + +Multiple values may be given to the 'man.viewer' configuration +variable. Their corresponding programs will be tried in the order +listed in the configuration file. For example, this configuration: +------------------------------------------------ [man] viewer = konqueror viewer = woman +------------------------------------------------ will try to use konqueror first. But this may fail (for example if DISPLAY is not set) and in that case emacs' woman mode will be tried. @@ -113,6 +119,38 @@ can configure the absolute path to konqueror by setting 'man.konqueror.path'. Otherwise, 'git help' assumes the tool is available in PATH. +man..cmd +~~~~~~~~~~~~~~ + +When the man viewer, specified by the 'man.viewer' configuration +variables, is not among the supported ones, then the corresponding +'man..cmd' configuration variable will be looked up. If this +variable exists then the specified tool will be treated as a custom +command and a shell eval will be used to run the command with the man +page passed as arguments. + +Note about konqueror +~~~~~~~~~~~~~~~~~~~~ + +When 'konqueror' is specified in the 'man.viewer' configuration +variable, we launch 'kfmclient' to try to open the man page on an +already opened konqueror in a new tab if possible. + +For consistency, we also try such a trick if 'man.konqueror.path' is +set to something like 'A_PATH_TO/konqueror'. That means we will try to +launch 'A_PATH_TO/kfmclient' instead. + +If you really want to use 'konqueror', then you can use something like +the following: + +------------------------------------------------ + [man] + viewer = konq + + [man "konq"] + cmd = A_PATH_TO/konqueror +------------------------------------------------ + Note about git config --global ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From ac3a4a2694fa8bea477b1a265efd6829de686e5c Mon Sep 17 00:00:00 2001 From: Christian Couder Date: Fri, 25 Apr 2008 08:25:41 +0200 Subject: [PATCH 5/5] documentation: web--browse: add a note about konqueror This note explains how to work around the fact that we try to use kfmclient to launch konqueror. Signed-off-by: Christian Couder Signed-off-by: Junio C Hamano --- Documentation/git-web--browse.txt | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/Documentation/git-web--browse.txt b/Documentation/git-web--browse.txt index ddbae5b194..92ef574565 100644 --- a/Documentation/git-web--browse.txt +++ b/Documentation/git-web--browse.txt @@ -20,7 +20,7 @@ The following browsers (or commands) are currently supported: * firefox (this is the default under X Window when not using KDE) * iceweasel -* konqueror (this is the default under KDE) +* konqueror (this is the default under KDE, see 'Note about konqueror' below) * w3m (this is the default outside graphical environments) * links * lynx @@ -71,6 +71,28 @@ variable exists then "git web--browse" will treat the specified tool as a custom command and will use a shell eval to run the command with the URLs passed as arguments. +Note about konqueror +-------------------- + +When 'konqueror' is specified by the a command line option or a +configuration variable, we launch 'kfmclient' to try to open the HTML +man page on an already opened konqueror in a new tab if possible. + +For consistency, we also try such a trick if 'brower.konqueror.path' is +set to something like 'A_PATH_TO/konqueror'. That means we will try to +launch 'A_PATH_TO/kfmclient' instead. + +If you really want to use 'konqueror', then you can use something like +the following: + +------------------------------------------------ + [web] + browser = konq + + [browser "konq"] + cmd = A_PATH_TO/konqueror +------------------------------------------------ + Note about git config --global ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~