This is an automated email from the git hooks/post-receive script.
git pushed a commit to reference refs/pull/51/head
in repository terminology.
View the commit online.
commit 4aa5c238b99ccd0d3cc57d6605e0ea01ed5d6c14
Author: Cedric BAIL <[email protected]>
AuthorDate: Mon Aug 3 13:26:54 2026 -0600
tytest: cover the scrollback, dump state, and allow chunked reads
Three gaps that between them let real bugs through.
The checksum covered both screens but only backsize/backpos/beacon of the
backlog, so everything that had scrolled off was invisible to the tests --
which is exactly where a mistake in the scroll or text-append path shows up.
Hash the rows too, read back through termpty_cellrow_get(). Only fifteen of
the existing tests produce any scrollback at all, so add
backlog_scroll_stress.sh, which overflows the ring with long lines, short
lines, wide characters and combining marks.
A failing test previously gave two different md5 strings and no way to find
out why. --dump prints the screen, the scrollback, the cursor, the modes and
any pending reply in a form two runs can be diffed against each other.
--chunk=N feeds tytest N bytes per read. At N=1 every escape sequence and
every multibyte character straddles a boundary, which is what makes
carry-over bugs reproducible instead of a matter of timing. The suite passes
identically at 1, 2, 3, 7, 13, 64 and 4096; run_tests.sh gained --chunk to
drive it.
Checksums are regenerated for the fifteen tests that have scrollback.
Co-Authored-By: Claude Opus 5 <[email protected]>
---
src/bin/tytest.c | 228 ++++++++++++++++++++++++++++++++++++++++-
src/bin/tytest_common.c | 149 +++++++++++++++++----------
src/bin/tytest_common.h | 2 +
tests/backlog_scroll_stress.sh | 56 ++++++++++
tests/run_tests.sh | 17 ++-
tests/tests.results | 31 +++---
6 files changed, 411 insertions(+), 72 deletions(-)
diff --git a/src/bin/tytest.c b/src/bin/tytest.c
index c8b402a5..dd99b46c 100644
--- a/src/bin/tytest.c
+++ b/src/bin/tytest.c
@@ -13,6 +13,8 @@
#include "config.h"
#include "termpty.h"
#include "termptyops.h"
+#include "backlog.h"
+#include "utf8.h"
#include "termiointernals.h"
#include "tytest.h"
#include "unit_tests.h"
@@ -144,6 +146,37 @@ _termpty_to_termpty_tests(Termpty *ty, Termpty_Tests *tt)
tt->bracketed_paste = ty->bracketed_paste;
}
+/* Fold the scrollback into the checksum.
+ *
+ * Only backsize/backpos/beacon used to be covered, so everything that had
+ * scrolled off the screen was invisible to the tests -- which is precisely
+ * where a bug in the scroll or text-append path shows up first. Rows are read
+ * back through termpty_cellrow_get() rather than reached into directly, so the
+ * test keeps comparing what a reader of the backlog would see even if how a
+ * row is stored changes. */
+static void
+_checksum_backlog(Termpty *ty, MD5_CTX *ctx)
+{
+ ssize_t len = termpty_backlog_length(ty);
+ int y;
+
+ for (y = 1; y <= (int)len; y++)
+ {
+ const Termcell *cells;
+ ssize_t w = 0;
+ uint32_t width;
+
+ cells = termpty_cellrow_get(ty, -y, &w);
+ if (!cells || (w < 0)) w = 0;
+ /* Fixed width, not sizeof(ssize_t): the checksum is compared across
+ * machines and must not depend on the size of a pointer. */
+ width = (uint32_t)w;
+ MD5Update(ctx, (unsigned char const*)&width, sizeof(width));
+ if (cells && (w > 0))
+ MD5Update(ctx, (unsigned char const*)cells, sizeof(Termcell) * w);
+ }
+}
+
static void
_tytest_checksum(Termpty *ty)
{
@@ -168,6 +201,8 @@ _tytest_checksum(Termpty *ty)
MD5Update(&ctx,
(unsigned char const*)ty->screen2,
sizeof(Termcell) * ty->w * ty->h);
+ /* The scrollback */
+ _checksum_backlog(ty, &ctx);
/* Icon/Title */
if (ty->prop.icon)
{
@@ -212,11 +247,196 @@ _tytest_checksum(Termpty *ty)
}
+/* Render a cell's codepoint into a dump-safe form.
+ *
+ * Anything that would move the cursor or otherwise talk back to the terminal
+ * displaying the dump has to be escaped, or reading a dump would garble the
+ * reader's own screen. */
+static void
+_dump_codepoint(Eina_Unicode g)
+{
+ char utf8[8];
+ int n;
+
+ if (g == 0)
+ {
+ putchar(' ');
+ return;
+ }
+ /* Media blocks are encoded with bit 31 set and are not text at all. */
+ if (g & 0x80000000)
+ {
+ printf("\\B");
+ return;
+ }
+ if (g < 0x20 || g == 0x7f)
+ {
+ printf("\\x%02x", (unsigned int)g);
+ return;
+ }
+ n = codepoint_to_utf8(g, utf8);
+ if (n <= 0)
+ {
+ printf("\\u%04x", (unsigned int)g);
+ return;
+ }
+ fwrite(utf8, 1, n, stdout);
+}
+
+/* Emit one row as text plus a run-length summary of its attributes.
+ *
+ * Attributes are summarised rather than printed per cell because the point is
+ * to make a diff between two dumps land on the cell that actually differs,
+ * without burying it in eighty identical attribute records. */
+static void
+_dump_row(const Termcell *cells, int w, const char *label)
+{
+ int x, start;
+
+ printf("%s |", label);
+ for (x = 0; x < w; x++)
+ _dump_codepoint(cells[x].codepoint);
+ printf("|\n");
+
+ x = 0;
+ while (x < w)
+ {
+ const Termatt *a = &cells[x].att;
+
+ start = x;
+ while ((x < w) &&
+ (memcmp(&cells[x].att, a, sizeof(Termatt)) == 0))
+ x++;
+ /* Skip the default run: saying nothing is clearer than saying nothing
+ * verbosely, and it keeps a clean screen's dump short. */
+ if ((a->fg != 0) || (a->bg != 0) || a->bold || a->faint || a->italic ||
+ a->underline || a->blink || a->blink2 || a->inverse ||
+ a->invisible || a->strike || a->fg256 || a->bg256 ||
+ a->fgintense || a->bgintense || a->dblwidth || a->autowrapped ||
+ a->newline || a->fraktur || a->framed || a->encircled ||
+ a->overlined || a->link_id)
+ {
+ printf("%s att %d-%d fg=%u bg=%u", label, start, x - 1,
+ (unsigned)a->fg, (unsigned)a->bg);
+ if (a->fg256) printf(" fg256");
+ if (a->bg256) printf(" bg256");
+ if (a->fgintense) printf(" fgint");
+ if (a->bgintense) printf(" bgint");
+ if (a->bold) printf(" bold");
+ if (a->faint) printf(" faint");
+ if (a->italic) printf(" italic");
+ if (a->underline) printf(" underline");
+ if (a->blink) printf(" blink");
+ if (a->blink2) printf(" blink2");
+ if (a->inverse) printf(" inverse");
+ if (a->invisible) printf(" invisible");
+ if (a->strike) printf(" strike");
+ if (a->dblwidth) printf(" dblwidth");
+ if (a->autowrapped) printf(" autowrapped");
+ if (a->newline) printf(" newline");
+ if (a->fraktur) printf(" fraktur");
+ if (a->framed) printf(" framed");
+ if (a->encircled) printf(" encircled");
+ if (a->overlined) printf(" overlined");
+ if (a->link_id) printf(" link=%u", (unsigned)a->link_id);
+ printf("\n");
+ }
+ }
+}
+
+/* Human-readable counterpart to _tytest_checksum().
+ *
+ * The checksum answers "did anything change"; this answers "what changed",
+ * which is the question a scalar-versus-SIMD parity failure actually raises.
+ * Two dumps piped through diff point straight at the offending cell. */
+static void
+_tytest_dump(Termpty *ty)
+{
+ ssize_t backlog_len;
+ int y;
+
+ printf("geom w=%d h=%d\n", ty->w, ty->h);
+ printf("cursor x=%d y=%d wrapnext=%d shape=%s\n",
+ ty->cursor_state.cx, ty->cursor_state.cy,
+ (int)ty->cursor_state.wrapnext, tytest_cursor_shape_get());
+ printf("mode altbuf=%d insert=%d wrap=%d bracketed_paste=%d\n",
+ (int)ty->altbuf, (int)ty->termstate.insert,
+ (int)ty->termstate.wrap, (int)ty->bracketed_paste);
+ printf("margin top=%d bottom=%d left=%d right=%d restrict=%d\n",
+ ty->termstate.top_margin, ty->termstate.bottom_margin,
+ ty->termstate.left_margin, ty->termstate.right_margin,
+ (int)ty->termstate.restrict_cursor);
+ printf("title=%s\n", ty->prop.title ? ty->prop.title : "(NULL)");
+ printf("icon=%s\n", ty->prop.icon ? ty->prop.icon : "(NULL)");
+
+ backlog_len = termpty_backlog_length(ty);
+ printf("backlog rows=%d\n", (int)backlog_len);
+ for (y = (int)backlog_len; y >= 1; y--)
+ {
+ const Termcell *cells;
+ ssize_t w = 0;
+ char label[32];
+
+ cells = termpty_cellrow_get(ty, -y, &w);
+ snprintf(label, sizeof(label), "b%-4d", -y);
+ if (cells && (w > 0)) _dump_row(cells, (int)w, label);
+ else printf("%s ||\n", label);
+ }
+
+ printf("screen\n");
+ for (y = 0; y < ty->h; y++)
+ {
+ char label[32];
+
+ snprintf(label, sizeof(label), "s%-4d", y);
+ _dump_row(&(TERMPTY_SCREEN(ty, 0, y)), ty->w, label);
+ }
+
+ if (ty->write_buffer.len)
+ {
+ size_t i;
+
+ printf("reply ");
+ for (i = 0; i < ty->write_buffer.len; i++)
+ {
+ unsigned char ch = (unsigned char)ty->write_buffer.buf[i];
+
+ if ((ch >= 0x20) && (ch < 0x7f)) putchar(ch);
+ else printf("\\x%02x", ch);
+ }
+ printf("\n");
+ }
+}
+
+static void
+_usage(const char *argv0)
+{
+ fprintf(stderr,
+ "usage: %s read escape codes on stdin, print a state checksum\n"
+ " %s --dump same, but print the state in a diffable text form\n"
+ " %s <test>|all run the built-in unit tests\n",
+ argv0, argv0, argv0);
+}
+
int
main(int argc, char **argv)
{
- if (argc > 1)
- return _run_tytests(argc, argv);
+ Eina_Bool dump = EINA_FALSE;
+ int chunk = 0;
+ int i;
+
+ for (i = 1; i < argc; i++)
+ {
+ if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help"))
+ {
+ _usage(argv[0]);
+ return 0;
+ }
+ else if (!strcmp(argv[i], "--dump")) dump = EINA_TRUE;
+ else if (!strncmp(argv[i], "--chunk=", 8)) chunk = atoi(argv[i] + 8);
+ /* Anything else is a unit test name, and those take over entirely. */
+ else return _run_tytests(argc, argv);
+ }
eina_init();
emile_init();
@@ -224,10 +444,12 @@ main(int argc, char **argv)
_log_domain = eina_log_domain_register("tytest", NULL);
tytest_common_init();
+ if (chunk > 0) tytest_common_set_chunk(chunk);
tytest_common_main_loop();
- _tytest_checksum(tytest_termpty_get());
+ if (dump) _tytest_dump(tytest_termpty_get());
+ else _tytest_checksum(tytest_termpty_get());
tytest_common_shutdown();
diff --git a/src/bin/tytest_common.c b/src/bin/tytest_common.c
index 766e12c6..14edbe93 100644
--- a/src/bin/tytest_common.c
+++ b/src/bin/tytest_common.c
@@ -11,6 +11,7 @@
#include "termpty.h"
#include "termptyops.h"
#include "termiointernals.h"
+#include "utf8.h"
#include "tytest_common.h"
#if defined(BINARY_TYTEST)
#include "colors.h"
@@ -479,24 +480,100 @@ _termpty_init(Termpty *ty, Config *config)
ty->backlog_beacon.screen_y = 0;
}
+/* Scratch buffers for the feed path. Grown on demand and kept between calls so
+ * that a benchmark measures the parser rather than the allocator. */
+static char *_feed_buf = NULL;
+static Eina_Unicode *_feed_codepoint = NULL;
+static int _feed_size = 0;
+
+static Eina_Bool
+_feed_reserve(int len)
+{
+ char *buf;
+ Eina_Unicode *codepoint;
+ int size;
+
+ /* Room for the bytes themselves, a multibyte sequence carried over from the
+ * previous chunk, and the NUL that utf8_to_codepoints() expects. */
+ size = len + UTF8_CARRY_MAX + 1;
+ if (size <= _feed_size) return EINA_TRUE;
+
+ buf = realloc(_feed_buf, size);
+ if (!buf) return EINA_FALSE;
+ _feed_buf = buf;
+
+ codepoint = realloc(_feed_codepoint, size * sizeof(Eina_Unicode));
+ if (!codepoint) return EINA_FALSE;
+ _feed_codepoint = codepoint;
+
+ _feed_size = size;
+ return EINA_TRUE;
+}
+
+/* Feed one chunk of raw pty bytes, exactly as if read() had just returned them.
+ * A multibyte sequence left dangling at the end of the chunk is retained and
+ * completed by the next call, so callers are free to split the stream anywhere. */
+void
+tytest_common_feed(const char *data, int datalen)
+{
+ char *rbuf;
+ int i, j, len, consumed;
+
+ if (datalen <= 0) return;
+ if (!_feed_reserve(datalen))
+ {
+ ERR("memerr: cannot grow feed buffer to %d bytes", datalen);
+ return;
+ }
+
+ rbuf = _feed_buf;
+ for (i = 0; i < (int)sizeof(_ty.oldbuf) && _ty.oldbuf[i] & 0x80; i++)
+ {
+ *rbuf = _ty.oldbuf[i];
+ rbuf++;
+ }
+ memcpy(rbuf, data, datalen);
+ len = (rbuf - _feed_buf) + datalen;
+
+ for (i = 0; i < (int)sizeof(_ty.oldbuf); i++)
+ _ty.oldbuf[i] = 0;
+
+ _feed_buf[len] = 0;
+ // convert UTF8 to codepoint integers
+ j = utf8_to_codepoints(_feed_buf, len, _feed_codepoint, &consumed);
+ /* Retain a multibyte sequence cut in half by the chunk boundary; it gets put
+ * back in front of the next chunk. */
+ for (i = 0; (i < len - consumed) && (i < (int)sizeof(_ty.oldbuf)); i++)
+ _ty.oldbuf[i] = _feed_buf[consumed + i];
+ _feed_codepoint[j] = 0;
+ termpty_handle_buf(&_ty, _feed_codepoint, j);
+}
+
+/* How much to take from the fd at a time.
+ *
+ * Adjustable so the suite can replay the same input at different chunk sizes.
+ * Feeding one byte at a time is a brutal test of the carry-over logic: every
+ * escape sequence and every multibyte character then straddles a boundary, and
+ * the result must still be identical to reading in big blocks. */
+static int _read_chunk = 4096;
+
+void
+tytest_common_set_chunk(int chunk)
+{
+ if (chunk > 0) _read_chunk = chunk;
+}
+
void
tytest_common_main_loop(void)
{
+ char buf[4096];
+ int len, want;
+
+ want = (_read_chunk < (int)sizeof(buf)) ? _read_chunk : (int)sizeof(buf);
+
do
{
- char buf[4097];
- Eina_Unicode codepoint[4097];
- int i, j;
- char *rbuf = buf;
- int len = sizeof(buf) - 1;
-
- for (i = 0; i < (int)sizeof(_ty.oldbuf) && _ty.oldbuf[i] & 0x80; i++)
- {
- *rbuf = _ty.oldbuf[i];
- rbuf++;
- len--;
- }
- len = read(_ty.fd, rbuf, len);
+ len = read(_ty.fd, buf, want);
if (len < 0 && errno != EAGAIN)
{
ERR("error while reading from tty slave fd");
@@ -504,46 +581,7 @@ tytest_common_main_loop(void)
}
if (len <= 0) break;
- for (i = 0; i < (int)sizeof(_ty.oldbuf); i++)
- _ty.oldbuf[i] = 0;
-
- len += rbuf - buf;
-
- buf[len] = 0;
- // convert UTF8 to codepoint integers
- j = 0;
- for (i = 0; i < len;)
- {
- int g = 0, prev_i = i;
-
- if (buf[i])
- {
- g = eina_unicode_utf8_next_get(buf, &i);
- if ((0xdc80 <= g) && (g <= 0xdcff) &&
- (len - prev_i) <= (int)sizeof(_ty.oldbuf))
- {
- int k;
- for (k = 0;
- (k < (int)sizeof(_ty.oldbuf)) &&
- (k < (len - prev_i));
- k++)
- {
- _ty.oldbuf[k] = buf[prev_i+k];
- }
- DBG("failure at %d/%d/%d", prev_i, i, len);
- break;
- }
- }
- else
- {
- g = 0;
- i++;
- }
- codepoint[j] = g;
- j++;
- }
- codepoint[j] = 0;
- termpty_handle_buf(&_ty, codepoint, j);
+ tytest_common_feed(buf, len);
}
while (1);
}
@@ -563,6 +601,11 @@ tytest_common_init(void)
void
tytest_common_shutdown(void)
{
+ free(_feed_buf);
+ _feed_buf = NULL;
+ free(_feed_codepoint);
+ _feed_codepoint = NULL;
+ _feed_size = 0;
config_del(_config);
#if defined(BINARY_TYTEST)
free(_cells);
diff --git a/src/bin/tytest_common.h b/src/bin/tytest_common.h
index ca3a1291..da74ed85 100644
--- a/src/bin/tytest_common.h
+++ b/src/bin/tytest_common.h
@@ -10,6 +10,8 @@
#define TY_BACKSIZE 50
void tytest_common_main_loop(void);
+void tytest_common_feed(const char *data, int datalen);
+void tytest_common_set_chunk(int chunk);
void tytest_common_init(void);
void tytest_common_shutdown(void);
void tytest_common_set_fd(int fd);
diff --git a/tests/backlog_scroll_stress.sh b/tests/backlog_scroll_stress.sh
new file mode 100755
index 00000000..b8158eda
--- /dev/null
+++ b/tests/backlog_scroll_stress.sh
@@ -0,0 +1,56 @@
+#!/bin/sh
+# Push far more content through the screen than the backlog can hold, so that
+# the scrollback ring wraps and old rows are evicted.
+#
+# Most of the suite never scrolls anything off screen, which left the whole
+# save/evict path uncovered. It is also exactly the path a bulk text-append
+# fast path is most likely to break, so it is worth exercising deliberately:
+# long printable runs, runs that wrap at the right margin, rows of differing
+# lengths, and attribute changes that must survive being saved and read back.
+
+# Known state.
+printf '\033c'
+
+# Backlog is 50 rows in the test harness; 120 lines guarantees eviction.
+i=1
+while [ $i -le 120 ]; do
+ # Vary the colour so saved rows are not all attribute-identical.
+ printf '\033[3%d;4%dm' $((i % 8)) $(((i / 8) % 8))
+
+ case $((i % 4)) in
+ 0)
+ # Short line: leaves the tail of the row untouched.
+ printf 'row %d\n' $i
+ ;;
+ 1)
+ # Long line: overruns 80 columns and must autowrap.
+ printf 'row %d ' $i
+ j=0
+ while [ $j -le 12 ]; do
+ printf 'abcdefghi'
+ j=$((j + 1))
+ done
+ printf '\n'
+ ;;
+ 2)
+ # Exactly-at-margin content, to catch off-by-one wrapping.
+ printf 'row %d ' $i
+ printf '%s' 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
+ printf '\n'
+ ;;
+ 3)
+ # Wide characters and a combining mark: the lead cell carries the
+ # codepoint with dblwidth set and the trailing cell must follow it into
+ # the backlog intact.
+ printf 'row %d 漢字テスト e\314\201 done\n' $i
+ ;;
+ esac
+ i=$((i + 1))
+done
+
+printf '\033[0m'
+
+# Scroll a little more with explicit SU/SD so the ring is left mid-rotation
+# rather than neatly aligned.
+printf '\033[5S'
+printf '\033[2T'
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index 9fb2d1e4..1ff55d09 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -9,6 +9,7 @@ VERBOSE=0
DEBUG=0
GENRESULTS=0
EXIT_ON_FAILURE=0
+CHUNK=""
NB_TESTS=0
OK_TESTS=0
FAILED_TESTS=0
@@ -72,6 +73,9 @@ where options are:
-r, --results=PATH Path to the result file
-d, --testdir=PATH Path to the test files
-e, --exitonfailure Exit as soon as a test fails
+ -c, --chunk=N Feed tytest N bytes per read, to exercise sequences
+ split across read boundaries. Results must match the
+ default run exactly.
Misc options:
-v, --verbose Be verbose about what is being done
@@ -128,6 +132,13 @@ while [ $# -gt 0 ]; do
-e|-exitonfailure|--exitonfailure)
EXIT_ON_FAILURE=1
;;
+ -c|-chunk|--chunk)
+ if [ -z "$value" ]; then
+ value=$1
+ shift
+ fi
+ CHUNK="--chunk=$value"
+ ;;
*)
echo "Unknown option: $option" 1>&2
;;
@@ -167,7 +178,11 @@ while read -r TEST EXPECTED_CHECKSUMS; do
if [ $VERBOSE -ne 0 ]; then
printf "%s... " "$TEST"
fi
- TEST_CHECKSUM=$("$TESTDIR"/"$TEST" | "$TYTEST")
+ if [ -n "$CHUNK" ]; then
+ TEST_CHECKSUM=$("$TESTDIR"/"$TEST" | "$TYTEST" "$CHUNK")
+ else
+ TEST_CHECKSUM=$("$TESTDIR"/"$TEST" | "$TYTEST")
+ fi
if [ $DEBUG -ne 0 ]; then
printf "(got %s, expected %s) " "$TEST_CHECKSUM" "$EXPECTED_CHECKSUMS"
fi
diff --git a/tests/tests.results b/tests/tests.results
index 8f6d270a..ca7e39eb 100644
--- a/tests/tests.results
+++ b/tests/tests.results
@@ -8,7 +8,7 @@ decfra-decera-default-values-restrict-cursor.sh c560b8109c4e1e5b73aa18565abc1745
decfra-decera-default-values-no-restrict-cursor.sh 7d7846049f209a0627e4d82e983e9b84
cursor-movements.sh 880a64ce470853df78fea1f06d3cb8d4
cursor-movements-alias.sh 880a64ce470853df78fea1f06d3cb8d4
-fonts.sh 6a28e19506e89e13b1746a94821e0c75
+fonts.sh 184ddefedae324506fede39b52392cf3
cursor-shape-0.sh c4158ed98a8e4104cb14063bbb14c248
cursor-shape-1.sh c4158ed98a8e4104cb14063bbb14c248
cursor-shape-2.sh c4158ed98a8e4104cb14063bbb14c248
@@ -29,7 +29,7 @@ dsr-deccksr.sh 63c573a679a63496d48ed24ff0707415
dsr-os.sh ec12b9bef28bd875d6140a4c1d5f7a02
dsr-pp.sh cce6b8bedc183f635d9a5d176bb32b79
dsr-udk.sh ff22d657614bb6137bdb5f0788b4c7c7
-colors.sh e32761a6b7f6099f0d68192365d6bde7
+colors.sh 03282bddefd22c8a9fac7dfc1d37a4ce
colors_regression.sh 988cea4d5f08c0896a94ac54b8060aa1
sgr-leading-trailing-semicolon.sh 04aad2aa7bad05daf66ac2266f6bfc20
sgr-truecolors.sh d4b734a8e0bce1cc329e6b72ca012f20
@@ -57,15 +57,15 @@ decrara-no-rectangular-restrict-cursor.sh 161735f93a179f96512bf9fae780262f
decic-decdc.sh 1e88ff7e19c9558f3f15a59dda5014dc
ich.sh d96a88b7beffe078a597255ce16bbbe4
deccra.sh da33245af1439f8c1c95805a95e19251
-ed-0.sh d8ae92dfe721d2fe1da925a18ddbe977
-ed-1.sh c5ce8829b95846c97eefb807aef08357
-ed-2.sh 94eb9cde56d9a07098ab2b06aea6790a
+ed-0.sh 4485e8a1bf1a91bb1c694aefc38cb41e
+ed-1.sh 52956f2a78f6b71c1f05a2f01978a1db
+ed-2.sh 6f56e3cd4306168d79fef3d8096f3545
ed-3.sh 85d65d2019328c901bca80f6aa33f0da
-ed-4.sh 2bd30bedaf289f7cce7d18069e0072de
+ed-4.sh c4aa110d74e408369943e81475829a57
el.sh 61fc84bf523380c997699b6f2dff7531
il.sh a56b8fc5367f6f2315fb1682fc1a3518
dl.sh 0b3355e7dc86eaf8ddfb72e577452026
-su.sh 4a12c024392a77d706024afec991dae9
+su.sh c39c0db4961a6b641f9459eaf8aa89e9
sd.sh 68181f983b5063cef1fef55b82ab3ca0
decst8c.sh 30db60c51a94776cd4cc09875902c641
ctc.sh 79d7fafcf9aacd8a142f7d902e6cb0e4
@@ -74,7 +74,7 @@ ech.sh bd3e4bb93bb4911779e69cfa87ed35ae
text_append_after_right_margin.sh 5afedcb8b0d8abb8ef5c619decfd5c33
cbt.sh 687e95911f04262b08fc48f78b15ed07
hpa.sh b4740ae6a395eb1fef152a4b77679f52
-rep.sh 3c7a143f9e026299d8d6cf204427686d
+rep.sh ae6e15852020def0169792f6d793f6d7
da.sh ff77a3285a98c78dd225d3f3ea7f8c4a
uts.sh f0f33a807af659ee05bde6d836bb4e46
vpa.sh 018997127c51f4826ed08c41297b987d
@@ -90,9 +90,9 @@ selection_box_drag.sh 9855fe72c325b9ed95de8a95f27e8b35
selection_double_click.sh b028759ce05954c71e3aace6910f384d
selection_word_regression.sh 86dc33e937bd5d6dabca2ed7de44f5cf
selection_triple_click.sh 1a628cbd6b88fe18328438028ca6e887
-selection_scrolls.sh 121e89e4234b3d56f095881b4a13505f
+selection_scrolls.sh 47bb71c59189e2b504f14a3daa0e0db5
selection_with_margins_scrolled.sh bde9eaae126e8bddbc340399edc8f565
-selection_in_history.sh f7c90908b3948fc8838498c1fba68bb8
+selection_in_history.sh 3438ed2bf58eb81e4995ad7df48b0768
selection_over_multiple_lines.sh 5f23b0087b117f0c13c390251a644aff
selection_invisible.sh b95410413cb1d967bd56c62ba51ed927
selection_to_position.sh e39538611df6cff3d3017b860f8c8227
@@ -131,11 +131,11 @@ title_icon_stack_default.sh 62a34a00406243ecf57a79d69b92ef50
zero-width-spaces.sh 4713ffc7a5f6e7573910183f1609275f
link_detection_email_surrounded.sh 119ce6c19b50fd02d9e5d7290baa7bac
link_detection_email_surrounded_more.sh 7abc7889df346369a53c9092268af131
-selection_scrolls_up.sh 9565ec642ad982e008c3856de955e356
-selection_box_in_history.sh ed2fba61de4316ac3dd08bd3c3d1c831
-selection_box_scrolls_up.sh 9565ec642ad982e008c3856de955e356
-selection_scrolls_down.sh 9565ec642ad982e008c3856de955e356
-selection_box_scrolls_down.sh 9565ec642ad982e008c3856de955e356
+selection_scrolls_up.sh 50974157db192d2a87f9140569973028
+selection_box_in_history.sh ce2327baf14ea3e20838ad542ef53c6e
+selection_box_scrolls_up.sh 50974157db192d2a87f9140569973028
+selection_scrolls_down.sh 50974157db192d2a87f9140569973028
+selection_box_scrolls_down.sh 50974157db192d2a87f9140569973028
true_color_cache_thrashing.sh 277c13fbac95cea95a07227a7b466f67
true_color_cache_reuse.sh 144a8199f4744ed031270d5ea69e00d2
selection_word_low_ascii_separators.sh 053af5439fb5432b6eb859b51c226747
@@ -153,3 +153,4 @@ xterm-colors-rgbi.sh e03b6094b2e6ff60b519f132e9fc4433
xterm-set-cursor-color.sh 014a0027499b74ab705575c08005f438
csi-38-no-value.sh 70a432233cdbeeffb383c51be47979d4
osc_selection.sh ee9d9efb1f820ffd54de9465a9a90221
+backlog_scroll_stress.sh 13a8e9401817e5aacaaad3442b66765e
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.