ButtonLSImpl.mesa
Copyright Ó 1990, 1992 by Xerox Corporation. All rights reserved.
Doug Wyatt, August 16, 1990 1:59 pm PDT
Bier, February 12, 1992 3:40 pm PST
Kenneth A. Pier, October 30, 1990 2:01 pm PST
Chauser, May 27, 1992 11:35 am PDT
DIRECTORY
ProcessProps, Atom, BasicTime, Commander, CommanderOps, IO, IOTioga, List, NodeProps, PFS, PFSNames, PriorityQueue, Process, Rope;
ButtonLSImpl: CEDAR PROGRAM
IMPORTS ProcessProps, BasicTime, Commander, CommanderOps, IO, IOTioga, List, NodeProps, PFS, PFSNames, PriorityQueue, Process, Rope
SHARES IO
~ BEGIN
ROPE: TYPE ~ Rope.ROPE;
PATH: TYPE ~ PFSNames.PATH;
STREAM: TYPE ~ IO.STREAM;
GMT: TYPE ~ BasicTime.GMT;
LORA: TYPE ~ LIST OF REF ANY;
FileItem: TYPE = REF FileItemRep;
FileItemRep: TYPE = RECORD [fullUName, attachedTo: PATH, created: GMT, bytes: INT, fileType: PFS.FileType];
SortPred: PriorityQueue.SortPred = {
[x: Item, y: Item, data: REF] RETURNS [BOOL]
xx: FileItem = NARROW[x];
yy: FileItem = NARROW[y];
options: LORA = NARROW[data];
FOR each: LORA ¬ options, each.rest WHILE each # NIL DO
SELECT each.first FROM
$MoreRecent => IF xx.created#yy.created THEN
RETURN [BasicTime.Period[xx.created, yy.created] < 0];
$LessRecent => IF xx.created#yy.created THEN
RETURN [BasicTime.Period[xx.created, yy.created] > 0];
$Larger => IF xx.bytes#yy.bytes THEN
RETURN [xx.bytes > yy.bytes];
$Smaller => IF xx.bytes#yy.bytes THEN
RETURN [xx.bytes < yy.bytes];
ENDCASE;
ENDLOOP;
RETURN [PFSNames.Compare[xx.fullUName, yy.fullUName, FALSE] = less];
};
QuotedStringError: ERROR = CODE;
CmdTokenBreak: PROC [char: CHAR] RETURNS [IO.CharClass] = {
IF char = '" THEN RETURN [break];
IF char = ' OR char = '\t OR char = ', OR char = '\l OR char = '\r THEN RETURN [sepr];
RETURN [other];
};
Token: TYPE = RECORD [value, literal: ROPE];
GetCmdToken: PROC [stream: IO.STREAM] RETURNS [token: Token ¬ [NIL, NIL]] = {
token.value ¬ token.literal ¬ IO.GetTokenRope[stream, CmdTokenBreak ! IO.EndOfStream => CONTINUE].token;
IF Rope.Equal[token.literal, "\""] THEN {
ref: REF;
IO.Backup[self: stream, char: '"];
ref ¬ IO.GetRefAny[stream ! IO.Error, IO.EndOfStream => ERROR QuotedStringError];
WITH ref SELECT FROM
rope: ROPE => token.value ¬ rope;
ENDCASE => ERROR QuotedStringError;
};
};
monthName: ARRAY BasicTime.MonthOfYear[January..December] OF ROPE ~ [
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
];
-- Stolen from DFUtilitiesImpl
DateFormat: TYPE = {explicit, omitted, greaterThan, notEqual};
Date: TYPE = RECORD [
format: DateFormat ¬ $omitted,
gmt: GMT ¬ BasicTime.nullGMT
'gmt' is valid only if dateFormat = $explicit. (We don't use a variant record because it complicates the client's life too much (i.e., the compiler is unnecessarily picky about assignments involving variant records that aren't REF-containing).)
];
Note: Dates returned by ParseFromStream are guaranteed to have `gmt' = nullGMT if `format' ~= $explicit. The other procedures of this interface ignore the 'gmt' field if 'format' ~= $explicit.
DateToStream: PROC [s: STREAM, date: Date] = {
SELECT date.format FROM
$explicit => {
months: ROPE = "JanFebMarAprMayJunJulAugSepOctNovDec";
up: BasicTime.Unpacked = BasicTime.Unpack[date.gmt
! BasicTime.OutOfRange, BasicTime.TimeParametersNotKnown => GO TO noDate];
ConvertZone: PROC = {
dst: BOOL = up.dst = yes;
SELECT up.zone FROM
0 => IF ~dst THEN s.PutRope["GMT"];
NAT[5*BasicTime.minutesPerHour] => s.PutRope[IF dst THEN "EDT" ELSE "EST"];
NAT[6*BasicTime.minutesPerHour] => s.PutRope[IF dst THEN "CDT" ELSE "CST"];
NAT[7*BasicTime.minutesPerHour] => s.PutRope[IF dst THEN "MDT" ELSE "MST"];
NAT[8*BasicTime.minutesPerHour] => s.PutRope[IF dst THEN "PDT" ELSE "PST"];
ENDCASE =>
s.PutF["%g%02d%02d",
[character[IF up.zone < 0 THEN '- ELSE '+]],
[cardinal[up.zone.ABS/BasicTime.minutesPerHour]],
[cardinal[up.zone.ABS MOD BasicTime.minutesPerHour]]
]
};
s.PutF["%02d-%g-%02d ",
[cardinal[up.day]],
[rope[months.Substr[start: up.month.ORD*3, len: 3]]],
[cardinal[up.year MOD 100]]
];
s.PutF["%02d:%02d:%02d ",
[cardinal[up.hour]], [cardinal[up.minute]], [cardinal[up.second]]];
ConvertZone[];
};
$notEqual => s.PutRope["~="];
$greaterThan => s.PutChar['>];
ENDCASE;
EXITS
noDate => NULL;
};
theButtonDataKey: ATOM ~ $ButtonData;
theButtonDataRope: ROPE ~ "Poppy1
Class: PopUpButton
MessageHandler: CommandTool
Menu: (
((<Concat \"Open \\\"\" <PropertyText ButtonLSFileName> \"\\\"\">) \"Open\" \"Opens a viewer on the file\")
()
(<Send Tioga <Concat \" \\\"\" <PropertyText ButtonLSFileName> \"\\\"\">> \"Stuff filename\" \"Stuff filename at the current insertion point\")
)
Feedback: (
(MouseMoved <SetCursor bullseye>)
)";
theButtonDataValue: REF ~ NodeProps.DoSpecs[theButtonDataKey, theButtonDataRope];
theDFButtonDataRope: ROPE ~ "Poppy1
Class: PopUpButton
MessageHandler: CommandTool
Menu: (
((<Concat \"Open \\\"\" <PropertyText ButtonLSFileName> \"\\\"\">) \"Open\" \"Opens a viewer on the df file\")
((<Concat \"cd \\\"\" <DirectoryPart <PropertyText ButtonLSFileName>> \"\\\"; ButtonOpen \\\"\" <PropertyText ButtonLSFileName> \"\\\"\">) \"ButtonOpen\" \"Opens a browser for the files in the DF file\")
(<Send Tioga <Concat \" \\\"\" <PropertyText ButtonLSFileName> \"\\\"\">> \"Stuff filename\" \"Stuff filename at the current insertion point\")
)
Feedback: (
(MouseMoved <SetCursor bullseye>)
)";
theDFButtonDataValue: REF ~ NodeProps.DoSpecs[theButtonDataKey, theDFButtonDataRope];
theDirectoryButtonDataRope: ROPE ~ "Poppy1
Class: PopUpButton
MessageHandler: ThisCommandTool
Menu: (
((<Concat \"ButtonLS \\\"\" <PropertyText ButtonLSFileName> \"/*!H\\\"\">) \"ButtonLS\" \"Recursively invoke ButtonLS on this directory\")
((<Send CommandTool <Concat \"Fork ButtonLS \\\"\" <PropertyText ButtonLSFileName> \"/*!H\\\"\">>) \"Fork ButtonLS\" \"Recursively invoke ButtonLS on this directory\")
(<Send Tioga <Concat \" \\\"\" <PropertyText ButtonLSFileName> \"/\\\"\">> \"Stuff directory name\" \"Stuff directory name at the current insertion point\")
)
Feedback: (
(MouseMoved <SetCursor bullseye>)
)";
theDirectoryButtonDataValue: REF ~ NodeProps.DoSpecs[theButtonDataKey, theDirectoryButtonDataRope];
thePostfixKey: ATOM ~ $Postfix;
thePostfixRope: ROPE ~ "-2.0 outlineBoxBearoff 1.0 outlineBoxThickness";
thePostfixValue: REF ~ NodeProps.DoSpecs[thePostfixKey, thePostfixRope];
theFileNameKey: ATOM ~ $ButtonLSFileName;
lookF: IOTioga.Looks ~ IOTioga.LooksFromRope["f"];
SetCharProp: PROC [stream: STREAM, key: ATOM, val: REF] ~ {
old: IOTioga.PropList ~ IOTioga.GetCharProps[stream];
new: IOTioga.PropList ~ IOTioga.PropPut[old, key, val];
IOTioga.SetCharProps[stream, new];
};
SetLagPrefix: PROC [fileName: PATH, lagPrefix: PATH, lagPrefixLen: INT] RETURNS [newLagPrefix: PATH, newLagPrefixLen: INT] = {
... sets the lagging prefix from the given file name, which is presumed to be syntactically correct, although it need not be complete. A file name without a prefix will set the lagPrefix to NIL. We also enforce lagPrefixLen = Rope.Length[lagPrefix] at exit, assuming that no other routine sets lagPrefix.
newPrefix: PATH ¬ IF fileName# NIL THEN PFSNames.Parent[fileName] ELSE NIL;
newLagPrefix ¬ lagPrefix;
newLagPrefixLen ¬ lagPrefixLen;
IF lagPrefix # NIL THEN {
IF PFSNames.Equal[lagPrefix, newPrefix] THEN RETURN; -- new prefix same as old
};
We have a new lagging prefix, so scan backwards for the LAST directory
newLagPrefix ¬ newPrefix;
newLagPrefixLen ¬ PFSNames.ComponentCount[newPrefix];
};
ListCommandAux: PROC [cmd: Commander.Handle, printOneFile: PrintOneFileProc] RETURNS [result: REF ¬ NIL, msg: ROPE ¬ NIL] = {
PrintOneFile: PROC [item: FileItem] = {
[lagPrefix, lagPrefixLen] ¬ printOneFile[out, item, lagPrefix, lagPrefixLen, briefPrint, narrowPrint, fullPrint, attachPrint, oneLine, prefixOnly, typePrint];
};
EachFileName: PFS.NameProc = {
[name: PATH] RETURNS [continue: BOOL]
attachedTo: PATH ¬ NIL;
created: BasicTime.GMT ¬ BasicTime.nullGMT;
bytes: INT ¬ -1;
fileType: PFS.FileType ¬ PFS.tUnspecified;
uniqueID: PFS.UniqueID;
item: FileItem ¬ NIL;
continue ¬ TRUE;
Process.CheckForAbort[];
IF xactLevelMatch AND componentsRequired # PFSNames.ComponentCount[name] THEN RETURN;
IF NOT prefixOnly THEN {
We may need the info
[attachedTo: attachedTo, bytes: bytes, uniqueID: uniqueID, fileType: fileType] ¬ PFS.FileInfo[name: name];
};
IF bytes >=0 AND lostFilesOnly THEN RETURN;
IF attachedTo#NIL AND unattachedOnly THEN RETURN;
item ¬ NEW[FileItemRep ¬ [name, attachedTo, uniqueID.egmt.gmt, bytes, PFS.tUnspecified]];
filesSeen ¬ filesSeen + 1;
IF bytes > 0 THEN bytesTotal ¬ bytesTotal + bytes;
SELECT TRUE FROM
prefixOnly => {
oldLag: PATH ¬ lagPrefix;
[lagPrefix, lagPrefixLen] ¬ SetLagPrefix[name, lagPrefix, lagPrefixLen];
IF oldLag # lagPrefix THEN {
item.fullUName ¬ lagPrefix;
PriorityQueue.Insert[pq, item];
};
};
complexSorting => PriorityQueue.Insert[pq, item];
ENDCASE => PrintOneFile[item];
};
EachFileInfo: PFS.InfoProc = {
item: FileItem ¬ NIL;
continue ¬ TRUE;
Process.CheckForAbort[];
IF xactLevelMatch AND componentsRequired # PFSNames.ComponentCount[fullFName] THEN RETURN;
IF bytes >=0 AND lostFilesOnly THEN RETURN;
IF attachedTo#NIL AND unattachedOnly THEN RETURN;
item ¬ NEW[FileItemRep ¬ [fullFName, attachedTo, uniqueID.egmt.gmt, bytes, fileType]];
filesSeen ¬ filesSeen + 1;
IF bytes > 0 THEN bytesTotal ¬ bytesTotal + bytes;
SELECT TRUE FROM
prefixOnly => {
oldLag: PATH ¬ lagPrefix;
[lagPrefix, lagPrefixLen] ¬ SetLagPrefix[fullFName, lagPrefix, lagPrefixLen];
IF oldLag # lagPrefix THEN {
item.fullUName ¬ lagPrefix;
PriorityQueue.Insert[pq, item];
};
};
complexSorting => PriorityQueue.Insert[pq, item];
ENDCASE => PrintOneFile[item];
};
TryPattern: PROC [pattern: PATH, allVersions: BOOL¬FALSE] = {
Do: PROC [] ~ {
ENABLE PFS.Error => IF error.group # $bug THEN {
IO.PutRope[cmd.err, " -- "];
IO.PutRope[cmd.err, error.explanation];
IO.PutRope[cmd.err, "\n"];
GO TO err};
patternsTried ¬ patternsTried + 1;
IF allVersions THEN {
pattern ¬ PFSNames.SetVersionNumber[pattern, [all]];
highestPrint ¬ FALSE;
};
IF highestPrint THEN
pattern ¬ PFSNames.SetVersionNumber[pattern, [highest]];
IF xactLevelMatch THEN {
pattern ¬ PFS.AbsoluteName[pattern];
componentsRequired ¬ PFSNames.ComponentCount[pattern];
};
complexSorting ¬ sortData # NIL;
SELECT TRUE FROM
prefixOnly => pq ¬ PriorityQueue.Create[SortPred, NIL];
complexSorting => pq ¬ PriorityQueue.Create[SortPred, sortData];
ENDCASE => pq ¬ NIL;
[lagPrefix, lagPrefixLen] ¬ SetLagPrefix[NIL, lagPrefix, lagPrefixLen];
IF prefixOnly OR xactLevelMatch
THEN PFS.EnumerateForNames[pattern, EachFileName]
In these cases it is better to enumerate the names, then get the info
ELSE PFS.EnumerateForInfo[pattern, EachFileInfo];
In these cases it is better to enumerate for info, to reduce server traffic
[lagPrefix, lagPrefixLen] ¬ SetLagPrefix[NIL, lagPrefix, lagPrefixLen];
IF pq # NIL THEN {
lagName: PATH ¬ NIL;
THROUGH [0..PriorityQueue.Size[pq]) DO
item: FileItem = NARROW[PriorityQueue.Remove[pq]];
IF prefixOnly THEN {
IF PFSNames.Equal[item.fullUName, lagName] THEN LOOP;
lagName ¬ item.fullUName;
};
PrintOneFile[item];
ENDLOOP;
};
EXITS
err => {IO.PutRope[cmd.err, "\n"]; RETURN};
};
wDir: ROPE ~ NARROW[ProcessProps.GetProp[$WorkingDirectory]];
newProp: List.AList ~ List.PutAssoc[$WDir, PFS.PathFromRope[wDir], NIL];
ProcessProps.AddPropList[newProp, Do];
};
AddSortOption: PROC [option: ATOM] = {
new: LORA ¬ LIST[option];
IF sortDataTail = NIL THEN sortData ¬ new ELSE sortDataTail.rest ¬ new;
sortDataTail ¬ new;
};
RemSortOption: PROC [option: ATOM] = {
lag: LORA ¬ sortData;
IF lag = NIL THEN RETURN;
IF lag.first = option THEN {
sortData ¬ sortData.rest;
RETURN};
FOR each: LORA ¬ lag.rest, each.rest WHILE each # NIL DO
IF each.first = option THEN {lag.rest ¬ each.rest; EXIT};
lag ¬ each;
ENDLOOP;
};
ProcessSwitches: PROC [arg: ROPE] = {
sense: BOOL ¬ TRUE;
direction: {up, down} ¬ down;
FOR index: INT IN [1..Rope.Length[arg]) DO
SELECT Rope.Fetch[arg, index] FROM
'~ => {sense ¬ NOT sense; LOOP};
'> => direction ¬ down;
'< => direction ¬ up;
'a, 'A => attachPrint ¬ sense;
'b, 'B => briefPrint ¬ sense;
'd, 'D => {
RemSortOption[$MoreRecent];
RemSortOption[$LessRecent];
IF sense THEN
AddSortOption[IF direction = up THEN $LessRecent ELSE $MoreRecent];
};
'f, 'F => fullPrint ¬ sense;
'h, 'H => highestPrint ¬ sense;
'k, 'K => keepPrint ¬ sense;
'n, 'N => narrowPrint ¬ sense;
'o, 'O => oneLine ¬ sense;
'p, 'P => prefixOnly ¬ sense;
'r, 'R => {
-- remoteCheck ← sense;
};
's, 'S => {
RemSortOption[$Larger];
RemSortOption[$Smaller];
IF sense THEN
AddSortOption[IF direction = up THEN $Smaller ELSE $Larger];
};
't, 'T => typePrint ¬ sense;
'u, 'U => unattachedOnly ¬ sense;
'x, 'X => xactLevelMatch ¬ sense;
'z, 'Z => lostFilesOnly ¬ sense;
ENDCASE => {
result ¬ $Failure;
msg ¬ Rope.Cat["Unknown switch: ", arg.Substr[0, index], " ", arg.Substr[index]];
RETURN;
};
sense ¬ TRUE;
ENDLOOP;
};
gHost, gDir: ROPE ¬ NIL;
out: STREAM = cmd.out;
lagPrefix: PATH ¬ NIL;
lagPrefixLen: INT ¬ 0;
patternsTried, filesSeen, bytesTotal: INT ¬ 0;
briefPrint, complexSorting, fullPrint, attachPrint, keepPrint, lostFilesOnly, narrowPrint, oneLine, prefixOnly, typePrint, unattachedOnly, xactLevelMatch: BOOL ¬ FALSE;
highestPrint: BOOL ¬ cmd.procData.clientData = $Highest;
componentsRequired: INT ¬ 0;
sortData: LORA ¬ NIL;
sortDataTail: LORA ¬ NIL;
pq: PriorityQueue.Ref ¬ NIL;
argStream: IO.STREAM ~ IO.RIS[cmd.commandLine];
DO
arg: Token = GetCmdToken[argStream ! QuotedStringError => {msg ¬ "Mismatched quotes"; GO TO failed}];
IF arg.value = NIL THEN EXIT;
IF Rope.Length[arg.value] = 0 THEN LOOP;
IF Rope.Fetch[arg.literal, 0] = '- THEN {
This argument sets switches for the remaining patterns
ProcessSwitches[arg.literal];
IF result = $Failure THEN RETURN;
LOOP;
};
Now the argument is assumed to be a file pattern.
TryPattern[PFS.PathFromRope[arg.value ! PFS.Error => IF error.group # $bug THEN {
IO.PutRope[cmd.err, " -- "];
IO.PutRope[cmd.err, error.explanation];
IO.PutRope[cmd.err, "\n"];
GO TO failed}]];
ENDLOOP;
IF patternsTried = 0 THEN TryPattern[PFS.PathFromRope["*" ! PFS.Error => IF error.group # $bug THEN {
IO.PutRope[cmd.err, " -- "];
IO.PutRope[cmd.err, error.explanation];
IO.PutRope[cmd.err, "\n"];
GO TO failed}]];
IF oneLine THEN IO.PutChar[out, '\n];
IF filesSeen > 0 THEN {
out: IO.STREAM ~ IO.ROS[];
IO.PutF1[out, "-- %g files", [integer[filesSeen]] ];
IF bytesTotal > 0 THEN IO.PutF1[out, ", %g total bytes", [integer[bytesTotal]] ];
IO.PutChar[out, '\n];
msg ¬ IO.RopeFromROS[out];
};
EXITS
failed => {result ¬ $Failure};
}; -- end of ListCommandProc
PrintOneFileProc: TYPE = PROC [out: IO.STREAM, item: FileItem, lagPrefix: PATH, lagPrefixLen: INT, briefPrint, narrowPrint, fullPrint, attachPrint, oneLine, prefixOnly, typePrint: BOOL] RETURNS [newLagPrefix: PATH, newLagPrefixLen: INT];
ButtonPrintOneFile: PrintOneFileProc = {
PROC [out: IO.STREAM, item: FileItem, lagPrefix: PATH, lagPrefixLen: INT, briefPrint, narrowPrint, fullPrint, attachPrint, oneLine, prefixOnly, typePrint: BOOL] RETURNS [newLagPrefix: PATH, newLagPrefixLen];
item: REF [fullUName, attachedTo: PATH, created: GMT, bytes: INT, keep: CARDINAL, PFS.FileType]
IsDF: PROC [p: PATH] RETURNS [BOOL] ~ {
name: ROPE ¬ PFSNames.ComponentRope[PFSNames.ShortName[p]];
RETURN [ Rope.Match[pattern: "*.df", object: name, case: FALSE] ];
};
oldLag: PATH ¬ lagPrefix;
printName: ROPE ¬ PFS.RopeFromPath[item.fullUName];
fullName: ROPE ¬ printName;
oldCharProps, newCharProps: IOTioga.PropList ¬ NIL;
newLagPrefix ¬ lagPrefix; newLagPrefixLen ¬ lagPrefixLen;
Process.CheckForAbort[];
IF NOT fullPrint AND NOT prefixOnly THEN {
Factor out the directories
[lagPrefix, lagPrefixLen] ¬ SetLagPrefix[item.fullUName, lagPrefix, lagPrefixLen];
IF oldLag # lagPrefix THEN {
IO.PutRope[out, PFS.RopeFromPath[lagPrefix]];
IO.PutChar[out, IF oneLine THEN ' ELSE '\n];
};
printName ¬ PFS.RopeFromPath[PFSNames.SubName[item.fullUName, lagPrefixLen]];
IF NOT oneLine THEN IO.PutRope[out, " "];
};
Emit the button and a space.
SetCharProp[out, theFileNameKey, fullName];
SetCharProp[out, theButtonDataKey, IF item.fileType=PFS.tDirectory THEN theDirectoryButtonDataValue ELSE IF IsDF[item.fullUName] THEN theDFButtonDataValue ELSE theButtonDataValue];
SetCharProp[out, thePostfixKey, thePostfixValue];
IO.PutRope[out, " "];
SetCharProp[out, thePostfixKey, NIL];
SetCharProp[out, theButtonDataKey, NIL];
IO.PutRope[out, " "];
SELECT TRUE FROM
prefixOnly => IO.PutRope[out, printName];
briefPrint => {
IO.PutRope[out, printName];
};
ENDCASE => {
form: ROPE = IF narrowPrint THEN "%g\n%12g " ELSE "%-24g %6g ";
IO.PutF[out, form, [rope[printName]], [integer[item.bytes]] ];
IF item.created = BasicTime.nullGMT
THEN IO.PutRope[out, "??"]
ELSE DateToStream[out, [explicit, item.created] ];
IF typePrint THEN {
r: ROPE ~ SELECT item.fileType FROM
PFS.tUnspecified => " tUnspec",
PFS.tDirectory => " tDir",
PFS.tText => " tText",
ENDCASE => IO.PutFR1[" t%g", [integer[item.fileType]]];
IO.PutRope[out, r];
};
IF attachPrint AND item.attachedTo#NIL THEN IO.PutF[out, "%g=> %g", [rope[IF oneLine THEN " " ELSE "\n "]], [rope[PFS.RopeFromPath[item.attachedTo]]]];
};
SetCharProp[out, theFileNameKey, NIL];
IO.PutChar[out, IF oneLine THEN ' ELSE '\n];
RETURN[lagPrefix, lagPrefixLen];
};
PlainPrintOneFile: PrintOneFileProc = {
PROC [out: IO.STREAM, item: FileItem, lagPrefix: PATH, lagPrefixLen: INT, briefPrint, narrowPrint, fullPrint, attachPrint, oneLine, prefixOnly, typePrint: BOOL] RETURNS [newLagPrefix: PATH, newLagPrefixLen];
item: REF [fullUName, attachedTo: PATH, created: GMT, bytes: INT, keep: CARDINAL, PFS.FileType]
oldLag: PATH ¬ lagPrefix;
printName: ROPE ¬ PFS.RopeFromPath[item.fullUName];
newLagPrefix ¬ lagPrefix; newLagPrefixLen ¬ lagPrefixLen;
Process.CheckForAbort[];
IF NOT fullPrint AND NOT prefixOnly THEN {
Factor out the directories
[lagPrefix, lagPrefixLen] ¬ SetLagPrefix[item.fullUName, lagPrefix, lagPrefixLen];
IF oldLag # lagPrefix THEN {
IO.PutRope[out, PFS.RopeFromPath[lagPrefix]];
IO.PutChar[out, IF oneLine THEN ' ELSE '\n];
};
printName ¬ PFS.RopeFromPath[PFSNames.SubName[item.fullUName, lagPrefixLen]];
IF NOT oneLine THEN IO.PutRope[out, " "];
};
SELECT TRUE FROM
prefixOnly => IO.PutRope[out, printName];
briefPrint => {
IO.PutRope[out, printName];
};
ENDCASE => {
form: ROPE = IF narrowPrint THEN "%g\n%12g " ELSE "%-24g %6g ";
IO.PutF[out, form, [rope[printName]], [integer[item.bytes]] ];
IF item.created = BasicTime.nullGMT
THEN IO.PutRope[out, "??"]
ELSE DateToStream[out, [explicit, item.created] ];
IF typePrint THEN {
r: ROPE ~ SELECT item.fileType FROM
PFS.tUnspecified => " tUnspec",
PFS.tDirectory => " tDir",
PFS.tText => " tText",
ENDCASE => IO.PutFR1[" t%g", [integer[item.fileType]]];
IO.PutRope[out, r];
};
IF attachPrint AND item.attachedTo#NIL THEN IO.PutF[out, "%g=> %g", [rope[IF oneLine THEN " " ELSE "\n "]], [rope[PFS.RopeFromPath[item.attachedTo]]]];
};
IO.PutChar[out, IF oneLine THEN ' ELSE '\n];
RETURN[lagPrefix, lagPrefixLen];
};
listDoc: ROPE = "{switch | pattern}*
Lists files matching pattern.
-a print attachments
-b brief format
-d date sort
-f full name print
-h highest version
-k keep print
-n narrow print
-o one line
-p prefixes only
-s size sort
-t file type print
-x exact level match
-u unattached files only
-z 0-length files only
-> sort decreasing
-< sort increasing";
ListCommand: Commander.CommandProc = {
[cmd: Handle] RETURNS [result: REFNIL, msg: ROPENIL]
CommandObject = [in, out, err: STREAM, commandLine, command: ROPE, ...]
RETURN ListCommandAux[cmd, PlainPrintOneFile];
};
ButtonListCommand: Commander.CommandProc = {
[cmd: Handle] RETURNS [result: REFNIL, msg: ROPENIL]
CommandObject = [in, out, err: STREAM, commandLine, command: ROPE, ...]
[] ¬ CommanderOps.DoCommand["Buttons on -quiet", cmd];
RETURN ListCommandAux[cmd, ButtonPrintOneFile];
};
ButtonGenTest: Commander.CommandProc ~ {
italic: IOTioga.Looks ~ IOTioga.LooksFromRope["i"];
bold: IOTioga.Looks ~ IOTioga.LooksFromRope["b"];
keyPostfix: ATOM ~ $Postfix;
purplePostfix: REF ~ NodeProps.DoSpecs[keyPostfix, "0.75 1 0.9 textColor"];
purpleProps: IOTioga.PropList ~ IOTioga.PropPut[NIL, $Postfix, purplePostfix];
IO.PutRope[cmd.out, "Here is some "];
IOTioga.AddLooks[cmd.out, italic];
IO.PutRope[cmd.out, "italic"];
IOTioga.RemoveLooks[cmd.out, italic];
IO.PutRope[cmd.out, " and "];
IOTioga.AddLooks[cmd.out, bold];
IO.PutRope[cmd.out, "bold"];
IOTioga.RemoveLooks[cmd.out, bold];
IO.PutRope[cmd.out, " text, and a "];
IOTioga.SetCharProps[cmd.out, purpleProps];
IO.PutRope[cmd.out, "purple"];
IOTioga.SetCharProps[cmd.out, NIL];
IO.PutRope[cmd.out, " word.\n"];
};
Commander.Register["ButtonLS", ButtonListCommand, listDoc];
Commander.Register["PlainLS", ListCommand, listDoc];
Commander.Register["ButtonGenTest", ButtonGenTest];
END.