summaryrefslogtreecommitdiffstats
path: root/stream.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2015-07-31 06:15:16 -0700
committerKaz Kylheku <kaz@kylheku.com>2015-07-31 06:15:16 -0700
commitdbbfc2c41a3710bc64df7b477fcfa536da79233f (patch)
treee4527f7c82e8304c59b71792b10ee240f98eae61 /stream.c
parentab1a633e67d04bb36b2b00461e1a72a786bab917 (diff)
downloadtxr-dbbfc2c41a3710bc64df7b477fcfa536da79233f.tar.gz
txr-dbbfc2c41a3710bc64df7b477fcfa536da79233f.tar.bz2
txr-dbbfc2c41a3710bc64df7b477fcfa536da79233f.zip
Multi-line, indented printing of structure.
* eval.c (op_error): New static function. (macro_form_p, fboundp): Static to external. (special_operator_p): New function. (eval_init): Register macrolet and symacrolet to op_error. These are recognized and processed by expand, but we want them in the op table so they are reported by special_operator_p. * eval.h (fboundp, macro_form_p, special_operator_p): Declared. * hash.c (print_key_val): Break long lines on spaces between pairs with stream_width_check. (hash_print_op): Implement split and indented printing. * lib.c (obj_print_impl): New static function, resulting from a merge of obj_print and obj_pprint. Fixes some wrong-way recursion bugs: obj_pprint recursed into obj_print in some places. Adds support for multi-line printing of vectors and lists, with indentation using the new interfaces in streams. * stream.c (strm_base_init): Update initializer. (put_indent, indent_mode_put_string): New static functions. (put_string): Use indent_mode_put_string in either of the two indent modes. (put_char): Implement indent mode. (get_indent_mode, test_set_indent_mode, set_indent_mode, get_indent, set_indent, inc_indent, width_check): New functions. * stream.h (enum indent_mode): New. (struct strm_base): indent_on member becomes indent_mode. New members data_width and code_width. (get_indent_mode, test_set_indent_mode, set_indent_mode, get_indent, set_indent, inc_indent, width_check): Declared. * tests/009/json.expected: Updated. * tests/010/seq.expected: Likewise. * tests/011/macros-2.expected: Likewise.
Diffstat (limited to 'stream.c')
-rw-r--r--stream.c148
1 files changed, 145 insertions, 3 deletions
diff --git a/stream.c b/stream.c
index c01c3aca..ccdab87e 100644
--- a/stream.c
+++ b/stream.c
@@ -69,7 +69,7 @@ val format_s;
void strm_base_init(struct strm_base *s)
{
- static struct strm_base init = { 0, 0, 0 };
+ static struct strm_base init = { indent_off, 60, 10, 0, 0 };
*s = init;
}
@@ -2608,6 +2608,42 @@ val formatv(val stream, val string, val args)
abort();
}
+static val put_indent(val stream, struct strm_ops *ops, cnum chars)
+{
+ while (chars--)
+ if (!ops->put_char(stream, chr(' ')))
+ return nil;
+ return t;
+}
+
+static val indent_mode_put_string(val stream, val string,
+ struct strm_ops *ops, struct strm_base *s)
+{
+ cnum col = s->column;
+ const wchar_t *str = c_str(string), *p = str;
+ val ret;
+
+ for (; *p; p++) {
+ switch (*p) {
+ case '\n':
+ col = 0;
+ break;
+ case '\t':
+ col = (col + 1) | 7;
+ break;
+ default:
+ if (iswprint(*p))
+ col++;
+ break;
+ }
+ }
+
+ if ((ret = ops->put_string(stream, string)) != nil)
+ s->column = col;
+
+ return ret;
+}
+
val put_string(val string, val stream)
{
stream = default_arg(stream, std_output);
@@ -2618,7 +2654,12 @@ val put_string(val string, val stream)
{
struct strm_ops *ops = coerce(struct strm_ops *, stream->co.ops);
- return ops->put_string(stream, string);
+ struct strm_base *s = coerce(struct strm_base *, stream->co.handle);
+
+ if (s->indent_mode == indent_off)
+ return ops->put_string(stream, string);
+
+ return indent_mode_put_string(stream, string, ops, s);
}
}
@@ -2632,7 +2673,34 @@ val put_char(val ch, val stream)
{
struct strm_ops *ops = coerce(struct strm_ops *, stream->co.ops);
- return ops->put_char(stream, ch);
+ struct strm_base *s = coerce(struct strm_base *, stream->co.handle);
+ wint_t cch = c_chr(ch);
+
+ if (s->indent_mode == indent_off)
+ return ops->put_char(stream, ch);
+
+ switch (cch) {
+ case L'\n':
+ if (ops->put_char(stream, ch) &&
+ put_indent(stream, ops, s->indent_chars)) {
+ s->column = s->indent_chars;
+ return t;
+ }
+ return nil;
+ case L'\t':
+ if (ops->put_char(stream, ch)) {
+ s->column = (s->column + 1) | 7;
+ return t;
+ }
+ return nil;
+ default:
+ if (ops->put_char(stream, ch)) {
+ if (iswprint(cch))
+ s->column++;
+ return t;
+ }
+ return nil;
+ }
}
}
@@ -2716,6 +2784,80 @@ val seek_stream(val stream, val offset, val whence)
}
}
+val get_indent_mode(val stream)
+{
+ struct strm_base *s = coerce(struct strm_base *, stream->co.handle);
+ return num_fast(s->indent_mode);
+}
+
+val test_set_indent_mode(val stream, val compare, val mode)
+{
+ struct strm_base *s = coerce(struct strm_base *, stream->co.handle);
+ val oldval = num_fast(s->indent_mode);
+ if (oldval == compare)
+ s->indent_mode = (enum indent_mode) c_num(mode);
+ return oldval;
+}
+
+val set_indent_mode(val stream, val mode)
+{
+ struct strm_base *s = coerce(struct strm_base *, stream->co.handle);
+ val oldval = num_fast(s->indent_mode);
+ if ((s->indent_mode = (enum indent_mode) c_num(mode)) == indent_off)
+ s->column = 0;
+ return oldval;
+}
+
+val get_indent(val stream)
+{
+ struct strm_base *s = coerce(struct strm_base *, stream->co.handle);
+ return num(s->indent_chars);
+}
+
+val set_indent(val stream, val indent)
+{
+ struct strm_base *s = coerce(struct strm_base *, stream->co.handle);
+ val oldval = num(s->indent_chars);
+ s->indent_chars = c_num(indent);
+ return oldval;
+}
+
+val inc_indent(val stream, val delta)
+{
+ struct strm_base *s = coerce(struct strm_base *, stream->co.handle);
+ val oldval = num(s->indent_chars);
+ val col = num(s->column);
+ s->indent_chars = c_num(plus(delta, col));
+ return oldval;
+}
+
+val width_check(val stream, val alt)
+{
+ struct strm_ops *ops = coerce(struct strm_ops *, stream->co.ops);
+ struct strm_base *s = coerce(struct strm_base *, stream->co.handle);
+
+
+ if ((s->indent_mode == indent_code &&
+ s->column >= s->indent_chars + s->code_width) ||
+ (s->indent_mode == indent_data &&
+ s->column >= s->indent_chars + s->data_width))
+ {
+ if (ops->put_char(stream, chr('\n')) &&
+ put_indent(stream, ops, s->indent_chars)) {
+ s->column = s->indent_chars;
+ return t;
+ }
+ return nil;
+ } else if (alt) {
+ ops->put_char(stream, alt);
+ s->column++;
+ return t;
+ }
+
+ return t;
+}
+
+
val get_string(val stream, val nchars, val close_after_p)
{
val strstream = make_string_output_stream();