|
|
BSD 4.3
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
static char rcsid[] = "$Header: /var/lib/cvsd/repos/CSRG/43BSD/contrib/B/src/bed/scrn.c,v 1.1.1.1 2018/04/24 16:12:54 root Exp $";
/*
* B editor -- Screen management package, higher level routines.
*/
#include "b.h"
#include "erro.h"
#include "bobj.h"
#include "node.h"
#include "supr.h"
#include "gram.h"
#include "cell.h"
extern bool dflag;
cell *gettop();
extern int focy;
extern int focx;
Visible int winstart;
Visible int winheight;
Visible int indent;
Visible int llength;
Visible bool noscroll;
Visible bool nosense;
Hidden cell *tops;
/*
* Actual screen update.
*/
Visible Procedure
actupdate(copybuffer, recording, lasttime)
value copybuffer;
bool recording;
bool lasttime; /* Yes if called from final screen update */
{
register cell *p;
cell *top = tops;
register int diff;
register int curlno;
register int delcnt = 0; /* Lines deleted during the process. */
/* Used as offset for lines that are on the screen. */
int totlines = 0;
int topline = 0;
int scrlines = 0;
if (winstart > 0)
growwin();
if (winstart <= 0) {
top = gettop(tops);
for (p = tops; p && p != top; p = p->c_link)
++topline;
totlines = topline;
}
startactupdate(lasttime);
focy = Nowhere;
for (p = top, curlno = winstart; p && curlno < winheight;
curlno += Space(p), p = p->c_link) {
++scrlines;
if (lasttime) {
p->c_newfocus = No;
p->c_newvhole = 0;
}
if (p->c_onscreen != Nowhere && Space(p) == Oldspace(p)) {
/* Old comrade */
diff = p->c_onscreen - (curlno+delcnt);
/* diff can't be negative due to 'makeroom' below! */
if (diff > 0) { /* Get him here */
trmscrollup(curlno, winheight, diff);
delcnt += diff;
}
if (p->c_oldfocus || p->c_newfocus
|| p->c_oldindent != p->c_newindent
|| p->c_onscreen + Space(p) >= winheight) {
delcnt = make2room(p, curlno, delcnt);
outline(p, curlno);
}
}
else { /* New guy, make him toe the line */
delcnt = makeroom(p, curlno, delcnt);
delcnt = make2room(p, curlno, delcnt);
outline(p, curlno);
}
p->c_onscreen = curlno;
p->c_oldindent = p->c_newindent;
p->c_oldvhole = p->c_newvhole;
p->c_oldfocus = p->c_newfocus;
}
totlines += scrlines;
for (; p; p = p->c_link) { /* Count rest and remove old memories */
++totlines;
/* This code should never find any garbage?! */
#ifndef NDEBUG
if (p->c_onscreen != Nowhere)
debug("[Garbage removed from screen list]");
#endif NDEBUG
p->c_onscreen = Nowhere;
}
trmscrollup(curlno, winheight, -delcnt);
curlno += delcnt;
if (curlno < winheight) { /* Clear lines beyond end of unit */
trmputdata(curlno, winheight-1, 0, "");
scrlines += winheight-curlno;
}
if (!lasttime) {
stsline(totlines, topline, scrlines, copybuffer, recording);
if (focy != Nowhere)
trmsync(focy, focx);
else
trmsync(winheight, 0);
}
endactupdate();
}
/*
* Grow the window if not maximum size.
*/
Hidden Procedure
growwin()
{
register int winsize;
register int growth;
register cell *p;
winsize = 0;
for (p = tops; p; p = p->c_link)
winsize += Space(p);
if (winsize <= winheight - winstart)
return; /* No need to grow */
if (winsize > winheight)
winsize = winheight; /* Limit size to maximum available */
growth = winsize - (winheight - winstart);
trmscrollup(0, winheight - (winstart!=winheight), growth);
winstart -= growth;
for (p = tops; p; p = p->c_link) {
if (p->c_onscreen != Nowhere)
p->c_onscreen -= growth;
}
}
/*
* Make room for possible insertions.
* (If a line is inserted, it may be necessary to delete lines
* further on the screen.)
*/
Hidden Procedure
makeroom(p, curlno, delcnt)
register cell *p;
register int curlno;
register int delcnt;
{
register int here = 0;
register int need = Space(p);
register int amiss;
int avail;
int diff;
Assert(p);
do {
p = p->c_link;
if (!p)
return delcnt;
} while (p->c_onscreen == Nowhere);
here = p->c_onscreen - delcnt;
avail = here - curlno;
amiss = need - avail;
#ifndef NDEBUG
if (dflag)
debug("[makeroom: curlno=%d, delcnt=%d, here=%d, avail=%d, amiss=%d]",
curlno, delcnt, here, avail, amiss);
#endif NDEBUG
if (amiss <= 0)
return delcnt;
if (amiss > delcnt) {
for (; p; p = p->c_link) {
if (p->c_onscreen != Nowhere) {
diff = amiss-delcnt;
if (p->c_onscreen - delcnt - here < diff)
diff = p->c_onscreen - delcnt - here;
if (diff > 0) {
trmscrollup(here, winheight, diff);
delcnt += diff;
}
p->c_onscreen += -delcnt + amiss;
here = p->c_onscreen - amiss;
if (p->c_onscreen >= winheight)
p->c_onscreen = Nowhere;
}
here += Space(p);
}
/* Now for all p encountered whose p->c_onscreen != Nowhere,
/* p->c_onscreen - amiss is its actual position. */
if (amiss > delcnt) {
trmscrollup(winheight - amiss, winheight, amiss-delcnt);
delcnt = amiss;
}
}
/* Now amiss <= delcnt */
trmscrollup(curlno + avail, winheight, -amiss);
return delcnt - amiss;
}
/*
* Addition to makeroom - make sure the status line is not overwritten.
* Returns new delcnt, like makeroom does.
*/
Hidden int
make2room(p, curlno, delcnt)
cell *p;
int curlno;
int delcnt;
{
int nextline = curlno + Space(p);
int sline = winheight - delcnt;
int diff;
if (sline < curlno) {
#ifndef NDEBUG
debug("[Status line overwritten]");
#endif NDEBUG
return delcnt;
}
if (nextline > winheight)
nextline = winheight;
diff = nextline - sline;
if (diff > 0) {
trmscrollup(sline, winheight, -diff);
delcnt -= diff;
}
return delcnt;
}
/*
* Routine called for every change in the screen.
*/
Visible Procedure
virtupdate(oldep, newep, highest)
environ *oldep;
environ *newep;
int highest;
{
environ old;
environ new;
register int oldlno;
register int newlno;
register int oldlcnt;
register int newlcnt;
register int i;
if (!oldep) {
highest = 1;
trmputdata(winstart, winheight, indent, "");
discard(tops);
tops = Cnil;
Ecopy(*newep, old);
}
else {
Ecopy(*oldep, old);
}
Ecopy(*newep, new);
savefocus(&new);
oldlcnt = fixlevels(&old, &new, highest);
newlcnt = -width(tree(new.focus));
if (newlcnt < 0)
newlcnt = 0;
i = -width(tree(old.focus));
if (i < 0)
i = 0;
newlcnt -= i - oldlcnt;
/* Offset newlcnt as much as oldcnt is offset */
oldlno = Ycoord(old.focus);
newlno = Ycoord(new.focus);
if (!atlinestart(&old))
++oldlcnt;
else
++oldlno;
if (!atlinestart(&new))
++newlcnt;
else
++newlno;
Assert(oldlno == newlno);
tops = replist(tops, build(new.focus, newlcnt), oldlno, oldlcnt);
setfocus(tops); /* Incorporate the information saved by savefocus */
Erelease(old);
Erelease(new);
}
Hidden bool
atlinestart(ep)
environ *ep;
{
register string repr = noderepr(tree(ep->focus))[0];
return Fw_negative(repr);
}
/*
* Make the two levels the same, and make sure they both are line starters
* if at all possible. Return the OLD number of lines to be replaced.
* (0 if the whole unit has no linefeeds.)
*/
Hidden int
fixlevels(oldep, newep, highest)
register environ *oldep;
register environ *newep;
register int highest;
{
register int oldpl = pathlength(oldep->focus);
register int newpl = pathlength(newep->focus);
register bool intraline = No;
register int w;
if (oldpl < highest)
highest = oldpl;
if (newpl < highest)
highest = newpl;
while (oldpl > highest) {
up(&oldep->focus) || Abort();
--oldpl;
}
while (newpl > highest) {
up(&newep->focus) || Abort();
--newpl;
}
if (Ycoord(newep->focus) != Ycoord(oldep->focus) ||
Level(newep->focus) != Level(newep->focus)) {
/* Inconsistency found. */
Assert(highest > 1); /* Inconsistency at top level. Stop. */
return fixlevels(oldep, newep, 1); /* Try to recover. */
}
intraline = width(tree(oldep->focus)) >= 0
&& width(tree(newep->focus)) >= 0;
while (!atlinestart(oldep) || !atlinestart(newep)) {
/* Find beginning of lines for both */
if (!up(&newep->focus)) {
Assert(!up(&newep->focus));
break;
}
--oldpl;
up(&oldep->focus) || Abort();
--newpl;
}
if (intraline)
return atlinestart(oldep);
w = width(tree(oldep->focus));
return w < 0 ? -w : 0;
}
/*
* Initialization code.
*/
Visible Procedure
initshow()
{
int flags = 0;
#ifndef NDEBUG
if (dflag)
fprintf(stderr, "*** initshow();\n\r");
#endif NDEBUG
if (!trmstart(&winheight, &llength, &flags)) {
endunix();
exit(2);
}
noscroll = (flags&2) == 0;
nosense = (flags&8) == 0;
winstart = --winheight;
}
/*
* Routine to move the cursor to the first line after the just edited
* document. (Called after each editing action.)
*/
Visible Procedure
endshow()
{
register cell *p;
register int last = winheight;
for (p = tops; p; p = p->c_link) {
if (p->c_onscreen != Nowhere)
last = p->c_onscreen + Oldspace(p);
}
if (last > winheight)
last = winheight;
discard(tops);
tops = Cnil;
trmputdata(last, winheight, 0, "");
trmsync(last, 0);
trmend();
}
/*
* Translate a cursor position in tree coordinates.
*
* ***** DOESN'T WORK IF SCREEN INDENT DIFFERS FROM TREE INDENT! *****
* (I.e. for lines with >= 80 spaces indentation)
*/
Visible bool
backtranslate(py, px)
int *py;
int *px;
{
cell *p;
int y = *py;
int x = *px;
int i;
for (i = 0, p = tops; p; ++i, p = p->c_link) {
if (p->c_onscreen != Nowhere
&& y >= p->c_onscreen && y < p->c_onscreen + Space(p)) {
*px += (y - p->c_onscreen) * llength - indent;
if (*px < 0)
*px = 0;
*py = i;
if (p->c_oldvhole && (y > focy || y == focy && x > focx))
--*px; /* Correction if beyond Vhole on same logical line */
return Yes;
}
}
error(GOTO_OUT);
return No;
}
/*
* Set the indent level and window start line.
*/
Visible Procedure
setindent(x)
int x;
{
winstart= winheight;
indent= x;
}
/*
* Show the command prompt.
*/
Visible Procedure cmdprompt(prompt)
string prompt;
{
setindent(strlen(prompt));
trmputdata(winstart, winstart, 0, prompt);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.