importsort-d

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

commit 6975f2ba3a28296e29591b89ea106901b3e5cdc8
parent 24ff863c360f25b4d0d357c9b255278db0763223
Author: Friedel Schön <[email protected]>
Date:   Sat, 23 Dec 2023 20:00:36 +0100

DO NOT TOUCH! do not overwrite untouched files issue #5

Diffstat:
Msrc/main.d | 11++++++-----
Msrc/sort.d | 86+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
2 files changed, 66 insertions(+), 31 deletions(-)

diff --git a/src/main.d b/src/main.d @@ -1,4 +1,4 @@ -// (c) 2022 Friedel Schon <[email protected]> +// (c) 2022-2023 Friedel Schon <[email protected]> module importsort.main; @@ -6,11 +6,12 @@ import argparse; import core.stdc.stdlib : exit; import importsort.sort : Import, sortImports; import std.array : replace; -import std.file : dirEntries, DirEntry, exists, isDir, isFile, SpanMode; +import std.file : DirEntry, SpanMode, dirEntries, exists, isDir, isFile; import std.functional : unaryFun; import std.range : empty; import std.stdio : File, stderr, stdin, stdout; import std.string : endsWith; +import std.typecons : nullable; /// current version (and something I always forget to update oops) enum VERSION = "0.3.3"; @@ -30,7 +31,7 @@ struct SortConfig { @(NamedArgument(["output", "o"]).Description("writes to `path` instead of stdout")) string output; - @(PositionalArgument(0).Description("inputfiles or folders, use - for stdin")) + @(PositionalArgument(0).Description("inputfiles or directories, use - for stdin")) string[] inputs; } @@ -87,7 +88,7 @@ DirEntry[] listEntries(alias F = "true")(string[] input, bool recursive) { return entries; } -mixin CLI!(SortConfig).main!((config) { +mixin CLI!(SortConfig).main!((SortConfig config) { if (config.recursive && config.inputs.empty) { stderr.writeln("error: cannot use '--recursive' and specify no input"); exit(1); @@ -104,7 +105,7 @@ mixin CLI!(SortConfig).main!((config) { if (config.inputs.empty) { auto outfile = config.output.empty ? stdout : File(config.output); - sortImports(stdin, outfile, config); + sortImports(config, stdin, nullable(outfile)); } else { listEntries(config.inputs, config.recursive).sortImports(config); } diff --git a/src/sort.d b/src/sort.d @@ -1,7 +1,10 @@ +// (c) 2022-2023 Friedel Schon <[email protected]> + module importsort.sort; import importsort.main : SortConfig; import std.algorithm : findSplit, remove, sort; +import std.algorithm.comparison : equal; import std.array : split; import std.conv : to; import std.file : DirEntry, rename; @@ -11,7 +14,7 @@ import std.regex : ctRegex, matchFirst; import std.stdio : File, stderr; import std.string : strip, stripLeft; import std.traits : isIterable; -import std.typecons : Yes; +import std.typecons : Nullable, Yes, nullable; import std.uni : asLowerCase; /// the pattern to determinate a line is an import or not @@ -80,11 +83,7 @@ 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) { - if (!matches) - return; - +void sortMatches(SortConfig config, Import[] matches) { if (config.merge) { for (int i = 0; i < matches.length; i++) { for (int j = i + 1; j < matches.length; j++) { @@ -101,6 +100,29 @@ void writeImports(File outfile, SortConfig config, Import[] matches) { } matches.sort!((a, b) => less(config, a.sortBy, b.sortBy)); + + foreach (m; matches) + m.idents.sort!((a, b) => less(config, a.sortBy, b.sortBy)); +} + +bool checkChanged(SortConfig config, Import[] matches) { + if (!matches) + return false; + + auto original = matches.dup; + + sortMatches(config, matches); + + return !equal(original, matches); +} + +/// write import-statements to `outfile` with `config` +void writeImports(File outfile, SortConfig config, Import[] matches) { + if (!matches) + return; + + sortMatches(config, matches); + bool first; foreach (m; matches) { @@ -133,30 +155,29 @@ 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) +void sortImports(R)(R entries, SortConfig config) if (isIterable!R && is(ElementType!R == DirEntry)) { - alias postFunc = unaryFun!P; File infile, outfile; foreach (entry; entries) { - stderr.writef("\033[34msorting \033[0;1m%s\033[0m\n", entry.name); - infile = File(entry.name); - outfile = File(entry.name ~ ".new", "w"); - sortImports(infile, outfile, config); + if (sortImports(config, infile, Nullable!(File).init)) { // is changed + infile.seek(0); + outfile = File(entry.name ~ ".new", "w"); + sortImports(config, infile, nullable(outfile)); + rename(entry.name ~ ".new", entry.name); + stderr.writef("\033[34msorted \033[0;1m%s\033[0m\n", entry.name); + outfile.close(); + } else { + stderr.writef("\033[33munchanged \033[0;1m%s\033[0m\n", entry.name); + } infile.close(); - outfile.close(); - - rename(entry.name ~ ".new", entry.name); - - cast(void) postFunc(entry.name); } } -/// raw-implementation of sort file (infile -> outfile) -void sortImports(File infile, File outfile, SortConfig config) { +bool sortImports(SortConfig config, File infile, Nullable!File outfile) { string softEnd = null; Import[] matches; @@ -164,8 +185,8 @@ void sortImports(File infile, File outfile, SortConfig config) { auto linestr = line.idup; if (auto match = linestr.matchFirst(PATTERN)) { // is import if (softEnd) { - if (!matches) - outfile.write(softEnd); + if (!matches && !outfile.isNull) + outfile.get().write(softEnd); softEnd = null; } @@ -191,7 +212,6 @@ void sortImports(File infile, File outfile, SortConfig config) { im.idents ~= Identifier(config.byBinding, id.strip); } } - im.idents.sort!((a, b) => less(config, a.sortBy, b.sortBy)); } matches ~= im; } else { @@ -199,16 +219,30 @@ void sortImports(File infile, File outfile, SortConfig config) { softEnd = linestr; } else { if (matches) { - outfile.writeImports(config, matches); + if (!outfile.isNull) + outfile.get().writeImports(config, matches); + else if (checkChanged(config, matches)) + return true; + matches = []; } if (softEnd) { - outfile.write(softEnd); + if (!outfile.isNull) + outfile.get().write(softEnd); softEnd = null; } - outfile.write(line); + if (!outfile.isNull) + outfile.get().write(line); } } } - outfile.writeImports(config, matches); + + // flush last imports + + if (!outfile.isNull) + outfile.get().writeImports(config, matches); + else if (checkChanged(config, matches)) + return true; + + return false; }