ExecHacks.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
McGregor on August 17, 1983 5:09 pm
Michael Plass on March 12, 1985 12:53:14 pm PST
Rick Beach, May 31, 1985 9:43:50 am PDT
Tim Diebert: July 1, 1985 9:27:11 am PDT
Michael Plass, July 23, 1985 2:41:28 pm PDT
Last Edited by: Gasbarro March 11, 1986 11:30:15 am PST
Spreitzer, January 21, 1986 7:03:22 pm PST
DIRECTORY Commander, CommandTool, Convert, EditedStream, FS, IO, List, Menus, ReadEvalPrint, Rope, SymTab, SystemVersion, TextReplace, TiogaOps, UserProfile, ViewerClasses, ViewerIO, ViewerOps,ViewerTools;
ExecHacks: CEDAR PROGRAM
IMPORTS Commander, CommandTool, Convert, EditedStream, FS, IO, List, Menus, Rope, SymTab, SystemVersion, TextReplace, TiogaOps, UserProfile, ViewerIO, ViewerOps, ViewerTools
= BEGIN
ROPE: TYPE = Rope.ROPE;
RopeList: TYPE = LIST OF ROPE;
doitButtonName, redoButtonName: ROPE;
unixRedoEnabled: BOOLTRUE;
historyKey: ATOM = $ExecHacksCommandHistory;
NoteProfile: PROC [reason: UserProfile.ProfileChangeReason] --UserProfile.ProfileChangedProc-- = {
doitButtonName ← UserProfile.Token["ExecHacks.DoitButtonName", "DoIt"];
redoButtonName ← UserProfile.Token["ExecHacks.RedoButtonName", "Redo"];
};
Blink: PROC = {ViewerOps.BlinkDisplay[]};
DoIt: Menus.MenuProc = {
exec: ViewerClasses.Viewer ~ NARROW[parent];
cmd: Commander.Handle ~ NARROW[clientData];
sel: ROPE ← ViewerTools.GetSelectionContents[];
function: ROPE;
IF Rope.Size[sel] <= 1 THEN {
selViewer: ViewerClasses.Viewer ← ViewerTools.GetSelectedViewer[];
IF selViewer = NIL THEN {Blink[]; RETURN};
sel ← selViewer.name;
};
{
fullFName, base, ext: ROPE; cp: FS.ComponentPositions; dirOmitted: BOOLEAN;
[fullFName, cp, dirOmitted] ← FS.ExpandName[sel ! FS.Error => CONTINUE];
IF fullFName = NIL THEN {Blink[]; RETURN};
base ← Rope.Substr[fullFName, cp.base.start, cp.base.length];
ext ← Rope.Substr[fullFName, cp.ext.start, cp.ext.length];
function ← IF ext.Length[] > 0
THEN UserProfile.Line[
key: Rope.Cat["ExecHacks.For.", ext],
default: SELECT TRUE FROM
ext.Equal["mesa", FALSE], ext.Equal["cedar", FALSE] => "RCompile <base>",
ext.Equal["config", FALSE] => "Bind <base>",
ext.Equal["cm", FALSE], ext.Equal["load", FALSE] => "<base>",
ext.Equal["df", FALSE] => "SModel <base>;\nVerifyDF <base>",
ext.Equal["bcd", FALSE] => "Run <base>",
ext.Equal["profile", FALSE] => IO.PutFR["Copy [User]<<base>>%g.%g> ← ///<base>.profile", IO.card[SystemVersion.release.major], IO.card[SystemVersion.release.minor]],
ENDCASE => "Blink"
]
ELSE UserProfile.Line["ExecHacks.ForNoExtension", "RCompile <base>"];
IF function.Equal["Blink"] THEN {Blink[]; RETURN};
function ← TextReplace.RopeMapFromPairs[LIST[["<base>", base, TRUE]]].Apply[function].Concat["\n"];
};
ViewerTools.SetSelection[exec, NIL];
BackupToPrompt[cmd];
exec.class.notify[exec, LIST[function]];
};
Redo: Menus.MenuProc = {
ScanAndStuff: PROC = {
exec: ViewerClasses.Viewer ~ NARROW[parent];
rope: ROPE;
SELECT mouseButton FROM
red, yellow => {
start, end: INT;
loc: TiogaOps.Location;
selectionViewer: ViewerClasses.Viewer;
[selectionViewer, loc, , , , ] ← TiogaOps.GetSelection[];
IF NOT selectionViewer = exec THEN { --force selection into command window
ViewerTools.SetSelection[exec, NIL];
[selectionViewer, loc, , , , ] ← TiogaOps.GetSelection[];
};
rope ← TiogaOps.GetRope[loc.node];
start ← loc.where;
IF Rope.Find[rope, "%", start] = -1 THEN {--end of ts, backup to before %
start ← start-1;
WHILE Rope.Fetch[rope, start]#'% DO start ← start-1; ENDLOOP;
start ← start-1;
};
WHILE Rope.Fetch[rope, start]#'% DO start ← start-1; ENDLOOP; --back to "% "
end ← start ← start+2;
WHILE Rope.Fetch[rope, end]#15C DO end ← end+1; ENDLOOP; --forward to CR
rope ← Rope.Substr[rope, start, end-start+1];
};
blue => {
rope ← "History -d 10\n";
};
ENDCASE => ERROR;
ViewerTools.SetSelection[exec, NIL];
BackupToPrompt[cmd];
exec.class.notify[exec, LIST[rope]];
};
cmd: Commander.Handle ~ NARROW[clientData];
ScanAndStuff[! ANY => {Blink[]; CONTINUE}];
};
UpdateHistory: PROC [cmd: Commander.Handle] RETURNS [result: REF ANYNIL, msg: ROPENIL] --Commander.CommandProc-- = {
history: RopeList ← NARROW[List.Assoc[aList: cmd.propertyList, key: historyKey]];
IF List.Assoc[aList: cmd.propertyList, key: $ParentCommander] # NIL THEN RETURN; --this filters out command files, but not "subcommands"
history ← CONS[cmd.command.Cat[cmd.commandLine], history];
cmd.propertyList ← List.PutAssoc[
aList: cmd.propertyList,
key: historyKey,
val: history
];
};
UNIXRedo: PROC [cmd: Commander.Handle] RETURNS [result: REF ANYNIL, msg: ROPENIL] --Commander.CommandProc-- = {
history: RopeList ← NARROW[List.Assoc[aList: cmd.propertyList, key: historyKey]];
cls: IO.STREAM = IO.RIS[cmd.commandLine];
trash: INT = cls.SkipWhitespace[];
key: ROPE = IF cls.EndOf[] THEN NIL ELSE cls.GetTokenRope[IO.IDProc].token;
[] ← cls.SkipWhitespace[];
IF NOT cls.EndOf[] THEN GOTO GiveUsage;
cls.Close[];
IF history # NIL THEN history ← history.rest; --strip this redo itself
FOR hl: RopeList ← history, hl.rest WHILE hl # NIL DO
cr: ROPE = hl.first;
IF key = NIL OR IsCmdPrefix[key, cr] THEN {
result ← CommandTool.DoCommand[cr, cmd];
EXIT;
};
REPEAT
FINISHED => RETURN [$Failure, IO.PutFR["No command in my history begins with \"%q\"", [rope[key]]]];
ENDLOOP;
EXITS
GiveUsage => {result ← $Failure; msg ← "Usage: Redo commandNamePrefix"}
};
IsCmdPrefix: PROC [prefix, command: ROPE] RETURNS [is: BOOL] = {
pLen: INT = prefix.Length[];
cLen: INT = command.Length[];
c: CHAR;
first, afterLast: INT ← 0;
FOR afterLast ← 0, afterLast+1
WHILE afterLast < cLen AND (c ← command.Fetch[afterLast]) # ' DO
SELECT c FROM
'/, '> => first ← afterLast+1;
ENDCASE;
ENDLOOP;
is ← pLen <= afterLast-first AND prefix.Equal[command.Substr[start: first, len: pLen], FALSE];
};
ListHistory: PROC [cmd: Commander.Handle] RETURNS [result: REF ANYNIL, msg: ROPENIL] --Commander.CommandProc-- = {
to: IO.STREAM = cmd.out;
prompt: ROPE = NARROW[List.Assoc[key: $Prompt, aList: cmd.propertyList]];
history: RopeList ← NARROW[List.Assoc[aList: cmd.propertyList, key: historyKey]];
toGive: RopeList ← NIL;
cls: IO.STREAM = IO.RIS[cmd.commandLine];
includeDuplicates: BOOLTRUE;
includePrompt: BOOLTRUE;
n: INT ← 10;
seen: SymTab.Ref;
FOR i: INT ← cls.SkipWhitespace[], cls.SkipWhitespace[] WHILE NOT cls.EndOf[] DO
toke: ROPE = cls.GetTokenRope[IO.IDProc].token;
SELECT TRUE FROM
toke.Equal["-%"] => includePrompt ← FALSE;
toke.Equal["+%"] => includePrompt ← TRUE;
toke.Equal["-d"] => includeDuplicates ← FALSE;
toke.Equal["+d"] => includeDuplicates ← TRUE;
ENDCASE => n ← Convert.IntFromRope[toke !Convert.Error => GOTO GiveUsage];
ENDLOOP;
cls.Close[];
IF NOT includeDuplicates THEN seen ← SymTab.Create[case: FALSE];
WHILE n > 0 DO
IF history = NIL THEN EXIT;
IF includeDuplicates OR NOT seen.Fetch[history.first].found THEN {
toGive ← CONS[history.first, toGive];
IF NOT includeDuplicates THEN [] ← seen.Insert[history.first, $seen];
n ← n - 1;
};
history ← history.rest;
ENDLOOP;
FOR toGive ← toGive, toGive.rest WHILE toGive # NIL DO
IF includePrompt THEN to.PutF[prompt, [rope["b"]], [rope["B"]]];
to.PutRope[toGive.first];
ENDLOOP;
result ← $OK;
EXITS
GiveUsage => {result ← $Failure; msg ← "Usage: History [-d] [-%] [number]"}
};
Greet: PROC [v: ViewerClasses.Viewer, cmd: Commander.Handle, paint: BOOL] = {
Add: PROC [me: Menus.MenuEntry, name: ROPE] = {
old: Menus.MenuEntry = Menus.FindEntry[v.menu, name];
IF old = NIL
THEN Menus.AppendMenuEntry[v.menu, me]
ELSE Menus.ReplaceMenuEntry[v.menu, old, me];
};
IF unixRedoEnabled AND cmd # NIL THEN {
cmd.propertyList ← CommandTool.RemoveProcFromList[aList: cmd.propertyList, listKey: $Before, proc: updateHistory];
cmd.propertyList ← CommandTool.AddProcToList[aList: cmd.propertyList, listKey: $Before, proc: updateHistory];
};
Add[Menus.CreateEntry[name: doitButtonName, proc: DoIt, fork: FALSE, clientData: cmd], doitButtonName];
Add[Menus.CreateEntry[name: redoButtonName, proc: Redo, fork: FALSE, clientData: cmd], redoButtonName];
IF paint THEN ViewerOps.PaintViewer[v, menu];
};
updateHistory: Commander.CommandProcHandle ← NEW [Commander.CommandProcObject ← [proc: UpdateHistory]];
BackupToPrompt: PROC [cmd: Commander.Handle] ={
inStream: IO.STREAM ← GetReadEvalPrint[cmd].in;
bufferContents: REF TEXT ← ViewerIO.GetBuffer[inStream];
IF bufferContents # NIL AND bufferContents.length > 0 AND bufferContents[bufferContents.length - 1] # '\n THEN {
FOR n: NAT DECREASING IN [0..bufferContents.length) DO
IF bufferContents[n] = '\n THEN {
EditedStream.UnAppendBufferChars[
stream: inStream, nChars: bufferContents.length - n - 1];
EXIT;
}
REPEAT
FINISHED => EditedStream.UnAppendBufferChars[stream: inStream, nChars: LAST[NAT]];
ENDLOOP;
};
};
GetReadEvalPrint: PROC [cmd: Commander.Handle] RETURNS [ReadEvalPrint.Handle] = {
Returns the enclosing ReadEvalPrint.Handle (NIL if no such handle).
DO
WITH CommandTool.GetProp[cmd, $ReadEvalPrintHandle] SELECT FROM
reph: ReadEvalPrint.Handle =>
IF reph # NIL AND reph.viewer # NIL THEN RETURN [reph];
ENDCASE;
WITH CommandTool.GetProp[cmd, $ParentCommander] SELECT FROM
next: Commander.Handle => {cmd ← next; LOOP;};
ENDCASE;
RETURN [NIL];
ENDLOOP;
};
AttachMenuItemsToExecs: PROC = {
PerViewer: ViewerOps.EnumProc = {
Greet[v, NIL, TRUE];
};
ViewerOps.EnumerateViewers[PerViewer];
};
ExecHacksCmdProc: Commander.CommandProc ~ {
handle: ReadEvalPrint.Handle ← NARROW[
Commander.GetProperty[$ReadEvalPrintHandle, cmd.propertyList]];
Greet[handle.viewer, cmd, TRUE];
};
UserProfile.CallWhenProfileChanges[NoteProfile];
[] ← ViewerEvents.RegisterEventProc[DoMenu, create, $Typescript, FALSE];
Commander.Register[key: "ExecHacks", proc: ExecHacksCmdProc, doc: "registers CommandTool menu buttons for compiling programs and redoing the last command."];
Commander.Register[key: "Redo", proc: UNIXRedo, doc: "redoes the last command with the given prefix"];
Commander.Register[key: "History", proc: ListHistory, doc: "lists the tail of the history list"];
END.