TypescriptDisplays:
CEDAR
PROGRAM
IMPORTS Atom, EditedStream, IO, RefText, Rope, TEditLocks, TextEdit, TextLooks, TextNode, TiogaOps, TypeScript, ViewerIO
= {OPEN CharDisplays;
REFTEXT: TYPE = REF TEXT;
ROPE: TYPE = Rope.ROPE;
Viewer: TYPE = ViewerClasses.Viewer;
typescriptDisplay: CharDisplayClass ←
NEW [CharDisplayClassRep ← [
Init: InitTSDisplay,
TakeChar: TSTakeChar,
CursorMove: TSCursorMove,
ClearAll: TSClearAll]];
TSDisplay: TYPE = REF TSDisplayRep;
TSDisplayRep:
PUBLIC
TYPE =
RECORD [
ts: Viewer,
fromDisplay: IO.STREAM,
TORoot, TONode: TiogaOps.Ref,
TNRoot: TextNode.Ref,
TNNode: TextNode.RefTextNode,
looks: TextLooks.Looks,
spaces: REFTEXT,
lineS: SEQUENCE length: NAT OF Line
];
Line:
TYPE =
RECORD [
tiogaCount: NAT,
key: ATOM];
InitTSDisplay:
PROC [cd: CharDisplay, initData:
REF
ANY] = {
tsd: TSDisplay ← NEW [TSDisplayRep[cd.class.lines]];
cd.otherInstanceData ← tsd;
tsd.ts ← TypeScript.Create[info: [name: cd.name, iconic: FALSE]];
TypeScript.ChangeLooks[tsd.ts, 'f];
[in: cd.fromDisplay] ← ViewerIO.CreateViewerStreams[name: cd.name, viewer: tsd.ts, editedStream: FALSE];
EditedStream.SetEcho[cd.fromDisplay, NIL];
tsd.TORoot ← TiogaOps.ViewerDoc[tsd.ts];
tsd.TNRoot ← TiogaOpsRefToTextNodeRef[tsd.TORoot];
tsd.looks ← TextLooks.RopeToLooks["f"];
tsd.spaces ← RefText.New[cd.class.columns];
FOR l:
NAT
IN [0 .. cd.class.lines)
DO
TypeScript.PutChar[tsd.ts, '\n];
tsd.lineS[l] ← [
tiogaCount: 0,
key: Atom.MakeAtom[IO.PutFR["Before%g", IO.int[l]]]
];
ENDLOOP;
SetLines[cd, tsd];
};
SetLines:
PROC [cd: CharDisplay, tsd: TSDisplay] = {
IsBegin:
PROC [ci:
INT]
RETURNS [is:
BOOL] =
INLINE {is ← ci = 0 OR nr.Fetch[ci-1] = '\n};
nr: ROPE;
lineNum, prevCI: INT;
TypeScript.Flush[tsd.ts];
tsd.TONode ← TiogaOps.LastChild[tsd.TORoot];
tsd.TNNode ← TextNode.NarrowToTextNode[TiogaOpsRefToTextNodeRef[tsd.TONode]];
nr ← TiogaOps.GetRope[tsd.TONode];
lineNum ← cd.class.lines;
prevCI ← nr.Length[];
FOR ci:
INT ← nr.Length[]-1, ci-1
WHILE lineNum > 0
DO
IF ci < 0 THEN ERROR;
IF IsBegin[ci]
THEN {
lineNum ← lineNum - 1;
TiogaOps.PutTextKey[node: tsd.TONode, where: ci, key: tsd.lineS[lineNum].key];
tsd.lineS[lineNum].tiogaCount ← prevCI - ci - 1;
prevCI ← ci;
};
ENDLOOP;
};
TiogaOpsRefToTextNodeRef:
PROC [tor: TiogaOps.Ref]
RETURNS [tnr: TextNode.Ref] =
TRUSTED {tnr ← LOOPHOLE[tor] --TiogaOpsImpl says TiogaOpsDefs.NodeBody = TextNode.Body--};
TSTakeChar:
PROC [cd: CharDisplay, char:
CHAR, insert:
BOOL ←
FALSE] = {
tsd: TSDisplay ← NARROW[cd.otherInstanceData];
lock: TEditLocks.LockRef ← NIL;
squash: [0 .. 1] ← IF insert THEN 0 ELSE 1;
base: INT ← TiogaOps.GetTextKey[node: tsd.TONode, key: tsd.lineS[cd.line].key].where;
wasEmpty: BOOL;
wasEmpty ← tsd.lineS[cd.line].tiogaCount = 0;
EnsureLineTo[cd, tsd, cd.line, cd.col+squash];
lock ← TEditLocks.Lock[doc: tsd.TNRoot, who: "Char Displays"];
{
ENABLE UNWIND => IF lock # NIL THEN TEditLocks.Unlock[tsd.TNRoot];
[] ← TextEdit.ReplaceByChar[root: tsd.TNRoot, dest: tsd.TNNode, char: char, start: base + cd.col, len: squash, looks: tsd.looks];
tsd.lineS[cd.line].tiogaCount ← tsd.lineS[cd.line].tiogaCount + 1 - squash;
TEditLocks.Unlock[doc: tsd.TNRoot];
};
IF wasEmpty OR cd.col = 0 THEN SetLines[cd, tsd];
TSCursorMove[cd, 0, 1, TRUE];
};
EnsureLineTo:
PROC [cd: CharDisplay, tsd: TSDisplay, line, col:
INT] = {
diff: INT ← col - tsd.lineS[line].tiogaCount;
lock: TEditLocks.LockRef ← NIL;
base: INT ← TiogaOps.GetTextKey[node: tsd.TONode, key: tsd.lineS[cd.line].key].where;
IF tsd.spaces.maxLength < diff THEN tsd.spaces ← RefText.New[diff];
WHILE tsd.spaces.length < diff
DO
tsd.spaces ← RefText.InlineAppendChar[tsd.spaces, Ascii.SP];
ENDLOOP;
IF diff <= 0 THEN RETURN;
lock ← TEditLocks.Lock[doc: tsd.TNRoot, who: "Char Displays"];
{
ENABLE UNWIND => IF lock # NIL THEN TEditLocks.Unlock[tsd.TNRoot];
[] ← TextEdit.ReplaceByString[root: tsd.TNRoot, dest: tsd.TNNode, string: tsd.spaces, stringStart: 0, stringNum: diff, start: base + tsd.lineS[line].tiogaCount, len: 0, looks: tsd.looks];
tsd.lineS[line].tiogaCount ← tsd.lineS[line].tiogaCount + diff;
TEditLocks.Unlock[doc: tsd.TNRoot];
};
};
TSCursorMove:
PROC [cd: CharDisplay, line, col:
INT, relative:
BOOL ←
FALSE] = {
tsd: TSDisplay ← NARROW[cd.otherInstanceData];
IF relative THEN {line ← line + cd.line; col ← col + cd.col};
IF cd.class.autoMargins
THEN {
dl: INT ← col / cd.class.columns;
line ← line + dl;
col ← col - dl * cd.class.columns;
}
ELSE col ← MIN[col, cd.class.columns-1];
IF line < 0 THEN ERROR;
IF line >= cd.class.lines
THEN {
delta: INT ← line - (cd.class.lines-1);
FOR i: INT IN [0 .. delta) DO TypeScript.PutChar[tsd.ts, '\n] ENDLOOP;
line ← line - delta;
SetLines[cd, tsd];
};
cd.line ← line;
cd.col ← col;
};
TSClearAll:
PROC [cd: CharDisplay] = {
TSCursorMove[cd: cd, col: 0, line: cd.class.lines*2];
TSCursorMove[cd: cd, col: 0, line: 0];
};
}.