Merge pull request #15727 from poettering/systemctl-list-sockets-tweak
systemctl: some table output tweaks
This commit is contained in:
@@ -28,6 +28,7 @@
|
||||
#define ANSI_HIGHLIGHT_YELLOW4 "\x1B[0;1;38;5;100m"
|
||||
|
||||
/* Underlined */
|
||||
#define ANSI_GREY_UNDERLINE "\x1B[0;4;38;5;245m"
|
||||
#define ANSI_HIGHLIGHT_RED_UNDERLINE "\x1B[0;1;4;31m"
|
||||
#define ANSI_HIGHLIGHT_GREEN_UNDERLINE "\x1B[0;1;4;32m"
|
||||
#define ANSI_HIGHLIGHT_YELLOW_UNDERLINE "\x1B[0;1;4;38;5;185m"
|
||||
@@ -138,6 +139,7 @@ DEFINE_ANSI_FUNC(highlight_grey, HIGHLIGHT_GREY);
|
||||
|
||||
DEFINE_ANSI_FUNC_UNDERLINE(underline, UNDERLINE, NORMAL);
|
||||
DEFINE_ANSI_FUNC_UNDERLINE(highlight_underline, HIGHLIGHT_UNDERLINE, HIGHLIGHT);
|
||||
DEFINE_ANSI_FUNC_UNDERLINE(grey_underline, GREY_UNDERLINE, GREY);
|
||||
DEFINE_ANSI_FUNC_UNDERLINE(highlight_red_underline, HIGHLIGHT_RED_UNDERLINE, HIGHLIGHT_RED);
|
||||
DEFINE_ANSI_FUNC_UNDERLINE(highlight_green_underline, HIGHLIGHT_GREEN_UNDERLINE, HIGHLIGHT_GREEN);
|
||||
DEFINE_ANSI_FUNC_UNDERLINE(highlight_yellow_underline, HIGHLIGHT_YELLOW_UNDERLINE, HIGHLIGHT_YELLOW);
|
||||
|
||||
+85
-10
@@ -73,6 +73,7 @@ typedef struct TableData {
|
||||
bool uppercase; /* Uppercase string on display */
|
||||
|
||||
const char *color; /* ANSI color string to use for this cell. When written to terminal should not move cursor. Will automatically be reset after the cell */
|
||||
const char *rgap_color; /* The ANSI color to use for the gap right of this cell. Usually used to underline entire rows in a gapless fashion */
|
||||
char *url; /* A URL to use for a clickable hyperlink */
|
||||
char *formatted; /* A cached textual representation of the cell data, before ellipsation/alignment */
|
||||
|
||||
@@ -334,7 +335,7 @@ static bool table_data_matches(
|
||||
return false;
|
||||
|
||||
/* If a color/url/uppercase flag is set, refuse to merge */
|
||||
if (d->color)
|
||||
if (d->color || d->rgap_color)
|
||||
return false;
|
||||
if (d->url)
|
||||
return false;
|
||||
@@ -542,6 +543,7 @@ static int table_dedup_cell(Table *t, TableCell *cell) {
|
||||
return -ENOMEM;
|
||||
|
||||
nd->color = od->color;
|
||||
nd->rgap_color = od->rgap_color;
|
||||
nd->url = TAKE_PTR(curl);
|
||||
nd->uppercase = od->uppercase;
|
||||
|
||||
@@ -671,6 +673,20 @@ int table_set_color(Table *t, TableCell *cell, const char *color) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int table_set_rgap_color(Table *t, TableCell *cell, const char *color) {
|
||||
int r;
|
||||
|
||||
assert(t);
|
||||
assert(cell);
|
||||
|
||||
r = table_dedup_cell(t, cell);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
table_get_data(t, cell)->rgap_color = empty_to_null(color);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int table_set_url(Table *t, TableCell *cell, const char *url) {
|
||||
_cleanup_free_ char *copy = NULL;
|
||||
int r;
|
||||
@@ -744,6 +760,7 @@ int table_update(Table *t, TableCell *cell, TableDataType type, const void *data
|
||||
return -ENOMEM;
|
||||
|
||||
nd->color = od->color;
|
||||
nd->rgap_color = od->rgap_color;
|
||||
nd->url = TAKE_PTR(curl);
|
||||
nd->uppercase = od->uppercase;
|
||||
|
||||
@@ -952,6 +969,25 @@ int table_add_many_internal(Table *t, TableDataType first_type, ...) {
|
||||
break;
|
||||
}
|
||||
|
||||
case TABLE_SET_RGAP_COLOR: {
|
||||
const char *c = va_arg(ap, const char*);
|
||||
r = table_set_rgap_color(t, last_cell, c);
|
||||
break;
|
||||
}
|
||||
|
||||
case TABLE_SET_BOTH_COLORS: {
|
||||
const char *c = va_arg(ap, const char*);
|
||||
|
||||
r = table_set_color(t, last_cell, c);
|
||||
if (r < 0) {
|
||||
va_end(ap);
|
||||
return r;
|
||||
}
|
||||
|
||||
r = table_set_rgap_color(t, last_cell, c);
|
||||
break;
|
||||
}
|
||||
|
||||
case TABLE_SET_URL: {
|
||||
const char *u = va_arg(ap, const char*);
|
||||
r = table_set_url(t, last_cell, u);
|
||||
@@ -1272,6 +1308,9 @@ static const char *table_data_format(Table *t, TableData *d, bool avoid_uppercas
|
||||
case TABLE_STRV: {
|
||||
char *p;
|
||||
|
||||
if (strv_isempty(d->strv))
|
||||
return strempty(t->empty_string);
|
||||
|
||||
p = strv_join(d->strv, "\n");
|
||||
if (!p)
|
||||
return NULL;
|
||||
@@ -1694,6 +1733,20 @@ static char *align_string_mem(const char *str, const char *url, size_t new_lengt
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool table_data_isempty(TableData *d) {
|
||||
assert(d);
|
||||
|
||||
if (d->type == TABLE_EMPTY)
|
||||
return true;
|
||||
|
||||
/* Let's also consider an empty strv as truly empty. */
|
||||
if (d->type == TABLE_STRV)
|
||||
return strv_isempty(d->strv);
|
||||
|
||||
/* Note that an empty string we do not consider empty here! */
|
||||
return false;
|
||||
}
|
||||
|
||||
static const char* table_data_color(TableData *d) {
|
||||
assert(d);
|
||||
|
||||
@@ -1701,12 +1754,21 @@ static const char* table_data_color(TableData *d) {
|
||||
return d->color;
|
||||
|
||||
/* Let's implicitly color all "empty" cells in grey, in case an "empty_string" is set that is not empty */
|
||||
if (d->type == TABLE_EMPTY)
|
||||
if (table_data_isempty(d))
|
||||
return ansi_grey();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char* table_data_rgap_color(TableData *d) {
|
||||
assert(d);
|
||||
|
||||
if (d->rgap_color)
|
||||
return d->rgap_color;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int table_print(Table *t, FILE *f) {
|
||||
size_t n_rows, *minimum_width, *maximum_width, display_columns, *requested_width,
|
||||
i, j, table_minimum_width, table_maximum_width, table_requested_width, table_effective_width,
|
||||
@@ -1958,12 +2020,13 @@ int table_print(Table *t, FILE *f) {
|
||||
row = t->data + i * t->n_columns;
|
||||
|
||||
do {
|
||||
const char *gap_color = NULL;
|
||||
more_sublines = false;
|
||||
|
||||
for (j = 0; j < display_columns; j++) {
|
||||
_cleanup_free_ char *buffer = NULL, *extracted = NULL;
|
||||
bool lines_truncated = false;
|
||||
const char *field;
|
||||
const char *field, *color = NULL;
|
||||
TableData *d;
|
||||
size_t l;
|
||||
|
||||
@@ -2042,23 +2105,35 @@ int table_print(Table *t, FILE *f) {
|
||||
field = buffer;
|
||||
}
|
||||
|
||||
if (row == t->data) /* underline header line fully, including the column separator */
|
||||
fputs(ansi_underline(), f);
|
||||
if (colors_enabled()) {
|
||||
if (gap_color)
|
||||
fputs(gap_color, f);
|
||||
else if (row == t->data) /* underline header line fully, including the column separator */
|
||||
fputs(ansi_underline(), f);
|
||||
}
|
||||
|
||||
if (j > 0)
|
||||
fputc(' ', f); /* column separator */
|
||||
fputc(' ', f); /* column separator left of cell */
|
||||
|
||||
if (table_data_color(d) && colors_enabled()) {
|
||||
if (row == t->data) /* first undo header underliner */
|
||||
if (colors_enabled()) {
|
||||
color = table_data_color(d);
|
||||
|
||||
/* Undo gap color */
|
||||
if (gap_color || (color && row == t->data))
|
||||
fputs(ANSI_NORMAL, f);
|
||||
|
||||
fputs(table_data_color(d), f);
|
||||
if (color)
|
||||
fputs(color, f);
|
||||
else if (gap_color && row == t->data) /* underline header line cell */
|
||||
fputs(ansi_underline(), f);
|
||||
}
|
||||
|
||||
fputs(field, f);
|
||||
|
||||
if (colors_enabled() && (table_data_color(d) || row == t->data))
|
||||
if (colors_enabled() && (color || row == t->data))
|
||||
fputs(ANSI_NORMAL, f);
|
||||
|
||||
gap_color = table_data_rgap_color(d);
|
||||
}
|
||||
|
||||
fputc('\n', f);
|
||||
|
||||
@@ -47,6 +47,8 @@ typedef enum TableDataType {
|
||||
TABLE_SET_ALIGN_PERCENT,
|
||||
TABLE_SET_ELLIPSIZE_PERCENT,
|
||||
TABLE_SET_COLOR,
|
||||
TABLE_SET_RGAP_COLOR,
|
||||
TABLE_SET_BOTH_COLORS,
|
||||
TABLE_SET_URL,
|
||||
TABLE_SET_UPPERCASE,
|
||||
|
||||
@@ -89,6 +91,7 @@ int table_set_weight(Table *t, TableCell *cell, unsigned weight);
|
||||
int table_set_align_percent(Table *t, TableCell *cell, unsigned percent);
|
||||
int table_set_ellipsize_percent(Table *t, TableCell *cell, unsigned percent);
|
||||
int table_set_color(Table *t, TableCell *cell, const char *color);
|
||||
int table_set_rgap_color(Table *t, TableCell *cell, const char *color);
|
||||
int table_set_url(Table *t, TableCell *cell, const char *url);
|
||||
int table_set_uppercase(Table *t, TableCell *cell, bool b);
|
||||
|
||||
|
||||
+44
-23
@@ -425,6 +425,8 @@ static int output_units_list(const UnitInfo *unit_infos, unsigned c) {
|
||||
if (arg_full)
|
||||
table_set_width(table, 0);
|
||||
|
||||
(void) table_set_empty_string(table, "-");
|
||||
|
||||
for (u = unit_infos; unit_infos && u < unit_infos + c; u++) {
|
||||
_cleanup_free_ char *j = NULL;
|
||||
const char *on_underline = "", *on_loaded = "", *on_active = "";
|
||||
@@ -438,14 +440,15 @@ static int output_units_list(const UnitInfo *unit_infos, unsigned c) {
|
||||
}
|
||||
|
||||
if (STR_IN_SET(u->load_state, "error", "not-found", "bad-setting", "masked") && !arg_plain) {
|
||||
on_circle = ansi_highlight_yellow();
|
||||
on_circle = underline ? ansi_highlight_yellow_underline() : ansi_highlight_yellow();
|
||||
circle = true;
|
||||
on_loaded = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
|
||||
} else if (streq(u->active_state, "failed") && !arg_plain) {
|
||||
on_circle = ansi_highlight_red();
|
||||
on_circle = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
|
||||
circle = true;
|
||||
on_active = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
|
||||
} else {
|
||||
on_circle = on_underline;
|
||||
on_active = on_underline;
|
||||
on_loaded = on_underline;
|
||||
}
|
||||
@@ -461,19 +464,19 @@ static int output_units_list(const UnitInfo *unit_infos, unsigned c) {
|
||||
|
||||
r = table_add_many(table,
|
||||
TABLE_STRING, circle ? special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE) : " ",
|
||||
TABLE_SET_COLOR, on_circle,
|
||||
TABLE_SET_BOTH_COLORS, on_circle,
|
||||
TABLE_STRING, id,
|
||||
TABLE_SET_COLOR, on_active,
|
||||
TABLE_SET_BOTH_COLORS, on_active,
|
||||
TABLE_STRING, u->load_state,
|
||||
TABLE_SET_COLOR, on_loaded,
|
||||
TABLE_SET_BOTH_COLORS, on_loaded,
|
||||
TABLE_STRING, u->active_state,
|
||||
TABLE_SET_COLOR, on_active,
|
||||
TABLE_SET_BOTH_COLORS, on_active,
|
||||
TABLE_STRING, u->sub_state,
|
||||
TABLE_SET_COLOR, on_active,
|
||||
TABLE_SET_BOTH_COLORS, on_active,
|
||||
TABLE_STRING, u->job_id ? u->job_type: "",
|
||||
TABLE_SET_COLOR, u->job_id ? on_underline : "",
|
||||
TABLE_SET_BOTH_COLORS, u->job_id ? on_underline : "",
|
||||
TABLE_STRING, u->description,
|
||||
TABLE_SET_COLOR, on_underline);
|
||||
TABLE_SET_BOTH_COLORS, on_underline);
|
||||
if (r < 0)
|
||||
return table_log_add_error(r);
|
||||
|
||||
@@ -1006,7 +1009,7 @@ static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
|
||||
const char *on, *off;
|
||||
int r;
|
||||
|
||||
table = table_new("listen", "type", "units", "activates");
|
||||
table = table_new("listen", "type", "unit", "activates");
|
||||
if (!table)
|
||||
return log_oom();
|
||||
|
||||
@@ -1021,9 +1024,11 @@ static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
|
||||
if (arg_full)
|
||||
table_set_width(table, 0);
|
||||
|
||||
(void) table_set_empty_string(table, "-");
|
||||
|
||||
if (cs) {
|
||||
for (s = socket_infos; s < socket_infos + cs; s++) {
|
||||
_cleanup_free_ char *j = NULL, *activates = NULL;
|
||||
_cleanup_free_ char *j = NULL;
|
||||
const char *path;
|
||||
|
||||
if (s->machine) {
|
||||
@@ -1034,17 +1039,25 @@ static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
|
||||
} else
|
||||
path = s->path;
|
||||
|
||||
activates = strv_join(s->triggered, ", ");
|
||||
if (!activates)
|
||||
return log_oom();
|
||||
|
||||
r = table_add_many(table,
|
||||
TABLE_STRING, path,
|
||||
TABLE_STRING, s->type,
|
||||
TABLE_STRING, s->id,
|
||||
TABLE_STRING, activates);
|
||||
TABLE_STRING, s->id);
|
||||
if (r < 0)
|
||||
return table_log_add_error(r);
|
||||
|
||||
if (strv_isempty(s->triggered))
|
||||
r = table_add_cell(table, NULL, TABLE_EMPTY, NULL);
|
||||
else if (strv_length(s->triggered) == 1)
|
||||
r = table_add_cell(table, NULL, TABLE_STRING, s->triggered[0]);
|
||||
else
|
||||
/* This should never happen, currently our socket units can only trigger a
|
||||
* single unit. But let's handle this anyway, who knows what the future
|
||||
* brings? */
|
||||
r = table_add_cell(table, NULL, TABLE_STRV, s->triggered);
|
||||
if (r < 0)
|
||||
return table_log_add_error(r);
|
||||
|
||||
}
|
||||
|
||||
on = ansi_highlight();
|
||||
@@ -1265,6 +1278,8 @@ static int output_timers_list(struct timer_info *timer_infos, unsigned n) {
|
||||
if (arg_full)
|
||||
table_set_width(table, 0);
|
||||
|
||||
(void) table_set_empty_string(table, "-");
|
||||
|
||||
if (n > 0) {
|
||||
for (t = timer_infos; t < timer_infos + n; t++) {
|
||||
_cleanup_free_ char *j = NULL, *activates = NULL;
|
||||
@@ -1478,6 +1493,8 @@ static int output_unit_file_list(const UnitFileList *units, unsigned c) {
|
||||
if (arg_full)
|
||||
table_set_width(table, 0);
|
||||
|
||||
(void) table_set_empty_string(table, "-");
|
||||
|
||||
for (const UnitFileList *u = units; u < units + c; u++) {
|
||||
const char *on_underline = NULL, *on_unit_color = NULL, *id;
|
||||
bool underline;
|
||||
@@ -1505,9 +1522,9 @@ static int output_unit_file_list(const UnitFileList *units, unsigned c) {
|
||||
|
||||
r = table_add_many(table,
|
||||
TABLE_STRING, id,
|
||||
TABLE_SET_COLOR, strempty(on_underline),
|
||||
TABLE_SET_BOTH_COLORS, strempty(on_underline),
|
||||
TABLE_STRING, unit_file_state_to_string(u->state),
|
||||
TABLE_SET_COLOR, strempty(on_unit_color));
|
||||
TABLE_SET_BOTH_COLORS, strempty(on_unit_color));
|
||||
if (r < 0)
|
||||
return table_log_add_error(r);
|
||||
|
||||
@@ -1528,10 +1545,11 @@ static int output_unit_file_list(const UnitFileList *units, unsigned c) {
|
||||
|
||||
r = table_add_many(table,
|
||||
TABLE_STRING, unit_preset_str,
|
||||
TABLE_SET_COLOR, strempty(on_preset_color));
|
||||
TABLE_SET_BOTH_COLORS, strempty(on_preset_color));
|
||||
} else
|
||||
r = table_add_many(table, TABLE_EMPTY);
|
||||
|
||||
r = table_add_many(table,
|
||||
TABLE_EMPTY,
|
||||
TABLE_SET_BOTH_COLORS, underline ? ansi_grey_underline() : ansi_grey());
|
||||
if (r < 0)
|
||||
return table_log_add_error(r);
|
||||
}
|
||||
@@ -2031,6 +2049,8 @@ static int output_machines_list(struct machine_info *machine_infos, unsigned n)
|
||||
if (arg_full)
|
||||
table_set_width(table, 0);
|
||||
|
||||
(void) table_set_empty_string(table, "-");
|
||||
|
||||
for (m = machine_infos; m < machine_infos + n; m++) {
|
||||
_cleanup_free_ char *mname = NULL;
|
||||
const char *on_state = "", *on_failed = "";
|
||||
@@ -2351,13 +2371,14 @@ static int output_jobs_list(sd_bus *bus, const struct job_info* jobs, unsigned n
|
||||
if (arg_full)
|
||||
table_set_width(table, 0);
|
||||
|
||||
(void) table_set_empty_string(table, "-");
|
||||
|
||||
for (j = jobs; j < jobs + n; j++) {
|
||||
if (streq(j->state, "running"))
|
||||
on = ansi_highlight();
|
||||
else
|
||||
on = "";
|
||||
|
||||
|
||||
r = table_add_many(table,
|
||||
TABLE_UINT, j->id,
|
||||
TABLE_STRING, j->name,
|
||||
|
||||
Reference in New Issue
Block a user