DIRECTORY Atom USING [GetPName], Commander USING [CommandProc, Handle, Lookup, Register], CommandExtras USING [MakeUninterpreted], CommandTool USING [DoCommand], Convert USING [RopeFromInt], EditedStream USING [UnAppendBufferChars], 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, MenuEntry, ReplaceMenuEntry], ReadEvalPrint USING [Handle], Rope USING [Cat, Concat, Equal, Fetch, Find, FromChar, FromRefText, Length, 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, 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; 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].token; br.def _ Rope.FromRefText[token]; IF br.def.Length[] = 0 THEN RETURN[$Failure, "No definition rope"]; IF br.def.Fetch[br.def.Length[] - 1] # '\n THEN br.def _ Rope.Concat[br.def, "\n"]; WHILE br.rep = NIL DO br.rep _ NARROW[List.Assoc[key: $ReadEvalPrintHandle, aList: cth.propertyList]]; IF br.rep # NIL AND br.rep.viewer # NIL THEN EXIT ELSE br.rep _ NIL; cth _ NARROW[List.Assoc[key: $ParentCommander, aList: cth.propertyList]]; IF cth = NIL THEN RETURN[$Failure, "Can't find $ReadEvalPrintHandle"]; ENDLOOP; Menus.AppendMenuEntry[menu: br.rep.viewer.menu, line: 0, entry: MBQueue.CreateMenuEntry[q: br.rep.menuHitQueue, name: name, proc: ButtonImplButtonProc, clientData: br]]; ViewerOps.PaintViewer[viewer: br.rep.viewer, hint: menu, clearClient: FALSE]; EXITS Die => NULL; }; commandLineStream.Close[]; }; DeleteButton: Commander.CommandProc = TRUSTED { commandLineStream: IO.STREAM = IO.RIS[cmd.commandLine]; name: Rope.ROPE; token: REF TEXT _ NEW[TEXT[30]]; br: ButtonImplRef _ NEW[ButtonImplObject]; cth: Commander.Handle _ cmd; oldEntry: Menus.MenuEntry; { ENABLE { IO.EndOfStream => GOTO Die; IO.Error => GOTO Die; }; token.length _ 0; token _ commandLineStream.GetToken[IO.TokenProc, token].token; name _ Rope.FromRefText[token]; commandLineStream.Close[]; WHILE br.rep = NIL DO br.rep _ NARROW[List.Assoc[key: $ReadEvalPrintHandle, aList: cth.propertyList]]; IF br.rep # NIL AND br.rep.viewer # NIL THEN EXIT ELSE br.rep _ NIL; cth _ NARROW[List.Assoc[key: $ParentCommander, aList: cth.propertyList]]; IF cth = NIL THEN RETURN[$Failure, "Can't find $ReadEvalPrintHandle"]; ENDLOOP; oldEntry _ Menus.FindEntry[menu: br.rep.viewer.menu, entryName: name]; IF oldEntry = NIL THEN RETURN[$Failure, "Can't find that button"]; Menus.ReplaceMenuEntry[menu: br.rep.viewer.menu, oldEntry: oldEntry, newEntry: NIL]; ViewerOps.PaintViewer[viewer: br.rep.viewer, hint: menu, clearClient: FALSE]; EXITS Die => NULL; }; }; 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; 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; def _ RopeSubst[old: "$CurrentSelection$", new: curSel, base: def, case: TRUE, allOccurrences: TRUE]; def _ RopeSubst[old: "$FileNameSelection$", new: fileName, base: def, case: TRUE, allOccurrences: TRUE]; def _ RopeSubst[old: "$SelectedViewerName$", new: viewerName, base: def, case: TRUE, allOccurrences: TRUE]; def _ RopeSubst[old: "$ViewerPosition$", new: Convert.RopeFromInt[index, 10, FALSE], base: def, case: TRUE, allOccurrences: TRUE]; def _ RopeSubst[old: "$MouseButton$", new: buttonRope, base: def, case: TRUE, allOccurrences: TRUE]; def _ RopeSubst[old: "$ControlKey$", new: controlRope, base: def, case: TRUE, allOccurrences: TRUE]; def _ RopeSubst[old: "$ShiftKey$", new: shiftRope, base: def, case: TRUE, allOccurrences: 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/DeleteButton", proc: DeleteButton, doc: "Delete a CommandTool herald button"]; }; Init[]; END. ¬CommandsCImpl.mesa L. Stewart, December 20, 1983 1:29 pm Teitelman, earlier if old is not found in base, then value = base. if allOccurrences THEN substitute for each occurrence of old, otherwise only for first. The first token willl be the name of the button. The rest of the commandLine will be the thing to stuff. A special character sequence, $$, will stand for the current selection. Get the rest of it! Search up chain of parents to find a ReadEvalPrint.Handle and the associated commander The first token willl be the name of the button. Search up chain of parents to find a ReadEvalPrint.Handle and the associated commander There are specialized tokens: $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 $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" Get prefix of current selection before the first CR The curSel is the fileName if curSel is longer than one character and contains no whitespace. If the selected viewer is the commandtoo, then set the caret to the end, or the ViewerIOExtras.TypeChars won't work. Ê ˜šœ™J™9—J˜šÏk ˜ Jšœœ ˜Jšœ œ)˜8Jšœœ˜(Jšœ œ ˜Jšœœ˜Jšœ œ˜)JšœœVœœ ˜†Jšœœ ˜Jšœœ˜ JšœœF˜QJšœœ ˜JšœœKœ˜kJšœ œ ˜Jšœ œ0˜>Jšœœ ˜Jšœœ˜,Jšœ œ˜Jšœ œ&˜7—J˜Jšœœ˜š˜JšœZœD˜ —Jš˜J˜šœœœ˜ Jš œœœœœ˜Jšœ ˜J˜—J˜Jšœ œœ˜&J˜šœœ˜(Jš œœœœœ˜7Jšœœ˜Jš œœœœœ˜ Jš œœœœœ˜J˜J˜šœ˜Jšœœ˜Jšœ œ˜J˜—J˜Jšœ#œ˜>Jšœ˜Jšœ&œ˜-šœœœ#œ˜Mšœœœœœœ(œœ˜Xšœ œ˜Jšœœ œ ˜%Jšœœ œ˜/Jšœœ˜—Jšœ˜—Jšœ#˜*J˜—J˜Jšœ9˜9Jšœ˜Jšœ œ ˜/Jšœx˜xJšœ˜Jš˜Jšœœ˜ J˜J˜—J˜šÏn œœœœœœœœœ˜sJšœœ˜Jšœœ˜Jšœœ˜ šœ>˜EJšœB˜BJšœœœ˜J˜Jšœ˜—Jšœ˜ J˜šœ/™/JšœW™W——J˜šžœœ œœœœœœ˜Jš œœœœœœ˜7Jš œœœœœ˜6Jšœ˜—Jšœœ˜ J˜—J˜Jšœ œœ ˜J˜š ž œœ œœœ˜;J˜Jšœ?œ˜NJšœÏc ˜—J™šœ'œ˜0Jšœœ˜7Jšœœ˜*Jš œœœœœ˜ Jšœ œ˜Jšœœ˜Jš œœœœœ˜7Jšœ œœœ˜$Jšœœœœ˜2J˜š œœœœœœ˜BJ˜Jšœ#œ˜;Jšœ˜šœœŸ/˜PJšœ œ˜ Jšœ œœ*˜=J˜ J˜—JšœOœ˜WJšœ˜—š œœœœ"œœ˜DJšœ[œ˜cJšœ˜—J˜Jšœ9˜9Jšœ'˜'Jšœ>˜>Jšœ˜JšœI˜IJ˜—J˜šœ œ˜Jšœ œœ˜!Jšœ˜J˜—J˜J™²šœ&œ˜/Jš œœœœœ˜7Jšœ œ˜Jš œœœœœ˜ Jšœœ˜*J˜J˜šœ˜Jšœœ˜Jšœ œ˜J˜—J˜Jšœ#œ˜>Jšœ˜Jšœ&œ˜-J™J˜Jšœ9˜9Jšœ!˜!Jšœœœ!˜CJšœ)œ$˜SJšœV™Všœ œ˜Jšœ œA˜PJš œ œœœœ˜1Jšœ œ˜Jšœœ=˜IJšœœœœ.˜FJšœ˜J˜—Jšœ©˜©JšœFœ˜MJš˜Jšœœ˜ J˜Jšœ˜J˜—J™J™0šœ&œ˜/Jš œœœœœ˜7Jšœ œ˜Jš œœœœœ˜ Jšœœ˜*J˜Jšœ˜J˜šœ˜Jšœœ˜Jšœ œ˜J˜—J˜Jšœ#œ˜>Jšœ˜Jšœ˜JšœV™Všœ œ˜Jšœ œA˜PJš œ œœœœ˜1Jšœ œ˜Jšœœ=˜IJšœœœœ.˜FJšœ˜J˜—JšœF˜FJšœ œœœ%˜BJšœOœ˜TJšœFœ˜MJš˜Jšœœ˜ J˜J˜—J˜™J™jJ™J™CJ™QJ™-J™ J™#—šœ)˜)Jšœœ ˜'Jšœ œ˜Jšœ œ˜Jšœœ˜#Jšœ˜Jšœœœ˜Jšœœœ˜Jšœœ˜Jšœœ˜ Jš œœœ œ œ ˜DJš œœœœ œ ˜