#include "exec_cmd.h"
#include "common-cmds.h"
#include "parse-options.h"
+#include "run-command.h"
+
+static struct man_viewer_list {
+ void (*exec)(const char *);
+ struct man_viewer_list *next;
+} *man_viewer_list;
enum help_format {
HELP_FORMAT_MAN,
HELP_FORMAT_WEB),
OPT_SET_INT('i', "info", &help_format, "show info page",
HELP_FORMAT_INFO),
+ OPT_END(),
};
static const char * const builtin_help_usage[] = {
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
+ warning("'%s': unsupported man viewer.", value);
+
+ return 0;
+}
+
static int git_help_config(const char *var, const char *value)
{
if (!strcmp(var, "help.format")) {
help_format = parse_help_format(value);
return 0;
}
+ if (!strcmp(var, "man.viewer")) {
+ if (!value)
+ return config_error_nonbool(var);
+ return add_man_viewer(value);
+ }
return git_default_config(var, value);
}
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();
- execlp("man", "man", page, NULL);
+ 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)