diff --git a/README.md b/README.md index 7ec9818..822d70e 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,7 @@ dfmt_template_constraint_style | **`conditional_newline_indent`** `conditional_n dfmt_single_template_constraint_indent | `true`, **`false`** | Set if the constraints are indented by a single tab instead of two. Has only an effect if the style set to `always_newline_indent` or `conditional_newline_indent`. dfmt_space_before_aa_colon | `true`, **`false`** | Adds a space after an associative array key before the `:` like in older dfmt versions. dfmt_keep_line_breaks | `true`, **`false`** | Keep existing line breaks if these don't violate other formatting rules. +dfmt_single_indent | `true`, **`false`** | Set if the code in parens is indented by a single tab instead of two. ## Terminology * Braces - `{` and `}` diff --git a/src/dfmt/config.d b/src/dfmt/config.d index 86706d1..8cb1ac3 100644 --- a/src/dfmt/config.d +++ b/src/dfmt/config.d @@ -59,6 +59,8 @@ struct Config OptionalBoolean dfmt_space_before_aa_colon; /// OptionalBoolean dfmt_keep_line_breaks; + /// + OptionalBoolean dfmt_single_indent; mixin StandardEditorConfigFields; @@ -88,6 +90,7 @@ struct Config dfmt_single_template_constraint_indent = OptionalBoolean.f; dfmt_space_before_aa_colon = OptionalBoolean.f; dfmt_keep_line_breaks = OptionalBoolean.f; + dfmt_single_indent = OptionalBoolean.f; } /** diff --git a/src/dfmt/formatter.d b/src/dfmt/formatter.d index f8883da..1aca12d 100644 --- a/src/dfmt/formatter.d +++ b/src/dfmt/formatter.d @@ -110,6 +110,7 @@ struct TokenFormatter(OutputRange) this.output = output; this.astInformation = astInformation; this.config = config; + this.indents = IndentStack(config); { auto eol = config.end_of_line; diff --git a/src/dfmt/indentation.d b/src/dfmt/indentation.d index c80c86c..7b5da72 100644 --- a/src/dfmt/indentation.d +++ b/src/dfmt/indentation.d @@ -5,6 +5,8 @@ module dfmt.indentation; +import dfmt.config; +import dfmt.editorconfig; import dparse.lexer; import std.bitmanip : bitfields; @@ -31,6 +33,14 @@ bool isTempIndent(IdType type) pure nothrow @nogc @safe */ struct IndentStack { + /// Configuration + private const Config* config; + + this(const Config* config) + { + this.config = config; + } + static struct Details { mixin(bitfields!( @@ -221,7 +231,7 @@ struct IndentStack /** * Dumps the current state of the indentation stack to `stderr`. Used for debugging. */ - void dump(size_t pos = size_t.max, string file = __FILE__, uint line = __LINE__) + void dump(size_t pos = size_t.max, string file = __FILE__, uint line = __LINE__) const { import dparse.lexer : str; import std.algorithm.iteration : map; @@ -260,6 +270,12 @@ private: if (i + 1 < index) { + if (config.dfmt_single_indent == OptionalBoolean.t && skipDoubleIndent(i, parenCount)) + { + parenCount = pc; + continue; + } + immutable currentIsNonWrapTemp = !details[i].wrap && details[i].temp && arr[i] != tok!")" && arr[i] != tok!"!"; if (arr[i] == tok!"static" @@ -276,7 +292,7 @@ private: continue; } } - else if (parenCount == 0 && arr[i] == tok!"(") + else if (parenCount == 0 && arr[i] == tok!"(" && config.dfmt_single_indent == OptionalBoolean.f) size++; if (arr[i] == tok!"!") @@ -287,6 +303,12 @@ private: } return size; } + + bool skipDoubleIndent(size_t i, int parenCount) const pure nothrow @safe @nogc + { + return (details[i + 1].wrap && arr[i] == tok!")") + || (parenCount == 0 && arr[i + 1] == tok!"," && arr[i] == tok!"("); + } } unittest diff --git a/src/dfmt/main.d b/src/dfmt/main.d index e4ee702..2bd03bb 100644 --- a/src/dfmt/main.d +++ b/src/dfmt/main.d @@ -95,6 +95,9 @@ else case "keep_line_breaks": optConfig.dfmt_keep_line_breaks = optVal; break; + case "single_indent": + optConfig.dfmt_single_indent = optVal; + break; default: assert(false, "Invalid command-line switch"); } @@ -125,7 +128,8 @@ else "space_before_aa_colon", &handleBooleans, "tab_width", &optConfig.tab_width, "template_constraint_style", &optConfig.dfmt_template_constraint_style, - "keep_line_breaks", &handleBooleans); + "keep_line_breaks", &handleBooleans, + "single_indent", &handleBooleans); // dfmt on } catch (GetOptException e) @@ -329,6 +333,7 @@ Formatting Options: --compact_labeled_statements --template_constraint_style --space_before_aa_colon + --single_indent `, optionsToString!(typeof(Config.dfmt_template_constraint_style))); } diff --git a/tests/allman/keep_single_indent.d.ref b/tests/allman/keep_single_indent.d.ref new file mode 100644 index 0000000..f164801 --- /dev/null +++ b/tests/allman/keep_single_indent.d.ref @@ -0,0 +1,49 @@ +unittest +{ + { + bool anotherTemplatedFunction(One, Two, Three)(One alpha, Two bravo, + Three charlie, double delta) + { + if (isNumeric!One && isNumeric!Two && isNumeric!Three && echo + && foxtrot && golf && hotel && india && juliet) + { + } + } + } +} + +void f() +{ + string a = "foo" + ~ "bar" /* bar */ + ~ "baz"; +} + +unittest +{ + if (a) + { + while (sBraceDepth == 0 && indents.topIsTemp() + && ((indents.top != tok!"if" && indents.top != tok!"version") + || !peekIs(tok!"else"))) + a(); + } +} + +unittest +{ + callFunc({ int i = 10; return i; }); + callFunc({ + int i = 10; + foo(alpha, bravo, charlie, delta, echo, foxtrot, golf, echo); + doStuff(withThings, andOtherStuff); + return i; + }); + callFunc({ + int i = 10; + foo(alpha_longVarName, bravo_longVarName, charlie_longVarName, delta_longVarName, + echo_longVarName, foxtrot_longVarName, golf_longVarName, echo_longVarName); + doStuff(withThings, andOtherStuff); + return i; + }, more_stuff); +} diff --git a/tests/allman/single_indent.d.ref b/tests/allman/single_indent.d.ref new file mode 100644 index 0000000..b4b497a --- /dev/null +++ b/tests/allman/single_indent.d.ref @@ -0,0 +1,41 @@ +unittest +{ + { + bool anotherTemplatedFunction(One, Two, Three)(One alpha, Two bravo, + Three charlie, double delta) + { + if (isNumeric!One && isNumeric!Two && isNumeric!Three && echo + && foxtrot && golf && hotel && india && juliet) + { + } + } + } +} + +unittest +{ + if (a) + { + while (sBraceDepth == 0 && indents.topIsTemp() + && ((indents.top != tok!"if" && indents.top != tok!"version") || !peekIs(tok!"else"))) + a(); + } +} + +unittest +{ + callFunc({ int i = 10; return i; }); + callFunc({ + int i = 10; + foo(alpha, bravo, charlie, delta, echo, foxtrot, golf, echo); + doStuff(withThings, andOtherStuff); + return i; + }); + callFunc({ + int i = 10; + foo(alpha_longVarName, bravo_longVarName, charlie_longVarName, delta_longVarName, + echo_longVarName, foxtrot_longVarName, golf_longVarName, echo_longVarName); + doStuff(withThings, andOtherStuff); + return i; + }, more_stuff); +} diff --git a/tests/keep_single_indent.args b/tests/keep_single_indent.args new file mode 100644 index 0000000..74b1ea5 --- /dev/null +++ b/tests/keep_single_indent.args @@ -0,0 +1,2 @@ +--single_indent true +--keep_line_breaks true diff --git a/tests/keep_single_indent.d b/tests/keep_single_indent.d new file mode 100644 index 0000000..c1c2d16 --- /dev/null +++ b/tests/keep_single_indent.d @@ -0,0 +1,49 @@ +unittest +{ + { + bool anotherTemplatedFunction(One, Two, Three)(One alpha, Two bravo, + Three charlie, double delta) + { + if (isNumeric!One && isNumeric!Two && isNumeric!Three && echo + && foxtrot && golf && hotel && india && juliet) + { + } + } + } +} + +void f() +{ + string a = "foo" + ~ "bar" /* bar */ + ~ "baz"; +} + +unittest +{ + if (a) + { + while (sBraceDepth == 0 && indents.topIsTemp() + && ((indents.top != tok!"if" && indents.top != tok!"version") + || !peekIs(tok!"else"))) + a(); + } +} + +unittest +{ + callFunc({ int i = 10; return i; }); + callFunc({ + int i = 10; + foo(alpha, bravo, charlie, delta, echo, foxtrot, golf, echo); + doStuff(withThings, andOtherStuff); + return i; + }); + callFunc({ + int i = 10; + foo(alpha_longVarName, bravo_longVarName, charlie_longVarName, delta_longVarName, + echo_longVarName, foxtrot_longVarName, golf_longVarName, echo_longVarName); + doStuff(withThings, andOtherStuff); + return i; + }, more_stuff); +} diff --git a/tests/otbs/keep_single_indent.d.ref b/tests/otbs/keep_single_indent.d.ref new file mode 100644 index 0000000..933dcde --- /dev/null +++ b/tests/otbs/keep_single_indent.d.ref @@ -0,0 +1,42 @@ +unittest { + { + bool anotherTemplatedFunction(One, Two, Three)(One alpha, Two bravo, + Three charlie, double delta) { + if (isNumeric!One && isNumeric!Two && isNumeric!Three && echo + && foxtrot && golf && hotel && india && juliet) { + } + } + } +} + +void f() { + string a = "foo" + ~ "bar" /* bar */ + ~ "baz"; +} + +unittest { + if (a) { + while (sBraceDepth == 0 && indents.topIsTemp() + && ((indents.top != tok!"if" && indents.top != tok!"version") + || !peekIs(tok!"else"))) + a(); + } +} + +unittest { + callFunc({ int i = 10; return i; }); + callFunc({ + int i = 10; + foo(alpha, bravo, charlie, delta, echo, foxtrot, golf, echo); + doStuff(withThings, andOtherStuff); + return i; + }); + callFunc({ + int i = 10; + foo(alpha_longVarName, bravo_longVarName, charlie_longVarName, delta_longVarName, + echo_longVarName, foxtrot_longVarName, golf_longVarName, echo_longVarName); + doStuff(withThings, andOtherStuff); + return i; + }, more_stuff); +} diff --git a/tests/otbs/single_indent.d.ref b/tests/otbs/single_indent.d.ref new file mode 100644 index 0000000..b84d23e --- /dev/null +++ b/tests/otbs/single_indent.d.ref @@ -0,0 +1,35 @@ +unittest { + { + bool anotherTemplatedFunction(One, Two, Three)(One alpha, Two bravo, + Three charlie, double delta) { + if (isNumeric!One && isNumeric!Two && isNumeric!Three && echo + && foxtrot && golf && hotel && india && juliet) { + } + } + } +} + +unittest { + if (a) { + while (sBraceDepth == 0 && indents.topIsTemp() + && ((indents.top != tok!"if" && indents.top != tok!"version") || !peekIs(tok!"else"))) + a(); + } +} + +unittest { + callFunc({ int i = 10; return i; }); + callFunc({ + int i = 10; + foo(alpha, bravo, charlie, delta, echo, foxtrot, golf, echo); + doStuff(withThings, andOtherStuff); + return i; + }); + callFunc({ + int i = 10; + foo(alpha_longVarName, bravo_longVarName, charlie_longVarName, delta_longVarName, + echo_longVarName, foxtrot_longVarName, golf_longVarName, echo_longVarName); + doStuff(withThings, andOtherStuff); + return i; + }, more_stuff); +} diff --git a/tests/single_indent.args b/tests/single_indent.args new file mode 100644 index 0000000..246c076 --- /dev/null +++ b/tests/single_indent.args @@ -0,0 +1 @@ +--single_indent true diff --git a/tests/single_indent.d b/tests/single_indent.d new file mode 100644 index 0000000..ffb2d50 --- /dev/null +++ b/tests/single_indent.d @@ -0,0 +1,42 @@ +unittest +{ + { + bool anotherTemplatedFunction(One, Two, Three)(One alpha, Two bravo, + Three charlie, double delta) + { + if (isNumeric!One && isNumeric!Two && isNumeric!Three && echo + && foxtrot && golf && hotel && india && juliet) + { + } + } + } +} + +unittest +{ + if (a) + { + while (sBraceDepth == 0 && indents.topIsTemp() + && ((indents.top != tok!"if" && indents.top != tok!"version") + || !peekIs(tok!"else"))) + a(); + } +} + +unittest +{ + callFunc({ int i = 10; return i; }); + callFunc({ + int i = 10; + foo(alpha, bravo, charlie, delta, echo, foxtrot, golf, echo); + doStuff(withThings, andOtherStuff); + return i; + }); + callFunc({ + int i = 10; + foo(alpha_longVarName, bravo_longVarName, charlie_longVarName, delta_longVarName, + echo_longVarName, foxtrot_longVarName, golf_longVarName, echo_longVarName); + doStuff(withThings, andOtherStuff); + return i; + }, more_stuff); +}