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>
Christian Couder committed
Mar 11, 2008 at 08:51 UTC
69099d6bedb0217d7c35f7202acd6185551d762f
1 file changed
+113
-78
help.c
+113
-78
@@ -10,7 +10,10 @@
10
#include "parse-options.h"
11
#include "run-command.h"
12
13
-static const char *man_viewer;
13
+static struct man_viewer_list {
14
+ void (*exec)(const char *);
15
+ struct man_viewer_list *next;
16
+} *man_viewer_list;
17
18
enum help_format {
19
HELP_FORMAT_MAN,
@@ -45,6 +48,102 @@ static enum help_format parse_help_format(const char *format)
48
die("unrecognized help format '%s'", format);
49
}
50
51
+static int check_emacsclient_version(void)
52
+{
53
+ struct strbuf buffer = STRBUF_INIT;
54
+ struct child_process ec_process;
55
+ const char *argv_ec[] = { "emacsclient", "--version", NULL };
56
+ int version;
57
+
58
+ /* emacsclient prints its version number on stderr */
59
+ memset(&ec_process, 0, sizeof(ec_process));
60
+ ec_process.argv = argv_ec;
61
+ ec_process.err = -1;
62
+ ec_process.stdout_to_stderr = 1;
63
+ if (start_command(&ec_process)) {
64
+ fprintf(stderr, "Failed to start emacsclient.\n");
65
+ return -1;
66
+ }
67
+ strbuf_read(&buffer, ec_process.err, 20);
68
+ close(ec_process.err);
69
+
70
+ /*
71
+ * Don't bother checking return value, because "emacsclient --version"
72
+ * seems to always exits with code 1.
73
+ */
74
+ finish_command(&ec_process);
75
+
76
+ if (prefixcmp(buffer.buf, "emacsclient")) {
77
+ fprintf(stderr, "Failed to parse emacsclient version.\n");
78
+ strbuf_release(&buffer);
79
+ return -1;
80
+ }
81
+
82
+ strbuf_remove(&buffer, 0, strlen("emacsclient"));
83
+ version = atoi(buffer.buf);
84
+
85
+ if (version < 22) {
86
+ fprintf(stderr,
87
+ "emacsclient version '%d' too old (< 22).\n",
88
+ version);
89
+ strbuf_release(&buffer);
90
+ return -1;
91
+ }
92
+
93
+ strbuf_release(&buffer);
94
+ return 0;
95
+}
96
+
97
+static void exec_woman_emacs(const char *page)
98
+{
99
+ if (!check_emacsclient_version()) {
100
+ /* This works only with emacsclient version >= 22. */
101
+ struct strbuf man_page = STRBUF_INIT;
102
+ strbuf_addf(&man_page, "(woman \"%s\")", page);
103
+ execlp("emacsclient", "emacsclient", "-e", man_page.buf, NULL);
104
+ }
105
+}
106
+
107
+static void exec_man_konqueror(const char *page)
108
+{
109
+ const char *display = getenv("DISPLAY");
110
+ if (display && *display) {
111
+ struct strbuf man_page = STRBUF_INIT;
112
+ strbuf_addf(&man_page, "man:%s(1)", page);
113
+ execlp("kfmclient", "kfmclient", "newTab", man_page.buf, NULL);
114
+ }
115
+}
116
+
117
+static void exec_man_man(const char *page)
118
+{
119
+ execlp("man", "man", page, NULL);
120
+}
121
+
122
+static void do_add_man_viewer(void (*exec)(const char *))
123
+{
124
+ struct man_viewer_list **p = &man_viewer_list;
125
+
126
+ while (*p)
127
+ p = &((*p)->next);
128
+ *p = xmalloc(sizeof(**p));
129
+ (*p)->next = NULL;
130
+ (*p)->exec = exec;
131
+}
132
+
133
+static int add_man_viewer(const char *value)
134
+{
135
+ if (!strcasecmp(value, "man"))
136
+ do_add_man_viewer(exec_man_man);
137
+ else if (!strcasecmp(value, "woman"))
138
+ do_add_man_viewer(exec_woman_emacs);
139
+ else if (!strcasecmp(value, "konqueror"))
140
+ do_add_man_viewer(exec_man_konqueror);
141
+ else
142
+ return error("'%s': unsupported man viewer.", value);
143
+
144
+ return 0;
145
+}
146
+
147
static int git_help_config(const char *var, const char *value)
148
{
149
if (!strcmp(var, "help.format")) {
@@ -53,8 +152,11 @@ static int git_help_config(const char *var, const char *value)
152
help_format = parse_help_format(value);
153
return 0;
154
}
56
- if (!strcmp(var, "man.viewer"))
57
- return git_config_string(&man_viewer, var, value);
155
+ if (!strcmp(var, "man.viewer")) {
156
+ if (!value)
157
+ return config_error_nonbool(var);
158
+ return add_man_viewer(value);
159
+ }
160
return git_default_config(var, value);
161
}
162
@@ -350,85 +452,18 @@ static void setup_man_path(void)
452
strbuf_release(&new_path);
453
}
454
353
-static int check_emacsclient_version(void)
354
-{
355
- struct strbuf buffer = STRBUF_INIT;
356
- struct child_process ec_process;
357
- const char *argv_ec[] = { "emacsclient", "--version", NULL };
358
- int version;
359
-
360
- /* emacsclient prints its version number on stderr */
361
- memset(&ec_process, 0, sizeof(ec_process));
362
- ec_process.argv = argv_ec;
363
- ec_process.err = -1;
364
- ec_process.stdout_to_stderr = 1;
365
- if (start_command(&ec_process)) {
366
- fprintf(stderr, "Failed to start emacsclient.\n");
367
- return -1;
368
- }
369
- strbuf_read(&buffer, ec_process.err, 20);
370
- close(ec_process.err);
371
-
372
- /*
373
- * Don't bother checking return value, because "emacsclient --version"
374
- * seems to always exits with code 1.
375
- */
376
- finish_command(&ec_process);
377
-
378
- if (prefixcmp(buffer.buf, "emacsclient")) {
379
- fprintf(stderr, "Failed to parse emacsclient version.\n");
380
- strbuf_release(&buffer);
381
- return -1;
382
- }
383
-
384
- strbuf_remove(&buffer, 0, strlen("emacsclient"));
385
- version = atoi(buffer.buf);
386
-
387
- if (version < 22) {
388
- fprintf(stderr,
389
- "emacsclient version '%d' too old (< 22).\n",
390
- version);
391
- strbuf_release(&buffer);
392
- return -1;
393
- }
394
-
395
- strbuf_release(&buffer);
396
- return 0;
397
-}
398
-
399
-static void exec_woman_emacs(const char *page)
400
-{
401
- if (!check_emacsclient_version()) {
402
- /* This works only with emacsclient version >= 22. */
403
- struct strbuf man_page = STRBUF_INIT;
404
- strbuf_addf(&man_page, "(woman \"%s\")", page);
405
- execlp("emacsclient", "emacsclient", "-e", man_page.buf, NULL);
406
- } else
407
- execlp("man", "man", page, NULL);
408
-}
409
-
410
-static void exec_man_konqueror(const char *page)
411
-{
412
- const char *display = getenv("DISPLAY");
413
- if (display && *display) {
414
- struct strbuf man_page = STRBUF_INIT;
415
- strbuf_addf(&man_page, "man:%s(1)", page);
416
- execlp("kfmclient", "kfmclient", "newTab", man_page.buf, NULL);
417
- } else
418
- execlp("man", "man", page, NULL);
419
-}
420
-
455
static void show_man_page(const char *git_cmd)
456
{
457
+ struct man_viewer_list *viewer;
458
const char *page = cmd_to_page(git_cmd);
459
+
460
setup_man_path();
425
- if (!man_viewer || !strcmp(man_viewer, "man"))
426
- execlp("man", "man", page, NULL);
427
- if (!strcmp(man_viewer, "woman"))
428
- exec_woman_emacs(page);
429
- if (!strcmp(man_viewer, "konqueror"))
430
- exec_man_konqueror(page);
431
- die("'%s': unsupported man viewer.", man_viewer);
461
+ for (viewer = man_viewer_list; viewer; viewer = viewer->next)
462
+ {
463
+ viewer->exec(page); /* will return when unable */
464
+ }
465
+ exec_man_man(page);
466
+ die("no man viewer handled the request");
467
}
468
469
static void show_info_page(const char *git_cmd)