#include "ex.h"
#include "ex_tune.h"
#include "ex_tty.h"
#include "ex_vis.h"
void
vopen(line *tp, int p)
{
int cnt;
struct vlinfo *vp, *vpc;
#ifdef ADEBUG
if (trace != NULL)
tfixnl(), fprintf(trace, "vopen(%d, %d)\n", lineno(tp), p);
#endif
if (state != VISUAL) {
if (vcnt)
if (hold & HOLDROL)
vup1();
else
vclean();
vcnt = vcline = 0;
p = WBOT; LASTLINE = WBOT + 1;
state = bastate;
WTOP = basWTOP;
WLINES = basWLINES;
}
vpc = &vlinfo[vcline];
for (vp = &vlinfo[vcnt]; vp >= vpc; vp--)
vlcopy(vp[1], vp[0]);
vcnt++;
if (Pline == numbline)
vdirty(vcline+1, WECHO);
getaline(*tp);
if (state == VISUAL && vcline == 0 && vcnt > 1 && p > ZERO) {
cnt = p + vdepth() - LINE(1);
if (cnt > 0) {
p -= cnt;
if (p < ZERO)
p = ZERO;
WTOP = p;
WLINES = WBOT - WTOP + 1;
}
}
vpc->vliny = p, vpc->vdepth = 0, vpc->vflags = 0;
cnt = vreopen(p, lineno(tp), vcline);
if (vcline + 1 == vcnt)
LINE(vcnt) = LINE(vcline) + cnt;
}
int
vreopen(int p, int lineno, int l)
{
int d;
struct vlinfo *vp = &vlinfo[l];
d = vp->vdepth;
if (d == 0 || (vp->vflags & VDIRT))
vp->vdepth = d = vdepth();
vp->vliny = p, vp->vflags &= ~VDIRT;
p = vglitchup(l, 0);
vigoto(p, 0);
pline(lineno);
if (state == VISUAL && l == vcline && vp->vliny < 0) {
vp->vliny = 0;
vscrap();
return (d);
}
if (hold & HOLDDOL)
return (d);
if (Putchar == listchar)
putchar('$');
if (vp->vliny + d - 1 > WBOT)
vcsync();
if (state == ONEOPEN) {
WCOLS = OCOLUMNS;
if (vdepth() > 1) {
WCOLS = TUBECOLS;
sethard();
} else
WCOLS = TUBECOLS;
} else if (state == HARDOPEN)
sethard();
if (vp->vliny + d > destline) {
if (insert_null_glitch && destcol == WCOLS)
vigoto(vp->vliny + d - 1, 0);
vclreol();
}
return (d);
}
int
vglitchup(int l, int o)
{
struct vlinfo *vp = &vlinfo[l];
int need;
int p = vp->vliny;
short oldhold, oldheldech;
bool glitched = 0;
if (l < vcnt - 1) {
need = p + vp->vdepth - (vp+1)->vliny;
if (need > 0) {
if (state == VISUAL && WTOP - ZERO >= need && insert_line && delete_line) {
glitched++;
WTOP -= need;
WLINES = WBOT - WTOP + 1;
p -= need;
if (p + o == WTOP) {
vp->vliny = WTOP;
return (WTOP + o);
}
vdellin(WTOP, need, -1);
oldheldech = heldech;
oldhold = hold;
hold |= HOLDECH;
}
vinslin((vp+1)->vliny, need, l);
if (glitched) {
hold = oldhold;
heldech = oldheldech;
}
}
} else
vp[1].vliny = vp[0].vliny + vp->vdepth;
return (p + o);
}
void
vinslin(int p, int cnt, int l)
{
int i;
bool could = 1;
#ifdef ADEBUG
if (trace)
tfixnl(), fprintf(trace, "vinslin(%d, %d, %d)\n", p, cnt, l);
#endif
if (p + cnt > WBOT && clr_eos) {
cnt = WECHO + 1 - p;
vgoto(p, 0), vputp(clr_eos, cnt);
vclrech(1);
vadjAL(p, cnt);
} else if (scroll_reverse && p == WTOP && costSR < costAL) {
for (i = cnt; i > 0; i--) {
vgoto(p, 0), vputp(scroll_reverse, 0);
if (i > 1 && (hold & HOLDAT) == 0)
putchar('@');
if (clr_eol && (memory_above || p != 0))
vputp(clr_eol, 1);
}
vadjAL(p, cnt);
} else if (insert_line) {
vgoto(p, 0);
if (parm_insert_line && (cnt>1 || *insert_line==0)) {
vputp(tparm(parm_insert_line, cnt, p), WECHO+1-p);
}
else if (change_scroll_region && *insert_line==0) {
vputp(save_cursor, 1);
vputp(tparm(change_scroll_region, p, lines-1), 1);
vputp(restore_cursor, 1);
for (i=cnt; i>0; i--)
vputp(scroll_reverse, 1);
vputp(tparm(change_scroll_region, 0, lines-1), 1);
vputp(restore_cursor, 1);
}
else {
vputp(insert_line, WECHO + 1 - p);
for (i = cnt - 1; i > 0; i--) {
vgoto(outline+1, 0);
vputp(insert_line, WECHO + 1 - outline);
if ((hold & HOLDAT) == 0)
putchar('@');
}
}
vadjAL(p, cnt);
} else
could = 0;
vopenup(cnt, could, l);
}
void
vopenup(int cnt, bool could, int l)
{
struct vlinfo *vc = &vlinfo[l + 1];
struct vlinfo *ve = &vlinfo[vcnt];
#ifdef ADEBUG
if (trace)
tfixnl(), fprintf(trace, "vopenup(%d, %d, %d)\n", cnt, could, l);
#endif
if (could)
for (; vc <= ve; vc++)
vc->vliny += cnt;
else {
vc->vliny += cnt, vc->vflags |= VDIRT;
while (vc < ve) {
int i = vc->vliny + vc->vdepth;
vc++;
if (i <= vc->vliny)
break;
vc->vliny = i, vc->vflags |= VDIRT;
}
}
vscrap();
}
void
vadjAL(int p, int cnt)
{
wchar_t *tlines[TUBELINES];
int from, to;
#ifdef ADEBUG
if (trace)
tfixnl(), fprintf(trace, "vadjal(%d, %d)\n", p, cnt);
#endif
copy(tlines, vtube, sizeof vtube);
for (from = p, to = p + cnt; to <= WECHO; from++, to++)
vtube[to] = tlines[from];
for (to = p; from <= WECHO; from++, to++) {
vtube[to] = tlines[from];
vclrbyte(vtube[to], WCOLS);
}
vclrech(0);
}
void
vrollup(int dl)
{
int cnt;
int dc = destcol;
#ifdef ADEBUG
if (trace)
tfixnl(), fprintf(trace, "vrollup(%d)\n", dl);
#endif
cnt = dl - (splitw ? WECHO : WBOT);
if (splitw && (state == VISUAL || state == CRTOPEN))
holdupd = 1;
vmoveitup(cnt, 1);
vscroll(cnt);
destline = dl - cnt, destcol = dc;
}
void
vup1(void)
{
vrollup(WBOT + 1);
}
void
vmoveitup(int cnt, bool doclr)
{
if (cnt == 0)
return;
#ifdef ADEBUG
if (trace)
tfixnl(), fprintf(trace, "vmoveitup(%d)\n", cnt);
#endif
if (doclr)
vclrech(0);
if (scroll_forward) {
destline = WECHO;
destcol = (NONL ? 0 : outcol % WCOLS);
fgoto();
while (cnt > 0)
vputp(scroll_forward, 0), cnt--;
}
else {
destline = WECHO + cnt;
destcol = (NONL ? 0 : outcol % WCOLS);
fgoto();
if (state == ONEOPEN || state == HARDOPEN) {
outline = destline = 0;
vclrbyte(vtube[0], WCOLS);
}
}
if (doclr && memory_below && clr_eol)
vclrech(0);
}
void
vscroll(int cnt)
{
int from, to;
wchar_t *tlines[TUBELINES];
#ifdef ADEBUG
if (trace)
fprintf(trace, "vscroll(%d)\n", cnt);
#endif
if (cnt < 0 || cnt > TUBELINES)
error(gettext("Internal error: vscroll"));
if (cnt == 0)
return;
copy(tlines, vtube, sizeof vtube);
for (to = ZERO, from = ZERO + cnt; to <= WECHO - cnt; to++, from++)
vtube[to] = tlines[from];
for (from = ZERO; to <= WECHO; to++, from++) {
vtube[to] = tlines[from];
vclrbyte(vtube[to], WCOLS);
}
for (from = 0; from <= vcnt; from++)
LINE(from) -= cnt;
}
void
vscrap(void)
{
int i, j;
#ifdef ADEBUG
if (trace)
tfixnl(), fprintf(trace, "vscrap\n"), tvliny();
#endif
if (splitw)
return;
if (vcnt && WBOT != WECHO && LINE(0) < WTOP && LINE(0) >= ZERO) {
WTOP = LINE(0);
WLINES = WBOT - WTOP + 1;
}
for (j = 0; j < vcnt; j++)
if (LINE(j) >= WTOP) {
if (j == 0)
break;
vcnt -= j, vcline -= j;
for (i = 0; i <= vcnt; i++)
vlcopy(vlinfo[i], vlinfo[i + j]);
break;
}
if (vcnt) {
for (j = 0; j <= vcnt; j++)
if (LINE(j) > WBOT || LINE(j) + DEPTH(j) - 1 > WBOT) {
vcnt = j;
break;
}
if (vcnt == 0)
LASTLINE = 0;
else
LASTLINE = LINE(vcnt-1) + DEPTH(vcnt-1);
}
#ifdef ADEBUG
if (trace)
tvliny();
#endif
}
void
vrepaint(unsigned char *curs)
{
wdot = NOLINE;
noteit(0);
vscrap();
if (vcnt == 0 || vcline < 0 || vcline > vcnt || holdupd && state != VISUAL) {
line *odol = dol;
vcnt = 0;
if (holdupd)
if (state == VISUAL)
(void)peekkey();
else
vup1();
holdupd = 0;
if (odol == zero)
fixzero();
vcontext(dot, '.');
noteit(1);
if (noteit(1) == 0 && odol == zero) {
CATCH
error(gettext("No lines in buffer"));
ENDCATCH
linebuf[0] = 0;
splitw = 0;
}
vnline(curs);
return;
}
getDOT();
if (FLAGS(0) & VDIRT)
vsync(WTOP);
if (vcline >= vcnt || LINE(vcline) > WBOT) {
short oldhold = hold;
hold |= HOLDAT, vredraw(LASTLINE), hold = oldhold;
if (vcline >= vcnt) {
int i = vcline - vcnt + 1;
dot -= i;
vcline -= i;
vroll(i);
} else
vsyncCL();
} else
vsync(vcline > 0 ? LINE(vcline - 1) : WTOP);
noteit(1);
vnline(curs);
}
void
vredraw(int p)
{
int l;
line *tp;
unsigned char temp[LBSIZE];
bool anydl = 0;
short oldhold = hold;
#ifdef ADEBUG
if (trace)
tfixnl(), fprintf(trace, "vredraw(%d)\n", p), tvliny();
#endif
if (holdupd) {
holdupd = 3;
return;
}
if (state == HARDOPEN || splitw)
return;
if (p < 0 )
error(gettext("Internal error: vredraw"));
vscrap();
CP(temp, linebuf);
l = 0;
tp = dot - vcline;
if (vcnt == 0)
LINE(0) = WTOP;
while (l < vcnt && LINE(l) < p)
l++, tp++;
heldech = 0;
hold |= HOLDECH;
for (; l < vcnt && Peekkey != ATTN; l++) {
if (l == vcline)
strcLIN(temp);
else
getaline(*tp);
if (LINE(l) != LINE(l + 1) && LINE(l) != p) {
if (anydl == 0 && memory_below && clr_eos) {
hold = oldhold;
vclrech(0);
anydl = 1;
hold |= HOLDECH;
heldech = 0;
}
vdellin(p, LINE(l) - p, l);
}
LINE(l) = p;
if (FLAGS(l) & VDIRT) {
DEPTH(l) = vdepth();
if (l != vcline && p + DEPTH(l) - 1 > WBOT) {
vscrap();
break;
}
FLAGS(l) &= ~VDIRT;
(void) vreopen(p, lineno(tp), l);
p = LINE(l) + DEPTH(l);
} else
p += DEPTH(l);
tp++;
}
if (state == VISUAL && p <= WBOT) {
int ovcline = vcline;
vcline = l;
for (; tp <= dol && Peekkey != ATTN; tp++) {
getaline(*tp);
if (p + vdepth() - 1 > WBOT)
break;
vopen(tp, p);
p += DEPTH(vcline);
vcline++;
}
vcline = ovcline;
}
for (; p <= WBOT && Peekkey != ATTN; p++)
vclrlin(p, tp);
strcLIN(temp);
hold = oldhold;
if (heldech)
vclrech(0);
#ifdef ADEBUG
if (trace)
tvliny();
#endif
}
void
vdellin(int p, int cnt, int l)
{
int i;
if (cnt == 0)
return;
if (delete_line == NOSTR || cnt < 0) {
FLAGS(l) |= VDIRT;
return;
}
#ifdef ADEBUG
if (trace)
tfixnl(), fprintf(trace, "vdellin(%d, %d, %d)\n", p, cnt, l);
#endif
vgoto(p, 0);
if (parm_delete_line && (cnt>1 || *delete_line==0)) {
vputp(tparm(parm_delete_line, cnt, p), WECHO-p);
}
else if (change_scroll_region && *delete_line==0) {
vputp(save_cursor, 1);
vputp(tparm(change_scroll_region, p, lines-1), 1);
vputp(tparm(cursor_address, lines-1, 0), 1);
for (i=0; i<cnt; i++)
(void) putch('\n');
vputp(tparm(change_scroll_region, 0, lines-1), 1);
vputp(restore_cursor, 1);
}
else {
for (i = 0; i < cnt; i++)
vputp(delete_line, WECHO - p);
}
vadjDL(p, cnt);
vcloseup(l, cnt);
}
void
vadjDL(int p, int cnt)
{
wchar_t *tlines[TUBELINES];
int from, to;
#ifdef ADEBUG
if (trace)
tfixnl(), fprintf(trace, "vadjDL(%d, %d)\n", p, cnt);
#endif
copy(tlines, vtube, sizeof vtube);
for (from = p + cnt, to = p; from <= WECHO; from++, to++)
vtube[to] = tlines[from];
for (from = p; to <= WECHO; from++, to++) {
vtube[to] = tlines[from];
vclrbyte(vtube[to], WCOLS);
}
}
void
vsyncCL(void)
{
vsync(LINE(vcline));
}
void
vsync(int p)
{
if (value(vi_REDRAW))
vredraw(p);
else
vsync1(p);
}
void
vsync1(int p)
{
int l;
unsigned char temp[LBSIZE];
struct vlinfo *vp = &vlinfo[0];
short oldhold = hold;
#ifdef ADEBUG
if (trace)
tfixnl(), fprintf(trace, "vsync1(%d)\n", p), tvliny();
#endif
if (holdupd) {
if (holdupd < 3)
holdupd = 2;
return;
}
if (state == HARDOPEN || splitw)
return;
vscrap();
CP(temp, linebuf);
if (vcnt == 0)
LINE(0) = WTOP;
l = 0;
while (l < vcnt && vp->vliny < p)
l++, vp++;
heldech = 0;
hold |= HOLDECH;
while (p <= WBOT && Peekkey != ATTN) {
if (l == 0 && state != VISUAL ||
(l < vcnt && (vp->vliny <= p || vp[0].vliny == vp[1].vliny))) {
if (l == 0 || vp->vliny < p || (vp->vflags & VDIRT)) {
if (l == vcline)
strcLIN(temp);
else
getaline(dot[l - vcline]);
if (l != vcline && (vp->vflags & VDIRT)) {
vp->vdepth = vdepth();
vp->vflags &= ~VDIRT;
if (p + vp->vdepth - 1 > WBOT)
break;
}
(void) vreopen(p, lineDOT() + (l - vcline), l);
}
p = vp->vliny + vp->vdepth;
vp++;
l++;
} else
vclrlin(p, dot + (l - vcline)), p++;
}
strcLIN(temp);
hold = oldhold;
if (heldech)
vclrech(0);
}
void
vcloseup(int l, int cnt)
{
int i;
#ifdef ADEBUG
if (trace)
tfixnl(), fprintf(trace, "vcloseup(%d, %d)\n", l, cnt);
#endif
for (i = l + 1; i <= vcnt; i++)
LINE(i) -= cnt;
}
void
vreplace(int l, int cnt, int newcnt)
{
int from, to, i;
bool savenote = 0;
#ifdef ADEBUG
if (trace) {
tfixnl(), fprintf(trace, "vreplace(%d, %d, %d)\n", l, cnt, newcnt);
tvliny();
}
#endif
if (l >= vcnt)
return;
if (l < 0) {
if (l + cnt < 0) {
vcnt = 0;
return;
}
cnt += l;
l = 0;
savenote++;
}
if (cnt < 0)
cnt = 0;
if (newcnt < 0)
newcnt = 0;
if (cnt > value(vi_REPORT) || newcnt > value(vi_REPORT))
savenote++;
if (cnt == newcnt || vcnt - l == newcnt && insert_line && delete_line) {
if (cnt > 1 && l + cnt > vcnt)
savenote++;
vdirty(l, newcnt);
} else {
if (cnt > 0) {
if (cnt > 1 && l + cnt > vcnt)
savenote++;
if (l + cnt >= vcnt)
cnt = vcnt - l;
else
for (from = l + cnt, to = l; from <= vcnt; to++, from++)
vlcopy(vlinfo[to], vlinfo[from]);
vcnt -= cnt;
}
if (newcnt > 0) {
if (newcnt > 1 && l + newcnt > vcnt + 1)
savenote++;
if (l + newcnt > WBOT && insert_line && delete_line) {
vcnt = l;
goto skip;
}
from = vcnt, to = vcnt + newcnt;
i = TUBELINES - to;
if (i < 0)
from += i, to += i;
vcnt = to;
for (; from >= l; from--, to--)
vlcopy(vlinfo[to], vlinfo[from]);
for (from = to + 1, to = l; to < l + newcnt && to <= WBOT + 1; to++) {
LINE(to) = LINE(from);
DEPTH(to) = 0;
FLAGS(to) = VDIRT;
}
}
}
skip:
if (Pline == numbline && cnt != newcnt)
vdirty(l, WECHO);
if (!savenote)
notecnt = 0;
#ifdef ADEBUG
if (trace)
tvliny();
#endif
}
void
sethard(void)
{
if (state == VISUAL)
return;
rubble = 0;
state = HARDOPEN;
if (hold & HOLDROL)
return;
vup1();
LINE(0) = WBOT;
if (Pline == numbline)
vgoto(WBOT, 0), viprintf("%6d ", lineDOT());
}
void
vdirty(int base, int i)
{
int l;
for (l = base; l < vcnt; l++) {
if (--i < 0)
return;
FLAGS(l) |= VDIRT;
}
}