Skip to content

Commit 297872f

Browse files
committed
Merge branch 'ma/pager-per-subcommand-action'
The "tag.pager" configuration variable was useless for those who actually create tag objects, as it interfered with the use of an editor. A new mechanism has been introduced for commands to enable pager depending on what operation is being carried out to fix this, and then "git tag -l" is made to run pager by default. * ma/pager-per-subcommand-action: git.c: ignore pager.* when launching builtin as dashed external tag: change default of `pager.tag` to "on" tag: respect `pager.tag` in list-mode only t7006: add tests for how git tag paginates git.c: provide setup_auto_pager() git.c: let builtins opt for handling `pager.foo` themselves builtin.h: take over documentation from api-builtin.txt
2 parents 8fbaf0b + 595d59e commit 297872f

File tree

6 files changed

+201
-76
lines changed

6 files changed

+201
-76
lines changed

Documentation/git-tag.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,9 @@ it in the repository configuration as follows:
205205
signingKey = <gpg-keyid>
206206
-------------------------------------
207207

208+
`pager.tag` is only respected when listing tags, i.e., when `-l` is
209+
used or implied. The default is to use a pager.
210+
See linkgit:git-config[1].
208211

209212
DISCUSSION
210213
----------

Documentation/technical/api-builtin.txt

Lines changed: 0 additions & 73 deletions
This file was deleted.

builtin.h

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,94 @@
66
#include "cache.h"
77
#include "commit.h"
88

9+
/*
10+
* builtin API
11+
* ===========
12+
*
13+
* Adding a new built-in
14+
* ---------------------
15+
*
16+
* There are 4 things to do to add a built-in command implementation to
17+
* Git:
18+
*
19+
* . Define the implementation of the built-in command `foo` with
20+
* signature:
21+
*
22+
* int cmd_foo(int argc, const char **argv, const char *prefix);
23+
*
24+
* . Add the external declaration for the function to `builtin.h`.
25+
*
26+
* . Add the command to the `commands[]` table defined in `git.c`.
27+
* The entry should look like:
28+
*
29+
* { "foo", cmd_foo, <options> },
30+
*
31+
* where options is the bitwise-or of:
32+
*
33+
* `RUN_SETUP`:
34+
* If there is not a Git directory to work on, abort. If there
35+
* is a work tree, chdir to the top of it if the command was
36+
* invoked in a subdirectory. If there is no work tree, no
37+
* chdir() is done.
38+
*
39+
* `RUN_SETUP_GENTLY`:
40+
* If there is a Git directory, chdir as per RUN_SETUP, otherwise,
41+
* don't chdir anywhere.
42+
*
43+
* `USE_PAGER`:
44+
*
45+
* If the standard output is connected to a tty, spawn a pager and
46+
* feed our output to it.
47+
*
48+
* `NEED_WORK_TREE`:
49+
*
50+
* Make sure there is a work tree, i.e. the command cannot act
51+
* on bare repositories.
52+
* This only makes sense when `RUN_SETUP` is also set.
53+
*
54+
* `SUPPORT_SUPER_PREFIX`:
55+
*
56+
* The built-in supports `--super-prefix`.
57+
*
58+
* `DELAY_PAGER_CONFIG`:
59+
*
60+
* If RUN_SETUP or RUN_SETUP_GENTLY is set, git.c normally handles
61+
* the `pager.<cmd>`-configuration. If this flag is used, git.c
62+
* will skip that step, instead allowing the built-in to make a
63+
* more informed decision, e.g., by ignoring `pager.<cmd>` for
64+
* certain subcommands.
65+
*
66+
* . Add `builtin/foo.o` to `BUILTIN_OBJS` in `Makefile`.
67+
*
68+
* Additionally, if `foo` is a new command, there are 4 more things to do:
69+
*
70+
* . Add tests to `t/` directory.
71+
*
72+
* . Write documentation in `Documentation/git-foo.txt`.
73+
*
74+
* . Add an entry for `git-foo` to `command-list.txt`.
75+
*
76+
* . Add an entry for `/git-foo` to `.gitignore`.
77+
*
78+
*
79+
* How a built-in is called
80+
* ------------------------
81+
*
82+
* The implementation `cmd_foo()` takes three parameters, `argc`, `argv,
83+
* and `prefix`. The first two are similar to what `main()` of a
84+
* standalone command would be called with.
85+
*
86+
* When `RUN_SETUP` is specified in the `commands[]` table, and when you
87+
* were started from a subdirectory of the work tree, `cmd_foo()` is called
88+
* after chdir(2) to the top of the work tree, and `prefix` gets the path
89+
* to the subdirectory the command started from. This allows you to
90+
* convert a user-supplied pathname (typically relative to that directory)
91+
* to a pathname relative to the top of the work tree.
92+
*
93+
* The return value from `cmd_foo()` becomes the exit status of the
94+
* command.
95+
*/
96+
997
#define DEFAULT_MERGE_LOG_LEN 20
1098

1199
extern const char git_usage_string[];
@@ -25,6 +113,18 @@ struct fmt_merge_msg_opts {
25113
extern int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
26114
struct fmt_merge_msg_opts *);
27115

116+
/**
117+
* If a built-in has DELAY_PAGER_CONFIG set, the built-in should call this early
118+
* when it wishes to respect the `pager.foo`-config. The `cmd` is the name of
119+
* the built-in, e.g., "foo". If a paging-choice has already been setup, this
120+
* does nothing. The default in `def` should be 0 for "pager off", 1 for "pager
121+
* on" or -1 for "punt".
122+
*
123+
* You should most likely use a default of 0 or 1. "Punt" (-1) could be useful
124+
* to be able to fall back to some historical compatibility name.
125+
*/
126+
extern void setup_auto_pager(const char *cmd, int def);
127+
28128
extern int is_builtin(const char *s);
29129

30130
extern int cmd_add(int argc, const char **argv, const char *prefix);

builtin/tag.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,9 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
440440
cmdmode = 'l';
441441
}
442442

443+
if (cmdmode == 'l')
444+
setup_auto_pager("tag", 1);
445+
443446
if ((create_tag_object || force) && (cmdmode != 0))
444447
usage_with_options(git_tag_usage, options);
445448

git.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,16 @@ static void commit_pager_choice(void) {
3333
}
3434
}
3535

36+
void setup_auto_pager(const char *cmd, int def)
37+
{
38+
if (use_pager != -1 || pager_in_use())
39+
return;
40+
use_pager = check_pager_config(cmd);
41+
if (use_pager == -1)
42+
use_pager = def;
43+
commit_pager_choice();
44+
}
45+
3646
static int handle_options(const char ***argv, int *argc, int *envchanged)
3747
{
3848
const char **orig_argv = *argv;
@@ -283,6 +293,7 @@ static int handle_alias(int *argcp, const char ***argv)
283293
*/
284294
#define NEED_WORK_TREE (1<<3)
285295
#define SUPPORT_SUPER_PREFIX (1<<4)
296+
#define DELAY_PAGER_CONFIG (1<<5)
286297

287298
struct cmd_struct {
288299
const char *cmd;
@@ -306,7 +317,8 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
306317
prefix = setup_git_directory_gently(&nongit_ok);
307318
}
308319

309-
if (use_pager == -1 && p->option & (RUN_SETUP | RUN_SETUP_GENTLY))
320+
if (use_pager == -1 && p->option & (RUN_SETUP | RUN_SETUP_GENTLY) &&
321+
!(p->option & DELAY_PAGER_CONFIG))
310322
use_pager = check_pager_config(p->cmd);
311323
if (use_pager == -1 && p->option & USE_PAGER)
312324
use_pager = 1;
@@ -454,7 +466,7 @@ static struct cmd_struct commands[] = {
454466
{ "stripspace", cmd_stripspace },
455467
{ "submodule--helper", cmd_submodule__helper, RUN_SETUP | SUPPORT_SUPER_PREFIX},
456468
{ "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
457-
{ "tag", cmd_tag, RUN_SETUP },
469+
{ "tag", cmd_tag, RUN_SETUP | DELAY_PAGER_CONFIG },
458470
{ "unpack-file", cmd_unpack_file, RUN_SETUP },
459471
{ "unpack-objects", cmd_unpack_objects, RUN_SETUP },
460472
{ "update-index", cmd_update_index, RUN_SETUP },
@@ -547,7 +559,7 @@ static void execv_dashed_external(const char **argv)
547559
if (get_super_prefix())
548560
die("%s doesn't support --super-prefix", argv[0]);
549561

550-
if (use_pager == -1)
562+
if (use_pager == -1 && !is_builtin(argv[0]))
551563
use_pager = check_pager_config(argv[0]);
552564
commit_pager_choice();
553565

t/t7006-pager.sh

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,86 @@ test_expect_success TTY 'configuration can enable pager (from subdir)' '
134134
}
135135
'
136136

137+
test_expect_success TTY 'git tag -l defaults to paging' '
138+
rm -f paginated.out &&
139+
test_terminal git tag -l &&
140+
test -e paginated.out
141+
'
142+
143+
test_expect_success TTY 'git tag -l respects pager.tag' '
144+
rm -f paginated.out &&
145+
test_terminal git -c pager.tag=false tag -l &&
146+
! test -e paginated.out
147+
'
148+
149+
test_expect_success TTY 'git tag -l respects --no-pager' '
150+
rm -f paginated.out &&
151+
test_terminal git -c pager.tag --no-pager tag -l &&
152+
! test -e paginated.out
153+
'
154+
155+
test_expect_success TTY 'git tag with no args defaults to paging' '
156+
# no args implies -l so this should page like -l
157+
rm -f paginated.out &&
158+
test_terminal git tag &&
159+
test -e paginated.out
160+
'
161+
162+
test_expect_success TTY 'git tag with no args respects pager.tag' '
163+
# no args implies -l so this should page like -l
164+
rm -f paginated.out &&
165+
test_terminal git -c pager.tag=false tag &&
166+
! test -e paginated.out
167+
'
168+
169+
test_expect_success TTY 'git tag --contains defaults to paging' '
170+
# --contains implies -l so this should page like -l
171+
rm -f paginated.out &&
172+
test_terminal git tag --contains &&
173+
test -e paginated.out
174+
'
175+
176+
test_expect_success TTY 'git tag --contains respects pager.tag' '
177+
# --contains implies -l so this should page like -l
178+
rm -f paginated.out &&
179+
test_terminal git -c pager.tag=false tag --contains &&
180+
! test -e paginated.out
181+
'
182+
183+
test_expect_success TTY 'git tag -a defaults to not paging' '
184+
test_when_finished "git tag -d newtag" &&
185+
rm -f paginated.out &&
186+
test_terminal git tag -am message newtag &&
187+
! test -e paginated.out
188+
'
189+
190+
test_expect_success TTY 'git tag -a ignores pager.tag' '
191+
test_when_finished "git tag -d newtag" &&
192+
rm -f paginated.out &&
193+
test_terminal git -c pager.tag tag -am message newtag &&
194+
! test -e paginated.out
195+
'
196+
197+
test_expect_success TTY 'git tag -a respects --paginate' '
198+
test_when_finished "git tag -d newtag" &&
199+
rm -f paginated.out &&
200+
test_terminal git --paginate tag -am message newtag &&
201+
test -e paginated.out
202+
'
203+
204+
test_expect_success TTY 'git tag as alias ignores pager.tag with -a' '
205+
test_when_finished "git tag -d newtag" &&
206+
rm -f paginated.out &&
207+
test_terminal git -c pager.tag -c alias.t=tag t -am message newtag &&
208+
! test -e paginated.out
209+
'
210+
211+
test_expect_success TTY 'git tag as alias respects pager.tag with -l' '
212+
rm -f paginated.out &&
213+
test_terminal git -c pager.tag=false -c alias.t=tag t -l &&
214+
! test -e paginated.out
215+
'
216+
137217
# A colored commit log will begin with an appropriate ANSI escape
138218
# for the first color; the text "commit" comes later.
139219
colorful() {

0 commit comments

Comments
 (0)