+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;
+}
+
+#include "normalMode.c"
+
+void selnormalize(void) {
+ historyOpToggle(1, 1);
+
+ int const oldb = sel.nb.y, olde = sel.ne.y;
+ if (sel.ob.x == -1) {
+ sel.ne.y = sel.nb.y = -1;
+ } else {
+ int const offsetBuffer = sel.alt ? 0 : insertOff + term.row;
+ int const off = sel.alt ? 0 : (histMode ? histOff : insertOff);
+ int const nby = rangeY(sel.ob.y - off),
+ ney = rangeY(sel.oe.y - off);
+ sel.swap = rangeY(sel.ob.y - offsetBuffer)
+ > rangeY(sel.oe.y - offsetBuffer);
+ sel.nb.y = sel.swap ? ney : nby;
+ sel.ne.y = !sel.swap ? ney : nby;
+ int const cnb = sel.nb.y < term.row, cne = sel.ne.y < term.row;
+ if (sel.type == SEL_REGULAR && sel.ob.y != sel.oe.y) {
+ if (cnb) sel.nb.x = (!sel.swap) ? sel.ob.x : sel.oe.x;
+ if (cne) sel.ne.x = (!sel.swap) ? sel.oe.x : sel.ob.x;
+ } else {
+ if (cnb) sel.nb.x = MIN(sel.ob.x, sel.oe.x);
+ if (cne) sel.ne.x = MAX(sel.ob.x, sel.oe.x);
+ }
+ }
+ int const nBet=sel.nb.y<=sel.ne.y, oBet=oldb<=olde;
+ for (int i = 0; i < term.row; ++i) {
+ int const n = nBet ? BETWEEN(i, sel.nb.y, sel.ne.y)
+ : OUT(i, sel.nb.y, sel.ne.y);
+ term.dirty[i] |= (sel.type == SEL_RECTANGULAR && n) ||
+ (n != (oBet ? BETWEEN(i,oldb,olde) : OUT(i,oldb,olde)));
+
+ }
+ if (BETWEEN(oldb, 0, term.row - 1)) term.dirty[oldb] = 1;
+ if (BETWEEN(olde, 0, term.row - 1)) term.dirty[olde] = 1;
+ if (BETWEEN(sel.nb.y, 0, term.row - 1)) term.dirty[sel.nb.y] = 1;
+ if (BETWEEN(sel.ne.y, 0, term.row - 1)) term.dirty[sel.ne.y] = 1;
+
+ historyOpToggle(-1, 1);
+}
+
+void
+selstart(int col, int row, int snap)
+{
+ selclear();
+ sel.mode = SEL_EMPTY;
+ sel.type = SEL_REGULAR;
+ sel.alt = IS_SET(MODE_ALTSCREEN);
+ sel.snap = snap;
+ sel.oe.x = sel.ob.x = col;
+ sel.oe.y = sel.ob.y = row + !sel.alt * (histMode ? histOff : insertOff);
+ if (sel.snap != 0) sel.mode = SEL_READY;
+ selnormalize();
+}
+
+void
+selextend(int col, int row, int type, int done)
+{
+ if (sel.mode == SEL_IDLE)