From 1c119753b3d31bf3c903331e2b3f5bd4fc1c378e Mon Sep 17 00:00:00 2001 From: "Adam D. Ruppe" Date: Wed, 1 Apr 2020 14:48:11 -0400 Subject: [PATCH] moar terminal fixes --- minigui.d | 35 ++++++++++------ terminal.d | 91 ++++++++++++++++++++++++++++++++-------- terminalemulator.d | 102 ++++++++++++++++++++++++++++++++++----------- 3 files changed, 174 insertions(+), 54 deletions(-) diff --git a/minigui.d b/minigui.d index 0aa30de..18e217f 100644 --- a/minigui.d +++ b/minigui.d @@ -2126,7 +2126,6 @@ class ScrollableWidget : Widget { } else version(win32_widgets) { recomputeChildLayout(); } else static assert(0); - } /// @@ -2473,6 +2472,16 @@ abstract class ScrollbarBase : Widget { private int step_ = 16; private int position_; + /// + bool atEnd() { + return position_ + viewableArea_ >= max_; + } + + /// + bool atStart() { + return position_ == 0; + } + /// void setViewableArea(int a) { viewableArea_ = a; @@ -2720,7 +2729,7 @@ class HorizontalScrollbar : ScrollbarBase { version(win32_widgets) { SCROLLINFO info; info.cbSize = info.sizeof; - info.nPage = a; + info.nPage = a + 1; info.fMask = SIF_PAGE; SetScrollInfo(hwnd, SB_CTL, &info, true); } else version(custom_widgets) { @@ -2828,7 +2837,7 @@ class VerticalScrollbar : ScrollbarBase { version(win32_widgets) { SCROLLINFO info; info.cbSize = info.sizeof; - info.nPage = a; + info.nPage = a + 1; info.fMask = SIF_PAGE; SetScrollInfo(hwnd, SB_CTL, &info, true); } else version(custom_widgets) { @@ -3493,6 +3502,11 @@ class ScrollMessageWidget : Widget { magic = true; } + /// + VerticalScrollbar verticalScrollBar() { return vsb; } + /// + HorizontalScrollbar horizontalScrollBar() { return hsb; } + void notify() { auto event = new Event("scroll", this); event.dispatch(); @@ -3786,18 +3800,15 @@ class Window : Widget { event.dispatch(); break; case SB_THUMBTRACK: - auto event = new Event("scrolltrack", *widgetp); + // eh kinda lying but i like the real time update display + auto event = new Event("scrolltoposition", *widgetp); event.intValue = pos; event.dispatch(); - /+ - if(m == SB_THUMBTRACK) { - // the event loop doesn't seem to carry on with a requested redraw.. - // so we request it to get our dirty bit set... - redraw(); - // then we need to immediately actually redraw it too for instant feedback to user + // the event loop doesn't seem to carry on with a requested redraw.. + // so we request it to get our dirty bit set... + // then we need to immediately actually redraw it too for instant feedback to user + if(redrawRequested) actualRedraw(); - } - +/ break; default: } diff --git a/terminal.d b/terminal.d index a4d28cc..0bcbb2c 100644 --- a/terminal.d +++ b/terminal.d @@ -1100,10 +1100,10 @@ struct Terminal { if(guiThread is null) { guiThread = new Thread( { - auto window = new TerminalEmulatorWindow(&this); + auto window = new TerminalEmulatorWindow(&this, null); mainWindow = window; mainWindow.win.addEventListener((NewTerminalEvent t) { - auto nw = new TerminalEmulatorWindow(t.t); + auto nw = new TerminalEmulatorWindow(t.t, null); t.t.tew = nw.tew; t.t = null; nw.show(); @@ -3582,7 +3582,6 @@ void main() { getter.prompt = "> "; getter.history = ["abcdefghijklmnopqrstuvwzyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ"]; terminal.writeln("\n" ~ getter.getline()); - terminal.writeln("\n" ~ getter.getline()); terminal.writeln("\n" ~ getter.getline()); getter.dispose(); @@ -5906,14 +5905,28 @@ version(TerminalDirectToEmulator) { return tew.terminalEmulator; } - private this(Terminal* term) { + private TerminalEmulatorWindow parent; + private TerminalEmulatorWindow[] children; + private void childClosing(TerminalEmulatorWindow t) { + foreach(idx, c; children) + if(c is t) + children = children[0 .. idx] ~ children[idx + 1 .. $]; + } + private void registerChild(TerminalEmulatorWindow t) { + children ~= t; + } + + private this(Terminal* term, TerminalEmulatorWindow parent) { + + this.parent = parent; + scope(success) if(parent) parent.registerChild(this); + super("Terminal Application", integratedTerminalEmulatorConfiguration.initialWidth * integratedTerminalEmulatorConfiguration.fontSize / 2, integratedTerminalEmulatorConfiguration.initialHeight * integratedTerminalEmulatorConfiguration.fontSize); smw = new ScrollMessageWidget(this); tew = new TerminalEmulatorWidget(term, smw); smw.addEventListener("scroll", () { - // import std.stdio; writeln(smw.position.x, " ", smw.position.y); tew.terminalEmulator.scrollbackTo(smw.position.x, smw.position.y + tew.terminalEmulator.height); redraw(); }); @@ -5925,6 +5938,27 @@ version(TerminalDirectToEmulator) { integratedTerminalEmulatorConfiguration.menuExtensionsConstructor(this); } + TerminalEmulator.TerminalCell[] delegate(TerminalEmulator.TerminalCell[] i) parentFilter; + + private void addScrollbackLineFromParent(TerminalEmulator.TerminalCell[] lineIn) { + if(parentFilter is null) + return; + + auto line = parentFilter(lineIn); + if(line is null) return; + + if(tew && tew.terminalEmulator) { + bool atBottom = smw.verticalScrollBar.atEnd && smw.horizontalScrollBar.atStart; + tew.terminalEmulator.addScrollbackLine(line); + tew.terminalEmulator.notifyScrollbackAdded(); + if(atBottom) { + tew.terminalEmulator.notifyScrollbarPosition(0, int.max); + tew.terminalEmulator.scrollbackTo(0, int.max); + tew.redraw(); + } + } + } + private TerminalEmulatorWidget tew; private ScrollMessageWidget smw; @@ -5960,17 +5994,26 @@ version(TerminalDirectToEmulator) { } dialog((FilterParams p) { - // FIXME: this should update in real time... somehow. - auto nw = new TerminalEmulatorWindow(null); - nw.tew.terminalEmulator.toggleScrollLock(); - foreach(line; tew.terminalEmulator.sbb[0 .. $]) { + auto nw = new TerminalEmulatorWindow(null, this); + + nw.parentFilter = (TerminalEmulator.TerminalCell[] line) { import std.algorithm; import std.uni; // omg autodecoding being kinda useful for once LOL if(line.map!(c => c.hasNonCharacterData ? dchar(0) : (p.caseSensitive ? c.ch : c.ch.toLower)). canFind(p.searchTerm)) - nw.tew.terminalEmulator.addScrollbackLine(line); + { + // I might highlight the match too, but meh for now + return line; + } + return null; + }; + + foreach(line; tew.terminalEmulator.sbb[0 .. $]) { + if(auto l = nw.parentFilter(line)) + nw.tew.terminalEmulator.addScrollbackLine(l); } + nw.tew.terminalEmulator.toggleScrollLock(); nw.tew.terminalEmulator.drawScrollback(); nw.title = "Filter Display"; nw.show(); @@ -5981,9 +6024,12 @@ version(TerminalDirectToEmulator) { @separator void Clear() { tew.terminalEmulator.clearScrollbackHistory(); - //tew.terminalEmulator.cls(); - // FIXME: move cursor back to 0,0 - // tell the application to redraw too (maybe signal size changed) + tew.terminalEmulator.cls(); + tew.terminalEmulator.moveCursor(0, 0); + if(tew.term) { + tew.term.windowSizeChanged = true; + tew.terminalEmulator.outgoingSignal.notify(); + } tew.redraw(); } @@ -6040,6 +6086,11 @@ version(TerminalDirectToEmulator) { if(term) term.hangedUp = true; + if(auto wi = cast(TerminalEmulatorWindow) this.parentWindow) { + if(wi.parent) + wi.parent.childClosing(wi); + } + // try to get it to terminate slightly more forcibly too, if possible if(sigIntExtension) sigIntExtension(); @@ -6113,11 +6164,17 @@ version(TerminalDirectToEmulator) { redraw(); } + override void addScrollbackLine(TerminalCell[] line) { + super.addScrollbackLine(line); + if(widget) + if(auto p = cast(TerminalEmulatorWindow) widget.parentWindow) { + foreach(child; p.children) + child.addScrollbackLineFromParent(line); + } + } + override void notifyScrollbackAdded() { - if(this.scrollbackLength > this.height) - widget.smw.setTotalArea(this.scrollbackWidth, this.scrollbackLength); - else - widget.smw.setTotalArea(this.width, this.height); + widget.smw.setTotalArea(this.scrollbackWidth > this.width ? this.scrollbackWidth : this.width, this.scrollbackLength > this.height ? this.scrollbackLength : this.height); } override void notifyScrollbarPosition(int x, int y) { diff --git a/terminalemulator.d b/terminalemulator.d index 6130a15..f440000 100644 --- a/terminalemulator.d +++ b/terminalemulator.d @@ -530,7 +530,7 @@ class TerminalEmulator { if((!alternateScreenActive || scrollingBack) && key == TerminalKey.ScrollLock) { toggleScrollLock(); - return false; + return true; } // scrollback controls. Unlike xterm, I only want to do this on the normal screen, since alt screen @@ -1233,8 +1233,7 @@ class TerminalEmulator { private int scrollbackWidth_; int scrollbackWidth() { - return screenWidth; - //return scrollbackWidth_; // FIXME + return scrollbackWidth_ > screenWidth ? scrollbackWidth_ : screenWidth; } /* virtual */ void notifyScrollbackAdded() {} @@ -1246,8 +1245,9 @@ class TerminalEmulator { if(alternateScreenActive && !scrollingBack) return; - if(!scrollingBack) + if(!scrollingBack) { startScrollback(); + } if(y < 0) y = 0; @@ -1259,10 +1259,12 @@ class TerminalEmulator { if(currentScrollback < 0) currentScrollback = 0; + if(currentScrollbackX < 0) + currentScrollbackX = 0; - if(currentScrollback == 0) + if(!scrollLock && currentScrollback == 0 && currentScrollbackX == 0) { endScrollback(); - else { + } else { cls(); showScrollbackOnScreen(alternateScreen, currentScrollback, false, currentScrollbackX); } @@ -1273,19 +1275,20 @@ class TerminalEmulator { return; if(!scrollingBack) { - if(delta <= 0) + if(delta <= 0 && deltaX == 0) return; // it does nothing to scroll down when not scrolling back startScrollback(); } currentScrollback += delta; - if(deltaX) { + if(!scrollbackReflow && deltaX) { currentScrollbackX += deltaX; - if(currentScrollbackX < 0) { + int max = scrollbackWidth - screenWidth; + if(max < 0) + max = 0; + if(currentScrollbackX > max) + currentScrollbackX = max; + if(currentScrollbackX < 0) currentScrollbackX = 0; - if(!scrollLock) - scrollbackReflow = true; - } else - scrollbackReflow = false; } int max = cast(int) scrollbackBuffer.length - screenHeight; @@ -1304,8 +1307,10 @@ class TerminalEmulator { if(currentScrollback > max) currentScrollback = max; + if(currentScrollback < 0) + currentScrollback = 0; - if(currentScrollback <= 0) + if(!scrollLock && currentScrollback <= 0 && currentScrollbackX <= 0) endScrollback(); else { cls(); @@ -1330,6 +1335,8 @@ class TerminalEmulator { } bool endScrollback() { + //if(scrollLock) + // return false; if(!scrollingBack) return false; scrollingBack = false; @@ -1342,20 +1349,62 @@ class TerminalEmulator { currentScrollback = 0; currentScrollbackX = 0; + if(!scrollLock) { + scrollbackReflow = true; + recalculateScrollbackLength(); + } + notifyScrollbarPosition(0, int.max); return true; } private bool scrollbackReflow = true; + /* deprecated? */ public void toggleScrollbackWrap() { scrollbackReflow = !scrollbackReflow; + recalculateScrollbackLength(); } private bool scrollLock = false; public void toggleScrollLock() { scrollLock = !scrollLock; scrollbackReflow = !scrollLock; + recalculateScrollbackLength(); + + if(scrollLock) { + startScrollback(); + + cls(); + currentScrollback = 0; + currentScrollbackX = 0; + showScrollbackOnScreen(alternateScreen, currentScrollback, scrollbackReflow, currentScrollbackX); + notifyScrollbarPosition(currentScrollbackX, scrollbackLength - currentScrollback - screenHeight); + } else { + endScrollback(); + } + + //cls(); + //drawScrollback(); + } + + private void recalculateScrollbackLength() { + int count = cast(int) scrollbackBuffer.length; + int max; + if(scrollbackReflow) { + foreach(line; scrollbackBuffer[]) { + count += cast(int) line.length / screenWidth; + } + } else { + foreach(line; scrollbackBuffer[]) { + if(line.length > max) + max = cast(int) line.length; + } + } + scrollbackWidth_ = max; + scrollbackLength = count; + notifyScrollbackAdded(); + notifyScrollbarPosition(currentScrollbackX, currentScrollback ? scrollbackLength - currentScrollback : int.max); } public void writeScrollbackToFile(string filename) { @@ -1368,8 +1417,8 @@ class TerminalEmulator { } } - public void drawScrollback() { - showScrollbackOnScreen(normalScreen, 0, true, 0); + public void drawScrollback(bool useAltScreen = false) { + showScrollbackOnScreen(useAltScreen ? alternateScreen : normalScreen, 0, true, 0); } private void showScrollbackOnScreen(ref TerminalCell[] screen, int howFar, bool reflow, int howFarX) { @@ -1460,6 +1509,10 @@ class TerminalEmulator { if(w == screenWidth && h == screenHeight) return; // we're already good, do nothing to avoid wasting time and possibly losing a line (bash doesn't seem to like being told it "resized" to the same size) + // do i like this? + if(scrollLock) + toggleScrollLock(); + endScrollback(); // FIXME: hack screenWidth = w; @@ -1492,15 +1545,7 @@ class TerminalEmulator { cursorY = cursorY; cursorX = cursorX; - - int count = cast(int) scrollbackBuffer.length; - if(scrollbackReflow) { - foreach(line; scrollbackBuffer[]) - count += cast(int) line.length / screenWidth; - } - scrollbackLength = count; - notifyScrollbackAdded(); - notifyScrollbarPosition(currentScrollbackX, currentScrollback ? scrollbackLength - currentScrollback : int.max); + recalculateScrollbackLength(); } private CursorPosition popSavedCursor() { @@ -1540,6 +1585,11 @@ class TerminalEmulator { notifyScrollbackAdded(); } + public void moveCursor(int x, int y) { + cursorX = x; + cursorY = y; + } + /* FIXME: i want these to be private */ protected { TextAttributes currentAttributes; @@ -1853,6 +1903,8 @@ class TerminalEmulator { 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(!alternateScreenActive)