Merge branch 'nd/columns'
A couple of commands learn --column option to produce columnar output. By Nguyễn Thái Ngọc Duy (9) and Zbigniew Jędrzejewski-Szmek (1) * nd/columns: tag: add --column column: support piping stdout to external git-column process status: add --column branch: add --column help: reuse print_columns() for help -a column: add dense layout support t9002: work around shells that are unable to set COLUMNS to 1 column: add columnar layout Stop starting pager recursively Add column layout skeleton and git-columnmaint
commit
f4ed0af6e2
|
@ -26,6 +26,7 @@
|
||||||
/git-cherry-pick
|
/git-cherry-pick
|
||||||
/git-clean
|
/git-clean
|
||||||
/git-clone
|
/git-clone
|
||||||
|
/git-column
|
||||||
/git-commit
|
/git-commit
|
||||||
/git-commit-tree
|
/git-commit-tree
|
||||||
/git-config
|
/git-config
|
||||||
|
|
|
@ -856,6 +856,44 @@ color.ui::
|
||||||
`never` if you prefer git commands not to use color unless enabled
|
`never` if you prefer git commands not to use color unless enabled
|
||||||
explicitly with some other configuration or the `--color` option.
|
explicitly with some other configuration or the `--color` option.
|
||||||
|
|
||||||
|
column.ui::
|
||||||
|
Specify whether supported commands should output in columns.
|
||||||
|
This variable consists of a list of tokens separated by spaces
|
||||||
|
or commas:
|
||||||
|
+
|
||||||
|
--
|
||||||
|
`always`;;
|
||||||
|
always show in columns
|
||||||
|
`never`;;
|
||||||
|
never show in columns
|
||||||
|
`auto`;;
|
||||||
|
show in columns if the output is to the terminal
|
||||||
|
`column`;;
|
||||||
|
fill columns before rows (default)
|
||||||
|
`row`;;
|
||||||
|
fill rows before columns
|
||||||
|
`plain`;;
|
||||||
|
show in one column
|
||||||
|
`dense`;;
|
||||||
|
make unequal size columns to utilize more space
|
||||||
|
`nodense`;;
|
||||||
|
make equal size columns
|
||||||
|
--
|
||||||
|
+
|
||||||
|
This option defaults to 'never'.
|
||||||
|
|
||||||
|
column.branch::
|
||||||
|
Specify whether to output branch listing in `git branch` in columns.
|
||||||
|
See `column.ui` for details.
|
||||||
|
|
||||||
|
column.status::
|
||||||
|
Specify whether to output untracked files in `git status` in columns.
|
||||||
|
See `column.ui` for details.
|
||||||
|
|
||||||
|
column.tag::
|
||||||
|
Specify whether to output tag listing in `git tag` in columns.
|
||||||
|
See `column.ui` for details.
|
||||||
|
|
||||||
commit.status::
|
commit.status::
|
||||||
A boolean to enable/disable inclusion of status information in the
|
A boolean to enable/disable inclusion of status information in the
|
||||||
commit message template when using an editor to prepare the commit
|
commit message template when using an editor to prepare the commit
|
||||||
|
|
|
@ -10,6 +10,7 @@ SYNOPSIS
|
||||||
[verse]
|
[verse]
|
||||||
'git branch' [--color[=<when>] | --no-color] [-r | -a]
|
'git branch' [--color[=<when>] | --no-color] [-r | -a]
|
||||||
[--list] [-v [--abbrev=<length> | --no-abbrev]]
|
[--list] [-v [--abbrev=<length> | --no-abbrev]]
|
||||||
|
[--column[=<options>] | --no-column]
|
||||||
[(--merged | --no-merged | --contains) [<commit>]] [<pattern>...]
|
[(--merged | --no-merged | --contains) [<commit>]] [<pattern>...]
|
||||||
'git branch' [--set-upstream | --track | --no-track] [-l] [-f] <branchname> [<start-point>]
|
'git branch' [--set-upstream | --track | --no-track] [-l] [-f] <branchname> [<start-point>]
|
||||||
'git branch' (-m | -M) [<oldbranch>] <newbranch>
|
'git branch' (-m | -M) [<oldbranch>] <newbranch>
|
||||||
|
@ -107,6 +108,14 @@ OPTIONS
|
||||||
default to color output.
|
default to color output.
|
||||||
Same as `--color=never`.
|
Same as `--color=never`.
|
||||||
|
|
||||||
|
--column[=<options>]::
|
||||||
|
--no-column::
|
||||||
|
Display branch listing in columns. See configuration variable
|
||||||
|
column.branch for option syntax.`--column` and `--no-column`
|
||||||
|
without options are equivalent to 'always' and 'never' respectively.
|
||||||
|
+
|
||||||
|
This option is only applicable in non-verbose mode.
|
||||||
|
|
||||||
-r::
|
-r::
|
||||||
--remotes::
|
--remotes::
|
||||||
List or delete (if used with -d) the remote-tracking branches.
|
List or delete (if used with -d) the remote-tracking branches.
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
git-column(1)
|
||||||
|
=============
|
||||||
|
|
||||||
|
NAME
|
||||||
|
----
|
||||||
|
git-column - Display data in columns
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
--------
|
||||||
|
[verse]
|
||||||
|
'git column' [--command=<name>] [--[raw-]mode=<mode>] [--width=<width>]
|
||||||
|
[--indent=<string>] [--nl=<string>] [--pading=<n>]
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
-----------
|
||||||
|
This command formats its input into multiple columns.
|
||||||
|
|
||||||
|
OPTIONS
|
||||||
|
-------
|
||||||
|
--command=<name>::
|
||||||
|
Look up layout mode using configuration variable column.<name> and
|
||||||
|
column.ui.
|
||||||
|
|
||||||
|
--mode=<mode>::
|
||||||
|
Specify layout mode. See configuration variable column.ui for option
|
||||||
|
syntax.
|
||||||
|
|
||||||
|
--raw-mode=<n>::
|
||||||
|
Same as --mode but take mode encoded as a number. This is mainly used
|
||||||
|
by other commands that have already parsed layout mode.
|
||||||
|
|
||||||
|
--width=<width>::
|
||||||
|
Specify the terminal width. By default 'git column' will detect the
|
||||||
|
terminal width, or fall back to 80 if it is unable to do so.
|
||||||
|
|
||||||
|
--indent=<string>::
|
||||||
|
String to be printed at the beginning of each line.
|
||||||
|
|
||||||
|
--nl=<N>::
|
||||||
|
String to be printed at the end of each line,
|
||||||
|
including newline character.
|
||||||
|
|
||||||
|
--padding=<N>::
|
||||||
|
The number of spaces between columns. One space by default.
|
||||||
|
|
||||||
|
|
||||||
|
Author
|
||||||
|
------
|
||||||
|
Written by Nguyen Thai Ngoc Duy <pclouds@gmail.com>
|
||||||
|
|
||||||
|
GIT
|
||||||
|
---
|
||||||
|
Part of the linkgit:git[1] suite
|
|
@ -77,6 +77,13 @@ configuration variable documented in linkgit:git-config[1].
|
||||||
Terminate entries with NUL, instead of LF. This implies
|
Terminate entries with NUL, instead of LF. This implies
|
||||||
the `--porcelain` output format if no other format is given.
|
the `--porcelain` output format if no other format is given.
|
||||||
|
|
||||||
|
--column[=<options>]::
|
||||||
|
--no-column::
|
||||||
|
Display untracked files in columns. See configuration variable
|
||||||
|
column.status for option syntax.`--column` and `--no-column`
|
||||||
|
without options are equivalent to 'always' and 'never'
|
||||||
|
respectively.
|
||||||
|
|
||||||
|
|
||||||
OUTPUT
|
OUTPUT
|
||||||
------
|
------
|
||||||
|
|
|
@ -13,6 +13,7 @@ SYNOPSIS
|
||||||
<tagname> [<commit> | <object>]
|
<tagname> [<commit> | <object>]
|
||||||
'git tag' -d <tagname>...
|
'git tag' -d <tagname>...
|
||||||
'git tag' [-n[<num>]] -l [--contains <commit>] [--points-at <object>]
|
'git tag' [-n[<num>]] -l [--contains <commit>] [--points-at <object>]
|
||||||
|
[--column[=<options>] | --no-column] [<pattern>...]
|
||||||
[<pattern>...]
|
[<pattern>...]
|
||||||
'git tag' -v <tagname>...
|
'git tag' -v <tagname>...
|
||||||
|
|
||||||
|
@ -84,6 +85,14 @@ OPTIONS
|
||||||
using fnmatch(3)). Multiple patterns may be given; if any of
|
using fnmatch(3)). Multiple patterns may be given; if any of
|
||||||
them matches, the tag is shown.
|
them matches, the tag is shown.
|
||||||
|
|
||||||
|
--column[=<options>]::
|
||||||
|
--no-column::
|
||||||
|
Display tag listing in columns. See configuration variable
|
||||||
|
column.tag for option syntax.`--column` and `--no-column`
|
||||||
|
without options are equivalent to 'always' and 'never' respectively.
|
||||||
|
+
|
||||||
|
This option is only applicable when listing tags without annotation lines.
|
||||||
|
|
||||||
--contains <commit>::
|
--contains <commit>::
|
||||||
Only list tags which contain the specified commit.
|
Only list tags which contain the specified commit.
|
||||||
|
|
||||||
|
|
3
Makefile
3
Makefile
|
@ -688,6 +688,7 @@ LIB_OBJS += bulk-checkin.o
|
||||||
LIB_OBJS += bundle.o
|
LIB_OBJS += bundle.o
|
||||||
LIB_OBJS += cache-tree.o
|
LIB_OBJS += cache-tree.o
|
||||||
LIB_OBJS += color.o
|
LIB_OBJS += color.o
|
||||||
|
LIB_OBJS += column.o
|
||||||
LIB_OBJS += combine-diff.o
|
LIB_OBJS += combine-diff.o
|
||||||
LIB_OBJS += commit.o
|
LIB_OBJS += commit.o
|
||||||
LIB_OBJS += compat/obstack.o
|
LIB_OBJS += compat/obstack.o
|
||||||
|
@ -818,6 +819,7 @@ BUILTIN_OBJS += builtin/checkout-index.o
|
||||||
BUILTIN_OBJS += builtin/checkout.o
|
BUILTIN_OBJS += builtin/checkout.o
|
||||||
BUILTIN_OBJS += builtin/clean.o
|
BUILTIN_OBJS += builtin/clean.o
|
||||||
BUILTIN_OBJS += builtin/clone.o
|
BUILTIN_OBJS += builtin/clone.o
|
||||||
|
BUILTIN_OBJS += builtin/column.o
|
||||||
BUILTIN_OBJS += builtin/commit-tree.o
|
BUILTIN_OBJS += builtin/commit-tree.o
|
||||||
BUILTIN_OBJS += builtin/commit.o
|
BUILTIN_OBJS += builtin/commit.o
|
||||||
BUILTIN_OBJS += builtin/config.o
|
BUILTIN_OBJS += builtin/config.o
|
||||||
|
@ -2224,6 +2226,7 @@ builtin/prune.o builtin/reflog.o reachable.o: reachable.h
|
||||||
builtin/commit.o builtin/revert.o wt-status.o: wt-status.h
|
builtin/commit.o builtin/revert.o wt-status.o: wt-status.h
|
||||||
builtin/tar-tree.o archive-tar.o: tar.h
|
builtin/tar-tree.o archive-tar.o: tar.h
|
||||||
connect.o transport.o url.o http-backend.o: url.h
|
connect.o transport.o url.o http-backend.o: url.h
|
||||||
|
builtin/branch.o builtin/commit.o builtin/tag.o column.o help.o pager.o: column.h
|
||||||
http-fetch.o http-walker.o remote-curl.o transport.o walker.o: walker.h
|
http-fetch.o http-walker.o remote-curl.o transport.o walker.o: walker.h
|
||||||
http.o http-walker.o http-push.o http-fetch.o remote-curl.o: http.h url.h
|
http.o http-walker.o http-push.o http-fetch.o remote-curl.o: http.h url.h
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,7 @@ extern int cmd_cherry(int argc, const char **argv, const char *prefix);
|
||||||
extern int cmd_cherry_pick(int argc, const char **argv, const char *prefix);
|
extern int cmd_cherry_pick(int argc, const char **argv, const char *prefix);
|
||||||
extern int cmd_clone(int argc, const char **argv, const char *prefix);
|
extern int cmd_clone(int argc, const char **argv, const char *prefix);
|
||||||
extern int cmd_clean(int argc, const char **argv, const char *prefix);
|
extern int cmd_clean(int argc, const char **argv, const char *prefix);
|
||||||
|
extern int cmd_column(int argc, const char **argv, const char *prefix);
|
||||||
extern int cmd_commit(int argc, const char **argv, const char *prefix);
|
extern int cmd_commit(int argc, const char **argv, const char *prefix);
|
||||||
extern int cmd_commit_tree(int argc, const char **argv, const char *prefix);
|
extern int cmd_commit_tree(int argc, const char **argv, const char *prefix);
|
||||||
extern int cmd_config(int argc, const char **argv, const char *prefix);
|
extern int cmd_config(int argc, const char **argv, const char *prefix);
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
#include "branch.h"
|
#include "branch.h"
|
||||||
#include "diff.h"
|
#include "diff.h"
|
||||||
#include "revision.h"
|
#include "revision.h"
|
||||||
|
#include "string-list.h"
|
||||||
|
#include "column.h"
|
||||||
|
|
||||||
static const char * const builtin_branch_usage[] = {
|
static const char * const builtin_branch_usage[] = {
|
||||||
"git branch [options] [-r | -a] [--merged | --no-merged]",
|
"git branch [options] [-r | -a] [--merged | --no-merged]",
|
||||||
|
@ -53,6 +55,9 @@ static enum merge_filter {
|
||||||
} merge_filter;
|
} merge_filter;
|
||||||
static unsigned char merge_filter_ref[20];
|
static unsigned char merge_filter_ref[20];
|
||||||
|
|
||||||
|
static struct string_list output = STRING_LIST_INIT_DUP;
|
||||||
|
static unsigned int colopts;
|
||||||
|
|
||||||
static int parse_branch_color_slot(const char *var, int ofs)
|
static int parse_branch_color_slot(const char *var, int ofs)
|
||||||
{
|
{
|
||||||
if (!strcasecmp(var+ofs, "plain"))
|
if (!strcasecmp(var+ofs, "plain"))
|
||||||
|
@ -70,6 +75,8 @@ static int parse_branch_color_slot(const char *var, int ofs)
|
||||||
|
|
||||||
static int git_branch_config(const char *var, const char *value, void *cb)
|
static int git_branch_config(const char *var, const char *value, void *cb)
|
||||||
{
|
{
|
||||||
|
if (!prefixcmp(var, "column."))
|
||||||
|
return git_column_config(var, value, "branch", &colopts);
|
||||||
if (!strcmp(var, "color.branch")) {
|
if (!strcmp(var, "color.branch")) {
|
||||||
branch_use_color = git_config_colorbool(var, value);
|
branch_use_color = git_config_colorbool(var, value);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -482,7 +489,12 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
|
||||||
else if (verbose)
|
else if (verbose)
|
||||||
/* " f7c0c00 [ahead 58, behind 197] vcs-svn: drop obj_pool.h" */
|
/* " f7c0c00 [ahead 58, behind 197] vcs-svn: drop obj_pool.h" */
|
||||||
add_verbose_info(&out, item, verbose, abbrev);
|
add_verbose_info(&out, item, verbose, abbrev);
|
||||||
printf("%s\n", out.buf);
|
if (column_active(colopts)) {
|
||||||
|
assert(!verbose && "--column and --verbose are incompatible");
|
||||||
|
string_list_append(&output, out.buf);
|
||||||
|
} else {
|
||||||
|
printf("%s\n", out.buf);
|
||||||
|
}
|
||||||
strbuf_release(&name);
|
strbuf_release(&name);
|
||||||
strbuf_release(&out);
|
strbuf_release(&out);
|
||||||
}
|
}
|
||||||
|
@ -741,6 +753,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
|
||||||
PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NONEG,
|
PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NONEG,
|
||||||
opt_parse_merge_filter, (intptr_t) "HEAD",
|
opt_parse_merge_filter, (intptr_t) "HEAD",
|
||||||
},
|
},
|
||||||
|
OPT_COLUMN(0, "column", &colopts, "list branches in columns"),
|
||||||
OPT_END(),
|
OPT_END(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -763,6 +776,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
|
||||||
}
|
}
|
||||||
hashcpy(merge_filter_ref, head_sha1);
|
hashcpy(merge_filter_ref, head_sha1);
|
||||||
|
|
||||||
|
|
||||||
argc = parse_options(argc, argv, prefix, options, builtin_branch_usage,
|
argc = parse_options(argc, argv, prefix, options, builtin_branch_usage,
|
||||||
0);
|
0);
|
||||||
|
|
||||||
|
@ -774,12 +788,22 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
|
||||||
|
|
||||||
if (abbrev == -1)
|
if (abbrev == -1)
|
||||||
abbrev = DEFAULT_ABBREV;
|
abbrev = DEFAULT_ABBREV;
|
||||||
|
finalize_colopts(&colopts, -1);
|
||||||
|
if (verbose) {
|
||||||
|
if (explicitly_enable_column(colopts))
|
||||||
|
die(_("--column and --verbose are incompatible"));
|
||||||
|
colopts = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (delete)
|
if (delete)
|
||||||
return delete_branches(argc, argv, delete > 1, kinds, quiet);
|
return delete_branches(argc, argv, delete > 1, kinds, quiet);
|
||||||
else if (list)
|
else if (list) {
|
||||||
return print_ref_list(kinds, detached, verbose, abbrev,
|
int ret = print_ref_list(kinds, detached, verbose, abbrev,
|
||||||
with_commit, argv);
|
with_commit, argv);
|
||||||
|
print_columns(&output, colopts, NULL);
|
||||||
|
string_list_clear(&output, 0);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
else if (edit_description) {
|
else if (edit_description) {
|
||||||
const char *branch_name;
|
const char *branch_name;
|
||||||
struct strbuf branch_ref = STRBUF_INIT;
|
struct strbuf branch_ref = STRBUF_INIT;
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
#include "builtin.h"
|
||||||
|
#include "cache.h"
|
||||||
|
#include "strbuf.h"
|
||||||
|
#include "parse-options.h"
|
||||||
|
#include "string-list.h"
|
||||||
|
#include "column.h"
|
||||||
|
|
||||||
|
static const char * const builtin_column_usage[] = {
|
||||||
|
"git column [options]",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
static unsigned int colopts;
|
||||||
|
|
||||||
|
static int column_config(const char *var, const char *value, void *cb)
|
||||||
|
{
|
||||||
|
return git_column_config(var, value, cb, &colopts);
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmd_column(int argc, const char **argv, const char *prefix)
|
||||||
|
{
|
||||||
|
struct string_list list = STRING_LIST_INIT_DUP;
|
||||||
|
struct strbuf sb = STRBUF_INIT;
|
||||||
|
struct column_options copts;
|
||||||
|
const char *command = NULL, *real_command = NULL;
|
||||||
|
struct option options[] = {
|
||||||
|
OPT_STRING(0, "command", &real_command, "name", "lookup config vars"),
|
||||||
|
OPT_COLUMN(0, "mode", &colopts, "layout to use"),
|
||||||
|
OPT_INTEGER(0, "raw-mode", &colopts, "layout to use"),
|
||||||
|
OPT_INTEGER(0, "width", &copts.width, "Maximum width"),
|
||||||
|
OPT_STRING(0, "indent", &copts.indent, "string", "Padding space on left border"),
|
||||||
|
OPT_INTEGER(0, "nl", &copts.nl, "Padding space on right border"),
|
||||||
|
OPT_INTEGER(0, "padding", &copts.padding, "Padding space between columns"),
|
||||||
|
OPT_END()
|
||||||
|
};
|
||||||
|
|
||||||
|
/* This one is special and must be the first one */
|
||||||
|
if (argc > 1 && !prefixcmp(argv[1], "--command=")) {
|
||||||
|
command = argv[1] + 10;
|
||||||
|
git_config(column_config, (void *)command);
|
||||||
|
} else
|
||||||
|
git_config(column_config, NULL);
|
||||||
|
|
||||||
|
memset(&copts, 0, sizeof(copts));
|
||||||
|
copts.width = term_columns();
|
||||||
|
copts.padding = 1;
|
||||||
|
argc = parse_options(argc, argv, "", options, builtin_column_usage, 0);
|
||||||
|
if (argc)
|
||||||
|
usage_with_options(builtin_column_usage, options);
|
||||||
|
if (real_command || command) {
|
||||||
|
if (!real_command || !command || strcmp(real_command, command))
|
||||||
|
die(_("--command must be the first argument"));
|
||||||
|
}
|
||||||
|
finalize_colopts(&colopts, -1);
|
||||||
|
while (!strbuf_getline(&sb, stdin, '\n'))
|
||||||
|
string_list_append(&list, sb.buf);
|
||||||
|
|
||||||
|
print_columns(&list, colopts, &copts);
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -27,6 +27,7 @@
|
||||||
#include "quote.h"
|
#include "quote.h"
|
||||||
#include "submodule.h"
|
#include "submodule.h"
|
||||||
#include "gpg-interface.h"
|
#include "gpg-interface.h"
|
||||||
|
#include "column.h"
|
||||||
|
|
||||||
static const char * const builtin_commit_usage[] = {
|
static const char * const builtin_commit_usage[] = {
|
||||||
"git commit [options] [--] <filepattern>...",
|
"git commit [options] [--] <filepattern>...",
|
||||||
|
@ -88,6 +89,7 @@ static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
|
||||||
static int no_post_rewrite, allow_empty_message;
|
static int no_post_rewrite, allow_empty_message;
|
||||||
static char *untracked_files_arg, *force_date, *ignore_submodule_arg;
|
static char *untracked_files_arg, *force_date, *ignore_submodule_arg;
|
||||||
static char *sign_commit;
|
static char *sign_commit;
|
||||||
|
static unsigned int colopts;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The default commit message cleanup mode will remove the lines
|
* The default commit message cleanup mode will remove the lines
|
||||||
|
@ -1173,6 +1175,8 @@ static int git_status_config(const char *k, const char *v, void *cb)
|
||||||
{
|
{
|
||||||
struct wt_status *s = cb;
|
struct wt_status *s = cb;
|
||||||
|
|
||||||
|
if (!prefixcmp(k, "column."))
|
||||||
|
return git_column_config(k, v, "status", &colopts);
|
||||||
if (!strcmp(k, "status.submodulesummary")) {
|
if (!strcmp(k, "status.submodulesummary")) {
|
||||||
int is_bool;
|
int is_bool;
|
||||||
s->submodule_summary = git_config_bool_or_int(k, v, &is_bool);
|
s->submodule_summary = git_config_bool_or_int(k, v, &is_bool);
|
||||||
|
@ -1238,6 +1242,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
|
||||||
{ OPTION_STRING, 0, "ignore-submodules", &ignore_submodule_arg, "when",
|
{ OPTION_STRING, 0, "ignore-submodules", &ignore_submodule_arg, "when",
|
||||||
"ignore changes to submodules, optional when: all, dirty, untracked. (Default: all)",
|
"ignore changes to submodules, optional when: all, dirty, untracked. (Default: all)",
|
||||||
PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
|
PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
|
||||||
|
OPT_COLUMN(0, "column", &colopts, "list untracked files in columns"),
|
||||||
OPT_END(),
|
OPT_END(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1251,6 +1256,8 @@ int cmd_status(int argc, const char **argv, const char *prefix)
|
||||||
argc = parse_options(argc, argv, prefix,
|
argc = parse_options(argc, argv, prefix,
|
||||||
builtin_status_options,
|
builtin_status_options,
|
||||||
builtin_status_usage, 0);
|
builtin_status_usage, 0);
|
||||||
|
finalize_colopts(&colopts, -1);
|
||||||
|
s.colopts = colopts;
|
||||||
|
|
||||||
if (null_termination && status_format == STATUS_FORMAT_LONG)
|
if (null_termination && status_format == STATUS_FORMAT_LONG)
|
||||||
status_format = STATUS_FORMAT_PORCELAIN;
|
status_format = STATUS_FORMAT_PORCELAIN;
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "common-cmds.h"
|
#include "common-cmds.h"
|
||||||
#include "parse-options.h"
|
#include "parse-options.h"
|
||||||
#include "run-command.h"
|
#include "run-command.h"
|
||||||
|
#include "column.h"
|
||||||
#include "help.h"
|
#include "help.h"
|
||||||
|
|
||||||
static struct man_viewer_list {
|
static struct man_viewer_list {
|
||||||
|
@ -30,6 +31,7 @@ enum help_format {
|
||||||
};
|
};
|
||||||
|
|
||||||
static int show_all = 0;
|
static int show_all = 0;
|
||||||
|
static unsigned int colopts;
|
||||||
static enum help_format help_format = HELP_FORMAT_NONE;
|
static enum help_format help_format = HELP_FORMAT_NONE;
|
||||||
static struct option builtin_help_options[] = {
|
static struct option builtin_help_options[] = {
|
||||||
OPT_BOOLEAN('a', "all", &show_all, "print all available commands"),
|
OPT_BOOLEAN('a', "all", &show_all, "print all available commands"),
|
||||||
|
@ -251,6 +253,8 @@ static int add_man_viewer_info(const char *var, const char *value)
|
||||||
|
|
||||||
static int git_help_config(const char *var, const char *value, void *cb)
|
static int git_help_config(const char *var, const char *value, void *cb)
|
||||||
{
|
{
|
||||||
|
if (!prefixcmp(var, "column."))
|
||||||
|
return git_column_config(var, value, "help", &colopts);
|
||||||
if (!strcmp(var, "help.format")) {
|
if (!strcmp(var, "help.format")) {
|
||||||
if (!value)
|
if (!value)
|
||||||
return config_error_nonbool(var);
|
return config_error_nonbool(var);
|
||||||
|
@ -424,8 +428,9 @@ int cmd_help(int argc, const char **argv, const char *prefix)
|
||||||
parsed_help_format = help_format;
|
parsed_help_format = help_format;
|
||||||
|
|
||||||
if (show_all) {
|
if (show_all) {
|
||||||
|
git_config(git_help_config, NULL);
|
||||||
printf(_("usage: %s%s"), _(git_usage_string), "\n\n");
|
printf(_("usage: %s%s"), _(git_usage_string), "\n\n");
|
||||||
list_commands(&main_cmds, &other_cmds);
|
list_commands(colopts, &main_cmds, &other_cmds);
|
||||||
printf("%s\n", _(git_more_info_string));
|
printf("%s\n", _(git_more_info_string));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "revision.h"
|
#include "revision.h"
|
||||||
#include "gpg-interface.h"
|
#include "gpg-interface.h"
|
||||||
#include "sha1-array.h"
|
#include "sha1-array.h"
|
||||||
|
#include "column.h"
|
||||||
|
|
||||||
static const char * const git_tag_usage[] = {
|
static const char * const git_tag_usage[] = {
|
||||||
"git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]",
|
"git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]",
|
||||||
|
@ -33,6 +34,7 @@ struct tag_filter {
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct sha1_array points_at;
|
static struct sha1_array points_at;
|
||||||
|
static unsigned int colopts;
|
||||||
|
|
||||||
static int match_pattern(const char **patterns, const char *ref)
|
static int match_pattern(const char **patterns, const char *ref)
|
||||||
{
|
{
|
||||||
|
@ -263,6 +265,8 @@ static int git_tag_config(const char *var, const char *value, void *cb)
|
||||||
int status = git_gpg_config(var, value, cb);
|
int status = git_gpg_config(var, value, cb);
|
||||||
if (status)
|
if (status)
|
||||||
return status;
|
return status;
|
||||||
|
if (!prefixcmp(var, "column."))
|
||||||
|
return git_column_config(var, value, "tag", &colopts);
|
||||||
return git_default_config(var, value, cb);
|
return git_default_config(var, value, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -459,6 +463,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
|
||||||
OPT_STRING('u', "local-user", &keyid, "key-id",
|
OPT_STRING('u', "local-user", &keyid, "key-id",
|
||||||
"use another key to sign the tag"),
|
"use another key to sign the tag"),
|
||||||
OPT__FORCE(&force, "replace the tag if exists"),
|
OPT__FORCE(&force, "replace the tag if exists"),
|
||||||
|
OPT_COLUMN(0, "column", &colopts, "show tag list in columns"),
|
||||||
|
|
||||||
OPT_GROUP("Tag listing options"),
|
OPT_GROUP("Tag listing options"),
|
||||||
{
|
{
|
||||||
|
@ -495,9 +500,25 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
|
||||||
|
|
||||||
if (list + delete + verify > 1)
|
if (list + delete + verify > 1)
|
||||||
usage_with_options(git_tag_usage, options);
|
usage_with_options(git_tag_usage, options);
|
||||||
if (list)
|
finalize_colopts(&colopts, -1);
|
||||||
return list_tags(argv, lines == -1 ? 0 : lines,
|
if (list && lines != -1) {
|
||||||
with_commit);
|
if (explicitly_enable_column(colopts))
|
||||||
|
die(_("--column and -n are incompatible"));
|
||||||
|
colopts = 0;
|
||||||
|
}
|
||||||
|
if (list) {
|
||||||
|
int ret;
|
||||||
|
if (column_active(colopts)) {
|
||||||
|
struct column_options copts;
|
||||||
|
memset(&copts, 0, sizeof(copts));
|
||||||
|
copts.padding = 2;
|
||||||
|
run_column_filter(colopts, &copts);
|
||||||
|
}
|
||||||
|
ret = list_tags(argv, lines == -1 ? 0 : lines, with_commit);
|
||||||
|
if (column_active(colopts))
|
||||||
|
stop_column_filter();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
if (lines != -1)
|
if (lines != -1)
|
||||||
die(_("-n option is only allowed with -l."));
|
die(_("-n option is only allowed with -l."));
|
||||||
if (with_commit)
|
if (with_commit)
|
||||||
|
|
|
@ -0,0 +1,434 @@
|
||||||
|
#include "cache.h"
|
||||||
|
#include "column.h"
|
||||||
|
#include "string-list.h"
|
||||||
|
#include "parse-options.h"
|
||||||
|
#include "run-command.h"
|
||||||
|
#include "utf8.h"
|
||||||
|
|
||||||
|
#define XY2LINEAR(d, x, y) (COL_LAYOUT((d)->colopts) == COL_COLUMN ? \
|
||||||
|
(x) * (d)->rows + (y) : \
|
||||||
|
(y) * (d)->cols + (x))
|
||||||
|
|
||||||
|
struct column_data {
|
||||||
|
const struct string_list *list;
|
||||||
|
unsigned int colopts;
|
||||||
|
struct column_options opts;
|
||||||
|
|
||||||
|
int rows, cols;
|
||||||
|
int *len; /* cell length */
|
||||||
|
int *width; /* index to the longest row in column */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* return length of 's' in letters, ANSI escapes stripped */
|
||||||
|
static int item_length(unsigned int colopts, const char *s)
|
||||||
|
{
|
||||||
|
int len, i = 0;
|
||||||
|
struct strbuf str = STRBUF_INIT;
|
||||||
|
|
||||||
|
strbuf_addstr(&str, s);
|
||||||
|
while ((s = strstr(str.buf + i, "\033[")) != NULL) {
|
||||||
|
int len = strspn(s + 2, "0123456789;");
|
||||||
|
i = s - str.buf;
|
||||||
|
strbuf_remove(&str, i, len + 3); /* \033[<len><func char> */
|
||||||
|
}
|
||||||
|
len = utf8_strwidth(str.buf);
|
||||||
|
strbuf_release(&str);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate cell width, rows and cols for a table of equal cells, given
|
||||||
|
* table width and how many spaces between cells.
|
||||||
|
*/
|
||||||
|
static void layout(struct column_data *data, int *width)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
*width = 0;
|
||||||
|
for (i = 0; i < data->list->nr; i++)
|
||||||
|
if (*width < data->len[i])
|
||||||
|
*width = data->len[i];
|
||||||
|
|
||||||
|
*width += data->opts.padding;
|
||||||
|
|
||||||
|
data->cols = (data->opts.width - strlen(data->opts.indent)) / *width;
|
||||||
|
if (data->cols == 0)
|
||||||
|
data->cols = 1;
|
||||||
|
|
||||||
|
data->rows = DIV_ROUND_UP(data->list->nr, data->cols);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void compute_column_width(struct column_data *data)
|
||||||
|
{
|
||||||
|
int i, x, y;
|
||||||
|
for (x = 0; x < data->cols; x++) {
|
||||||
|
data->width[x] = XY2LINEAR(data, x, 0);
|
||||||
|
for (y = 0; y < data->rows; y++) {
|
||||||
|
i = XY2LINEAR(data, x, y);
|
||||||
|
if (i < data->list->nr &&
|
||||||
|
data->len[data->width[x]] < data->len[i])
|
||||||
|
data->width[x] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Shrink all columns by shortening them one row each time (and adding
|
||||||
|
* more columns along the way). Hopefully the longest cell will be
|
||||||
|
* moved to the next column, column is shrunk so we have more space
|
||||||
|
* for new columns. The process ends when the whole thing no longer
|
||||||
|
* fits in data->total_width.
|
||||||
|
*/
|
||||||
|
static void shrink_columns(struct column_data *data)
|
||||||
|
{
|
||||||
|
data->width = xrealloc(data->width,
|
||||||
|
sizeof(*data->width) * data->cols);
|
||||||
|
while (data->rows > 1) {
|
||||||
|
int x, total_width, cols, rows;
|
||||||
|
rows = data->rows;
|
||||||
|
cols = data->cols;
|
||||||
|
|
||||||
|
data->rows--;
|
||||||
|
data->cols = DIV_ROUND_UP(data->list->nr, data->rows);
|
||||||
|
if (data->cols != cols)
|
||||||
|
data->width = xrealloc(data->width,
|
||||||
|
sizeof(*data->width) * data->cols);
|
||||||
|
compute_column_width(data);
|
||||||
|
|
||||||
|
total_width = strlen(data->opts.indent);
|
||||||
|
for (x = 0; x < data->cols; x++) {
|
||||||
|
total_width += data->len[data->width[x]];
|
||||||
|
total_width += data->opts.padding;
|
||||||
|
}
|
||||||
|
if (total_width > data->opts.width) {
|
||||||
|
data->rows = rows;
|
||||||
|
data->cols = cols;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compute_column_width(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Display without layout when not enabled */
|
||||||
|
static void display_plain(const struct string_list *list,
|
||||||
|
const char *indent, const char *nl)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < list->nr; i++)
|
||||||
|
printf("%s%s%s", indent, list->items[i].string, nl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print a cell to stdout with all necessary leading/traling space */
|
||||||
|
static int display_cell(struct column_data *data, int initial_width,
|
||||||
|
const char *empty_cell, int x, int y)
|
||||||
|
{
|
||||||
|
int i, len, newline;
|
||||||
|
|
||||||
|
i = XY2LINEAR(data, x, y);
|
||||||
|
if (i >= data->list->nr)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
len = data->len[i];
|
||||||
|
if (data->width && data->len[data->width[x]] < initial_width) {
|
||||||
|
/*
|
||||||
|
* empty_cell has initial_width chars, if real column
|
||||||
|
* is narrower, increase len a bit so we fill less
|
||||||
|
* space.
|
||||||
|
*/
|
||||||
|
len += initial_width - data->len[data->width[x]];
|
||||||
|
len -= data->opts.padding;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (COL_LAYOUT(data->colopts) == COL_COLUMN)
|
||||||
|
newline = i + data->rows >= data->list->nr;
|
||||||
|
else
|
||||||
|
newline = x == data->cols - 1 || i == data->list->nr - 1;
|
||||||
|
|
||||||
|
printf("%s%s%s",
|
||||||
|
x == 0 ? data->opts.indent : "",
|
||||||
|
data->list->items[i].string,
|
||||||
|
newline ? data->opts.nl : empty_cell + len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Display COL_COLUMN or COL_ROW */
|
||||||
|
static void display_table(const struct string_list *list,
|
||||||
|
unsigned int colopts,
|
||||||
|
const struct column_options *opts)
|
||||||
|
{
|
||||||
|
struct column_data data;
|
||||||
|
int x, y, i, initial_width;
|
||||||
|
char *empty_cell;
|
||||||
|
|
||||||
|
memset(&data, 0, sizeof(data));
|
||||||
|
data.list = list;
|
||||||
|
data.colopts = colopts;
|
||||||
|
data.opts = *opts;
|
||||||
|
|
||||||
|
data.len = xmalloc(sizeof(*data.len) * list->nr);
|
||||||
|
for (i = 0; i < list->nr; i++)
|
||||||
|
data.len[i] = item_length(colopts, list->items[i].string);
|
||||||
|
|
||||||
|
layout(&data, &initial_width);
|
||||||
|
|
||||||
|
if (colopts & COL_DENSE)
|
||||||
|
shrink_columns(&data);
|
||||||
|
|
||||||
|
empty_cell = xmalloc(initial_width + 1);
|
||||||
|
memset(empty_cell, ' ', initial_width);
|
||||||
|
empty_cell[initial_width] = '\0';
|
||||||
|
for (y = 0; y < data.rows; y++) {
|
||||||
|
for (x = 0; x < data.cols; x++)
|
||||||
|
if (display_cell(&data, initial_width, empty_cell, x, y))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(data.len);
|
||||||
|
free(data.width);
|
||||||
|
free(empty_cell);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_columns(const struct string_list *list, unsigned int colopts,
|
||||||
|
const struct column_options *opts)
|
||||||
|
{
|
||||||
|
struct column_options nopts;
|
||||||
|
|
||||||
|
if (!list->nr)
|
||||||
|
return;
|
||||||
|
assert((colopts & COL_ENABLE_MASK) != COL_AUTO);
|
||||||
|
|
||||||
|
memset(&nopts, 0, sizeof(nopts));
|
||||||
|
nopts.indent = opts && opts->indent ? opts->indent : "";
|
||||||
|
nopts.nl = opts && opts->nl ? opts->nl : "\n";
|
||||||
|
nopts.padding = opts ? opts->padding : 1;
|
||||||
|
nopts.width = opts && opts->width ? opts->width : term_columns() - 1;
|
||||||
|
if (!column_active(colopts)) {
|
||||||
|
display_plain(list, "", "\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (COL_LAYOUT(colopts)) {
|
||||||
|
case COL_PLAIN:
|
||||||
|
display_plain(list, nopts.indent, nopts.nl);
|
||||||
|
break;
|
||||||
|
case COL_ROW:
|
||||||
|
case COL_COLUMN:
|
||||||
|
display_table(list, colopts, &nopts);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
die("BUG: invalid layout mode %d", COL_LAYOUT(colopts));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int finalize_colopts(unsigned int *colopts, int stdout_is_tty)
|
||||||
|
{
|
||||||
|
if ((*colopts & COL_ENABLE_MASK) == COL_AUTO) {
|
||||||
|
if (stdout_is_tty < 0)
|
||||||
|
stdout_is_tty = isatty(1);
|
||||||
|
*colopts &= ~COL_ENABLE_MASK;
|
||||||
|
if (stdout_is_tty)
|
||||||
|
*colopts |= COL_ENABLED;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct colopt {
|
||||||
|
const char *name;
|
||||||
|
unsigned int value;
|
||||||
|
unsigned int mask;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define LAYOUT_SET 1
|
||||||
|
#define ENABLE_SET 2
|
||||||
|
|
||||||
|
static int parse_option(const char *arg, int len, unsigned int *colopts,
|
||||||
|
int *group_set)
|
||||||
|
{
|
||||||
|
struct colopt opts[] = {
|
||||||
|
{ "always", COL_ENABLED, COL_ENABLE_MASK },
|
||||||
|
{ "never", COL_DISABLED, COL_ENABLE_MASK },
|
||||||
|
{ "auto", COL_AUTO, COL_ENABLE_MASK },
|
||||||
|
{ "plain", COL_PLAIN, COL_LAYOUT_MASK },
|
||||||
|
{ "column", COL_COLUMN, COL_LAYOUT_MASK },
|
||||||
|
{ "row", COL_ROW, COL_LAYOUT_MASK },
|
||||||
|
{ "dense", COL_DENSE, 0 },
|
||||||
|
};
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(opts); i++) {
|
||||||
|
int set = 1, arg_len = len, name_len;
|
||||||
|
const char *arg_str = arg;
|
||||||
|
|
||||||
|
if (!opts[i].mask) {
|
||||||
|
if (arg_len > 2 && !strncmp(arg_str, "no", 2)) {
|
||||||
|
arg_str += 2;
|
||||||
|
arg_len -= 2;
|
||||||
|
set = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
name_len = strlen(opts[i].name);
|
||||||
|
if (arg_len != name_len ||
|
||||||
|
strncmp(arg_str, opts[i].name, name_len))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch (opts[i].mask) {
|
||||||
|
case COL_ENABLE_MASK:
|
||||||
|
*group_set |= ENABLE_SET;
|
||||||
|
break;
|
||||||
|
case COL_LAYOUT_MASK:
|
||||||
|
*group_set |= LAYOUT_SET;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts[i].mask)
|
||||||
|
*colopts = (*colopts & ~opts[i].mask) | opts[i].value;
|
||||||
|
else {
|
||||||
|
if (set)
|
||||||
|
*colopts |= opts[i].value;
|
||||||
|
else
|
||||||
|
*colopts &= ~opts[i].value;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return error("unsupported option '%s'", arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_config(unsigned int *colopts, const char *value)
|
||||||
|
{
|
||||||
|
const char *sep = " ,";
|
||||||
|
int group_set = 0;
|
||||||
|
|
||||||
|
while (*value) {
|
||||||
|
int len = strcspn(value, sep);
|
||||||
|
if (len) {
|
||||||
|
if (parse_option(value, len, colopts, &group_set))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
value += len;
|
||||||
|
}
|
||||||
|
value += strspn(value, sep);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Setting layout implies "always" if neither always, never
|
||||||
|
* nor auto is specified.
|
||||||
|
*
|
||||||
|
* Current value in COL_ENABLE_MASK is disregarded. This means if
|
||||||
|
* you set column.ui = auto and pass --column=row, then "auto"
|
||||||
|
* will become "always".
|
||||||
|
*/
|
||||||
|
if ((group_set & LAYOUT_SET) && !(group_set & ENABLE_SET))
|
||||||
|
*colopts = (*colopts & ~COL_ENABLE_MASK) | COL_ENABLED;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int column_config(const char *var, const char *value,
|
||||||
|
const char *key, unsigned int *colopts)
|
||||||
|
{
|
||||||
|
if (!value)
|
||||||
|
return config_error_nonbool(var);
|
||||||
|
if (parse_config(colopts, value))
|
||||||
|
return error("invalid column.%s mode %s", key, value);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int git_column_config(const char *var, const char *value,
|
||||||
|
const char *command, unsigned int *colopts)
|
||||||
|
{
|
||||||
|
const char *it = skip_prefix(var, "column.");
|
||||||
|
if (!it)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!strcmp(it, "ui"))
|
||||||
|
return column_config(var, value, "ui", colopts);
|
||||||
|
|
||||||
|
if (command && !strcmp(it, command))
|
||||||
|
return column_config(var, value, it, colopts);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int parseopt_column_callback(const struct option *opt,
|
||||||
|
const char *arg, int unset)
|
||||||
|
{
|
||||||
|
unsigned int *colopts = opt->value;
|
||||||
|
*colopts |= COL_PARSEOPT;
|
||||||
|
*colopts &= ~COL_ENABLE_MASK;
|
||||||
|
if (unset) /* --no-column == never */
|
||||||
|
return 0;
|
||||||
|
/* --column == always unless "arg" states otherwise */
|
||||||
|
*colopts |= COL_ENABLED;
|
||||||
|
if (arg)
|
||||||
|
return parse_config(colopts, arg);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fd_out = -1;
|
||||||
|
static struct child_process column_process;
|
||||||
|
|
||||||
|
int run_column_filter(int colopts, const struct column_options *opts)
|
||||||
|
{
|
||||||
|
const char *av[10];
|
||||||
|
int ret, ac = 0;
|
||||||
|
struct strbuf sb_colopt = STRBUF_INIT;
|
||||||
|
struct strbuf sb_width = STRBUF_INIT;
|
||||||
|
struct strbuf sb_padding = STRBUF_INIT;
|
||||||
|
|
||||||
|
if (fd_out != -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
av[ac++] = "column";
|
||||||
|
strbuf_addf(&sb_colopt, "--raw-mode=%d", colopts);
|
||||||
|
av[ac++] = sb_colopt.buf;
|
||||||
|
if (opts && opts->width) {
|
||||||
|
strbuf_addf(&sb_width, "--width=%d", opts->width);
|
||||||
|
av[ac++] = sb_width.buf;
|
||||||
|
}
|
||||||
|
if (opts && opts->indent) {
|
||||||
|
av[ac++] = "--indent";
|
||||||
|
av[ac++] = opts->indent;
|
||||||
|
}
|
||||||
|
if (opts && opts->padding) {
|
||||||
|
strbuf_addf(&sb_padding, "--padding=%d", opts->padding);
|
||||||
|
av[ac++] = sb_padding.buf;
|
||||||
|
}
|
||||||
|
av[ac] = NULL;
|
||||||
|
|
||||||
|
fflush(stdout);
|
||||||
|
memset(&column_process, 0, sizeof(column_process));
|
||||||
|
column_process.in = -1;
|
||||||
|
column_process.out = dup(1);
|
||||||
|
column_process.git_cmd = 1;
|
||||||
|
column_process.argv = av;
|
||||||
|
|
||||||
|
ret = start_command(&column_process);
|
||||||
|
|
||||||
|
strbuf_release(&sb_colopt);
|
||||||
|
strbuf_release(&sb_width);
|
||||||
|
strbuf_release(&sb_padding);
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
fd_out = dup(1);
|
||||||
|
close(1);
|
||||||
|
dup2(column_process.in, 1);
|
||||||
|
close(column_process.in);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int stop_column_filter(void)
|
||||||
|
{
|
||||||
|
if (fd_out == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
fflush(stdout);
|
||||||
|
close(1);
|
||||||
|
finish_command(&column_process);
|
||||||
|
dup2(fd_out, 1);
|
||||||
|
close(fd_out);
|
||||||
|
fd_out = -1;
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
#ifndef COLUMN_H
|
||||||
|
#define COLUMN_H
|
||||||
|
|
||||||
|
#define COL_LAYOUT_MASK 0x000F
|
||||||
|
#define COL_ENABLE_MASK 0x0030 /* always, never or auto */
|
||||||
|
#define COL_PARSEOPT 0x0040 /* --column is given from cmdline */
|
||||||
|
#define COL_DENSE 0x0080 /* Shrink columns when possible,
|
||||||
|
making space for more columns */
|
||||||
|
|
||||||
|
#define COL_DISABLED 0x0000 /* must be zero */
|
||||||
|
#define COL_ENABLED 0x0010
|
||||||
|
#define COL_AUTO 0x0020
|
||||||
|
|
||||||
|
#define COL_LAYOUT(c) ((c) & COL_LAYOUT_MASK)
|
||||||
|
#define COL_COLUMN 0 /* Fill columns before rows */
|
||||||
|
#define COL_ROW 1 /* Fill rows before columns */
|
||||||
|
#define COL_PLAIN 15 /* one column */
|
||||||
|
|
||||||
|
#define explicitly_enable_column(c) \
|
||||||
|
(((c) & COL_PARSEOPT) && column_active(c))
|
||||||
|
|
||||||
|
struct column_options {
|
||||||
|
int width;
|
||||||
|
int padding;
|
||||||
|
const char *indent;
|
||||||
|
const char *nl;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct option;
|
||||||
|
extern int parseopt_column_callback(const struct option *, const char *, int);
|
||||||
|
extern int git_column_config(const char *var, const char *value,
|
||||||
|
const char *command, unsigned int *colopts);
|
||||||
|
extern int finalize_colopts(unsigned int *colopts, int stdout_is_tty);
|
||||||
|
static inline int column_active(unsigned int colopts)
|
||||||
|
{
|
||||||
|
return (colopts & COL_ENABLE_MASK) == COL_ENABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern void print_columns(const struct string_list *list, unsigned int colopts,
|
||||||
|
const struct column_options *opts);
|
||||||
|
|
||||||
|
extern int run_column_filter(int colopts, const struct column_options *);
|
||||||
|
extern int stop_column_filter(void);
|
||||||
|
|
||||||
|
#endif
|
|
@ -20,6 +20,7 @@ git-cherry-pick mainporcelain
|
||||||
git-citool mainporcelain
|
git-citool mainporcelain
|
||||||
git-clean mainporcelain
|
git-clean mainporcelain
|
||||||
git-clone mainporcelain common
|
git-clone mainporcelain common
|
||||||
|
git-column purehelpers
|
||||||
git-commit mainporcelain common
|
git-commit mainporcelain common
|
||||||
git-commit-tree plumbingmanipulators
|
git-commit-tree plumbingmanipulators
|
||||||
git-config ancillarymanipulators
|
git-config ancillarymanipulators
|
||||||
|
|
1
git.c
1
git.c
|
@ -348,6 +348,7 @@ static void handle_internal_command(int argc, const char **argv)
|
||||||
{ "cherry-pick", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE },
|
{ "cherry-pick", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE },
|
||||||
{ "clean", cmd_clean, RUN_SETUP | NEED_WORK_TREE },
|
{ "clean", cmd_clean, RUN_SETUP | NEED_WORK_TREE },
|
||||||
{ "clone", cmd_clone },
|
{ "clone", cmd_clone },
|
||||||
|
{ "column", cmd_column, RUN_SETUP_GENTLY },
|
||||||
{ "commit", cmd_commit, RUN_SETUP | NEED_WORK_TREE },
|
{ "commit", cmd_commit, RUN_SETUP | NEED_WORK_TREE },
|
||||||
{ "commit-tree", cmd_commit_tree, RUN_SETUP },
|
{ "commit-tree", cmd_commit_tree, RUN_SETUP },
|
||||||
{ "config", cmd_config, RUN_SETUP_GENTLY },
|
{ "config", cmd_config, RUN_SETUP_GENTLY },
|
||||||
|
|
58
help.c
58
help.c
|
@ -4,6 +4,8 @@
|
||||||
#include "levenshtein.h"
|
#include "levenshtein.h"
|
||||||
#include "help.h"
|
#include "help.h"
|
||||||
#include "common-cmds.h"
|
#include "common-cmds.h"
|
||||||
|
#include "string-list.h"
|
||||||
|
#include "column.h"
|
||||||
|
|
||||||
void add_cmdname(struct cmdnames *cmds, const char *name, int len)
|
void add_cmdname(struct cmdnames *cmds, const char *name, int len)
|
||||||
{
|
{
|
||||||
|
@ -70,31 +72,25 @@ void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes)
|
||||||
cmds->cnt = cj;
|
cmds->cnt = cj;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pretty_print_string_list(struct cmdnames *cmds, int longest)
|
static void pretty_print_string_list(struct cmdnames *cmds,
|
||||||
|
unsigned int colopts)
|
||||||
{
|
{
|
||||||
int cols = 1, rows;
|
struct string_list list = STRING_LIST_INIT_NODUP;
|
||||||
int space = longest + 1; /* min 1 SP between words */
|
struct column_options copts;
|
||||||
int max_cols = term_columns() - 1; /* don't print *on* the edge */
|
int i;
|
||||||
int i, j;
|
|
||||||
|
|
||||||
if (space < max_cols)
|
for (i = 0; i < cmds->cnt; i++)
|
||||||
cols = max_cols / space;
|
string_list_append(&list, cmds->names[i]->name);
|
||||||
rows = DIV_ROUND_UP(cmds->cnt, cols);
|
/*
|
||||||
|
* always enable column display, we only consult column.*
|
||||||
for (i = 0; i < rows; i++) {
|
* about layout strategy and stuff
|
||||||
printf(" ");
|
*/
|
||||||
|
colopts = (colopts & ~COL_ENABLE_MASK) | COL_ENABLED;
|
||||||
for (j = 0; j < cols; j++) {
|
memset(&copts, 0, sizeof(copts));
|
||||||
int n = j * rows + i;
|
copts.indent = " ";
|
||||||
int size = space;
|
copts.padding = 2;
|
||||||
if (n >= cmds->cnt)
|
print_columns(&list, colopts, &copts);
|
||||||
break;
|
string_list_clear(&list, 0);
|
||||||
if (j == cols-1 || n + rows >= cmds->cnt)
|
|
||||||
size = 1;
|
|
||||||
printf("%-*s", size, cmds->names[n]->name);
|
|
||||||
}
|
|
||||||
putchar('\n');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int is_executable(const char *name)
|
static int is_executable(const char *name)
|
||||||
|
@ -203,29 +199,21 @@ void load_command_list(const char *prefix,
|
||||||
exclude_cmds(other_cmds, main_cmds);
|
exclude_cmds(other_cmds, main_cmds);
|
||||||
}
|
}
|
||||||
|
|
||||||
void list_commands(struct cmdnames *main_cmds, struct cmdnames *other_cmds)
|
void list_commands(unsigned int colopts,
|
||||||
|
struct cmdnames *main_cmds, struct cmdnames *other_cmds)
|
||||||
{
|
{
|
||||||
int i, longest = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < main_cmds->cnt; i++)
|
|
||||||
if (longest < main_cmds->names[i]->len)
|
|
||||||
longest = main_cmds->names[i]->len;
|
|
||||||
for (i = 0; i < other_cmds->cnt; i++)
|
|
||||||
if (longest < other_cmds->names[i]->len)
|
|
||||||
longest = other_cmds->names[i]->len;
|
|
||||||
|
|
||||||
if (main_cmds->cnt) {
|
if (main_cmds->cnt) {
|
||||||
const char *exec_path = git_exec_path();
|
const char *exec_path = git_exec_path();
|
||||||
printf_ln(_("available git commands in '%s'"), exec_path);
|
printf_ln(_("available git commands in '%s'"), exec_path);
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
pretty_print_string_list(main_cmds, longest);
|
pretty_print_string_list(main_cmds, colopts);
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (other_cmds->cnt) {
|
if (other_cmds->cnt) {
|
||||||
printf_ln(_("git commands available from elsewhere on your $PATH"));
|
printf_ln(_("git commands available from elsewhere on your $PATH"));
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
pretty_print_string_list(other_cmds, longest);
|
pretty_print_string_list(other_cmds, colopts);
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
3
help.h
3
help.h
|
@ -25,7 +25,6 @@ extern void add_cmdname(struct cmdnames *cmds, const char *name, int len);
|
||||||
/* Here we require that excludes is a sorted list. */
|
/* Here we require that excludes is a sorted list. */
|
||||||
extern void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes);
|
extern void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes);
|
||||||
extern int is_in_cmdlist(struct cmdnames *cmds, const char *name);
|
extern int is_in_cmdlist(struct cmdnames *cmds, const char *name);
|
||||||
extern void list_commands(struct cmdnames *main_cmds,
|
extern void list_commands(unsigned int colopts, struct cmdnames *main_cmds, struct cmdnames *other_cmds);
|
||||||
struct cmdnames *other_cmds);
|
|
||||||
|
|
||||||
#endif /* HELP_H */
|
#endif /* HELP_H */
|
||||||
|
|
2
pager.c
2
pager.c
|
@ -73,7 +73,7 @@ void setup_pager(void)
|
||||||
{
|
{
|
||||||
const char *pager = git_pager(isatty(1));
|
const char *pager = git_pager(isatty(1));
|
||||||
|
|
||||||
if (!pager)
|
if (!pager || pager_in_use())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -234,5 +234,7 @@ extern int parse_opt_noop_cb(const struct option *, const char *, int);
|
||||||
PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 }
|
PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 }
|
||||||
#define OPT__COLOR(var, h) \
|
#define OPT__COLOR(var, h) \
|
||||||
OPT_COLOR_FLAG(0, "color", (var), (h))
|
OPT_COLOR_FLAG(0, "color", (var), (h))
|
||||||
|
#define OPT_COLUMN(s, l, v, h) \
|
||||||
|
{ OPTION_CALLBACK, (s), (l), (v), "style", (h), PARSE_OPT_OPTARG, parseopt_column_callback }
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -160,6 +160,83 @@ test_expect_success 'git branch --list -d t should fail' '
|
||||||
test_path_is_missing .git/refs/heads/t
|
test_path_is_missing .git/refs/heads/t
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'git branch --column' '
|
||||||
|
COLUMNS=81 git branch --column=column >actual &&
|
||||||
|
cat >expected <<\EOF &&
|
||||||
|
a/b/c bam foo l * master n o/p r
|
||||||
|
abc bar j/k m/m master2 o/o q
|
||||||
|
EOF
|
||||||
|
test_cmp expected actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'git branch --column with an extremely long branch name' '
|
||||||
|
long=this/is/a/part/of/long/branch/name &&
|
||||||
|
long=z$long/$long/$long/$long &&
|
||||||
|
test_when_finished "git branch -d $long" &&
|
||||||
|
git branch $long &&
|
||||||
|
COLUMNS=80 git branch --column=column >actual &&
|
||||||
|
cat >expected <<EOF &&
|
||||||
|
a/b/c
|
||||||
|
abc
|
||||||
|
bam
|
||||||
|
bar
|
||||||
|
foo
|
||||||
|
j/k
|
||||||
|
l
|
||||||
|
m/m
|
||||||
|
* master
|
||||||
|
master2
|
||||||
|
n
|
||||||
|
o/o
|
||||||
|
o/p
|
||||||
|
q
|
||||||
|
r
|
||||||
|
$long
|
||||||
|
EOF
|
||||||
|
test_cmp expected actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'git branch with column.*' '
|
||||||
|
git config column.ui column &&
|
||||||
|
git config column.branch "dense" &&
|
||||||
|
COLUMNS=80 git branch >actual &&
|
||||||
|
git config --unset column.branch &&
|
||||||
|
git config --unset column.ui &&
|
||||||
|
cat >expected <<\EOF &&
|
||||||
|
a/b/c bam foo l * master n o/p r
|
||||||
|
abc bar j/k m/m master2 o/o q
|
||||||
|
EOF
|
||||||
|
test_cmp expected actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'git branch --column -v should fail' '
|
||||||
|
test_must_fail git branch --column -v
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'git branch -v with column.ui ignored' '
|
||||||
|
git config column.ui column &&
|
||||||
|
COLUMNS=80 git branch -v | cut -c -10 | sed "s/ *$//" >actual &&
|
||||||
|
git config --unset column.ui &&
|
||||||
|
cat >expected <<\EOF &&
|
||||||
|
a/b/c
|
||||||
|
abc
|
||||||
|
bam
|
||||||
|
bar
|
||||||
|
foo
|
||||||
|
j/k
|
||||||
|
l
|
||||||
|
m/m
|
||||||
|
* master
|
||||||
|
master2
|
||||||
|
n
|
||||||
|
o/o
|
||||||
|
o/p
|
||||||
|
q
|
||||||
|
r
|
||||||
|
EOF
|
||||||
|
test_cmp expected actual
|
||||||
|
'
|
||||||
|
|
||||||
mv .git/config .git/config-saved
|
mv .git/config .git/config-saved
|
||||||
|
|
||||||
test_expect_success 'git branch -m q q2 without config should succeed' '
|
test_expect_success 'git branch -m q q2 without config should succeed' '
|
||||||
|
|
|
@ -263,6 +263,50 @@ test_expect_success 'tag -l can accept multiple patterns' '
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'listing tags in column' '
|
||||||
|
COLUMNS=40 git tag -l --column=row >actual &&
|
||||||
|
cat >expected <<\EOF &&
|
||||||
|
a1 aa1 cba t210 t211
|
||||||
|
v0.2.1 v1.0 v1.0.1 v1.1.3
|
||||||
|
EOF
|
||||||
|
test_cmp expected actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'listing tags in column with column.*' '
|
||||||
|
git config column.tag row &&
|
||||||
|
git config column.ui dense &&
|
||||||
|
COLUMNS=40 git tag -l >actual &&
|
||||||
|
git config --unset column.ui &&
|
||||||
|
git config --unset column.tag &&
|
||||||
|
cat >expected <<\EOF &&
|
||||||
|
a1 aa1 cba t210 t211
|
||||||
|
v0.2.1 v1.0 v1.0.1 v1.1.3
|
||||||
|
EOF
|
||||||
|
test_cmp expected actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'listing tag with -n --column should fail' '
|
||||||
|
test_must_fail git tag --column -n
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'listing tags -n in column with column.ui ignored' '
|
||||||
|
git config column.ui "row dense" &&
|
||||||
|
COLUMNS=40 git tag -l -n >actual &&
|
||||||
|
git config --unset column.ui &&
|
||||||
|
cat >expected <<\EOF &&
|
||||||
|
a1 Foo
|
||||||
|
aa1 Foo
|
||||||
|
cba Foo
|
||||||
|
t210 Foo
|
||||||
|
t211 Foo
|
||||||
|
v0.2.1 Foo
|
||||||
|
v1.0 Foo
|
||||||
|
v1.0.1 Foo
|
||||||
|
v1.1.3 Foo
|
||||||
|
EOF
|
||||||
|
test_cmp expected actual
|
||||||
|
'
|
||||||
|
|
||||||
# creating and verifying lightweight tags:
|
# creating and verifying lightweight tags:
|
||||||
|
|
||||||
test_expect_success \
|
test_expect_success \
|
||||||
|
|
|
@ -59,6 +59,30 @@ test_expect_success 'status (1)' '
|
||||||
test_i18ngrep "use \"git rm --cached <file>\.\.\.\" to unstage" output
|
test_i18ngrep "use \"git rm --cached <file>\.\.\.\" to unstage" output
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'status --column' '
|
||||||
|
COLUMNS=50 git status --column="column dense" >output &&
|
||||||
|
cat >expect <<\EOF &&
|
||||||
|
# On branch master
|
||||||
|
# Changes to be committed:
|
||||||
|
# (use "git reset HEAD <file>..." to unstage)
|
||||||
|
#
|
||||||
|
# new file: dir2/added
|
||||||
|
#
|
||||||
|
# Changes not staged for commit:
|
||||||
|
# (use "git add <file>..." to update what will be committed)
|
||||||
|
# (use "git checkout -- <file>..." to discard changes in working directory)
|
||||||
|
#
|
||||||
|
# modified: dir1/modified
|
||||||
|
#
|
||||||
|
# Untracked files:
|
||||||
|
# (use "git add <file>..." to include in what will be committed)
|
||||||
|
#
|
||||||
|
# dir1/untracked dir2/untracked untracked
|
||||||
|
# dir2/modified output
|
||||||
|
EOF
|
||||||
|
test_cmp expect output
|
||||||
|
'
|
||||||
|
|
||||||
cat >expect <<\EOF
|
cat >expect <<\EOF
|
||||||
# On branch master
|
# On branch master
|
||||||
# Changes to be committed:
|
# Changes to be committed:
|
||||||
|
|
|
@ -0,0 +1,180 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
test_description='git column'
|
||||||
|
. ./test-lib.sh
|
||||||
|
|
||||||
|
test_expect_success 'setup' '
|
||||||
|
cat >lista <<\EOF
|
||||||
|
one
|
||||||
|
two
|
||||||
|
three
|
||||||
|
four
|
||||||
|
five
|
||||||
|
six
|
||||||
|
seven
|
||||||
|
eight
|
||||||
|
nine
|
||||||
|
ten
|
||||||
|
eleven
|
||||||
|
EOF
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'never' '
|
||||||
|
git column --indent=Z --mode=never <lista >actual &&
|
||||||
|
test_cmp lista actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'always' '
|
||||||
|
cat >expected <<\EOF &&
|
||||||
|
Zone
|
||||||
|
Ztwo
|
||||||
|
Zthree
|
||||||
|
Zfour
|
||||||
|
Zfive
|
||||||
|
Zsix
|
||||||
|
Zseven
|
||||||
|
Zeight
|
||||||
|
Znine
|
||||||
|
Zten
|
||||||
|
Zeleven
|
||||||
|
EOF
|
||||||
|
git column --indent=Z --mode=plain <lista >actual &&
|
||||||
|
test_cmp expected actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success '80 columns' '
|
||||||
|
cat >expected <<\EOF &&
|
||||||
|
one two three four five six seven eight nine ten eleven
|
||||||
|
EOF
|
||||||
|
COLUMNS=80 git column --mode=column <lista >actual &&
|
||||||
|
test_cmp expected actual
|
||||||
|
'
|
||||||
|
|
||||||
|
cat >expected <<\EOF
|
||||||
|
one
|
||||||
|
two
|
||||||
|
three
|
||||||
|
four
|
||||||
|
five
|
||||||
|
six
|
||||||
|
seven
|
||||||
|
eight
|
||||||
|
nine
|
||||||
|
ten
|
||||||
|
eleven
|
||||||
|
EOF
|
||||||
|
|
||||||
|
test_expect_success COLUMNS_CAN_BE_1 'COLUMNS = 1' '
|
||||||
|
COLUMNS=1 git column --mode=column <lista >actual &&
|
||||||
|
test_cmp expected actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'width = 1' '
|
||||||
|
git column --mode=column --width=1 <lista >actual &&
|
||||||
|
test_cmp expected actual
|
||||||
|
'
|
||||||
|
|
||||||
|
COLUMNS=20
|
||||||
|
export COLUMNS
|
||||||
|
|
||||||
|
test_expect_success '20 columns' '
|
||||||
|
cat >expected <<\EOF &&
|
||||||
|
one seven
|
||||||
|
two eight
|
||||||
|
three nine
|
||||||
|
four ten
|
||||||
|
five eleven
|
||||||
|
six
|
||||||
|
EOF
|
||||||
|
git column --mode=column <lista >actual &&
|
||||||
|
test_cmp expected actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success '20 columns, nodense' '
|
||||||
|
cat >expected <<\EOF &&
|
||||||
|
one seven
|
||||||
|
two eight
|
||||||
|
three nine
|
||||||
|
four ten
|
||||||
|
five eleven
|
||||||
|
six
|
||||||
|
EOF
|
||||||
|
git column --mode=column,nodense < lista > actual &&
|
||||||
|
test_cmp expected actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success '20 columns, dense' '
|
||||||
|
cat >expected <<\EOF &&
|
||||||
|
one five nine
|
||||||
|
two six ten
|
||||||
|
three seven eleven
|
||||||
|
four eight
|
||||||
|
EOF
|
||||||
|
git column --mode=column,dense < lista > actual &&
|
||||||
|
test_cmp expected actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success '20 columns, padding 2' '
|
||||||
|
cat >expected <<\EOF &&
|
||||||
|
one seven
|
||||||
|
two eight
|
||||||
|
three nine
|
||||||
|
four ten
|
||||||
|
five eleven
|
||||||
|
six
|
||||||
|
EOF
|
||||||
|
git column --mode=column --padding 2 <lista >actual &&
|
||||||
|
test_cmp expected actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success '20 columns, indented' '
|
||||||
|
cat >expected <<\EOF &&
|
||||||
|
one seven
|
||||||
|
two eight
|
||||||
|
three nine
|
||||||
|
four ten
|
||||||
|
five eleven
|
||||||
|
six
|
||||||
|
EOF
|
||||||
|
git column --mode=column --indent=" " <lista >actual &&
|
||||||
|
test_cmp expected actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success '20 columns, row first' '
|
||||||
|
cat >expected <<\EOF &&
|
||||||
|
one two
|
||||||
|
three four
|
||||||
|
five six
|
||||||
|
seven eight
|
||||||
|
nine ten
|
||||||
|
eleven
|
||||||
|
EOF
|
||||||
|
git column --mode=row <lista >actual &&
|
||||||
|
test_cmp expected actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success '20 columns, row first, nodense' '
|
||||||
|
cat >expected <<\EOF &&
|
||||||
|
one two
|
||||||
|
three four
|
||||||
|
five six
|
||||||
|
seven eight
|
||||||
|
nine ten
|
||||||
|
eleven
|
||||||
|
EOF
|
||||||
|
git column --mode=row,nodense <lista >actual &&
|
||||||
|
test_cmp expected actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success '20 columns, row first, dense' '
|
||||||
|
cat >expected <<\EOF &&
|
||||||
|
one two three
|
||||||
|
four five six
|
||||||
|
seven eight nine
|
||||||
|
ten eleven
|
||||||
|
EOF
|
||||||
|
git column --mode=row,dense <lista >actual &&
|
||||||
|
test_cmp expected actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_done
|
28
wt-status.c
28
wt-status.c
|
@ -11,6 +11,7 @@
|
||||||
#include "remote.h"
|
#include "remote.h"
|
||||||
#include "refs.h"
|
#include "refs.h"
|
||||||
#include "submodule.h"
|
#include "submodule.h"
|
||||||
|
#include "column.h"
|
||||||
|
|
||||||
static char default_wt_status_colors[][COLOR_MAXLEN] = {
|
static char default_wt_status_colors[][COLOR_MAXLEN] = {
|
||||||
GIT_COLOR_NORMAL, /* WT_STATUS_HEADER */
|
GIT_COLOR_NORMAL, /* WT_STATUS_HEADER */
|
||||||
|
@ -641,6 +642,8 @@ static void wt_status_print_other(struct wt_status *s,
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct strbuf buf = STRBUF_INIT;
|
struct strbuf buf = STRBUF_INIT;
|
||||||
|
static struct string_list output = STRING_LIST_INIT_DUP;
|
||||||
|
struct column_options copts;
|
||||||
|
|
||||||
if (!l->nr)
|
if (!l->nr)
|
||||||
return;
|
return;
|
||||||
|
@ -649,12 +652,33 @@ static void wt_status_print_other(struct wt_status *s,
|
||||||
|
|
||||||
for (i = 0; i < l->nr; i++) {
|
for (i = 0; i < l->nr; i++) {
|
||||||
struct string_list_item *it;
|
struct string_list_item *it;
|
||||||
|
const char *path;
|
||||||
it = &(l->items[i]);
|
it = &(l->items[i]);
|
||||||
|
path = quote_path(it->string, strlen(it->string),
|
||||||
|
&buf, s->prefix);
|
||||||
|
if (column_active(s->colopts)) {
|
||||||
|
string_list_append(&output, path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
status_printf(s, color(WT_STATUS_HEADER, s), "\t");
|
status_printf(s, color(WT_STATUS_HEADER, s), "\t");
|
||||||
status_printf_more(s, color(WT_STATUS_UNTRACKED, s),
|
status_printf_more(s, color(WT_STATUS_UNTRACKED, s),
|
||||||
"%s\n", quote_path(it->string, strlen(it->string),
|
"%s\n", path);
|
||||||
&buf, s->prefix));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
strbuf_release(&buf);
|
||||||
|
if (!column_active(s->colopts))
|
||||||
|
return;
|
||||||
|
|
||||||
|
strbuf_addf(&buf, "%s#\t%s",
|
||||||
|
color(WT_STATUS_HEADER, s),
|
||||||
|
color(WT_STATUS_UNTRACKED, s));
|
||||||
|
memset(&copts, 0, sizeof(copts));
|
||||||
|
copts.padding = 1;
|
||||||
|
copts.indent = buf.buf;
|
||||||
|
if (want_color(s->use_color))
|
||||||
|
copts.nl = GIT_COLOR_RESET "\n";
|
||||||
|
print_columns(&output, s->colopts, &copts);
|
||||||
|
string_list_clear(&output, 0);
|
||||||
strbuf_release(&buf);
|
strbuf_release(&buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,7 @@ struct wt_status {
|
||||||
enum untracked_status_type show_untracked_files;
|
enum untracked_status_type show_untracked_files;
|
||||||
const char *ignore_submodule_arg;
|
const char *ignore_submodule_arg;
|
||||||
char color_palette[WT_STATUS_MAXSLOT][COLOR_MAXLEN];
|
char color_palette[WT_STATUS_MAXSLOT][COLOR_MAXLEN];
|
||||||
|
int colopts;
|
||||||
|
|
||||||
/* These are computed during processing of the individual sections */
|
/* These are computed during processing of the individual sections */
|
||||||
int commitable;
|
int commitable;
|
||||||
|
|
Loading…
Reference in New Issue