diff options
author | bptato <nincsnevem662@gmail.com> | 2024-09-13 22:26:51 +0200 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2024-09-13 23:45:22 +0200 |
commit | f362c0a03e0ac34d3ab2dcf02db9009990ea4240 (patch) | |
tree | ee7ff6a6519b6afd224f56ae5e3543ccf77927e0 | |
parent | e33fe22813e27652bb2d9de2c9f01ccb0376acca (diff) | |
download | chawan-f362c0a03e0ac34d3ab2dcf02db9009990ea4240.tar.gz |
term: improve damage tracking, special case yaft
It still sucks, but at least now it flashes a bit less. (I should really redo it properly some time) Also, special case yaft so that we always output sixels for it.
-rw-r--r-- | src/local/pager.nim | 1 | ||||
-rw-r--r-- | src/local/term.nim | 56 |
2 files changed, 42 insertions, 15 deletions
diff --git a/src/local/pager.nim b/src/local/pager.nim index 4640cf6a..bba25c23 100644 --- a/src/local/pager.nim +++ b/src/local/pager.nim @@ -592,6 +592,7 @@ proc initImages(pager: Pager; container: Container) = newImages.add(canvasImage) pager.term.clearImages(pager.bufHeight) pager.term.canvasImages = newImages + pager.term.checkImageDamage(pager.bufHeight) proc draw*(pager: Pager) = var redraw = false diff --git a/src/local/term.nim b/src/local/term.nim index 8d7cc353..47d79e54 100644 --- a/src/local/term.nim +++ b/src/local/term.nim @@ -683,8 +683,9 @@ proc positionImage(term: Terminal; image: CanvasImage; x, y, maxw, maxh: int): var width = image.width var height = image.height if term.imageMode == imSixel: - #TODO a better solution would be to split up the image here so that it - # still gets fully displayed on the screen, or at least downscale it... + # we *could* scale the images down, but this doesn't really look + # like a problem worth solving. just set the max sizes in xterm + # appropriately. width = min(width - image.offx, term.sixelMaxWidth) + image.offx height = min(height - image.offy, term.sixelMaxHeight) + image.offy image.dispw = min(width + xpx, maxwpx) - xpx @@ -692,15 +693,16 @@ proc positionImage(term: Terminal; image: CanvasImage; x, y, maxw, maxh: int): image.damaged = true return image.dispw > image.offx and image.disph > image.offy -proc clearImage*(term: Terminal; image: CanvasImage; maxh: int) = +proc clearImage(term: Terminal; image: CanvasImage; maxh: int) = case term.imageMode of imNone: discard of imSixel: # we must clear sixels the same way as we clear text. - let ey = min(image.y + image.height, maxh) + let h = (image.height + term.attrs.ppl - 1) div term.attrs.ppl # ceil + let ey = min(image.y + h, maxh) let x = max(image.x, 0) for y in max(image.y, 0) ..< ey: - term.lineDamage[y] = min(x, term.lineDamage[y]) + term.lineDamage[y] = min(term.lineDamage[y], x) of imKitty: term.imagesToClear.add(image) @@ -710,6 +712,34 @@ proc clearImages*(term: Terminal; maxh: int) = term.clearImage(image, maxh) image.marked = false +proc checkImageDamage*(term: Terminal; maxh: int) = + if term.imageMode == imSixel: + for image in term.canvasImages: + # check if any line of our image is damaged + let h = (image.height + term.attrs.ppl - 1) div term.attrs.ppl # ceil + let ey0 = min(image.y + h, maxh) + # here we floor, so that a last line with rounding error (which + # will not fully cover text) is always cleared + let ey1 = min(image.y + image.height div term.attrs.ppl, maxh) + let mx = image.x + (image.dispw - image.offx) div term.attrs.ppc + for y in max(image.y, 0) ..< ey0: + let od = term.lineDamage[y] + if od < mx: + image.damaged = true + if y >= ey1: + break + if od >= image.x: + # damage starts inside this image; skip clear (but only if + # the damage was not caused by a printing character) + var textFound = false + let si = y * term.attrs.width + for i in si + od ..< si + term.attrs.width: + if term.canvas[i].str.len > 0 and term.canvas[i].str[0] != ' ': + textFound = true + break + if not textFound: + term.lineDamage[y] = mx + proc loadImage*(term: Terminal; data: Blob; pid, imageId, x, y, width, height, rx, ry, maxw, maxh, erry, offx, dispw: int): CanvasImage = if (let image = term.findImage(pid, imageId, rx, ry, width, height, erry, @@ -723,14 +753,6 @@ proc loadImage*(term: Terminal; data: Blob; pid, imageId, x, y, width, height, # no longer on screen image.dead = true return nil - elif term.imageMode == imSixel: - # check if any line of our image is damaged - let ey = min(image.y + image.height, maxh) - let mx = (image.offx + image.dispw) div term.attrs.ppc - for y in max(image.y, 0) ..< ey: - if term.lineDamage[y] < mx: - image.damaged = true - break # only mark old images; new images will not be checked until the next # initImages call. image.marked = true @@ -926,6 +948,10 @@ proc quit*(term: Terminal) = if term.config.input.use_mouse: term.disableMouse() if term.smcup: + if term.imageMode == imSixel: + # xterm seems to keep sixels in the alt screen; clear these so + # it doesn't flash in the user's face the next time they do smcup + term.write(term.clearDisplay()) term.write(term.disableAltScreen()) else: term.write(term.cursorGoto(0, term.attrs.height - 1) & @@ -1204,10 +1230,10 @@ proc detectTermAttributes(term: Terminal; windowOnly: bool): TermStartResult = elif r.heightPx != 0: term.attrs.ppl = r.heightPx div r.height if not windowOnly: # we don't check for kitty, so don't override this - if qaSixel in r.attrs: - term.imageMode = imSixel if qaKittyImage in r.attrs: term.imageMode = imKitty + elif qaSixel in r.attrs or getEnv("TERM").startsWith("yaft"): # meh + term.imageMode = imSixel if term.imageMode == imSixel: # adjust after windowChange if r.registers != 0: # I need at least 2 registers, and can't do anything with more |