runtime: format: add truncation and single-line support to value_writer
This commit is contained in:
@@ -125,7 +125,11 @@ static enum bshell_status process_record(
|
|||||||
|
|
||||||
fx_stream *in_stream = fx_process_get_stdin(cmd_p->cmd_proc);
|
fx_stream *in_stream = fx_process_get_stdin(cmd_p->cmd_proc);
|
||||||
if (!cmd_p->cmd_writer_init) {
|
if (!cmd_p->cmd_writer_init) {
|
||||||
bshell_value_writer_init(&cmd_p->cmd_writer, in_stream);
|
bshell_value_writer_init(
|
||||||
|
&cmd_p->cmd_writer,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
in_stream);
|
||||||
cmd_p->cmd_writer_init = true;
|
cmd_p->cmd_writer_init = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ static void format_value_fallback(const fx_value *value, fx_stream *dest)
|
|||||||
enum bshell_status format_value_default(const fx_value *value, fx_stream *dest)
|
enum bshell_status format_value_default(const fx_value *value, fx_stream *dest)
|
||||||
{
|
{
|
||||||
struct bshell_value_writer writer;
|
struct bshell_value_writer writer;
|
||||||
bshell_value_writer_init(&writer, dest);
|
bshell_value_writer_init(&writer, 0, 0, dest);
|
||||||
bshell_value_writer_write(&writer, value);
|
bshell_value_writer_write(&writer, value);
|
||||||
bshell_value_writer_cleanup(&writer);
|
bshell_value_writer_cleanup(&writer);
|
||||||
|
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ enum bshell_status bshell_table_ctx_prepare_columns_from_format(
|
|||||||
|
|
||||||
if (column_defs[i].col_width <= tty_width) {
|
if (column_defs[i].col_width <= tty_width) {
|
||||||
columns[i].col_width = column_defs[i].col_width;
|
columns[i].col_width = column_defs[i].col_width;
|
||||||
tty_width -= columns[i].col_width;
|
tty_width -= (columns[i].col_width + 1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -289,6 +289,10 @@ enum bshell_status bshell_table_ctx_print_headers(struct bshell_table_ctx *ctx)
|
|||||||
fx_stream_write_char(ctx->ctx_out, ' ');
|
fx_stream_write_char(ctx->ctx_out, ' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (i < ctx->ctx_columns_count - 1) {
|
||||||
|
fx_stream_write_char(ctx->ctx_out, ' ');
|
||||||
|
}
|
||||||
|
|
||||||
if (to_write != title_chars_remaining) {
|
if (to_write != title_chars_remaining) {
|
||||||
repeat = true;
|
repeat = true;
|
||||||
}
|
}
|
||||||
@@ -316,6 +320,10 @@ enum bshell_status bshell_table_ctx_print_headers(struct bshell_table_ctx *ctx)
|
|||||||
for (; x < c->col_width; x++) {
|
for (; x < c->col_width; x++) {
|
||||||
fx_stream_write_char(ctx->ctx_out, ' ');
|
fx_stream_write_char(ctx->ctx_out, ' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (i < ctx->ctx_columns_count - 1) {
|
||||||
|
fx_stream_write_char(ctx->ctx_out, ' ');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
reset_tty_colour();
|
reset_tty_colour();
|
||||||
@@ -327,14 +335,22 @@ enum bshell_status bshell_table_ctx_print_record(
|
|||||||
struct bshell_table_ctx *ctx,
|
struct bshell_table_ctx *ctx,
|
||||||
const fx_value *record)
|
const fx_value *record)
|
||||||
{
|
{
|
||||||
fx_stringstream *strm = fx_stringstream_create();
|
struct bshell_value_writer writer;
|
||||||
|
size_t written = 0;
|
||||||
|
|
||||||
for (size_t i = 0; i < ctx->ctx_columns_count; i++) {
|
for (size_t i = 0; i < ctx->ctx_columns_count; i++) {
|
||||||
struct bshell_table_ctx_column *c = &ctx->ctx_columns[i];
|
struct bshell_table_ctx_column *c = &ctx->ctx_columns[i];
|
||||||
if (c->col_width == 0) {
|
if (c->col_width == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
fx_stringstream_reset(strm);
|
bshell_value_writer_init(
|
||||||
|
&writer,
|
||||||
|
BSHELL_VALUE_WRITER_NO_NEWLINE
|
||||||
|
| BSHELL_VALUE_WRITER_ONELINE
|
||||||
|
| BSHELL_VALUE_WRITER_TRUNCATE,
|
||||||
|
c->col_width,
|
||||||
|
ctx->ctx_out);
|
||||||
fx_value column_value = FX_VALUE_EMPTY;
|
fx_value column_value = FX_VALUE_EMPTY;
|
||||||
if (c->col_property) {
|
if (c->col_property) {
|
||||||
fx_status status = fx_property_get_value(
|
fx_status status = fx_property_get_value(
|
||||||
@@ -342,34 +358,23 @@ enum bshell_status bshell_table_ctx_print_record(
|
|||||||
record,
|
record,
|
||||||
&column_value);
|
&column_value);
|
||||||
if (FX_OK(status)) {
|
if (FX_OK(status)) {
|
||||||
fx_value_to_string(&column_value, strm, NULL);
|
written = bshell_value_writer_write(
|
||||||
|
&writer,
|
||||||
|
&column_value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t to_write = fx_stringstream_get_length(strm);
|
for (size_t x = written; x < c->col_width; x++) {
|
||||||
const char *s = fx_stringstream_get_cstr(strm);
|
|
||||||
bool overflow = false;
|
|
||||||
if (to_write > c->col_width) {
|
|
||||||
to_write = c->col_width - 2;
|
|
||||||
overflow = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t x;
|
|
||||||
for (x = 0; x < to_write; x++) {
|
|
||||||
fx_stream_write_char(ctx->ctx_out, s[x]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (overflow) {
|
|
||||||
fx_stream_write_char(ctx->ctx_out, L'…');
|
|
||||||
x++;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (; x < c->col_width; x++) {
|
|
||||||
fx_stream_write_char(ctx->ctx_out, ' ');
|
fx_stream_write_char(ctx->ctx_out, ' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (i < ctx->ctx_columns_count - 1) {
|
||||||
|
fx_stream_write_char(ctx->ctx_out, ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
bshell_value_writer_cleanup(&writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
fx_stream_write_char(ctx->ctx_out, '\n');
|
fx_stream_write_char(ctx->ctx_out, '\n');
|
||||||
fx_stringstream_unref(strm);
|
|
||||||
return BSHELL_SUCCESS;
|
return BSHELL_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,17 +15,22 @@ static void initialise_table(
|
|||||||
w->w_table_initialised = true;
|
w->w_table_initialised = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void write_iterable(struct bshell_value_writer *w, const fx_value *value)
|
static size_t write_iterable(
|
||||||
|
struct bshell_value_writer *w,
|
||||||
|
const fx_value *value)
|
||||||
{
|
{
|
||||||
|
size_t written = 0;
|
||||||
fx_array *array = NULL;
|
fx_array *array = NULL;
|
||||||
fx_value_get_object(value, &array);
|
fx_value_get_object(value, &array);
|
||||||
|
|
||||||
const fx_iterator *it = fx_iterator_begin(array);
|
const fx_iterator *it = fx_iterator_begin(array);
|
||||||
fx_foreach(v, it)
|
fx_foreach(v, it)
|
||||||
{
|
{
|
||||||
bshell_value_writer_write(w, v);
|
written += bshell_value_writer_write(w, v);
|
||||||
}
|
}
|
||||||
fx_iterator_unref(it);
|
fx_iterator_unref(it);
|
||||||
|
|
||||||
|
return written;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool string_has_trailing_newline(const char *s)
|
static bool string_has_trailing_newline(const char *s)
|
||||||
@@ -38,34 +43,105 @@ static bool string_has_trailing_newline(const char *s)
|
|||||||
return s[len - 1] == '\n';
|
return s[len - 1] == '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
static void write_string(struct bshell_value_writer *w, const fx_value *value)
|
static size_t write_control_char(struct bshell_value_writer *w, fx_wchar c)
|
||||||
{
|
{
|
||||||
const char *str = NULL;
|
bool oneline = (w->w_flags & BSHELL_VALUE_WRITER_ONELINE) != 0;
|
||||||
fx_value_get_cstr(value, &str);
|
size_t written = 1;
|
||||||
fx_stream_write_cstr(w->w_dest, str, NULL);
|
|
||||||
|
|
||||||
if (!string_has_trailing_newline(str)) {
|
switch (c) {
|
||||||
|
case '\n':
|
||||||
|
if (oneline) {
|
||||||
|
fx_stream_write_cstr(w->w_dest, "\\n", &written);
|
||||||
|
} else {
|
||||||
fx_stream_write_char(w->w_dest, '\n');
|
fx_stream_write_char(w->w_dest, '\n');
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case '\r':
|
||||||
|
fx_stream_write_cstr(w->w_dest, "\\r", NULL);
|
||||||
|
break;
|
||||||
|
case '\t':
|
||||||
|
fx_stream_write_cstr(w->w_dest, "\\t", NULL);
|
||||||
|
break;
|
||||||
|
case '\b':
|
||||||
|
fx_stream_write_cstr(w->w_dest, "\\b", NULL);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
written = 0;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void write_value(struct bshell_value_writer *w, const fx_value *value)
|
return written;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t write_string(struct bshell_value_writer *w, const fx_value *value)
|
||||||
|
{
|
||||||
|
const char *s = NULL;
|
||||||
|
size_t written = 0;
|
||||||
|
fx_value_get_cstr(value, &s);
|
||||||
|
bool trailing_newline = string_has_trailing_newline(s);
|
||||||
|
bool inhibit_newline
|
||||||
|
= (w->w_flags & BSHELL_VALUE_WRITER_NO_NEWLINE) != 0;
|
||||||
|
bool truncate = (w->w_flags & BSHELL_VALUE_WRITER_TRUNCATE) != 0;
|
||||||
|
|
||||||
|
for (written = 0; *s;) {
|
||||||
|
if (truncate && written == w->w_max_width - 1) {
|
||||||
|
fx_stream_write_char(w->w_dest, L'…');
|
||||||
|
written++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_wchar c = fx_wchar_utf8_codepoint_decode(s);
|
||||||
|
unsigned int stride = fx_wchar_utf8_codepoint_size(c);
|
||||||
|
if (stride == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fx_wchar_is_graph(c)) {
|
||||||
|
written += write_control_char(w, c);
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
|
||||||
|
char cs[5] = {0};
|
||||||
|
fx_wchar_utf8_codepoint_encode(c, cs);
|
||||||
|
|
||||||
|
size_t n = 0;
|
||||||
|
fx_stream_write_cstr(w->w_dest, cs, &n);
|
||||||
|
written += n;
|
||||||
|
|
||||||
|
next:
|
||||||
|
s += stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!trailing_newline && !inhibit_newline) {
|
||||||
|
fx_stream_write_char(w->w_dest, '\n');
|
||||||
|
written++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return written;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t write_value(struct bshell_value_writer *w, const fx_value *value)
|
||||||
{
|
{
|
||||||
const fx_type *ty = fx_type_get_by_id(value->v_type);
|
const fx_type *ty = fx_type_get_by_id(value->v_type);
|
||||||
if (fx_value_is_type(value, FX_TYPE_STRING)) {
|
if (fx_value_is_type(value, FX_TYPE_STRING)
|
||||||
write_string(w, value);
|
|| fx_value_is_type(value, FX_TYPE_CSTR)) {
|
||||||
return;
|
return write_string(w, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fx_type_get_interface(ty, FX_TYPE_ITERABLE)) {
|
if (fx_type_get_interface(ty, FX_TYPE_ITERABLE)) {
|
||||||
write_iterable(w, value);
|
return write_iterable(w, value);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fx_type_is_value_type(value->v_type)) {
|
if (fx_type_is_value_type(value->v_type)) {
|
||||||
fx_value_to_string(value, w->w_dest, NULL);
|
fx_stringstream_reset(w->w_tmp);
|
||||||
fx_stream_write_char(w->w_dest, '\n');
|
fx_value_to_string(value, w->w_tmp, NULL);
|
||||||
return;
|
fx_stream_write_char(w->w_tmp, '\n');
|
||||||
|
size_t result = fx_stringstream_get_length(w->w_tmp);
|
||||||
|
fx_stream_write_cstr(
|
||||||
|
w->w_dest,
|
||||||
|
fx_stringstream_get_cstr(w->w_tmp),
|
||||||
|
NULL);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!w->w_table_initialised) {
|
if (!w->w_table_initialised) {
|
||||||
@@ -73,19 +149,27 @@ static void write_value(struct bshell_value_writer *w, const fx_value *value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bshell_table_ctx_print_record(&w->w_table_ctx, value);
|
bshell_table_ctx_print_record(&w->w_table_ctx, value);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bshell_value_writer_init(struct bshell_value_writer *w, fx_stream *dest)
|
void bshell_value_writer_init(
|
||||||
|
struct bshell_value_writer *w,
|
||||||
|
enum bshell_value_writer_flags flags,
|
||||||
|
size_t max_width,
|
||||||
|
fx_stream *dest)
|
||||||
{
|
{
|
||||||
memset(w, 0x00, sizeof *w);
|
memset(w, 0x00, sizeof *w);
|
||||||
w->w_dest = dest;
|
w->w_dest = dest;
|
||||||
|
w->w_flags = flags;
|
||||||
|
w->w_max_width = max_width;
|
||||||
|
w->w_tmp = fx_stringstream_create();
|
||||||
}
|
}
|
||||||
|
|
||||||
void bshell_value_writer_write(
|
size_t bshell_value_writer_write(
|
||||||
struct bshell_value_writer *w,
|
struct bshell_value_writer *w,
|
||||||
const fx_value *value)
|
const fx_value *value)
|
||||||
{
|
{
|
||||||
write_value(w, value);
|
return write_value(w, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bshell_value_writer_cleanup(struct bshell_value_writer *w)
|
void bshell_value_writer_cleanup(struct bshell_value_writer *w)
|
||||||
@@ -94,5 +178,7 @@ void bshell_value_writer_cleanup(struct bshell_value_writer *w)
|
|||||||
bshell_table_ctx_cleanup(&w->w_table_ctx);
|
bshell_table_ctx_cleanup(&w->w_table_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fx_stringstream_unref(w->w_tmp);
|
||||||
|
|
||||||
w->w_table_initialised = false;
|
w->w_table_initialised = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
#include <bshell/format.h>
|
#include <bshell/format.h>
|
||||||
|
|
||||||
static struct bshell_table_column verb_table_columns[] = {
|
static struct bshell_table_column verb_table_columns[] = {
|
||||||
TABLE_COLUMN("verb", "verb", 13),
|
TABLE_COLUMN("verb", "verb", 12),
|
||||||
TABLE_COLUMN("alias_prefix", "alias_prefix", 13),
|
TABLE_COLUMN("alias_prefix", "alias_prefix", 12),
|
||||||
TABLE_COLUMN("group", "group", 13),
|
TABLE_COLUMN("group", "group", 12),
|
||||||
TABLE_COLUMN("description", "description", COL_WIDTH_INFINITE),
|
TABLE_COLUMN("description", "description", COL_WIDTH_INFINITE),
|
||||||
};
|
};
|
||||||
|
|
||||||
struct bshell_table verb_bshell_table = {
|
struct bshell_table verb_bshell_table = {
|
||||||
.fmt_columns = verb_table_columns,
|
.fmt_columns = verb_table_columns,
|
||||||
.fmt_column_count = sizeof verb_table_columns
|
.fmt_column_count
|
||||||
/ sizeof verb_table_columns[0],
|
= sizeof verb_table_columns / sizeof verb_table_columns[0],
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include <fx/reflection/property.h>
|
#include <fx/reflection/property.h>
|
||||||
#include <fx/reflection/type.h>
|
#include <fx/reflection/type.h>
|
||||||
#include <fx/stream.h>
|
#include <fx/stream.h>
|
||||||
|
#include <fx/stringstream.h>
|
||||||
#include <fx/value.h>
|
#include <fx/value.h>
|
||||||
|
|
||||||
#define TABLE_COLUMN(display_name, property_name, width) \
|
#define TABLE_COLUMN(display_name, property_name, width) \
|
||||||
@@ -18,6 +19,12 @@
|
|||||||
}
|
}
|
||||||
#define COL_WIDTH_INFINITE ((size_t)-1)
|
#define COL_WIDTH_INFINITE ((size_t)-1)
|
||||||
|
|
||||||
|
enum bshell_value_writer_flags {
|
||||||
|
BSHELL_VALUE_WRITER_ONELINE = 0x01u,
|
||||||
|
BSHELL_VALUE_WRITER_TRUNCATE = 0x02u,
|
||||||
|
BSHELL_VALUE_WRITER_NO_NEWLINE = 0x04u,
|
||||||
|
};
|
||||||
|
|
||||||
struct bshell_table_column {
|
struct bshell_table_column {
|
||||||
const char *col_display_name;
|
const char *col_display_name;
|
||||||
const char *col_property_name;
|
const char *col_property_name;
|
||||||
@@ -49,7 +56,10 @@ struct bshell_table_ctx {
|
|||||||
|
|
||||||
struct bshell_value_writer {
|
struct bshell_value_writer {
|
||||||
struct bshell_table_ctx w_table_ctx;
|
struct bshell_table_ctx w_table_ctx;
|
||||||
|
enum bshell_value_writer_flags w_flags;
|
||||||
|
size_t w_max_width;
|
||||||
bool w_table_initialised;
|
bool w_table_initialised;
|
||||||
|
fx_stringstream *w_tmp;
|
||||||
fx_stream *w_dest;
|
fx_stream *w_dest;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -82,8 +92,10 @@ extern enum bshell_status bshell_table_ctx_print_record(
|
|||||||
|
|
||||||
extern void bshell_value_writer_init(
|
extern void bshell_value_writer_init(
|
||||||
struct bshell_value_writer *w,
|
struct bshell_value_writer *w,
|
||||||
|
enum bshell_value_writer_flags flags,
|
||||||
|
size_t max_width,
|
||||||
fx_stream *dest);
|
fx_stream *dest);
|
||||||
extern void bshell_value_writer_write(
|
extern size_t bshell_value_writer_write(
|
||||||
struct bshell_value_writer *w,
|
struct bshell_value_writer *w,
|
||||||
const fx_value *value);
|
const fx_value *value);
|
||||||
extern void bshell_value_writer_cleanup(struct bshell_value_writer *w);
|
extern void bshell_value_writer_cleanup(struct bshell_value_writer *w);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
void bshell_runtime_begin_output(struct bshell_runtime *rt)
|
void bshell_runtime_begin_output(struct bshell_runtime *rt)
|
||||||
{
|
{
|
||||||
bshell_value_writer_init(&rt->rt_writer, fx_stdout);
|
bshell_value_writer_init(&rt->rt_writer, 0, 0, fx_stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bshell_runtime_output_value(
|
void bshell_runtime_output_value(
|
||||||
|
|||||||
Reference in New Issue
Block a user