diff --git a/docs/content/3.manual/manual.yml b/docs/content/3.manual/manual.yml index 95d8d53f..8028e47a 100644 --- a/docs/content/3.manual/manual.yml +++ b/docs/content/3.manual/manual.yml @@ -140,6 +140,14 @@ sections: will result in more compact output by instead putting each JSON object on a single line. + * `--tab`: + + Use a tab for each indentation level instead of two spaces. + + * `--indent n`: + + Use the given number of spaces (no more than 8) for indentation. + * `--colour-output` / `-C` and `--monochrome-output` / `-M`: By default, jq outputs colored JSON if writing to a diff --git a/jv.h b/jv.h index aa374ad1..28f6ae05 100644 --- a/jv.h +++ b/jv.h @@ -159,14 +159,20 @@ jv jv_object_iter_value(jv, int); int jv_get_refcnt(jv); -enum { +enum jv_print_flags { JV_PRINT_PRETTY = 1, JV_PRINT_ASCII = 2, JV_PRINT_COLOUR = 4, JV_PRINT_SORTED = 8, JV_PRINT_INVALID = 16, JV_PRINT_REFCOUNT = 32, + JV_PRINT_TAB = 64, + JV_PRINT_SPACE0 = 256, + JV_PRINT_SPACE1 = 512, + JV_PRINT_SPACE2 = 1024, }; +#define JV_PRINT_INDENT_FLAGS(n) \ + ((n) < 0 || (n) > 7 ? JV_PRINT_TAB | JV_PRINT_PRETTY : (n) == 0 ? 0 : (n) << 8 | JV_PRINT_PRETTY) void jv_dumpf(jv, FILE *f, int flags); void jv_dump(jv, int flags); void jv_show(jv, int flags); diff --git a/jv_print.c b/jv_print.c index 4b6c4bb9..8615bec6 100644 --- a/jv_print.c +++ b/jv_print.c @@ -37,9 +37,14 @@ static void put_str(const char* s, FILE* fout, jv* strout) { put_buf(s, strlen(s), fout, strout); } -static void put_space(int n, FILE* fout, jv* strout) { - while (n--) { - put_char(' ', fout, strout); +static void put_indent(int n, int flags, FILE* fout, jv* strout) { + if (flags & JV_PRINT_TAB) { + while (n--) + put_char('\t', fout, strout); + } else { + n *= ((flags & (JV_PRINT_SPACE0 | JV_PRINT_SPACE1 | JV_PRINT_SPACE2)) >> 8); + while (n--) + put_char(' ', fout, strout); } } @@ -110,8 +115,6 @@ static void jvp_dump_string(jv str, int ascii_only, FILE* F, jv* S) { put_char('"', F, S); } -enum { INDENT = 2 }; - static void put_refcnt(struct dtoa_context* C, int refcnt, FILE *F, jv* S){ char buf[JVP_DTOA_FMT_MAX_LEN]; put_char(' ', F, S); @@ -184,23 +187,23 @@ static void jv_dump_term(struct dtoa_context* C, jv x, int flags, int indent, FI put_str("[", F, S); if (flags & JV_PRINT_PRETTY) { put_char('\n', F, S); - put_space(indent+INDENT, F, S); + put_indent(indent + 1, flags, F, S); } jv_array_foreach(x, i, elem) { if (i!=0) { if (flags & JV_PRINT_PRETTY) { put_str(",\n", F, S); - put_space(indent+INDENT, F, S); + put_indent(indent + 1, flags, F, S); } else { put_str(",", F, S); } } - jv_dump_term(C, elem, flags, indent + INDENT, F, S); + jv_dump_term(C, elem, flags, indent + 1, F, S); if (colour) put_str(colour, F, S); } if (flags & JV_PRINT_PRETTY) { put_char('\n', F, S); - put_space(indent, F, S); + put_indent(indent, flags, F, S); } if (colour) put_str(colour, F, S); put_char(']', F, S); @@ -216,7 +219,7 @@ static void jv_dump_term(struct dtoa_context* C, jv x, int flags, int indent, FI put_char('{', F, S); if (flags & JV_PRINT_PRETTY) { put_char('\n', F, S); - put_space(indent+INDENT, F, S); + put_indent(indent + 1, flags, F, S); } int first = 1; int i = 0; @@ -250,7 +253,7 @@ static void jv_dump_term(struct dtoa_context* C, jv x, int flags, int indent, FI if (!first) { if (flags & JV_PRINT_PRETTY){ put_str(",\n", F, S); - put_space(indent+INDENT, F, S); + put_indent(indent + 1, flags, F, S); } else { put_str(",", F, S); } @@ -267,12 +270,12 @@ static void jv_dump_term(struct dtoa_context* C, jv x, int flags, int indent, FI put_str((flags & JV_PRINT_PRETTY) ? ": " : ":", F, S); if (colour) put_str(COLRESET, F, S); - jv_dump_term(C, value, flags, indent + INDENT, F, S); + jv_dump_term(C, value, flags, indent + 1, F, S); if (colour) put_str(colour, F, S); } if (flags & JV_PRINT_PRETTY) { put_char('\n', F, S); - put_space(indent, F, S); + put_indent(indent, flags, F, S); } if (colour) put_str(colour, F, S); put_char('}', F, S); @@ -300,7 +303,7 @@ void jv_dump(jv x, int flags) { /* This one is nice for use in debuggers */ void jv_show(jv x, int flags) { if (flags == -1) - flags = JV_PRINT_PRETTY | JV_PRINT_COLOUR; + flags = JV_PRINT_PRETTY | JV_PRINT_COLOUR | JV_PRINT_INDENT_FLAGS(2); jv_dumpf(jv_copy(x), stderr, flags | JV_PRINT_INVALID); fflush(stderr); } diff --git a/main.c b/main.c index 4ada621d..246b2dfd 100644 --- a/main.c +++ b/main.c @@ -48,6 +48,7 @@ static void usage(int code) { "\t -C\t\tcolorize JSON;\n" "\t -M\t\tmonochrome (don't colorize JSON);\n" "\t -S\t\tsort keys of objects on output;\n" + "\t --tab\tuse tabs for indentation;\n" "\t --arg a v\tset variable $a to value ;\n" "\t --argjson a v\tset variable $a to JSON value ;\n" "\t --slurpfile a f\tset variable $a to an array of JSON texts read from ;\n" @@ -91,7 +92,6 @@ enum { RAW_INPUT = 2, PROVIDE_NULL = 4, RAW_OUTPUT = 8, - COMPACT_OUTPUT = 16, ASCII_OUTPUT = 32, COLOUR_OUTPUT = 64, NO_COLOUR_OUTPUT = 128, @@ -174,6 +174,7 @@ int main(int argc, char* argv[]) { goto out; } + int dumpopts = JV_PRINT_INDENT_FLAGS(2); const char* program = 0; jq_util_input_state input_state = jq_util_input_init(NULL, NULL); // XXX add err_cb @@ -221,7 +222,7 @@ int main(int argc, char* argv[]) { if (!short_opts) continue; } if (isoption(argv[i], 'c', "compact-output", &short_opts)) { - options |= COMPACT_OUTPUT; + dumpopts &= ~(JV_PRINT_TAB | JV_PRINT_INDENT_FLAGS(7)); if (!short_opts) continue; } if (isoption(argv[i], 'C', "color-output", &short_opts)) { @@ -260,6 +261,26 @@ int main(int argc, char* argv[]) { options |= RAW_OUTPUT | RAW_NO_LF; if (!short_opts) continue; } + if (isoption(argv[i], 0, "tab", &short_opts)) { + dumpopts &= ~JV_PRINT_INDENT_FLAGS(7); + dumpopts |= JV_PRINT_TAB | JV_PRINT_PRETTY; + if (!short_opts) continue; + } + if (isoption(argv[i], 0, "indent", &short_opts)) { + if (i >= argc - 1) { + fprintf(stderr, "%s: --indent takes one parameter\n", progname); + die(); + } + dumpopts &= ~(JV_PRINT_TAB | JV_PRINT_INDENT_FLAGS(7)); + int indent = atoi(argv[i+1]); + if (indent < -1 || indent > 7) { + fprintf(stderr, "%s: --indent takes a number between -1 and 7\n", progname); + die(); + } + dumpopts |= JV_PRINT_INDENT_FLAGS(indent); + i++; + if (!short_opts) continue; + } if (isoption(argv[i], 0, "seq", &short_opts)) { options |= SEQ; if (!short_opts) continue; @@ -279,7 +300,7 @@ int main(int argc, char* argv[]) { // FIXME: For --arg* we should check that the varname is acceptable if (isoption(argv[i], 0, "arg", &short_opts)) { if (i >= argc - 2) { - fprintf(stderr, "%s: --arg takes two parameters (e.g. -a varname value)\n", progname); + fprintf(stderr, "%s: --arg takes two parameters (e.g. --arg varname value)\n", progname); die(); } jv arg = jv_object(); @@ -291,7 +312,7 @@ int main(int argc, char* argv[]) { } if (isoption(argv[i], 0, "argjson", &short_opts)) { if (i >= argc - 2) { - fprintf(stderr, "%s: --argjson takes two parameters (e.g. -a varname text)\n", progname); + fprintf(stderr, "%s: --argjson takes two parameters (e.g. --argjson varname text)\n", progname); die(); } jv v = jv_parse(argv[i+2]); @@ -314,7 +335,7 @@ int main(int argc, char* argv[]) { else which = "slurpfile"; if (i >= argc - 2) { - fprintf(stderr, "%s: --%s takes two parameters (e.g. -a varname filename)\n", progname, which); + fprintf(stderr, "%s: --%s takes two parameters (e.g. --%s varname filename)\n", progname, which, which); die(); } jv arg = jv_object(); @@ -370,7 +391,6 @@ int main(int argc, char* argv[]) { } } - int dumpopts = 0; #ifndef WIN32 /* Disable colour by default on Windows builds as Windows terminals tend not to display it correctly */ @@ -378,7 +398,6 @@ int main(int argc, char* argv[]) { dumpopts |= JV_PRINT_COLOUR; #endif if (options & SORTED_OUTPUT) dumpopts |= JV_PRINT_SORTED; - if (!(options & COMPACT_OUTPUT)) dumpopts |= JV_PRINT_PRETTY; if (options & ASCII_OUTPUT) dumpopts |= JV_PRINT_ASCII; if (options & COLOUR_OUTPUT) dumpopts |= JV_PRINT_COLOUR; if (options & NO_COLOUR_OUTPUT) dumpopts &= ~JV_PRINT_COLOUR;