From 738148b861aef8b012c0b884e70a595011eb53a0 Mon Sep 17 00:00:00 2001 From: "Adam D. Ruppe" Date: Thu, 2 Apr 2020 15:03:57 -0400 Subject: [PATCH] perf --- terminal.d | 45 +++++++++++++++++++++++++++++++++++++++++---- terminalemulator.d | 40 ++++++++++++++++++++++++++++++++-------- 2 files changed, 73 insertions(+), 12 deletions(-) diff --git a/terminal.d b/terminal.d index 0bcbb2c..7b6d0d3 100644 --- a/terminal.d +++ b/terminal.d @@ -1109,7 +1109,15 @@ struct Terminal { nw.show(); }); tew = window.tew; - window.loop(); + //try + window.loop(); + /* + catch(Throwable t) { + import std.stdio; + stdout.writeln(t); + stdout.flush(); + } + */ }); guiThread.start(); guiThread.priority = Thread.PRIORITY_MAX; // gui thread needs responsiveness @@ -1813,10 +1821,13 @@ struct Terminal { } +/ - void writePrintableString(in char[] s, ForceOption force = ForceOption.automatic) { + void writePrintableString(const(char)[] s, ForceOption force = ForceOption.automatic) { // an escape character is going to mess things up. Actually any non-printable character could, but meh // assert(s.indexOf("\033") == -1); + if(s.length == 0) + return; + // tracking cursor position // FIXME: by grapheme? foreach(dchar ch; s) { @@ -1852,7 +1863,26 @@ struct Terminal { +/ } - writeStringRaw(s); + version(TerminalDirectToEmulator) { + // this breaks up extremely long output a little as an aid to the + // gui thread; by breaking it up, it helps to avoid monopolizing the + // event loop. Easier to do here than in the thread itself because + // this one doesn't have escape sequences to break up so it avoids work. + while(s.length) { + auto len = s.length; + if(len > 1024 * 32) { + len = 1024 * 32; + // get to the start of a utf-8 sequence. kidna sorta. + while(len && (s[len] & 0x1000_0000)) + len--; + } + auto next = s[0 .. len]; + s = s[len .. $]; + writeStringRaw(next); + } + } else { + writeStringRaw(s); + } } /* private */ bool _wrapAround = true; @@ -1864,6 +1894,8 @@ struct Terminal { // you really, really shouldn't use this unless you know what you are doing /*private*/ void writeStringRaw(in char[] s) { writeBuffer ~= s; // buffer it to do everything at once in flush() calls + if(writeBuffer.length > 1024 * 32) + flush(); } /// Clears the screen. @@ -6214,13 +6246,18 @@ version(TerminalDirectToEmulator) { } protected override void demandAttention() { - //window.requestAttention(); + if(widget && widget.parentWindow) + widget.parentWindow.win.requestAttention(); } protected override void copyToClipboard(string text) { setClipboardText(widget.parentWindow.win, text); } + override int maxScrollbackLength() const { + return int.max; // no scrollback limit for custom programs + } + protected override void pasteFromClipboard(void delegate(in char[]) dg) { static if(UsingSimpledisplayX11) getPrimarySelection(widget.parentWindow.win, dg); diff --git a/terminalemulator.d b/terminalemulator.d index f440000..4482795 100644 --- a/terminalemulator.d +++ b/terminalemulator.d @@ -362,6 +362,9 @@ class TerminalEmulator { start = idx; end = selectionEnd; } + if(start < 0 || end >= ((alternateScreenActive ? alternateScreen.length : normalScreen.length))) + return false; + foreach(ref cell; (alternateScreenActive ? alternateScreen : normalScreen)[start .. end]) { cell.invalidated = true; cell.selected = false; @@ -1477,10 +1480,12 @@ class TerminalEmulator { bool overflowed; foreach(cell; line) { cell.invalidated = true; - if(overflowed) + if(overflowed) { screen[cursorY * screenWidth + cursorX] = overflowCell; - else + break; + } else { screen[cursorY * screenWidth + cursorX] = cell; + } if(cursorX == screenWidth-1) { if(scrollbackReflow) { @@ -1665,8 +1670,12 @@ class TerminalEmulator { void clear() { start = 0; length_ = 0; + backing = null; } + // FIXME: if scrollback hits limits the scroll bar needs + // to understand the circular buffer + void opOpAssign(string op : "~")(TerminalCell[] line) { if(length_ < maxScrollback) { backing.assumeSafeAppend(); @@ -1900,26 +1909,41 @@ class TerminalEmulator { } } + private int recalculationThreshold = 0; public void addScrollbackLine(TerminalCell[] line) { scrollbackBuffer ~= line; - if(!scrollbackReflow && line.length > scrollbackWidth_) - scrollbackWidth_ = cast(int) line.length; - scrollbackLength = cast(int) (scrollbackLength + 1 + (scrollbackBuffer[cast(int) scrollbackBuffer.length - 1].length) / screenWidth); - notifyScrollbackAdded(); + if(scrollbackBuffer.length_ == ScrollbackBuffer.maxScrollback) { + recalculationThreshold++; + if(recalculationThreshold > 100) { + recalculateScrollbackLength(); + notifyScrollbackAdded(); + recalculationThreshold = 0; + } + } else { + if(!scrollbackReflow && line.length > scrollbackWidth_) + scrollbackWidth_ = cast(int) line.length; + scrollbackLength = cast(int) (scrollbackLength + 1 + (scrollbackBuffer[cast(int) scrollbackBuffer.length - 1].length) / screenWidth); + notifyScrollbackAdded(); + } + if(!alternateScreenActive) notifyScrollbarPosition(0, int.max); } + protected int maxScrollbackLength() pure const @nogc nothrow { + return 1024; + } + bool insertMode = false; void newLine(bool commitScrollback) { if(!alternateScreenActive && commitScrollback) { // I am limiting this because obscenely long lines are kinda useless anyway and // i don't want it to eat excessive memory when i spam some thing accidentally - if(currentScrollbackLine.length < 1024) + if(currentScrollbackLine.length < maxScrollbackLength()) addScrollbackLine(currentScrollbackLine.sliceTrailingWhitespace); else - addScrollbackLine(currentScrollbackLine[0 .. 1024].sliceTrailingWhitespace); + addScrollbackLine(currentScrollbackLine[0 .. maxScrollbackLength()].sliceTrailingWhitespace); currentScrollbackLine = null; currentScrollbackLine.reserve(64);