#!/bin/sh -e
# Generated by patch2vi from unified diff
# Available separators: 0003-0010 0013-0014 0016-0037 0102 0104-0105 0107-0110 0112 0120-0123 0126-0127 0131-0132 0136 0172 0176-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 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> 	return pos >= 0 && pos < lb->ln_n \\? lb->ln\\[pos] : NULL;
}

int lbuf_undo\\(struct lbuf \\*lb, int \\*row, int \\*off\\)
\\{
	if \\(!lb->hist_u\\)${ESC}${SEP}1??${ESC}${SEP}${LB}
${ESC}${SEP}1??+2m 1${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}%f> 	return pos >= 0 && pos < lb->ln_n \\? lb->ln\\[pos] : NULL;
}

${ESC}${SEP}3??${ESC}${SEP}${LB}
${ESC}${SEP}3??+2m 1${ESC}${ESC}${ESC}${SEP}${OK1}p OK lbuf.c:395:a3${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}m 0${ESC}${SEP}1;0${ESC}${SEP}grp 1${ESC}${SEP}%f> 	free\\(sb->s\\);
	return 0;
}.*(	struct lopt \\*lo = &lb->hist\\[lb->hist_u - 1];)
	const int useq = lo->seq;
	sbuf sb;${ESC}${SEP}8??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}8??-5m 1${ESC}${ESC}${ESC}${SEP}${OK1}p OK lbuf.c:395: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> 	}
	sbufn_chr\\(sb, '\\\\n'\\)
	lbuf_edit\\(lb, sb->s, beg, end, o1, \\*o2\\);.*(	if \\(lb->hist_u == lb->hist_n\\) \\{)
		lbuf_copymark\\(lb->tmp_mark, lb->mark_sb\\)
		lbuf_copymark\\(\\(lb->tmp_mark \\+ 2\\), lb->mark_se\\)${ESC}${SEP}9??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}9??-8m 1${ESC}${ESC}${ESC}${SEP}${OK1}p OK lbuf.c:395:a9${ESC}${SEP}'0${SEP}${LB}
${SEP}1;3;8;9??!${DBG1:-ya!112${ESC}${SEP}prp${ESC}${SEP}p FAIL lbuf.c:395${ESC}${SEP}pr${INTR}${QF1}}${SEP}${LB}
${SEP}${LB}
${SEP}'1i int lbuf_undojump(struct lbuf *lb, int *pos, int *off)
{
	struct lopt *lo;
	static int last_hist_u;
	int hist_u = lb->hist_u;
	int useq;
	int rpos = 0;
	int ret = 0;
	if (!last_hist_u) {
		last_hist_u = hist_u;
		ret = 2;
	}
	if (hist_u) {
		do {
			lo = &lb->hist[hist_u - 1];
			useq = lo->seq;
			while (hist_u && lb->hist[hist_u - 1].seq == useq)
				lo = &lb->hist[--hist_u];
		} while (hist_u && hist_u >= last_hist_u);
		last_hist_u = hist_u;
		hist_u = lb->hist_u;
		while (hist_u != last_hist_u) {
			lo = &lb->hist[--hist_u];
			if (lb->hist[last_hist_u].pos > lo->pos) {
				rpos += lo->n_ins;
				rpos -= lo->n_del;
			}
		}
	} else
		return ret ? ret : 1;
	*pos = rpos + lb->hist[last_hist_u].pos;
	*off = lo->pos_off;
	return ret;
}

${SEP}??!${DBG2:-ya!112${ESC}${SEP}prp${ESC}${SEP}p FAIL lbuf.c:395:m1${ESC}${SEP}pr${INTR}${QF2}}${SEP}b1${SEP}%ya 98${SEP}?${ESC}${SEP}${LB}
${ESC}${SEP}%f> 				vi_hidch = !vi_hidch;
				vi_mod \\|= 1;
				break;
			case TK_CTL\\('v'\\):
				vi_arg = \\(vi_wsel % 5\\) \\+ !!\\*vi_word;
			case TK_CTL\\('c'\\):${ESC}${SEP}1??${ESC}${SEP}${LB}
${ESC}${SEP}1??+2m 1${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}%f> 				vi_hidch = !vi_hidch;
				vi_mod \\|= 1;
				break;${ESC}${SEP}3??${ESC}${SEP}${LB}
${ESC}${SEP}3??+2m 1${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:1436:a3${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}grp 1${ESC}${SEP}%f> 				vi_hidch = !vi_hidch;.*?
				vi_mod \\|= 1;.*?
(				break;)${ESC}${SEP}7??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}7??m 1${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:1436:a7${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}m 0${ESC}${SEP}1;0${ESC}${SEP}grp 1${ESC}${SEP}%f> 				}
				break;
			case 'V':.*(				if \\(vi_arg && vi_arg <= 5\\) \\{)
					vi_wsel = vi_arg;
					vi_word = _vi_word \\+ vi_arg;${ESC}${SEP}8??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}8??-4m 1${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:1436: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> 					goto do_excmd; }
				default:
					term_dec\\(\\).*(					vi_word = _vi_word \\+ \\(!\\*vi_word \\* vi_wsel\\);)
				vi_rshift = 0;
				vi_mod \\|= 1;${ESC}${SEP}9??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}9??-8m 1${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.c:1436:a9${ESC}${SEP}'0${SEP}${LB}
${SEP}1;3;7;8;9??!${DBG1:-ya!112${ESC}${SEP}prp${ESC}${SEP}p FAIL vi.c:1436${ESC}${SEP}pr${INTR}${QF1}}${SEP}${LB}
${SEP}${LB}
${SEP}'1i 			case TK_CTL('o'):
				next_hop:
				if (lbuf_undojump(xb, &xrow, &xoff))
					vi_drawmsg_mpt(\"undo jmp failed\")
				else if (xrow == nrow)
					goto next_hop;
				vi_col = vi_off2col(xb, xrow, xoff);
				xoff = vi_col2off(xb, xrow, vi_col);
				xtop = MAX(0, xrow - xrows / 2);
				vi_mod = 1;
				break;
${SEP}??!${DBG2:-ya!112${ESC}${SEP}prp${ESC}${SEP}p FAIL vi.c:1436:m1${ESC}${SEP}pr${INTR}${QF2}}${SEP}b2${SEP}%ya 98${SEP}?${ESC}${SEP}${LB}
${ESC}${SEP}%f> void lbuf_smark\\(struct lbuf \\*lb, struct lopt \\*lo, int beg, int o1\\);
void lbuf_emark\\(struct lbuf \\*lb, struct lopt \\*lo, int end, int o2\\);
struct lopt \\*lbuf_opt\\(struct lbuf \\*lb, int beg, int o1, int n_del\\);
void lbuf_mark\\(struct lbuf \\*lb, int mk, int pos, int off\\);
int lbuf_jump\\(struct lbuf \\*lb, int mk, int \\*pos, int \\*off\\);
int lbuf_undo\\(struct lbuf \\*lb, int \\*row, int \\*off\\);${ESC}${SEP}1??${ESC}${SEP}${LB}
${ESC}${SEP}1??+2m 1${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}%f> void lbuf_smark\\(struct lbuf \\*lb, struct lopt \\*lo, int beg, int o1\\);
void lbuf_emark\\(struct lbuf \\*lb, struct lopt \\*lo, int end, int o2\\);
struct lopt \\*lbuf_opt\\(struct lbuf \\*lb, int beg, int o1, int n_del\\);${ESC}${SEP}3??${ESC}${SEP}${LB}
${ESC}${SEP}3??+2m 1${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.h:170:a3${ESC}${ESC}${ESC}${SEP}1q${ESC}${SEP}${LB}
${ESC}${SEP}grp 1${ESC}${SEP}%f> void lbuf_smark\\(struct lbuf \\*lb, struct lopt \\*lo, int beg, int o1\\);.*?
void lbuf_emark\\(struct lbuf \\*lb, struct lopt \\*lo, int end, int o2\\);.*?
(struct lopt \\*lbuf_opt\\(struct lbuf \\*lb, int beg, int o1, int n_del\\);)${ESC}${SEP}7??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}7??m 1${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.h:170: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 \\*lbuf_joinsb\\(struct lbuf \\*lb, int r1, int r2, sbuf \\*i, int \\*o1, int \\*o2\\);
int lbuf_join\\(struct lbuf \\*lb, int beg, int end, int o1, int \\*o2, int flg\\);
char \\*lbuf_get\\(struct lbuf \\*lb, int pos\\);.*(int lbuf_redo\\(struct lbuf \\*lb, int \\*row, int \\*off\\);)
void lbuf_saved\\(struct lbuf \\*lb, int clear\\);
int lbuf_indents\\(struct lbuf \\*lb, int r\\);${ESC}${SEP}8??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}8??-4m 1${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.h:170: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> void lbuf_region\\(struct lbuf \\*lb, sbuf \\*sb, int r1, int o1, int r2, int o2\\);
int lbuf_pos2off\\(struct lbuf \\*lb, int r1, int o1, int r2, int o2, int row, int off\\);
int lbuf_off2pos\\(struct lbuf \\*lb, int r1, int o1, int r2, int o2, int boff, int \\*row, int \\*off\\);.*(int lbuf_eol\\(struct lbuf \\*lb, int r, int state\\);)
int lbuf_next\\(struct lbuf \\*lb, int dir, int \\*r, int \\*o\\);
int lbuf_findchar\\(struct lbuf \\*lb, char \\*cs, int cmd, int n, int \\*r, int \\*o\\);${ESC}${SEP}9??${ESC}${SEP}${LB}
${ESC}${SEP}grp 0${ESC}${SEP}9??-7m 1${ESC}${ESC}${ESC}${SEP}${OK1}p OK vi.h:170:a9${ESC}${SEP}'0${SEP}${LB}
${SEP}1;3;7;8;9??!${DBG1:-ya!112${ESC}${SEP}prp${ESC}${SEP}p FAIL vi.h:170${ESC}${SEP}pr${INTR}${QF1}}${SEP}${LB}
${SEP}${LB}
${SEP}'1i int lbuf_undojump(struct lbuf *lb, int *pos, int *off);
${SEP}??!${DBG2:-ya!112${ESC}${SEP}prp${ESC}${SEP}p FAIL vi.h:170:m1${ESC}${SEP}pr${INTR}${QF2}}${SEP}vis 2${SEP}b0${SEP}w${SEP}b1${SEP}w${SEP}b2${SEP}w${SEP}2q" > "$P2VIF"
EXINIT='%ya 97:? %@97' $VI -e 'lbuf.c' 'vi.c' 'vi.h' "$P2VIF"

exit 0
=== PATCH2VI DELTA ===
=== PATCH2VI PATCH ===
diff --git a/lbuf.c b/lbuf.c
index 75dd0ce8..6498250f 100644
--- a/lbuf.c
+++ b/lbuf.c
@@ -393,6 +393,41 @@ char *lbuf_get(struct lbuf *lb, int pos)
 	return pos >= 0 && pos < lb->ln_n ? lb->ln[pos] : NULL;
 }
 
+int lbuf_undojump(struct lbuf *lb, int *pos, int *off)
+{
+	struct lopt *lo;
+	static int last_hist_u;
+	int hist_u = lb->hist_u;
+	int useq;
+	int rpos = 0;
+	int ret = 0;
+	if (!last_hist_u) {
+		last_hist_u = hist_u;
+		ret = 2;
+	}
+	if (hist_u) {
+		do {
+			lo = &lb->hist[hist_u - 1];
+			useq = lo->seq;
+			while (hist_u && lb->hist[hist_u - 1].seq == useq)
+				lo = &lb->hist[--hist_u];
+		} while (hist_u && hist_u >= last_hist_u);
+		last_hist_u = hist_u;
+		hist_u = lb->hist_u;
+		while (hist_u != last_hist_u) {
+			lo = &lb->hist[--hist_u];
+			if (lb->hist[last_hist_u].pos > lo->pos) {
+				rpos += lo->n_ins;
+				rpos -= lo->n_del;
+			}
+		}
+	} else
+		return ret ? ret : 1;
+	*pos = rpos + lb->hist[last_hist_u].pos;
+	*off = lo->pos_off;
+	return ret;
+}
+
 int lbuf_undo(struct lbuf *lb, int *row, int *off)
 {
 	if (!lb->hist_u)
diff --git a/vi.c b/vi.c
index 357df5ff..e80c50db 100644
--- a/vi.c
+++ b/vi.c
@@ -1434,6 +1434,17 @@ void vi(int init)
 				vi_hidch = !vi_hidch;
 				vi_mod |= 1;
 				break;
+			case TK_CTL('o'):
+				next_hop:
+				if (lbuf_undojump(xb, &xrow, &xoff))
+					vi_drawmsg_mpt("undo jmp failed")
+				else if (xrow == nrow)
+					goto next_hop;
+				vi_col = vi_off2col(xb, xrow, xoff);
+				xoff = vi_col2off(xb, xrow, vi_col);
+				xtop = MAX(0, xrow - xrows / 2);
+				vi_mod = 1;
+				break;
 			case TK_CTL('v'):
 				vi_arg = (vi_wsel % 5) + !!*vi_word;
 			case TK_CTL('c'):
diff --git a/vi.h b/vi.h
index 6466711d..47110655 100644
--- a/vi.h
+++ b/vi.h
@@ -168,6 +168,7 @@ char *lbuf_get(struct lbuf *lb, int pos);
 void lbuf_smark(struct lbuf *lb, struct lopt *lo, int beg, int o1);
 void lbuf_emark(struct lbuf *lb, struct lopt *lo, int end, int o2);
 struct lopt *lbuf_opt(struct lbuf *lb, int beg, int o1, int n_del);
+int lbuf_undojump(struct lbuf *lb, int *pos, int *off);
 void lbuf_mark(struct lbuf *lb, int mk, int pos, int off);
 int lbuf_jump(struct lbuf *lb, int mk, int *pos, int *off);
 int lbuf_undo(struct lbuf *lb, int *row, int *off);
