#!/bin/sh -e
# Generated by patch2vi from unified diff
# Available separators: 0003-0010 0013-0014 0016-0037 0104 0107 0112 0121 0126-0131 0136 0177-0377

# Pass any argument to use patch(1) instead of nextvi ex commands
if [ -n "$1" ]; then
    sed '1,/^=== PATCH2VI PATCH ===$/d' "$0" | patch -p1 --merge=diff3
    exit $?
fi

VI=${VI:-vi}
if ! $VI -? 2>&1 | grep -q 'Nextvi'; then
    echo "Error: $VI is not nextvi" >&2
    echo "Set VI environment variable to point to nextvi binary" >&2
    exit 1
fi

SEP="$(printf '\001')"
ESC="$(printf '\002')"
# Command that handles readability line breaks
LB="0?"
# Phase 1 (search/mark): errors disabled by default,
# DBG1=1 enables error reporting, QF1=1 quits on failure
# OK1: with DBG1=1 also report fallback anchor successes
[ "$DBG1" = "1" ] && OK1= || OK1="0?"
[ "$DBG1" = "1" ] && DBG1= || DBG1="0?"
[ "$QF1" = "1" ] && QF1="${ESC}${SEP}vis 2${ESC}${SEP}q!1" || QF1=
# Phase 2 (edits): DBG2=1 disables errors, QF2=1 ignores them
# OK2: with DBG2= also report fallback substitute successes
[ "$DBG2" = "1" ] && OK2="0?" || OK2=
[ "$DBG2" = "1" ] && DBG2="0?" || DBG2=
[ "$QF2" = "1" ] && QF2= || QF2="${ESC}${SEP}vis 2${ESC}${SEP}q!1"
# Enters vi at failing code line in this script
# Designed for state inspection mid execution
[ "$INTR" = "1" ] && INTR="${ESC}${SEP}|sc|${ESC}${SEP}vis 2:fr 0:e $0:83reg %@47:%f> %@112:&Q:b0:|sc! ${ESC}${ESC}${ESC}${SEP}|:vis 3${ESC}${SEP}q1" || INTR=

# Patch: lbuf.c ren.c vi.c vi.h
# Body too large for EXINIT/argv: stage it in a file
( : > /tmp/p2vi.$$ ) 2>/dev/null && P2VIF=/tmp/p2vi.$$ || P2VIF=./p2vi.$$
trap 'rm -f "$P2VIF"' EXIT
printf '%s\n' "|sc! ${ESC}${SEP}|:vis 3${SEP}fr 98${SEP}b0${SEP}%ya 98${SEP}?${ESC}${SEP}${LB}
${ESC}${SEP}%f> static int lbuf_replace\\(struct lbuf \\*lb, sbuf \\*sb, char \\*s, struct lopt \\*lo, int n_del, int n_ins\\)
\\{
	int i, pos = lo->pos;
	if \\(s\\) \\{
		for \\(; \\*s; n_ins\\+\\+\\) \\{
			int l = linelength\\(s\\);${ESC}${SEP}1??${ESC}${SEP}${LB}
${ESC}${SEP}1??+2m 1${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}%f> static int lbuf_replace\\(struct lbuf \\*lb, sbuf \\*sb, char \\*s, struct lopt \\*lo, int n_del, int n_ins\\)
\\{
	int i, pos = lo->pos;${ESC}${SEP}3??${ESC}${SEP}${LB}
${ESC}${SEP}3??+2m 1${ESC}${ESC}${ESC}${SEP}${OK1}p OK lbuf.c:101:a3${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}grp 1${ESC}${SEP}%f> static int lbuf_replace\\(struct lbuf \\*lb, sbuf \\*sb, char \\*s, struct lopt \\*lo, int n_del, int n_ins\\).*?
\\{.*?
(	int i, pos = lo->pos;)${ESC}${SEP}7??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}7??m 1${ESC}${ESC}${ESC}${SEP}${OK1}p OK lbuf.c:101:a7${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}m 0${ESC}${SEP}1;0${ESC}${SEP}grp 1${ESC}${SEP}%f> 	int len = dstrlen\\(s, '\\\\n'\\);
	return s\\[len] == '\\\\n' \\? len \\+ 1 : len;
}.*(			int l_nonl = l - \\(s\\[l - !!l] == '\\\\n'\\);)
			struct linfo \\*n = emalloc\\(l_nonl \\+ 5 \\+ sizeof\\(struct linfo\\)\\);
			n->len = l_nonl;${ESC}${SEP}8??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}8??-4m 1${ESC}${ESC}${ESC}${SEP}${OK1}p OK lbuf.c:101:a8${ESC}${SEP}'0${ESC}${SEP}8??${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}m 0${ESC}${SEP}1;0${ESC}${SEP}grp 1${ESC}${SEP}%f> 	free\\(lb->ln\\);
	free\\(lb\\);
}.*(			n->grec = 0;)
			char \\*ln = \\(char\\*\\)\\(n \\+ 1\\);
			memcpy\\(ln, s, l_nonl\\);${ESC}${SEP}9??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}9??-7m 1${ESC}${ESC}${ESC}${SEP}${OK1}p OK lbuf.c:101:a9${ESC}${SEP}'0${SEP}${LB}
${SEP}1;3;7;8;9??!${DBG1:-ya!112${ESC}${SEP}prp${ESC}${SEP}p FAIL lbuf.c:101${ESC}${SEP}pr${INTR}${QF1}}${SEP}${LB}
${SEP}${LB}
${SEP}'1i 	syn_blockhl_invalidate();
${SEP}??!${DBG2:-ya!112${ESC}${SEP}prp${ESC}${SEP}p FAIL lbuf.c:101:m1${ESC}${SEP}pr${INTR}${QF2}}${SEP}b1${SEP}%ya 98${SEP}?${ESC}${SEP}${LB}
${ESC}${SEP}%f> int ftidx;
int syn_blockhl;

static int syn_initft\\(int fti, int n, char \\*name, int flg\\)
\\{
	if \\(fti >= ftmidx\\)${ESC}${SEP}1??${ESC}${SEP}${LB}
${ESC}${SEP}1??+2m 1${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}%f> int ftidx;
int syn_blockhl;

${ESC}${SEP}3??${ESC}${SEP}${LB}
${ESC}${SEP}3??+2m 1${ESC}${ESC}${ESC}${SEP}${OK1}p OK ren.c:251:a3${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}m 0${ESC}${SEP}1;0${ESC}${SEP}grp 1${ESC}${SEP}%f> static rset \\*syn_ftrs;
static int last_scdir;
static int blockatt, blockflg, blockdep;.*(		ftmap = erealloc\\(ftmap, \\(fti \\+ 1\\) \\* sizeof\\(\\*ftmap\\)\\);)
	int i = n, set = hls\\[i]\\.set;
	char \\*pats\\[hlslen];${ESC}${SEP}8??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}8??-4m 1${ESC}${ESC}${ESC}${SEP}${OK1}p OK ren.c:251:a8${ESC}${SEP}'0${ESC}${SEP}8??${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}m 0${ESC}${SEP}1;0${ESC}${SEP}grp 1${ESC}${SEP}%f> };
static struct ftmap \\*ftmap;
static int ftmidx;.*(	for \\(; i < hlslen && hls\\[i]\\.ft == name && hls\\[i]\\.set == set; i\\+\\+\\))
		pats\\[i - n] = hls\\[i]\\.pat;
	ftmap\\[fti]\\.setbidx = n;${ESC}${SEP}9??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}9??-7m 1${ESC}${ESC}${ESC}${SEP}${OK1}p OK ren.c:251:a9${ESC}${SEP}'0${SEP}${LB}
${SEP}1;3;8;9??!${DBG1:-ya!112${ESC}${SEP}prp${ESC}${SEP}p FAIL ren.c:251${ESC}${SEP}pr${INTR}${QF1}}${SEP}${LB}
${SEP}?${ESC}${SEP}${LB}
${ESC}${SEP}%f+ 	goto default_hl;
}

void syn_scdir\\(int scdir\\)
\\{
	if \\(!scdir \\|\\| abs\\(scdir\\) > xrows \\|\\| \\(last_scdir > 0\\) != \\(scdir > 0\\)\\) \\{${ESC}${SEP}1??${ESC}${SEP}${LB}
${ESC}${SEP}1??+2m 2${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}%f+ 	goto default_hl;
}

${ESC}${SEP}3??${ESC}${SEP}${LB}
${ESC}${SEP}3??+2m 2${ESC}${ESC}${ESC}${SEP}${OK1}p OK ren.c:292:a3${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}m 0${ESC}${SEP}1;0${ESC}${SEP}grp 1${ESC}${SEP}%f> 	if \\(ftmidx\\)
		return NULL;
	i = 0;.*(int syn_merge\\(int old, int new\\))
\\{
	if \\(new & SYN_OWR\\)${ESC}${SEP}8??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}8??-10m 2${ESC}${ESC}${ESC}${SEP}${OK1}p OK ren.c:292:a8${ESC}${SEP}'0${ESC}${SEP}8??${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}m 0${ESC}${SEP}1;0${ESC}${SEP}grp 1${ESC}${SEP}%f> 			ftmidx\\+\\+;
			return ftmap\\[ftidx]\\.ft;
		}.*(		return new & ~SYN_OWR;)
	int fg = SYN_FGSET\\(new\\) \\? SYN_FG\\(new\\) : SYN_FG\\(old\\);
	int bg = SYN_BGSET\\(new\\) \\? SYN_BG\\(new\\) : SYN_BG\\(old\\);${ESC}${SEP}9??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}9??-13m 2${ESC}${ESC}${ESC}${SEP}${OK1}p OK ren.c:292:a9${ESC}${SEP}'0${SEP}${LB}
${SEP}1;3;8;9??!${DBG1:-ya!112${ESC}${SEP}prp${ESC}${SEP}p FAIL ren.c:292${ESC}${SEP}pr${INTR}${QF1}}${SEP}${LB}
${SEP}?${ESC}${SEP}${LB}
${ESC}${SEP}%f+ void syn_scdir\\(int scdir\\)
\\{
	if \\(!scdir \\|\\| abs\\(scdir\\) > xrows \\|\\| \\(last_scdir > 0\\) != \\(scdir > 0\\)\\) \\{
		last_scdir = scdir;
		syn_blockhl = -1;
		blockdep = 0;${ESC}${SEP}1??${ESC}${SEP}${LB}
${ESC}${SEP}1??+2m 3${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}%f+ void syn_scdir\\(int scdir\\)
\\{
	if \\(!scdir \\|\\| abs\\(scdir\\) > xrows \\|\\| \\(last_scdir > 0\\) != \\(scdir > 0\\)\\) \\{${ESC}${SEP}3??${ESC}${SEP}${LB}
${ESC}${SEP}3??+2m 3${ESC}${ESC}${ESC}${SEP}${OK1}p OK ren.c:295:a3${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}grp 1${ESC}${SEP}%f+ void syn_scdir\\(int scdir\\).*?
\\{.*?
(	if \\(!scdir \\|\\| abs\\(scdir\\) > xrows \\|\\| \\(last_scdir > 0\\) != \\(scdir > 0\\)\\) \\{)${ESC}${SEP}7??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}7??m 3${ESC}${ESC}${ESC}${SEP}${OK1}p OK ren.c:295:a7${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}m 0${ESC}${SEP}1;0${ESC}${SEP}grp 1${ESC}${SEP}%f> 	if \\(ftmidx\\)
		return NULL;
	i = 0;.*(int syn_merge\\(int old, int new\\))
\\{
	if \\(new & SYN_OWR\\)${ESC}${SEP}8??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}8??-7m 3${ESC}${ESC}${ESC}${SEP}${OK1}p OK ren.c:295:a8${ESC}${SEP}'0${ESC}${SEP}8??${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}m 0${ESC}${SEP}1;0${ESC}${SEP}grp 1${ESC}${SEP}%f> 			ftmidx\\+\\+;
			return ftmap\\[ftidx]\\.ft;
		}.*(		return new & ~SYN_OWR;)
	int fg = SYN_FGSET\\(new\\) \\? SYN_FG\\(new\\) : SYN_FG\\(old\\);
	int bg = SYN_BGSET\\(new\\) \\? SYN_BG\\(new\\) : SYN_BG\\(old\\);${ESC}${SEP}9??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}9??-10m 3${ESC}${ESC}${ESC}${SEP}${OK1}p OK ren.c:295:a9${ESC}${SEP}'0${SEP}${LB}
${SEP}1;3;7;8;9??!${DBG1:-ya!112${ESC}${SEP}prp${ESC}${SEP}p FAIL ren.c:295${ESC}${SEP}pr${INTR}${QF1}}${SEP}${LB}
${SEP}?${ESC}${SEP}${LB}
${ESC}${SEP}%f+ 
void syn_highlight\\(int \\*att, char \\*s, int n\\)
\\{
	int fti = ftidx, blockhl = syn_blockhl, blockcont = -1;
	re:;
	rset \\*rs = ftmap\\[fti]\\.rs;
	int subs\\[rs->nsubc], \\*catt, \\*iatt, sl, c;${ESC}${SEP}1??${ESC}${SEP}${LB}
${ESC}${SEP}1??+3m 4${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}%f+ 	int fti = ftidx, blockhl = syn_blockhl, blockcont = -1;
	re:;
	rset \\*rs = ftmap\\[fti]\\.rs;
	int subs\\[rs->nsubc], \\*catt, \\*iatt, sl, c;${ESC}${SEP}2??${ESC}${SEP}${LB}
${ESC}${SEP}2??m 4${ESC}${ESC}${ESC}${SEP}${OK1}p OK ren.c:321:a2${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}%f+ 
void syn_highlight\\(int \\*att, char \\*s, int n\\)
\\{${ESC}${SEP}3??${ESC}${SEP}${LB}
${ESC}${SEP}3??+3m 4${ESC}${ESC}${ESC}${SEP}${OK1}p OK ren.c:321:a3${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP};0${ESC}${SEP}fr${ESC}${SEP}.,\$f+ ^	int fti = ftidx, blockhl = syn_blockhl, blockcont = -1;\$${ESC}${SEP}4??${ESC}${SEP}${LB}
${ESC}${SEP}4??m 4${ESC}${ESC}${ESC}${SEP}${OK1}p OK ren.c:321:a4${ESC}${ESC}${ESC}${SEP}fr 98${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}fr 98${ESC}${SEP}${LB}
${ESC}${SEP}%f+ 	re:;
	rset \\*rs = ftmap\\[fti]\\.rs;
	int subs\\[rs->nsubc], \\*catt, \\*iatt, sl, c;${ESC}${SEP}5??${ESC}${SEP}${LB}
${ESC}${SEP}5??-1m 4${ESC}${ESC}${ESC}${SEP}${OK1}p OK ren.c:321:a5${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}%f+ 
.......n.........t..nt .a..,..... .s,.......
\\{
..n..........idx,........ ...y...lo....,..l....o........
..e.;
.r...........tm.....i..r..
.i.........s...........c.t....i..t. s...c.${ESC}${SEP}6??${ESC}${SEP}${LB}
${ESC}${SEP}6??+3m 4${ESC}${ESC}${ESC}${SEP}${OK1}p OK ren.c:321:a6${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}grp 1${ESC}${SEP}%f+ .*?
void syn_highlight\\(int \\*att, char \\*s, int n\\).*?
\\{.*?
(	int fti = ftidx, blockhl = syn_blockhl, blockcont = -1;)${ESC}${SEP}7??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}7??m 4${ESC}${ESC}${ESC}${SEP}${OK1}p OK ren.c:321:a7${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}m 0${ESC}${SEP}1;0${ESC}${SEP}grp 1${ESC}${SEP}%f> 		att = &blockatt;
	return \\(\\*att & 0xffff\\) == \\(a & 0xffff\\);
}.*(	int cend, sidx = 0, flg = 0, hl, j, i, ii;)
	while \\(\\(sl = rset_find\\(rs, s \\+ sidx, subs, flg\\)\\) >= 0\\) \\{
		cend = 1;${ESC}${SEP}8??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}8??-4m 4${ESC}${ESC}${ESC}${SEP}${OK1}p OK ren.c:321:a8${ESC}${SEP}'0${ESC}${SEP}8??${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}m 0${ESC}${SEP}1;0${ESC}${SEP}grp 1${ESC}${SEP}%f> static int syn_tatt\\(int \\*att, int a, int pb\\)
\\{
	if \\(SYN_SET\\(BATT, a\\) && pb && \\(!\\*att \\|\\| !SYN_SET\\(BP, blockflg\\)\\)\\).*(		hl = sl \\+ ftmap\\[fti]\\.setbidx;)
		sl = rs->grpnsubc\\[sl];
		catt = hls\\[hl]\\.att;${ESC}${SEP}9??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}9??-7m 4${ESC}${ESC}${ESC}${SEP}${OK1}p OK ren.c:321:a9${ESC}${SEP}'0${SEP}${LB}
${SEP}1;2;3;4;5;6;7;8;9??!${DBG1:-ya!112${ESC}${SEP}prp${ESC}${SEP}p FAIL ren.c:321${ESC}${SEP}pr${INTR}${QF1}}${SEP}${LB}
${SEP}?${ESC}${SEP}${LB}
${ESC}${SEP}%f+ 	fti\\+\\+;
	if \\(ftmidx > fti && ftmap\\[fti-1]\\.ft == ftmap\\[fti]\\.ft\\)
		goto re;
	if \\(syn_blockhl < 0 \\|\\| blockhl < 0\\)
		return;
	for \\(j = 0; j < n; j\\+\\+\\)${ESC}${SEP}1??${ESC}${SEP}${LB}
${ESC}${SEP}1??+2m 5${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}%f+ 	fti\\+\\+;
	if \\(ftmidx > fti && ftmap\\[fti-1]\\.ft == ftmap\\[fti]\\.ft\\)
		goto re;${ESC}${SEP}3??${ESC}${SEP}${LB}
${ESC}${SEP}3??+2m 5${ESC}${ESC}${ESC}${SEP}${OK1}p OK ren.c:406:a3${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}grp 1${ESC}${SEP}%f+ 	fti\\+\\+;.*?
	if \\(ftmidx > fti && ftmap\\[fti-1]\\.ft == ftmap\\[fti]\\.ft\\).*?
(		goto re;)${ESC}${SEP}7??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}7??m 5${ESC}${ESC}${ESC}${SEP}${OK1}p OK ren.c:406:a7${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}m 0${ESC}${SEP}1;0${ESC}${SEP}grp 1${ESC}${SEP}%f> 		sidx \\+= cend;
		flg = REG_NOTBOL;
	}.*(		if \\(!att\\[j] \\|\\| !SYN_SET\\(BP, blockflg\\)\\))
			att\\[j] = blockatt;
}${ESC}${SEP}8??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}8??-4m 5${ESC}${ESC}${ESC}${SEP}${OK1}p OK ren.c:406:a8${ESC}${SEP}'0${ESC}${SEP}8??${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}m 0${ESC}${SEP}1;0${ESC}${SEP}grp 1${ESC}${SEP}%f> 			}
			i \\+= inc;
		}.*(char \\*syn_filetype\\(char \\*path\\))
\\{
	int hl = rset_find\\(syn_ftrs, path, NULL, 0\\);${ESC}${SEP}9??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}9??-8m 5${ESC}${ESC}${ESC}${SEP}${OK1}p OK ren.c:406:a9${ESC}${SEP}'0${SEP}${LB}
${SEP}1;3;7;8;9??!${DBG1:-ya!112${ESC}${SEP}prp${ESC}${SEP}p FAIL ren.c:406${ESC}${SEP}pr${INTR}${QF1}}${SEP}${LB}
${SEP}${LB}
${SEP}'1i /* block-highlight pair cache, keyed by lbuf line pointer */
struct hl_cache_entry {
	char *ln;
	int gen;
	int blockhl;
	int blockatt;
	int ftidx;
};
#define HL_CACHE_BITS	10
#define HL_CACHE_SIZE	(1 << HL_CACHE_BITS)
#define HL_CACHE_MASK	(HL_CACHE_SIZE - 1)
#define HL_CACHE_PROBE	8
static struct hl_cache_entry hl_cache[HL_CACHE_SIZE];
static int hl_cache_gen = 1;
static struct lbuf *syn_lb;
static int syn_row;

static int hl_cache_hash(char *ln)
{
	return (int)(((size_t)ln >> 4) & HL_CACHE_MASK);
}

static struct hl_cache_entry *hl_cache_find(char *ln)
{
	if (!ln)
		return NULL;
	int h = hl_cache_hash(ln);
	for (int i = 0; i < HL_CACHE_PROBE; i++) {
		struct hl_cache_entry *e = &hl_cache[(h + i) & HL_CACHE_MASK];
		if (e->ln == ln && e->gen == hl_cache_gen)
			return e;
		if (!e->ln)
			return NULL;
	}
	return NULL;
}

static void hl_cache_set(char *ln, int blockhl, int blockatt_v, int fti)
{
	if (!ln)
		return;
	int h = hl_cache_hash(ln);
	struct hl_cache_entry *slot = &hl_cache[h];
	for (int i = 0; i < HL_CACHE_PROBE; i++) {
		struct hl_cache_entry *e = &hl_cache[(h + i) & HL_CACHE_MASK];
		if (!e->ln || e->ln == ln || e->gen != hl_cache_gen) {
			slot = e;
			break;
		}
	}
	slot->ln = ln;
	slot->gen = hl_cache_gen;
	slot->blockhl = blockhl;
	slot->blockatt = blockatt_v;
	slot->ftidx = fti;
}

void syn_blockhl_invalidate(void)
{
	hl_cache_gen++;
}

void syn_setrow(struct lbuf *lb, int row)
{
	syn_lb = lb;
	syn_row = row;
}

static int *hl_scan_att;
static int hl_scan_att_sz;
static int hl_scan_active;

/* extend the cache chain backward to row 0 or nearest cached row */
static void hl_scan_until(int target_row)
{
	if (hl_scan_active || target_row <= 0)
		return;
	int from = 0;
	for (int r = target_row - 1; r > 0; r--) {
		char *ln = lbuf_get(syn_lb, r);
		struct hl_cache_entry *e = hl_cache_find(ln);
		if (e && e->ftidx == ftidx) {
			from = r + 1;
			break;
		}
	}
	int saved_row = syn_row;
	int saved_blockhl = syn_blockhl;
	int saved_blockatt = blockatt;
	int saved_last_scdir = last_scdir;
	last_scdir = 0;
	hl_scan_active = 1;
	for (int r = from; r <= target_row; r++) {
		char *ln = lbuf_get(syn_lb, r);
		if (!ln)
			break;
		int len = lbuf_s(ln)->len;
		if (len + 1 > hl_scan_att_sz) {
			hl_scan_att_sz = (len + 1) * 2;
			hl_scan_att = erealloc(hl_scan_att, hl_scan_att_sz * sizeof(int));
		}
		memset(hl_scan_att, 0, (len + 1) * sizeof(int));
		syn_row = r;
		syn_highlight(hl_scan_att, ln, len);
	}
	hl_scan_active = 0;
	syn_row = saved_row;
	syn_blockhl = saved_blockhl;
	blockatt = saved_blockatt;
	last_scdir = saved_last_scdir;
}

${SEP}??!${DBG2:-ya!112${ESC}${SEP}prp${ESC}${SEP}p FAIL ren.c:251:m1${ESC}${SEP}pr${INTR}${QF2}}${SEP}${LB}
${SEP}'2i int sign_changed;

${SEP}??!${DBG2:-ya!112${ESC}${SEP}prp${ESC}${SEP}p FAIL ren.c:292:m2${ESC}${SEP}pr${INTR}${QF2}}${SEP}${LB}
${SEP}'3i 		sign_changed = (last_scdir > 0) != (scdir > 0);
		if (sign_changed)
			hl_cache_gen++;
${SEP}??!${DBG2:-ya!112${ESC}${SEP}prp${ESC}${SEP}p FAIL ren.c:295:m3${ESC}${SEP}pr${INTR}${QF2}}${SEP}${LB}
${SEP}'4c 	int fti = ftidx, blockhl, blockcont = -1, trusted = 0;
	char *cur_ln = NULL;
	blockhl = syn_blockhl;
	if (syn_lb && syn_row >= 0 && syn_row < lbuf_len(syn_lb)) {
		cur_ln = lbuf_get(syn_lb, syn_row);
		if (syn_row == 0) {
			syn_blockhl = -1;
			blockatt = 0;
			trusted = 1;
		} else {
			char *prev_ln = lbuf_get(syn_lb, syn_row - 1);
			struct hl_cache_entry *e = hl_cache_find(prev_ln);
			if ((!e || e->ftidx != ftidx) && !hl_scan_active) {
				hl_scan_until(syn_row);
				e = hl_cache_find(prev_ln);
			}
			if (e && e->ftidx == ftidx) {
				struct hl_cache_entry *cur_e = hl_cache_find(cur_ln);
				if (cur_e && cur_e->ftidx == ftidx && cur_e->blockhl != e->blockhl) {
					/* block boundary: direction changed the state */
				} else {
					syn_blockhl = e->blockhl;
					blockatt = e->blockatt;
					if (blockhl < 0 && e->blockhl >= 0)
						blockhl = e->blockhl;
				}
				trusted = 1;
			}
		}
	}
${SEP}??!${DBG2:-ya!112${ESC}${SEP}prp${ESC}${SEP}p FAIL ren.c:321:m4${ESC}${SEP}pr${INTR}${QF2}}${SEP}${LB}
${SEP}'5i 	if (trusted && cur_ln)
		hl_cache_set(cur_ln, syn_blockhl, blockatt, ftidx);
${SEP}??!${DBG2:-ya!112${ESC}${SEP}prp${ESC}${SEP}p FAIL ren.c:406:m5${ESC}${SEP}pr${INTR}${QF2}}${SEP}b2${SEP}%ya 98${SEP}?${ESC}${SEP}${LB}
${ESC}${SEP}%f> static void vi_drawrow\\(int row\\)
\\{
	int l1, i, i1, lnnum = vi_lnnum;
	char \\*c, \\*s;
	static char ch\\[5] = \"~\";
	if \\(xmpt == 1 && !vi_status && row == xtop \\+ xrows - 1\\)${ESC}${SEP}1??${ESC}${SEP}${LB}
${ESC}${SEP}1??+2m 1${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}%f> static void vi_drawrow\\(int row\\)
\\{
	int l1, i, i1, lnnum = vi_lnnum;${ESC}${SEP}3??${ESC}${SEP}${LB}
${ESC}${SEP}3??+2m 1${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:130:a3${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}grp 1${ESC}${SEP}%f> static void vi_drawrow\\(int row\\).*?
\\{.*?
(	int l1, i, i1, lnnum = vi_lnnum;)${ESC}${SEP}7??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}7??m 1${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:130:a7${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}m 0${ESC}${SEP}1;0${ESC}${SEP}grp 1${ESC}${SEP}%f> 	tmp\\[l1] = \\*snum; \\\\
	ret = func; \\\\
} } \\\\.*(	if \\(\\*vi_word && xled\\) \\{)
		int noff, nrow, ret;
		c = lbuf_get\\(xb, xrow\\);${ESC}${SEP}8??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}8??-5m 1${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:130:a8${ESC}${SEP}'0${ESC}${SEP}8??${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}m 0${ESC}${SEP}1;0${ESC}${SEP}grp 1${ESC}${SEP}%f> 		break; \\\\
	i = i > 99 \\? i % 100 : i; \\\\
	itoa\\(i%10 \\? i%10 : i, snum\\); \\\\.*(		if \\(row != xrow\\+1 \\|\\| !c \\|\\| \\*c == '\\\\n'\\) \\{)
			vi_rshift = \\(row > xrow\\+1 && c && \\*c != '\\\\n'\\);
			s = lbuf_get\\(xb, row - vi_rshift\\);${ESC}${SEP}9??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}9??-8m 1${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:130:a9${ESC}${SEP}'0${SEP}${LB}
${SEP}1;3;7;8;9??!${DBG1:-ya!112${ESC}${SEP}prp${ESC}${SEP}p FAIL vi.c:130${ESC}${SEP}pr${INTR}${QF1}}${SEP}${LB}
${SEP}?${ESC}${SEP}${LB}
${ESC}${SEP}%f+ 		if \\(row != xrow\\+1 \\|\\| !c \\|\\| \\*c == '\\\\n'\\) \\{
			vi_rshift = \\(row > xrow\\+1 && c && \\*c != '\\\\n'\\);
			s = lbuf_get\\(xb, row - vi_rshift\\);
			goto skip;
		}
		char tmp\\[xcols\\+3], snum\\[32];${ESC}${SEP}1??${ESC}${SEP}${LB}
${ESC}${SEP}1??+2m 2${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}%f+ 		if \\(row != xrow\\+1 \\|\\| !c \\|\\| \\*c == '\\\\n'\\) \\{
			vi_rshift = \\(row > xrow\\+1 && c && \\*c != '\\\\n'\\);
			s = lbuf_get\\(xb, row - vi_rshift\\);${ESC}${SEP}3??${ESC}${SEP}${LB}
${ESC}${SEP}3??+2m 2${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:140:a3${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}grp 1${ESC}${SEP}%f+ 		if \\(row != xrow\\+1 \\|\\| !c \\|\\| \\*c == '\\\\n'\\) \\{.*?
			vi_rshift = \\(row > xrow\\+1 && c && \\*c != '\\\\n'\\);.*?
(			s = lbuf_get\\(xb, row - vi_rshift\\);)${ESC}${SEP}7??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}7??m 2${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:140:a7${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}m 0${ESC}${SEP}1;0${ESC}${SEP}grp 1${ESC}${SEP}%f> 	if \\(\\*vi_word && xled\\) \\{
		int noff, nrow, ret;
		c = lbuf_get\\(xb, xrow\\);.*(		memset\\(tmp, ' ', xcols\\+1\\);)
		tmp\\[xcols\\+1] = '\\\\n';
		tmp\\[xcols\\+2] = '\\\\0';${ESC}${SEP}8??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}8??-4m 2${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:140:a8${ESC}${SEP}'0${ESC}${SEP}8??${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}m 0${ESC}${SEP}1;0${ESC}${SEP}grp 1${ESC}${SEP}%f> 	static char ch\\[5] = \"~\";
	if \\(xmpt == 1 && !vi_status && row == xtop \\+ xrows - 1\\)
		return;.*(		i1 = isupper\\(\\(unsigned char\\)\\*vi_word\\);)
		if \\(\\*vi_word == 'e' \\|\\| \\*vi_word == 'E'\\)
			vi_drawnum\\(lbuf_wordend\\(xb, i1, 2, &nrow, &noff\\)\\)${ESC}${SEP}9??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}9??-7m 2${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:140:a9${ESC}${SEP}'0${SEP}${LB}
${SEP}1;3;7;8;9??!${DBG1:-ya!112${ESC}${SEP}prp${ESC}${SEP}p FAIL vi.c:140${ESC}${SEP}pr${INTR}${QF1}}${SEP}${LB}
${SEP}?${ESC}${SEP}${LB}
${ESC}${SEP}%f+ 		return;
	}
	s = lbuf_get\\(xb, row\\);
	skip:
	rstate \\+= row != xrow;${ESC}${SEP}1??${ESC}${SEP}${LB}
${ESC}${SEP}1??+2m 3${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}%f+ 		return;
	}
	s = lbuf_get\\(xb, row\\);${ESC}${SEP}3??${ESC}${SEP}${LB}
${ESC}${SEP}3??+2m 3${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:172:a3${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}grp 1${ESC}${SEP}%f+ 		return;.*?
	}.*?
(	s = lbuf_get\\(xb, row\\);)${ESC}${SEP}7??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}7??m 3${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:172:a7${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}m 0${ESC}${SEP}1;0${ESC}${SEP}grp 1${ESC}${SEP}%f> 		restore\\(syn_blockhl\\)
		restore\\(xtd\\)
		restore\\(ftidx\\).*(			c = itoa\\(row\\+1-vi_rshift, tmp\\);)
			\\*c\\+\\+ = ' ';
			i = itoalen\\(xtop\\+xrows\\);${ESC}${SEP}8??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}8??-9m 3${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:172:a8${ESC}${SEP}'0${ESC}${SEP}8??${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}m 0${ESC}${SEP}1;0${ESC}${SEP}grp 1${ESC}${SEP}%f> 		syn_setft\\(n_ft\\);
		RS\\(2, led_crender\\(tmp, row - xtop, 0, 0, xcols\\)\\)
		restore\\(xorder\\).*(		p = c;)
		if \\(lnnum == 1 \\|\\| lnnum & 4 \\|\\| lnnum & 8\\) \\{
			c = itoa\\(abs\\(xrow-row\\+vi_rshift\\), c\\);${ESC}${SEP}9??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}9??-13m 3${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:172:a9${ESC}${SEP}'0${SEP}${LB}
${SEP}1;3;7;8;9??!${DBG1:-ya!112${ESC}${SEP}prp${ESC}${SEP}p FAIL vi.c:172${ESC}${SEP}pr${INTR}${QF1}}${SEP}${LB}
${SEP}?${ESC}${SEP}${LB}
${ESC}${SEP}%f+ 	skip:
	rstate \\+= row != xrow;
	if \\(!s\\)
		s = row \\? ch : ch\\+1;${ESC}${SEP}1??${ESC}${SEP}${LB}
${ESC}${SEP}1??+2m 4${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}%f+ 	if \\(!s\\)
		s = row \\? ch : ch\\+1;${ESC}${SEP}2??${ESC}${SEP}${LB}
${ESC}${SEP}2??m 4${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:175:a2${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}%f+ 	skip:
	rstate \\+= row != xrow;${ESC}${SEP}3??${ESC}${SEP}${LB}
${ESC}${SEP}3??+2m 4${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:175:a3${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP};0${ESC}${SEP}fr${ESC}${SEP}.,\$f+ ^	if \\(!s\\)\$${ESC}${SEP}4??${ESC}${SEP}${LB}
${ESC}${SEP}4??m 4${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:175:a4${ESC}${ESC}${ESC}${SEP}fr 98${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}fr 98${ESC}${SEP}${LB}
${ESC}${SEP};0${ESC}${SEP}fr${ESC}${SEP}.,\$f+ ^		s = row \\? ch : ch\\+1;\$${ESC}${SEP}5??${ESC}${SEP}${LB}
${ESC}${SEP}5??-1m 4${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:175:a5${ESC}${ESC}${ESC}${SEP}fr 98${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}fr 98${ESC}${SEP}${LB}
${ESC}${SEP}%f+ .s...:
	.....e... ... ........
......s\\)
.	. . ... .......c....${ESC}${SEP}6??${ESC}${SEP}${LB}
${ESC}${SEP}6??+2m 4${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:175:a6${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}grp 1${ESC}${SEP}%f+ 	skip:.*?
	rstate \\+= row != xrow;.*?
(	if \\(!s\\))${ESC}${SEP}7??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}7??m 4${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:175:a7${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}m 0${ESC}${SEP}1;0${ESC}${SEP}grp 1${ESC}${SEP}%f> 		restore\\(syn_blockhl\\)
		restore\\(xtd\\)
		restore\\(ftidx\\).*(			c = itoa\\(row\\+1-vi_rshift, tmp\\);)
			\\*c\\+\\+ = ' ';
			i = itoalen\\(xtop\\+xrows\\);${ESC}${SEP}8??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}8??-6m 4${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:175:a8${ESC}${SEP}'0${ESC}${SEP}8??${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}m 0${ESC}${SEP}1;0${ESC}${SEP}grp 1${ESC}${SEP}%f> 		syn_setft\\(n_ft\\);
		RS\\(2, led_crender\\(tmp, row - xtop, 0, 0, xcols\\)\\)
		restore\\(xorder\\).*(		p = c;)
		if \\(lnnum == 1 \\|\\| lnnum & 4 \\|\\| lnnum & 8\\) \\{
			c = itoa\\(abs\\(xrow-row\\+vi_rshift\\), c\\);${ESC}${SEP}9??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}9??-10m 4${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:175:a9${ESC}${SEP}'0${SEP}${LB}
${SEP}1;2;3;4;5;6;7;8;9??!${DBG1:-ya!112${ESC}${SEP}prp${ESC}${SEP}p FAIL vi.c:175${ESC}${SEP}pr${INTR}${QF1}}${SEP}${LB}
${SEP}?${ESC}${SEP}${LB}
${ESC}${SEP}%f+ 		s = row \\? ch : ch\\+1;
	else if \\(lnnum && xled\\) \\{
		char tmp\\[32], tmp1\\[32], \\*p;
		c = tmp, i = 0, i1 = 0;
		if \\(lnnum == 1 \\|\\| lnnum & 2\\) \\{${ESC}${SEP}1??${ESC}${SEP}${LB}
${ESC}${SEP}1??+1m 5${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}%f+ 	else if \\(lnnum && xled\\) \\{
		char tmp\\[32], tmp1\\[32], \\*p;
		c = tmp, i = 0, i1 = 0;
		if \\(lnnum == 1 \\|\\| lnnum & 2\\) \\{${ESC}${SEP}2??${ESC}${SEP}${LB}
${ESC}${SEP}2??m 5${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:177:a2${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP};0${ESC}${SEP}fr${ESC}${SEP}.,\$f+ ^		s = row \\? ch : ch\\+1;\$${ESC}${SEP}3??${ESC}${SEP}${LB}
${ESC}${SEP}3??+1m 5${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:177:a3${ESC}${ESC}${ESC}${SEP}fr 98${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}fr 98${ESC}${SEP}${LB}
${ESC}${SEP};0${ESC}${SEP}fr${ESC}${SEP}.,\$f+ ^	else if \\(lnnum && xled\\) \\{\$${ESC}${SEP}4??${ESC}${SEP}${LB}
${ESC}${SEP}4??m 5${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:177:a4${ESC}${ESC}${ESC}${SEP}fr 98${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}fr 98${ESC}${SEP}${LB}
${ESC}${SEP}%f+ 		char tmp\\[32], tmp1\\[32], \\*p;
		c = tmp, i = 0, i1 = 0;
		if \\(lnnum == 1 \\|\\| lnnum & 2\\) \\{${ESC}${SEP}5??${ESC}${SEP}${LB}
${ESC}${SEP}5??-1m 5${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:177:a5${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}%f+ ......r........: .h.1.
..... if \\(.n....&&...e....
....ar.....3.., ...1....,...;
........p............=...
	... ....u.... .........m....\\)..${ESC}${SEP}6??${ESC}${SEP}${LB}
${ESC}${SEP}6??+1m 5${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:177:a6${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}grp 1${ESC}${SEP}%f+ 		s = row \\? ch : ch\\+1;.*?
(	else if \\(lnnum && xled\\) \\{)${ESC}${SEP}7??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}7??m 5${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:177:a7${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}m 0${ESC}${SEP}1;0${ESC}${SEP}grp 1${ESC}${SEP}%f> 		restore\\(syn_blockhl\\)
		restore\\(xtd\\)
		restore\\(ftidx\\).*(			c = itoa\\(row\\+1-vi_rshift, tmp\\);)
			\\*c\\+\\+ = ' ';
			i = itoalen\\(xtop\\+xrows\\);${ESC}${SEP}8??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}8??-4m 5${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:177:a8${ESC}${SEP}'0${ESC}${SEP}8??${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}m 0${ESC}${SEP}1;0${ESC}${SEP}grp 1${ESC}${SEP}%f> 		syn_setft\\(n_ft\\);
		RS\\(2, led_crender\\(tmp, row - xtop, 0, 0, xcols\\)\\)
		restore\\(xorder\\).*(		p = c;)
		if \\(lnnum == 1 \\|\\| lnnum & 4 \\|\\| lnnum & 8\\) \\{
			c = itoa\\(abs\\(xrow-row\\+vi_rshift\\), c\\);${ESC}${SEP}9??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}9??-8m 5${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:177:a9${ESC}${SEP}'0${SEP}${LB}
${SEP}1;2;3;4;5;6;7;8;9??!${DBG1:-ya!112${ESC}${SEP}prp${ESC}${SEP}p FAIL vi.c:177${ESC}${SEP}pr${INTR}${QF1}}${SEP}${LB}
${SEP}?${ESC}${SEP}${LB}
${ESC}${SEP}%f+ 		vi_lncol = dir_context\\(s\\) < 0 \\? 0 : l1;
		memset\\(c, ' ', l1 - \\(c - tmp\\)\\);
		c\\[l1 - \\(c - tmp\\)] = '\\\\0';
		led_crender\\(s, row - xtop, l1, xleft, xleft \\+ xcols - l1\\)${ESC}${SEP}1??${ESC}${SEP}${LB}
${ESC}${SEP}1??+2m 6${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}%f+ 		vi_lncol = dir_context\\(s\\) < 0 \\? 0 : l1;
		memset\\(c, ' ', l1 - \\(c - tmp\\)\\);
		c\\[l1 - \\(c - tmp\\)] = '\\\\0';${ESC}${SEP}3??${ESC}${SEP}${LB}
${ESC}${SEP}3??+2m 6${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:195:a3${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}grp 1${ESC}${SEP}%f+ 		vi_lncol = dir_context\\(s\\) < 0 \\? 0 : l1;.*?
		memset\\(c, ' ', l1 - \\(c - tmp\\)\\);.*?
(		c\\[l1 - \\(c - tmp\\)] = '\\\\0';)${ESC}${SEP}7??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}7??m 6${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:195:a7${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}m 0${ESC}${SEP}1;0${ESC}${SEP}grp 1${ESC}${SEP}%f> 		}
		\\*c = '\\\\0';
		l1 = \\(c - tmp\\) \\+ \\(i\\+i1 - \\(strlen\\(tmp\\) - !!i - !!i1\\)\\);.*(		if \\(\\(lnnum == 1 \\|\\| lnnum & 4\\) && !xleft && vi_lncol\\) \\{)
			for \\(i1 = 0; i1 < rstate->cmax &&
					memchr\\(\" \\\\t\", \\*rstate->chrs\\[ren_off\\(s, i1\\)], 2\\);\\)${ESC}${SEP}8??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}8??-5m 6${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:195:a8${ESC}${SEP}'0${ESC}${SEP}8??${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}m 0${ESC}${SEP}1;0${ESC}${SEP}grp 1${ESC}${SEP}%f> 			c = itoa\\(abs\\(xrow-row\\+vi_rshift\\), c\\);
			\\*c\\+\\+ = ' ';
			i1 = itoalen\\(xrows\\);.*(				i1 = ren_next\\(s, i1, 1\\);)
			i1 -= \\(itoa\\(abs\\(xrow-row\\+vi_rshift\\), tmp1\\) - tmp1\\)\\+1;
			if \\(i1 >= 0\\) \\{${ESC}${SEP}9??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}9??-8m 6${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:195:a9${ESC}${SEP}'0${SEP}${LB}
${SEP}1;3;7;8;9??!${DBG1:-ya!112${ESC}${SEP}prp${ESC}${SEP}p FAIL vi.c:195${ESC}${SEP}pr${INTR}${QF1}}${SEP}${LB}
${SEP}?${ESC}${SEP}${LB}
${ESC}${SEP}%f+ 		led_crender\\(s, row - xtop, l1, xleft, xleft \\+ xcols - l1\\)
		preserve\\(int, syn_blockhl, syn_blockhl = -1;\\)
		preserve\\(int, ftidx,\\)
		syn_setft\\(nn_ft\\);${ESC}${SEP}1??${ESC}${SEP}${LB}
${ESC}${SEP}1??m 7${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP};0${ESC}${SEP}fr${ESC}${SEP}.,\$f+ ^		led_crender\\(s, row - xtop, l1, xleft, xleft \\+ xcols - l1\\)\$${ESC}${SEP}3??${ESC}${SEP}${LB}
${ESC}${SEP}3??m 7${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:196:a3${ESC}${ESC}${ESC}${SEP}fr 98${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}fr 98${ESC}${SEP}${LB}
${ESC}${SEP}m 0${ESC}${SEP}1;0${ESC}${SEP}grp 1${ESC}${SEP}%f> 		}
		\\*c = '\\\\0';
		l1 = \\(c - tmp\\) \\+ \\(i\\+i1 - \\(strlen\\(tmp\\) - !!i - !!i1\\)\\);.*(		if \\(\\(lnnum == 1 \\|\\| lnnum & 4\\) && !xleft && vi_lncol\\) \\{)
			for \\(i1 = 0; i1 < rstate->cmax &&
					memchr\\(\" \\\\t\", \\*rstate->chrs\\[ren_off\\(s, i1\\)], 2\\);\\)${ESC}${SEP}8??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}8??-4m 7${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:196:a8${ESC}${SEP}'0${ESC}${SEP}8??${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}m 0${ESC}${SEP}1;0${ESC}${SEP}grp 1${ESC}${SEP}%f> 			c = itoa\\(abs\\(xrow-row\\+vi_rshift\\), c\\);
			\\*c\\+\\+ = ' ';
			i1 = itoalen\\(xrows\\);.*(				i1 = ren_next\\(s, i1, 1\\);)
			i1 -= \\(itoa\\(abs\\(xrow-row\\+vi_rshift\\), tmp1\\) - tmp1\\)\\+1;
			if \\(i1 >= 0\\) \\{${ESC}${SEP}9??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}9??-7m 7${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:196:a9${ESC}${SEP}'0${SEP}${LB}
${SEP}1;3;8;9??!${DBG1:-ya!112${ESC}${SEP}prp${ESC}${SEP}p FAIL vi.c:196${ESC}${SEP}pr${INTR}${QF1}}${SEP}${LB}
${SEP}?${ESC}${SEP}${LB}
${ESC}${SEP}%f+ 		restore\\(ftidx\\)
		return;
	}
	led_crender\\(s, row - xtop, 0, xleft, xleft \\+ xcols\\)${ESC}${SEP}1??${ESC}${SEP}${LB}
${ESC}${SEP}1??+2m 8${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}%f+ 		restore\\(ftidx\\)
		return;
	}${ESC}${SEP}3??${ESC}${SEP}${LB}
${ESC}${SEP}3??+2m 8${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:214:a3${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}m 0${ESC}${SEP}1;0${ESC}${SEP}grp 1${ESC}${SEP}%f> 		}
		RS\\(2, led_prender\\(tmp, row - xtop, 0, 0, l1\\)\\)
		restore\\(syn_blockhl\\).*(/\\* redraw the screen \\*/)
static void vi_drawagain\\(int i\\)
\\{${ESC}${SEP}8??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}8??-5m 8${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:214:a8${ESC}${SEP}'0${ESC}${SEP}8??${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}m 0${ESC}${SEP}1;0${ESC}${SEP}grp 1${ESC}${SEP}%f> 				memset\\(p, ' ', strlen\\(p\\)\\);
				RS\\(2, led_prender\\(tmp1, row - xtop, l1\\+i1, 0, l1\\)\\)
			}.*(	syn_scdir\\(0\\);)
	for \\(; i < xtop \\+ xrows; i\\+\\+\\)
		vi_drawrow\\(i\\);${ESC}${SEP}9??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}9??-8m 8${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:214:a9${ESC}${SEP}'0${SEP}${LB}
${SEP}1;3;8;9??!${DBG1:-ya!112${ESC}${SEP}prp${ESC}${SEP}p FAIL vi.c:214${ESC}${SEP}pr${INTR}${QF1}}${SEP}${LB}
${SEP}?${ESC}${SEP}${LB}
${ESC}${SEP}%f+ 	led_crender\\(s, row - xtop, 0, xleft, xleft \\+ xcols\\)
	rstate = rstates;
}

${ESC}${SEP}1??${ESC}${SEP}${LB}
${ESC}${SEP}1??m 9${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP};0${ESC}${SEP}fr${ESC}${SEP}.,\$f+ ^	led_crender\\(s, row - xtop, 0, xleft, xleft \\+ xcols\\)\$${ESC}${SEP}3??${ESC}${SEP}${LB}
${ESC}${SEP}3??m 9${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:215:a3${ESC}${ESC}${ESC}${SEP}fr 98${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}fr 98${ESC}${SEP}${LB}
${ESC}${SEP}m 0${ESC}${SEP}1;0${ESC}${SEP}grp 1${ESC}${SEP}%f> 		}
		RS\\(2, led_prender\\(tmp, row - xtop, 0, 0, l1\\)\\)
		restore\\(syn_blockhl\\).*(/\\* redraw the screen \\*/)
static void vi_drawagain\\(int i\\)
\\{${ESC}${SEP}8??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}8??-4m 9${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:215:a8${ESC}${SEP}'0${ESC}${SEP}8??${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}m 0${ESC}${SEP}1;0${ESC}${SEP}grp 1${ESC}${SEP}%f> 				memset\\(p, ' ', strlen\\(p\\)\\);
				RS\\(2, led_prender\\(tmp1, row - xtop, l1\\+i1, 0, l1\\)\\)
			}.*(	syn_scdir\\(0\\);)
	for \\(; i < xtop \\+ xrows; i\\+\\+\\)
		vi_drawrow\\(i\\);${ESC}${SEP}9??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}9??-7m 9${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:215:a9${ESC}${SEP}'0${SEP}${LB}
${SEP}1;3;8;9??!${DBG1:-ya!112${ESC}${SEP}prp${ESC}${SEP}p FAIL vi.c:215${ESC}${SEP}pr${INTR}${QF1}}${SEP}${LB}
${SEP}${LB}
${SEP}'1i 	int s_row = -1;
${SEP}??!${DBG2:-ya!112${ESC}${SEP}prp${ESC}${SEP}p FAIL vi.c:130:m1${ESC}${SEP}pr${INTR}${QF2}}${SEP}${LB}
${SEP}'2i 			s_row = row - vi_rshift;
${SEP}??!${DBG2:-ya!112${ESC}${SEP}prp${ESC}${SEP}p FAIL vi.c:140:m2${ESC}${SEP}pr${INTR}${QF2}}${SEP}${LB}
${SEP}'3i 	s_row = row;
${SEP}??!${DBG2:-ya!112${ESC}${SEP}prp${ESC}${SEP}p FAIL vi.c:172:m3${ESC}${SEP}pr${INTR}${QF2}}${SEP}${LB}
${SEP}'4s/\\)/) {/${SEP}??!${DBG2:-ya!112${ESC}${SEP}prp${ESC}${SEP}p FAIL vi.c:175:m4${ESC}${SEP}pr${INTR}${QF2}}${SEP}${LB}
${SEP}'5c 		s_row = -1;
	} else if (lnnum && xled) {
${SEP}??!${DBG2:-ya!112${ESC}${SEP}prp${ESC}${SEP}p FAIL vi.c:177:m5${ESC}${SEP}pr${INTR}${QF2}}${SEP}${LB}
${SEP}'6i 		syn_setrow(xb, s_row);
${SEP}??!${DBG2:-ya!112${ESC}${SEP}prp${ESC}${SEP}p FAIL vi.c:195:m6${ESC}${SEP}pr${INTR}${QF2}}${SEP}${LB}
${SEP}'7i 		syn_setrow(NULL, 0);
${SEP}??!${DBG2:-ya!112${ESC}${SEP}prp${ESC}${SEP}p FAIL vi.c:196:m7${ESC}${SEP}pr${INTR}${QF2}}${SEP}${LB}
${SEP}'8i 	if (s_row >= 0)
		syn_setrow(xb, s_row);
${SEP}??!${DBG2:-ya!112${ESC}${SEP}prp${ESC}${SEP}p FAIL vi.c:214:m8${ESC}${SEP}pr${INTR}${QF2}}${SEP}${LB}
${SEP}'9i 	syn_setrow(NULL, 0);
${SEP}??!${DBG2:-ya!112${ESC}${SEP}prp${ESC}${SEP}p FAIL vi.c:215:m9${ESC}${SEP}pr${INTR}${QF2}}${SEP}b3${SEP}%ya 98${SEP}?${ESC}${SEP}${LB}
${ESC}${SEP}%f> int syn_findhl\\(int id\\);
int syn_addhl\\(char \\*reg, int id\\);
void syn_init\\(void\\);

/\\* uc\\.c: utf-8 helper functions \\*/
extern unsigned char utf8_length\\[256];${ESC}${SEP}1??${ESC}${SEP}${LB}
${ESC}${SEP}1??+2m 1${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}%f> int syn_findhl\\(int id\\);
int syn_addhl\\(char \\*reg, int id\\);
void syn_init\\(void\\);${ESC}${SEP}3??${ESC}${SEP}${LB}
${ESC}${SEP}3??+2m 1${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.h:265:a3${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}grp 1${ESC}${SEP}%f> int syn_findhl\\(int id\\);.*?
int syn_addhl\\(char \\*reg, int id\\);.*?
(void syn_init\\(void\\);)${ESC}${SEP}7??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}7??m 1${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.h:265:a7${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}m 0${ESC}${SEP}1;0${ESC}${SEP}grp 1${ESC}${SEP}%f> char \\*syn_filetype\\(char \\*path\\);
int syn_merge\\(int old, int new\\);
void syn_reloadft\\(int hl, int flg\\);.*(extern int zwlen, def_zwlen;)
extern int bclen, def_bclen;
/\\* the length of a given utf-8 character \\*/${ESC}${SEP}8??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}8??-4m 1${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.h:265:a8${ESC}${SEP}'0${ESC}${SEP}8??${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}m 0${ESC}${SEP}1;0${ESC}${SEP}grp 1${ESC}${SEP}%f> char \\*syn_setft\\(char \\*ft\\);
void syn_scdir\\(int scdir\\);
void syn_highlight\\(int \\*att, char \\*s, int n\\);.*(#define uc_len\\(s\\) utf8_length\\[\\(unsigned char\\)s\\[0]])
/\\* the unicode codepoint of a given utf-8 character \\*/
#define uc_code\\(dst, s, l\\) \\\\${ESC}${SEP}9??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}9??-7m 1${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.h:265:a9${ESC}${SEP}'0${SEP}${LB}
${SEP}1;3;7;8;9??!${DBG1:-ya!112${ESC}${SEP}prp${ESC}${SEP}p FAIL vi.h:265${ESC}${SEP}pr${INTR}${QF1}}${SEP}${LB}
${SEP}${LB}
${SEP}'1i void syn_setrow(struct lbuf *lb, int row);
void syn_blockhl_invalidate(void);
${SEP}??!${DBG2:-ya!112${ESC}${SEP}prp${ESC}${SEP}p FAIL vi.h:265:m1${ESC}${SEP}pr${INTR}${QF2}}${SEP}vis 2${SEP}b0${SEP}w${SEP}b1${SEP}w${SEP}b2${SEP}w${SEP}b3${SEP}w${SEP}2q" > "$P2VIF"
EXINIT='%ya 97:? %@97' $VI -e 'lbuf.c' 'ren.c' 'vi.c' 'vi.h' "$P2VIF"

exit 0
=== PATCH2VI DELTA ===
=== PATCH2VI PATCH ===
diff --git a/lbuf.c b/lbuf.c
index 75dd0ce8..0a2a1edc 100644
--- a/lbuf.c
+++ b/lbuf.c
@@ -99,6 +99,7 @@ static int linelength(char *s)
 static int lbuf_replace(struct lbuf *lb, sbuf *sb, char *s, struct lopt *lo, int n_del, int n_ins)
 {
 	int i, pos = lo->pos;
+	syn_blockhl_invalidate();
 	if (s) {
 		for (; *s; n_ins++) {
 			int l = linelength(s);
diff --git a/ren.c b/ren.c
index 4fd79fba..ac42d54d 100644
--- a/ren.c
+++ b/ren.c
@@ -249,6 +249,118 @@ static int blockatt, blockflg, blockdep;
 int ftidx;
 int syn_blockhl;
 
+/* block-highlight pair cache, keyed by lbuf line pointer */
+struct hl_cache_entry {
+	char *ln;
+	int gen;
+	int blockhl;
+	int blockatt;
+	int ftidx;
+};
+#define HL_CACHE_BITS	10
+#define HL_CACHE_SIZE	(1 << HL_CACHE_BITS)
+#define HL_CACHE_MASK	(HL_CACHE_SIZE - 1)
+#define HL_CACHE_PROBE	8
+static struct hl_cache_entry hl_cache[HL_CACHE_SIZE];
+static int hl_cache_gen = 1;
+static struct lbuf *syn_lb;
+static int syn_row;
+
+static int hl_cache_hash(char *ln)
+{
+	return (int)(((size_t)ln >> 4) & HL_CACHE_MASK);
+}
+
+static struct hl_cache_entry *hl_cache_find(char *ln)
+{
+	if (!ln)
+		return NULL;
+	int h = hl_cache_hash(ln);
+	for (int i = 0; i < HL_CACHE_PROBE; i++) {
+		struct hl_cache_entry *e = &hl_cache[(h + i) & HL_CACHE_MASK];
+		if (e->ln == ln && e->gen == hl_cache_gen)
+			return e;
+		if (!e->ln)
+			return NULL;
+	}
+	return NULL;
+}
+
+static void hl_cache_set(char *ln, int blockhl, int blockatt_v, int fti)
+{
+	if (!ln)
+		return;
+	int h = hl_cache_hash(ln);
+	struct hl_cache_entry *slot = &hl_cache[h];
+	for (int i = 0; i < HL_CACHE_PROBE; i++) {
+		struct hl_cache_entry *e = &hl_cache[(h + i) & HL_CACHE_MASK];
+		if (!e->ln || e->ln == ln || e->gen != hl_cache_gen) {
+			slot = e;
+			break;
+		}
+	}
+	slot->ln = ln;
+	slot->gen = hl_cache_gen;
+	slot->blockhl = blockhl;
+	slot->blockatt = blockatt_v;
+	slot->ftidx = fti;
+}
+
+void syn_blockhl_invalidate(void)
+{
+	hl_cache_gen++;
+}
+
+void syn_setrow(struct lbuf *lb, int row)
+{
+	syn_lb = lb;
+	syn_row = row;
+}
+
+static int *hl_scan_att;
+static int hl_scan_att_sz;
+static int hl_scan_active;
+
+/* extend the cache chain backward to row 0 or nearest cached row */
+static void hl_scan_until(int target_row)
+{
+	if (hl_scan_active || target_row <= 0)
+		return;
+	int from = 0;
+	for (int r = target_row - 1; r > 0; r--) {
+		char *ln = lbuf_get(syn_lb, r);
+		struct hl_cache_entry *e = hl_cache_find(ln);
+		if (e && e->ftidx == ftidx) {
+			from = r + 1;
+			break;
+		}
+	}
+	int saved_row = syn_row;
+	int saved_blockhl = syn_blockhl;
+	int saved_blockatt = blockatt;
+	int saved_last_scdir = last_scdir;
+	last_scdir = 0;
+	hl_scan_active = 1;
+	for (int r = from; r <= target_row; r++) {
+		char *ln = lbuf_get(syn_lb, r);
+		if (!ln)
+			break;
+		int len = lbuf_s(ln)->len;
+		if (len + 1 > hl_scan_att_sz) {
+			hl_scan_att_sz = (len + 1) * 2;
+			hl_scan_att = erealloc(hl_scan_att, hl_scan_att_sz * sizeof(int));
+		}
+		memset(hl_scan_att, 0, (len + 1) * sizeof(int));
+		syn_row = r;
+		syn_highlight(hl_scan_att, ln, len);
+	}
+	hl_scan_active = 0;
+	syn_row = saved_row;
+	syn_blockhl = saved_blockhl;
+	blockatt = saved_blockatt;
+	last_scdir = saved_last_scdir;
+}
+
 static int syn_initft(int fti, int n, char *name, int flg)
 {
 	if (fti >= ftmidx)
@@ -290,9 +402,14 @@ char *syn_setft(char *ft)
 	goto default_hl;
 }
 
+int sign_changed;
+
 void syn_scdir(int scdir)
 {
 	if (!scdir || abs(scdir) > xrows || (last_scdir > 0) != (scdir > 0)) {
+		sign_changed = (last_scdir > 0) != (scdir > 0);
+		if (sign_changed)
+			hl_cache_gen++;
 		last_scdir = scdir;
 		syn_blockhl = -1;
 		blockdep = 0;
@@ -318,7 +435,36 @@ static int syn_tatt(int *att, int a, int pb)
 
 void syn_highlight(int *att, char *s, int n)
 {
-	int fti = ftidx, blockhl = syn_blockhl, blockcont = -1;
+	int fti = ftidx, blockhl, blockcont = -1, trusted = 0;
+	char *cur_ln = NULL;
+	blockhl = syn_blockhl;
+	if (syn_lb && syn_row >= 0 && syn_row < lbuf_len(syn_lb)) {
+		cur_ln = lbuf_get(syn_lb, syn_row);
+		if (syn_row == 0) {
+			syn_blockhl = -1;
+			blockatt = 0;
+			trusted = 1;
+		} else {
+			char *prev_ln = lbuf_get(syn_lb, syn_row - 1);
+			struct hl_cache_entry *e = hl_cache_find(prev_ln);
+			if ((!e || e->ftidx != ftidx) && !hl_scan_active) {
+				hl_scan_until(syn_row);
+				e = hl_cache_find(prev_ln);
+			}
+			if (e && e->ftidx == ftidx) {
+				struct hl_cache_entry *cur_e = hl_cache_find(cur_ln);
+				if (cur_e && cur_e->ftidx == ftidx && cur_e->blockhl != e->blockhl) {
+					/* block boundary: direction changed the state */
+				} else {
+					syn_blockhl = e->blockhl;
+					blockatt = e->blockatt;
+					if (blockhl < 0 && e->blockhl >= 0)
+						blockhl = e->blockhl;
+				}
+				trusted = 1;
+			}
+		}
+	}
 	re:;
 	rset *rs = ftmap[fti].rs;
 	int subs[rs->nsubc], *catt, *iatt, sl, c;
@@ -404,6 +550,8 @@ void syn_highlight(int *att, char *s, int n)
 	fti++;
 	if (ftmidx > fti && ftmap[fti-1].ft == ftmap[fti].ft)
 		goto re;
+	if (trusted && cur_ln)
+		hl_cache_set(cur_ln, syn_blockhl, blockatt, ftidx);
 	if (syn_blockhl < 0 || blockhl < 0)
 		return;
 	for (j = 0; j < n; j++)
diff --git a/vi.c b/vi.c
index 357df5ff..3267972b 100644
--- a/vi.c
+++ b/vi.c
@@ -128,6 +128,7 @@ for (i = 0, ret = 0;; i++) { \
 static void vi_drawrow(int row)
 {
 	int l1, i, i1, lnnum = vi_lnnum;
+	int s_row = -1;
 	char *c, *s;
 	static char ch[5] = "~";
 	if (xmpt == 1 && !vi_status && row == xtop + xrows - 1)
@@ -138,6 +139,7 @@ static void vi_drawrow(int row)
 		if (row != xrow+1 || !c || *c == '\n') {
 			vi_rshift = (row > xrow+1 && c && *c != '\n');
 			s = lbuf_get(xb, row - vi_rshift);
+			s_row = row - vi_rshift;
 			goto skip;
 		}
 		char tmp[xcols+3], snum[32];
@@ -170,11 +172,13 @@ static void vi_drawrow(int row)
 		return;
 	}
 	s = lbuf_get(xb, row);
+	s_row = row;
 	skip:
 	rstate += row != xrow;
-	if (!s)
+	if (!s) {
 		s = row ? ch : ch+1;
-	else if (lnnum && xled) {
+		s_row = -1;
+	} else if (lnnum && xled) {
 		char tmp[32], tmp1[32], *p;
 		c = tmp, i = 0, i1 = 0;
 		if (lnnum == 1 || lnnum & 2) {
@@ -193,7 +197,9 @@ static void vi_drawrow(int row)
 		vi_lncol = dir_context(s) < 0 ? 0 : l1;
 		memset(c, ' ', l1 - (c - tmp));
 		c[l1 - (c - tmp)] = '\0';
+		syn_setrow(xb, s_row);
 		led_crender(s, row - xtop, l1, xleft, xleft + xcols - l1)
+		syn_setrow(NULL, 0);
 		preserve(int, syn_blockhl, syn_blockhl = -1;)
 		preserve(int, ftidx,)
 		syn_setft(nn_ft);
@@ -212,7 +218,10 @@ static void vi_drawrow(int row)
 		restore(ftidx)
 		return;
 	}
+	if (s_row >= 0)
+		syn_setrow(xb, s_row);
 	led_crender(s, row - xtop, 0, xleft, xleft + xcols)
+	syn_setrow(NULL, 0);
 	rstate = rstates;
 }
 
diff --git a/vi.h b/vi.h
index 6466711d..b1a2adcc 100644
--- a/vi.h
+++ b/vi.h
@@ -263,6 +263,8 @@ void syn_reloadft(int hl, int flg);
 int syn_findhl(int id);
 int syn_addhl(char *reg, int id);
 void syn_init(void);
+void syn_setrow(struct lbuf *lb, int row);
+void syn_blockhl_invalidate(void);
 
 /* uc.c: utf-8 helper functions */
 extern unsigned char utf8_length[256];
