-- file: EditorFind.Mesa -- edited by Brotz, April 27, 1981 4:38 PM -- edited by Barth, December 15, 1980 4:18 PM -- edited by Schroeder, March 15, 1981 3:17 PM DIRECTORY Ascii, dsD: FROM "DisplayDefs", Editor, exD: FROM "ExceptionDefs", inD: FROM "InteractorDefs", Inline, intCommon: FROM "IntCommon", lmD: FROM "LaurelMenuDefs", ovD: FROM "OverviewDefs", Storage, String, vmD: FROM "VirtualMgrDefs"; EditorFind: PROGRAM IMPORTS dsD, Editor, exD, inD, intC: intCommon, Inline, lmD, Storage, String, vmD EXPORTS Editor, inD SHARES vmD = BEGIN OPEN Editor, inD; FCommand: PUBLIC PROCEDURE = BEGIN lmD.ChangeEditorMenu[find]; IndicateCommandBusy[intC.currentCommand _ intC.findHouse]; FindCommand[intC.findHouse, FALSE]; intC.currentCommand _ NIL; IndicateCommandFinished[intC.findHouse]; END; -- of FCommand -- FindCommand: PUBLIC CommandProcedure = -- Starting at the current selection, searches for text in following brackets. If -- found, selects the found text and normalizes it in the composed message -- region. BEGIN mnp: MessageTextNbrPtr = intC.cmTextNbr; target: TextSelectionPtr = @intC.target; found: BOOLEAN; at, atEnd: ovD.CharIndex; IF ~mnp.haveMessage THEN RETURN; IF ~confirmed THEN BEGIN DisplayFindSyntaxHint[]; IF ~ConfirmBrackets[intC.findBracketsHouse, TRUE] THEN RETURN; END; [found, at, atEnd] _ FindOperation[intC.findBracketsHouse.text, target.end, vmD.GetMessageSize[mnp.message], mnp]; IF found THEN BEGIN CancelTargetSelection[]; CancelSourceSelection[mnp]; StopBlinkingCaret[]; target^ _ TextSelection [mnp, at, atEnd, at, char, intC.editorType = modeless AND at < atEnd]; intC.pendingDeleteSetByControl _ FALSE; DoTargetSelection[]; [] _ MakeCharIndexVisible[at, mnp]; IF intC.editorType = modeless THEN SetCaretBlinking[target.point, mnp]; END ELSE exD.DisplayException[exD.textNotFound]; END; -- of FindCommand -- DisplayFindSyntaxHint: PROCEDURE = BEGIN exD.DisplayExceptionLine[exD.findHintOne, 1]; exD.DisplayExceptionLine[exD.findHintTwo, 2]; END; -- of DisplayFindSyntaxHint -- SCommand: PUBLIC PROCEDURE = BEGIN lmD.ChangeEditorMenu[substitute]; IndicateCommandBusy[intC.currentCommand _ intC.substituteHouse]; SubstituteCommand[intC.substituteHouse, FALSE]; intC.currentCommand _ NIL; IndicateCommandFinished[intC.substituteHouse]; END; -- of SCommand -- SubstituteCommand: PUBLIC CommandProcedure = -- Within the bounds of the current selection, substitutes the text in the -- following brackets for each occurence of the text in the preceding brackets. BEGIN target: TextSelectionPtr = @intC.target; originalStart, start, end, at, atEnd, patternEnd: ovD.CharIndex; mnp: MessageTextNbrPtr _ target.mnp; composedMessage: vmD.ComposeMessagePtr _ LOOPHOLE[mnp.message]; old: STRING _ intC.substituteOldBracketsHouse.text; new: STRING _ intC.substituteNewBracketsHouse.text; normalNew: STRING _ [maxBracketStringLength]; found: BOOLEAN; matchedLength, putLength: CARDINAL; count: CARDINAL _ 0; IF ~mnp.haveMessage THEN RETURN; IF ~confirmed THEN BEGIN IF ~ConfirmBrackets[intC.substituteNewBracketsHouse, TRUE] THEN RETURN; DisplayFindSyntaxHint[]; IF ~ConfirmBrackets[intC.substituteOldBracketsHouse, TRUE] THEN {exD.ClearExceptionsRegion[]; RETURN}; END; putLength _ MIN[new.length, old.length]; originalStart _ start _ target.start; end _ target.end; exD.ClearExceptionsRegion[]; FOR i: CARDINAL IN [0 .. new.length) DO normalNew[i] _ Inline.BITAND[new[i], ovD.CharMask]; ENDLOOP; DO [found, at, atEnd, patternEnd] _ FindOperation[old, start, end, mnp]; IF ~found THEN EXIT; IF count = 0 THEN BEGIN -- save selected range for undo. ResetBuffers[mnp]; InsertRangeInMess[0, mnp.deletionBuffer, [start, end, composedMessage]]; intC.commandType _ replace; intC.actionPoint _ originalStart; END; count _ count + 1; matchedLength _ atEnd - at; end _ end + new.length - matchedLength; putLength _ MIN[new.length, matchedLength]; FOR i: CARDINAL IN [0 .. putLength) DO vmD.PutMessageChar[composedMessage, at + i, normalNew[i]]; ENDLOOP; SELECT new.length FROM < matchedLength => vmD.DeleteRangeInMessage [from: [start: at + putLength, end: atEnd, message: composedMessage]]; > matchedLength => BEGIN vmD.StartMessageInsertion[composedMessage, at + putLength]; [] _ vmD.InsertSubstringInMessage[composedMessage, normalNew, putLength, new.length - putLength]; vmD.StopMessageInsertion[composedMessage]; END; ENDCASE; start _ at + new.length + (patternEnd - atEnd); ENDLOOP; IF count > 0 THEN BEGIN InsertRangeInMess [0, mnp.insertionBuffer, [target.start, end, composedMessage]]; IF intC.editorType = modeless THEN StopBlinkingCaret[]; IF count = 1 THEN exD.DisplayExceptionLine[exD.oneSubMade, 1] ELSE BEGIN countMessage: STRING _ [30]; String.AppendDecimal[countMessage, count]; String.AppendString[countMessage, " substitutions made."L]; exD.DisplayExceptionStringOnLine[countMessage, 1]; END; target.pendingDelete _ FALSE; target.end _ end; target.mode _ char; target.point _ end; SetHighWaterMark[0]; RefreshToPlaceCharOnLine[originalStart, mnp.lines, mnp, TRUE]; IF intC.editorType = modeless THEN SetCaretBlinking[end, mnp]; intC.composedMessageEdited _ TRUE; TurnOnDeliver[]; END ELSE exD.DisplayException[exD.noSubMade]; END; -- of SubstituteCommand -- FindOperation: PUBLIC PROCEDURE [s: STRING, start, end: ovD.CharIndex, mnp: MessageTextNbrPtr] RETURNS [found: BOOLEAN, at, atEnd, patternEnd: ovD.CharIndex] = -- Searches for a match to s within [start .. end) of mnp.message. If found, returns TRUE, -- with [at .. atEnd) the matched range, BEGIN anyStringPattern: CHARACTER = ovD.LineBreakValue; oneCharPattern: CHARACTER = ovD.LineBreakValue + 1; oneAlphaPattern: CHARACTER = ovD.LineBreakValue + 2; oneNonAlphaPattern: CHARACTER = ovD.LineBreakValue + 3; anyAlphaPattern: CHARACTER = ovD.LineBreakValue + 4; anyNonAlphaPattern: CHARACTER = ovD.LineBreakValue + 5; leftBracketPattern: CHARACTER = ovD.LineBreakValue + 6; rightBracketPattern: CHARACTER = ovD.LineBreakValue + 7; StackArray: TYPE = ARRAY [1 .. maxBracketStringLength] OF CARDINAL; textPosStack, patternPosStack: POINTER TO StackArray; patternString: STRING _ [maxBracketStringLength]; char, patternChar, firstPatChar1, firstPatChar2: CHARACTER _ 377C; charType: dsD.CharProperty; psIndex: CARDINAL _ 0; beginPos, endPos, patternPos, textPos, patternAnchor, textAnchor: CARDINAL; stackPtr: [0..maxBracketStringLength] _ 0; message: vmD.VirtualMessagePtr = mnp.message; get: POINTER TO vmD.CharCache _ @message.get; leftBracketSeen, rightBracketSeen: BOOLEAN _ FALSE; firstPatternCharIsNormal: BOOLEAN _ FALSE; found _ FALSE; -- start of main line code for FindOperation -- -- first, normalize search string, processing special characters. IF s.length > maxBracketStringLength THEN exD.SysBug[]; BEGIN -- for EXITS. i: CARDINAL; FOR i _ 0, i + 1 UNTIL i >= s.length DO SELECT (char _ Inline.BITAND[s[i], ovD.CharMask]) FROM '' => BEGIN IF i + 1 < s.length THEN i _ i + 1 ELSE GO TO MalformedInput; patternString[psIndex] _ s[i]; IF psIndex = 0 THEN {firstPatternCharIsNormal _ TRUE; firstPatChar1 _ s[i]}; END; IN ['A .. 'Z], IN ['a .. 'z] => BEGIN patternString[psIndex] _ Inline.BITOR[char, ovD.LineBreakValue]; IF psIndex = 0 THEN BEGIN firstPatternCharIsNormal _ TRUE; firstPatChar1 _ String.UpperCase[char]; firstPatChar2 _ String.LowerCase[char]; END; END; '# => patternString[psIndex] _ oneCharPattern; '* => patternString[psIndex] _ anyStringPattern; '@ => patternString[psIndex] _ oneAlphaPattern; '! => patternString[psIndex] _ oneNonAlphaPattern; '& => patternString[psIndex] _ anyAlphaPattern; '~ => patternString[psIndex] _ anyNonAlphaPattern; '{ => patternString[psIndex] _ leftBracketPattern; '} => patternString[psIndex] _ rightBracketPattern; ENDCASE => BEGIN patternString[psIndex] _ char; IF psIndex = 0 THEN {firstPatternCharIsNormal _ TRUE; firstPatChar1 _ char}; END; IF char = '{ THEN {IF leftBracketSeen THEN GO TO MalformedInput ELSE leftBracketSeen _ TRUE}; IF char = '} THEN {IF rightBracketSeen THEN GO TO MalformedInput ELSE rightBracketSeen _ TRUE}; psIndex _ psIndex + 1; ENDLOOP; FOR psIndex _ psIndex, psIndex - 1 UNTIL psIndex = 0 DO SELECT patternString[psIndex - 1] FROM anyStringPattern, anyAlphaPattern, anyNonAlphaPattern => NULL; ENDCASE => EXIT; ENDLOOP; IF (patternString.length _ psIndex) = 0 THEN GO TO MalformedInput; EXITS MalformedInput => {exD.DisplayException[exD.malformedSearchString]; RETURN}; END; -- for EXITS -- Now search. BEGIN -- for EXITS textPosStack _ Storage.Node[SIZE[StackArray]]; patternPosStack _ Storage.Node[SIZE[StackArray]]; FOR at _ start, at + 1 UNTIL at = end DO IF firstPatternCharIsNormal THEN BEGIN char _ Inline.BITAND[ovD.CharMask, IF at IN [get.first .. get.free) THEN get.string[at + get.floor - get.first] ELSE vmD.GetMessageChar[message, at]]; IF char # firstPatChar1 AND char # firstPatChar2 THEN LOOP; patternPos _ 1; textPos _ at + 1; END ELSE {patternPos _ 0; textPos _ at}; -- save where name began matching non-* seg of pattern patternAnchor _ 0; beginPos _ textAnchor _ at; DO IF patternPos >= patternString.length THEN BEGIN found _ TRUE; at _ beginPos; atEnd _ IF rightBracketSeen THEN endPos ELSE textPos; patternEnd _ textPos; GO TO Return; END; SELECT (patternChar _ patternString[patternPos]) FROM anyStringPattern => {patternAnchor _ patternPos _ patternPos + 1; textAnchor _ textPos; stackPtr _ 0}; leftBracketPattern => {beginPos _ textPos; patternPos _ patternPos +1}; rightBracketPattern => {endPos _ textPos; patternPos _ patternPos +1}; anyNonAlphaPattern, anyAlphaPattern => BEGIN stackPtr _ stackPtr + 1; textPosStack[stackPtr] _ textPos; patternPosStack[stackPtr] _ patternPos; patternPos _ patternPos + 1; END; ENDCASE => BEGIN IF textPos >= end THEN GO TO Return; IF patternChar = oneCharPattern THEN BEGIN IF patternPos # 0 AND patternPos = patternAnchor THEN -- first char(s) of * segment {patternAnchor _ patternAnchor + 1; textAnchor _ textPos + 1}; patternPos _ patternPos + 1; textPos _ textPos + 1; END ELSE BEGIN char _ Inline.BITAND [ovD.CharMask, IF textPos IN [get.first .. get.free) THEN get.string[textPos + get.floor - get.first] ELSE vmD.GetMessageChar[message, textPos]]; charType _ dsD.GetCharBreakProp[char]; IF (patternChar = oneNonAlphaPattern AND charType # alphaNumeric) OR (patternChar = oneAlphaPattern AND charType = alphaNumeric) OR (patternChar = char) OR (patternChar > ovD.LineBreakValue AND ((patternChar_Inline.BITAND[ovD.CharMask, patternChar]) IN ['A..'Z] OR patternChar IN ['a .. 'z]) AND String.LowerCase[patternChar] = String.LowerCase[char]) THEN -- chars match -- {patternPos _ patternPos + 1; textPos _ textPos + 1} ELSE BEGIN WHILE stackPtr # 0 DO charType _ dsD.GetCharBreakProp[Inline.BITAND [ovD.CharMask, IF textPosStack[stackPtr] IN [get.first .. get.free) THEN get.string[textPosStack[stackPtr] + get.floor - get.first] ELSE vmD.GetMessageChar[message, textPosStack[stackPtr]]]]; IF (patternString[patternPosStack[stackPtr]] = anyNonAlphaPattern AND charType # alphaNumeric) OR (patternString[patternPosStack[stackPtr]] = anyAlphaPattern AND charType = alphaNumeric) THEN BEGIN patternPos _ patternPosStack[stackPtr] + 1; textPos _ textPosStack[stackPtr] _ textPosStack[stackPtr] + 1; EXIT END; stackPtr _ stackPtr - 1; ENDLOOP; IF stackPtr = 0 THEN -- implicit AND patternAnchor # 0 (there was a *) BEGIN patternPos _ patternAnchor; textPos _ textAnchor _ textAnchor + 1; END; IF patternAnchor = 0 AND stackPtr = 0 THEN EXIT; END; END; END; ENDLOOP; ENDLOOP; GO TO Return; EXITS Return => {Storage.Free[textPosStack]; Storage.Free[patternPosStack]} END; -- of EXITS -- END; -- of FindOperation -- SelectNextBlank: PUBLIC PROCEDURE [mnp: MessageTextNbrPtr, forward: BOOLEAN _ TRUE] = -- Implements editor NEXT command. BEGIN target: TextSelectionPtr = @intC.target; nextStart, nextEnd: ovD.CharIndex; message: vmD.VirtualMessagePtr = mnp.message; messageLength: ovD.CharIndex = vmD.GetMessageSize[message]; IF forward THEN BEGIN FOR nextStart _ IF target.pendingDelete THEN target.end ELSE target.point, nextStart + 1 UNTIL nextStart >= messageLength DO IF vmD.GetMessageChar[message, nextStart] = Ascii.ControlA THEN EXIT; REPEAT FINISHED => GO TO NoBlankFound; ENDLOOP; FOR nextEnd _ nextStart + 1, nextEnd + 1 UNTIL nextEnd >= messageLength DO IF vmD.GetMessageChar[message, nextEnd] = Ascii.ControlB THEN EXIT; REPEAT FINISHED => GO TO NoBlankFound; ENDLOOP; END ELSE BEGIN nextEnd _ IF target.pendingDelete THEN target.start ELSE target.point; UNTIL nextEnd = 0 DO nextEnd _ nextEnd - 1; IF vmD.GetMessageChar[message, nextEnd] = Ascii.ControlB THEN EXIT; REPEAT FINISHED => GO TO NoBlankFound; ENDLOOP; FOR nextStart _ nextEnd, nextStart - 1 UNTIL nextStart = 0 DO IF vmD.GetMessageChar[message, nextStart - 1] = Ascii.ControlA THEN {nextStart _ nextStart - 1; EXIT}; REPEAT FINISHED => GO TO NoBlankFound; ENDLOOP; END; CancelTargetSelection[]; target^ _ TextSelection[mnp, nextStart, nextEnd + 1, nextStart, word, TRUE]; intC.pendingDeleteSetByControl _ FALSE; DoTargetSelection[]; [] _ MakeCharIndexVisible[nextStart, mnp]; EXITS NoBlankFound => exD.DisplayException[exD.noBlankFound]; END; -- of SelectNextBlank -- SelectEverything: PUBLIC PROCEDURE [mnp: MessageTextNbrPtr] = -- Implements editor E command. BEGIN CancelTargetSelection[]; intC.target _ TextSelection [mnp, 0, vmD.GetMessageSize[mnp.message], 0, char, intC.editorType = modeless]; intC.pendingDeleteSetByControl _ FALSE; DoTargetSelection[]; END; -- of SelectEverything -- END. -- of EditorFind --z19932(635)\f1