mirror of
https://github.com/PDP-10/stacken.git
synced 2026-02-28 17:09:15 +00:00
1776 lines
50 KiB
ObjectPascal
1776 lines
50 KiB
ObjectPascal
(* AMIS screen handler. *) (* -*- PASCAL -*- *)
|
|
|
|
(****************************************************************************)
|
|
(* *)
|
|
(* Copyright (C) 1980, 1981, 1982, 1983, 1984, 1985, 1986, 1987 by *)
|
|
(* Stacken, Royal Institute Of Technology, Stockholm, Sweden. *)
|
|
(* All rights reserved. *)
|
|
(* *)
|
|
(* This software is furnished under a license and may be used and copied *)
|
|
(* only in accordance with the terms of such license and with the *)
|
|
(* inclusion of the above copyright notice. This software or any other *)
|
|
(* copies thereof may not be provided or otherwise made available to any *)
|
|
(* other person. No title to and ownership of the software is hereby *)
|
|
(* transferred. *)
|
|
(* *)
|
|
(* The information in this software is subject to change without notice *)
|
|
(* and should not be construed as a commitment by Stacken. *)
|
|
(* *)
|
|
(* Stacken assumes no responsibility for the use or reliability of its *)
|
|
(* software on equipment which is not supported by Stacken. *)
|
|
(* *)
|
|
(****************************************************************************)
|
|
|
|
(*$E+*)(*$T-*)
|
|
|
|
(**********************************************************************)
|
|
(* Module SCREEN of AMIS *)
|
|
(* *)
|
|
(* This module is responsible for the screen that shows a section of *)
|
|
(* the buffer, the mode area and the echo area. *)
|
|
(* *)
|
|
(* Author: Anders Str|m *)
|
|
(* *)
|
|
(* Last update: 1982-01-26 /AS *)
|
|
(* *)
|
|
(**********************************************************************)
|
|
|
|
module screen;
|
|
|
|
const
|
|
CtrlAtSign = 0; CtrlA = 1; CtrlB = 2;
|
|
CtrlC = 3; CtrlD = 4; CtrlE = 5;
|
|
CtrlF = 6; CtrlG = 7; CtrlH = 8;
|
|
CtrlI = 9; CtrlJ = 10; CtrlK = 11;
|
|
CtrlL = 12; CtrlM = 13; CtrlN = 14;
|
|
CtrlO = 15; CtrlP = 16; CtrlQ = 17;
|
|
CtrlR = 18; CtrlS = 19; CtrlT = 20;
|
|
CtrlU = 21; CtrlV = 22; CtrlW = 23;
|
|
CtrlX = 24; CtrlY = 25; CtrlZ = 26;
|
|
CtrlLeftBracket = 27; CtrlBackSlash = 28; CtrlRightBracket = 29;
|
|
CtrlUpArrow = 30; CtrlUnderScore = 31; RubOut = 127;
|
|
|
|
Null = CtrlAtSign; Bell = CtrlG; BackSpace = CtrlH;
|
|
HorizontalTab = CtrlI; LineFeed = CtrlJ; FormFeed = CtrlL;
|
|
CarriageReturn = CtrlM; Escape = CtrlLeftBracket;
|
|
|
|
HelpChar = CtrlUnderScore;
|
|
|
|
strsize= 40;
|
|
|
|
maxwidth= 132;
|
|
maxheight= 72;
|
|
modemaxheight= 1;
|
|
echomaxheight= 1;
|
|
pcntwidth= 9;
|
|
|
|
rrbeg= 0;
|
|
|
|
type
|
|
string= packed array[1..strsize] of char;
|
|
bufpos= integer;
|
|
charset = set of char;
|
|
|
|
states= (newline, oldline, control, noline);
|
|
linetext= packed array [0..maxwidth] of char;
|
|
(* Window line status *)
|
|
line= record
|
|
show: linetext; showlen: integer; showpos: bufpos;
|
|
updated: boolean;
|
|
end;
|
|
lstate= record
|
|
bfpos: bufpos; state: states;
|
|
end;
|
|
statearr= array [0..maxheight] of lstate;
|
|
(* Status for percent field *)
|
|
pcmode= record
|
|
mode: (bad, none, top, bot, pcent);
|
|
val: integer;
|
|
modif: boolean;
|
|
end;
|
|
|
|
CharImage = packed array [1..4] of char; (* What a character looks like. *)
|
|
|
|
bmodes= (ok, pos, nopos);
|
|
|
|
var
|
|
lines: array [0..maxheight] of line;
|
|
curstate: statearr;
|
|
(* Flag indicating vlidity of curstate *)
|
|
(* OK - is OK, but changes might have happend *)
|
|
(* pos - the position of winstart might be good *)
|
|
(* nopos - need a wrepos followed by a build *)
|
|
built: bmodes;
|
|
|
|
(* Current size of screen *)
|
|
screenheight, screenwidth: integer;
|
|
|
|
(* Flag indicating that entire screen is blank *)
|
|
csflg: boolean;
|
|
(* Flag indicating that we should do a refresh *)
|
|
dorefresh: boolean;
|
|
|
|
(* Mark of where changes have occured *)
|
|
first, last, count: bufpos;
|
|
|
|
(* Total height of window *)
|
|
winheight: integer;
|
|
(* Top and bottom of selected window *)
|
|
winfirst, winlast: integer;
|
|
|
|
(* What we show in the window *)
|
|
winstart, winend: bufpos;
|
|
(* Current position in window *)
|
|
hpos, vpos: integer; knownpos: boolean;
|
|
(* Flag indicating that we may have simple case of updating *)
|
|
simplep, noprelude: boolean; scount, spos: integer;
|
|
|
|
(* Information about two window mode *)
|
|
splitline: integer; (* Where to split window *)
|
|
nwins: integer; (* Number of window *)
|
|
curwin: integer; (* Current window (base 1) *)
|
|
new_window, new_buffer: integer;
|
|
xwinstart, xwinend, xdot: array [1..2] of bufpos;
|
|
xbuilt: array [1..2] of bmodes;
|
|
xok: array [1..2] of boolean;
|
|
(* Currently selected buffer, and shown buffer *)
|
|
curbuffer, showbuffer: array [1..2] of integer;
|
|
|
|
(* Buffer values, as we know them *)
|
|
rrdot, rrz: bufpos;
|
|
|
|
modelines: array [0..modemaxheight] of linetext;
|
|
(* Current top and height of mode area *)
|
|
modetop, modeheight: integer;
|
|
(* Current position in mode area *)
|
|
moderow, modecol: integer;
|
|
|
|
echolines: array [0..echomaxheight] of linetext;
|
|
(* Current top and height of echo area *)
|
|
echotop, echoheight: integer;
|
|
(* Current position in echo area *)
|
|
echorow, echocol: integer;
|
|
|
|
(* Data for mode line clock *)
|
|
ClockIsOn: boolean; (* Knows if the clock is on or not *)
|
|
ClockRow, ClockCol: integer; (* Knows where in mode line clock is *)
|
|
|
|
(* Percent field status *)
|
|
pcfld: pcmode;
|
|
(* Overwrite variables *)
|
|
orow, ocol: integer;
|
|
ovmode, ovflush: boolean;
|
|
|
|
(* Cost for different operations, used to select an optimal *)
|
|
(* update strategy, wrt these cost. The reference for costs *)
|
|
(* are the cost of outputting one character, which costs 1. *)
|
|
linecost: integer; (* Cost for updating one line *)
|
|
scrollcost: integer; (* Cost for scrolling one line *)
|
|
idcharcost: integer; (* Cost for inserting or deleting one character *)
|
|
|
|
(* Flags telling what terminal features we can use. *)
|
|
xyflag : boolean; (* We have Direct Cursor Adressing. *)
|
|
eolflag : boolean; (* We have Erase to End Of Line. *)
|
|
scrflag : boolean; (* We have Region Scroll. *)
|
|
|
|
printable : set of char; (* What chars are printable. *)
|
|
|
|
chrview : array [char] of CharImage;
|
|
chrvlen : array [char] of 0..4;
|
|
|
|
EolFirst : char; (* First char of EOL. *)
|
|
EolLineFeed : boolean; (* TRUE if single Line Feed is EOL too. *)
|
|
|
|
blanktext, messedtext: linetext;
|
|
|
|
(****************************************)
|
|
(* *)
|
|
(* External procedures used *)
|
|
(* *)
|
|
(****************************************)
|
|
|
|
(* Module TTYIO *)
|
|
|
|
procedure ttyforce; external;
|
|
procedure bug(n: string); external;
|
|
procedure GetClock(var Hours, Minutes: integer); external;
|
|
|
|
(* Module BUFFER *)
|
|
|
|
function getdot: bufpos; external;
|
|
procedure setdot(pt: bufpos); external;
|
|
function getsize: bufpos; external;
|
|
function bgetchar(i: bufpos): char; external;
|
|
function getmodified: boolean; external;
|
|
function getlines(i: bufpos): bufpos; external;
|
|
procedure isetbuf(n: integer); external;
|
|
function ateol(i: bufpos; d: integer): boolean; external;
|
|
function eolsize: integer; external;
|
|
procedure EolString(var s: string; var i: integer); external;
|
|
|
|
(* Module TERM *)
|
|
|
|
procedure TrmSize(var rows, col: integer); external;
|
|
procedure TrmFeatures(var xyflag, eolflag, scrflag: boolean); external;
|
|
procedure TrmPrintable(var printable: charset); external;
|
|
procedure trmpos(row, col: integer); external;
|
|
procedure trmeol; external;
|
|
procedure trmout(c: char); external;
|
|
procedure trmscr(y1, y2, n: integer); external;
|
|
procedure trmclr; external;
|
|
procedure trminv; external;
|
|
procedure trmniv; external;
|
|
procedure trmich(c: char); external;
|
|
procedure trmdch; external;
|
|
procedure trmcst(var scrollcost, idcharcost: integer); external;
|
|
procedure TrmWhere(var row, col: integer); external;
|
|
|
|
(* Module INPUT *)
|
|
|
|
function kbdrunning: boolean; external;
|
|
function readc: char; external;
|
|
function check(t: integer): boolean; external;
|
|
procedure reread; external;
|
|
|
|
(* Module UTILITY *)
|
|
|
|
function StrLength(var Str: string): integer; external;
|
|
|
|
(****************************************)
|
|
(* *)
|
|
(* Utilities in this module *)
|
|
(* *)
|
|
(****************************************)
|
|
|
|
|
|
procedure markmessed(i: integer);
|
|
begin
|
|
with lines[i] do begin
|
|
show:= messedtext; showlen:= screenwidth;
|
|
updated:= false;
|
|
end;
|
|
end;
|
|
|
|
procedure markblank(i: integer);
|
|
begin
|
|
with lines[i] do begin
|
|
showpos:= -1; show:= blanktext;
|
|
showlen:= 0; updated:= false;
|
|
end;
|
|
end;
|
|
|
|
(**** STARTOFLINE ****)
|
|
function startofline(p: bufpos): bufpos;
|
|
(* Find where the line containing p starts. *)
|
|
(* If the line is more than a screenful, just get a pointer about *)
|
|
(* a screen backwards *)
|
|
label 1;
|
|
var stop: integer;
|
|
begin (* startofline *)
|
|
stop:= p-winheight*screenwidth;
|
|
if stop<rrbeg then stop:= rrbeg;
|
|
while p>stop do begin
|
|
if ateol(p, -1) then goto 1;
|
|
p:= p-1;
|
|
end;
|
|
1:
|
|
startofline:= p;
|
|
end (* startofline *);
|
|
|
|
(**** WDOWNLINES ****)
|
|
function wdownlines(pt: bufpos; n: integer): bufpos;
|
|
(* Starting at pt move n screen lines down, returning new position *)
|
|
label 1;
|
|
var h: integer; ch: char;
|
|
begin (* wdownlines *)
|
|
h:= 0;
|
|
if n<=0 then goto 1;
|
|
while pt<rrz do begin
|
|
ch:= bgetchar(pt);
|
|
if EolLineFeed and (ch=chr(LineFeed)) then begin
|
|
pt:= pt+1; h:= 0; n:= n-1;
|
|
if n<=0 then goto 1;
|
|
end else if ateol(pt, 1) then begin
|
|
pt:= pt+eolsize; h:= 0; n:= n-1;
|
|
if n<=0 then goto 1;
|
|
end else begin
|
|
if h>=(screenwidth-1) then begin
|
|
h:= 0; n:= n-1;
|
|
if n<=0 then goto 1;
|
|
end;
|
|
if ch in printable then begin
|
|
h:= h+1;
|
|
end else if ch=chr(HorizontalTab) then begin
|
|
h:= (h div 8)*8+8;
|
|
if h>=screenwidth then begin
|
|
h:= 0; n:= n-1;
|
|
if n<=0 then goto 1;
|
|
end;
|
|
end else if ch=chr(Escape) then begin
|
|
h:= h+1;
|
|
end else begin
|
|
h:= h+2;
|
|
if h>=screenwidth then begin
|
|
h:= h-screenwidth+1; n:= n-1;
|
|
if n<=0 then goto 1;
|
|
end;
|
|
end;
|
|
pt:= pt+1;
|
|
end;
|
|
end;
|
|
1:
|
|
wdownlines:= pt;
|
|
end (* wdownlines *);
|
|
|
|
(**** WNLINES ****)
|
|
function wnlines(pt: bufpos): integer;
|
|
(* computes number of window lines a text line needs *)
|
|
(* starting at pt *)
|
|
label 1;
|
|
var h, v: integer; ch: char;
|
|
begin (* wnlines *)
|
|
h:= 0; v:= 1;
|
|
while pt<rrz do begin
|
|
ch:= bgetchar(pt);
|
|
if EolLineFeed then begin
|
|
if ch = chr(LineFeed) then goto 1;
|
|
end;
|
|
if ch = EolFirst then begin
|
|
if ateol(pt, 1) then goto 1;
|
|
end;
|
|
if h>=(screenwidth-1) then begin
|
|
h:= 0; v:= v+1;
|
|
end;
|
|
if ch in printable then begin
|
|
h:= h+1;
|
|
end else if ch=chr(HorizontalTab) then begin
|
|
h:= (h div 8)*8+8;
|
|
if h>=screenwidth then begin
|
|
h:= 0; v:= v+1;
|
|
end;
|
|
end else if ch=chr(Escape) then begin
|
|
h:= h+1;
|
|
end else begin
|
|
h:= h+2;
|
|
if h>=screenwidth then begin
|
|
h:= h-screenwidth+1; v:= v+1;
|
|
end;
|
|
end;
|
|
pt:= pt+1;
|
|
end;
|
|
1:
|
|
wnlines:= v;
|
|
end (* wnlines *);
|
|
|
|
(**** WXNLINES ****)
|
|
function wxnlines(pt, pe: bufpos): integer;
|
|
(* computes number of window lines needed for a text line, *)
|
|
(* from pt to pe *)
|
|
var h, v: integer; ch: char;
|
|
begin (* wxnlines *)
|
|
h:= 0; v:= 1;
|
|
for pt:= pt to pe-1 do begin
|
|
ch:= bgetchar(pt);
|
|
if (h+1)>=screenwidth then begin
|
|
h:= h-screenwidth+1; v:= v+1;
|
|
end;
|
|
if ch in printable then begin
|
|
h:= h+1;
|
|
end else if ch=chr(HorizontalTab) then begin
|
|
h:= (h div 8)*8+8;
|
|
if h>=screenwidth then begin
|
|
h:= 0; v:= v+1;
|
|
end;
|
|
end else if ch=chr(Escape) then begin
|
|
h:= h+1;
|
|
end else begin
|
|
h:= h+2;
|
|
if h>=screenwidth then begin
|
|
h:= h-screenwidth+1; v:= v+1;
|
|
end;
|
|
end;
|
|
end;
|
|
wxnlines:= v;
|
|
end (* wxnlines *);
|
|
|
|
(**** WUPLINES ****)
|
|
function wuplines(pt: bufpos; n: integer): integer;
|
|
(* Starting at pt move n screen-lines up, returning new position *)
|
|
var p: bufpos;
|
|
begin (* wuplines *)
|
|
p:= startofline(pt);
|
|
n:= n+1-wxnlines(p, pt);
|
|
while (p>rrbeg) and (n>0) do begin
|
|
p:= startofline(p-2); n:= n-wnlines(p);
|
|
end;
|
|
if n<0 then p:= wdownlines(p, -n);
|
|
wuplines:= p;
|
|
end (* wuplines *);
|
|
|
|
(**** WREPOS ****)
|
|
procedure wrepos(goalline: integer);
|
|
(* Reposition the window, gives new value to WINSTART *)
|
|
begin (* wrepos *)
|
|
winstart:= wuplines(rrdot, goalline-winfirst);
|
|
built:= pos;
|
|
end (* wrepos *);
|
|
|
|
(**** BUILDLINE ****)
|
|
procedure buildline(v: integer);
|
|
label 1;
|
|
var ch: char; h: integer; sflg: states; pt: bufpos;
|
|
begin (* buildline *)
|
|
with curstate[v] do begin
|
|
sflg:= state; pt:= bfpos;
|
|
end;
|
|
h:= 0; if sflg=control then h:= 1;
|
|
while true do begin
|
|
(* loop over characters *)
|
|
if pt=rrdot then begin
|
|
hpos:= h; vpos:= v; knownpos:= true;
|
|
end;
|
|
if pt>=rrz then begin
|
|
pt:= rrz+1; sflg:= noline; goto 1;
|
|
end;
|
|
ch:= bgetchar(pt);
|
|
if EolLineFeed then begin
|
|
if ch = chr(LineFeed) then begin
|
|
pt:= pt+1; sflg:= newline; goto 1;
|
|
end;
|
|
end;
|
|
if ch = EolFirst then begin
|
|
if ateol(pt, 1) then begin
|
|
pt:= pt+eolsize; sflg:= newline; goto 1;
|
|
end;
|
|
end;
|
|
if h=(screenwidth-1) then begin
|
|
sflg:= oldline; goto 1;
|
|
end else if ch in printable then begin
|
|
h:= h+1; pt:= pt+1;
|
|
end else if ch=chr(HorizontalTab) then begin
|
|
h:= (h div 8)*8+8; pt:=pt+1;
|
|
if h>=screenwidth then begin
|
|
sflg:= oldline; goto 1;
|
|
end;
|
|
end else if ch=chr(Escape) then begin
|
|
h:= h+1; pt:= pt+1;
|
|
end else begin
|
|
h:= h+2; pt:= pt+1;
|
|
if h>=screenwidth then begin
|
|
sflg:= control; goto 1;
|
|
end;
|
|
end;
|
|
end (* WHILE loop over characters*);
|
|
1:
|
|
with curstate[v+1] do begin
|
|
state:= sflg; bfpos:= pt;
|
|
end;
|
|
if v=winlast then winend:= pt-1;
|
|
lines[v].updated:= false;
|
|
end (* buildline *);
|
|
|
|
(**** WBUILD ****)
|
|
procedure wbuild;
|
|
var i: integer;
|
|
begin (* wbuild *)
|
|
knownpos:= false;
|
|
with curstate[winfirst] do begin
|
|
bfpos:= winstart; state:= newline;
|
|
end;
|
|
for i:= winfirst to winlast do buildline(i);
|
|
built:= ok;
|
|
end (* wbuild *);
|
|
|
|
(**** TryScroll ****)
|
|
procedure tryscroll(v: integer);
|
|
(* Try to get things better by scrolling *)
|
|
label 1, 9;
|
|
var v0, i: integer; pt: bufpos;
|
|
begin (* tryscroll *)
|
|
(* 1. If we are at end of buffer, do nothing *)
|
|
(* 2. Try scrolling up or down *)
|
|
pt:= curstate[v].bfpos; if pt>=rrz then goto 9;
|
|
if v>winlast then goto 9;
|
|
for v0:= winfirst to winlast do begin
|
|
if lines[v0].showpos=pt then goto 1;
|
|
end;
|
|
v0:= v;
|
|
pt:= lines[v0].showpos; if pt>=rrz then goto 9;
|
|
for v:= winfirst to winlast do begin
|
|
if curstate[v].bfpos=pt then goto 1;
|
|
end;
|
|
goto 9;
|
|
1:
|
|
if v0>v then begin (* Scroll up *)
|
|
if (v0-v)*scrollcost>(winlast+1-v0)*linecost then goto 9;
|
|
trmscr(v, winlast, v0-v);
|
|
for i:= v to winlast+v-v0 do begin
|
|
lines[i]:= lines[i+v0-v];
|
|
lines[i].updated:= false;
|
|
end;
|
|
for i:= winlast+1+v-v0 to winlast do markblank(i);
|
|
end else if v0<v then begin (* Scroll down *)
|
|
if (v-v0)*scrollcost>(winlast+1-v)*linecost then goto 9;
|
|
trmscr(v0, winlast, v0-v);
|
|
for i:= winlast downto v do begin
|
|
with lines[i] do begin
|
|
showpos:= lines[i+v0-v].showpos;
|
|
show:= lines[i+v0-v].show;
|
|
showlen:= lines[i+v0-v].showlen;
|
|
updated:= false;
|
|
end;
|
|
end;
|
|
for i:= v0 to v-1 do markblank(i);
|
|
end;
|
|
9:
|
|
end (* tryscroll *);
|
|
|
|
(**** PARTBUILD ****)
|
|
procedure partbuild;
|
|
label 1, 2, 3, 9;
|
|
var
|
|
v, v1, v2: integer; bp: bufpos;
|
|
oldstate: statearr;
|
|
begin
|
|
(* Copy curstate to oldstate, updating values *)
|
|
(* to use new buffer positons. *)
|
|
for v:= winfirst to winlast+1 do begin
|
|
oldstate[v].state:= curstate[v].state;
|
|
bp:= curstate[v].bfpos;
|
|
if bp>=first then begin
|
|
bp:= bp+count;
|
|
if bp<last then bp:= -1
|
|
end;
|
|
oldstate[v].bfpos:= bp;
|
|
end;
|
|
(* Find first line after first change *)
|
|
for v1:= winfirst+1 to winlast+1 do begin
|
|
if curstate[v1].bfpos>=first then goto 1;
|
|
(* The predicate:
|
|
(bfpos>first) or ((bfpos=first) and (state<>newline))
|
|
gives a cheaper computation below, but more cost for
|
|
the predicate. *)
|
|
end;
|
|
(* Change is entirely after window. *)
|
|
goto 9;
|
|
1:
|
|
if curstate[v1].bfpos>first then begin
|
|
v1:= v1-1;
|
|
end else if curstate[v1].state<>newline then begin
|
|
v1:= v1-1;
|
|
end;
|
|
(* Build lines past last change *)
|
|
for v2:= v1 to winlast do begin
|
|
with curstate[v2] do begin
|
|
if bfpos>=last then begin
|
|
if (state=newline) or (state=noline) then goto 2;
|
|
end;
|
|
end;
|
|
buildline(v2);
|
|
end;
|
|
(* Change extends after window. *)
|
|
goto 9;
|
|
2:
|
|
(* Test if rest of window can be left as it is. *)
|
|
if ((curstate[v2].bfpos = oldstate[v2].bfpos) and
|
|
(curstate[v2].state = oldstate[v2].state)) then begin
|
|
for v:= v2+1 to winlast+1 do curstate[v]:= oldstate[v];
|
|
goto 9;
|
|
end;
|
|
(* Could not, thats bad. Try find how much it changed. *)
|
|
for v:= v1 to winlast+1 do begin
|
|
if ((curstate[v2].bfpos = oldstate[v].bfpos) and
|
|
(curstate[v2].state = oldstate[v].state)) then goto 3;
|
|
end;
|
|
(* Could not find any match, try our last chance *)
|
|
(* Maybe position after last wasn't start of a line before *)
|
|
if curstate[v2].bfpos=last then begin
|
|
buildline(v2); v2:= v2+1; goto 2;
|
|
end;
|
|
(* do it really hard. *)
|
|
for v2:= v2 to winlast+1 do buildline(v2);
|
|
goto 9;
|
|
3:
|
|
(* Screen is shifted. *)
|
|
v1:= v-v2;
|
|
if v1>0 then begin
|
|
(* Shifted up, so shift information up. *)
|
|
for v:= v2 to winlast+1-v1 do begin
|
|
curstate[v]:= oldstate[v+v1];
|
|
lines[v].updated:= false;
|
|
end;
|
|
(* Then build rest of window the hard way. *)
|
|
for v:= winlast+1-v1 to winlast do buildline(v);
|
|
end else begin
|
|
(* Shifted down, so shift information down. *)
|
|
for v:= v2 to winlast+1 do begin
|
|
curstate[v]:= oldstate[v+v1];
|
|
lines[v].updated:= false;
|
|
end;
|
|
end;
|
|
if scrflag then tryscroll(v2);
|
|
9:
|
|
(* Window end might have moved. *)
|
|
winend:= curstate[winlast+1].bfpos-1;
|
|
end (* partbuild *);
|
|
|
|
(**** UPDATELINE ****)
|
|
procedure updateline(v: integer; var newline: linetext);
|
|
label 1;
|
|
var
|
|
len, h, hmax: integer; ch, ch0, ch1: char;
|
|
|
|
begin (* updateline *)
|
|
len:= 0;
|
|
for h:= 0 to screenwidth-1 do if newline[h] <> ' ' then len:= h+1;
|
|
hmax:= -1; ch0:= ' '; ch1:= ' ';
|
|
with lines[v] do begin
|
|
if xyflag then begin
|
|
for h:=0 to len-1 do begin
|
|
ch:= newline[h];
|
|
if ch<>show[h] then begin
|
|
if (hmax=-1) or (h-hmax>3) then begin
|
|
trmpos(v, h);
|
|
end else begin
|
|
if (h-hmax)>2 then trmout(ch1);
|
|
if (h-hmax)>1 then trmout(ch0);
|
|
end;
|
|
trmout(ch); hmax:= h;
|
|
end;
|
|
ch1:= ch0; ch0:= ch;
|
|
end;
|
|
end else begin
|
|
h:= 0;
|
|
while newline[h]=show[h] do begin
|
|
h:= h+1; if h>=len then goto 1;
|
|
end;
|
|
trmpos(v, h);
|
|
for h:= h to len-1 do trmout(newline[h]);
|
|
end;
|
|
1:
|
|
if len<showlen then begin
|
|
trmpos(v, len);
|
|
if eolflag then begin
|
|
trmeol;
|
|
end else begin
|
|
for h:= len to showlen-1 do trmout(' ');
|
|
end;
|
|
end;
|
|
end;
|
|
with lines[v] do begin
|
|
updated:= true; showlen:= len; show:= newline;
|
|
end;
|
|
end (* updateline *);
|
|
|
|
(**** WUPDL ****)
|
|
procedure wupdl(v: integer);
|
|
(* Update a line in the window section. *)
|
|
label 1, 2, 9;
|
|
var
|
|
newline: linetext; len: integer;
|
|
h, hmax: integer; ch, ch0, ch1: char;
|
|
pt: bufpos;
|
|
|
|
begin (* wupdl *)
|
|
if v>=winheight then bug('Internal error V>=WINHEIGHT in SCREEN/AS');
|
|
if (nwins=2) and (v=splitline) then begin
|
|
newline:= blanktext;
|
|
for h:= 0 to (screenwidth-10) do newline[h]:= '-';
|
|
end else if (v<winfirst) or (v>winlast) then begin
|
|
goto 9;
|
|
end else begin
|
|
newline:= blanktext;
|
|
h:= 0; pt:= curstate[v].bfpos;
|
|
if curstate[v].state=control then begin
|
|
ch:= bgetchar(pt-1);
|
|
if ch=chr(RubOut) then begin
|
|
newline[0]:= '?';
|
|
(*@VMS: end else if ch>chr(RubOut) then begin newline[0]:= '*'; *)
|
|
end else begin
|
|
newline[0]:= chr(ord(ch)+64);
|
|
end;
|
|
h:= 1; len:= 1;
|
|
end;
|
|
while (pt<rrz) do begin
|
|
ch:= bgetchar(pt);
|
|
if EolLineFeed then begin
|
|
if ch = chr(LineFeed) then goto 2;
|
|
end;
|
|
if ch = EolFirst then begin
|
|
if ateol(pt, 1) then goto 2;
|
|
end;
|
|
pt:= pt+1;
|
|
if h>=(screenwidth-1) then goto 1;
|
|
if ch in printable then begin
|
|
newline[h]:= ch; h:= h+1;
|
|
if ch<>' ' then len:= h;
|
|
end else if ch=chr(HorizontalTab) then begin
|
|
h:= (h div 8)*8+8;
|
|
if h>=screenwidth then goto 1;
|
|
end else if ch=chr(Escape) then begin
|
|
newline[h]:= '$'; h:= h+1; len:= h;
|
|
end else begin
|
|
newline[h]:= '^'; h:= h+1;
|
|
if h>=(screenwidth-1) then goto 1;
|
|
if ch=chr(RubOut) then begin
|
|
newline[h]:= '?';
|
|
(*@VMS: END ELSE IF ch>chr(RubOut) THEN BEGIN newline[h]:= '*'; *)
|
|
end else begin
|
|
newline[h]:= chr(ord(ch)+64);
|
|
end;
|
|
h:= h+1; len:= h;
|
|
end;
|
|
end (* WHILE *);
|
|
goto 2;
|
|
1:
|
|
newline[screenwidth-1]:= '!';
|
|
len:= screenwidth;
|
|
2:
|
|
lines[v].showpos:= curstate[v].bfpos;
|
|
end;
|
|
updateline(v, newline);
|
|
9:
|
|
end (* wupdl *);
|
|
|
|
(**** WSETPOS ****)
|
|
procedure wsetpos;
|
|
var ch: char; p: bufpos;
|
|
begin (* wsetpos *)
|
|
vpos:= winfirst+1;
|
|
while (rrdot>=curstate[vpos].bfpos) and (vpos<=winlast) do vpos:= vpos+1;
|
|
if rrdot>=curstate[vpos].bfpos then begin
|
|
bug('WSETPOS outside window (in SCREEN)/AS ');
|
|
end;
|
|
vpos:= vpos-1; hpos:= 0;
|
|
with curstate[vpos] do begin
|
|
p:= bfpos;
|
|
if state=control then hpos:= 1;
|
|
end;
|
|
while p<rrdot do begin
|
|
ch:= bgetchar(p);
|
|
if EolLineFeed and (ch=chr(LineFeed)) then begin
|
|
hpos:= 0; p:= p+1;
|
|
end else if ateol(p, 1) then begin
|
|
hpos:= 0; p:= p+eolsize;
|
|
end else begin
|
|
p:= p+1;
|
|
if ch in printable then begin
|
|
hpos:= hpos+1;
|
|
end else if ch=chr(HorizontalTab) then begin
|
|
hpos:= (hpos div 8)*8+8;
|
|
end else if ch=chr(Escape) then begin
|
|
hpos:= hpos+1
|
|
end else begin
|
|
hpos:= hpos+2;
|
|
end;
|
|
end;
|
|
end;
|
|
knownpos:= true;
|
|
end (* wsetpos *);
|
|
|
|
(**** WUPD1 ****)
|
|
procedure wupd1;
|
|
(* Make sure all information about what should be in window is correct. *)
|
|
var i: integer;
|
|
begin (* wupd1 *)
|
|
if curbuffer[curwin]<>showbuffer[curwin] then begin
|
|
built:= nopos;
|
|
rrdot:= getdot; rrz:= getsize;
|
|
first:= rrbeg; last:= rrz; count:= 0;
|
|
showbuffer[curwin]:= curbuffer[curwin];
|
|
end;
|
|
for i:= winfirst to winlast do begin
|
|
with lines[i] do begin
|
|
if showpos>=first then begin
|
|
showpos:= showpos+count;
|
|
if showpos<last then showpos:= -1
|
|
end;
|
|
end;
|
|
end;
|
|
if built=pos then begin
|
|
if rrdot>=winstart then wbuild;
|
|
end else if (built=ok) and (last>=first) then begin
|
|
partbuild;
|
|
end;
|
|
if (rrdot<winstart) or (rrdot>winend) or (built=nopos) then begin
|
|
if (not eolflag) and (nwins=1) then dorefresh:= true;
|
|
wrepos((winfirst+winlast) div 2); wbuild;
|
|
if (rrdot<winstart) or (rrdot>winend) then begin
|
|
bug('Dot outside window in WUPD1 (SCREEN)/AS ');
|
|
end;
|
|
end;
|
|
last:= rrbeg; first:= rrz; count:= 0;
|
|
end (* wupd1 *);
|
|
|
|
(**** PCNTUPDATE ****)
|
|
procedure pcntupdate;
|
|
(* Update percent field *)
|
|
var npcfld: pcmode; pcntrow, pcntcol: integer;
|
|
begin (* pcntupdate *)
|
|
with npcfld do begin
|
|
pcntrow:= modeheight-1;
|
|
pcntcol:= screenwidth-pcntwidth-1; val:= 0;
|
|
if winend=rrz then begin
|
|
if winstart=rrbeg then begin
|
|
mode:= none;
|
|
end else begin
|
|
mode:= bot;
|
|
end;
|
|
end else if winstart=rrbeg then begin
|
|
mode:= top;
|
|
end else begin
|
|
mode:= pcent;
|
|
val:= (100*winstart) div rrz;
|
|
end;
|
|
modif:= getmodified;
|
|
end;
|
|
if ((npcfld.mode<>pcfld.mode) or (npcfld.val<>pcfld.val)
|
|
or (npcfld.modif<>pcfld.modif)) then begin
|
|
lines[modetop+pcntrow].updated:= false;
|
|
with npcfld do begin
|
|
if mode<>none then begin
|
|
modelines[pcntrow][pcntcol ]:= '-';
|
|
modelines[pcntrow][pcntcol+1]:= '-';
|
|
case mode of
|
|
pcent:
|
|
begin
|
|
modelines[pcntrow][pcntcol+2]:= chr((val div 10)+ord('0'));
|
|
modelines[pcntrow][pcntcol+3]:= chr((val mod 10)+ord('0'));
|
|
modelines[pcntrow][pcntcol+4]:= '%';
|
|
end;
|
|
top:
|
|
begin
|
|
modelines[pcntrow][pcntcol+2]:= 'T';
|
|
modelines[pcntrow][pcntcol+3]:= 'O';
|
|
modelines[pcntrow][pcntcol+4]:= 'P';
|
|
end;
|
|
bot:
|
|
begin
|
|
modelines[pcntrow][pcntcol+2]:= 'B';
|
|
modelines[pcntrow][pcntcol+3]:= 'O';
|
|
modelines[pcntrow][pcntcol+4]:= 'T';
|
|
end;
|
|
end (* case *);
|
|
modelines[pcntrow][pcntcol+5]:= '-';
|
|
modelines[moderow][pcntcol+6]:= '-';
|
|
pcntcol:= pcntcol+7;
|
|
end;
|
|
if modif then begin
|
|
modelines[pcntrow][pcntcol ]:= ' ';
|
|
modelines[pcntrow][pcntcol+1]:= '*';
|
|
pcntcol:= pcntcol+2;
|
|
end;
|
|
for pcntcol:= pcntcol to screenwidth-1 do begin
|
|
modelines[pcntrow][pcntcol]:= ' ';
|
|
end;
|
|
end;
|
|
pcfld:= npcfld;
|
|
end;
|
|
end (* pcntupdate *);
|
|
|
|
(**** NEWOWLINE ****)
|
|
procedure newowline(row: integer);
|
|
var i, morerow, morecol: integer; c: char;
|
|
begin (* newowline *)
|
|
ocol:= 0; orow:= row;
|
|
if orow > winlast then begin
|
|
pcfld.mode:= bad;
|
|
morerow:= modeheight-1;
|
|
morecol:= screenwidth-pcntwidth-1;
|
|
modelines[morerow][morecol ]:= '-';
|
|
modelines[morerow][morecol+1]:= '-';
|
|
modelines[morerow][morecol+2]:= 'M';
|
|
modelines[morerow][morecol+3]:= 'O';
|
|
modelines[morerow][morecol+4]:= 'R';
|
|
modelines[morerow][morecol+5]:= 'E';
|
|
modelines[morerow][morecol+6]:= '-';
|
|
modelines[morerow][morecol+7]:= '-';
|
|
modelines[morerow][morecol+8]:= ' ';
|
|
updateline(modetop+morerow, modelines[morerow]);
|
|
trmpos(modetop+morerow, screenwidth-1);
|
|
c:= readc; (* Wait for the user to type something *)
|
|
if c<>' ' then begin (* If he didn't type a space *)
|
|
ovflush:= true; (* Set flushed flag *)
|
|
modelines[morerow][morecol ]:= 'F';
|
|
modelines[morerow][morecol+1]:= 'L';
|
|
modelines[morerow][morecol+2]:= 'U';
|
|
modelines[morerow][morecol+3]:= 'S';
|
|
modelines[morerow][morecol+4]:= 'H';
|
|
modelines[morerow][morecol+5]:= 'E';
|
|
modelines[morerow][morecol+6]:= 'D';
|
|
modelines[morerow][morecol+7]:= ' ';
|
|
modelines[morerow][morecol+8]:= ' ';
|
|
updateline(modetop+morerow, modelines[morerow]);
|
|
ttyforce; (* Force the line out *)
|
|
if c<>chr(RubOut) then reread; (* Reread all flush chars except rubout *)
|
|
end else begin
|
|
orow:= winfirst;
|
|
end;
|
|
end;
|
|
if not ovflush then begin
|
|
trmpos(orow, 0);
|
|
if eolflag then begin
|
|
trmeol;
|
|
end else begin
|
|
for i:= 1 to lines[orow].showlen do trmout(' ');
|
|
trmpos(orow, 0);
|
|
end;
|
|
markblank(orow);
|
|
end;
|
|
end (* newowline *);
|
|
|
|
procedure wupd0;
|
|
label
|
|
9;
|
|
var
|
|
i: integer;
|
|
begin
|
|
if scrflag then tryscroll(winfirst);
|
|
if check(0) then goto 9;
|
|
if not knownpos then wsetpos;
|
|
if not lines[vpos].updated then wupdl(vpos);
|
|
if csflg then begin
|
|
csflg:= false;
|
|
for i:= 1 to winheight do begin
|
|
if vpos+i<winheight then begin
|
|
if not lines[vpos+i].updated then begin
|
|
wupdl(vpos+i);
|
|
if check(0) then goto 9
|
|
end;
|
|
end;
|
|
if vpos-i>=0 then begin
|
|
if not lines[vpos-i].updated then begin
|
|
wupdl(vpos-i);
|
|
if check(0) then goto 9;
|
|
end;
|
|
end;
|
|
end;
|
|
end else begin
|
|
for i:= 0 to winheight-1 do begin
|
|
if not lines[i].updated then begin
|
|
wupdl(i);
|
|
if check(0) then goto 9;
|
|
end;
|
|
end;
|
|
end;
|
|
9:
|
|
end;
|
|
|
|
procedure winprelude(unsimplify: boolean);
|
|
label
|
|
9;
|
|
var
|
|
i: integer;
|
|
begin
|
|
if noprelude then goto 9;
|
|
noprelude:= true;
|
|
(* Four cases: *)
|
|
(* 0/ Same window and same buffer *)
|
|
(* 1/ Same window with other buffer *)
|
|
(* 2/ Other window with same buffer as last in this window *)
|
|
(* 3/ Other window with changed buffer *)
|
|
(* Case 0 is ignored, case 1 requires just a reset of variables, *)
|
|
(* case 3 is like case 1 after switching window, *)
|
|
(* case 2 requires resetting dot to same position as last time *)
|
|
if (new_window<>curwin) or (new_buffer<>curbuffer[curwin]) then begin
|
|
unsimplify:= true;
|
|
if new_window<>curwin then begin
|
|
xwinstart[curwin]:= winstart; xwinend[curwin]:= winend;
|
|
xbuilt[curwin]:= built; xdot[curwin]:= rrdot;
|
|
if (first<=last) or (built<>ok) then xok[curwin]:= false;
|
|
curwin:= new_window;
|
|
if curwin=1 then begin
|
|
winfirst:= 0; winlast:= splitline-1;
|
|
end else begin
|
|
winfirst:= splitline+1; winlast:= winheight-1;
|
|
end;
|
|
winstart:= xwinstart[curwin]; winend:= xwinend[curwin];
|
|
built:= xbuilt[curwin]; knownpos:= false;
|
|
rrdot:= xdot[curwin]; rrz:= getsize;
|
|
(* Case 3 done, check for case 2 *)
|
|
if curbuffer[curwin]=new_buffer then begin
|
|
if rrdot>rrz then rrdot:= rrz;
|
|
setdot(rrdot);
|
|
if built<pos then built:= pos;
|
|
end else begin
|
|
rrdot:= getdot; built:= nopos;
|
|
end;
|
|
end;
|
|
curbuffer[curwin]:= new_buffer;
|
|
rrz:= getsize; rrdot:= getdot;
|
|
end;
|
|
if unsimplify then begin
|
|
if scount>0 then begin
|
|
for i:= spos+1 to winlast+1 do begin
|
|
with lines[i] do showpos:= showpos+scount;
|
|
with curstate[i] do bfpos:= bfpos+scount;
|
|
end;
|
|
end;
|
|
simplep:= false; scount:= 0;
|
|
end;
|
|
noprelude:= false;
|
|
9:
|
|
end;
|
|
|
|
procedure wswitch;
|
|
(* Switch window, including switch of buffer *)
|
|
begin
|
|
new_window:= 3-new_window; new_buffer:= curbuffer[new_window];
|
|
if new_buffer=0 then bug('No buffer selected for this window /AS ');
|
|
isetbuf(new_buffer);
|
|
winprelude(true);
|
|
end;
|
|
|
|
procedure UpdModeLines;
|
|
var i: integer;
|
|
begin
|
|
for i:= 0 to modeheight-1 do begin
|
|
if not lines[modetop+i].updated then begin
|
|
updateline(modetop+i, modelines[i]);
|
|
(*** IF check(0) THEN GOTO 9; ***)
|
|
end;
|
|
end;
|
|
end (* UpdModeLines *);
|
|
|
|
(****************************************)
|
|
(* *)
|
|
(* Entries to this module *)
|
|
(* *)
|
|
(****************************************)
|
|
|
|
(**** WININSERT ****)
|
|
(*@VMS: [global] *)
|
|
procedure wininsert(n: bufpos);
|
|
(* n characters inserted at dot *)
|
|
begin (* wininsert *)
|
|
winprelude(false);
|
|
if first>rrdot then first:= rrdot;
|
|
rrdot:= rrdot+n; rrz:= rrz+n;
|
|
last:= last+n;
|
|
if rrdot>last then last:= rrdot;
|
|
count:= count+n;
|
|
knownpos:= false;
|
|
end (* wininsert *);
|
|
|
|
(**** WINDELETE ****)
|
|
(*@VMS: [global] *)
|
|
procedure windelete(n: bufpos);
|
|
(* n characters deleted at dot *)
|
|
begin (* windelete *)
|
|
winprelude(true);
|
|
if first>rrdot then first:= rrdot;
|
|
rrz:= rrz-n;
|
|
last:= last-n;
|
|
if rrdot>last then last:= rrdot;
|
|
count:= count-n;
|
|
knownpos:= false;
|
|
end (* windelete *);
|
|
|
|
(**** WINSETDOT ****)
|
|
(*@VMS: [global] *)
|
|
procedure winsetdot(pt: bufpos);
|
|
(* Dot is set to pt *)
|
|
begin (* winsetdot *)
|
|
winprelude(true);
|
|
rrdot:= pt;
|
|
knownpos:= false;
|
|
end (* winsetdot *);
|
|
|
|
(**** WINPOS ****)
|
|
(*@VMS: [global] *)
|
|
procedure winpos(row: integer);
|
|
(* Position window so that dot is on specified row *)
|
|
begin (* winpos *)
|
|
winprelude(true);
|
|
if row<0 then begin
|
|
row:= winlast+1+row;
|
|
if row>=winfirst then wrepos(row);
|
|
end else begin
|
|
row:= winfirst+row;
|
|
if row<=winlast then wrepos(row);
|
|
end;
|
|
end (* winpos *);
|
|
|
|
(**** WINSCROLL ****)
|
|
(*@VMS: [global] *)
|
|
procedure winscroll(n: integer);
|
|
(* Scroll window n lines up or down *)
|
|
begin (* winscroll *)
|
|
winprelude(true);
|
|
wupd1; (* Make sure Winstart and Winend are OK *)
|
|
if not knownpos then wsetpos;
|
|
if n<0 then begin
|
|
winstart:= wuplines(winstart, -n);
|
|
if vpos-n>winlast then setdot(winstart);
|
|
end else begin
|
|
winstart:= wdownlines(winstart, n);
|
|
if vpos-n<winfirst then setdot(winstart);
|
|
end;
|
|
built:= pos;
|
|
end (* winscroll *);
|
|
|
|
(**** WINSELECT ****)
|
|
(*@VMS: [global] *)
|
|
procedure winselect(n: integer);
|
|
var cb: integer;
|
|
begin (* winselect *)
|
|
if nwins=2 then begin
|
|
if n=0 then begin
|
|
new_window:= 3-new_window;
|
|
end else begin
|
|
new_window:= n;
|
|
end;
|
|
(* This seems to have "interesting" effects. Therefore, figure *)
|
|
(* out something else. Later, that is... *)
|
|
(* winprelude(true); *)
|
|
end;
|
|
end (* winselect *);
|
|
|
|
(**** WINBUF ****)
|
|
(*@VMS: [global] *)
|
|
procedure winbuf(n: integer);
|
|
(* This is to inform us that current buffer has changed. *)
|
|
begin (* winbuf *)
|
|
new_buffer:= n;
|
|
end (* winbuf *);
|
|
|
|
(**** WINGROW ****)
|
|
(*@VMS: [global] *)
|
|
procedure wingrow(n: integer);
|
|
(* Grow (or shrink) current window *)
|
|
var i, o: integer;
|
|
begin (* wingrow *)
|
|
winprelude(true);
|
|
if curwin=2 then begin
|
|
n:= splitline-n;
|
|
end else begin
|
|
n:= splitline+n;
|
|
end;
|
|
if n<1 then n:= 1;
|
|
if n>(winheight-2) then n:= winheight-2;
|
|
o:= splitline; splitline:= n;
|
|
if nwins=2 then begin
|
|
if curwin=1 then begin
|
|
winlast:= n-1;
|
|
end else begin
|
|
winfirst:= n+1;
|
|
end;
|
|
if built<pos then built:= pos;
|
|
xok[1]:= false; xok[2]:= false;
|
|
with lines[n] do begin
|
|
updated:= false; showpos:= -1;
|
|
end;
|
|
if curwin=1 then begin
|
|
wswitch;
|
|
winscroll(o-n);
|
|
wswitch;
|
|
end else begin
|
|
winscroll(n-o);
|
|
end;
|
|
end;
|
|
end (* wingrow *);
|
|
|
|
(**** WINNO ****)
|
|
(*@VMS: [global] *)
|
|
procedure winno(n: integer);
|
|
(* Tells us how many windows to use, current maximum 2 *)
|
|
var
|
|
i: integer;
|
|
begin (* winno *)
|
|
winprelude(true);
|
|
if n=1 then begin
|
|
if curwin<>1 then bug('Window one not selected /as ');
|
|
nwins:= 1; winfirst:= 0; winlast:= winheight-1;
|
|
if built<pos then built:= pos;
|
|
end else if n=2 then begin
|
|
if nwins<>2 then begin
|
|
xwinstart[2]:= 0; xwinend[2]:= 0;
|
|
xbuilt[2]:= nopos; xdot[2]:= 0;
|
|
nwins:= 2; new_window:= 2;
|
|
if splitline<1 then splitline:= 1;
|
|
if splitline>(winheight-2) then splitline:= winheight-2;
|
|
winlast:= splitline-1;
|
|
if built<pos then built:= pos;
|
|
xok[1]:= false; xok[2]:= false;
|
|
with lines[splitline] do begin
|
|
updated:= false; showpos:= -1;
|
|
end;
|
|
end;
|
|
end else begin
|
|
bug('Illegal argument to WINNO /as ');
|
|
end;
|
|
end (* winno *);
|
|
|
|
(**** WINCUR ****)
|
|
(*@VMS: [global] *)
|
|
function wincur: integer;
|
|
begin (* wincur *)
|
|
wincur:= curwin;
|
|
end (* wincur *);
|
|
|
|
(**** WINREFRESH ****)
|
|
(*@VMS: [global] *)
|
|
procedure winrefresh;
|
|
(* Tells us that it is time to refresh the window *)
|
|
(* It is our responsibility to position the window *)
|
|
var i: integer;
|
|
begin (* winrefresh *)
|
|
winprelude(true);
|
|
rrdot:= getdot; rrz:= getsize;
|
|
if not dorefresh then wrepos((winfirst+winlast) div 2);
|
|
trmclr;
|
|
pcfld.mode:= bad; csflg:= true;
|
|
for i:= 0 to screenheight do markblank(i);
|
|
xok[1]:= false; xok[2]:= false;
|
|
end (* winrefresh *);
|
|
|
|
(**** WINREWRITE ****)
|
|
(*@VMS: [global] *)
|
|
procedure winrewrite(n: integer);
|
|
(* Rewrite n lines around current line *)
|
|
var i, low, high: integer;
|
|
begin (* winrewrite *)
|
|
winprelude(true);
|
|
if built=ok then begin
|
|
if (rrdot>=winstart) and (rrdot<=winend) then begin
|
|
if not knownpos then wsetpos;
|
|
if n<1 then n:= 1;
|
|
low:= vpos-((n-1) div 2);
|
|
if low<0 then low:= 0;
|
|
high:= low+n-1;
|
|
if high>winlast then high:= winlast;
|
|
for i:= low to high do markmessed(i);
|
|
end;
|
|
end;
|
|
end (* winrewrite *);
|
|
|
|
(**** WINUPDATE ****)
|
|
(*@VMS: [global] *)
|
|
procedure winupdate;
|
|
(* here we are allowed to do updating *)
|
|
label 1, 9;
|
|
var i: integer; c: char;
|
|
begin (* winupdate *)
|
|
winprelude(false);
|
|
if simplep then begin
|
|
trmpos(vpos, hpos);
|
|
while first<last do begin
|
|
c:= bgetchar(first);
|
|
if not (c in printable) then goto 1;
|
|
if hpos>=screenwidth-1 then goto 1;
|
|
trmout(c);
|
|
with lines[vpos] do begin
|
|
show[hpos]:= c; showlen:= hpos+1;
|
|
end;
|
|
hpos:= hpos+1; spos:= vpos;
|
|
first:= first+1; count:= count-1; scount:= scount+1;
|
|
end;
|
|
knownpos:= true; ttyforce; goto 9;
|
|
1:
|
|
winprelude(true);
|
|
end;
|
|
if ovmode then begin
|
|
(* Wait for the user to type something *)
|
|
c:= readc;
|
|
if c<>' ' then reread;
|
|
end;
|
|
orow:= winfirst; (* Reset overwrite lines *)
|
|
ovmode:= false; ovflush:= false;
|
|
if check(0) then goto 9;
|
|
xok[curwin]:= false;
|
|
wupd1;
|
|
if dorefresh then begin
|
|
winrefresh; dorefresh:= false;
|
|
end;
|
|
for i:= 0 to echoheight-1 do begin
|
|
if not lines[echotop+i].updated then begin
|
|
updateline(echotop+i, echolines[i]);
|
|
if check(0) then goto 9;
|
|
end;
|
|
end;
|
|
pcntupdate;
|
|
UpdModeLines;
|
|
if check(0) then goto 9;
|
|
wupd0;
|
|
if check(0) then goto 9;
|
|
xok[curwin]:= true;
|
|
if nwins=2 then begin
|
|
if not xok[3-curwin] then begin
|
|
wswitch;
|
|
if built<pos then built:= pos;
|
|
wupd1; wupd0;
|
|
wswitch;
|
|
last:= rrbeg; first:= rrz; count:= 0;
|
|
if check(0) then goto 9;
|
|
xok[3-curwin]:= true;
|
|
end;
|
|
end;
|
|
if not knownpos then wsetpos;
|
|
trmpos(vpos, hpos); ttyforce; (* Force, just like Echoupdate. / JMR *)
|
|
simplep:= (ateol(rrdot, 1) or (rrdot=rrz)) and pcfld.modif;
|
|
9:
|
|
end (* winupdate *);
|
|
|
|
(**** WINOVTOP ***)
|
|
(*@VMS: [global] *)
|
|
procedure winovtop;
|
|
(* Starts new overwrite at top left cornet *)
|
|
begin (* winovtop *)
|
|
winprelude(true);
|
|
if not ovflush then begin
|
|
ovmode:= true;
|
|
newowline(winfirst);
|
|
end;
|
|
end (* winovtop *);
|
|
|
|
(**** WINOVERWRITE ****)
|
|
(*@VMS: [global] *)
|
|
procedure winoverwrite(ch: char);
|
|
(* overwrites text in buffer with garbage *)
|
|
label 9;
|
|
begin (* winoverwrite *)
|
|
winprelude(true);
|
|
if ovflush then goto 9;
|
|
if not ovmode then begin
|
|
ovmode:= true;
|
|
newowline(orow);
|
|
end;
|
|
if (ch<' ') or (ch=chr(RubOut)) then begin
|
|
if ch=chr(LineFeed) then begin
|
|
newowline(orow+1);
|
|
end else if ch=chr(CarriageReturn) then begin
|
|
ocol:= 0;
|
|
end else if ch=chr(HorizontalTab) then begin
|
|
ocol:= (ocol div 8)*8+8;
|
|
end else begin
|
|
winoverwrite('^');
|
|
if ch=chr(RubOut) then begin
|
|
winoverwrite('?');
|
|
end else begin
|
|
winoverwrite(chr(ord(ch)+64));
|
|
end;
|
|
end;
|
|
end else begin
|
|
if ocol>screenwidth-1 then begin
|
|
newowline(orow+1);
|
|
end;
|
|
trmpos(orow, ocol);
|
|
with lines[orow] do begin
|
|
show[ocol]:= ch;
|
|
trmout(ch);
|
|
ocol:= ocol+1;
|
|
if ocol>showlen then showlen:= ocol;
|
|
end;
|
|
end;
|
|
9:
|
|
end (* winoverwrite *);
|
|
|
|
(**** WINOVCLEAR ****)
|
|
(*@VMS: [global] *)
|
|
procedure winovclear;
|
|
(* Reset overwritemode *)
|
|
begin (* winovclear *)
|
|
winprelude(true);
|
|
ovmode:= false; ovflush:= false;
|
|
end (* winovclear *);
|
|
|
|
(**** PCNTMESSED ****)
|
|
(*@VMS: [global] *)
|
|
procedure pcntmessed;
|
|
(* Indicate that percent field is messed *)
|
|
begin (* pcntmessed *)
|
|
winprelude(true);
|
|
pcfld.mode:= bad;
|
|
end (* pcntmessed *);
|
|
|
|
(**** WINTOP ****)
|
|
(*@VMS: [global] *)
|
|
function wintop: bufpos;
|
|
(* Returns the position of the beginning of the window *)
|
|
begin (* wintop *)
|
|
wintop:= winstart;
|
|
end (* wintop *);
|
|
|
|
(**** WINSIZE ****)
|
|
(*@VMS: [global] *)
|
|
procedure winsize(var height, width: integer);
|
|
(* Returns the size of the window *)
|
|
begin (* winsize *)
|
|
height:= winlast-winfirst+1; width:= screenwidth;
|
|
end (* winsize *);
|
|
|
|
(**** DOTPOS ****)
|
|
(*@VMS: [global] *)
|
|
procedure dotpos(var row, col: integer);
|
|
(* Return screen position of dot *)
|
|
begin (* dotpos *)
|
|
winprelude(true);
|
|
wupd1;
|
|
if not knownpos then wsetpos;
|
|
row:= vpos+winfirst; col:= hpos;
|
|
end (* dotpos *);
|
|
|
|
(**** POSDOT ****)
|
|
(*@VMS: [global] *)
|
|
function posdot(x: integer): bufpos;
|
|
label 9;
|
|
var pt: bufpos; pos: integer; ch: char;
|
|
begin (* posdot *)
|
|
pt:= rrdot; pos:= 0;
|
|
while (pt<rrz) and (pos<x) do begin
|
|
ch:= bgetchar(pt);
|
|
if ch in printable then begin
|
|
pos:= pos+1;
|
|
end else begin
|
|
if ch=chr(HorizontalTab) then begin
|
|
pos:= ((pos+8) div 8) * 8;
|
|
end else if ch=chr(Escape) then begin
|
|
pos:= pos+1;
|
|
end else begin
|
|
pos:= pos+2;
|
|
end;
|
|
if ateol(pt, 1) then goto 9;
|
|
if pos>x then goto 9;
|
|
end;
|
|
pt:= pt+1;
|
|
end;
|
|
9:
|
|
posdot:= pt;
|
|
end (* posdot *);
|
|
|
|
(**** MODEWRITE ****)
|
|
(*@VMS: [global] *)
|
|
procedure modewrite(ch: char);
|
|
begin
|
|
winprelude(true);
|
|
if (moderow<modeheight-1) and (modecol=screenwidth-1) then begin
|
|
lines[modetop+moderow].updated:= false;
|
|
modelines[moderow][modecol]:= '!';
|
|
moderow:= moderow+1; modecol:= 0;
|
|
end;
|
|
if (moderow<modeheight-1) and (modecol<=screenwidth-1)
|
|
or (moderow=modeheight-1) and (modecol<=screenwidth-pcntwidth-2) then begin
|
|
lines[modetop+moderow].updated:= false;
|
|
modelines[moderow][modecol]:= ch; modecol:= modecol+1;
|
|
end;
|
|
end (* modewrite *);
|
|
|
|
(*---------------------------------------------------------------------------*)
|
|
(* ModeArrow writes a character in the mode area. Control characters are *)
|
|
(* written in the uparrow form. *)
|
|
|
|
procedure ModeArrow(c: char);
|
|
var
|
|
i: integer;
|
|
begin
|
|
if c in printable then begin
|
|
modewrite(c)
|
|
end else begin
|
|
for i := 1 to chrvlen[c]
|
|
do modewrite(chrview[c, i]);
|
|
end;
|
|
end;
|
|
|
|
(*---------------------------------------------------------------------------*)
|
|
(* ModeString writes a string in the mode area, followed by one space. *)
|
|
|
|
(*@VMS: [global] *)
|
|
procedure ModeString(Str: string);
|
|
var
|
|
pos: integer;
|
|
begin
|
|
for pos := 1 to StrLength(Str)
|
|
do ModeArrow(Str[pos]);
|
|
modewrite(' ');
|
|
end;
|
|
|
|
(**** MODEPOS ****)
|
|
(*@VMS: [global] *)
|
|
procedure modepos(row, col: integer);
|
|
begin
|
|
moderow:= row; modecol:= col;
|
|
end (* modepos *);
|
|
|
|
(**** MODEWHERE ****)
|
|
(*@VMS: [global] *)
|
|
procedure modewhere(var row, col: integer);
|
|
begin
|
|
row:= moderow; col:= modecol;
|
|
end (* modewhere *);
|
|
|
|
(**** MODESIZE ****)
|
|
(*@VMS: [global] *)
|
|
procedure modesize(var height, width: integer);
|
|
begin
|
|
height:= modeheight; width:= screenwidth;
|
|
end (* modesize *);
|
|
|
|
(**** MODECLEAR ****)
|
|
(*@VMS: [global] *)
|
|
procedure modeclear;
|
|
var row, col: integer;
|
|
begin
|
|
winprelude(true);
|
|
for row:= modetop to modetop+modeheight-1 do lines[row].updated:= false;
|
|
for row:= 0 to modeheight-2 do modelines[row]:= blanktext;
|
|
for col:= 0 to screenwidth-10-1 do modelines[modeheight-1][col]:= ' ';
|
|
moderow:= 0; modecol:= 0;
|
|
ClockIsOn:= false; (* The clock is off now. *)
|
|
end (* modeclear *);
|
|
|
|
(**** TimeOut ****)
|
|
(*@VMS: [global] *)
|
|
procedure TimeOut(Hours, Minutes: integer);
|
|
begin
|
|
modewrite(chr((Hours div 10) + ord('0')));
|
|
modewrite(chr((Hours mod 10) + ord('0')));
|
|
modewrite(':');
|
|
modewrite(chr((Minutes div 10) + ord('0')));
|
|
modewrite(chr((Minutes mod 10) + ord('0')));
|
|
end (* TimeOut *);
|
|
|
|
(**** TIMESTAMP ****)
|
|
(*@VMS: [global] *)
|
|
procedure TimeStamp;
|
|
var
|
|
MRow, MCol: integer;
|
|
TRow, TCol: integer;
|
|
Hour, Minute: integer;
|
|
Void: boolean;
|
|
begin
|
|
if ClockIsOn then begin (* Only update if the clock is on *)
|
|
TrmWhere(TRow, TCol); (* Get position on physical screen *)
|
|
modewhere(MRow, MCol); (* Save mode line position *)
|
|
GetClock(Hour, Minute); (* Get current time *)
|
|
if Minute = 0 (* Even hour? *)
|
|
then begin
|
|
modepos(ClockRow, ClockCol); (* Go to clock field *)
|
|
modewrite('P');
|
|
modewrite('l');
|
|
modewrite('i');
|
|
modewrite('n');
|
|
modewrite('g');
|
|
UpdModeLines; (* Update the mode line *)
|
|
ttyforce; (* Force all output *)
|
|
Void := check(1); (* Wait a second. *)
|
|
end;
|
|
modepos(ClockRow, ClockCol); (* Go to clock field *)
|
|
TimeOut(Hour, Minute); (* Put new time in mode line *)
|
|
modepos(MRow, MCol); (* Restore old mode line pos *)
|
|
UpdModeLines; (* Update the mode line *)
|
|
trmpos(TRow, TCol); (* Restore physical position *)
|
|
ttyforce; (* Force out all buffers *)
|
|
end;
|
|
end (* TimeStamp *);
|
|
|
|
(**** MODETIME ****)
|
|
(*@VMS: [global] *)
|
|
procedure ModeTime;
|
|
var
|
|
Hour, Minute: integer;
|
|
begin
|
|
ClockIsOn:= true; (* The clock just got turned on... *)
|
|
ClockRow := moderow;
|
|
ClockCol := modecol;
|
|
GetClock(Hour, Minute);
|
|
TimeOut(Hour, Minute); (* Get the clock going... *)
|
|
end (* ModeTime *);
|
|
|
|
(**** ECHOUPDATE ****)
|
|
(*@VMS: [global] *)
|
|
procedure echoupdate;
|
|
var row: integer;
|
|
begin
|
|
simplep:= false;
|
|
if not kbdrunning then begin
|
|
for row:= echotop to echotop+echoheight-1 do
|
|
if not lines[row].updated then updateline(row, echolines[row-echotop]);
|
|
trmpos(echotop+echorow, echocol); ttyforce;
|
|
end;
|
|
end (* echoupdate *);
|
|
|
|
(**** ECHOEOL ****)
|
|
(*@VMS: [global] *)
|
|
procedure echoeol;
|
|
var col: integer;
|
|
begin
|
|
winprelude(true);
|
|
lines[echotop+echorow].updated:= false;
|
|
for col:= echocol to screenwidth-1 do echolines[echorow][col]:= ' ';
|
|
end (* echoeol *);
|
|
|
|
(**** ECHOWRITE ****)
|
|
(*@VMS: [global] *)
|
|
procedure echowrite(ch: char);
|
|
begin
|
|
winprelude(true);
|
|
if (echorow<echoheight-1) and (echocol=screenwidth-1) then begin
|
|
lines[echotop+echorow].updated:=false;
|
|
echolines[echorow][echocol]:= '!';
|
|
echorow:= echorow+1; echocol:= 0;
|
|
end;
|
|
if (echorow<echoheight) and (echocol<=screenwidth-1) then begin
|
|
lines[echotop+echorow].updated:= false;
|
|
if (echorow=echoheight-1) and (echocol>=screenwidth-2) then begin
|
|
echocol:= 0; echoeol;
|
|
end;
|
|
echolines[echorow][echocol]:= ch; echocol:= echocol+1;
|
|
end;
|
|
end (* echowrite *);
|
|
|
|
(*@VMS: [global] *)
|
|
procedure echopos(row, col: integer);
|
|
begin
|
|
echorow:= row; echocol:= col;
|
|
end (* echopos *);
|
|
|
|
(**** ECHOWHERE ****)
|
|
(*@VMS: [global] *)
|
|
procedure echowhere(var row, col: integer);
|
|
begin
|
|
row:= echorow; col:= echocol;
|
|
end (* echowhere *);
|
|
|
|
(**** ECHOSIZE ****)
|
|
(*@VMS: [global] *)
|
|
procedure echosize(var height, width: integer);
|
|
begin
|
|
height:= echoheight; width:= screenwidth;
|
|
end (* echosize *);
|
|
|
|
(*---------------------------------------------------------------------------*)
|
|
(* EchoArrow writes a character in the echo area. Control characters are *)
|
|
(* written in the uparrow form. *)
|
|
|
|
(*@VMS: [global] *)
|
|
procedure EchoArrow(c: char);
|
|
var
|
|
i: integer;
|
|
begin
|
|
if c in printable then begin
|
|
echowrite(c)
|
|
end else begin
|
|
for i := 1 to chrvlen[c]
|
|
do echowrite(chrview[c, i]);
|
|
end;
|
|
end;
|
|
|
|
(*---------------------------------------------------------------------------*)
|
|
(* EchoString writes a string in the echo area, followed by one space. *)
|
|
|
|
(*@VMS: [global] *)
|
|
procedure EchoString(Str: string);
|
|
var
|
|
pos: integer;
|
|
begin
|
|
for pos := 1 to StrLength(Str)
|
|
do EchoArrow(Str[pos]);
|
|
echowrite(' ');
|
|
end;
|
|
|
|
(*---------------------------------------------------------------------------*)
|
|
|
|
(*@VMS: [global] *)
|
|
procedure WinFlags(flags: string);
|
|
var c: char;
|
|
begin
|
|
c := flags[3]; (* "Display line feed as EOL" *)
|
|
if c = '+' then EolLineFeed := true;
|
|
if c = '-' then EolLineFeed := false;
|
|
c := flags[4]; (* "Display Escape as $" *)
|
|
if c = '+' then begin
|
|
chrview[chr(Escape)] := '$ ';
|
|
chrvlen[chr(Escape)] := 1;
|
|
end;
|
|
if c = '-' then begin
|
|
chrview[chr(Escape)] := '^[ ';
|
|
chrvlen[chr(Escape)] := 2;
|
|
end;
|
|
end;
|
|
|
|
(*---------------------------------------------------------------------------*)
|
|
|
|
(*@VMS: [global] *)
|
|
procedure scrinit(total: boolean);
|
|
var
|
|
i: integer;
|
|
eol: string;
|
|
begin (* wininit *)
|
|
for i:= 0 to maxwidth do begin
|
|
blanktext[i]:= ' '; messedtext[i]:= chr(RubOut);
|
|
end;
|
|
(* Initialize terminal dependent variables *)
|
|
TrmSize(screenheight, screenwidth);
|
|
TrmFeatures(xyflag, eolflag, scrflag);
|
|
TrmPrintable(printable);
|
|
for i := 0 to 31 do begin
|
|
chrview[chr(i)][1] := '^';
|
|
chrview[chr(i)][2] := chr(i + 64);
|
|
chrvlen[chr(i)] := 2;
|
|
end;
|
|
(*@TOPS: chrview[chr(Escape)] := '$ '; *)
|
|
(*@TOPS: chrvlen[chr(Escape)] := 1; *)
|
|
for i := 32 to 126 do begin
|
|
chrview[chr(i)][1] := chr(i);
|
|
chrvlen[chr(i)] := 1;
|
|
end;
|
|
chrview[chr(127)] := '^? ';
|
|
chrvlen[chr(127)] := 2;
|
|
(*@VMS:
|
|
for i := 128 to 255 do begin
|
|
chrview[chr(i)] := '^* ';
|
|
chrvlen[chr(i)] := 2;
|
|
end;
|
|
*) (* Done simple VMS set-up. *)
|
|
if screenheight > maxheight then screenheight := maxheight;
|
|
if screenwidth > maxwidth then screenwidth := maxwidth;
|
|
if screenwidth>40 then echoheight:= 1 else echoheight:= 2;
|
|
echotop:= screenheight-echoheight;
|
|
echorow:=0; echocol:= 0;
|
|
for i:= 0 to echoheight-1 do echolines[i]:= blanktext;
|
|
if screenwidth>40 then modeheight:= 1 else modeheight:= 2;
|
|
modetop:= echotop-modeheight;
|
|
moderow:= 0; modecol:= 0;
|
|
for i:= 0 to modeheight-1 do modelines[i]:= blanktext;
|
|
ClockIsOn:= false; (* The clock is not yet on *)
|
|
winheight:= modetop;
|
|
winfirst:= 0; winlast:= winheight-1;
|
|
if total then begin
|
|
splitline:= winheight div 2;
|
|
nwins:= 1; curwin:= 1;
|
|
end else begin
|
|
wingrow(0);
|
|
end;
|
|
linecost:= 20; trmcst(scrollcost, idcharcost);
|
|
(* Say complete update necessary *)
|
|
if total then begin
|
|
rrdot:= 0; rrz:= 0;
|
|
end;
|
|
first:= 0; last:= rrz; count:= rrz;
|
|
csflg:= true;
|
|
noprelude:= false;
|
|
if total then begin
|
|
built:= nopos;
|
|
winstart:= 0; winend:= 0;
|
|
xwinstart[1]:= 0; xwinend[1]:= 0;
|
|
xwinstart[2]:= 0; xwinend[2]:= 0;
|
|
curbuffer[1]:= 1; curbuffer[2]:= 0;
|
|
showbuffer[1]:= 1; showbuffer[2]:= 0;
|
|
end else begin
|
|
if built=ok then built:= pos;
|
|
xok[1]:= false; xok[2]:= false;
|
|
end;
|
|
new_buffer:= curbuffer[curwin]; new_window:= curwin;
|
|
hpos:= 0; vpos:= 0; knownpos:= false;
|
|
simplep:= false; scount:= 0; spos:= 0;
|
|
ovmode:= false; ovflush:= false; orow:= 0;
|
|
EolString(eol, i);
|
|
EolFirst := eol[1];
|
|
EolLineFeed := false;
|
|
end; (* scrinit *)
|
|
|
|
(*---------------------------------------------------------------------------*)
|
|
|
|
(*@TOPS: begin end. *)
|
|
(*@VMS: end. *)
|