home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fred Fish Collection 1.5
/
ffcollection-1-5-1992-11.iso
/
ff_disks
/
100-199
/
ff197.lzh
/
Stevie
/
screen.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-03-28
|
12KB
|
509 lines
/*
* STEVIE - Simply Try this Editor for VI Enthusiasts
*
* Code Contributions By : Tim Thompson twitch!tjt
* Tony Andrews onecom!wldrdg!tony
* G. R. (Fred) Walter watmath!watcgl!grwalter
*/
#include "stevie.h"
/*
* The following variable is set (in cursupdate) to the number of physical
* lines taken by the line the cursor is on. We use this to avoid extra calls
* to plines(). The optimized routines updateline() and redrawline()
* make sure that the size of the cursor line hasn't changed. If so, lines below
* the cursor will move up or down and we need to call the routines
* updateNextscreen() and updateRealscreen() to examine the entire screen.
*/
static int Cline_size; /* size (in rows) of the cursor line */
static int Cline_row; /* starting row of the cursor line */
/*
* updateline() - like updateNextscreen() but only for cursor line
*
* This determines whether or not we need to call updateNextscreen() to examine
* the entire screen for changes. This occurs if the size of the cursor line
* (in rows) hasn't changed.
*/
void
updateline()
{
register int row;
register int col;
register char *screenp;
register char c;
LPtr memp;
register char *nextrow;
char extra[16];
char *p_extra;
int n_extra;
int n;
bool_t eof;
int lno; /* number of the line we're doing */
int coff; /* column offset */
MustRedrawLine = TRUE;
coff = P(P_NU) ? 8 : 0;
/*
* This should be done more efficiently.
*/
if (P(P_NU))
lno = cntllines(Filemem, Curschar);
screenp = Nextscreen + (Cline_row * Columns);
memp = *Curschar;
memp.index = 0;
eof = FALSE;
col = 0;
row = Cline_row;
p_extra = NULL;
n_extra = 0;
if (P(P_NU)) {
strcpy(extra, mkline(lno));
p_extra = extra;
n_extra = 8;
}
while (!eof) {
/* Get the next character to put on the screen. */
/*
* The 'extra' array contains the extra stuff that is inserted to
* represent special characters (tabs, and other non-printable stuff.
* The order in the 'extra' array is reversed.
*/
if (n_extra > 0) {
c = *p_extra++;
n_extra--;
} else {
c = gchar(&memp);
if (inc(&memp) == -1)
eof = TRUE;
/*
* when getting a character from the file, we may have to turn it
* into something else on the way to putting it into
* 'Nextscreen'.
*/
if (c == TAB && !P(P_LS)) {
strcpy(extra, " ");
p_extra = extra;
/* tab amount depends on current column */
n_extra = ((P(P_TS) - 1) - (col - coff) % P(P_TS));
c = ' ';
} else if (c == NUL && P(P_LS)) {
extra[0] = NUL;
p_extra = extra;
n_extra = 1;
c = '$';
} else if (c != NUL && (n = chars[c].ch_size) > 1) {
p_extra = chars[c].ch_str;
c = *p_extra++;
n_extra = n - 1;
}
}
if (c == NUL) {
row++;
/* get pointer to start of next row */
nextrow = Nextscreen + (row * Columns);
/* blank out the rest of this row */
while (screenp < nextrow)
*screenp++ = ' ';
break;
}
if (col >= Columns) {
row++;
col = 0;
}
/* store the character in Nextscreen */
*screenp++ = c;
col++;
}
if ((row - Cline_row) != Cline_size) {
updateNextscreen(VALID_TO_CURSCHAR);
}
}
/*
* redrawline
*
* Like updateRealscreen() but only for the cursor line.
*/
void
redrawline()
{
register char *np = Nextscreen + (Cline_row * Columns);
register char *rp = Realscreen + (Cline_row * Columns);
register char *endline;
register int row, col;
int gorow = -1, gocol = -1;
if (RedrawingDisabled)
return;
if (!MustRedrawLine && !MustRedrawScreen)
return;
if (MustRedrawScreen) {
msg("STEVIE internal error: redrawline called");
sleep(5);
}
endline = np + (Cline_size * Columns);
row = Cline_row;
col = 0;
outstr(T_CI); /* disable cursor */
for (; np < endline; np++, rp++) {
/* If desired screen (contents of Nextscreen) does not */
/* match what's really there, put it there. */
if (*np != *rp) {
/* if we are positioned at the right place, */
/* we don't have to use windgoto(). */
if (gocol != col || gorow != row) {
/*
* If we're just off by one, don't send an entire esc. seq.
* (this happens a lot!)
*/
if (gorow == row && gocol + 1 == col) {
outchar(*(np - 1));
gocol++;
} else
windgoto(gorow = row, gocol = col);
}
outchar(*rp = *np);
gocol++;
}
if (++col >= Columns) {
col = 0;
row++;
}
}
outstr(T_CV); /* enable cursor again */
MustRedrawScreen = FALSE;
}
/*
* prt_line() - print the given line
*/
void
prt_line(s)
char *s;
{
register int si = 0;
register int c;
register int col = 0;
char extra[16];
int n_extra = 0;
int n;
for (;;) {
if (n_extra > 0)
c = extra[--n_extra];
else {
c = s[si++];
if (c == TAB && !P(P_LS)) {
strcpy(extra, " ");
/* tab amount depends on current column */
n_extra = (P(P_TS) - 1) - col % P(P_TS);
c = ' ';
} else if (c == NUL && P(P_LS)) {
extra[0] = NUL;
n_extra = 1;
c = '$';
} else if (c != NUL && (n = chars[c].ch_size) > 1) {
char *p;
n_extra = 0;
p = chars[c].ch_str;
/* copy 'ch-str'ing into 'extra' in reverse */
while (n > 1)
extra[n_extra++] = p[--n];
c = p[0];
}
}
if (c == NUL)
break;
outchar(c);
col++;
}
}
void
screenclear()
{
register char *rp;
register char *np;
register char *end;
register int i;
outstr(T_ED); /* clear the display */
rp = Realscreen;
end = Realscreen + Rows * Columns;
np = Nextscreen;
/* blank out the stored screens */
while (rp != end)
*rp++ = *np++ = ' ';
/* clear screen info */
for (i = 0; i < Rows; i++) {
LinePointers[i] = NULL;
LineSizes[i] = '\0';
}
NumLineSizes = 0;
}
void
cursupdate()
{
LPtr *p;
LPtr *pp;
char c;
int incr, nlines;
int i;
int didincr;
if (bufempty()) { /* special case - file is empty */
*Topchar = *Filemem;
*Curschar = *Filemem;
for (i = 0; i < Rows; i++)
LineSizes[i] = 0;
} else if (LINEOF(Curschar) < LINEOF(Topchar)) {
nlines = cntllines(Curschar, Topchar);
/*
* if the cursor is above the top of the screen, put it at the top of
* the screen..
*/
*Topchar = *Curschar;
Topchar->index = 0;
/*
* ... and, if we weren't very close to begin with, we scroll so that
* the line is close to the middle.
*/
if (nlines > Rows / 3) {
p = Topchar;
for (i = 0; i < Rows / 3; i += plines(p)) {
pp = prevline(p);
if (pp == NULL)
break;
p = pp;
}
*Topchar = *p;
} else
s_ins(0, nlines - 1, Rows, Columns);
updateNextscreen(VALID);
} else if (LINEOF(Curschar) >= LINEOF(Botchar)) {
nlines = cntllines(Botchar, Curschar);
/*
* If the cursor is off the bottom of the screen, put it at the top
* of the screen.. ... and back up
*/
if (nlines > Rows / 3) {
p = Curschar;
for (i = 0; i < (2 * Rows) / 3; i += plines(p)) {
pp = prevline(p);
if (pp == NULL)
break;
p = pp;
}
*Topchar = *p;
} else {
scrollup(nlines);
}
updateNextscreen(VALID);
}
Cursrow = Curscol = Cursvcol = i = 0;
for (p = Topchar; p->linep != Curschar->linep; p = nextline(p))
Cursrow += LineSizes[i++];
if (P(P_NU))
Curscol = 8;
Cline_row = Cursrow;
if (i >= NumLineSizes) { /* Should only happen with a line that is too
* long to fit on the last screen line. */
Cline_size = 0;
} else {
Cline_size = LineSizes[i];
for (i = 0; i <= Curschar->index; i++) {
c = Curschar->linep->s[i];
/* A tab gets expanded, depending on the current column */
if (c == TAB && !P(P_LS))
incr = P(P_TS) - (Cursvcol % P(P_TS));
else
incr = chars[c].ch_size;
Curscol += incr;
Cursvcol += incr;
if (Curscol >= Columns) {
Curscol -= Columns;
Cursrow++;
didincr = TRUE;
} else
didincr = FALSE;
}
if (didincr)
Cursrow--;
if (c == TAB && State == NORMAL && !P(P_LS)) {
Curscol--;
Cursvcol--;
} else {
Curscol -= incr;
Cursvcol -= incr;
}
if (Curscol < 0)
Curscol += Columns;
}
if (set_want_col) {
Curswant = Cursvcol;
set_want_col = FALSE;
}
}
/*
* The rest of the routines in this file perform screen manipulations. The
* given operation is performed physically on the screen. The corresponding
* change is also made to the internal screen image. In this way, the editor
* anticipates the effect of editing changes on the appearance of the screen.
* That way, when we call screenupdate a complete redraw isn't usually
* necessary. Another advantage is that we can keep adding code to anticipate
* screen changes, and in the meantime, everything still works.
*/
/*
* s_ins(row, nlines, total_rows, columns) - insert 'nlines' lines at 'row'
*/
void
s_ins(row, nlines, total_rows, columns)
int row;
int nlines;
int total_rows;
int columns;
{
register char *s; /* src for block copy */
register char *d; /* dest for block copy */
register char *e; /* end point for copy */
int i;
if (nlines > (total_rows - 1 - row))
nlines = total_rows - 1 - row;
if ((T_IL[0] == NUL) || RedrawingDisabled || nlines <= 0)
return;
/*
* It "looks" better if we do all the inserts at once
*/
outstr(T_SC); /* save position */
if (T_IL_B[0] == NUL) {
for (i = 0; i < nlines; i++) {
windgoto(row, 0);
outstr(T_IL);
}
} else {
windgoto(row, 0);
outstr(T_IL);
if (nlines >= 10)
outchar((char) (nlines / 10 + '0'));
outchar((char) (nlines % 10 + '0'));
outstr(T_IL_B);
}
windgoto(total_rows - 1, 0); /* delete any garbage that may have */
outstr(T_EL); /* been shifted to the bottom line */
outstr(T_RC); /* restore the cursor position */
/*
* Now do a block move to update the internal screen image
*/
d = Realscreen + (columns * (total_rows - 1)) - 1;
s = d - (columns * nlines);
e = Realscreen + (columns * row);
while (s >= e)
*d-- = *s--;
/*
* Clear the inserted lines
*/
s = Realscreen + (row * columns);
e = s + (nlines * columns);
while (s < e)
*s++ = ' ';
}
/*
* s_del(row, nlines, total_rows, columns) - delete 'nlines' lines at 'row'
*/
void
s_del(row, nlines, total_rows, columns)
int row;
int nlines;
int total_rows;
int columns;
{
register char *s;
register char *d;
register char *e;
int i;
if (nlines > (total_rows - 1 - row))
nlines = total_rows - 1 - row;
if ((T_DL[0] == NUL) || RedrawingDisabled || nlines <= 0)
return;
outstr(T_SC); /* save position */
windgoto(total_rows - 1, 0); /* delete any garbage that */
outstr(T_EL); /* was on the status line */
/* delete the lines */
if (T_DL_B[0] == NUL) {
for (i = 0; i < nlines; i++) {
windgoto(row, 0);
outstr(T_DL); /* delete a line */
}
} else {
windgoto(row, 0);
outstr(T_DL);
if (nlines >= 10)
outchar((char) (nlines / 10 + '0'));
outchar((char) (nlines % 10 + '0'));
outstr(T_DL_B);
}
outstr(T_RC); /* restore position */
/*
* do a block move to update the internal image
*/
d = Realscreen + (row * columns);
s = d + (nlines * columns);
e = Realscreen + ((total_rows - 1) * columns);
while (s < e)
*d++ = *s++;
while (d < e) /* clear the lines at the bottom */
*d++ = ' ';
}