diff options
Diffstat (limited to 'main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.cs')
-rw-r--r-- | main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.cs | 848 |
1 files changed, 848 insertions, 0 deletions
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.cs new file mode 100644 index 0000000000..e7ce3ef053 --- /dev/null +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.cs @@ -0,0 +1,848 @@ +// +// MonoDevelopWorkspace.cs +// +// Author: +// Mike Krüger <mkrueger@xamarin.com> +// +// Copyright (c) 2014 Xamarin Inc. (http://xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; +using Microsoft.CodeAnalysis; +using System.Linq; +using System.IO; +using MonoDevelop.Core; +using System.Collections.Generic; +using System.Threading; +using Microsoft.CodeAnalysis.Text; +using System.Threading.Tasks; +using MonoDevelop.Ide.Editor; +using Microsoft.CodeAnalysis.Host; +using MonoDevelop.Core.Text; +using System.Collections.Concurrent; +using MonoDevelop.Ide.CodeFormatting; +using MonoDevelop.Core.ProgressMonitoring; +using Gtk; + +namespace MonoDevelop.Ide.TypeSystem +{ + class MonoDevelopWorkspace : Workspace + { + readonly static HostServices services = Microsoft.CodeAnalysis.Host.Mef.MefHostServices.DefaultHost; + CancellationTokenSource src = new CancellationTokenSource (); + MonoDevelop.Projects.Solution currentMonoDevelopSolution; + object addLock = new object(); + bool added; + bool internalChanges; + + public MonoDevelop.Projects.Solution MonoDevelopSolution { + get { + return currentMonoDevelopSolution; + } + } + + public MonoDevelopWorkspace () : base (services, "MonoDevelopWorkspace") + { + if (IdeApp.Workspace != null) { + IdeApp.Workspace.ActiveConfigurationChanged += HandleActiveConfigurationChanged; + } + } + + protected override void Dispose (bool finalize) + { + base.Dispose (finalize); + if (IdeApp.Workspace != null) { + IdeApp.Workspace.ActiveConfigurationChanged -= HandleActiveConfigurationChanged; + } + + } + + internal void InformDocumentTextChange (DocumentId id, SourceText text) + { + base.ApplyDocumentTextChanged (id, text); + } + + void CancelLoad () + { + src.Cancel (); + src = new CancellationTokenSource (); + } + + static StatusBarIcon statusIcon = null; + static int workspacesLoading = 0; + + internal static event EventHandler LoadingFinished; + + static void OnLoadingFinished (EventArgs e) + { + var handler = LoadingFinished; + if (handler != null) + handler (null, e); + } + + internal void HideStatusIcon () + { + Gtk.Application.Invoke (delegate { + workspacesLoading--; + if (workspacesLoading == 0 && statusIcon != null) { + statusIcon.Dispose (); + statusIcon = null; + OnLoadingFinished (EventArgs.Empty); + } + }); + } + + internal void ShowStatusIcon () + { + Gtk.Application.Invoke (delegate { + workspacesLoading++; + if (statusIcon != null) + return; + statusIcon = IdeApp.Workbench?.StatusBar.ShowStatusIcon (ImageService.GetIcon ("md-parser")); + }); + } + + void HandleActiveConfigurationChanged (object sender, EventArgs e) + { + if (currentMonoDevelopSolution == null) + return; + ShowStatusIcon (); + CancelLoad (); + var token = src.Token; + Task.Run (() => { + try { + return CreateSolutionInfo (currentMonoDevelopSolution, token); + } catch (Exception ex) { + LoggingService.LogError ("Error while reloading solution.", ex); + return null; + } + }).ContinueWith ((Task<SolutionInfo> t) => { + try { + if (t.Status == TaskStatus.RanToCompletion) { + if (t.Result == null) + return; + OnSolutionReloaded (t.Result); + } + } finally { + HideStatusIcon (); + } + }); + } + + SolutionInfo CreateSolutionInfo (MonoDevelop.Projects.Solution solution, CancellationToken token) + { + var projects = new ConcurrentBag<ProjectInfo> (); + var mdProjects = solution.GetAllProjects (); + Parallel.ForEach (mdProjects, proj => { + if (token.IsCancellationRequested) + return; + projects.Add (LoadProject (proj, token)); + }); + if (token.IsCancellationRequested) + return null; + var solutionInfo = SolutionInfo.Create (GetSolutionId (solution), VersionStamp.Create (), solution.FileName, projects); + lock (addLock) { + if (!added) { + added = true; + OnSolutionAdded (solutionInfo); + } + } + return solutionInfo; + } + + public void TryLoadSolution (MonoDevelop.Projects.Solution solution/*, IProgressMonitor progressMonitor*/) + { + this.currentMonoDevelopSolution = solution; + CancelLoad (); + CreateSolutionInfo (solution, src.Token); + } + + public void UnloadSolution () + { + OnSolutionRemoved (); + } + + Dictionary<MonoDevelop.Projects.Solution, SolutionId> solutionIdMap = new Dictionary<MonoDevelop.Projects.Solution, SolutionId> (); + + internal SolutionId GetSolutionId (MonoDevelop.Projects.Solution solution) + { + if (solution == null) + throw new ArgumentNullException ("solution"); + lock (solutionIdMap) { + SolutionId result; + if (!solutionIdMap.TryGetValue (solution, out result)) { + result = SolutionId.CreateNewId (solution.Name); + solutionIdMap [solution] = result; + } + return result; + } + } + + ConcurrentDictionary<MonoDevelop.Projects.Project, ProjectId> projectIdMap = new ConcurrentDictionary<MonoDevelop.Projects.Project, ProjectId> (); + ConcurrentDictionary<ProjectId, ProjectData> projectDataMap = new ConcurrentDictionary<ProjectId, ProjectData> (); + + internal MonoDevelop.Projects.Project GetMonoProject (Project project) + { + return GetMonoProject (project.Id); + } + + internal MonoDevelop.Projects.Project GetMonoProject (ProjectId projectId) + { + foreach (var kv in projectIdMap) { + if (kv.Value == projectId) + return kv.Key; + } + return null; + } + + public bool Contains (ProjectId projectId) + { + return projectDataMap.ContainsKey (projectId); + } + + internal ProjectId GetProjectId (MonoDevelop.Projects.Project p) + { + lock (projectIdMap) { + ProjectId result; + if (projectIdMap.TryGetValue (p, out result)) + return result; + return null; + } + } + + internal ProjectId GetOrCreateProjectId (MonoDevelop.Projects.Project p) + { + lock (projectIdMap) { + ProjectId result; + if (!projectIdMap.TryGetValue (p, out result)) { + result = ProjectId.CreateNewId (p.Name); + projectIdMap [p] = result; + } + return result; + } + } + + ProjectData GetProjectData (ProjectId id) + { + lock (projectIdMap) { + ProjectData result; + if (projectDataMap.TryGetValue (id, out result)) { + return result; + } + return null; + } + } + + ProjectData GetOrCreateProjectData (ProjectId id) + { + lock (projectIdMap) { + ProjectData result; + if (!projectDataMap.TryGetValue (id, out result)) { + result = new ProjectData (id); + projectDataMap [id] = result; + } + return result; + } + } + + class ProjectData + { + readonly ProjectId projectId; + readonly Dictionary<string, DocumentId> documentIdMap; + + public ProjectInfo Info { + get; + set; + } + + public ProjectData (ProjectId projectId) + { + this.projectId = projectId; + documentIdMap = new Dictionary<string, DocumentId> (FilePath.PathComparer); + } + + internal DocumentId GetOrCreateDocumentId (string name) + { + lock (documentIdMap) { + DocumentId result; + if (!documentIdMap.TryGetValue (name, out result)) { + result = DocumentId.CreateNewId (projectId, name); + documentIdMap [name] = result; + } + return result; + } + } + + public DocumentId GetDocumentId (string name) + { + DocumentId result; + if (!documentIdMap.TryGetValue (name, out result)) + return null; + return result; + } + + internal void RemoveDocument (string name) + { + documentIdMap.Remove (name); + } + } + + internal DocumentId GetDocumentId (ProjectId projectId, string name) + { + var data = GetProjectData (projectId); + if (data == null) + return null; + return data.GetDocumentId (name); + } + + public override bool CanApplyChange (ApplyChangesKind feature) + { + return true; + } + + ProjectInfo LoadProject (MonoDevelop.Projects.Project p, CancellationToken token) + { + if (!projectIdMap.ContainsKey (p)) { + p.FileAddedToProject += OnFileAdded; + p.FileRemovedFromProject += OnFileRemoved; + p.FileRenamedInProject += OnFileRenamed; + p.Modified += OnProjectModified; + } + + var projectId = GetOrCreateProjectId (p); + var projectData = GetOrCreateProjectData (projectId); + var config = IdeApp.Workspace != null ? p.GetConfiguration (IdeApp.Workspace.ActiveConfiguration) as MonoDevelop.Projects.DotNetProjectConfiguration : null; + MonoDevelop.Projects.DotNetConfigurationParameters cp = null; + if (config != null) + cp = config.CompilationParameters as MonoDevelop.Projects.DotNetConfigurationParameters; + FilePath fileName = IdeApp.Workspace != null ? p.GetOutputFileName (IdeApp.Workspace.ActiveConfiguration) : new FilePath (p.Name + ".dll"); + var info = ProjectInfo.Create ( + projectId, + VersionStamp.Create (), + p.Name, + fileName.FileNameWithoutExtension, + LanguageNames.CSharp, + p.FileName, + fileName, + cp != null ? cp.CreateCompilationOptions () : null, + cp != null ? cp.CreateParseOptions () : null, + CreateDocuments (projectData, p, token), + CreateProjectReferences (p, token), + CreateMetadataReferences (p, projectId, token) + ); + + projectData.Info = info; + return info; + } + + internal static Func<string, TextLoader> CreateTextLoader = fileName => new MonoDevelopTextLoader (fileName); + + static DocumentInfo CreateDocumentInfo (string projectName, ProjectData id, MonoDevelop.Projects.ProjectFile f) + { + var sourceCodeKind = f.FilePath.Extension == ".sketchcs" ? SourceCodeKind.Interactive : SourceCodeKind.Regular; + return DocumentInfo.Create ( + id.GetOrCreateDocumentId (f.Name), + f.FilePath, + new [] { projectName }.Concat (f.ProjectVirtualPath.ParentDirectory.ToString ().Split (Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)), + sourceCodeKind, + CreateTextLoader (f.Name), + f.Name, + false + ); + } + + IEnumerable<DocumentInfo> CreateDocuments (ProjectData id, MonoDevelop.Projects.Project p, CancellationToken token) + { + var duplicates = new HashSet<DocumentId> (); + foreach (var f in p.Files) { + if (token.IsCancellationRequested) + yield break; + if (TypeSystemParserNode.IsCompileBuildAction (f.BuildAction)) { + if (!duplicates.Add (id.GetOrCreateDocumentId (f.Name))) + continue; + yield return CreateDocumentInfo (p.Name, id, f); + continue; + } + var mimeType = DesktopService.GetMimeTypeForUri (f.FilePath); + var node = TypeSystemService.GetTypeSystemParserNode (mimeType, f.BuildAction); + if (node == null || !node.Parser.CanGenerateProjection (mimeType, f.BuildAction, p.SupportedLanguages)) + continue; + if (!duplicates.Add (id.GetOrCreateDocumentId (f.Name))) + continue; + var options = new ParseOptions { + FileName = f.FilePath, + Project = p, + Content = StringTextSource.ReadFrom (f.FilePath), + }; + var projections = node.Parser.GenerateProjections (options); + foreach (var projection in projections.Result) { + yield return DocumentInfo.Create ( + id.GetOrCreateDocumentId (projection.Document.FileName), + projection.Document.FileName, + null, + SourceCodeKind.Regular, + TextLoader.From (TextAndVersion.Create (new MonoDevelopSourceText (projection.Document), VersionStamp.Create (), projection.Document.FileName)), + f.Name, + false + ); + } + } + } + + static IEnumerable<MetadataReference> CreateMetadataReferences (MonoDevelop.Projects.Project p, ProjectId projectId, CancellationToken token) + { + var netProject = p as MonoDevelop.Projects.DotNetProject; + if (netProject == null) + yield break; + var configurationSelector = IdeApp.Workspace?.ActiveConfiguration ?? MonoDevelop.Projects.ConfigurationSelector.Default; + var hashSet = new HashSet<string> (FilePath.PathComparer); + + bool addFacadeAssemblies = false; + + foreach (string file in netProject.GetReferencedAssemblies (configurationSelector, false)) { + if (token.IsCancellationRequested) + yield break; + string fileName; + if (!Path.IsPathRooted (file)) { + fileName = Path.Combine (Path.GetDirectoryName (netProject.FileName), file); + } else { + fileName = Path.GetFullPath (file); + } + if (hashSet.Contains (fileName)) + continue; + hashSet.Add (fileName); + yield return MetadataReferenceCache.LoadReference (projectId, fileName); + addFacadeAssemblies |= MonoDevelop.Core.Assemblies.SystemAssemblyService.ContainsReferenceToSystemRuntime (fileName); + } + + // HACK: Facade assemblies should be added by the project system. Remove that when the project system can do that. + if (addFacadeAssemblies) { + if (netProject != null) { + var runtime = netProject.TargetRuntime ?? MonoDevelop.Core.Runtime.SystemAssemblyService.DefaultRuntime; + var facades = runtime.FindFacadeAssembliesForPCL (netProject.TargetFramework); + foreach (var facade in facades) + yield return MetadataReferenceCache.LoadReference (projectId, facade); + } + } + + foreach (var pr in p.GetReferencedItems (configurationSelector)) { + if (token.IsCancellationRequested) + yield break; + var referencedProject = pr as MonoDevelop.Projects.DotNetProject; + if (referencedProject == null) + continue; + if (TypeSystemService.IsOutputTrackedProject (referencedProject)) { + var fileName = referencedProject.GetOutputFileName (configurationSelector); + yield return MetadataReferenceCache.LoadReference (projectId, fileName); + } + } + } + + IEnumerable<ProjectReference> CreateProjectReferences (MonoDevelop.Projects.Project p, CancellationToken token) + { + foreach (var pr in p.GetReferencedItems (MonoDevelop.Projects.ConfigurationSelector.Default)) { + if (token.IsCancellationRequested) + yield break; + var referencedProject = pr as MonoDevelop.Projects.DotNetProject; + if (referencedProject == null) + continue; + if (TypeSystemService.IsOutputTrackedProject (referencedProject)) + continue; + yield return new ProjectReference (GetOrCreateProjectId (referencedProject)); + } + } + + #region Open documents + public override bool CanOpenDocuments { + get { + return true; + } + } + + public override void OpenDocument (DocumentId documentId, bool activate = true) + { + var document = GetDocument (documentId); + if (document == null) + return; + MonoDevelop.Projects.Project prj = null; + foreach (var curPrj in IdeApp.Workspace.GetAllProjects ()) { + if (GetProjectId (curPrj) == documentId.ProjectId) { + prj = curPrj; + break; + } + } + IdeApp.Workbench.OpenDocument (new MonoDevelop.Ide.Gui.FileOpenInformation ( + DetermineFilePath(document.Id, document.Name, document.FilePath, document.Folders), + prj, + activate + )); + } + + List<MonoDevelopSourceTextContainer> openDocuments = new List<MonoDevelopSourceTextContainer>(); + internal void InformDocumentOpen (DocumentId documentId, ITextDocument editor) + { + var document = this.GetDocument (documentId); + if (document == null) { + return; + } + if (IsDocumentOpen (documentId)) + InformDocumentClose (documentId, document.FilePath); + var monoDevelopSourceTextContainer = new MonoDevelopSourceTextContainer (documentId, editor); + lock (openDocuments) { + openDocuments.Add (monoDevelopSourceTextContainer); + } + OnDocumentOpened (documentId, monoDevelopSourceTextContainer); + } + + Solution newSolution; + public override bool TryApplyChanges (Solution newSolution) + { + this.newSolution = newSolution; + return base.TryApplyChanges (newSolution); + } + + protected override void ApplyProjectChanges (ProjectChanges projectChanges) + { + try { + internalChanges = true; + base.ApplyProjectChanges (projectChanges); + var data = GetMonoProject (projectChanges.NewProject); + if (data != null) { + Application.Invoke (delegate { + data.Save (new NullProgressMonitor ()); + }); + } + } finally { + internalChanges = false; + } + } + + protected override void ApplyAdditionalDocumentAdded (DocumentInfo info, SourceText text) + { + base.ApplyAdditionalDocumentAdded (info, text); + } + + protected override void OnDocumentTextChanged (Document document) + { + base.OnDocumentTextChanged (document); + } + + protected override void OnDocumentClosing (DocumentId documentId) + { + base.OnDocumentClosing (documentId); + lock (openDocuments) { + var openDoc = openDocuments.FirstOrDefault (d => d.Id == documentId); + if (openDoc != null) { +// openDoc.TextChanged -= HandleTextChanged; + openDocuments.Remove (openDoc); + } + } + } + +// internal override bool CanChangeActiveContextDocument { +// get { +// return true; +// } +// } + + public void InformDocumentClose (DocumentId analysisDocument, string filePath) + { + try { + OnDocumentClosed (analysisDocument, new MonoDevelopTextLoader (filePath)); + } catch (Exception e) { + LoggingService.LogError ("Exception while closing document.", e); + } + } + + public override void CloseDocument (DocumentId documentId) + { + } + + protected override void ApplyDocumentTextChanged (DocumentId id, SourceText text) + { + var document = GetDocument (id); + + if (document == null) + return; + bool isOpen; + var data = TextFileProvider.Instance.GetTextEditorData (document.FilePath, out isOpen); + var changes = text.GetTextChanges (document.GetTextAsync ().Result).OrderByDescending (c => c.Span.Start).ToList (); + + int delta = 0; + foreach (var change in changes) { + data.ReplaceText (change.Span.Start, change.Span.Length, change.NewText); + delta += change.Span.Length - change.NewText.Length; + } + + if (!isOpen) { + var formatter = CodeFormatterService.GetFormatter (data.MimeType); + var mp = GetMonoProject (CurrentSolution.GetProject (id.ProjectId)); + string currentText = data.Text; + foreach (var change in changes) { + delta -= change.Span.Length - change.NewText.Length; + var startOffset = change.Span.Start - delta; + var str = formatter.FormatText (mp.Policies, currentText, startOffset, startOffset + change.NewText.Length); + data.ReplaceText (startOffset, change.NewText.Length, str); + } + data.Save (); + FileService.NotifyFileChanged (document.FilePath); + } else { + var formatter = CodeFormatterService.GetFormatter (data.MimeType); + var documentContext = IdeApp.Workbench.Documents.FirstOrDefault (d => FilePath.PathComparer.Compare (d.FileName, document.FilePath) == 0); + if (documentContext != null) { + foreach (var change in changes) { + delta -= change.Span.Length - change.NewText.Length; + var startOffset = change.Span.Start - delta; + formatter.OnTheFlyFormat ((TextEditor)data, documentContext, startOffset, startOffset + change.NewText.Length); + } + } + } + OnDocumentTextChanged (id, new MonoDevelopSourceText(data), PreservationMode.PreserveValue); + } + + protected override void ApplyDocumentAdded (DocumentInfo info, SourceText text) + { + var id = info.Id; + var path = DetermineFilePath (info.Id, info.Name, info.FilePath, info.Folders, true); + + MonoDevelop.Projects.Project mdProject = null; + + if (id.ProjectId != null) { + var project = CurrentSolution.GetProject (id.ProjectId); + mdProject = GetMonoProject (project); + if (mdProject == null) + LoggingService.LogWarning ("Couldn't find project for newly generated file {0} (Project {1}).", path, info.Id.ProjectId); + } + + string formattedText; + var formatter = CodeFormatterService.GetFormatter (DesktopService.GetMimeTypeForUri (path)); + if (formatter != null && mdProject != null) { + formattedText = formatter.FormatText (mdProject.Policies, text.ToString ()); + } else { + formattedText = text.ToString (); + } + + var textSource = new StringTextSource (formattedText, text.Encoding ?? System.Text.Encoding.UTF8); + try { + textSource.WriteTextTo (path); + } catch (Exception e) { + LoggingService.LogError ("Exception while saving file to " + path, e); + } + + if (mdProject != null) { + var file = new MonoDevelop.Projects.ProjectFile (path); + Application.Invoke (delegate { + mdProject.Files.Add (file); + IdeApp.ProjectOperations.Save (mdProject); + }); + } + + OnDocumentAdded (info.WithTextLoader (new MonoDevelopTextLoader (path))); + } + + string DetermineFilePath (DocumentId id, string name, string filePath, IReadOnlyList<string> docFolders, bool createDirectory = false) + { + var path = filePath; + + if (string.IsNullOrEmpty (path)) { + var monoProject = GetMonoProject (id.ProjectId); + + // If the first namespace name matches the name of the project, then we don't want to + // generate a folder for that. The project is implicitly a folder with that name. + IEnumerable<string> folders; + if (docFolders.FirstOrDefault () == monoProject.Name) { + folders = docFolders.Skip (1); + } else { + folders = docFolders; + } + + if (folders.Any ()) { + string baseDirectory = Path.Combine (monoProject.BaseDirectory, Path.Combine (folders.ToArray ())); + try { + if (createDirectory && !Directory.Exists (baseDirectory)) + Directory.CreateDirectory (baseDirectory); + } catch (Exception e) { + LoggingService.LogError ("Error while creating directory for a new file : " + baseDirectory, e); + } + path = Path.Combine (baseDirectory, name); + } + } + return path; + } + #endregion + + public Document GetDocument (DocumentId documentId, CancellationToken cancellationToken = default(CancellationToken)) + { + var project = CurrentSolution.GetProject (documentId.ProjectId); + if (project == null) + return null; + return project.GetDocument (documentId); + } + + public void UpdateFileContent (string fileName, string text) + { + SourceText newText = SourceText.From (text); + foreach (var project in this.projectDataMap.Keys) { + var docId = this.GetDocumentId (project, fileName); + if (docId == null) + continue; + base.OnDocumentTextChanged (docId, newText, PreservationMode.PreserveIdentity); + } + } + + public void AddProject (MonoDevelop.Projects.Project project) + { + var info = LoadProject (project, default(CancellationToken)); + OnProjectAdded (info); + } + + public void RemoveProject (MonoDevelop.Projects.Project project) + { + var id = GetProjectId (project); + if (id != null) { + foreach (var docId in GetOpenDocumentIds (id).ToList ()) { + ClearOpenDocument (docId); + } + OnProjectRemoved (id); + ProjectId val; + projectIdMap.TryRemove (project, out val); + ProjectData val2; + projectDataMap.TryRemove (id, out val2); + MetadataReferenceCache.RemoveReferences (id); + + project.FileAddedToProject -= OnFileAdded; + project.FileRemovedFromProject -= OnFileRemoved; + project.FileRenamedInProject -= OnFileRenamed; + project.Modified -= OnProjectModified; + } + } + + #region Project modification handlers + + void OnFileAdded (object sender, MonoDevelop.Projects.ProjectFileEventArgs args) + { + if (internalChanges) + return; + var project = (MonoDevelop.Projects.Project)sender; + foreach (MonoDevelop.Projects.ProjectFileEventInfo fargs in args) { + if (!TypeSystemParserNode.IsCompileBuildAction (fargs.ProjectFile.BuildAction)) + continue; + var projectId = GetProjectId (project); + var newDocument = CreateDocumentInfo (project.Name, GetProjectData (projectId), fargs.ProjectFile); + OnDocumentAdded (newDocument); + } + } + + void OnFileRemoved (object sender, MonoDevelop.Projects.ProjectFileEventArgs args) + { + if (internalChanges) + return; + var project = (MonoDevelop.Projects.Project)sender; + foreach (MonoDevelop.Projects.ProjectFileEventInfo fargs in args) { + var projectId = GetProjectId (project); + var data = GetProjectData (projectId); + var id = data.GetDocumentId (fargs.ProjectFile.FilePath); + if (id != null) { + ClearDocumentData (id); + OnDocumentRemoved (id); + data.RemoveDocument (fargs.ProjectFile.FilePath); + } + } + } + + void OnFileRenamed (object sender, MonoDevelop.Projects.ProjectFileRenamedEventArgs args) + { + if (internalChanges) + return; + var project = (MonoDevelop.Projects.Project)sender; + foreach (MonoDevelop.Projects.ProjectFileRenamedEventInfo fargs in args) { + if (!TypeSystemParserNode.IsCompileBuildAction (fargs.ProjectFile.BuildAction)) + continue; + + var projectId = GetProjectId (project); + var data = GetProjectData (projectId); + + var id = data.GetDocumentId (fargs.OldName); + if (id != null) { + if (this.IsDocumentOpen (id)) { + this.InformDocumentClose (id, fargs.OldName); + } + OnDocumentRemoved (id); + data.RemoveDocument (fargs.OldName); + } + + var newDocument = CreateDocumentInfo (project.Name, GetProjectData (projectId), fargs.ProjectFile); + OnDocumentAdded (newDocument); + } + } + + void OnProjectModified (object sender, MonoDevelop.Projects.SolutionItemModifiedEventArgs args) + { + if (internalChanges) + return; + if (!args.Any (x => x.Hint == "TargetFramework" || x.Hint == "References")) + return; + var project = (MonoDevelop.Projects.Project)sender; + var projectId = GetProjectId (project); + OnProjectReloaded (LoadProject (project, default(CancellationToken))); + } + + #endregion + + } + +// static class MonoDevelopWorkspaceFeatures +// { +// static FeaturePack pack; +// +// public static FeaturePack Features { +// get { +// if (pack == null) +// Interlocked.CompareExchange (ref pack, ComputePack (), null); +// return pack; +// } +// } +// +// static FeaturePack ComputePack () +// { +// var assemblies = new List<Assembly> (); +// var workspaceCoreAssembly = typeof(Workspace).Assembly; +// assemblies.Add (workspaceCoreAssembly); +// +// LoadAssembly (assemblies, "Microsoft.CodeAnalysis.CSharp.Workspaces"); +// //LoadAssembly (assemblies, "Microsoft.CodeAnalysis.VisualBasic.Workspaces"); +// +// var catalogs = assemblies.Select (a => new System.ComponentModel.Composition.Hosting.AssemblyCatalog (a)); +// +// return new MefExportPack (catalogs); +// } +// +// static void LoadAssembly (List<Assembly> assemblies, string assemblyName) +// { +// try { +// var loadedAssembly = Assembly.Load (assemblyName); +// assemblies.Add (loadedAssembly); +// } catch (Exception e) { +// LoggingService.LogWarning ("Couldn't load assembly:" + assemblyName, e); +// } +// } +// } + +}
\ No newline at end of file |