]>
Commit | Line | Data |
---|---|---|
f67b45f8 | 1 | #include "cache.h" |
ea27a18c | 2 | #include "run-command.h" |
a3da8821 | 3 | #include "sigchain.h" |
f67b45f8 | 4 | |
a3d023d0 JH |
5 | #ifndef DEFAULT_PAGER |
6 | #define DEFAULT_PAGER "less" | |
7 | #endif | |
8 | ||
4914c962 NTND |
9 | struct pager_config { |
10 | const char *cmd; | |
11 | int want; | |
12 | char *value; | |
13 | }; | |
14 | ||
f67b45f8 | 15 | /* |
bfdd9ffd JS |
16 | * This is split up from the rest of git so that we can do |
17 | * something different on Windows. | |
f67b45f8 LT |
18 | */ |
19 | ||
ac0ba18d | 20 | static const char *pager_argv[] = { NULL, NULL }; |
ea27a18c JK |
21 | static struct child_process pager_process; |
22 | ||
bfdd9ffd JS |
23 | static void wait_for_pager(void) |
24 | { | |
25 | fflush(stdout); | |
26 | fflush(stderr); | |
27 | /* signal EOF to pager */ | |
28 | close(1); | |
29 | close(2); | |
30 | finish_command(&pager_process); | |
31 | } | |
f67b45f8 | 32 | |
a3da8821 JK |
33 | static void wait_for_pager_signal(int signo) |
34 | { | |
35 | wait_for_pager(); | |
36 | sigchain_pop(signo); | |
37 | raise(signo); | |
38 | } | |
39 | ||
64778d24 | 40 | const char *git_pager(int stdout_is_tty) |
f67b45f8 | 41 | { |
63618245 | 42 | const char *pager; |
f67b45f8 | 43 | |
64778d24 | 44 | if (!stdout_is_tty) |
63618245 JN |
45 | return NULL; |
46 | ||
47 | pager = getenv("GIT_PAGER"); | |
cad3a205 JH |
48 | if (!pager) { |
49 | if (!pager_program) | |
ef90d6d4 | 50 | git_config(git_default_config, NULL); |
54adf370 | 51 | pager = pager_program; |
cad3a205 | 52 | } |
c27d205a ML |
53 | if (!pager) |
54 | pager = getenv("PAGER"); | |
402461aa | 55 | if (!pager) |
a3d023d0 | 56 | pager = DEFAULT_PAGER; |
ed016612 | 57 | if (!*pager || !strcmp(pager, "cat")) |
63618245 JN |
58 | pager = NULL; |
59 | ||
60 | return pager; | |
61 | } | |
62 | ||
63 | void setup_pager(void) | |
64 | { | |
64778d24 | 65 | const char *pager = git_pager(isatty(1)); |
63618245 | 66 | |
c0459ca4 | 67 | if (!pager) |
402461aa JS |
68 | return; |
69 | ||
ad6c3739 ZJS |
70 | /* |
71 | * force computing the width of the terminal before we redirect | |
72 | * the standard output to the pager. | |
73 | */ | |
74 | (void) term_columns(); | |
75 | ||
2e6c012e | 76 | setenv("GIT_PAGER_IN_USE", "true", 1); |
85fb65ed | 77 | |
bfdd9ffd | 78 | /* spawn the pager */ |
ac0ba18d JK |
79 | pager_argv[0] = pager; |
80 | pager_process.use_shell = 1; | |
ea27a18c JK |
81 | pager_process.argv = pager_argv; |
82 | pager_process.in = -1; | |
e54c1f2d JN |
83 | if (!getenv("LESS") || !getenv("LV")) { |
84 | static const char *env[3]; | |
85 | int i = 0; | |
86 | ||
87 | if (!getenv("LESS")) | |
b3275838 | 88 | env[i++] = "LESS=FRX"; |
e54c1f2d JN |
89 | if (!getenv("LV")) |
90 | env[i++] = "LV=-c"; | |
91 | env[i] = NULL; | |
25fc1786 JS |
92 | pager_process.env = env; |
93 | } | |
bfdd9ffd JS |
94 | if (start_command(&pager_process)) |
95 | return; | |
96 | ||
97 | /* original process continues, but writes to the pipe */ | |
98 | dup2(pager_process.in, 1); | |
a8335024 JH |
99 | if (isatty(2)) |
100 | dup2(pager_process.in, 2); | |
bfdd9ffd JS |
101 | close(pager_process.in); |
102 | ||
103 | /* this makes sure that the parent terminates after the pager */ | |
a3da8821 | 104 | sigchain_push_common(wait_for_pager_signal); |
bfdd9ffd | 105 | atexit(wait_for_pager); |
f67b45f8 | 106 | } |
6e9af863 JK |
107 | |
108 | int pager_in_use(void) | |
109 | { | |
110 | const char *env; | |
6e9af863 JK |
111 | env = getenv("GIT_PAGER_IN_USE"); |
112 | return env ? git_config_bool("GIT_PAGER_IN_USE", env) : 0; | |
113 | } | |
ad6c3739 ZJS |
114 | |
115 | /* | |
116 | * Return cached value (if set) or $COLUMNS environment variable (if | |
117 | * set and positive) or ioctl(1, TIOCGWINSZ).ws_col (if positive), | |
118 | * and default to 80 if all else fails. | |
119 | */ | |
120 | int term_columns(void) | |
121 | { | |
122 | static int term_columns_at_startup; | |
123 | ||
124 | char *col_string; | |
125 | int n_cols; | |
126 | ||
127 | if (term_columns_at_startup) | |
128 | return term_columns_at_startup; | |
129 | ||
130 | term_columns_at_startup = 80; | |
131 | ||
132 | col_string = getenv("COLUMNS"); | |
133 | if (col_string && (n_cols = atoi(col_string)) > 0) | |
134 | term_columns_at_startup = n_cols; | |
135 | #ifdef TIOCGWINSZ | |
136 | else { | |
137 | struct winsize ws; | |
138 | if (!ioctl(1, TIOCGWINSZ, &ws) && ws.ws_col) | |
139 | term_columns_at_startup = ws.ws_col; | |
140 | } | |
141 | #endif | |
142 | ||
143 | return term_columns_at_startup; | |
144 | } | |
4d9e079e | 145 | |
ec7ff5ba ZJS |
146 | /* |
147 | * How many columns do we need to show this number in decimal? | |
148 | */ | |
149 | int decimal_width(int number) | |
150 | { | |
151 | int i, width; | |
152 | ||
153 | for (width = 1, i = 10; i <= number; width++) | |
154 | i *= 10; | |
155 | return width; | |
156 | } | |
4914c962 NTND |
157 | |
158 | static int pager_command_config(const char *var, const char *value, void *data) | |
159 | { | |
160 | struct pager_config *c = data; | |
59556548 | 161 | if (starts_with(var, "pager.") && !strcmp(var + 6, c->cmd)) { |
4914c962 NTND |
162 | int b = git_config_maybe_bool(var, value); |
163 | if (b >= 0) | |
164 | c->want = b; | |
165 | else { | |
166 | c->want = 1; | |
167 | c->value = xstrdup(value); | |
168 | } | |
169 | } | |
170 | return 0; | |
171 | } | |
172 | ||
173 | /* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */ | |
174 | int check_pager_config(const char *cmd) | |
175 | { | |
176 | struct pager_config c; | |
177 | c.cmd = cmd; | |
178 | c.want = -1; | |
179 | c.value = NULL; | |
180 | git_config(pager_command_config, &c); | |
181 | if (c.value) | |
182 | pager_program = c.value; | |
183 | return c.want; | |
184 | } |