diff options
author | Lluis Sanchez <llsan@microsoft.com> | 2019-04-02 14:47:19 +0300 |
---|---|---|
committer | Lluis Sanchez <llsan@microsoft.com> | 2019-04-02 14:47:19 +0300 |
commit | 034efec5570d1ca12d7314ce2447692e379f446f (patch) | |
tree | 2ea03cbffcf1167f8b4b931a139729d496f073f6 /main/src | |
parent | 8fc7d7e202598c31fdbb54d84e3e1fcd1003eb1c (diff) | |
parent | 0331b37ed370c639781c87ac969992f362d34eb0 (diff) |
Merge remote-tracking branch 'xamarin/master-vnext' into new-service-model
Diffstat (limited to 'main/src')
55 files changed, 984 insertions, 602 deletions
diff --git a/main/src/addins/MacPlatform/MacPlatform.cs b/main/src/addins/MacPlatform/MacPlatform.cs index 6dfb61f82f..b0dda5c1ea 100644 --- a/main/src/addins/MacPlatform/MacPlatform.cs +++ b/main/src/addins/MacPlatform/MacPlatform.cs @@ -640,7 +640,7 @@ namespace MonoDevelop.MacIntegration //OpenFiles may pump the mainloop, but can't do that from an AppleEvent GLib.Idle.Add (delegate { Ide.WelcomePage.WelcomePageService.HideWelcomePageOrWindow (); - var trackTTC = IdeApp.StartTimeToCodeLoadTimer (); + var trackTTC = IdeStartupTracker.StartupTracker.StartTimeToCodeLoadTimer (); IdeApp.OpenFiles (e.Documents.Select ( doc => new FileOpenInformation (doc.Key, null, doc.Value, 1, OpenDocumentOptions.DefaultInternal)), null @@ -651,7 +651,7 @@ namespace MonoDevelop.MacIntegration var firstFile = e.Documents.First ().Key; - IdeApp.TrackTimeToCode (GetDocumentTypeFromFilename (firstFile)); + IdeStartupTracker.StartupTracker.TrackTimeToCode (GetDocumentTypeFromFilename (firstFile)); }); return false; }); @@ -660,7 +660,7 @@ namespace MonoDevelop.MacIntegration ApplicationEvents.OpenUrls += delegate (object sender, ApplicationUrlEventArgs e) { GLib.Idle.Add (delegate { - var trackTTC = IdeApp.StartTimeToCodeLoadTimer (); + var trackTTC = IdeStartupTracker.StartupTracker.StartTimeToCodeLoadTimer (); // Open files via the monodevelop:// URI scheme, compatible with the // common TextMate scheme: http://blog.macromates.com/2007/the-textmate-url-scheme/ IdeApp.OpenFiles (e.Urls.Select (url => { @@ -690,7 +690,7 @@ namespace MonoDevelop.MacIntegration } var firstFile = e.Urls.First (); - IdeApp.TrackTimeToCode (GetDocumentTypeFromFilename (firstFile)); + IdeStartupTracker.StartupTracker.TrackTimeToCode (GetDocumentTypeFromFilename (firstFile)); }); return false; }); diff --git a/main/src/addins/MonoDevelop.AspNetCore/MonoDevelop.AspNetCore/AspNetCoreCertificateManager.cs b/main/src/addins/MonoDevelop.AspNetCore/MonoDevelop.AspNetCore/AspNetCoreCertificateManager.cs index 1e5ec4d5ab..d6bcd21706 100644 --- a/main/src/addins/MonoDevelop.AspNetCore/MonoDevelop.AspNetCore/AspNetCoreCertificateManager.cs +++ b/main/src/addins/MonoDevelop.AspNetCore/MonoDevelop.AspNetCore/AspNetCoreCertificateManager.cs @@ -37,7 +37,8 @@ namespace MonoDevelop.AspNetCore static class AspNetCoreCertificateManager { public static bool IsDevelopmentCertificateTrusted { get; private set; } - + static readonly DotNetCoreVersion MinimumCoreRuntime = DotNetCoreVersion.Parse ("2.1"); + static readonly DotNetCoreVersion MinimumCoreSDK = DotNetCoreVersion.Parse ("2.1.300"); /// <summary> /// Only supported projects should be checked. If the development certificate /// was found to be trusted then do not check again for the current IDE session. @@ -52,8 +53,8 @@ namespace MonoDevelop.AspNetCore } /// <summary> - /// Only .NET Core 2.1 projects are supported. - /// Also need .NET Core SDK 2.1 to be installed. + /// Only .NET Core 2.1 projects and higher are supported. + /// Also need .NET Core SDK 2.1 or higher to be installed. /// Also check if the project is using https. /// </summary> public static bool IsProjectSupported (DotNetProject project, SolutionItemRunConfiguration runConfiguration) @@ -63,8 +64,8 @@ namespace MonoDevelop.AspNetCore return false; } - return project.TargetFramework.IsNetCoreApp ("2.1") && - IsNetCoreSdk21Installed () && + return project.TargetFramework.IsNetCoreAppOrHigher (MinimumCoreRuntime) && + IsNetCoreSdk21OrHigherInstalled () && UsingHttps (runConfiguration); } @@ -74,21 +75,15 @@ namespace MonoDevelop.AspNetCore return aspNetCoreRunConfiguration?.UsingHttps () == true; } - static bool IsNetCoreSdk21Installed () - { - return DotNetCoreSdk.Versions.Any (IsNetCoreSdk21); - } + static bool IsNetCoreSdk21OrHigherInstalled () => DotNetCoreSdk.Versions.Any (IsNetCoreSdk21OrHigher); /// <summary> - /// This checks for .NET Core SDK 2.1 to be installed. Note that the - /// .NET Core SDK versions is confusing. Here we want the .NET Core 2.1 + /// This checks for .NET Core SDK 2.1 or higher to be installed. Note that the + /// .NET Core SDK versions is confusing. Here we want at least the .NET Core 2.1 /// SDK that supports .NET Core App 2.1. Not the .NET Core 2.1 SDK that /// supports .NET Core App 2.0 only. /// </summary> - static bool IsNetCoreSdk21 (DotNetCoreVersion version) - { - return version.Major == 2 && version.Minor == 1 && version.Patch >= 300; - } + static bool IsNetCoreSdk21OrHigher (DotNetCoreVersion version) => version >= MinimumCoreSDK; public static async Task TrustDevelopmentCertificate (ProgressMonitor monitor) { diff --git a/main/src/addins/MonoDevelop.AspNetCore/Properties/MonoDevelop.AspNetCore.addin.xml b/main/src/addins/MonoDevelop.AspNetCore/Properties/MonoDevelop.AspNetCore.addin.xml index a91a288055..f7ce13dbca 100644 --- a/main/src/addins/MonoDevelop.AspNetCore/Properties/MonoDevelop.AspNetCore.addin.xml +++ b/main/src/addins/MonoDevelop.AspNetCore/Properties/MonoDevelop.AspNetCore.addin.xml @@ -79,7 +79,7 @@ For example, .NET Core 1.1 SDK does not have a Razor template so having the 1.1 templates first
would cause the Razor template to be last in the New Project dialog if both 1.1 and 2.x templates
are available. -->
- <Condition id="AspNetCoreSdkInstalled" sdkVersion="3.0">
+ <Condition id="AspNetCoreSdkInstalled" sdkVersion="3.0">
<Template
id="Microsoft.Web.Empty.CSharp"
templateId="Microsoft.Web.Empty.CSharp.3.0"
@@ -169,6 +169,19 @@ category="netcore/app/aspnet"
formatExclude="*.min.css|*.min.js|*.map"
defaultParameters="IncludeLaunchSettings=true" />
+ <Template
+ id="Microsoft.Web.Razor.Library.CSharp"
+ templateId="Microsoft.Web.Razor.Library.CSharp.3.0"
+ _overrideName="Razor Class Library"
+ _overrideDescription="A project for creating a Razor class library that targets .NET Standard"
+ path="${DotNetCoreSdk.3.0.Templates.Web.ProjectTemplates.nupkg}"
+ icon="md-netcore-empty-project"
+ imageId="md-netcore-empty-project"
+ wizard="MonoDevelop.DotNetCore.ProjectTemplateWizard"
+ condition="UseNetCore30=true"
+ category="netcore/app/aspnet"
+ formatExclude="*.min.css|*.min.js|*.map"
+ defaultParameters="IncludeLaunchSettings=true" />
</Condition>
<Condition id="AspNetCoreSdkInstalled" sdkVersion="2.2">
<Template
@@ -260,6 +273,19 @@ category="netcore/app/aspnet"
formatExclude="*.min.css|*.min.js|*.map"
defaultParameters="IncludeLaunchSettings=true" />
+ <Template
+ id="Microsoft.Web.Razor.Library.CSharp"
+ templateId="Microsoft.Web.Razor.Library.CSharp.2.2"
+ _overrideName="Razor Class Library"
+ _overrideDescription="A project for creating a Razor class library that targets .NET Standard"
+ path="${DotNetCoreSdk.2.2.Templates.Web.ProjectTemplates.nupkg}"
+ icon="md-netcore-empty-project"
+ imageId="md-netcore-empty-project"
+ wizard="MonoDevelop.DotNetCore.ProjectTemplateWizard"
+ condition="UseNetCore22=true"
+ category="netcore/app/aspnet"
+ formatExclude="*.min.css|*.min.js|*.map"
+ defaultParameters="IncludeLaunchSettings=true" />
</Condition>
<Condition id="AspNetCoreSdkInstalled" sdkVersion="2.1">
<Template
@@ -351,6 +377,19 @@ category="netcore/app/aspnet"
formatExclude="*.min.css|*.min.js|*.map"
defaultParameters="IncludeLaunchSettings=true" />
+ <Template
+ id="Microsoft.Web.Razor.Library.CSharp"
+ templateId="Microsoft.Web.Razor.Library.CSharp.2.1"
+ _overrideName="Razor Class Library"
+ _overrideDescription="A project for creating a Razor class library that targets .NET Standard"
+ path="${DotNetCoreSdk.2.1.Templates.Web.ProjectTemplates.nupkg}"
+ icon="md-netcore-empty-project"
+ imageId="md-netcore-empty-project"
+ wizard="MonoDevelop.DotNetCore.ProjectTemplateWizard"
+ condition="UseNetCore21=true"
+ category="netcore/app/aspnet"
+ formatExclude="*.min.css|*.min.js|*.map"
+ defaultParameters="IncludeLaunchSettings=true" />
</Condition>
<Condition id="AspNetCoreSdkInstalled" sdkVersion="2.0">
<Template
diff --git a/main/src/addins/MonoDevelop.AspNetCore/Templates/MVCViewImportsPage.xft.xml b/main/src/addins/MonoDevelop.AspNetCore/Templates/MVCViewImportsPage.xft.xml index 8393e4a536..9b1002de01 100644 --- a/main/src/addins/MonoDevelop.AspNetCore/Templates/MVCViewImportsPage.xft.xml +++ b/main/src/addins/MonoDevelop.AspNetCore/Templates/MVCViewImportsPage.xft.xml @@ -14,7 +14,10 @@ </TemplateConfiguration> <Conditions> - <AspNetCore /> + <Or> + <AspNetCore /> + <ProjectCapability Name="DotNetCoreRazor"/> + </Or> </Conditions> <!-- Template Content --> diff --git a/main/src/addins/MonoDevelop.AspNetCore/Templates/MVCViewLayoutPage.xft.xml b/main/src/addins/MonoDevelop.AspNetCore/Templates/MVCViewLayoutPage.xft.xml index 5fbc33c8f3..dd332cb77b 100644 --- a/main/src/addins/MonoDevelop.AspNetCore/Templates/MVCViewLayoutPage.xft.xml +++ b/main/src/addins/MonoDevelop.AspNetCore/Templates/MVCViewLayoutPage.xft.xml @@ -14,7 +14,10 @@ </TemplateConfiguration> <Conditions> - <AspNetCore /> + <Or> + <AspNetCore /> + <ProjectCapability Name="DotNetCoreRazor"/> + </Or> </Conditions> <!-- Template Content --> diff --git a/main/src/addins/MonoDevelop.AspNetCore/Templates/MVCViewPage.xft.xml b/main/src/addins/MonoDevelop.AspNetCore/Templates/MVCViewPage.xft.xml index 39106f6040..3ba1cd42df 100644 --- a/main/src/addins/MonoDevelop.AspNetCore/Templates/MVCViewPage.xft.xml +++ b/main/src/addins/MonoDevelop.AspNetCore/Templates/MVCViewPage.xft.xml @@ -14,7 +14,10 @@ </TemplateConfiguration> <Conditions> - <AspNetCore /> + <Or> + <AspNetCore /> + <ProjectCapability Name="DotNetCoreRazor"/> + </Or> </Conditions> <!-- Template Content --> diff --git a/main/src/addins/MonoDevelop.AspNetCore/Templates/MVCViewStartPage.xft.xml b/main/src/addins/MonoDevelop.AspNetCore/Templates/MVCViewStartPage.xft.xml index 9615880eae..b7306129ec 100644 --- a/main/src/addins/MonoDevelop.AspNetCore/Templates/MVCViewStartPage.xft.xml +++ b/main/src/addins/MonoDevelop.AspNetCore/Templates/MVCViewStartPage.xft.xml @@ -14,7 +14,10 @@ </TemplateConfiguration> <Conditions> - <AspNetCore /> + <Or> + <AspNetCore /> + <ProjectCapability Name="DotNetCoreRazor"/> + </Or> </Conditions> <!-- Template Content --> diff --git a/main/src/addins/MonoDevelop.AspNetCore/Templates/RazorPage.xft.xml b/main/src/addins/MonoDevelop.AspNetCore/Templates/RazorPage.xft.xml index 68fce01577..30ddd41fc5 100644 --- a/main/src/addins/MonoDevelop.AspNetCore/Templates/RazorPage.xft.xml +++ b/main/src/addins/MonoDevelop.AspNetCore/Templates/RazorPage.xft.xml @@ -14,7 +14,10 @@ </TemplateConfiguration> <Conditions> - <AspNetCore minVersion="2.0"/> + <Or> + <AspNetCore minVersion="2.0"/> + <ProjectCapability Name="DotNetCoreRazor"/> + </Or> </Conditions> <!-- Template Content --> diff --git a/main/src/addins/MonoDevelop.AspNetCore/Templates/RazorPageWithPageModel.xft.xml b/main/src/addins/MonoDevelop.AspNetCore/Templates/RazorPageWithPageModel.xft.xml index a2db23ea8e..dcd7c8fc53 100644 --- a/main/src/addins/MonoDevelop.AspNetCore/Templates/RazorPageWithPageModel.xft.xml +++ b/main/src/addins/MonoDevelop.AspNetCore/Templates/RazorPageWithPageModel.xft.xml @@ -14,7 +14,10 @@ </TemplateConfiguration> <Conditions> - <AspNetCore minVersion="2.0" /> + <Or> + <AspNetCore minVersion="2.0"/> + <ProjectCapability Name="DotNetCoreRazor"/> + </Or> </Conditions> <!-- Template Content --> diff --git a/main/src/addins/MonoDevelop.AspNetCore/Templates/RazorTagHelper.xft.xml b/main/src/addins/MonoDevelop.AspNetCore/Templates/RazorTagHelper.xft.xml index 637686310e..42562c570f 100644 --- a/main/src/addins/MonoDevelop.AspNetCore/Templates/RazorTagHelper.xft.xml +++ b/main/src/addins/MonoDevelop.AspNetCore/Templates/RazorTagHelper.xft.xml @@ -14,7 +14,10 @@ </TemplateConfiguration> <Conditions> - <AspNetCore /> + <Or> + <AspNetCore /> + <ProjectCapability Name="DotNetCoreRazor"/> + </Or> </Conditions> <!-- Template Content --> diff --git a/main/src/addins/MonoDevelop.Debugger.VSCodeDebugProtocol/MonoDevelop.Debugger.VsCodeDebugProtocol/packages.config b/main/src/addins/MonoDevelop.Debugger.VSCodeDebugProtocol/MonoDevelop.Debugger.VsCodeDebugProtocol/packages.config deleted file mode 100644 index 5f282702bb..0000000000 --- a/main/src/addins/MonoDevelop.Debugger.VSCodeDebugProtocol/MonoDevelop.Debugger.VsCodeDebugProtocol/packages.config +++ /dev/null @@ -1 +0,0 @@ -
\ No newline at end of file diff --git a/main/src/addins/MonoDevelop.DesignerSupport/AddinInfo.cs b/main/src/addins/MonoDevelop.DesignerSupport/AddinInfo.cs index 3fa48ba6ac..60adee7d2d 100644 --- a/main/src/addins/MonoDevelop.DesignerSupport/AddinInfo.cs +++ b/main/src/addins/MonoDevelop.DesignerSupport/AddinInfo.cs @@ -14,3 +14,8 @@ using Mono.Addins.Description; [assembly:AddinDependency ("Core", MonoDevelop.BuildInfo.Version)] [assembly:AddinDependency ("Ide", MonoDevelop.BuildInfo.Version)] + +#if MAC +[assembly: ImportAddinAssembly ("Xamarin.PropertyEditing.dll")] +[assembly: ImportAddinAssembly ("Xamarin.PropertyEditing.Mac.dll")] +#endif diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/Styles.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/Styles.cs index 6b62628491..0963655a61 100644 --- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/Styles.cs +++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/Styles.cs @@ -1,4 +1,4 @@ -#if MAC
+#if MAC
using AppKit;
using MonoDevelop.Ide; using Xamarin.PropertyEditing.Mac; @@ -29,14 +29,12 @@ namespace MonoDevelop.DesignerSupport public static void LoadStyles ()
{ if (IdeApp.Preferences.UserInterfaceTheme == Theme.Light) { - PropertyEditorPanel.ThemeManager.Theme = Xamarin.PropertyEditing.Themes.PropertyEditorTheme.Light; HeaderBackgroundColor = NSColor.FromRgb (0.98f, 0.98f, 0.98f); HeaderBorderBackgroundColor = NSColor.FromRgb (0.96f, 0.96f, 0.96f);
LabelSelectedForegroundColor = NSColor.Highlight;
ToolbarBackgroundColor = NSColor.White;
CellBackgroundSelectedColor = NSColor.FromRgb (0.36f, 0.54f, 0.90f);
} else {
- PropertyEditorPanel.ThemeManager.Theme = Xamarin.PropertyEditing.Themes.PropertyEditorTheme.Dark;
CellBackgroundSelectedColor = NSColor.FromRgb (0.38f, 0.55f, 0.91f);
HeaderBackgroundColor = NSColor.FromRgb (0.29f, 0.29f, 0.29f);
HeaderBorderBackgroundColor = NSColor.FromRgb (0.29f, 0.29f, 0.29f);
diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.csproj b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.csproj index 27cb32a163..86aa268f00 100644 --- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.csproj +++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.csproj @@ -144,6 +144,7 @@ <Compile Include="MonoDevelop.DesignerSupport\NativePropertyEditors\PropertyInfo\DirectoryPathPropertyInfo.cs" /> <Compile Include="MonoDevelop.DesignerSupport\IPropertyPad.cs" /> <Compile Include="MonoDevelop.DesignerSupport\NativePropertyEditors\PropertyInfo\FlagDescriptorPropertyInfo.cs" /> + <Compile Include="MonoDevelop.DesignerSupport\NativePropertyEditors\PropertyPadItem.cs" /> </ItemGroup> <ItemGroup> <EmbeddedResource Include="MonoDevelop.DesignerSupport.addin.xml" /> diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs index de3512f570..29d0001577 100644 --- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs +++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs @@ -116,15 +116,15 @@ namespace MonoDevelop.DesignerSupport } } - Tuple<object, object []> currentSelectedObject; + PropertyPadItem currentSelectedObject; public void SetCurrentObject (object lastComponent, object [] propertyProviders) { if (lastComponent != null) { - var selection = new Tuple<object, object []> (lastComponent, propertyProviders); + var selection = new PropertyPadItem (lastComponent, propertyProviders); if (currentSelectedObject != selection) { propertyEditorPanel.SelectedItems.Clear (); - propertyEditorPanel.SelectedItems.Add (new Tuple<object, object []> (lastComponent, propertyProviders)); + propertyEditorPanel.SelectedItems.Add (selection); currentSelectedObject = selection; } } diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyInfo/DirectoryPathPropertyInfo.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyInfo/DirectoryPathPropertyInfo.cs index 6a070d80c1..6de957d826 100644 --- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyInfo/DirectoryPathPropertyInfo.cs +++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyInfo/DirectoryPathPropertyInfo.cs @@ -24,7 +24,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -#if MAC +#if MAC && false using System; using System.Threading.Tasks; diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyInfo/FilePathPropertyInfo.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyInfo/FilePathPropertyInfo.cs index 563c5eee6b..393416929a 100644 --- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyInfo/FilePathPropertyInfo.cs +++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyInfo/FilePathPropertyInfo.cs @@ -40,11 +40,11 @@ namespace MonoDevelop.DesignerSupport { } - public override Type Type => typeof (FilePath); + public override Type Type => typeof (Xamarin.PropertyEditing.Common.FilePath); internal override void SetValue<T> (object target, T value) { - if (value is FilePath filePath) { + if (value is Xamarin.PropertyEditing.Common.FilePath filePath) { PropertyDescriptor.SetValue (PropertyProvider, new MonoDevelop.Core.FilePath (filePath.Source)); } else { throw new Exception (string.Format ("Value: {0} of type {1} is not a DirectoryPath", value, value.GetType ())); @@ -53,8 +53,8 @@ namespace MonoDevelop.DesignerSupport internal override Task<T> GetValueAsync<T> (object target) { - if (target is Core.FilePath directoryPath) { - T result = (T)(object)new FilePath (directoryPath.FullPath); + if (target is MonoDevelop.Core.FilePath directoryPath) { + T result = (T)(object)new Xamarin.PropertyEditing.Common.FilePath (directoryPath.FullPath); return Task.FromResult (result); } Core.LoggingService.LogWarning ("Value: {0} of type {1} is not a DirectoryPath", target, target.GetType ()); diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyPadEditorProvider.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyPadEditorProvider.cs index 1d74baaf33..8752869230 100644 --- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyPadEditorProvider.cs +++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyPadEditorProvider.cs @@ -41,19 +41,14 @@ namespace MonoDevelop.DesignerSupport class PropertyPadEditorProvider : IEditorProvider { - Tuple<object, object[]> currentObject; - IObjectEditor currentEditor; - public IReadOnlyDictionary<Type, ITypeInfo> KnownTypes { get; } = new Dictionary<Type, ITypeInfo> (); public Task<IObjectEditor> GetObjectEditorAsync (object item) { - if (item is Tuple<object, object []> tuple) { - this.currentObject = tuple; - this.currentEditor = new PropertyPadObjectEditor (tuple); ; - return Task.FromResult (currentEditor); + if (item is PropertyPadItem propertyPadItem) { + return Task.FromResult<IObjectEditor> (new PropertyPadObjectEditor (propertyPadItem)); } return Task.FromResult<IObjectEditor> (null); } diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyPadItem.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyPadItem.cs new file mode 100644 index 0000000000..ecd5235fd8 --- /dev/null +++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyPadItem.cs @@ -0,0 +1,69 @@ +// +// PropertyPadItem.cs +// +// Author: +// jmedrano <josmed@microsoft.com> +// +// Copyright (c) 2018 +// +// 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. + +#if MAC + +using System; +using System.Threading.Tasks; +using MonoDevelop.Core; +using Xamarin.PropertyEditing; + +namespace MonoDevelop.DesignerSupport +{ + class PropertyPadItem + { + public PropertyPadItem (object target, object [] providers) + { + Target = target; + Providers = providers; + } + + public object Target { get; } + public object[] Providers { get; } + + public async Task<ValueInfo<T>> GetPropertyValueInfoAsProppyType<T> (DescriptorPropertyInfo propertyInfo) + { + T value = await propertyInfo.GetValueAsync<T> (this); + return new ValueInfo<T> { + Value = value, + Source = ValueSource.Local, + //ValueDescriptor = valueInfoString.ValueDescriptor, + //CustomExpression = valueString + }; + } + + public void SetPropertyValueInfoAsProppyType<T> (DescriptorPropertyInfo info, ValueInfo<T> value, PropertyVariation variations) + { + try { + info.SetValue (this, value.Value); + } catch (Exception ex) { + LoggingService.LogError ("Error setting the value", ex); + } + } + } +} + +#endif
\ No newline at end of file diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyPadObjectEditor.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyPadObjectEditor.cs index 40fa6dc49a..c272b78a4a 100644 --- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyPadObjectEditor.cs +++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditors/PropertyPadObjectEditor.cs @@ -39,9 +39,9 @@ using MonoDevelop.Core; namespace MonoDevelop.DesignerSupport { class PropertyPadObjectEditor - : IObjectEditor, INameableObject, IObjectEventEditor + : IObjectEditor, INameableObject { - private readonly object target; + private readonly PropertyPadItem propertyItem; public string Name { get; private set; @@ -51,7 +51,7 @@ namespace MonoDevelop.DesignerSupport private static readonly IObjectEditor [] EmptyDirectChildren = new IObjectEditor [0]; private readonly List<PropertyDescriptorEventInfo> events = new List<PropertyDescriptorEventInfo> (); - public object Target => this.target; + public object Target => this.propertyItem; public ITypeInfo TargetType => ToTypeInfo (Target.GetType ()); @@ -65,7 +65,7 @@ namespace MonoDevelop.DesignerSupport public IReadOnlyDictionary<IPropertyInfo, KnownProperty> KnownProperties => null; - public IObjectEditor Parent => throw new NotImplementedException (); + public IObjectEditor Parent => null; public IReadOnlyList<IObjectEditor> DirectChildren => EmptyDirectChildren; @@ -73,10 +73,10 @@ namespace MonoDevelop.DesignerSupport public event EventHandler<EditorPropertyChangedEventArgs> PropertyChanged; - public PropertyPadObjectEditor (Tuple<object, object []> target) + public PropertyPadObjectEditor (PropertyPadItem propertyItem) { - this.target = target.Item1; - foreach (object propertyProvider in target.Item2) { + this.propertyItem = propertyItem; + foreach (object propertyProvider in propertyItem.Providers) { var props = GetProperties (propertyProvider, null); for (int i = 0; i < props.Count; i++) { @@ -118,10 +118,10 @@ namespace MonoDevelop.DesignerSupport } if (propertyDescriptor.PropertyType.IsAssignableFrom (typeof (Core.FilePath))) { - var isDirectoryPropertyDescriptor = GetPropertyDescriptor (propertyDescriptor.GetChildProperties (), nameof (Core.FilePath.IsDirectory)); - if (isDirectoryPropertyDescriptor != null && (bool)isDirectoryPropertyDescriptor.GetValue (target)) { - return new DirectoryPathPropertyInfo (propertyDescriptor, PropertyProvider, valueSources); - } + //var isDirectoryPropertyDescriptor = GetPropertyDescriptor (propertyDescriptor.GetChildProperties (), nameof (Core.FilePath.IsDirectory)); + //if (isDirectoryPropertyDescriptor != null && (bool)isDirectoryPropertyDescriptor.GetValue (propertyItem)) { + // return new DirectoryPathPropertyInfo (propertyDescriptor, PropertyProvider, valueSources); + //} return new FilePathPropertyInfo (propertyDescriptor, PropertyProvider, valueSources); } @@ -139,20 +139,6 @@ namespace MonoDevelop.DesignerSupport return TypeDescriptor.GetProperties (component); } - #region NOT SUPORTED - - public Task AttachHandlerAsync (IEventInfo ev, string handlerName) - { - throw new NotImplementedException (); - } - - public Task DetachHandlerAsync (IEventInfo ev, string handlerName) - { - throw new NotImplementedException (); - } - - #endregion - public async Task<AssignableTypesResult> GetAssignableTypesAsync (IPropertyInfo property, bool childTypes) { return new AssignableTypesResult (Array.Empty<ITypeInfo> ()); @@ -166,7 +152,7 @@ namespace MonoDevelop.DesignerSupport if (!(ev is Xamarin.PropertyEditing.Reflection.ReflectionEventInfo info)) throw new ArgumentException (); - return Task.FromResult (info.GetHandlers (this.target)); + return Task.FromResult (info.GetHandlers (this.propertyItem)); } public Task<string> GetNameAsync () @@ -184,17 +170,10 @@ namespace MonoDevelop.DesignerSupport if (property == null) throw new ArgumentNullException (nameof (property)); - if (!(property is DescriptorPropertyInfo info)) - throw new ArgumentException (); - - T value = await info.GetValueAsync<T> (this.target); + if (!(property is DescriptorPropertyInfo propertyInfo)) + throw new ArgumentException ("Property should be a DescriptorPropertyInfo", nameof (property)); - return new ValueInfo<T> { - Value = value, - Source = ValueSource.Local, - //ValueDescriptor = valueInfoString.ValueDescriptor, - //CustomExpression = valueString - }; + return await propertyItem.GetPropertyValueInfoAsProppyType<T> (propertyInfo); } public Task RemovePropertyVariantAsync (IPropertyInfo property, PropertyVariation variant) @@ -208,21 +187,19 @@ namespace MonoDevelop.DesignerSupport return Task.FromResult (true); } - public Task SetValueAsync<T> (IPropertyInfo propertyInfo, ValueInfo<T> valueInfo, PropertyVariation variations = null) + public Task SetValueAsync<T> (IPropertyInfo propertyInfo, ValueInfo<T> value, PropertyVariation variations = null) { if (propertyInfo == null) throw new ArgumentNullException (nameof (propertyInfo)); if (propertyInfo is DescriptorPropertyInfo info && info.CanWrite) { - try { - info.SetValue (this.target, valueInfo.Value); - } catch (Exception ex) { - LoggingService.LogError ("Error setting the value", ex); - } + + propertyItem.SetPropertyValueInfoAsProppyType (info, value, variations); OnPropertyChanged (info); + return Task.CompletedTask; } - return Task.CompletedTask; + throw new ArgumentException ($"Property should be a writeable {nameof (DescriptorPropertyInfo)}.", nameof (propertyInfo)); } protected virtual void OnPropertyChanged (IPropertyInfo property) diff --git a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore.Tests/MonoDevelop.DotNetCore.Tests/DotNetCoreProjectTemplateTests.cs b/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore.Tests/MonoDevelop.DotNetCore.Tests/DotNetCoreProjectTemplateTests.cs index 7a51d6a7f7..4522ea3c8e 100644 --- a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore.Tests/MonoDevelop.DotNetCore.Tests/DotNetCoreProjectTemplateTests.cs +++ b/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore.Tests/MonoDevelop.DotNetCore.Tests/DotNetCoreProjectTemplateTests.cs @@ -271,6 +271,7 @@ namespace MonoDevelop.DotNetCore.Tests [TestCase ("Microsoft.Web.RazorPages.CSharp", "UseNetCore21=true")] [TestCase ("Microsoft.Web.WebApi.CSharp", "UseNetCore21=true")] [TestCase ("Microsoft.Web.WebApi.FSharp", "UseNetCore21=true")] + [TestCase ("Microsoft.Web.Razor.Library.CSharp", "UseNetCore21=true")] public async Task AspNetCore21 (string templateId, string parameters) { if (!IsDotNetCoreSdk21Installed ()) { @@ -287,6 +288,7 @@ namespace MonoDevelop.DotNetCore.Tests [TestCase ("Microsoft.Web.RazorPages.CSharp", "UseNetCore22=true")] [TestCase ("Microsoft.Web.WebApi.CSharp", "UseNetCore22=true")] [TestCase ("Microsoft.Web.WebApi.FSharp", "UseNetCore22=true")] + [TestCase ("Microsoft.Web.Razor.Library.CSharp", "UseNetCore22=true")] public async Task AspNetCore22 (string templateId, string parameters) { if (!IsDotNetCoreSdk22Installed ()) { @@ -304,6 +306,7 @@ namespace MonoDevelop.DotNetCore.Tests [TestCase ("Microsoft.Web.RazorPages.CSharp", "UseNetCore30=true")] [TestCase ("Microsoft.Web.WebApi.CSharp", "UseNetCore30=true")] [TestCase ("Microsoft.Web.WebApi.FSharp", "UseNetCore30=true")] + [TestCase ("Microsoft.Web.Razor.Library.CSharp", "UseNetCore30=true")] public async Task AspNetCore30 (string templateId, string parameters) { if (!IsDotNetCoreSdk30Installed ()) { diff --git a/main/src/addins/MonoDevelop.Packaging/MonoDevelop.Packaging.csproj b/main/src/addins/MonoDevelop.Packaging/MonoDevelop.Packaging.csproj index d1da520ca1..bc0bde87a3 100644 --- a/main/src/addins/MonoDevelop.Packaging/MonoDevelop.Packaging.csproj +++ b/main/src/addins/MonoDevelop.Packaging/MonoDevelop.Packaging.csproj @@ -7,7 +7,7 @@ <ProjectGuid>{443311BF-766D-4863-B5A1-AFAA7F41DBDA}</ProjectGuid> <TargetFrameworkVersion>$(MDFrameworkVersion)</TargetFrameworkVersion> <OutputPath>..\..\..\build\AddIns\MonoDevelop.Packaging</OutputPath> - <_BuildPackagingVersion>0.2.0</_BuildPackagingVersion> + <_BuildPackagingVersion>0.2.5-dev.8</_BuildPackagingVersion> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' " /> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> diff --git a/main/src/addins/MonoDevelop.Packaging/MonoDevelop.Packaging/DotNetProjectExtensions.cs b/main/src/addins/MonoDevelop.Packaging/MonoDevelop.Packaging/DotNetProjectExtensions.cs index 8f6eb98264..b973cfecd6 100644 --- a/main/src/addins/MonoDevelop.Packaging/MonoDevelop.Packaging/DotNetProjectExtensions.cs +++ b/main/src/addins/MonoDevelop.Packaging/MonoDevelop.Packaging/DotNetProjectExtensions.cs @@ -70,7 +70,7 @@ namespace MonoDevelop.Packaging public static void InstallBuildPackagingNuGetPackage (IEnumerable<Project> projects) { string packagesFolder = GetPackagesFolder (); - var packageReference = new PackageManagementPackageReference ("NuGet.Build.Packaging", "0.2.0"); + var packageReference = new PackageManagementPackageReference ("NuGet.Build.Packaging", "0.2.5-dev.8"); var packageReferences = new [] { packageReference }; diff --git a/main/src/addins/MonoDevelop.Packaging/Templates/CrossPlatformLibrary.xpt.xml b/main/src/addins/MonoDevelop.Packaging/Templates/CrossPlatformLibrary.xpt.xml index 2bfa014101..bbc1befa97 100644 --- a/main/src/addins/MonoDevelop.Packaging/Templates/CrossPlatformLibrary.xpt.xml +++ b/main/src/addins/MonoDevelop.Packaging/Templates/CrossPlatformLibrary.xpt.xml @@ -29,7 +29,7 @@ DefaultNamespace="${ProjectName}" HideGettingStarted="true" /> <Packages> - <Package ID="NuGet.Build.Packaging" Version="0.2.0" directory="../packages" /> + <Package ID="NuGet.Build.Packaging" Version="0.2.5-dev.8" directory="../packages" /> </Packages> <Files> <FileTemplateReference TemplateID="EmptyClass" name="MyClass.cs" /> @@ -50,7 +50,7 @@ <Reference type="Project" refto="${ProjectName}.Shared" /> </References> <Packages> - <Package ID="NuGet.Build.Packaging" Version="0.2.0" directory="../packages" /> + <Package ID="NuGet.Build.Packaging" Version="0.2.5-dev.8" directory="../packages" /> </Packages> <Files> <FileTemplateReference TemplateID="CSharpAssemblyInfo" name="AssemblyInfo.cs" /> @@ -67,7 +67,7 @@ <Reference type="Project" refto="${ProjectName}.Shared" /> </References> <Packages> - <Package ID="NuGet.Build.Packaging" Version="0.2.0" directory="../packages" /> + <Package ID="NuGet.Build.Packaging" Version="0.2.5-dev.8" directory="../packages" /> </Packages> <Files> <FileTemplateReference TemplateID="CSharpAssemblyInfo" name="AssemblyInfo.cs" /> @@ -77,7 +77,7 @@ <Project name="${ProjectName}.NuGet" directory="${ProjectName}.NuGet" type="NuGetPackaging" if="CreateNuGetProject"> <Options TargetFrameworkVersion="4.5" DefaultNamespace="${ProjectName}" HideGettingStarted="true" /> <Packages> - <Package ID="NuGet.Build.Packaging" Version="0.2.0" directory="../packages" /> + <Package ID="NuGet.Build.Packaging" Version="0.2.5-dev.8" directory="../packages" /> </Packages> <References> <Reference type="Project" refto="${ProjectName}.Android" if="CreateAndroidProject" /> diff --git a/main/src/addins/MonoDevelop.Packaging/Templates/PackagingProject.xpt.xml b/main/src/addins/MonoDevelop.Packaging/Templates/PackagingProject.xpt.xml index e5d699884f..82dbbd1fc5 100644 --- a/main/src/addins/MonoDevelop.Packaging/Templates/PackagingProject.xpt.xml +++ b/main/src/addins/MonoDevelop.Packaging/Templates/PackagingProject.xpt.xml @@ -18,7 +18,7 @@ <Project name="${ProjectName}" directory="." type="NuGetPackaging"> <Options TargetFrameworkVersion="4.5" /> <Packages> - <Package ID="NuGet.Build.Packaging" Version="0.2.0" directory="../packages" /> + <Package ID="NuGet.Build.Packaging" Version="0.2.5-dev.8" directory="../packages" /> </Packages> <Files> <File name="readme.txt"><![CDATA[ diff --git a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeActions/CodeActionEditorExtension.cs b/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeActions/CodeActionEditorExtension.cs index 38dd1c42a4..3da12a678e 100644 --- a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeActions/CodeActionEditorExtension.cs +++ b/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeActions/CodeActionEditorExtension.cs @@ -186,7 +186,18 @@ namespace MonoDevelop.CodeActions { Runtime.AssertMainThread (); var caretOffset = Editor.CaretOffset; - return collections.Select (c => FilterOnUIThread (c, workspace)).Where(x => x != null).OrderBy(x => GetDistance (x, caretOffset)).ToImmutableArray (); + var builder = ImmutableArray.CreateBuilder<CodeFixCollection> (collections.Length); + var ids = new HashSet<string> (); + foreach (var c in collections) { + if (!ids.Add (c.FirstDiagnostic.Id)) + continue; + var filtered = FilterOnUIThread (c, workspace); + if (filtered == null) + continue; + builder.Add (filtered); + } + builder.Sort ((x, y) => GetDistance (x, caretOffset).CompareTo (GetDistance (y, caretOffset))); + return builder.ToImmutableArray (); } static int GetDistance (CodeFixCollection fixCollection, int caretOffset) diff --git a/main/src/addins/MonoDevelop.SourceEditor2/MonoDevelop.SourceEditor.QuickTasks/QuickTaskOverviewMode.cs b/main/src/addins/MonoDevelop.SourceEditor2/MonoDevelop.SourceEditor.QuickTasks/QuickTaskOverviewMode.cs index 6af63e47b2..87836059be 100644 --- a/main/src/addins/MonoDevelop.SourceEditor2/MonoDevelop.SourceEditor.QuickTasks/QuickTaskOverviewMode.cs +++ b/main/src/addins/MonoDevelop.SourceEditor2/MonoDevelop.SourceEditor.QuickTasks/QuickTaskOverviewMode.cs @@ -86,14 +86,14 @@ namespace MonoDevelop.SourceEditor.QuickTasks get { return okImage; } - }
-
- Cairo.Color win81Slider;
+ } + + Cairo.Color win81Slider; Cairo.Color win81SliderPrelight; int win81ScrollbarWidth; - protected override void OnStyleSet (Style previous_style)
- {
+ protected override void OnStyleSet (Style previous_style) + { base.OnStyleSet (previous_style); if (Core.Platform.IsWindows) { using (var scrollstyle = Rc.GetStyleByPaths (Settings, null, null, VScrollbar.GType)) { @@ -228,7 +228,7 @@ namespace MonoDevelop.SourceEditor.QuickTasks } void DestroyBackgroundSurface () - {
+ { if (backgroundSurface != null) { backgroundSurface.Dispose (); backgroundSurface = null; @@ -1002,20 +1002,20 @@ namespace MonoDevelop.SourceEditor.QuickTasks } void IndicatorSurfaceTimeoutHandler (bool forceUpdate) - {
- indicatorIdleTimout = 0;
- if (!IsRealized)
- return;
- var allocation = Allocation;
- src?.Cancel ();
- src = new CancellationTokenSource ();
- new IdleUpdater (this, src.Token) { ForceUpdate = forceUpdate }.Start ();
+ { + indicatorIdleTimout = 0; + if (!IsRealized) + return; + var allocation = Allocation; + src?.Cancel (); + src = new CancellationTokenSource (); + new IdleUpdater (this, src.Token) { ForceUpdate = forceUpdate }.Start (); } void RemoveIndicatorIdleHandler () { + src?.Cancel (); if (indicatorIdleTimout > 0) { - src?.Cancel (); GLib.Source.Remove (indicatorIdleTimout); indicatorIdleTimout = 0; } @@ -1415,8 +1415,8 @@ namespace MonoDevelop.SourceEditor.QuickTasks public QuickTaskAccessible (QuickTaskStrip parent, QuickTaskOverviewMode parentMode, QuickTask t) : this (parent, parentMode) { task = t; - usage = null;
-
+ usage = null; + var line = mode.TextEditor.OffsetToLineNumber (t.Location); Accessible.Title = t.Description; Accessible.Help = string.Format (GettextCatalog.GetString ("Jump to line {0}"), line.ToString ()); diff --git a/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor/MonoDevelop.TextEditor.csproj b/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor/MonoDevelop.TextEditor.csproj index 30e59d1313..c728874351 100644 --- a/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor/MonoDevelop.TextEditor.csproj +++ b/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor/MonoDevelop.TextEditor.csproj @@ -18,7 +18,7 @@ <InternalsVisibleTo Include="MonoDevelop.TextEditor.Wpf" /> <Reference Include="PresentationFramework" /> <Reference Include="PresentationCore" /> - <ProjectReference Include="..\..\MonoDevelop.DesignerSupport\MonoDevelop.DesignerSupport.csproj" /> + <ProjectReference Include="..\..\MonoDevelop.DesignerSupport\MonoDevelop.DesignerSupport.csproj" Private="false" /> </ItemGroup> <ItemGroup> <Compile Include="..\..\..\..\external\vs-editor-core\src\Editor\Text\Impl\BaseViewImpl\VacuousTextDataModel.cs" Link="Util\VacuousTextDataModel.cs" /> diff --git a/main/src/addins/PerformanceDiagnostics/PerformanceDiagnostics/Commands.cs b/main/src/addins/PerformanceDiagnostics/PerformanceDiagnostics/Commands.cs index b82de9cb12..852c472a20 100644 --- a/main/src/addins/PerformanceDiagnostics/PerformanceDiagnostics/Commands.cs +++ b/main/src/addins/PerformanceDiagnostics/PerformanceDiagnostics/Commands.cs @@ -25,6 +25,12 @@ namespace PerformanceDiagnosticsAddIn public class ProfileFor5SecondsHandler : CommandHandler { + protected override void Update (CommandInfo info) + { + info.DisableOnShellLock = false; + base.Update (info); + } + protected override void Run () { UIThreadMonitor.Instance.Profile (5); @@ -46,6 +52,7 @@ namespace PerformanceDiagnosticsAddIn protected override void Update(CommandInfo info) { info.Checked = UIThreadMonitor.Instance.ToggleProfilingChecked; + info.DisableOnShellLock = false; base.Update(info); } diff --git a/main/src/addins/PerformanceDiagnostics/PerformanceDiagnostics/UIThreadMonitor.cs b/main/src/addins/PerformanceDiagnostics/PerformanceDiagnostics/UIThreadMonitor.cs index cfa5c6c497..894fee35d9 100644 --- a/main/src/addins/PerformanceDiagnostics/PerformanceDiagnostics/UIThreadMonitor.cs +++ b/main/src/addins/PerformanceDiagnostics/PerformanceDiagnostics/UIThreadMonitor.cs @@ -210,7 +210,11 @@ namespace PerformanceDiagnosticsAddIn internal static void ConvertJITAddressesToMethodNames (string fileName, string profilingType) { + // sample line to replace: + // ??? (in <unknown binary>) [0x103648455] var rx = new Regex (@"\?\?\? \(in <unknown binary>\) \[0x([0-9a-f]+)\]", RegexOptions.Compiled); + + if (File.Exists (fileName) && new FileInfo (fileName).Length > 0) { Directory.CreateDirectory (Options.OutputPath); var outputFilename = Path.Combine (Options.OutputPath, $"{BrandingService.ApplicationName}_{profilingType}_{DateTime.Now:yyyy-MM-dd__HH-mm-ss}.txt"); @@ -219,14 +223,18 @@ namespace PerformanceDiagnosticsAddIn using (var sw = new StreamWriter (outputFilename)) { string line; while ((line = sr.ReadLine ()) != null) { - if (rx.IsMatch (line)) { - var match = rx.Match (line); + + var match = rx.Match (line); + if (match.Success) { var offset = long.Parse (match.Groups [1].Value, NumberStyles.HexNumber); - string pmipMethodName; - if (!methodsCache.TryGetValue (offset, out pmipMethodName)) { + + if (!methodsCache.TryGetValue (offset, out var pmipMethodName)) { pmipMethodName = mono_pmip (offset)?.TrimStart (); + if (pmipMethodName != null) + pmipMethodName = PmipParser.ToSample (pmipMethodName, offset); methodsCache.Add (offset, pmipMethodName); } + if (pmipMethodName != null) { line = line.Remove (match.Index, match.Length); line = line.Insert (match.Index, pmipMethodName); @@ -238,6 +246,95 @@ namespace PerformanceDiagnosticsAddIn } } + static class PmipParser + { + // pmip output: + // (wrapper managed-to-native) Gtk.Application:gtk_main () [{0x7f968e48d1e8} + 0xdf] (0x122577d50 0x122577f28) [0x7f9682702c90 - MonoDevelop.exe] + // MonoDevelop.Startup.MonoDevelopMain:Main (string[]) [{0x7faef5700948} + 0x93] [/Users/therzok/Work/md/monodevelop/main/src/core/MonoDevelop.Startup/MonoDevelop.Startup/MonoDevelopMain.cs :: 39u] (0x10e7609c0 0x10e760aa8) [0x7faef7002d80 - MonoDevelop.exe] + + // sample symbolified line: + // start (in libdyld.dylib) + 1 [0x7fff79c7ded9] + // mono_hit_runtime_invoke (in mono64) + 1619 [0x102f90083] mini-runtime.c:3148 + public static string ToSample (string initialInput, long offset) + { + try { + var input = initialInput.AsSpan (); + var sb = new StringBuilder (); + string filename = null; + + // Cut off wrapper part. + if (input.StartsWith ("(wrapper".AsSpan ())) { + input = input.Slice (input.IndexOf (')') + 1).TrimStart (); + } + + // If it starts with <Module>:, trim it. + if (input.StartsWith ("<Module>:".AsSpan ())) { + input = input.Slice ("<Module>:".Length); + } + + // Usually a generic trampoline marker, don't bother parsing. + if (input[0] == '<') + return input.ToString (); + + // Decode method signature + // Gtk.Application:gtk_main () [{0x7f968e48d1e8} + 0xdf] + var endMethodSignature = input.IndexOf ('{'); + var methodSignature = input.Slice (0, endMethodSignature - 2); // " [" + input = input.Slice (endMethodSignature + 1).TrimStart (); + + // Append chars, escaping what might be unreadable by instruments. + for (int i = 0; i < methodSignature.Length; ++i) { + var ch = methodSignature [i]; + if (ch == ' ') + continue; + + if (ch == ':') { + sb.Append ("::"); + continue; + } + + if (ch == '.') { + sb.Append ("_"); + continue; + } + + if (ch == '[' && methodSignature [i + 1] == ']') { + sb.Append ("*"); + i++; + continue; + } + + sb.Append (ch); + } + + // Add some data to match format, + 0 is because it doesn't matter, we're not looking at native code. + sb.Append (" (in MonoDevelop.exe) + 0 ["); + sb.AppendFormat ("0x{0:x}", offset); + sb.Append ("]"); + + // Skip the rest of the block(s) after the method signature until we get a path. + input = input.Slice (input.IndexOf ('[') + 1).TrimStart (); + + if (input[0] == '/') { + // We have a filename + var end = input.IndexOf (']'); + var filepath = input.Slice (0, end - 1).Trim (); // trim u + filename = filepath.ToString (); + } + + if (filename != null) { + sb.Append (" "); + sb.Append (filename); + } + + return sb.ToString (); + } catch (Exception e) { + LoggingService.LogInternalError ($"Failed to parse line '{initialInput}'", e); + return initialInput; + } + } + } + ConnectionInfo currentConnection; class ConnectionInfo diff --git a/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/GitRepository.cs b/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/GitRepository.cs index c82a36cb7b..86a4f93b9f 100644 --- a/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/GitRepository.cs +++ b/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/GitRepository.cs @@ -1779,7 +1779,7 @@ namespace MonoDevelop.VersionControl.Git public string GetCurrentBranch () { - return RunOperation (() => RootRepository.Head.FriendlyName); + return RunSafeOperation (() => RootRepository.Head.FriendlyName); } void SwitchBranchInternal (ProgressMonitor monitor, string branch) diff --git a/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.Dialogs/SelectRepositoryDialog.cs b/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.Dialogs/SelectRepositoryDialog.cs index cd80d2ceac..c65e4434cc 100644 --- a/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.Dialogs/SelectRepositoryDialog.cs +++ b/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.Dialogs/SelectRepositoryDialog.cs @@ -402,7 +402,8 @@ namespace MonoDevelop.VersionControl.Dialogs } var vcs = systems [repCombo.Active]; - entryFolder.Text = defaultPath + vcs.GetRelativeCheckoutPathForRemote (edit.RelativePath); + var projectNameFolder = System.IO.Path.DirectorySeparatorChar + System.IO.Path.GetFileName (edit.RelativePath); + entryFolder.Text = defaultPath + vcs.GetRelativeCheckoutPathForRemote (projectNameFolder); } } } diff --git a/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.Views/CellRendererDiff.cs b/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.Views/CellRendererDiff.cs index 54824f5ab1..2c41dd248d 100644 --- a/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.Views/CellRendererDiff.cs +++ b/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.Views/CellRendererDiff.cs @@ -150,70 +150,8 @@ namespace MonoDevelop.VersionControl.Views // Rendering is done in two steps: // 1) Get a list of blocks to render // 2) render the blocks - - int y = cell_area.Y + 2; - - // cline keeps track of the current source code line (the one to jump to when double clicking) - int cline = 1; - bool inHeader = true; - BlockInfo currentBlock = null; - - List<BlockInfo> blocks = new List<BlockInfo> (); - - for (int n=0; n<lines.Length; n++, y += lineHeight) { - - string line = lines [n]; - if (line.Length == 0) { - currentBlock = null; - y -= lineHeight; - continue; - } - - char tag = line [0]; - - if (line.StartsWith ("---", StringComparison.Ordinal) || - line.StartsWith ("+++", StringComparison.Ordinal)) { - // Ignore this part of the header. - currentBlock = null; - y -= lineHeight; - continue; - } - if (tag == '@') { - int l = ParseCurrentLine (line); - if (l != -1) cline = l - 1; - inHeader = false; - } else if (tag == '+' && !inHeader) - cline++; - BlockType type; - switch (tag) { - case '-': type = BlockType.Removed; break; - case '+': type = BlockType.Added; break; - case '@': type = BlockType.Info; break; - default: type = BlockType.Unchanged; break; - } - - if (currentBlock == null || type != currentBlock.Type) { - if (y > maxy) - break; - - // Starting a new block. Mark section ends between a change block and a normal code block - if (currentBlock != null && IsChangeBlock (currentBlock.Type) && !IsChangeBlock (type)) - currentBlock.SectionEnd = true; - - currentBlock = new BlockInfo () { - YStart = y, - FirstLine = n, - Type = type, - SourceLineStart = cline, - SectionStart = (blocks.Count == 0 || !IsChangeBlock (blocks[blocks.Count - 1].Type)) && IsChangeBlock (type) - }; - blocks.Add (currentBlock); - } - // Include the line in the current block - currentBlock.YEnd = y + lineHeight; - currentBlock.LastLine = n; - } + var blocks = CalculateBlocks (maxy, cell_area.Y + 2); // Now render the blocks @@ -315,7 +253,81 @@ namespace MonoDevelop.VersionControl.Views window.DrawLayout (widget.Style.TextGC (GetState(widget, flags)), cell_area.X, y, layout); } } - + + List<BlockInfo> CalculateBlocks (int maxy, int y) + { + // cline keeps track of the current source code line (the one to jump to when double clicking) + int cline = 1; + + BlockInfo currentBlock = null; + + var result = new List<BlockInfo> (); + int removedLines = 0; + for (int n = 0; n < lines.Length; n++, y += lineHeight) { + + string line = lines [n]; + if (line.Length == 0) { + currentBlock = null; + y -= lineHeight; + continue; + } + + char tag = line [0]; + + if (line.StartsWith ("---", StringComparison.Ordinal) || + line.StartsWith ("+++", StringComparison.Ordinal)) { + // Ignore this part of the header. + currentBlock = null; + y -= lineHeight; + continue; + } + if (tag == '@') { + int l = ParseCurrentLine (line); + if (l != -1) cline = l - 1; + } else + cline++; + + BlockType type; + switch (tag) { + case '-': + type = BlockType.Removed; + removedLines++; + break; + case '+': type = BlockType.Added; break; + case '@': type = BlockType.Info; break; + default: type = BlockType.Unchanged; break; + } + + if (type != BlockType.Removed && removedLines > 0) { + cline -= removedLines; + removedLines = 0; + } + + if (currentBlock == null || type != currentBlock.Type) { + if (y > maxy) + break; + + // Starting a new block. Mark section ends between a change block and a normal code block + if (currentBlock != null && IsChangeBlock (currentBlock.Type) && !IsChangeBlock (type)) + currentBlock.SectionEnd = true; + + currentBlock = new BlockInfo { + YStart = y, + FirstLine = n, + Type = type, + SourceLineStart = cline, + SectionStart = (result.Count == 0 || !IsChangeBlock (result [result.Count - 1].Type)) && IsChangeBlock (type) + }; + result.Add (currentBlock); + } + // Include the line in the current block + currentBlock.YEnd = y + lineHeight; + currentBlock.LastLine = n; + } + + return result; + } + static bool IsChangeBlock (BlockType t) { return t == BlockType.Added || t == BlockType.Removed; diff --git a/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.Views/StatusView.cs b/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.Views/StatusView.cs index ff8d111a1c..30a2dd0338 100644 --- a/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.Views/StatusView.cs +++ b/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.Views/StatusView.cs @@ -13,6 +13,7 @@ using MonoDevelop.Components.Commands; using MonoDevelop.Projects; using MonoDevelop.Ide; using System.Text; +using System.Threading.Tasks; namespace MonoDevelop.VersionControl.Views { @@ -447,29 +448,50 @@ namespace MonoDevelop.VersionControl.Views showRemoteStatus.Sensitive = false; buttonCommit.Sensitive = false; - ThreadPool.QueueUserWorkItem (delegate { - lock (updateLock) { - if (fileList != null) { - var group = fileList.GroupBy (v => v.IsDirectory || v.WorkspaceObject is SolutionFolderItem); - foreach (var item in group) { - // Is directory. - if (item.Key) { - foreach (var directory in item) - changeSet.AddFiles (vc.GetDirectoryVersionInfo (directory.Path, remoteStatus, true)); - } else - changeSet.AddFiles (item.Select (v => v.VersionInfo).ToArray ()); - } - changeSet.AddFiles (fileList.Where (v => !v.IsDirectory).Select (v => v.VersionInfo).ToArray ()); - fileList = null; + lock (updateLock) { + if (!cancelUpdate.IsCancellationRequested) + cancelUpdate.Cancel (); + cancelUpdate = new CancellationTokenSource (); + var token = cancelUpdate.Token; + updateTask = updateTask.ContinueWith (t => RunUpdate (token), token, TaskContinuationOptions.LazyCancellation, TaskScheduler.Default); + } + } + + CancellationTokenSource cancelUpdate = new CancellationTokenSource (); + Task updateTask = Task.FromResult (true); + + void RunUpdate (CancellationToken cancel) + { + try { + cancel.ThrowIfCancellationRequested (); + if (fileList != null) { + var group = fileList.GroupBy (v => v.IsDirectory || v.WorkspaceObject is SolutionFolderItem); + foreach (var item in group) { + // Is directory. + if (item.Key) { + foreach (var directory in item) + changeSet.AddFiles (vc.GetDirectoryVersionInfo (directory.Path, remoteStatus, true)); + } else + changeSet.AddFiles (item.Select (v => v.VersionInfo).ToArray ()); } - List<VersionInfo> newList = new List<VersionInfo> (); - newList.AddRange (vc.GetDirectoryVersionInfo (filepath, remoteStatus, true)); - Runtime.RunInMainThread (delegate { - if (!disposed) - LoadStatus (newList); - }); + fileList = null; } - }); + + cancel.ThrowIfCancellationRequested (); + var newList = new List<VersionInfo> (); + newList.AddRange (vc.GetDirectoryVersionInfo (filepath, remoteStatus, true)); + + cancel.ThrowIfCancellationRequested (); + Runtime.RunInMainThread (delegate { + // skip status reloading if another update is queued + if (!cancel.IsCancellationRequested && !disposed) + LoadStatus (newList); + }).Ignore (); + } catch (Exception ex) { + if (!(ex is OperationCanceledException)) + LoggingService.LogError ("VCS StatusView update failed", ex); + throw; + } } void LoadStatus (List<VersionInfo> newList) diff --git a/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/Repository.cs b/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/Repository.cs index 6153628e47..02316c9a1a 100644 --- a/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/Repository.cs +++ b/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/Repository.cs @@ -106,7 +106,9 @@ namespace MonoDevelop.VersionControl } } - VersionControlService.repositoryCache.TryRemove (RepositoryPath.CanonicalPath, out _); + lock (VersionControlService.repositoryCacheLock) { + VersionControlService.repositoryCache.Remove (RepositoryPath.CanonicalPath); + } infoCache?.Dispose (); infoCache = null; diff --git a/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/VersionControlService.cs b/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/VersionControlService.cs index c5d9b098d2..610af88219 100644 --- a/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/VersionControlService.cs +++ b/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/VersionControlService.cs @@ -211,7 +211,8 @@ namespace MonoDevelop.VersionControl return String.Empty; } - internal static ConcurrentDictionary<Repository, InternalRepositoryReference> referenceCache = new ConcurrentDictionary<Repository, InternalRepositoryReference> (); + internal static readonly object referenceCacheLock = new object (); + internal static Dictionary<Repository, InternalRepositoryReference> referenceCache = new Dictionary<Repository, InternalRepositoryReference> (); public static Repository GetRepository (WorkspaceObject entry) { if (IsGloballyDisabled) @@ -225,14 +226,20 @@ namespace MonoDevelop.VersionControl InternalRepositoryReference rref = null; if (repo != null) { repo.AddRef (); - rref = referenceCache.GetOrAdd (repo, r => new InternalRepositoryReference (r)); + lock (referenceCacheLock) { + if (!referenceCache.TryGetValue (repo, out rref)) { + rref = new InternalRepositoryReference (repo); + referenceCache [repo] = rref; + } + } } entry.ExtendedProperties [typeof(InternalRepositoryReference)] = rref; return repo; } - internal static readonly ConcurrentDictionary<FilePath,Repository> repositoryCache = new ConcurrentDictionary<FilePath,Repository> (); + internal static readonly object repositoryCacheLock = new object (); + internal static readonly Dictionary<FilePath,Repository> repositoryCache = new Dictionary<FilePath,Repository> (); public static Repository GetRepositoryReference (string path, string id) { VersionControlSystem detectedVCS = null; @@ -256,22 +263,21 @@ namespace MonoDevelop.VersionControl bestMatch = bestMatch.CanonicalPath; - try { - return repositoryCache.GetOrAdd (bestMatch, p => { - var result = detectedVCS?.GetRepositoryReference (p, id); - if (result != null) { + lock (repositoryCacheLock) { + if (repositoryCache.TryGetValue (bestMatch, out var repository)) + return repository; + + try { + var repo = detectedVCS?.GetRepositoryReference (bestMatch, id); + if (repo != null) { + repositoryCache.Add (bestMatch, repo); Instrumentation.Repositories.Inc (new RepositoryMetadata (detectedVCS)); - result.RepositoryPath = p.CanonicalPath; - return result; } - // never add null values - throw new ArgumentNullException ("result"); - }); - } catch (Exception e) { - // ArgumentNullException for "result" is expected when GetRepositoryReference returns null, no need to log - if (!(e is ArgumentNullException ne) || ne.ParamName != "result") - LoggingService.LogInternalError ($"Could not query {detectedVCS.Name} repository reference", e); - return null; + return repo; + } catch (Exception e) { + LoggingService.LogError ($"Could not query {detectedVCS.Name} repository reference", e); + return null; + } } } @@ -839,7 +845,9 @@ namespace MonoDevelop.VersionControl public void Dispose () { - VersionControlService.referenceCache.TryRemove (repo, out _); + lock (VersionControlService.referenceCacheLock) { + VersionControlService.referenceCache.Remove (repo); + } repo.Unref (); } } diff --git a/main/src/addins/VersionControl/MonoDevelop.VersionControl/VersionControl.addin.xml b/main/src/addins/VersionControl/MonoDevelop.VersionControl/VersionControl.addin.xml index ec2e9bd127..e66d577a8a 100644 --- a/main/src/addins/VersionControl/MonoDevelop.VersionControl/VersionControl.addin.xml +++ b/main/src/addins/VersionControl/MonoDevelop.VersionControl/VersionControl.addin.xml @@ -204,6 +204,8 @@ <CommandItem id = "MonoDevelop.VersionControl.Commands.Diff"/> <CommandItem id = "MonoDevelop.VersionControl.Commands.Log"/> <CommandItem id = "MonoDevelop.VersionControl.Commands.Annotate"/> + <SeparatorItem/> + <CommandItem id = "MonoDevelop.VersionControl.Commands.Revert"/> </ItemSet> <SeparatorItem/> </Extension> diff --git a/main/src/addins/WindowsPlatform/WindowsPlatform/WindowsPlatform.cs b/main/src/addins/WindowsPlatform/WindowsPlatform/WindowsPlatform.cs index 133db60e95..d5cb477e85 100644 --- a/main/src/addins/WindowsPlatform/WindowsPlatform/WindowsPlatform.cs +++ b/main/src/addins/WindowsPlatform/WindowsPlatform/WindowsPlatform.cs @@ -73,66 +73,66 @@ namespace MonoDevelop.Platform } #region Toolbar implementation - Components.Commands.CommandManager commandManager; - string commandMenuAddinPath; - string appMenuAddinPath; - public override bool SetGlobalMenu (Components.Commands.CommandManager commandManager, string commandMenuAddinPath, string appMenuAddinPath) - { - // Only store this information. Release it when creating the main toolbar. - this.commandManager = commandManager; - this.commandMenuAddinPath = commandMenuAddinPath; - this.appMenuAddinPath = appMenuAddinPath; - - return true; - } - - const int WM_SYSCHAR = 0x0106; - internal override void AttachMainToolbar (Gtk.VBox parent, Components.MainToolbar.IMainToolbarView toolbar) - { - titleBar = new TitleBar (); - var topMenu = new WPFTitlebar (titleBar); - - //commandManager.IncompleteKeyPressed += (sender, e) => { - // if (e.Key == Gdk.Key.Alt_L) { - // Keyboard.Focus(titleBar.DockTitle.Children[0]); - // } - //}; - parent.PackStart (topMenu, false, true, 0); - SetupMenu (); - - parent.PackStart ((WPFToolbar)toolbar, false, true, 0); - } - - void SetupMenu () - { - // TODO: Use this? - CommandEntrySet appCes = commandManager.CreateCommandEntrySet (appMenuAddinPath); - - CommandEntrySet ces = commandManager.CreateCommandEntrySet (commandMenuAddinPath); - var mainMenu = new Menu { - IsMainMenu = true, - FocusVisualStyle = null, - }; - foreach (CommandEntrySet ce in ces) - { - var item = new TitleMenuItem (commandManager, ce, menu: mainMenu); - mainMenu.Items.Add(item); - } - - titleBar.DockTitle.Children.Add (mainMenu); - DockPanel.SetDock (mainMenu, Dock.Left); - - commandManager = null; - commandMenuAddinPath = appMenuAddinPath = null; - } - - TitleBar titleBar; - internal override Components.MainToolbar.IMainToolbarView CreateMainToolbar (Gtk.Window window) - { - return new WPFToolbar { - HeightRequest = 40, - }; - } + //Components.Commands.CommandManager commandManager; + //string commandMenuAddinPath; + //string appMenuAddinPath; + //public override bool SetGlobalMenu (Components.Commands.CommandManager commandManager, string commandMenuAddinPath, string appMenuAddinPath) + //{ + // // Only store this information. Release it when creating the main toolbar. + // this.commandManager = commandManager; + // this.commandMenuAddinPath = commandMenuAddinPath; + // this.appMenuAddinPath = appMenuAddinPath; + + // return true; + //} + + //const int WM_SYSCHAR = 0x0106; + // internal override void AttachMainToolbar (Gtk.VBox parent, Components.MainToolbar.IMainToolbarView toolbar) + //{ + // titleBar = new TitleBar (); + // var topMenu = new WPFTitlebar (titleBar); + + // //commandManager.IncompleteKeyPressed += (sender, e) => { + // // if (e.Key == Gdk.Key.Alt_L) { + // // Keyboard.Focus(titleBar.DockTitle.Children[0]); + // // } + // //}; + // parent.PackStart (topMenu, false, true, 0); + // SetupMenu (); + + // parent.PackStart ((WPFToolbar)toolbar, false, true, 0); + //} + + //void SetupMenu () + //{ + // // TODO: Use this? + // CommandEntrySet appCes = commandManager.CreateCommandEntrySet (appMenuAddinPath); + + // CommandEntrySet ces = commandManager.CreateCommandEntrySet (commandMenuAddinPath); + // var mainMenu = new Menu { + // IsMainMenu = true, + // FocusVisualStyle = null, + // }; + // foreach (CommandEntrySet ce in ces) + // { + // var item = new TitleMenuItem (commandManager, ce, menu: mainMenu); + // mainMenu.Items.Add(item); + // } + + // titleBar.DockTitle.Children.Add (mainMenu); + // DockPanel.SetDock (mainMenu, Dock.Left); + + // commandManager = null; + // commandMenuAddinPath = appMenuAddinPath = null; + //} + + //TitleBar titleBar; + //internal override Components.MainToolbar.IMainToolbarView CreateMainToolbar (Gtk.Window window) + //{ + // return new WPFToolbar { + // HeightRequest = 40, + // }; + //} #endregion public override bool GetIsFullscreen (Components.Window window) diff --git a/main/src/addins/Xml/Editor/BaseXmlEditorExtension.cs b/main/src/addins/Xml/Editor/BaseXmlEditorExtension.cs index b37fa41673..a645cf49c3 100644 --- a/main/src/addins/Xml/Editor/BaseXmlEditorExtension.cs +++ b/main/src/addins/Xml/Editor/BaseXmlEditorExtension.cs @@ -472,7 +472,7 @@ namespace MonoDevelop.Xml.Editor var encoding = Editor.Encoding.WebName; list.Add (new BaseXmlCompletionData($"?xml version=\"1.0\" encoding=\"{encoding}\" ?>")); } - AddCloseTag (list, Tracker.Engine.Nodes); + AddCloseTag (list, Tracker.Engine.Nodes, currentChar); if (tracker.Engine.CurrentState is XmlNameState) if (GetCompletionCommandOffset (out var cpos, out var wlen)) list.TriggerWordLength = wlen; @@ -678,8 +678,8 @@ namespace MonoDevelop.Xml.Editor } return null; } - - protected static void AddCloseTag (CompletionDataList completionList, NodeStack stack) + + protected static void AddCloseTag (CompletionDataList completionList, NodeStack stack, char currentChar) { //FIXME: search forward to see if tag's closed already var elements = new List<XElement> (); @@ -692,7 +692,12 @@ namespace MonoDevelop.Xml.Editor if (elements.Count == 0) { string name = el.Name.FullName; - completionList.Add (new XmlTagCompletionData ("/" + name + ">", 0, true) { + var sb = StringBuilderCache.Allocate (); + if (currentChar != '/') + sb.Append ("/"); + sb.Append (name); + sb.Append (">"); + completionList.Add (new XmlTagCompletionData (StringBuilderCache.ReturnAndFree (sb), 0, true) { Description = GettextCatalog.GetString ("Closing tag for '{0}'", name) }); } else { diff --git a/main/src/addins/Xml/Tests/CodeCompletion/XmlCodeCompletionTests.cs b/main/src/addins/Xml/Tests/CodeCompletion/XmlCodeCompletionTests.cs index 5ffe1c26ce..92afb0b270 100644 --- a/main/src/addins/Xml/Tests/CodeCompletion/XmlCodeCompletionTests.cs +++ b/main/src/addins/Xml/Tests/CodeCompletion/XmlCodeCompletionTests.cs @@ -6,6 +6,7 @@ using MonoDevelop.Ide.Editor.Extension; using MonoDevelop.Xml.Editor; using NUnit.Framework; using MonoDevelop.Ide.CodeCompletion; +using System.Linq; namespace MonoDevelop.Xml.Tests.CodeCompletion { @@ -22,6 +23,46 @@ namespace MonoDevelop.Xml.Tests.CodeCompletion await ext.TriggerCompletion (Ide.CodeCompletion.CompletionTriggerReason.CompletionCommand); ext.KeyPress (KeyDescriptor.FromGtk (Gdk.Key.colon, ':', Gdk.ModifierType.None)); Assert.IsTrue (CompletionWindowManager.IsVisible); + CompletionWindowManager.Wnd.HideWindow (); + } + } + + /// <summary> + /// FeedbackTicket 739349: XAML Editor: When a closing tag already has '</' present, choosing the closing element from the completion window enters an invalid closing tag such as <//ContentView> + /// </summary> + [Test] + public async Task TestVSTS739349 () + { + const string input = @" +<Foo> +</F"; + using (var testCase = await SetupTestCase (input, input.Length)) { + var doc = testCase.Document; + var ext = doc.GetContent<BaseXmlEditorExtension> (); + ext.CompletionWidget = doc.Editor.GetViewContent ().GetContent<ICompletionWidget> (); + await ext.TriggerCompletion (Ide.CodeCompletion.CompletionTriggerReason.CompletionCommand); + Assert.IsTrue (CompletionWindowManager.IsVisible); + + Assert.AreEqual ("Foo>", CompletionWindowManager.Wnd.SelectedItem.DisplayText); + CompletionWindowManager.Wnd.HideWindow (); + } + } + + [Test] + public async Task TestVSTS739349_Case2 () + { + const string input = @" +<Foo> +<"; + using (var testCase = await SetupTestCase (input, input.Length)) { + var doc = testCase.Document; + var ext = doc.GetContent<BaseXmlEditorExtension> (); + ext.CompletionWidget = doc.Editor.GetViewContent ().GetContent<ICompletionWidget> (); + await ext.TriggerCompletion (Ide.CodeCompletion.CompletionTriggerReason.CompletionCommand); + Assert.IsTrue (CompletionWindowManager.IsVisible); + var list = CompletionWindowManager.Wnd.GetFilteredItems (); + Assert.IsTrue (list.Any (i => i.DisplayText == "/Foo>")); + CompletionWindowManager.Wnd.HideWindow (); } } diff --git a/main/src/core/MonoDevelop.Ide/ExtensionModel/MainMenu.addin.xml b/main/src/core/MonoDevelop.Ide/ExtensionModel/MainMenu.addin.xml index 2335c3c0ce..1de3bd4529 100644 --- a/main/src/core/MonoDevelop.Ide/ExtensionModel/MainMenu.addin.xml +++ b/main/src/core/MonoDevelop.Ide/ExtensionModel/MainMenu.addin.xml @@ -265,6 +265,8 @@ <CommandItem id = "MonoDevelop.Ide.Commands.WindowCommands.SplitWindowHorizontally" /> <CommandItem id = "MonoDevelop.Ide.Commands.WindowCommands.UnsplitWindow" /> <CommandItem id = "MonoDevelop.Ide.Commands.WindowCommands.SwitchSplitWindow" />--> + <SeparatorItem id = "welcomePageSep" /> + <CommandItem id = "MonoDevelop.Ide.Commands.ViewCommands.ShowWelcomePage" /> <SeparatorItem id = "contentSep" /> <CommandItem id = "MonoDevelop.Ide.Commands.WindowCommands.OpenWindowList" /> <SeparatorItem id = "windowDocSep" /> @@ -278,8 +280,6 @@ <CommandItem id = "MonoDevelop.Ide.Commands.WindowCommands.OpenDocument8" /> <CommandItem id = "MonoDevelop.Ide.Commands.WindowCommands.OpenDocument9" /> <CommandItem id = "MonoDevelop.Ide.Commands.WindowCommands.OpenDocumentList" /> - <SeparatorItem id = "welcomePageSep" /> - <CommandItem id = "MonoDevelop.Ide.Commands.ViewCommands.ShowWelcomePage" /> </ItemSet> <ItemSet id = "Help" _label = "_Help"> diff --git a/main/src/core/MonoDevelop.Ide/ExtensionModel/MonoDevelop.Ide.addin.xml b/main/src/core/MonoDevelop.Ide/ExtensionModel/MonoDevelop.Ide.addin.xml index 7c053a7b9c..3ffd21814c 100644 --- a/main/src/core/MonoDevelop.Ide/ExtensionModel/MonoDevelop.Ide.addin.xml +++ b/main/src/core/MonoDevelop.Ide/ExtensionModel/MonoDevelop.Ide.addin.xml @@ -68,7 +68,7 @@ <ExtensionPoint path = "/MonoDevelop/Ide/InitCompleteHandlers" name = "Post inialization handlers"> <Description>Commands to be automatically executed when the IDE finishes initalization.</Description> - <ExtensionNode name="Class"> + <ExtensionNode name="Class" objectType="MonoDevelop.Components.Commands.CommandHandler"> <Description>A subclass of MonoDevelop.Components.Commands.CommandHandler</Description> </ExtensionNode> </ExtensionPoint> diff --git a/main/src/core/MonoDevelop.Ide/Gui/MonoDevelop.Ide.Projects.AddExternalFileDialog.cs b/main/src/core/MonoDevelop.Ide/Gui/MonoDevelop.Ide.Projects.AddExternalFileDialog.cs index 76e6194b6f..075e8f449a 100644 --- a/main/src/core/MonoDevelop.Ide/Gui/MonoDevelop.Ide.Projects.AddExternalFileDialog.cs +++ b/main/src/core/MonoDevelop.Ide/Gui/MonoDevelop.Ide.Projects.AddExternalFileDialog.cs @@ -242,7 +242,6 @@ namespace MonoDevelop.Ide.Projects this.DefaultHeight = 286; this.radioKeep.Hide (); this.checkApplyAll.Hide (); - this.Show (); } } } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockContainer.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockContainer.cs index 9b63190523..39b63f339e 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockContainer.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockContainer.cs @@ -403,50 +403,51 @@ namespace MonoDevelop.Components.Docking internal bool UpdatePlaceholder (DockItem item, Gdk.Size size, bool allowDocking) { - if (!Runtime.IsMainThread) { - var msg = "UpdatePlaceholder called from background thread."; - LoggingService.LogInternalError ($"{msg}\n{Environment.StackTrace}", new InvalidOperationException (msg)); - } + try { + Runtime.AssertMainThread (); - var placeholderWindow = this.placeholderWindow; - var padTitleWindow = this.padTitleWindow; + var placeholderWindow = this.placeholderWindow; + var padTitleWindow = this.padTitleWindow; - if (placeholderWindow == null || padTitleWindow == null) - return false; - - int px, py; - GetPointer (out px, out py); - - placeholderWindow.AllowDocking = allowDocking; - - int ox, oy; - GdkWindow.GetOrigin (out ox, out oy); - - int tw, th; - padTitleWindow.GetSize (out tw, out th); - padTitleWindow.Move (ox + px - tw/2, oy + py - th/2); - padTitleWindow.GdkWindow.KeepAbove = true; - - DockDelegate dockDelegate; - Gdk.Rectangle rect; - if (allowDocking && layout.GetDockTarget (item, px, py, out dockDelegate, out rect)) { - placeholderWindow.Relocate (ox + rect.X, oy + rect.Y, rect.Width, rect.Height, true); - placeholderWindow.Show (); - placeholderWindow.SetDockInfo (dockDelegate, rect); - return true; - } else { - int w,h; - var gi = layout.FindDockGroupItem (item.Id); - if (gi != null) { - w = gi.Allocation.Width; - h = gi.Allocation.Height; + if (placeholderWindow == null || padTitleWindow == null || !IsRealized) + return false; + + int px, py; + GetPointer (out px, out py); + + placeholderWindow.AllowDocking = allowDocking; + + int ox, oy; + GdkWindow.GetOrigin (out ox, out oy); + + int tw, th; + padTitleWindow.GetSize (out tw, out th); + padTitleWindow.Move (ox + px - tw / 2, oy + py - th / 2); + padTitleWindow.GdkWindow.KeepAbove = true; + + DockDelegate dockDelegate; + Gdk.Rectangle rect; + if (allowDocking && layout.GetDockTarget (item, px, py, out dockDelegate, out rect)) { + placeholderWindow.Relocate (ox + rect.X, oy + rect.Y, rect.Width, rect.Height, true); + placeholderWindow.Show (); + placeholderWindow.SetDockInfo (dockDelegate, rect); + return true; } else { - w = item.DefaultWidth; - h = item.DefaultHeight; + int w, h; + var gi = layout.FindDockGroupItem (item.Id); + if (gi != null) { + w = gi.Allocation.Width; + h = gi.Allocation.Height; + } else { + w = item.DefaultWidth; + h = item.DefaultHeight; + } + placeholderWindow.Relocate (ox + px - w / 2, oy + py - h / 2, w, h, false); + placeholderWindow.Show (); + placeholderWindow.AllowDocking = false; } - placeholderWindow.Relocate (ox + px - w / 2, oy + py - h / 2, w, h, false); - placeholderWindow.Show (); - placeholderWindow.AllowDocking = false; + } catch (Exception ex) { + LoggingService.LogInternalError ("Updating the dock container placeholder failed", ex); } return false; diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Extension/FoldingTextEditorExtension.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Extension/FoldingTextEditorExtension.cs index 82eae3fc76..a8c3509b90 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Extension/FoldingTextEditorExtension.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Extension/FoldingTextEditorExtension.cs @@ -82,73 +82,77 @@ namespace MonoDevelop.Ide.Editor.Extension if (parsedDocument == null || !Editor.Options.ShowFoldMargin || parsedDocument.Flags.HasFlag (ParsedDocumentFlags.SkipFoldings)) return; // don't update parsed documents that contain errors - the foldings from there may be invalid. - if (await parsedDocument.HasErrorsAsync (token)) + if (await parsedDocument.HasErrorsAsync (token).ConfigureAwait (false)) return; + IReadOnlyList<FoldingRegion> foldings = null; try { - var foldSegments = new List<IFoldSegment> (); - - foreach (FoldingRegion region in await parsedDocument.GetFoldingsAsync (token)) { - if (token.IsCancellationRequested) - return; - var type = FoldingType.Unknown; - bool setFolded = false; - bool folded = false; - //decide whether the regions should be folded by default - switch (region.Type) { - case FoldType.Member: - type = FoldingType.TypeMember; - break; - case FoldType.Type: - type = FoldingType.TypeDefinition; - break; - case FoldType.UserRegion: - type = FoldingType.Region; - setFolded = DefaultSourceEditorOptions.Instance.DefaultRegionsFolding; - folded = true; - break; - case FoldType.Comment: - type = FoldingType.Comment; - setFolded = DefaultSourceEditorOptions.Instance.DefaultCommentFolding; - folded = true; - break; - case FoldType.CommentInsideMember: - type = FoldingType.Comment; - setFolded = DefaultSourceEditorOptions.Instance.DefaultCommentFolding; - folded = false; - break; - case FoldType.Undefined: - setFolded = true; - folded = region.IsFoldedByDefault; - break; - } - var start = Editor.LocationToOffset (region.Region.Begin); - var end = Editor.LocationToOffset (region.Region.End); - var marker = Editor.CreateFoldSegment (start, end - start); - foldSegments.Add (marker); - marker.CollapsedText = region.Name; - marker.FoldingType = type; - //and, if necessary, set its fold state - if (marker != null && setFolded && firstTime) { - // only fold on document open, later added folds are NOT folded by default. - marker.IsCollapsed = folded; - continue; - } - if (marker != null && region.Region.Contains (caretLocation.Line, caretLocation.Column)) - marker.IsCollapsed = false; - } - if (firstTime) { - Editor.SetFoldings (foldSegments); - } else { - Application.Invoke ((o, args) => { - if (!token.IsCancellationRequested) - Editor.SetFoldings (foldSegments); - }); - } + foldings = await parsedDocument.GetFoldingsAsync(token).ConfigureAwait (false); } catch (OperationCanceledException) { + return; } catch (Exception ex) { LoggingService.LogError ("Unhandled exception in ParseInformationUpdaterWorkerThread", ex); } + if (token.IsCancellationRequested) + return; + await Runtime.RunInMainThread (delegate { + var foldSegments = new List<IFoldSegment> (); + try { + foreach (var region in foldings) { + if (token.IsCancellationRequested) + return; + var type = FoldingType.Unknown; + bool setFolded = false; + bool folded = false; + //decide whether the regions should be folded by default + switch (region.Type) { + case FoldType.Member: + type = FoldingType.TypeMember; + break; + case FoldType.Type: + type = FoldingType.TypeDefinition; + break; + case FoldType.UserRegion: + type = FoldingType.Region; + setFolded = DefaultSourceEditorOptions.Instance.DefaultRegionsFolding; + folded = true; + break; + case FoldType.Comment: + type = FoldingType.Comment; + setFolded = DefaultSourceEditorOptions.Instance.DefaultCommentFolding; + folded = true; + break; + case FoldType.CommentInsideMember: + type = FoldingType.Comment; + setFolded = DefaultSourceEditorOptions.Instance.DefaultCommentFolding; + folded = false; + break; + case FoldType.Undefined: + setFolded = true; + folded = region.IsFoldedByDefault; + break; + } + var start = Editor.LocationToOffset (region.Region.Begin); + var end = Editor.LocationToOffset (region.Region.End); + var marker = Editor.CreateFoldSegment (start, end - start); + foldSegments.Add (marker); + marker.CollapsedText = region.Name; + marker.FoldingType = type; + //and, if necessary, set its fold state + if (marker != null && setFolded && firstTime) { + // only fold on document open, later added folds are NOT folded by default. + marker.IsCollapsed = folded; + continue; + } + if (marker != null && region.Region.Contains (caretLocation.Line, caretLocation.Column)) + marker.IsCollapsed = false; + } + Editor.SetFoldings (foldSegments); + } catch (OperationCanceledException) { + } catch (Exception ex) { + LoggingService.LogError ("Unhandled exception in ParseInformationUpdaterWorkerThread", ex); + } + }); } } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/EditorPreferences.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/EditorPreferences.cs index e7de100b4b..eb3bf0f0a6 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/EditorPreferences.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/EditorPreferences.cs @@ -90,7 +90,7 @@ namespace MonoDevelop.Ide.Editor OutliningUndoStep = Wrap<bool> ("GenerateFormattingUndoStep", DefaultTextViewOptions.OutliningUndoOptionName); ShowChangeTrackingMargin = Wrap ("EnableQuickDiff", DefaultTextViewHostOptions.ChangeTrackingName, false); ShowGlyphMargin = Wrap<bool> ("ShowGlyphMargin", DefaultTextViewHostOptions.GlyphMarginName); - ShowLineNumberMargin = Wrap<bool> ("ShowLineNumberMargin", DefaultTextViewHostOptions.LineNumberMarginName); + ShowLineNumberMargin = Wrap ("ShowLineNumberMargin", DefaultTextViewHostOptions.LineNumberMarginName, true); ShowOutliningMargin = Wrap<bool> ("ShowFoldMargin", DefaultTextViewHostOptions.OutliningMarginName); TrimTrailingWhitespace = Wrap ("RemoveTrailingWhitespaces", DefaultOptions.TrimTrailingWhiteSpaceOptionName, true); // UseVirtualSpace should be a combination of IndentStyle == MonoDevelop.Ide.Editor.IndentStyle.Smart && RemoveTrailingWhitespaces diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Components/ExtensibleTreeView.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Components/ExtensibleTreeView.cs index 9f737ed3b4..d1b25c2ca9 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Components/ExtensibleTreeView.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Components/ExtensibleTreeView.cs @@ -503,7 +503,7 @@ namespace MonoDevelop.Ide.Gui.Components var rect = text_render.GetStatusIconArea (tree, cellArea); if (cx >= rect.X && cx <= rect.Right) { tree.ConvertBinWindowToWidgetCoords (rect.X, rect.Y, out rect.X, out rect.Y); - ShowStatusMessage (it, rect, info); + ShowStatusMessage (path, rect, info); popupShown = true; } } @@ -514,17 +514,17 @@ namespace MonoDevelop.Ide.Gui.Components } bool statusMessageVisible; - Gtk.TreeIter statusIconIter; + Gtk.TreePath statusIconPath; TooltipPopoverWindow statusPopover; - void ShowStatusMessage (Gtk.TreeIter it, Gdk.Rectangle rect, NodeInfo info) + void ShowStatusMessage (Gtk.TreePath path, Gdk.Rectangle rect, NodeInfo info) { - if (statusMessageVisible && store.GetPath (it).Equals (store.GetPath (statusIconIter))) + if (statusMessageVisible && path.Equals (statusIconPath)) return; if (statusPopover != null) statusPopover.Destroy (); statusMessageVisible = true; - statusIconIter = it; + statusIconPath = path; statusPopover = TooltipPopoverWindow.Create (); statusPopover.ShowArrow = true; diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Workbench.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Workbench.cs index f98640dfaf..e3b9988b50 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Workbench.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Workbench.cs @@ -81,6 +81,7 @@ namespace MonoDevelop.Ide.Gui public event EventHandler GuiLocked; public event EventHandler GuiUnlocked; bool fileEventsFrozen; + bool hasEverBeenShown = false; internal void Initialize (ProgressMonitor monitor) { @@ -134,20 +135,22 @@ namespace MonoDevelop.Ide.Gui Counters.Initialization.Trace ("Setting memento"); workbench.Memento = memento; - Counters.Initialization.Trace ("Setting layout"); - workbench.CurrentLayout = "Solution"; - - // now we have an layout set notify it - Counters.Initialization.Trace ("Setting layout"); - if (LayoutChanged != null) - LayoutChanged (this, EventArgs.Empty); - Counters.Initialization.Trace ("Initializing monitors"); monitors.Initialize (); } internal void Show () { + if (!hasEverBeenShown) { + workbench.CurrentLayout = "Solution"; + + // now we have an layout set notify it + if (LayoutChanged != null) + LayoutChanged (this, EventArgs.Empty); + + hasEverBeenShown = true; + } + // Very important: see https://github.com/mono/monodevelop/pull/6064 // Otherwise the editor may not be focused on IDE startup and can't be // focused even by clicking with the mouse. diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MiscellaneousFilesWorkspace.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MiscellaneousFilesWorkspace.cs index 7e3cecfdc0..247d065aba 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MiscellaneousFilesWorkspace.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MiscellaneousFilesWorkspace.cs @@ -27,11 +27,16 @@ using System.Linq; using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
+
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Text;
+
using Microsoft.VisualStudio.Composition;
using Microsoft.VisualStudio.Text;
+
+using Mono.Addins; + using MonoDevelop.Ide.Composition;
namespace MonoDevelop.Ide.TypeSystem
@@ -65,7 +70,10 @@ namespace MonoDevelop.Ide.TypeSystem [ImportingConstructor]
public MiscellaneousFilesWorkspace ()
: base (CompositionManager.Instance.HostServices, WorkspaceKind.MiscellaneousFiles)
- {
+ { + foreach (var factory in AddinManager.GetExtensionObjects<Microsoft.CodeAnalysis.Options.IDocumentOptionsProviderFactory> ("/MonoDevelop/Ide/TypeService/OptionProviders"))
+ Services.GetRequiredService<Microsoft.CodeAnalysis.Options.IOptionService> ().RegisterDocumentOptionsProvider (factory.Create (this));
+
defaultProjectId = ProjectId.CreateNewId (DefaultProjectName);
var compilationOptions = new CSharpCompilationOptions (OutputKind.ConsoleApplication);
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 b0a37fe68c..ab63acc39e 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: @@ -104,8 +104,10 @@ namespace MonoDevelop.Ide.TypeSystem var config = IdeApp.IsInitialized ? p.GetConfiguration (IdeApp.Workspace.ActiveConfiguration) as MonoDevelop.Projects.DotNetProjectConfiguration : null; MonoDevelop.Projects.DotNetCompilerParameters cp = config?.CompilationParameters; FilePath fileName = IdeApp.IsInitialized ? p.GetOutputFileName (IdeApp.Workspace.ActiveConfiguration) : (FilePath)""; - if (fileName.IsNullOrEmpty) + + if (fileName.IsNullOrEmpty) { fileName = new FilePath (p.Name + ".dll"); + } if (!hackyCache.TryGetCachedItems (p, workspace.MetadataReferenceManager, projectMap, out var sourceFiles, out var analyzerFiles, out var references, out var projectReferences)) { (references, projectReferences) = await metadataHandler.Value.CreateReferences (p, token).ConfigureAwait (false); @@ -148,7 +150,7 @@ namespace MonoDevelop.Ide.TypeSystem // TODO: Pass in the WorkspaceMetadataFileReferenceResolver var info = ProjectInfo.Create ( projectId, - VersionStamp.Create (), + GetVersionStamp (p), p.Name, fileName.FileNameWithoutExtension, (p as MonoDevelop.Projects.DotNetProject)?.RoslynLanguageName ?? LanguageNames.CSharp, @@ -169,6 +171,16 @@ namespace MonoDevelop.Ide.TypeSystem return info; } + VersionStamp GetVersionStamp (MonoDevelop.Projects.Project project) + { + try { + return VersionStamp.Create (File.GetLastWriteTimeUtc (project.FileName)); + } catch (Exception e) { + LoggingService.LogInternalError ("Failed to create version stamp", e); + return VersionStamp.Create (); + } + } + async Task<ConcurrentBag<ProjectInfo>> CreateProjectInfos (IEnumerable<MonoDevelop.Projects.Project> mdProjects, CancellationToken token) { var projects = new ConcurrentBag<ProjectInfo> (); diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj index 5b4b8edaa4..91f1f0e7fa 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj @@ -4201,6 +4201,7 @@ <Compile Include="MonoDevelop.Components\Mac\NSStackViewExtensions.cs" /> <Compile Include="MonoDevelop.Components\Mac\NSLabel.cs" /> <Compile Include="MonoDevelop.Components\Mac\NSLine.cs" /> + <Compile Include="MonoDevelop.Ide\IdeStartupTracker.cs" /> </ItemGroup> <ItemGroup> <Data Include="options\DefaultEditingLayout.xml" /> diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/Ide.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/Ide.cs index 960da88fd3..ca0bda6546 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/Ide.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/Ide.cs @@ -100,22 +100,8 @@ namespace MonoDevelop.Ide } } - static TimeToCodeMetadata ttcMetadata; - static Stopwatch ttcStopwatch; - static long startupCompletedTicks; - static long ttcDuration = 3 * TimeSpan.TicksPerSecond; // Wait 3 seconds before ignoring TTC events - - internal static void OnStartupCompleted (StartupMetadata startupMetadata, Stopwatch ttcTimer) + internal static void OnStartupCompleted () { - ttcMetadata = new TimeToCodeMetadata { - StartupTime = startupMetadata.CorrectedStartupTime - }; - ttcMetadata.AddProperties (startupMetadata); - - ttcStopwatch = ttcTimer; - startupCompletedTicks = ttcStopwatch.ElapsedTicks; - LoggingService.LogDebug ("TTC starting"); - startupCompleted?.Invoke (null, EventArgs.Empty); } @@ -327,73 +313,6 @@ namespace MonoDevelop.Ide Ide.IdeApp.Workbench.StatusBar.ShowWarning (e.Message); } - internal static void TrackTimeToCode (TimeToCodeMetadata.DocumentType documentType) - { - LoggingService.LogDebug("Tracking TTC"); - if (ttcStopwatch == null || timeToCodeSolutionTimer == null) { - LoggingService.LogDebug("Ignoring TTC"); - return; - } - - ttcStopwatch.Stop (); - timeToCodeSolutionTimer.Stop (); - - if (ttcMetadata == null) { - timeToCodeSolutionTimer = null; - ttcStopwatch = null; - throw new Exception ("SendTimeToCode called before initialisation completed"); - } - - LoggingService.LogDebug ("Processing TTC"); - ttcMetadata.SolutionLoadTime = timeToCodeSolutionTimer.ElapsedMilliseconds; - - ttcMetadata.CorrectedDuration = ttcStopwatch.ElapsedMilliseconds; - ttcMetadata.Type = documentType; - - Counters.TimeToCode.Inc ("SolutionLoaded", ttcMetadata); - - timeToCodeSolutionTimer = null; - timeToCodeWorkspaceTimer = Stopwatch.StartNew (); - - MonoDevelopWorkspace.LoadingFinished += CompleteTimeToIntellisense; - } - - static void CompleteTimeToIntellisense (object sender, EventArgs e) - { - // Reuse ttcMetadata, as it already has other information set. - MonoDevelopWorkspace.LoadingFinished -= CompleteTimeToIntellisense; - - timeToCodeWorkspaceTimer.Stop (); - - ttcMetadata.IntellisenseLoadTime = timeToCodeWorkspaceTimer.ElapsedMilliseconds; - ttcMetadata.CorrectedDuration += timeToCodeWorkspaceTimer.ElapsedMilliseconds; - - Counters.TimeToIntellisense.Inc ("IntellisenseLoaded", ttcMetadata); - } - - - static Stopwatch timeToCodeSolutionTimer = new Stopwatch (); - static Stopwatch timeToCodeWorkspaceTimer = null; - internal static bool StartTimeToCodeLoadTimer () - { - if (ttcStopwatch.ElapsedTicks - startupCompletedTicks > ttcDuration) { - LoggingService.LogDebug ($"Not starting TTC timer: {ttcStopwatch.ElapsedTicks - startupCompletedTicks}"); - return false; - } - LoggingService.LogDebug ("Starting TTC timer"); - timeToCodeSolutionTimer.Start (); - - return true; - } - - 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) { diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeStartup.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeStartup.cs index b12343faf4..2a69143203 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeStartup.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeStartup.cs @@ -62,10 +62,6 @@ namespace MonoDevelop.Ide List<AddinError> errorsList = new List<AddinError> (); bool initialized; - static Stopwatch startupTimer = new Stopwatch (); - static Stopwatch startupSectionTimer = new Stopwatch (); - static Stopwatch timeToCodeTimer = new Stopwatch (); - static Dictionary<string, long> sectionTimings = new Dictionary<string, long> (); static bool hideWelcomePage; static TimeToCodeMetadata ttcMetadata; @@ -86,12 +82,10 @@ namespace MonoDevelop.Ide //ensure native libs initialized before we hit anything that p/invokes Platform.Initialize (); - sectionTimings ["PlatformInitialization"] = startupSectionTimer.ElapsedMilliseconds; - startupSectionTimer.Restart (); + IdeStartupTracker.StartupTracker.MarkSection ("PlatformInitialization"); GettextCatalog.Initialize (); - sectionTimings ["GettextInitialization"] = startupSectionTimer.ElapsedMilliseconds; - startupSectionTimer.Restart (); + IdeStartupTracker.StartupTracker.MarkSection ("GettextInitialization"); LoggingService.LogInfo ("Operating System: {0}", SystemInformation.GetOperatingSystemDescription ()); @@ -137,8 +131,10 @@ namespace MonoDevelop.Ide LoggingService.LogError ("Error initialising GLib logging.", ex); } - sectionTimings ["GtkInitialization"] = startupSectionTimer.ElapsedMilliseconds; - startupSectionTimer.Restart (); + var args = options.RemainingArgs.ToArray (); + IdeTheme.InitializeGtk (BrandingService.ApplicationName, ref args); + + IdeStartupTracker.StartupTracker.MarkSection ("GtkInitialization"); LoggingService.LogInfo ("Using GTK+ {0}", IdeVersionInfo.GetGtkVersion ()); // XWT initialization @@ -149,8 +145,7 @@ namespace MonoDevelop.Ide Xwt.Toolkit.CurrentEngine.RegisterBackend<IExtendedTitleBarDialogBackend, GtkExtendedTitleBarDialogBackend> (); IdeTheme.SetupXwtTheme (); - sectionTimings ["XwtInitialization"] = startupSectionTimer.ElapsedMilliseconds; - startupSectionTimer.Restart (); + IdeStartupTracker.StartupTracker.MarkSection ("XwtInitialization"); //default to Windows IME on Windows if (Platform.IsWindows && GtkWorkarounds.GtkMinorVersion >= 16) { @@ -166,14 +161,12 @@ namespace MonoDevelop.Ide SynchronizationContext.SetSynchronizationContext (DispatchService.SynchronizationContext); Runtime.MainSynchronizationContext = SynchronizationContext.Current; - sectionTimings ["DispatchInitialization"] = startupSectionTimer.ElapsedMilliseconds; - startupSectionTimer.Restart (); + IdeStartupTracker.StartupTracker.MarkSection ("DispatchInitialization"); // Initialize Roslyn's synchronization context RoslynServices.RoslynService.Initialize (); - sectionTimings ["RoslynInitialization"] = startupSectionTimer.ElapsedMilliseconds; - startupSectionTimer.Restart (); + IdeStartupTracker.StartupTracker.MarkSection ("RoslynInitialization"); AddinManager.AddinLoadError += OnAddinError; @@ -202,8 +195,7 @@ namespace MonoDevelop.Ide if (!options.NewWindow && startupInfo.HasFiles && instanceConnection.TryConnect (startupInfo)) return 0; - sectionTimings ["RuntimeInitialization"] = startupSectionTimer.ElapsedMilliseconds; - startupSectionTimer.Restart (); + IdeStartupTracker.StartupTracker.MarkSection ("RuntimeInitialization"); bool restartRequested = PropertyService.Get ("MonoDevelop.Core.RestartRequested", false); startupInfo.Restarted = restartRequested; @@ -215,8 +207,7 @@ namespace MonoDevelop.Ide IdeApp.Customizer.OnCoreInitialized (); - sectionTimings ["ThemeInitialized"] = startupSectionTimer.ElapsedMilliseconds; - startupSectionTimer.Restart (); + IdeStartupTracker.StartupTracker.MarkSection ("ThemeInitialized"); IdeApp.IsRunning = true; @@ -254,8 +245,7 @@ namespace MonoDevelop.Ide Counters.Initialization.Trace ("Initializing Platform Service"); await Runtime.GetService<DesktopService> (); - sectionTimings["PlatformInitialization"] = startupSectionTimer.ElapsedMilliseconds; - startupSectionTimer.Restart (); + IdeStartupTracker.StartupTracker.MarkSection ("PlatformInitialization"); monitor.Step (1); @@ -263,8 +253,7 @@ namespace MonoDevelop.Ide CheckFileWatcher (); - sectionTimings["FileWatcherInitialization"] = startupSectionTimer.ElapsedMilliseconds; - startupSectionTimer.Restart (); + IdeStartupTracker.StartupTracker.MarkSection ("FileWatcherInitialization"); Exception error = null; int reportedFailures = 0; @@ -274,8 +263,7 @@ namespace MonoDevelop.Ide //force initialisation before the workbench so that it can register stock icons for GTK before they get requested ImageService.Initialize (); - sectionTimings ["ImageInitialization"] = startupSectionTimer.ElapsedMilliseconds; - startupSectionTimer.Restart (); + IdeStartupTracker.StartupTracker.MarkSection ("ImageInitialization"); // If we display an error dialog before the main workbench window on OS X then a second application menu is created // which is then replaced with a second empty Apple menu. @@ -285,8 +273,7 @@ namespace MonoDevelop.Ide hideWelcomePage = options.NoStartWindow || startupInfo.HasFiles || IdeApp.Preferences.StartupBehaviour.Value != OnStartupBehaviour.ShowStartWindow; await IdeApp.Initialize (monitor); - sectionTimings ["AppInitialization"] = startupSectionTimer.ElapsedMilliseconds; - startupSectionTimer.Restart (); + IdeStartupTracker.StartupTracker.MarkSection ("AppInitialization"); if (errorsList.Count > 0) { using (AddinLoadErrorDialog dlg = new AddinLoadErrorDialog (errorsList.ToArray (), false)) { @@ -341,8 +328,7 @@ namespace MonoDevelop.Ide errorsList = null; AddinManager.AddinLoadError -= OnAddinError; - sectionTimings["BasicInitializationCompleted"] = startupSectionTimer.ElapsedMilliseconds; - startupSectionTimer.Restart (); + IdeStartupTracker.StartupTracker.MarkSection ("BasicInitializationCompleted"); instanceConnection.FileOpenRequested += (sender, a) => { foreach (var e in a) @@ -351,15 +337,13 @@ namespace MonoDevelop.Ide instanceConnection.StartListening (); - sectionTimings["SocketInitialization"] = startupSectionTimer.ElapsedMilliseconds; - startupSectionTimer.Restart (); + IdeStartupTracker.StartupTracker.MarkSection ("SocketInitialization"); initialized = true; MessageService.RootWindow = IdeApp.Workbench.RootWindow; Xwt.MessageDialog.RootWindow = Xwt.Toolkit.CurrentEngine.WrapWindow (IdeApp.Workbench.RootWindow); - sectionTimings["WindowOpened"] = startupSectionTimer.ElapsedMilliseconds; - startupSectionTimer.Restart (); + IdeStartupTracker.StartupTracker.MarkSection ("WindowOpened"); Thread.CurrentThread.Name = "GUI Thread"; Counters.Initialization.Trace ("Running IdeApp"); @@ -374,11 +358,8 @@ namespace MonoDevelop.Ide // we show the main window. DispatchService.RunPendingEvents (); - sectionTimings ["PumpEventLoop"] = startupSectionTimer.ElapsedMilliseconds; - startupTimer.Stop (); - startupSectionTimer.Stop (); - - CreateStartupMetadata (startupInfo, sectionTimings); + IdeStartupTracker.StartupTracker.MarkSection ("PumpEventLoop"); + IdeStartupTracker.StartupTracker.Stop (startupInfo); GLib.Idle.Add (OnIdle); @@ -449,19 +430,6 @@ namespace MonoDevelop.Ide return false; } - void CreateStartupMetadata (StartupInfo si, Dictionary<string, long> timings) - { - var result = IdeServices.DesktopService.PlatformTelemetry; - if (result == null) { - return; - } - - var startupMetadata = GetStartupMetadata (si, result, timings); - Counters.Startup.Inc (startupMetadata); - - IdeApp.OnStartupCompleted (startupMetadata, timeToCodeTimer); - } - static DateTime lastIdle; static bool lockupCheckRunning = true; @@ -565,10 +533,11 @@ namespace MonoDevelop.Ide { if (args.Change == ExtensionChange.Add) { try { - if (typeof(CommandHandler).IsInstanceOfType (args.ExtensionObject)) - typeof(CommandHandler).GetMethod ("Run", System.Reflection.BindingFlags.NonPublic|System.Reflection.BindingFlags.Instance, null, Type.EmptyTypes, null).Invoke (args.ExtensionObject, null); - else + if (args.ExtensionObject is CommandHandler handler) { + handler.InternalRun (); + } else { LoggingService.LogError ("Type " + args.ExtensionObject.GetType () + " must be a subclass of MonoDevelop.Components.Commands.CommandHandler"); + } } catch (Exception ex) { LoggingService.LogError (ex.ToString ()); } @@ -706,13 +675,8 @@ namespace MonoDevelop.Ide public static int Main (string[] args, IdeCustomizer customizer = null) { - // Using a Stopwatch instead of a TimerCounter since calling - // TimerCounter.BeginTiming here would occur before any timer - // handlers can be registered. So instead the startup duration is - // set as a metadata property on the Counters.Startup counter. - startupTimer.Start (); - startupSectionTimer.Start (); - timeToCodeTimer.Start (); + + IdeStartupTracker.StartupTracker.Start (); var options = MonoDevelopOptions.Parse (args); if (options.ShowHelp || options.Error != null) @@ -737,8 +701,7 @@ namespace MonoDevelop.Ide exename = exename.ToLower (); Runtime.SetProcessName (exename); - sectionTimings ["mainInitialization"] = startupSectionTimer.ElapsedMilliseconds; - startupSectionTimer.Restart (); + IdeStartupTracker.StartupTracker.MarkSection ("mainInitialization"); var app = new IdeStartup (); ret = app.Run (options); @@ -782,49 +745,6 @@ namespace MonoDevelop.Ide return null; } - enum StartupType - { - Normal = 0x0, - ConfigurationChange = 0x1, - FirstLaunch = 0x2, - DebuggerPresent = 0x10, - CommandExecuted = 0x20, - LaunchedAsDebugger = 0x40, - FirstLaunchSetup = 0x80, - - // Monodevelop specific - FirstLaunchAfterUpgrade = 0x10000 - } - - static StartupMetadata GetStartupMetadata (StartupInfo startupInfo, IPlatformTelemetryDetails platformDetails, Dictionary<string, long> timings) - { - var assetType = StartupAssetType.FromStartupInfo (startupInfo); - StartupType startupType = StartupType.Normal; - - if (startupInfo.Restarted && !IdeApp.IsInitialRunAfterUpgrade) { - startupType = StartupType.ConfigurationChange; // Assume a restart without upgrading was the result of a config change - } else if (IdeApp.IsInitialRun) { - startupType = StartupType.FirstLaunch; - } else if (IdeApp.IsInitialRunAfterUpgrade) { - startupType = StartupType.FirstLaunchAfterUpgrade; - } else if (Debugger.IsAttached) { - startupType = StartupType.DebuggerPresent; - } - - return new StartupMetadata { - CorrectedStartupTime = startupTimer.ElapsedMilliseconds, - StartupType = Convert.ToInt32 (startupType), - AssetTypeId = assetType.Id, - AssetTypeName = assetType.Name, - IsInitialRun = IdeApp.IsInitialRun, - IsInitialRunAfterUpgrade = IdeApp.IsInitialRunAfterUpgrade, - TimeSinceMachineStart = (long)platformDetails.TimeSinceMachineStart.TotalMilliseconds, - TimeSinceLogin = (long)platformDetails.TimeSinceLogin.TotalMilliseconds, - Timings = timings, - StartupBehaviour = IdeApp.Preferences.StartupBehaviour.Value - }; - } - internal static OpenWorkspaceItemMetadata GetOpenWorkspaceOnStartupMetadata () { var metadata = new OpenWorkspaceItemMetadata { diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeStartupTracker.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeStartupTracker.cs new file mode 100644 index 0000000000..c2579f0346 --- /dev/null +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeStartupTracker.cs @@ -0,0 +1,205 @@ +// +// IdeStartupTracker.cs +// +// Author: +// iain <iaholmes@microsoft.com> +// +// Copyright (c) 2019 +// +// 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.Diagnostics; + +using MonoDevelop.Core; + +using MonoDevelop.Ide.Desktop; +using MonoDevelop.Ide.Gui; +using MonoDevelop.Ide.TypeSystem; + +namespace MonoDevelop.Ide +{ + internal class IdeStartupTracker + { + static Lazy<IdeStartupTracker> startupTracker = new Lazy<IdeStartupTracker> (() => new IdeStartupTracker ()); + static internal IdeStartupTracker StartupTracker => startupTracker.Value; + + const long ttcDuration = 3 * TimeSpan.TicksPerSecond; // Wait 3 seconds before ignoring TTC events + + Stopwatch startupTimer = new Stopwatch (); + Stopwatch startupSectionTimer = new Stopwatch (); + Stopwatch timeToCodeTimer = new Stopwatch (); + Stopwatch timeToCodeSolutionTimer = new Stopwatch (); + Stopwatch timeToCodeWorkspaceTimer; + + Dictionary<string, long> sectionTimings = new Dictionary<string, long> (); + StartupInfo startupInfo; + TimeToCodeMetadata ttcMetadata; + + IdeStartupTracker () + { + + } + + internal void Start () + { + // Using a Stopwatch instead of a TimerCounter since calling + // TimerCounter.BeginTiming here would occur before any timer + // handlers can be registered. So instead the startup duration is + // set as a metadata property on the Counters.Startup counter. + startupTimer.Start (); + startupSectionTimer.Start (); + timeToCodeTimer.Start (); + } + + internal void Stop (StartupInfo startupInfo) + { + startupTimer.Stop (); + startupSectionTimer.Stop (); + + this.startupInfo = startupInfo; + + var result = DesktopService.PlatformTelemetry; + if (result == null) { + return; + } + + StartupCompleted (result); + } + + internal void StartupCompleted (IPlatformTelemetryDetails platformTelemetryDetails) + { + var startupMetadata = GetStartupMetadata (platformTelemetryDetails); + Counters.Startup.Inc (startupMetadata); + + // Start TTC timer + ttcMetadata = new TimeToCodeMetadata { + StartupTime = startupMetadata.CorrectedStartupTime + }; + ttcMetadata.AddProperties (startupMetadata); + + LoggingService.LogDebug ("TTC starting"); + } + + internal void MarkSection (string name) + { + sectionTimings [name] = startupSectionTimer.ElapsedMilliseconds; + startupSectionTimer.Restart (); + } + + enum StartupType + { + Normal = 0x0, + ConfigurationChange = 0x1, + FirstLaunch = 0x2, + DebuggerPresent = 0x10, + CommandExecuted = 0x20, + LaunchedAsDebugger = 0x40, + FirstLaunchSetup = 0x80, + + // Monodevelop specific + FirstLaunchAfterUpgrade = 0x10000 + } + + StartupMetadata GetStartupMetadata (IPlatformTelemetryDetails platformDetails) + { + var assetType = StartupAssetType.FromStartupInfo (startupInfo); + StartupType startupType = StartupType.Normal; + + if (startupInfo.Restarted && !IdeApp.IsInitialRunAfterUpgrade) { + startupType = StartupType.ConfigurationChange; // Assume a restart without upgrading was the result of a config change + } else if (IdeApp.IsInitialRun) { + startupType = StartupType.FirstLaunch; + } else if (IdeApp.IsInitialRunAfterUpgrade) { + startupType = StartupType.FirstLaunchAfterUpgrade; + } else if (Debugger.IsAttached) { + startupType = StartupType.DebuggerPresent; + } + + return new StartupMetadata { + CorrectedStartupTime = startupTimer.ElapsedMilliseconds, + StartupType = Convert.ToInt32 (startupType), + AssetTypeId = assetType.Id, + AssetTypeName = assetType.Name, + IsInitialRun = IdeApp.IsInitialRun, + IsInitialRunAfterUpgrade = IdeApp.IsInitialRunAfterUpgrade, + TimeSinceMachineStart = (long)platformDetails.TimeSinceMachineStart.TotalMilliseconds, + TimeSinceLogin = (long)platformDetails.TimeSinceLogin.TotalMilliseconds, + Timings = sectionTimings, + StartupBehaviour = IdeApp.Preferences.StartupBehaviour.Value + }; + } + + internal void TrackTimeToCode (TimeToCodeMetadata.DocumentType documentType) + { + LoggingService.LogDebug ("Tracking TTC"); + if (this.timeToCodeTimer == null || timeToCodeSolutionTimer == null) { + LoggingService.LogDebug ("Ignoring TTC"); + return; + } + + timeToCodeTimer.Stop (); + timeToCodeSolutionTimer.Stop (); + + if (ttcMetadata == null) { + timeToCodeSolutionTimer = null; + timeToCodeTimer = null; + throw new Exception ("SendTimeToCode called before initialisation completed"); + } + + LoggingService.LogDebug ("Processing TTC"); + ttcMetadata.SolutionLoadTime = timeToCodeSolutionTimer.ElapsedMilliseconds; + + ttcMetadata.CorrectedDuration = timeToCodeTimer.ElapsedMilliseconds; + ttcMetadata.Type = documentType; + + Counters.TimeToCode.Inc ("SolutionLoaded", ttcMetadata); + + timeToCodeSolutionTimer = null; + + timeToCodeWorkspaceTimer = Stopwatch.StartNew (); + MonoDevelopWorkspace.LoadingFinished += CompleteTimeToIntellisense; + } + + void CompleteTimeToIntellisense (object sender, EventArgs args) + { + // Reuse ttcMetadata, as it already has other information set. + MonoDevelopWorkspace.LoadingFinished -= CompleteTimeToIntellisense; + + timeToCodeWorkspaceTimer.Stop (); + ttcMetadata.IntellisenseLoadTime = timeToCodeWorkspaceTimer.ElapsedMilliseconds; + ttcMetadata.CorrectedDuration += timeToCodeWorkspaceTimer.ElapsedMilliseconds; + + Counters.TimeToIntellisense.Inc ("IntellisenseLoaded", ttcMetadata); + } + + internal bool StartTimeToCodeLoadTimer () + { + if (timeToCodeTimer.ElapsedTicks - startupTimer.ElapsedTicks > ttcDuration) { + LoggingService.LogDebug ($"Not starting TTC timer: {timeToCodeTimer.ElapsedTicks - startupTimer.ElapsedTicks}"); + return false; + } + LoggingService.LogDebug ("Starting TTC timer"); + timeToCodeSolutionTimer.Start (); + + return true; + } + + } +} diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/ProjectOperations.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/ProjectOperations.cs index ddab4c2070..2a7dc180ab 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/ProjectOperations.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/ProjectOperations.cs @@ -947,8 +947,8 @@ namespace MonoDevelop.Ide } AlertButton delete = new AlertButton (GettextCatalog.GetString ("Delete from Disk")); - AlertButton result = MessageService.AskQuestion (question, secondaryText, - delete, AlertButton.Cancel, AlertButton.Remove); + AlertButton result = MessageService.GenericAlert (MessageService.RootWindow, Gui.Stock.Question, question, secondaryText, + delete, AlertButton.Cancel, AlertButton.Remove); if (result == delete) { if (!workspace.RequestItemUnload (prj)) return; |