102030405060708090100110120130140150160170180190200210220230240250260270280290300310320330340350360370380390400410420430440450460470480490500510520530540550560570580590600610620630640650660670680690700710720730740750760770780790800810820830840850860870880890900910920930940950960970980990100010101020103010401050106010701080109011001110112011301140115011601170118011901200121012201230124012501260127012801290130013101321133013401350136013701380139014001410142014301440145014601470148014901500151015201531154015511561157015811590160016101620163245721640165016601670168122861691228617001711228617201734145174414517541451760177997178997179997180018199718299718399718401854186418741880189019001910192019301940195019601976143198614319902000201020202030204020502060207020802090210021102120213021402150216021702180219022002210222022302240225022602270228022902300231023202330234023502360237023802390240024102420243024402456143246024702480249025002510252025302540255025602570258025902600261026280537263026461432650266614326761432686143269614327002710272027302740275027602770278027902800281028202830284028502860287137528802890290029102920293029402950296029702980299030003010302030303040305030603070308030903100311031203130314031503160317031803190320032103220323032403250326032703280329033003310332033303340335033603370338033903400341034203430344034503460347034803490350035103520353035403550356035703580359036003610362036303640365036603670368036903700371037203730374037503760377037803790380038103820383038403850386038703880389039003910392039303940395039603970398039904000 module trial.reporters.writer; import std.stdio; import std.algorithm; import std.string; ReportWriter defaultWriter; interface ReportWriter { enum Context { active, inactive, success, info, warning, danger, _default } void goTo(int); void write(string, Context = Context.active); void writeReverse(string, Context = Context.active); void writeln(string, Context = Context.active); void showCursor(); void hideCursor(); uint width(); } class ConsoleWriter : ReportWriter { void goTo(int) { } void write(string text, Context) { std.stdio.write(text); } void writeReverse(string text, Context) { std.stdio.write(text); } void writeln(string text, Context) { std.stdio.writeln(text); } void showCursor() { } void hideCursor() { } uint width() { return 80; } } import trial.terminal; shared static this() { version(Windows) { import core.sys.windows.windows; SetConsoleCP(65001); SetConsoleOutputCP(65001); auto consoleType = GetFileType(GetStdHandle(STD_OUTPUT_HANDLE)); if(consoleType == 2) { writeln("using the color console."); defaultWriter = new ColorConsoleWriter; } else { writeln("using the standard console."); defaultWriter = new ConsoleWriter; } std.stdio.stdout.flush; } else { defaultWriter = new ColorConsoleWriter; } } class ColorConsoleWriter : ReportWriter { private { int[string] cues; Terminal terminal; int lines = 0; bool movedToBottom = false; Context currentContext = Context._default; bool isReversed = false; } this() { this.terminal = Terminal(ConsoleOutputType.linear); this.terminal._suppressDestruction = true; lines = this.terminal.cursorY; } void setColor(Context context) { if (!isReversed && context == currentContext) { return; } isReversed = false; currentContext = context; switch (context) { case Context.active: terminal.color(Color.white | Bright, Color.DEFAULT); break; case Context.inactive: terminal.color(Color.black | Bright, Color.DEFAULT); break; case Context.success: terminal.color(Color.green | Bright, Color.DEFAULT); break; case Context.info: terminal.color(Color.cyan, Color.DEFAULT); break; case Context.warning: terminal.color(Color.yellow, Color.DEFAULT); break; case Context.danger: terminal.color(Color.red, Color.DEFAULT); break; default: terminal.reset(); } } void setColorReverse(Context context) { if (!isReversed && context == currentContext) { return; } currentContext = context; isReversed = true; switch (context) { case Context.active: terminal.color(Color.DEFAULT, Color.white | Bright); break; case Context.inactive: terminal.color(Color.DEFAULT, Color.black | Bright); break; case Context.success: terminal.color(Color.DEFAULT, Color.green | Bright); break; case Context.info: terminal.color(Color.DEFAULT, Color.cyan); break; case Context.warning: terminal.color(Color.DEFAULT, Color.yellow); break; case Context.danger: terminal.color(Color.DEFAULT, Color.red); break; default: terminal.reset(); } } void resetColor() { setColor(Context._default); } void goTo(int y) { if (!movedToBottom) { movedToBottom = true; terminal.moveTo(0, terminal.height - 1); } terminal.moveTo(0, terminal.cursorY - y, ForceOption.alwaysSend); } void write(string text, Context context) { lines += text.count!(a => a == '\n'); setColor(context); terminal.write(text); terminal.flush; resetColor; terminal.flush; } void writeReverse(string text, Context context) { lines += text.count!(a => a == '\n'); setColorReverse(context); terminal.write(text); resetColor; terminal.flush; } void writeln(string text, Context context) { this.write(text ~ "\n", context); } void showCursor() { terminal.showCursor; } void hideCursor() { terminal.hideCursor; } uint width() { return terminal.width; } } class BufferedWriter : ReportWriter { string buffer = ""; private { size_t line = 0; size_t charPos = 0; bool replace; string[] screen; } void goTo(int y) { line = line - y; charPos = 0; } uint width() { return 80; } void write(string text, Context) { auto lines = text.count!(a => a == '\n'); auto pieces = buffer.split("\n"); auto newLines = text.split("\n"); for (auto i = line; i < line + newLines.length; i++) { if (i != line) { charPos = 0; } while (i >= screen.length) { screen ~= ""; } auto newLine = newLines[i - line]; if (charPos + newLine.length >= screen[i].length) { screen[i] = screen[i][0 .. charPos] ~ newLine; } else { screen[i] = screen[i][0 .. charPos] ~ newLine ~ screen[i][charPos + newLine.length .. $]; } charPos = charPos + newLine.length; } buffer = screen.join("\n"); screen = buffer.split("\n"); line += lines; } void writeReverse(string text, Context c) { write(text, c); } void writeln(string text, Context c) { write(text ~ '\n', c); } void showCursor() { } void hideCursor() { } }
module trial.reporters.writer; import std.stdio; import std.algorithm; import std.string; ReportWriter defaultWriter; interface ReportWriter { enum Context { active, inactive, success, info, warning, danger, _default } void goTo(int); void write(string, Context = Context.active); void writeReverse(string, Context = Context.active); void writeln(string, Context = Context.active); void showCursor(); void hideCursor(); uint width(); } class ConsoleWriter : ReportWriter { void goTo(int) { } void write(string text, Context) { std.stdio.write(text); } void writeReverse(string text, Context) { std.stdio.write(text); } void writeln(string text, Context) { std.stdio.writeln(text); } void showCursor() { } void hideCursor() { } uint width() { return 80; } } import trial.terminal; shared static this() { version(Windows) { import core.sys.windows.windows; SetConsoleCP(65001); SetConsoleOutputCP(65001); auto consoleType = GetFileType(GetStdHandle(STD_OUTPUT_HANDLE)); if(consoleType == 2) { writeln("using the color console."); defaultWriter = new ColorConsoleWriter; } else { writeln("using the standard console."); defaultWriter = new ConsoleWriter; } std.stdio.stdout.flush; } else { defaultWriter = new ColorConsoleWriter; } } class ColorConsoleWriter : ReportWriter { private { int[string] cues; Terminal terminal; int lines = 0; bool movedToBottom = false; Context currentContext = Context._default; bool isReversed = false; } this() { this.terminal = Terminal(ConsoleOutputType.linear); this.terminal._suppressDestruction = true; lines = this.terminal.cursorY; } void setColor(Context context) { if (!isReversed && context == currentContext) { return; } isReversed = false; currentContext = context; switch (context) { case Context.active: terminal.color(Color.white | Bright, Color.DEFAULT); break; case Context.inactive: terminal.color(Color.black | Bright, Color.DEFAULT); break; case Context.success: terminal.color(Color.green | Bright, Color.DEFAULT); break; case Context.info: terminal.color(Color.cyan, Color.DEFAULT); break; case Context.warning: terminal.color(Color.yellow, Color.DEFAULT); break; case Context.danger: terminal.color(Color.red, Color.DEFAULT); break; default: terminal.reset(); } } void setColorReverse(Context context) { if (!isReversed && context == currentContext) { return; } currentContext = context; isReversed = true; switch (context) { case Context.active: terminal.color(Color.DEFAULT, Color.white | Bright); break; case Context.inactive: terminal.color(Color.DEFAULT, Color.black | Bright); break; case Context.success: terminal.color(Color.DEFAULT, Color.green | Bright); break; case Context.info: terminal.color(Color.DEFAULT, Color.cyan); break; case Context.warning: terminal.color(Color.DEFAULT, Color.yellow); break; case Context.danger: terminal.color(Color.DEFAULT, Color.red); break; default: terminal.reset(); } } void resetColor() { setColor(Context._default); } void goTo(int y) { if (!movedToBottom) { movedToBottom = true; terminal.moveTo(0, terminal.height - 1); } terminal.moveTo(0, terminal.cursorY - y, ForceOption.alwaysSend); } void write(string text, Context context) { lines += text.count!(a => a == '\n'); setColor(context); terminal.write(text); terminal.flush; resetColor; terminal.flush; } void writeReverse(string text, Context context) { lines += text.count!(a => a == '\n'); setColorReverse(context); terminal.write(text); resetColor; terminal.flush; } void writeln(string text, Context context) { this.write(text ~ "\n", context); } void showCursor() { terminal.showCursor; } void hideCursor() { terminal.hideCursor; } uint width() { return terminal.width; } } class BufferedWriter : ReportWriter { string buffer = ""; private { size_t line = 0; size_t charPos = 0; bool replace; string[] screen; } void goTo(int y) { line = line - y; charPos = 0; } uint width() { return 80; } void write(string text, Context) { auto lines = text.count!(a => a == '\n'); auto pieces = buffer.split("\n"); auto newLines = text.split("\n"); for (auto i = line; i < line + newLines.length; i++) { if (i != line) { charPos = 0; } while (i >= screen.length) { screen ~= ""; } auto newLine = newLines[i - line]; if (charPos + newLine.length >= screen[i].length) { screen[i] = screen[i][0 .. charPos] ~ newLine; } else { screen[i] = screen[i][0 .. charPos] ~ newLine ~ screen[i][charPos + newLine.length .. $]; } charPos = charPos + newLine.length; } buffer = screen.join("\n"); screen = buffer.split("\n"); line += lines; } void writeReverse(string text, Context c) { write(text, c); } void writeln(string text, Context c) { write(text ~ '\n', c); } void showCursor() { } void hideCursor() { } }