<> <> DIRECTORY Basics, BasicTime, DFOperations, DFUtilities, FS, IO, List, ProcessProps, RedBlackTree, Rope, TEditOps, UserProfile, ViewerClasses, ViewerTools; GetDWIM: CEDAR PROGRAM IMPORTS DFUtilities, FS, IO, RedBlackTree, Rope, TEditOps, UserProfile, ViewerTools = BEGIN ROPE: TYPE = Rope.ROPE; ROPEList: TYPE = LIST OF ROPE; Viewer: TYPE = ViewerClasses.Viewer; inPlace, processDF, assocExts, followAttachments, tryRenaming: BOOLEAN _ FALSE; OldFNP: PROC [ROPE, Viewer] RETURNS [fileName: ROPE, search: ROPE] _ NIL; log: IO.STREAM _ NIL; Debug: PROC = {log _ IO.ROS[]}; DontDebug: PROC = {log _ NIL}; GetLog: PROC RETURNS [r: ROPE] = {r _ log.RopeFromROS[]}; sourceFileExtensions, implFileExtensions: ROPEList _ NIL; DWIMit: PROC [orgName: ROPE, viewer: Viewer] 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 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 Member[ext, implFileExtensions] AND Exists[fileName _ allButExt.Cat[".", ext]] THEN { search _ goalExt; RETURN [found _ TRUE]}; IF assocExts AND NOT allButExt.Equal[lastImplAssoced, FALSE] THEN { lastImplAssoced _ allButExt; FOR ifel: ROPEList _ implFileExtensions, 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 Member[ext, sourceFileExtensions] 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 _ sourceFileExtensions, ifel.rest WHILE ifel # NIL DO IF Exists[fileName _ allButExt.Cat[".", ifel.first]] THEN { search _ goalExt; RETURN [found _ TRUE]}; ENDLOOP; }; }; stop _ stop; }; found: BOOL _ FALSE; goalFull, goalExpanded, goalBase, goalExt: ROPE; goalCP: FS.ComponentPositions; goalExtended, goalVersioned: BOOL; wDir: ROPE _ IF viewer # NIL THEN TEditOps.WorkingDirectoryFromViewer[viewer] ELSE NIL; lastSourceAssoced, lastImplAssoced: ROPE _ NIL; dotPos: INT; mesaNote: MesaNote; <> IF tryRenaming AND (dotPos _ orgName.Find["."]) >= 0 AND (mesaNote _ GetMesaNote[viewer]) # NIL THEN { short: ROPE _ orgName.Substr[len: dotPos]; rest: ROPE _ orgName.Substr[start: dotPos]; found: BOOL _ FALSE; FOR ml: MapList _ mesaNote.maps, ml.rest WHILE ml # NIL AND NOT found DO IF ml.first.short.Equal[short] THEN { found _ TRUE; orgName _ ml.first.long.Concat[rest]; }; ENDLOOP; }; 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 { 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; } ELSE { EnumerateForInfo[base: goalBase, exts: sourceFileExtensions, proc: Consume, wDir: wDir]; IF found THEN RETURN; }; }; <> IF viewer # NIL THEN BEGIN IF processDF AND IsADFFileName[viewer.file] THEN BEGIN [] _ Find[viewer.file, Try, BaseMatch, FullMatch]; IF found THEN RETURN; END; END; <> IF OldFNP # NIL THEN [fileName, search] _ OldFNP[orgName, viewer] ELSE {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; Member: PROC [r: ROPE, in: ROPEList] RETURNS [m: BOOL] = { FOR in _ in, in.rest WHILE in # NIL DO IF in.first.Equal[r, FALSE] THEN RETURN [TRUE]; ENDLOOP; m _ FALSE}; IsADFFileName: PROC [name: ROPE] RETURNS [isa: BOOLEAN] = {isa _ name.Find[s2: ".DF!", case: FALSE] >= 0}; 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; MesaNote: TYPE = REF MesaNoteRep; MesaNoteRep: TYPE = RECORD [ name: ROPE, maps: MapList ]; MapList: TYPE = LIST OF Map; Map: TYPE = RECORD [short, long: ROPE]; mesaNotes: RedBlackTree.Table _ RedBlackTree.Create[GetMNKey, CompareMNs]; FlushMesaCache: PROC = { mesaNotes _ RedBlackTree.Create[GetMNKey, CompareMNs]; }; GetMesaNote: PROC [v: Viewer] RETURNS [mn: MesaNote] = { vFull: ROPE _ NIL; vcp: FS.ComponentPositions; ext, name: ROPE; IF v = NIL THEN RETURN [NIL]; [vFull, vcp] _ FS.ExpandName[v.name !FS.Error => CONTINUE]; IF vFull = NIL THEN RETURN [NIL]; ext _ vFull.Substr[start: vcp.ext.start, len: vcp.ext.length]; IF NOT (ext.Equal["mesa", FALSE] OR ext.Equal["cedar", FALSE]) THEN RETURN [NIL]; name _ vFull.Substr[len: vcp.ext.start + vcp.ext.length]; mn _ NARROW[mesaNotes.Lookup[name]]; IF mn # NIL THEN RETURN; mn _ NEW [MesaNoteRep _ [ name: name, maps: AnalyzeMesa[ViewerTools.GetContents[v]] ]]; mesaNotes.Insert[mn, mn.name]; }; AnalyzeMesa: PROC [module: ROPE] RETURNS [maps: MapList] = { ENABLE IO.Error => CONTINUE; Work: PROC [intro: ROPE] = { start: INT = module.Find[intro]; in: IO.STREAM; toke: ROPE; IF start < 0 THEN RETURN; in _ IO.RIS[module.Substr[start: start]]; toke _ in.GetCedarTokenRope[].token; IF toke.Equal[intro] THEN { FOR toke _ in.GetCedarTokenRope[].token, in.GetCedarTokenRope[].token DO short, long: ROPE; IF toke.Equal[";"] OR toke.Equal["}"] OR toke.Equal["END"] OR toke.Equal["="] OR toke.Equal["EXPORTS"] OR toke.Equal["SHARES"] THEN EXIT; short _ toke; toke _ in.GetCedarTokenRope[].token; IF toke.Equal[","] THEN LOOP; IF NOT toke.Equal[":"] THEN EXIT; long _ in.GetCedarTokenRope[].token; maps _ CONS[[short, long], maps]; toke _ in.GetCedarTokenRope[].token; IF NOT toke.Equal[","] THEN EXIT; ENDLOOP; }; in.Close[]; }; maps _ NIL; Work["IMPORTS"]; Work["OPEN"]; }; GetMNKey: PROC [data: REF ANY] RETURNS [key: ROPE] = { mn: MesaNote = NARROW[data]; RETURN [mn.name]; }; CompareMNs: PROC [k, data: REF ANY] RETURNS [Basics.Comparison] = { k1: ROPE = NARROW[k]; k2: ROPE = GetMNKey[data]; RETURN [k1.Compare[k2]]; }; NoticeProfileChanges: PROC [reason: UserProfile.ProfileChangeReason] --UserProfile.ProfileChangedProc-- = BEGIN tryRenaming _ UserProfile.Boolean["GetDWIM.TryRenaming", TRUE]; processDF _ UserProfile.Boolean["GetDWIM.ProcessDF", TRUE]; assocExts _ UserProfile.Boolean["GetDWIM.AssociateExtensions", TRUE]; followAttachments _ UserProfile.Boolean["GetDWIM.FollowAttachments", TRUE]; sourceFileExtensions _ UserProfile.ListOfTokens["SourceFileExtensions", LIST["mesa", "tioga", "df", "cm", "config", "style"]]; implFileExtensions _ UserProfile.ListOfTokens["ImplFileExtensions", LIST["mesa", "cedar"]]; IF (processDF OR assocExts) AND NOT inPlace THEN BEGIN inPlace _ TRUE; OldFNP _ TEditOps.ReplaceFileNameProc[DWIMit]; END; END; UserProfile.CallWhenProfileChanges[NoticeProfileChanges]; END.