From 24be6ddc2e053320f674d6ca0408645e147a67d6 Mon Sep 17 00:00:00 2001 From: Hackerpilot Date: Tue, 19 Jan 2016 05:20:31 -0800 Subject: [PATCH] Run dfmt on itself and debug some wrapping calculations --- src/dfmt/ast_info.d | 13 +- src/dfmt/config.d | 8 +- src/dfmt/editorconfig.d | 7 +- src/dfmt/formatter.d | 32 ++-- src/dfmt/globmatch_editorconfig.d | 240 +++++++++++++++--------------- src/dfmt/indentation.d | 27 +++- src/dfmt/main.d | 43 ++++-- src/dfmt/tokens.d | 40 ++--- src/dfmt/wrapping.d | 16 +- tests/allman/parenIndent.d.ref | 36 +++++ tests/allman/wrapping1.d.ref | 2 +- tests/otbs/parenIndent.d.ref | 31 ++++ tests/otbs/wrapping1.d.ref | 2 +- tests/parenIndent.d | 32 ++++ 14 files changed, 333 insertions(+), 196 deletions(-) create mode 100644 tests/allman/parenIndent.d.ref create mode 100644 tests/otbs/parenIndent.d.ref create mode 100644 tests/parenIndent.d diff --git a/src/dfmt/ast_info.d b/src/dfmt/ast_info.d index 9a9c0f1..4703888 100644 --- a/src/dfmt/ast_info.d +++ b/src/dfmt/ast_info.d @@ -96,7 +96,8 @@ final class FormatVisitor : ASTVisitor auto condition = dec.compileCondition; if (condition.versionCondition !is null) { - astInformation.conditionalWithElseLocations ~= condition.versionCondition.versionIndex; + astInformation.conditionalWithElseLocations + ~= condition.versionCondition.versionIndex; } else if (condition.debugCondition !is null) { @@ -151,8 +152,10 @@ final class FormatVisitor : ASTVisitor { if (functionBody.blockStatement !is null) astInformation.doubleNewlineLocations ~= functionBody.blockStatement.endLocation; - if (functionBody.bodyStatement !is null && functionBody.bodyStatement.blockStatement !is null) - astInformation.doubleNewlineLocations ~= functionBody.bodyStatement.blockStatement.endLocation; + if (functionBody.bodyStatement !is null && functionBody.bodyStatement + .blockStatement !is null) + astInformation.doubleNewlineLocations + ~= functionBody.bodyStatement.blockStatement.endLocation; functionBody.accept(this); } @@ -203,8 +206,8 @@ final class FormatVisitor : ASTVisitor override void visit(const UnaryExpression unary) { if (unary.prefix.type == tok!"~" || unary.prefix.type == tok!"&" - || unary.prefix.type == tok!"*" || unary.prefix.type == tok!"+" - || unary.prefix.type == tok!"-") + || unary.prefix.type == tok!"*" + || unary.prefix.type == tok!"+" || unary.prefix.type == tok!"-") { astInformation.unaryLocations ~= unary.prefix.index; } diff --git a/src/dfmt/config.d b/src/dfmt/config.d index 060fdab..5158d44 100644 --- a/src/dfmt/config.d +++ b/src/dfmt/config.d @@ -21,7 +21,7 @@ enum BraceStyle enum TemplateConstraintStyle { - unspecified, + unspecified, conditional_newline_indent, conditional_newline, always_newline, @@ -54,7 +54,6 @@ struct Config mixin StandardEditorConfigFields; - /** * Initializes the standard EditorConfig properties with default values that * make sense for D code. @@ -89,8 +88,9 @@ struct Config if (dfmt_soft_max_line_length > max_line_length) { - stderr.writefln("Column hard limit (%d) must be greater than or equal to column soft limit (%d)", - max_line_length, dfmt_soft_max_line_length); + stderr.writefln( + "Column hard limit (%d) must be greater than or equal to column soft limit (%d)", + max_line_length, dfmt_soft_max_line_length); return false; } return true; diff --git a/src/dfmt/editorconfig.d b/src/dfmt/editorconfig.d index dbb828d..cee0000 100644 --- a/src/dfmt/editorconfig.d +++ b/src/dfmt/editorconfig.d @@ -73,11 +73,11 @@ mixin template StandardEditorConfigFields() auto thisN = &mixin("this." ~ N); static if (N == "pattern") continue; - else static if (is (T == enum)) + else static if (is(T == enum)) *thisN = otherN != T.unspecified ? otherN : *thisN; - else static if (is (T == int)) + else static if (is(T == int)) *thisN = otherN != -1 ? otherN : *thisN; - else static if (is (T == string)) + else static if (is(T == string)) *thisN = otherN !is null ? otherN : *thisN; else static assert(false); @@ -143,6 +143,7 @@ EC getConfigFor(EC)(string path) static if (__VERSION__ >= 2067) { import std.algorithm : each; + configs.each!(a => a.each!(b => result.merge(b, fileName)))(); } else diff --git a/src/dfmt/formatter.d b/src/dfmt/formatter.d index 52cc18b..93d0400 100644 --- a/src/dfmt/formatter.d +++ b/src/dfmt/formatter.d @@ -15,7 +15,7 @@ import dfmt.wrapping; import std.array; void format(OutputRange)(string source_desc, ubyte[] buffer, OutputRange output, - Config* formatterConfig) + Config* formatterConfig) { LexerConfig config; config.stringBehavior = StringBehavior.source; @@ -33,7 +33,7 @@ void format(OutputRange)(string source_desc, ubyte[] buffer, OutputRange output, auto tokens = byToken(buffer, config, &cache).array(); auto depths = generateDepthInfo(tokens); auto tokenFormatter = TokenFormatter!OutputRange(buffer, tokens, depths, - output, &astInformation, formatterConfig); + output, &astInformation, formatterConfig); tokenFormatter.format(); } @@ -79,7 +79,7 @@ struct TokenFormatter(OutputRange) * decisions. */ this(const ubyte[] rawSource, const(Token)[] tokens, immutable short[] depths, - OutputRange output, ASTInformation* astInformation, Config* config) + OutputRange output, ASTInformation* astInformation, Config* config) { this.rawSource = rawSource; this.tokens = tokens; @@ -259,7 +259,7 @@ private: || isBasicType(current.type) || currentIs(tok!"@") || currentIs(tok!"if") || isNumberLiteral(tokens[index].type) || (inAsm - && peekBack2Is(tok!";") && currentIs(tok!"[")))) + && peekBack2Is(tok!";") && currentIs(tok!"[")))) { write(" "); } @@ -387,7 +387,7 @@ private: break; else if (t == tok!"import" && !currentIs(tok!"import") && !currentIs(tok!"}") && !(currentIs(tok!"public") - && peekIs(tok!"import")) + && peekIs(tok!"import")) && !indents.topIsOneOf(tok!"if", tok!"debug", tok!"version")) { simpleNewline(); @@ -461,11 +461,11 @@ private: newline(); immutable size_t j = expressionEndIndex(index); linebreakHints = chooseLineBreakTokens(index, tokens[index .. j], - depths[index .. j], config, currentLineLength, indentLevel); + depths[index .. j], config, currentLineLength, indentLevel); } else if (!currentIs(tok!")") && !currentIs(tok!"]") && (linebreakHints.canFindIndex(index - 1) - || (linebreakHints.length == 0 && currentLineLength > config.max_line_length))) + || (linebreakHints.length == 0 && currentLineLength > config.max_line_length))) { newline(); } @@ -479,8 +479,7 @@ private: body { parenDepth--; - if (parenDepth == 0) - indents.popWrapIndents(); + indents.popWrapIndents(); if (indents.topIs(tok!"(")) indents.pop(); @@ -686,7 +685,7 @@ private: a => tokenLength(a)).sum(); immutable bool multiline = l > config.dfmt_soft_max_line_length || tokens[index .. e].canFind!(a => a.type == tok!"comment" - || isBlockHeaderToken(a.type))(); + || isBlockHeaderToken(a.type))(); writeToken(); if (multiline) { @@ -762,7 +761,7 @@ private: write("}"); if (index + 1 < tokens.length && astInformation.doubleNewlineLocations.canFindIndex( - tokens[index].index) && !peekIs(tok!"}") + tokens[index].index) && !peekIs(tok!"}") && !peekIs(tok!";") && !peekIs(tok!"comment", false)) { simpleNewline(); @@ -1150,7 +1149,7 @@ private: } else if (!peekIs(tok!"}") && (linebreakHints.canFind(index) || (linebreakHints.length == 0 - && currentLineLength > config.dfmt_soft_max_line_length))) + && currentLineLength > config.dfmt_soft_max_line_length))) { pushWrapIndent(); writeToken(); @@ -1172,7 +1171,7 @@ private: { immutable size_t j = expressionEndIndex(i); linebreakHints = chooseLineBreakTokens(i, tokens[i .. j], depths[i .. j], - config, currentLineLength, indentLevel); + config, currentLineLength, indentLevel); } void regenLineBreakHintsIfNecessary(immutable size_t i) @@ -1215,7 +1214,7 @@ private: if (niBraceDepth > 0 && !peekBackIsSlashSlash() && hasCurrent && tokens[index].type == tok!"}" && !assumeSorted(astInformation.funLitEndLocations).equalRange( - tokens[index].index).empty) + tokens[index].index).empty) { write(" "); return; @@ -1279,6 +1278,7 @@ private: } else if (currentIs(tok!"{")) { + indents.dump(); indents.popWrapIndents(); if (peekBackIsSlashSlash() && peekBack2Is(tok!";")) { @@ -1298,7 +1298,7 @@ private: } while (sBraceDepth == 0 && indents.topIsTemp() && ((indents.top != tok!"if" - && indents.top != tok!"version") || !peekIs(tok!"else"))) + && indents.top != tok!"version") || !peekIs(tok!"else"))) { indents.pop(); } @@ -1329,10 +1329,12 @@ private: } else { + indents.dump(); if (indents.topIsTemp() && (peekBackIsOneOf(true, tok!"}", tok!";") && indents.top != tok!";")) indents.popTempIndents(); indentLevel = indents.indentLevel; + indents.dump(); } indent(); } diff --git a/src/dfmt/globmatch_editorconfig.d b/src/dfmt/globmatch_editorconfig.d index f171c71..28d3e75 100644 --- a/src/dfmt/globmatch_editorconfig.d +++ b/src/dfmt/globmatch_editorconfig.d @@ -10,15 +10,15 @@ import std.path : filenameCharCmp, isDirSeparator; // From std.path with changes: // * changes meaning to match all characters except '/' // ** added to take over the old meaning of * -bool globMatchEditorConfig(CaseSensitive cs = CaseSensitive.osDefault, C, Range) -(Range path, const(C)[] pattern) -@safe pure nothrow -if (isForwardRange!Range && isSomeChar!(ElementEncodingType!Range) && - isSomeChar!C && is(Unqual!C == Unqual!(ElementEncodingType!Range))) +bool globMatchEditorConfig(CaseSensitive cs = CaseSensitive.osDefault, C, Range)( + Range path, const(C)[] pattern) @safe pure nothrow if (isForwardRange!Range + && isSomeChar!(ElementEncodingType!Range) && isSomeChar!C + && is(Unqual!C == Unqual!(ElementEncodingType!Range))) in { // Verify that pattern[] is valid import std.algorithm : balancedParens; + assert(balancedParens(pattern, '[', ']', 0)); assert(balancedParens(pattern, '{', '}', 0)); } @@ -29,11 +29,13 @@ body static if (RC.sizeof == 1 && isSomeString!Range) { import std.utf : byChar; + return globMatchEditorConfig!cs(path.byChar, pattern); } else static if (RC.sizeof == 2 && isSomeString!Range) { import std.utf : byWchar; + return globMatchEditorConfig!cs(path.byWchar, pattern); } else @@ -44,134 +46,131 @@ body const pc = pattern[pi]; switch (pc) { - case '*': - if (pi < pattern.length-1 && pattern[pi+1] == '*') + case '*': + if (pi < pattern.length - 1 && pattern[pi + 1] == '*') + { + if (pi + 2 == pattern.length) + return true; + for (; !path.empty; path.popFront()) { - if (pi + 2 == pattern.length) + auto p = path.save; + if (globMatchEditorConfig!(cs, C)(p, pattern[pi + 2 .. pattern.length])) return true; - for (; !path.empty; path.popFront()) + } + return false; + } + else + { + if (pi + 1 == pattern.length) + return true; + for (; !path.empty; path.popFront()) + { + auto p = path.save; + //if (p[0].to!dchar.isDirSeparator() && !pattern[pi+1].isDirSeparator()) + // return false; + if (globMatchEditorConfig!(cs, C)(p, pattern[pi + 1 .. pattern.length])) + return true; + if (p[0].to!dchar.isDirSeparator()) + return false; + } + return false; + } + case '?': + if (path.empty) + return false; + path.popFront(); + break; + + case '[': + if (path.empty) + return false; + auto nc = path.front; + path.popFront(); + auto not = false; + ++pi; + if (pattern[pi] == '!') + { + not = true; + ++pi; + } + auto anymatch = false; + while (1) + { + const pc2 = pattern[pi]; + if (pc2 == ']') + break; + if (!anymatch && (filenameCharCmp!cs(nc, pc2) == 0)) + anymatch = true; + ++pi; + } + if (anymatch == not) + return false; + break; + + case '{': + // find end of {} section + auto piRemain = pi; + for (; piRemain < pattern.length && pattern[piRemain] != '}'; ++piRemain) + { + } + + if (piRemain < pattern.length) + ++piRemain; + ++pi; + + while (pi < pattern.length) + { + const pi0 = pi; + C pc3 = pattern[pi]; + // find end of current alternative + for (; pi < pattern.length && pc3 != '}' && pc3 != ','; ++pi) + { + pc3 = pattern[pi]; + } + + auto p = path.save; + if (pi0 == pi) + { + if (globMatchEditorConfig!(cs, C)(p, pattern[piRemain .. $])) { - auto p = path.save; - if (globMatchEditorConfig!(cs, C)(p, - pattern[pi + 2 .. pattern.length])) - return true; + return true; } - return false; + ++pi; } else { - if (pi + 1 == pattern.length) - return true; - for (; !path.empty; path.popFront()) - { - auto p = path.save; - //if (p[0].to!dchar.isDirSeparator() && !pattern[pi+1].isDirSeparator()) - // return false; - if (globMatchEditorConfig!(cs, C)(p, - pattern[pi + 1 .. pattern.length])) - return true; - if (p[0].to!dchar.isDirSeparator()) - return false; - } - return false; - } - case '?': - if (path.empty) - return false; - path.popFront(); - break; - - case '[': - if (path.empty) - return false; - auto nc = path.front; - path.popFront(); - auto not = false; - ++pi; - if (pattern[pi] == '!') - { - not = true; - ++pi; - } - auto anymatch = false; - while (1) - { - const pc2 = pattern[pi]; - if (pc2 == ']') - break; - if (!anymatch && (filenameCharCmp!cs(nc, pc2) == 0)) - anymatch = true; - ++pi; - } - if (anymatch == not) - return false; - break; - - case '{': - // find end of {} section - auto piRemain = pi; - for (; piRemain < pattern.length - && pattern[piRemain] != '}'; ++piRemain) - { } - - if (piRemain < pattern.length) - ++piRemain; - ++pi; - - while (pi < pattern.length) - { - const pi0 = pi; - C pc3 = pattern[pi]; - // find end of current alternative - for (; pi < pattern.length && pc3 != '}' && pc3 != ','; ++pi) - { - pc3 = pattern[pi]; - } - - auto p = path.save; - if (pi0 == pi) - { - if (globMatchEditorConfig!(cs, C)(p, pattern[piRemain..$])) - { - return true; - } - ++pi; - } - else - { - /* Match for: + /* Match for: * pattern[pi0..pi-1] ~ pattern[piRemain..$] */ - if (pattmp.ptr == null) - // Allocate this only once per function invocation. - // Should do it with malloc/free, but that would make it impure. - pattmp = new C[pattern.length]; + if (pattmp.ptr == null) // Allocate this only once per function invocation. + // Should do it with malloc/free, but that would make it impure. + pattmp = new C[pattern.length]; - const len1 = pi - 1 - pi0; - pattmp[0 .. len1] = pattern[pi0 .. pi - 1]; + const len1 = pi - 1 - pi0; + pattmp[0 .. len1] = pattern[pi0 .. pi - 1]; - const len2 = pattern.length - piRemain; - pattmp[len1 .. len1 + len2] = pattern[piRemain .. $]; + const len2 = pattern.length - piRemain; + pattmp[len1 .. len1 + len2] = pattern[piRemain .. $]; - if (globMatchEditorConfig!(cs, C)(p, pattmp[0 .. len1 + len2])) - { - return true; - } - } - if (pc3 == '}') + if (globMatchEditorConfig!(cs, C)(p, pattmp[0 .. len1 + len2])) { - break; + return true; } } - return false; + if (pc3 == '}') + { + break; + } + } + return false; - default: - if (path.empty) - return false; - if (filenameCharCmp!cs(pc, path.front) != 0) - return false; - path.popFront(); - break; + default: + if (path.empty) + return false; + if (filenameCharCmp!cs(pc, path.front) != 0) + return false; + path.popFront(); + break; } } return path.empty; @@ -180,8 +179,8 @@ body unittest { - assert (globMatchEditorConfig!(CaseSensitive.no)("foo", "Foo")); - assert (!globMatchEditorConfig!(CaseSensitive.yes)("foo", "Foo")); + assert(globMatchEditorConfig!(CaseSensitive.no)("foo", "Foo")); + assert(!globMatchEditorConfig!(CaseSensitive.yes)("foo", "Foo")); assert(globMatchEditorConfig("foo", "*")); assert(globMatchEditorConfig("foo.bar"w, "*"w)); @@ -225,7 +224,7 @@ unittest assert(!globMatchEditorConfig("foo", "foob")); assert(!globMatchEditorConfig("foo", "foo{b}")); - assert (globMatchEditorConfig(`foo/foo\bar`, "f**b**r")); + assert(globMatchEditorConfig(`foo/foo\bar`, "f**b**r")); assert(globMatchEditorConfig("foo", "**")); assert(globMatchEditorConfig("foo/bar", "foo/bar")); assert(globMatchEditorConfig("foo/bar", "foo/*")); @@ -235,6 +234,5 @@ unittest assert(!globMatchEditorConfig("/foo/bar/gluu/sar.png", "*/sar.png")); assert(!globMatchEditorConfig("/foo/bar/gluu/sar.png", "*/*.png")); - static assert(globMatchEditorConfig("foo.bar", "[!gh]*bar")); } diff --git a/src/dfmt/indentation.d b/src/dfmt/indentation.d index ce7ab80..489f418 100644 --- a/src/dfmt/indentation.d +++ b/src/dfmt/indentation.d @@ -12,8 +12,8 @@ import dparse.lexer; */ bool isWrapIndent(IdType type) pure nothrow @nogc @safe { - return type != tok!"{" && type != tok!"case" && type != tok!"@" - && type != tok!"]" && type != tok!"(" && isOperator(type); + return type != tok!"{" && type != tok!"case" && type != tok!"@" + && type != tok!"]" && type != tok!"(" && isOperator(type); } /** @@ -151,6 +151,15 @@ struct IndentStack return cast(int) index; } + void dump() + { + /+import std.stdio : stderr; + import dparse.lexer : str; + import std.algorithm.iteration : map; + + stderr.writefln("\033[31m%(%s %)\033[0m", arr[0 .. index].map!(a => str(a)));+/ + } + private: size_t index; @@ -163,12 +172,24 @@ private: return 0; immutable size_t j = k == size_t.max ? index : k; int size = 0; + int parenCount; foreach (i; 0 .. j) { if (i + 1 < index) { - if (arr[i] == tok!"]") + if (arr[i] == tok!"(") + parenCount++; + else if (arr[i] == tok!"]") continue; + else + { + if (isWrapIndent(arr[i]) && parenCount > 0) + { + parenCount = 0; + continue; + } + //parenCount = 0; + } immutable currentIsNonWrapTemp = !isWrapIndent(arr[i]) && isTempIndent(arr[i]); immutable nextIsParenOrSwitch = arr[i + 1] == tok!"(" || arr[i + 1] == tok!"switch" || arr[i + 1] == tok!"{"; diff --git a/src/dfmt/main.d b/src/dfmt/main.d index 00fbeca..3a39b43 100644 --- a/src/dfmt/main.d +++ b/src/dfmt/main.d @@ -32,8 +32,10 @@ else { import dfmt.editorconfig : OptionalBoolean; import std.exception : enforceEx; + enforceEx!GetOptException(value == "true" || value == "false", "Invalid argument"); - immutable OptionalBoolean optVal = value == "true" ? OptionalBoolean.t : OptionalBoolean.f; + immutable OptionalBoolean optVal = value == "true" ? OptionalBoolean.t + : OptionalBoolean.f; switch (option) { case "align_switch_statements": @@ -54,7 +56,8 @@ else case "compact_labeled_statements": optConfig.dfmt_compact_labeled_statements = optVal; break; - default: assert(false, "Invalid command-line switch"); + default: + assert(false, "Invalid command-line switch"); } } @@ -113,17 +116,19 @@ else return 1; File output = stdout; - version(Windows) + version (Windows) { // On Windows, set stdout to binary mode (needed for correct EOL writing) // See Phobos' stdio.File.rawWrite { import std.stdio; + immutable fd = fileno(output.getFP()); setmode(fd, _O_BINARY); - version(CRuntime_DigitalMars) + version (CRuntime_DigitalMars) { import core.atomic : atomicOp; + atomicOp!"&="(__fhnd_info[fd], ~FHND_TEXT); } } @@ -176,15 +181,18 @@ else } } -private string optionsToString(E)() if(is(E == enum)) { - import std.traits:EnumMembers; - import std.conv; - string result = "["; - foreach(i, option; EnumMembers!E) { - result ~= to!string(option) ~ "|"; - } - result = result[0 .. $-1] ~ "]"; - return result; +private string optionsToString(E)() if (is(E == enum)) +{ + import std.traits : EnumMembers; + import std.conv; + + string result = "["; + foreach (i, option; EnumMembers!E) + { + result ~= to!string(option) ~ "|"; + } + result = result[0 .. $ - 1] ~ "]"; + return result; } private void printHelp() @@ -199,11 +207,13 @@ Options: Formatting Options: --align_switch_statements - --brace_style `, optionsToString!(typeof(Config.dfmt_brace_style))(), ` + --brace_style `, + optionsToString!(typeof(Config.dfmt_brace_style))(), ` --end_of_line --help|h --indent_size - --indent_style|t `, optionsToString!(typeof(Config.indent_style))(), ` + --indent_style|t `, + optionsToString!(typeof(Config.indent_style))(), ` --soft_max_line_length --max_line_length --outdent_attributes @@ -211,7 +221,8 @@ Formatting Options: --selective_import_space --split_operator_at_line_end --compact_labeled_statements - --template_constraint_style `, optionsToString!(typeof(Config.dfmt_template_constraint_style))()); + --template_constraint_style `, + optionsToString!(typeof(Config.dfmt_template_constraint_style))()); } private string createFilePath(bool readFromStdin, string fileName) diff --git a/src/dfmt/tokens.d b/src/dfmt/tokens.d index 8ef032c..0a6f768 100644 --- a/src/dfmt/tokens.d +++ b/src/dfmt/tokens.d @@ -195,7 +195,6 @@ pure nothrow @safe @nogc unittest assert(breakCost(tok!".", u) != 1000); } - private string generateFixedLengthCases() { import std.algorithm : map; @@ -205,11 +204,11 @@ private string generateFixedLengthCases() assert(__ctfe); string[] spacedOperatorTokens = [ - ",", "..", "...", "/", "/=", "!", "!<", "!<=", "!<>", "!<>=", "!=", "!>", - "!>=", "%", "%=", "&", "&&", "&=", "*", "*=", "+", "+=", "-", "-=", ":", - ";", "<", "<<", "<<=", "<=", "<>", "<>=", "=", "==", "=>", ">", ">=", - ">>", ">>=", ">>>", ">>>=", "?", "@", "^", "^=", "^^", "^^=", "|", "|=", "||", - "~", "~=" + ",", "..", "...", "/", "/=", "!", "!<", "!<=", "!<>", "!<>=", "!=", + "!>", "!>=", "%", "%=", "&", "&&", "&=", "*", "*=", "+", "+=", "-", + "-=", ":", ";", "<", "<<", "<<=", "<=", "<>", "<>=", "=", "==", "=>", + ">", ">=", ">>", ">>=", ">>>", ">>>=", "?", "@", "^", "^=", "^^", + "^^=", "|", "|=", "||", "~", "~=" ]; immutable spacedOperatorTokenCases = spacedOperatorTokens.map!( a => format(`case tok!"%s": return %d + 1;`, a, a.length)).join("\n\t"); @@ -219,20 +218,21 @@ private string generateFixedLengthCases() "break", "byte", "case", "cast", "catch", "cdouble", "cent", "cfloat", "char", "class", "const", "continue", "creal", "dchar", "debug", "default", "delegate", "delete", "deprecated", "do", "double", "else", - "enum", "export", "extern", "false", "final", "finally", "float", "for", - "foreach", "foreach_reverse", "function", "goto", "idouble", "if", - "ifloat", "immutable", "import", "in", "inout", "int", "interface", - "invariant", "ireal", "is", "lazy", "long", "macro", "mixin", "module", - "new", "nothrow", "null", "out", "override", "package", "pragma", - "private", "protected", "public", "pure", "real", "ref", "return", - "scope", "shared", "short", "static", "struct", "super", "switch", - "synchronized", "template", "this", "throw", "true", "try", "typedef", - "typeid", "typeof", "ubyte", "ucent", "uint", "ulong", "union", - "unittest", "ushort", "version", "void", "volatile", "wchar", "while", - "with", "__DATE__", "__EOF__", "__FILE__", "__FUNCTION__", "__gshared", - "__LINE__", "__MODULE__", "__parameters", "__PRETTY_FUNCTION__", - "__TIME__", "__TIMESTAMP__", "__traits", "__vector", "__VENDOR__", - "__VERSION__", "$", "++", "--", ".", "[", "]", "(", ")", "{", "}" + "enum", "export", "extern", "false", "final", "finally", "float", + "for", "foreach", "foreach_reverse", "function", "goto", "idouble", + "if", "ifloat", "immutable", "import", "in", "inout", "int", + "interface", "invariant", "ireal", "is", "lazy", "long", "macro", + "mixin", "module", "new", "nothrow", "null", "out", "override", + "package", "pragma", "private", "protected", "public", "pure", "real", + "ref", "return", "scope", "shared", "short", "static", "struct", + "super", "switch", "synchronized", "template", "this", "throw", "true", + "try", "typedef", "typeid", "typeof", "ubyte", "ucent", "uint", + "ulong", "union", "unittest", "ushort", "version", "void", "volatile", + "wchar", "while", "with", "__DATE__", "__EOF__", "__FILE__", + "__FUNCTION__", "__gshared", "__LINE__", "__MODULE__", "__parameters", + "__PRETTY_FUNCTION__", "__TIME__", "__TIMESTAMP__", "__traits", + "__vector", "__VENDOR__", "__VERSION__", "$", "++", "--", ".", "[", + "]", "(", ")", "{", "}" ]; immutable identifierTokenCases = identifierTokens.map!( a => format(`case tok!"%s": return %d;`, a, a.length)).join("\n\t"); diff --git a/src/dfmt/wrapping.d b/src/dfmt/wrapping.d index a42c5da..52ca119 100644 --- a/src/dfmt/wrapping.d +++ b/src/dfmt/wrapping.d @@ -12,13 +12,14 @@ import dfmt.config; struct State { this(uint breaks, const Token[] tokens, immutable short[] depths, - const Config* config, int currentLineLength, int indentLevel) pure @safe + const Config* config, int currentLineLength, int indentLevel) pure @safe { import std.math : abs; import core.bitop : popcnt, bsf; import std.algorithm : min, map, sum; - immutable int remainingCharsMultiplier = config.max_line_length - config.dfmt_soft_max_line_length; + immutable int remainingCharsMultiplier = config.max_line_length + - config.dfmt_soft_max_line_length; immutable int newlinePenalty = remainingCharsMultiplier * 20; this.breaks = breaks; @@ -119,7 +120,7 @@ private: } size_t[] chooseLineBreakTokens(size_t index, const Token[] tokens, - immutable short[] depths, const Config* config, int currentLineLength, int indentLevel) + immutable short[] depths, const Config* config, int currentLineLength, int indentLevel) { import std.container.rbtree : RedBlackTree; import std.algorithm : filter, min; @@ -139,7 +140,7 @@ size_t[] chooseLineBreakTokens(size_t index, const Token[] tokens, immutable size_t tokensEnd = min(tokens.length, ALGORITHMIC_COMPLEXITY_SUCKS); auto open = new RedBlackTree!State; open.insert(State(0, tokens[0 .. tokensEnd], depths[0 .. tokensEnd], config, - currentLineLength, indentLevel)); + currentLineLength, indentLevel)); State lowest; while (!open.empty) { @@ -152,7 +153,8 @@ size_t[] chooseLineBreakTokens(size_t index, const Token[] tokens, return genRetVal(current.breaks, index); } validMoves!(typeof(open))(open, tokens[0 .. tokensEnd], - depths[0 .. tokensEnd], current.breaks, config, currentLineLength, indentLevel); + depths[0 .. tokensEnd], current.breaks, config, currentLineLength, + indentLevel); } if (open.empty) return genRetVal(lowest.breaks, index); @@ -162,8 +164,8 @@ size_t[] chooseLineBreakTokens(size_t index, const Token[] tokens, } void validMoves(OR)(auto ref OR output, const Token[] tokens, - immutable short[] depths, uint current, const Config* config, - int currentLineLength, int indentLevel) + immutable short[] depths, uint current, const Config* config, + int currentLineLength, int indentLevel) { import std.algorithm : sort, canFind; import std.array : insertInPlace; diff --git a/tests/allman/parenIndent.d.ref b/tests/allman/parenIndent.d.ref new file mode 100644 index 0000000..03620de --- /dev/null +++ b/tests/allman/parenIndent.d.ref @@ -0,0 +1,36 @@ +unittest +{ + if (a) + { + while (sBraceDepth == 0 && indents.topIsTemp() + && ((indents.top != tok!"if" && indents.top != tok!"version") + || !peekIs(tok!"else"))) + { + a(); + } + } + + if (parenDepth == 0 && (peekIs(tok!"is") || peekIs(tok!"in") + || peekIs(tok!"out") || peekIs(tok!"body"))) + writeToken(); + + { + { + while (sBraceDepth == 0 && indents.topIsTemp() + && ((indents.top != tok!"if" + && indents.top != tok!"version") || !peekIs(tok!"else"))) + { + indents.pop(); + } + } + } + + { + while (sBraceDepth == 0 && indents.topIsTemp() + && ((indents.top != tok!"if" && indents.top != tok!"version") + || !peekIs(tok!"else"))) + { + indents.pop(); + } + } +} diff --git a/tests/allman/wrapping1.d.ref b/tests/allman/wrapping1.d.ref index e8746a0..320b14b 100644 --- a/tests/allman/wrapping1.d.ref +++ b/tests/allman/wrapping1.d.ref @@ -4,6 +4,6 @@ void main(string[] args) { addErrorMessage(line, column, KEY, "Expression %s is true: already checked on line %d.".format( - expressions[prevLocation].formatted, expressions[prevLocation].line)); + expressions[prevLocation].formatted, expressions[prevLocation].line)); } } diff --git a/tests/otbs/parenIndent.d.ref b/tests/otbs/parenIndent.d.ref new file mode 100644 index 0000000..053585f --- /dev/null +++ b/tests/otbs/parenIndent.d.ref @@ -0,0 +1,31 @@ +unittest { + if (a) { + while (sBraceDepth == 0 && indents.topIsTemp() + && ((indents.top != tok!"if" && indents.top != tok!"version") + || !peekIs(tok!"else"))) { + a(); + } + } + + if (parenDepth == 0 && (peekIs(tok!"is") || peekIs(tok!"in") + || peekIs(tok!"out") || peekIs(tok!"body"))) + writeToken(); + + { + { + while (sBraceDepth == 0 && indents.topIsTemp() + && ((indents.top != tok!"if" + && indents.top != tok!"version") || !peekIs(tok!"else"))) { + indents.pop(); + } + } + } + + { + while (sBraceDepth == 0 && indents.topIsTemp() + && ((indents.top != tok!"if" && indents.top != tok!"version") + || !peekIs(tok!"else"))) { + indents.pop(); + } + } +} diff --git a/tests/otbs/wrapping1.d.ref b/tests/otbs/wrapping1.d.ref index 352e1cc..1e3b571 100644 --- a/tests/otbs/wrapping1.d.ref +++ b/tests/otbs/wrapping1.d.ref @@ -2,6 +2,6 @@ void main(string[] args) { if (prevLocation != size_t.max) { addErrorMessage(line, column, KEY, "Expression %s is true: already checked on line %d.".format( - expressions[prevLocation].formatted, expressions[prevLocation].line)); + expressions[prevLocation].formatted, expressions[prevLocation].line)); } } diff --git a/tests/parenIndent.d b/tests/parenIndent.d new file mode 100644 index 0000000..cce0da9 --- /dev/null +++ b/tests/parenIndent.d @@ -0,0 +1,32 @@ +unittest +{ + if (a) + { + while (sBraceDepth == 0 && indents.topIsTemp() + && ((indents.top != tok!"if" && indents.top != tok!"version")|| !peekIs(tok!"else"))) + { + a(); + } + } + + if (parenDepth == 0 && (peekIs(tok!"is") || peekIs(tok!"in") + || peekIs(tok!"out") || peekIs(tok!"body"))) + writeToken(); + + { + { + while (sBraceDepth == 0 && indents.topIsTemp()&& ((indents.top != tok!"if" +&& indents.top != tok!"version") || !peekIs(tok!"else"))) + { + indents.pop(); + } + } + } + + { + while (sBraceDepth == 0 && indents.topIsTemp()&& ((indents.top != tok!"if" && indents.top != tok!"version") || !peekIs(tok!"else"))) + { + indents.pop(); + } + } +}