| Linus Torvalds | f67b45f | 2006-02-28 19:26:21 | [diff] [blame] | 1 | #include "cache.h" |
| Jeff King | ea27a18 | 2008-07-22 07:14:12 | [diff] [blame] | 2 | #include "run-command.h" |
| Jeff King | a3da882 | 2009-01-22 06:03:28 | [diff] [blame] | 3 | #include "sigchain.h" |
| Linus Torvalds | f67b45f | 2006-02-28 19:26:21 | [diff] [blame] | 4 | |
| Junio C Hamano | a3d023d | 2009-10-31 01:45:34 | [diff] [blame] | 5 | #ifndef DEFAULT_PAGER |
| 6 | #define DEFAULT_PAGER "less" |
| 7 | #endif |
| 8 | |
| Nguyį»
n ThĆ”i Ngį»c Duy | 4914c96 | 2012-10-26 15:53:52 | [diff] [blame] | 9 | struct pager_config { |
| 10 | const char *cmd; |
| 11 | int want; |
| 12 | char *value; |
| 13 | }; |
| 14 | |
| Linus Torvalds | f67b45f | 2006-02-28 19:26:21 | [diff] [blame] | 15 | /* |
| Johannes Sixt | bfdd9ff | 2007-12-08 20:28:41 | [diff] [blame] | 16 | * This is split up from the rest of git so that we can do |
| 17 | * something different on Windows. |
| Linus Torvalds | f67b45f | 2006-02-28 19:26:21 | [diff] [blame] | 18 | */ |
| 19 | |
| Jeff King | ac0ba18 | 2009-12-30 10:53:57 | [diff] [blame] | 20 | static const char *pager_argv[] = { NULL, NULL }; |
| Jeff King | ea27a18 | 2008-07-22 07:14:12 | [diff] [blame] | 21 | static struct child_process pager_process; |
| 22 | |
| Johannes Sixt | bfdd9ff | 2007-12-08 20:28:41 | [diff] [blame] | 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 | } |
| Linus Torvalds | f67b45f | 2006-02-28 19:26:21 | [diff] [blame] | 32 | |
| Jeff King | a3da882 | 2009-01-22 06:03:28 | [diff] [blame] | 33 | static void wait_for_pager_signal(int signo) |
| 34 | { |
| 35 | wait_for_pager(); |
| 36 | sigchain_pop(signo); |
| 37 | raise(signo); |
| 38 | } |
| 39 | |
| Jonathan Nieder | 64778d2 | 2010-02-14 11:59:59 | [diff] [blame] | 40 | const char *git_pager(int stdout_is_tty) |
| Linus Torvalds | f67b45f | 2006-02-28 19:26:21 | [diff] [blame] | 41 | { |
| Jonathan Nieder | 6361824 | 2009-10-31 01:41:27 | [diff] [blame] | 42 | const char *pager; |
| Linus Torvalds | f67b45f | 2006-02-28 19:26:21 | [diff] [blame] | 43 | |
| Jonathan Nieder | 64778d2 | 2010-02-14 11:59:59 | [diff] [blame] | 44 | if (!stdout_is_tty) |
| Jonathan Nieder | 6361824 | 2009-10-31 01:41:27 | [diff] [blame] | 45 | return NULL; |
| 46 | |
| 47 | pager = getenv("GIT_PAGER"); |
| Junio C Hamano | cad3a20 | 2007-08-07 04:08:43 | [diff] [blame] | 48 | if (!pager) { |
| 49 | if (!pager_program) |
| Johannes Schindelin | ef90d6d | 2008-05-14 17:46:53 | [diff] [blame] | 50 | git_config(git_default_config, NULL); |
| Brian Gernhardt | 54adf37 | 2007-07-03 18:18:11 | [diff] [blame] | 51 | pager = pager_program; |
| Junio C Hamano | cad3a20 | 2007-08-07 04:08:43 | [diff] [blame] | 52 | } |
| Brian Gernhardt | 54adf37 | 2007-07-03 18:18:11 | [diff] [blame] | 53 | if (!pager) |
| Matthias Lederhofer | c27d205 | 2006-07-31 13:27:00 | [diff] [blame] | 54 | pager = getenv("PAGER"); |
| 55 | if (!pager) |
| Junio C Hamano | a3d023d | 2009-10-31 01:45:34 | [diff] [blame] | 56 | pager = DEFAULT_PAGER; |
| Jeff King | ed01661 | 2013-09-03 07:41:50 | [diff] [blame] | 57 | if (!*pager || !strcmp(pager, "cat")) |
| Jonathan Nieder | 6361824 | 2009-10-31 01:41:27 | [diff] [blame] | 58 | pager = NULL; |
| 59 | |
| 60 | return pager; |
| 61 | } |
| 62 | |
| 63 | void setup_pager(void) |
| 64 | { |
| Jonathan Nieder | 64778d2 | 2010-02-14 11:59:59 | [diff] [blame] | 65 | const char *pager = git_pager(isatty(1)); |
| Jonathan Nieder | 6361824 | 2009-10-31 01:41:27 | [diff] [blame] | 66 | |
| Nguyį»
n ThĆ”i Ngį»c Duy | 88e8f90 | 2012-04-13 10:54:34 | [diff] [blame] | 67 | if (!pager || pager_in_use()) |
| Johannes Schindelin | 402461a | 2006-04-16 02:44:25 | [diff] [blame] | 68 | return; |
| 69 | |
| Zbigniew JÄdrzejewski-Szmek | ad6c373 | 2012-02-12 14:12:32 | [diff] [blame] | 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 | |
| Jeff King | 2e6c012 | 2011-08-18 05:02:29 | [diff] [blame] | 76 | setenv("GIT_PAGER_IN_USE", "true", 1); |
| Junio C Hamano | 85fb65e | 2006-06-06 23:58:40 | [diff] [blame] | 77 | |
| Johannes Sixt | bfdd9ff | 2007-12-08 20:28:41 | [diff] [blame] | 78 | /* spawn the pager */ |
| Jeff King | ac0ba18 | 2009-12-30 10:53:57 | [diff] [blame] | 79 | pager_argv[0] = pager; |
| 80 | pager_process.use_shell = 1; |
| Jeff King | ea27a18 | 2008-07-22 07:14:12 | [diff] [blame] | 81 | pager_process.argv = pager_argv; |
| 82 | pager_process.in = -1; |
| Jonathan Nieder | e54c1f2 | 2014-01-07 02:14:05 | [diff] [blame] | 83 | if (!getenv("LESS") || !getenv("LV")) { |
| 84 | static const char *env[3]; |
| 85 | int i = 0; |
| 86 | |
| 87 | if (!getenv("LESS")) |
| 88 | env[i++] = "LESS=FRSX"; |
| 89 | if (!getenv("LV")) |
| 90 | env[i++] = "LV=-c"; |
| 91 | env[i] = NULL; |
| Johannes Sixt | 25fc178 | 2009-09-11 17:45:07 | [diff] [blame] | 92 | pager_process.env = env; |
| 93 | } |
| Johannes Sixt | bfdd9ff | 2007-12-08 20:28:41 | [diff] [blame] | 94 | if (start_command(&pager_process)) |
| 95 | return; |
| 96 | |
| 97 | /* original process continues, but writes to the pipe */ |
| 98 | dup2(pager_process.in, 1); |
| Junio C Hamano | a833502 | 2008-12-15 08:33:34 | [diff] [blame] | 99 | if (isatty(2)) |
| 100 | dup2(pager_process.in, 2); |
| Johannes Sixt | bfdd9ff | 2007-12-08 20:28:41 | [diff] [blame] | 101 | close(pager_process.in); |
| 102 | |
| 103 | /* this makes sure that the parent terminates after the pager */ |
| Jeff King | a3da882 | 2009-01-22 06:03:28 | [diff] [blame] | 104 | sigchain_push_common(wait_for_pager_signal); |
| Johannes Sixt | bfdd9ff | 2007-12-08 20:28:41 | [diff] [blame] | 105 | atexit(wait_for_pager); |
| Linus Torvalds | f67b45f | 2006-02-28 19:26:21 | [diff] [blame] | 106 | } |
| Jeff King | 6e9af86 | 2007-12-11 06:27:33 | [diff] [blame] | 107 | |
| 108 | int pager_in_use(void) |
| 109 | { |
| 110 | const char *env; |
| Jeff King | 6e9af86 | 2007-12-11 06:27:33 | [diff] [blame] | 111 | env = getenv("GIT_PAGER_IN_USE"); |
| 112 | return env ? git_config_bool("GIT_PAGER_IN_USE", env) : 0; |
| 113 | } |
| Zbigniew JÄdrzejewski-Szmek | ad6c373 | 2012-02-12 14:12:32 | [diff] [blame] | 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 | } |
| Junio C Hamano | 4d9e079 | 2012-02-20 08:15:11 | [diff] [blame] | 145 | |
| 146 | /* |
| Zbigniew JÄdrzejewski-Szmek | ec7ff5b | 2012-02-12 14:16:20 | [diff] [blame] | 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 | } |
| Nguyį»
n ThĆ”i Ngį»c Duy | 4914c96 | 2012-10-26 15:53:52 | [diff] [blame] | 157 | |
| 158 | static int pager_command_config(const char *var, const char *value, void *data) |
| 159 | { |
| 160 | struct pager_config *c = data; |
| Christian Couder | 5955654 | 2013-11-30 20:55:40 | [diff] [blame] | 161 | if (starts_with(var, "pager.") && !strcmp(var + 6, c->cmd)) { |
| Nguyį»
n ThĆ”i Ngį»c Duy | 4914c96 | 2012-10-26 15:53:52 | [diff] [blame] | 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 | } |