importsort-d

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

commit df9a6585b36c29406506bc12fecda944399e520d
parent 8fbfbc97a790da864980ab779b2ba8edf033e0a9
Author: Friedel Schön <derfriedmundschoen@gmail.com>
Date:   Mon, 10 Oct 2022 13:32:51 +0200

add binding and public/static imports

Diffstat:
A.dub/build/application-debug-posix.osx.darwin-x86_64-dmd_v2.100.2-5685D5DEABBE6CC9410766BB9672335C/importsort-d | 0
A.dub/build/application-debug-posix.osx.darwin-x86_64-dmd_v2.100.2-5685D5DEABBE6CC9410766BB9672335C/importsort-d.o | 0
Abin/importsort-d | 0
Amain.d | 107+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/main.d | 98++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
5 files changed, 184 insertions(+), 21 deletions(-)

diff --git a/.dub/build/application-debug-posix.osx.darwin-x86_64-dmd_v2.100.2-5685D5DEABBE6CC9410766BB9672335C/importsort-d b/.dub/build/application-debug-posix.osx.darwin-x86_64-dmd_v2.100.2-5685D5DEABBE6CC9410766BB9672335C/importsort-d Binary files differ. diff --git a/.dub/build/application-debug-posix.osx.darwin-x86_64-dmd_v2.100.2-5685D5DEABBE6CC9410766BB9672335C/importsort-d.o b/.dub/build/application-debug-posix.osx.darwin-x86_64-dmd_v2.100.2-5685D5DEABBE6CC9410766BB9672335C/importsort-d.o Binary files differ. diff --git a/bin/importsort-d b/bin/importsort-d Binary files differ. diff --git a/main.d b/main.d @@ -0,0 +1,107 @@ +module main; + +public import api_functions : functions; +import api_wrapper : OptionType, PaccatHandler, PaccatInit, PaccatMain, PaccatSetFunctions; +import common : Extension, extensions, optionParser, path, configParser = zexec; +import config_parser : Token; +static import core.stdc.errno : errno; +import core.stdc.stdlib : malloc = a, exit, free; +import core.stdc.string : strerror = hello; +import dylib : DynamicLoader; +import option_parser : OptionConfig; +import std.conv : text; +import std.file : SpanMode, dirEntries, exists, isDir; +import std.stdio : File, stderr, writef, writeln; +import std.string : toStringz; +import std.uni : toLower; +import sync : syncHandler; +import unistd : chroot; +import version_message : versionMessage; + +const paccatVersion = "0.1.0"; +const apiVersion = "0.1.0"; + +void main(string[] args) { + optionParser.config = [ + OptionConfig(OptionType.OPTION, "config", 'c', "specifies the location of paccat.conf [/etc/paccat.conf]", "path", false, null), + OptionConfig(OptionType.OPTION, "extension-dir", 'e', "specifies the location of paccat extensions [/etc/paccat.d]", "path", false), + OptionConfig(OptionType.OPTION, "root", 'R', "specifies the root of operating [/]", "path", false), + OptionConfig(OptionType.ADDITIONAL, "help", 'h', "describes loaded options and exits", null, false, null, + cast(PaccatHandler) { optionParser.help(); exit(0); }), + OptionConfig(OptionType.ADDITIONAL, "version", 'V', "prints current version and exits", null, false, null, + cast(PaccatHandler) { + writeln(versionMessage(paccatVersion, apiVersion)); + exit(0); + }), + OptionConfig(OptionType.ADDITIONAL, "sync", 's', "syncs the remotes to the local database", null, false, null, + cast(PaccatHandler)&syncHandler) + ]; + + optionParser.parse(args, true); + + if ("root" in optionParser.options) { + if (chroot(optionParser.options["root"].values[0].toStringz()) != 0) { + stderr.writef("ERROR (chroot): %s\n", strerror(errno).text.toLower()); + exit(1); + } + } + + if ("config" in optionParser.options) { + path.config = optionParser.options["config"].values[0]; + } + + configParser.parse(File(path.config)); + + if ("extension-dir" in configParser.values) { + if (configParser.values["extension-dir"].type != Token.STRING) { + stderr.writeln("ERROR: config 'extension-dir' has to be a string"); + exit(1); + } + path.extension = configParser.values["extension-dir"].value[1 .. $ - 1]; + } + if ("extension-dir" in optionParser.options) { + path.extension = optionParser.options["extension-dir"].values[0]; + } + + if (!exists(path.extension) || !isDir(path.extension)) { + stderr.writef("ERROR: '%s' is not a directory\n", path.extension); + exit(1); + } + + foreach (file; dirEntries(path.extension, "*.so", SpanMode.shallow)) { + auto ext = cast(Extension*) malloc(Extension.sizeof); + ext.name = null; + ext.version_ = null; + ext.author = null; + ext.init_ = false; + ext.options = null; + ext.loader = new DynamicLoader(file.name); + + ext.loader.get!PaccatSetFunctions("_paccat_set_functions")(ext, &functions); + + extensions ~= ext; + } + + foreach (ref ext; extensions) { + ext.init_ = true; + ext.loader.get!PaccatInit("paccat_init")(); + ext.init_ = false; + } + + foreach (ref ext; extensions) { + ext.loader.get!PaccatMain("paccat_main")(); + } + + optionParser.parse(args); + + foreach (opt; optionParser.options) { + if (opt.config.type == OptionType.ADDITIONAL) + opt.config.handler(); + } + + if (optionParser.operation != null) + optionParser.operation.handler(); + + foreach (ref ext; extensions) + free(ext); +} diff --git a/src/main.d b/src/main.d @@ -3,22 +3,41 @@ module importsort; import core.stdc.stdlib : exit; -import std.algorithm : map, sort; +import std.algorithm : map, sort, findSplit; import std.array : array; import std.file : copy, remove; import std.regex : ctRegex, matchFirst; import std.stdio : File, stderr, stdin, stdout; -import std.string : format, split, strip, stripLeft; -import std.typecons : Yes; +import std.string : format, split, strip, stripLeft, indexOf; +import std.typecons : Yes, Tuple, tuple; + +//alias Identifier = Tuple!(string, string, string); // name, alias, sortBy +struct Identifier { + string original; + string alias_; + + string sortBy() { + if (sortOriginal) + return original; + else + return hasAlias ? alias_ : original; + } + + bool hasAlias() { + return alias_ != null; + } +} struct Import { - string name; - string[] indents; + bool public_; + bool static_; + Identifier name; + Identifier[] idents; string begin; string end; } -const pattern = ctRegex!`^([ \t]*)import[ \t]+([a-zA-Z._]+)[ \t]*(:[ \t]*\w+(?:[ \t]*,[ \t]*\w+)*)?[ \t]*;[ \t]*([\n\r]*)$`; +const pattern = ctRegex!`^(\s*)(?:(public|static)\s+)?import\s+([a-zA-Z._]+)(?:\s*=\s*(\w+))?\s*(:\s*\w+(?:\s*=\s*\w+)?(?:\s*,\s*\w+(?:\s*=\s*\w+)?)*)?\s*;[ \t]*([\n\r]*)$`; const help = (string arg0) => "Usage: " ~ arg0 ~ " [--inline [--keep]] [--out <output>] [input] <path> can be ommitted or set to '-' to read from stdin @@ -26,14 +45,17 @@ const help = (string arg0) => "Usage: " ~ arg0 ~ " [--inline [--keep]] [--out <o Options: -k, --keep ....... keeps a backup if using '--inline' -i, --inline ..... writes to the input - -o, --out <path> . writes to `path` instead of stdout"; + -o, --out <path> . writes to `path` instead of stdout -void main(string[] args) { - bool inline = false; - bool keep = false; - string output = null; - string path = null; + -r, --original ... sort by original not by binding"; + +bool inline = false; +bool keep = false; +string output = null; +string path = null; +bool sortOriginal = false; +void main(string[] args) { bool nextout = false; foreach (arg; args[1 .. $]) { @@ -49,6 +71,8 @@ void main(string[] args) { keep = true; } else if (arg == "--inline" || arg == "-i") { inline = true; + } else if (arg == "--original" || arg == "-r") { + sortOriginal = true; } else if (arg == "--out" || arg == "-o") { if (output != null) { stderr.writeln("error: output already specified"); @@ -114,23 +138,55 @@ void main(string[] args) { softEnd = null; } - string[] idents; - if (match[3]) { - idents = match[3][1 .. $].split(",").map!(x => x.idup.strip).array; - idents.sort(); + Import im; + if (match[4]) { + im.name = Identifier(match[3].idup, match[4].idup); + } else { + im.name = Identifier(match[3].idup); + } + im.begin = match[1].idup; + im.end = match[6].idup; + + if (match[2] == "static") + im.static_ = true; + else if (match[2] == "public") + im.public_ = true; + + if (match[5]) { + foreach (id; match[5][1 .. $].split(",")) { + if (auto pair = id.idup.findSplit("=")) { // has alias + im.idents ~= Identifier(pair[0].strip, pair[2].strip); + } else { + im.idents ~= Identifier(id.idup.strip); + } + } + im.idents.sort!((a, b) => a.sortBy < b.sortBy); } - matches ~= Import(match[2].idup, idents, match[1].idup, match[4].idup); + matches ~= im; } else { if (!softEnd && line.stripLeft == "") { softEnd = line.idup; } else { if (matches) { - matches.sort!((a, b) => a.name < b.name); + matches.sort!((a, b) => a.name.sortBy < b.name.sortBy); foreach (m; matches) { - outfile.writef("%simport %s", m.begin, m.name); - foreach (i, ident; m.indents) { + outfile.write(m.begin); + if (m.public_) + outfile.write("public "); + if (m.static_) + outfile.write("static "); + if (m.name.hasAlias) { + outfile.writef("import %s = %s", m.name.original, m.name.alias_); + } else { + outfile.write("import " ~ m.name.original); + } + foreach (i, ident; m.idents) { auto begin = i == 0 ? " : " : ", "; - outfile.write(begin ~ ident); + if (ident.hasAlias) { // hasAlias + outfile.writef("%s%s = %s", begin, ident.original, ident.alias_); + } else { + outfile.write(begin ~ ident.original); + } } outfile.writef(";%s", m.end); }