1 // (c) 2022 Friedel Schon <derfriedmundschoen@gmail.com> 2 3 module importsort.main; 4 5 import core.stdc.stdlib : exit; 6 import importsort.sort : Import, SortConfig, sortImports; 7 import std.array : replace; 8 import std.conv : ConvException, parse; 9 import std.file : DirEntry, SpanMode, dirEntries, exists, isDir, isFile; 10 import std.functional : unaryFun; 11 import std.stdio : File, stderr, stdin, stdout; 12 import std.string : endsWith; 13 14 /// name of binary (for help) 15 enum BINARY = "importsort-d"; 16 17 /// current version (and something I always forget to update oops) 18 enum VERSION = "0.3.0"; 19 20 /// the help-message from `help.txt` 21 enum HELP = import("help.txt") 22 .replace("{binary}", BINARY) 23 .replace("{version}", VERSION); 24 25 /// list entries (`ls`) from all arguments 26 DirEntry[] listEntries(alias F = "true")(string[] input, bool recursive) { 27 alias filterFunc = unaryFun!F; 28 29 DirEntry[] entries; 30 31 foreach (path; input) { 32 if (!exists(path)) { 33 stderr.writef("error: '%s' does not exist\n", path); 34 exit(1); 35 } else if (isDir(path)) { 36 foreach (entry; dirEntries(path, recursive ? SpanMode.depth : SpanMode.shallow)) { 37 if (entry.isFile && entry.name.endsWith(".d") && filterFunc(entry.name)) 38 entries ~= entry; 39 } 40 } else if (isFile(path)) { 41 if (!path.endsWith(".d")) { 42 stderr.writef("error: '%s' is not a .d-file\n", path); 43 exit(1); 44 } 45 if (filterFunc(path)) 46 entries ~= DirEntry(path); 47 } else { 48 stderr.writef("error: '%s' is not a file or directory\n", path); 49 exit(1); 50 } 51 } 52 return entries; 53 } 54 55 /// the main-function (nothing to explain) 56 void main(string[] args) { 57 SortConfig config; 58 bool inline; 59 string output; 60 string[] input; 61 bool watcher; 62 bool watcherDelaySet; 63 double watcherDelay = 0.1; // sec 64 bool recursive; 65 66 // -*- option parser -*- 67 68 bool nextOutput; 69 bool nextWatcherDelay; 70 foreach (arg; args[1 .. $]) { 71 if (nextOutput) { 72 output = arg; 73 nextOutput = false; 74 } else if (nextWatcherDelay) { 75 try { 76 watcherDelay = parse!double(arg); 77 } catch (ConvException) { 78 stderr.writef("error: cannot parse delay '%s' to an integer\n", arg); 79 exit(1); 80 } 81 watcherDelaySet = true; 82 nextWatcherDelay = false; 83 } else if (arg == "--help" || arg == "-h") { 84 stdout.writeln(HELP); 85 return; 86 } else if (arg == "--verbose" || arg == "-v") { 87 config.verbose = true; 88 } else if (arg == "--keep" || arg == "-k") { 89 config.keepLine = true; 90 } else if (arg == "--attribute" || arg == "-a") { 91 config.byAttribute = true; 92 } else if (arg == "--binding" || arg == "-b") { 93 config.byBinding = true; 94 } else if (arg == "--merge" || arg == "-m") { 95 config.merge = true; 96 } else if (arg == "--inline" || arg == "-i") { 97 inline = true; 98 } else if (arg == "--recursive" || arg == "-r") { 99 recursive = true; 100 // TODO: --watch 101 /*} else if (arg == "--watch" || arg == "-w") { 102 watcher = true; 103 } else if (arg == "--delay" || arg == "-d") { 104 if (watcherDelaySet) { 105 stderr.writeln("error: watcher-delay already specified"); 106 stderr.writeln(HELP); 107 exit(1); 108 } 109 nextWatcherDelay = true;*/ 110 } else if (arg == "--output" || arg == "-o") { 111 if (output != null) { 112 stderr.writeln("error: output already specified"); 113 stderr.writeln(HELP); 114 exit(1); 115 } 116 nextOutput = true; 117 } else if (arg[0] == '-') { 118 stderr.writef("error: unknown option '%s'\n", arg); 119 stderr.writeln(HELP); 120 exit(1); 121 } else { 122 input ~= arg; 123 } 124 } 125 if (recursive && input.length == 0) { 126 stderr.writeln("error: cannot use '--recursive' and specify no input"); 127 exit(1); 128 } 129 if (inline && input.length == 0) { 130 stderr.writeln("error: cannot use '--inline' and read from stdin"); 131 exit(1); 132 } 133 if ((!inline || output.length > 0) && input.length > 0) { 134 stderr.writeln("error: if you use inputs you must use '--inline'"); 135 exit(1); 136 } 137 // -*- operation -*- 138 139 /* if (watcher) { 140 stderr.writeln("\033[1;34mwatching files...\033[0m"); 141 SysTime[string] lastModified; 142 for (;;) { 143 auto entries = listEntries!(x => x !in lastModified 144 || lastModified[x] != x.timeLastModified)(input, recursive); 145 146 foreach (entry; entries) { 147 lastModified[entry.name] = entry.timeLastModified; 148 } 149 entries.sortImports(config); 150 Thread.sleep(Duration!"msecs"(cast(long) watcherDelay * 1000)); 151 } 152 } else 153 */ 154 if (input == null) { 155 File outfile = (output == null) ? stdout : File(output); 156 157 sortImports(stdin, outfile, config); 158 if (output) 159 outfile.close(); 160 } else { 161 listEntries(input, recursive).sortImports(config); 162 } 163 }