DIRECTORY BasicTime, DFUtilities, FileDWIM, FS, IO, MessageWindow, Rope, RopeList, TEditOps, TEditProfile, UserProfile, VersionMap, VersionMapDefaults, ViewerClasses; FileDWIMImpl: CEDAR PROGRAM IMPORTS BasicTime, DFUtilities, FS, IO, MessageWindow, Rope, RopeList, TEditOps, TEditProfile, UserProfile, VersionMap, VersionMapDefaults EXPORTS FileDWIM = BEGIN OPEN FileDWIM; ROPEList: TYPE = LIST OF ROPE; Viewer: TYPE = ViewerClasses.Viewer; ResolveHint: PUBLIC PROC [hint: ROPE, contextFileName: ROPE _ NIL, searchHack: BOOL _ FALSE, tryAll: BOOL _ TRUE] RETURNS [ans: Answer] = { fullContextName, fullShortName: ROPE; contextCP, shortCP: FS.ComponentPositions; wDir: ROPE _ NIL; isADfFileName, standardExtension: BOOL _ FALSE; ans _ [NIL, NIL]; IF contextFileName.Length[] # 0 THEN { [fullContextName, contextCP, ] _ FS.ExpandName[contextFileName]; wDir _ fullContextName.Substr[len: contextCP.base.start]; isADfFileName _ fullContextName.Substr[start: contextCP.ext.start, len: contextCP.ext.length].Equal["df", FALSE]; }; [fullShortName, shortCP, ] _ FS.ExpandName[hint, wDir]; IF OK[ans _ TryFull[fullShortName]] THEN RETURN; {hadDir: BOOL = HasDir[hint]; hasExtension: BOOL = shortCP.ext.start # shortCP.base.start + shortCP.base.length; hasVersion: BOOL = shortCP.ver.start # shortCP.ext.start + shortCP.ext.length; base: ROPE = fullShortName.Substr[start: shortCP.base.start, len: shortCP.base.length]; ext: ROPE = fullShortName.Substr[start: shortCP.ext.start, len: shortCP.ext.length]; extless: ROPE = fullShortName.Substr[len: shortCP.base.start + shortCP.base.length]; shortPart: ROPE = fullShortName.Substr[start: shortCP.base.start]; IF hasExtension OR hasVersion OR NOT tryAll THEN NULL ELSE { IF verbose THEN MessageWindow.Append[Rope.Cat["Trying source extensions to ", fullShortName], TRUE]; IF OK[ans _ TryExtensions[fullShortName, TEditProfile.sourceExtensions]] THEN RETURN; }; [ans.fullFileName, ans.searchFor] _ DWIMit[hint, wDir, contextFileName, searchHack, isADfFileName]; IF OK[ans] OR hasVersion OR NOT tryAll THEN RETURN; IF searchHack AND hasExtension THEN { standardExtension _ RopeList.Memb[TEditProfile.sourceExtensions, ext, FALSE]; IF NOT standardExtension THEN { IF verbose THEN MessageWindow.Append[Rope.Cat["Looking for prog=", extless, ", search=", ext], TRUE]; IF OK[ans _ TryExtensions[extless, TEditProfile.implExtensions]] THEN {ans.searchFor _ ext; RETURN}; }; }; IF (NOT hadDir) AND TEditProfile.tryVersionMap THEN { IF verbose THEN MessageWindow.Append[Rope.Cat["Trying version maps for ", shortPart], TRUE]; IF OK[ans _ TryVersionMap[shortPart]] THEN NULL ELSE IF NOT hasExtension THEN { ans _ TryVersionMapExtensions[base, TEditProfile.sourceExtensions]; } ELSE IF NOT standardExtension THEN { IF OK[ans _ TryVersionMapExtensions[base, TEditProfile.implExtensions]] THEN ans.searchFor _ ext; }; IF verbose THEN MessageWindow.Append[" .", FALSE]; }; }}; HasDir: PROC [rope: ROPE] RETURNS [has: BOOL] = { FOR i: INT IN [0 .. rope.Length[]) DO SELECT rope.Fetch[i] FROM '[, '], '<, '>, '/ => RETURN [TRUE]; ENDCASE => NULL; ENDLOOP; has _ FALSE}; OK: PROC [ans: Answer] RETURNS [ok: BOOL] = {ok _ ans.fullFileName.Length[] # 0}; TryFull: PROC [fullFileName: ROPE] RETURNS [ans: Answer] = { RETURN [IF Exists[fullFileName] THEN [fullFileName, NIL] ELSE [NIL, NIL]]}; TryExtensions: PROC [extless: ROPE, extensions: LIST OF ROPE] RETURNS [ans: Answer] = { base: ROPE ~ extless.Concat["."]; ans _ [NIL, NIL]; FOR list: ROPEList _ extensions, list.rest UNTIL list=NIL DO IF Exists[ans.fullFileName _ base.Concat[list.first]] THEN RETURN; ENDLOOP; ans.fullFileName _ NIL; }; TryVersionMap: PROC [shortName: ROPE] RETURNS [ans: Answer] = { mapList: VersionMap.MapList ~ VersionMapDefaults.GetMapList[$Source]; ranges: VersionMap.RangeList ~ VersionMap.ShortNameToRanges[mapList, shortName]; bestName: ROPE _ NIL; bestDate: BasicTime.GMT _ BasicTime.nullGMT; FOR list: VersionMap.RangeList _ ranges, list.rest UNTIL list=NIL DO range: VersionMap.Range _ list.first; WHILE range.len # 0 DO fullName: ROPE; created: BasicTime.GMT; [name: fullName, created: created, next: range] _ VersionMap.RangeToEntry[range]; IF bestDate = BasicTime.nullGMT OR BasicTime.Period[from: bestDate, to: created] > 0 THEN {bestDate _ created; bestName _ fullName}; ENDLOOP; ENDLOOP; ans _ [bestName, NIL]; }; TryVersionMapExtensions: PROC [name: ROPE, extensions: ROPEList] RETURNS [ans: Answer] = { base: ROPE ~ name.Concat["."]; FOR list: LIST OF ROPE _ extensions, list.rest UNTIL list=NIL DO IF OK[ans _ TryVersionMap[base.Concat[list.first]]] THEN RETURN; ENDLOOP; ans _ [NIL, NIL]; }; processDF, assocExts, followAttachments: BOOLEAN _ FALSE; DWIMit: PROC [orgName, wDir, contextFileName: ROPE, searchHack, isADfFileName: BOOL] RETURNS [fileName: ROPE, search: ROPE] = BEGIN Try: PROC [dir, short: ROPE, BaseMatch, FullMatch: PROC [dir, file, ext: ROPE] RETURNS [stop: BOOL]] RETURNS [stop: BOOL] = { cp: FS.ComponentPositions; expanded, dirPart: ROPE; stop _ FALSE; [expanded, cp, ] _ FS.ExpandName[dir.Concat[short], NIL]; dirPart _ expanded.Substr[start: 0, len: cp.base.start]; IF goalVersioned THEN { IF expanded.Substr[start: cp.base.start, len: cp.ver.start+cp.ver.length - cp.base.start].Equal[s2: goalFull, case: FALSE] THEN stop _ FullMatch[dirPart, goalFull, NIL]; } ELSE { testBase: ROPE _ expanded.Substr[start: cp.base.start, len: cp.base.length]; testExt: ROPE _ expanded.Substr[start: cp.ext.start, len: cp.ext.length]; IF testBase.Equal[goalBase, FALSE] THEN { stop _ IF testExt.Equal[goalExt, FALSE] THEN FullMatch[dirPart, goalFull, NIL] ELSE BaseMatch[dirPart, testBase, testExt] }; }; stop _ stop; }; FullMatch: PROC [dir, file, ext: ROPE] RETURNS [stop: BOOL] = { IF (ext.Length[]=0 OR searchHack) AND Exists[fileName _ dir.Cat[file]] THEN { search _ ext; RETURN [found _ TRUE]}; stop _ stop; }; BaseMatch: PROC [dir, file, ext: ROPE] RETURNS [stop: BOOL] = { allButExt: ROPE _ dir.Cat[file]; stop _ FALSE; IF goalExtended THEN { IF assocExts AND Exists[fileName _ allButExt.Cat[".", goalExt]] THEN { search _ NIL; RETURN [found _ TRUE]}; IF searchHack AND RopeList.Memb[TEditProfile.implExtensions, ext, FALSE] AND Exists[fileName _ allButExt.Cat[".", ext]] THEN { search _ goalExt; RETURN [found _ TRUE]}; IF searchHack AND assocExts AND NOT allButExt.Equal[lastImplAssoced, FALSE] THEN { lastImplAssoced _ allButExt; FOR ifel: ROPEList _ TEditProfile.implExtensions, ifel.rest WHILE ifel # NIL DO IF Exists[fileName _ allButExt.Cat[".", ifel.first]] THEN { search _ goalExt; RETURN [found _ TRUE]}; ENDLOOP; }; }; IF NOT goalExtended THEN { IF RopeList.Memb[TEditProfile.sourceExtensions, ext, FALSE] AND Exists[fileName _ allButExt.Cat[".", ext]] THEN { search _ NIL; RETURN [found _ TRUE]}; IF assocExts AND NOT allButExt.Equal[lastSourceAssoced, FALSE] THEN { lastSourceAssoced _ allButExt; FOR ifel: ROPEList _ TEditProfile.sourceExtensions, ifel.rest WHILE ifel # NIL DO IF Exists[fileName _ allButExt.Cat[".", ifel.first]] THEN { search _ NIL; RETURN [found _ TRUE]}; ENDLOOP; }; }; stop _ stop; }; found: BOOL _ FALSE; goalFull, goalExpanded, goalBase, goalExt: ROPE; goalCP: FS.ComponentPositions; goalExtended, goalVersioned: BOOL; lastSourceAssoced, lastImplAssoced: ROPE _ NIL; goalFull _ orgName; [goalExpanded, goalCP, ] _ FS.ExpandName[orgName]; goalBase _ goalExpanded.Substr[start: goalCP.base.start, len: goalCP.base.length]; goalExt _ goalExpanded.Substr[start: goalCP.ext.start, len: goalCP.ext.length]; goalExtended _ goalCP.ext.length # 0; goalVersioned _ goalCP.ver.length # 0; { Consume: PROC [fullFName, attachedTo: ROPE, created: BasicTime.GMT, bytes: INT, keep: CARDINAL] RETURNS [continue: BOOLEAN] --FS.InfoProc-- = { IF Try[NIL, fullFName, BaseMatch, FullMatch] THEN RETURN [FALSE]; IF followAttachments AND attachedTo # NIL AND Try[NIL, attachedTo, BaseMatch, FullMatch] THEN RETURN [FALSE]; }; IF assocExts AND followAttachments THEN { IF verbose THEN MessageWindow.Append[Rope.Cat["Looking for attachments to follow from ", goalBase], TRUE]; FS.EnumerateForInfo[pattern: goalBase.Cat["!H"], proc: Consume, wDir: wDir !FS.Error => CONTINUE]; IF found THEN RETURN; FS.EnumerateForInfo[pattern: goalBase.Cat[".*!H"], proc: Consume, wDir: wDir !FS.Error => CONTINUE]; IF found THEN RETURN; } }; IF contextFileName.Length[] # 0 THEN { IF processDF AND isADfFileName THEN { IF verbose THEN MessageWindow.Append["Trying DF smarts", TRUE]; [] _ Find[contextFileName, Try, BaseMatch, FullMatch]; IF verbose THEN MessageWindow.Append[" .", FALSE]; IF found THEN RETURN; }; }; fileName _ search _ NIL; END; EnumerateForInfo: PROC [base: ROPE, exts: ROPEList, proc: FS.InfoProc, wDir: ROPE _ NIL] = { FOR exts _ exts, exts.rest WHILE exts # NIL DO fullFName, attachedTo: ROPE; keep: CARDINAL; bytes: INT; created: BasicTime.GMT; [fullFName:fullFName, attachedTo:attachedTo, keep:keep, bytes:bytes, created:created] _ FS.FileInfo[name: base.Cat[".", exts.first], remoteCheck: FALSE, wDir: wDir !FS.Error => LOOP]; IF NOT proc[fullFName:fullFName, attachedTo:attachedTo, keep:keep, bytes:bytes, created:created] THEN EXIT; ENDLOOP; wDir _ wDir; }; Find: PROC [ dfFileName: ROPE, Try: PROC [ dir, short: ROPE, BaseMatch, FullMatch: PROC [dir, file, ext: ROPE] RETURNS [stop: BOOL]] RETURNS [stop: BOOL], BaseMatch, FullMatch: PROC [dir, file, ext: ROPE] RETURNS [stop: BOOL]] RETURNS [stopped: BOOL] = BEGIN PerItem: PROC [item: REF ANY] RETURNS [stop: BOOL _ FALSE] --DFUtilities.ProcessItemProc-- = BEGIN WITH item SELECT FROM di: REF DFUtilities.DirectoryItem => dir _ di.path1; fi: REF DFUtilities.FileItem => IF Try[dir, fi.name, BaseMatch, FullMatch] THEN stop _ TRUE; ii: REF DFUtilities.ImportsItem => { IF Try[NIL, ii.path1, BaseMatch, FullMatch] THEN stop _ TRUE ELSE { tryThis: BOOL _ ii.list = NIL; RightOn: PROC [dir, file, ext: ROPE] RETURNS [stop: BOOL] = { tryThis _ stop _ TRUE; }; Almost: PROC [dir, file, ext: ROPE] RETURNS [stop: BOOL] = { IF stop _ assocExts THEN tryThis _ TRUE; }; IF NOT tryThis THEN FOR i: NAT IN [0 .. ii.list.nEntries) WHILE NOT tryThis DO [] _ Try["[]<>", ii.list[i].name, Almost, RightOn]; ENDLOOP; IF tryThis THEN stop _ Find[ii.path1, Try, BaseMatch, FullMatch]; }; }; ii: REF DFUtilities.IncludeItem => stop _ Find[ii.path1, Try, BaseMatch, FullMatch]; c: REF DFUtilities.CommentItem => NULL; w: REF DFUtilities.WhiteSpaceItem => NULL; ENDCASE => ERROR; stopped _ stop; END; from: IO.STREAM _ NIL; dir: ROPE _ NIL; stopped _ FALSE; from _ FS.StreamOpen[dfFileName !FS.Error => CONTINUE]; IF from = NIL THEN RETURN; DFUtilities.ParseFromStream[in: from, proc: PerItem]; from.Close[]; END; inPlace, doSearchHack: BOOL _ FALSE; OldFNP: PROC [ROPE, Viewer] RETURNS [fileName: ROPE, search: ROPE] _ NIL; GetDWIM: PROC [orgName: ROPE, viewer: Viewer] RETURNS [fileName: ROPE, search: ROPE]--TEditOps.FileNameProc-- = { contextFileName: ROPE = IF viewer # NIL THEN viewer.file ELSE NIL; IF orgName.Length[] = 0 THEN RETURN [NIL, NIL]; SELECT orgName.Fetch[0] FROM '[, '/, '<, '> => RETURN [NIL, NIL]; ENDCASE => NULL; [fileName, search] _ ResolveHint[orgName, contextFileName, doSearchHack, FALSE].ans; IF fileName = NIL AND OldFNP # NIL THEN [fileName, search] _ OldFNP[orgName, viewer]; }; verbose: BOOL _ TRUE; Exists: PROC [fileName: ROPE] RETURNS [exists: BOOLEAN] = BEGIN exists _ TRUE; [] _ FS.FileInfo[name: fileName, remoteCheck: FALSE ! FS.Error => {exists _ FALSE; CONTINUE}]; exists _ exists; --wouldn't it be nice if we could really break on exit? END; NoticeProfileChanges: PROC [reason: UserProfile.ProfileChangeReason] --UserProfile.ProfileChangedProc-- = BEGIN doSearchHack _ UserProfile.Boolean["FileDWIM.DoSearchHack", FALSE]; processDF _ UserProfile.Boolean["FileDWIM.ProcessDF", TRUE]; assocExts _ UserProfile.Boolean["FileDWIM.AssociateExtensions", TRUE]; followAttachments _ UserProfile.Boolean["FileDWIM.FollowAttachments", TRUE]; verbose _ UserProfile.Boolean["FileDWIM.Verbose", FALSE]; IF (processDF OR assocExts) AND NOT inPlace THEN BEGIN inPlace _ TRUE; OldFNP _ TEditOps.ReplaceFileNameProc[GetDWIM]; END; END; UserProfile.CallWhenProfileChanges[NoticeProfileChanges]; END. θFileDWIMImpl.mesa Mike Spreitzer August 7, 1986 5:59:21 pm PDT The basic stuff Modeled after TEditDocuments2Impl.LookupSource --- too bad that doesn't have quite the right interface. From old GetDWIM ... First, look around locally. ELSE {--redundant with first standard TryExtensions EnumerateForInfo[base: goalBase, exts: TEditProfile.sourceExtensions, proc: Consume, wDir: wDir]; IF found THEN RETURN; }; Next, try DF-file smarts. Lastly, give up. Tioga Helper Common Utoolities Κπ– "cedar" style˜code™K™,—K˜KšΟk œ#œœt˜¦K˜šΟn œœ˜Kšœœœd˜ŠKšœ ˜K˜—K˜Kšœœ ˜K˜Kš œ œœœœ˜Kšœœ˜$head™Kšœg™gK˜šž œœœœœœœœ œœœ˜‹Kšœ œ˜%Kšœœ˜*Kšœœœ˜Kšœ"œœ˜/Kšœœœ˜šœœ˜&Kšœ!œ˜@Kšœ9˜9Kšœjœ˜qK˜—Kšœœ˜7Kšœœœœ˜0Kšœ œ˜Kšœœ@˜RKšœ œ>˜NKšœœM˜WKšœœK˜TKšœ œG˜TKšœ œ3˜Bšœœ œœœœœ˜˜LKšœ œ<˜Išœœœ˜)Kš œœœœœœ&˜yK˜—K˜—K˜ K˜—š ž œœœœœ˜?šœœ œ"œ˜MK˜ Kšœ œ˜—K˜ K˜—š ž œœœœœ˜?Kšœ œ˜ Kšœœ˜ šœœ˜šœ œ0œ˜FKšœ œ˜ Kšœ œ˜—š œ œ1œœ,œ˜~Kšœ˜Kšœ œ˜—š œ œ œœ"œœ˜RKšœ˜šœ9œœ˜Ošœ3œ˜;Kšœ˜Kšœ œ˜—Kšœ˜—K˜—K˜—šœœœ˜šœ3œœ,œ˜qKšœ œ˜ Kšœ œ˜—š œ œœ$œœ˜EKšœ˜šœ;œœ˜Qšœ3œ˜;Kšœ œ˜ Kšœ œ˜—Kšœ˜—K˜—K˜—K˜ K˜—Kšœœœ˜Kšœ+œ˜0Kšœœ˜Kšœœ˜"Kšœ$œœ˜/K˜Kšœœ˜2KšœR˜RKšœO˜OKšœ%˜%Kšœ&˜&™Kšœ˜šžœœœœ œœœ œΟcœ˜Kš œœ#œœœ˜AKšœœœœœ$œœœ˜mK˜—šœ œœ˜)Kšœ œUœ˜jKšœJœ œ˜bKšœœœ˜KšœLœ œ˜dKšœœœ˜K˜—šœ/™3Kšœa™aKšœœœ™K™—K˜—K™šœœ˜&šœ œœ˜%Kšœ œ*œ˜?K˜6Kšœ œœ˜2Kšœœœ˜Kšœ˜—Kšœ˜—K™Kšœœ˜Kšœ˜—K˜š žœœœœœœ˜\šœœœ˜.Kšœœ˜Kšœœ˜Kšœœ˜ Kšœœ˜Kš œXœ8œœ œ˜·Kšœœ[œœ˜kKšœ˜—K˜ K˜—K˜šžœ˜ šœ˜Kšœ œ˜šžœ˜ šœ˜Kšœ œ˜Kš œ ž œœœœœ˜G—Kšœœ˜—Kš œ ž œœœœœ˜G—Kšœ œ˜Kš˜šžœœœœœœœŸœ˜\Kš˜šœœ˜Kšœœ-˜4Kš œœœ)œœ˜\šœœ˜$Kšœœ"œ˜<šœ˜Kšœ œ œ˜š žœœœœœ˜=Kšœœ˜K˜—š žœœœœœ˜