<> <> <> DIRECTORY MessageWindow, Rope, TEditDocument, TEditInput, TEditInputExtras, TEditInputOps, TEditOps, TEditRefresh, TEditSelection, TextEdit, TextFind, TextNode, TreeFind, ViewerClasses, ViewerOps; KeyboardScan: CEDAR PROGRAM IMPORTS MessageWindow, Rope, TEditInput, TEditInputExtras, TEditOps, TEditRefresh, TEditSelection, TextFind, TextNode, TreeFind, ViewerOps ={ ROPE: TYPE = Rope.ROPE; Viewer: TYPE = ViewerClasses.Viewer; Location: TYPE = TextNode.Location; Selection: TYPE = TEditDocument.Selection; SelectionId: TYPE ~ TEditDocument.SelectionId; record: BOOL _ TRUE; ScanNull: PROC [viewer: Viewer _ NIL] RETURNS [recordAtom: BOOL _ record, quit: BOOL _ TRUE] --TEditInput.CommandProc-- = {RETURN}; ScanStart: PROC [viewer: Viewer _ NIL] RETURNS [recordAtom: BOOL _ record, quit: BOOL _ TRUE] --TEditInput.CommandProc-- = { NoteStart: PROC [tdd: TEditDocument.TEditDocumentData, tSel: Selection] = { TEditSelection.Copy[source: tSel, dest: startSel]; RETURN}; TEditSelection.CallWithSelAndDocAndTddLocks[viewer, primary, NoteStart]; target _ NIL; failTailLen _ 0; findWhere _ forwards; caseMatters _ FALSE; RETURN}; ScanUpper: PROC [viewer: Viewer _ NIL] RETURNS [recordAtom: BOOL _ record, quit: BOOL _ TRUE] --TEditInput.CommandProc-- = {case _ Upper}; ScanLower: PROC [viewer: Viewer _ NIL] RETURNS [recordAtom: BOOL _ record, quit: BOOL _ TRUE] --TEditInput.CommandProc-- = {case _ Lower}; ScanForward: PROC [viewer: Viewer _ NIL] RETURNS [recordAtom: BOOL _ record, quit: BOOL _ TRUE] --TEditInput.CommandProc-- = {findWhere _ forwards}; ScanBackward: PROC [viewer: Viewer _ NIL] RETURNS [recordAtom: BOOL _ record, quit: BOOL _ TRUE] --TEditInput.CommandProc-- = {findWhere _ backwards}; ScanReverse: PROC [viewer: Viewer _ NIL] RETURNS [recordAtom: BOOL _ record, quit: BOOL _ TRUE] --TEditInput.CommandProc-- = {SELECT findWhere FROM forwards => {findWhere _ backwards; MessageWindow.Append["Leaping backwards", TRUE]}; backwards => {findWhere _ forwards; MessageWindow.Append["Leaping forwards", TRUE]}; ENDCASE => ERROR}; ScanToggleCase: PROC [viewer: Viewer _ NIL] RETURNS [recordAtom: BOOL _ record, quit: BOOL _ TRUE] --TEditInput.CommandProc-- = { caseMatters _ NOT caseMatters; MessageWindow.Append[IF caseMatters THEN "Case matters" ELSE "Case doesn't matter", TRUE]}; Case: TYPE = {Upper, Lower}; case: Case; startSel: TEditDocument.Selection ~ TEditSelection.Create[]; findWhere: TEditSelection.FindWhere; caseMatters: BOOL; target, lastTarget: ROPE _ NIL; failTailLen: NAT _ 0; ScanTo: PROC [data: REF ANY, viewer: Viewer, param: REF ANY] RETURNS [recordAtom: BOOL, quit: BOOL] --TEditInputExtras.CommandClosureProc-- ~ { parmRope: ROPE ~ NARROW[param]; raw: CHAR ~ IF parmRope.Length = 1 THEN parmRope.Fetch[0] ELSE ERROR; goal: CHAR ~ IF raw NOT IN ['A .. 'Z] THEN raw ELSE SELECT case FROM Upper => raw, Lower => raw - 'A + 'a, ENDCASE => ERROR; newTarget: ROPE ~ target.Concat[Rope.FromChar[goal]]; target _ lastTarget _ newTarget; IF failTailLen>0 THEN {failTailLen _ failTailLen+1; Bitch[target]} ELSE IF NOT FindRope[viewer, newTarget, FALSE, findWhere, FALSE, FALSE, primary, caseMatters] THEN failTailLen _ 1; RETURN [TRUE, TRUE]}; ScanRepeat: PROC [viewer: Viewer] RETURNS [recordAtom: BOOL _ record, quit: BOOL _ TRUE] = { target _ lastTarget; IF failTailLen>0 THEN Bitch[target] ELSE IF NOT FindRope[viewer, target, TRUE, findWhere, FALSE, FALSE, primary, caseMatters] THEN failTailLen _ 1; RETURN}; ScanShorten: PROC [viewer: Viewer] RETURNS [recordAtom: BOOL _ record, quit: BOOL _ TRUE] = { oldLen: INT ~ target.Length; IF oldLen>0 THEN target _ lastTarget _ target.Substr[len: oldLen-1]; IF oldLen<=1 THEN { MessageWindow.Append["Empty search.", TRUE]; ViewerOps.BlinkDisplay[]; RETURN}; IF failTailLen>0 THEN failTailLen _ failTailLen-1; IF failTailLen>0 THEN Bitch[target] ELSE IF NOT FindRope[viewer, target, FALSE, findWhere, FALSE, FALSE, primary, caseMatters] THEN failTailLen _ 1; RETURN}; FindRope: PUBLIC PROC [viewer: Viewer, rope: ROPE, moveOn: BOOL, findWhere: TEditSelection.FindWhere _ anywhere, def, word: BOOL _ FALSE, id: SelectionId _ primary, case: BOOL _ TRUE -- case => case of characters is significant --] RETURNS [found: BOOL] = { IF (found _ DoFind[viewer, rope, moveOn, findWhere, def, word, id, case]) THEN MessageWindow.Clear[] ELSE Bitch[rope]; RETURN}; Bitch: PROC [target: ROPE] ~ { IF Rope.Size[target]>50 THEN target _ Rope.Concat[Rope.Substr[target, 0, 47], "..."]; MessageWindow.Append[Rope.Concat[target, " not found."], TRUE]; ViewerOps.BlinkDisplay[]; RETURN}; NormalizeLoc: PROC [loc: Location, dw: INT] RETURNS [Location] ~ { IF loc.where=TextNode.NodeItself THEN loc.where _ 0; loc.where _ MIN[loc.node.rope.Length, MAX[INT[0], loc.where + dw]]; RETURN [loc]}; DoFind: PUBLIC PROC [viewer: Viewer, rope: ROPE, moveOn: BOOL, findWhere: TEditSelection.FindWhere _ anywhere, def, word: BOOL _ FALSE, id: SelectionId _ primary, case: BOOL _ TRUE -- case => case of characters is significant --] RETURNS [found: BOOL] = { finder: TreeFind.Finder _ NIL; where: TextNode.RefTextNode _ NIL; first, last: Location; at, atEnd: TextNode.Offset _ 0; mv: INT ~ IF moveOn THEN 1 ELSE 0; targLen: INT ~ rope.Length; inViewer: BOOL _ FALSE; DoFindIt: PROC [tdd: TEditDocument.TEditDocumentData, tSel: Selection] = { interrupt: REF BOOL ~ TEditInput.interrupt; Forward: PROC = { first _ NormalizeLoc[tSel.start.pos, mv]; [found,where,at,atEnd,,] _ TreeFind.Try[finder: finder, first: first.node, start: first.where, interrupt: interrupt]; }; Backward: PROC = { first _ NormalizeLoc[tSel.start.pos, targLen-mv]; [found,where,at,atEnd,,] _ TreeFind.TryBackwards[finder: finder, first: first.node, len: first.where, interrupt: interrupt] }; FromStart: PROC = { first _ [TextNode.FirstChild[tdd.text], 0]; last _ NormalizeLoc[tSel.start.pos, targLen+mv]; [found,where,at,atEnd,,] _ TreeFind.Try[finder: finder, first: first.node, start: first.where, last: last.node, lastLen: last.where, interrupt: interrupt] }; FromEnd: PROC = { first _ [TextNode.LastWithin[tdd.text], 0]; first.where _ first.node.rope.Length; last _ NormalizeLoc[tSel.start.pos, -mv]; [found,where,at,atEnd,,] _ TreeFind.TryBackwards[finder: finder, first: first.node, len: first.where, last: last.node, lastStart: last.where, interrupt: interrupt] }; interrupt^ _ FALSE; IF NOT (inViewer _ tSel.viewer=viewer) THEN RETURN; SELECT findWhere FROM backwards => { Backward[]; IF NOT found THEN FromEnd[] }; forwards => { Forward[]; IF NOT found THEN FromStart[] }; ENDCASE => ERROR; IF found THEN { IF def THEN atEnd _ atEnd-1; -- skip the trailing : tSel.start.pos _ [where,at]; tSel.end.pos _ [where,MAX[0,atEnd-1]]; tSel.granularity _ IF word THEN word ELSE char; tSel.insertion _ before; tSel.pendingDelete _ FALSE; tSel.viewer _ viewer; tSel.data _ tdd; } ELSE { TEditSelection.Copy[source: startSel, dest: tSel]; }; TEditOps.RememberCurrentPosition[viewer]; TEditSelection.SetSelLooks[tSel]; TEditSelection.MakeSelection[new: tSel, selection: id]; IF closeOnLeap THEN TEditInput.CloseEvent[]; TEditRefresh.ScrollToEndOfSel[viewer, FALSE, id]; }; found _ FALSE; IF Rope.Size[rope] = 0 THEN RETURN; IF def THEN rope _ Rope.Concat[rope,":"]; finder _ TreeFind.CreateFromRope[pattern: rope, literal: TRUE, ignoreCase: NOT case, word: word ! TextFind.MalformedPattern => IF ec=toobig THEN GOTO TooBig <> ]; IF finder#NIL THEN TEditSelection.CallWithSelAndDocAndTddLocks[viewer, id, DoFindIt]; IF NOT inViewer THEN { MessageWindow.Append["This can't happen!", TRUE]; MessageWindow.Blink[]; }; EXITS TooBig => { MessageWindow.Append["Pattern too long", TRUE]; MessageWindow.Blink[]; }; }; closeOnLeap: BOOL _ FALSE; Start: PROC = { TEditInput.Register[$ScanNull, ScanNull]; TEditInput.Register[$ScanStart, ScanStart]; TEditInput.Register[$ScanRepeat, ScanRepeat]; TEditInput.Register[$ScanShorten, ScanShorten]; TEditInput.Register[$ScanUpper, ScanUpper]; TEditInput.Register[$ScanLower, ScanLower]; TEditInput.Register[$ScanForward, ScanForward]; TEditInput.Register[$ScanBackward, ScanBackward]; TEditInput.Register[$ScanReverse, ScanReverse]; TEditInput.Register[$ScanToggleCase, ScanToggleCase]; TEditInputExtras.RegisterClosure[[$ScanTo, ScanTo, NIL]]; }; Start[]; }.