diff options
41 files changed, 438 insertions, 405 deletions
diff --git a/main/external/debugger-libs b/main/external/debugger-libs -Subproject 1d8b829ad9cc7091ee464268a5d75a3e49429c5 +Subproject 694e1afd1f525e183cc60156d1bd929321bf87c diff --git a/main/external/vs-editor-api b/main/external/vs-editor-api -Subproject 199f195723d8d43352ca5842e0d45d16786bd6f +Subproject f2439c71580618ad284a768860a9787f90f50a0 diff --git a/main/src/addins/GnomePlatform/GnomePlatform.cs b/main/src/addins/GnomePlatform/GnomePlatform.cs index d24bd6f705..f597e4a930 100644 --- a/main/src/addins/GnomePlatform/GnomePlatform.cs +++ b/main/src/addins/GnomePlatform/GnomePlatform.cs @@ -231,7 +231,7 @@ namespace MonoDevelop.Platform ? BashPause : String.Empty; - return String.Format (@" -title ""{4}"" -e bash -c ""cd {3} ; '{0}' {1} ; {2}""", + return String.Format (@" -title ""{4}"" -e bash -c ""cd {3} ; '""{0}""' {1} ; {2}""", command, EscapeArgs (args), extra_commands, @@ -259,7 +259,7 @@ namespace MonoDevelop.Platform ? BashPause.Replace ("'", "\"") : String.Empty; - return String.Format (@" --nofork --workdir=""{3}"" -e ""bash"" -c '{0} {1} ; {2}'", + return String.Format (@" --nofork --workdir=""{3}"" -e ""bash"" -c '""{0}"" {1} ; {2}'", command, args, extra_commands, diff --git a/main/src/addins/MacPlatform/Dialogs/MacAlertDialogHandler.cs b/main/src/addins/MacPlatform/Dialogs/MacAlertDialogHandler.cs index 7666fd55a7..d60bd6244d 100644 --- a/main/src/addins/MacPlatform/Dialogs/MacAlertDialogHandler.cs +++ b/main/src/addins/MacPlatform/Dialogs/MacAlertDialogHandler.cs @@ -42,6 +42,23 @@ using MonoDevelop.Components.AtkCocoaHelper; namespace MonoDevelop.MacIntegration { + sealed class AlertDelegate : NSAlertDelegate + { + readonly string HelpUrl; + public AlertDelegate (string helpUrl) + { + HelpUrl = helpUrl; + } + + public override bool ShowHelp (NSAlert alert) + { + if (!string.IsNullOrEmpty (HelpUrl)) { + IdeServices.DesktopService.ShowUrl (HelpUrl); + } + return true; + } + } + class MacAlertDialogHandler : IAlertDialogHandler { public bool Run (AlertDialogData data) @@ -78,6 +95,11 @@ namespace MonoDevelop.MacIntegration alert.MessageText = data.Message.Text; + if (!string.IsNullOrEmpty (data.Message.HelpUrl)) { + alert.Delegate = new AlertDelegate (data.Message.HelpUrl); + alert.ShowsHelp = true; + } + int accessoryViewItemsCount = data.Options.Count; string secondaryText = data.Message.SecondaryText ?? string.Empty; diff --git a/main/src/addins/MacPlatform/MacInterop/CoreFoundation.cs b/main/src/addins/MacPlatform/MacInterop/CoreFoundation.cs index e2d4ab8949..8fbdcd6814 100644 --- a/main/src/addins/MacPlatform/MacInterop/CoreFoundation.cs +++ b/main/src/addins/MacPlatform/MacInterop/CoreFoundation.cs @@ -150,75 +150,5 @@ namespace MonoDevelop.MacInterop Shell = 0x00000008, All = 0xFFFFFFFF } - - public static IntPtr CreatePathUrl (string path) - { - IntPtr str = IntPtr.Zero; - IntPtr url = IntPtr.Zero; - try { - str = CreateString (path); - if (str == IntPtr.Zero) - throw new Exception ("CreateString failed"); - url = CFURLCreateWithFileSystemPath (IntPtr.Zero, str, CFUrlPathStyle.Posix, false); - if (url == IntPtr.Zero) - throw new Exception ("CFURLCreateWithFileSystemPath failed"); - return url; - } finally { - if (str != IntPtr.Zero) - Release (str); - } - } - - public static string UrlToPath (IntPtr url) - { - IntPtr str = IntPtr.Zero; - try { - str = CFURLCopyFileSystemPath (url, CFUrlPathStyle.Posix); - return str == IntPtr.Zero? null : FetchString (str); - } finally { - if (str != IntPtr.Zero) - Release (str); - } - } - - public static string GetApplicationUrl (string filePath, LSRolesMask roles) - { - IntPtr url = IntPtr.Zero; - try { - url = CreatePathUrl (filePath); - IntPtr appUrl = IntPtr.Zero; - if (LSGetApplicationForURL (url, roles, IntPtr.Zero, ref appUrl) == 0 && appUrl != IntPtr.Zero) - return UrlToPath (appUrl); - return null; - } finally { - if (url != IntPtr.Zero) - Release (url); - } - } - - public static string[] GetApplicationUrls (string filePath, LSRolesMask roles) - { - IntPtr url = IntPtr.Zero; - IntPtr arr = IntPtr.Zero; - try { - url = CreatePathUrl (filePath); - arr = LSCopyApplicationURLsForURL (url, roles); - if (arr == IntPtr.Zero) - return new string[0]; - int count = CFArrayGetCount (arr); - string[] values = new string [count]; - for (int i = 0; i < values.Length; i++ ) { - var u = CFArrayGetValueAtIndex (arr, i); - if (u != IntPtr.Zero) - values[i] = UrlToPath (u); - } - return values; - } finally { - if (url != IntPtr.Zero) - Release (url); - if (arr != IntPtr.Zero) - Release (arr); - } - } } } diff --git a/main/src/addins/MacPlatform/MacPlatform.cs b/main/src/addins/MacPlatform/MacPlatform.cs index 49cadaa103..354d857363 100644 --- a/main/src/addins/MacPlatform/MacPlatform.cs +++ b/main/src/addins/MacPlatform/MacPlatform.cs @@ -980,18 +980,19 @@ namespace MonoDevelop.MacIntegration checkUniqueName.Add ("MonoDevelop"); checkUniqueName.Add (BrandingService.ApplicationName); - string def = MonoDevelop.MacInterop.CoreFoundation.GetApplicationUrl (filename, - MonoDevelop.MacInterop.CoreFoundation.LSRolesMask.All); + var def = global::CoreServices.LaunchServices.GetDefaultApplicationUrlForUrl (NSUrl.FromString (filename)); var apps = new List<DesktopApplication> (); - foreach (var app in MonoDevelop.MacInterop.CoreFoundation.GetApplicationUrls (filename, - MonoDevelop.MacInterop.CoreFoundation.LSRolesMask.All)) { - if (string.IsNullOrEmpty (app) || !checkUniquePath.Add (app)) - continue; - var name = NSFileManager.DefaultManager.DisplayName (app); - if (checkUniqueName.Add (name)) - apps.Add (new MacDesktopApplication (app, name, def != null && def == app)); + var retrievedApps = global::CoreServices.LaunchServices.GetApplicationUrlsForUrl (NSUrl.FromString (filename), global::CoreServices.LSRoles.All); + if (retrievedApps != null) { + foreach (var app in retrievedApps) { + if (string.IsNullOrEmpty (app.Path) || !checkUniquePath.Add (app.Path)) + continue; + if (checkUniqueName.Add (app.LastPathComponent)) { + apps.Add (new MacDesktopApplication (app.Path, Path.GetFileNameWithoutExtension (app.LastPathComponent), def != null && def == app)); + } + } } apps.Sort ((DesktopApplication a, DesktopApplication b) => { @@ -1012,8 +1013,11 @@ namespace MonoDevelop.MacIntegration public override void Launch (params string[] files) { - foreach (var file in files) - NSWorkspace.SharedWorkspace.OpenFile (file, Id); + NSWorkspace.SharedWorkspace.OpenUrls ( + Array.ConvertAll (files, file => NSUrl.FromString (file)), + NSBundle.FromPath (Id).BundleIdentifier, + NSWorkspaceLaunchOptions.Default, + NSAppleEventDescriptor.DescriptorWithBoolean (true)); } } diff --git a/main/src/addins/MonoDevelop.AspNetCore/MonoDevelop.AspNetCore.csproj b/main/src/addins/MonoDevelop.AspNetCore/MonoDevelop.AspNetCore.csproj index ba66ded95c..986ea86ede 100644 --- a/main/src/addins/MonoDevelop.AspNetCore/MonoDevelop.AspNetCore.csproj +++ b/main/src/addins/MonoDevelop.AspNetCore/MonoDevelop.AspNetCore.csproj @@ -46,6 +46,7 @@ <Compile Include="MonoDevelop.AspNetCore\LaunchProfileDataExtensions.cs" /> <Compile Include="MonoDevelop.AspNetCore\LaunchProfileProvider.cs" /> <Compile Include="MonoDevelop.AspNetCore\AspNetCoreNestingRulesProvider.cs" /> + <Compile Include="MonoDevelop.AspNetCore\AspNetCoreExecutionTarget.cs" /> </ItemGroup> <ItemGroup> <EmbeddedResource Include="Properties\MonoDevelop.AspNetCore.addin.xml" /> diff --git a/main/src/addins/MonoDevelop.AspNetCore/MonoDevelop.AspNetCore/AspNetCoreExecutionCommand.cs b/main/src/addins/MonoDevelop.AspNetCore/MonoDevelop.AspNetCore/AspNetCoreExecutionCommand.cs index 2c1d3c471b..da240f9e9a 100644 --- a/main/src/addins/MonoDevelop.AspNetCore/MonoDevelop.AspNetCore/AspNetCoreExecutionCommand.cs +++ b/main/src/addins/MonoDevelop.AspNetCore/MonoDevelop.AspNetCore/AspNetCoreExecutionCommand.cs @@ -28,7 +28,7 @@ using MonoDevelop.DotNetCore; namespace MonoDevelop.AspNetCore { - public class AspNetCoreExecutionCommand : DotNetCoreExecutionCommand + public class AspNetCoreExecutionCommand : DotNetCoreBaseExecutionCommand { public AspNetCoreExecutionCommand (string directory, string outputPath, string arguments) : base (directory, outputPath, arguments) diff --git a/main/src/addins/MonoDevelop.AspNetCore/MonoDevelop.AspNetCore/AspNetCoreExecutionHandler.cs b/main/src/addins/MonoDevelop.AspNetCore/MonoDevelop.AspNetCore/AspNetCoreExecutionHandler.cs index 1c93be2f29..0453fd8c30 100644 --- a/main/src/addins/MonoDevelop.AspNetCore/MonoDevelop.AspNetCore/AspNetCoreExecutionHandler.cs +++ b/main/src/addins/MonoDevelop.AspNetCore/MonoDevelop.AspNetCore/AspNetCoreExecutionHandler.cs @@ -24,14 +24,13 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -using MonoDevelop.Core; -using MonoDevelop.Core.Execution; -using MonoDevelop.Ide; using System; using System.Linq; -using System.Threading; using System.Threading.Tasks; using System.Net.Sockets; +using MonoDevelop.Core; +using MonoDevelop.Core.Execution; +using MonoDevelop.Ide; namespace MonoDevelop.AspNetCore { @@ -57,13 +56,15 @@ namespace MonoDevelop.AspNetCore dotNetCoreCommand.WorkingDirectory, console, envVariables); + if (dotNetCoreCommand.LaunchBrowser) { - LaunchBrowser (dotNetCoreCommand.ApplicationURL, dotNetCoreCommand.LaunchURL, process.Task).Ignore (); + LaunchBrowserAsync (dotNetCoreCommand.ApplicationURL, dotNetCoreCommand.LaunchURL, dotNetCoreCommand.Target, process.Task).Ignore (); } + return process; } - public static async Task LaunchBrowser (string appUrl, string launchUrl, Task processTask) + public static async Task LaunchBrowserAsync (string appUrl, string launchUrl, ExecutionTarget target, Task processTask) { launchUrl = launchUrl ?? ""; Uri launchUri; @@ -84,12 +85,12 @@ namespace MonoDevelop.AspNetCore //Try to connect every 50ms while process is running while (!processTask.IsCompleted) { - await Task.Delay (50); + await Task.Delay (50).ConfigureAwait (false); using (var tcpClient = new TcpClient ()) { try { - tcpClient.Connect (launchUri.Host, launchUri.Port); + await tcpClient.ConnectAsync (launchUri.Host, launchUri.Port).ConfigureAwait (false); // pause briefly to allow the server process to initialize - await Task.Delay (TimeSpan.FromSeconds (1)); + await Task.Delay (TimeSpan.FromSeconds (1)).ConfigureAwait (false); break; } catch { } @@ -102,7 +103,12 @@ namespace MonoDevelop.AspNetCore } // Process is still alive hence we succesfully connected inside loop to web server, launch browser - IdeServices.DesktopService.ShowUrl (launchUri.AbsoluteUri); + var aspNetCoreTarget = target as AspNetCoreExecutionTarget; + if (aspNetCoreTarget != null && !aspNetCoreTarget.DesktopApplication.IsDefault) { + aspNetCoreTarget.DesktopApplication.Launch (launchUri.AbsoluteUri); + } else { + IdeServices.DesktopService.ShowUrl (launchUri.AbsoluteUri); + } } } }
\ No newline at end of file diff --git a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/FilePathExtensions.cs b/main/src/addins/MonoDevelop.AspNetCore/MonoDevelop.AspNetCore/AspNetCoreExecutionTarget.cs index 4c065a5a99..86cef8a38e 100644 --- a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/FilePathExtensions.cs +++ b/main/src/addins/MonoDevelop.AspNetCore/MonoDevelop.AspNetCore/AspNetCoreExecutionTarget.cs @@ -1,10 +1,10 @@ // -// FilePathExtensions.cs +// AspNetCoreExecutionTarget.cs // // Author: -// Matt Ward <matt.ward@xamarin.com> +// Rodrigo Moya <rodrigo.moya@xamarin.com> // -// Copyright (c) 2017 Xamarin Inc. (http://xamarin.com) +// Copyright (c) 2019 Microsoft, Inc. (http://www.microsoft.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -24,26 +24,22 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -using MonoDevelop.Core; +using MonoDevelop.Core.Execution; +using MonoDevelop.Ide.Desktop; -namespace MonoDevelop.DotNetCore +namespace MonoDevelop.AspNetCore { - static class FilePathExtensions + class AspNetCoreExecutionTarget : ExecutionTarget { - public static bool HasSupportedDotNetCoreProjectFileExtension (this FilePath file) + internal AspNetCoreExecutionTarget (DesktopApplication desktopApplication) { - return file.HasExtension (".csproj") || file.HasExtension (".fsproj") || file.HasExtension (".vbproj"); + DesktopApplication = desktopApplication; } - /// <summary> - /// HACK: Hide certain files in Solution window. The solution's .userprefs - /// file is the only file is included properly with the .NET Core MSBuild - /// targets. - /// </summary> - public static bool ShouldBeHidden (this FilePath file) - { - return file.HasExtension (".userprefs") || - file.FileName == ".DS_Store"; - } + public override string Name => DesktopApplication.DisplayName; + + public override string Id => DesktopApplication.Id; + + public DesktopApplication DesktopApplication { get; } } } diff --git a/main/src/addins/MonoDevelop.AspNetCore/MonoDevelop.AspNetCore/AspNetCoreProjectExtension.cs b/main/src/addins/MonoDevelop.AspNetCore/MonoDevelop.AspNetCore/AspNetCoreProjectExtension.cs index ae503d3388..d7176986f1 100644 --- a/main/src/addins/MonoDevelop.AspNetCore/MonoDevelop.AspNetCore/AspNetCoreProjectExtension.cs +++ b/main/src/addins/MonoDevelop.AspNetCore/MonoDevelop.AspNetCore/AspNetCoreProjectExtension.cs @@ -24,6 +24,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. using System; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using MonoDevelop.Core; @@ -100,6 +101,20 @@ namespace MonoDevelop.AspNetCore return base.OnExecute (monitor, context, configuration, runConfiguration); } + protected override IEnumerable<ExecutionTarget> OnGetExecutionTargets (ConfigurationSelector configuration) + { + var result = new List<ExecutionTarget> (); + foreach (var browser in IdeServices.DesktopService.GetApplications ("https://localhost")) { + if (browser.IsDefault) { + result.Insert (0, new AspNetCoreExecutionTarget (browser)); + } else { + result.Add (new AspNetCoreExecutionTarget (browser)); + } + } + + return result.Count > 0 ? result : base.OnGetExecutionTargets (configuration); + } + async Task CheckCertificateThenExecute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration, SolutionItemRunConfiguration runConfiguration) { if (AspNetCoreCertificateManager.CheckDevelopmentCertificateIsTrusted (Project, runConfiguration)) { diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/Counters.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/Counters.cs index 4fed6bfbab..c8fd7030f7 100644 --- a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/Counters.cs +++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/Counters.cs @@ -35,6 +35,7 @@ namespace MonoDevelop.Debugger public static Counter EvaluationStats = InstrumentationService.CreateCounter ("Evaluation Statistics", "Debugger", id: "Debugger.EvaluationStatistics"); public static TimerCounter<DebuggerStartMetadata> DebuggerStart = InstrumentationService.CreateTimerCounter<DebuggerStartMetadata> ("Debugger Start", "Debugger", id: "Debugger.Start"); public static TimerCounter<DebuggerActionMetadata> DebuggerAction = InstrumentationService.CreateTimerCounter<DebuggerActionMetadata> ("Debugger Action", "Debugger", id: "Debugger.Action"); + public static Counter DebuggerBusy = InstrumentationService.CreateCounter ("Debugger Busy", "Debugger", id: "Debugger.Busy"); } class DebuggerStartMetadata : CounterMetadata diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/DebuggingService.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/DebuggingService.cs index 9e19487fc4..5ed2950d2e 100644 --- a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/DebuggingService.cs +++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/DebuggingService.cs @@ -905,6 +905,23 @@ namespace MonoDevelop.Debugger await Runtime.RunInMainThread (delegate { busyEvaluator.UpdateBusyState (args); if (args.IsBusy) { + var session = (DebuggerSession) s; + + if (sessions.TryGetValue (session, out var manager)) { + var metadata = new Dictionary<string, object> { + ["DebuggerType"] = manager.Engine.Id, + ["Debugger.AsyncOperation.Description"] = args.Description, + ["Debugger.EvaluationOptions.AllowDisplayStringEvaluation"] = args.EvaluationContext.Options.AllowDisplayStringEvaluation, + ["Debugger.EvaluationOptions.AllowMethodEvaluation"] = args.EvaluationContext.Options.AllowMethodEvaluation, + ["Debugger.EvaluationOptions.AllowTargetInvoke"] = args.EvaluationContext.Options.AllowTargetInvoke, + ["Debugger.EvaluationOptions.AllowToStringCalls"] = args.EvaluationContext.Options.AllowToStringCalls, + ["Debugger.EvaluationOptions.ChunkRawStrings"] = args.EvaluationContext.Options.ChunkRawStrings, + ["Debugger.EvaluationOptions.EvaluationTimeout"] = args.EvaluationContext.Options.EvaluationTimeout, + }; + + Counters.DebuggerBusy.Inc (1, null, metadata); + } + if (busyStatusIcon == null) { busyStatusIcon = IdeApp.Workbench.StatusBar.ShowStatusIcon (ImageService.GetIcon ("md-bug", Gtk.IconSize.Menu)); busyStatusIcon.SetAlertMode (100); @@ -1422,9 +1439,9 @@ namespace MonoDevelop.Debugger if (typeSymbol != null && (arity == 0 || arity == typeSymbol.Arity)) { return symbol; } - var namespaceSymbol = symbol as Microsoft.CodeAnalysis.INamespaceSymbol;
- if (namespaceSymbol != null) {
- return namespaceSymbol;
+ var namespaceSymbol = symbol as Microsoft.CodeAnalysis.INamespaceSymbol; + if (namespaceSymbol != null) { + return namespaceSymbol; } } return null; 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 f4485c2e44..b27555e83c 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 @@ -25,6 +25,7 @@ // THE SOFTWARE. using System; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using MonoDevelop.Ide.Templates; @@ -32,7 +33,7 @@ using MonoDevelop.Projects; using NUnit.Framework; using IdeUnitTests; using MonoDevelop.Projects.FileNesting; - +using MonoDevelop.Core.Execution; namespace MonoDevelop.DotNetCore.Tests { @@ -264,18 +265,18 @@ namespace MonoDevelop.DotNetCore.Tests await CreateFromTemplateAndBuild ("NetCore2x", templateId, parameters); } - [TestCase ("Microsoft.Web.Empty.CSharp", "UseNetCore21=true")] - [TestCase ("Microsoft.Web.Empty.FSharp", "UseNetCore21=true")] - [TestCase ("Microsoft.Web.Mvc.CSharp", "UseNetCore21=true")] - [TestCase ("Microsoft.Web.Mvc.FSharp", "UseNetCore21=true")] - [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")] - [TestCase ("Microsoft.Web.Spa.Angular.CSharp", "UseNetCore21=true")] - [TestCase ("Microsoft.Web.Spa.React.CSharp", "UseNetCore21=true")] - [TestCase ("Microsoft.Web.Spa.ReactRedux.CSharp", "UseNetCore21=true")] - public async Task AspNetCore21 (string templateId, string parameters) + [TestCase ("Microsoft.Web.Empty.CSharp", "UseNetCore21=true", true)] + [TestCase ("Microsoft.Web.Empty.FSharp", "UseNetCore21=true", true)] + [TestCase ("Microsoft.Web.Mvc.CSharp", "UseNetCore21=true", true)] + [TestCase ("Microsoft.Web.Mvc.FSharp", "UseNetCore21=true", true)] + [TestCase ("Microsoft.Web.RazorPages.CSharp", "UseNetCore21=true", true)] + [TestCase ("Microsoft.Web.WebApi.CSharp", "UseNetCore21=true", true)] + [TestCase ("Microsoft.Web.WebApi.FSharp", "UseNetCore21=true", true)] + [TestCase ("Microsoft.Web.Razor.Library.CSharp", "UseNetCore21=true", false)] + [TestCase ("Microsoft.Web.Spa.Angular.CSharp", "UseNetCore21=true", true)] + [TestCase ("Microsoft.Web.Spa.React.CSharp", "UseNetCore21=true", true)] + [TestCase ("Microsoft.Web.Spa.ReactRedux.CSharp", "UseNetCore21=true", true)] + public async Task AspNetCore21 (string templateId, string parameters, bool checkExecutionTargets) { if (!IsDotNetCoreSdk21Installed ()) { Assert.Ignore (".NET Core 2.1 SDK is not installed - required by project template."); @@ -286,21 +287,21 @@ namespace MonoDevelop.DotNetCore.Tests Assert.Ignore ("Node is not installed - required by project template"); } - await CreateFromTemplateAndBuild ("NetCore2x", templateId, parameters, CheckAspNetCoreNestingRules); + await CreateFromTemplateAndBuild ("NetCore2x", templateId, parameters, CheckAspNetCoreNestingRules, checkExecutionTargets); } - [TestCase ("Microsoft.Web.Empty.CSharp", "UseNetCore22=true")] - [TestCase ("Microsoft.Web.Empty.FSharp", "UseNetCore22=true")] - [TestCase ("Microsoft.Web.Mvc.CSharp", "UseNetCore22=true")] - [TestCase ("Microsoft.Web.Mvc.FSharp", "UseNetCore22=true")] - [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")] - [TestCase ("Microsoft.Web.Spa.Angular.CSharp", "UseNetCore22=true")] - [TestCase ("Microsoft.Web.Spa.React.CSharp", "UseNetCore22=true")] - [TestCase ("Microsoft.Web.Spa.ReactRedux.CSharp", "UseNetCore22=true")] - public async Task AspNetCore22 (string templateId, string parameters) + [TestCase ("Microsoft.Web.Empty.CSharp", "UseNetCore22=true", true)] + [TestCase ("Microsoft.Web.Empty.FSharp", "UseNetCore22=true", true)] + [TestCase ("Microsoft.Web.Mvc.CSharp", "UseNetCore22=true", true)] + [TestCase ("Microsoft.Web.Mvc.FSharp", "UseNetCore22=true", true)] + [TestCase ("Microsoft.Web.RazorPages.CSharp", "UseNetCore22=true", true)] + [TestCase ("Microsoft.Web.WebApi.CSharp", "UseNetCore22=true", true)] + [TestCase ("Microsoft.Web.WebApi.FSharp", "UseNetCore22=true", true)] + [TestCase ("Microsoft.Web.Razor.Library.CSharp", "UseNetCore22=true", false)] + [TestCase ("Microsoft.Web.Spa.Angular.CSharp", "UseNetCore22=true", true)] + [TestCase ("Microsoft.Web.Spa.React.CSharp", "UseNetCore22=true", true)] + [TestCase ("Microsoft.Web.Spa.ReactRedux.CSharp", "UseNetCore22=true", true)] + public async Task AspNetCore22 (string templateId, string parameters, bool checkExecutionTargets) { if (!IsDotNetCoreSdk22Installed ()) { Assert.Ignore (".NET Core 2.2 SDK is not installed - required by project template."); @@ -311,22 +312,21 @@ namespace MonoDevelop.DotNetCore.Tests Assert.Ignore ("Node is not installed - required by project template"); } - await CreateFromTemplateAndBuild ("NetCore2x", templateId, parameters, CheckAspNetCoreNestingRules); + await CreateFromTemplateAndBuild ("NetCore2x", templateId, parameters, CheckAspNetCoreNestingRules, checkExecutionTargets); } - [Ignore ("Requires .NET Core App 3.0 runtime")] - [TestCase ("Microsoft.Web.Empty.CSharp", "UseNetCore30=true")] - [TestCase ("Microsoft.Web.Empty.FSharp", "UseNetCore30=true")] - [TestCase ("Microsoft.Web.Mvc.CSharp", "UseNetCore30=true")] - [TestCase ("Microsoft.Web.Mvc.FSharp", "UseNetCore30=true")] - [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")] - [TestCase ("Microsoft.Web.Spa.Angular.CSharp", "UseNetCore30=true")] - [TestCase ("Microsoft.Web.Spa.React.CSharp", "UseNetCore30=true")] - [TestCase ("Microsoft.Web.Spa.ReactRedux.CSharp", "UseNetCore30=true")] - public async Task AspNetCore30 (string templateId, string parameters) + [TestCase ("Microsoft.Web.Empty.CSharp", "UseNetCore30=true", true)] + [TestCase ("Microsoft.Web.Empty.FSharp", "UseNetCore30=true", true)] + [TestCase ("Microsoft.Web.Mvc.CSharp", "UseNetCore30=true", true)] + [TestCase ("Microsoft.Web.Mvc.FSharp", "UseNetCore30=true", true)] + [TestCase ("Microsoft.Web.RazorPages.CSharp", "UseNetCore30=true", true)] + [TestCase ("Microsoft.Web.WebApi.CSharp", "UseNetCore30=true", true)] + [TestCase ("Microsoft.Web.WebApi.FSharp", "UseNetCore30=true", true)] + [TestCase ("Microsoft.Web.Razor.Library.CSharp", "UseNetCore30=true", false)] + [TestCase ("Microsoft.Web.Spa.Angular.CSharp", "UseNetCore30=true", true)] + [TestCase ("Microsoft.Web.Spa.React.CSharp", "UseNetCore30=true", true)] + [TestCase ("Microsoft.Web.Spa.ReactRedux.CSharp", "UseNetCore30=true", true)] + public async Task AspNetCore30 (string templateId, string parameters, bool checkExecutionTargets) { if (!IsDotNetCoreSdk30Installed ()) { Assert.Ignore (".NET Core 3.0 SDK is not installed - required by project template."); @@ -337,7 +337,7 @@ namespace MonoDevelop.DotNetCore.Tests Assert.Ignore ("Node is not installed - required by project template"); } - await CreateFromTemplateAndBuild ("NetCore30", templateId, parameters, CheckAspNetCoreNestingRules); + await CreateFromTemplateAndBuild ("NetCore30", templateId, parameters, CheckAspNetCoreNestingRules, checkExecutionTargets); } static bool IsDotNetCoreSdk2xInstalled () @@ -366,7 +366,7 @@ namespace MonoDevelop.DotNetCore.Tests return DotNetCoreSdk.Versions.Any (version => version.Major == 3 && version.Minor == 0); } - static async Task CreateFromTemplateAndBuild (string basename, string templateId, string parameters, Action<Solution> preBuildChecks = null) + static async Task CreateFromTemplateAndBuild (string basename, string templateId, string parameters, Action<Solution> preBuildChecks = null, bool checkExecutionTargets = false) { using (var ptt = new ProjectTemplateTest (basename, templateId)) { @@ -377,6 +377,18 @@ namespace MonoDevelop.DotNetCore.Tests var template = await ptt.CreateAndBuild (preBuildChecks); CheckProjectTypeGuids (ptt.Solution, GetProjectTypeGuid (template)); + // Blacklist library projects, which don't get any execution target + if (checkExecutionTargets) { + foreach (var p in ptt.Solution.GetAllProjects ().OfType<DotNetProject> ()) { + foreach (var config in p.Configurations) { + var targets = p.GetExecutionTargets (config.Selector)?.ToList () ?? new List<ExecutionTarget> (); + if (System.IO.Directory.Exists ("/Applications/Safari.app")) + Assert.True (targets.Any (x => x.Name.Contains ("Safari")), $"Configuration {config.Name} didn't contain Safari"); + if (System.IO.Directory.Exists ("/Applications/Google Chrome.app")) + Assert.True (targets.Any (x => x.Name.Contains ("Google Chrome")), $"Configuration {config.Name} didn't contain Chrome"); + } + } + } } } diff --git a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore.csproj b/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore.csproj index 2a1c0e630c..bb1c502dc0 100644 --- a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore.csproj +++ b/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore.csproj @@ -26,7 +26,7 @@ <Compile Include="MonoDevelop.DotNetCore\DotNetCorePath.cs" /> <Compile Include="MonoDevelop.DotNetCore\DotNetCoreExecutionHandler.cs" /> <Compile Include="MonoDevelop.DotNetCore.Templating\DotNetCoreProjectTemplateWizard.cs" /> - <Compile Include="MonoDevelop.DotNetCore\DotNetCoreNotInstalledDialog.cs" /> + <Compile Include="MonoDevelop.DotNetCore\DotNetCoreNotInstalledInfoBar.cs" /> <Compile Include="MonoDevelop.DotNetCore\DotNetCoreSdkPaths.cs" /> <Compile Include="MonoDevelop.DotNetCore\DotNetCoreCanReferenceProjectExtension.cs" /> <Compile Include="MonoDevelop.DotNetCore\DotNetCliToolReference.cs" /> @@ -39,7 +39,6 @@ <Compile Include="MonoDevelop.DotNetCore\TargetFrameworkExtensions.cs" /> <Compile Include="MonoDevelop.DotNetCore\DummyMSBuildOptionsPanel.cs" /> <Compile Include="MonoDevelop.DotNetCore\TargetFrameworkMonikerExtensions.cs" /> - <Compile Include="MonoDevelop.DotNetCore\FilePathExtensions.cs" /> <Compile Include="MonoDevelop.DotNetCore.NodeBuilders\ProjectDependenciesNode.cs" /> <Compile Include="MonoDevelop.DotNetCore\ProjectReferenceExtensions.cs" /> <Compile Include="MonoDevelop.DotNetCore.NodeBuilders\ProjectDependenciesNodeBuilder.cs" /> diff --git a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreExecutionCommand.cs b/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreExecutionCommand.cs index 646fb372fc..de4542a37b 100644 --- a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreExecutionCommand.cs +++ b/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreExecutionCommand.cs @@ -28,9 +28,9 @@ using MonoDevelop.Core.Execution; namespace MonoDevelop.DotNetCore { - public class DotNetCoreExecutionCommand : ProcessExecutionCommand + public class DotNetCoreBaseExecutionCommand : ProcessExecutionCommand { - public DotNetCoreExecutionCommand (string directory, string outputPath, string arguments) + public DotNetCoreBaseExecutionCommand (string directory, string outputPath, string arguments) { WorkingDirectory = directory; OutputPath = outputPath; @@ -50,4 +50,12 @@ namespace MonoDevelop.DotNetCore public string ApplicationURL { get; set; } public PipeTransportSettings PipeTransport { get; set; } } + + public class DotNetCoreExecutionCommand : DotNetCoreBaseExecutionCommand + { + public DotNetCoreExecutionCommand (string directory, string outputPath, string arguments) + : base (directory, outputPath, arguments) + { + } + } }
\ No newline at end of file diff --git a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreExecutionHandler.cs b/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreExecutionHandler.cs index 01f0858897..272092479d 100644 --- a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreExecutionHandler.cs +++ b/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreExecutionHandler.cs @@ -24,14 +24,10 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -using MonoDevelop.Core; -using MonoDevelop.Core.Execution; -using MonoDevelop.Ide; using System; using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using System.Net.Sockets; +using MonoDevelop.Core; +using MonoDevelop.Core.Execution; namespace MonoDevelop.DotNetCore { @@ -56,52 +52,8 @@ namespace MonoDevelop.DotNetCore dotNetCoreCommand.WorkingDirectory, console, envVariables); - if (dotNetCoreCommand.LaunchBrowser) { - LaunchBrowser (dotNetCoreCommand.ApplicationURL, dotNetCoreCommand.LaunchURL, process.Task).Ignore (); - } - return process; - } - public static async Task LaunchBrowser (string appUrl, string launchUrl, Task processTask) - { - launchUrl = launchUrl ?? ""; - Uri launchUri; - //Check if lanuchUrl is valid absolute url and use it if it is... - if (!Uri.TryCreate (launchUrl, UriKind.Absolute, out launchUri)) { - //Otherwise check if appUrl is valid absolute and lanuchUrl is relative then concat them... - Uri appUri; - if (!Uri.TryCreate (appUrl, UriKind.Absolute, out appUri)) { - LoggingService.LogWarning ("Failed to launch browser because invalid launch and app urls."); - return; - } - if (!Uri.TryCreate (launchUrl, UriKind.Relative, out launchUri)) { - LoggingService.LogWarning ("Failed to launch browser because invalid launch url."); - return; - } - launchUri = new Uri (appUri, launchUri); - } - - //Try to connect every 50ms while process is running - while (!processTask.IsCompleted) { - await Task.Delay (50); - using (var tcpClient = new TcpClient ()) { - try { - tcpClient.Connect (launchUri.Host, launchUri.Port); - // pause briefly to allow the server process to initialize - await Task.Delay (TimeSpan.FromSeconds (1)); - break; - } catch { - } - } - } - - if (processTask.IsCompleted) { - LoggingService.LogDebug ("Failed to launch browser because process exited before server started listening."); - return; - } - - // Process is still alive hence we succesfully connected inside loop to web server, launch browser - IdeServices.DesktopService.ShowUrl (launchUri.AbsoluteUri); + return process; } } }
\ No newline at end of file diff --git a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreNotInstalledDialog.cs b/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreNotInstalledInfoBar.cs index 9fb149f4f3..dd4578c87d 100644 --- a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreNotInstalledDialog.cs +++ b/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreNotInstalledInfoBar.cs @@ -1,5 +1,5 @@ // -// DotNetCoreNotInstalledDialog.cs +// DotNetCoreNotInstalledInfoBar.cs // // Author: // Matt Ward <matt.ward@xamarin.com> @@ -26,70 +26,38 @@ using MonoDevelop.Core; using MonoDevelop.Ide; -using MonoDevelop.Ide.Gui; -using System; +using MonoDevelop.Ide.Gui.Components; namespace MonoDevelop.DotNetCore { - class DotNetCoreNotInstalledDialog : IDisposable + class DotNetCoreNotInstalledInfoBar { - static readonly string defaultMessage = GettextCatalog.GetString (".NET Core SDK is not installed. This is required to build and run .NET Core projects."); - - GenericMessage message; - AlertButton downloadButton; string downloadUrl = DotNetCoreDownloadUrl.GetDotNetCoreDownloadUrl (); - public DotNetCoreNotInstalledDialog () - { - Build (); - } - - void Build () - { - message = new GenericMessage { - Text = defaultMessage, - DefaultButton = 1, - Icon = Stock.Information - }; - - downloadButton = new AlertButton (GettextCatalog.GetString ("Download .NET Core...")); - message.Buttons.Add (AlertButton.Cancel); - message.Buttons.Add (downloadButton); - - message.AlertButtonClicked += AlertButtonClicked; - } - - void AlertButtonClicked (object sender, AlertButtonEventArgs e) - { - if (e.Button == downloadButton) - IdeServices.DesktopService.ShowUrl (downloadUrl); - } - - public void Dispose () - { - message.AlertButtonClicked -= AlertButtonClicked; - } + public string Message { get; set; } + public bool IsUnsupportedVersion { get; set; } + public bool IsNetStandard { get; set; } + public DotNetCoreVersion RequiredDotNetCoreVersion { get; set; } + public string CurrentDotNetCorePath { get; set; } - public void Show () + public void Prompt () { - if (IsUnsupportedVersion || IsNetStandard) //for .net standard we'll show generic message + var items = new InfoBarItem [] { + new InfoBarItem (GettextCatalog.GetString ("Download .NET Core"), InfoBarItemKind.Button, DownloadButtonClicked, true) + }; + + if (IsUnsupportedVersion || IsNetStandard || RequiredDotNetCoreVersion == null) //for .net standard we'll show generic message Message = DotNetCoreSdk.GetNotSupportedVersionMessage (); else { Message = DotNetCoreSdk.GetNotSupportedVersionMessage (RequiredDotNetCoreVersion.OriginalString); downloadUrl = DotNetCoreDownloadUrl.GetDotNetCoreDownloadUrl (RequiredDotNetCoreVersion); } - MessageService.GenericAlert (message); + IdeApp.Workbench.ShowInfoBar (false, new InfoBarOptions (Message) { + Items = items + }); } - public string Message { - get { return message.Text; } - set { message.Text = value; } - } - - public bool IsUnsupportedVersion { get; set; } - public bool IsNetStandard { get; set; } - public DotNetCoreVersion RequiredDotNetCoreVersion { get; set; } - public string CurrentDotNetCorePath { get; set; } + void DownloadButtonClicked () => IdeServices.DesktopService.ShowUrl (downloadUrl); } } diff --git a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreProjectExtension.cs b/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreProjectExtension.cs index df43588e79..217a718ff0 100644 --- a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreProjectExtension.cs +++ b/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreProjectExtension.cs @@ -194,10 +194,7 @@ namespace MonoDevelop.DotNetCore Task ShowCannotExecuteDotNetCoreApplicationDialog () { return Runtime.RunInMainThread (() => { - using (var dialog = new DotNetCoreNotInstalledDialog ()) { - dialog.Message = GettextCatalog.GetString (".NET Core is required to run this application."); - dialog.Show (); - } + CreateInfoBarInstance ().Prompt (); }); } @@ -206,19 +203,23 @@ namespace MonoDevelop.DotNetCore return Runtime.RunInMainThread (() => { if (ShownDotNetCoreSdkNotInstalledDialogForSolution ()) return; - + Project.ParentSolution.ExtendedProperties [ShownDotNetCoreSdkInstalledExtendedPropertyName] = "true"; - using (var dialog = new DotNetCoreNotInstalledDialog ()) { - dialog.IsUnsupportedVersion = unsupportedSdkVersion; - dialog.RequiredDotNetCoreVersion = DotNetCoreVersion.Parse (Project.TargetFramework.Id.Version); - dialog.CurrentDotNetCorePath = sdkPaths.MSBuildSDKsPath; - dialog.IsNetStandard = Project.TargetFramework.Id.IsNetStandard (); - dialog.Show (); - } + CreateInfoBarInstance (unsupportedSdkVersion).Prompt (); }); } + DotNetCoreNotInstalledInfoBar CreateInfoBarInstance (bool unsupportedSdkVersion = false) + { + return new DotNetCoreNotInstalledInfoBar { + IsUnsupportedVersion = unsupportedSdkVersion, + RequiredDotNetCoreVersion = DotNetCoreVersion.Parse (Project.TargetFramework.Id.Version), + CurrentDotNetCorePath = sdkPaths.MSBuildSDKsPath, + IsNetStandard = Project.TargetFramework.Id.IsNetStandard () + }; + } + bool ShownDotNetCoreSdkNotInstalledDialogForSolution () { return Project.ParentSolution.ExtendedProperties.Contains (ShownDotNetCoreSdkInstalledExtendedPropertyName); diff --git a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreSdk.cs b/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreSdk.cs index 60028713d4..50992bf057 100644 --- a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreSdk.cs +++ b/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreSdk.cs @@ -184,10 +184,10 @@ namespace MonoDevelop.DotNetCore { string GetMessage (DotNetCoreVersion currentVersion) { - return GettextCatalog.GetString ("NET Core {0}.{1} SDK version {2} is not compatible with this version of Visual Studio for Mac. Install the latest update to the .NET Core {0}.{1} SDK by visiting {3}.", currentVersion.Major, currentVersion.Minor, currentVersion.ToString (), DotNetCoreDownloadUrl.GetDotNetCoreDownloadUrl (currentVersion)); + return GettextCatalog.GetString (".NET Core {0}.{1} SDK version {2} is not compatible with this version of Visual Studio for Mac. Install the latest update to the .NET Core {0}.{1} SDK by visiting {3}", currentVersion.Major, currentVersion.Minor, currentVersion.ToString (), DotNetCoreDownloadUrl.GetDotNetCoreDownloadUrl (currentVersion)); } - var installedVersion = Versions.OrderByDescending (x => x).FirstOrDefault (); + var installedVersion = Versions?.OrderByDescending (x => x).FirstOrDefault (); if (installedVersion != null) { if (installedVersion < DotNetCoreVersion.MinimumSupportedSdkVersion) { return GetMessage (installedVersion); @@ -198,7 +198,7 @@ namespace MonoDevelop.DotNetCore } } - return GettextCatalog.GetString (".NET Core {0} SDK is required to build this application, and is not installed. Install the latest update to the .NET Core {0} SDK by visiting {1}.", version, DotNetCoreDownloadUrl.GetDotNetCoreDownloadUrl (version)); + return GettextCatalog.GetString (".NET Core {0} SDK is required to build this application, and is not installed. Install the latest update to the .NET Core {0} SDK by visiting {1}", version, DotNetCoreDownloadUrl.GetDotNetCoreDownloadUrl (version)); } } } diff --git a/main/src/addins/MonoDevelop.SourceEditor2/MonoDevelop.SourceEditor/ExtensibleTextEditor.cs b/main/src/addins/MonoDevelop.SourceEditor2/MonoDevelop.SourceEditor/ExtensibleTextEditor.cs index dcafc9625b..42e3275c59 100644 --- a/main/src/addins/MonoDevelop.SourceEditor2/MonoDevelop.SourceEditor/ExtensibleTextEditor.cs +++ b/main/src/addins/MonoDevelop.SourceEditor2/MonoDevelop.SourceEditor/ExtensibleTextEditor.cs @@ -550,8 +550,12 @@ namespace MonoDevelop.SourceEditor LoggingService.LogError ("DoInsertTemplate(): Can't find valid document"); return false; } - - return DoInsertTemplate (EditorExtension.Editor, doc.DocumentContext); + try { + return DoInsertTemplate (doc.Editor, doc.DocumentContext); + } catch (Exception e) { + LoggingService.LogInternalError ($"Error while trying to insert template: Editor={doc.Editor}, Ctx={doc.DocumentContext}.", e); + return false; + } } public bool DoInsertTemplate (TextEditor editor, DocumentContext ctx) diff --git a/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor/Properties/MonoDevelop.TextEditor.addin.xml b/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor/Properties/MonoDevelop.TextEditor.addin.xml index 977ce7d472..969f61f267 100644 --- a/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor/Properties/MonoDevelop.TextEditor.addin.xml +++ b/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor/Properties/MonoDevelop.TextEditor.addin.xml @@ -152,6 +152,9 @@ <Map id="MonoDevelop.Ide.Commands.EditCommands.ToggleAllFoldings" argsType="Microsoft.VisualStudio.Text.Editor.Commanding.Commands.ToggleAllOutliningCommandArgs" /> <Map id="MonoDevelop.Ide.Commands.EditCommands.FoldDefinitions" argsType="Microsoft.VisualStudio.Text.Editor.Commanding.Commands.ToggleOutliningDefinitionsCommandArgs" /> <Map id="MonoDevelop.Ide.Commands.EditCommands.EnableDisableFolding" argsType="Microsoft.VisualStudio.Text.Editor.Commanding.Commands.ToggleOutliningEnabledCommandArgs" /> + + <Map id="MonoDevelop.Ide.Commands.TextEditorCommands.ExpandSelection" argsType="Microsoft.VisualStudio.Text.Editor.Commanding.Commands.ExpandSelectionCommandArgs" /> + <Map id="MonoDevelop.Ide.Commands.TextEditorCommands.ShrinkSelection" argsType="Microsoft.VisualStudio.Text.Editor.Commanding.Commands.ContractSelectionCommandArgs" /> </Extension> <!-- diff --git a/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor/TextViewContent.Commands.cs b/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor/TextViewContent.Commands.cs index bb7f8ea4ec..869774abef 100644 --- a/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor/TextViewContent.Commands.cs +++ b/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor/TextViewContent.Commands.cs @@ -95,7 +95,6 @@ namespace MonoDevelop.TextEditor [TextEditorCommands.MovePrevWord] = op => op.MoveToPreviousWord (extendSelection: false), [TextEditorCommands.MoveNextWord] = op => op.MoveToNextWord (extendSelection: false), - [TextEditorCommands.ExpandSelection] = op => op.SelectEnclosing (), [TextEditorCommands.ExpandSelectionToLine] = op => op.MoveToEndOfLine (extendSelection: true), [TextEditorCommands.SelectionMoveLeft] = op => op.MoveToPreviousCharacter (extendSelection: true), diff --git a/main/src/addins/MonoDevelop.UnitTesting.NUnit/NUnit3Runner/NUnitTestRunner.cs b/main/src/addins/MonoDevelop.UnitTesting.NUnit/NUnit3Runner/NUnitTestRunner.cs index 903745c6b0..2b1e9e1c16 100644 --- a/main/src/addins/MonoDevelop.UnitTesting.NUnit/NUnit3Runner/NUnitTestRunner.cs +++ b/main/src/addins/MonoDevelop.UnitTesting.NUnit/NUnit3Runner/NUnitTestRunner.cs @@ -56,6 +56,7 @@ namespace NUnit3Runner {
engine = TestEngineActivator.CreateInstance (); filterService = engine.Services.GetService<ITestFilterService>(); + AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; } [MessageHandler] @@ -223,7 +224,13 @@ namespace NUnit3Runner } } } - + + Assembly CurrentDomain_AssemblyResolve (object sender, ResolveEventArgs args) + { + var name = new AssemblyName (args.Name); + return AppDomain.CurrentDomain.GetAssemblies ().FirstOrDefault (a => AssemblyName.ReferenceMatchesDefinition (name, a.GetName ())); + } + private TestFilter CreateTestFilter (string[] nameFilter) { ITestFilterBuilder builder = filterService.GetTestFilterBuilder(); diff --git a/main/src/core/MonoDevelop.Core/CoreExtensions.Array.cs b/main/src/core/MonoDevelop.Core/CoreExtensions.Array.cs new file mode 100644 index 0000000000..efa5f2155c --- /dev/null +++ b/main/src/core/MonoDevelop.Core/CoreExtensions.Array.cs @@ -0,0 +1,33 @@ +// +// CoreExtensions.Array.cs +// +// Author: +// Marius Ungureanu <maungu@microsoft.com> +// +// Copyright (c) 2019 Microsoft Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System; +namespace System +{ + public static partial class CoreExtensions + { + internal static bool Contains<T> (this T [] arr, T value) => Array.IndexOf (arr, value) != -1; + } +} diff --git a/main/src/core/MonoDevelop.Core/CoreExtensions.ReaderWriterLockSlim.cs b/main/src/core/MonoDevelop.Core/CoreExtensions.ReaderWriterLockSlim.cs new file mode 100644 index 0000000000..b4805ff230 --- /dev/null +++ b/main/src/core/MonoDevelop.Core/CoreExtensions.ReaderWriterLockSlim.cs @@ -0,0 +1,90 @@ +// +// CoreExtensions.ReaderWriterLockSlim.cs +// +// Author: +// Marius Ungureanu <maungu@microsoft.com> +// +// Copyright (c) 2019 Microsoft Inc. +// +// 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.Threading; + +namespace System +{ + public static partial class CoreExtensions + { + internal static ReadLockExiter Read (this ReaderWriterLockSlim @lock) + => new ReadLockExiter (@lock); + + internal readonly struct ReadLockExiter : IDisposable + { + readonly ReaderWriterLockSlim _lock; + + internal ReadLockExiter (ReaderWriterLockSlim @lock) + { + _lock = @lock; + @lock.EnterReadLock (); + } + + public void Dispose () => _lock.ExitReadLock (); + } + + internal static UpgradeableReadLockExiter UpgradeableRead (this ReaderWriterLockSlim @lock) + => new UpgradeableReadLockExiter (@lock); + + internal readonly struct UpgradeableReadLockExiter : IDisposable + { + readonly ReaderWriterLockSlim _lock; + + internal UpgradeableReadLockExiter (ReaderWriterLockSlim @lock) + { + _lock = @lock; + @lock.EnterUpgradeableReadLock (); + } + + public void Dispose () + { + if (_lock.IsWriteLockHeld) { + _lock.ExitWriteLock (); + } + + _lock.ExitUpgradeableReadLock (); + } + + public void EnterWrite () => _lock.EnterWriteLock (); + } + + internal static WriteLockExiter Write (this ReaderWriterLockSlim @lock) + => new WriteLockExiter (@lock); + + internal readonly struct WriteLockExiter : IDisposable + { + readonly ReaderWriterLockSlim _lock; + + internal WriteLockExiter (ReaderWriterLockSlim @lock) + { + _lock = @lock; + @lock.EnterWriteLock (); + } + + public void Dispose () => _lock.ExitWriteLock (); + } + } +} diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/SystemAssemblyService.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/SystemAssemblyService.cs index 8817782fed..5eb2a9b08d 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/SystemAssemblyService.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/SystemAssemblyService.cs @@ -234,22 +234,26 @@ namespace MonoDevelop.Core.Assemblies return aname; } + static readonly ReaderWriterLockSlim readerWriterLock = new ReaderWriterLockSlim (); static readonly Dictionary<string, AssemblyName> assemblyNameCache = new Dictionary<string, AssemblyName> (); internal static AssemblyName GetAssemblyNameObj (string file) { AssemblyName name; - lock (assemblyNameCache) { + using (readerWriterLock.Read ()) { if (assemblyNameCache.TryGetValue (file, out name)) return name; } try { name = AssemblyName.GetAssemblyName (file); - lock (assemblyNameCache) { - assemblyNameCache [file] = name; + + using (readerWriterLock.Write ()) { + if (assemblyNameCache.TryGetValue (file, out var alreadyAdded)) + return alreadyAdded; + + return assemblyNameCache [file] = name; } - return name; } catch (FileNotFoundException) { // GetAssemblyName is not case insensitive in mono/windows. This is a workaround foreach (string f in Directory.GetFiles (Path.GetDirectoryName (file), Path.GetFileName (file))) { diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj index c86fd60eab..63d61dadf9 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj @@ -740,6 +740,8 @@ <Compile Include="CoreExtensions.IEnumerable.cs" /> <Compile Include="CoreExtensions.Memoize.cs" /> <Compile Include="CoreExtensions.EventHandlers.cs" /> + <Compile Include="CoreExtensions.Array.cs" /> + <Compile Include="CoreExtensions.ReaderWriterLockSlim.cs" /> </ItemGroup> <ItemGroup> <None Include="BuildVariables.cs.in" /> diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/DefaultMSBuildEngine.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/DefaultMSBuildEngine.cs index 1c14ad2329..e821b48bf6 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/DefaultMSBuildEngine.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/DefaultMSBuildEngine.cs @@ -333,8 +333,9 @@ namespace MonoDevelop.Projects.MSBuild void Evaluate (ProjectInfo project, MSBuildEvaluationContext context, MSBuildPropertyGroup group) { - if (!string.IsNullOrEmpty (group.Condition) && !SafeParseAndEvaluate (project, context, group.Condition, true)) + if (!SafeParseAndEvaluate (project, context, group.Condition, true)) { return; + } foreach (var prop in group.GetProperties ()) Evaluate (project, context, prop); @@ -342,14 +343,11 @@ namespace MonoDevelop.Projects.MSBuild void Evaluate (ProjectInfo project, MSBuildEvaluationContext context, MSBuildItemGroup items) { - bool conditionIsTrue = true; - - if (!string.IsNullOrEmpty (items.Condition)) - conditionIsTrue = SafeParseAndEvaluate (project, context, items.Condition); + bool conditionIsTrue = SafeParseAndEvaluate (project, context, items.Condition); foreach (var item in items.Items) { - var trueCond = conditionIsTrue && (string.IsNullOrEmpty (item.Condition) || SafeParseAndEvaluate (project, context, item.Condition)); + var trueCond = conditionIsTrue && SafeParseAndEvaluate (project, context, item.Condition); if (!string.IsNullOrEmpty (item.Update)) { var update = context.EvaluateString (item.Update); @@ -472,7 +470,7 @@ namespace MonoDevelop.Projects.MSBuild var rootProject = project.GetRootMSBuildProject (); foreach (var p in item.Metadata.GetProperties ()) { - if (string.IsNullOrEmpty (p.Condition) || SafeParseAndEvaluate (project, context, p.Condition, true)) { + if (SafeParseAndEvaluate (project, context, p.Condition, true)) { string evaluatedValue = context.EvaluateString (p.Value); string unevaluatedValue = p.Value; @@ -519,7 +517,10 @@ namespace MonoDevelop.Projects.MSBuild { var exclude = ExcludeToRegex (remove); do { - foreach (var globInclude in project.GlobIncludes.Where (g => g.Item.Name == item.Name)) { + foreach (var globInclude in project.GlobIncludes) { + if (globInclude.Item.Name != item.Name) + continue; + if (globInclude.RemoveRegex != null) exclude = globInclude.RemoveRegex + "|" + exclude; globInclude.RemoveRegex = new Regex (exclude); @@ -643,7 +644,7 @@ namespace MonoDevelop.Projects.MSBuild } // Now override metadata from the new item definition foreach (var c in item.Metadata.GetProperties ()) { - if (string.IsNullOrEmpty (c.Condition) || SafeParseAndEvaluate (project, context, c.Condition, true)) + if (SafeParseAndEvaluate (project, context, c.Condition, true)) md [c.Name] = new MSBuildPropertyEvaluated (project.Project, c.Name, c.Value, context.EvaluateString (c.Value)); } ((MSBuildPropertyGroupEvaluated)newItem.Metadata).SetProperties (md); @@ -840,7 +841,7 @@ namespace MonoDevelop.Projects.MSBuild void Evaluate (ProjectInfo project, MSBuildEvaluationContext context, MSBuildImportGroup imports, bool evalItems) { - if (!string.IsNullOrEmpty (imports.Condition) && !SafeParseAndEvaluate (project, context, imports.Condition, true)) + if (!SafeParseAndEvaluate (project, context, imports.Condition, true)) return; foreach (var item in imports.Imports) @@ -867,10 +868,8 @@ namespace MonoDevelop.Projects.MSBuild static IEnumerable<string> GetIncludesForWildcardFilePath (MSBuildProject project, string path, Regex directoryExcludeRegex = null) { var subpath = SplitWildcardFilePath (path); - - WildcardExpansionFunc<string> func = delegate (string file, string include, string recursiveDir) { - return include; - }; + + WildcardExpansionFunc<string> func = (file, include, recursiveDir) => include; return ExpandWildcardFilePath (project, project.BaseDirectory, FilePath.Null, false, subpath.AsSpan (), func, directoryExcludeRegex); } @@ -925,7 +924,7 @@ namespace MonoDevelop.Projects.MSBuild else if (!baseDir.EndsWith ("\\", StringComparison.Ordinal)) baseDir += '\\'; var recursiveDir = baseRecursiveDir.IsNullOrEmpty ? FilePath.Null : basePath.ToRelative (baseRecursiveDir); - res = res.Concat (Directory.EnumerateFiles (basePath, path).Select (f => func (f, baseDir + Path.GetFileName (f), recursiveDir))); + res = res.Concat (Directory.GetFiles (basePath, path).Select (f => func (f, baseDir + Path.GetFileName (f), recursiveDir))); } else { // Directory specifier // Look for matching directories. @@ -1006,7 +1005,7 @@ namespace MonoDevelop.Projects.MSBuild try { context.SetItemContext (include, evaluatedFile, recursiveDir); foreach (var c in sourceItem.Metadata.GetProperties ()) { - if (string.IsNullOrEmpty (c.Condition) || SafeParseAndEvaluate (pinfo, context, c.Condition, true)) + if (SafeParseAndEvaluate (pinfo, context, c.Condition, true)) md [c.Name] = new MSBuildPropertyEvaluated (project, c.Name, c.Value, context.EvaluateString (c.Value)) { Condition = c.Condition }; } } finally { @@ -1023,19 +1022,16 @@ namespace MonoDevelop.Projects.MSBuild void Evaluate (ProjectInfo project, MSBuildEvaluationContext context, MSBuildProperty prop) { - if (string.IsNullOrEmpty (prop.Condition) || SafeParseAndEvaluate (project, context, prop.Condition, true)) { - bool needsItemEvaluation; - var val = context.Evaluate (prop.UnevaluatedValue, out needsItemEvaluation); - if (needsItemEvaluation) - context.SetPropertyNeedsTransformEvaluation (prop.Name); - StoreProperty (project, prop.Name, prop.UnevaluatedValue, val); - context.SetPropertyValue (prop.Name, val); + if (!SafeParseAndEvaluate (project, context, prop.Condition, true)) { + return; } - } - MSBuildItemEvaluated Evaluate (ProjectInfo project, MSBuildEvaluationContext context, MSBuildItem item) - { - return CreateEvaluatedItem (context, project, project.Project, item, context.EvaluateString (item.Include)); + bool needsItemEvaluation; + var val = context.Evaluate (prop.UnevaluatedValue, out needsItemEvaluation); + if (needsItemEvaluation) + context.SetPropertyNeedsTransformEvaluation (prop.Name); + StoreProperty (project, prop.Name, prop.UnevaluatedValue, val); + context.SetPropertyValue (prop.Name, val); } IReadOnlyList<ProjectInfo> GetImportedProjects (ProjectInfo project, MSBuildImport import) @@ -1167,7 +1163,7 @@ namespace MonoDevelop.Projects.MSBuild } else basePath = project.Project.BaseDirectory; - if (!string.IsNullOrEmpty (import.Condition) && !SafeParseAndEvaluate (project, context, import.Condition, true, basePath)) { + if (!SafeParseAndEvaluate (project, context, import.Condition, true, basePath)) { // Condition evaluates to false. Keep searching because maybe another value for the path property makes // the condition evaluate to true. keepSearching = true; @@ -1259,13 +1255,10 @@ namespace MonoDevelop.Projects.MSBuild void Evaluate (ProjectInfo project, MSBuildEvaluationContext context, MSBuildItemDefinitionGroup items) { - bool conditionIsTrue = true; - - if (!string.IsNullOrEmpty (items.Condition)) - conditionIsTrue = SafeParseAndEvaluate (project, context, items.Condition); + bool conditionIsTrue = SafeParseAndEvaluate (project, context, items.Condition); foreach (var item in items.Items) { - var trueCond = conditionIsTrue && (string.IsNullOrEmpty (item.Condition) || SafeParseAndEvaluate (project, context, item.Condition)); + var trueCond = conditionIsTrue && SafeParseAndEvaluate (project, context, item.Condition); if (trueCond) { var it = CreateEvaluatedItem (context, project, project.Project, item, string.Empty); project.EvaluatedItemDefinitions.Add (it); @@ -1277,7 +1270,7 @@ namespace MonoDevelop.Projects.MSBuild bool SafeParseAndEvaluate (ProjectInfo project, MSBuildEvaluationContext context, string condition, bool collectConditionedProperties = false, string customEvalBasePath = null) { try { - if (String.IsNullOrEmpty (condition)) + if (string.IsNullOrEmpty (condition)) return true; context.CustomFullDirectoryName = customEvalBasePath; diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProjectInstance.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProjectInstance.cs index 7c8df89ff8..a23254c86c 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProjectInstance.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProjectInstance.cs @@ -145,13 +145,13 @@ namespace MonoDevelop.Projects.MSBuild } } - var evalItems = new Dictionary<string,MSBuildItemEvaluated> (); + var evalItems = new Dictionary<(string, string),MSBuildItemEvaluated> (); foreach (var it in e.GetEvaluatedItems (project)) { var xit = it as MSBuildItemEvaluated; if (xit == null) { xit = CreateEvaluatedItem (e, it); var itemId = e.GetItemMetadata (it, NodeIdPropertyName); - var key = itemId + " " + xit.Include; + var key = (itemId, xit.Include); if (evalItems.ContainsKey (key)) continue; // xbuild seems to return duplicate items when using wildcards. This is a workaround to avoid the duplicates. MSBuildItem pit; @@ -164,14 +164,14 @@ namespace MonoDevelop.Projects.MSBuild evaluatedItems.Add (xit); } - var evalItemsNoCond = new Dictionary<string,MSBuildItemEvaluated> (); + var evalItemsNoCond = new Dictionary<(string, string),MSBuildItemEvaluated> (); foreach (var it in e.GetEvaluatedItemsIgnoringCondition (project)) { var xit = it as MSBuildItemEvaluated; if (xit == null) { xit = CreateEvaluatedItem (e, it); var itemId = e.GetItemMetadata (it, NodeIdPropertyName); MSBuildItemEvaluated evItem; - var key = itemId + " " + xit.Include; + var key = (itemId, xit.Include); if (evalItemsNoCond.ContainsKey (key)) continue; // xbuild seems to return duplicate items when using wildcards. This is a workaround to avoid the duplicates. if (!string.IsNullOrEmpty (itemId) && evalItems.TryGetValue (key, out evItem)) { diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs index c527edea1d..3df66730cc 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs @@ -3998,7 +3998,7 @@ namespace MonoDevelop.Projects if (p2 == null) return false; if (!p.ValueType.Equals (p.Value, p2.UnevaluatedValue)) { - if (p2.UnevaluatedValue != null && p2.UnevaluatedValue.Contains ('%')) { + if (p2.UnevaluatedValue != null && p2.UnevaluatedValue.IndexOf ('%') != -1) { // Check evaluated value is a match. if (!p.ValueType.Equals (p.Value, p2.Value)) return false; diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AtkCocoaHelper/AtkCocoaHelperMac.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AtkCocoaHelper/AtkCocoaHelperMac.cs index 2180972ffd..a5dd9aef0a 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AtkCocoaHelper/AtkCocoaHelperMac.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AtkCocoaHelper/AtkCocoaHelperMac.cs @@ -384,6 +384,12 @@ namespace MonoDevelop.Components.AtkCocoaHelper return; } + // bug #940756 suggests that some elements do not respond to this selector + // so check before sending so it doesn't throw an ObjC exception + if (!((NSObject)titleNsa).RespondsToSelector (selAccessibilityServesAsTitleForUIElements)) { + return; + } + IntPtr ptr = Messaging.IntPtr_objc_msgSend (titleNsa.Handle, selAccessibilityServesAsTitleForUIElements_Handle); using (var array = Runtime.GetNSObject<NSArray> (ptr)) { if (array == null) diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/Formats/Sublime3Format.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/Formats/Sublime3Format.cs index 7c76092b57..94bd292793 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/Formats/Sublime3Format.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/Formats/Sublime3Format.cs @@ -340,7 +340,7 @@ namespace MonoDevelop.Ide.Editor.Highlighting break; case 'S': // A non-whitespace character: /[^ \t\r\n\f]/ for (int i = 0; i < table.Length; i++) { - if (" \\t\\r\\n\\f".Contains ((char)i)) + if (" \\t\\r\\n\\f".IndexOf ((char)i) != -1) continue; table [i] = negativeGroup ? -1 : 1; } @@ -432,7 +432,7 @@ namespace MonoDevelop.Ide.Editor.Highlighting { for (int i = 0; i < table.Length; i++) { var cat = char.GetUnicodeCategory ((char)i); - if (categories.Contains (cat)) { + if (categories.IndexOf (cat) != -1) { table [i] = negativeGroup ? -1 : 1; } } @@ -562,7 +562,7 @@ namespace MonoDevelop.Ide.Editor.Highlighting void AddChar (StringBuilder result, char ch) { - if ("[]\\".Contains (ch)) { + if ("[]\\".IndexOf (ch) != -1) { result.Append ('\\'); result.Append (ch); return; diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Components/InfoBar.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Components/InfoBar.cs index 157cf72bb9..d34803143b 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Components/InfoBar.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Components/InfoBar.cs @@ -55,8 +55,17 @@ namespace MonoDevelop.Ide.Gui.Components mainBox.PackStart (new ImageView (ImageService.GetIcon (Stock.Information, Gtk.IconSize.Menu)), marginLeft: 11); mainBox.PackStart (descriptionLabel = new Label (description)); + int firstItem = 0; if (items.Length > 0 && items[0].Kind == InfoBarItemKind.Hyperlink) { + firstItem = 1; + var link = new InfoBarLink { + Text = items [0].Title, + }; + link.AddAction (items [0].Action); + if (items [0].CloseAfter) + link.AddAction (() => Dispose ()); mainBox.PackStart (new Label ("–")); + mainBox.PackStart (link); } var closeButton = new InfoBarCloseButton { @@ -65,7 +74,10 @@ namespace MonoDevelop.Ide.Gui.Components }; closeButton.AddAction (() => Dispose ()); - foreach (var item in items) { + var widgets = new List<Widget> (items.Length); + + for (int i = items.Length - 1; i >= firstItem; i--) { + var item = items [i]; // TODO: abstract this into a factory. Widget toAdd = null; switch (item.Kind) @@ -101,10 +113,12 @@ namespace MonoDevelop.Ide.Gui.Components } if (toAdd != null) - mainBox.PackStart (toAdd); + widgets.Add (toAdd); } mainBox.PackEnd (closeButton); + foreach (var widget in widgets) + mainBox.PackEnd (widget); if (IdeApp.Preferences == null || IdeApp.Preferences.UserInterfaceTheme == Theme.Light) { Content = new FrameBox (mainBox) { diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Documents/DocumentManager.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Documents/DocumentManager.cs index 80a607ed29..9fa9964212 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Documents/DocumentManager.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Documents/DocumentManager.cs @@ -694,14 +694,6 @@ namespace MonoDevelop.Ide.Gui.Documents navigator.JumpToLine (fileInfo.Line, fileInfo.Column);*/ } - Document FindDocument (IWorkbenchWindow window) - { - foreach (Document doc in Documents) - if (doc.Window == window) - return doc; - return null; - } - void WatchDocument (Document doc) { if (doc.IsFile) { diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Pads.ProjectPad/FolderNodeBuilder.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Pads.ProjectPad/FolderNodeBuilder.cs index dcf9e34ad0..281bf70cbe 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Pads.ProjectPad/FolderNodeBuilder.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Pads.ProjectPad/FolderNodeBuilder.cs @@ -91,7 +91,8 @@ namespace MonoDevelop.Ide.Gui.Pads.ProjectPad continue; if (file.Subtype != Subtype.Directory) { - if (file.DependsOnFile != null) + // If file depends on something other than a directory, continue + if (file.DependsOnFile != null && file.DependsOnFile.Subtype != Subtype.Directory) continue; dir = file.IsLink diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/MessageService.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/MessageService.cs index dd6b82f1fc..f2f29168a8 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/MessageService.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/MessageService.cs @@ -661,6 +661,7 @@ namespace MonoDevelop.Ide public string Text { get; set; } public string SecondaryText { get; set; } + public string HelpUrl { get; set; } public bool AllowApplyToAll { get; set; } public int DefaultButton { get; set; } public CancellationToken CancellationToken { get; private set; } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/RootWorkspace.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/RootWorkspace.cs index 4f8628cf0f..9ea10d064e 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/RootWorkspace.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/RootWorkspace.cs @@ -530,7 +530,7 @@ namespace MonoDevelop.Ide await SavePreferencesAsync (); if (closeProjectFiles && documentManager != null) { - foreach (Document doc in documentManager.Documents.ToArray ()) { + foreach (Document doc in documentManager.Documents) { if (!await doc.Close (force)) return false; } @@ -565,8 +565,11 @@ namespace MonoDevelop.Ide if (RequestItemUnload (item)) { if (closeItemFiles && documentManager != null) { - var projects = item.GetAllItems<Project> (); - foreach (Document doc in documentManager.Documents.Where (d => d.Owner != null && projects.Contains (d.Owner)).ToArray ()) { + var projects = new Lazy<List<Project>> (() => item.GetAllItems<Project> ().ToList ()); + foreach (Document doc in documentManager.Documents) { + if (doc.Owner is null || !projects.Value.Contains (doc.Owner)) + continue; + if (!await doc.Close ()) return; } diff --git a/main/tests/MacPlatform.Tests/CoreFoundationTests.cs b/main/tests/MacPlatform.Tests/CoreFoundationTests.cs index 462af84a36..d685170e24 100644 --- a/main/tests/MacPlatform.Tests/CoreFoundationTests.cs +++ b/main/tests/MacPlatform.Tests/CoreFoundationTests.cs @@ -43,69 +43,6 @@ namespace MacPlatform.Tests MonoDevelop.MacInterop.CoreFoundation.Release (testString); } - - [Test] - public static void TestURL () - { - string test = "http://www.monodevelop.org"; - IntPtr testUrl = MonoDevelop.MacInterop.CoreFoundation.CreatePathUrl (test); - - Assert.AreEqual (MonoDevelop.MacInterop.CoreFoundation.UrlToPath (testUrl), test); - - MonoDevelop.MacInterop.CoreFoundation.Release (testUrl); - } - - static string plistFile = Path.Combine (Util.TestsRootDir, "test-projects", "mac-platform", "Info.plist.in"); - - [Test] - public void TestApplicationUrls () - { - using (var helper = new PListFile ()) { - string [] results = MonoDevelop.MacInterop.CoreFoundation.GetApplicationUrls (helper.FilePath, MonoDevelop.MacInterop.CoreFoundation.LSRolesMask.All); - - Assert.Greater (results.Length, 0); - } - } - - [Test] - public void TestApplicationUrl () - { - using (var helper = new PListFile ()) { - string result = MonoDevelop.MacInterop.CoreFoundation.GetApplicationUrl (helper.FilePath, MonoDevelop.MacInterop.CoreFoundation.LSRolesMask.All); - - Assert.NotNull (result); - } - } - - [Test] - public void TestApplicationUrlOnPListIn () - { - string [] results = MonoDevelop.MacInterop.CoreFoundation.GetApplicationUrls (plistFile, MonoDevelop.MacInterop.CoreFoundation.LSRolesMask.All); - - Assert.AreEqual (0, results.Length); - - string result = MonoDevelop.MacInterop.CoreFoundation.GetApplicationUrl (plistFile, MonoDevelop.MacInterop.CoreFoundation.LSRolesMask.All); - - Assert.Null (result); - } - - class PListFile : IDisposable - { - readonly string dir = MonoDevelop.Core.FileService.CreateTempDirectory (); - public string FilePath { get; } - - public PListFile () - { - FilePath = Path.Combine (dir, "Info.plist"); - File.Copy (plistFile, FilePath, true); - } - - public void Dispose () - { - if (Directory.Exists (dir)) - Directory.Delete (dir, true); - } - } } } diff --git a/main/tests/MacPlatform.Tests/MacPlatformTest.cs b/main/tests/MacPlatform.Tests/MacPlatformTest.cs index c285aac1c5..a06feaddee 100644 --- a/main/tests/MacPlatform.Tests/MacPlatformTest.cs +++ b/main/tests/MacPlatform.Tests/MacPlatformTest.cs @@ -206,6 +206,18 @@ namespace MacPlatform.Tests Assert.That (stacktrace, Contains.Substring ("at MonoDevelop.MacIntegration.MacPlatformService.HandleUncaughtException")); } + + [Test] + public void GetBrowsers () + { + var browsers = IdeServices.DesktopService.GetApplications ("https://localhost"); + Assert.NotNull (browsers); + Assert.That (browsers.Count (), Is.AtLeast (1)); + if (Directory.Exists ("/Applications/Safari.app")) + Assert.True (browsers.Any (x => x.DisplayName.Contains ("Safari")), "Safari is installed but wasn't returned by GetApplications()"); + if (Directory.Exists ("/Applications/Google Chrome.app")) + Assert.True (browsers.Any (x => x.DisplayName.Contains ("Google Chrome")), "Google Chrome is installed but wasn't returned by GetApplications()"); + } } } diff --git a/version-checks b/version-checks index 896eae1451..a0523a8256 100644 --- a/version-checks +++ b/version-checks @@ -17,7 +17,7 @@ DEP[0]=md-addins DEP_NAME[0]=MDADDINS DEP_PATH[0]=${top_srcdir}/../md-addins DEP_MODULE[0]=git@github.com:xamarin/md-addins.git -DEP_NEEDED_VERSION[0]=3d83b2aea8023b01d253ef3d3f89fe0b4e08cd90 +DEP_NEEDED_VERSION[0]=3d2b45809b28a92825732240bea2d6f33cb6c44e DEP_BRANCH_AND_REMOTE[0]="master origin/master" # heap-shot |