git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Christian Couder <chriscool@tuxfamily.org>
To: "Junio Hamano" <junkio@cox.net>, "Pascal Obry" <pascal@obry.net>,
	"Xavier Maillard" <xma@gnu.org>
Cc: git@vger.kernel.org
Subject: [PATCH] help: implement multi-valued "man.viewer" config option
Date: Tue, 11 Mar 2008 08:51:12 +0100	[thread overview]
Message-ID: <20080311085113.176df1af.chriscool@tuxfamily.org> (raw)

Junio suggested:
> How about allowing multi-valued man.viewer like this:
>
>        [man]
>                viewer = woman
>                viewer = konqueror
>                viewer = man
>
> and have:
>
>        static struct man_viewer {
>                char *name;
>                void (*exec)(const char *);
>        } viewers[] = {
>                { "woman", exec_woman },
>                { "konqueror", exec_konqueror },
>                { "man", exec_man },
>                { NULL, },
>        };
>
> Then you can iterate the man.viewer values, ask the viewer's
> exec() function to show the page (or return when it is not
> in an environment that it can be useful).
>
> show_man_page() would become:
>
>        for (each viewer in user's config)
>                viewer.exec(page); /* will return when unable */
>        die("no man viewer handled the request");

This patch implements the above using a list of exec functions that
is filled when reading the config.

To do that the exec functions have been moved before reading the
config. This makes the patch much longer than it would be otherwise.

Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
---
 help.c |  191 ++++++++++++++++++++++++++++++++++++++--------------------------
 1 files changed, 113 insertions(+), 78 deletions(-)

	This is on top of my previous "man.viewer" patches:

	[PATCH 1/2] help: add "man.viewer" config var to use "woman" or "konqueror"
	[PATCH 2/2] Documentation: help: describe 'man.viewer' config variable

diff --git a/help.c b/help.c
index 2cb152d..5da8c9c 100644
--- a/help.c
+++ b/help.c
@@ -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)
-- 
1.5.4.4.595.g9c65

             reply	other threads:[~2008-03-11  7:46 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-03-11  7:51 Christian Couder [this message]
2008-03-12  1:00 ` [PATCH] help: implement multi-valued "man.viewer" config option Xavier Maillard
2008-03-12  7:23   ` Christian Couder
2008-03-14  1:00     ` Xavier Maillard
2008-03-14  5:26       ` Christian Couder
2008-03-15 13:00         ` Xavier Maillard

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20080311085113.176df1af.chriscool@tuxfamily.org \
    --to=chriscool@tuxfamily.org \
    --cc=git@vger.kernel.org \
    --cc=junkio@cox.net \
    --cc=pascal@obry.net \
    --cc=xma@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).