-- file: IntBracketsCom.Mesa -- edited by Brotz, April 9, 1981 2:10 PM -- edited by Schroeder, December 2, 1980 9:59 AM -- edited by Levin, January 27, 1981 12:20 PM DIRECTORY AltoFileDefs, Ascii, crD: FROM "CoreDefs", csD: FROM "CoreStreamDefs", displayCommon: FROM "DisplayCommon", dsD: FROM "DisplayDefs", Editor, exD: FROM "ExceptionDefs", inD: FROM "InteractorDefs", Inline, intCommon: FROM "IntCommon", KeyDefs, ovD: FROM "OverviewDefs", Storage, StreamDefs, String, vmD: FROM "VirtualMgrDefs"; IntBracketsCom: PROGRAM IMPORTS crD, csD, disC: displayCommon, dsD, Editor, exD, inD, Inline, intC: intCommon, Storage, String, vmD EXPORTS inD = BEGIN OPEN inD; -- Purpose: handles user interactions including the display, keyboard and -- mouse. This division gathers together commands and their arguments and is -- responsible for the display of all error messages. -- Global variables -- currentBracketsHouse: HousePtr _ NIL; currentBracketsX: ScreenXCoord; ConfirmBrackets: PUBLIC PROC [hp: HousePtr, acceptWhiteSpace: BOOLEAN _ FALSE, fileExtension: STRING _ NIL] RETURNS [confirmed: BOOLEAN] = -- Accepts keyboard input file name, sets hp.text to this file name, and displays -- it in its display position. Changes area of screen sensitive to mouse to -- reflect new brackets size. Returns Boolean value FALSE if brackets fill in -- is aborted, TRUE if completed. BEGIN aborted: BOOLEAN; dirStream: csD.StreamHandle _ NIL; foundMatch: BOOLEAN _ FALSE; cachePtr: crD.CacheNodePtr _ crD.fileCacheHeader; GetNextFile: PROCEDURE [s: STRING] = BEGIN DVFront: TYPE = MACHINE DEPENDENT RECORD [SELECT OVERLAID * FROM word => [word: UNSPECIFIED], stuff => [type: [AltoFileDefs.DEfree .. AltoFileDefs.DElast], length: [0 .. 1777B]], ENDCASE]; dvFront: DVFront; filename: STRING _ [AltoFileDefs.FilenameChars]; EquivPart: PROCEDURE [s: STRING, part: String.SubString] RETURNS [BOOLEAN] = BEGIN ssd: String.SubStringDescriptor _ [s, 0, s.length]; RETURN[String.EquivalentSubStrings[@ssd, part]]; END; -- of EquivPart -- IsMatch: PROCEDURE [file: STRING] RETURNS [BOOLEAN] = BEGIN ssd: String.SubStringDescriptor; IF file.length <= fileExtension.length THEN RETURN[FALSE]; ssd _ [file, file.length - fileExtension.length, fileExtension.length]; IF EquivPart[fileExtension, @ssd] THEN BEGIN ssd.length _ ssd.offset; ssd.offset _ 0; IF ~EquivPart[s, @ssd] THEN BEGIN s.length _ 0; String.AppendSubString[s, @ssd]; RETURN[TRUE]; END; END; RETURN[FALSE]; END; -- of IsMatch -- -- first cycle through the Alto Core file cache. UNTIL cachePtr = NIL DO IF IsMatch[cachePtr.key] THEN {cachePtr _ cachePtr.next; RETURN} ELSE cachePtr _ cachePtr.next; ENDLOOP; IF dirStream = NIL THEN dirStream _ csD.OpenFromName["SysDir"L, intC.user, byte, read, 2]; DO position: csD.Position; Advance: PROCEDURE = BEGIN csD.SetPosition[dirStream, MIN[position + (dvFront.length -1) * 2, csD.GetLength[dirStream]]]; END; -- of Advance -- SELECT csD.ReadBlock[dirStream, @dvFront.word, 0, 2] FROM 0 => IF foundMatch THEN {csD.Reset[dirStream]; foundMatch _ FALSE; LOOP} ELSE EXIT; 2 => NULL; ENDCASE => exD.SysBug[]; position _ csD.GetPosition[dirStream]; SELECT dvFront.type FROM AltoFileDefs.DEfree => Advance[]; AltoFileDefs.DEfile => BEGIN csD.SetPosition[dirStream, position + (SIZE[AltoFileDefs.DV] -1) * 2]; [] _ csD.ReadBlock [dirStream, @filename.text, 0, filename.length _ csD.Read[dirStream]]; Advance[]; IF IsMatch[filename] THEN {foundMatch _ TRUE; RETURN}; END; ENDCASE => exD.SysBug[]; ENDLOOP; END; -- of GetNextFile -- dsD.ChangeCursor[charArrow]; [aborted, hp.rightX] _ GetStringForBrackets [hp: hp, leftX: hp.leftX, rightX: hp.rightX, maxDeltaX: (IF hp.nextHouse = NIL OR hp.nextHouse.lineNumber # hp.lineNumber THEN inD.rightMargin ELSE hp.nextHouse.leftX) - hp.leftX, bracketFace: boldFace, displayChars: TRUE, initialDisplayString: hp.text, abortString: hp.text, outputString: hp.text, acceptWhiteSpace: acceptWhiteSpace, enumerate: IF fileExtension = NIL THEN NIL ELSE GetNextFile]; IF dirStream ~= NIL THEN csD.Close[dirStream]; dsD.ChangeCursor[hourGlass]; exD.ClearExceptionsRegion[]; RETURN[~aborted] END; -- of ConfirmBrackets -- Confirm: PUBLIC PROC [lineNumber: CARDINAL] RETURNS [confirmed: BOOLEAN] = -- Displays confirmation message on lineNumber of exception region, waits for -- confirmation input from user, displays exception if unexpected input -- received. BEGIN char: CHARACTER; keystream: StreamDefs.StreamHandle = intC.keystream; IF ~disC.bitMapReady THEN RETURN[FALSE]; IF intC.autoConfirm THEN RETURN[TRUE]; SELECT (char _ ConfirmInner[lineNumber]) FROM Ascii.DEL, Editor.cancelCode, 'N, 'n => confirmed _ FALSE; Ascii.ESC, Ascii.SP, 'Y, 'y, Ascii.CR => confirmed _ TRUE; ENDCASE => BEGIN confirmed _ FALSE; exD.DisplayBothExceptionLines[NIL, exD.illegalCommand, NIL, exD.pressToContinue]; DO WHILE keystream.endof[keystream] DO IdleLoop[]; ENDLOOP; IF (char _ keystream.get[keystream]) = Ascii.DEL OR char = Editor.cancelCode THEN EXIT; ENDLOOP; END; exD.ClearExceptionsRegion[]; END; -- of Confirm -- ConfirmInner: PUBLIC PROC [lineNumber: CARDINAL] RETURNS [char: CHARACTER] = -- Displays confirmation message on lineNumber of exception region, waits for -- confirmation input from user, returns character typed by user. BEGIN keystream: StreamDefs.StreamHandle = intC.keystream; cursorState: {black, white} _ white; cursorLastUpdated: CARDINAL; oldCursor: dsD.CursorShape _ dsD.GetCursor[].shape; -- flush keystream keystream.reset[keystream]; SELECT lineNumber FROM 0 => NULL; 1 => exD.DisplayException[exD.confirmMessage]; ENDCASE => exD.DisplayExceptionLine[exD.confirmMessage, lineNumber]; dsD.SetCursor[questionMark]; cursorLastUpdated _ realTimeClock^; WHILE keystream.endof[keystream] AND MouseButton[middle, up] DO IdleLoop[]; IF LOOPHOLE[realTimeClock^ - cursorLastUpdated, CARDINAL] >= 9 THEN BEGIN IF cursorState = white THEN {cursorState _ black; dsD.SetCursor[invertQuestionMark]} ELSE {cursorState _ white; dsD.SetCursor[questionMark]}; cursorLastUpdated _ realTimeClock^; END; ENDLOOP; dsD.SetCursor[oldCursor]; RETURN[IF keystream.endof[keystream] THEN HoldYellow[] ELSE keystream.get[keystream]]; END; -- of ConfirmInner -- AskUserToConfirm: PUBLIC PROCEDURE [exception: exD.Exception] RETURNS [confirmed: BOOLEAN] = -- Displays string corresponding to exception and the confirmation request -- message to user. Returns the user's answer. BEGIN exD.DisplayException[exception]; RETURN[Confirm[2]] END; -- of AskUserToConfirm -- GetStringForBrackets: PUBLIC PROCEDURE [hp: HousePtr, leftX, rightX: ScreenXCoord, maxDeltaX: CARDINAL, bracketFace: dsD.FaceType, displayChars: BOOLEAN, initialDisplayString, abortString, outputString: STRING, acceptWhiteSpace: BOOLEAN _ FALSE, enumerate: PROC [STRING] _ NIL] RETURNS [aborted: BOOLEAN, newRightX: ScreenXCoord] = -- Displays initialDisplayString in brackets. Accepts keyboard input and -- displays it appended to initialDisplayString. If abort (DEL or CANCEL), -- displays abortString in brackets and terminates. On termination (DEL or -- CANCEL or ESC (or DO)), puts the then displayed string in outputString. -- Returns the new right x position. BEGIN state: {fullString, dots}; s: STRING; limX, stringStartX, endOfDots: ScreenXCoord; keystream: StreamDefs.StreamHandle = intC.keystream; charWidth: CARDINAL; trailer: STRING _ " }"L; trailingWidth: CARDINAL = dsD.GetStringWidth[trailer, bracketFace]; i: CARDINAL; firstChar: BOOLEAN _ TRUE; savedInputAcceptor: KeyboardInputAcceptor _ inD.keyboardInputAcceptorPtr^; savedCommandMode: BOOLEAN _ intC.commandMode; FinishedWithBrackets: ERROR = CODE; BracketsInputAcceptor: KeyboardInputAcceptor = BEGIN TerminateBrackets: PROCEDURE [abort: BOOLEAN] = BEGIN IF (aborted _ abort) AND displayChars THEN PutStringInBrackets[abortString]; IF ~aborted OR outputString # abortString THEN BEGIN outputString.length _ 0; String.AppendString[outputString, IF aborted THEN abortString ELSE s]; END; ReplaceTrailerWithBracket[]; ERROR FinishedWithBrackets; END; AcceptNormalChar: PROCEDURE = BEGIN IF firstChar THEN MakeBracketsAndStringEmpty[]; String.AppendChar[s, char ! String.StringBoundsFault => GO TO Ignore]; IF displayChars THEN BEGIN charWidth _ dsD.GetVisibleCharWidth[char]; SELECT state FROM fullString => IF currentBracketsX + charWidth > limX THEN PutLongStringInBrackets[s] ELSE {SlideTrailer[charWidth]; PutCharInBitMap[char]}; dots => RefreshAfterDots[s]; ENDCASE; END; EXITS Ignore => NULL; END; -- of AcceptNormalChar -- StopBlinkingCaret[]; SELECT char FROM Editor.cancelCode, Ascii.DEL => TerminateBrackets[abort: TRUE]; Ascii.ControlW => BackWord[]; Ascii.ESC => TerminateBrackets[abort: FALSE]; Editor.nextBracketStringCode => BEGIN IF enumerate # NIL THEN {enumerate[s]; PutStringInBrackets[s]; firstChar _ TRUE}; SetBracketsCaretBlinking[]; RETURN; END; Ascii.CR, Ascii.SP, Ascii.TAB => IF acceptWhiteSpace THEN BEGIN IF char # Ascii.SP THEN char _ Inline.BITOR[char, ovD.LineBreakValue]; AcceptNormalChar[]; END ELSE TerminateBrackets[abort: FALSE]; Editor.shiftedSelectionFlag => BEGIN IF firstChar THEN MakeBracketsAndStringEmpty[]; InsertSourceSelection[]; END; Editor.insertDeletionCode => BEGIN IF firstChar THEN MakeBracketsAndStringEmpty[]; InsertLastDeletion[]; END; Ascii.BS, Ascii.ControlA => BackSpace[]; ENDCASE => AcceptNormalChar[]; firstChar _ FALSE; SetBracketsCaretBlinking[]; END; -- of BracketsInputAcceptor -- PutCharInBitMap: PROCEDURE [char: CHARACTER] = BEGIN currentBracketsX _ dsD.PutCharInBitMap[char, currentBracketsX, currentBracketsHouse.topY, plainFace]; END; -- of PutCharInBitMap -- PutStringInBitMap: PROCEDURE [s: STRING] = BEGIN FOR i: CARDINAL IN [0 .. s.length) DO PutCharInBitMap[s[i]]; ENDLOOP; END; -- of PutStringInBitMap -- GetVisibleStringWidth: PROCEDURE [s: STRING] RETURNS [width: CARDINAL] = BEGIN width _ 0; FOR i: CARDINAL IN [0 .. s.length) DO width _ width + dsD.GetVisibleCharWidth[s[i]]; ENDLOOP; END; -- of GetVisibleStringWidth -- SlideTrailer: PROCEDURE [amount: INTEGER] = INLINE BEGIN dsD.SlideRectangleHorizontally[currentBracketsX, currentBracketsX + trailingWidth, currentBracketsHouse.topY, currentBracketsHouse.bottomY, amount]; END; -- of SlideTrailer -- ReplaceTrailerWithBracket: PROCEDURE = BEGIN dsD.ClearRectangle[currentBracketsX, currentBracketsX + trailingWidth, currentBracketsHouse.topY, currentBracketsHouse.bottomY]; newRightX _ dsD.PutCharInBitMap['}, currentBracketsX, currentBracketsHouse.topY, bracketFace]; END; -- of ReplaceTrailerWithBracket -- MakeBracketsAndStringEmpty: PROCEDURE = BEGIN IF s.length > 0 THEN BEGIN s.length _ 0; SlideTrailer[stringStartX - currentBracketsX]; currentBracketsX _ stringStartX; state _ fullString; END; END; -- of MakeBracketsAndStringEmpty -- ResetBrackets: PROCEDURE = BEGIN dsD.ClearRectangle[leftX, currentBracketsX + trailingWidth, currentBracketsHouse.topY, currentBracketsHouse.bottomY]; currentBracketsX _ dsD.PutCharInBitMap ['{, leftX, currentBracketsHouse.topY, bracketFace]; END; -- of ResetBrackets -- RefreshAfterDots: PROCEDURE[s: STRING] = BEGIN x: ScreenXCoord _ endOfDots; FOR i _ s.length-1, i-1 DO IF (x _ dsD.GetVisibleCharWidth[s[i]] + x) > limX THEN EXIT; ENDLOOP; dsD.ClearRectangle[endOfDots, currentBracketsX + trailingWidth, currentBracketsHouse.topY, currentBracketsHouse.bottomY]; currentBracketsX _ endOfDots; FOR i IN [i + 1 .. s.length) DO PutCharInBitMap[s[i]]; ENDLOOP; [] _ dsD.PutStringInBitMap[currentBracketsX, currentBracketsHouse.topY, trailer, bracketFace]; END; -- of RefreshAfterDots -- PutLongStringInBrackets: PROCEDURE [s: STRING] = BEGIN ResetBrackets[]; FOR i IN [0..5] DO PutCharInBitMap[s[i]]; ENDLOOP; PutStringInBitMap["..."L]; endOfDots _ currentBracketsX; state _ dots; RefreshAfterDots[s]; END; -- of PutLongStringInBrackets -- PutShortStringInBrackets: PROCEDURE [s: STRING] = INLINE BEGIN ResetBrackets[]; PutStringInBitMap[s]; [] _ dsD.PutStringInBitMap[currentBracketsX, currentBracketsHouse.topY, trailer, bracketFace]; state _ fullString; END; -- of PutShortStringInBrackets -- PutStringInBrackets: PROCEDURE [s: STRING] = BEGIN IF stringStartX + GetVisibleStringWidth[s] > limX THEN PutLongStringInBrackets[s] ELSE PutShortStringInBrackets[s]; END; -- of PutStringInBrackets -- BackSpace: PROCEDURE = BEGIN IF s.length > 0 THEN BEGIN IF intC.editorType = modal OR (KeyDefs.Keys.FL4 = up AND KeyDefs.Keys.FR5 = up AND KeyDefs.Keys.Spare3 = up) THEN BEGIN -- just a backspace. char: CHARACTER _ s[s.length _ s.length - 1]; IF displayChars THEN BEGIN charWidth _ dsD.GetVisibleCharWidth[char]; SELECT state FROM fullString => BEGIN SlideTrailer[-charWidth]; currentBracketsX _ currentBracketsX - charWidth; END; dots => IF stringStartX + GetVisibleStringWidth[s] <= limX THEN BEGIN ResetBrackets[]; PutStringInBitMap[s]; [] _ dsD.PutStringInBitMap[currentBracketsX, currentBracketsHouse.topY, trailer, bracketFace]; state _ fullString; END ELSE RefreshAfterDots[s]; ENDCASE; END; END ELSE BackWord[]; -- modeless backword. END; END; -- of BackSpace -- BackWord: PROCEDURE = BEGIN -- First, back up over punctuation characters. UNTIL s.length = 0 DO SELECT disC.charPropertyTable[s[s.length - 1]] FROM punctuation, white => s.length _ s.length - 1; ENDCASE => EXIT; ENDLOOP; -- Then, back up over non-punctuation characters. UNTIL s.length = 0 DO SELECT disC.charPropertyTable[s[s.length - 1]] FROM punctuation, white => EXIT; ENDCASE => s.length _ s.length - 1; ENDLOOP; PutStringInBrackets[s]; END; -- of BackWord -- InsertSourceSelection: PROCEDURE = INLINE BEGIN selection: TextSelection _ intC.source; Editor.ClearSourceSelection[]; InsertFromMessage[selection.start, selection.end, selection.mnp.message]; END; -- of InsertSourceSelection -- InsertLastDeletion: PROCEDURE = INLINE BEGIN message: vmD.VirtualMessagePtr = intC.cmTextNbr.deletionBuffer; InsertFromMessage[0, vmD.GetMessageSize[message], message]; END; -- of InsertLastDeletion -- InsertFromMessage: PROCEDURE [start, end: ovD.CharIndex, message: vmD.VirtualMessagePtr] = BEGIN width: CARDINAL; string: STRING _ [maxBracketStringLength]; char: CHARACTER; end _ MIN[end, start + s.maxlength - s.length]; FOR i: ovD.CharIndex IN [start .. end) DO SELECT (char _ Inline.BITAND[vmD.GetMessageChar[message, i], ovD.CharMask]) FROM Ascii.CR, Ascii.SP, Ascii.TAB => IF acceptWhiteSpace THEN BEGIN IF char # Ascii.SP THEN char _ Inline.BITOR[char, ovD.LineBreakValue]; String.AppendChar[string, char]; END ELSE {keystream.putback[keystream, Ascii.ESC]; EXIT}; ENDCASE => String.AppendChar[string, char]; ENDLOOP; String.AppendString[s, string]; width _ GetVisibleStringWidth[string]; IF displayChars THEN SELECT state FROM fullString => IF currentBracketsX + width > limX THEN PutLongStringInBrackets[s] ELSE {SlideTrailer[width]; PutStringInBitMap[string]}; dots => RefreshAfterDots[s]; ENDCASE; END; -- of InsertFromMessage -- currentBracketsHouse _ hp; s _ Storage.String[outputString.maxlength]; String.AppendString[s, initialDisplayString]; limX _ leftX + maxDeltaX - trailingWidth; currentBracketsX _ rightX - trailingWidth; -- rightX may not equal leftX+maxDeltaX stringStartX _ dsD.GetStringWidth["{"L, bracketFace] + leftX; PutStringInBrackets[s]; keyboardInputAcceptorPtr^ _ BracketsInputAcceptor; intC.commandMode _ FALSE; SetBracketsCaretBlinking[]; ScreenTracker[brackets ! FinishedWithBrackets => CONTINUE]; currentBracketsHouse _ NIL; Storage.FreeString[s]; keyboardInputAcceptorPtr^ _ savedInputAcceptor; intC.commandMode _ savedCommandMode; END; -- of GetStringForBrackets -- SetBracketsCaretBlinking: PUBLIC PROCEDURE = -- Like StartBlinkingCaret, but works with the current caret in brackets. BEGIN IF currentBracketsHouse = NIL THEN ERROR; StartBlinkingCaret[currentBracketsX, (currentBracketsHouse.topY + currentBracketsHouse.bottomY) / 2]; END; -- of SetBracketsCaretBlinking -- HoldYellow: PRIVATE PROCEDURE RETURNS [char: CHARACTER] = BEGIN keystream: StreamDefs.StreamHandle = intC.keystream; char _ Ascii.ESC; UNTIL MouseButton[middle, up] DO IdleLoop[]; IF ~keystream.endof[keystream] THEN char _ keystream.get[keystream]; IF MouseButton[left, down] OR MouseButton[right, down] THEN char _ IF intC.editorType = modeless THEN Editor.cancelCode ELSE Ascii.DEL; ENDLOOP; END; -- of HoldYellow -- END. -- of IntBracketsCom --z20461(529)\f1