Skip to content

Commit

Permalink
Add prettyio.d
Browse files Browse the repository at this point in the history
  • Loading branch information
nordlow committed Feb 29, 2024
1 parent 17fe91e commit 07b092d
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 98 deletions.
4 changes: 3 additions & 1 deletion source/dub/test/other.d
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ version (unittest):
import std.algorithm;
import std.format;
import dub.test.base;
import dub.test.prettyio;
import nxt.prettyio;

// https://github.com/dlang/dub/issues/2696
unittest
Expand Down Expand Up @@ -63,7 +63,9 @@ version "1.0.0"`, PackageFormat.sdl);
root.mkdir(BDir);
root.writeFile(BDir ~ "dub.json", `{"name": "b", "version": "1.0.0" }`);
});

dub.cwritePretty(0, "dub");

dub.m_packageManager.m_dbgFlag = false;

dub.loadPackage();
Expand Down
244 changes: 147 additions & 97 deletions source/dub/test/prettyio.d
Original file line number Diff line number Diff line change
@@ -1,70 +1,20 @@
/** Pretty Printing.
*
* Copyright: Per Nordlöw 2022-.
* License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
* Authors: $(WEB Per Nordlöw)
*
* TODO: Merge in wip-src/pretty.d
*
* Test: dmd -I.. -i -unittest -version=show -main -run prettyio.d
*/
module dub.test.prettyio;

// TODO: instead override?:
// void toString(Sink)(ref scope Sink sink) const scope;

/++ Colorized version of `std.stdio.write`.
+/
void cwrite(T...)(T args) {
import std.stdio : sw = write;
version (none) import nxt.ansi_escape : putWithSGRs; // TODO: use below:
alias w = pathWrapperSymbol;
static foreach (arg; args) {{
static immutable S = typeof(arg).stringof;
// pragma(msg, __FILE__, "(", __LINE__, ",1): Debug: ", S);
// static if (S == "URL")
// sw(w, arg, w); // TODO: SGR.yellowForegroundColor
// else static if (S == "Path")
// sw(w, arg, w); // TODO: SGR.whiteForegroundColor
// else static if (S == "FilePath")
// sw(w, arg, w); // TODO: SGR.whiteForegroundColor
// else static if (S == "DirPath")
// sw(w, arg, w); // TODO: SGR.cyanForegroundColor
// else static if (S == "ExePath")
// sw(w, arg, w); // TODO: SGR.lightRedForegroundColor
// else static if (S == "FileName")
// sw(w, arg, w); // TODO: SGR.whiteForegroundColor
// else static if (S == "DirName")
// sw(w, arg, w); // TODO: SGR.redForegroundColor
// else static if (S == "ExitStatus")
// sw(w, arg, w); // TODO: SGR.greenForegroundColor if arg == 0, otherwise SGR.redForegroundColor
// else
sw(arg);
}}
}

/++ Colorized version of `std.stdio.writeln`.
+/
void cwriteln(T...)(T args) {
import std.stdio : swln = writeln;
// TODO: is this ok?:
cwrite!(T)(args);
swln();
}
module nxt.prettyio;

/++ Wrapper symbol when printing paths and URLs to standard out (`stdout`) and standard error (`stderr`).
+/
private static immutable string pathWrapperSymbol = `"`;

/++ Colorized pretty print `arg`.
+/
void cwritePretty(T)(T arg,
in size_t depth = 0,
in char[] fieldName = [],
in char[] indent = "\t",
in char[] lterm = "\n",
in bool showType = true,
in void*[] ptrs = []) {
void cwritePretty(T)(T arg, in size_t depth = 0, in char[] fieldName = [], in char[] indent = "\t", in char[] lterm = "\n", in bool showType = true) {
scope const(void)*[] ptrs;
cwritePrettyHelper!(T)(arg, depth, fieldName, indent, lterm, showType, ptrs);
}
private void cwritePrettyHelper(T)(T arg, in size_t depth = 0, in char[] fieldName = [], in char[] indent = "\t", in char[] lterm = "\n", in bool showType = true, ref scope const(void)*[] ptrs) {
void cwriteIndent() {
foreach (_; 0 .. depth) cwrite(indent);
}
Expand All @@ -79,7 +29,10 @@ void cwritePretty(T)(T arg,
// cwrite("class ");
if (showType) cwrite(typeName, " ");
}
import std.traits : isArray, isSomeString, isSomeChar;
void cwriteAddress(in void* ptr) {
cwrite('@', ptr);
}
import std.traits : isArray, isSomeString, isSomeChar, isPointer;
import std.range.primitives : ElementType;
cwriteIndent();
cwriteFieldName();
Expand All @@ -88,24 +41,52 @@ void cwritePretty(T)(T arg,
import std.traits : FieldNameTuple;
void cwriteMembers() {
foreach (memberName; FieldNameTuple!T)
cwritePretty(__traits(getMember, arg, memberName), depth + 1, memberName, indent);
cwritePrettyHelper(__traits(getMember, arg, memberName), depth + 1,
memberName, indent, lterm, showType, ptrs);
}
static if (is(T == class)) {
const(void)* ptr;
() @trusted { ptr = cast(void*)arg; }();
cwriteAddress(ptr);
if (arg is null) {
cwrite("null", lterm);
cwrite(lterm);
} else {
cwrite('@', cast(void*)arg, ' ');
cwrite("{", lterm);
cwriteMembers();
cwriteIndent();
cwrite("}", lterm);
const ix = ptrs.indexOf(ptr);
cwrite(' ');
if (ix != -1) { // `ptr` already printed
cwrite("#", ix, lterm); // Emacs-Lisp-style back-reference
} else {
cwrite("#", ptrs.length, ' '); // Emacs-Lisp-style back-reference
cwrite("{", lterm);
ptrs ~= ptr;
cwriteMembers();
cwriteIndent();
cwrite("}", lterm);
}
}
} else {
cwrite("{", lterm);
cwriteMembers();
cwriteIndent();
cwrite("}", lterm);
}
} else static if (isPointer!T) {
const ptr = cast(void*)arg;
cwriteAddress(ptr);
if (arg is null) {
cwrite(lterm);
} else {
import nxt.algorithm : indexOf;
const ix = ptrs.indexOf(ptr);
cwrite(' ');
if (ix != -1) { // `ptr` already printed
cwrite("#", ix, lterm); // Emacs-Lisp-style back-reference
} else {
cwrite("#", ptrs.length, " -> "); // Emacs-Lisp-style back-reference
ptrs ~= ptr;
cwritePrettyHelper(*arg, depth, [], indent, lterm, showType, ptrs);
}
}
} else static if (isSomeString!T) {
cwrite('"', arg, '"', lterm);
} else static if (isSomeChar!T) {
Expand All @@ -115,11 +96,11 @@ void cwritePretty(T)(T arg,
alias E = ElementType!(T);
foreach (ref element; arg) {
static if (__traits(isScalar, E)) {
cwritePretty(element, 0, [], [], [], false);
cwritePrettyHelper(element, 0, [], [], [], false, ptrs);
cwrite(',');
} else {
cwriteln();
cwritePretty(element, depth + 1, [], indent);
cwritePrettyHelper(element, depth + 1, [], indent, lterm, showType, ptrs);
}
}
static if (__traits(isScalar, E)) {
Expand All @@ -135,44 +116,113 @@ void cwritePretty(T)(T arg,
}
}

@safe struct P {
double x;
double y;
double z;
/++ Colorized version of `std.stdio.write`.
+/
void cwrite(T...)(T args) {
import std.stdio : sw = write;
version (none) import nxt.ansi_escape : putWithSGRs; // TODO: use below:
alias w = pathWrapperSymbol;
static foreach (arg; args) {{
static immutable S = typeof(arg).stringof;
// pragma(msg, __FILE__, "(", __LINE__, ",1): Debug: ", S);
// static if (S == "URL")
// sw(w, arg, w); // TODO: SGR.yellowForegroundColor
// else static if (S == "Path")
// sw(w, arg, w); // TODO: SGR.whiteForegroundColor
// else static if (S == "FilePath")
// sw(w, arg, w); // TODO: SGR.whiteForegroundColor
// else static if (S == "DirPath")
// sw(w, arg, w); // TODO: SGR.cyanForegroundColor
// else static if (S == "ExePath")
// sw(w, arg, w); // TODO: SGR.lightRedForegroundColor
// else static if (S == "FileName")
// sw(w, arg, w); // TODO: SGR.whiteForegroundColor
// else static if (S == "DirName")
// sw(w, arg, w); // TODO: SGR.redForegroundColor
// else static if (S == "ExitStatus")
// sw(w, arg, w); // TODO: SGR.greenForegroundColor if arg == 0, otherwise SGR.redForegroundColor
// else
sw(arg);
}}
}

@safe struct S {
int x;
double y;
char[3] c3 = "abc";
string w3 = "xyz";
int[3] i3;
float[3] f3;
double[3] d3;
real[3] r3;
int[string] ais = ["a":1, "b":2];
P[string] ps = ["a":P(1,2,3)];
/++ Colorized version of `std.stdio.writeln`.
+/
void cwriteln(T...)(T args) {
import std.stdio : swln = writeln;
// TODO: is this ok?:
cwrite!(T)(args);
swln();
}

@safe class Cls {
this(int x) {
this.x = x;
version (show)
unittest {
@safe struct P {
double x;
double y;
double z;
}
int x;
}

@safe struct Top {
S s;
S[2] s2;
Cls cls;
Cls clsNull;
string name;
int[] numbers;
}
@safe struct S {
int x;
double y;
char[3] c3 = "abc";
string w3 = "xyz";
int[3] i3;
float[3] f3;
double[3] d3;
real[3] r3;
int[string] ais = ["a":1, "b":2];
P[string] ps = ["a":P(1,2,3)];
P* pp0 = null;
P* pp1 = new P(1,2,3);
}

@safe class Cls {
this(int x) {
this.x = x;
this.parent = this;
}
int x;
Cls parent;
}

@safe struct Top {
S s;
S[2] s2;
Cls cls;
Cls clsNull;
string name;
int[] numbers;
}

version (show)
@safe unittest {
S s = S(10, 20.5);
Top top = { s, [s,s], new Cls(1), null, "example", [1, 2, 3] };
top.cwritePretty(0, "top", "\t");
top.cwritePretty(0, "top", "\t", "\n");
}

/** Array-specialization of `indexOf` with default predicate.
*
* TODO: Add optimized implementation for needles with length >=
* `largeNeedleLength` with no repeat of elements.
*/
ptrdiff_t indexOf(T)(scope inout(T)[] haystack,
scope const(T)[] needle) @trusted {
// enum largeNeedleLength = 4;
if (haystack.length < needle.length)
return -1;
foreach (const offset; 0 .. haystack.length - needle.length + 1)
if (haystack.ptr[offset .. offset + needle.length] == needle)
return offset;
return -1;
}
/// ditto
ptrdiff_t indexOf(T)(scope inout(T)[] haystack,
scope const T needle) {
static if (is(T == char))
assert(needle < 128); // See_Also: https://forum.dlang.org/post/[email protected]
foreach (const offset, const ref element; haystack)
if (element == needle)
return offset;
return -1;
}

0 comments on commit 07b092d

Please sign in to comment.