TiogaFileWatcherImpl.mesa
Copyright © 1985, 1986 by Xerox Corporation. All rights reserved.
Michael Plass, May 1, 1986 12:03:13 pm PDT
Doug Wyatt, September 2, 1986 5:48:23 pm PDT
DIRECTORY
AbbrevExpand USING [Validate, ValidateAll],
Ascii USING [Lower],
Atom USING [MakeAtomFromRefText],
FS USING [ComponentPositions, Error, ExpandName],
FSBackdoor USING [CreateEvent, NextCreateEvent],
MessageWindow USING [Append, Blink],
NodeStyleValidate USING [ValidateStyle, ValidateStyles],
Process USING [Detach],
RefText USING [AppendRope, ObtainScratch, ReleaseScratch],
Rope USING [Cat, Equal, Fetch, Length, ROPE, Run],
TEditDocument USING [TEditDocumentData],
TEditDocumentPrivate USING [DoLoadFile],
UserProfile USING [CallWhenProfileChanges, ProfileChangedProc],
ViewerClasses USING [Viewer],
ViewerForkers USING [ForkPaint],
ViewerLocks USING [CallUnderViewerTreeLock],
ViewerOps USING [EnumerateChildren, EnumerateViewers, EnumProc];
TiogaFileWatcherImpl: CEDAR PROGRAM
IMPORTS AbbrevExpand, Ascii, Atom, FS, FSBackdoor, MessageWindow, NodeStyleValidate, Process, RefText, Rope, TEditDocumentPrivate, UserProfile, ViewerForkers, ViewerLocks, ViewerOps
= BEGIN
ROPE: TYPE = Rope.ROPE;
highestVersion: CARDINAL ~ CARDINAL.LAST;
ExtensionType: TYPE = {nil, tip, style, abbreviations};
Info:
TYPE =
RECORD[
name: ROPE ← NIL, -- full FName
len: INT ← 0, -- length of name, omitting version part
baseStart: INT ← 0, -- index of start of base name
baseLen: INT ← 0, -- length of base name
version: CARDINAL ← highestVersion, -- version number
type: ExtensionType ← nil -- extension type
];
LowerCaseAtom:
PROC[rope:
ROPE, start, len:
INT]
RETURNS [atom:
ATOM ←
NIL] ~ {
scratch: REF TEXT ~ RefText.ObtainScratch[100];
text: REF TEXT ~ RefText.AppendRope[to: scratch, from: rope, start: start, len: len];
FOR i: NAT IN [0..text.length) DO text[i] ← Ascii.Lower[text[i]] ENDLOOP;
atom ← Atom.MakeAtomFromRefText[text];
RefText.ReleaseScratch[scratch];
};
ParseFileName:
PROC[name:
ROPE]
RETURNS[info: Info ← []] = {
cp: FS.ComponentPositions;
[fullFName: name, cp: cp] ← FS.ExpandName[name ! FS.Error => GOTO Fail];
info.name ← name; -- full name
info.len ← cp.ext.start+cp.ext.length; -- length up to end of extension
info.baseStart ← cp.base.start;
info.baseLen ← cp.base.length;
IF cp.ver.length>0
THEN {
-- parse version number
start: INT ~ cp.ver.start;
len: INT ~ cp.ver.length;
version: CARDINAL ← 0;
FOR i:
INT
IN[start..start+len)
DO
version ← version*10+(name.Fetch[i]-'0);
ENDLOOP;
info.version ← version;
};
IF cp.ext.length>0
THEN {
-- look for special extensions
start: INT ~ cp.ext.start;
len: INT ~ cp.ext.length;
MatchExtension:
PROC[x:
ROPE]
RETURNS[
BOOL] = {
RETURN[Rope.Length[x]=len AND Rope.Run[s1: name, pos1: start, s2: x, case: FALSE]=len]
};
SELECT
TRUE
FROM
MatchExtension["tip"] => info.type ← tip;
MatchExtension["style"] => info.type ← style;
MatchExtension["abbreviations"] => info.type ← abbreviations;
ENDCASE;
};
EXITS Fail => RETURN;
};
NamesMatch:
PROC[a, b: Info]
RETURNS[
BOOL] = {
RETURN[a.len=b.len AND Rope.Run[s1: a.name, s2: b.name, case: FALSE]>=a.len];
};
autoStyleLoad:
BOOL ←
TRUE;
Style wizards might like to disable the auto-reload.
stop: BOOL ← FALSE;
RefreshTextViewers:
PROC ~ {
repaint:
PROC [v: ViewerClasses.Viewer]
RETURNS [
BOOL ←
TRUE] = {
IF
NOT v.iconic
THEN {
WITH v.data
SELECT
FROM
tdd: TEditDocument.TEditDocumentData => ViewerForkers.ForkPaint[viewer: v, hint: all, clearClient: TRUE, whatChanged: NIL, tryShortCuts: TRUE];
ENDCASE => IF v.parent = NIL THEN ViewerOps.EnumerateChildren[v, repaint];
};
RETURN [TRUE];
};
ViewerOps.EnumerateViewers[repaint];
};
NewProfile: UserProfile.ProfileChangedProc ~ {
[] ← AbbrevExpand.ValidateAll[];
IF NodeStyleValidate.ValidateStyles[]
THEN TRUSTED {Process.Detach[FORK RefreshTextViewers[]]};
};
TiogaFileWatcher:
PROC = {
event: REF READONLY FSBackdoor.CreateEvent ← NIL;
old, new: Info;
needStyleRepaint: BOOL ← FALSE;
DO
editingOldVersion: BOOL ← FALSE;
action: ViewerOps.EnumProc
-- [v: Viewer] -- = {
IF v.class.flavor#$Text THEN RETURN;
Crock: if v.saveInProgress, SaveViewer may have just written the file but not fixed up v.file and v.newVersion yet. Since SaveViewer doesn't lock the viewer there seems to be no good way to synchronize this properly.
IF v.destroyed OR v.saveInProgress THEN RETURN;
Assume the following convention for v.name and v.file in a $Text viewer v:
v.file always contains the full FName obtained from FS.GetName
If an explicit version was requested, then v.name matches v.file; otherwise, v.name contains v.file with the version part omitted.
IF Rope.Equal[s1: v.name, s2: v.file, case: FALSE] THEN RETURN; -- explicit version
old ← ParseFileName[v.file];
IF NamesMatch[old, new]
AND new.version>old.version
THEN {
IF v.destroyed THEN NULL
ELSE IF v.newVersion THEN editingOldVersion ← TRUE
ELSE [] ← TEditDocumentPrivate.DoLoadFile[parent: v, fileName: v.name];
};
};
IF (event =
NIL
OR event.chain =
NIL)
AND needStyleRepaint
THEN {
Will wait for a creation event; time to repaint because of the new style
ViewerLocks.CallUnderViewerTreeLock[RefreshTextViewers];
needStyleRepaint ← FALSE;
};
event ← FSBackdoor.NextCreateEvent[event];
IF stop THEN EXIT;
new ← ParseFileName[event.fName];
SELECT new.type
FROM
tip => xxx;
abbreviations => {[] ← AbbrevExpand.Validate[LowerCaseAtom[new.name, new.baseStart, new.baseLen]]};
style => {
IF autoStyleLoad AND NodeStyleValidate.ValidateStyle[LowerCaseAtom[new.name, new.baseStart, new.baseLen]] THEN needStyleRepaint ← TRUE;
};
ENDCASE;
ViewerOps.EnumerateViewers[action];
IF editingOldVersion
THEN {
MessageWindow.Append[message: Rope.Cat[
"Warning: ", new.name, " was created while you were editing an older version."],
clearFirst: TRUE];
MessageWindow.Blink[];
};
ENDLOOP;
};
Start:
PROC = {
stop ← FALSE;
TRUSTED { Process.Detach[FORK TiogaFileWatcher] };
UserProfile.CallWhenProfileChanges[NewProfile];
};
Stop: PROC = { stop ← TRUE };
Start[];
END.