22#include "column.h"
33#include "string-list.h"
44#include "parse-options.h"
5+ #include "utf8.h"
6+
7+ #define XY2LINEAR (d , x , y ) (COL_LAYOUT((d)->colopts) == COL_COLUMN ? \
8+ (x) * (d)->rows + (y) : \
9+ (y) * (d)->cols + (x))
10+
11+ struct column_data {
12+ const struct string_list * list ;
13+ unsigned int colopts ;
14+ struct column_options opts ;
15+
16+ int rows , cols ;
17+ int * len ; /* cell length */
18+ };
19+
20+ /* return length of 's' in letters, ANSI escapes stripped */
21+ static int item_length (unsigned int colopts , const char * s )
22+ {
23+ int len , i = 0 ;
24+ struct strbuf str = STRBUF_INIT ;
25+
26+ strbuf_addstr (& str , s );
27+ while ((s = strstr (str .buf + i , "\033[" )) != NULL ) {
28+ int len = strspn (s + 2 , "0123456789;" );
29+ i = s - str .buf ;
30+ strbuf_remove (& str , i , len + 3 ); /* \033[<len><func char> */
31+ }
32+ len = utf8_strwidth (str .buf );
33+ strbuf_release (& str );
34+ return len ;
35+ }
36+
37+ /*
38+ * Calculate cell width, rows and cols for a table of equal cells, given
39+ * table width and how many spaces between cells.
40+ */
41+ static void layout (struct column_data * data , int * width )
42+ {
43+ int i ;
44+
45+ * width = 0 ;
46+ for (i = 0 ; i < data -> list -> nr ; i ++ )
47+ if (* width < data -> len [i ])
48+ * width = data -> len [i ];
49+
50+ * width += data -> opts .padding ;
51+
52+ data -> cols = (data -> opts .width - strlen (data -> opts .indent )) / * width ;
53+ if (data -> cols == 0 )
54+ data -> cols = 1 ;
55+
56+ data -> rows = DIV_ROUND_UP (data -> list -> nr , data -> cols );
57+ }
558
659/* Display without layout when not enabled */
760static void display_plain (const struct string_list * list ,
@@ -13,6 +66,61 @@ static void display_plain(const struct string_list *list,
1366 printf ("%s%s%s" , indent , list -> items [i ].string , nl );
1467}
1568
69+ /* Print a cell to stdout with all necessary leading/traling space */
70+ static int display_cell (struct column_data * data , int initial_width ,
71+ const char * empty_cell , int x , int y )
72+ {
73+ int i , len , newline ;
74+
75+ i = XY2LINEAR (data , x , y );
76+ if (i >= data -> list -> nr )
77+ return -1 ;
78+ len = data -> len [i ];
79+ if (COL_LAYOUT (data -> colopts ) == COL_COLUMN )
80+ newline = i + data -> rows >= data -> list -> nr ;
81+ else
82+ newline = x == data -> cols - 1 || i == data -> list -> nr - 1 ;
83+
84+ printf ("%s%s%s" ,
85+ x == 0 ? data -> opts .indent : "" ,
86+ data -> list -> items [i ].string ,
87+ newline ? data -> opts .nl : empty_cell + len );
88+ return 0 ;
89+ }
90+
91+ /* Display COL_COLUMN or COL_ROW */
92+ static void display_table (const struct string_list * list ,
93+ unsigned int colopts ,
94+ const struct column_options * opts )
95+ {
96+ struct column_data data ;
97+ int x , y , i , initial_width ;
98+ char * empty_cell ;
99+
100+ memset (& data , 0 , sizeof (data ));
101+ data .list = list ;
102+ data .colopts = colopts ;
103+ data .opts = * opts ;
104+
105+ data .len = xmalloc (sizeof (* data .len ) * list -> nr );
106+ for (i = 0 ; i < list -> nr ; i ++ )
107+ data .len [i ] = item_length (colopts , list -> items [i ].string );
108+
109+ layout (& data , & initial_width );
110+
111+ empty_cell = xmalloc (initial_width + 1 );
112+ memset (empty_cell , ' ' , initial_width );
113+ empty_cell [initial_width ] = '\0' ;
114+ for (y = 0 ; y < data .rows ; y ++ ) {
115+ for (x = 0 ; x < data .cols ; x ++ )
116+ if (display_cell (& data , initial_width , empty_cell , x , y ))
117+ break ;
118+ }
119+
120+ free (data .len );
121+ free (empty_cell );
122+ }
123+
16124void print_columns (const struct string_list * list , unsigned int colopts ,
17125 const struct column_options * opts )
18126{
@@ -35,6 +143,10 @@ void print_columns(const struct string_list *list, unsigned int colopts,
35143 case COL_PLAIN :
36144 display_plain (list , nopts .indent , nopts .nl );
37145 break ;
146+ case COL_ROW :
147+ case COL_COLUMN :
148+ display_table (list , colopts , & nopts );
149+ break ;
38150 default :
39151 die ("BUG: invalid layout mode %d" , COL_LAYOUT (colopts ));
40152 }
@@ -69,6 +181,8 @@ static int parse_option(const char *arg, int len, unsigned int *colopts,
69181 { "never" , COL_DISABLED , COL_ENABLE_MASK },
70182 { "auto" , COL_AUTO , COL_ENABLE_MASK },
71183 { "plain" , COL_PLAIN , COL_LAYOUT_MASK },
184+ { "column" , COL_COLUMN , COL_LAYOUT_MASK },
185+ { "row" , COL_ROW , COL_LAYOUT_MASK },
72186 };
73187 int i ;
74188
0 commit comments