{"thread":{"id":"12788","subject":"[PATCH] help: use \"man.<tool>.cmd\" as custom man viewer command","startedAt":"2008-03-21T07:07:18Z","lastAt":"2008-03-21T07:07:18Z","messageCount":1,"participants":["Christian Couder"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"72579","messageId":"20080321080718.315458f2.chriscool@tuxfamily.org","threadId":"12788","inReplyTo":null,"subject":"[PATCH] help: use \"man.<tool>.cmd\" as custom man viewer command","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2008-03-21T07:07:18Z","receivedAt":"2008-03-21T07:07:18Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"Currently \"git help -m GITCMD\" is restricted to a set of man\nviewers defined at compile time. You can subvert the\n\"man.<tool>.path\" to force \"git help -m\" to use a different man,\nviewer, but if you have a man viewer whose invocation syntax does\nnot match one of the current tools then you would have to write a\nwrapper script for it.\n\nThis patch adds a git config variable \"man.<tool>.cmd\" which\nallows a more flexible man viewer choice.\n\nIf you run \"git help -m GITCMD\" with the \"man.viewer\" config\nvariable set to an unrecognized tool then it will query the\n\"man.<tool>.cmd\" config variable. If this variable exists, then\nthe specified tool will be treated as a custom man viewer and it\nwill be run in a shell with the man page name of the GITCMD added\nas extra parameter.\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n help.c |   79 +++++++++++++++++++++++++++++++++++++++++++++++----------------\n 1 files changed, 59 insertions(+), 20 deletions(-)\n\n\tThis patch applies on top of my previous patches:\n\n\t[PATCH 1/2] help: use man viewer path from \"man.<tool>.path\" config var\n\t[PATCH 2/2] documentation: help: add \"man.<tool>.path\" config variable\n\n\ndiff --git a/help.c b/help.c\nindex fd88c22..b907dd9 100644\n--- a/help.c\n+++ b/help.c\n@@ -11,8 +11,9 @@\n #include \"run-command.h\"\n \n static struct man_viewer_list {\n-\tvoid (*exec)(const char *);\n \tstruct man_viewer_list *next;\n+\tvoid (*exec)(const char *, const char *);\n+\tchar name[FLEX_ARRAY];\n } *man_viewer_list;\n \n static struct man_viewer_info_list {\n@@ -112,12 +113,11 @@ static int check_emacsclient_version(void)\n \treturn 0;\n }\n \n-static void exec_woman_emacs(const char *page)\n+static void exec_woman_emacs(const char *page, const char *path)\n {\n \tif (!check_emacsclient_version()) {\n \t\t/* This works only with emacsclient version >= 22. */\n \t\tstruct strbuf man_page = STRBUF_INIT;\n-\t\tconst char *path = get_man_viewer_info(\"woman\");\n \n \t\tif (!path)\n \t\t\tpath = \"emacsclient\";\n@@ -127,12 +127,11 @@ static void exec_woman_emacs(const char *page)\n \t}\n }\n \n-static void exec_man_konqueror(const char *page)\n+static void exec_man_konqueror(const char *page, const char *path)\n {\n \tconst char *display = getenv(\"DISPLAY\");\n \tif (display && *display) {\n \t\tstruct strbuf man_page = STRBUF_INIT;\n-\t\tconst char *path = get_man_viewer_info(\"konqueror\");\n \n \t\t/* It's simpler to launch konqueror using kfmclient. */\n \t\tif (path) {\n@@ -153,37 +152,45 @@ static void exec_man_konqueror(const char *page)\n \t}\n }\n \n-static void exec_man_man(const char *page)\n+static void exec_man_man(const char *page, const char *path)\n {\n-\tconst char *path = get_man_viewer_info(\"man\");\n-\n \tif (!path)\n \t\tpath = \"man\";\n \texeclp(path, \"man\", page, NULL);\n \twarning(\"failed to exec '%s': %s\", path, strerror(errno));\n }\n \n-static void do_add_man_viewer(void (*exec)(const char *))\n+static void exec_man_cmd(const char *page, const char *cmd)\n+{\n+\tstruct strbuf shell_cmd = STRBUF_INIT;\n+\tstrbuf_addf(&shell_cmd, \"%s %s\", cmd, page);\n+\texecl(\"/bin/sh\", \"sh\", \"-c\", shell_cmd.buf, NULL);\n+\twarning(\"failed to exec '%s': %s\", cmd, strerror(errno));\n+}\n+\n+static void do_add_man_viewer(void (*exec)(const char *, const char *),\n+\t\t\t      const char *name)\n {\n \tstruct man_viewer_list **p = &man_viewer_list;\n+\tsize_t len = strlen(name);\n \n \twhile (*p)\n \t\tp = &((*p)->next);\n-\t*p = xmalloc(sizeof(**p));\n-\t(*p)->next = NULL;\n+\t*p = xcalloc(1, sizeof(**p) + len + 1);\n+\tstrncpy((*p)->name, name, len);\n \t(*p)->exec = exec;\n }\n \n static int add_man_viewer(const char *value)\n {\n \tif (!strcasecmp(value, \"man\"))\n-\t\tdo_add_man_viewer(exec_man_man);\n+\t\tdo_add_man_viewer(exec_man_man, value);\n \telse if (!strcasecmp(value, \"woman\"))\n-\t\tdo_add_man_viewer(exec_woman_emacs);\n+\t\tdo_add_man_viewer(exec_woman_emacs, value);\n \telse if (!strcasecmp(value, \"konqueror\"))\n-\t\tdo_add_man_viewer(exec_man_konqueror);\n+\t\tdo_add_man_viewer(exec_man_konqueror, value);\n \telse\n-\t\twarning(\"'%s': unsupported man viewer.\", value);\n+\t\tdo_add_man_viewer(exec_man_cmd, value);\n \n \treturn 0;\n }\n@@ -200,13 +207,18 @@ static void do_add_man_viewer_info(const char *name,\n \tman_viewer_info_list = new;\n }\n \n+static int supported_man_viewer(const char *name, size_t len)\n+{\n+\treturn (!strncasecmp(\"man\", name, len) ||\n+\t\t!strncasecmp(\"woman\", name, len) ||\n+\t\t!strncasecmp(\"konqueror\", name, len));\n+}\n+\n static int add_man_viewer_path(const char *name,\n \t\t\t       size_t len,\n \t\t\t       const char *value)\n {\n-\tif (!strncasecmp(\"man\", name, len) ||\n-\t    !strncasecmp(\"woman\", name, len) ||\n-\t    !strncasecmp(\"konqueror\", name, len))\n+\tif (supported_man_viewer(name, len))\n \t\tdo_add_man_viewer_info(name, len, value);\n \telse\n \t\twarning(\"'%s': path for unsupported man viewer.\", name);\n@@ -214,6 +226,20 @@ static int add_man_viewer_path(const char *name,\n \treturn 0;\n }\n \n+static int add_man_viewer_cmd(const char *name,\n+\t\t\t      size_t len,\n+\t\t\t      const char *value)\n+{\n+\tif (supported_man_viewer(name, len))\n+\t\twarning(\"'%s': cmd for supported man viewer.\\n\"\n+\t\t\t\"Please consider using 'man.<tool>.path' instead.\",\n+\t\t\tname);\n+\telse\n+\t\tdo_add_man_viewer_info(name, len, value);\n+\n+\treturn 0;\n+}\n+\n static int add_man_viewer_info(const char *var, const char *value)\n {\n \tconst char *name = var + 4;\n@@ -227,6 +253,11 @@ static int add_man_viewer_info(const char *var, const char *value)\n \t\t\treturn config_error_nonbool(var);\n \t\treturn add_man_viewer_path(name, subkey - name, value);\n \t}\n+\tif (!strcmp(subkey, \".cmd\")) {\n+\t\tif (!value)\n+\t\t\treturn config_error_nonbool(var);\n+\t\treturn add_man_viewer_cmd(name, subkey - name, value);\n+\t}\n \n \twarning(\"'%s': unsupported man viewer sub key.\", subkey);\n \treturn 0;\n@@ -546,14 +577,22 @@ static void setup_man_path(void)\n static void show_man_page(const char *git_cmd)\n {\n \tstruct man_viewer_list *viewer;\n+\tconst char *info;\n \tconst char *page = cmd_to_page(git_cmd);\n \n \tsetup_man_path();\n \tfor (viewer = man_viewer_list; viewer; viewer = viewer->next)\n \t{\n-\t\tviewer->exec(page); /* will return when unable */\n+\t\tint supported = supported_man_viewer(viewer->name,\n+\t\t\t\t\t\t     strlen(viewer->name));\n+\t\tinfo = get_man_viewer_info(viewer->name);\n+\t\tif (supported || info)\n+\t\t\tviewer->exec(page, info); /* will return when unable */\n+\t\telse\n+\t\t\twarning(\"%s: unknown man viewer\", viewer->name);\n \t}\n-\texec_man_man(page);\n+\tinfo = get_man_viewer_info(\"man\");\n+\texec_man_man(page, info);\n \tdie(\"no man viewer handled the request\");\n }\n \n-- \n1.5.5.rc0.124.g91c15.dirty\n"}]}