diff --git a/.gitattributes b/.gitattributes index f961279..5958377 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,3 +2,15 @@ tests/issue0228.d text eol=lf tests/allman/issue0228.d.ref text eol=crlf tests/knr/issue0228.d.ref text eol=crlf tests/otbs/issue0228.d.ref text eol=crlf +tests/issue0552_lf.d text eol=lf +tests/allman/issue0552_lf.d.ref text eol=lf +tests/knr/issue0552_lf.d.ref text eol=lf +tests/otbs/issue0552_lf.d.ref text eol=lf +tests/issue0552_cr.d text eol=cr +tests/allman/issue0552_cr.d.ref text eol=cr +tests/knr/issue0552_cr.d.ref text eol=cr +tests/otbs/issue0552_cr.d.ref text eol=cr +tests/issue0552_crlf.d text eol=crlf +tests/allman/issue0552_crlf.d.ref text eol=crlf +tests/knr/issue0552_crlf.d.ref text eol=crlf +tests/otbs/issue0552_crlf.d.ref text eol=crlf diff --git a/README.md b/README.md index 822d70e..b5fae36 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ void main(string[] args) ### Standard EditorConfig properties Property Name | Allowed Values | Description --------------|----------------|------------ -end_of_line | `cr`, `crlf` and **`lf`** | [See EditorConfig documentation.](https://github.com/editorconfig/editorconfig/wiki/EditorConfig-Properties#end_of_line) +end_of_line | `cr`, `crlf` and `lf` | [See EditorConfig documentation.](https://github.com/editorconfig/editorconfig/wiki/EditorConfig-Properties#end_of_line) When not set, `dfmt` adopts the first line ending in the input. insert_final_newline | **`true`** | Not supported. `dfmt` always inserts a final newline. charset | **`UTF-8`** | Not supported. `dfmt` only works correctly on UTF-8. indent_style | `tab`, **`space`** | [See EditorConfig documentation.](https://github.com/editorconfig/editorconfig/wiki/EditorConfig-Properties#indent_style) diff --git a/src/dfmt/config.d b/src/dfmt/config.d index b2e49ed..d6f31b7 100644 --- a/src/dfmt/config.d +++ b/src/dfmt/config.d @@ -10,7 +10,7 @@ import dfmt.editorconfig; /// Brace styles enum BraceStyle { - unspecified, + _unspecified, /// $(LINK https://en.wikipedia.org/wiki/Indent_style#Allman_style) allman, /// $(LINK https://en.wikipedia.org/wiki/Indent_style#Variant:_1TBS) @@ -23,7 +23,7 @@ enum BraceStyle enum TemplateConstraintStyle { - unspecified, + _unspecified, conditional_newline_indent, conditional_newline, always_newline, @@ -73,7 +73,7 @@ struct Config void initializeWithDefaults() { pattern = "*.d"; - end_of_line = EOL.lf; + end_of_line = EOL._default; indent_style = IndentStyle.space; indent_size = 4; tab_width = 4; diff --git a/src/dfmt/editorconfig.d b/src/dfmt/editorconfig.d index 205b9a4..ce79f7c 100644 --- a/src/dfmt/editorconfig.d +++ b/src/dfmt/editorconfig.d @@ -26,21 +26,22 @@ private auto commentRe = ctRegex!(`^\s*[#;].*$`); enum OptionalBoolean : ubyte { - unspecified = 3, + _unspecified = 3, t = 1, f = 0 } enum IndentStyle : ubyte { - unspecified, + _unspecified, tab, space } enum EOL : ubyte { - unspecified, + _unspecified, + _default, lf, cr, crlf @@ -74,7 +75,7 @@ mixin template StandardEditorConfigFields() static if (N == "pattern") continue; else static if (is(T == enum)) - *thisN = otherN != T.unspecified ? otherN : *thisN; + *thisN = otherN != T._unspecified ? otherN : *thisN; else static if (is(T == int)) *thisN = otherN != -1 ? otherN : *thisN; else static if (is(T == string)) diff --git a/src/dfmt/formatter.d b/src/dfmt/formatter.d index 5184092..8dcab2a 100644 --- a/src/dfmt/formatter.d +++ b/src/dfmt/formatter.d @@ -121,8 +121,13 @@ struct TokenFormatter(OutputRange) this.eolString = "\n"; else if (eol == eol.crlf) this.eolString = "\r\n"; - else if (eol == eol.unspecified) + else if (eol == eol._unspecified) assert(false, "config.end_of_line was unspecified"); + else + { + assert (eol == eol._default); + this.eolString = eolStringFromInput; + } } } @@ -201,6 +206,17 @@ private: /// and paren indentation is ignored.line breaks and "[" reset the counter. int parenDepthOnLine; + string eolStringFromInput() const + { + import std.algorithm : countUntil; + + // Intentional wraparound, -1 turns into uint.max when not found: + const firstCR = cast(uint) rawSource.countUntil("\r"); + if (firstCR < cast(uint) rawSource.countUntil("\n")) + return firstCR == rawSource.countUntil("\r\n") ? "\r\n" : "\r"; + return "\n"; + } + void formatStep() { import std.range : assumeSorted; @@ -376,7 +392,7 @@ private: import dfmt.editorconfig : OB = OptionalBoolean; with (TemplateConstraintStyle) final switch (config.dfmt_template_constraint_style) { - case unspecified: + case _unspecified: assert(false, "Config was not validated properly"); case conditional_newline: immutable l = currentLineLength + betweenParenLength(tokens[index + 1 .. $]); diff --git a/src/dfmt/main.d b/src/dfmt/main.d index 7a4d843..316d8a2 100644 --- a/src/dfmt/main.d +++ b/src/dfmt/main.d @@ -289,12 +289,14 @@ private version (Windows) template optionsToString(E) if (is(E == enum)) { + import std.algorithm.searching : startsWith; + enum optionsToString = () { string result = "("; foreach (s; [__traits(allMembers, E)]) { - if (s != "unspecified") + if (!s.startsWith("_")) result ~= s ~ "|"; } result = result[0 .. $ - 1] ~ ")"; diff --git a/tests/allman/issue0552_cr.d.ref b/tests/allman/issue0552_cr.d.ref new file mode 100644 index 0000000..e776d11 --- /dev/null +++ b/tests/allman/issue0552_cr.d.ref @@ -0,0 +1 @@ +/// Testing CR line endings. void main() { } \ No newline at end of file diff --git a/tests/allman/issue0552_crlf.d.ref b/tests/allman/issue0552_crlf.d.ref new file mode 100644 index 0000000..f226e53 --- /dev/null +++ b/tests/allman/issue0552_crlf.d.ref @@ -0,0 +1,4 @@ +/// Testing CRLF line endings. +void main() +{ +} diff --git a/tests/allman/issue0552_lf.d.ref b/tests/allman/issue0552_lf.d.ref new file mode 100644 index 0000000..ca5d2ac --- /dev/null +++ b/tests/allman/issue0552_lf.d.ref @@ -0,0 +1,4 @@ +/// Testing LF line endings. +void main() +{ +} diff --git a/tests/issue0552_cr.d b/tests/issue0552_cr.d new file mode 100644 index 0000000..e776d11 --- /dev/null +++ b/tests/issue0552_cr.d @@ -0,0 +1 @@ +/// Testing CR line endings. void main() { } \ No newline at end of file diff --git a/tests/issue0552_crlf.d b/tests/issue0552_crlf.d new file mode 100644 index 0000000..f226e53 --- /dev/null +++ b/tests/issue0552_crlf.d @@ -0,0 +1,4 @@ +/// Testing CRLF line endings. +void main() +{ +} diff --git a/tests/issue0552_lf.d b/tests/issue0552_lf.d new file mode 100644 index 0000000..ca5d2ac --- /dev/null +++ b/tests/issue0552_lf.d @@ -0,0 +1,4 @@ +/// Testing LF line endings. +void main() +{ +} diff --git a/tests/knr/issue0552_cr.d.ref b/tests/knr/issue0552_cr.d.ref new file mode 100644 index 0000000..e776d11 --- /dev/null +++ b/tests/knr/issue0552_cr.d.ref @@ -0,0 +1 @@ +/// Testing CR line endings. void main() { } \ No newline at end of file diff --git a/tests/knr/issue0552_crlf.d.ref b/tests/knr/issue0552_crlf.d.ref new file mode 100644 index 0000000..f226e53 --- /dev/null +++ b/tests/knr/issue0552_crlf.d.ref @@ -0,0 +1,4 @@ +/// Testing CRLF line endings. +void main() +{ +} diff --git a/tests/knr/issue0552_lf.d.ref b/tests/knr/issue0552_lf.d.ref new file mode 100644 index 0000000..ca5d2ac --- /dev/null +++ b/tests/knr/issue0552_lf.d.ref @@ -0,0 +1,4 @@ +/// Testing LF line endings. +void main() +{ +} diff --git a/tests/otbs/issue0552_cr.d.ref b/tests/otbs/issue0552_cr.d.ref new file mode 100644 index 0000000..246eac2 --- /dev/null +++ b/tests/otbs/issue0552_cr.d.ref @@ -0,0 +1 @@ +/// Testing CR line endings. void main() { } \ No newline at end of file diff --git a/tests/otbs/issue0552_crlf.d.ref b/tests/otbs/issue0552_crlf.d.ref new file mode 100644 index 0000000..d3d01c6 --- /dev/null +++ b/tests/otbs/issue0552_crlf.d.ref @@ -0,0 +1,3 @@ +/// Testing CRLF line endings. +void main() { +} diff --git a/tests/otbs/issue0552_lf.d.ref b/tests/otbs/issue0552_lf.d.ref new file mode 100644 index 0000000..0856a1e --- /dev/null +++ b/tests/otbs/issue0552_lf.d.ref @@ -0,0 +1,3 @@ +/// Testing LF line endings. +void main() { +} diff --git a/tests/test.d b/tests/test.d index 43f50d1..9310a2a 100755 --- a/tests/test.d +++ b/tests/test.d @@ -29,13 +29,10 @@ int main() if (const result = spawnProcess(dfmtCommand, stdin, File(outFileName, "w")).wait) return result; - // As long as dfmt defaults to LF line endings (issue #552), we'll have to default to ignore - // the line endings in our verification with the reference. - const keepTerminator = dfmtCommand.any!(a => a.canFind("--end_of_line")).to!(Flag!"keepTerminator"); const outText = outFileName.readText; const refText = refFileName.readText; - const outLines = outText.splitLines(keepTerminator); - const refLines = refText.splitLines(keepTerminator); + const outLines = outText.splitLines(Yes.keepTerminator); + const refLines = refText.splitLines(Yes.keepTerminator); foreach (i; 0 .. min(refLines.length, outLines.length)) if (outLines[i] != refLines[i]) { @@ -56,26 +53,6 @@ int main() writefln("%(%s%)", [outLines[refLines.length]]); return 1; } - - // As long as dfmt defaults to LF line endings (issue #552) we need an explicit trailing newline check. - // because a) splitLines gives the same number of lines regardless whether the last line ends with a newline, - // and b) when line endings are ignored the trailing endline is of course also ignored. - if (outText.endsWithNewline) - { - if (!refText.endsWithNewline) - { - writeln(outFileName, " ends with a newline, but ", refFileName, " does not."); - return 1; - } - } - else - { - if (refText.endsWithNewline) - { - writeln(refFileName, " ends with a newline, but ", outFileName, " does not."); - return 1; - } - } } foreach (entry; dirEntries("expected_failures", "*.d", SpanMode.shallow)) @@ -88,16 +65,3 @@ int main() writeln("All tests succeeded."); return 0; } - -bool endsWithNewline(string text) pure -{ - // Same criteria as https://dlang.org/phobos/std_string.html#.lineSplitter - return - text.endsWith('\n') || - text.endsWith('\r') || - text.endsWith(lineSep) || - text.endsWith(paraSep) || - text.endsWith('\u0085') || - text.endsWith('\v') || - text.endsWith('\f'); -}