help: implement multi-valued "man.viewer" config option

This allows multiple viewer candidates to be listed in the configuration
file, like this:

        [man]
                viewer = woman
                viewer = konqueror
                viewer = man

The candidates are tried in the order listed in the configuration file,
and the first suitable one (e.g. konqueror cannot be used outside windowed
environment) is used.

Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
Tested-by: Xavier Maillard <xma@gnu.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Christian Couder 2008-03-11 08:51:12 +01:00 committed by Junio C Hamano
parent b5578f3335
commit 69099d6bed

191
help.c
View File

@ -10,7 +10,10 @@
#include "parse-options.h"
#include "run-command.h"
static const char *man_viewer;
static struct man_viewer_list {
void (*exec)(const char *);
struct man_viewer_list *next;
} *man_viewer_list;
enum help_format {
HELP_FORMAT_MAN,
@ -45,6 +48,102 @@ static enum help_format parse_help_format(const char *format)
die("unrecognized help format '%s'", format);
}
static int check_emacsclient_version(void)
{
struct strbuf buffer = STRBUF_INIT;
struct child_process ec_process;
const char *argv_ec[] = { "emacsclient", "--version", NULL };
int version;
/* emacsclient prints its version number on stderr */
memset(&ec_process, 0, sizeof(ec_process));
ec_process.argv = argv_ec;
ec_process.err = -1;
ec_process.stdout_to_stderr = 1;
if (start_command(&ec_process)) {
fprintf(stderr, "Failed to start emacsclient.\n");
return -1;
}
strbuf_read(&buffer, ec_process.err, 20);
close(ec_process.err);
/*
* Don't bother checking return value, because "emacsclient --version"
* seems to always exits with code 1.
*/
finish_command(&ec_process);
if (prefixcmp(buffer.buf, "emacsclient")) {
fprintf(stderr, "Failed to parse emacsclient version.\n");
strbuf_release(&buffer);
return -1;
}
strbuf_remove(&buffer, 0, strlen("emacsclient"));
version = atoi(buffer.buf);
if (version < 22) {
fprintf(stderr,
"emacsclient version '%d' too old (< 22).\n",
version);
strbuf_release(&buffer);
return -1;
}
strbuf_release(&buffer);
return 0;
}
static void exec_woman_emacs(const char *page)
{
if (!check_emacsclient_version()) {
/* This works only with emacsclient version >= 22. */
struct strbuf man_page = STRBUF_INIT;
strbuf_addf(&man_page, "(woman \"%s\")", page);
execlp("emacsclient", "emacsclient", "-e", man_page.buf, NULL);
}
}
static void exec_man_konqueror(const char *page)
{
const char *display = getenv("DISPLAY");
if (display && *display) {
struct strbuf man_page = STRBUF_INIT;
strbuf_addf(&man_page, "man:%s(1)", page);
execlp("kfmclient", "kfmclient", "newTab", man_page.buf, NULL);
}
}
static void exec_man_man(const char *page)
{
execlp("man", "man", page, NULL);
}
static void do_add_man_viewer(void (*exec)(const char *))
{
struct man_viewer_list **p = &man_viewer_list;
while (*p)
p = &((*p)->next);
*p = xmalloc(sizeof(**p));
(*p)->next = NULL;
(*p)->exec = exec;
}
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);
else
return error("'%s': unsupported man viewer.", value);
return 0;
}
static int git_help_config(const char *var, const char *value)
{
if (!strcmp(var, "help.format")) {
@ -53,8 +152,11 @@ static int git_help_config(const char *var, const char *value)
help_format = parse_help_format(value);
return 0;
}
if (!strcmp(var, "man.viewer"))
return git_config_string(&man_viewer, var, value);
if (!strcmp(var, "man.viewer")) {
if (!value)
return config_error_nonbool(var);
return add_man_viewer(value);
}
return git_default_config(var, value);
}
@ -350,85 +452,18 @@ static void setup_man_path(void)
strbuf_release(&new_path);
}
static int check_emacsclient_version(void)
{
struct strbuf buffer = STRBUF_INIT;
struct child_process ec_process;
const char *argv_ec[] = { "emacsclient", "--version", NULL };
int version;
/* emacsclient prints its version number on stderr */
memset(&ec_process, 0, sizeof(ec_process));
ec_process.argv = argv_ec;
ec_process.err = -1;
ec_process.stdout_to_stderr = 1;
if (start_command(&ec_process)) {
fprintf(stderr, "Failed to start emacsclient.\n");
return -1;
}
strbuf_read(&buffer, ec_process.err, 20);
close(ec_process.err);
/*
* Don't bother checking return value, because "emacsclient --version"
* seems to always exits with code 1.
*/
finish_command(&ec_process);
if (prefixcmp(buffer.buf, "emacsclient")) {
fprintf(stderr, "Failed to parse emacsclient version.\n");
strbuf_release(&buffer);
return -1;
}
strbuf_remove(&buffer, 0, strlen("emacsclient"));
version = atoi(buffer.buf);
if (version < 22) {
fprintf(stderr,
"emacsclient version '%d' too old (< 22).\n",
version);
strbuf_release(&buffer);
return -1;
}
strbuf_release(&buffer);
return 0;
}
static void exec_woman_emacs(const char *page)
{
if (!check_emacsclient_version()) {
/* This works only with emacsclient version >= 22. */
struct strbuf man_page = STRBUF_INIT;
strbuf_addf(&man_page, "(woman \"%s\")", page);
execlp("emacsclient", "emacsclient", "-e", man_page.buf, NULL);
} else
execlp("man", "man", page, NULL);
}
static void exec_man_konqueror(const char *page)
{
const char *display = getenv("DISPLAY");
if (display && *display) {
struct strbuf man_page = STRBUF_INIT;
strbuf_addf(&man_page, "man:%s(1)", page);
execlp("kfmclient", "kfmclient", "newTab", man_page.buf, NULL);
} else
execlp("man", "man", page, NULL);
}
static void show_man_page(const char *git_cmd)
{
struct man_viewer_list *viewer;
const char *page = cmd_to_page(git_cmd);
setup_man_path();
if (!man_viewer || !strcmp(man_viewer, "man"))
execlp("man", "man", page, NULL);
if (!strcmp(man_viewer, "woman"))
exec_woman_emacs(page);
if (!strcmp(man_viewer, "konqueror"))
exec_man_konqueror(page);
die("'%s': unsupported man viewer.", man_viewer);
for (viewer = man_viewer_list; viewer; viewer = viewer->next)
{
viewer->exec(page); /* will return when unable */
}
exec_man_man(page);
die("no man viewer handled the request");
}
static void show_info_page(const char *git_cmd)