runtime: format: add truncation and single-line support to value_writer
This commit is contained in:
@@ -15,17 +15,22 @@ static void initialise_table(
|
||||
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_value_get_object(value, &array);
|
||||
|
||||
const fx_iterator *it = fx_iterator_begin(array);
|
||||
fx_foreach(v, it)
|
||||
{
|
||||
bshell_value_writer_write(w, v);
|
||||
written += bshell_value_writer_write(w, v);
|
||||
}
|
||||
fx_iterator_unref(it);
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
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';
|
||||
}
|
||||
|
||||
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;
|
||||
fx_value_get_cstr(value, &str);
|
||||
fx_stream_write_cstr(w->w_dest, str, NULL);
|
||||
bool oneline = (w->w_flags & BSHELL_VALUE_WRITER_ONELINE) != 0;
|
||||
size_t written = 1;
|
||||
|
||||
if (!string_has_trailing_newline(str)) {
|
||||
fx_stream_write_char(w->w_dest, '\n');
|
||||
switch (c) {
|
||||
case '\n':
|
||||
if (oneline) {
|
||||
fx_stream_write_cstr(w->w_dest, "\\n", &written);
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
static void write_value(struct bshell_value_writer *w, const fx_value *value)
|
||||
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);
|
||||
if (fx_value_is_type(value, FX_TYPE_STRING)) {
|
||||
write_string(w, value);
|
||||
return;
|
||||
if (fx_value_is_type(value, FX_TYPE_STRING)
|
||||
|| fx_value_is_type(value, FX_TYPE_CSTR)) {
|
||||
return write_string(w, value);
|
||||
}
|
||||
|
||||
if (fx_type_get_interface(ty, FX_TYPE_ITERABLE)) {
|
||||
write_iterable(w, value);
|
||||
return;
|
||||
return write_iterable(w, value);
|
||||
}
|
||||
|
||||
if (fx_type_is_value_type(value->v_type)) {
|
||||
fx_value_to_string(value, w->w_dest, NULL);
|
||||
fx_stream_write_char(w->w_dest, '\n');
|
||||
return;
|
||||
fx_stringstream_reset(w->w_tmp);
|
||||
fx_value_to_string(value, w->w_tmp, NULL);
|
||||
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) {
|
||||
@@ -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);
|
||||
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);
|
||||
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,
|
||||
const fx_value *value)
|
||||
{
|
||||
write_value(w, value);
|
||||
return write_value(w, value);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
fx_stringstream_unref(w->w_tmp);
|
||||
|
||||
w->w_table_initialised = false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user