-- file: EditorMain.Mesa -- edited by Schroeder, January 25, 1980 9:24 AM -- edited by Brotz, November 12, 1981 4:09 PM -- edited by Levin, February 22, 1980 12:42 PM DIRECTORY Ascii USING [BS, ControlW, DEL, ESC], dsD: FROM "DisplayDefs" USING [ChangeCursor, CursorShape, GetCursor], Editor USING [AcceptTypeIn, BracketCommand, ButlersBoundaryCommand, cancelCode, ClearSourceSelection, ComKey, CommandType, DeUnderlineSelection, FCommand, GCommand, insertDeletionCode, InsertFromLastCommand, InsertLastDeletion, nextCode, PCommand, Redo, RefreshFromFirstChange, SCommand, SelectEverything, SelectNextBlank, shiftedSelectionFlag, ShiftKey, TCommand, UnderlineSelection, Undo, UnrecognizedCommand], exD: FROM "ExceptionDefs" USING [ClearExceptionsRegion, SysBug], inD: FROM "InteractorDefs" USING [CaretIsBlinking, CharIndex, HousePtr, KeyboardInputAcceptor, MessageTextNbrPtr, SetCaretBlinking, StopBlinkingCaret, TextHouseRefresher, TextSelection, TextSelectionPtr], intCommon USING [actionPoint, commandMode, commandType, composedMessageEdited, deliverCommandHouse, deliverCommandVisible, editorType, newTargetSelection, pendingCommandType, runCommandMode, secondarySelectionEnabled, source, target], String USING [AppendString, LowerCase], vmD: FROM "VirtualMgrDefs" USING [CharIndex, ComposedMessage, ComposedMessagePtr, DeleteRangeInMessage, DisplayMessage, GetMessageSize, InsertRangeInMessage, MessageRange, ReplaceRangeInMessage, UnlockTOC]; EditorMain: PROGRAM IMPORTS dsD, Editor, exD, inD, intC: intCommon, String, vmD EXPORTS Editor = BEGIN OPEN Editor, inD; -- Editor Department of the Interactor Division -- Implements the editor for the composed message. Commands are: Insert, -- Append, Replace, Delete, Undo, Redo. Other operations (which are not -- commands per se) are selection, scrolling, and command aborting. -- Selection convention: a range is represented by a nonempty half open -- interval; a point is represented by an empty half open interval; selection -- beyond the message end is represented by the point [messageLength .. -- messageLength). -- Private global variables -- modelessEditor: BOOLEAN = (intC.editorType = modeless); deleteChar: CHARACTER = IF modelessEditor THEN Ascii.DEL ELSE 'd; target: TextSelectionPtr = @intC.target; source: TextSelectionPtr = @intC.source; secondarySelectionEnabled: POINTER TO BOOLEAN = @intC.secondarySelectionEnabled; Decode: PUBLIC KeyboardInputAcceptor = -- PROCEDURE [mnp: MessageTextNbrPtr, char: CHARACTER] -- Dispatches to specific routines for handling a specific editor command. Fixes up scratch -- buffer and lastCommand upon return of any of the command routines. BEGIN commandMode: POINTER TO BOOLEAN = @intC.commandMode; savedUpperLeftCharIndex: CharIndex _ mnp.lines.firstCharIndex; savedCursor: dsD.CursorShape; interpretChar: BOOLEAN _ char = Ascii.ESC OR char = Ascii.DEL OR char = shiftedSelectionFlag OR (IF ~modelessEditor THEN commandMode^ ELSE ComKey[down] OR char = cancelCode OR char = insertDeletionCode OR char = nextCode); IF ~mnp.haveMessage AND char # shiftedSelectionFlag AND ~(interpretChar AND (char IN ['0 .. '9])) THEN RETURN; exD.ClearExceptionsRegion[]; [savedCursor, , ] _ dsD.GetCursor[]; StopBlinkingCaret[]; IF interpretChar THEN BEGIN char _ String.LowerCase[char]; SELECT char FROM 'i => StartInsertionCommand[mnp, insert]; 'a => StartInsertionCommand[mnp, append]; 'd, deleteChar => DCommand[mnp]; Ascii.DEL => AbortTypeinCommand[mnp]; -- only possible if modal editor. 'r => RCommand[mnp]; 'u, cancelCode => Undo[mnp]; 'g => GCommand[mnp]; 'p => PCommand[mnp]; -- Editor.shiftedSelectionFlag (untypeable) is flag for shifted insertion. shiftedSelectionFlag => InsertSourceSelection[mnp]; Ascii.ESC => BEGIN IF commandMode^ OR modelessEditor THEN Redo[mnp] ELSE IF secondarySelectionEnabled^ THEN BEGIN IF source.end = 0 THEN InsertFromLastCommand[mnp] ELSE InsertSourceSelection[mnp]; END ELSE TerminateInsertion[mnp]; commandMode^ _ TRUE; secondarySelectionEnabled^ _ FALSE; END; Ascii.BS => IF modelessEditor THEN AcceptTypeIn[mnp, Ascii.ControlW] ELSE UnrecognizedCommand[]; 'e => SelectEverything[mnp]; nextCode => IF modelessEditor THEN SelectNextBlank[mnp, ShiftKey[up]] ELSE UnrecognizedCommand[]; insertDeletionCode => IF modelessEditor THEN InsertLastDeletion[mnp] ELSE UnrecognizedCommand[]; 's => SCommand[]; 'f => FCommand[]; 't => TCommand[mnp]; 'b, '', '", '[, '<, '(, '{, '- => BracketCommand[mnp, char]; IN ['0 .. '9] => ButlersBoundaryCommand[char - '0]; ENDCASE => {CancelSourceSelection[mnp]; UnrecognizedCommand[]}; END ELSE BEGIN CancelSourceSelection[mnp]; AcceptTypeIn[mnp, char]; IF modelessEditor THEN TurnOnDeliver[]; END; dsD.ChangeCursor[savedCursor]; intC.runCommandMode _ FALSE; IF CaretIsBlinking[] THEN SetCaretBlinking[target.point, mnp]; END; -- of Decode -- StartInsertionCommand: PROCEDURE [mnp: MessageTextNbrPtr, cType: CommandType] = BEGIN target.point _ IF cType = insert THEN target.start ELSE target.end; IF ~modelessEditor THEN BEGIN intC.commandMode _ FALSE; secondarySelectionEnabled^ _ TRUE; intC.pendingCommandType _ cType; END; IF target.pendingDelete THEN {CancelTargetSelection[]; DoTargetSelection[]}; END; -- of StartInsertionCommand -- DCommand: PROCEDURE [mnp: MessageTextNbrPtr] = -- Deletes the selected text from the composed message. BEGIN IF target.start # target.end THEN BEGIN Deleter[mnp]; ResetInsertionBuffer[mnp]; DoTargetSelection[]; END; END; -- of DCommand -- AbortTypeinCommand: PROCEDURE [mnp: MessageTextNbrPtr] = INLINE -- Processes a DEL in the modal editor BEGIN IF secondarySelectionEnabled^ THEN BEGIN CancelSourceSelection[mnp]; -- abort pending command. IF intC.pendingCommandType = noCommand THEN exD.SysBug[]; IF intC.pendingCommandType = replace THEN Undo[mnp]; intC.pendingCommandType _ noCommand; END ELSE IF intC.commandMode THEN UnrecognizedCommand[] ELSE TerminateInsertion[mnp]; intC.commandMode _ TRUE; END; -- of AbortTypeinCommand -- RCommand: PROCEDURE [mnp: MessageTextNbrPtr] = INLINE -- Initiates a Replace operation. BEGIN IF modelessEditor THEN DCommand[mnp] ELSE BEGIN IF intC.commandType = delete THEN BEGIN -- save previous deletion for possible 'R ESC' insertion. SwapInsertionWithDeletionBuffer[mnp]; ResetDeletionBuffer[mnp]; END; Deleter[mnp]; intC.commandMode _ intC.newTargetSelection _ FALSE; secondarySelectionEnabled^ _ TRUE; intC.pendingCommandType _ replace; END; END; -- of RCommand -- Deleter: PUBLIC PROCEDURE [mnp: MessageTextNbrPtr] = -- Deletes primary selection from mnp.message. Sets new primary selection to the -- null range at the start of the just used primary selection. Depends on caller -- to adjust primary selection after return if default selection is desired. BEGIN start: CharIndex = target.start; end: CharIndex = target.end; target.pendingDelete _ FALSE; vmD.ReplaceRangeInMessage [to: vmD.MessageRange[0, vmD.GetMessageSize[mnp.deletionBuffer], mnp.deletionBuffer], from: vmD.MessageRange[start, end, mnp.message]]; vmD.DeleteRangeInMessage[from: vmD.MessageRange[start, end, mnp.message]]; intC.actionPoint _ start; intC.commandType _ delete; target^ _ TextSelection[mnp, start, start, start, 0, char, FALSE]; target.point _ start; RefreshFromFirstChange[actionIndex: start, deletedChars: end - start, insertedChars: 0, mnp: mnp]; TurnOnDeliver[]; END; -- of Deleter -- InsertSourceSelection: PROCEDURE [mnp: MessageTextNbrPtr] = BEGIN commandType: POINTER TO CommandType = @intC.commandType; actionPoint: POINTER TO CharIndex = @intC.actionPoint; start, end: CharIndex; modalSecondaryInsertion: BOOLEAN = (~modelessEditor AND secondarySelectionEnabled^); sourceSel: TextSelection = source^; newInsertion: BOOLEAN = intC.newTargetSelection OR sourceSel.pendingDelete; insertionLength: CARDINAL = sourceSel.end - sourceSel.start; insertionBufferLength: CharIndex; message: vmD.ComposedMessagePtr = vmD.ComposedMessage[mnp.message]; ClearSourceSelection[unlock: FALSE]; BEGIN -- for EXITS -- IF insertionLength = 0 OR ~mnp.haveMessage THEN GO TO UnlockSourceSel; IF modalSecondaryInsertion THEN ResetInsertionBuffer[mnp]; IF modelessEditor AND newInsertion THEN ResetBuffers[mnp]; IF sourceSel.pendingDelete THEN BEGIN delStart, delEnd, targetStart, targetEnd, targetPoint: CharIndex; overlap: CARDINAL _ 0; DeUnderlineSelection[target, target]; targetPoint _ targetStart _ IF target.pendingDelete THEN target.start ELSE target.point; targetEnd _ IF target.pendingDelete THEN target.end ELSE target.point; delStart _ MIN[sourceSel.start, targetStart]; delEnd _ MAX[sourceSel.end, targetEnd]; vmD.InsertRangeInMessage[targetIndex: 0, targetMessage: mnp.deletionBuffer, from: vmD.MessageRange[delStart, delEnd, message]]; vmD.DeleteRangeInMessage[from: [sourceSel.start, sourceSel.end, message]]; SELECT TRUE FROM (targetStart IN [sourceSel.start .. sourceSel.end)) => BEGIN IF targetEnd > sourceSel.end THEN vmD.DeleteRangeInMessage[ [sourceSel.start, sourceSel.start + (targetEnd - sourceSel.end), message]]; targetPoint _ sourceSel.start; overlap _ MIN[sourceSel.end, targetEnd] - targetStart; END; (targetEnd IN [sourceSel.start .. sourceSel.end)) => BEGIN vmD.DeleteRangeInMessage[[targetStart, sourceSel.start, message]]; overlap _ targetEnd - sourceSel.start; END; (targetStart <= sourceSel.start AND targetEnd >= sourceSel.end) => BEGIN vmD.DeleteRangeInMessage [[targetStart, targetEnd - insertionLength, message]]; overlap _ insertionLength; END; (targetStart >= sourceSel.end) => BEGIN vmD.DeleteRangeInMessage[ [targetStart - insertionLength, targetEnd - insertionLength, message]]; targetPoint _ targetStart - insertionLength; END; ENDCASE => vmD.DeleteRangeInMessage[[targetStart, targetEnd, message]]; vmD.InsertRangeInMessage[targetPoint, message, [sourceSel.start - delStart, sourceSel.end - delStart, mnp.deletionBuffer]]; vmD.InsertRangeInMessage[0, mnp.insertionBuffer, [delStart, delEnd - (targetEnd - targetStart - overlap), message]]; actionPoint^ _ delStart; commandType^ _ replace; target^ _ [mnp, targetPoint + insertionLength, targetPoint + insertionLength, 0, 0, char, FALSE]; UpdateScreen[start: delStart, nCharsDeleted: delEnd - delStart, nCharsInserted: vmD.GetMessageSize[mnp.insertionBuffer], mnp: mnp, select: TRUE]; target.point _ targetPoint + insertionLength; intC.newTargetSelection _ TRUE; GO TO UnlockSourceSel; END; insertionBufferLength _ vmD.GetMessageSize[mnp.insertionBuffer]; vmD.InsertRangeInMessage [targetIndex: insertionBufferLength, targetMessage: mnp.insertionBuffer, from: vmD.MessageRange[sourceSel.start, sourceSel.end, sourceSel.mnp.message]]; IF target.pendingDelete THEN BEGIN target.pendingDelete _ FALSE; actionPoint^ _ start _ target.start; end _ target.end; commandType^ _ replace; vmD.InsertRangeInMessage [targetIndex: 0, targetMessage: mnp.deletionBuffer, from: [start, end, message]]; END ELSE BEGIN start _ end _ target.point; IF newInsertion THEN BEGIN DeUnderlineSelection[target, target]; actionPoint^ _ target.point; commandType^ _ insert; END ELSE BEGIN IF ~modelessEditor THEN commandType^ _ intC.pendingCommandType ELSE SELECT commandType^ FROM delete => commandType^ _ replace; insert, replace => NULL; ENDCASE => commandType^ _ insert; END; END; vmD.ReplaceRangeInMessage[to: [start, end, message], from: vmD.MessageRange[insertionBufferLength, insertionBufferLength + insertionLength, mnp.insertionBuffer]]; target^ _ TextSelection[mnp, start, start + insertionLength, 0, 0, char, FALSE]; IF modalSecondaryInsertion THEN {intC.pendingCommandType _ noCommand; actionPoint^ _ start} ELSE {target.start _ target.end; intC.newTargetSelection _ FALSE}; UpdateScreen[start: start, nCharsDeleted: end - start, nCharsInserted: insertionLength, mnp: mnp, select: modalSecondaryInsertion]; GO TO UnlockSourceSel; EXITS UnlockSourceSel => BEGIN IF (sourceSel.key = 0) # sourceSel.mnp.editable THEN exD.SysBug[]; IF sourceSel.key # 0 THEN vmD.UnlockTOC[vmD.DisplayMessage[sourceSel.mnp.message].toc, sourceSel.key]; END; END; -- for EXITS block -- END; -- of InsertSourceSelection -- TerminateInsertion: PROCEDURE [mnp: MessageTextNbrPtr] = BEGIN IF intC.pendingCommandType = noCommand THEN exD.SysBug[]; intC.commandType _ intC.pendingCommandType; IF intC.pendingCommandType # replace THEN ResetDeletionBuffer[mnp]; intC.pendingCommandType _ noCommand; target^ _ TextSelection[mnp, intC.actionPoint, target.point, target.point, 0, char, FALSE]; DoTargetSelection[]; TurnOnDeliver[]; END; -- of TerminateInsertion -- CancelTargetSelection: PUBLIC PROCEDURE = BEGIN DeUnderlineSelection[target, target]; target.pendingDelete _ FALSE; intC.newTargetSelection _ FALSE; END; -- of CancelTargetSelection -- DoTargetSelection: PUBLIC PROCEDURE = BEGIN IF ~modelessEditor AND target.start = target.end THEN target.end _ MIN[target.end + 1, vmD.GetMessageSize[target.mnp.message]]; UnderlineSelection[target, target]; intC.newTargetSelection _ (target.start # target.end); END; -- of DoTargetSelection -- CancelSourceSelection: PUBLIC PROCEDURE [mnp: MessageTextNbrPtr] = BEGIN IF modelessEditor OR ~secondarySelectionEnabled^ THEN RETURN; secondarySelectionEnabled^ _ FALSE; IF source.end # 0 THEN ClearSourceSelection[]; IF intC.pendingCommandType = replace THEN ResetInsertionBuffer[mnp]; END; -- of CancelSourceSelection -- UpdateScreen: PUBLIC PROCEDURE [start: CharIndex, nCharsDeleted, nCharsInserted: CARDINAL, mnp: MessageTextNbrPtr, select: BOOLEAN _ TRUE] = -- Shortcut call to screen refreshers. Updates selections and Deliver command as well. BEGIN RefreshFromFirstChange [actionIndex: start, deletedChars: nCharsDeleted, insertedChars: nCharsInserted, mnp: mnp]; target.point _ start + nCharsInserted; IF select THEN DoTargetSelection[]; TurnOnDeliver[]; END; -- of UpdateScreen -- ResetBuffers: PUBLIC PROCEDURE [mnp: MessageTextNbrPtr] = -- Resets both mnp.insertionBufffer and mnp.deletionBuffer. BEGIN ResetInsertionBuffer[mnp]; ResetDeletionBuffer[mnp]; intC.commandType _ noCommand; intC.actionPoint _ 0; END; -- of ResetBuffers -- ResetDeletionBuffer: PUBLIC PROCEDURE [mnp: MessageTextNbrPtr] = BEGIN vmD.DeleteRangeInMessage [from: vmD.MessageRange[0, vmD.GetMessageSize[mnp.deletionBuffer], mnp.deletionBuffer]]; END; -- of ResetDeletionBuffer -- ResetInsertionBuffer: PUBLIC PROCEDURE [mnp: MessageTextNbrPtr] = -- Resets mnp.insertionBuffer to be empty. BEGIN vmD.DeleteRangeInMessage [from: vmD.MessageRange[0, vmD.GetMessageSize[mnp.insertionBuffer], mnp.insertionBuffer]]; END; -- of ResetInsertionBuffer -- SwapMessageWithDeletionBuffer: PUBLIC PROCEDURE [mnp: MessageTextNbrPtr] = -- Exchanges contents of mnp.message with mnp.deletionBuffer. BEGIN tempBuffer: vmD.ComposedMessagePtr _ mnp.deletionBuffer; mnp.deletionBuffer _ vmD.ComposedMessage[mnp.message]; mnp.message _ tempBuffer; END; -- of SwapMessageWithDeletionBuffer -- SwapMessageWithInsertionBuffer: PUBLIC PROCEDURE [mnp: MessageTextNbrPtr] = -- Exchanges contents of mnp.message with mnp.insertionBuffer. BEGIN tempBuffer: vmD.ComposedMessagePtr _ mnp.insertionBuffer; mnp.insertionBuffer _ vmD.ComposedMessage[mnp.message]; mnp.message _ tempBuffer; END; -- of SwapMessageWithInsertionBuffer -- SwapInsertionWithDeletionBuffer: PUBLIC PROCEDURE [mnp: MessageTextNbrPtr] = -- Exchanges contents of mnp.insertionBuffer with mnp.deletionBuffer. BEGIN tempBuffer: vmD.ComposedMessagePtr _ mnp.insertionBuffer; mnp.insertionBuffer _ mnp.deletionBuffer; mnp.deletionBuffer _ tempBuffer; END; -- of SwapInsertionWithDeletionBuffer -- TurnOnDeliver: PUBLIC PROCEDURE = BEGIN deliverCommandHouse: HousePtr = intC.deliverCommandHouse; intC.composedMessageEdited _ TRUE; IF deliverCommandHouse.typeface ~= boldFace THEN BEGIN deliverCommandHouse.text.length _ 0; String.AppendString[deliverCommandHouse.text, "Deliver"L]; deliverCommandHouse.typeface _ boldFace; deliverCommandHouse.callable _ TRUE; IF intC.deliverCommandVisible THEN TextHouseRefresher[deliverCommandHouse]; END; END; -- of TurnOnDeliver -- END. -- of EditorMain -- z19932(635)\f1