Promptery.Mesa
last mangled by Spreitzer on the occasion of March 20, 1986 5:35:13 pm PST
DIRECTORY BasicTime, Booting, Commander, CommandTool, Convert, FS, IO, List, ProcessProps, Random, Rope, ThisMachine, UserCredentials, UserProfile;
Promptery: CEDAR PROGRAM
IMPORTS BasicTime, Booting, Commander, CommandTool, Convert, FS, IO, List, ProcessProps, Random, Rope, ThisMachine, UserCredentials, UserProfile =
BEGIN
ROPE: TYPE = Rope.ROPE;
RopeList: TYPE = LIST OF ROPE;
PromptVector: TYPE = REF PromptVectorRep;
PromptVectorRep: TYPE = RECORD [
length: CARDINAL,
totalWeight: REAL,
ropes: SEQUENCE size: CARDINAL OF Prompt];
Prompt: TYPE = RECORD [incrWeight, sumWeight: REAL, rope: ROPE];
prompts: PromptVector ← NewPromptVector[255];
files: RopeList ← NIL;
installationDirectory: ROPE ← CommandTool.CurrentWorkingDirectory[];
enabled: BOOLEANFALSE;
rs: Random.RandomStream;
Subst: PROC [in, old, new: ROPE] RETURNS [out: ROPE] =
BEGIN
begin: INT;
out ← in;
WHILE (begin ← out.Find[old]) >= 0 DO
out ← out.Replace[start: begin, len: old.Length[], with: new];
ENDLOOP;
END;
AddPrompt: PROC [old: PromptVector, weight: REAL, r: ROPE] RETURNS [new: PromptVector] =
BEGIN
IF old.size = old.length
THEN BEGIN
new ← NEW [PromptVectorRep[old.size*2]];
new.length ← old.length;
new.totalWeight ← old.totalWeight;
FOR i: CARDINAL IN [0 .. old.length) DO new[i] ← old[i] ENDLOOP;
END
ELSE new ← old;
new[new.length] ← [
incrWeight: weight,
sumWeight: weight +
(IF new.length > 0 THEN new[new.length-1].sumWeight ELSE 0),
rope: r];
new.length ← new.length+1;
new.totalWeight ← new.totalWeight + weight;
END;
AddFile: PROC [to: PromptVector, fileName, wDir: ROPE] RETURNS [new: PromptVector] =
BEGIN
file: IO.STREAMNIL;
ok: BOOLEANTRUE;
new ← to;
file ← FS.StreamOpen[fileName: fileName, wDir: wDir !FS.Error => {ok ← FALSE; CONTINUE}];
IF NOT ok THEN RETURN;
DO
r: ROPE;
w: REAL;
[] ← file.SkipWhitespace[];
IF file.EndOf[] THEN EXIT;
w ← file.GetReal[];
r ← IO.GetRopeLiteral[file];
new ← AddPrompt[new, w, r];
ENDLOOP;
file.Close[];
END;
NewPromptVector: PROC [size: CARDINAL] RETURNS [new: PromptVector] =
{new ← NEW [PromptVectorRep[size]]; new.totalWeight ← new.length ← 0};
NoticeChanges: UserProfile.ProfileChangedProc --PROC [reason: ProfileChangeReason]-- =
BEGIN
newFiles: RopeList ← UserProfile.ListOfTokens[key: "Promptery.Sources", default: LIST ["Prompts.txt"]];
temp1, temp2: RopeList;
enabled ← UserProfile.Boolean[key: "Promptery.Enabled", default: FALSE];
temp1 ← files;
temp2 ← newFiles;
WHILE (temp1 # NIL) AND (temp2 # NIL) DO
IF NOT temp1.first.Equal[temp2.first] THEN EXIT;
temp1 ← temp1.rest;
temp2 ← temp2.rest;
ENDLOOP;
IF (temp1 # NIL) OR (temp2 # NIL)
THEN BEGIN
files ← newFiles;
prompts.totalWeight ← prompts.length ← 0;
FOR newFiles ← newFiles, newFiles.rest WHILE newFiles # NIL DO
prompts ← AddFile[prompts, newFiles.first, installationDirectory];
ENDLOOP;
END;
END;
changePromptHandle: Commander.CommandProcHandle ←
NEW [Commander.CommandProcObject ← [proc: ChangePrompt]];
SetPromptery: PROC [cmd: Commander.Handle] RETURNS [result: REFNIL, msg: Rope.ROPENIL] --Commander.CommandProc-- =
BEGIN
cls: IO.STREAMIO.RIS[cmd.commandLine];
toke: ROPENIL;
cmd.propertyList ← CommandTool.RemoveProcFromList[aList: cmd.propertyList, listKey: $After, proc: changePromptHandle];
cmd.propertyList ← CommandTool.AddProcToList[listKey: $After, proc: changePromptHandle, aList: cmd.propertyList];
toke ← cls.GetTokenRope[IO.IDProc !IO.Error, IO.EndOfStream => CONTINUE].token;
IF toke = NIL THEN NULL ELSE
IF toke.Equal["on", FALSE] THEN enabled ← TRUE ELSE
IF toke.Equal["off", FALSE] THEN enabled ← FALSE ELSE
RETURN [$Failure, "Usage: Promptery [on|off]"];
END;
theGoddamCompilerDefaultsToRefTextInsteadOfROPE: ROPE ← "%l%% %l";
ChangePrompt: PROC [cmd: Commander.Handle] RETURNS [result: REFNIL, msg: Rope.ROPENIL] --Commander.CommandProc-- =
BEGIN
min, max: CARDINAL;
prompt, userName, time, wdir: ROPE;
spot: REAL;
IF NOT enabled THEN {
cmd.propertyList ← List.PutAssoc[key: $Prompt, val: theGoddamCompilerDefaultsToRefTextInsteadOfROPE, aList: cmd.propertyList];
cmd.propertyList ← CommandTool.RemoveProcFromList[aList: cmd.propertyList, listKey: $After, proc: changePromptHandle];
RETURN;
};
IF prompts.length = 0 THEN
BEGIN
cmd.out.PutF["%lNo prompts! (UserProfile entry Promptery.Sources lists only bad filenames)%l\n", IO.rope["bi"], IO.rope["BI"]];
RETURN;
END;
spot ← prompts.totalWeight*rs.ChooseInt[min: 0, max: 1000000000]/1000000000.0;
min ← 0; max ← prompts.length - 1;
spot has index IN [min, max]
WHILE max > min DO
mid: CARDINAL ← (min+max)/2;
IF prompts[mid].sumWeight >= spot THEN max ← mid ELSE min ← mid + 1;
ENDLOOP;
prompt ← prompts[min].rope;
userName ← UserCredentials.Get[].name;
time ← Convert.RopeFromTime[from: BasicTime.Now[], end: seconds];
wdir ← NARROW[List.Assoc[key: $WorkingDirectory, aList: ProcessProps.GetPropList[]]];
prompt ← Subst[prompt, "<machine>", machineName];
prompt ← Subst[prompt, "<user>", userName];
prompt ← Subst[prompt, "<time>", time];
prompt ← Subst[prompt, "<wdir>", wdir];
prompt ← Rope.Cat["%l", prompt, "%l"];
cmd.propertyList ← List.PutAssoc[key: $Prompt, val: prompt, aList: cmd.propertyList];
result ← List.Assoc[key: $Result, aList: cmd.propertyList];
Work around bug in CommandTool.CallList
END;
machineName: ROPE ← ThisMachine.Name[];
Randomize: Booting.RollbackProc --PROC[clientData: REF ANY]-- =
{rs ← Random.Create[seed: -1]};
Randomize[NIL];
UserProfile.CallWhenProfileChanges[NoticeChanges];
Commander.Register[key: "Promptery", proc: SetPromptery, doc: "sets up dynamic prompting"];
Booting.RegisterProcs[r: Randomize];
END.