importsort-d

Sort and format imports in DLang
Log | Files | Refs | README

commit bfef09fa451dee524bbfb98f579ec2f801063376
parent f9d2d8c3cdbfeb1e48e0a7efbe8ebeb9ffa46e59
Author: Friedel Schön <[email protected]>
Date:   Fri, 22 Dec 2023 20:48:50 +0100

keep original formatting

Diffstat:
Msrc/main.d | 48+++++++++++++++---------------------------------
Msrc/sort.d | 124+++++++++++++++++++++++++------------------------------------------------------
2 files changed, 54 insertions(+), 118 deletions(-)

diff --git a/src/main.d b/src/main.d @@ -13,39 +13,28 @@ import std.range : empty; import std.string : endsWith; /// list entries (`ls`) from all arguments -DirEntry[] listEntries(alias F = "true")(string[] input, bool recursive) -{ +DirEntry[] listEntries(alias F = "true")(string[] input, bool recursive) { alias filterFunc = unaryFun!F; DirEntry[] entries; - foreach (path; input) - { - if (!exists(path)) - { + foreach (path; input) { + if (!exists(path)) { stderr.writef("error: '%s' does not exist\n", path); exit(19); - } - else if (isDir(path)) - { - foreach (entry; dirEntries(path, recursive ? SpanMode.depth : SpanMode.shallow)) - { + } else if (isDir(path)) { + foreach (entry; dirEntries(path, recursive ? SpanMode.depth : SpanMode.shallow)) { if (entry.isFile && entry.name.endsWith(".d") && filterFunc(entry.name)) entries ~= entry; } - } - else if (isFile(path)) - { - if (!path.endsWith(".d")) - { + } else if (isFile(path)) { + if (!path.endsWith(".d")) { stderr.writef("error: '%s' is not a .d-file\n", path); exit(11); } if (filterFunc(path)) entries ~= DirEntry(path); - } - else - { + } else { stderr.writef("error: '%s' is not a file or directory\n", path); exit(12); } @@ -53,32 +42,25 @@ DirEntry[] listEntries(alias F = "true")(string[] input, bool recursive) return entries; } -int _main(SortConfig config) -{ - if (config.recursive && config.inputs.empty) - { +int _main(SortConfig config) { + if (config.recursive && config.inputs.empty) { stderr.writeln("error: cannot use '--recursive' and specify no input"); exit(1); } - if (config.inplace && config.inputs.empty) - { + if (config.inplace && config.inputs.empty) { stderr.writeln("error: cannot use inplace and read from stdin"); exit(2); } - if (!config.inputs.empty && (!config.inplace || !config.output.empty)) - { + if (!config.inputs.empty && (!config.inplace || !config.output.empty)) { stderr.writeln( - "error: if you use inputs you must use inplace sorting or provide an output"); + "error: if you use inputs you must use inplace sorting or provide an output"); exit(3); } - if (config.inputs.empty) - { + if (config.inputs.empty) { auto outfile = config.output.empty ? stdout : File(config.output); sortImports(stdin, outfile, config); - } - else - { + } else { listEntries(config.inputs, config.recursive).sortImports(config); } return 0; diff --git a/src/sort.d b/src/sort.d @@ -19,10 +19,8 @@ enum VERSION = "0.3.0"; /// configuration for sorting imports @(Command("importsort-d").Description("Sorts dlang imports").Epilog("Version: v" ~ VERSION)) -struct SortConfig -{ - @(ArgumentGroup("Input/Output arguments").Description("Define in- and output behavior")) - { +struct SortConfig { + @(ArgumentGroup("Input/Output arguments").Description("Define in- and output behavior")) { @(NamedArgument(["recursive", "r"]).Description("recursively search in directories")) bool recursive = false; @@ -37,8 +35,7 @@ struct SortConfig string[] inputs; } - @(ArgumentGroup("Sorting arguments").Description("Tune import sorting algorithms")) - { + @(ArgumentGroup("Sorting arguments").Description("Tune import sorting algorithms")) { /// won't format the line, keep it as-is @(NamedArgument(["keep", "k"]).Description("keeps the line as-is instead of formatting")) bool keepLine = false; @@ -66,8 +63,7 @@ struct SortConfig enum PATTERN = ctRegex!`^(\s*)(?:(public|static)\s+)?import\s+(?:(\w+)\s*=\s*)?([a-zA-Z._]+)\s*(:\s*\w+(?:\s*=\s*\w+)?(?:\s*,\s*\w+(?:\s*=\s*\w+)?)*)?\s*;[ \t]*([\n\r]*)$`; /// helper-struct for identifiers and its bindings -struct Identifier -{ +struct Identifier { /// SortConfig::byBinding bool byBinding; @@ -78,14 +74,12 @@ struct Identifier string binding; /// wether this import has a binding or not - @property bool hasBinding() - { + @property bool hasBinding() { return binding != null; } /// the string to sort - string sortBy() - { + string sortBy() { if (byBinding) return hasBinding ? binding : original; else @@ -94,8 +88,7 @@ struct Identifier } /// the import statement description -struct Import -{ +struct Import { /// SortConfig::byAttribute bool byAttribute; @@ -121,34 +114,27 @@ struct Import string end; /// the string to sort - string sortBy() - { + string sortBy() { if (byAttribute && (public_ || static_)) return '\0' ~ name.sortBy; return name.sortBy; } } -bool less(SortConfig config, string a, string b) -{ +bool less(SortConfig config, string a, string b) { return config.ignoreCase ? a.asLowerCase.to!string < b.asLowerCase.to!string : a < b; } /// write import-statements to `outfile` with `config` -void writeImports(File outfile, SortConfig config, Import[] matches) -{ +void writeImports(File outfile, SortConfig config, Import[] matches) { if (!matches) return; - if (config.merge) - { - for (int i = 0; i < matches.length; i++) - { - for (int j = i + 1; j < matches.length; j++) - { + if (config.merge) { + for (int i = 0; i < matches.length; i++) { + for (int j = i + 1; j < matches.length; j++) { if (matches[i].name.original == matches[j].name.original - && matches[i].name.binding == matches[j].name.binding) - { + && matches[i].name.binding == matches[j].name.binding) { matches[i].line = null; matches[i].idents ~= matches[j].idents; @@ -162,38 +148,27 @@ void writeImports(File outfile, SortConfig config, Import[] matches) matches.sort!((a, b) => less(config, a.sortBy, b.sortBy)); bool first; - foreach (m; matches) - { - if (config.keepLine && m.line.length > 0) - { + foreach (m; matches) { + if (config.keepLine && m.line.length > 0) { outfile.write(m.line); - } - else - { + } else { outfile.write(m.begin); if (m.public_) outfile.write("public "); if (m.static_) outfile.write("static "); - if (m.name.hasBinding) - { + if (m.name.hasBinding) { outfile.writef("import %s = %s", m.name.binding, m.name.original); - } - else - { + } else { outfile.write("import " ~ m.name.original); } first = true; - foreach (ident; m.idents) - { + foreach (ident; m.idents) { auto begin = first ? " : " : ", "; first = false; - if (ident.hasBinding) - { // hasBinding + if (ident.hasBinding) { // hasBinding outfile.writef("%s%s = %s", begin, ident.binding, ident.original); - } - else - { + } else { outfile.write(begin ~ ident.original); } } @@ -204,13 +179,11 @@ void writeImports(File outfile, SortConfig config, Import[] matches) /// sort imports of an entry (file) (entries: DirEntry[]) void sortImports(alias P = "true", R)(R entries, SortConfig config) - if (isIterable!R && is(ElementType!R == DirEntry)) -{ + if (isIterable!R && is(ElementType!R == DirEntry)) { alias postFunc = unaryFun!P; File infile, outfile; - foreach (entry; entries) - { + foreach (entry; entries) { stderr.writef("\033[34msorting \033[0;1m%s\033[0m\n", entry.name); infile = File(entry.name); @@ -228,30 +201,23 @@ void sortImports(alias P = "true", R)(R entries, SortConfig config) } /// raw-implementation of sort file (infile -> outfile) -void sortImports(File infile, File outfile, SortConfig config) -{ +void sortImports(File infile, File outfile, SortConfig config) { string softEnd = null; Import[] matches; - foreach (line; infile.byLine(Yes.keepTerminator)) - { + foreach (line; infile.byLine(Yes.keepTerminator)) { auto linestr = line.idup; - if (auto match = linestr.matchFirst(PATTERN)) - { // is import - if (softEnd) - { + if (auto match = linestr.matchFirst(PATTERN)) { // is import + if (softEnd) { if (!matches) outfile.write(softEnd); softEnd = null; } auto im = Import(config.byAttribute, linestr); - if (match[3]) - { + if (match[3]) { im.name = Identifier(config.byBinding, match[4], match[3]); - } - else - { + } else { im.name = Identifier(config.byBinding, match[4]); } im.begin = match[1]; @@ -262,38 +228,26 @@ void sortImports(File infile, File outfile, SortConfig config) else if (match[2] == "public") im.public_ = true; - if (match[5]) - { - foreach (id; match[5][1 .. $].split(",")) - { - if (auto pair = id.findSplit("=")) - { // has alias + if (match[5]) { + foreach (id; match[5][1 .. $].split(",")) { + if (auto pair = id.findSplit("=")) { // has alias im.idents ~= Identifier(config.byBinding, pair[2].strip, pair[0].strip); - } - else - { + } else { im.idents ~= Identifier(config.byBinding, id.strip); } } im.idents.sort!((a, b) => less(config, a.sortBy, b.sortBy)); } matches ~= im; - } - else - { - if (!softEnd && linestr.stripLeft == "") - { + } else { + if (!softEnd && linestr.stripLeft == "") { softEnd = linestr; - } - else - { - if (matches) - { + } else { + if (matches) { outfile.writeImports(config, matches); matches = []; } - if (softEnd) - { + if (softEnd) { outfile.write(softEnd); softEnd = null; }