EditorComfortsBImpl.mesa
Copyright © 1984, 1985 by Xerox Corporation. All rights reserved.
Teitelman, May 11, 1983 2:53 pm
Russ Atkinson (RRA) January 21, 1985 10:44:10 pm PST
Maxwell, January 20, 1984 2:23:51 pm PST
DIRECTORY
AMTypes USING [TV, TVToType, TVType, Type, TypeClass],
Interpreter USING [Evaluate],
IO USING [BreakProc, GetCedarTokenRope, RIS, RopeFromROS, ROS, STREAM, TokenProc],
MessageWindow USING [Append, Blink, Clear],
PrintTV USING [PrintType],
Process USING [Detach],
Rope USING [Cat, Concat, Fetch, Find, FromChar, IsEmpty, Length, Replace, ROPE, Run, Substr],
TiogaOps USING [BackSpace, Break, CallWithLocks, ClearLooks, CommandProc, FindText, FindWord, FindDef, FirstChild, GetCaret, GetRope, GetSelection, GoToPreviousCharacter, InsertRope, IsComment, Location, Nest, Next, NextPlaceholder, PutProp, PutTextKey, Ref, RegisterAbbrevFailedProc, RegisterCommand, SaveSelA, SearchDir, SetComment, SetLooks, SetNotComment, SetSelection, ViewerDoc, WhichSelection],
TiogaOpsDefs USING [Ref],
Terminal USING [BlinkBWDisplay, Current],
ViewerClasses USING [Viewer],
ViewerTools USING [GetSelectionContents, GetSelectedViewer],
WindowManager USING [UnWaitCursor, WaitCursor];
EditorComfortsBImpl: CEDAR PROGRAM
IMPORTS AMTypes, Interpreter, IO, MessageWindow, PrintTV, Process, Rope, TiogaOps, Terminal, ViewerTools, WindowManager
= BEGIN
Types
Location: TYPE = TiogaOps.Location;
ROPE: TYPE = Rope.ROPE;
STREAM: TYPE = IO.STREAM;
TiogaRef: TYPE = TiogaOpsDefs.Ref;
TV: TYPE = AMTypes.TV;
Viewer: TYPE = ViewerClasses.Viewer;
Remembering last search
targetOfLastSearch: ROPE;
should all be one procedure if TiogaCommandProc were right type.
SearchProc: TYPE = PROC [viewer: Viewer, rope: ROPE, whichDir: TiogaOps.SearchDir, which: TiogaOps.WhichSelection, case: BOOL] RETURNS [found: BOOL];
SaveLastSearch: PROC [viewer: Viewer, proc: SearchProc, dir: TiogaOps.SearchDir, case: BOOL] RETURNS [quit: BOOLFALSE] = {
rope: ROPE = ViewerTools.GetSelectionContents[];
SELECT TRUE FROM
Rope.Length[rope] # 0 => targetOfLastSearch ← rope;
Rope.IsEmpty[targetOfLastSearch] => {};
ENDCASE => {
found: BOOL ← proc[viewer, targetOfLastSearch, dir, primary, case];
quit ← TRUE;
IF NOT found THEN TRUSTED {
MessageWindow.Append[Rope.Concat[targetOfLastSearch, " not Found"], TRUE];
Terminal.BlinkBWDisplay[Terminal.Current[]];
};
};
};
FindNext: TiogaOps.CommandProc = {
recordAtom ← FALSE;
quit ← SaveLastSearch[viewer, TiogaOps.FindText, forwards, TRUE];
};
FindAny: TiogaOps.CommandProc = {
recordAtom ← FALSE;
quit ← SaveLastSearch[viewer, TiogaOps.FindText, anywhere, TRUE];
};
FindPrev: TiogaOps.CommandProc = {
recordAtom ← FALSE;
quit ← SaveLastSearch[viewer, TiogaOps.FindText, backwards, TRUE];
};
FindNextCaseless: TiogaOps.CommandProc = {
recordAtom ← FALSE;
quit ← SaveLastSearch[viewer, TiogaOps.FindText, forwards, FALSE];
};
FindAnyCaseless: TiogaOps.CommandProc = {
recordAtom ← FALSE;
quit ← SaveLastSearch[viewer, TiogaOps.FindText, anywhere, FALSE];
};
FindPrevCaseless: TiogaOps.CommandProc = {
recordAtom ← FALSE;
quit ← SaveLastSearch[viewer, TiogaOps.FindText, backwards, FALSE];
};
FindNextWord: TiogaOps.CommandProc = {
recordAtom ← FALSE;
quit ← SaveLastSearch[viewer, TiogaOps.FindWord, forwards, TRUE];
};
FindAnyWord: TiogaOps.CommandProc = {
recordAtom ← FALSE;
quit ← SaveLastSearch[viewer, TiogaOps.FindWord, anywhere, TRUE];
};
FindPrevWord: TiogaOps.CommandProc = {
quit ← SaveLastSearch[viewer, TiogaOps.FindWord, backwards, TRUE];
};
FindNextWordCaseless: TiogaOps.CommandProc = {
recordAtom ← FALSE;
quit ← SaveLastSearch[viewer, TiogaOps.FindWord, forwards, FALSE];
};
FindAnyWordCaseless: TiogaOps.CommandProc = {
recordAtom ← FALSE;
quit ← SaveLastSearch[viewer, TiogaOps.FindWord, anywhere, FALSE];
};
FindPrevWordCaseless: TiogaOps.CommandProc = {
quit ← SaveLastSearch[viewer, TiogaOps.FindWord, backwards, FALSE];
};
FindNextDef: TiogaOps.CommandProc = {
recordAtom ← FALSE;
quit ← SaveLastSearch[viewer, TiogaOps.FindDef, forwards, TRUE];
};
FindAnyDef: TiogaOps.CommandProc = {
recordAtom ← FALSE;
quit ← SaveLastSearch[viewer, TiogaOps.FindDef, anywhere, TRUE];
};
FindPrevDef: TiogaOps.CommandProc = {
recordAtom ← FALSE;
quit ← SaveLastSearch[viewer, TiogaOps.FindDef, backwards, TRUE];
};
Control-E expansion
Expand: PROC RETURNS [BOOL] = {
caret: Location ← TiogaOps.GetCaret[];
r: ROPE ← TiogaOps.GetRope[caret.node];
i: INT ← caret.where;
IF i = 0 THEN RETURN[FALSE];
WHILE i > 0 DO
IF NOT IO.TokenProc[Rope.Fetch[r, i - 1]] = other THEN EXIT;
i ← i -1;
ENDLOOP;
TRUSTED {
forked because evaluating the expression might require confirmation.
Process.Detach[FORK Expand0[Rope.Substr[base: r, start: i, len: caret.where - i], caret]]};
RETURN[TRUE];
};
Expand0: PROC [name: ROPE, caret: Location] = {
Expand1: PROC [root: REF] = {
IF newName # NIL THEN {
TiogaOps.BackSpace[Rope.Length[name]];
TiogaOps.InsertRope[newName];
caret ← TiogaOps.GetCaret[];
};
TiogaOps.SaveSelA[];
TiogaOps.PutProp[n: caret.node, name: $StartOfExpansion, value: expansion];
TiogaOps.PutTextKey[node: caret.node, where: caret.where - 1, key: expansion];
associates a sticky address with the first character in the expansion. expansion is used as the key simply because it is a unique ref. could just as easily have done a gensym.
IF Rope.Run[s1: expansion, s2: " -- "] = 4
THEN {
expansion ← Rope.Substr[expansion, 4];
TiogaOps.ClearLooks[which: caret];
TiogaOps.InsertRope[" = {"];
TiogaOps.Break[];
TiogaOps.Nest[];
TiogaOps.SetComment[];
TiogaOps.SetLooks[looks: "ck", which: caret];
TiogaOps.InsertRope[expansion];
TiogaOps.ClearLooks[which: caret];
TiogaOps.Break[];
TiogaOps.SetNotComment[];
TiogaOps.InsertRope["Body"];
TiogaOps.Break[];
TiogaOps.InsertRope["};"];
[] ← TiogaOps.NextPlaceholder[dir: backwards, gotoend: FALSE];
}
ELSE {
TiogaOps.InsertRope[expansion];
TiogaOps.GoToPreviousCharacter[Rope.Length[expansion]];
[] ← TiogaOps.NextPlaceholder[gotoend: FALSE];
};
};
viewer: Viewer ← TiogaOps.GetSelection[].viewer;
expansion, newName: ROPE;
IF Rope.Find[name, "."] = -1 THEN {
should check and if module not loaded, then search file instead of evaluating
n: TiogaRef ← TiogaOps.FirstChild[TiogaOps.ViewerDoc[viewer]];
WHILE n # NIL DO
r: ROPE = TiogaOps.GetRope[n];
IF NOT TiogaOps.IsComment[n] AND (Rope.Find[r, "PROGRAM"] # -1 OR Rope.Find[r, "MONITOR"] # -1) THEN {
name ← Rope.Cat[IO.GetCedarTokenRope[IO.RIS[r]].token, ".", name];
EXIT
};
n ← TiogaOps.Next[n];
ENDLOOP;
};
MessageWindow.Append[message: Rope.Cat["Evaluating ", name, "..."], clearFirst: TRUE];
WindowManager.WaitCursor[];
[expansion, newName] ← ExpandRecord[name, viewer
! UNWIND => WindowManager.UnWaitCursor[]];
WindowManager.UnWaitCursor[];
IF viewer = TiogaOps.GetSelection[].viewer
THEN {
IF TiogaOps.GetCaret[] # caret THEN {
MessageWindow.Append["Caret has moved, insertion NOT performed.", TRUE];
MessageWindow.Blink[];
RETURN;
};
}
ELSE TiogaOps.SetSelection[viewer: viewer, start: caret, end: caret];
user went to some other viewer or exec while waiting.
MessageWindow.Clear[];
IF useLocks THEN TiogaOps.CallWithLocks[proc: Expand1] ELSE Expand1[NIL];
};
ExpandRecord: PROC [name: ROPE, viewer: Viewer] RETURNS [expansion: ROPE, newName: ROPE] = {
h: STREAM = IO.ROS[];
i: INT;
tv: TV;
errorRope: ROPE;
noResult: BOOL;
type: AMTypes.Type;
[tv, errorRope, noResult] ← Interpreter.Evaluate[rope: name]; -- Abort?
IF noResult THEN {
MessageWindow.Append[errorRope, TRUE];
MessageWindow.Blink[];
GOTO Fail};
type ← AMTypes.TVType[tv];
IF AMTypes.TypeClass[type] = type THEN {
PrintTV.PrintType[type: AMTypes.TVToType[tv], put: h, verbose: TRUE];
if the tv describes a type, e.g. Commander.CommandProc, don't want the type of that object, which would just be TYPE, but rather the object itself, printed as a type.
expansion ← h.RopeFromROS[];
i ← Rope.Find[expansion, "["];
IF i = -1
THEN expansion ← NIL
ELSE expansion ← Rope.Concat[" -- ", Rope.Substr[base: expansion, start: i]];
RETURN;
};
PrintTV.PrintType[type: type, put: h, verbose: TRUE];
expansion ← h.RopeFromROS[];
IF (i ← Rope.Find[expansion, "RETURNS"]) # -1 THEN
expansion ← Rope.Substr[base: expansion, len: i - 1];
the minus one is to delete the space before the RETURNS. important in case of typescripts, so that ctrl-next puts you at the end of the typescript.
i ← Rope.Find[expansion, "["];
IF i = -1 THEN {expansion ← "[]"; RETURN};
expansion ← Rope.Substr[expansion, i]; -- strips off the PROCEDURE, PROC, ERROR, RECORD, whatever.
{Expand1: PROC [args: ROPE] RETURNS[expansion: ROPE] = {
left: ROPE = Rope.FromChar['\001];
right: ROPE = Rope.FromChar['\002];
i, length: INT;
i ← 1;
expansion ← args;
length ← Rope.Length[expansion];
DO
i is the first character in this argument. find end of argument
n: INT ← -1; -- will be character position of :
j: INT ← i; -- will be position of the first character beyond this argument, i.e. the , or ]
WHILE j < length DO
SELECT Rope.Fetch[expansion, j] FROM
'', '\\ => j ← j + 2;
'], ', => EXIT;
': => n ← j;
'[ => -- default value for this argument is a record constructor. find matching right ] and replace interior by its expansion
{count: INT ← 1;
k: INT ← j + 1;
r: ROPE;
nChars: INT;
WHILE k < length DO
SELECT Rope.Fetch[expansion, k] FROM
'', '\\ => {k ← k + 2; LOOP};
'[ => count ← count + 1;
'] => IF (count ← count - 1) = 0 THEN EXIT;
ENDCASE;
k ← k + 1;
REPEAT
FINISHED => GOTO Fail; -- did not find matching ]
ENDLOOP;
nChars ← k - j + 1;
r ← Expand1[Rope.Substr[base: expansion, start: j, len: nChars]];
expansion ← Rope.Replace[base: expansion, start: j, len: nChars, with: r];
length ← Rope.Length[expansion];
j ← k + (Rope.Length[r] - nChars) + 1; -- first character beyond the matching ]
EXIT;
};
ENDCASE;
j ← j + 1;
ENDLOOP;
IF n = -1 OR j >= length THEN GOTO Fail;
expansion ← Rope.Replace[base: expansion, start: j, len: 0, with: right];
insert right place holder. work from right so positions accurate.
expansion ← Rope.Replace[base: expansion, start: n + 2, len: 0, with: left];
+ 2 to skip over the : and the space.
length ← length + 2;
i ← j + 3;
IF i = length THEN EXIT;
ENDLOOP;
EXITS
Fail => expansion ← args;
};
expansion ← Expand1[expansion];
};
EXITS Fail => expansion ← NIL;
};
Initialization
useLocks: BOOLTRUE;
TiogaOps.RegisterAbbrevFailedProc[Expand];
TiogaOps.RegisterCommand[$FindNext, FindNext];
TiogaOps.RegisterCommand[$FindAny, FindAny];
TiogaOps.RegisterCommand[$FindPrev, FindPrev];
TiogaOps.RegisterCommand[$FindNextCaseless, FindNextCaseless];
TiogaOps.RegisterCommand[$FindAnyCaseless, FindAnyCaseless];
TiogaOps.RegisterCommand[$FindPrevCaseless, FindPrevCaseless];
TiogaOps.RegisterCommand[$FindNextWord, FindNextWord];
TiogaOps.RegisterCommand[$FindAnyWord, FindAnyWord];
TiogaOps.RegisterCommand[$FindPrevWord, FindPrevWord];
TiogaOps.RegisterCommand[$FindNextWordCaseless, FindNextWordCaseless];
TiogaOps.RegisterCommand[$FindAnyWordCaseless, FindAnyWordCaseless];
TiogaOps.RegisterCommand[$FindPrevWordCaseless, FindPrevWordCaseless];
TiogaOps.RegisterCommand[$FindNextDef, FindNextDef];
TiogaOps.RegisterCommand[$FindAnyDef, FindAnyDef];
TiogaOps.RegisterCommand[$FindPrevDef, FindPrevDef];
END.
Edited on December 1, 1982 11:29 pm, by Teitelman
fixed bug in addIfPrevious, createNew so that if there were no non-comment nodes, would fail
fixed addIfPrevious to search through all children for "changes to"
use TiogaExtraOps.CompareLocOrder rather than SelectBranches
fix middle button continuation to add a new comments field.
changes to: UpdateChangeLog
Edited on December 2, 1982 1:29 pm, by Teitelman
fixed bug causing two appearances of ChangeLog.
fixed control-E not to stop scanning on *. Add PROGRAM name in case no .
changes to: UpdateLastEdited, ChangeLogEntry, UpdateChangeLog, SetDefaultSwitches, Expand0
Edited on December 2, 1982 3:09 pm, by Teitelman
changes to: Expand0
Edited on December 3, 1982 12:57 pm, by Teitelman
fixed bug relating to naked CR in non-node structure file causing loop in UpdateLastEdit
changes to: UpdateLastEdited
Edited on December 14, 1982 1:53 pm, by Teitelmann, SelectDate
Edited on December 14, 1982 2:05 pm, by Teitelman
fixed updatedate to keep looking after it finds an appropriate comment, and to change the last one it finds.
changes to: UpdateLastEdited, DIRECTORY
Edited on December 20, 1982 5:03 pm, by Teitelman
fixed FindLastChangeLog to stop on NIL node, rather than rootNode, because if the last node happens to have children, cauused infinite loop.
changes to: UpdateChangeLog
Edited on December 22, 1982 12:49 pm, by Teitelman
changes to: Expand0, UpdateLastEdited, TokenProc (local of IsADecl, local of CreateChangeEntry, local of UpdateChangeLog), IsADecl (local of CreateChangeEntry, local of UpdateChangeLog), CreateChangeEntry (local of UpdateChangeLog), UpdateChangeLog, IMPORTS, Expand
Edited on January 25, 1983 11:10 pm, by Teitelman
changes to: UpdateForSave
Edited on January 28, 1983 6:51 pm, by Teitelman
changes to: UpdateChangeLog, RedSave
Edited on February 1, 1983 9:32 pm, by Teitelman
changes to: RedSave, CloseAndOpenIconicFile, SetDefaultSwitches, IMPORTS, PrintStars (local of RedSave), Stars (local of RedSave)
Edited on February 9, 1983 5:17 pm, by Teitelman
changes to: RedSave, Stars (local of RedSave), sessionLog, Stars (local of RedSave)
Edited on March 10, 1983 3:02 am, by Teitelman
changes to: IMPORTS, RedSave
Edited on March 31, 1983 5:03 pm, by Teitelman
changes to: SaveLastSearch, Expand
Edited on May 9, 1983 6:13 pm, by Teitelman
changes to: IMPORTS, RedSave, proc (local of RedSave), proc (local of RedSave)
Edited on May 11, 1983 2:51 pm, by Teitelman
added catch phrase for SyntaxError to IsADecl. User had clicked changelog on a file that did not contain cedar and GetCedarTokenRope blew up.
changes to: IsADecl (local of CreateChangeEntry, local of UpdateChangeLog)
Edited on January 3, 1984 2:16 pm, by Maxwell
converted to Cedar 5. moved procedures that used the UserExec to end of file. commented out references to UserExecExtras in RedSave.