+void historyOpToggle(int start, int paint) {
+ if (!histOp == !(histOp + start)) if ((histOp += start) || 1) return;
+ if (histMode && paint && (!IS_SET(MODE_ALTSCREEN) || altToggle)) draw();
+ tcursor(CURSOR_SAVE);
+ histOp += start;
+ if (histMode && altToggle) {
+ tswapscreen();
+ memset(term.dirty,0,sizeof(*term.dirty)*term.row);
+ }
+ tcursor(CURSOR_LOAD);
+ *(!IS_SET(MODE_ALTSCREEN)?&term.line:&term.alt)=&buf[histOp?histOff:insertOff];
+}
+
+void historyModeToggle(int start) {
+ if (!(histMode = (histOp = !!start))) {
+ selnormalize();
+ tfulldirt();
+ } else {
+ tcursor(CURSOR_SAVE);
+ histOp = 0;
+ histOff = insertOff;
+ }
+}
+
+int historyBufferScroll(int n) {
+ if (IS_SET(MODE_ALTSCREEN) || !n) return histOp;
+ int p=abs(n=(n<0) ? max(n,-term.row) : min(n,term.row)), r=term.row-p,
+ s=sizeof(*term.dirty), *ptr=histOp?&histOff:&insertOff;
+ if (!histMode || histOp) tfulldirt(); else {
+ memmove(&term.dirty[-min(n,0)], &term.dirty[max(n,0)], s*r);
+ memset(&term.dirty[n>0 ? r : 0], 0, s * p);
+ }
+ int const prevOffBuf = sel.alt ? 0 : insertOff + term.row;
+ term.line = &buf[*ptr = (buffSize+*ptr+n) % buffSize];
+ // Cut part of selection removed from buffer, and update sel.ne/b.
+ if (sel.ob.x != -1 && !histOp && n) {
+ int const offBuf = sel.alt ? 0 : insertOff + term.row,
+ pb = rangeY(sel.ob.y - prevOffBuf),
+ pe = rangeY(sel.oe.y - prevOffBuf);
+ int const b = rangeY(sel.ob.y - offBuf), nln = n < 0,
+ e = rangeY(sel.oe.y - offBuf), last = offBuf - nln;
+ if (pb != b && ((pb < b) != nln)) sel.ob.y = last;
+ if (pe != e && ((pe < e) != nln)) sel.oe.y = last;
+ if (sel.oe.y == last && sel.ob.y == last) selclear();
+ }
+ selnormalize();
+ // Clear the new region exposed by the shift.
+ if (!histOp) tclearregion(0, n>0?r+1:0, buffCols-1, n>0?term.row:p-1);
+ return 1;
+}
+
+int historyMove(int x, int y, int ly) {
+ historyOpToggle(1, 1);
+ y += ((term.c.x += x) < 0 ?term.c.x-term.col :term.c.x) / term.col;//< x
+ if ((term.c.x %= term.col) < 0) term.c.x += term.col;
+ if ((term.c.y += y) >= term.row) ly += term.c.y - term.row + 1; //< y
+ else if (term.c.y < 0) ly += term.c.y;
+ term.c.y = MIN(MAX(term.c.y, 0), term.row - 1);
+ int off=insertOff-histOff, bot=rangeY(off), top=-rangeY(-term.row-off),
+ pTop = (-ly>-top), pBot = (ly > bot), fin=histMode&&(pTop||pBot);
+ if (fin && (x||y)) term.c.x = pBot ? term.col-1 : 0;
+ historyBufferScroll(fin ? (pBot ? bot : top) : ly);
+ historyOpToggle(-1, 1);
+ return fin;
+}