From ca94e4851759c70a3f44e6ed4d2d1f3296ed0bcf Mon Sep 17 00:00:00 2001 From: Lluis Sanchez Date: Fri, 15 Feb 2019 18:57:44 +0100 Subject: Convert several IDE services into Service instances The new IdeServices class has references to the core IDE services. Revamped the IDE initialization code. The UI loop is started earlier and that allows starting the services asynchronously. Code that previously was referencing static service classes or services available in IdeApp now reference IdeServices. --- .../CompositionManager.cs | 50 +-- .../MonoDevelop.Ide.Composition/PlatformCatalog.cs | 30 +- .../MonoDevelop.Ide.Desktop/RecentOpen.cs | 19 +- .../SyntaxHighlightingService.cs | 48 ++- .../DefaultSourceEditorOptions.cs | 35 +- .../MonoDevelop.Ide.Extensions/IdeCustomizer.cs | 4 +- .../MonoDevelop.Ide.Fonts/FontService.cs | 71 ++-- .../MonoDevelop.Ide.Gui/ProgressMonitorManager.cs | 158 +++++++++ .../MonoDevelop.Ide.Gui/ProgressMonitors.cs | 132 ++++--- .../MonoDevelop.Ide.Gui/StartupInfo.cs | 115 ------- .../NavigationHistoryService.cs | 378 +++++++++++---------- .../CommentTasksProvider.Legacy.cs | 100 ++++-- .../MonoDevelop.Ide.Tasks/CommentTasksProvider.cs | 44 +-- .../MonoDevelop.Ide.Tasks/TaskService.cs | 84 ++--- .../MonoDevelop.Ide.Tasks/TaskSeverity.cs | 39 +++ .../MonoDevelop.Ide.Tasks/TaskStore.cs | 89 ++--- .../TextEditorService.cs | 109 +++--- ...onoDevelopWorkspace.MetadataReferenceHandler.cs | 10 +- .../MonoDevelopWorkspace.ProjectSystemHandler.cs | 18 +- .../MonoDevelopWorkspace.cs | 214 ++++++------ .../TypeSystemService.cs | 262 ++++++++------ .../TypeSystemService_WorkspaceHandling.cs | 141 ++++---- .../MonoDevelop.Ide/MonoDevelop.Ide/AddinError.cs | 66 ++++ .../MonoDevelop.Ide/DesktopService.cs | 171 ++++++---- .../core/MonoDevelop.Ide/MonoDevelop.Ide/Ide.cs | 153 ++++----- .../MonoDevelop.Ide/IdeInstanceConnection.cs | 141 ++++++++ .../MonoDevelop.Ide/IdePreferences.cs | 69 ++-- .../MonoDevelop.Ide/MonoDevelop.Ide/IdeServices.cs | 113 ++++++ .../MonoDevelop.Ide/MonoDevelop.Ide/IdeStartup.cs | 318 +++++------------ .../MonoDevelop.Ide/MonoDevelopOptions.cs | 96 ++++++ .../MonoDevelop.Ide/ProjectOperations.cs | 317 ++++++++--------- .../MonoDevelop.Ide/RootWorkspace.cs | 333 +++++++++++++----- 32 files changed, 2277 insertions(+), 1650 deletions(-) create mode 100644 main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/ProgressMonitorManager.cs delete mode 100644 main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/StartupInfo.cs create mode 100644 main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Tasks/TaskSeverity.cs create mode 100644 main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/AddinError.cs create mode 100644 main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeInstanceConnection.cs create mode 100644 main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeServices.cs create mode 100644 main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/MonoDevelopOptions.cs (limited to 'main/src') diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/CompositionManager.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/CompositionManager.cs index cacad176b2..39e3eaaf25 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/CompositionManager.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/CompositionManager.cs @@ -45,10 +45,10 @@ namespace MonoDevelop.Ide.Composition { /// /// The host of the MonoDevelop MEF composition. Uses https://github.com/Microsoft/vs-mef. - /// - public partial class CompositionManager + /// + [DefaultServiceImplementation] + public partial class CompositionManager: Service { - static Task creationTask; static CompositionManager instance; static readonly Resolver StandardResolver = Resolver.DefaultInstance; @@ -56,55 +56,44 @@ namespace MonoDevelop.Ide.Composition new AttributedPartDiscoveryV1 (StandardResolver), new AttributedPartDiscovery (StandardResolver, true)); - public static CompositionManager Instance { + public static CompositionManager Instance { get { if (instance == null) { - var task = InitializeAsync (); + var task = Runtime.GetService (); if (!task.IsCompleted && Runtime.IsMainThread) { LoggingService.LogInfo ("UI thread queried MEF while it was still being built:{0}{1}", Environment.NewLine, Environment.StackTrace); } - instance = task.Result; - } - - return instance; - } + instance = task.WaitAndGetResult (); + } + + return instance; + } } - /// - /// Starts initializing the MEF composition on a background thread. Thread-safe. - /// - public static Task InitializeAsync () + protected override Task OnInitialize (ServiceProvider serviceProvider) { - if (creationTask == null) { - lock (typeof (CompositionManager)) { - if (creationTask == null) { - creationTask = Task.Run (() => CreateInstanceAsync ()); - } - } - } - - return creationTask; + return Task.Run (async () => await InitializeInstanceAsync ()); } /// /// Returns an instance of type T that is exported by some composition part. The instance is shared (singleton). /// - public static T GetExportedValue () => Instance.ExportProvider.GetExportedValue (); + public T GetExportedValue () => ExportProvider.GetExportedValue (); /// /// Returns all instances of type T that are exported by some composition part. The instances are shared (singletons). /// - public static IEnumerable GetExportedValues () => Instance.ExportProvider.GetExportedValues (); + public IEnumerable GetExportedValues () => ExportProvider.GetExportedValues (); /// /// Returns a lazy holding the instance of type T that is exported by some composition part. The instance is shared (singleton). /// - public static Lazy GetExport () => new Lazy (() => Instance.ExportProvider.GetExportedValue ()); + public static Lazy GetExport () => new Lazy (() => Instance.ExportProvider.GetExportedValue ()); /// /// Returns a lazy holding all instances of type T that are exported by some composition part. The instances are shared (singletons). /// - public static Lazy> GetExports () => new Lazy> (() => Instance.ExportProvider.GetExportedValues ()); + public static Lazy> GetExports () => new Lazy> (() => Instance.ExportProvider.GetExportedValues ()); public RuntimeComposition RuntimeComposition { get; private set; } public IExportProviderFactory ExportProviderFactory { get; private set; } @@ -116,13 +105,6 @@ namespace MonoDevelop.Ide.Composition { } - static async Task CreateInstanceAsync () - { - var compositionManager = new CompositionManager (); - await compositionManager.InitializeInstanceAsync (); - return compositionManager; - } - async Task InitializeInstanceAsync () { var assemblies = ReadAssembliesFromAddins (); diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/PlatformCatalog.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/PlatformCatalog.cs index 2cd0faaae1..d26e9d4644 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/PlatformCatalog.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/PlatformCatalog.cs @@ -1,42 +1,30 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. -// +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// using System; -using System.Linq; -using System.Collections.Generic; using System.Collections.Immutable; using System.ComponentModel.Composition; -using System.ComponentModel.Composition.Hosting; -using System.Reflection; -using System.Diagnostics; -using System.ComponentModel; using System.IO; using System.Threading; -using System.Threading.Tasks; - -using Mono.Addins; -using MonoDevelop.Core; -using MonoDevelop.Core.AddIns; -using MonoDevelop.Ide.Editor.Highlighting; -using MonoDevelop.Ide.Composition; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Classification; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Tagging; using Microsoft.VisualStudio.Utilities; - +using MonoDevelop.Ide.Composition; + namespace Microsoft.VisualStudio.Platform -{ - [Export] +{ + [Export] public class PlatformCatalog { static PlatformCatalog instance; public static PlatformCatalog Instance { get { if (instance == null) { - instance = CompositionManager.GetExportedValue (); + instance = CompositionManager.Instance.GetExportedValue (); } return instance; diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Desktop/RecentOpen.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Desktop/RecentOpen.cs index 84ec664cb0..286b85f889 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Desktop/RecentOpen.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Desktop/RecentOpen.cs @@ -1,4 +1,4 @@ -// +// // RecentOpen.cs // // Author: @@ -34,6 +34,7 @@ using System.IO; using MonoDevelop.Core; using System.Linq; +using MonoDevelop.Projects; namespace MonoDevelop.Ide.Desktop { @@ -84,7 +85,7 @@ namespace MonoDevelop.Ide.Desktop IList Get (string grp) { var gp = recentFiles.GetItemsInGroup (grp); - return gp.Select (i => new RecentFile (i.LocalPath, i.Private, i.Timestamp)).ToList (); + return gp.Select (i => new RecentFile (this, i.LocalPath, i.Private, i.Timestamp)).ToList (); } public override void ClearProjects () @@ -163,6 +164,8 @@ namespace MonoDevelop.Ide.Desktop favoriteFiles = PropertyService.Get (FavoritesConfigKey, new List ()); } + internal DesktopService DesktopService { get; set; } + public IList GetProjects () { var projects = OnGetProjects (); @@ -172,7 +175,7 @@ namespace MonoDevelop.Ide.Desktop if (entry != null) result.Add (entry); else - result.Add (new RecentFile (f, Path.GetFileNameWithoutExtension (f), DateTime.Now)); + result.Add (new RecentFile (this, f, Path.GetFileNameWithoutExtension (f), DateTime.Now)); } foreach (var e in projects) if (!result.Contains (e)) @@ -202,7 +205,7 @@ namespace MonoDevelop.Ide.Desktop protected abstract IList OnGetProjects (); protected abstract IList OnGetFiles (); - public void AddFile (string fileName, MonoDevelop.Projects.Project project) + public void AddFile (string fileName, WorkspaceObject project) { var projectName = project != null? project.Name : null; var displayName = projectName != null? @@ -234,9 +237,11 @@ namespace MonoDevelop.Ide.Desktop { string displayName, fileName; DateTime timestamp; + RecentFiles recenFiles; - public RecentFile (string fileName, string displayName, DateTime timestamp) + public RecentFile (RecentFiles recenFiles, string fileName, string displayName, DateTime timestamp) { + this.recenFiles = recenFiles; this.fileName = fileName; this.displayName = displayName; this.timestamp = timestamp; @@ -244,10 +249,10 @@ namespace MonoDevelop.Ide.Desktop public bool IsFavorite { get { - return DesktopService.RecentFiles.IsFavoriteFile (fileName); + return recenFiles.IsFavoriteFile (fileName); } set { - DesktopService.RecentFiles.SetFavoriteFile (fileName, value); + recenFiles.SetFavoriteFile (fileName, value); } } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/SyntaxHighlightingService.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/SyntaxHighlightingService.cs index 216d3b88e2..63f28b5746 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/SyntaxHighlightingService.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/SyntaxHighlightingService.cs @@ -1,4 +1,4 @@ -// SyntaxModeService.cs +// SyntaxModeService.cs // // Author: // Mike Krüger @@ -51,15 +51,24 @@ namespace MonoDevelop.Ide.Editor.Highlighting static LanguageBundle extensionBundle = new LanguageBundle ("extensions", null) { BuiltInBundle = true }; internal static LanguageBundle userThemeBundle = new LanguageBundle ("userThemes", null) { BuiltInBundle = true }; static List languageBundles = new List (); + static bool stylesInitialized; + + public static FilePath SyntaxModePath { + get { + return UserProfile.Current.UserDataRoot.Combine ("ColorThemes"); + } + } internal static IEnumerable AllBundles { get { + InitializeStylesAndModes (); return languageBundles; } } public static string[] Styles { get { + InitializeStylesAndModes (); var result = new List (); foreach (var bundle in languageBundles) { for (int i = 0; i < bundle.EditorThemes.Count; ++i) { @@ -73,7 +82,8 @@ namespace MonoDevelop.Ide.Editor.Highlighting } public static bool ContainsStyle (string styleName) - { + { + InitializeStylesAndModes (); foreach (var bundle in languageBundles) { for (int i = 0; i < bundle.EditorThemes.Count; ++i) { var style = bundle.EditorThemes[i]; @@ -146,6 +156,7 @@ namespace MonoDevelop.Ide.Editor.Highlighting internal static IEnumerable GetSettings (ScopeStack scope) { + InitializeStylesAndModes (); foreach (var bundle in languageBundles) { foreach (var setting in bundle.Settings) { if (!setting.Scopes.Any (s => TmSetting.IsSettingMatch (scope, s))) @@ -156,6 +167,7 @@ namespace MonoDevelop.Ide.Editor.Highlighting } internal static IEnumerable GetSnippets (ScopeStack scope) { + InitializeStylesAndModes (); foreach (var bundle in languageBundles) { foreach (var setting in bundle.Snippets) { if (!setting.Scopes.Any (s => TmSetting.IsSettingMatch (scope, s))) @@ -167,6 +179,7 @@ namespace MonoDevelop.Ide.Editor.Highlighting public static EditorTheme GetEditorTheme (string name) { + InitializeStylesAndModes (); foreach (var bundle in languageBundles) { for (int i = 0; i < bundle.EditorThemes.Count; ++i) { var style = bundle.EditorThemes[i]; @@ -187,11 +200,13 @@ namespace MonoDevelop.Ide.Editor.Highlighting internal static void Remove (EditorTheme style) { + InitializeStylesAndModes (); userThemeBundle.Remove (style); } internal static void Remove (LanguageBundle style) { + InitializeStylesAndModes (); languageBundles.Remove (style); } @@ -201,6 +216,29 @@ namespace MonoDevelop.Ide.Editor.Highlighting return result; } + static void InitializeStylesAndModes () + { + if (!stylesInitialized) { + stylesInitialized = true; + LoadCustomStylesAndModes (); + } + } + + public static void LoadCustomStylesAndModes () + { + bool success = true; + if (!Directory.Exists (SyntaxModePath)) { + try { + Directory.CreateDirectory (SyntaxModePath); + } catch (Exception e) { + success = false; + LoggingService.LogError ("Can't create syntax mode directory", e); + } + } + if (success) + SyntaxHighlightingService.LoadStylesAndModesInPath (SyntaxModePath); + } + internal static void LoadStylesAndModesInPath (string path) { foreach (string file in Directory.GetFiles (path)) { @@ -738,7 +776,7 @@ namespace MonoDevelop.Ide.Editor.Highlighting static SyntaxHighlightingDefinition GetSyntaxHighlightingDefinitionByMimeType (string mimeType) { - foreach (string mt in DesktopService.GetMimeTypeInheritanceChain (mimeType)) { + foreach (string mt in IdeServices.DesktopService.GetMimeTypeInheritanceChain (mimeType)) { if (mimeType == "application/octet-stream" || mimeType == "text/plain") return null; @@ -746,7 +784,7 @@ namespace MonoDevelop.Ide.Editor.Highlighting foreach (var h in bundle.Highlightings) { foreach (var fe in h.FileTypes) { var uri = fe.StartsWith (".", StringComparison.Ordinal) ? "a" + fe : "a." + fe; - var mime = DesktopService.GetMimeTypeForUri (uri); + var mime = IdeServices.DesktopService.GetMimeTypeForUri (uri); if (mimeType == mime) { return h.GetSyntaxHighlightingDefinition (); } @@ -766,7 +804,7 @@ namespace MonoDevelop.Ide.Editor.Highlighting } if (mimeType == null) { - mimeType = DesktopService.GetMimeTypeForUri (fileName); + mimeType = IdeServices.DesktopService.GetMimeTypeForUri (fileName); } } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/DefaultSourceEditorOptions.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/DefaultSourceEditorOptions.cs index 332b67a09e..db7317a9ee 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/DefaultSourceEditorOptions.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/DefaultSourceEditorOptions.cs @@ -30,6 +30,7 @@ using MonoDevelop.Ide.Fonts; using MonoDevelop.Ide.Editor.Extension; using Microsoft.VisualStudio.CodingConventions; using System.Threading.Tasks; +using MonoDevelop.Ide.TypeSystem; namespace MonoDevelop.Ide.Editor { @@ -52,25 +53,25 @@ namespace MonoDevelop.Ide.Editor public sealed class DefaultSourceEditorOptions : ITextEditorOptions { static DefaultSourceEditorOptions instance; - //static TextStylePolicy defaultPolicy; + static ITextEditorOptions plainEditor; static bool inited; ICodingConventionContext context; public static DefaultSourceEditorOptions Instance { - get { return instance; } + get { + Init (); + return instance; + } } public static ITextEditorOptions PlainEditor { - get; - private set; - } - - static DefaultSourceEditorOptions () - { - Init (); + get { + Init (); + return plainEditor; + } } - public static void Init () + static void Init () { if (inited) return; @@ -80,7 +81,7 @@ namespace MonoDevelop.Ide.Editor instance = new DefaultSourceEditorOptions (policy); MonoDevelop.Projects.Policies.PolicyService.DefaultPolicies.PolicyChanged += instance.HandlePolicyChanged; - PlainEditor = new PlainEditorOptions (); + plainEditor = new PlainEditorOptions (); } internal void FireChange () @@ -266,8 +267,10 @@ namespace MonoDevelop.Ide.Editor wordNavigationStyle = ConfigurationProperty.Create ("WordNavigationStyle", WordNavigationStyle.Windows); UpdateStylePolicy (currentPolicy); - FontService.RegisterFontChangedCallback ("Editor", UpdateFont); - FontService.RegisterFontChangedCallback ("MessageBubbles", UpdateFont); + Runtime.ServiceProvider.WhenServiceInitialized (s => { + s.RegisterFontChangedCallback ("Editor", UpdateFont); + s.RegisterFontChangedCallback ("MessageBubbles", UpdateFont); + }); IdeApp.Preferences.ColorScheme.Changed += OnColorSchemeChanged; } @@ -745,7 +748,7 @@ namespace MonoDevelop.Ide.Editor public string FontName { get { - return FontService.FilterFontName (FontService.GetUnderlyingFontName ("Editor")); + return IdeApp.FontService.FilterFontName (IdeApp.FontService.GetUnderlyingFontName ("Editor")); } set { throw new InvalidOperationException ("Set font through font service"); @@ -754,7 +757,7 @@ namespace MonoDevelop.Ide.Editor public string GutterFontName { get { - return FontService.FilterFontName (FontService.GetUnderlyingFontName ("Editor")); + return IdeApp.FontService.FilterFontName (IdeApp.FontService.GetUnderlyingFontName ("Editor")); } set { throw new InvalidOperationException ("Set font through font service"); @@ -848,7 +851,7 @@ namespace MonoDevelop.Ide.Editor public void Dispose () { - FontService.RemoveCallback (UpdateFont); + IdeApp.FontService.RemoveCallback (UpdateFont); IdeApp.Preferences.ColorScheme.Changed -= OnColorSchemeChanged; if (context != null) context.CodingConventionsChangedAsync -= UpdateContextOptions; diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Extensions/IdeCustomizer.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Extensions/IdeCustomizer.cs index ad13837725..52dadbbabf 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Extensions/IdeCustomizer.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Extensions/IdeCustomizer.cs @@ -40,7 +40,7 @@ namespace MonoDevelop.Ide.Extensions /// /// Called just after the initializer is created /// - internal protected virtual void Initialize () + internal protected virtual void Initialize (StartupInfo startupInfo) { } @@ -54,7 +54,7 @@ namespace MonoDevelop.Ide.Extensions /// /// Called when the Ide has been initialized /// - internal protected virtual void OnIdeInitialized (bool hideWelcomePage) + internal protected virtual void OnIdeInitialized () { } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Fonts/FontService.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Fonts/FontService.cs index 815c4360c5..df7eab8d2e 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Fonts/FontService.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Fonts/FontService.cs @@ -1,5 +1,5 @@ -// -// FontService.cs +// +// IdeApp.FontService.cs // // Author: // Mike Krüger @@ -27,44 +27,45 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using Mono.Addins; using MonoDevelop.Core; using Pango; namespace MonoDevelop.Ide.Fonts { - public static class FontService + [DefaultServiceImplementation] + public class FontService: Service { - static List fontDescriptions = new List (); - static Dictionary loadedFonts = new Dictionary (); - static Properties fontProperties; + List fontDescriptions = new List (); + Dictionary loadedFonts = new Dictionary (); + Properties fontProperties; + DesktopService desktopService; - static string defaultMonospaceFontName = String.Empty; - static FontDescription defaultMonospaceFont = new FontDescription (); + string defaultMonospaceFontName = String.Empty; + FontDescription defaultMonospaceFont = new FontDescription (); - static void LoadDefaults () + void LoadDefaults () { if (defaultMonospaceFont != null) { defaultMonospaceFont.Dispose (); } #pragma warning disable 618 - defaultMonospaceFontName = DesktopService.DefaultMonospaceFont; + defaultMonospaceFontName = desktopService.DefaultMonospaceFont; defaultMonospaceFont = FontDescription.FromString (defaultMonospaceFontName); #pragma warning restore 618 } - internal static IEnumerable FontDescriptions { + internal IEnumerable FontDescriptions { get { return fontDescriptions; } } - - internal static void Initialize () - { - if (fontProperties != null) - throw new InvalidOperationException ("Already initialized"); + protected override async Task OnInitialize (ServiceProvider serviceProvider) + { + desktopService = await serviceProvider.GetService (); fontProperties = PropertyService.Get ("FontProperties", new Properties ()); AddinManager.AddExtensionNodeHandler ("/MonoDevelop/Ide/Fonts", delegate(object sender, ExtensionNodeEventArgs args) { @@ -84,28 +85,28 @@ namespace MonoDevelop.Ide.Fonts LoadDefaults (); } - public static FontDescription MonospaceFont { get { return defaultMonospaceFont; } } - public static FontDescription SansFont { get { return Gui.Styles.DefaultFont; } } + public FontDescription MonospaceFont { get { return defaultMonospaceFont; } } + public FontDescription SansFont { get { return Gui.Styles.DefaultFont; } } - public static string MonospaceFontName { get { return defaultMonospaceFontName; } } - public static string SansFontName { get { return Gui.Styles.DefaultFontName; } } + public string MonospaceFontName { get { return defaultMonospaceFontName; } } + public string SansFontName { get { return Gui.Styles.DefaultFontName; } } [Obsolete ("Use MonospaceFont")] - public static FontDescription DefaultMonospaceFontDescription { + public FontDescription DefaultMonospaceFontDescription { get { if (defaultMonospaceFont == null) - defaultMonospaceFont = LoadFont (DesktopService.DefaultMonospaceFont); + defaultMonospaceFont = LoadFont (desktopService.DefaultMonospaceFont); return defaultMonospaceFont; } } - static FontDescription LoadFont (string name) + FontDescription LoadFont (string name) { var fontName = FilterFontName (name); return FontDescription.FromString (fontName); } - public static string FilterFontName (string name) + public string FilterFontName (string name) { switch (name) { case "_DEFAULT_MONOSPACE": @@ -117,7 +118,7 @@ namespace MonoDevelop.Ide.Fonts } } - public static string GetUnderlyingFontName (string name) + public string GetUnderlyingFontName (string name) { var result = fontProperties.Get (name); @@ -142,14 +143,14 @@ namespace MonoDevelop.Ide.Fonts /// /// If set to false and no custom font has been set, the method will return null. /// - public static FontDescription GetFontDescription (string name, bool createDefaultFont = true) + public FontDescription GetFontDescription (string name, bool createDefaultFont = true) { if (loadedFonts.ContainsKey (name)) return loadedFonts [name]; return loadedFonts [name] = LoadFont (GetUnderlyingFontName (name)); } - internal static FontDescriptionCodon GetFont (string name) + internal FontDescriptionCodon GetFont (string name) { foreach (var d in fontDescriptions) { if (d.Name == name) @@ -159,7 +160,7 @@ namespace MonoDevelop.Ide.Fonts return null; } - public static void SetFont (string name, string value) + public void SetFont (string name, string value) { if (loadedFonts.ContainsKey (name)) loadedFonts.Remove (name); @@ -176,20 +177,20 @@ namespace MonoDevelop.Ide.Fonts } } - internal static ConfigurationProperty GetFontProperty (string name) + internal ConfigurationProperty GetFontProperty (string name) { return new FontConfigurationProperty (name); } - static Dictionary> fontChangeCallbacks = new Dictionary> (); - public static void RegisterFontChangedCallback (string fontName, Action callback) + Dictionary> fontChangeCallbacks = new Dictionary> (); + public void RegisterFontChangedCallback (string fontName, Action callback) { if (!fontChangeCallbacks.ContainsKey (fontName)) fontChangeCallbacks [fontName] = new List (); fontChangeCallbacks [fontName].Add (callback); } - public static void RemoveCallback (Action callback) + public void RemoveCallback (Action callback) { foreach (var list in fontChangeCallbacks.Values.ToList ()) list.Remove (callback); @@ -203,17 +204,17 @@ namespace MonoDevelop.Ide.Fonts public FontConfigurationProperty (string name) { this.name = name; - FontService.RegisterFontChangedCallback (name, OnChanged); + IdeApp.FontService.RegisterFontChangedCallback (name, OnChanged); } protected override FontDescription OnGetValue () { - return FontService.GetFontDescription (name); + return IdeApp.FontService.GetFontDescription (name); } protected override bool OnSetValue (FontDescription value) { - FontService.SetFont (name, value.ToString ()); + IdeApp.FontService.SetFont (name, value.ToString ()); return true; } } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/ProgressMonitorManager.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/ProgressMonitorManager.cs new file mode 100644 index 0000000000..1bef639297 --- /dev/null +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/ProgressMonitorManager.cs @@ -0,0 +1,158 @@ +// +// ProgressMonitorManager.cs +// +// Author: +// Lluis Sanchez Gual +// +// Copyright (C) 2005 Novell, Inc (http://www.novell.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 MonoDevelop.Core; +using MonoDevelop.Core.Execution; +using MonoDevelop.Ide.FindInFiles; +using System.Threading; + +namespace MonoDevelop.Ide.Gui +{ + [DefaultServiceImplementation(typeof(IdeProgressMonitorManager))] + public abstract class ProgressMonitorManager : Service + { + public ProgressMonitor GetBuildProgressMonitor () + { + return OnGetBuildProgressMonitor (); + } + + public ProgressMonitor GetCleanProgressMonitor () + { + return OnGetCleanProgressMonitor (); + } + + public ProgressMonitor GetRebuildProgressMonitor () + { + return OnGetRebuildProgressMonitor (); + } + + public OutputProgressMonitor GetRunProgressMonitor () + { + return GetRunProgressMonitor (null); + } + + public OutputProgressMonitor GetRunProgressMonitor (string titleSuffix) + { + return OnGetRunProgressMonitor (titleSuffix); + } + + public OutputProgressMonitor GetToolOutputProgressMonitor (bool bringToFront, CancellationTokenSource cs = null) + { + return OnGetToolOutputProgressMonitor (bringToFront, cs); + } + + public ProgressMonitor GetLoadProgressMonitor (bool lockGui) + { + return OnGetLoadProgressMonitor (lockGui); + } + + public ProgressMonitor GetProjectLoadProgressMonitor (bool lockGui) + { + return OnGetProjectLoadProgressMonitor (lockGui); + } + + public ProgressMonitor GetSaveProgressMonitor (bool lockGui) + { + return OnGetSaveProgressMonitor (lockGui); + } + + public OperationConsole CreateConsole (bool closeOnDispose, CancellationToken cancellationToken) + { + return OnCreateConsole (closeOnDispose, cancellationToken); + } + + public ProgressMonitor GetStatusProgressMonitor (string title, IconId icon, bool showErrorDialogs, bool showTaskTitle, bool lockGui, Pad statusSourcePad, bool showCancelButton) + { + return OnGetStatusProgressMonitor (title, icon, showErrorDialogs, showTaskTitle, lockGui, statusSourcePad, showCancelButton); + } + + public ProgressMonitor GetStatusProgressMonitor (string title, IconId icon, bool showErrorDialogs, bool showTaskTitle = true, bool lockGui = false, Pad statusSourcePad = null) + { + return GetStatusProgressMonitor (title, icon, showErrorDialogs, showTaskTitle, lockGui, statusSourcePad, showCancelButton: false); + } + + public ProgressMonitor GetBackgroundProgressMonitor (string title, IconId icon) + { + return OnGetBackgroundProgressMonitor (title, icon); + } + + public OutputProgressMonitor GetOutputProgressMonitor (string title, IconId icon, bool bringToFront, bool allowMonitorReuse, bool visible = true) + { + return GetOutputProgressMonitor (null, title, icon, bringToFront, allowMonitorReuse, visible); + } + + public OutputProgressMonitor GetOutputProgressMonitor (string id, string title, IconId icon, bool bringToFront, bool allowMonitorReuse, bool visible = true) + { + return GetOutputProgressMonitor (id, title, icon, bringToFront, allowMonitorReuse, null, visible); + } + + public OutputProgressMonitor GetOutputProgressMonitor (string id, string title, IconId icon, bool bringToFront, bool allowMonitorReuse, string titleSuffix, bool visible = true) + { + return OnGetOutputProgressMonitor (id, title, icon, bringToFront, allowMonitorReuse, titleSuffix, visible); + } + + public SearchProgressMonitor GetSearchProgressMonitor (bool bringToFront, bool focusPad = false, CancellationTokenSource cancellationTokenSource = null) + { + return OnGetSearchProgressMonitor (bringToFront, focusPad, cancellationTokenSource); + } + + public OperationConsoleFactory ConsoleFactory { + get { return OnGetConsoleFactory (); } + } + + protected abstract OperationConsoleFactory OnGetConsoleFactory (); + + protected abstract ProgressMonitor OnGetBuildProgressMonitor (); + + protected abstract ProgressMonitor OnGetCleanProgressMonitor (); + + protected abstract ProgressMonitor OnGetRebuildProgressMonitor (); + + protected abstract OutputProgressMonitor OnGetRunProgressMonitor (string titleSuffix); + + protected abstract OutputProgressMonitor OnGetToolOutputProgressMonitor (bool bringToFront, CancellationTokenSource cs); + + protected abstract ProgressMonitor OnGetLoadProgressMonitor (bool lockGui); + + protected abstract ProgressMonitor OnGetProjectLoadProgressMonitor (bool lockGui); + + protected abstract ProgressMonitor OnGetSaveProgressMonitor (bool lockGui); + + protected abstract OperationConsole OnCreateConsole (bool closeOnDispose, CancellationToken cancellationToken); + + protected abstract ProgressMonitor OnGetStatusProgressMonitor (string title, IconId icon, bool showErrorDialogs, bool showTaskTitle, bool lockGui, Pad statusSourcePad, bool showCancelButton); + + protected abstract ProgressMonitor OnGetBackgroundProgressMonitor (string title, IconId icon); + + protected abstract OutputProgressMonitor OnGetOutputProgressMonitor (string id, string title, IconId icon, bool bringToFront, bool allowMonitorReuse, string titleSuffix, bool visible); + + protected abstract SearchProgressMonitor OnGetSearchProgressMonitor (bool bringToFront, bool focusPad, CancellationTokenSource cancellationTokenSource); + } +} diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/ProgressMonitors.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/ProgressMonitors.cs index ea0811283e..7c18b46f77 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/ProgressMonitors.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/ProgressMonitors.cs @@ -40,126 +40,119 @@ using MonoDevelop.Ide.FindInFiles; using MonoDevelop.Components.Docking; using System.Threading; using MonoDevelop.Ide.Gui.Components; +using System.Threading.Tasks; namespace MonoDevelop.Ide.Gui { - public class ProgressMonitorManager : GuiSyncObject + public class IdeProgressMonitorManager : ProgressMonitorManager { List searchMonitors = new List (); List outputMonitors = new List (); - + /******************************/ - internal void Initialize () + protected override Task OnInitialize (ServiceProvider serviceProvider) { + return Task.CompletedTask; } - - public ProgressMonitor GetBuildProgressMonitor () + + protected override ProgressMonitor OnGetBuildProgressMonitor () { return GetBuildProgressMonitor (GettextCatalog.GetString ("Building...")); } - - public ProgressMonitor GetCleanProgressMonitor () + + protected override ProgressMonitor OnGetCleanProgressMonitor () { return GetBuildProgressMonitor (GettextCatalog.GetString ("Cleaning...")); } - - public ProgressMonitor GetRebuildProgressMonitor () + + protected override ProgressMonitor OnGetRebuildProgressMonitor () { return GetBuildProgressMonitor (GettextCatalog.GetString ("Rebuilding...")); } - private ProgressMonitor GetBuildProgressMonitor (string statusText) + ProgressMonitor GetBuildProgressMonitor (string statusText) { - Pad pad = IdeApp.Workbench.GetPad (); - ErrorListPad errorPad = (ErrorListPad) pad.Content; - AggregatedProgressMonitor mon = new AggregatedProgressMonitor (errorPad.GetBuildProgressMonitor ()); - mon.AddFollowerMonitor (GetStatusProgressMonitor (statusText, Stock.StatusBuild, false, true, false, pad, true)); - return mon; + return Runtime.RunInMainThread (() => { + Pad pad = IdeApp.Workbench.GetPad (); + ErrorListPad errorPad = (ErrorListPad)pad.Content; + AggregatedProgressMonitor mon = new AggregatedProgressMonitor (errorPad.GetBuildProgressMonitor ()); + mon.AddFollowerMonitor (GetStatusProgressMonitor (statusText, Stock.StatusBuild, false, true, false, pad, true)); + return mon; + }).Result; } - public OutputProgressMonitor GetRunProgressMonitor () - { - return GetRunProgressMonitor (null); - } - - public OutputProgressMonitor GetRunProgressMonitor (string titleSuffix) + protected override OutputProgressMonitor OnGetRunProgressMonitor (string titleSuffix) { return GetOutputProgressMonitor ("MonoDevelop.Ide.ApplicationOutput", GettextCatalog.GetString ("Application Output"), Stock.PadExecute, false, true, titleSuffix); } - - public OutputProgressMonitor GetToolOutputProgressMonitor (bool bringToFront, CancellationTokenSource cs = null) + + protected override OutputProgressMonitor OnGetToolOutputProgressMonitor (bool bringToFront, CancellationTokenSource cs = null) { return GetOutputProgressMonitor ("MonoDevelop.Ide.ToolOutput", GettextCatalog.GetString ("Tool Output"), Stock.PadExecute, bringToFront, true); } - - public ProgressMonitor GetLoadProgressMonitor (bool lockGui) + + protected override ProgressMonitor OnGetLoadProgressMonitor (bool lockGui) { return GetStatusProgressMonitor (GettextCatalog.GetString ("Loading..."), Stock.StatusSolutionOperation, true, false, lockGui); } - - public ProgressMonitor GetProjectLoadProgressMonitor (bool lockGui) + + protected override ProgressMonitor OnGetProjectLoadProgressMonitor (bool lockGui) { - return new GtkProjectLoadProgressMonitor (GetLoadProgressMonitor (lockGui)); + return Runtime.RunInMainThread (() => { + return new GtkProjectLoadProgressMonitor (GetLoadProgressMonitor (lockGui)); + }).Result; } - - public ProgressMonitor GetSaveProgressMonitor (bool lockGui) + + protected override ProgressMonitor OnGetSaveProgressMonitor (bool lockGui) { return GetStatusProgressMonitor (GettextCatalog.GetString ("Saving..."), Stock.StatusSolutionOperation, true, false, lockGui); } - - public OperationConsole CreateConsole (bool closeOnDispose, CancellationToken cancellationToken) + + protected override OperationConsole OnCreateConsole (bool closeOnDispose, CancellationToken cancellationToken) { return ((OutputProgressMonitor)GetOutputProgressMonitor ("MonoDevelop.Ide.ApplicationOutput", GettextCatalog.GetString ("Application Output"), Stock.MessageLog, false, true)).Console; } - CustomConsoleFactory customConsoleFactory = new CustomConsoleFactory (); - public OperationConsoleFactory ConsoleFactory { - get { return customConsoleFactory; } - } - - class CustomConsoleFactory: OperationConsoleFactory + protected override ProgressMonitor OnGetStatusProgressMonitor (string title, IconId icon, bool showErrorDialogs, bool showTaskTitle, bool lockGui, Pad statusSourcePad, bool showCancelButton) { - protected override OperationConsole OnCreateConsole (CreateConsoleOptions options) - { - return ((OutputProgressMonitor)IdeApp.Workbench.ProgressMonitors.GetOutputProgressMonitor ("MonoDevelop.Ide.ApplicationOutput", GettextCatalog.GetString ("Application Output"), Stock.MessageLog, options.BringToFront, true, titleSuffix:options.Title)).Console; - } + return Runtime.RunInMainThread (() => { + return new StatusProgressMonitor (title, icon, showErrorDialogs, showTaskTitle, lockGui, statusSourcePad, showCancelButton); + }).Result; } - /******************************/ - public ProgressMonitor GetStatusProgressMonitor (string title, IconId icon, bool showErrorDialogs, bool showTaskTitle, bool lockGui, Pad statusSourcePad, bool showCancelButton) - { - return new StatusProgressMonitor (title, icon, showErrorDialogs, showTaskTitle, lockGui, statusSourcePad, showCancelButton); - } - - public ProgressMonitor GetStatusProgressMonitor (string title, IconId icon, bool showErrorDialogs, bool showTaskTitle = true, bool lockGui = false, Pad statusSourcePad = null) - { - return GetStatusProgressMonitor (title, icon, showErrorDialogs, showTaskTitle, lockGui, statusSourcePad, showCancelButton: false); - } - - public ProgressMonitor GetBackgroundProgressMonitor (string title, IconId icon) + protected override ProgressMonitor OnGetBackgroundProgressMonitor (string title, IconId icon) { - return new BackgroundProgressMonitor (title, icon); + return Runtime.RunInMainThread (() => { + return new BackgroundProgressMonitor (title, icon); + }).Result; } - public OutputProgressMonitor GetOutputProgressMonitor (string title, IconId icon, bool bringToFront, bool allowMonitorReuse, bool visible = true) + protected override OutputProgressMonitor OnGetOutputProgressMonitor (string id, string title, IconId icon, bool bringToFront, bool allowMonitorReuse, string titleSuffix, bool visible) { - return GetOutputProgressMonitor (null, title, icon, bringToFront, allowMonitorReuse, visible); + return Runtime.RunInMainThread (() => { + if (!string.IsNullOrEmpty (titleSuffix)) { + title += " - " + titleSuffix; + } + Pad pad = CreateMonitorPad (id, title, icon, bringToFront, allowMonitorReuse, true); + pad.Visible = visible; + return ((DefaultMonitorPad)pad.Content).BeginProgress (title); + }).Result; } - public OutputProgressMonitor GetOutputProgressMonitor (string id, string title, IconId icon, bool bringToFront, bool allowMonitorReuse, bool visible = true) + CustomConsoleFactory customConsoleFactory = new CustomConsoleFactory (); + + protected override OperationConsoleFactory OnGetConsoleFactory () { - return GetOutputProgressMonitor (id, title, icon, bringToFront, allowMonitorReuse, null, visible); + return customConsoleFactory; } - - public OutputProgressMonitor GetOutputProgressMonitor (string id, string title, IconId icon, bool bringToFront, bool allowMonitorReuse, string titleSuffix, bool visible = true) + + class CustomConsoleFactory : OperationConsoleFactory { - if (!string.IsNullOrEmpty (titleSuffix)) { - title += " - " + titleSuffix; + protected override OperationConsole OnCreateConsole (CreateConsoleOptions options) + { + return ((OutputProgressMonitor)IdeApp.Workbench.ProgressMonitors.GetOutputProgressMonitor ("MonoDevelop.Ide.ApplicationOutput", GettextCatalog.GetString ("Application Output"), Stock.MessageLog, options.BringToFront, true, titleSuffix: options.Title)).Console; } - Pad pad = CreateMonitorPad (id, title, icon, bringToFront, allowMonitorReuse, true); - pad.Visible = visible; - return ((DefaultMonitorPad) pad.Content).BeginProgress (title); } /// @@ -186,6 +179,8 @@ namespace MonoDevelop.Ide.Gui internal Pad CreateMonitorPad (string id, string title, string icon, bool bringToFront, bool allowMonitorReuse, bool show) { + Runtime.AssertMainThread (); + Pad pad = null; if (icon == null) icon = Stock.OutputIcon; @@ -280,8 +275,11 @@ namespace MonoDevelop.Ide.Gui pad.Destroy (); } - public SearchProgressMonitor GetSearchProgressMonitor (bool bringToFront, bool focusPad = false, CancellationTokenSource cancellationTokenSource = null) + protected override SearchProgressMonitor OnGetSearchProgressMonitor (bool bringToFront, bool focusPad, CancellationTokenSource cancellationTokenSource) { + if (!Runtime.IsMainThread) + return Runtime.RunInMainThread (() => GetSearchProgressMonitor (bringToFront, focusPad, cancellationTokenSource)).Result; + Pad pad = null; string title = GettextCatalog.GetString ("Search Results"); diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/StartupInfo.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/StartupInfo.cs deleted file mode 100644 index 40b6be2273..0000000000 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/StartupInfo.cs +++ /dev/null @@ -1,115 +0,0 @@ -// -// StartupInfo.cs: -// -// Authors: -// Christian Hergert -// Todd Berman -// John Luke -// -// Copyright (C) 2005, Christian Hergert -// -// 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 System.IO; -using System.Collections.Generic; -using System.Text.RegularExpressions; -using System.Linq; - -namespace MonoDevelop.Ide.Gui -{ - internal class StartupInfo - { - List requestedFileList = new List (); - List parameterList = new List (); - - public IList ParameterList { - get { return parameterList; } - } - - public IEnumerable RequestedFileList { - get { return requestedFileList; } - } - - public bool HasFiles { - get { return requestedFileList.Count > 0; } - } - - public bool HasSolutionFile { - get { - return requestedFileList.Any (f => File.Exists (f.FileName) && (Services.ProjectService.IsWorkspaceItemFile (f.FileName) || Services.ProjectService.IsSolutionItemFile (f.FileName))); - } - } - - internal bool Restarted { get; set; } - - /// - /// Set to true if a project was opened on startup. - /// - internal bool OpenedRecentProject { get; set; } - - /// - /// Set to true if files were opened on startup. - /// - internal bool OpenedFiles { get; set; } - - /// - /// Matches a filename string with optional line and column - /// (/foo/bar/blah.cs;22;31) - /// - public static readonly Regex FileExpression = new Regex (@"^(?[^;]+)(;(?\d+))?(;(?\d+))?$", RegexOptions.Compiled); - - public StartupInfo (IEnumerable args) - { - foreach (string arg in args) { - string a = arg; - Match fileMatch = FileExpression.Match (a); - - // this does not yet work with relative paths - if (a[0] == '~') { - var sf = MonoDevelop.Core.Platform.IsWindows ? Environment.SpecialFolder.UserProfile : Environment.SpecialFolder.Personal; - a = Path.Combine (Environment.GetFolderPath (sf), a.Substring (1)); - } - - if (fileMatch != null && fileMatch.Success) { - string filename = fileMatch.Groups["filename"].Value; - if (File.Exists (filename)) { - int line = 1, column = 1; - filename = Path.GetFullPath (filename); - if (fileMatch.Groups["line"].Success) - int.TryParse (fileMatch.Groups["line"].Value, out line); - if (fileMatch.Groups["column"].Success) - int.TryParse (fileMatch.Groups["column"].Value, out column); - var file = new FileOpenInformation (filename, null, line, column, OpenDocumentOptions.Default); - requestedFileList.Add (file); - } - } else if (a[0] == '-' || a[0] == '/') { - int markerLength = 1; - - if (a.Length >= 2 && a[0] == '-' && a[1] == '-') { - markerLength = 2; - } - - parameterList.Add(a.Substring (markerLength)); - } - } - } - } -} diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Navigation/NavigationHistoryService.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Navigation/NavigationHistoryService.cs index 1189a325a3..91ad434dac 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Navigation/NavigationHistoryService.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Navigation/NavigationHistoryService.cs @@ -1,120 +1,150 @@ -// -// NavigationHistoryService.cs -// +// +// NavigationHistoryManager.cs +// // Author: -// Michael Hutchinson -// Lluis Sanchez Gual -// -// Copyright (C) 2008 Novell, Inc (http://www.novell.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. +// Lluis Sanchez // - +// Copyright (c) 2019 Microsoft +// +// 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 System.Collections.Generic; -using System.Linq; - -using MonoDevelop.Ide.Gui.Content; +using System.Threading.Tasks; +using MonoDevelop.Core; using MonoDevelop.Ide.Gui; -using MonoDevelop.Projects; +using MonoDevelop.Ide.Gui.Content; +using MonoDevelop.Ide.Gui.Documents; using MonoDevelop.Ide.TextEditing; +using MonoDevelop.Projects; namespace MonoDevelop.Ide.Navigation { - public static class NavigationHistoryService + [DefaultServiceImplementation] + public class NavigationHistoryService: IService { - static HistoryList history = new HistoryList (); - static List> closedHistory = new List> (); + HistoryList history = new HistoryList (); + List> closedHistory = new List> (); + DocumentManager documentManager; + RootWorkspace workspace; + TextEditorService textEditorService; //used to prevent re-logging the current point during a switch - static bool switching; - + bool switching; + //whethor the current node is transient. Prevents excession automatic logging when switching rapidly between //documents - static bool currentIsTransient; - - //the amount of time until a "transient" current node bevomes "permanent" - static uint TRANSIENT_TIMEOUT = 10000; //ms - - static Document currentDoc; - - static NavigationHistoryService () + bool currentIsTransient; + + //the amount of time until a "transient" current node becomes "permanent" + uint TRANSIENT_TIMEOUT = 10000; //ms + + Document currentDoc; + + Task IService.Dispose () { - IdeApp.Workspace.LastWorkspaceItemClosed += delegate { - history.Clear (); - OnHistoryChanged (); - closedHistory.Clear (); - OnClosedHistoryChanged (); - }; - - IdeApp.Workbench.DocumentOpened += delegate (object sender, DocumentEventArgs e) { - closedHistory.RemoveAll(np => (np.Item1 as DocumentNavigationPoint)?.FileName == e.Document.FileName); - OnClosedHistoryChanged (); - }; - - IdeApp.Workbench.DocumentClosing += delegate(object sender, DocumentEventArgs e) { - NavigationPoint point = GetNavPointForDoc (e.Document, true) as DocumentNavigationPoint; - if (point == null) - return; - - closedHistory.Add (new Tuple (point, IdeApp.Workbench.Documents.IndexOf (e.Document))); - OnClosedHistoryChanged (); - }; + workspace.LastWorkspaceItemClosed -= Workspace_LastWorkspaceItemClosed; + workspace.FileRenamedInProject -= FileRenamed; + + documentManager.DocumentOpened -= DocumentManager_DocumentOpened; + documentManager.DocumentClosing -= DocumentManager_DocumentClosing; + documentManager.ActiveDocumentChanged -= ActiveDocChanged; + + textEditorService.LineCountChanged -= LineCountChanged; + textEditorService.LineCountChangesCommitted -= CommitCountChanges; + textEditorService.LineCountChangesReset -= ResetCountChanges; + return Task.CompletedTask; + } + + async Task IService.Initialize (ServiceProvider serviceProvider) + { + workspace = await serviceProvider.GetService (); + workspace.LastWorkspaceItemClosed += Workspace_LastWorkspaceItemClosed; + workspace.FileRenamedInProject += FileRenamed; + + documentManager = await serviceProvider.GetService (); + documentManager.DocumentOpened += DocumentManager_DocumentOpened; + documentManager.DocumentClosing += DocumentManager_DocumentClosing; + documentManager.ActiveDocumentChanged += ActiveDocChanged; //keep nav points up to date - TextEditorService.LineCountChanged += LineCountChanged; - TextEditorService.LineCountChangesCommitted += CommitCountChanges; - TextEditorService.LineCountChangesReset += ResetCountChanges; - IdeApp.Workspace.FileRenamedInProject += FileRenamed; - - IdeApp.Workbench.ActiveDocumentChanged += ActiveDocChanged; - } - - public static void LogActiveDocument () + textEditorService = await serviceProvider.GetService (); + textEditorService.LineCountChanged += LineCountChanged; + textEditorService.LineCountChangesCommitted += CommitCountChanges; + textEditorService.LineCountChangesReset += ResetCountChanges; + } + + void Workspace_LastWorkspaceItemClosed (object sender, EventArgs e) + { + Reset (); + } + + void DocumentManager_DocumentOpened (object sender, DocumentEventArgs e) + { + closedHistory.RemoveAll (np => (np.Item1 as DocumentNavigationPoint)?.FileName == e.Document.FileName); + OnClosedHistoryChanged (); + } + + Task DocumentManager_DocumentClosing (object sender, DocumentCloseEventArgs e) + { + NavigationPoint point = GetNavPointForDoc (e.Document, true) as DocumentNavigationPoint; + if (point == null) + return Task.CompletedTask; + + closedHistory.Add (new Tuple (point, documentManager.Documents.IndexOf (e.Document))); + OnClosedHistoryChanged (); + return Task.CompletedTask; + } + + public void LogActiveDocument () { LogActiveDocument (false); } - - public static void LogActiveDocument (bool transient) + + public void Reset () + { + history.Clear (); + OnHistoryChanged (); + closedHistory.Clear (); + OnClosedHistoryChanged (); + } + + public void LogActiveDocument (bool transient) { if (switching) return; - - NavigationPoint point = GetNavPointForActiveDoc (false); + + var point = GetNavPointForActiveDoc (false); if (point == null) return; - - NavigationHistoryItem item = new NavigationHistoryItem (point); - + + var item = new NavigationHistoryItem (point); + //if the current node's transient but has been around for a while, consider making it permanent if (Current == null || - (currentIsTransient && DateTime.Now.Subtract (Current.Created).TotalMilliseconds > TRANSIENT_TIMEOUT)) - { + (currentIsTransient && DateTime.Now.Subtract (Current.Created).TotalMilliseconds > TRANSIENT_TIMEOUT)) { currentIsTransient = false; } - + //if the current point's transient, always replace it - if (currentIsTransient) - { + if (currentIsTransient) { //collapse down possible extra point in history - NavigationHistoryItem backOne = history[-1]; + var backOne = history [-1]; if (backOne != null && point.ShouldReplace (backOne.NavigationPoint)) { // The new node is the same as the last permanent, so we can discard it history.RemoveCurrent (); @@ -126,71 +156,68 @@ namespace MonoDevelop.Ide.Navigation } } //if the new point wants to replace the old one, let it - else if (Current != null && !transient && point.ShouldReplace (Current.NavigationPoint)) - { + else if (Current != null && !transient && point.ShouldReplace (Current.NavigationPoint)) { history.ReplaceCurrent (item); - + //but in this case, the point should not be transient -- unless the old point was, //but that's handled earlier currentIsTransient = false; } //final choice: append the the node //BUT only if the existing current node would not want to replace the new node - else if (Current == null || !Current.NavigationPoint.ShouldReplace (point)) - { + else if (Current == null || !Current.NavigationPoint.ShouldReplace (point)) { history.AddPoint (item); currentIsTransient = transient; - } - else + } else item.Dispose (); - + OnHistoryChanged (); } - - static NavigationPoint GetNavPointForActiveDoc (bool forClosedHistory) + + NavigationPoint GetNavPointForActiveDoc (bool forClosedHistory) { - return GetNavPointForDoc (IdeApp.Workbench.ActiveDocument, forClosedHistory); + return GetNavPointForDoc (documentManager.ActiveDocument, forClosedHistory); } - - static NavigationPoint GetNavPointForDoc (Document doc, bool forClosedHistory) + + NavigationPoint GetNavPointForDoc (Document doc, bool forClosedHistory) { if (doc == null) return null; - + NavigationPoint point = null; - + INavigable navigable = doc.GetContent (); if (navigable != null) { point = navigable.BuildNavigationPoint (); if (point != null) return point; } - + var editBuf = doc.Editor; if (editBuf != null) { - if (forClosedHistory) { - point = new TextFileNavigationPoint (doc.FileName, editBuf.CaretLine, editBuf.CaretColumn); - } else { - point = new TextFileNavigationPoint (doc, editBuf); + if (forClosedHistory) { + point = new TextFileNavigationPoint (doc.FileName, editBuf.CaretLine, editBuf.CaretColumn); + } else { + point = new TextFileNavigationPoint (doc, editBuf); } if (point != null) return point; } - + return new DocumentNavigationPoint (doc); } - + #region Navigation - - public static bool CanMoveForward { + + public bool CanMoveForward { get { return history.CanMoveForward; } } - - public static bool CanMoveBack { + + public bool CanMoveBack { get { return history.CanMoveBack; } } - - public static void MoveForward () + + public void MoveForward () { LogActiveDocument (); if (history.CanMoveForward) { @@ -199,8 +226,8 @@ namespace MonoDevelop.Ide.Navigation OnHistoryChanged (); } } - - public static void MoveBack () + + public void MoveBack () { // Log current point before moving back, to make sure a MoveForward will return to the same position LogActiveDocument (); @@ -210,15 +237,15 @@ namespace MonoDevelop.Ide.Navigation OnHistoryChanged (); } } - - public static void MoveTo (NavigationHistoryItem item) + + public void MoveTo (NavigationHistoryItem item) { history.MoveTo (item); SwitchToCurrent (); OnHistoryChanged (); } - - static void SwitchToCurrent () + + void SwitchToCurrent () { currentIsTransient = false; switching = true; @@ -226,19 +253,20 @@ namespace MonoDevelop.Ide.Navigation history.Current.Show (); switching = false; } - + #endregion #region Closed Document List - public static bool HasClosedDocuments { + public bool HasClosedDocuments { get { return closedHistory.Count != 0; } } - public static async void OpenLastClosedDocument () { + public async void OpenLastClosedDocument () + { if (HasClosedDocuments) { int closedHistoryIndex = closedHistory.Count - 1; - var tuple = closedHistory[closedHistoryIndex]; + var tuple = closedHistory [closedHistoryIndex]; closedHistory.RemoveAt (closedHistoryIndex); OnClosedHistoryChanged (); var doc = await tuple.Item1.ShowDocument (); @@ -248,120 +276,120 @@ namespace MonoDevelop.Ide.Navigation } #endregion - - public static IList GetNavigationList (int desiredLength) + + public IList GetNavigationList (int desiredLength) { return history.GetList (desiredLength); } - - public static IList GetNavigationList (int desiredLength, out int currentIndex) + + public IList GetNavigationList (int desiredLength, out int currentIndex) { return history.GetList (desiredLength, out currentIndex); } - - public static NavigationHistoryItem Current { get { return history.Current; } } - - public static bool IsCurrent (NavigationHistoryItem point) + + public NavigationHistoryItem Current { get { return history.Current; } } + + public bool IsCurrent (NavigationHistoryItem point) { return history.IsCurrent (point); } - - public static void Clear () + + public void Clear () { history.Clear (); LogActiveDocument (); } - - public static event EventHandler HistoryChanged; - public static event EventHandler ClosedHistoryChanged; - - static void OnHistoryChanged () + + public event EventHandler HistoryChanged; + public event EventHandler ClosedHistoryChanged; + + void OnHistoryChanged () { HistoryChanged?.Invoke (null, EventArgs.Empty); } - static void OnClosedHistoryChanged () + void OnClosedHistoryChanged () { ClosedHistoryChanged?.Invoke (null, EventArgs.Empty); } - + #region Handling active doc change events - - static void ActiveDocChanged (object sender, EventArgs args) + + void ActiveDocChanged (object sender, EventArgs args) { LogActiveDocument (true); - AttachToDoc (IdeApp.Workbench.ActiveDocument); + AttachToDoc (documentManager.ActiveDocument); } - - static void AttachToDoc (Document document) + + void AttachToDoc (Document document) { DetachFromCurrentDoc (); if (document == null) return; - + currentDoc = document; - + currentDoc.Closed += HandleCurrentDocClosed; - + if (currentDoc.Editor != null) { currentDoc.Editor.TextChanged += BufferTextChanged; currentDoc.Editor.CaretPositionChanged += BufferCaretPositionChanged; } } - static void HandleCurrentDocClosed (object sender, EventArgs e) + void HandleCurrentDocClosed (object sender, EventArgs e) { DetachFromCurrentDoc (); } - - static void DetachFromCurrentDoc () + + void DetachFromCurrentDoc () { if (currentDoc == null) return; - - currentDoc.Closed -= HandleCurrentDocClosed; + + currentDoc.Closed -= HandleCurrentDocClosed; if (currentDoc.Editor != null) { currentDoc.Editor.TextChanged -= BufferTextChanged; currentDoc.Editor.CaretPositionChanged -= BufferCaretPositionChanged; } currentDoc = null; } - - static void BufferCaretPositionChanged (object sender, EventArgs args) + + void BufferCaretPositionChanged (object sender, EventArgs args) { LogActiveDocument (true); } - - static void BufferTextChanged (object sender, EventArgs args) + + void BufferTextChanged (object sender, EventArgs args) { LogActiveDocument (); } - + #endregion - + #region Text file line number and snippet updating - - static void LineCountChanged (object sender, LineCountEventArgs args) + + void LineCountChanged (object sender, LineCountEventArgs args) { -// MonoDevelop.Projects.Text.ITextFile textFile = (MonoDevelop.Projects.Text.ITextFile) sender; + // MonoDevelop.Projects.Text.ITextFile textFile = (MonoDevelop.Projects.Text.ITextFile) sender; } - - static void CommitCountChanges (object sender, TextFileEventArgs args) + + void CommitCountChanges (object sender, TextFileEventArgs args) { -// MonoDevelop.Projects.Text.ITextFile textFile = (MonoDevelop.Projects.Text.ITextFile) sender; + // MonoDevelop.Projects.Text.ITextFile textFile = (MonoDevelop.Projects.Text.ITextFile) sender; } - - static void ResetCountChanges (object sender, TextFileEventArgs args) + + void ResetCountChanges (object sender, TextFileEventArgs args) { -// MonoDevelop.Projects.Text.ITextFile textFile = (MonoDevelop.Projects.Text.ITextFile) sender; + // MonoDevelop.Projects.Text.ITextFile textFile = (MonoDevelop.Projects.Text.ITextFile) sender; } - - static void FileRenamed (object sender, ProjectFileRenamedEventArgs e) + + void FileRenamed (object sender, ProjectFileRenamedEventArgs e) { bool historyChanged = false, closedHistoryChanged = false; - foreach (NavigationHistoryItem point in history) { - foreach (ProjectFileRenamedEventInfo args in e) { + foreach (var point in history) { + foreach (var args in e) { var dp = point.NavigationPoint as DocumentNavigationPoint; historyChanged |= (dp?.HandleRenameEvent (args.OldName, args.NewName)).GetValueOrDefault (); } @@ -371,7 +399,7 @@ namespace MonoDevelop.Ide.Navigation OnHistoryChanged (); foreach (var point in closedHistory) { - foreach (ProjectFileRenamedEventInfo args in e) { + foreach (var args in e) { var dp = point.Item1 as DocumentNavigationPoint; closedHistoryChanged |= (dp?.HandleRenameEvent (args.OldName, args.NewName)).GetValueOrDefault (); } @@ -380,7 +408,7 @@ namespace MonoDevelop.Ide.Navigation if (closedHistoryChanged) OnClosedHistoryChanged (); } - + #endregion } } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Tasks/CommentTasksProvider.Legacy.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Tasks/CommentTasksProvider.Legacy.cs index b9bc822f3d..1c126a7337 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Tasks/CommentTasksProvider.Legacy.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Tasks/CommentTasksProvider.Legacy.cs @@ -29,23 +29,32 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using MonoDevelop.Core; +using MonoDevelop.Ide.Editor; using MonoDevelop.Ide.Gui; using MonoDevelop.Projects; +using MonoDevelop.Ide.Gui.Documents; namespace MonoDevelop.Ide.Tasks { - static partial class CommentTasksProvider + partial class CommentTasksProvider { internal static class Legacy { + static Dictionary projectTags = new Dictionary (); + static CancellationTokenSource src = new CancellationTokenSource (); + internal static void Initialize () { - IdeApp.Workspace.LastWorkspaceItemClosed += LastWorkspaceItemClosed; - IdeApp.Workspace.WorkspaceItemUnloaded += OnWorkspaceItemUnloaded; - IdeApp.Workbench.DocumentOpened += WorkbenchDocumentOpened; - IdeApp.Workbench.DocumentClosed += WorkbenchDocumentClosed; + Runtime.ServiceProvider.WhenServiceInitialized (s => { + s.LastWorkspaceItemClosed += LastWorkspaceItemClosed; + s.WorkspaceItemUnloaded += OnWorkspaceItemUnloaded; + }); } + public static Dictionary ProjectTags => projectTags; + + public static CancellationToken CancellationToken => src.Token; + static void LastWorkspaceItemClosed (object sender, EventArgs e) { projectTags.Clear (); @@ -59,8 +68,6 @@ namespace MonoDevelop.Ide.Tasks } } - static Dictionary projectTags = new Dictionary (); - static CancellationTokenSource src = new CancellationTokenSource (); static void UpdateCommentTagsForProject (Project project, CancellationToken token) { if (token.IsCancellationRequested) @@ -72,7 +79,7 @@ namespace MonoDevelop.Ide.Tasks } var files = project.Files.Where (x => { - var mt = DesktopService.GetMimeTypeForUri (x.FilePath); + var mt = IdeServices.DesktopService.GetMimeTypeForUri (x.FilePath); // FIXME: Handle all language services. // Discard files with known IToDoCommentService implementations @@ -118,41 +125,60 @@ namespace MonoDevelop.Ide.Tasks } }); } + } + } - static void WorkbenchDocumentClosed (object sender, DocumentEventArgs e) - { - e.Document.DocumentParsed -= HandleDocumentParsed; - } + [ExportDocumentControllerExtension (MimeType = "*")] + class LegacyDocumentExtension: DocumentControllerExtension + { + DocumentContext context; - static void WorkbenchDocumentOpened (object sender, DocumentEventArgs e) - { - e.Document.DocumentParsed += HandleDocumentParsed; + public override async Task SupportsController (DocumentController controller) + { + if (!await base.SupportsController (controller) || !(controller is FileDocumentController)) + return false; + + if (controller is FileDocumentController file) { + // C# uses the roslyn-provided todo comments system. + //if (file.MimeType == "text/x-csharp") + // return false; } + var s = controller.GetContent () != null; + return s; + } - static void HandleDocumentParsed (object sender, EventArgs e) - { - var doc = (Document)sender; + public override Task Initialize (Properties status) + { + context = Controller.GetContent (); + context.DocumentParsed += Context_DocumentParsed; + return base.Initialize (status); + } - // C# uses the roslyn-provided todo comments system. - if (doc.Editor.MimeType == "text/x-csharp") - return; + public override void Dispose () + { + if (context != null) + context.DocumentParsed -= Context_DocumentParsed; + base.Dispose (); + } - var pd = doc.ParsedDocument; - var project = doc.Project; - if (pd == null || project == null) - return; - ProjectCommentTags tags; - if (!projectTags.TryGetValue (project, out tags)) - return; - var token = src.Token; - var file = doc.FileName; - Task.Run (async () => { - try { - tags.UpdateTags (project, file, await pd.GetTagCommentsAsync (token).ConfigureAwait (false)); - } catch (OperationCanceledException) { - } - }); - } + void Context_DocumentParsed (object sender, EventArgs e) + { + var pd = context.ParsedDocument; + var project = Controller.Owner as Project; + if (project == null || !(Controller is FileDocumentController fileController)) + return; + ProjectCommentTags tags; + if (!CommentTasksProvider.Legacy.ProjectTags.TryGetValue (project, out tags)) + return; + var token = CommentTasksProvider.Legacy.CancellationToken; + var file = fileController.FilePath; + Task.Run (async () => { + try { + tags.UpdateTags (project, file, await pd.GetTagCommentsAsync (token).ConfigureAwait (false)); + } catch (OperationCanceledException) { + } + }); } + } } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Tasks/CommentTasksProvider.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Tasks/CommentTasksProvider.cs index 7ebf74d055..6a3b3e5172 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Tasks/CommentTasksProvider.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Tasks/CommentTasksProvider.cs @@ -1,4 +1,4 @@ -// +// // CommentTasksProvider.cs // // Author: @@ -30,29 +30,31 @@ using System.Collections.Immutable; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.Editor.Implementation.TodoComments; +using MonoDevelop.Core; using MonoDevelop.Ide.TypeSystem; using MonoDevelop.Projects; using System.Linq; +using System.Threading.Tasks; +using MonoDevelop.Ide.Composition; namespace MonoDevelop.Ide.Tasks { - static partial class CommentTasksProvider + partial class CommentTasksProvider { - internal static void Initialize () - { - var todoListProvider = Composition.CompositionManager.GetExportedValue (); - todoListProvider.TodoListUpdated += OnTodoListUpdated; - } + TaskService taskService; - static CommentTasksProvider() + public static void Initialize () { - IdeApp.Initialized += (sender, args) => { - IdeApp.Workspace.SolutionLoaded += OnSolutionLoaded; - IdeApp.Workspace.WorkspaceItemClosed += OnWorkspaceItemClosed; - + Runtime.ServiceProvider.WhenServiceInitialized (compositionManager => { + var todoListProvider = compositionManager.GetExportedValue (); + todoListProvider.TodoListUpdated += OnTodoListUpdated; + }); + + Runtime.ServiceProvider.WhenServiceInitialized (workspace => { + workspace.SolutionLoaded += OnSolutionLoaded; + workspace.WorkspaceItemClosed += OnWorkspaceItemClosed; Legacy.Initialize (); - }; - + }); CommentTag.SpecialCommentTagsChanged += OnSpecialTagsChanged; } @@ -85,15 +87,15 @@ namespace MonoDevelop.Ide.Tasks return; if (triggerLoad == null || triggerLoad.Invoke (cachedUntilViewCreated.Count)) { - var changes = cachedUntilViewCreated.Values.Select (x => x.ToCommentTaskChange ()).Where (x => x != null).ToList (); - TaskService.InformCommentTasks (new CommentTasksChangedEventArgs (changes)); + var changes = cachedUntilViewCreated.Values.Select (x => ToCommentTaskChange (x)).Where (x => x != null).ToList (); + IdeServices.TaskService.InformCommentTasks (new CommentTasksChangedEventArgs (changes)); cachedUntilViewCreated = null; triggerLoad = null; } } } - public static CommentTaskChange ToCommentTaskChange (this TodoItemsUpdatedArgs args) + public static CommentTaskChange ToCommentTaskChange (TodoItemsUpdatedArgs args) { if (!TryGetDocument (args, out var doc, out var project)) return null; @@ -149,19 +151,19 @@ namespace MonoDevelop.Ide.Tasks var change = ToCommentTaskChange (args); if (change != null) - TaskService.InformCommentTasks (new CommentTasksChangedEventArgs (new [] { change })); + IdeServices.TaskService.InformCommentTasks (new CommentTasksChangedEventArgs (new [] { change })); } static async void OnSolutionLoaded (object sender, SolutionEventArgs args) { - var ws = await TypeSystemService.GetWorkspaceAsync (args.Solution); + var ws = await IdeApp.TypeSystemService.GetWorkspaceAsync (args.Solution); UpdateWorkspaceOptions (ws); } static async void OnWorkspaceItemClosed (object sender, WorkspaceItemEventArgs args) { if (args.Item is MonoDevelop.Projects.Solution sol) { - var ws = await TypeSystemService.GetWorkspaceAsync (sol); + var ws = await IdeApp.TypeSystemService.GetWorkspaceAsync (sol); lock (lockObject) { if (cachedUntilViewCreated == null) @@ -180,7 +182,7 @@ namespace MonoDevelop.Ide.Tasks static void OnSpecialTagsChanged (object sender, EventArgs args) { - foreach (var ws in TypeSystemService.AllWorkspaces) + foreach (var ws in IdeApp.TypeSystemService.AllWorkspaces) UpdateWorkspaceOptions (ws); } } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Tasks/TaskService.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Tasks/TaskService.cs index 6f61d562fe..5ac4e99d7f 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Tasks/TaskService.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Tasks/TaskService.cs @@ -1,5 +1,5 @@ // -// TaskService.cs +// IdeServices.TaskService.cs // // Author: // Lluis Sanchez Gual @@ -27,51 +27,57 @@ using System; using System.IO; using System.Collections.Generic; -using System.Xml.Serialization; using MonoDevelop.Core; using MonoDevelop.Core.Serialization; using MonoDevelop.Projects; using MonoDevelop.Ide.Gui; +using System.Threading.Tasks; namespace MonoDevelop.Ide.Tasks { - public enum TaskSeverity + [DefaultServiceImplementation] + public class TaskService: Service { - Error, - Warning, - Information, - Comment - } - - public static class TaskService - { - static TaskStore errors = new TaskStore (); - static TaskStore userTasks = new TaskStore (); - - static bool errorBubblesVisible = true; - static bool warningBubblesVisible = true; + TaskStore errors = new TaskStore (); + TaskStore userTasks = new TaskStore (); - static TaskService () + bool errorBubblesVisible = true; + bool warningBubblesVisible = true; + + RootWorkspace rootWorkspace; + + protected override Task OnInitialize (ServiceProvider serviceProvider) { - if (IdeApp.Workspace != null) { - IdeApp.Workspace.WorkspaceItemLoaded += OnWorkspaceItemLoaded; - IdeApp.Workspace.WorkspaceItemUnloaded += OnWorkspaceItemUnloaded; + serviceProvider.WhenServiceInitialized (s => { + rootWorkspace = s; + rootWorkspace.WorkspaceItemLoaded += OnWorkspaceItemLoaded; + rootWorkspace.WorkspaceItemUnloaded += OnWorkspaceItemUnloaded; CommentTasksProvider.Legacy.Initialize (); - } + }); errors.ItemName = GettextCatalog.GetString ("Warning/Error"); userTasks.ItemName = GettextCatalog.GetString ("User Task"); + return Task.CompletedTask; } - - public static TaskStore Errors { + + protected override Task OnDispose () + { + if (rootWorkspace != null) { + rootWorkspace.WorkspaceItemLoaded -= OnWorkspaceItemLoaded; + rootWorkspace.WorkspaceItemUnloaded -= OnWorkspaceItemUnloaded; + } + return base.OnDispose (); + } + + public TaskStore Errors { get { return errors; } } - public static TaskStore UserTasks { + public TaskStore UserTasks { get { return userTasks; } } - public static bool ErrorBubblesVisible { + public bool ErrorBubblesVisible { get { return errorBubblesVisible; } set { if (errorBubblesVisible != value) { @@ -82,7 +88,7 @@ namespace MonoDevelop.Ide.Tasks } } - public static bool WarningBubblesVisible { + public bool WarningBubblesVisible { get { return warningBubblesVisible; } set { if (warningBubblesVisible != value) { @@ -93,9 +99,9 @@ namespace MonoDevelop.Ide.Tasks } } - public static event EventHandler BubblesVisibilityChanged; + public event EventHandler BubblesVisibilityChanged; - public static void ShowErrors () + public void ShowErrors () { Pad errorsPad = IdeApp.Workbench.GetPad (); if (errorsPad != null) { @@ -107,7 +113,7 @@ namespace MonoDevelop.Ide.Tasks /// /// Shows a description of the task in the status bar /// - public static void ShowStatus (TaskListEntry t) + public void ShowStatus (TaskListEntry t) { if (t == null) IdeApp.Workbench.StatusBar.ShowMessage (GettextCatalog.GetString ("No more errors or warnings")); @@ -119,7 +125,7 @@ namespace MonoDevelop.Ide.Tasks IdeApp.Workbench.StatusBar.ShowMessage (t.Description); } - static void OnWorkspaceItemLoaded (object sender, WorkspaceItemEventArgs e) + void OnWorkspaceItemLoaded (object sender, WorkspaceItemEventArgs e) { string fileToLoad = GetUserTasksFilename (e.Item); @@ -143,7 +149,7 @@ namespace MonoDevelop.Ide.Tasks } } - static void OnWorkspaceItemUnloaded (object sender, WorkspaceItemEventArgs e) + void OnWorkspaceItemUnloaded (object sender, WorkspaceItemEventArgs e) { // Save UserTasks to xml file SaveUserTasks (e.Item); @@ -154,13 +160,13 @@ namespace MonoDevelop.Ide.Tasks userTasks.RemoveItemTasks (e.Item, true); } - static FilePath GetUserTasksFilename (WorkspaceItem item) + FilePath GetUserTasksFilename (WorkspaceItem item) { FilePath combinePath = item.FileName.ParentDirectory; return combinePath.Combine (item.FileName.FileNameWithoutExtension + ".usertasks"); } - internal static void SaveUserTasks (WorkspaceObject item) + internal void SaveUserTasks (WorkspaceObject item) { string fileToSave = GetUserTasksFilename ((WorkspaceItem)item); try { @@ -178,16 +184,16 @@ namespace MonoDevelop.Ide.Tasks } - public static event EventHandler JumpedToTask; + public event EventHandler JumpedToTask; - internal static void InformJumpToTask (TaskListEntry task) + internal void InformJumpToTask (TaskListEntry task) { EventHandler handler = JumpedToTask; if (handler != null) handler (null, new TaskEventArgs (task)); } - internal static void InformCommentTasks (CommentTasksChangedEventArgs args) + internal void InformCommentTasks (CommentTasksChangedEventArgs args) { if (args.Changes.Count == 0) return; @@ -197,11 +203,11 @@ namespace MonoDevelop.Ide.Tasks handler (null, args); } - public static event EventHandler CommentTasksChanged; + public event EventHandler CommentTasksChanged; - public static event EventHandler TaskToggled; + public event EventHandler TaskToggled; - public static void FireTaskToggleEvent (object sender, TaskEventArgs e) + public void FireTaskToggleEvent (object sender, TaskEventArgs e) { var handler = TaskToggled; if (handler != null) diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Tasks/TaskSeverity.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Tasks/TaskSeverity.cs new file mode 100644 index 0000000000..b029de5edb --- /dev/null +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Tasks/TaskSeverity.cs @@ -0,0 +1,39 @@ +// +// IdeServices.TaskService.cs +// +// Author: +// Lluis Sanchez Gual +// +// Copyright (c) 2009 Novell, Inc (http://www.novell.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. + + + +namespace MonoDevelop.Ide.Tasks +{ + public enum TaskSeverity + { + Error, + Warning, + Information, + Comment + } +} + diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Tasks/TaskStore.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Tasks/TaskStore.cs index 35abbfcb97..5ec1c1d7a3 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Tasks/TaskStore.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Tasks/TaskStore.cs @@ -1,4 +1,4 @@ -// +// // TaskStore.cs // // Author: @@ -59,47 +59,52 @@ namespace MonoDevelop.Ide.Tasks List tasksAdded; List tasksRemoved; - + public TaskStore () { - if (IdeApp.Workspace != null) { - IdeApp.Workspace.FileRenamedInProject += ProjectFileRenamed; - IdeApp.Workspace.FileRemovedFromProject += ProjectFileRemoved; - } + IdeServices.Workspace.FileRenamedInProject += ProjectFileRenamed; + IdeServices.Workspace.FileRemovedFromProject += ProjectFileRemoved; - TextEditorService.LineCountChangesCommitted += delegate (object sender, TextFileEventArgs args) { - foreach (TaskListEntry task in GetFileTasks (args.TextFile.Name.FullPath)) + IdeServices.TextEditorService.LineCountChangesCommitted += TextEditorService_LineCountChangesCommitted; + IdeServices.TextEditorService.LineCountChangesReset += TextEditorService_LineCountChangesReset; + IdeServices.TextEditorService.LineCountChanged += TextEditorService_LineCountChanged; + } + + void TextEditorService_LineCountChangesCommitted (object sender, TextFileEventArgs args) + { + foreach (TaskListEntry task in GetFileTasks (args.TextFile.Name.FullPath)) + task.SavedLine = -1; + } + + void TextEditorService_LineCountChangesReset (object sender, TextFileEventArgs args) + { + Runtime.AssertMainThread (); + TaskListEntry [] ctasks = GetFileTasks (args.TextFile.Name.FullPath); + foreach (TaskListEntry task in ctasks) { + if (task.SavedLine != -1) { + task.Line = task.SavedLine; task.SavedLine = -1; - }; - - TextEditorService.LineCountChangesReset += delegate (object sender, TextFileEventArgs args) { - Runtime.AssertMainThread (); - TaskListEntry[] ctasks = GetFileTasks (args.TextFile.Name.FullPath); - foreach (TaskListEntry task in ctasks) { - if (task.SavedLine != -1) { - task.Line = task.SavedLine; - task.SavedLine = -1; - } } - NotifyTasksChanged (ctasks); - }; - - TextEditorService.LineCountChanged += delegate (object sender, LineCountEventArgs args) { - Runtime.AssertMainThread (); - if (args.TextFile == null || args.TextFile.Name.IsNullOrEmpty) - return; - TaskListEntry[] ctasks = GetFileTasks (args.TextFile.Name.FullPath); - foreach (TaskListEntry task in ctasks) { - if (task.Line > args.LineNumber || (task.Line == args.LineNumber && task.Column >= args.Column)) { - if (task.SavedLine == -1) - task.SavedLine = task.Line; - task.Line += args.LineCount; - } + } + NotifyTasksChanged (ctasks); + } + + void TextEditorService_LineCountChanged (object sender, LineCountEventArgs args) + { + Runtime.AssertMainThread (); + if (args.TextFile == null || args.TextFile.Name.IsNullOrEmpty) + return; + TaskListEntry [] ctasks = GetFileTasks (args.TextFile.Name.FullPath); + foreach (TaskListEntry task in ctasks) { + if (task.Line > args.LineNumber || (task.Line == args.LineNumber && task.Column >= args.Column)) { + if (task.SavedLine == -1) + task.SavedLine = task.Line; + task.Line += args.LineCount; } - NotifyTasksChanged (ctasks); - }; + } + NotifyTasksChanged (ctasks); } - + public void Add (TaskListEntry task) { Runtime.AssertMainThread (); @@ -396,7 +401,7 @@ namespace MonoDevelop.Ide.Tasks protected override async Task DoShow () { Document result = await base.DoShow (); - TaskService.InformJumpToTask (task); + IdeServices.TaskService.InformJumpToTask (task); return result; } } @@ -434,7 +439,7 @@ namespace MonoDevelop.Ide.Tasks CurrentLocationTaskChanged (this, EventArgs.Empty); if (currentLocationTask != null) { - TaskService.ShowStatus (currentLocationTask); + IdeServices.TaskService.ShowStatus (currentLocationTask); return new TaskNavigationPoint (currentLocationTask); } else { @@ -459,12 +464,12 @@ namespace MonoDevelop.Ide.Tasks return false; //only text files - var mimeType = DesktopService.GetMimeTypeForUri (t.FileName); - if (!DesktopService.GetMimeTypeIsText (mimeType)) + var mimeType = IdeServices.DesktopService.GetMimeTypeForUri (t.FileName); + if (!IdeServices.DesktopService.GetMimeTypeIsText (mimeType)) return false; //only files for which we have a default internal display binding - var binding = DisplayBindingService.GetDefaultBinding (t.FileName, mimeType, p); + var binding = IdeApp.Services.DisplayBindingService.GetDefaultBinding (t.FileName, mimeType, p); if (binding == null || !binding.CanUseAsDefault || binding is IExternalDisplayBinding) return false; @@ -508,7 +513,7 @@ namespace MonoDevelop.Ide.Tasks CurrentLocationTaskChanged (this, EventArgs.Empty); if (currentLocationTask != null) { - TaskService.ShowStatus (currentLocationTask); + IdeServices.TaskService.ShowStatus (currentLocationTask); return new TaskNavigationPoint (currentLocationTask); } else { @@ -525,7 +530,7 @@ namespace MonoDevelop.Ide.Tasks } return -1; } - + public string ItemName { get; set; } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TextEditing/TextEditorService.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TextEditing/TextEditorService.cs index 74385431b9..a7fe3e89f0 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TextEditing/TextEditorService.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TextEditing/TextEditorService.cs @@ -29,51 +29,17 @@ using System.Linq; using MonoDevelop.Core; using System.Collections.Generic; using MonoDevelop.Projects.Text; +using System.Threading.Tasks; namespace MonoDevelop.Ide.TextEditing { /// /// Offers several methods for tracking changes being done in edited files /// - public static class TextEditorService + [DefaultServiceImplementation] + public class TextEditorService: Service { - static Dictionary> fileExtensions = new Dictionary> (); - - static TextEditorService () - { - LineCountChanged += delegate(object sender, LineCountEventArgs e) { - foreach (var ext in GetFileLineExtensions (e.TextFile.Name).Where (ex => ex.TrackLinePosition).ToList ()) { - if (ext.Line > e.LineNumber) { - if (ext.Line + e.LineCount < e.LineNumber) - ext.NotifyDeleted (); - if (ext.OriginalLine == -1) - ext.OriginalLine = ext.Line; - ext.Line += e.LineCount; - ext.Refresh (); - } - else if (ext.Line == e.LineNumber && e.LineCount < 0) { - ext.NotifyDeleted (); - if (ext.OriginalLine == -1) - ext.OriginalLine = ext.Line; - ext.Line += e.LineCount; - ext.Refresh (); - } - } - }; - LineCountChangesCommitted += delegate(object sender, TextFileEventArgs e) { - foreach (var ext in GetFileLineExtensions (e.TextFile.Name).Where (ex => ex.TrackLinePosition)) - ext.OriginalLine = -1; - }; - LineCountChangesReset += delegate(object sender, TextFileEventArgs e) { - foreach (var ext in GetFileLineExtensions (e.TextFile.Name).Where (ex => ex.TrackLinePosition)) { - if (ext.OriginalLine != -1) { - ext.Line = ext.OriginalLine; - ext.OriginalLine = -1; - ext.Refresh (); - } - } - }; - } + Dictionary> fileExtensions = new Dictionary> (); /// /// Notifies to the text editor service that there has been a line count change in a file being edited @@ -90,8 +56,25 @@ namespace MonoDevelop.Ide.TextEditing /// /// Column. /// - public static void NotifyLineCountChanged (ITextFile textFile, int lineNumber, int lineCount, int column) + public void NotifyLineCountChanged (ITextFile textFile, int lineNumber, int lineCount, int column) { + foreach (var ext in GetFileLineExtensions (textFile.Name).Where (ex => ex.TrackLinePosition).ToList ()) { + if (ext.Line > lineNumber) { + if (ext.Line + lineCount < lineNumber) + ext.NotifyDeleted (); + if (ext.OriginalLine == -1) + ext.OriginalLine = ext.Line; + ext.Line += lineCount; + ext.Refresh (); + } else if (ext.Line == lineNumber && lineCount < 0) { + ext.NotifyDeleted (); + if (ext.OriginalLine == -1) + ext.OriginalLine = ext.Line; + ext.Line += lineCount; + ext.Refresh (); + } + } + if (LineCountChanged != null) LineCountChanged (textFile, new LineCountEventArgs (textFile, lineNumber, lineCount, column)); } @@ -102,8 +85,15 @@ namespace MonoDevelop.Ide.TextEditing /// /// Text file. /// - public static void NotifyLineCountChangesReset (ITextFile textFile) + public void NotifyLineCountChangesReset (ITextFile textFile) { + foreach (var ext in GetFileLineExtensions (textFile.Name).Where (ex => ex.TrackLinePosition)) { + if (ext.OriginalLine != -1) { + ext.Line = ext.OriginalLine; + ext.OriginalLine = -1; + ext.Refresh (); + } + } if (LineCountChangesReset != null) LineCountChangesReset (textFile, new TextFileEventArgs (textFile)); } @@ -114,13 +104,16 @@ namespace MonoDevelop.Ide.TextEditing /// /// Text file. /// - public static void NotifyLineCountChangesCommitted (ITextFile textFile) + public void NotifyLineCountChangesCommitted (ITextFile textFile) { + foreach (var ext in GetFileLineExtensions (textFile.Name).Where (ex => ex.TrackLinePosition)) + ext.OriginalLine = -1; + if (LineCountChangesCommitted != null) LineCountChangesCommitted (textFile, new TextFileEventArgs (textFile)); } - static IEnumerable GetFileLineExtensions (FilePath file) + IEnumerable GetFileLineExtensions (FilePath file) { file = file.CanonicalPath; return fileExtensions.Values.SelectMany (e => e).OfType ().Where (e => e.File.CanonicalPath == file); @@ -132,8 +125,9 @@ namespace MonoDevelop.Ide.TextEditing /// /// The extension. /// - public static void RegisterExtension (FileExtension extension) + public void RegisterExtension (FileExtension extension) { + extension.TextEditorService = this; List list; if (!fileExtensions.TryGetValue (extension.File, out list)) list = fileExtensions [extension.File] = new List (); @@ -147,7 +141,7 @@ namespace MonoDevelop.Ide.TextEditing /// /// Extension. /// - public static void UnregisterExtension (FileExtension extension) + public void UnregisterExtension (FileExtension extension) { List list; if (!fileExtensions.TryGetValue (extension.File, out list)) @@ -156,13 +150,13 @@ namespace MonoDevelop.Ide.TextEditing NotifyExtensionRemoved (extension); } - static void NotifyExtensionAdded (FileExtension extension) + void NotifyExtensionAdded (FileExtension extension) { if (FileExtensionAdded != null) FileExtensionAdded (null, new FileExtensionEventArgs () { Extension = extension }); } - static void NotifyExtensionRemoved (FileExtension extension) + void NotifyExtensionRemoved (FileExtension extension) { if (FileExtensionRemoved != null) FileExtensionRemoved (null, new FileExtensionEventArgs () { Extension = extension }); @@ -177,7 +171,7 @@ namespace MonoDevelop.Ide.TextEditing /// /// File. /// - public static FileExtension[] GetFileExtensions (FilePath file) + public FileExtension[] GetFileExtensions (FilePath file) { List list; if (!fileExtensions.TryGetValue (file, out list)) @@ -186,7 +180,7 @@ namespace MonoDevelop.Ide.TextEditing return list.ToArray (); } - internal static void Refresh (FileExtension ext) + internal void Refresh (FileExtension ext) { NotifyExtensionRemoved (ext); NotifyExtensionAdded (ext); @@ -195,36 +189,27 @@ namespace MonoDevelop.Ide.TextEditing /// /// Occurs when there has been a line count change in a file being edited /// - public static event EventHandler LineCountChanged; + public event EventHandler LineCountChanged; /// /// Occurs when all previous line change notifications for a file have to be discarded /// - public static event EventHandler LineCountChangesReset; + public event EventHandler LineCountChangesReset; /// /// Occurs when all previous line change notifications for a file have to be committed /// - public static event EventHandler LineCountChangesCommitted; + public event EventHandler LineCountChangesCommitted; /// /// Occurs when a text editor extension has been added /// - public static event EventHandler FileExtensionAdded; + public event EventHandler FileExtensionAdded; /// /// Occurs when a text editor extension has been removed /// - public static event EventHandler FileExtensionRemoved; + public event EventHandler FileExtensionRemoved; } - - - - - - - - - } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.MetadataReferenceHandler.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.MetadataReferenceHandler.cs index b070146e50..999d6d6164 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.MetadataReferenceHandler.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.MetadataReferenceHandler.cs @@ -1,4 +1,4 @@ -// +// // MonoDevelopWorkspace.MetadataReferenceHandler.cs // // Author: @@ -86,7 +86,7 @@ namespace MonoDevelop.Ide.TypeSystem Result = new List (), Project = netProject, Visited = new HashSet (FilePath.PathComparer), - ConfigurationSelector = IdeApp.Workspace?.ActiveConfiguration ?? MonoDevelop.Projects.ConfigurationSelector.Default, + ConfigurationSelector = IdeApp.IsInitialized ? IdeApp.Workspace.ActiveConfiguration : MonoDevelop.Projects.ConfigurationSelector.Default, Token = token, }; @@ -140,7 +140,7 @@ namespace MonoDevelop.Ide.TypeSystem if (data.Token.IsCancellationRequested) return false; - if (!(pr is MonoDevelop.Projects.DotNetProject referencedProject) || !TypeSystemService.IsOutputTrackedProject (referencedProject)) + if (!(pr is MonoDevelop.Projects.DotNetProject referencedProject) || !IdeApp.TypeSystemService.IsOutputTrackedProject (referencedProject)) continue; var fileName = referencedProject.GetOutputFileName (data.ConfigurationSelector); @@ -167,7 +167,7 @@ namespace MonoDevelop.Ide.TypeSystem List references; try { - var config = IdeApp.Workspace?.ActiveConfiguration ?? MonoDevelop.Projects.ConfigurationSelector.Default; + var config = IdeApp.IsInitialized ? IdeApp.Workspace.ActiveConfiguration : MonoDevelop.Projects.ConfigurationSelector.Default; references = await netProj.GetReferences (config, token).ConfigureAwait (false); } catch (Exception e) { LoggingService.LogError ("Error while getting referenced projects.", e); @@ -191,7 +191,7 @@ namespace MonoDevelop.Ide.TypeSystem if (!addedProjects.Add (referencedProject)) continue; - if (TypeSystemService.IsOutputTrackedProject (referencedProject)) + if (IdeApp.TypeSystemService.IsOutputTrackedProject (referencedProject)) continue; var aliases = pr.EnumerateAliases (); diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.ProjectSystemHandler.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.ProjectSystemHandler.cs index 1293ad41d8..b059f08a0e 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.ProjectSystemHandler.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.ProjectSystemHandler.cs @@ -1,4 +1,4 @@ -// +// // MonoDevelopWorkspace.ProjectSystemHandler.cs // // Author: @@ -61,7 +61,7 @@ namespace MonoDevelop.Ide.TypeSystem this.projections = projections; metadataHandler = new Lazy (() => new MetadataReferenceHandler (workspace.MetadataReferenceManager, projectMap)); - hostDiagnosticUpdateSource = new Lazy (() => new HostDiagnosticUpdateSource (workspace, Composition.CompositionManager.GetExportedValue ())); + hostDiagnosticUpdateSource = new Lazy (() => new HostDiagnosticUpdateSource (workspace, workspace.compositionManager.GetExportedValue ())); } #region Solution mapping @@ -84,7 +84,7 @@ namespace MonoDevelop.Ide.TypeSystem static async void OnSolutionModified (object sender, MonoDevelop.Projects.WorkspaceItemEventArgs args) { var sol = (MonoDevelop.Projects.Solution)args.Item; - var workspace = await TypeSystemService.GetWorkspaceAsync (sol, CancellationToken.None); + var workspace = await IdeApp.TypeSystemService.GetWorkspaceAsync (sol, CancellationToken.None); var solId = workspace.ProjectHandler.GetSolutionId (sol); if (solId == null) return; @@ -111,9 +111,9 @@ namespace MonoDevelop.Ide.TypeSystem { var projectId = projectMap.GetOrCreateId (p, oldProject); - var config = IdeApp.Workspace != null ? p.GetConfiguration (IdeApp.Workspace.ActiveConfiguration) as MonoDevelop.Projects.DotNetProjectConfiguration : null; + var config = IdeApp.IsInitialized ? p.GetConfiguration (IdeApp.Workspace.ActiveConfiguration) as MonoDevelop.Projects.DotNetProjectConfiguration : null; MonoDevelop.Projects.DotNetCompilerParameters cp = config?.CompilationParameters; - FilePath fileName = IdeApp.Workspace != null ? p.GetOutputFileName (IdeApp.Workspace.ActiveConfiguration) : (FilePath)""; + FilePath fileName = IdeApp.IsInitialized ? p.GetOutputFileName (IdeApp.Workspace.ActiveConfiguration) : (FilePath)""; if (fileName.IsNullOrEmpty) fileName = new FilePath (p.Name + ".dll"); @@ -291,8 +291,8 @@ namespace MonoDevelop.Ide.TypeSystem static bool CanGenerateAnalysisContextForNonCompileable (MonoDevelop.Projects.Project p, MonoDevelop.Projects.ProjectFile f) { - var mimeType = DesktopService.GetMimeTypeForUri (f.FilePath); - var node = TypeSystemService.GetTypeSystemParserNode (mimeType, f.BuildAction); + var mimeType = IdeServices.DesktopService.GetMimeTypeForUri (f.FilePath); + var node = IdeApp.TypeSystemService.GetTypeSystemParserNode (mimeType, f.BuildAction); if (node?.Parser == null) return false; return node.Parser.CanGenerateAnalysisDocument (mimeType, f.BuildAction, p.SupportedLanguages); @@ -339,8 +339,8 @@ namespace MonoDevelop.Ide.TypeSystem IEnumerable GenerateProjections (MonoDevelop.Projects.ProjectFile f, DocumentMap documentMap, MonoDevelop.Projects.Project p, ProjectData oldProjectData, HashSet duplicates) { - var mimeType = DesktopService.GetMimeTypeForUri (f.FilePath); - var node = TypeSystemService.GetTypeSystemParserNode (mimeType, f.BuildAction); + var mimeType = IdeServices.DesktopService.GetMimeTypeForUri (f.FilePath); + var node = IdeApp.TypeSystemService.GetTypeSystemParserNode (mimeType, f.BuildAction); if (node == null || !node.Parser.CanGenerateProjection (mimeType, f.BuildAction, p.SupportedLanguages)) yield break; var options = new ParseOptions { diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.cs index 753abf5af7..14f66e6d0d 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.cs @@ -1,29 +1,29 @@ -// -// MonoDevelopWorkspace.cs -// -// Author: -// Mike Krüger -// -// 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. - +// +// MonoDevelopWorkspace.cs +// +// Author: +// Mike Krüger +// +// 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; @@ -36,17 +36,10 @@ 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 Gtk; using MonoDevelop.Ide.Editor.Projection; -using System.Reflection; -using Microsoft.CodeAnalysis.Host.Mef; -using System.Text; -using System.Collections.Immutable; using System.ComponentModel; using Mono.Addins; -using MonoDevelop.Core.AddIns; using Microsoft.CodeAnalysis.Extensions; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Shared.Options; @@ -55,6 +48,9 @@ using Microsoft.CodeAnalysis.SolutionCrawler; using MonoDevelop.Ide.Composition; using MonoDevelop.Ide.RoslynServices; using MonoDevelop.Core.Assemblies; +using MonoDevelop.Ide.Gui.Documents; +using MonoDevelop.Ide.Gui; +using Document = Microsoft.CodeAnalysis.Document; namespace MonoDevelop.Ide.TypeSystem { @@ -62,11 +58,18 @@ namespace MonoDevelop.Ide.TypeSystem { public const string ServiceLayer = nameof(MonoDevelopWorkspace); - // Background compiler is used to trigger compilations in the background for the solution and hold onto them - // so in case nothing references the solution in current stacks, they're not collected. - // We previously used to experience pathological GC times on large solutions, and this was caused - // by the compilations being freed out of memory due to only being weakly referenced, and recomputing them on - // a case by case basis. + private readonly ServiceProvider serviceProvider; + TypeSystemService typeSystemService; + DesktopService desktopService; + DocumentManager documentManager; + RootWorkspace workspace; + CompositionManager compositionManager; + + // Background compiler is used to trigger compilations in the background for the solution and hold onto them + // so in case nothing references the solution in current stacks, they're not collected. + // We previously used to experience pathological GC times on large solutions, and this was caused + // by the compilations being freed out of memory due to only being weakly referenced, and recomputing them on + // a case by case basis. BackgroundCompiler backgroundCompiler; internal readonly WorkspaceId Id; @@ -83,13 +86,12 @@ namespace MonoDevelop.Ide.TypeSystem public MonoDevelop.Projects.Solution MonoDevelopSolution { get; } internal MonoDevelopMetadataReferenceManager MetadataReferenceManager => manager.Value; - internal static HostServices HostServices => CompositionManager.Instance.HostServices; - - static MonoDevelopWorkspace () - { - Tasks.CommentTasksProvider.Initialize (); - } - + + static MonoDevelopWorkspace () + { + Tasks.CommentTasksProvider.Initialize (); + } + /// /// This bypasses the type system service. Use with care. /// @@ -99,9 +101,11 @@ namespace MonoDevelop.Ide.TypeSystem OnSolutionAdded (sInfo); } - internal MonoDevelopWorkspace (MonoDevelop.Projects.Solution solution) : base (HostServices, WorkspaceKind.Host) - { + internal MonoDevelopWorkspace (HostServices hostServices, MonoDevelop.Projects.Solution solution, TypeSystemService typeSystemService) : base (hostServices, WorkspaceKind.Host) + { this.MonoDevelopSolution = solution; + this.serviceProvider = typeSystemService.ServiceProvider ?? Runtime.ServiceProvider; + this.typeSystemService = typeSystemService; this.Id = WorkspaceId.Next (); Projections = new ProjectionData (); @@ -109,19 +113,25 @@ namespace MonoDevelop.Ide.TypeSystem ProjectMap = new ProjectDataMap (this); ProjectHandler = new ProjectSystemHandler (this, ProjectMap, Projections); manager = new Lazy (() => Services.GetService ()); - metadataHandler = new Lazy (() => new MetadataReferenceHandler (MetadataReferenceManager, ProjectMap)); - - if (IdeApp.Workspace != null && solution != null) { - IdeApp.Workspace.ActiveConfigurationChanged += HandleActiveConfigurationChanged; - } + metadataHandler = new Lazy (() => new MetadataReferenceHandler (MetadataReferenceManager, ProjectMap)); + } + + internal async Task Initialize () + { + serviceProvider.WhenServiceInitialized (s => { + workspace = s; + if (MonoDevelopSolution != null) + workspace.ActiveConfigurationChanged += HandleActiveConfigurationChanged; + }); + backgroundCompiler = new BackgroundCompiler (this); var cacheService = Services.GetService (); if (cacheService != null) - cacheService.CacheFlushRequested += OnCacheFlushRequested; - - // Trigger running compiler syntax and semantic errors via the diagnostic analyzer engine - IdeApp.Preferences.Roslyn.FullSolutionAnalysisRuntimeEnabled = true; + cacheService.CacheFlushRequested += OnCacheFlushRequested; + + // Trigger running compiler syntax and semantic errors via the diagnostic analyzer engine + TypeSystemService.Preferences.FullSolutionAnalysisRuntimeEnabled = true; Options = Options.WithChangedOption (Microsoft.CodeAnalysis.Diagnostics.InternalRuntimeDiagnosticOptions.Syntax, true) .WithChangedOption (Microsoft.CodeAnalysis.Diagnostics.InternalRuntimeDiagnosticOptions.Semantic, true) // Turn on FSA on a new workspace addition @@ -132,21 +142,26 @@ namespace MonoDevelop.Ide.TypeSystem // https://github.com/mono/monodevelop/issues/4149 https://github.com/dotnet/roslyn/issues/25453 .WithChangedOption (Microsoft.CodeAnalysis.Storage.StorageOptions.SolutionSizeThreshold, MonoDevelop.Core.Platform.IsLinux ? int.MaxValue : 0); - if (IdeApp.Preferences.EnableSourceAnalysis) { + if (TypeSystemService.EnableSourceAnalysis) { var solutionCrawler = Services.GetService (); solutionCrawler.Register (this); } - IdeApp.Preferences.EnableSourceAnalysis.Changed += OnEnableSourceAnalysisChanged; - - // TODO: Unhack C# here when monodevelop workspace supports more than C# - IdeApp.Preferences.Roslyn.FullSolutionAnalysisRuntimeEnabledChanged += OnEnableFullSourceAnalysisChanged; + TypeSystemService.EnableSourceAnalysis.Changed += OnEnableSourceAnalysisChanged; + + // TODO: Unhack C# here when monodevelop workspace supports more than C# + TypeSystemService.Preferences.FullSolutionAnalysisRuntimeEnabledChanged += OnEnableFullSourceAnalysisChanged; foreach (var factory in AddinManager.GetExtensionObjects("/MonoDevelop/Ide/TypeService/OptionProviders")) Services.GetRequiredService ().RegisterDocumentOptionsProvider (factory.Create (this)); - if (solution != null) - DesktopService.MemoryMonitor.StatusChanged += OnMemoryStatusChanged; + desktopService = await serviceProvider.GetService ().ConfigureAwait (false); + documentManager = await serviceProvider.GetService ().ConfigureAwait (false); + compositionManager = await serviceProvider.GetService ().ConfigureAwait (false); + + if (MonoDevelopSolution != null) { + Runtime.RunInMainThread (() => desktopService.MemoryMonitor.StatusChanged += OnMemoryStatusChanged).Ignore (); + } } bool lowMemoryLogged; @@ -173,7 +188,7 @@ namespace MonoDevelop.Ide.TypeSystem return; Options = Options.WithChangedOption (RuntimeOptions.FullSolutionAnalysis, false); - IdeApp.Preferences.Roslyn.FullSolutionAnalysisRuntimeEnabled = false; + TypeSystemService.Preferences.FullSolutionAnalysisRuntimeEnabled = false; if (IsUserOptionOn ()) { // let user know full analysis is turned off due to memory concern. // make sure we show info bar only once for the same solution. @@ -182,7 +197,7 @@ namespace MonoDevelop.Ide.TypeSystem const string LowVMMoreInfoLink = "https://go.microsoft.com/fwlink/?linkid=2003417&clcid=0x409"; Services.GetService ().ShowGlobalErrorInfo ( GettextCatalog.GetString ("{0} has suspended some advanced features to improve performance", BrandingService.ApplicationName), - new InfoBarUI ("Learn more", InfoBarUI.UIKind.HyperLink, () => DesktopService.ShowUrl (LowVMMoreInfoLink), closeAfterAction: false), + new InfoBarUI ("Learn more", InfoBarUI.UIKind.HyperLink, () => desktopService.ShowUrl (LowVMMoreInfoLink), closeAfterAction: false), new InfoBarUI ("Restore", InfoBarUI.UIKind.Button, () => Options = Options.WithChangedOption (RuntimeOptions.FullSolutionAnalysis, true)) ); } @@ -214,7 +229,7 @@ namespace MonoDevelop.Ide.TypeSystem // check languages currently on solution. since we only show info bar once, we don't need to track solution changes. var languages = CurrentSolution.Projects.Select (p => p.Language).Distinct (); foreach (var language in languages) { - if (IdeApp.Preferences.Roslyn.For (language).SolutionCrawlerClosedFileDiagnostic) { + if (TypeSystemService.Preferences.For (language).SolutionCrawlerClosedFileDiagnostic) { return true; } } @@ -225,12 +240,12 @@ namespace MonoDevelop.Ide.TypeSystem void OnEnableSourceAnalysisChanged(object sender, EventArgs args) { var solutionCrawler = Services.GetService (); - if (IdeApp.Preferences.EnableSourceAnalysis) + if (TypeSystemService.EnableSourceAnalysis) solutionCrawler.Register (this); else solutionCrawler.Unregister (this); - var diagnosticAnalyzer = CompositionManager.GetExportedValue (); + var diagnosticAnalyzer = compositionManager.GetExportedValue (); diagnosticAnalyzer.Reanalyze (this); } @@ -238,7 +253,7 @@ namespace MonoDevelop.Ide.TypeSystem { // we only want to turn on FSA if the option is explicitly enabled, // we don't want to turn it off here. - if (IdeApp.Preferences.Roslyn.FullSolutionAnalysisRuntimeEnabled) { + if (TypeSystemService.Preferences.FullSolutionAnalysisRuntimeEnabled) { Options = Options.WithChangedOption (RuntimeOptions.FullSolutionAnalysis, true); } } @@ -255,14 +270,15 @@ namespace MonoDevelop.Ide.TypeSystem MetadataReferenceManager.ClearCache (); - IdeApp.Preferences.EnableSourceAnalysis.Changed -= OnEnableSourceAnalysisChanged; - IdeApp.Preferences.Roslyn.FullSolutionAnalysisRuntimeEnabledChanged -= OnEnableFullSourceAnalysisChanged; - DesktopService.MemoryMonitor.StatusChanged -= OnMemoryStatusChanged; + TypeSystemService.EnableSourceAnalysis.Changed -= OnEnableSourceAnalysisChanged; + TypeSystemService.Preferences.FullSolutionAnalysisRuntimeEnabledChanged -= OnEnableFullSourceAnalysisChanged; + desktopService.MemoryMonitor.StatusChanged -= OnMemoryStatusChanged; CancelLoad (); - if (IdeApp.Workspace != null) { - IdeApp.Workspace.ActiveConfigurationChanged -= HandleActiveConfigurationChanged; - } + + if (workspace != null) + workspace.ActiveConfigurationChanged -= HandleActiveConfigurationChanged; + if (MonoDevelopSolution != null) { foreach (var prj in MonoDevelopSolution.GetAllProjects ()) { UnloadMonoProject (prj); @@ -293,7 +309,7 @@ namespace MonoDevelop.Ide.TypeSystem internal void HideStatusIcon () { - TypeSystemService.HideTypeInformationGatheringIcon (() => { + typeSystemService.HideTypeInformationGatheringIcon (() => { LoadingFinished?.Invoke (this, EventArgs.Empty); WorkspaceLoaded?.Invoke (this, EventArgs.Empty); }); @@ -303,7 +319,7 @@ namespace MonoDevelop.Ide.TypeSystem internal void ShowStatusIcon () { - TypeSystemService.ShowTypeInformationGatheringIcon (); + typeSystemService.ShowTypeInformationGatheringIcon (); } async void HandleActiveConfigurationChanged (object sender, EventArgs e) @@ -357,7 +373,7 @@ namespace MonoDevelop.Ide.TypeSystem if (doc != null) { var mdProject = GetMonoProject (doc.Project); if (doc != null) { - IdeApp.Workbench.OpenDocument (doc.FilePath, mdProject, activate); + documentManager.OpenDocument (new FileOpenInformation (doc.FilePath, mdProject, activate)).Ignore (); } } } @@ -535,9 +551,9 @@ namespace MonoDevelop.Ide.TypeSystem } } else { var formatter = CodeFormatterService.GetFormatter (data.MimeType); - var documentContext = IdeApp.Workbench.Documents.FirstOrDefault (d => FilePath.PathComparer.Compare (d.FileName, filePath) == 0); + var documentContext = documentManager.Documents.FirstOrDefault (d => FilePath.PathComparer.Compare (d.FileName, filePath) == 0)?.DocumentContext; var root = await projectChanges.NewProject.GetDocument (id).GetSyntaxRootAsync (); - var annotatedNode = root.DescendantNodesAndSelf ().FirstOrDefault (n => n.HasAnnotation (TypeSystemService.InsertionModeAnnotation)); + var annotatedNode = root.DescendantNodesAndSelf ().FirstOrDefault (n => n.HasAnnotation (typeSystemService.InsertionModeAnnotation)); SyntaxToken? renameTokenOpt = root.GetAnnotatedNodesAndTokens (Microsoft.CodeAnalysis.CodeActions.RenameAnnotation.Kind) .Where (s => s.IsToken) .Select (s => s.AsToken ()) @@ -568,7 +584,7 @@ namespace MonoDevelop.Ide.TypeSystem } } if (annotatedNode != null && GetInsertionPoints != null) { - IdeApp.Workbench.Documents.First (d => d.FileName == editor.FileName).Select (); + documentManager.Documents.First (d => d.FileName == editor.FileName).Select (); var formattedVersion = editor.Version; int startOffset = versionBeforeFormat.MoveOffsetTo (editor.Version, annotatedNode.Span.Start); @@ -677,9 +693,9 @@ namespace MonoDevelop.Ide.TypeSystem async Task UpdateProjectionsDocuments (Document document, ITextDocument data) { - var project = TypeSystemService.GetMonoProject (document.Project); + var project = typeSystemService.GetMonoProject (document.Project); var file = project.Files.GetFile (data.FileName); - var node = TypeSystemService.GetTypeSystemParserNode (data.MimeType, file.BuildAction); + var node = typeSystemService.GetTypeSystemParserNode (data.MimeType, file.BuildAction); if (node != null && node.Parser.CanGenerateProjection (data.MimeType, file.BuildAction, project.SupportedLanguages)) { var options = new ParseOptions { FileName = file.FilePath, @@ -747,20 +763,17 @@ namespace MonoDevelop.Ide.TypeSystem } catch (Exception ex) { LoggingService.LogError ("Error applying changes to documents", ex); } - if (IdeApp.Workbench != null) { - var changedFiles = new HashSet (tryApplyState_documentTextChangedContents.Keys, FilePath.PathComparer); - foreach (var w in IdeApp.Workbench.Documents) { - if (w.IsFile && changedFiles.Contains (w.FileName)) { - w.StartReparseThread (); - } + var changedFiles = new HashSet (tryApplyState_documentTextChangedContents.Keys, FilePath.PathComparer); + foreach (var w in documentManager.Documents) { + if (w.IsFile && changedFiles.Contains (w.FileName)) { + w.DocumentContext.ReparseDocument (); } } }, CancellationToken.None, TaskContinuationOptions.None, Runtime.MainTaskScheduler); } - if (tryApplyState_changedProjects.Count > 0) { - ProjectSaveTask = IdeApp.ProjectOperations.SaveAsync (tryApplyState_changedProjects); - } + if (tryApplyState_changedProjects.Count > 0) + ProjectSaveTask = IdeApp.IsInitialized ? IdeApp.ProjectOperations.SaveAsync (tryApplyState_changedProjects) : Task.WhenAll (tryApplyState_changedProjects.Select (p => p.SaveAsync (new ProgressMonitor ()))); return ret; } finally { @@ -817,7 +830,7 @@ namespace MonoDevelop.Ide.TypeSystem info = info.WithFilePath (path).WithTextLoader (new MonoDevelopTextLoader (path)); string formattedText; - var formatter = CodeFormatterService.GetFormatter (DesktopService.GetMimeTypeForUri (path)); + var formatter = CodeFormatterService.GetFormatter (desktopService.GetMimeTypeForUri (path)); if (formatter != null && mdProject != null) { formattedText = formatter.FormatText (mdProject.Policies, text.ToString ()); } else { @@ -857,10 +870,10 @@ namespace MonoDevelop.Ide.TypeSystem } //force-close the old doc even if it's dirty - var openDoc = IdeApp.Workbench.Documents.FirstOrDefault (d => d.IsFile && filePath.Equals (d.FileName)); + var openDoc = documentManager.Documents.FirstOrDefault (d => d.IsFile && filePath.Equals (d.FileName)); if (openDoc != null && openDoc.IsDirty) { - openDoc.Save (); - ((Gui.SdiWorkspaceWindow)openDoc.Window).CloseWindow (true, true).Wait (); + openDoc.Save ().Wait (); + openDoc.Close ().Wait (); } //this will fire a OnDocumentRemoved event via OnFileRemoved @@ -1080,10 +1093,10 @@ namespace MonoDevelop.Ide.TypeSystem if (monoProject != null) { var pf = monoProject.GetProjectFile (fileName); if (pf != null) { - var mimeType = DesktopService.GetMimeTypeForUri (fileName); - if (TypeSystemService.CanParseProjections (monoProject, mimeType, fileName)) { + var mimeType = desktopService.GetMimeTypeForUri (fileName); + if (typeSystemService.CanParseProjections (monoProject, mimeType, fileName)) { var parseOptions = new ParseOptions { Project = monoProject, FileName = fileName, Content = new StringTextSource (text), BuildAction = pf.BuildAction }; - var task = TypeSystemService.ParseProjection (parseOptions, mimeType); + var task = typeSystemService.ParseProjection (parseOptions, mimeType); tasks.Add (task); } } @@ -1112,9 +1125,10 @@ namespace MonoDevelop.Ide.TypeSystem #region Project modification handlers List modifiedProjects = new List (); - readonly object projectModifyLock = new object (); + readonly object projectModifyLock = new object (); bool freezeProjectModify; Dictionary projectModifiedCts = new Dictionary (); + void OnProjectModified (object sender, MonoDevelop.Projects.SolutionItemModifiedEventArgs args) { lock (projectModifyLock) { diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TypeSystemService.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TypeSystemService.cs index bb351a6601..56c189d674 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TypeSystemService.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TypeSystemService.cs @@ -1,5 +1,5 @@ -// -// TypeSystemService.cs +// +// IdeApp.TypeSystemService.cs // // Author: // Mike Krüger @@ -30,31 +30,42 @@ using System.IO; using MonoDevelop.Projects; using Mono.Addins; using MonoDevelop.Core; -using MonoDevelop.Ide; using System.Threading; using System.Xml; using ICSharpCode.NRefactory.Utils; using System.Threading.Tasks; using MonoDevelop.Ide.Extensions; using MonoDevelop.Core.Assemblies; -using System.Text; using MonoDevelop.Ide.Editor; using MonoDevelop.Core.Text; -using Microsoft.CodeAnalysis.Text; -using Mono.Posix; +using MonoDevelop.Ide.RoslynServices.Options; +using MonoDevelop.Ide.Gui.Documents; +using MonoDevelop.Ide.Composition; namespace MonoDevelop.Ide.TypeSystem { - public static partial class TypeSystemService + [DefaultServiceImplementation] + public partial class TypeSystemService: Service { const string CurrentVersion = "1.1.9"; - static IEnumerable parsers; - static string[] filesSkippedInParseThread = new string[0]; - public static Microsoft.CodeAnalysis.SyntaxAnnotation InsertionModeAnnotation = new Microsoft.CodeAnalysis.SyntaxAnnotation(); - internal static MonoDevelopRuleSetManager RuleSetManager { get; } = new MonoDevelopRuleSetManager (); + DocumentManager documentManager; + DesktopService desktopService; + RootWorkspace rootWorkspace; + CompositionManager compositionManager; + + IEnumerable parsers; + string[] filesSkippedInParseThread = new string[0]; + + public Microsoft.CodeAnalysis.SyntaxAnnotation InsertionModeAnnotation { get; } = new Microsoft.CodeAnalysis.SyntaxAnnotation(); - internal static IEnumerable Parsers { + // Preferences + internal static RoslynPreferences Preferences { get; } = new RoslynPreferences (); + internal static ConfigurationProperty EnableSourceAnalysis = ConfigurationProperty.Create ("MonoDevelop.AnalysisCore.AnalysisEnabled_V2", true); + + internal MonoDevelopRuleSetManager RuleSetManager { get; } = new MonoDevelopRuleSetManager (); + + internal IEnumerable Parsers { get { return parsers; } @@ -63,20 +74,16 @@ namespace MonoDevelop.Ide.TypeSystem } } - public static void RemoveSkippedfile (FilePath fileName) + protected override async Task OnInitialize (ServiceProvider serviceProvider) { - filesSkippedInParseThread = filesSkippedInParseThread.Where (f => f != fileName).ToArray (); - } + IntitializeTrackedProjectHandling (); - public static void AddSkippedFile (FilePath fileName) - { - if (filesSkippedInParseThread.Any (f => f == fileName)) - return; - filesSkippedInParseThread = filesSkippedInParseThread.Concat (new string[] { fileName }).ToArray (); - } + serviceProvider.WhenServiceInitialized (s => documentManager = s); + serviceProvider.WhenServiceInitialized (s => { + rootWorkspace = s; + rootWorkspace.ActiveConfigurationChanged += HandleActiveConfigurationChanged; + }); - static TypeSystemService () - { RoslynServices.RoslynService.Initialize (); CleanupCache (); parsers = AddinManager.GetExtensionNodes ("/MonoDevelop/TypeSystem/Parser"); @@ -89,64 +96,95 @@ namespace MonoDevelop.Ide.TypeSystem initialLoad = false; try { - emptyWorkspace = new MonoDevelopWorkspace (null); + compositionManager = await serviceProvider.GetService ().ConfigureAwait (false); + emptyWorkspace = new MonoDevelopWorkspace (compositionManager.HostServices, null, this); + await emptyWorkspace.Initialize ().ConfigureAwait (false); } catch (Exception e) { LoggingService.LogFatalError ("Can't create roslyn workspace", e); } - FileService.FileChanged += delegate(object sender, FileEventArgs e) { - // if (!TrackFileChanges) - // return; - - var filesToUpdate = new List (); - foreach (var file in e) { - // Open documents are handled by the Document class itself. - if (IdeApp.Workbench != null && IdeApp.Workbench.GetDocument (file.FileName) != null) - continue; - - foreach (var w in workspaces) { - foreach (var p in w.CurrentSolution.ProjectIds) { - if (w.GetDocumentId (p, file.FileName) != null) { - filesToUpdate.Add (file.FileName); - goto found; - } + FileService.FileChanged += FileService_FileChanged; + + desktopService = await serviceProvider.GetService (); + } + + protected override Task OnDispose () + { + FileService.FileChanged -= FileService_FileChanged; + if (rootWorkspace != null) + rootWorkspace.ActiveConfigurationChanged -= HandleActiveConfigurationChanged; + FinalizeTrackedProjectHandling (); + return Task.CompletedTask; + } + + void FileService_FileChanged (object sender, FileEventArgs e) + { + var filesToUpdate = new List (); + foreach (var file in e) { + // Open documents are handled by the Document class itself. + if (documentManager?.GetDocument (file.FileName) != null) + continue; + + foreach (var w in workspaces) { + foreach (var p in w.CurrentSolution.ProjectIds) { + if (w.GetDocumentId (p, file.FileName) != null) { + filesToUpdate.Add (file.FileName); + goto found; } } - found:; - } - if (filesToUpdate.Count == 0) - return; + found:; - Task.Run (async delegate { - try { - foreach (var file in filesToUpdate) { - var text = MonoDevelop.Core.Text.StringTextSource.ReadFrom (file).Text; - foreach (var w in workspaces) - await w.UpdateFileContent (file, text); + } + if (filesToUpdate.Count == 0) + return; + + Task.Run (async delegate { + try { + foreach (var file in filesToUpdate) { + var text = MonoDevelop.Core.Text.StringTextSource.ReadFrom (file).Text; + foreach (var w in workspaces) + await w.UpdateFileContent (file, text); + } + + Gtk.Application.Invoke ((o, args) => { + if (documentManager != null) { + foreach (var w in documentManager.Documents) + w.DocumentContext?.ReparseDocument (); } + }); + } catch (Exception) { } + }); + } - Gtk.Application.Invoke ((o, args) => { - if (IdeApp.Workbench != null) - foreach (var w in IdeApp.Workbench.Documents) - w.StartReparseThread (); - }); - } catch (Exception) {} - }); - }; + public void RemoveSkippedFile (FilePath fileName) + { + filesSkippedInParseThread = filesSkippedInParseThread.Where (f => f != fileName).ToArray (); + } - IntitializeTrackedProjectHandling (); + public void AddSkippedFile (FilePath fileName) + { + if (filesSkippedInParseThread.Any (f => f == fileName)) + return; + filesSkippedInParseThread = filesSkippedInParseThread.Concat (new string [] { fileName }).ToArray (); } - public static TypeSystemParser GetParser (string mimeType, string buildAction = BuildAction.Compile) + internal async Task CreateEmptyWorkspace () + { + var ws = new MonoDevelopWorkspace (compositionManager.HostServices, null, this); + await ws.Initialize (); + return ws; + } + + public TypeSystemParser GetParser (string mimeType, string buildAction = BuildAction.Compile) { var n = GetTypeSystemParserNode (mimeType, buildAction); return n != null ? n.Parser : null; } - internal static TypeSystemParserNode GetTypeSystemParserNode (string mimeType, string buildAction) + internal TypeSystemParserNode GetTypeSystemParserNode (string mimeType, string buildAction) { - foreach (var mt in DesktopService.GetMimeTypeInheritanceChain (mimeType)) { + foreach (var mt in desktopService.GetMimeTypeInheritanceChain (mimeType)) { var provider = Parsers.FirstOrDefault (p => p.CanParse (mt, buildAction)); if (provider != null) return provider; @@ -154,7 +192,7 @@ namespace MonoDevelop.Ide.TypeSystem return null; } - public static Task ParseFile (Project project, string fileName, CancellationToken cancellationToken = default(CancellationToken)) + public Task ParseFile (Project project, string fileName, CancellationToken cancellationToken = default(CancellationToken)) { StringTextSource text; @@ -166,10 +204,10 @@ namespace MonoDevelop.Ide.TypeSystem return TaskUtil.Default(); } - return ParseFile (project, fileName, DesktopService.GetMimeTypeForUri (fileName), text, cancellationToken); + return ParseFile (project, fileName, desktopService.GetMimeTypeForUri (fileName), text, cancellationToken); } - public static Task ParseFile (ParseOptions options, string mimeType, CancellationToken cancellationToken = default(CancellationToken)) + public Task ParseFile (ParseOptions options, string mimeType, CancellationToken cancellationToken = default(CancellationToken)) { if (options == null) throw new ArgumentNullException (nameof(options)); @@ -194,7 +232,7 @@ namespace MonoDevelop.Ide.TypeSystem } } - internal static bool CanParseProjections (Project project, string mimeType, string fileName) + internal bool CanParseProjections (Project project, string mimeType, string fileName) { var projectFile = project.GetProjectFile (fileName); if (projectFile == null) @@ -205,22 +243,22 @@ namespace MonoDevelop.Ide.TypeSystem return parser.CanGenerateProjection (mimeType, projectFile.BuildAction, project.SupportedLanguages); } - public static Task ParseFile (Project project, string fileName, string mimeType, ITextSource content, CancellationToken cancellationToken = default(CancellationToken)) + public Task ParseFile (Project project, string fileName, string mimeType, ITextSource content, CancellationToken cancellationToken = default(CancellationToken)) { return ParseFile (new ParseOptions { FileName = fileName, Project = project, Content = content }, mimeType, cancellationToken); } - public static Task ParseFile (Project project, string fileName, string mimeType, TextReader content, CancellationToken cancellationToken = default(CancellationToken)) + public Task ParseFile (Project project, string fileName, string mimeType, TextReader content, CancellationToken cancellationToken = default(CancellationToken)) { return ParseFile (project, fileName, mimeType, new StringTextSource (content.ReadToEnd ()), cancellationToken); } - public static Task ParseFile (Project project, IReadonlyTextDocument data, CancellationToken cancellationToken = default(CancellationToken)) + public Task ParseFile (Project project, IReadonlyTextDocument data, CancellationToken cancellationToken = default(CancellationToken)) { return ParseFile (project, data.FileName, data.MimeType, data, cancellationToken); } - internal static async Task ParseProjection (ParseOptions options, string mimeType, CancellationToken cancellationToken = default(CancellationToken)) + internal async Task ParseProjection (ParseOptions options, string mimeType, CancellationToken cancellationToken = default(CancellationToken)) { if (options == null) throw new ArgumentNullException (nameof(options)); @@ -268,26 +306,26 @@ namespace MonoDevelop.Ide.TypeSystem } } - internal static Task ParseProjection (Project project, string fileName, string mimeType, ITextSource content, CancellationToken cancellationToken = default(CancellationToken)) + internal Task ParseProjection (Project project, string fileName, string mimeType, ITextSource content, CancellationToken cancellationToken = default(CancellationToken)) { return ParseProjection (new ParseOptions { FileName = fileName, Project = project, Content = content }, mimeType, cancellationToken); } - internal static Task ParseProjection (Project project, string fileName, string mimeType, TextReader content, CancellationToken cancellationToken = default(CancellationToken)) + internal Task ParseProjection (Project project, string fileName, string mimeType, TextReader content, CancellationToken cancellationToken = default(CancellationToken)) { return ParseProjection (project, fileName, mimeType, new StringTextSource (content.ReadToEnd ()), cancellationToken); } - internal static Task ParseProjection (Project project, IReadonlyTextDocument data, CancellationToken cancellationToken = default(CancellationToken)) + internal Task ParseProjection (Project project, IReadonlyTextDocument data, CancellationToken cancellationToken = default(CancellationToken)) { return ParseProjection (project, data.FileName, data.MimeType, data, cancellationToken); } #region Folding parsers - static List foldingParsers; + List foldingParsers; - static IEnumerable FoldingParsers { + IEnumerable FoldingParsers { get { if (foldingParsers == null) { foldingParsers = new List (); @@ -306,9 +344,9 @@ namespace MonoDevelop.Ide.TypeSystem } } - public static IFoldingParser GetFoldingParser (string mimeType) + public IFoldingParser GetFoldingParser (string mimeType) { - foreach (var mt in DesktopService.GetMimeTypeInheritanceChain (mimeType)) { + foreach (var mt in desktopService.GetMimeTypeInheritanceChain (mimeType)) { var node = FoldingParsers.FirstOrDefault (n => n.MimeType == mt); if (node != null) return node.CreateInstance () as IFoldingParser; @@ -319,7 +357,7 @@ namespace MonoDevelop.Ide.TypeSystem #region Parser Database Handling - static string GetCacheDirectory (TargetFramework framework) + string GetCacheDirectory (TargetFramework framework) { var derivedDataPath = UserProfile.Current.CacheDir.Combine ("DerivedData"); @@ -342,7 +380,7 @@ namespace MonoDevelop.Ide.TypeSystem return result; } - static string InternalGetCacheDirectory (FilePath filename) + string InternalGetCacheDirectory (FilePath filename) { CanonicalizePath (ref filename); var assemblyCacheRoot = GetAssemblyCacheRoot (filename); @@ -367,14 +405,14 @@ namespace MonoDevelop.Ide.TypeSystem /// The cache directory. /// The project to get the cache for. /// If set to true the creation is forced and the method doesn't return null. - public static string GetCacheDirectory (Project project, bool forceCreation = false) + public string GetCacheDirectory (Project project, bool forceCreation = false) { if (project == null) throw new ArgumentNullException (nameof(project)); return GetCacheDirectory (project.FileName, forceCreation); } - static readonly Dictionary cacheLocker = new Dictionary (); + readonly Dictionary cacheLocker = new Dictionary (); /// /// Gets the cache directory for arbitrary file names. @@ -383,7 +421,7 @@ namespace MonoDevelop.Ide.TypeSystem /// The cache directory. /// The file name to get the cache for. /// If set to true the creation is forced and the method doesn't return null. - public static string GetCacheDirectory (string fileName, bool forceCreation = false) + public string GetCacheDirectory (string fileName, bool forceCreation = false) { if (fileName == null) throw new ArgumentNullException (nameof(fileName)); @@ -416,9 +454,9 @@ namespace MonoDevelop.Ide.TypeSystem public string Version { get; set; } } - static readonly Dictionary cacheDirectoryCache = new Dictionary (); + readonly Dictionary cacheDirectoryCache = new Dictionary (); - static void CanonicalizePath (ref FilePath fileName) + void CanonicalizePath (ref FilePath fileName) { try { // There are some situations where that may cause an exception. @@ -433,7 +471,7 @@ namespace MonoDevelop.Ide.TypeSystem } } - static bool CheckCacheDirectoryIsCorrect (FilePath filename, FilePath candidate, out string result) + bool CheckCacheDirectoryIsCorrect (FilePath filename, FilePath candidate, out string result) { CanonicalizePath (ref filename); CanonicalizePath (ref candidate); @@ -471,7 +509,7 @@ namespace MonoDevelop.Ide.TypeSystem } } - static string GetAssemblyCacheRoot (string filename) + string GetAssemblyCacheRoot (string filename) { string derivedDataPath = UserProfile.Current.CacheDir.Combine ("DerivedData"); string name = Path.GetFileName (filename); @@ -485,7 +523,7 @@ namespace MonoDevelop.Ide.TypeSystem /// Use this method instead of the normal string.GetHashCode if the hash code /// is persisted to disk. /// - static int GetStableHashCode(string text) + int GetStableHashCode(string text) { unchecked { int h = 0; @@ -496,7 +534,7 @@ namespace MonoDevelop.Ide.TypeSystem } } - static IEnumerable GetPossibleCacheDirNames (string baseName) + IEnumerable GetPossibleCacheDirNames (string baseName) { int i = 0; while (i < 999999) { @@ -506,12 +544,12 @@ namespace MonoDevelop.Ide.TypeSystem throw new Exception ("Too many cache directories"); } - static string EscapeToXml (string txt) + string EscapeToXml (string txt) { return new System.Xml.Linq.XText (txt).ToString (); } - static string CreateCacheDirectory (FilePath fileName) + string CreateCacheDirectory (FilePath fileName) { CanonicalizePath (ref fileName); try { @@ -532,9 +570,9 @@ namespace MonoDevelop.Ide.TypeSystem } } - static readonly FastSerializer sharedSerializer = new FastSerializer (); + readonly FastSerializer sharedSerializer = new FastSerializer (); - static T DeserializeObject (string path) where T : class + T DeserializeObject (string path) where T : class { var t = Counters.ParserService.ObjectDeserialized.BeginTiming (path); try { @@ -553,7 +591,7 @@ namespace MonoDevelop.Ide.TypeSystem } } - static void SerializeObject (string path, object obj) + void SerializeObject (string path, object obj) { if (obj == null) throw new ArgumentNullException (nameof(obj)); @@ -579,7 +617,7 @@ namespace MonoDevelop.Ide.TypeSystem /// /// Removes all cache directories which are older than 30 days. /// - static void CleanupCache () + void CleanupCache () { string derivedDataPath = UserProfile.Current.CacheDir.Combine ("DerivedData"); IEnumerable cacheDirectories; @@ -610,7 +648,7 @@ namespace MonoDevelop.Ide.TypeSystem } } - static void RemoveCache (string cacheDir) + void RemoveCache (string cacheDir) { try { Directory.Delete (cacheDir, true); @@ -619,7 +657,7 @@ namespace MonoDevelop.Ide.TypeSystem } } - static void TouchCache (string cacheDir) + void TouchCache (string cacheDir) { try { Directory.SetLastWriteTime (cacheDir, DateTime.Now); @@ -628,7 +666,7 @@ namespace MonoDevelop.Ide.TypeSystem } } - static void StoreExtensionObject (string cacheDir, object extensionObject) + void StoreExtensionObject (string cacheDir, object extensionObject) { if (cacheDir == null) throw new ArgumentNullException (nameof(cacheDir)); @@ -649,7 +687,7 @@ namespace MonoDevelop.Ide.TypeSystem #endregion - internal static void InformDocumentClose (Microsoft.CodeAnalysis.DocumentId analysisDocument, FilePath fileName) + internal void InformDocumentClose (Microsoft.CodeAnalysis.DocumentId analysisDocument, FilePath fileName) { foreach (var w in workspaces) { if (w.GetOpenDocumentIds (analysisDocument.ProjectId).Contains (analysisDocument) ) @@ -658,7 +696,7 @@ namespace MonoDevelop.Ide.TypeSystem } } - internal static void InformDocumentOpen (Microsoft.CodeAnalysis.DocumentId analysisDocument, TextEditor editor, DocumentContext context) + internal void InformDocumentOpen (Microsoft.CodeAnalysis.DocumentId analysisDocument, TextEditor editor, DocumentContext context) { foreach (var w in workspaces) { if (w.Contains (analysisDocument.ProjectId)) { @@ -672,7 +710,7 @@ namespace MonoDevelop.Ide.TypeSystem } } - internal static void InformDocumentOpen (Microsoft.CodeAnalysis.Workspace ws, Microsoft.CodeAnalysis.DocumentId analysisDocument, TextEditor editor, DocumentContext context) + internal void InformDocumentOpen (Microsoft.CodeAnalysis.Workspace ws, Microsoft.CodeAnalysis.DocumentId analysisDocument, TextEditor editor, DocumentContext context) { if (ws == null) throw new ArgumentNullException (nameof (ws)); @@ -685,7 +723,7 @@ namespace MonoDevelop.Ide.TypeSystem static bool gotDocumentRequestError = false; - public static Microsoft.CodeAnalysis.ProjectId GetProjectId (MonoDevelop.Projects.Project project) + public Microsoft.CodeAnalysis.ProjectId GetProjectId (MonoDevelop.Projects.Project project) { if (project == null) throw new ArgumentNullException (nameof(project)); @@ -698,7 +736,7 @@ namespace MonoDevelop.Ide.TypeSystem return null; } - public static Microsoft.CodeAnalysis.Document GetCodeAnalysisDocument (Microsoft.CodeAnalysis.DocumentId docId, CancellationToken cancellationToken = default (CancellationToken)) + public Microsoft.CodeAnalysis.Document GetCodeAnalysisDocument (Microsoft.CodeAnalysis.DocumentId docId, CancellationToken cancellationToken = default (CancellationToken)) { if (docId == null) throw new ArgumentNullException (nameof(docId)); @@ -711,7 +749,7 @@ namespace MonoDevelop.Ide.TypeSystem return null; } - public static MonoDevelop.Projects.Project GetMonoProject (Microsoft.CodeAnalysis.Project project) + public MonoDevelop.Projects.Project GetMonoProject (Microsoft.CodeAnalysis.Project project) { if (project == null) throw new ArgumentNullException (nameof(project)); @@ -725,7 +763,7 @@ namespace MonoDevelop.Ide.TypeSystem } - public static MonoDevelop.Projects.Project GetMonoProject (Microsoft.CodeAnalysis.DocumentId documentId) + public MonoDevelop.Projects.Project GetMonoProject (Microsoft.CodeAnalysis.DocumentId documentId) { foreach (var w in workspaces) { var doc = w.GetDocument (documentId); @@ -739,10 +777,10 @@ namespace MonoDevelop.Ide.TypeSystem return null; } - static StatusBarIcon statusIcon = null; - static int workspacesLoading = 0; + StatusBarIcon statusIcon = null; + int workspacesLoading = 0; - internal static void ShowTypeInformationGatheringIcon () + internal void ShowTypeInformationGatheringIcon () { Gtk.Application.Invoke ((o, args) => { workspacesLoading++; @@ -756,13 +794,15 @@ namespace MonoDevelop.Ide.TypeSystem }); } - internal static void HideTypeInformationGatheringIcon (Action callback = null) + internal void HideTypeInformationGatheringIcon (Action callback = null) { Gtk.Application.Invoke ((o, args) => { workspacesLoading--; - if (workspacesLoading == 0 && statusIcon != null) { - statusIcon.Dispose (); - statusIcon = null; + if (workspacesLoading == 0) { + if (statusIcon != null) { + statusIcon.Dispose (); + statusIcon = null; + } callback?.Invoke (); } }); diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TypeSystemService_WorkspaceHandling.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TypeSystemService_WorkspaceHandling.cs index 66780c4c5b..a9b2ed71f5 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TypeSystemService_WorkspaceHandling.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TypeSystemService_WorkspaceHandling.cs @@ -1,5 +1,5 @@ // -// TypeSystemService.cs +// IdeApp.TypeSystemService.cs // // Author: // Mike Krüger @@ -39,23 +39,23 @@ using System.ComponentModel; namespace MonoDevelop.Ide.TypeSystem { - public static partial class TypeSystemService + public partial class TypeSystemService { //Internal for unit test - internal static readonly MonoDevelopWorkspace emptyWorkspace; + internal MonoDevelopWorkspace emptyWorkspace; - static object workspaceLock = new object(); - static ImmutableList workspaces = ImmutableList.Empty; - static ConcurrentDictionary> workspaceRequests = new ConcurrentDictionary> (); + object workspaceLock = new object(); + ImmutableList workspaces = ImmutableList.Empty; + ConcurrentDictionary> workspaceRequests = new ConcurrentDictionary> (); - public static ImmutableArray AllWorkspaces { + public ImmutableArray AllWorkspaces { get { return workspaces.ToImmutableArray (); } } - public static MonoDevelopWorkspace GetWorkspace (MonoDevelop.Projects.Solution solution) + public MonoDevelopWorkspace GetWorkspace (MonoDevelop.Projects.Solution solution) { if (solution == null) throw new ArgumentNullException (nameof(solution)); @@ -66,7 +66,7 @@ namespace MonoDevelop.Ide.TypeSystem return emptyWorkspace; } - public static async Task GetWorkspaceAsync (MonoDevelop.Projects.Solution solution, CancellationToken cancellationToken = default (CancellationToken)) + public async Task GetWorkspaceAsync (MonoDevelop.Projects.Solution solution, CancellationToken cancellationToken = default (CancellationToken)) { var workspace = GetWorkspace (solution); if (workspace != emptyWorkspace) @@ -85,7 +85,7 @@ namespace MonoDevelop.Ide.TypeSystem return workspace; } - internal static MonoDevelopWorkspace GetWorkspace (WorkspaceId id) + internal MonoDevelopWorkspace GetWorkspace (WorkspaceId id) { foreach (var ws in workspaces) { if (ws.Id.Equals (id)) @@ -94,9 +94,9 @@ namespace MonoDevelop.Ide.TypeSystem return emptyWorkspace; } - public static Microsoft.CodeAnalysis.Workspace Workspace { + public Microsoft.CodeAnalysis.Workspace Workspace { get { - var solution = IdeApp.ProjectOperations?.CurrentSelectedSolution; + var solution = rootWorkspace?.CurrentSelectedSolution; if (solution == null) return emptyWorkspace; return GetWorkspace (solution); @@ -104,7 +104,7 @@ namespace MonoDevelop.Ide.TypeSystem } - public static void NotifyFileChange (string fileName, string text) + public void NotifyFileChange (string fileName, string text) { try { foreach (var ws in workspaces) @@ -114,37 +114,36 @@ namespace MonoDevelop.Ide.TypeSystem } } - internal static async Task> Load (WorkspaceItem item, ProgressMonitor progressMonitor, CancellationToken cancellationToken = default (CancellationToken), bool showStatusIcon = true) + internal async Task> Load (WorkspaceItem item, ProgressMonitor progressMonitor, CancellationToken cancellationToken = default (CancellationToken), bool showStatusIcon = true) { using (Counters.ParserService.WorkspaceItemLoaded.BeginTiming ()) { - var wsList = CreateWorkspaces (item).ToList(); + var wsList = new List (); + await CreateWorkspaces (item, wsList); //If we want BeginTiming to work correctly we need to `await` await InternalLoad (wsList, progressMonitor, cancellationToken, showStatusIcon).ConfigureAwait (false); - return wsList.ToList (); + return wsList; } } - static IEnumerable CreateWorkspaces (WorkspaceItem item) + async Task CreateWorkspaces (WorkspaceItem item, List result) { if (item is MonoDevelop.Projects.Workspace ws) { - foreach (var wsItem in ws.Items) { - foreach (var mdWorkspace in CreateWorkspaces (wsItem)) { - yield return mdWorkspace; - } - } + foreach (var wsItem in ws.Items) + await CreateWorkspaces (wsItem, result); ws.ItemAdded += OnWorkspaceItemAdded; ws.ItemRemoved += OnWorkspaceItemRemoved; } else if (item is MonoDevelop.Projects.Solution solution) { - var workspace = new MonoDevelopWorkspace (solution); + var workspace = new MonoDevelopWorkspace (compositionManager.HostServices, solution, this); + await workspace.Initialize (); lock (workspaceLock) workspaces = workspaces.Add (workspace); solution.SolutionItemAdded += OnSolutionItemAdded; solution.SolutionItemRemoved += OnSolutionItemRemoved; - yield return workspace; + result.Add (workspace); } } - static async Task InternalLoad (List mdWorkspaces, ProgressMonitor progressMonitor, CancellationToken cancellationToken = default (CancellationToken), bool showStatusIcon = true) + async Task InternalLoad (List mdWorkspaces, ProgressMonitor progressMonitor, CancellationToken cancellationToken = default (CancellationToken), bool showStatusIcon = true) { foreach (var workspace in mdWorkspaces) { if (showStatusIcon) @@ -160,7 +159,7 @@ namespace MonoDevelop.Ide.TypeSystem } } - internal static void Unload (MonoDevelop.Projects.WorkspaceItem item) + internal void Unload (MonoDevelop.Projects.WorkspaceItem item) { var ws = item as MonoDevelop.Projects.Workspace; if (ws != null) { @@ -186,7 +185,7 @@ namespace MonoDevelop.Ide.TypeSystem } } - public static DocumentId GetDocumentId (MonoDevelop.Projects.Project project, string fileName) + public DocumentId GetDocumentId (MonoDevelop.Projects.Project project, string fileName) { if (project == null) throw new ArgumentNullException (nameof(project)); @@ -201,7 +200,7 @@ namespace MonoDevelop.Ide.TypeSystem return null; } - public static DocumentId GetDocumentId (Microsoft.CodeAnalysis.Workspace workspace, MonoDevelop.Projects.Project project, string fileName) + public DocumentId GetDocumentId (Microsoft.CodeAnalysis.Workspace workspace, MonoDevelop.Projects.Project project, string fileName) { if (project == null) throw new ArgumentNullException (nameof(project)); @@ -218,7 +217,7 @@ namespace MonoDevelop.Ide.TypeSystem } - public static DocumentId GetDocumentId (ProjectId projectId, string fileName) + public DocumentId GetDocumentId (ProjectId projectId, string fileName) { if (projectId == null) throw new ArgumentNullException (nameof(projectId)); @@ -231,7 +230,7 @@ namespace MonoDevelop.Ide.TypeSystem return null; } - public static IEnumerable GetDocuments (string fileName) + public IEnumerable GetDocuments (string fileName) { if (fileName == null) throw new ArgumentNullException (nameof(fileName)); @@ -245,7 +244,7 @@ namespace MonoDevelop.Ide.TypeSystem } } - public static Microsoft.CodeAnalysis.Project GetCodeAnalysisProject (MonoDevelop.Projects.Project project) + public Microsoft.CodeAnalysis.Project GetCodeAnalysisProject (MonoDevelop.Projects.Project project) { if (project == null) throw new ArgumentNullException (nameof(project)); @@ -257,7 +256,7 @@ namespace MonoDevelop.Ide.TypeSystem return null; } - public static async Task GetCodeAnalysisProjectAsync (MonoDevelop.Projects.Project project, CancellationToken cancellationToken = default (CancellationToken)) + public async Task GetCodeAnalysisProjectAsync (MonoDevelop.Projects.Project project, CancellationToken cancellationToken = default (CancellationToken)) { var parentSolution = project.ParentSolution; var workspace = await GetWorkspaceAsync (parentSolution, cancellationToken); @@ -287,7 +286,7 @@ namespace MonoDevelop.Ide.TypeSystem return proj; } - public static Task GetCompilationAsync (MonoDevelop.Projects.Project project, CancellationToken cancellationToken = default(CancellationToken)) + public Task GetCompilationAsync (MonoDevelop.Projects.Project project, CancellationToken cancellationToken = default(CancellationToken)) { if (project == null) throw new ArgumentNullException (nameof(project)); @@ -298,7 +297,7 @@ namespace MonoDevelop.Ide.TypeSystem return Task.FromResult (default(Compilation)); } - internal static Microsoft.CodeAnalysis.Project GetProject (MonoDevelop.Projects.Project project, CancellationToken cancellationToken = default (CancellationToken)) + internal Microsoft.CodeAnalysis.Project GetProject (MonoDevelop.Projects.Project project, CancellationToken cancellationToken = default (CancellationToken)) { foreach (var w in workspaces) { var projectId = w.GetProjectId (project); @@ -312,17 +311,17 @@ namespace MonoDevelop.Ide.TypeSystem return null; } - static void OnWorkspaceItemAdded (object s, MonoDevelop.Projects.WorkspaceItemEventArgs args) + void OnWorkspaceItemAdded (object s, MonoDevelop.Projects.WorkspaceItemEventArgs args) { - TypeSystemService.Load (args.Item, null).Ignore (); + Load (args.Item, null).Ignore (); } - static void OnWorkspaceItemRemoved (object s, MonoDevelop.Projects.WorkspaceItemEventArgs args) + void OnWorkspaceItemRemoved (object s, MonoDevelop.Projects.WorkspaceItemEventArgs args) { Unload (args.Item); } - static async void OnSolutionItemAdded (object sender, MonoDevelop.Projects.SolutionItemChangeEventArgs args) + async void OnSolutionItemAdded (object sender, MonoDevelop.Projects.SolutionItemChangeEventArgs args) { try { var project = args.SolutionItem as MonoDevelop.Projects.Project; @@ -354,7 +353,7 @@ namespace MonoDevelop.Ide.TypeSystem } } - static void OnSolutionItemRemoved (object sender, MonoDevelop.Projects.SolutionItemChangeEventArgs args) + void OnSolutionItemRemoved (object sender, MonoDevelop.Projects.SolutionItemChangeEventArgs args) { if (args.Reloading) { return; @@ -369,37 +368,46 @@ namespace MonoDevelop.Ide.TypeSystem } #region Tracked project handling - static readonly List outputTrackedProjects = new List (); + readonly List outputTrackedProjects = new List (); - static void IntitializeTrackedProjectHandling () + void IntitializeTrackedProjectHandling () { - AddinManager.AddExtensionNodeHandler ("/MonoDevelop/TypeSystem/OutputTracking", delegate (object sender, ExtensionNodeEventArgs args) { - var node = (TypeSystemOutputTrackingNode)args.ExtensionNode; - switch (args.Change) { - case ExtensionChange.Add: - AddOutputTrackingNode (node); - break; - case ExtensionChange.Remove: - outputTrackedProjects.Remove (node); - break; - } - }); - if (IdeApp.ProjectOperations != null) + AddinManager.AddExtensionNodeHandler ("/MonoDevelop/TypeSystem/OutputTracking", OutputTrackingExtensionChanged); + IdeApp.Initialized += (sender, e) => { IdeApp.ProjectOperations.EndBuild += HandleEndBuild; - if (IdeApp.Workspace != null) - IdeApp.Workspace.ActiveConfigurationChanged += HandleActiveConfigurationChanged; + }; + } + + void FinalizeTrackedProjectHandling () + { + AddinManager.RemoveExtensionNodeHandler ("/MonoDevelop/TypeSystem/OutputTracking", OutputTrackingExtensionChanged); + if (IdeApp.IsInitialized) + IdeApp.ProjectOperations.EndBuild -= HandleEndBuild; + } + + void OutputTrackingExtensionChanged (object sender, ExtensionNodeEventArgs args) + { + var node = (TypeSystemOutputTrackingNode)args.ExtensionNode; + switch (args.Change) { + case ExtensionChange.Add: + AddOutputTrackingNode (node); + break; + case ExtensionChange.Remove: + outputTrackedProjects.Remove (node); + break; + } } /// /// Adds an output tracking node for unit testing purposes. /// - [EditorBrowsable(EditorBrowsableState.Never)] - internal static void AddOutputTrackingNode (TypeSystemOutputTrackingNode node) + [EditorBrowsable (EditorBrowsableState.Never)] + internal void AddOutputTrackingNode (TypeSystemOutputTrackingNode node) { outputTrackedProjects.Add (node); } - static void HandleEndBuild (object sender, BuildEventArgs args) + void HandleEndBuild (object sender, BuildEventArgs args) { var project = args.SolutionItem as DotNetProject; if (project == null) @@ -407,10 +415,10 @@ namespace MonoDevelop.Ide.TypeSystem CheckProjectOutput (project, true); } - static void HandleActiveConfigurationChanged (object sender, EventArgs e) + void HandleActiveConfigurationChanged (object sender, EventArgs e) { - if (IdeApp.ProjectOperations.CurrentSelectedSolution != null) { - foreach (var pr in IdeApp.ProjectOperations.CurrentSelectedSolution.GetAllProjects ()) { + if (rootWorkspace?.CurrentSelectedSolution != null) { + foreach (var pr in rootWorkspace.CurrentSelectedSolution.GetAllProjects ()) { var project = pr as DotNetProject; if (project != null) CheckProjectOutput (project, true); @@ -418,23 +426,24 @@ namespace MonoDevelop.Ide.TypeSystem } } - internal static bool IsOutputTrackedProject (DotNetProject project) + internal bool IsOutputTrackedProject (DotNetProject project) { if (project == null) - throw new ArgumentNullException (nameof(project)); + throw new ArgumentNullException (nameof(project)); return outputTrackedProjects.Any (otp => string.Equals (otp.LanguageName, project.LanguageName, StringComparison.OrdinalIgnoreCase)) || project.GetTypeTags().Any (tag => outputTrackedProjects.Any (otp => string.Equals (otp.ProjectType, tag, StringComparison.OrdinalIgnoreCase))); } - static void CheckProjectOutput (DotNetProject project, bool autoUpdate) + void CheckProjectOutput (DotNetProject project, bool autoUpdate) { if (project == null) throw new ArgumentNullException (nameof(project)); if (IsOutputTrackedProject (project)) { if (autoUpdate) { // update documents - foreach (var openDocument in IdeApp.Workbench.Documents) { - openDocument.ReparseDocument (); + if (documentManager != null) { + foreach (var openDocument in documentManager.Documents) + openDocument.DocumentContext.ReparseDocument (); } } } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/AddinError.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/AddinError.cs new file mode 100644 index 0000000000..466ef7e3ce --- /dev/null +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/AddinError.cs @@ -0,0 +1,66 @@ +// +// IdeStartup.cs +// +// Author: +// Lluis Sanchez Gual +// +// Copyright (C) 2011 Xamarin Inc (http://xamarin.com) +// Copyright (C) 2005-2011 Novell, Inc (http://www.novell.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; + +namespace MonoDevelop.Ide +{ + public class AddinError + { + string addinFile; + Exception exception; + bool fatal; + string message; + + public AddinError (string addin, string message, Exception exception, bool fatal) + { + this.addinFile = addin; + this.message = message; + this.exception = exception; + this.fatal = fatal; + } + + public string AddinFile { + get { return addinFile; } + } + + public string Message { + get { return message; } + } + + public Exception Exception { + get { return exception; } + } + + public bool Fatal { + get { return fatal; } + } + } +} diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/DesktopService.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/DesktopService.cs index c44c8ddcc9..27fb9ebda6 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/DesktopService.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/DesktopService.cs @@ -1,5 +1,5 @@ -// -// DesktopService.cs +// +// IdeApp.DesktopService.cs // // Author: // Lluis Sanchez Gual @@ -32,17 +32,17 @@ using MonoDevelop.Core; using System.IO; using MonoDevelop.Components; using MonoDevelop.Components.MainToolbar; -using MonoDevelop.Ide.Fonts; using System.Threading.Tasks; namespace MonoDevelop.Ide { - public static class DesktopService + [DefaultServiceImplementation] + public class DesktopService : Service { - static PlatformService platformService; - static Xwt.Toolkit nativeToolkit; + PlatformService platformService; + Xwt.Toolkit nativeToolkit; - static PlatformService PlatformService { + PlatformService PlatformService { get { if (platformService == null) throw new InvalidOperationException ("Not initialized"); @@ -50,18 +50,17 @@ namespace MonoDevelop.Ide } } - public static void Initialize () + protected override Task OnInitialize (ServiceProvider serviceProvider) { - if (platformService != null) - return; - object[] platforms = AddinManager.GetExtensionObjects ("/MonoDevelop/Core/PlatformService"); + object [] platforms = AddinManager.GetExtensionObjects ("/MonoDevelop/Core/PlatformService"); if (platforms.Length > 0) - platformService = (PlatformService) platforms [0]; + platformService = (PlatformService)platforms [0]; else { platformService = new DefaultPlatformService (); LoggingService.LogFatalError ("A platform service implementation has not been found."); } PlatformService.Initialize (); + if (PlatformService.CanOpenTerminal) Runtime.ProcessService.SetExternalConsoleHandler (PlatformService.StartConsoleProcess); @@ -78,15 +77,29 @@ namespace MonoDevelop.Ide ThermalMonitor = platformService.CreateThermalMonitor (); ThermalMonitor.StatusChanged += OnThermalStatusChanged; - FontService.Initialize (); + return Task.CompletedTask; } - static void OnMemoryStatusChanged (object sender, PlatformMemoryStatusEventArgs args) + protected override Task OnDispose () + { + if (PlatformService.CanOpenTerminal) + Runtime.ProcessService.SetExternalConsoleHandler (null); + + FileService.FileRemoved -= NotifyFileRemoved; + FileService.FileRenamed -= NotifyFileRenamed; + + MemoryMonitor.StatusChanged -= OnMemoryStatusChanged; + ThermalMonitor.StatusChanged -= OnThermalStatusChanged; + + return Task.CompletedTask; + } + + void OnMemoryStatusChanged (object sender, PlatformMemoryStatusEventArgs args) { Counters.MemoryPressure.Inc (args.CounterMetadata); } - static void OnThermalStatusChanged (object sender, PlatformThermalStatusEventArgs args) + void OnThermalStatusChanged (object sender, PlatformThermalStatusEventArgs args) { Counters.ThermalNotification.Inc (args.CounterMetadata); } @@ -95,7 +108,7 @@ namespace MonoDevelop.Ide /// Returns the XWT toolkit for the native toolkit (Cocoa on Mac, WPF on Windows) /// /// The native toolkit. - public static Xwt.Toolkit NativeToolkit { + public Xwt.Toolkit NativeToolkit { get { if (nativeToolkit == null) nativeToolkit = platformService.LoadNativeToolkit (); @@ -103,63 +116,62 @@ namespace MonoDevelop.Ide } } - public static void SetGlobalProgress (double progress) + public void SetGlobalProgress (double progress) { platformService.SetGlobalProgressBar (progress); } - public static void ShowGlobalProgressIndeterminate () + public void ShowGlobalProgressIndeterminate () { platformService.ShowGlobalProgressBarIndeterminate (); } - public static void ShowGlobalProgressError () + public void ShowGlobalProgressError () { platformService.ShowGlobalProgressBarError (); } - public static IEnumerable GetApplications (string filename) + public IEnumerable GetApplications (string filename) { return PlatformService.GetApplications (filename); } - [Obsolete ("Use FontService")] - public static string DefaultMonospaceFont { + internal string DefaultMonospaceFont { get { return PlatformService.DefaultMonospaceFont; } } - public static string PlatformName { + public string PlatformName { get { return PlatformService.Name; } } [Obsolete] - public static string DefaultControlLeftRightBehavior { + public string DefaultControlLeftRightBehavior { get { return PlatformService.DefaultControlLeftRightBehavior; } } - public static void ShowUrl (string url) + public void ShowUrl (string url) { PlatformService.ShowUrl (url); } - public static void OpenFile (string filename) + public void OpenFile (string filename) { PlatformService.OpenFile (filename); } - public static void OpenFolder (FilePath folderPath, params FilePath[] selectFiles) + public void OpenFolder (FilePath folderPath, params FilePath [] selectFiles) { PlatformService.OpenFolder (folderPath, selectFiles); } - public static string GetMimeTypeForRoslynLanguage (string language) + public string GetMimeTypeForRoslynLanguage (string language) { return PlatformService.GetMimeTypeForRoslynLanguage (language); } - public static IEnumerable GetMimeTypeInheritanceChainForRoslynLanguage (string language) + public IEnumerable GetMimeTypeInheritanceChainForRoslynLanguage (string language) { var mime = GetMimeTypeForRoslynLanguage (language); if (mime == null) { @@ -168,22 +180,22 @@ namespace MonoDevelop.Ide return GetMimeTypeInheritanceChain (mime); } - public static string GetMimeTypeForUri (string uri) + public string GetMimeTypeForUri (string uri) { return PlatformService.GetMimeTypeForUri (uri); } - public static string GetMimeTypeDescription (string mimeType) + public string GetMimeTypeDescription (string mimeType) { return PlatformService.GetMimeTypeDescription (mimeType); } - public static bool GetMimeTypeIsText (string mimeType) + public bool GetMimeTypeIsText (string mimeType) { return PlatformService.GetMimeTypeIsText (mimeType); } - public static bool GetFileIsText (string file, string mimeType = null) + public bool GetFileIsText (string file, string mimeType = null) { if (mimeType == null) { mimeType = GetMimeTypeForUri (file); @@ -198,7 +210,7 @@ namespace MonoDevelop.Ide return !MonoDevelop.Core.Text.TextFileUtility.IsBinary (file); } - public async static Task GetFileIsTextAsync (string file, string mimeType = null) + public async Task GetFileIsTextAsync (string file, string mimeType = null) { if (mimeType == null) { mimeType = GetMimeTypeForUri (file); @@ -213,7 +225,7 @@ namespace MonoDevelop.Ide return false; using (var f = File.OpenRead (file)) { - var buf = new byte[8192]; + var buf = new byte [8192]; var read = f.Read (buf, 0, buf.Length); for (int i = 0; i < read; i++) if (buf [i] == 0) @@ -223,42 +235,42 @@ namespace MonoDevelop.Ide }); } - public static bool GetMimeTypeIsSubtype (string subMimeType, string baseMimeType) + public bool GetMimeTypeIsSubtype (string subMimeType, string baseMimeType) { return PlatformService.GetMimeTypeIsSubtype (subMimeType, baseMimeType); } - public static IEnumerable GetMimeTypeInheritanceChain (string mimeType) + public IEnumerable GetMimeTypeInheritanceChain (string mimeType) { return PlatformService.GetMimeTypeInheritanceChain (mimeType); } - public static IEnumerable GetMimeTypeInheritanceChainForFile (string filename) + public IEnumerable GetMimeTypeInheritanceChainForFile (string filename) { return GetMimeTypeInheritanceChain (GetMimeTypeForUri (filename)); } - public static Xwt.Drawing.Image GetIconForFile (string filename) + public Xwt.Drawing.Image GetIconForFile (string filename) { return PlatformService.GetIconForFile (filename); } - public static Xwt.Drawing.Image GetIconForFile (string filename, Gtk.IconSize size) + public Xwt.Drawing.Image GetIconForFile (string filename, Gtk.IconSize size) { return PlatformService.GetIconForFile (filename).WithSize (size); } - public static Xwt.Drawing.Image GetIconForType (string mimeType) + public Xwt.Drawing.Image GetIconForType (string mimeType) { return PlatformService.GetIconForType (mimeType); } - public static Xwt.Drawing.Image GetIconForType (string mimeType, Gtk.IconSize size) + public Xwt.Drawing.Image GetIconForType (string mimeType, Gtk.IconSize size) { return PlatformService.GetIconForType (mimeType).WithSize (size); } - internal static bool SetGlobalMenu (MonoDevelop.Components.Commands.CommandManager commandManager, + internal bool SetGlobalMenu (MonoDevelop.Components.Commands.CommandManager commandManager, string commandMenuAddinPath, string appMenuAddinPath) { return PlatformService.SetGlobalMenu (commandManager, commandMenuAddinPath, appMenuAddinPath); @@ -266,22 +278,22 @@ namespace MonoDevelop.Ide // Used for preserve the file attributes when monodevelop opens & writes a file. // This should work on unix & mac platform. - public static object GetFileAttributes (string fileName) + public object GetFileAttributes (string fileName) { return PlatformService.GetFileAttributes (fileName); } - public static void SetFileAttributes (string fileName, object attributes) + public void SetFileAttributes (string fileName, object attributes) { PlatformService.SetFileAttributes (fileName, attributes); } - public static Xwt.Rectangle GetUsableMonitorGeometry (int screenNumber, int monitorNumber) + public Xwt.Rectangle GetUsableMonitorGeometry (int screenNumber, int monitorNumber) { return PlatformService.GetUsableMonitorGeometry (screenNumber, monitorNumber); } - public static bool CanOpenTerminal { + public bool CanOpenTerminal { get { return PlatformService.CanOpenTerminal; } @@ -293,7 +305,7 @@ namespace MonoDevelop.Ide /// Working directory. /// Environment variables. /// Window title. - public static void OpenTerminal ( + public void OpenTerminal ( FilePath workingDirectory, IDictionary environmentVariables = null, string windowTitle = null) @@ -301,13 +313,14 @@ namespace MonoDevelop.Ide PlatformService.OpenTerminal (workingDirectory, environmentVariables, windowTitle); } - public static RecentFiles RecentFiles { + public RecentFiles RecentFiles { get { + PlatformService.RecentFiles.DesktopService = this; return PlatformService.RecentFiles; } } - static void NotifyFileRemoved (object sender, FileEventArgs args) + void NotifyFileRemoved (object sender, FileEventArgs args) { foreach (FileEventInfo e in args) { if (!e.IsDirectory) { @@ -316,7 +329,7 @@ namespace MonoDevelop.Ide } } - static void NotifyFileRenamed (object sender, FileCopyEventArgs args) + void NotifyFileRenamed (object sender, FileCopyEventArgs args) { if (args.IsExternal) return; @@ -328,17 +341,17 @@ namespace MonoDevelop.Ide } } - internal static string GetUpdaterUrl () + internal string GetUpdaterUrl () { return PlatformService.GetUpdaterUrl (); } - internal static IEnumerable GetUpdaterEnvironmentFlags () + internal IEnumerable GetUpdaterEnvironmentFlags () { return PlatformService.GetUpdaterEnviromentFlags (); } - internal static void StartUpdatesInstaller (FilePath installerDataFile, FilePath updatedInstallerPath) + internal void StartUpdatesInstaller (FilePath installerDataFile, FilePath updatedInstallerPath) { PlatformService.StartUpdatesInstaller (installerDataFile, updatedInstallerPath); } @@ -346,65 +359,65 @@ namespace MonoDevelop.Ide /// /// Grab the desktop focus for the window. /// - internal static void GrabDesktopFocus (Gtk.Window window) + internal void GrabDesktopFocus (Gtk.Window window) { PlatformService.GrabDesktopFocus (window); } - public static void FocusWindow (Window window) + public void FocusWindow (Window window) { - if (window != null) + if (window != null) PlatformService.FocusWindow (window); } - public static void RemoveWindowShadow (Window window) + public void RemoveWindowShadow (Window window) { PlatformService.RemoveWindowShadow (window); } - public static void SetMainWindowDecorations (Window window) + public void SetMainWindowDecorations (Window window) { PlatformService.SetMainWindowDecorations (window); } - internal static MainToolbarController CreateMainToolbar (Gtk.Window window) + internal MainToolbarController CreateMainToolbar (Gtk.Window window) { return new MainToolbarController (PlatformService.CreateMainToolbar (window)); } - internal static void AttachMainToolbar (Gtk.VBox parent, MainToolbarController toolbar) + internal void AttachMainToolbar (Gtk.VBox parent, MainToolbarController toolbar) { PlatformService.AttachMainToolbar (parent, toolbar.ToolbarView); toolbar.Initialize (); } - public static bool GetIsFullscreen (Window window) + public bool GetIsFullscreen (Window window) { return PlatformService.GetIsFullscreen (window); } - public static void SetIsFullscreen (Window window, bool isFullscreen) + public void SetIsFullscreen (Window window, bool isFullscreen) { PlatformService.SetIsFullscreen (window, isFullscreen); } - public static bool IsModalDialogRunning () + public bool IsModalDialogRunning () { return PlatformService.IsModalDialogRunning (); } - internal static void AddChildWindow (Gtk.Window parent, Gtk.Window child) + internal void AddChildWindow (Gtk.Window parent, Gtk.Window child) { PlatformService.AddChildWindow (parent, child); } - internal static void RemoveChildWindow (Gtk.Window parent, Gtk.Window child) + internal void RemoveChildWindow (Gtk.Window parent, Gtk.Window child) { PlatformService.RemoveChildWindow (parent, child); } - internal static void PlaceWindow (Gtk.Window window, int x, int y, int width, int height) + internal void PlaceWindow (Gtk.Window window, int x, int y, int width, int height) { PlatformService.PlaceWindow (window, x, y, width, height); } @@ -414,28 +427,36 @@ namespace MonoDevelop.Ide /// /// false if the user cancels exiting. /// true to reopen current workspace. - internal static void RestartIde (bool reopenWorkspace) + internal void RestartIde (bool reopenWorkspace) { PlatformService.RestartIde (reopenWorkspace); } - public static bool AccessibilityInUse { + public bool AccessibilityInUse { get { return PlatformService.AccessibilityInUse; } } - public static bool AccessibilityKeyboardFocusInUse { + public bool AccessibilityKeyboardFocusInUse { get { return PlatformService.AccessibilityKeyboardFocusInUse; } } - internal static string GetNativeRuntimeDescription () => PlatformService.GetNativeRuntimeDescription (); + internal string GetNativeRuntimeDescription () => PlatformService.GetNativeRuntimeDescription (); + + public ThermalMonitor ThermalMonitor { get; private set; } + public MemoryMonitor MemoryMonitor { get; private set; } + + IPlatformTelemetryDetails platformTelemetryDetails; - public static ThermalMonitor ThermalMonitor { get; private set; } - public static MemoryMonitor MemoryMonitor { get; private set; } - static readonly Lazy platformTelemetryDetails = new Lazy (() => PlatformService.CreatePlatformTelemetryDetails ()); - public static IPlatformTelemetryDetails PlatformTelemetry => platformTelemetryDetails.Value; + public IPlatformTelemetryDetails PlatformTelemetry { + get { + if (platformTelemetryDetails == null) + platformTelemetryDetails = PlatformService.CreatePlatformTelemetryDetails (); + return platformTelemetryDetails; + } + } } } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/Ide.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/Ide.cs index 8327ba0b14..4eaf87b1f9 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/Ide.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/Ide.cs @@ -1,4 +1,4 @@ -// +// // IdeApp.cs // // Author: @@ -38,19 +38,21 @@ using Mono.Addins.Setup; using MonoDevelop.Components.Commands; using MonoDevelop.Projects; -using MonoDevelop.Ide.Gui.Pads; using MonoDevelop.Ide.CustomTools; using System.Linq; using MonoDevelop.Ide.Gui; -using MonoDevelop.Ide.Desktop; using System.Collections.Generic; using MonoDevelop.Components.AutoTest; using MonoDevelop.Ide.TypeSystem; using MonoDevelop.Ide.Extensions; using MonoDevelop.Ide.Templates; using System.Threading.Tasks; -using MonoDevelop.Ide.RoslynServices.Options; using MonoDevelop.Ide.RoslynServices; +using MonoDevelop.Ide.Tasks; +using MonoDevelop.Ide.TextEditing; +using MonoDevelop.Ide.Navigation; +using MonoDevelop.Ide.Fonts; +using MonoDevelop.Ide.Composition; namespace MonoDevelop.Ide { @@ -58,14 +60,10 @@ namespace MonoDevelop.Ide { static bool isInitialized; static Workbench workbench; - static ProjectOperations projectOperations; static HelpOperations helpOperations; static CommandManager commandService; - static IdeServices ideServices; - static RootWorkspace workspace; - readonly static IdePreferences preferences; + static TypeSystemService typeSystemService; - static bool isMainRunning; static bool isInitialRun; static bool isInitialRunAfterUpgrade; static Version upgradedFromVersion; @@ -131,23 +129,14 @@ namespace MonoDevelop.Ide get { return CommandService.ApplicationHasFocus; } } - static IdeApp () - { - preferences = new IdePreferences (); - } - public static Workbench Workbench { get { return workbench; } } - - public static ProjectOperations ProjectOperations { - get { return projectOperations; } - } - - public static RootWorkspace Workspace { - get { return workspace; } - } - + + public static ProjectOperations ProjectOperations => IdeServices.ProjectOperations; + + public static RootWorkspace Workspace => IdeServices.Workspace; + public static HelpOperations HelpOperations { get { return helpOperations; } } @@ -155,12 +144,16 @@ namespace MonoDevelop.Ide public static CommandManager CommandService { get { return commandService; } } - - public static IdeServices Services { - get { return ideServices; } + + public static TypeSystemService TypeSystemService { + get { + if (typeSystemService == null) + typeSystemService = Runtime.GetService ().Result; + return typeSystemService; + } } - public static IdePreferences Preferences => preferences; + public static IdePreferences Preferences { get; } = new IdePreferences (); public static bool IsInitialized { get { @@ -203,22 +196,30 @@ namespace MonoDevelop.Ide } } - public static void Initialize (ProgressMonitor monitor) => Initialize (monitor, false); - - internal static void Initialize (ProgressMonitor monitor, bool hideWelcomePage) + public static async Task Initialize (ProgressMonitor monitor) { // Already done in IdeSetup, but called again since unit tests don't use IdeSetup. DispatchService.Initialize (); + commandService = await Runtime.GetService (); + await Runtime.GetService (); + await Runtime.GetService (); + await Runtime.GetService (); + Counters.Initialization.Trace ("Creating Workbench"); workbench = new Workbench (); + Counters.Initialization.Trace ("Creating Root Workspace"); - workspace = new RootWorkspace (); + await Runtime.GetService (); + Counters.Initialization.Trace ("Creating Services"); - projectOperations = new ProjectOperations (); + await Runtime.GetService (); helpOperations = new HelpOperations (); - commandService = new CommandManager (); - ideServices = new IdeServices (); + + await Runtime.GetService (); + await Runtime.GetService (); + await Runtime.GetService (); + CustomToolService.Init (); commandService.CommandTargetScanStarted += CommandServiceCommandTargetScanStarted; @@ -246,7 +247,7 @@ namespace MonoDevelop.Ide monitor.Step (1); Counters.Initialization.Trace ("Initializing Workbench"); - workbench.Initialize (monitor); + await workbench.Initialize (monitor); monitor.Step (1); Counters.Initialization.Trace ("Initializing WelcomePage service"); @@ -263,13 +264,7 @@ namespace MonoDevelop.Ide commandService.EnableIdleUpdate = true; if (Customizer != null) - Customizer.OnIdeInitialized (hideWelcomePage); - - // Startup commands - Counters.Initialization.Trace ("Running Startup Commands"); - AddinManager.AddExtensionNodeHandler ("/MonoDevelop/Ide/StartupHandlers", OnExtensionChanged); - monitor.Step (1); - monitor.EndTask (); + Customizer.OnIdeInitialized (); // Set initial run flags Counters.Initialization.Trace ("Upgrading Settings"); @@ -290,16 +285,9 @@ namespace MonoDevelop.Ide PropertyService.Set ("MonoDevelop.Core.LastRunVersion", Runtime.Version.ToString ()); PropertyService.SaveProperties (); } - - // The ide is now initialized - isInitialized = true; - - if (initializedEvent != null) { - initializedEvent (null, EventArgs.Empty); - initializedEvent = null; - } - + monitor.EndTask (); + //FIXME: we should really make this on-demand. consumers can display a "loading help cache" message like VS MonoDevelop.Projects.HelpService.AsyncInitialize (); @@ -311,6 +299,28 @@ namespace MonoDevelop.Ide AutoTestService.NotifyEvent ("MonoDevelop.Ide.IdeStart"); Gtk.LinkButton.SetUriHook ((button, uri) => Xwt.Desktop.OpenUrl (uri)); + + // Start initializing the type system service in the background + Runtime.GetService ().Ignore (); + + // The ide is now initialized + OnInitialized (); + } + + static void OnInitialized () + { + // The ide is now initialized + + isInitialized = true; + + if (initializedEvent != null) { + initializedEvent (null, EventArgs.Empty); + initializedEvent = null; + } + + // Startup commands + Counters.Initialization.Trace ("Running Startup Commands"); + AddinManager.AddExtensionNodeHandler ("/MonoDevelop/Ide/StartupHandlers", OnExtensionChanged); } static void KeyBindingFailed (object sender, KeyBindingFailedEventArgs e) @@ -334,6 +344,14 @@ namespace MonoDevelop.Ide return false; } + public static void BringToFront () + { + Initialized += (sender, e) => { + if (!Ide.WelcomePage.WelcomePageService.HasWindowImplementation) + Workbench.Present (); + }; + } + //this method is MIT/X11, 2009, Michael Hutchinson / (c) Novell public static void OpenFiles (IEnumerable files) { @@ -427,16 +445,7 @@ namespace MonoDevelop.Ide } } - public static void Run () - { - // finally run the workbench window ... - isMainRunning = true; - Gtk.Application.Run (); - } - - public static bool IsRunning { - get { return isMainRunning; } - } + public static bool IsRunning { get; internal set; } public static bool IsExiting { get; private set; } @@ -448,7 +457,6 @@ namespace MonoDevelop.Ide IsExiting = true; if (await workbench.Close ()) { Gtk.Application.Quit (); - isMainRunning = false; return true; } IsExiting = false; @@ -471,11 +479,11 @@ namespace MonoDevelop.Ide PropertyService.Set ("MonoDevelop.Core.RestartRequested", true); try { - DesktopService.RestartIde (reopenWorkspace); + IdeServices.DesktopService.RestartIde (reopenWorkspace); } catch (Exception ex) { LoggingService.LogError ("Restarting IDE failed", ex); } - // return true here even if DesktopService.RestartIde has failed, + // return true here even if IdeServices.DesktopService.RestartIde has failed, // because the Ide has already been closed. return true; } @@ -542,7 +550,7 @@ namespace MonoDevelop.Ide return; // If a modal dialog is open, try again later - if (DesktopService.IsModalDialogRunning ()) { + if (IdeServices.DesktopService.IsModalDialogRunning ()) { DispatchIdleActions (1000); return; } @@ -627,19 +635,4 @@ namespace MonoDevelop.Ide } } } - - public class IdeServices - { - readonly Lazy templatingService = new Lazy (() => new TemplatingService ()); - - public ProjectService ProjectService { - get { return MonoDevelop.Projects.Services.ProjectService; } - } - - public TemplatingService TemplatingService { - get { return templatingService.Value; } - } - - internal RoslynService RoslynService { get; } = new RoslynService (); - } } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeInstanceConnection.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeInstanceConnection.cs new file mode 100644 index 0000000000..8e476b33c9 --- /dev/null +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeInstanceConnection.cs @@ -0,0 +1,141 @@ +// +// IdeInstanceConnection.cs +// +// Author: +// Lluis Sanchez +// +// Copyright (c) 2019 Microsoft +// +// 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 System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Text; +using Mono.Unix; +using MonoDevelop.Core; +using MonoDevelop.Ide.Extensions; +using MonoDevelop.Ide.Gui; + +namespace MonoDevelop.Ide +{ + class IdeInstanceConnection + { + const int ipcBasePort = 40000; + + string socket_filename; + Socket listen_socket = null; + EndPoint ep; + + public event EventHandler FileOpenRequested; + + public void Initialize (bool ipcTcp) + { + if (ipcTcp) { + listen_socket = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP); + ep = new IPEndPoint (IPAddress.Loopback, ipcBasePort + HashSdbmBounded (Environment.UserName)); + } else { + socket_filename = "/tmp/md-" + Environment.GetEnvironmentVariable ("USER") + "-socket"; + listen_socket = new Socket (AddressFamily.Unix, SocketType.Stream, ProtocolType.IP); + ep = new UnixEndPoint (socket_filename); + } + } + + public bool TryConnect (StartupInfo startupInfo) + { + try { + StringBuilder builder = new StringBuilder (); + foreach (var file in startupInfo.RequestedFileList) { + builder.AppendFormat ("{0};{1};{2}\n", file.FileName, file.Line, file.Column); + } + listen_socket.Connect (ep); + listen_socket.Send (Encoding.UTF8.GetBytes (builder.ToString ())); + return true; + } catch { + // Reset the socket + if (null != socket_filename && File.Exists (socket_filename)) + File.Delete (socket_filename); + return false; + } + } + + public void StartListening () + { + // FIXME: we should probably track the last 'selected' one + // and do this more cleanly + try { + listen_socket.Bind (ep); + listen_socket.Listen (5); + listen_socket.BeginAccept (new AsyncCallback (ListenCallback), listen_socket); + } catch { + // Socket already in use + } + } + + void ListenCallback (IAsyncResult state) + { + var files = new List (); + + Socket sock = (Socket)state.AsyncState; + + Socket client = sock.EndAccept (state); + ((Socket)state.AsyncState).BeginAccept (new AsyncCallback (ListenCallback), sock); + byte [] buf = new byte [1024]; + client.Receive (buf); + foreach (string filename in Encoding.UTF8.GetString (buf).Split ('\n')) { + string trimmed = filename.Trim (); + string file = ""; + foreach (char c in trimmed) { + if (c == 0x0000) + continue; + file += c; + } + files.Add (file); + } + if (files.Count > 0) { + GLib.Idle.Add (() => { + FileOpenRequested?.Invoke (this, new FileEventArgs (files, false)); + return false; + }); + } + } + + public void Dispose () + { + // unloading services + if (null != socket_filename) + File.Delete (socket_filename); + } + + /// SDBM-style hash, bounded to a range of 1000. + static int HashSdbmBounded (string input) + { + ulong hash = 0; + for (int i = 0; i < input.Length; i++) { + unchecked { + hash = ((ulong)input [i]) + (hash << 6) + (hash << 16) - hash; + } + } + + return (int)(hash % 1000); + } + + } +} diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdePreferences.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdePreferences.cs index a83a27648a..aa19d3d248 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdePreferences.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdePreferences.cs @@ -34,6 +34,7 @@ using MonoDevelop.Ide.Editor; using MonoDevelop.Ide.Editor.Highlighting; using System.Linq; using MonoDevelop.Ide.RoslynServices.Options; +using MonoDevelop.Ide.TypeSystem; namespace MonoDevelop.Ide { @@ -67,12 +68,12 @@ namespace MonoDevelop.Ide public class IdePreferences { - internal RoslynPreferences Roslyn { get; } internal IdePreferences () { - Roslyn = new RoslynPreferences (); } + internal RoslynPreferences Roslyn => TypeSystemService.Preferences; + public readonly ConfigurationProperty EnableInstrumentation = Runtime.Preferences.EnableInstrumentation; public readonly ConfigurationProperty EnableAutomatedTesting = Runtime.Preferences.EnableAutomatedTesting; @@ -89,39 +90,14 @@ namespace MonoDevelop.Ide public readonly ConfigurationProperty DefaultHideMessageBubbles = ConfigurationProperty.Create ("MonoDevelop.Ide.DefaultHideMessageBubbles", false); public readonly ConfigurationProperty ShowMessageBubbles = ConfigurationProperty.Create ("MonoDevelop.Ide.NewShowMessageBubbles", MonoDevelop.Ide.ShowMessageBubbles.ForErrorsAndWarnings); - public readonly ConfigurationProperty DefaultTargetRuntime = new DefaultTargetRuntimeProperty (); - - class DefaultTargetRuntimeProperty: ConfigurationProperty - { - ConfigurationProperty defaultTargetRuntimeText = ConfigurationProperty.Create ("MonoDevelop.Ide.DefaultTargetRuntime", "__current"); - - public DefaultTargetRuntimeProperty () - { - defaultTargetRuntimeText.Changed += (s,e) => OnChanged (); - } - - protected override TargetRuntime OnGetValue () - { - string id = defaultTargetRuntimeText.Value; - if (id == "__current") - return Runtime.SystemAssemblyService.CurrentRuntime; - TargetRuntime tr = Runtime.SystemAssemblyService.GetTargetRuntime (id); - return tr ?? Runtime.SystemAssemblyService.CurrentRuntime; - } - - protected override bool OnSetValue (TargetRuntime value) - { - defaultTargetRuntimeText.Value = value.IsRunning ? "__current" : value.Id; - return true; - } - } + public ConfigurationProperty DefaultTargetRuntime => RootWorkspace.DefaultTargetRuntime; public readonly ConfigurationProperty UserInterfaceLanguage = Runtime.Preferences.UserInterfaceLanguage; public readonly ConfigurationProperty UserInterfaceThemeName = ConfigurationProperty.Create ("MonoDevelop.Ide.UserInterfaceTheme", Platform.IsLinux ? "" : "Light"); public readonly ConfigurationProperty WorkbenchCompactness = ConfigurationProperty.Create ("MonoDevelop.Ide.WorkbenchCompactness", MonoDevelop.Ide.WorkbenchCompactness.Normal); public readonly ConfigurationProperty LoadPrevSolutionOnStartup = ConfigurationProperty.Create ("SharpDevelop.LoadPrevProjectOnStartup", false); public readonly ConfigurationProperty CreateFileBackupCopies = ConfigurationProperty.Create ("SharpDevelop.CreateBackupCopy", false); - public readonly ConfigurationProperty LoadDocumentUserProperties = ConfigurationProperty.Create ("SharpDevelop.LoadDocumentProperties", true); + public ConfigurationProperty LoadDocumentUserProperties => IdeApp.Workbench.DocumentManager.Preferences.LoadDocumentUserProperties; public readonly ConfigurationProperty EnableDocumentSwitchDialog = ConfigurationProperty.Create ("MonoDevelop.Core.Gui.EnableDocumentSwitchDialog", true); public readonly ConfigurationProperty ShowTipsAtStartup = ConfigurationProperty.Create ("MonoDevelop.Core.Gui.Dialog.TipOfTheDayView.ShowTipsAtStartup", false); @@ -130,12 +106,14 @@ namespace MonoDevelop.Ide /// /// Font to use for treeview pads. Returns null if no custom font is set. /// - public readonly ConfigurationProperty CustomPadFont = FontService.GetFontProperty ("Pad"); + public ConfigurationProperty CustomPadFont => customPadFont.Value; + readonly Lazy> customPadFont = new Lazy> (() => IdeApp.FontService.GetFontProperty ("Pad")); /// /// Font to use for output pads. Returns null if no custom font is set. /// - public readonly ConfigurationProperty CustomOutputPadFont = FontService.GetFontProperty ("OutputPad"); + public ConfigurationProperty CustomOutputPadFont => customOutputPadFont.Value; + readonly Lazy> customOutputPadFont = new Lazy> (() => IdeApp.FontService.GetFontProperty ("OutputPad")); public readonly ConfigurationProperty EnableCompletionCategoryMode = ConfigurationProperty.Create ("EnableCompletionCategoryMode", false); public readonly ConfigurationProperty ForceSuggestionMode = ConfigurationProperty.Create ("ForceCompletionSuggestionMode", false); @@ -158,7 +136,7 @@ namespace MonoDevelop.Ide internal static readonly string DefaultLightColorScheme = "Light"; internal static readonly string DefaultDarkColorScheme = "Dark"; - public readonly ConfigurationProperty EnableSourceAnalysis = ConfigurationProperty.Create ("MonoDevelop.AnalysisCore.AnalysisEnabled_V2", true); + public ConfigurationProperty EnableSourceAnalysis => TypeSystemService.EnableSourceAnalysis; public readonly ConfigurationProperty EnableUnitTestEditorIntegration = ConfigurationProperty.Create ("Testing.EnableUnitTestEditorIntegration", false); public readonly SchemeConfigurationProperty ColorScheme = new SchemeConfigurationProperty ("ColorScheme", DefaultLightColorScheme, DefaultDarkColorScheme); @@ -231,7 +209,32 @@ namespace MonoDevelop.Ide } } } - + + class DefaultTargetRuntimeProperty : ConfigurationProperty + { + ConfigurationProperty defaultTargetRuntimeText = ConfigurationProperty.Create ("MonoDevelop.Ide.DefaultTargetRuntime", "__current"); + + public DefaultTargetRuntimeProperty () + { + defaultTargetRuntimeText.Changed += (s, e) => OnChanged (); + } + + protected override TargetRuntime OnGetValue () + { + string id = defaultTargetRuntimeText.Value; + if (id == "__current") + return Runtime.SystemAssemblyService.CurrentRuntime; + TargetRuntime tr = Runtime.SystemAssemblyService.GetTargetRuntime (id); + return tr ?? Runtime.SystemAssemblyService.CurrentRuntime; + } + + protected override bool OnSetValue (TargetRuntime value) + { + defaultTargetRuntimeText.Value = value.IsRunning ? "__current" : value.Id; + return true; + } + } + public enum BeforeCompileAction { Nothing, SaveAllFiles, diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeServices.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeServices.cs new file mode 100644 index 0000000000..a6db7a3067 --- /dev/null +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeServices.cs @@ -0,0 +1,113 @@ +// +// IdeApp.cs +// +// Author: +// Lluis Sanchez Gual +// +// Copyright (C) 2005 Novell, Inc (http://www.novell.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 MonoDevelop.Core; + +using MonoDevelop.Projects; +using MonoDevelop.Ide.Gui; +using MonoDevelop.Ide.Templates; +using System.Threading.Tasks; +using MonoDevelop.Ide.RoslynServices; +using MonoDevelop.Ide.Tasks; +using MonoDevelop.Ide.TextEditing; +using MonoDevelop.Ide.Navigation; +using MonoDevelop.Ide.Fonts; +using MonoDevelop.Ide.TypeSystem; +using MonoDevelop.Ide.Gui.Documents; + +namespace MonoDevelop.Ide +{ + public static class IdeServices + { + static TextEditorService textEditorService; + static NavigationHistoryService navigationHistoryManager; + static DisplayBindingService displayBindingService; + static FontService fontService; + static TypeSystemService typeSystemService; + static DesktopService desktopService; + static DocumentManager documentManager; + static RootWorkspace workspace; + static ProgressMonitorManager progressMonitorManager; + static TaskService taskService; + static ProjectOperations projectOperations; + + static IdeServices () + { + Runtime.ServiceProvider.WhenServiceInitialized (s => textEditorService = s); + Runtime.ServiceProvider.WhenServiceInitialized (s => navigationHistoryManager = s); + Runtime.ServiceProvider.WhenServiceInitialized (s => displayBindingService = s); + Runtime.ServiceProvider.WhenServiceInitialized (s => fontService = s); + Runtime.ServiceProvider.WhenServiceInitialized (s => typeSystemService = s); + Runtime.ServiceProvider.WhenServiceInitialized (s => desktopService = s); + Runtime.ServiceProvider.WhenServiceInitialized (s => documentManager = s); + Runtime.ServiceProvider.WhenServiceInitialized (s => workspace = s); + Runtime.ServiceProvider.WhenServiceInitialized (s => progressMonitorManager = s); + Runtime.ServiceProvider.WhenServiceInitialized (s => taskService = s); + Runtime.ServiceProvider.WhenServiceInitialized (s => projectOperations = s); + } + + public static TextEditorService TextEditorService => Initialized (textEditorService); + + public static NavigationHistoryService NavigationHistoryService => Initialized (navigationHistoryManager); + + public static DisplayBindingService DisplayBindingService => Initialized (displayBindingService); + + public static FontService FontService => Initialized (fontService); + + public static TypeSystemService TypeSystemService => Initialized (typeSystemService); + + public static DesktopService DesktopService => Initialized (desktopService); + + public static RootWorkspace Workspace => Initialized (workspace); + + public static ProgressMonitorManager ProgressMonitorManager => Initialized (progressMonitorManager); + + static Lazy templatingService = new Lazy (() => new TemplatingService ()); + + public static ProjectService ProjectService => MonoDevelop.Projects.Services.ProjectService; + + public static TemplatingService TemplatingService => templatingService.Value; + + public static DocumentManager DocumentManager => Initialized (documentManager); + + public static TaskService TaskService => Initialized (taskService); + + public static ProjectOperations ProjectOperations => Initialized (projectOperations); + + static T Initialized (T s) where T : class + { + if (s == null) + throw new InvalidOperationException ("Service " + typeof (T) + " not initialized"); + return s; + } + } +} diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeStartup.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeStartup.cs index 0b8064d536..f02398a7d7 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeStartup.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeStartup.cs @@ -1,4 +1,4 @@ -// +// // IdeStartup.cs // // Author: @@ -30,20 +30,13 @@ using System; using System.IO; -using System.Collections; using System.Reflection; using System.Threading; -using System.Net; using System.Net.Sockets; using System.Text; using System.Text.RegularExpressions; using System.Linq; -using Microsoft.CodeAnalysis.Utilities; -using Microsoft.CodeAnalysis.Editor.Shared.Utilities; - -using Mono.Unix; - using Mono.Addins; using MonoDevelop.Components.Commands; using MonoDevelop.Core; @@ -58,15 +51,17 @@ using MonoDevelop.Components.Extensions; using MonoDevelop.Ide.Desktop; using System.Threading.Tasks; using MonoDevelop.Components; +using MonoDevelop.Ide.Gui.Shell; +using MonoDevelop.Ide.Composition; namespace MonoDevelop.Ide { public class IdeStartup: IApplication { - Socket listen_socket = null; + static IdeInstanceConnection instanceConnection; + List errorsList = new List (); bool initialized; - static readonly int ipcBasePort = 40000; static Stopwatch startupTimer = new Stopwatch (); static Stopwatch startupSectionTimer = new Stopwatch (); static Stopwatch timeToCodeTimer = new Stopwatch (); @@ -82,7 +77,7 @@ namespace MonoDevelop.Ide return Task.FromResult (options.Error != null? -1 : 0); return Task.FromResult (Run (options)); } - + int Run (MonoDevelopOptions options) { LoggingService.LogInfo ("Starting {0} {1}", BrandingService.ApplicationLongName, IdeVersionInfo.MonoDevelopVersion); @@ -100,13 +95,11 @@ namespace MonoDevelop.Ide LoggingService.LogInfo ("Operating System: {0}", SystemInformation.GetOperatingSystemDescription ()); - if (!Platform.IsWindows) { - // The assembly resolver for MSBuild 15 assemblies needs to be defined early on. - // Whilst Runtime.Initialize loads the MSBuild 15 assemblies from Mono this seems - // to be too late to prevent the MEF composition and the static registrar from - // failing to load the MonoDevelop.Ide assembly which now uses MSBuild 15 assemblies. - ResolveMSBuildAssemblies (); - } + // The assembly resolver for MSBuild 15 assemblies needs to be defined early on. + // Whilst Runtime.Initialize loads the MSBuild 15 assemblies from Mono this seems + // to be too late to prevent the MEF composition and the static registrar from + // failing to load the MonoDevelop.Ide assembly which now uses MSBuild 15 assemblies. + ResolveMSBuildAssemblies (); Counters.Initialization.BeginTiming (); @@ -124,9 +117,15 @@ namespace MonoDevelop.Ide // explicit GLib type system initialization for GLib < 2.36 before any other type system access GLib.GType.Init (); + var args = options.RemainingArgs.ToArray (); + + IdeTheme.InitializeGtk (BrandingService.ApplicationName, ref args); + + var startupInfo = new StartupInfo (options, args); + IdeApp.Customizer = options.IdeCustomizer ?? new IdeCustomizer (); try { - IdeApp.Customizer.Initialize (); + IdeApp.Customizer.Initialize (startupInfo); } catch (UnauthorizedAccessException ua) { LoggingService.LogError ("Unauthorized access: " + ua.Message); return 1; @@ -138,22 +137,19 @@ namespace MonoDevelop.Ide LoggingService.LogError ("Error initialising GLib logging.", ex); } - var args = options.RemainingArgs.ToArray (); - IdeTheme.InitializeGtk (BrandingService.ApplicationName, ref args); - - sectionTimings["GtkInitialization"] = startupSectionTimer.ElapsedMilliseconds; + sectionTimings ["GtkInitialization"] = startupSectionTimer.ElapsedMilliseconds; startupSectionTimer.Restart (); LoggingService.LogInfo ("Using GTK+ {0}", IdeVersionInfo.GetGtkVersion ()); // XWT initialization - FilePath p = typeof(IdeStartup).Assembly.Location; - Runtime.LoadAssemblyFrom (p.ParentDirectory.Combine("Xwt.Gtk.dll")); + FilePath p = typeof (IdeStartup).Assembly.Location; + Runtime.LoadAssemblyFrom (p.ParentDirectory.Combine ("Xwt.Gtk.dll")); Xwt.Application.InitializeAsGuest (Xwt.ToolkitType.Gtk); - Xwt.Toolkit.CurrentEngine.RegisterBackend (); - Xwt.Toolkit.CurrentEngine.RegisterBackend (); + Xwt.Toolkit.CurrentEngine.RegisterBackend (); + Xwt.Toolkit.CurrentEngine.RegisterBackend (); IdeTheme.SetupXwtTheme (); - sectionTimings["XwtInitialization"] = startupSectionTimer.ElapsedMilliseconds; + sectionTimings ["XwtInitialization"] = startupSectionTimer.ElapsedMilliseconds; startupSectionTimer.Restart (); //default to Windows IME on Windows @@ -163,34 +159,34 @@ namespace MonoDevelop.Ide if (string.IsNullOrEmpty (val.Val as string)) GtkWorkarounds.SetProperty (settings, "gtk-im-module", new GLib.Value ("ime")); } - - string socket_filename = null; - EndPoint ep = null; - + DispatchService.Initialize (); // Set a synchronization context for the main gtk thread SynchronizationContext.SetSynchronizationContext (DispatchService.SynchronizationContext); Runtime.MainSynchronizationContext = SynchronizationContext.Current; - sectionTimings["DispatchInitialization"] = startupSectionTimer.ElapsedMilliseconds; + sectionTimings ["DispatchInitialization"] = startupSectionTimer.ElapsedMilliseconds; startupSectionTimer.Restart (); // Initialize Roslyn's synchronization context RoslynServices.RoslynService.Initialize (); - sectionTimings["RoslynInitialization"] = startupSectionTimer.ElapsedMilliseconds; + sectionTimings ["RoslynInitialization"] = startupSectionTimer.ElapsedMilliseconds; startupSectionTimer.Restart (); AddinManager.AddinLoadError += OnAddinError; - var startupInfo = new StartupInfo (args); + Counters.Initialization.Trace ("Initializing Runtime"); + Runtime.Initialize (true); + + // Register services used by the IDE + + RegisterServices (); // If a combine was specified, force --newwindow. if (!options.NewWindow && startupInfo.HasFiles) { - Counters.Initialization.Trace ("Pre-Initializing Runtime to load files in existing window"); - Runtime.Initialize (true); foreach (var file in startupInfo.RequestedFileList) { if (MonoDevelop.Projects.Services.ProjectService.IsWorkspaceItemFile (file.FileName)) { options.NewWindow = true; @@ -198,9 +194,13 @@ namespace MonoDevelop.Ide } } } - - Counters.Initialization.Trace ("Initializing Runtime"); - Runtime.Initialize (true); + + instanceConnection = new IdeInstanceConnection (); + instanceConnection.Initialize (options.IpcTcp); + + // If not opening a combine, connect to existing monodevelop and pass filename(s) and exit + if (!options.NewWindow && startupInfo.HasFiles && instanceConnection.TryConnect (startupInfo)) + return 0; sectionTimings ["RuntimeInitialization"] = startupSectionTimer.ElapsedMilliseconds; startupSectionTimer.Restart (); @@ -209,54 +209,56 @@ namespace MonoDevelop.Ide startupInfo.Restarted = restartRequested; PropertyService.Set ("MonoDevelop.Core.RestartRequested", false); - IdeApp.Customizer.OnCoreInitialized (); - Counters.Initialization.Trace ("Initializing theme"); IdeTheme.SetupGtkTheme (); - sectionTimings["ThemeInitialized"] = startupSectionTimer.ElapsedMilliseconds; + IdeApp.Customizer.OnCoreInitialized (); + + sectionTimings ["ThemeInitialized"] = startupSectionTimer.ElapsedMilliseconds; startupSectionTimer.Restart (); + IdeApp.IsRunning = true; + + // Run the main loop + Gtk.Application.Invoke ((s, e) => { + MainLoop (options, startupInfo).Ignore (); + }); + Gtk.Application.Run (); + + IdeApp.IsRunning = false; + + IdeApp.Customizer.OnIdeShutdown (); + + instanceConnection.Dispose (); + + lockupCheckRunning = false; + Runtime.Shutdown (); + + IdeApp.Customizer.OnCoreShutdown (); + + InstrumentationService.Stop (); + + MonoDevelop.Components.GtkWorkarounds.Terminate (); + + return 0; + } + + async Task MainLoop (MonoDevelopOptions options, StartupInfo startupInfo) + { ProgressMonitor monitor = new MonoDevelop.Core.ProgressMonitoring.ConsoleProgressMonitor (); monitor.BeginTask (GettextCatalog.GetString ("Starting {0}", BrandingService.ApplicationName), 2); //make sure that the platform service is initialised so that the Mac platform can subscribe to open-document events Counters.Initialization.Trace ("Initializing Platform Service"); - DesktopService.Initialize (); + await Runtime.GetService (); sectionTimings["PlatformInitialization"] = startupSectionTimer.ElapsedMilliseconds; startupSectionTimer.Restart (); monitor.Step (1); - if (options.IpcTcp) { - listen_socket = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP); - ep = new IPEndPoint (IPAddress.Loopback, ipcBasePort + HashSdbmBounded (Environment.UserName)); - } else { - socket_filename = "/tmp/md-" + Environment.GetEnvironmentVariable ("USER") + "-socket"; - listen_socket = new Socket (AddressFamily.Unix, SocketType.Stream, ProtocolType.IP); - ep = new UnixEndPoint (socket_filename); - } - - // If not opening a combine, connect to existing monodevelop and pass filename(s) and exit - if (!options.NewWindow && startupInfo.HasFiles) { - try { - StringBuilder builder = new StringBuilder (); - foreach (var file in startupInfo.RequestedFileList) { - builder.AppendFormat ("{0};{1};{2}\n", file.FileName, file.Line, file.Column); - } - listen_socket.Connect (ep); - listen_socket.Send (Encoding.UTF8.GetBytes (builder.ToString ())); - return 0; - } catch { - // Reset the socket - if (null != socket_filename && File.Exists (socket_filename)) - File.Delete (socket_filename); - } - } - Counters.Initialization.Trace ("Checking System"); CheckFileWatcher (); @@ -281,7 +283,7 @@ namespace MonoDevelop.Ide Counters.Initialization.Trace ("Initializing IdeApp"); hideWelcomePage = startupInfo.HasFiles; - IdeApp.Initialize (monitor, hideWelcomePage); + await IdeApp.Initialize (monitor); sectionTimings ["AppInitialization"] = startupSectionTimer.ElapsedMilliseconds; startupSectionTimer.Restart (); @@ -302,10 +304,10 @@ namespace MonoDevelop.Ide // load previous combine RecentFile openedProject = null; if (IdeApp.Preferences.LoadPrevSolutionOnStartup && !startupInfo.HasSolutionFile && !IdeApp.Workspace.WorkspaceItemIsOpening && !IdeApp.Workspace.IsOpen) { - openedProject = DesktopService.RecentFiles.MostRecentlyUsedProject; + openedProject = IdeServices.DesktopService.RecentFiles.MostRecentlyUsedProject; if (openedProject != null) { var metadata = GetOpenWorkspaceOnStartupMetadata (); - IdeApp.Workspace.OpenWorkspaceItem (openedProject.FileName, true, true, metadata).ContinueWith (t => IdeApp.OpenFiles (startupInfo.RequestedFileList, metadata), TaskScheduler.FromCurrentSynchronizationContext ()); + IdeApp.Workspace.OpenWorkspaceItem (openedProject.FileName, true, true, metadata).ContinueWith (t => IdeApp.OpenFiles (startupInfo.RequestedFileList, metadata), TaskScheduler.FromCurrentSynchronizationContext ()).Ignore(); startupInfo.OpenedRecentProject = true; } } @@ -341,15 +343,12 @@ namespace MonoDevelop.Ide sectionTimings["BasicInitializationCompleted"] = startupSectionTimer.ElapsedMilliseconds; startupSectionTimer.Restart (); - // FIXME: we should probably track the last 'selected' one - // and do this more cleanly - try { - listen_socket.Bind (ep); - listen_socket.Listen (5); - listen_socket.BeginAccept (new AsyncCallback (ListenCallback), listen_socket); - } catch { - // Socket already in use - } + instanceConnection.FileOpenRequested += (sender, a) => { + foreach (var e in a) + OpenFile (e.FileName); + }; + + instanceConnection.StartListening (); sectionTimings["SocketInitialization"] = startupSectionTimer.ElapsedMilliseconds; startupSectionTimer.Restart (); @@ -392,25 +391,16 @@ namespace MonoDevelop.Ide CreateStartupMetadata (startupInfo, sectionTimings); GLib.Idle.Add (OnIdle); - IdeApp.Run (); - - IdeApp.Customizer.OnIdeShutdown (); - - // unloading services - if (null != socket_filename) - File.Delete (socket_filename); - lockupCheckRunning = false; - Runtime.Shutdown (); - IdeApp.Customizer.OnCoreShutdown (); - - InstrumentationService.Stop (); - - MonoDevelop.Components.GtkWorkarounds.Terminate (); - return 0; } + void RegisterServices () + { + Runtime.RegisterServiceType (); + Runtime.RegisterServiceType (); + } + void FMOpenTimerExpired () { IdeApp.Workspace.FirstWorkspaceItemOpened -= CompleteSolutionTimeToCode; @@ -427,6 +417,9 @@ namespace MonoDevelop.Ide /// void ResolveMSBuildAssemblies () { + if (Platform.IsWindows) + return; + var currentRuntime = MonoRuntimeInfo.FromCurrentRuntime (); if (currentRuntime != null) { msbuildBinDir = Path.Combine (currentRuntime.Prefix, "lib", "mono", "msbuild", "15.0", "bin"); @@ -462,7 +455,8 @@ namespace MonoDevelop.Ide static bool OnIdle () { - Composition.CompositionManager.InitializeAsync ().Ignore (); + // Make sure the composition manager started initializing + Runtime.GetService (); // OpenDocuments appears when the app is idle. if (!hideWelcomePage && !WelcomePage.WelcomePageService.HasWindowImplementation) { @@ -476,7 +470,7 @@ namespace MonoDevelop.Ide void CreateStartupMetadata (StartupInfo startupInfo, Dictionary timings) { - var result = DesktopService.PlatformTelemetry; + var result = IdeServices.DesktopService.PlatformTelemetry; if (result == null) { return; } @@ -647,26 +641,6 @@ namespace MonoDevelop.Ide if (errorsList != null) errorsList.Add (new AddinError (args.AddinId, args.Message, args.Exception, false)); } - - void ListenCallback (IAsyncResult state) - { - Socket sock = (Socket)state.AsyncState; - - Socket client = sock.EndAccept (state); - ((Socket)state.AsyncState).BeginAccept (new AsyncCallback (ListenCallback), sock); - byte[] buf = new byte[1024]; - client.Receive (buf); - foreach (string filename in Encoding.UTF8.GetString (buf).Split ('\n')) { - string trimmed = filename.Trim (); - string file = ""; - foreach (char c in trimmed) { - if (c == 0x0000) - continue; - file += c; - } - GLib.Idle.Add (() => OpenFile (file)); - } - } static bool OpenFile (string file) { @@ -739,7 +713,7 @@ namespace MonoDevelop.Ide return false; } if (res == info) - DesktopService.ShowUrl ("https://bugzilla.xamarin.com/show_bug.cgi?id=21755"); + IdeServices.DesktopService.ShowUrl ("https://bugzilla.xamarin.com/show_bug.cgi?id=21755"); if (res == cont) { bool exists = Directory.Exists ("/Library/Contextual Menu Items/SCFinderPlugin.plugin"); LoggingService.LogInternalError ("SCPlugin detected", new Exception ("SCPlugin detected. Continuing " + (exists ? "Installed." : "Uninstalled."))); @@ -791,19 +765,6 @@ namespace MonoDevelop.Ide } } - /// SDBM-style hash, bounded to a range of 1000. - static int HashSdbmBounded (string input) - { - ulong hash = 0; - for (int i = 0; i < input.Length; i++) { - unchecked { - hash = ((ulong)input[i]) + (hash << 6) + (hash << 16) - hash; - } - } - - return (int)(hash % 1000); - } - public static int Main (string[] args, IdeCustomizer customizer = null) { // Using a Stopwatch instead of a TimerCounter since calling @@ -931,95 +892,4 @@ namespace MonoDevelop.Ide return metadata; } } - - public class MonoDevelopOptions - { - MonoDevelopOptions () - { - IpcTcp = (PlatformID.Unix != Environment.OSVersion.Platform); - RedirectOutput = true; - } - - Mono.Options.OptionSet GetOptionSet () - { - return new Mono.Options.OptionSet { - { "no-splash", "Do not display splash screen (deprecated).", s => {} }, - { "ipc-tcp", "Use the Tcp channel for inter-process communication.", s => IpcTcp = true }, - { "new-window", "Do not open in an existing instance of " + BrandingService.ApplicationName, s => NewWindow = true }, - { "h|?|help", "Show help", s => ShowHelp = true }, - { "perf-log", "Enable performance counter logging", s => PerfLog = true }, - { "no-redirect", "Disable redirection of stdout/stderr to a log file", s => RedirectOutput = false }, - }; - } - - public static MonoDevelopOptions Parse (string[] args) - { - var opt = new MonoDevelopOptions (); - var optSet = opt.GetOptionSet (); - - try { - opt.RemainingArgs = optSet.Parse (args); - } catch (Mono.Options.OptionException ex) { - opt.Error = ex.ToString (); - } - - if (opt.Error != null) { - Console.WriteLine ("ERROR: {0}", opt.Error); - Console.WriteLine ("Pass --help for usage information."); - } - - if (opt.ShowHelp) { - Console.WriteLine (BrandingService.ApplicationName + " " + BuildInfo.VersionLabel); - Console.WriteLine ("Options:"); - optSet.WriteOptionDescriptions (Console.Out); - const string openFileText = " file.ext;line;column"; - Console.Write (openFileText); - Console.Write (new string (' ', 29 - openFileText.Length)); - Console.WriteLine ("Opens a file at specified integer line and column"); - } - - return opt; - } - - public bool IpcTcp { get; set; } - public bool NewWindow { get; set; } - public bool ShowHelp { get; set; } - public bool PerfLog { get; set; } - public bool RedirectOutput { get; set; } - public string Error { get; set; } - public IList RemainingArgs { get; set; } - public IdeCustomizer IdeCustomizer { get; set; } - } - - public class AddinError - { - string addinFile; - Exception exception; - bool fatal; - string message; - - public AddinError (string addin, string message, Exception exception, bool fatal) - { - this.addinFile = addin; - this.message = message; - this.exception = exception; - this.fatal = fatal; - } - - public string AddinFile { - get { return addinFile; } - } - - public string Message { - get { return message; } - } - - public Exception Exception { - get { return exception; } - } - - public bool Fatal { - get { return fatal; } - } - } } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/MonoDevelopOptions.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/MonoDevelopOptions.cs new file mode 100644 index 0000000000..b3a54c6ba4 --- /dev/null +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/MonoDevelopOptions.cs @@ -0,0 +1,96 @@ +// +// IdeStartup.cs +// +// Author: +// Lluis Sanchez Gual +// +// Copyright (C) 2011 Xamarin Inc (http://xamarin.com) +// Copyright (C) 2005-2011 Novell, Inc (http://www.novell.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 MonoDevelop.Core; +using MonoDevelop.Ide.Gui; +using System.Collections.Generic; +using MonoDevelop.Ide.Extensions; + +namespace MonoDevelop.Ide +{ + public class MonoDevelopOptions + { + MonoDevelopOptions () + { + IpcTcp = (PlatformID.Unix != Environment.OSVersion.Platform); + RedirectOutput = true; + } + + Mono.Options.OptionSet GetOptionSet () + { + return new Mono.Options.OptionSet { + { "ipc-tcp", "Use the Tcp channel for inter-process communication.", s => IpcTcp = true }, + { "new-window", "Do not open in an existing instance of " + BrandingService.ApplicationName, s => NewWindow = true }, + { "h|?|help", "Show help", s => ShowHelp = true }, + { "perf-log", "Enable performance counter logging", s => PerfLog = true }, + { "no-redirect", "Disable redirection of stdout/stderr to a log file", s => RedirectOutput = false }, + }; + } + + public static MonoDevelopOptions Parse (string [] args) + { + var opt = new MonoDevelopOptions (); + var optSet = opt.GetOptionSet (); + + try { + opt.RemainingArgs = optSet.Parse (args); + } catch (Mono.Options.OptionException ex) { + opt.Error = ex.ToString (); + } + + if (opt.Error != null) { + Console.WriteLine ("ERROR: {0}", opt.Error); + Console.WriteLine ("Pass --help for usage information."); + } + + if (opt.ShowHelp) { + Console.WriteLine (BrandingService.ApplicationName + " " + BuildInfo.VersionLabel); + Console.WriteLine ("Options:"); + optSet.WriteOptionDescriptions (Console.Out); + const string openFileText = " file.ext;line;column"; + Console.Write (openFileText); + Console.Write (new string (' ', 29 - openFileText.Length)); + Console.WriteLine ("Opens a file at specified integer line and column"); + } + + return opt; + } + + public bool IpcTcp { get; set; } + public bool NewWindow { get; set; } + public bool ShowHelp { get; set; } + public bool PerfLog { get; set; } + public bool RedirectOutput { get; set; } + public string Error { get; set; } + public IList RemainingArgs { get; set; } + public IdeCustomizer IdeCustomizer { get; set; } + } +} diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/ProjectOperations.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/ProjectOperations.cs index a95c85d240..e20d881b26 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/ProjectOperations.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/ProjectOperations.cs @@ -1,4 +1,4 @@ -// +// // ProjectOperations.cs // // Author: @@ -48,14 +48,18 @@ using MonoDevelop.Ide.TypeSystem; using MonoDevelop.Projects; using MonoDevelop.Projects.MSBuild; using ExecutionContext = MonoDevelop.Projects.ExecutionContext; +using MonoDevelop.Ide.Gui.Documents; namespace MonoDevelop.Ide { /// /// This is the basic interface to the workspace. - /// - public partial class ProjectOperations - { + /// + [DefaultServiceImplementation] + public partial class ProjectOperations: Service + { + RootWorkspace workspace; + AsyncOperation currentBuildOperation = new AsyncOperation (Task.FromResult (BuildResult.CreateSuccess ()), null); MultipleAsyncOperation currentRunOperation = MultipleAsyncOperation.CompleteMultipleOperation; IBuildTarget currentBuildOperationOwner; @@ -63,86 +67,77 @@ namespace MonoDevelop.Ide SelectReferenceDialog selDialog = null; - SolutionFolderItem currentSolutionItem = null; - WorkspaceItem currentWorkspaceItem = null; - object currentItem; - - BuildResult lastResult = new BuildResult (); - internal ProjectOperations () { - IdeApp.Workspace.WorkspaceItemUnloaded += OnWorkspaceItemUnloaded; - IdeApp.Workspace.ItemUnloading += IdeAppWorkspaceItemUnloading; - - } + } + + protected override async Task OnInitialize (ServiceProvider serviceProvider) + { + workspace = await serviceProvider.GetService (); + workspace.WorkspaceItemUnloaded += OnWorkspaceItemUnloaded; + workspace.ItemUnloading += IdeAppWorkspaceItemUnloading; + await Task.WhenAll (new Task [] { + serviceProvider.GetService (), + serviceProvider.GetService (), + serviceProvider.GetService () + }); + } + + protected override Task OnDispose () + { + workspace.WorkspaceItemUnloaded -= OnWorkspaceItemUnloaded; + workspace.ItemUnloading -= IdeAppWorkspaceItemUnloading; + return base.OnDispose (); + } - [Obsolete ("This property will be removed.")] - public BuildResult LastCompilerResult { - get { return lastResult; } - } - public Project CurrentSelectedProject { get { - return currentSolutionItem as Project; + return workspace.CurrentSelectedProject; } } public Solution CurrentSelectedSolution { get { - return currentWorkspaceItem as Solution; + return workspace.CurrentSelectedSolution; } } public IBuildTarget CurrentSelectedBuildTarget { get { - if (currentSolutionItem is IBuildTarget) - return (IBuildTarget) currentSolutionItem; - return currentWorkspaceItem as IBuildTarget; + return workspace.CurrentSelectedBuildTarget; } } public WorkspaceObject CurrentSelectedObject { get { - return (WorkspaceObject)currentSolutionItem ?? (WorkspaceObject) currentWorkspaceItem; + return workspace.CurrentSelectedObject; } } public WorkspaceItem CurrentSelectedWorkspaceItem { get { - return currentWorkspaceItem; + return workspace.CurrentSelectedWorkspaceItem; } - set { - if (value != currentWorkspaceItem) { - WorkspaceItem oldValue = currentWorkspaceItem; - currentWorkspaceItem = value; - if (oldValue is Solution || value is Solution) - OnCurrentSelectedSolutionChanged(new SolutionEventArgs (currentWorkspaceItem as Solution)); - } + set { + workspace.CurrentSelectedWorkspaceItem = value; } } public SolutionFolderItem CurrentSelectedSolutionItem { - get { - if (currentSolutionItem == null && CurrentSelectedSolution != null) - return CurrentSelectedSolution.RootFolder; - return currentSolutionItem; + get { + return workspace.CurrentSelectedSolutionItem; } - set { - if (value != currentSolutionItem) { - SolutionFolderItem oldValue = currentSolutionItem; - currentSolutionItem = value; - if (oldValue is Project || value is Project) - OnCurrentProjectChanged (new ProjectEventArgs(currentSolutionItem as Project)); - } + set { + workspace.CurrentSelectedSolutionItem = value; } } public object CurrentSelectedItem { get { - return currentItem; + return workspace.CurrentSelectedItem; } set { - currentItem = value; + workspace.CurrentSelectedItem = value; } } @@ -191,45 +186,12 @@ namespace MonoDevelop.Ide if (owner == target) return true; else if (target is RootWorkspace) - return ContainsTarget (owner, IdeApp.ProjectOperations.CurrentSelectedSolution); + return ContainsTarget (owner, IdeServices.ProjectOperations.CurrentSelectedSolution); else if (owner is WorkspaceItem) return ((WorkspaceItem)owner).ContainsItem (target); return false; } - /* - string GetDeclaredFile(IMember item) - { - if (item is IMember) { - IMember mem = (IMember) item; - if (mem.Region == null) - return null; - else if (mem.Region.FileName != null) - return mem.Region.FileName; - else if (mem.DeclaringType != null) { - foreach (IType c in mem.DeclaringType.Parts) { - if ((mem is IField && c.Fields.Contains((IField)mem)) || - (mem is IEvent && c.Events.Contains((IEvent)mem)) || - (mem is IProperty && c.Properties.Contains((IProperty)mem)) || - (mem is IMethod && c.Methods.Contains((IMethod)mem))) { - return GetClassFileName(c); - } - } - } - } else if (item is IType) { - IType cls = (IType) item; - return GetClassFileName (cls); - } else if (item is MonoDevelop.Projects.Parser.LocalVariable) { - MonoDevelop.Projects.Parser.LocalVariable cls = (MonoDevelop.Projects.Parser.LocalVariable) item; - return cls.Region.FileName; - } - return null; - } - - public bool CanJumpToDeclaration (IMember item) - { - return (GetDeclaredFile(item) != null); - }*/ - + public bool CanJumpToDeclaration (Microsoft.CodeAnalysis.ISymbol symbol) { if (symbol == null) @@ -264,7 +226,7 @@ namespace MonoDevelop.Ide return new MonoDevelop.Ide.FindInFiles.SearchResult (provider, position, part.Name.Length); } - public async void JumpTo (Microsoft.CodeAnalysis.ISymbol symbol, Microsoft.CodeAnalysis.Location location, Project project = null) + public async void JumpTo (Microsoft.CodeAnalysis.ISymbol symbol, Microsoft.CodeAnalysis.Location location, WorkspaceObject project = null) { if (location == null) return; @@ -276,7 +238,7 @@ namespace MonoDevelop.Ide var metadataDllName = location.MetadataModule.Name; if (metadataDllName == "CommonLanguageRuntimeLibrary") metadataDllName = "corlib.dll"; - foreach (var assembly in await dn.GetReferencedAssemblies (IdeApp.Workspace.ActiveConfiguration)) { + foreach (var assembly in await dn.GetReferencedAssemblies (workspace.ActiveConfiguration)) { if (assembly.FilePath.ToString ().IndexOf (metadataDllName, StringComparison.Ordinal) > 0) { fileName = dn.GetAbsoluteChildPath (assembly.FilePath); break; @@ -284,11 +246,11 @@ namespace MonoDevelop.Ide } if (fileName == null) return; - var doc = await IdeApp.Workbench.OpenDocument (new FileOpenInformation (fileName, project)); + var doc = await IdeServices.DocumentManager.OpenDocument (new FileOpenInformation (fileName, project as Project)); if (doc != null) { doc.RunWhenLoaded (delegate { - var handler = doc.PrimaryView.GetContent (); + var handler = doc.GetContent (); if (handler != null) handler.Open (symbol); }); @@ -298,27 +260,27 @@ namespace MonoDevelop.Ide } var filePath = location.SourceTree.FilePath; var offset = location.SourceSpan.Start; - if (project?.ParentSolution != null) { + if (project is SolutionFolderItem item && item.ParentSolution != null) { string projectedName; int projectedOffset; - if (TypeSystemService.GetWorkspace (project.ParentSolution).TryGetOriginalFileFromProjection (filePath, offset, out projectedName, out projectedOffset)) { + if (IdeServices.TypeSystemService.GetWorkspace (item.ParentSolution).TryGetOriginalFileFromProjection (filePath, offset, out projectedName, out projectedOffset)) { filePath = projectedName; offset = projectedOffset; } } - await IdeApp.Workbench.OpenDocument (new FileOpenInformation (filePath, project) { + await IdeServices.DocumentManager.OpenDocument (new FileOpenInformation (filePath, project as Project) { Offset = offset }); } - public void JumpToDeclaration (Microsoft.CodeAnalysis.ISymbol symbol, Project project = null, bool askIfMultipleLocations = true) + public void JumpToDeclaration (Microsoft.CodeAnalysis.ISymbol symbol, WorkspaceObject project = null, bool askIfMultipleLocations = true) { if (symbol == null) throw new ArgumentNullException ("symbol"); var locations = symbol.Locations; if (askIfMultipleLocations && locations.Length > 1) { - using (var monitor = IdeApp.Workbench.ProgressMonitors.GetSearchProgressMonitor (true, true)) { + using (var monitor = IdeServices.ProgressMonitorManager.GetSearchProgressMonitor (true, true)) { foreach (var part in locations) { if (monitor.CancellationToken.IsCancellationRequested) return; @@ -341,7 +303,7 @@ namespace MonoDevelop.Ide metadataDllName = "corlib.dll"; var dn = project as DotNetProject; if (dn != null) { - foreach (var assembly in await dn.GetReferencedAssemblies (IdeApp.Workspace.ActiveConfiguration)) { + foreach (var assembly in await dn.GetReferencedAssemblies (workspace.ActiveConfiguration)) { if (assembly.FilePath.ToString ().IndexOf(metadataDllName, StringComparison.Ordinal) > 0) { fileName = dn.GetAbsoluteChildPath (assembly.FilePath); break; @@ -350,10 +312,10 @@ namespace MonoDevelop.Ide } if (fileName == null || !File.Exists (fileName)) return; - var doc = await IdeApp.Workbench.OpenDocument (new FileOpenInformation (fileName)); + var doc = await IdeServices.DocumentManager.OpenDocument (new FileOpenInformation (fileName)); if (doc != null) { doc.RunWhenLoaded (delegate { - var handler = doc.PrimaryView.GetContent (); + var handler = doc.GetContent (); if (handler != null) handler.Open (documentationCommentId, openInPublicOnlyMode); }); @@ -366,8 +328,8 @@ namespace MonoDevelop.Ide if (item is SolutionFolderItem) { await SaveAsync (((SolutionFolderItem)item).ParentSolution); } else { - await IdeApp.Workspace.SaveAsync (); - IdeApp.Workspace.SavePreferences (); + await workspace.SaveAsync (); + workspace.SavePreferences (); } } @@ -382,7 +344,7 @@ namespace MonoDevelop.Ide try { if (MessageService.RunCustomDialog (dlg) == (int) Gtk.ResponseType.Ok) { - using (ProgressMonitor monitor = IdeApp.Workbench.ProgressMonitors.GetToolOutputProgressMonitor (true)) { + using (ProgressMonitor monitor = IdeServices.ProgressMonitorManager.GetToolOutputProgressMonitor (true)) { await Services.ProjectService.Export (monitor, item.FileName, dlg.TargetFolder, dlg.Format); } } @@ -417,7 +379,7 @@ namespace MonoDevelop.Ide if (!AllowSave (entry)) return; - ProgressMonitor monitor = IdeApp.Workbench.ProgressMonitors.GetSaveProgressMonitor (true); + ProgressMonitor monitor = IdeServices.ProgressMonitorManager.GetSaveProgressMonitor (true); try { await entry.SaveAsync (monitor); monitor.ReportSuccess (GettextCatalog.GetString ("Project saved.")); @@ -443,7 +405,7 @@ namespace MonoDevelop.Ide if (!AllowSave (item)) return; - ProgressMonitor monitor = IdeApp.Workbench.ProgressMonitors.GetSaveProgressMonitor (true); + ProgressMonitor monitor = IdeServices.ProgressMonitorManager.GetSaveProgressMonitor (true); try { await item.SaveAsync (monitor); monitor.ReportSuccess (GettextCatalog.GetString ("Solution saved.")); @@ -498,7 +460,7 @@ namespace MonoDevelop.Ide items = notSavedEntries; } - ProgressMonitor monitor = IdeApp.Workbench.ProgressMonitors.GetSaveProgressMonitor (true); + ProgressMonitor monitor = IdeServices.ProgressMonitorManager.GetSaveProgressMonitor (true); try { var tasks = new List (); monitor.BeginTask (null, count); @@ -545,7 +507,7 @@ namespace MonoDevelop.Ide if (!AllowSave (item)) return; - ProgressMonitor monitor = IdeApp.Workbench.ProgressMonitors.GetSaveProgressMonitor (true); + ProgressMonitor monitor = IdeServices.ProgressMonitorManager.GetSaveProgressMonitor (true); try { await item.SaveAsync (monitor); monitor.ReportSuccess (GettextCatalog.GetString ("Item saved.")); @@ -632,7 +594,7 @@ namespace MonoDevelop.Ide var selectedProject = (SolutionItem) entry; var optionsDialog = new ProjectOptionsDialog (IdeApp.Workbench.RootWindow, selectedProject); - var conf = selectedProject.GetConfiguration (IdeApp.Workspace.ActiveConfiguration); + var conf = selectedProject.GetConfiguration (workspace.ActiveConfiguration); optionsDialog.CurrentConfig = conf != null ? conf.Name : null; optionsDialog.CurrentPlatform = conf != null ? conf.Platform : null; try { @@ -647,7 +609,7 @@ namespace MonoDevelop.Ide } } await SaveAsync (selectedProject); - IdeApp.Workspace.SavePreferences (); + workspace.SavePreferences (); IdeApp.Workbench.ReparseOpenDocuments (); } } finally { @@ -658,13 +620,13 @@ namespace MonoDevelop.Ide Solution solution = (Solution) entry; var optionsDialog = new CombineOptionsDialog (IdeApp.Workbench.RootWindow, solution); - optionsDialog.CurrentConfig = IdeApp.Workspace.ActiveConfigurationId; + optionsDialog.CurrentConfig = workspace.ActiveConfigurationId; try { if (panelId != null) optionsDialog.SelectPanel (panelId); if (MessageService.RunCustomDialog (optionsDialog) == (int) Gtk.ResponseType.Ok) { await SaveAsync (solution); - await IdeApp.Workspace.SavePreferences (solution); + await workspace.SavePreferences (solution); } } finally { optionsDialog.Destroy (); @@ -684,7 +646,7 @@ namespace MonoDevelop.Ide if (si.ParentSolution != null) await SaveAsync (si.ParentSolution); } - IdeApp.Workspace.SavePreferences (); + workspace.SavePreferences (); } } finally { optionsDialog.Destroy (); @@ -771,7 +733,7 @@ namespace MonoDevelop.Ide public async Task AddWorkspaceItem (Workspace parentWorkspace, string itemFileName) { - using (ProgressMonitor monitor = IdeApp.Workbench.ProgressMonitors.GetProjectLoadProgressMonitor (true)) { + using (ProgressMonitor monitor = IdeServices.ProgressMonitorManager.GetProjectLoadProgressMonitor (true)) { WorkspaceItem it = await Services.ProjectService.ReadWorkspaceItem (monitor, itemFileName); if (it != null) { parentWorkspace.Items.Add (it); @@ -841,7 +803,7 @@ namespace MonoDevelop.Ide } if (res != null) - await IdeApp.Workspace.SaveAsync (); + await workspace.SaveAsync (); return res; } @@ -859,7 +821,7 @@ namespace MonoDevelop.Ide AddingEntryToCombine (this, args); if (args.Cancel) return null; - using (ProgressMonitor monitor = IdeApp.Workbench.ProgressMonitors.GetProjectLoadProgressMonitor (true)) { + using (ProgressMonitor monitor = IdeServices.ProgressMonitorManager.GetProjectLoadProgressMonitor (true)) { return await folder.AddItem (monitor, args.FileName, true); } } @@ -938,7 +900,7 @@ namespace MonoDevelop.Ide SolutionItem prj = item as SolutionItem; if (prj == null) { - if (MessageService.Confirm (question, AlertButton.Remove) && IdeApp.Workspace.RequestItemUnload (item)) + if (MessageService.Confirm (question, AlertButton.Remove) && workspace.RequestItemUnload (item)) RemoveItemFromSolution (prj).Ignore(); return; } @@ -947,7 +909,7 @@ namespace MonoDevelop.Ide AlertButton result = MessageService.AskQuestion (question, secondaryText, delete, AlertButton.Cancel, AlertButton.Remove); if (result == delete) { - if (!IdeApp.Workspace.RequestItemUnload (prj)) + if (!workspace.RequestItemUnload (prj)) return; ConfirmProjectDeleteDialog dlg = new ConfirmProjectDeleteDialog (prj); try { @@ -978,19 +940,19 @@ namespace MonoDevelop.Ide dlg.Dispose (); } } - else if (result == AlertButton.Remove && IdeApp.Workspace.RequestItemUnload (prj)) { + else if (result == AlertButton.Remove && workspace.RequestItemUnload (prj)) { RemoveItemFromSolution (prj).Ignore(); } } async Task RemoveItemFromSolution (SolutionFolderItem prj) { - foreach (var doc in IdeApp.Workbench.Documents.Where (d => d.Project == prj).ToArray ()) + foreach (var doc in IdeServices.DocumentManager.Documents.Where (d => d.Owner == prj).ToArray ()) await doc.Close (); Solution sol = prj.ParentSolution; prj.ParentFolder.Items.Remove (prj); prj.Dispose (); - await IdeApp.ProjectOperations.SaveAsync (sol); + await SaveAsync (sol); } /// @@ -1018,19 +980,19 @@ namespace MonoDevelop.Ide public bool CanExecute (IBuildTarget entry) { - ExecutionContext context = new ExecutionContext (Runtime.ProcessService.DefaultExecutionHandler, IdeApp.Workbench.ProgressMonitors.ConsoleFactory, IdeApp.Workspace.ActiveExecutionTarget); + ExecutionContext context = new ExecutionContext (Runtime.ProcessService.DefaultExecutionHandler, IdeServices.ProgressMonitorManager.ConsoleFactory, workspace.ActiveExecutionTarget); return CanExecute (entry, context); } public bool CanExecute (IBuildTarget entry, IExecutionHandler handler) { - ExecutionContext context = new ExecutionContext (handler, IdeApp.Workbench.ProgressMonitors.ConsoleFactory, IdeApp.Workspace.ActiveExecutionTarget); - return entry.CanExecute (context, IdeApp.Workspace.ActiveConfiguration); + ExecutionContext context = new ExecutionContext (handler, IdeServices.ProgressMonitorManager.ConsoleFactory, workspace.ActiveExecutionTarget); + return entry.CanExecute (context, workspace.ActiveConfiguration); } public bool CanExecute (IBuildTarget entry, ExecutionContext context) { - return entry.CanExecute (context, IdeApp.Workspace.ActiveConfiguration); + return entry.CanExecute (context, workspace.ActiveConfiguration); } public AsyncOperation Execute (IBuildTarget entry, bool buildBeforeExecuting = true) @@ -1040,20 +1002,20 @@ namespace MonoDevelop.Ide public AsyncOperation Execute (IBuildTarget entry, IExecutionHandler handler, bool buildBeforeExecuting = true) { - ExecutionContext context = new ExecutionContext (handler, IdeApp.Workbench.ProgressMonitors.ConsoleFactory, IdeApp.Workspace.ActiveExecutionTarget); + ExecutionContext context = new ExecutionContext (handler, IdeServices.ProgressMonitorManager.ConsoleFactory, workspace.ActiveExecutionTarget); return Execute (entry, context, buildBeforeExecuting); } public AsyncOperation Execute (IBuildTarget entry, IExecutionHandler handler, ConfigurationSelector configuration = null, RunConfiguration runConfiguration = null, bool buildBeforeExecuting = true) { - ExecutionContext context = new ExecutionContext (handler, IdeApp.Workbench.ProgressMonitors.ConsoleFactory, IdeApp.Workspace.ActiveExecutionTarget); + ExecutionContext context = new ExecutionContext (handler, IdeServices.ProgressMonitorManager.ConsoleFactory, workspace.ActiveExecutionTarget); return Execute (entry, context, configuration, runConfiguration, buildBeforeExecuting); } public AsyncOperation Execute (IBuildTarget entry, ExecutionContext context, bool buildBeforeExecuting = true) { var cs = new CancellationTokenSource (); - return new AsyncOperation (ExecuteAsync (entry, context, cs, IdeApp.Workspace.ActiveConfiguration, null, buildBeforeExecuting), cs); + return new AsyncOperation (ExecuteAsync (entry, context, cs, workspace.ActiveConfiguration, null, buildBeforeExecuting), cs); } public AsyncOperation Execute (IBuildTarget entry, ExecutionContext context, ConfigurationSelector configuration = null, RunConfiguration runConfiguration = null, bool buildBeforeExecuting = true) @@ -1093,7 +1055,7 @@ namespace MonoDevelop.Ide Counters.TrackingBuildAndDeploy = true; if (configuration == null) - configuration = IdeApp.Workspace.ActiveConfiguration; + configuration = workspace.ActiveConfiguration; var bth = context.ExecutionHandler as IConfigurableExecutionHandler; var rt = entry as IRunTarget; @@ -1162,7 +1124,7 @@ namespace MonoDevelop.Ide public bool CanExecuteFile (string file, IExecutionHandler handler) { - ExecutionContext context = new ExecutionContext (handler, IdeApp.Workbench.ProgressMonitors.ConsoleFactory, IdeApp.Workspace.ActiveExecutionTarget); + ExecutionContext context = new ExecutionContext (handler, IdeServices.ProgressMonitorManager.ConsoleFactory, workspace.ActiveExecutionTarget); return CanExecuteFile (file, context); } @@ -1176,7 +1138,7 @@ namespace MonoDevelop.Ide public AsyncOperation ExecuteFile (string file, IExecutionHandler handler) { - ExecutionContext context = new ExecutionContext (handler, IdeApp.Workbench.ProgressMonitors.ConsoleFactory, IdeApp.Workspace.ActiveExecutionTarget); + ExecutionContext context = new ExecutionContext (handler, IdeServices.ProgressMonitorManager.ConsoleFactory, workspace.ActiveExecutionTarget); return ExecuteFile (file, context); } @@ -1199,7 +1161,7 @@ namespace MonoDevelop.Ide ITimeTracker tt = Counters.BuildItemTimer.BeginTiming ("Cleaning " + entry.Name); try { var cs = new CancellationTokenSource (); - ProgressMonitor monitor = IdeApp.Workbench.ProgressMonitors.GetCleanProgressMonitor ().WithCancellationSource (cs); + ProgressMonitor monitor = IdeServices.ProgressMonitorManager.GetCleanProgressMonitor ().WithCancellationSource (cs); OnStartClean (monitor, tt); @@ -1227,7 +1189,7 @@ namespace MonoDevelop.Ide BuildResult res = null; try { tt.Trace ("Cleaning item"); - res = await entry.Clean (monitor, IdeApp.Workspace.ActiveConfiguration, InitOperationContext (entry, operationContext)); + res = await entry.Clean (monitor, workspace.ActiveConfiguration, InitOperationContext (entry, operationContext)); } catch (Exception ex) { monitor.ReportError (GettextCatalog.GetString ("Clean failed."), ex); } finally { @@ -1301,9 +1263,10 @@ namespace MonoDevelop.Ide tasks [n].Owner = this; } - TaskService.Errors.AddRange (tasks); - TaskService.Errors.ResetLocationList (); - IdeApp.Workbench.ActiveLocationList = TaskService.Errors; + IdeServices.TaskService.Errors.AddRange (tasks); + IdeServices.TaskService.Errors.ResetLocationList (); + if (IdeApp.IsInitialized) + IdeApp.Workbench.ActiveLocationList = IdeServices.TaskService.Errors; return tasks; } @@ -1319,11 +1282,11 @@ namespace MonoDevelop.Ide errorsPad.BringToFront (); break; case BuildResultStates.OnErrors: - if (TaskService.Errors.Any (task => task.Severity == TaskSeverity.Error)) + if (IdeServices.TaskService.Errors.Any (task => task.Severity == TaskSeverity.Error)) goto case BuildResultStates.Always; break; case BuildResultStates.OnErrorsOrWarnings: - if (TaskService.Errors.Any (task => task.Severity == TaskSeverity.Error || task.Severity == TaskSeverity.Warning)) + if (IdeServices.TaskService.Errors.Any (task => task.Severity == TaskSeverity.Error || task.Severity == TaskSeverity.Warning)) goto case BuildResultStates.Always; break; } @@ -1340,7 +1303,7 @@ namespace MonoDevelop.Ide if (currentBuildOperation != null && !currentBuildOperation.IsCompleted) return currentBuildOperation; var cs = new CancellationTokenSource (); - ProgressMonitor monitor = IdeApp.Workbench.ProgressMonitors.GetRebuildProgressMonitor ().WithCancellationSource (cs); + ProgressMonitor monitor = IdeServices.ProgressMonitorManager.GetRebuildProgressMonitor ().WithCancellationSource (cs); var t = RebuildAsync (entry, monitor, operationContext); t = t.ContinueWith (ta => { @@ -1639,7 +1602,7 @@ namespace MonoDevelop.Ide var cs = new CancellationTokenSource (); if (cancellationToken != null) cs = CancellationTokenSource.CreateLinkedTokenSource (cs.Token, cancellationToken.Value); - ProgressMonitor monitor = IdeApp.Workbench.ProgressMonitors.GetBuildProgressMonitor ().WithCancellationSource (cs); + ProgressMonitor monitor = IdeServices.ProgressMonitorManager.GetBuildProgressMonitor ().WithCancellationSource (cs); BeginBuild (monitor, tt, false); var t = BuildSolutionItemAsync (entry, monitor, tt, skipPrebuildCheck, operationContext); currentBuildOperation = new AsyncOperation (t, cs); @@ -1666,7 +1629,7 @@ namespace MonoDevelop.Ide if (skipPrebuildCheck || result.ErrorCount == 0) { tt.Trace ("Building item"); - result = await entry.Build (monitor, IdeApp.Workspace.ActiveConfiguration, true, InitOperationContext (entry, operationContext)); + result = await entry.Build (monitor, workspace.ActiveConfiguration, true, InitOperationContext (entry, operationContext)); } } catch (Exception ex) { monitor.ReportError (GettextCatalog.GetString ("Build failed."), ex); @@ -1696,9 +1659,9 @@ namespace MonoDevelop.Ide if (ctx.ExecutionTarget == null) { var item = target as SolutionItem; if (item != null) - ctx.ExecutionTarget = IdeApp.Workspace.GetActiveExecutionTarget (item); + ctx.ExecutionTarget = IdeServices.Workspace.GetActiveExecutionTarget (item); else - ctx.ExecutionTarget = IdeApp.Workspace.ActiveExecutionTarget; + ctx.ExecutionTarget = IdeServices.Workspace.ActiveExecutionTarget; } return (T)ctx; } @@ -1708,8 +1671,8 @@ namespace MonoDevelop.Ide { var couldNotSaveError = "The build has been aborted as the file '{0}' could not be saved"; - foreach (var doc in IdeApp.Workbench.Documents) { - if (doc.IsDirty && doc.Project != null) { + foreach (var doc in IdeServices.DocumentManager.Documents) { + if (doc.IsDirty && doc.Owner != null) { if (MessageService.AskQuestion (GettextCatalog.GetString ("Save changed documents before building?"), GettextCatalog.GetString ("Some of the open documents have unsaved changes."), AlertButton.BuildWithoutSave, AlertButton.Save) == AlertButton.Save) { @@ -1728,8 +1691,8 @@ namespace MonoDevelop.Ide { var couldNotSaveError = "The build has been aborted as the file '{0}' could not be saved"; - foreach (var doc in new List (IdeApp.Workbench.Documents)) { - if (doc.IsDirty && doc.Project != null) { + foreach (var doc in new List (IdeServices.DocumentManager.Documents)) { + if (doc.IsDirty && doc.Owner != null) { await doc.Save (); if (doc.IsDirty) { doc.Select (); @@ -1763,7 +1726,7 @@ namespace MonoDevelop.Ide { tt.Trace ("Start build event"); if (!isRebuilding) { - MonoDevelop.Ide.Tasks.TaskService.Errors.ClearByOwner (this); + IdeServices.TaskService.Errors.ClearByOwner (this); } if (StartBuild != null) { StartBuild (this, new BuildEventArgs (monitor, true)); @@ -1776,7 +1739,7 @@ namespace MonoDevelop.Ide tt.Trace ("Begin reporting build result"); try { if (result != null) { - lastResult = result; + var lastResult = result; monitor.Log.WriteLine (); var msg = GettextCatalog.GetString ( @@ -2473,7 +2436,7 @@ namespace MonoDevelop.Ide void OnStartClean (ProgressMonitor monitor, ITimeTracker tt) { tt.Trace ("Start clean event"); - TaskService.Errors.ClearByOwner (this); + IdeServices.TaskService.Errors.ClearByOwner (this); if (StartClean != null) { StartClean (this, new CleanEventArgs (monitor)); } @@ -2504,39 +2467,39 @@ namespace MonoDevelop.Ide void OnWorkspaceItemUnloaded (object s, WorkspaceItemEventArgs args) { - if (ContainsTarget (args.Item, currentSolutionItem)) + if (ContainsTarget (args.Item, workspace.CurrentSelectedSolutionItem)) CurrentSelectedSolutionItem = null; - if (ContainsTarget (args.Item, currentWorkspaceItem)) + if (ContainsTarget (args.Item, CurrentSelectedWorkspaceItem)) CurrentSelectedWorkspaceItem = null; - if ((currentItem is IBuildTarget) && ContainsTarget (args.Item, ((WorkspaceObject)currentItem))) + if ((CurrentSelectedItem is WorkspaceObject) && ContainsTarget (args.Item, ((WorkspaceObject)CurrentSelectedItem))) CurrentSelectedItem = null; } - protected virtual void OnCurrentSelectedSolutionChanged(SolutionEventArgs e) - { - if (CurrentSelectedSolutionChanged != null) { - CurrentSelectedSolutionChanged (this, e); - } - } - - protected virtual void OnCurrentProjectChanged(ProjectEventArgs e) - { - if (CurrentSelectedProject != null) { - StringParserService.Properties["PROJECTNAME"] = CurrentSelectedProject.Name; - } - if (CurrentProjectChanged != null) { - CurrentProjectChanged (this, e); - } - } - public event BuildEventHandler StartBuild; public event BuildEventHandler EndBuild; public event EventHandler BeforeStartProject; public event CleanEventHandler StartClean; public event CleanEventHandler EndClean; - - public event EventHandler CurrentSelectedSolutionChanged; - public event ProjectEventHandler CurrentProjectChanged; + + public event EventHandler CurrentSelectedSolutionChanged { + add { + workspace.CurrentSelectedSolutionChanged += value; + } + remove { + workspace.CurrentSelectedSolutionChanged -= value; + } + } + + public event ProjectEventHandler CurrentProjectChanged { + add { + workspace.CurrentProjectChanged += value; + } + + remove { + workspace.CurrentProjectChanged -= value; + } + } + public event EventHandler ProjectCreated; // Fired just before an entry is added to a combine @@ -2619,12 +2582,10 @@ namespace MonoDevelop.Ide public ITextDocument GetEditableTextFile (FilePath filePath) { - if (IdeApp.IsInitialized) { - foreach (var doc in IdeApp.Workbench.Documents) { - if (doc.FileName == filePath) { - var ef = doc.Editor; - if (ef != null) return ef; - } + foreach (var doc in IdeServices.DocumentManager.Documents) { + if (doc.FileName == filePath) { + var ef = doc.Editor; + if (ef != null) return ef; } } @@ -2665,7 +2626,7 @@ namespace MonoDevelop.Ide { if (filePath.IsNullOrEmpty) throw new ArgumentNullException ("filePath"); - foreach (var doc in IdeApp.Workbench.Documents) { + foreach (var doc in IdeServices.DocumentManager.Documents) { if (IsSearchedDocument (doc, filePath)) { return doc.Editor; } @@ -2676,16 +2637,14 @@ namespace MonoDevelop.Ide public ITextDocument GetTextEditorData (FilePath filePath, out bool isOpen) { - if (IdeApp.Workbench != null) { - foreach (var doc in IdeApp.Workbench.Documents) { - if (IsSearchedDocument (doc, filePath)) { - isOpen = true; - return doc.Editor; - } + foreach (var doc in IdeServices.DocumentManager.Documents) { + if (IsSearchedDocument (doc, filePath)) { + isOpen = true; + return doc.Editor; } } - var data = TextEditorFactory.CreateNewDocument (filePath, DesktopService.GetMimeTypeForUri(filePath)); + var data = TextEditorFactory.CreateNewDocument (filePath, IdeServices.DesktopService.GetMimeTypeForUri(filePath)); isOpen = false; return data; diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/RootWorkspace.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/RootWorkspace.cs index 97a5eb8144..f0c5f31fc3 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/RootWorkspace.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/RootWorkspace.cs @@ -1,4 +1,4 @@ -// RootWorkspace.cs +// RootWorkspace.cs // // Author: // Lluis Sanchez Gual @@ -44,15 +44,23 @@ using MonoDevelop.Ide.Gui; using MonoDevelop.Ide.Projects; using MonoDevelop.Core.Execution; using System.Threading.Tasks; +using MonoDevelop.Ide.TypeSystem; +using MonoDevelop.Ide.Gui.Documents; namespace MonoDevelop.Ide { - public sealed class RootWorkspace: WorkspaceObject, IBuildTarget + [DefaultServiceImplementation] + public sealed class RootWorkspace: WorkspaceObject, IBuildTarget, IService { + ServiceProvider serviceProvider; RootWorkspaceItemCollection items; -// IParserDatabase parserDatabase; string activeConfiguration; bool useDefaultRuntime; + DocumentManager documentManager; + + SolutionFolderItem currentSolutionItem = null; + WorkspaceItem currentWorkspaceItem = null; + object currentItem; internal RootWorkspace () { @@ -60,20 +68,121 @@ namespace MonoDevelop.Ide currentWorkspaceLoadTask = new TaskCompletionSource (); currentWorkspaceLoadTask.SetResult (true); + } + Task IService.Initialize (ServiceProvider serviceProvider) + { + this.serviceProvider = serviceProvider; FileService.FileRenamed += CheckFileRename; - + + serviceProvider.WhenServiceInitialized (s => { + documentManager = s; + }); + // Set the initial active runtime UseDefaultRuntime = true; - IdeApp.Preferences.DefaultTargetRuntime.Changed += delegate { + DefaultTargetRuntime.Changed += delegate { // If the default runtime changes and current active is default, update it if (UseDefaultRuntime) { - Runtime.SystemAssemblyService.DefaultRuntime = IdeApp.Preferences.DefaultTargetRuntime; + Runtime.SystemAssemblyService.DefaultRuntime = DefaultTargetRuntime; useDefaultRuntime = true; } }; + return Task.CompletedTask; } - + + Task IService.Dispose () + { + return Task.CompletedTask; + } + + internal static ConfigurationProperty DefaultTargetRuntime = new DefaultTargetRuntimeProperty (); + + public Project CurrentSelectedProject { + get { + return currentSolutionItem as Project; + } + } + + public Solution CurrentSelectedSolution { + get { + return currentWorkspaceItem as Solution; + } + } + + public IBuildTarget CurrentSelectedBuildTarget { + get { + if (currentSolutionItem is IBuildTarget) + return (IBuildTarget)currentSolutionItem; + return currentWorkspaceItem as IBuildTarget; + } + } + + public WorkspaceObject CurrentSelectedObject { + get { + return (WorkspaceObject)currentSolutionItem ?? (WorkspaceObject)currentWorkspaceItem; + } + } + + public WorkspaceItem CurrentSelectedWorkspaceItem { + get { + return currentWorkspaceItem; + } + set { + if (value != currentWorkspaceItem) { + WorkspaceItem oldValue = currentWorkspaceItem; + currentWorkspaceItem = value; + if (oldValue is Solution || value is Solution) + OnCurrentSelectedSolutionChanged (new SolutionEventArgs (currentWorkspaceItem as Solution)); + } + } + } + + public SolutionFolderItem CurrentSelectedSolutionItem { + get { + if (currentSolutionItem == null && CurrentSelectedSolution != null) + return CurrentSelectedSolution.RootFolder; + return currentSolutionItem; + } + set { + if (value != currentSolutionItem) { + SolutionFolderItem oldValue = currentSolutionItem; + currentSolutionItem = value; + if (oldValue is Project || value is Project) + OnCurrentProjectChanged (new ProjectEventArgs (currentSolutionItem as Project)); + } + } + } + + void OnCurrentSelectedSolutionChanged (SolutionEventArgs e) + { + if (CurrentSelectedSolutionChanged != null) { + CurrentSelectedSolutionChanged (this, e); + } + } + + void OnCurrentProjectChanged (ProjectEventArgs e) + { + if (CurrentSelectedProject != null) { + StringParserService.Properties ["PROJECTNAME"] = CurrentSelectedProject.Name; + } + if (CurrentProjectChanged != null) { + CurrentProjectChanged (this, e); + } + } + + public event EventHandler CurrentSelectedSolutionChanged; + public event ProjectEventHandler CurrentProjectChanged; + + public object CurrentSelectedItem { + get { + return currentItem; + } + set { + currentItem = value; + } + } + public RootWorkspaceItemCollection Items { get { return items; @@ -151,7 +260,7 @@ namespace MonoDevelop.Ide if (useDefaultRuntime != value) { useDefaultRuntime = value; if (value) - Runtime.SystemAssemblyService.DefaultRuntime = IdeApp.Preferences.DefaultTargetRuntime; + Runtime.SystemAssemblyService.DefaultRuntime = DefaultTargetRuntime; } } } @@ -183,8 +292,8 @@ namespace MonoDevelop.Ide public IEnumerable GetExecutionDependencies () { - if (IdeApp.ProjectOperations.CurrentSelectedSolution != null) - return IdeApp.ProjectOperations.CurrentSelectedSolution.GetExecutionDependencies (); + if (CurrentSelectedSolution != null) + return CurrentSelectedSolution.GetExecutionDependencies (); else return new IBuildTarget [0]; } @@ -216,13 +325,42 @@ namespace MonoDevelop.Ide } } -#endregion - -#region Build and run operations - + // When looking for the project to which the file belongs, look first + // in the active project, then the active solution, and so on + public Project GetProjectContainingFile (FilePath fileName) + { + Project project = null; + if (CurrentSelectedProject != null) { + if (CurrentSelectedProject.Files.GetFile (fileName) != null) + project = CurrentSelectedProject; + else if (CurrentSelectedProject.FileName == fileName) + project = CurrentSelectedProject; + } + if (project == null && CurrentSelectedWorkspaceItem != null) { + project = CurrentSelectedWorkspaceItem.GetProjectsContainingFile (fileName).FirstOrDefault (); + if (project == null) { + WorkspaceItem it = CurrentSelectedWorkspaceItem.ParentWorkspace; + while (it != null && project == null) { + project = it.GetProjectsContainingFile (fileName).FirstOrDefault (); + it = it.ParentWorkspace; + } + } + } + if (project == null) { + project = GetProjectsContainingFile (fileName).FirstOrDefault (); + } + return project; + } + + + #endregion + + #region Build and run operations + public async Task SaveAsync () { - ProgressMonitor monitor = IdeApp.Workbench.ProgressMonitors.GetSaveProgressMonitor (true); + var monitorManager = await Runtime.GetService (); + ProgressMonitor monitor = monitorManager.GetSaveProgressMonitor (true); try { await SaveAsync (monitor); monitor.ReportSuccess (GettextCatalog.GetString ("Workspace saved.")); @@ -240,8 +378,8 @@ namespace MonoDevelop.Ide bool IBuildTarget.CanExecute (ExecutionContext context, ConfigurationSelector configuration) { - if (IdeApp.ProjectOperations.CurrentSelectedSolution != null) - return IdeApp.ProjectOperations.CurrentSelectedSolution.CanExecute (context, configuration); + if (CurrentSelectedSolution != null) + return CurrentSelectedSolution.CanExecute (context, configuration); else { return false; } @@ -295,7 +433,7 @@ namespace MonoDevelop.Ide public Task Execute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration) { - Solution sol = IdeApp.ProjectOperations.CurrentSelectedSolution ?? GetAllSolutions ().FirstOrDefault (); + Solution sol = CurrentSelectedSolution ?? GetAllSolutions ().FirstOrDefault (); if (sol != null) return sol.Execute (monitor, context, configuration); else @@ -321,9 +459,11 @@ namespace MonoDevelop.Ide bool IsDirtyFileInCombine { get { + if (documentManager == null) + return false; foreach (Project projectEntry in GetAllProjects()) { foreach (ProjectFile fInfo in projectEntry.Files) { - foreach (Document doc in IdeApp.Workbench.Documents) { + foreach (Document doc in documentManager.Documents) { if (doc.IsDirty && doc.FileName == fInfo.FilePath) { return true; } @@ -362,26 +502,28 @@ namespace MonoDevelop.Ide public async Task Close (bool saveWorkspacePreferencies) { - return await Close (saveWorkspacePreferencies, true); + return await Close (saveWorkspacePreferencies, true, false); } - - internal async Task Close (bool saveWorkspacePreferencies, bool closeProjectFiles) + + internal async Task Close (bool saveWorkspacePreferencies, bool closeProjectFiles, bool force = false) { if (Items.Count > 0) { ITimeTracker timer = Counters.CloseWorkspaceTimer.BeginTiming (); try { - // Request permission for unloading the items - foreach (WorkspaceItem it in new List (Items)) { - if (!RequestItemUnload (it)) - return false; + if (!force) { + // Request permission for unloading the items + foreach (WorkspaceItem it in new List (Items)) { + if (!RequestItemUnload (it)) + return false; + } } if (saveWorkspacePreferencies) SavePreferences (); - if (closeProjectFiles) { - foreach (Document doc in IdeApp.Workbench.Documents.ToArray ()) { - if (!await doc.Close ()) + if (closeProjectFiles && documentManager != null) { + foreach (Document doc in documentManager.Documents.ToArray ()) { + if (!await doc.Close (force)) return false; } } @@ -392,6 +534,7 @@ namespace MonoDevelop.Ide it.Dispose (); } catch (Exception ex) { MessageService.ShowError (GettextCatalog.GetString ("Could not close solution '{0}'.", it.Name), ex); + return false; } } } finally { @@ -413,9 +556,9 @@ namespace MonoDevelop.Ide } if (RequestItemUnload (item)) { - if (closeItemFiles) { + if (closeItemFiles && documentManager != null) { var projects = item.GetAllItems (); - foreach (Document doc in IdeApp.Workbench.Documents.Where (d => d.Project != null && projects.Contains (d.Project)).ToArray ()) { + foreach (Document doc in documentManager.Documents.Where (d => d.Owner != null && projects.Contains (d.Owner)).ToArray ()) { if (!await doc.Close ()) return; } @@ -514,8 +657,9 @@ namespace MonoDevelop.Ide { var item = GetAllItems ().FirstOrDefault (w => w.FileName == file.FullPath); if (item != null) { - IdeApp.ProjectOperations.CurrentSelectedWorkspaceItem = item; - IdeApp.Workbench.StatusBar.ShowWarning (GettextCatalog.GetString ("{0} is already opened", item.FileName.FileName)); + CurrentSelectedWorkspaceItem = item; + if (IdeApp.IsInitialized) + IdeApp.Workbench.StatusBar.ShowWarning (GettextCatalog.GetString ("{0} is already opened", item.FileName.FileName)); return true; } @@ -524,12 +668,14 @@ namespace MonoDevelop.Ide return false; } - var monitor = loadMonitor ?? IdeApp.Workbench.ProgressMonitors.GetProjectLoadProgressMonitor (true); + var monitorManager = await Runtime.GetService (); + var monitor = loadMonitor ?? monitorManager.GetProjectLoadProgressMonitor (true); bool reloading = IsReloading; monitor = monitor.WithCancellationSource (openingItemCancellationSource); - IdeApp.Workbench.LockGui (); + if (IdeApp.IsInitialized) + IdeApp.Workbench.LockGui (); metadata = GetOpenWorkspaceItemMetadata (metadata); ITimeTracker timer = Counters.OpenWorkspaceItemTimer.BeginTiming (metadata); @@ -540,22 +686,26 @@ namespace MonoDevelop.Ide timer.End (); monitor.Dispose (); - IdeApp.Workbench.UnlockGui (); + + if (IdeApp.IsInitialized) + IdeApp.Workbench.UnlockGui (); } } void ReattachDocumentProjects (IEnumerable closedDocs) { - foreach (Document doc in IdeApp.Workbench.Documents) { - if (doc.Project == null && doc.IsFile) { - Project p = GetProjectsContainingFile (doc.FileName).FirstOrDefault (); - if (p != null) - doc.SetProject (p); + if (documentManager != null) { + foreach (Document doc in documentManager.Documents) { + if (doc.Owner == null && doc.IsFile) { + Project p = GetProjectsContainingFile (doc.FileName).FirstOrDefault (); + if (p != null) + doc.AttachToProject (p); + } } - } - if (closedDocs != null) { - foreach (string doc in closedDocs) { - IdeApp.Workbench.OpenDocument (doc, null, false); + if (closedDocs != null) { + foreach (string doc in closedDocs) { + documentManager.OpenDocument (new FileOpenInformation (doc, null, false)).Ignore (); + } } } } @@ -588,7 +738,7 @@ namespace MonoDevelop.Ide } timer.Trace ("Getting wrapper solution"); - item = await IdeApp.Services.ProjectService.GetWrapperSolution (monitor, file); + item = await IdeServices.ProjectService.GetWrapperSolution (monitor, file); } if (item == null) { @@ -599,7 +749,7 @@ namespace MonoDevelop.Ide } timer.Trace ("Registering to recent list"); - DesktopService.RecentFiles.AddProject (item.FileName, item.Name); + Runtime.PeekService ()?.RecentFiles.AddProject (item.FileName, item.Name); } catch (Exception ex) { LoggingService.LogError ("Load operation failed", ex); @@ -630,10 +780,10 @@ namespace MonoDevelop.Ide item.Dispose (); return false; } - if (IdeApp.ProjectOperations.CurrentSelectedWorkspaceItem == null) - IdeApp.ProjectOperations.CurrentSelectedWorkspaceItem = GetAllSolutions ().FirstOrDefault (); + if (CurrentSelectedWorkspaceItem == null) + CurrentSelectedWorkspaceItem = GetAllSolutions ().FirstOrDefault (); - Document.IsInProjectSettingLoadingProcess = true; + RoslynDocumentContext.IsInProjectSettingLoadingProcess = true; try { if (Items.Count == 1 && loadPreferences) { timer.Trace ("Restoring workspace preferences"); @@ -649,7 +799,7 @@ namespace MonoDevelop.Ide UpdateOpenWorkspaceItemMetadata (metadata, item); } finally { - Document.IsInProjectSettingLoadingProcess = false; + RoslynDocumentContext.IsInProjectSettingLoadingProcess = false; } } return true; @@ -772,22 +922,6 @@ namespace MonoDevelop.Ide return item.SaveUserProperties (); } - [Obsolete ("FileService will generate events for all workspace files.")] - public FileStatusTracker GetFileStatusTracker () - { - FileStatusTracker fs = new FileStatusTracker (); - fs.AddFiles (GetKnownFiles ()); - return fs; - } - - static IEnumerable GetKnownFiles () - { - foreach (WorkspaceItem item in IdeApp.Workspace.Items) { - foreach (FilePath file in item.GetItemFiles (true)) - yield return file; - } - } - int reloadingCount; internal bool IsReloading { @@ -831,7 +965,8 @@ namespace MonoDevelop.Ide } } else { - using (ProgressMonitor m = IdeApp.Workbench.ProgressMonitors.GetSaveProgressMonitor (true)) { + var monitorManager = await Runtime.GetService (); + using (ProgressMonitor m = monitorManager.GetSaveProgressMonitor (true)) { await item.ParentWorkspace.ReloadItem (m, item); if (closedDocs != null) ReattachDocumentProjects (closedDocs); @@ -870,7 +1005,8 @@ namespace MonoDevelop.Ide IEnumerable closedDocs = result.Item2; if (allowReload) { - using (ProgressMonitor m = IdeApp.Workbench.ProgressMonitors.GetProjectLoadProgressMonitor (true)) { + var monitorManager = await Runtime.GetService (); + using (ProgressMonitor m = monitorManager.GetProjectLoadProgressMonitor (true)) { // Root folders never need to reload await entry.ParentFolder.ReloadItem (m, entry); if (closedDocs != null) @@ -945,7 +1081,7 @@ namespace MonoDevelop.Ide break; } if (msg != null) { - if (!MessageService.Confirm (GettextCatalog.GetString ("The project '{0}' has been modified by an external application. Do you want to reload it?", docs[0].Project.Name), msg, AlertButton.Reload)) + if (!MessageService.Confirm (GettextCatalog.GetString ("The project '{0}' has been modified by an external application. Do you want to reload it?", docs[0].Owner.Name), msg, AlertButton.Reload)) return Tuple.Create (true, closedDocs); } @@ -955,7 +1091,7 @@ namespace MonoDevelop.Ide if (doc.IsDirty) hasUnsaved = true; if (doc.ProjectReloadCapability != ProjectReloadCapability.None) - doc.SetProject (null); + doc.AttachToProject (null); else { FilePath file = doc.IsFile ? doc.FileName : FilePath.Null; EventHandler saved = delegate { @@ -978,12 +1114,14 @@ namespace MonoDevelop.Ide return Tuple.Create (true, closedDocs); } - internal static List GetOpenDocuments (Project project, bool modifiedOnly) + List GetOpenDocuments (Project project, bool modifiedOnly) { List docs = new List (); - foreach (Document doc in IdeApp.Workbench.Documents) { - if (doc.Project == project && (!modifiedOnly || doc.IsDirty)) { - docs.Add (doc); + if (documentManager != null) { + foreach (Document doc in documentManager.Documents) { + if (doc.Owner == project && (!modifiedOnly || doc.IsDirty)) { + docs.Add (doc); + } } } return docs; @@ -996,10 +1134,7 @@ namespace MonoDevelop.Ide internal void NotifyItemAdded (WorkspaceItem item) { - MonoDevelop.Ide.TypeSystem.TypeSystemService.Load (item, null).ContinueWith(t => { - if (t.IsFaulted) - LoggingService.LogError("Could not load parser database.", t.Exception); - }); + LoadWorkspaceTypeSystem (item).Ignore (); if (Runtime.IsMainThread) NotifyItemAddedGui (item, IsReloading); else { @@ -1024,14 +1159,25 @@ namespace MonoDevelop.Ide NotifyConfigurationsChanged (null, args); if (Items.Count == 1 && !reloading) { - IdeApp.Workbench.CurrentLayout = "Solution"; + if (IdeApp.IsInitialized) + IdeApp.Workbench.CurrentLayout = "Solution"; if (FirstWorkspaceItemOpened != null) FirstWorkspaceItemOpened (this, args); } if (WorkspaceItemOpened != null) WorkspaceItemOpened (this, args); } - + + async Task LoadWorkspaceTypeSystem (WorkspaceItem item) + { + try { + var typeSystem = await serviceProvider.GetService (); + await typeSystem.Load (item, null); + } catch (Exception ex) { + LoggingService.LogError ("Could not load parser database.", ex); + }; + } + internal void NotifyItemRemoved (WorkspaceItem item) { if (Runtime.IsMainThread) @@ -1064,11 +1210,18 @@ namespace MonoDevelop.Ide if (LastWorkspaceItemClosed != null) LastWorkspaceItemClosed (this, EventArgs.Empty); } - MonoDevelop.Ide.TypeSystem.TypeSystemService.Unload (item); + + UnloadWorkspaceTypeSystem (item).Ignore (); NotifyDescendantItemRemoved (this, args); } - + + async Task UnloadWorkspaceTypeSystem (WorkspaceItem item) + { + var typeSystem = await serviceProvider.GetService (); + typeSystem.Unload (item); + } + void SubscribeSolution (Solution sol) { sol.FileAddedToProject += NotifyFileAddedToProject; @@ -1169,11 +1322,11 @@ namespace MonoDevelop.Ide { NotifyItemRemovedFromSolutionRec (sender, args.SolutionItem, args.Solution, args); } - + void NotifyItemRemovedFromSolutionRec (object sender, SolutionFolderItem e, Solution sol, SolutionItemChangeEventArgs originalArgs) { - if (e == IdeApp.ProjectOperations.CurrentSelectedSolutionItem) - IdeApp.ProjectOperations.CurrentSelectedSolutionItem = null; + if (e == CurrentSelectedSolutionItem) + CurrentSelectedSolutionItem = null; if (e is SolutionFolder) { foreach (SolutionFolderItem ce in ((SolutionFolder)e).Items) @@ -1243,11 +1396,11 @@ namespace MonoDevelop.Ide sol.RootFolder.RenameFileInProjects (e.SourceFile, e.TargetFile); } } - -#endregion -#region Event declaration - + #endregion + + #region Event declaration + /// /// Fired when a file is removed from a project. /// -- cgit v1.2.3