KeyboardScan.Mesa
Last Edited by: Spreitzer, November 27, 1985 5:29:49 pm PST
Last tweaked by Mike Spreitzer on January 28, 1988 5:50:16 pm PST
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: BOOLTRUE;
ScanNull: PROC [viewer: Viewer ← NIL] RETURNS [recordAtom: BOOL ← record, quit: BOOLTRUE] --TEditInput.CommandProc-- =
{RETURN};
ScanStart: PROC [viewer: Viewer ← NIL] RETURNS [recordAtom: BOOL ← record, quit: BOOLTRUE] --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: BOOLTRUE] --TEditInput.CommandProc-- =
{case ← Upper};
ScanLower: PROC [viewer: Viewer ← NIL] RETURNS [recordAtom: BOOL ← record, quit: BOOLTRUE] --TEditInput.CommandProc-- =
{case ← Lower};
ScanForward: PROC [viewer: Viewer ← NIL] RETURNS [recordAtom: BOOL ← record, quit: BOOLTRUE] --TEditInput.CommandProc-- =
{findWhere ← forwards};
ScanBackward: PROC [viewer: Viewer ← NIL] RETURNS [recordAtom: BOOL ← record, quit: BOOLTRUE] --TEditInput.CommandProc-- =
{findWhere ← backwards};
ScanReverse: PROC [viewer: Viewer ← NIL] RETURNS [recordAtom: BOOL ← record, quit: BOOLTRUE] --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: BOOLTRUE] --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: ROPENIL;
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: BOOLTRUE] = {
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: BOOLTRUE] = {
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: BOOLFALSE, id: SelectionId ← primary, case: BOOLTRUE -- 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: BOOLFALSE, id: SelectionId ← primary, case: BOOLTRUE -- 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: BOOLFALSE;
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
since literal=TRUE, no other PatternErrorCode should occur
];
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: BOOLFALSE;
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[];
}.