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; 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; IF v.destroyed OR v.saveInProgress THEN RETURN; 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 { ViewerLocks.CallUnderViewerTreeLock[RefreshTextViewers]; needStyleRepaint _ FALSE; }; event _ FSBackdoor.NextCreateEvent[event]; IF stop THEN EXIT; new _ ParseFileName[event.fName]; SELECT new.type FROM 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. .TiogaFileWatcherImpl.mesa Copyright c 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 Style wizards might like to disable the auto-reload. 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. 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. Will wait for a creation event; time to repaint because of the new style tip => xxx; ΚΕ˜codešœ™Kšœ Οmœ7™BK™*K™,—K™šΟk ˜ Jšœ žœ˜+Jšœžœ ˜Jšœžœ˜!Jšžœžœ)˜1Jšœ žœ ˜0Jšœžœ˜$Jšœžœ!˜8Jšœžœ ˜Jšœžœ-˜:Jšœžœžœ˜2Jšœžœ˜(Jšœžœ˜(Jšœ žœ.˜?Jšœžœ ˜Jšœžœ ˜ Jšœ žœ˜,Jšœ žœ1˜@—K˜KšΠblœžœž˜#Kšžœžœ˜΅Kšœž˜K˜Kšžœžœžœ˜K˜Kšœžœžœžœ˜)Kšœžœ$˜7šœžœžœ˜KšœžœžœΟc ˜Kšœžœ (˜6Kšœ žœ ˜2Kšœ žœ ˜(Kšœ žœ ˜5Kšœ ˜+Kšœ˜—K˜šΟn œžœžœžœžœžœžœ˜OKšœ žœžœ˜/K•StartOfExpansionD[to: REF TEXT, from: ROPE, start: INT _ 0, len: NAT _ 32767]šœžœžœG˜UKš žœžœžœžœ žœ˜IKšœ&˜&Kšœ ˜ Kšœ˜K˜—š‘ œžœžœžœ˜K™‚—Kš žœ*žœžœžœ ˜SKšœ˜šžœžœžœ˜:Kšžœ žœž˜Kšžœžœžœž˜2KšžœC˜GK˜—K˜—š žœ žœžœžœžœžœ˜AK™HKšœ8˜8Kšœžœ˜Kšœ˜—Kšœ*˜*Kšžœžœžœ˜Kšœ!˜!šžœ ž˜K™ Kšœc˜c˜ KšžœžœVžœžœ˜‡K˜—Kšžœ˜—K˜#šžœžœ˜˜'KšœP˜PKšœ žœ˜—K˜Kšœ˜—Kšžœ˜—K˜K˜—š‘œžœ˜Kšœžœ˜ Kšžœžœ˜2Kšœ/˜/K˜—K˜Kš‘œžœ žœ˜K˜K˜K˜Kšžœ˜—…—