<> <> <> <> DIRECTORY Atom USING [GetPName], Commander USING [CommandProc, Handle, Lookup, Register], CommandExtras USING [MakeUninterpreted], CommandTool USING [DoCommand], Convert USING [RopeFromInt], EditedStream USING [UnAppendBufferChars], FileNames USING [GetShortName], IO USING [BreakProc, Close, EndOf, EndOfStream, Error, GetRefAny, GetToken, IDProc, PeekChar, RIS, SkipWhitespace, STREAM, TokenProc], List USING [Assoc], MBQueue USING [CreateMenuEntry], Menus USING [AppendMenuEntry, ClickProc, FindEntry, Menu, MenuEntry, ReplaceMenuEntry], ReadEvalPrint USING [Handle], Rope USING [Cat, Concat, Equal, Find, FromChar, FromRefText, Length, Match, Replace, ROPE, SkipTo, Substr], RopeList USING [Reverse], TiogaOps USING [GetSelection, Location, LocOffset, Ref, Root], ViewerClasses USING [Viewer], ViewerIOExtras USING [GetBuffer, TypeChars], ViewerOps USING [PaintViewer], ViewerTools USING [GetSelectionContents, SetSelection]; CommandsCImpl: CEDAR PROGRAM IMPORTS Atom, Commander, CommandExtras, CommandTool, Convert, EditedStream, FileNames, List, MBQueue, Menus, IO, Rope, RopeList, TiogaOps, ViewerIOExtras, ViewerOps, ViewerTools = BEGIN AliasCellObject: TYPE = RECORD [ args: LIST OF Rope.ROPE _ NIL, def: Rope.ROPE ]; AliasCell: TYPE = REF AliasCellObject; Alias: Commander.CommandProc = TRUSTED { commandLineStream: IO.STREAM = IO.RIS[cmd.commandLine]; name, def: Rope.ROPE; token: REF TEXT _ NEW[TEXT[30]]; args: LIST OF Rope.ROPE _ NIL; aliasCell: AliasCell; { ENABLE { IO.EndOfStream => GOTO Die; IO.Error => GOTO Die; }; token.length _ 0; token _ commandLineStream.GetToken[IO.TokenProc, token].token; name _ Rope.FromRefText[token]; [] _ commandLineStream.SkipWhitespace[FALSE]; IF NOT commandLineStream.EndOf[] AND commandLineStream.PeekChar[] = '( THEN { FOR l: LIST OF REF ANY _ NARROW[commandLineStream.GetRefAny[]], l.rest UNTIL l = NIL DO WITH l.first SELECT FROM r: Rope.ROPE => args _ CONS[r, args]; a: ATOM => args _ CONS[Atom.GetPName[a], args]; ENDCASE => ERROR; ENDLOOP; TRUSTED {args _ RopeList.Reverse[args]; }; }; token.length _ 0; token _ commandLineStream.GetToken[CRBreak, token].token; def _ Rope.FromRefText[token]; aliasCell _ NEW[AliasCellObject _ [args, def]]; Commander.Register[ key: name, proc: AliasImplProc, doc: Rope.Concat["Alias ", cmd.commandLine], clientData: aliasCell]; commandLineStream.Close[]; EXITS Die => NULL; }; }; RopeSubst: PROC [old, new, base: Rope.ROPE, case: BOOL _ FALSE, allOccurrences: BOOL _ TRUE] RETURNS[Rope.ROPE] = { <> <> lenOld: INT = old.Length[]; lenNew: INT = new.Length[]; i: INT _ 0; WHILE (i _ Rope.Find[s1: base, s2: old, case: case, pos1: i]) # -1 DO base _ Rope.Replace[base: base, start: i, len: lenOld, with: new]; IF ~allOccurrences THEN EXIT; i _ i + lenNew; ENDLOOP; RETURN[base]; }; RopeMemb: PROC [rope: Rope.ROPE, lst: LIST OF Rope.ROPE] RETURNS[BOOL] = { FOR l: LIST OF Rope.ROPE _ lst, l.rest UNTIL l = NIL DO IF Rope.Equal[rope, l.first, FALSE] THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE] }; gennum: LONG CARDINAL _ 10000; UniqueRope: PROC [c: CHARACTER _ 'A] RETURNS[Rope.ROPE] = { gennum _ gennum + 1; RETURN[Rope.Concat[Rope.FromChar[c], Convert.RopeFromInt[gennum, 10, FALSE]]]; }; -- of Gensym <<>> AliasImplProc: Commander.CommandProc = TRUSTED { aliasCell: AliasCell _ NARROW[cmd.procData.clientData]; newCommandLine: Rope.ROPE _ aliasCell.def; token: REF TEXT _ NEW[TEXT[30]]; new: Rope.ROPE; restOfStream: Rope.ROPE; commandLineStream: IO.STREAM = IO.RIS[cmd.commandLine]; synonyms: LIST OF REF SynonymRecord; SynonymRecord: TYPE = RECORD[key, val: Rope.ROPE]; FOR l: LIST OF Rope.ROPE _ aliasCell.args, l.rest UNTIL l = NIL DO token.length _ 0; token _ commandLineStream.GetToken[IO.IDProc, token].token; new _ Rope.FromRefText[token]; IF RopeMemb[new, l.rest] THEN { -- e.g. args are (x y) and substituting y gorp. dummy: Rope.ROPE = UniqueRope[]; synonyms _ CONS[NEW[SynonymRecord _ [new, dummy]], synonyms]; new _ dummy; }; newCommandLine _ RopeSubst[old: l.first, new: new, base: newCommandLine, case: FALSE]; ENDLOOP; FOR l: LIST OF REF SynonymRecord _ synonyms, l.rest UNTIL l = NIL DO newCommandLine _ RopeSubst[old: l.first.val, new: l.first.key, base: newCommandLine, case: FALSE]; ENDLOOP; token.length _ 0; token _ commandLineStream.GetToken[CRBreak, token].token; restOfStream _ Rope.FromRefText[token]; newCommandLine _ Rope.Cat[newCommandLine, restOfStream, "\n"]; commandLineStream.Close[]; result _ CommandTool.DoCommand[commandLine: newCommandLine, parent: cmd]; }; CRBreak: IO.BreakProc = { IF char = '\n THEN RETURN[break]; RETURN[other]; }; CreateButton: Commander.CommandProc = TRUSTED { <> commandLineStream: IO.STREAM = IO.RIS[cmd.commandLine]; name: Rope.ROPE; def: Rope.ROPE; token: REF TEXT _ NEW[TEXT[30]]; br: ButtonImplRef _ NEW[ButtonImplObject]; cth: Commander.Handle _ cmd; { ENABLE { IO.EndOfStream => GOTO Die; IO.Error => GOTO Die; }; token.length _ 0; token _ commandLineStream.GetToken[IO.TokenProc, token].token; name _ Rope.FromRefText[token]; [] _ commandLineStream.SkipWhitespace[FALSE]; <> token.length _ 0; token _ commandLineStream.GetToken[CRBreak, token ! IO.EndOfStream => CONTINUE].token; def _ Rope.FromRefText[token]; SELECT TRUE FROM Rope.Length[def] = 0 => def _ NIL; Rope.Match["*\n", def] => {}; ENDCASE => def _ Rope.Concat[def, "\n"]; br.def _ def; <> DO br.rep _ NARROW[List.Assoc[key: $ReadEvalPrintHandle, aList: cth.propertyList]]; IF br.rep # NIL AND br.rep.viewer # NIL THEN EXIT; cth _ NARROW[List.Assoc[key: $ParentCommander, aList: cth.propertyList]]; IF cth = NIL THEN RETURN[$Failure, "Can't find $ReadEvalPrintHandle"]; ENDLOOP; <> IF br # NIL AND br.rep # NIL THEN { viewer: ViewerClasses.Viewer _ br.rep.viewer; IF viewer # NIL THEN { menu: Menus.Menu _ br.rep.viewer.menu; IF menu # NIL THEN { new: Menus.MenuEntry _ IF def = NIL THEN NIL ELSE MBQueue.CreateMenuEntry[q: br.rep.menuHitQueue, name: name, proc: ButtonImplButtonProc, clientData: br]; old: Menus.MenuEntry _ Menus.FindEntry[menu, name]; SELECT TRUE FROM old # NIL => Menus.ReplaceMenuEntry[menu, old, new]; new # NIL => Menus.AppendMenuEntry[menu, new, 0]; ENDCASE; ViewerOps.PaintViewer[viewer: viewer, hint: menu, clearClient: FALSE]; }; }; }; EXITS Die => NULL; }; commandLineStream.Close[]; }; <<>> <> <<$CurrentSelection$ => replaced by the current selection up to but not including the first carriage return>> <<$FileNameSelection$ => replaced by the current selection if it appears to be a file name, otherwise replaced by the name of the selected viewer>> <<$ShortFileNameSelection$ => same as $FileNameSelection$ except that version number and directory are omitted>> <<$SelectedViewerName$ => replaced by the name of the selected viewer>> <<$ViewerPosition$ => replaced by the position of the current selection in a viewer>> <<$MouseButton$ => "left", "middle", or "right">> <<$ShiftKey$ => "shift", "noShift">> <<$ControlKey$ "control", "noControl">> ButtonImplButtonProc: Menus.ClickProc = { br: ButtonImplRef _ NARROW[clientData]; def: Rope.ROPE; curSel: Rope.ROPE; viewer: ViewerClasses.Viewer _ NIL; start: TiogaOps.Location; viewerName: Rope.ROPE _ NIL; fileName: Rope.ROPE _ NIL; shortFileName: Rope.ROPE _ NIL; index: INT _ -1; pos: INT; controlRope: Rope.ROPE _ IF control THEN "control" ELSE "noControl"; shiftRope: Rope.ROPE _ IF shift THEN "shift" ELSE "noShift"; buttonRope: Rope.ROPE; SELECT mouseButton FROM red => buttonRope _ "red"; yellow => buttonRope _ "middle"; blue => buttonRope _ "right"; ENDCASE => ERROR; IF br = NIL THEN RETURN; def _ br.def; [viewer: viewer, start: start] _ TiogaOps.GetSelection[primary]; curSel _ ViewerTools.GetSelectionContents[]; IF viewer # NIL AND NOT viewer.destroyed AND NOT viewer.newFile THEN { root: TiogaOps.Ref _ TiogaOps.Root[start.node]; offset: INT _ TiogaOps.LocOffset[loc1: [root, 0], loc2: start, skipCommentNodes: TRUE]; index _ offset; viewerName _ viewer.name; }; <> pos _ curSel.Find["\n"]; IF pos # -1 THEN curSel _ Rope.Substr[base: curSel, start: 0, len: pos]; <> fileName _ IF (Rope.SkipTo[s: curSel, pos: 0, skip: " "] = curSel.Length[]) AND (curSel.Length[] > 1) THEN curSel ELSE viewerName; shortFileName _ FileNames.GetShortName[path: fileName, stripOffVersionNumber: TRUE]; def _ RopeSubst[ old: "$CurrentSelection$", new: curSel, base: def, case: TRUE]; def _ RopeSubst[ old: "$FileNameSelection$", new: fileName, base: def, case: TRUE]; def _ RopeSubst[ old: "$ShortFileNameSelection$", new: shortFileName, base: def, case: TRUE]; def _ RopeSubst[ old: "$SelectedViewerName$", new: viewerName, base: def, case: TRUE]; def _ RopeSubst[ old: "$ViewerPosition$", new: Convert.RopeFromInt[index, 10, FALSE], base: def, case: TRUE]; def _ RopeSubst[ old: "$MouseButton$", new: buttonRope, base: def, case: TRUE]; def _ RopeSubst[ old: "$ControlKey$", new: controlRope, base: def, case: TRUE]; def _ RopeSubst[ old: "$ShiftKey$", new: shiftRope, base: def, case: TRUE]; { bufferContents: REF TEXT _ ViewerIOExtras.GetBuffer[br.rep.in]; 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: br.rep.in, nChars: bufferContents.length - n - 1]; EXIT; } REPEAT FINISHED => EditedStream.UnAppendBufferChars[stream: br.rep.in, nChars: LAST[NAT]]; ENDLOOP; }; }; <> IF viewer = br.rep.viewer THEN ViewerTools.SetSelection[viewer: viewer, selection: NIL]; ViewerIOExtras.TypeChars[editedViewerStream: br.rep.in, chars: def]; }; ButtonImplRef: TYPE = REF ButtonImplObject; ButtonImplObject: TYPE = RECORD [ rep: ReadEvalPrint.Handle _ NIL, def: Rope.ROPE _ NIL ]; Init: PROC = { Commander.Register[key: "///Commands/Alias", proc: Alias, doc: "Create an alias for a command"]; Commander.Register[key: "///Commands/CreateButton", proc: CreateButton, doc: "Create a CommandTool herald button"]; CommandExtras.MakeUninterpreted[Commander.Lookup["///Commands/CreateButton"]]; Commander.Register[key: "///Commands/RemoveButton", proc: CreateButton, doc: "Remove a CommandTool herald button"]; }; Init[]; END.