-- File: ExecKeyboard.mesa
-- edited by Levin, January 20, 1981 5:16 PM
-- edited by Brotz, November 12, 1981 4:25 PM.

DIRECTORY
csD: FROM "CoreStreamDefs" USING [Destroy, GetLength, GetPosition, Open, Position,
Read, Reset, SetPosition, StreamHandle, Write],
Editor USING [ClearSourceSelection],
exD: FROM "ExceptionDefs" USING [SysBug],
inD: FROM "InteractorDefs" USING [CharIndex, TextSelection, TextSelectionPtr],
Inline USING [BITAND, BITOR],
intCommon USING [source],
KeyPrivate USING [charactersAvailable, ks, monitor],
LaurelExecImpDefs USING [takeFromSecondaryChar],
ovD: FROM "OverviewDefs" USING [CharMask, LineBreakValue],
StreamDefs USING [KeyboardHandle, KeyBufChars],
vmD: FROM "VirtualMgrDefs" USING [CharIndex, GetMessageChar, VirtualMessagePtr];

ExecKeyboard: MONITOR LOCKS KeyPrivate.monitor
IMPORTS csD, Editor, exD, Inline, intC: intCommon, KeyPrivate, vmD
EXPORTS LaurelExecImpDefs
SHARES StreamDefs = PUBLIC

BEGIN
OPEN LaurelExecImpDefs;

selectionCS: csD.StreamHandle ← NIL;

InitSourceSelection: PROCEDURE =
BEGIN
selection: inD.TextSelection ← intC.source;
IF selection.start = selection.end THEN exD.SysBug[];
IF ~StuffIntoKeystream[@selection] THEN
BEGIN
oldPosition: csD.Position;
IF selectionCS = NIL THEN selectionCS ← csD.Open[NIL, byte, write];
oldPosition ← csD.GetPosition[selectionCS];
csD.SetPosition[selectionCS, csD.GetLength[selectionCS]];
FOR i: vmD.CharIndex IN [selection.start .. selection.end-1) DO
csD.Write[selectionCS, Inline.BITAND
[vmD.GetMessageChar [selection.mnp.message, i], ovD.CharMask]];
ENDLOOP;
csD.Write[selectionCS, Inline.BITOR
[vmD.GetMessageChar[selection.mnp.message, selection.end-1],
ovD.LineBreakValue]];
csD.SetPosition[selectionCS, oldPosition];
PutCharIntoKeystream[takeFromSecondaryChar];
END;
Editor.ClearSourceSelection[];
END; -- of InitSourceSelection --


GetFromSourceSelection: PROCEDURE RETURNS [char: CHARACTER] =
BEGIN
char ← csD.Read[selectionCS];
IF csD.GetPosition[selectionCS] = csD.GetLength[selectionCS] THEN csD.Reset[selectionCS];
END; -- of GetFromSourceSelection --


FlushSourceSelection: PROCEDURE =
BEGIN
IF selectionCS # NIL THEN {csD.Destroy[selectionCS]; selectionCS←NIL};
END; -- of FlushSourceSelection --


StuffIntoKeystream: ENTRY PROCEDURE[selection: inD.TextSelectionPtr]
RETURNS [BOOLEAN] =
BEGIN
breathingSpace: CARDINAL = 5;
selectionLength: CARDINAL = selection.end - selection.start;
ks: StreamDefs.KeyboardHandle = KeyPrivate.ks;
ksSpace: CARDINAL =
(IF ks.in >= ks.out THEN StreamDefs.KeyBufChars - (ks.in - ks.out)
ELSE ks.out - ks.in) - 1;
message: vmD.VirtualMessagePtr = selection.mnp.message;

IF selectionLength + breathingSpace > ksSpace THEN RETURN[FALSE];
FOR i: vmD.CharIndex IN [selection.start .. selection.end) DO
ks.buffer[ks.in] ← vmD.GetMessageChar[message, i];
ks.in ← (ks.in + 1) MOD StreamDefs.KeyBufChars;
ENDLOOP;
BROADCAST KeyPrivate.charactersAvailable;
RETURN[TRUE]
END;


PutCharIntoKeystream: ENTRY PROCEDURE[char: CHARACTER] =
BEGIN
ks: StreamDefs.KeyboardHandle = KeyPrivate.ks;
newIn: CARDINAL ← (ks.in + 1) MOD StreamDefs.KeyBufChars;
IF newIn ~= ks.out THEN {ks.buffer[ks.in] ← char; ks.in ← newIn};
BROADCAST KeyPrivate.charactersAvailable;
END;

END. -- of ExecKeyboard --