-
Notifications
You must be signed in to change notification settings - Fork 77
Project cache invalidating #72
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,7 @@ open System.Diagnostics | |
open EnvDTE | ||
open VSLangProj | ||
open FSharp.CompilerBinding | ||
open FSharpVSPowerTools | ||
|
||
type ProjectProvider(project : VSProject) = | ||
do Debug.Assert(project <> null && project.Project <> null, "Input project should be well-formed.") | ||
|
@@ -56,7 +57,7 @@ type ProjectProvider(project : VSProject) = | |
yield! this.References | ||
|] | ||
| None -> | ||
Debug.WriteLine("[Project System] Can't read project file. Fall back to default compiler flags.") | ||
debug "[Project System] Can't read project file. Fall back to default compiler flags." | ||
[| | ||
yield "--noframework" | ||
yield "--debug-" | ||
|
@@ -70,9 +71,9 @@ type ProjectProvider(project : VSProject) = | |
| Some p -> | ||
ProjectParser.getFiles p | ||
| None -> | ||
Debug.WriteLine("[Project System] Can't read project file. Fall back to incomplete source files.") | ||
debug "[Project System] Can't read project file. Fall back to incomplete source files." | ||
let projectItems = project.Project.ProjectItems | ||
Debug.Assert(Seq.cast<ProjectItem> projectItems <> null && projectItems.Count > 0, "Should have file names in the project.") | ||
Debug.Assert (Seq.cast<ProjectItem> projectItems <> null && projectItems.Count > 0, "Should have file names in the project.") | ||
projectItems | ||
|> Seq.cast<ProjectItem> | ||
|> Seq.filter (fun item -> try item.Document <> null with _ -> false) | ||
|
@@ -82,38 +83,42 @@ type ProjectProvider(project : VSProject) = | |
|> Seq.map (fun item -> Path.Combine(currentDir, item.Properties.["FileName"].Value.ToString())) | ||
|> Seq.toArray | ||
|
||
[<CompilationRepresentation (CompilationRepresentationFlags.ModuleSuffix)>] | ||
module ProjectProvider = | ||
open FSharpVSPowerTools | ||
|
||
type private Message = Get of Document * AsyncReplyChannel<ProjectProvider option> | ||
/// Cache of ProjectProviders. Listens for projects changes and invalidates itself. | ||
module ProjectsCache = | ||
type private Message = | ||
| Get of Document * AsyncReplyChannel<ProjectProvider option> | ||
| Remove of projectUniqueName:string | ||
|
||
let private agent = MailboxProcessor.Start(fun inbox -> | ||
let rec loop (projects: Map<string, ProjectProvider>) = async { | ||
let! msg = inbox.Receive() | ||
match msg with | ||
| Get (doc, r) -> | ||
let project = | ||
try Option.ofNull (doc.ProjectItem.ContainingProject.Object :?> VSProject) | ||
with _ -> None | ||
doc.ProjectItem.VSProject | ||
|> Option.bind (fun vsProject -> | ||
match projects |> Map.tryFind vsProject.Project.UniqueName with | ||
| None -> | ||
try | ||
debug "Creating new project provider." | ||
debug "[ProjectsCache] Creating new project provider." | ||
Some (ProjectProvider (vsProject)) | ||
with _ -> | ||
debug "Can't find containing project. Probably the document is opened in an ad-hoc way." | ||
debug "[ProjectsCache] Can't find containing project. Probably the document is opened in an ad-hoc way." | ||
None | ||
| x -> debug "Found cached project provider."; x) | ||
| x -> debug "[ProjectsCache] Found cached project provider."; x) | ||
|
||
r.Reply project | ||
let projects = | ||
match project with | ||
| Some p -> projects |> Map.add p.UniqueName p | ||
| _ -> projects | ||
return! loop projects } | ||
return! loop projects | ||
| Remove uniqueProjectName -> | ||
debug "[ProjectsCache] %s has been removed from cache." uniqueProjectName | ||
return! loop (projects |> Map.remove uniqueProjectName) } | ||
loop Map.empty) | ||
|
||
SolutionEvents.ProjectChanged.Add (fun vsProject -> agent.Post (Remove vsProject.Project.UniqueName)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar comments as in the |
||
|
||
/// Returns ProjectProvider for given Documents (it caches ProjectProviders forever for now). | ||
let get document = agent.PostAndReply (fun r -> Get (document, r)) | ||
let getProject document = agent.PostAndReply (fun r -> Get (document, r)) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -106,3 +106,28 @@ module Dte = | |
System.Diagnostics.Debug.Assert(doc <> null && doc.ProjectItem.ContainingProject <> null, | ||
"Should be able to find active document and active project.") | ||
doc | ||
|
||
type ProjectItem with | ||
member x.VSProject = | ||
Option.ofNull x | ||
|> Option.bind (fun item -> | ||
try Option.ofNull (item.ContainingProject.Object :?> VSProject) with _ -> None) | ||
|
||
module SolutionEvents = | ||
let private projectChanged = Event<_>() | ||
let private dte = Package.GetGlobalService(typedefof<DTE>) :?> DTE | ||
let private events = dte.Events :?> EnvDTE80.Events2 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These two dynamic castings could raise InvalidCaseException. Might be good idea to wrap them in try/with and process |
||
|
||
let private onProjectChanged (projectItem: ProjectItem) = | ||
projectItem.VSProject | ||
|> Option.iter (fun item -> | ||
debug "[ProjectsCache] %s changed." projectItem.Name | ||
item.Project.Save() | ||
projectChanged.Trigger item) | ||
|
||
events.ProjectItemsEvents.add_ItemRenamed (fun p _ -> onProjectChanged p) | ||
events.ProjectItemsEvents.add_ItemRemoved (fun p -> onProjectChanged p) | ||
events.ProjectItemsEvents.add_ItemAdded (fun p -> onProjectChanged p) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think this is a good place for subscribing events. This works on some order of module evaluation but might not work on other orders. A better place could be the |
||
|
||
/// Raised when any project in solution has changed. | ||
let ProjectChanged = projectChanged.Publish |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure
doc.ProjectItem
could be null in some case.