-- file: EditorUndo.Mesa
-- edited by Brotz, November 12, 1981 4:11 PM
-- edited by Levin, February 22, 1980 12:42 PM

DIRECTORY
Editor USING [CancelTargetSelection, CommandType, RefreshSoThatFirstCharStartsLine,
ResetDeletionBuffer, ResetInsertionBuffer, SwapInsertionWithDeletionBuffer,
SwapMessageWithDeletionBuffer, TurnOnDeliver, UpdateScreen],
exD: FROM "ExceptionDefs" USING [SysBug],
inD: FROM "InteractorDefs" USING [CharIndex, MessageTextNbrPtr, TextSelection,
TextSelectionPtr],
intCommon USING [actionPoint, commandType, editorType, newTargetSelection,
pendingCommandType, target],
vmD: FROM "VirtualMgrDefs" USING [CharIndex, GetMessageSize, InsertRangeInMessage,
MessageRange, ReplaceRangeInMessage];

EditorUndo: PROGRAM
IMPORTS Editor, exD, intC: intCommon, vmD
EXPORTS Editor =

BEGIN
OPEN Editor, inD;


Undo: PUBLIC PROCEDURE [mnp: MessageTextNbrPtr] =
-- Undoes the last command, ignoring subsequent window commands or selections.
BEGIN
commandType: POINTER TO CommandType = @intC.commandType;
actionPoint: POINTER TO CharIndex = @intC.actionPoint;
target: TextSelectionPtr = @intC.target;
modelessEditor: BOOLEAN = (intC.editorType = modeless);
IF commandType↑ = noCommand THEN RETURN;
CancelTargetSelection[];
IF commandType↑ = get THEN
BEGIN -- flip buffers back
SwapMessageWithDeletionBuffer[mnp];
target↑ ← TextSelection[mnp, 0, vmD.GetMessageSize[mnp.message], 0, 0, char, FALSE];
IF modelessEditor THEN {target.start ← target.end; intC.newTargetSelection ← FALSE};
RefreshSoThatFirstCharStartsLine[0, mnp.lines, mnp];
TurnOnDeliver[];
END
ELSE BEGIN
thisInsertionLength: CARDINAL = vmD.GetMessageSize[mnp.deletionBuffer];
thisDeletionLength: CARDINAL = vmD.GetMessageSize[mnp.insertionBuffer];
vmD.ReplaceRangeInMessage
[to: vmD.MessageRange[actionPoint↑,
actionPoint↑ + vmD.GetMessageSize[mnp.insertionBuffer], mnp.message],
from: vmD.MessageRange[0, thisInsertionLength, mnp.deletionBuffer]];
SwapInsertionWithDeletionBuffer[mnp];
target↑ ← TextSelection
[mnp, actionPoint↑, actionPoint↑ + thisInsertionLength, 0, 0, char, FALSE];
IF modelessEditor THEN {target.start ← target.end; intC.newTargetSelection ← FALSE};
UpdateScreen[start: actionPoint↑, nCharsDeleted: thisDeletionLength,
nCharsInserted: thisInsertionLength, mnp: mnp];
END;
commandType↑ ← SELECT commandType↑ FROM
get => get,
insert, append => delete,
delete => insert,
ENDCASE => replace;
END; -- of Undo --


Redo: PUBLIC PROCEDURE [mnp: MessageTextNbrPtr] =
-- Redoes the last command with the Segment [start .. end).
BEGIN
commandType: POINTER TO CommandType = @intC.commandType;
target: TextSelectionPtr = @intC.target;
start: CharIndex ← target.start;
end: CharIndex ← target.end;
modelessEditor: BOOLEAN = (intC.editorType = modeless);
insertionLength: CARDINAL = vmD.GetMessageSize[mnp.insertionBuffer];
deletionBufferLength: CARDINAL = vmD.GetMessageSize[mnp.deletionBuffer];

IF modelessEditor AND start = end THEN RETURN;
SELECT commandType↑ FROM
noCommand, get => RETURN;
insert => IF modelessEditor THEN start ← end ← target.point ELSE end ← start;
append => IF modelessEditor THEN start ← end ← target.point ELSE start ← end;
ENDCASE;

IF commandType↑ = insert OR commandType↑ = append THEN
CancelTargetSelection[]
ELSE target.pendingDelete ← FALSE;
intC.actionPoint ← start;
vmD.ReplaceRangeInMessage
[to: vmD.MessageRange[0, deletionBufferLength, mnp.deletionBuffer],
from: vmD.MessageRange[start, end, mnp.message]];
vmD.ReplaceRangeInMessage[to: vmD.MessageRange[start, end, mnp.message],
from: vmD.MessageRange[0, insertionLength, mnp.insertionBuffer]];
target↑ ← TextSelection[mnp, start, start + insertionLength, 0, 0, char, FALSE];
IF modelessEditor THEN
{target.start ← target.end; intC.newTargetSelection ← FALSE};
UpdateScreen[start: start, nCharsDeleted: end - start,
nCharsInserted: insertionLength, mnp: mnp];
END; -- of Redo --


InsertFromLastCommand: PUBLIC PROCEDURE [mnp: MessageTextNbrPtr] =
-- Only callable if editorType = modal.
BEGIN
target: TextSelectionPtr = @intC.target;
insertionLength: CARDINAL;
IF intC.editorType = modeless OR intC.pendingCommandType = noCommand THEN
exD.SysBug[];
IF (intC.pendingCommandType = insert OR intC.pendingCommandType = append)
AND intC.commandType = delete
THEN BEGIN
SwapInsertionWithDeletionBuffer[mnp];
ResetDeletionBuffer[mnp];
END;
intC.commandType ← intC.pendingCommandType;
intC.actionPoint ← target.point;
intC.pendingCommandType ← noCommand;
CancelTargetSelection[];
insertionLength ← vmD.GetMessageSize[mnp.insertionBuffer];
vmD.InsertRangeInMessage
[targetIndex: target.point, targetMessage: LOOPHOLE[mnp.message],
from: vmD.MessageRange[0, insertionLength, mnp.insertionBuffer]];
target↑ ← TextSelection
[mnp, intC.actionPoint, intC.actionPoint + insertionLength, 0, 0, char, FALSE];
UpdateScreen
[start: intC.actionPoint, nCharsDeleted: 0, nCharsInserted: insertionLength, mnp: mnp];
END; -- of InsertFromLastCommand --


InsertLastDeletion: PUBLIC PROCEDURE [mnp: MessageTextNbrPtr] =
BEGIN
-- Only callable if editor is modeless.
target: TextSelectionPtr = @intC.target;
commandType: POINTER TO CommandType = @intC.commandType;
insertionLength: CARDINAL= vmD.GetMessageSize[mnp.deletionBuffer];
deletionLength: CARDINAL ← 0;
insertionBufferIndex: CharIndex;
IF intC.newTargetSelection THEN
BEGIN
IF target.pendingDelete THEN
BEGIN
target.point ← target.start;
commandType↑ ← replace;
END
ELSE {CancelTargetSelection[]; commandType↑ ← insert};
ResetInsertionBuffer[mnp];
intC.actionPoint ← target.point;
intC.newTargetSelection ← FALSE;
END
ELSE IF commandType↑ = delete THEN commandType↑ ← replace;
insertionBufferIndex ← vmD.GetMessageSize[mnp.insertionBuffer];
-- Move deletion buffer contents to insertion buffer.
vmD.InsertRangeInMessage
[targetIndex: insertionBufferIndex, targetMessage: mnp.insertionBuffer,
from: vmD.MessageRange[0, insertionLength, mnp.deletionBuffer]];
IF target.pendingDelete THEN
BEGIN
-- Move selection to deletion buffer.
deletionLength ← target.end - target.start;
vmD.ReplaceRangeInMessage[to: [0, insertionLength, mnp.deletionBuffer],
from: [target.start, target.end, mnp.message]];
END;
-- Move new stuff to message.
vmD.ReplaceRangeInMessage
[to: [target.point, target.point + deletionLength, LOOPHOLE[mnp.message]],
from: [insertionBufferIndex, insertionBufferIndex + insertionLength, mnp.insertionBuffer]];
target↑ ← TextSelection[mnp, target.point + insertionLength, target.point + insertionLength,
target.point, 0, char, FALSE];
UpdateScreen[start: target.point, nCharsDeleted: deletionLength,
nCharsInserted: insertionLength, mnp: mnp];
END; -- of InsertLastDeletion --


END. -- of EditorUndo --