DIRECTORY Commander USING [CommandProc, Handle, Register, CommandObject], CommandTool USING [ArgumentVector, Parse, Failed, GetProp], Convert USING [CardFromRope, Error], FileNames USING [CurrentWorkingDirectory, ConvertToSlashFormat, ResolveRelativePath, HomeDirectory], FS USING [ExpandName, Error, ErrorDesc], List USING [PutAssoc], ProcessProps USING [GetPropList], ReadEvalPrint USING [Handle], Rope USING [ROPE, Fetch, Length, Concat, Cat, Substr, Index], ViewerClasses USING [Viewer], ViewerOps USING [PaintViewer]; WorkingDirectory: CEDAR PROGRAM IMPORTS Commander, CommandTool, Convert, FileNames, FS, List, ProcessProps, Rope, ViewerOps = { HomeDirectoryAbbreviation: Rope.ROPE _ "~/"; GetHomeDirectoryAbbreviation: PROCEDURE [] RETURNS [Rope.ROPE] = { RETURN [HomeDirectoryAbbreviation]; }; SetHomeDirectoryAbbreviation: PROCEDURE [new: Rope.ROPE] RETURNS [old: Rope.ROPE] = { old _ GetHomeDirectoryAbbreviation[]; HomeDirectoryAbbreviation _ new; }; FSErrorMsg: PROCEDURE [error: FS.ErrorDesc] RETURNS [Rope.ROPE] = { SELECT error.group FROM lock => RETURN[" -- locked!\n"]; ENDCASE => IF error.code = $unknownFile THEN RETURN [" -- not found!\n"] ELSE RETURN[Rope.Cat[" -- FS.Error: ", error.explanation, "\n"]]; }; TildeCompact: PROCEDURE [dir: Rope.ROPE] RETURNS [Rope.ROPE] = { RopeIsPrefix: PROCEDURE [prefix: Rope.ROPE, subject: Rope.ROPE, case: BOOL _ TRUE] RETURNS [BOOL] = { RETURN [subject.Substr[len: prefix.Length[]].Index[s2: prefix, case: case] = 0]; }; FileNamesIsAbsolutePath: PROCEDURE [name: Rope.ROPE] RETURNS [BOOL] = { RETURN [ name.Fetch[0] = '/ OR name.Fetch[0] = '[ ]; }; home: Rope.ROPE = FileNames.HomeDirectory[]; dir _ FileNames.ResolveRelativePath[FileNames.ConvertToSlashFormat[dir]]; IF dir.Length[] # 0 AND NOT FileNamesIsAbsolutePath[dir] THEN dir _ Rope.Concat[FileNames.CurrentWorkingDirectory[], dir]; IF RopeIsPrefix[prefix: home, subject: dir] THEN dir _ Rope.Concat[GetHomeDirectoryAbbreviation[], Rope.Substr[dir, home.Length[]]]; RETURN [dir]; }; SetCommandToolHerald: PROCEDURE [cmd: REF Commander.CommandObject, wDir: Rope.ROPE] = { WITH CommandTool.GetProp[cmd, $ReadEvalPrintHandle] SELECT FROM rep: ReadEvalPrint.Handle => { root: ViewerClasses.Viewer _ rep.viewer; IF root # NIL THEN { root.name _ Rope.Concat["CommandTool: WD = ", wDir]; root.label _ TildeCompact[wDir]; ViewerOps.PaintViewer[viewer: root, hint: caption, clearClient: FALSE]; FOR v: ViewerClasses.Viewer _ root.link, v.link WHILE v # NIL AND v # root DO v.name _ root.name; v.name _ root.label; ViewerOps.PaintViewer[viewer: v, hint: caption, clearClient: FALSE]; ENDLOOP; }; }; ENDCASE; }; ChangeWorkingDirectory: Commander.CommandProc = { wDir: Rope.ROPE; argv: CommandTool.ArgumentVector _ CommandTool.Parse[cmd, TRUE ! CommandTool.Failed => {msg _ errorMsg; GO TO oops}]; list: LIST OF Rope.ROPE _ NARROW[CommandTool.GetProp[cmd, $WorkingDirectoryStack]]; SELECT cmd.procData.clientData FROM $PushWorkingDirectory, $Push, $PushR => list _ CONS[FileNames.CurrentWorkingDirectory[], list]; ENDCASE; SELECT cmd.procData.clientData FROM $ChangeWorkingDirectory, $CD, $CDR, $PushWorkingDirectory, $Push, $PushR => { root: BOOL _ (cmd.procData.clientData = $CDR OR cmd.procData.clientData = $PushR); SELECT argv.argc FROM 1 => wDir _ IF root THEN "///" ELSE FileNames.HomeDirectory[]; 2 => { wDir _ argv[1]; IF root THEN { wDir _ FileNames.ConvertToSlashFormat[FS.ExpandName[wDir, "///" ! FS.Error => { msg _ FSErrorMsg[error]; GO TO oops }; ].fullFName]; }; }; ENDCASE => { msg _ "Usage: ChangeWorkingDirectory directoryName"; GO TO oops }; }; $PopWorkingDirectory, $Pop => { IF list = NIL THEN wDir _ FileNames.CurrentWorkingDirectory[] ELSE { wDir _ list.first; list _ list.rest; }; }; $RollDirectoryStack, $RollDS => { count: CARDINAL; ListOfRopeAppend1: PROCEDURE [list: LIST OF Rope.ROPE, element: Rope.ROPE] RETURNS [LIST OF Rope.ROPE] = { IF list = NIL THEN RETURN [CONS[element, NIL]] ELSE RETURN [CONS[list.first, ListOfRopeAppend1[list.rest, element]]]; }; SELECT argv.argc FROM 1 => { count _ 1; }; 2 => { count _ Convert.CardFromRope[argv[1] ! Convert.Error => GO TO rollUsage ]; }; ENDCASE => GO TO rollUsage; list _ CONS[FileNames.CurrentWorkingDirectory[], list]; FOR rolls: CARDINAL IN [1..count] DO list _ ListOfRopeAppend1[list.rest, list.first]; ENDLOOP; wDir _ list.first; list _ list.rest; EXITS rollUsage => { msg _ "Usage: RollDirectoryStack [count: CARDINAL _ 1]"; GO TO oops; }; }; ENDCASE => GO TO huh; [result, msg] _ SetWD[wDir]; IF result # $Failure THEN { cmd.propertyList _ List.PutAssoc[$WorkingDirectoryStack, list, cmd.propertyList]; SetCommandToolHerald[cmd, msg]; }; SELECT cmd.procData.clientData FROM $CD, $Push, $Pop, $RollDS => msg _ TildeCompact[msg]; ENDCASE; EXITS oops => result _ $Failure; huh => { result _ $Failure; msg _ "bad clientData" }; }; SetWD: PROCEDURE [wDir: Rope.ROPE] RETURNS [result: REF ANY _ NIL, msg: Rope.ROPE _ NIL] = { wDir _ FileNames.ResolveRelativePath[FileNames.ConvertToSlashFormat[wDir]]; IF wDir.Length[] = 0 THEN RETURN[$Failure, "empty working directory"]; IF wDir.Fetch[0] # '/ THEN wDir _ Rope.Concat[FileNames.CurrentWorkingDirectory[], wDir]; IF wDir.Fetch[wDir.Length[] - 1] # '/ THEN wDir _ Rope.Concat[wDir, "/"]; IF wDir.Length[] < 3 THEN RETURN[NIL]; msg _ wDir; [] _ List.PutAssoc[key: $WorkingDirectory, val: wDir, aList: ProcessProps.GetPropList[]]; }; PrintWorkingDirectory: Commander.CommandProc = { RETURN[NIL, FileNames.CurrentWorkingDirectory[]]; }; PrintDirectoryStack: Commander.CommandProc = { IF cmd.procData.clientData = $PDS THEN msg _ TildeCompact[FileNames.CurrentWorkingDirectory[]] ELSE msg _ FileNames.CurrentWorkingDirectory[]; FOR list: LIST OF Rope.ROPE _ NARROW[CommandTool.GetProp[cmd, $WorkingDirectoryStack]], list.rest UNTIL list = NIL DO IF cmd.procData.clientData = $PDS THEN msg _ Rope.Cat[msg, " ", TildeCompact[list.first]] ELSE msg _ Rope.Cat[msg, " ", list.first]; ENDLOOP; RETURN[NIL, msg]; }; WorkingDirectory: Commander.CommandProc = { SetCommandToolHerald[cmd: cmd, wDir: FileNames.CurrentWorkingDirectory[]]; }; Init: PROCEDURE = { Commander.Register[ key: "PrintWorkingDirectory", proc: PrintWorkingDirectory, doc: "Print working directory", clientData: $PrintWorkingDirectory]; Commander.Register[ key: "PWD", proc: PrintWorkingDirectory, doc: "Print working directory", clientData: $PWD]; Commander.Register[ key: "PrintDirectoryStack", proc: PrintDirectoryStack, doc: "Print directory stack", clientData: $PrintDirectoryStack]; Commander.Register[ key: "PDS", proc: PrintDirectoryStack, doc: "Print working directory", clientData: $PDS]; Commander.Register[ key: "ChangeWorkingDirectory", proc: ChangeWorkingDirectory, doc: "Change working directory", clientData: $ChangeWorkingDirectory]; Commander.Register[ key: "CD", proc: ChangeWorkingDirectory, doc: "Change working directory", clientData: $CD]; Commander.Register[ key: "CDR", proc: ChangeWorkingDirectory, doc: "Change working directory (root relative)", clientData: $CDR]; Commander.Register[ key: "PushWorkingDirectory", proc: ChangeWorkingDirectory, doc: "Push working directory", clientData: $PushWorkingDirectory]; Commander.Register[ key: "Push", proc: ChangeWorkingDirectory, doc: "Push working directory", clientData: $Push]; Commander.Register[ key: "PushR", proc: ChangeWorkingDirectory, doc: "Push working directory (root relative)", clientData: $PushR]; Commander.Register[ key: "PopWorkingDirectory", proc: ChangeWorkingDirectory, doc: "Pop working directory", clientData: $PopWorkingDirectory]; Commander.Register[ key: "Pop", proc: ChangeWorkingDirectory, doc: "Pop working directory", clientData: $Pop]; Commander.Register[ key: "RollDirectoryStack", proc: ChangeWorkingDirectory, doc: "Roll the directory stack n times", clientData: $RollDirectoryStack]; Commander.Register[ key: "RollDS", proc: ChangeWorkingDirectory, doc: "Roll the directory stack n times", clientData: $RollDS]; Commander.Register[ key: "WorkingDirectory", proc: WorkingDirectory, doc: "Initialize the CommandTool herald", clientData: NIL]; }; Init[]; }. WorkingDirectory.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Last edited by PeterKessler, July 9, 1985 12:00:00 pm PDT Peter Kessler February 12, 1986 3:12:37 pm PST This program manipulates the same data structures as the CommandTool that define the current working directory and stack of working directories of a command tool. There are several major changes from the standard CommandTool: (1) The label of the CommandTool viewer is set to the ``TildeCompaction'' of the current working directory (so it prints in the space available) rather than the full name of the command tool viewer. Even heathens who think of /// as their home directory will be pleased to get whatever comes after the ``///'' instead of the leading ``CommandTool: WD = ''. TildeCompaction is defined by the procedure TildeCompact below, which substitutes an abbreviation for the user's home directory. Directories outside the user's home directory are untouched. The default printing of a directories is now the TildeCompation of the directory, for command like ``cd''. For sanity, the ``pwd'' command (and the long forms of the other commands, e.g. ``ChangeWorkingDirectory'') print the long form of the directory. (2) The stack of working directories can now be printed! The commands ``pds'' and ``PrintDirectoryStack'' print (respectively) the short and long forms of the directories in the stack, with the current working directory on the left. (3) The stack of working directories can now be rolled. The command ``RollDirectoryStack'' takes a cardinal argument (default 1) and rolls the directory stack that number of times. (No, I didn't implement the two argument form of roll, since I can't remember which argument comes first.) [cmd: REF CommandObject] RETURNS [result: REF _ NIL, msg: Rope.ROPE _ NIL] CommandObject = [ in, out, err: STREAM, commandLine, command: Rope.ROPE, propertyList: List.AList, procData: CommandProcHandle] Note that this procedure only knows it is dealing with lists of Rope.ROPE in the declaration of the arguments and return value. Given a type T, this could take lists of T and a T and return a list of T. no arguments means roll the directory stack once. one argument means roll the directory stack argv[1] times cons the current directory onto the list, roll the list, and extract the first element. Do a bit of checking! [cmd: REF CommandObject] RETURNS [result: REF _ NIL, msg: Rope.ROPE _ NIL] CommandObject = [ in, out, err: STREAM, commandLine, command: ROPE, propertyList: List.AList, procData: CommandProcHandle] IF cmd.procData.clientData = $PWD THEN RETURN[NIL, TildeCompact[FileNames.CurrentWorkingDirectory[]]] ELSE [cmd: REF CommandObject] RETURNS [result: REF _ NIL, msg: Rope.ROPE _ NIL] CommandObject = [ in, out, err: STREAM, commandLine, command: ROPE, propertyList: List.AList, procData: CommandProcHandle] [cmd: REF CommandObject] RETURNS [result: REF _ NIL, msg: Rope.ROPE _ NIL] CommandObject = [ in, out, err: STREAM, commandLine, command: ROPE, propertyList: List.AList, procData: CommandProcHandle] Κ ώ˜code™Kšœ Οmœ1™Kšœ)žœžœ˜6—Kš œžœžœžœžœ3˜Sšžœž˜#šœ'˜'Kšœžœ,˜7—Kšžœ˜—šžœž˜#šœM˜MKšœžœ#žœ#˜Ršžœ ž˜Kšœ žœžœžœ˜>šœ˜Kšœ˜šžœžœ˜šœ&žœ˜?šœžœ ˜Kšœ˜Kšžœžœ˜ Kšœ˜—Kšœ ˜ —K˜—K˜—šžœ˜ Kšœ4˜4Kšžœžœ˜ Kšœ˜——Kšœ˜—˜šžœž˜ Kšžœ+˜/šž˜Kšœ˜K˜K˜——Kšœ˜—šœ!˜!Kšœžœ˜š œž œžœžœžœžœžœžœžœžœ˜jK™Λšžœž˜ šžœ˜Kšžœžœ žœ˜—šž˜Kšžœžœ5˜A——K˜—šžœ ž˜šœ˜K™1K˜ K˜—šœ˜K™9šœ$˜$Kšœžœžœ ˜"Kšœ˜—K˜—Kšžœžœžœ ˜—K™WKšœžœ,˜7šžœžœžœ ž˜$Kšœ0˜0Kšžœ˜—K˜K˜šž˜šœ˜Kšœ8˜8Kšžœžœ˜ Kšœ˜——K˜—Kšžœžœžœ˜—Kšœ˜šžœžœ˜KšœQ˜QKšœ˜K˜—šžœž˜#Kšœ5˜5Kšžœ˜—šž˜Kšœ˜˜K˜K˜K˜——K˜—K˜š œž œ žœžœ žœžœžœ žœžœ˜\KšœK˜KK™Kšžœžœžœ&˜Fšžœž˜Kšœ>˜>—Kšžœ$žœ˜IKšžœžœžœžœ˜&Kšœ ˜ KšœY˜YK˜—K˜š œ˜0Kš œžœžœ žœžœž œžœ™Jšœ™Kšœžœžœ™1Kšœ6™6—šžœ™!šž™Kšžœžœ4™>—šž™Kšžœžœ'˜1——K˜—K˜š œ˜.Kš œžœžœ žœžœž œžœ™Jšœ™Kšœžœžœ™1Kšœ6™6—šžœ˜!Kšžœ8˜žœžœž˜ušžœ˜!Kšžœ3˜7Kšžœ&˜*—Kšžœ˜—Kšžœžœ˜K˜—K˜š œ˜+Kš œžœžœ žœžœž œžœ™Jšœ™Kšœžœžœ™1Kšœ6™6—JšœJ˜JK˜—K˜š œž œ˜šœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ$˜$—šœ˜Kšœ ˜ Kšœ˜Kšœ˜Kšœ˜—šœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ"˜"—šœ˜Kšœ ˜ Kšœ˜Kšœ˜Kšœ˜—šœ˜Kšœ˜Kšœ˜Kšœ ˜ Kšœ%˜%—šœ˜Kšœ ˜ Kšœ˜Kšœ ˜ Kšœ˜—šœ˜Kšœ ˜ Kšœ˜Kšœ0˜0Kšœ˜—šœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ#˜#—šœ˜Kšœ ˜ Kšœ˜Kšœ˜Kšœ˜—šœ˜Kšœ ˜ Kšœ˜Kšœ.˜.Kšœ˜—šœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ"˜"—šœ˜Kšœ ˜ Kšœ˜Kšœ˜Kšœ˜—šœ˜Kšœ˜Kšœ˜Kšœ(˜(Kšœ!˜!—šœ˜Kšœ˜Kšœ˜Kšœ(˜(Kšœ˜—šœ˜Kšœ˜Kšœ˜Kšœ)˜)Kšœ žœ˜—K˜—K˜K˜K˜K˜K˜——…—Ž6’