diff options
32 files changed, 2277 insertions, 1650 deletions
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 {
/// <summary> /// The host of the MonoDevelop MEF composition. Uses https://github.com/Microsoft/vs-mef. - /// </summary> - public partial class CompositionManager + /// </summary>
+ [DefaultServiceImplementation] + public partial class CompositionManager: Service {
- static Task<CompositionManager> 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<CompositionManager> ();
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;
+ }
}
- /// <summary> - /// Starts initializing the MEF composition on a background thread. Thread-safe. - /// </summary> - public static Task<CompositionManager> 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 ());
} /// <summary> /// Returns an instance of type T that is exported by some composition part. The instance is shared (singleton). /// </summary> - public static T GetExportedValue<T> () => Instance.ExportProvider.GetExportedValue<T> ();
+ public T GetExportedValue<T> () => ExportProvider.GetExportedValue<T> ();
/// <summary>
/// Returns all instances of type T that are exported by some composition part. The instances are shared (singletons).
/// </summary>
- public static IEnumerable<T> GetExportedValues<T> () => Instance.ExportProvider.GetExportedValues<T> (); + public IEnumerable<T> GetExportedValues<T> () => ExportProvider.GetExportedValues<T> (); /// <summary>
/// Returns a lazy holding the instance of type T that is exported by some composition part. The instance is shared (singleton).
/// </summary>
- public static Lazy<T> GetExport<T> () => new Lazy<T> (() => Instance.ExportProvider.GetExportedValue<T> ()); + public static Lazy<T> GetExport<T> () => new Lazy<T> (() => Instance.ExportProvider.GetExportedValue<T> ());
/// <summary>
/// Returns a lazy holding all instances of type T that are exported by some composition part. The instances are shared (singletons).
/// </summary>
- public static Lazy<IEnumerable<T>> GetExports<T> () => new Lazy<IEnumerable<T>> (() => Instance.ExportProvider.GetExportedValues<T> ()); + public static Lazy<IEnumerable<T>> GetExports<T> () => new Lazy<IEnumerable<T>> (() => Instance.ExportProvider.GetExportedValues<T> ());
public RuntimeComposition RuntimeComposition { get; private set; } public IExportProviderFactory ExportProviderFactory { get; private set; } @@ -116,13 +105,6 @@ namespace MonoDevelop.Ide.Composition { } - static async Task<CompositionManager> 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<PlatformCatalog> ();
+ instance = CompositionManager.Instance.GetExportedValue<PlatformCatalog> ();
}
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<RecentFile> 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<string> ()); } + internal DesktopService DesktopService { get; set; } + public IList<RecentFile> 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<RecentFile> OnGetProjects (); protected abstract IList<RecentFile> 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 <mkrueger@novell.com> @@ -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<LanguageBundle> languageBundles = new List<LanguageBundle> (); + static bool stylesInitialized; + + public static FilePath SyntaxModePath { + get { + return UserProfile.Current.UserDataRoot.Combine ("ColorThemes"); + } + } internal static IEnumerable<LanguageBundle> AllBundles { get { + InitializeStylesAndModes (); return languageBundles; } } public static string[] Styles { get { + InitializeStylesAndModes (); var result = new List<string> (); 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<TmSetting> 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<TmSnippet> 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<FontService> (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 /// <summary> /// Called just after the initializer is created /// </summary> - internal protected virtual void Initialize () + internal protected virtual void Initialize (StartupInfo startupInfo) { } @@ -54,7 +54,7 @@ namespace MonoDevelop.Ide.Extensions /// <summary> /// Called when the Ide has been initialized /// </summary> - 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 <mkrueger@novell.com> @@ -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<FontDescriptionCodon> fontDescriptions = new List<FontDescriptionCodon> (); - static Dictionary<string, FontDescription> loadedFonts = new Dictionary<string, FontDescription> (); - static Properties fontProperties; + List<FontDescriptionCodon> fontDescriptions = new List<FontDescriptionCodon> (); + Dictionary<string, FontDescription> loadedFonts = new Dictionary<string, FontDescription> (); + 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<FontDescriptionCodon> FontDescriptions { + internal IEnumerable<FontDescriptionCodon> 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<DesktopService> (); 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<string> (name); @@ -142,14 +143,14 @@ namespace MonoDevelop.Ide.Fonts /// <param name='createDefaultFont'> /// If set to <c>false</c> and no custom font has been set, the method will return null. /// </param> - 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<FontDescription> GetFontProperty (string name) + internal ConfigurationProperty<FontDescription> GetFontProperty (string name) { return new FontConfigurationProperty (name); } - static Dictionary<string, List<Action>> fontChangeCallbacks = new Dictionary<string, List<Action>> (); - public static void RegisterFontChangedCallback (string fontName, Action callback) + Dictionary<string, List<Action>> fontChangeCallbacks = new Dictionary<string, List<Action>> (); + public void RegisterFontChangedCallback (string fontName, Action callback) { if (!fontChangeCallbacks.ContainsKey (fontName)) fontChangeCallbacks [fontName] = new List<Action> (); 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<Pad> searchMonitors = new List<Pad> (); List<Pad> outputMonitors = new List<Pad> (); - + /******************************/ - 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> (); - 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> (); + 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); } /// <summary> @@ -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 <christian.hergert@gmail.com> -// Todd Berman <tberman@off.net> -// John Luke <john.luke@gmail.com> -// -// 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<FileOpenInformation> requestedFileList = new List<FileOpenInformation> (); - List<string> parameterList = new List<string> (); - - public IList<string> ParameterList { - get { return parameterList; } - } - - public IEnumerable<FileOpenInformation> 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; } - - /// <summary> - /// Set to true if a project was opened on startup. - /// </summary> - internal bool OpenedRecentProject { get; set; } - - /// <summary> - /// Set to true if files were opened on startup. - /// </summary> - internal bool OpenedFiles { get; set; } - - /// <summary> - /// Matches a filename string with optional line and column - /// (/foo/bar/blah.cs;22;31) - /// </summary> - public static readonly Regex FileExpression = new Regex (@"^(?<filename>[^;]+)(;(?<line>\d+))?(;(?<column>\d+))?$", RegexOptions.Compiled); - - public StartupInfo (IEnumerable<string> 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 <mhutchinson@novell.com> -// Lluis Sanchez Gual <lluis@novell.com> -// -// 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 <llsan@microsoft.com> // - +// 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<Tuple<NavigationPoint, int>> closedHistory = new List<Tuple<NavigationPoint, int>> (); + HistoryList history = new HistoryList (); + List<Tuple<NavigationPoint, int>> closedHistory = new List<Tuple<NavigationPoint, int>> (); + 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<NavigationPoint, int> (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<RootWorkspace> (); + workspace.LastWorkspaceItemClosed += Workspace_LastWorkspaceItemClosed; + workspace.FileRenamedInProject += FileRenamed; + + documentManager = await serviceProvider.GetService<DocumentManager> (); + 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> (); + 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<NavigationPoint, int> (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<INavigable> (); 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<NavigationHistoryItem> GetNavigationList (int desiredLength) + + public IList<NavigationHistoryItem> GetNavigationList (int desiredLength) { return history.GetList (desiredLength); } - - public static IList<NavigationHistoryItem> GetNavigationList (int desiredLength, out int currentIndex) + + public IList<NavigationHistoryItem> 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<Project, ProjectCommentTags> projectTags = new Dictionary<Project, ProjectCommentTags> (); + 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<RootWorkspace> (s => { + s.LastWorkspaceItemClosed += LastWorkspaceItemClosed; + s.WorkspaceItemUnloaded += OnWorkspaceItemUnloaded; + }); } + public static Dictionary<Project, ProjectCommentTags> 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<Project, ProjectCommentTags> projectTags = new Dictionary<Project, ProjectCommentTags> (); - 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<bool> 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<DocumentContext> () != null; + return s; + } - static void HandleDocumentParsed (object sender, EventArgs e) - { - var doc = (Document)sender; + public override Task Initialize (Properties status) + { + context = Controller.GetContent<DocumentContext> (); + 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<ITodoListProvider> (); - 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> (compositionManager => { + var todoListProvider = compositionManager.GetExportedValue<ITodoListProvider> (); + todoListProvider.TodoListUpdated += OnTodoListUpdated; + }); + + Runtime.ServiceProvider.WhenServiceInitialized<RootWorkspace> (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 <lluis@novell.com> @@ -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<RootWorkspace> (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<MonoDevelop.Ide.Gui.Pads.ErrorListPad> (); if (errorsPad != null) { @@ -107,7 +113,7 @@ namespace MonoDevelop.Ide.Tasks /// <summary> /// Shows a description of the task in the status bar /// </summary> - 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<TaskEventArgs> JumpedToTask; + public event EventHandler<TaskEventArgs> JumpedToTask; - internal static void InformJumpToTask (TaskListEntry task) + internal void InformJumpToTask (TaskListEntry task) { EventHandler<TaskEventArgs> 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<CommentTasksChangedEventArgs> CommentTasksChanged; + public event EventHandler<CommentTasksChangedEventArgs> CommentTasksChanged; - public static event EventHandler<TaskEventArgs> TaskToggled; + public event EventHandler<TaskEventArgs> 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 <lluis@novell.com> +// +// 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<TaskListEntry> tasksAdded; List<TaskListEntry> 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<Document> 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 { /// <summary> /// Offers several methods for tracking changes being done in edited files /// </summary> - public static class TextEditorService + [DefaultServiceImplementation] + public class TextEditorService: Service { - static Dictionary<FilePath,List<FileExtension>> fileExtensions = new Dictionary<FilePath,List<FileExtension>> (); - - 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<FilePath,List<FileExtension>> fileExtensions = new Dictionary<FilePath,List<FileExtension>> (); /// <summary> /// 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 /// <param name='column'> /// Column. /// </param> - 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 /// <param name='textFile'> /// Text file. /// </param> - 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 /// <param name='textFile'> /// Text file. /// </param> - 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<FileLineExtension> GetFileLineExtensions (FilePath file) + IEnumerable<FileLineExtension> GetFileLineExtensions (FilePath file) { file = file.CanonicalPath; return fileExtensions.Values.SelectMany (e => e).OfType<FileLineExtension> ().Where (e => e.File.CanonicalPath == file); @@ -132,8 +125,9 @@ namespace MonoDevelop.Ide.TextEditing /// <param name='extension'> /// The extension. /// </param> - public static void RegisterExtension (FileExtension extension) + public void RegisterExtension (FileExtension extension) { + extension.TextEditorService = this; List<FileExtension> list; if (!fileExtensions.TryGetValue (extension.File, out list)) list = fileExtensions [extension.File] = new List<FileExtension> (); @@ -147,7 +141,7 @@ namespace MonoDevelop.Ide.TextEditing /// <param name='extension'> /// Extension. /// </param> - public static void UnregisterExtension (FileExtension extension) + public void UnregisterExtension (FileExtension extension) { List<FileExtension> 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 /// <param name='file'> /// File. /// </param> - public static FileExtension[] GetFileExtensions (FilePath file) + public FileExtension[] GetFileExtensions (FilePath file) { List<FileExtension> 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 /// <summary> /// Occurs when there has been a line count change in a file being edited /// </summary> - public static event EventHandler<LineCountEventArgs> LineCountChanged; + public event EventHandler<LineCountEventArgs> LineCountChanged; /// <summary> /// Occurs when all previous line change notifications for a file have to be discarded /// </summary> - public static event EventHandler<TextFileEventArgs> LineCountChangesReset; + public event EventHandler<TextFileEventArgs> LineCountChangesReset; /// <summary> /// Occurs when all previous line change notifications for a file have to be committed /// </summary> - public static event EventHandler<TextFileEventArgs> LineCountChangesCommitted; + public event EventHandler<TextFileEventArgs> LineCountChangesCommitted; /// <summary> /// Occurs when a text editor extension has been added /// </summary> - public static event EventHandler<FileExtensionEventArgs> FileExtensionAdded; + public event EventHandler<FileExtensionEventArgs> FileExtensionAdded; /// <summary> /// Occurs when a text editor extension has been removed /// </summary> - public static event EventHandler<FileExtensionEventArgs> FileExtensionRemoved; + public event EventHandler<FileExtensionEventArgs> 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<MonoDevelopMetadataReference> (), Project = netProject, Visited = new HashSet<string> (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<MonoDevelop.Projects.AssemblyReference> 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<MetadataReferenceHandler> (() => new MetadataReferenceHandler (workspace.MetadataReferenceManager, projectMap)); - hostDiagnosticUpdateSource = new Lazy<HostDiagnosticUpdateSource> (() => new HostDiagnosticUpdateSource (workspace, Composition.CompositionManager.GetExportedValue<IDiagnosticUpdateSourceRegistrationService> ())); + hostDiagnosticUpdateSource = new Lazy<HostDiagnosticUpdateSource> (() => new HostDiagnosticUpdateSource (workspace, workspace.compositionManager.GetExportedValue<IDiagnosticUpdateSourceRegistrationService> ())); } #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<DocumentInfo> GenerateProjections (MonoDevelop.Projects.ProjectFile f, DocumentMap documentMap, MonoDevelop.Projects.Project p, ProjectData oldProjectData, HashSet<DocumentId> 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 <mkrueger@xamarin.com>
-//
-// Copyright (c) 2014 Xamarin Inc. (http://xamarin.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
+// +// MonoDevelopWorkspace.cs +// +// Author: +// Mike Krüger <mkrueger@xamarin.com> +// +// Copyright (c) 2014 Xamarin Inc. (http://xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + using System;
using Microsoft.CodeAnalysis;
using System.Linq;
@@ -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 (); + } + /// <summary>
/// This bypasses the type system service. Use with care.
/// </summary>
@@ -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<MonoDevelopMetadataReferenceManager> (() => Services.GetService<MonoDevelopMetadataReferenceManager> ());
- metadataHandler = new Lazy<MetadataReferenceHandler> (() => new MetadataReferenceHandler (MetadataReferenceManager, ProjectMap));
-
- if (IdeApp.Workspace != null && solution != null) {
- IdeApp.Workspace.ActiveConfigurationChanged += HandleActiveConfigurationChanged;
- }
+ metadataHandler = new Lazy<MetadataReferenceHandler> (() => new MetadataReferenceHandler (MetadataReferenceManager, ProjectMap)); + }
+ + internal async Task Initialize ()
+ {
+ serviceProvider.WhenServiceInitialized<RootWorkspace> (s => { + workspace = s; + if (MonoDevelopSolution != null) + workspace.ActiveConfigurationChanged += HandleActiveConfigurationChanged; + });
+
backgroundCompiler = new BackgroundCompiler (this); var cacheService = Services.GetService<IWorkspaceCacheService> ();
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<ISolutionCrawlerRegistrationService> ();
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<Microsoft.CodeAnalysis.Options.IDocumentOptionsProviderFactory>("/MonoDevelop/Ide/TypeService/OptionProviders"))
Services.GetRequiredService<Microsoft.CodeAnalysis.Options.IOptionService> ().RegisterDocumentOptionsProvider (factory.Create (this));
- if (solution != null)
- DesktopService.MemoryMonitor.StatusChanged += OnMemoryStatusChanged;
+ desktopService = await serviceProvider.GetService<DesktopService> ().ConfigureAwait (false); + documentManager = await serviceProvider.GetService<DocumentManager> ().ConfigureAwait (false); + compositionManager = await serviceProvider.GetService<CompositionManager> ().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<IErrorReportingService> ().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<ISolutionCrawlerRegistrationService> ();
- if (IdeApp.Preferences.EnableSourceAnalysis)
+ if (TypeSystemService.EnableSourceAnalysis)
solutionCrawler.Register (this);
else
solutionCrawler.Unregister (this); - var diagnosticAnalyzer = CompositionManager.GetExportedValue<Microsoft.CodeAnalysis.Diagnostics.IDiagnosticAnalyzerService> (); + var diagnosticAnalyzer = compositionManager.GetExportedValue<Microsoft.CodeAnalysis.Diagnostics.IDiagnosticAnalyzerService> (); 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<string> (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<string> (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<MonoDevelop.Projects.DotNetProject> modifiedProjects = new List<MonoDevelop.Projects.DotNetProject> ();
- readonly object projectModifyLock = new object ();
+ readonly object projectModifyLock = new object (); bool freezeProjectModify;
Dictionary<MonoDevelop.Projects.DotNetProject, CancellationTokenSource> projectModifiedCts = new Dictionary<MonoDevelop.Projects.DotNetProject, CancellationTokenSource> ();
+
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 <mkrueger@novell.com> @@ -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<TypeSystemParserNode> 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<TypeSystemParserNode> parsers; + string[] filesSkippedInParseThread = new string[0]; + + public Microsoft.CodeAnalysis.SyntaxAnnotation InsertionModeAnnotation { get; } = new Microsoft.CodeAnalysis.SyntaxAnnotation(); - internal static IEnumerable<TypeSystemParserNode> Parsers { + // Preferences + internal static RoslynPreferences Preferences { get; } = new RoslynPreferences (); + internal static ConfigurationProperty<bool> EnableSourceAnalysis = ConfigurationProperty.Create ("MonoDevelop.AnalysisCore.AnalysisEnabled_V2", true); + + internal MonoDevelopRuleSetManager RuleSetManager { get; } = new MonoDevelopRuleSetManager (); + + internal IEnumerable<TypeSystemParserNode> 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<DocumentManager> (s => documentManager = s); + serviceProvider.WhenServiceInitialized<RootWorkspace> (s => { + rootWorkspace = s; + rootWorkspace.ActiveConfigurationChanged += HandleActiveConfigurationChanged; + }); - static TypeSystemService () - { RoslynServices.RoslynService.Initialize (); CleanupCache (); parsers = AddinManager.GetExtensionNodes<TypeSystemParserNode> ("/MonoDevelop/TypeSystem/Parser"); @@ -89,64 +96,95 @@ namespace MonoDevelop.Ide.TypeSystem initialLoad = false; try { - emptyWorkspace = new MonoDevelopWorkspace (null); + compositionManager = await serviceProvider.GetService<CompositionManager> ().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<string> (); - 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<DesktopService> (); + } + + 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<string> (); + 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<MonoDevelopWorkspace> 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<ParsedDocument> ParseFile (Project project, string fileName, CancellationToken cancellationToken = default(CancellationToken)) + public Task<ParsedDocument> ParseFile (Project project, string fileName, CancellationToken cancellationToken = default(CancellationToken)) { StringTextSource text; @@ -166,10 +204,10 @@ namespace MonoDevelop.Ide.TypeSystem return TaskUtil.Default<ParsedDocument>(); } - return ParseFile (project, fileName, DesktopService.GetMimeTypeForUri (fileName), text, cancellationToken); + return ParseFile (project, fileName, desktopService.GetMimeTypeForUri (fileName), text, cancellationToken); } - public static Task<ParsedDocument> ParseFile (ParseOptions options, string mimeType, CancellationToken cancellationToken = default(CancellationToken)) + public Task<ParsedDocument> 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<ParsedDocument> ParseFile (Project project, string fileName, string mimeType, ITextSource content, CancellationToken cancellationToken = default(CancellationToken)) + public Task<ParsedDocument> 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<ParsedDocument> ParseFile (Project project, string fileName, string mimeType, TextReader content, CancellationToken cancellationToken = default(CancellationToken)) + public Task<ParsedDocument> 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<ParsedDocument> ParseFile (Project project, IReadonlyTextDocument data, CancellationToken cancellationToken = default(CancellationToken)) + public Task<ParsedDocument> ParseFile (Project project, IReadonlyTextDocument data, CancellationToken cancellationToken = default(CancellationToken)) { return ParseFile (project, data.FileName, data.MimeType, data, cancellationToken); } - internal static async Task<ParsedDocumentProjection> ParseProjection (ParseOptions options, string mimeType, CancellationToken cancellationToken = default(CancellationToken)) + internal async Task<ParsedDocumentProjection> 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<ParsedDocumentProjection> ParseProjection (Project project, string fileName, string mimeType, ITextSource content, CancellationToken cancellationToken = default(CancellationToken)) + internal Task<ParsedDocumentProjection> 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<ParsedDocumentProjection> ParseProjection (Project project, string fileName, string mimeType, TextReader content, CancellationToken cancellationToken = default(CancellationToken)) + internal Task<ParsedDocumentProjection> 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<ParsedDocumentProjection> ParseProjection (Project project, IReadonlyTextDocument data, CancellationToken cancellationToken = default(CancellationToken)) + internal Task<ParsedDocumentProjection> ParseProjection (Project project, IReadonlyTextDocument data, CancellationToken cancellationToken = default(CancellationToken)) { return ParseProjection (project, data.FileName, data.MimeType, data, cancellationToken); } #region Folding parsers - static List<MimeTypeExtensionNode> foldingParsers; + List<MimeTypeExtensionNode> foldingParsers; - static IEnumerable<MimeTypeExtensionNode> FoldingParsers { + IEnumerable<MimeTypeExtensionNode> FoldingParsers { get { if (foldingParsers == null) { foldingParsers = new List<MimeTypeExtensionNode> (); @@ -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 /// <returns>The cache directory.</returns> /// <param name="project">The project to get the cache for.</param> /// <param name="forceCreation">If set to <c>true</c> the creation is forced and the method doesn't return null.</param> - 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<string, object> cacheLocker = new Dictionary<string, object> (); + readonly Dictionary<string, object> cacheLocker = new Dictionary<string, object> (); /// <summary> /// Gets the cache directory for arbitrary file names. @@ -383,7 +421,7 @@ namespace MonoDevelop.Ide.TypeSystem /// <returns>The cache directory.</returns> /// <param name="fileName">The file name to get the cache for.</param> /// <param name="forceCreation">If set to <c>true</c> the creation is forced and the method doesn't return null.</param> - 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<FilePath, CacheDirectoryInfo> cacheDirectoryCache = new Dictionary<FilePath, CacheDirectoryInfo> (); + readonly Dictionary<FilePath, CacheDirectoryInfo> cacheDirectoryCache = new Dictionary<FilePath, CacheDirectoryInfo> (); - 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 <c>string.GetHashCode</c> if the hash code /// is persisted to disk. /// </summary> - static int GetStableHashCode(string text) + int GetStableHashCode(string text) { unchecked { int h = 0; @@ -496,7 +534,7 @@ namespace MonoDevelop.Ide.TypeSystem } } - static IEnumerable<string> GetPossibleCacheDirNames (string baseName) + IEnumerable<string> 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<T> (string path) where T : class + T DeserializeObject<T> (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 /// <summary> /// Removes all cache directories which are older than 30 days. /// </summary> - static void CleanupCache () + void CleanupCache () { string derivedDataPath = UserProfile.Current.CacheDir.Combine ("DerivedData"); IEnumerable<string> 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 <mkrueger@xamarin.com> @@ -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<MonoDevelopWorkspace> workspaces = ImmutableList<MonoDevelopWorkspace>.Empty; - static ConcurrentDictionary<MonoDevelop.Projects.Solution, TaskCompletionSource<MonoDevelopWorkspace>> workspaceRequests = new ConcurrentDictionary<MonoDevelop.Projects.Solution, TaskCompletionSource<MonoDevelopWorkspace>> (); + object workspaceLock = new object(); + ImmutableList<MonoDevelopWorkspace> workspaces = ImmutableList<MonoDevelopWorkspace>.Empty; + ConcurrentDictionary<MonoDevelop.Projects.Solution, TaskCompletionSource<MonoDevelopWorkspace>> workspaceRequests = new ConcurrentDictionary<MonoDevelop.Projects.Solution, TaskCompletionSource<MonoDevelopWorkspace>> (); - public static ImmutableArray<Microsoft.CodeAnalysis.Workspace> AllWorkspaces { + public ImmutableArray<Microsoft.CodeAnalysis.Workspace> AllWorkspaces { get { return workspaces.ToImmutableArray<Microsoft.CodeAnalysis.Workspace> (); } } - 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<MonoDevelopWorkspace> GetWorkspaceAsync (MonoDevelop.Projects.Solution solution, CancellationToken cancellationToken = default (CancellationToken)) + public async Task<MonoDevelopWorkspace> 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<List<MonoDevelopWorkspace>> Load (WorkspaceItem item, ProgressMonitor progressMonitor, CancellationToken cancellationToken = default (CancellationToken), bool showStatusIcon = true) + internal async Task<List<MonoDevelopWorkspace>> 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<MonoDevelopWorkspace> (); + 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<MonoDevelopWorkspace> CreateWorkspaces (WorkspaceItem item) + async Task CreateWorkspaces (WorkspaceItem item, List<MonoDevelopWorkspace> 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<MonoDevelopWorkspace> mdWorkspaces, ProgressMonitor progressMonitor, CancellationToken cancellationToken = default (CancellationToken), bool showStatusIcon = true) + async Task InternalLoad (List<MonoDevelopWorkspace> 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<DocumentId> GetDocuments (string fileName) + public IEnumerable<DocumentId> 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<Microsoft.CodeAnalysis.Project> GetCodeAnalysisProjectAsync (MonoDevelop.Projects.Project project, CancellationToken cancellationToken = default (CancellationToken)) + public async Task<Microsoft.CodeAnalysis.Project> 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<Compilation> GetCompilationAsync (MonoDevelop.Projects.Project project, CancellationToken cancellationToken = default(CancellationToken)) + public Task<Compilation> 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<TypeSystemOutputTrackingNode> outputTrackedProjects = new List<TypeSystemOutputTrackingNode> (); + readonly List<TypeSystemOutputTrackingNode> outputTrackedProjects = new List<TypeSystemOutputTrackingNode> (); - 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; + } } /// <summary> /// Adds an output tracking node for unit testing purposes. /// </summary> - [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 <lluis@novell.com> @@ -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) /// </summary> /// <returns>The native toolkit.</returns> - 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<DesktopApplication> GetApplications (string filename) + public IEnumerable<DesktopApplication> 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<string> GetMimeTypeInheritanceChainForRoslynLanguage (string language) + public IEnumerable<string> 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<bool> GetFileIsTextAsync (string file, string mimeType = null) + public async Task<bool> 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<string> GetMimeTypeInheritanceChain (string mimeType) + public IEnumerable<string> GetMimeTypeInheritanceChain (string mimeType) { return PlatformService.GetMimeTypeInheritanceChain (mimeType); } - public static IEnumerable<string> GetMimeTypeInheritanceChainForFile (string filename) + public IEnumerable<string> 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 /// <param name="workingDirectory">Working directory.</param> /// <param name="environmentVariables">Environment variables.</param> /// <param name="windowTitle">Window title.</param> - public static void OpenTerminal ( + public void OpenTerminal ( FilePath workingDirectory, IDictionary<string, string> 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<string> GetUpdaterEnvironmentFlags () + internal IEnumerable<string> 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 /// <summary> /// Grab the desktop focus for the window. /// </summary> - 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 /// </summary> /// <returns> false if the user cancels exiting. </returns> /// <param name="reopenWorkspace"> true to reopen current workspace. </param> - 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<IPlatformTelemetryDetails> platformTelemetryDetails = new Lazy<IPlatformTelemetryDetails> (() => 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<TypeSystemService> ().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<CommandManager> (); + await Runtime.GetService<DesktopService> (); + await Runtime.GetService<FontService> (); + await Runtime.GetService<TaskService> (); + Counters.Initialization.Trace ("Creating Workbench"); workbench = new Workbench (); + Counters.Initialization.Trace ("Creating Root Workspace"); - workspace = new RootWorkspace (); + await Runtime.GetService<RootWorkspace> (); + Counters.Initialization.Trace ("Creating Services"); - projectOperations = new ProjectOperations (); + await Runtime.GetService<ProjectOperations> (); helpOperations = new HelpOperations (); - commandService = new CommandManager (); - ideServices = new IdeServices (); + + await Runtime.GetService<TextEditorService> (); + await Runtime.GetService<NavigationHistoryService> (); + await Runtime.GetService<DisplayBindingService> (); + 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<TypeSystemService> ().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<FileOpenInformation> 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> templatingService = new Lazy<TemplatingService> (() => 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 <llsan@microsoft.com> +// +// 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<FileEventArgs> 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<FilePath> (); + + 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); + } + + /// <summary>SDBM-style hash, bounded to a range of 1000.</summary> + 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<bool> EnableInstrumentation = Runtime.Preferences.EnableInstrumentation; public readonly ConfigurationProperty<bool> EnableAutomatedTesting = Runtime.Preferences.EnableAutomatedTesting; @@ -89,39 +90,14 @@ namespace MonoDevelop.Ide public readonly ConfigurationProperty<bool> DefaultHideMessageBubbles = ConfigurationProperty.Create ("MonoDevelop.Ide.DefaultHideMessageBubbles", false); public readonly ConfigurationProperty<ShowMessageBubbles> ShowMessageBubbles = ConfigurationProperty.Create ("MonoDevelop.Ide.NewShowMessageBubbles", MonoDevelop.Ide.ShowMessageBubbles.ForErrorsAndWarnings); - public readonly ConfigurationProperty<TargetRuntime> DefaultTargetRuntime = new DefaultTargetRuntimeProperty (); - - class DefaultTargetRuntimeProperty: ConfigurationProperty<TargetRuntime> - { - ConfigurationProperty<string> 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<TargetRuntime> DefaultTargetRuntime => RootWorkspace.DefaultTargetRuntime; public readonly ConfigurationProperty<string> UserInterfaceLanguage = Runtime.Preferences.UserInterfaceLanguage; public readonly ConfigurationProperty<string> UserInterfaceThemeName = ConfigurationProperty.Create ("MonoDevelop.Ide.UserInterfaceTheme", Platform.IsLinux ? "" : "Light"); public readonly ConfigurationProperty<WorkbenchCompactness> WorkbenchCompactness = ConfigurationProperty.Create ("MonoDevelop.Ide.WorkbenchCompactness", MonoDevelop.Ide.WorkbenchCompactness.Normal); public readonly ConfigurationProperty<bool> LoadPrevSolutionOnStartup = ConfigurationProperty.Create ("SharpDevelop.LoadPrevProjectOnStartup", false); public readonly ConfigurationProperty<bool> CreateFileBackupCopies = ConfigurationProperty.Create ("SharpDevelop.CreateBackupCopy", false); - public readonly ConfigurationProperty<bool> LoadDocumentUserProperties = ConfigurationProperty.Create ("SharpDevelop.LoadDocumentProperties", true); + public ConfigurationProperty<bool> LoadDocumentUserProperties => IdeApp.Workbench.DocumentManager.Preferences.LoadDocumentUserProperties; public readonly ConfigurationProperty<bool> EnableDocumentSwitchDialog = ConfigurationProperty.Create ("MonoDevelop.Core.Gui.EnableDocumentSwitchDialog", true); public readonly ConfigurationProperty<bool> ShowTipsAtStartup = ConfigurationProperty.Create ("MonoDevelop.Core.Gui.Dialog.TipOfTheDayView.ShowTipsAtStartup", false); @@ -130,12 +106,14 @@ namespace MonoDevelop.Ide /// <summary> /// Font to use for treeview pads. Returns null if no custom font is set. /// </summary> - public readonly ConfigurationProperty<Pango.FontDescription> CustomPadFont = FontService.GetFontProperty ("Pad"); + public ConfigurationProperty<Pango.FontDescription> CustomPadFont => customPadFont.Value; + readonly Lazy<ConfigurationProperty<Pango.FontDescription>> customPadFont = new Lazy<ConfigurationProperty<Pango.FontDescription>> (() => IdeApp.FontService.GetFontProperty ("Pad")); /// <summary> /// Font to use for output pads. Returns null if no custom font is set. /// </summary> - public readonly ConfigurationProperty<Pango.FontDescription> CustomOutputPadFont = FontService.GetFontProperty ("OutputPad"); + public ConfigurationProperty<Pango.FontDescription> CustomOutputPadFont => customOutputPadFont.Value; + readonly Lazy<ConfigurationProperty<Pango.FontDescription>> customOutputPadFont = new Lazy<ConfigurationProperty<Pango.FontDescription>> (() => IdeApp.FontService.GetFontProperty ("OutputPad")); public readonly ConfigurationProperty<bool> EnableCompletionCategoryMode = ConfigurationProperty.Create ("EnableCompletionCategoryMode", false); public readonly ConfigurationProperty<bool> 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<bool> EnableSourceAnalysis = ConfigurationProperty.Create ("MonoDevelop.AnalysisCore.AnalysisEnabled_V2", true); + public ConfigurationProperty<bool> EnableSourceAnalysis => TypeSystemService.EnableSourceAnalysis; public readonly ConfigurationProperty<bool> 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<TargetRuntime> + { + ConfigurationProperty<string> 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<TextEditorService> (s => textEditorService = s); + Runtime.ServiceProvider.WhenServiceInitialized<NavigationHistoryService> (s => navigationHistoryManager = s); + Runtime.ServiceProvider.WhenServiceInitialized<DisplayBindingService> (s => displayBindingService = s); + Runtime.ServiceProvider.WhenServiceInitialized<FontService> (s => fontService = s); + Runtime.ServiceProvider.WhenServiceInitialized<TypeSystemService> (s => typeSystemService = s); + Runtime.ServiceProvider.WhenServiceInitialized<DesktopService> (s => desktopService = s); + Runtime.ServiceProvider.WhenServiceInitialized<DocumentManager> (s => documentManager = s); + Runtime.ServiceProvider.WhenServiceInitialized<RootWorkspace> (s => workspace = s); + Runtime.ServiceProvider.WhenServiceInitialized<ProgressMonitorManager> (s => progressMonitorManager = s); + Runtime.ServiceProvider.WhenServiceInitialized<TaskService> (s => taskService = s); + Runtime.ServiceProvider.WhenServiceInitialized<ProjectOperations> (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> templatingService = new Lazy<TemplatingService> (() => 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> (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<AddinError> errorsList = new List<AddinError> (); 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<IExtendedTitleBarWindowBackend,GtkExtendedTitleBarWindowBackend> (); - Xwt.Toolkit.CurrentEngine.RegisterBackend<IExtendedTitleBarDialogBackend,GtkExtendedTitleBarDialogBackend> (); + Xwt.Toolkit.CurrentEngine.RegisterBackend<IExtendedTitleBarWindowBackend, GtkExtendedTitleBarWindowBackend> (); + Xwt.Toolkit.CurrentEngine.RegisterBackend<IExtendedTitleBarDialogBackend, GtkExtendedTitleBarDialogBackend> (); 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<int> 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<DesktopService> (); 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<ProgressMonitorManager, IdeProgressMonitorManager> (); + Runtime.RegisterServiceType<IShell, DefaultWorkbench> (); + } + void FMOpenTimerExpired () { IdeApp.Workspace.FirstWorkspaceItemOpened -= CompleteSolutionTimeToCode; @@ -427,6 +417,9 @@ namespace MonoDevelop.Ide /// </summary> 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<CompositionManager> (); // OpenDocuments appears when the app is idle. if (!hideWelcomePage && !WelcomePage.WelcomePageService.HasWindowImplementation) { @@ -476,7 +470,7 @@ namespace MonoDevelop.Ide void CreateStartupMetadata (StartupInfo startupInfo, Dictionary<string, long> 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 } } - /// <summary>SDBM-style hash, bounded to a range of 1000.</summary> - 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<string> 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<string> 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 {
/// <summary> /// This is the basic interface to the workspace. - /// </summary> - public partial class ProjectOperations - { + /// </summary>
+ [DefaultServiceImplementation] + public partial class ProjectOperations: Service + {
+ RootWorkspace workspace;
+ AsyncOperation<BuildResult> currentBuildOperation = new AsyncOperation<BuildResult> (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<RootWorkspace> (); + workspace.WorkspaceItemUnloaded += OnWorkspaceItemUnloaded;
+ workspace.ItemUnloading += IdeAppWorkspaceItemUnloading;
+ await Task.WhenAll (new Task [] {
+ serviceProvider.GetService<DocumentManager> (),
+ serviceProvider.GetService<ProgressMonitorManager> (),
+ serviceProvider.GetService<TaskService> ()
+ });
+ }
+
+ 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<MonoDevelop.Ide.Gui.Content.IOpenNamedElementHandler> (); + var handler = doc.GetContent<MonoDevelop.Ide.Gui.Content.IOpenNamedElementHandler> (); 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<MonoDevelop.Ide.Gui.Content.IOpenNamedElementHandler> (); + var handler = doc.GetContent<MonoDevelop.Ide.Gui.Content.IOpenNamedElementHandler> (); 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<Task> (); 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<WorkspaceItem> 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); } /// <summary> @@ -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<BuildResult> (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<MonoDevelop.Ide.Gui.Document> (IdeApp.Workbench.Documents)) { - if (doc.IsDirty && doc.Project != null) { + foreach (var doc in new List<MonoDevelop.Ide.Gui.Document> (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<SolutionEventArgs> CurrentSelectedSolutionChanged; - public event ProjectEventHandler CurrentProjectChanged; + + public event EventHandler<SolutionEventArgs> CurrentSelectedSolutionChanged { + add { + workspace.CurrentSelectedSolutionChanged += value; + } + remove { + workspace.CurrentSelectedSolutionChanged -= value;
+ } + } + + public event ProjectEventHandler CurrentProjectChanged { + add { + workspace.CurrentProjectChanged += value; + } + + remove { + workspace.CurrentProjectChanged -= value;
+ } + } + public event EventHandler<ProjectCreatedEventArgs> 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 <lluis@novell.com> @@ -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<bool> (); currentWorkspaceLoadTask.SetResult (true); + } + Task IService.Initialize (ServiceProvider serviceProvider) + { + this.serviceProvider = serviceProvider; FileService.FileRenamed += CheckFileRename; - + + serviceProvider.WhenServiceInitialized<DocumentManager> (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<TargetRuntime> 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<SolutionEventArgs> 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<IBuildTarget> 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<ProgressMonitorManager> (); + 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<bool> Close (bool saveWorkspacePreferencies) { - return await Close (saveWorkspacePreferencies, true); + return await Close (saveWorkspacePreferencies, true, false); } - - internal async Task<bool> Close (bool saveWorkspacePreferencies, bool closeProjectFiles) + + internal async Task<bool> 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<WorkspaceItem> (Items)) { - if (!RequestItemUnload (it)) - return false; + if (!force) { + // Request permission for unloading the items + foreach (WorkspaceItem it in new List<WorkspaceItem> (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<Project> (); - 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<WorkspaceItem> ().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<ProgressMonitorManager> (); + 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<string> 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<DesktopService> ()?.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<FilePath> 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<ProgressMonitorManager> (); + 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<string> closedDocs = result.Item2; if (allowReload) { - using (ProgressMonitor m = IdeApp.Workbench.ProgressMonitors.GetProjectLoadProgressMonitor (true)) { + var monitorManager = await Runtime.GetService<ProgressMonitorManager> (); + 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<Document> GetOpenDocuments (Project project, bool modifiedOnly) + List<Document> GetOpenDocuments (Project project, bool modifiedOnly) { List<Document> docs = new List<Document> (); - 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<TypeSystemService> (); + 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<TypeSystemService> (); + 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 + /// <summary> /// Fired when a file is removed from a project. /// </summary> |