Currently "git help -m GITCMD" is restricted to a set of man viewers defined at compile time. You can subvert the "man.<tool>.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.<tool>.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.<tool>.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 <chriscool@xxxxxxxxxxxxx> --- help.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++---------------- 1 files changed, 59 insertions(+), 20 deletions(-) This patch applies on top of my previous patches: [PATCH 1/2] help: use man viewer path from "man.<tool>.path" config var [PATCH 2/2] documentation: help: add "man.<tool>.path" config variable diff --git a/help.c b/help.c index fd88c22..b907dd9 100644 --- a/help.c +++ b/help.c @@ -11,8 +11,9 @@ #include "run-command.h" static struct man_viewer_list { - void (*exec)(const char *); struct man_viewer_list *next; + void (*exec)(const char *, const char *); + char name[FLEX_ARRAY]; } *man_viewer_list; static struct man_viewer_info_list { @@ -112,12 +113,11 @@ static int check_emacsclient_version(void) return 0; } -static void exec_woman_emacs(const char *page) +static void exec_woman_emacs(const char *page, const char *path) { if (!check_emacsclient_version()) { /* This works only with emacsclient version >= 22. */ struct strbuf man_page = STRBUF_INIT; - const char *path = get_man_viewer_info("woman"); if (!path) path = "emacsclient"; @@ -127,12 +127,11 @@ static void exec_woman_emacs(const char *page) } } -static void exec_man_konqueror(const char *page) +static void exec_man_konqueror(const char *page, const char *path) { const char *display = getenv("DISPLAY"); if (display && *display) { struct strbuf man_page = STRBUF_INIT; - const char *path = get_man_viewer_info("konqueror"); /* It's simpler to launch konqueror using kfmclient. */ if (path) { @@ -153,37 +152,45 @@ static void exec_man_konqueror(const char *page) } } -static void exec_man_man(const char *page) +static void exec_man_man(const char *page, const char *path) { - const char *path = get_man_viewer_info("man"); - 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 exec_man_cmd(const char *page, const char *cmd) +{ + 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 do_add_man_viewer(void (*exec)(const char *, const char *), + 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 = xcalloc(1, sizeof(**p) + len + 1); + strncpy((*p)->name, name, len); (*p)->exec = exec; } static int add_man_viewer(const char *value) { if (!strcasecmp(value, "man")) - do_add_man_viewer(exec_man_man); + do_add_man_viewer(exec_man_man, value); else if (!strcasecmp(value, "woman")) - do_add_man_viewer(exec_woman_emacs); + do_add_man_viewer(exec_woman_emacs, value); else if (!strcasecmp(value, "konqueror")) - do_add_man_viewer(exec_man_konqueror); + do_add_man_viewer(exec_man_konqueror, value); else - warning("'%s': unsupported man viewer.", value); + do_add_man_viewer(exec_man_cmd, value); return 0; } @@ -200,13 +207,18 @@ static void do_add_man_viewer_info(const char *name, man_viewer_info_list = new; } +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_path(const char *name, size_t len, const char *value) { - if (!strncasecmp("man", name, len) || - !strncasecmp("woman", name, len) || - !strncasecmp("konqueror", name, len)) + if (supported_man_viewer(name, len)) do_add_man_viewer_info(name, len, value); else warning("'%s': path for unsupported man viewer.", name); @@ -214,6 +226,20 @@ static int add_man_viewer_path(const char *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.<tool>.path' instead.", + name); + else + do_add_man_viewer_info(name, len, value); + + return 0; +} + static int add_man_viewer_info(const char *var, const char *value) { const char *name = var + 4; @@ -227,6 +253,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; @@ -546,14 +577,22 @@ static void setup_man_path(void) static void show_man_page(const char *git_cmd) { struct man_viewer_list *viewer; + const char *info; const char *page = cmd_to_page(git_cmd); setup_man_path(); for (viewer = man_viewer_list; viewer; viewer = viewer->next) { - viewer->exec(page); /* will return when unable */ + int supported = supported_man_viewer(viewer->name, + strlen(viewer->name)); + info = get_man_viewer_info(viewer->name); + if (supported || info) + viewer->exec(page, info); /* will return when unable */ + else + warning("%s: unknown man viewer", viewer->name); } - exec_man_man(page); + info = get_man_viewer_info("man"); + exec_man_man(page, info); die("no man viewer handled the request"); } -- 1.5.5.rc0.124.g91c15.dirty -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html