mirror of https://github.com/adamdruppe/arsd.git
fix compile
This commit is contained in:
parent
d8720892c8
commit
8c67623cf6
103
cgi.d
103
cgi.d
|
@ -4698,6 +4698,99 @@ interface EventIoServer {
|
||||||
void fileClosed(int fd);
|
void fileClosed(int fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the sink should buffer it
|
||||||
|
private void serialize(T)(scope void delegate(ubyte[]) sink, T t) {
|
||||||
|
static if(is(T == struct)) {
|
||||||
|
foreach(member; __traits(allMembers, T))
|
||||||
|
serialize(sink, __traits(getMember, t, member));
|
||||||
|
} else static if(is(T : int)) {
|
||||||
|
// no need to think of endianness just because this is only used
|
||||||
|
// for local, same-machine stuff anyway. thanks private lol
|
||||||
|
sink((cast(ubyte*) &t)[0 .. t.sizeof]);
|
||||||
|
} else static if(is(T == string) || is(T : const(ubyte)[])) {
|
||||||
|
// these are common enough to optimize
|
||||||
|
int len = cast(int) t.length; // want length consistent size tho, in case 32 bit program sends to 64 bit server, etc.
|
||||||
|
sink((cast(ubyte*) &len)[0 .. int.sizeof]);
|
||||||
|
sink(cast(ubyte[]) t[]);
|
||||||
|
} else static if(is(T : A[], A)) {
|
||||||
|
// generic array is less optimal but still prolly ok
|
||||||
|
static assert(0, T.stringof);
|
||||||
|
int len = cast(int) t.length;
|
||||||
|
sink((cast(ubyte*) &len)[0 .. int.sizeof]);
|
||||||
|
foreach(item; t)
|
||||||
|
serialize(item);
|
||||||
|
} else static assert(0, T.stringof);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deserialize(T)(scope ubyte[] delegate(int sz) get, scope void delegate(T) dg) {
|
||||||
|
static if(is(T == struct)) {
|
||||||
|
T t;
|
||||||
|
foreach(member; __traits(allMembers, T))
|
||||||
|
deserialize(get, (T mbr) { __traits(getMember, t, member) = mbr; });
|
||||||
|
dg(t);
|
||||||
|
} else static if(is(T : int)) {
|
||||||
|
// no need to think of endianness just because this is only used
|
||||||
|
// for local, same-machine stuff anyway. thanks private lol
|
||||||
|
T t;
|
||||||
|
auto data = get(t.sizeof);
|
||||||
|
t = (cast(T[]) data)[0];
|
||||||
|
dg(t);
|
||||||
|
} else static if(is(T == string) || is(T : const(ubyte)[])) {
|
||||||
|
// these are common enough to optimize
|
||||||
|
int len;
|
||||||
|
auto data = get(len.sizeof);
|
||||||
|
len = (cast(int[]) data)[0];
|
||||||
|
|
||||||
|
/*
|
||||||
|
typeof(T[0])[2000] stackBuffer;
|
||||||
|
T buffer;
|
||||||
|
|
||||||
|
if(len < stackBuffer.length)
|
||||||
|
buffer = stackBuffer[0 .. len];
|
||||||
|
else
|
||||||
|
buffer = new T(len);
|
||||||
|
|
||||||
|
data = get(len * typeof(T[0]).sizeof);
|
||||||
|
*/
|
||||||
|
|
||||||
|
T t = cast(T) get(len * typeof(T[0]).sizeof);
|
||||||
|
|
||||||
|
dg(t);
|
||||||
|
|
||||||
|
} else static assert(0, T.stringof);
|
||||||
|
}
|
||||||
|
|
||||||
|
unittest {
|
||||||
|
serialize((ubyte[] b) { assert(b == [0, 0, 0, 1]); }, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
interface MyLocalServer {}
|
||||||
|
|
||||||
|
MyLocalServer connectToLocalServer() { return null; } // return an auto-generated version that RPCs to the interface
|
||||||
|
|
||||||
|
class MyLocalServerImpl : MyLocalServer {} // handle the calls.
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
FIXME:
|
||||||
|
add a version command line arg
|
||||||
|
version data in the library
|
||||||
|
management gui as external program
|
||||||
|
|
||||||
|
at server with event_fd for each run
|
||||||
|
use .mangleof in the at function name
|
||||||
|
|
||||||
|
i think the at server will have to:
|
||||||
|
pipe args to the child
|
||||||
|
collect child output for logging
|
||||||
|
get child return value for logging
|
||||||
|
|
||||||
|
on windows timers work differently. idk how to best combine with the io stuff.
|
||||||
|
|
||||||
|
will have to have dump and restore too, so i can restart without losing stuff.
|
||||||
|
*/
|
||||||
|
|
||||||
final class BasicDataServer : EventIoServer {
|
final class BasicDataServer : EventIoServer {
|
||||||
static struct ClientConnection {
|
static struct ClientConnection {
|
||||||
/+
|
/+
|
||||||
|
@ -4714,7 +4807,7 @@ final class BasicDataServer : EventIoServer {
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
void handleLocalConnectionData(IoOp* op, int receivedFd);
|
void handleLocalConnectionData(IoOp* op, int receivedFd) {}
|
||||||
|
|
||||||
void handleLocalConnectionClose(IoOp* op) {} // doesn't really matter, this is a fairly stateless go
|
void handleLocalConnectionClose(IoOp* op) {} // doesn't really matter, this is a fairly stateless go
|
||||||
void handleLocalConnectionComplete(IoOp* op) {} // again, irrelevant
|
void handleLocalConnectionComplete(IoOp* op) {} // again, irrelevant
|
||||||
|
@ -4742,6 +4835,14 @@ final class BasicDataServer : EventIoServer {
|
||||||
char[16] sessionId;
|
char[16] sessionId;
|
||||||
Operation operation;
|
Operation operation;
|
||||||
|
|
||||||
|
ushort dataType;
|
||||||
|
/*
|
||||||
|
int
|
||||||
|
float
|
||||||
|
string
|
||||||
|
ubyte[]
|
||||||
|
*/
|
||||||
|
|
||||||
int keyLength;
|
int keyLength;
|
||||||
char[128] keyBuffer;
|
char[128] keyBuffer;
|
||||||
|
|
||||||
|
|
|
@ -18,22 +18,26 @@
|
||||||
ought to just work.
|
ought to just work.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
---
|
||||||
auto data = cast(immutable(ubyte)[])
|
auto data = cast(immutable(ubyte)[])
|
||||||
std.file.read("my-windows-file.txt");
|
std.file.read("my-windows-file.txt");
|
||||||
string utf8String = convertToUtf8(data, "windows-1252");
|
string utf8String = convertToUtf8(data, "windows-1252");
|
||||||
// utf8String can now be used
|
// utf8String can now be used
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
The encodings currently implemented for decoding are:
|
The encodings currently implemented for decoding are:
|
||||||
UTF-8 (a no-op; it simply casts the array to string)
|
$(LIST
|
||||||
UTF-16,
|
* UTF-8 (a no-op; it simply casts the array to string)
|
||||||
UTF-32,
|
* UTF-16,
|
||||||
Windows-1252,
|
* UTF-32,
|
||||||
ISO 8859 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, and 16.
|
* Windows-1252,
|
||||||
|
* ISO 8859 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, and 16.
|
||||||
|
* KOI8-R
|
||||||
|
)
|
||||||
|
|
||||||
It treats ISO 8859-1, Latin-1, and Windows-1252 the same way, since
|
It treats ISO 8859-1, Latin-1, and Windows-1252 the same way, since
|
||||||
those labels are pretty much de-facto the same thing in wild documents.
|
those labels are pretty much de-facto the same thing in wild documents (people mislabel them a lot and I found it more useful to just deal with it than to be pedantic).
|
||||||
|
|
||||||
|
|
||||||
This module currently makes no attempt to look at control characters.
|
This module currently makes no attempt to look at control characters.
|
||||||
*/
|
*/
|
||||||
|
|
7
dom.d
7
dom.d
|
@ -71,7 +71,7 @@ bool isConvenientAttribute(string name) {
|
||||||
/// The main document interface, including a html parser.
|
/// The main document interface, including a html parser.
|
||||||
class Document : FileResource {
|
class Document : FileResource {
|
||||||
/// Convenience method for web scraping. Requires [arsd.http2] to be
|
/// Convenience method for web scraping. Requires [arsd.http2] to be
|
||||||
/// included in the build.
|
/// included in the build as well as [arsd.characterencodings].
|
||||||
static Document fromUrl()(string url) {
|
static Document fromUrl()(string url) {
|
||||||
import arsd.http2;
|
import arsd.http2;
|
||||||
auto client = new HttpClient();
|
auto client = new HttpClient();
|
||||||
|
@ -79,7 +79,10 @@ class Document : FileResource {
|
||||||
auto req = client.navigateTo(Uri(url), HttpVerb.GET);
|
auto req = client.navigateTo(Uri(url), HttpVerb.GET);
|
||||||
auto res = req.waitForCompletion();
|
auto res = req.waitForCompletion();
|
||||||
|
|
||||||
return new Document(cast(string) res.content);
|
auto document = new Document();
|
||||||
|
document.parseGarbage(cast(string) res.content);
|
||||||
|
|
||||||
|
return document;
|
||||||
}
|
}
|
||||||
|
|
||||||
///.
|
///.
|
||||||
|
|
218
htmltotext.d
218
htmltotext.d
|
@ -7,10 +7,47 @@ import std.string;
|
||||||
|
|
||||||
import std.uni : isWhite;
|
import std.uni : isWhite;
|
||||||
|
|
||||||
|
///
|
||||||
class HtmlConverter {
|
class HtmlConverter {
|
||||||
int width;
|
int width;
|
||||||
|
|
||||||
|
/++
|
||||||
|
Will enable color output using VT codes. Determines color through dom.d's css support, which means you need to apply a stylesheet first.
|
||||||
|
|
||||||
|
---
|
||||||
|
import arsd.dom;
|
||||||
|
|
||||||
|
auto document = new Document(source_code_for_html);
|
||||||
|
auto stylesheet = new Stylesheet(source_code_for_css);
|
||||||
|
stylesheet.apply(document);
|
||||||
|
---
|
||||||
|
+/
|
||||||
|
bool enableVtOutput;
|
||||||
|
|
||||||
|
|
||||||
|
string color;
|
||||||
|
string backgroundColor;
|
||||||
|
|
||||||
|
///
|
||||||
void htmlToText(Element element, bool preformatted, int width) {
|
void htmlToText(Element element, bool preformatted, int width) {
|
||||||
|
string color, backgroundColor;
|
||||||
|
if(enableVtOutput) {
|
||||||
|
color = element.computedStyle.getValue("color");
|
||||||
|
backgroundColor = element.computedStyle.getValue("background-color");
|
||||||
|
}
|
||||||
|
|
||||||
|
string originalColor = this.color, originalBackgroundColor = this.backgroundColor;
|
||||||
|
|
||||||
|
this.color = color.length ? color : this.color;
|
||||||
|
this.backgroundColor = backgroundColor.length ? backgroundColor : this.backgroundColor;
|
||||||
|
|
||||||
|
scope(exit) {
|
||||||
|
// the idea is as we pop working back up the tree, it restores what it was here
|
||||||
|
this.color = originalColor;
|
||||||
|
this.backgroundColor = originalBackgroundColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
this.width = width;
|
this.width = width;
|
||||||
if(auto tn = cast(TextNode) element) {
|
if(auto tn = cast(TextNode) element) {
|
||||||
foreach(dchar ch; tn.nodeValue) {
|
foreach(dchar ch; tn.nodeValue) {
|
||||||
|
@ -115,19 +152,27 @@ class HtmlConverter {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "span":
|
case "span":
|
||||||
/*
|
if(enableVtOutput) {
|
||||||
auto csc = element.computedStyle.getValue("color");
|
auto csc = color; // element.computedStyle.getValue("color");
|
||||||
if(csc.length) {
|
if(csc.length) {
|
||||||
auto c = Color.fromString(csc);
|
auto c = Color.fromString(csc);
|
||||||
s ~= format("\033[38;2;%d;%d;%dm", c.r, c.g, c.b);
|
s ~= format("\033[38;2;%d;%d;%dm", c.r, c.g, c.b);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bold = element.computedStyle.getValue("font-weight") == "bold";
|
||||||
|
|
||||||
|
if(bold)
|
||||||
|
s ~= "\033[1m";
|
||||||
|
|
||||||
|
sinkChildren();
|
||||||
|
|
||||||
|
if(bold)
|
||||||
|
s ~= "\033[0m";
|
||||||
|
if(csc.length)
|
||||||
|
s ~= "\033[39m";
|
||||||
|
} else {
|
||||||
|
sinkChildren();
|
||||||
}
|
}
|
||||||
sinkChildren();
|
|
||||||
|
|
||||||
if(csc.length)
|
|
||||||
s ~= "\033[39m";
|
|
||||||
*/
|
|
||||||
|
|
||||||
sinkChildren();
|
|
||||||
break;
|
break;
|
||||||
case "p":
|
case "p":
|
||||||
startBlock();
|
startBlock();
|
||||||
|
@ -138,9 +183,15 @@ class HtmlConverter {
|
||||||
case "em", "i":
|
case "em", "i":
|
||||||
if(element.innerText.length == 0)
|
if(element.innerText.length == 0)
|
||||||
break;
|
break;
|
||||||
sink('*', false);
|
if(enableVtOutput) {
|
||||||
sinkChildren();
|
s ~= "\033[1m";
|
||||||
sink('*', false);
|
sinkChildren();
|
||||||
|
s ~= "\033[0m";
|
||||||
|
} else {
|
||||||
|
sink('*', false);
|
||||||
|
sinkChildren();
|
||||||
|
sink('*', false);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case "u":
|
case "u":
|
||||||
if(element.innerText.length == 0)
|
if(element.innerText.length == 0)
|
||||||
|
@ -258,6 +309,7 @@ class HtmlConverter {
|
||||||
int olDepth;
|
int olDepth;
|
||||||
int ulDepth;
|
int ulDepth;
|
||||||
|
|
||||||
|
///
|
||||||
string convert(string html, bool wantWordWrap = true, int wrapAmount = 74) {
|
string convert(string html, bool wantWordWrap = true, int wrapAmount = 74) {
|
||||||
Document document = new Document;
|
Document document = new Document;
|
||||||
|
|
||||||
|
@ -277,11 +329,13 @@ class HtmlConverter {
|
||||||
return convert(start, wantWordWrap, wrapAmount);
|
return convert(start, wantWordWrap, wrapAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
string convert(Element start, bool wantWordWrap = true, int wrapAmount = 74) {
|
string convert(Element start, bool wantWordWrap = true, int wrapAmount = 74) {
|
||||||
htmlToText(start, false, wrapAmount);
|
htmlToText(start, false, wrapAmount);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
void reset() {
|
void reset() {
|
||||||
s = null;
|
s = null;
|
||||||
justOutputWhitespace = true;
|
justOutputWhitespace = true;
|
||||||
|
@ -289,6 +343,7 @@ class HtmlConverter {
|
||||||
justOutputMargin = true;
|
justOutputMargin = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
string s;
|
string s;
|
||||||
bool justOutputWhitespace = true;
|
bool justOutputWhitespace = true;
|
||||||
bool justOutputBlock = true;
|
bool justOutputBlock = true;
|
||||||
|
@ -406,140 +461,9 @@ class HtmlConverter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
string htmlToText(string html, bool wantWordWrap = true, int wrapAmount = 74) {
|
string htmlToText(string html, bool wantWordWrap = true, int wrapAmount = 74) {
|
||||||
auto converter = new HtmlConverter();
|
auto converter = new HtmlConverter();
|
||||||
return converter.convert(html, true, wrapAmount);
|
return converter.convert(html, true, wrapAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
string repeat(string s, ulong num) {
|
|
||||||
string ret;
|
|
||||||
foreach(i; 0 .. num)
|
|
||||||
ret ~= s;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
import std.stdio;
|
|
||||||
version(none)
|
|
||||||
void penis() {
|
|
||||||
|
|
||||||
again:
|
|
||||||
string result = "";
|
|
||||||
foreach(ele; start.tree) {
|
|
||||||
if(ele is start) continue;
|
|
||||||
if(ele.nodeType != 1) continue;
|
|
||||||
|
|
||||||
switch(ele.tagName) {
|
|
||||||
goto again;
|
|
||||||
case "h1":
|
|
||||||
ele.innerText = "\r" ~ ele.innerText ~ "\n" ~ repeat("=", ele.innerText.length) ~ "\r";
|
|
||||||
ele.stripOut();
|
|
||||||
goto again;
|
|
||||||
case "h2":
|
|
||||||
ele.innerText = "\r" ~ ele.innerText ~ "\n" ~ repeat("-", ele.innerText.length) ~ "\r";
|
|
||||||
ele.stripOut();
|
|
||||||
goto again;
|
|
||||||
case "h3":
|
|
||||||
ele.innerText = "\r" ~ ele.innerText.toUpper ~ "\r";
|
|
||||||
ele.stripOut();
|
|
||||||
goto again;
|
|
||||||
case "td":
|
|
||||||
case "p":
|
|
||||||
/*
|
|
||||||
if(ele.innerHTML.length > 1)
|
|
||||||
ele.innerHTML = "\r" ~ wrap(ele.innerHTML) ~ "\r";
|
|
||||||
ele.stripOut();
|
|
||||||
goto again;
|
|
||||||
*/
|
|
||||||
break;
|
|
||||||
case "a":
|
|
||||||
string href = ele.getAttribute("href");
|
|
||||||
if(href && !ele.hasClass("no-brackets")) {
|
|
||||||
if(ele.hasClass("href-text"))
|
|
||||||
ele.innerText = href;
|
|
||||||
else {
|
|
||||||
if(ele.innerText != href)
|
|
||||||
ele.innerText = ele.innerText ~ " <" ~ href ~ "> ";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ele.stripOut();
|
|
||||||
goto again;
|
|
||||||
case "ol":
|
|
||||||
case "ul":
|
|
||||||
ele.innerHTML = "\r" ~ ele.innerHTML ~ "\r";
|
|
||||||
break;
|
|
||||||
case "li":
|
|
||||||
if(!ele.innerHTML.startsWith("* "))
|
|
||||||
ele.innerHTML = "* " ~ ele.innerHTML ~ "\r";
|
|
||||||
// ele.stripOut();
|
|
||||||
break;
|
|
||||||
case "sup":
|
|
||||||
ele.innerText = "^" ~ ele.innerText;
|
|
||||||
ele.stripOut();
|
|
||||||
break;
|
|
||||||
case "img":
|
|
||||||
string alt = ele.getAttribute("alt");
|
|
||||||
if(alt)
|
|
||||||
result ~= ele.alt;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ele.stripOut();
|
|
||||||
goto again;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
again2:
|
|
||||||
//start.innerHTML = start.innerHTML().replace("\u0001", "\n");
|
|
||||||
|
|
||||||
foreach(ele; start.tree) {
|
|
||||||
if(ele.tagName == "td") {
|
|
||||||
if(ele.directText().strip().length) {
|
|
||||||
ele.prependText("\r");
|
|
||||||
ele.appendText("\r");
|
|
||||||
}
|
|
||||||
ele.stripOut();
|
|
||||||
goto again2;
|
|
||||||
} else if(ele.tagName == "p") {
|
|
||||||
if(strip(ele.innerText()).length > 1) {
|
|
||||||
string res = "";
|
|
||||||
string all = ele.innerText().replace("\n \n", "\n\n");
|
|
||||||
foreach(part; all.split("\n\n"))
|
|
||||||
res ~= "\r" ~ strip( wantWordWrap ? wrap(part, /*74*/ wrapAmount) : part ) ~ "\r";
|
|
||||||
ele.innerText = res;
|
|
||||||
} else
|
|
||||||
ele.innerText = strip(ele.innerText);
|
|
||||||
ele.stripOut();
|
|
||||||
goto again2;
|
|
||||||
} else if(ele.tagName == "li") {
|
|
||||||
auto part = ele.innerText;
|
|
||||||
part = strip( wantWordWrap ? wrap(part, wrapAmount - 2) : part );
|
|
||||||
part = " " ~ part.replace("\n", "\n\v") ~ "\r";
|
|
||||||
ele.innerText = part;
|
|
||||||
ele.stripOut();
|
|
||||||
goto again2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result = start.innerText();
|
|
||||||
result = squeeze(result, " ");
|
|
||||||
|
|
||||||
result = result.replace("\r ", "\r");
|
|
||||||
result = result.replace(" \r", "\r");
|
|
||||||
|
|
||||||
//result = result.replace("\u00a0", " ");
|
|
||||||
|
|
||||||
|
|
||||||
result = squeeze(result, "\r");
|
|
||||||
result = result.replace("\r", "\n\n");
|
|
||||||
|
|
||||||
result = result.replace("\v", " ");
|
|
||||||
|
|
||||||
result = result.replace("舗", "'"); // HACK: this shouldn't be needed, but apparently is in practice surely due to a bug elsewhere
|
|
||||||
result = result.replace(""", "\""); // HACK: this shouldn't be needed, but apparently is in practice surely due to a bug elsewhere
|
|
||||||
//result = htmlEntitiesDecode(result); // for special chars mainly
|
|
||||||
|
|
||||||
result = result.replace("\u0001 ", "\n");
|
|
||||||
result = result.replace("\u0001", "\n");
|
|
||||||
|
|
||||||
//a = std.regex.replace(a, std.regex.regex("(\n\t)+", "g"), "\n"); //\t");
|
|
||||||
return result.strip;
|
|
||||||
}
|
|
||||||
|
|
86
terminal.d
86
terminal.d
|
@ -3606,7 +3606,7 @@ struct ScrollbackBuffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear() {
|
void clear() {
|
||||||
lines = null;
|
lines.clear();
|
||||||
clickRegions = null;
|
clickRegions = null;
|
||||||
scrollbackPosition = 0;
|
scrollbackPosition = 0;
|
||||||
}
|
}
|
||||||
|
@ -3708,9 +3708,87 @@ struct ScrollbackBuffer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: limit scrollback lines.length
|
static struct CircularBuffer(T) {
|
||||||
|
T[] backing;
|
||||||
|
|
||||||
Line[] lines;
|
enum maxScrollback = 8192; // as a power of 2, i hope the compiler optimizes the % below to a simple bit mask...
|
||||||
|
|
||||||
|
int start;
|
||||||
|
int length_;
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
backing = null;
|
||||||
|
start = 0;
|
||||||
|
length_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t length() {
|
||||||
|
return length_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void opOpAssign(string op : "~")(T line) {
|
||||||
|
if(length_ < maxScrollback) {
|
||||||
|
backing.assumeSafeAppend();
|
||||||
|
backing ~= line;
|
||||||
|
length_++;
|
||||||
|
} else {
|
||||||
|
backing[start] = line;
|
||||||
|
start++;
|
||||||
|
if(start == maxScrollback)
|
||||||
|
start = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
T opIndex(int idx) {
|
||||||
|
return backing[(start + idx) % maxScrollback];
|
||||||
|
}
|
||||||
|
T opIndex(Dollar idx) {
|
||||||
|
return backing[(start + (length + idx.offsetFromEnd)) % maxScrollback];
|
||||||
|
}
|
||||||
|
|
||||||
|
CircularBufferRange opSlice(int startOfIteration, Dollar end) {
|
||||||
|
return CircularBufferRange(&this, startOfIteration, cast(int) length - startOfIteration + end.offsetFromEnd);
|
||||||
|
}
|
||||||
|
CircularBufferRange opSlice(int startOfIteration, int end) {
|
||||||
|
return CircularBufferRange(&this, startOfIteration, end - startOfIteration);
|
||||||
|
}
|
||||||
|
CircularBufferRange opSlice() {
|
||||||
|
return CircularBufferRange(&this, 0, cast(int) length);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct CircularBufferRange {
|
||||||
|
CircularBuffer* item;
|
||||||
|
int position;
|
||||||
|
int remaining;
|
||||||
|
this(CircularBuffer* item, int startOfIteration, int count) {
|
||||||
|
this.item = item;
|
||||||
|
position = startOfIteration;
|
||||||
|
remaining = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
T front() { return (*item)[position]; }
|
||||||
|
bool empty() { return remaining <= 0; }
|
||||||
|
void popFront() {
|
||||||
|
position++;
|
||||||
|
remaining--;
|
||||||
|
}
|
||||||
|
|
||||||
|
T back() { return (*item)[remaining - 1 - position]; }
|
||||||
|
void popBack() {
|
||||||
|
remaining--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct Dollar {
|
||||||
|
int offsetFromEnd;
|
||||||
|
Dollar opBinary(string op : "-")(int rhs) {
|
||||||
|
return Dollar(offsetFromEnd - rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Dollar opDollar() { return Dollar(0); }
|
||||||
|
}
|
||||||
|
|
||||||
|
CircularBuffer!Line lines;
|
||||||
string name;
|
string name;
|
||||||
|
|
||||||
int x, y, width, height;
|
int x, y, width, height;
|
||||||
|
@ -3840,7 +3918,7 @@ struct ScrollbackBuffer {
|
||||||
// second pass: actually draw it
|
// second pass: actually draw it
|
||||||
int linePos = remaining;
|
int linePos = remaining;
|
||||||
|
|
||||||
foreach(idx, line; lines[start .. start + howMany]) {
|
foreach(line; lines[start .. start + howMany]) {
|
||||||
int written = 0;
|
int written = 0;
|
||||||
|
|
||||||
if(linePos < 0) {
|
if(linePos < 0) {
|
||||||
|
|
Loading…
Reference in New Issue