<> <> <> <> <> <> <> <> <> <<>> 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: BOOL _ TRUE; 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 ", ext.Equal["config", FALSE] => "Bind ", ext.Equal["cm", FALSE], ext.Equal["load", FALSE] => "", ext.Equal["df", FALSE] => "SModel ;\nVerifyDF ", ext.Equal["bcd", FALSE] => "Run ", ext.Equal["profile", FALSE] => IO.PutFR["Copy [User]<>%g.%g> _ ///.profile", IO.card[SystemVersion.release.major], IO.card[SystemVersion.release.minor]], ENDCASE => "Blink" ] ELSE UserProfile.Line["ExecHacks.ForNoExtension", "RCompile "]; IF function.Equal["Blink"] THEN {Blink[]; RETURN}; function _ TextReplace.RopeMapFromPairs[LIST[["", 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 ANY _ NIL, msg: ROPE _ NIL] --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 ANY _ NIL, msg: ROPE _ NIL] --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 ANY _ NIL, msg: ROPE _ NIL] --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 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] = { <> 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.