ExecHacks.mesa
Copyright © 1985, 1986 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
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
Mike Spreitzer December 9, 1986 6:10:55 pm PST
Eric Nickell, September 30, 1986 3:46:13 pm PDT
Bertrand Serlet August 31, 1986 9:35:24 pm PDT
Spreitzer, January 21, 1986 7:03:22 pm PST
Rick Beach, January 2, 1987 3:16:07 pm PST
=
BEGIN
ROPE: TYPE = Rope.ROPE;
RopeList: TYPE = LIST OF ROPE;
DoItButtonData: TYPE ~ RECORD [cmd: Commander.Handle, name: ROPE];
doitButtonNames: LIST OF ROPE;
redoButtonName: ROPE;
redoEnabled: BOOL ← TRUE;
saveAndDoItEnabled: BOOL ← TRUE;
historyKey: ATOM = $ExecHacksCommandHistory;
NoteProfile: UserProfile.ProfileChangedProc= {
doitButtonNames ← UserProfile.ListOfTokens["ExecHacks.DoitButtonName", LIST["DoIt"]];
redoButtonName ← UserProfile.Token["ExecHacks.RedoButtonName", "Redo"];
saveAndDoItEnabled ← UserProfile.Boolean["ExecHacks.SaveAndDoIt", TRUE];
};
Blink:
PROC = {ViewerOps.BlinkDisplay[]};
DoIt: Menus.MenuProc = {
[parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE]
sel: ROPE ← ViewerTools.GetSelectionContents[];
doitButtonData: REF DoItButtonData ~ NARROW[clientData];
IF Rope.Size[sel] <= 1
THEN {
selViewer: ViewerClasses.Viewer ← ViewerTools.GetSelectedViewer[];
IF selViewer = NIL THEN {Blink[]; RETURN};
sel ← selViewer.name;
};
InternalDoIt[exec: NARROW[parent], sel: sel, cmd: doitButtonData.cmd, name: doitButtonData.name];
};
Does the action wanted by name in the CommandTool cmd (associated with the viewer exec)
dummyRope: ROPE ~ "ESN, December 23, 1986 3:02:26 pm PST";
InternalDoIt:
PROC [exec: ViewerClasses.Viewer, cmd: Commander.Handle, sel, name:
ROPE] = {
function: ROPE;
{
fullFName, ext: ROPE; cp: FS.ComponentPositions; dirOmitted: BOOLEAN;
UPExecHacksLine:
PROC [key:
ROPE]
RETURNS [
ROPE] ~ {
upKey: ROPE ~ IF ext.Length[] > 0 THEN IO.PutFR[format: "ExecHacks.%g.%g", v1: [rope[key]], v2: [rope[ext]]] ELSE IO.PutFR[format: "ExecHacks.%gNoExtension", v1: [rope[key]]];
RETURN [UserProfile.Line[key: upKey, default: dummyRope]];
};
FoundIt:
PROC [rope:
ROPE]
RETURNS [
BOOL] ~ {
function ← rope;
RETURN [function#dummyRope];
};
DefaultCommands:
PROC [ext:
ROPE]
RETURNS [default:
ROPE] ~ {
default ←
SELECT
TRUE
FROM
ext.IsEmpty[] => "RCompile <base>",
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";
};
[fullFName, cp, dirOmitted] ← FS.ExpandName[sel ! FS.Error => CONTINUE];
IF fullFName = NIL THEN {Blink[]; RETURN};
ext ← Rope.Substr[fullFName, cp.ext.start, cp.ext.length];
SELECT
TRUE
FROM
--When FoundIt returns TRUE, function is set appropriately
FoundIt[UPExecHacksLine[name]] => {}; --First check under the button name
FoundIt[UPExecHacksLine["For"]] => {}; --Next check under "For"
FoundIt[DefaultCommands[ext]] => {};
ENDCASE => ERROR;
IF function.Equal["Blink"] THEN {Blink[]; RETURN};
function ←
TextReplace.RopeMapFromPairs[
LIST[
["<server>", fullFName.Substr[cp.server.start, cp.server.length], TRUE],
["<dir>", fullFName.Substr[cp.dir.start, cp.dir.length], TRUE],
["<subDirs>", fullFName.Substr[cp.subDirs.start, cp.subDirs.length], TRUE],
["<directory>", fullFName.Substr[0, cp.base.start], TRUE],
["<base>", fullFName.Substr[cp.base.start, cp.base.length], TRUE],
["<ext>", ext, TRUE],
["<short>", fullFName.Substr[cp.base.start, cp.ext.start + cp.ext.length - cp.base.start], TRUE],
["<ver>", fullFName.Substr[cp.ver.start, cp.ver.length], TRUE],
["<fileName>", fullFName, TRUE]
]].Apply[function].Concat["\n"];
};
ViewerTools.SetSelection[exec, NIL];
BackupToPrompt[cmd];
exec.class.notify[exec, LIST[function]];
};
SaveAndDoIt: TiogaOps.CommandProc = {
fileName: ROPE ← viewer.name;
directory: ROPE ← FileNames.Directory[fileName];
commandToolName: ROPE ← Rope.Cat["CommandTool: WD = ", directory];
exec: ViewerClasses.Viewer ~ ViewerOps.FindViewer[commandToolName];
rep: ReadEvalPrint.Handle;
cmd: Commander.Handle;
IF NOT saveAndDoItEnabled THEN RETURN;
IF exec=NIL THEN {MessageWindow.Append["SaveAndDoIt: Can't do it, no CommandTool for this directory", TRUE]; MessageWindow.Blink[]; RETURN};
rep ← NARROW [Atom.GetPropFromList[exec.props, $ReadEvalPrint]];
cmd ← NARROW [rep.clientData];
Process.Yield[];
[] ← CedarProcess.Fork[SaveAndDoItProcess, NEW [SaveAndDoItProcessDataRec ← [viewer: viewer, exec: exec, sel: fileName, cmd: cmd]]];
};
SaveAndDoItProcessData: TYPE = REF SaveAndDoItProcessDataRec;
SaveAndDoItProcessDataRec:
TYPE =
RECORD [
viewer, exec: ViewerClasses.Viewer,
cmd: Commander.Handle,
sel: ROPE
];
SaveAndDoItProcess: CedarProcess.ForkableProc = {
saveData: SaveAndDoItProcessData ← NARROW [data];
Process.Yield[];
Process.Pause[Process.MsecToTicks[200]]; -- to let the time for the forked save process set the saveInProgress flag
WHILE saveData.viewer.saveInProgress
DO
Process.Yield[];
Process.Pause[Process.MsecToTicks[400]]; -- please save ...
MessageWindow.Append["SaveAndDoIt: waiting for save to complete ... ", TRUE];
ENDLOOP;
Process.Yield[];
MessageWindow.Append["SaveAndDoIt: save done; doing it !", TRUE];
Process.Yield[];
InternalDoIt[exec: saveData.exec, sel: saveData.sel, cmd: saveData.cmd, name: doitButtonNames.first];
};
Redo: Menus.MenuProc = {
ScanAndStuff:
PROC = {
exec: ViewerClasses.Viewer ~ NARROW[parent];
cmdList, cmdListTail: LIST OF REF ANY ← NIL;
SELECT mouseButton
FROM
red, yellow => {
Execute all the commands found within the selection
tsRope: ROPE;
start, end: INT;
startLoc, endLoc: TiogaOps.Location;
selectionViewer: ViewerClasses.Viewer;
[selectionViewer, startLoc, endLoc, , , ] ← TiogaOps.GetSelection[];
IF
NOT selectionViewer = exec
THEN {
--force selection into command window
ViewerTools.SetSelection[exec, NIL];
[selectionViewer, startLoc, endLoc, , , ] ← TiogaOps.GetSelection[];
};
tsRope ← TiogaOps.GetRope[startLoc.node];
start ← startLoc.where;
IF Rope.Find[tsRope, "%", start] = -1
THEN {
end of typescript, backup to before %
start ← start-1;
WHILE Rope.Fetch[tsRope, start]#'% DO start ← start-1; ENDLOOP;
start ← start-1;
};
WHILE Rope.Fetch[tsRope, start]#'% DO start ← start-1; ENDLOOP; --back up to "%" preceeding command of interest
WHILE start+2 < endLoc.where
DO
rope: ROPE;
end ← start ← start+2;
WHILE Rope.Fetch[tsRope, end]#15C DO end ← end+1; ENDLOOP; --forward to CR
rope ← Rope.Substr[tsRope, start, end-start+1];
IF cmdListTail =
NIL
THEN
cmdList ← cmdListTail ← LIST[rope]
ELSE
cmdListTail ← cmdListTail.rest ← LIST[rope];
start ← end;
WHILE Rope.Fetch[tsRope, start]#'% DO start ← start+1; ENDLOOP;
ENDLOOP;
};
blue => {
cmdList ← LIST["History -d 10\n"];
};
ENDCASE => ERROR;
ViewerTools.SetSelection[exec, NIL];
BackupToPrompt[cmd];
exec.class.notify[exec, cmdList];
};
cmd: Commander.Handle ~ NARROW[clientData];
ScanAndStuff[! ANY => {Blink[]; CONTINUE}];
};
UpdateHistoryProc: 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
];
};
RedoCmd: 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];
};
HistoryCmd: 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: BOOL ← TRUE;
includePrompt: BOOL ← TRUE;
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 v = NIL THEN RETURN;
IF redoEnabled
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];
};
FOR eachButton:
LIST
OF
ROPE ← doitButtonNames, eachButton.rest
UNTIL eachButton=
NIL
DO
name: ROPE ~ eachButton.first;
Add[Menus.CreateEntry[name: name, proc: DoIt, fork: FALSE, clientData: NEW[DoItButtonData ← [cmd: cmd, name: name]]], name];
ENDLOOP;
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: UpdateHistoryProc]];
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];
};
ExecHacksCmd: Commander.CommandProc ~ {
handle: ReadEvalPrint.Handle ← NARROW[
Commander.GetProperty[$ReadEvalPrintHandle, cmd.propertyList]];
Greet[handle.viewer, cmd, TRUE];
};
AlterIcon: ViewerEvents.EventProc = {
[viewer: ViewerClasses.Viewer, event: ViewerEvents.ViewerEvent, before: BOOL] RETURNS [abort: BOOL ← FALSE]
IF viewer.parent=
NIL
AND viewer.file#
NIL
THEN {
Icon:
PROC [r1, r2:
ROPE ←
NIL]
RETURNS [found:
BOOL] ~ {
iconName ← UserProfile.Token[key: Rope.Cat["ExecHacks.", r1, r2]];
RETURN [iconName#NIL]
};
cp: FS.ComponentPositions;
fullFName, extension, iconName: ROPE;
[cp: cp, fullFName: fullFName] ← FS.ExpandName[name: viewer.file];
extension ← Rope.Substr[base: fullFName, start: cp.ext.start, len: cp.ext.length];
SELECT
TRUE
FROM
viewer.newVersion AND Icon["DirtyIcon.", extension] => {};
Icon["Icon.", extension] => {};
viewer.newVersion AND (iconName ← IconRegistry.IsRegistered[Rope.Cat["Dirty", extension]].name)#NIL => {};
(iconName ← IconRegistry.IsRegistered[extension].name)#NIL => {};
viewer.newVersion AND Icon["DefaultDirtyIcon"] => {};
Icon["DefaultIcon"] => {};
ENDCASE;
IF iconName#NIL THEN viewer.icon ← IconRegistry.GetIcon[iconName: iconName, default: viewer.icon];
};
};
UserProfile.CallWhenProfileChanges[NoteProfile];
[] ← ViewerEvents.RegisterEventProc[DoMenu, create, $Typescript, FALSE];
[] ← ViewerEvents.RegisterEventProc[proc: AlterIcon, event: close, before: TRUE];
[] ← ViewerEvents.RegisterEventProc[proc: AlterIcon, event: save, before: FALSE];
[] ← ViewerEvents.RegisterEventProc[proc: AlterIcon, event: edit, before: FALSE];
TiogaOps.RegisterCommand[name: $BlueSave, proc: SaveAndDoIt, before: FALSE];
Commander.Register[key: "///Commands/ExecHacks", proc: ExecHacksCmd, doc: "registers CommandTool menu buttons for compiling programs and redoing the last command."];
Commander.Register[key: "///Commands/Redo", proc: RedoCmd, doc: "Redo <string> — redoes the last command that begins with string"];
Commander.Register[key: "///Commands/History", proc: HistoryCmd, doc: "History <option>* <n> — lists the last n commands in this CommandTool viewer\n -% omit % prompt\n +% include % prompt\n -d remove duplicate commands\n +d include duplicates"];