diff --git a/terminal.d b/terminal.d index 0532de6..5c424c8 100644 --- a/terminal.d +++ b/terminal.d @@ -3171,25 +3171,57 @@ struct ScrollbackBuffer { int start = cast(int) lines.length; int howMany = 0; + bool firstPartial = false; + size_t firstPartialStartIndex; + // we'll work backwards to figure out how much will fit... // this will give accurate per-line things even with changing width and wrapping // while being generally efficient - we usually want to show the end of the list // anyway; actually using the scrollback is a bit of an exceptional case. + + // It could probably do this instead of on each redraw, on each resize or insertion. + // or at least cache between redraws until one of those invalidates it. foreach_reverse(line; lines) { int written = 0; - foreach(component; line.components) { + int brokenLineCount; + size_t[16] lineBreaksBuffer; + size_t[] lineBreaks = lineBreaksBuffer[]; + comp_loop: foreach(component; line.components) { auto towrite = component.text; - written += towrite.length; - while(written > width) { - written -= width; - remaining--; - if(remaining <= 0) - break; + foreach(idx, dchar ch; towrite) { + if(written >= width) { + if(brokenLineCount == lineBreaks.length) + lineBreaks ~= idx; + else + lineBreaks[brokenLineCount] = idx; + + brokenLineCount++; + + written = 0; + } + + if(ch == '\t') + written += 8; // FIXME + else + written++; } } - remaining--; + lineBreaks = lineBreaks[0 .. brokenLineCount]; + foreach_reverse(lineBreak; lineBreaks) { + if(remaining == 1) { + firstPartial = true; + firstPartialStartIndex = lineBreak; + break; + } else { + remaining--; + } + if(remaining <= 0) + break; + } + + remaining--; start--; howMany++; @@ -3202,23 +3234,45 @@ struct ScrollbackBuffer { foreach(idx, line; lines[start .. start + howMany]) { int written = 0; + + if(linePos < 0) { + linePos++; + continue; + } terminal.moveTo(x, y + ((linePos >= 0) ? linePos : 0)); foreach(component; line.components) { terminal.color(component.color, component.background); auto towrite = component.text; - while(linePos < 0 && width < towrite.length) { - towrite = towrite[width .. $]; - linePos++; + + again: + + if(linePos >= height) + break; + + if(firstPartial) { + towrite = towrite[firstPartialStartIndex .. $]; + firstPartial = false; } - terminal.write(towrite); - written += towrite.length; - while(written > width) { - written -= width; - linePos++; - if(linePos >= height) - break; + + foreach(idx, dchar ch; towrite) { + if(written >= width) { + terminal.write(towrite[0 .. idx]); + towrite = towrite[idx .. $]; + linePos++; + written = 0; + terminal.moveTo(x, y + linePos); + goto again; + } + + if(ch == '\t') + written += 8; // FIXME + else + written++; } + + if(towrite.length) + terminal.write(towrite); } if(written < width) @@ -3231,6 +3285,7 @@ struct ScrollbackBuffer { break; } + if(linePos < height) foreach(i; linePos .. height) { if(i >= 0 && i < height) { terminal.moveTo(x, y + i); @@ -3242,12 +3297,14 @@ struct ScrollbackBuffer { void addLine(string line) { lines ~= Line([LineComponent(line)]); + if(scrollbackPosition) // if the user is scrolling back, we want to keep them basically centered where they are + scrollbackPosition++; } void scrollUp(int lines = 1) { scrollbackPosition += lines; - if(scrollbackPosition >= this.lines.length) - scrollbackPosition = cast(int) this.lines.length - 1; + //if(scrollbackPosition >= this.lines.length) + // scrollbackPosition = cast(int) this.lines.length - 1; } void scrollDown(int lines = 1) {