summaryrefslogtreecommitdiff
path: root/pager.c
diff options
context:
space:
mode:
Diffstat (limited to 'pager.c')
-rw-r--r--pager.c158
1 files changed, 124 insertions, 34 deletions
diff --git a/pager.c b/pager.c
index 27d4c8a17a..ae79643363 100644
--- a/pager.c
+++ b/pager.c
@@ -6,31 +6,74 @@
#define DEFAULT_PAGER "less"
#endif
-/*
- * This is split up from the rest of git so that we can do
- * something different on Windows.
- */
-
-static const char *pager_argv[] = { NULL, NULL };
static struct child_process pager_process = CHILD_PROCESS_INIT;
+static const char *pager_program;
-static void wait_for_pager(void)
+static void wait_for_pager(int in_signal)
{
- fflush(stdout);
- fflush(stderr);
+ if (!in_signal) {
+ fflush(stdout);
+ fflush(stderr);
+ }
/* signal EOF to pager */
close(1);
close(2);
- finish_command(&pager_process);
+ if (in_signal)
+ finish_command_in_signal(&pager_process);
+ else
+ finish_command(&pager_process);
+}
+
+static void wait_for_pager_atexit(void)
+{
+ wait_for_pager(0);
}
static void wait_for_pager_signal(int signo)
{
- wait_for_pager();
+ wait_for_pager(1);
sigchain_pop(signo);
raise(signo);
}
+static int core_pager_config(const char *var, const char *value, void *data)
+{
+ if (!strcmp(var, "core.pager"))
+ return git_config_string(&pager_program, var, value);
+ return 0;
+}
+
+static void read_early_config(config_fn_t cb, void *data)
+{
+ git_config_with_options(cb, data, NULL, 1);
+
+ /*
+ * Note that this is a really dirty hack that does the wrong thing in
+ * many cases. The crux of the problem is that we cannot run
+ * setup_git_directory() early on in git's setup, so we have no idea if
+ * we are in a repository or not, and therefore are not sure whether
+ * and how to read repository-local config.
+ *
+ * So if we _aren't_ in a repository (or we are but we would reject its
+ * core.repositoryformatversion), we'll read whatever is in .git/config
+ * blindly. Similarly, if we _are_ in a repository, but not at the
+ * root, we'll fail to find .git/config (because it's really
+ * ../.git/config, etc). See t7006 for a complete set of failures.
+ *
+ * However, we have historically provided this hack because it does
+ * work some of the time (namely when you are at the top-level of a
+ * valid repository), and would rarely make things worse (i.e., you do
+ * not generally have a .git/config file sitting around).
+ */
+ if (!startup_info->have_repository) {
+ struct git_config_source repo_config;
+
+ memset(&repo_config, 0, sizeof(repo_config));
+ repo_config.file = ".git/config";
+ git_config_with_options(cb, data, &repo_config, 1);
+ }
+}
+
const char *git_pager(int stdout_is_tty)
{
const char *pager;
@@ -41,7 +84,7 @@ const char *git_pager(int stdout_is_tty)
pager = getenv("GIT_PAGER");
if (!pager) {
if (!pager_program)
- git_config(git_default_config, NULL);
+ read_early_config(core_pager_config, NULL);
pager = pager_program;
}
if (!pager)
@@ -54,6 +97,40 @@ const char *git_pager(int stdout_is_tty)
return pager;
}
+static void setup_pager_env(struct argv_array *env)
+{
+ const char **argv;
+ int i;
+ char *pager_env = xstrdup(PAGER_ENV);
+ int n = split_cmdline(pager_env, &argv);
+
+ if (n < 0)
+ die("malformed build-time PAGER_ENV: %s",
+ split_cmdline_strerror(n));
+
+ for (i = 0; i < n; i++) {
+ char *cp = strchr(argv[i], '=');
+
+ if (!cp)
+ die("malformed build-time PAGER_ENV");
+
+ *cp = '\0';
+ if (!getenv(argv[i])) {
+ *cp = '=';
+ argv_array_push(env, argv[i]);
+ }
+ }
+ free(pager_env);
+ free(argv);
+}
+
+void prepare_pager_args(struct child_process *pager_process, const char *pager)
+{
+ argv_array_push(&pager_process->args, pager);
+ pager_process->use_shell = 1;
+ setup_pager_env(&pager_process->env_array);
+}
+
void setup_pager(void)
{
const char *pager = git_pager(isatty(1));
@@ -70,14 +147,8 @@ void setup_pager(void)
setenv("GIT_PAGER_IN_USE", "true", 1);
/* spawn the pager */
- pager_argv[0] = pager;
- pager_process.use_shell = 1;
- pager_process.argv = pager_argv;
+ prepare_pager_args(&pager_process, pager);
pager_process.in = -1;
- if (!getenv("LESS"))
- argv_array_push(&pager_process.env_array, "LESS=FRX");
- if (!getenv("LV"))
- argv_array_push(&pager_process.env_array, "LV=-c");
argv_array_push(&pager_process.env_array, "GIT_PAGER_IN_USE");
if (start_command(&pager_process))
return;
@@ -90,7 +161,7 @@ void setup_pager(void)
/* this makes sure that the parent terminates after the pager */
sigchain_push_common(wait_for_pager_signal);
- atexit(wait_for_pager);
+ atexit(wait_for_pager_atexit);
}
int pager_in_use(void)
@@ -143,23 +214,42 @@ int decimal_width(uintmax_t number)
return width;
}
-/* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */
-int check_pager_config(const char *cmd)
+struct pager_command_config_data {
+ const char *cmd;
+ int want;
+ char *value;
+};
+
+static int pager_command_config(const char *var, const char *value, void *vdata)
{
- int want = -1;
- struct strbuf key = STRBUF_INIT;
- const char *value = NULL;
- strbuf_addf(&key, "pager.%s", cmd);
- if (git_config_key_is_valid(key.buf) &&
- !git_config_get_value(key.buf, &value)) {
- int b = git_config_maybe_bool(key.buf, value);
+ struct pager_command_config_data *data = vdata;
+ const char *cmd;
+
+ if (skip_prefix(var, "pager.", &cmd) && !strcmp(cmd, data->cmd)) {
+ int b = git_config_maybe_bool(var, value);
if (b >= 0)
- want = b;
+ data->want = b;
else {
- want = 1;
- pager_program = xstrdup(value);
+ data->want = 1;
+ data->value = xstrdup(value);
}
}
- strbuf_release(&key);
- return want;
+
+ return 0;
+}
+
+/* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */
+int check_pager_config(const char *cmd)
+{
+ struct pager_command_config_data data;
+
+ data.cmd = cmd;
+ data.want = -1;
+ data.value = NULL;
+
+ read_early_config(pager_command_config, &data);
+
+ if (data.value)
+ pager_program = data.value;
+ return data.want;
}