diff options
Diffstat (limited to 'main/src')
22 files changed, 277 insertions, 120 deletions
diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Completion/CompletionProvider/ProtocolMemberCompletionProvider.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Completion/CompletionProvider/ProtocolMemberCompletionProvider.cs index e707916017..b52b291c29 100644 --- a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Completion/CompletionProvider/ProtocolMemberCompletionProvider.cs +++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Completion/CompletionProvider/ProtocolMemberCompletionProvider.cs @@ -97,6 +97,22 @@ namespace MonoDevelop.CSharp.Completion.Provider return; var startToken = token.GetPreviousTokenIfTouchingWord (position); + + // We're marking the context as exclusive, to resolve the + // regression in the new editor that appeared since introducing + // Roslyn's provider mechanism. The actual override completion + // provider took precedence and therefore this one was ignored. + // We submitted a PR for roslyn, that allows multiple providers, + // marked as exclusive, to render suggestions. + // See: https://github.com/dotnet/roslyn/pull/36088 + // + // Important note, though, we should only set exclusivity when + // we are actually competing with an override provider - that + // is, if the token before this one is the override keyword. If + // it's not, we're not competing, and therefore shouldn't set + // this to true, as we'll be the ones stealing the spotlight. + context.IsExclusive = startToken.IsKind (SyntaxKind.OverrideKeyword); + TryDetermineReturnType (startToken, model, cancellationToken, out ITypeSymbol returnType, out SyntaxToken tokenBeforeReturnType); if (returnType == null) { var enclosingType = model.GetEnclosingSymbol (position, cancellationToken) as INamedTypeSymbol; @@ -155,7 +171,7 @@ namespace MonoDevelop.CSharp.Completion.Provider pDict = pDict.Add ("InsertionText", sb.ToString ()); pDict = pDict.Add ("DescriptionMarkup", "- <span foreground=\"darkgray\" size='small'>" + inlineDescription + "</span>"); pDict = pDict.Add ("Description", await GenerateQuickInfo (semanticModel, position, m, cancellationToken)); - pDict = pDict.Add ("DeclarationBegin", declarationBegin.ToString()); + pDict = pDict.Add ("DeclarationBegin", declarationBegin.ToString ()); var tags = ImmutableArray<string>.Empty.Add ("NewMethod"); var completionData = CompletionItem.Create (m.Name, sortText: m.ToSignatureDisplayString (), properties: pDict, rules: ProtocolCompletionRules, tags: tags, inlineDescription: inlineDescription); @@ -468,5 +484,23 @@ namespace MonoDevelop.CSharp.Completion.Provider .WithIsSealed (isSealed);*/ return overrideToken.IsKind (SyntaxKind.OverrideKeyword) && IsOnStartLine (text, startLine, overrideToken.Parent.SpanStart); } + + public override bool ShouldTriggerCompletion (SourceText text, int position, CompletionTrigger trigger, Microsoft.CodeAnalysis.Options.OptionSet options) + { + // This method is overridden because Roslyn's Completion Service calls us, in cases + // where the change kind is an Insertion or Deletion. This mimics the behavior + // of the OverrideCompletionProvider provided by Roslyn, so we'll now get called + // in all the same cases as that one. The goal is to also display our protocol member + // completion suggestions, even when the user types "overrides" and presses space. + // See here: http://source.roslyn.io/#Microsoft.CodeAnalysis.Features/Completion/CompletionServiceWithProviders.cs,231 + switch (trigger.Kind) { + case CompletionTriggerKind.Insertion when position > 0: + var insertedCharacterPosition = position - 1; + return Microsoft.CodeAnalysis.CSharp.Completion.Providers.CompletionUtilities.IsTriggerAfterSpaceOrStartOfWordCharacter (text, insertedCharacterPosition, options); + + default: + return false; + } + } } }
\ No newline at end of file diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Formatting/CSharpFormatter.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Formatting/CSharpFormatter.cs index 9b3b4ca8e4..bf0d3cbef8 100644 --- a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Formatting/CSharpFormatter.cs +++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Formatting/CSharpFormatter.cs @@ -1,29 +1,29 @@ -//
-// CSharpFormatter.cs
-//
-// Author:
-// Mike Krüger <mkrueger@novell.com>
-//
-// Copyright (c) 2009 Novell, Inc (http://www.novell.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
+// +// CSharpFormatter.cs +// +// Author: +// Mike Krüger <mkrueger@novell.com> +// +// Copyright (c) 2009 Novell, Inc (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + using System; using System.Collections.Generic; using System.Threading; @@ -50,6 +50,7 @@ using MonoDevelop.CSharp.OptionProvider; using Microsoft.VisualStudio.CodingConventions; using System.Linq; using System.Collections.Immutable; +using System.Runtime.CompilerServices; namespace MonoDevelop.CSharp.Formatting { @@ -81,7 +82,7 @@ namespace MonoDevelop.CSharp.Formatting var endSegment = startLine != endLine ? editor.GetLine (endLine) : startSegment; if (endSegment == null) return; -
+ try { var document = context.AnalysisDocument; @@ -93,15 +94,15 @@ namespace MonoDevelop.CSharp.Formatting formattingRules.Add (ContainedDocumentPreserveFormattingRule.Instance); formattingRules.AddRange (Formatter.GetDefaultFormattingRules (document)); - var workspace = document.Project.Solution.Workspace;
+ var workspace = document.Project.Solution.Workspace; var root = await document.GetSyntaxRootAsync (cancellationToken).ConfigureAwait (false); - var options = await document.GetOptionsAsync (cancellationToken).ConfigureAwait (false);
+ var options = await document.GetOptionsAsync (cancellationToken).ConfigureAwait (false); var changes = Formatter.GetFormattedTextChanges ( root, new TextSpan [] { new TextSpan (startSegment.Offset, endSegment.EndOffset - startSegment.Offset) }, workspace, options, formattingRules, cancellationToken); if (changes == null) - return;
+ return; await Runtime.RunInMainThread (delegate { editor.ApplyTextChanges (changes); editor.FixVirtualIndentation (); @@ -159,6 +160,9 @@ namespace MonoDevelop.CSharp.Formatting { readonly OptionSet optionSet; readonly ICodingConventionsSnapshot codingConventionsSnapshot; + private static readonly ConditionalWeakTable<IReadOnlyDictionary<string, object>, IReadOnlyDictionary<string, string>> s_convertedDictionaryCache = + new ConditionalWeakTable<IReadOnlyDictionary<string, object>, IReadOnlyDictionary<string, string>> (); + public DocumentOptions (OptionSet optionSet, ICodingConventionsSnapshot codingConventionsSnapshot) { @@ -166,20 +170,24 @@ namespace MonoDevelop.CSharp.Formatting this.codingConventionsSnapshot = codingConventionsSnapshot; } - public bool TryGetDocumentOption (OptionKey option, OptionSet underlyingOptions, out object value) + public bool TryGetDocumentOption (OptionKey option, out object value) { if (codingConventionsSnapshot != null) { var editorConfigPersistence = option.Option.StorageLocations.OfType<IEditorConfigStorageLocation> ().SingleOrDefault (); if (editorConfigPersistence != null) { - - var tempRawConventions = codingConventionsSnapshot.AllRawConventions; - // HACK: temporarly map our old Dictionary<string, object> to a Dictionary<string, string>. This will go away in a future commit. - // see https://github.com/dotnet/roslyn/commit/6a5be42f026f8d0432cfe8ee7770ff8f6be01bd6#diff-626aa9dd2f6e07eafa8eac7ddb0eb291R34 - var allRawConventions = ImmutableDictionary.CreateRange (tempRawConventions.Select (c => Roslyn.Utilities.KeyValuePairUtil.Create (c.Key, c.Value.ToString ()))); + // Temporarly map our old Dictionary<string, object> to a Dictionary<string, string>. This can go away once we either + // eliminate the legacy editorconfig support, or we change IEditorConfigStorageLocation.TryGetOption to take + // some interface that lets us pass both the Dictionary<string, string> we get from the new system, and the + // Dictionary<string, object> from the old system. + // + // We cache this with a conditional weak table so we're able to maintain the assumptions in EditorConfigNamingStyleParser + // that the instance doesn't regularly change and thus can be used for further caching + var allRawConventions = s_convertedDictionaryCache.GetValue ( + codingConventionsSnapshot.AllRawConventions, + d => ImmutableDictionary.CreateRange (d.Select (c => KeyValuePairUtil.Create (c.Key, c.Value.ToString ())))); try { - var underlyingOption = underlyingOptions.GetOption (option); - if (editorConfigPersistence.TryGetOption (underlyingOption, allRawConventions, option.Option.Type, out value)) + if (editorConfigPersistence.TryGetOption (allRawConventions, option.Option.Type, out value)) return true; } catch (Exception ex) { LoggingService.LogError ("Error while getting editor config preferences.", ex); @@ -188,10 +196,6 @@ namespace MonoDevelop.CSharp.Formatting } var result = optionSet.GetOption (option); - if (result == underlyingOptions.GetOption (option)) { - value = null; - return false; - } value = result; return true; } @@ -210,7 +214,7 @@ namespace MonoDevelop.CSharp.Formatting public override object GetOption (OptionKey optionKey) { - if (optionsProvider.TryGetDocumentOption (optionKey, fallbackOptionSet, out object value)) + if (optionsProvider.TryGetDocumentOption (optionKey, out object value)) return value; return fallbackOptionSet.GetOption (optionKey); } diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.OptionProvider/CSharpDocumentOptionsProvider.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.OptionProvider/CSharpDocumentOptionsProvider.cs index 0ff4f59c7f..b48aca4ce4 100644 --- a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.OptionProvider/CSharpDocumentOptionsProvider.cs +++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.OptionProvider/CSharpDocumentOptionsProvider.cs @@ -29,6 +29,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Options; +using Roslyn.Utilities; using MonoDevelop.CSharp.Formatting; using MonoDevelop.Ide.Gui.Content; using MonoDevelop.Ide.TypeSystem; @@ -40,6 +41,7 @@ using System.Linq; using MonoDevelop.Ide.Editor; using System.Collections.Generic; using System.Collections.Immutable; +using System.Runtime.CompilerServices; namespace MonoDevelop.CSharp.OptionProvider { @@ -87,6 +89,8 @@ namespace MonoDevelop.CSharp.OptionProvider TextStylePolicy TextPolicy => textpolicy ?? (textpolicy = policyBag?.Get<TextStylePolicy> (types) ?? PolicyService.InvariantPolicies?.Get<TextStylePolicy> (types)); readonly ICodingConventionsSnapshot codingConventionsSnapshot; + private static readonly ConditionalWeakTable<IReadOnlyDictionary<string, object>, IReadOnlyDictionary<string, string>> s_convertedDictionaryCache = + new ConditionalWeakTable<IReadOnlyDictionary<string, object>, IReadOnlyDictionary<string, string>> (); public DocumentOptions (PolicyBag policyBag, ICodingConventionsSnapshot codingConventionsSnapshot) { @@ -94,20 +98,24 @@ namespace MonoDevelop.CSharp.OptionProvider this.codingConventionsSnapshot = codingConventionsSnapshot; } - public bool TryGetDocumentOption (OptionKey option, OptionSet underlyingOptions, out object value) + public bool TryGetDocumentOption (OptionKey option, out object value) { if (codingConventionsSnapshot != null) { var editorConfigPersistence = option.Option.StorageLocations.OfType<IEditorConfigStorageLocation> ().SingleOrDefault (); if (editorConfigPersistence != null) { - - var tempRawConventions = codingConventionsSnapshot.AllRawConventions; - // HACK: temporarly map our old Dictionary<string, object> to a Dictionary<string, string>. This will go away in a future commit. - // see https://github.com/dotnet/roslyn/commit/6a5be42f026f8d0432cfe8ee7770ff8f6be01bd6#diff-626aa9dd2f6e07eafa8eac7ddb0eb291R34 - var allRawConventions = ImmutableDictionary.CreateRange (tempRawConventions.Select (c => Roslyn.Utilities.KeyValuePairUtil.Create (c.Key, c.Value.ToString ()))); + // Temporarly map our old Dictionary<string, object> to a Dictionary<string, string>. This can go away once we either + // eliminate the legacy editorconfig support, or we change IEditorConfigStorageLocation.TryGetOption to take + // some interface that lets us pass both the Dictionary<string, string> we get from the new system, and the + // Dictionary<string, object> from the old system. + // + // We cache this with a conditional weak table so we're able to maintain the assumptions in EditorConfigNamingStyleParser + // that the instance doesn't regularly change and thus can be used for further caching + var allRawConventions = s_convertedDictionaryCache.GetValue ( + codingConventionsSnapshot.AllRawConventions, + d => ImmutableDictionary.CreateRange (d.Select (c => KeyValuePairUtil.Create (c.Key, c.Value.ToString ())))); try { - var underlyingOption = Policy.OptionSet.GetOption (option); - if (editorConfigPersistence.TryGetOption (underlyingOption, allRawConventions, option.Option.Type, out value)) + if (editorConfigPersistence.TryGetOption (allRawConventions, option.Option.Type, out value)) return true; } catch (Exception ex) { LoggingService.LogError ("Error while getting editor config preferences.", ex); @@ -141,10 +149,6 @@ namespace MonoDevelop.CSharp.OptionProvider } var result = Policy.OptionSet.GetOption (option); - if (result == underlyingOptions.GetOption (option)) { - value = null; - return false; - } value = result; return true; } diff --git a/main/src/addins/MacPlatform/MacPlatform.cs b/main/src/addins/MacPlatform/MacPlatform.cs index 1629226be7..06754b11a1 100644 --- a/main/src/addins/MacPlatform/MacPlatform.cs +++ b/main/src/addins/MacPlatform/MacPlatform.cs @@ -286,11 +286,7 @@ namespace MonoDevelop.MacIntegration public override Xwt.Toolkit LoadNativeToolkit () { - var path = Path.GetDirectoryName (GetType ().Assembly.Location); - Assembly.LoadFrom (Path.Combine (path, "Xwt.XamMac.dll")); - - // Also calls NSApplication.Init(); - var loaded = Xwt.Toolkit.Load (Xwt.ToolkitType.XamMac); + var loaded = NativeToolkitHelper.LoadCocoa (); loaded.RegisterBackend<Xwt.Backends.IDialogBackend, ThemedMacDialogBackend> (); loaded.RegisterBackend<Xwt.Backends.IWindowBackend, ThemedMacWindowBackend> (); @@ -347,6 +343,15 @@ namespace MonoDevelop.MacIntegration if (MacSystemInformation.OsVersion >= MacSystemInformation.Sierra) NSWindow.AllowsAutomaticWindowTabbing = false; + + // At this point, Cocoa should have been initialized; it is initialized along with Gtk+ at the beginning of IdeStartup.Run + // If LaunchReason is still Unknown at this point, it means we have missed the NSApplicationDidLaunch notification for some reason and + // we fall back to it being a Normal startup to unblock anything waiting for that notification. + if (IdeApp.LaunchReason == IdeApp.LaunchType.Unknown) { + LoggingService.LogWarning ("Missed NSApplicationDidLaunch notification, assuming normal startup"); + IdeApp.LaunchReason = IdeApp.LaunchType.Normal; + } + return loaded; } diff --git a/main/src/addins/MonoDevelop.SourceEditor2/VSEditor/TextEditorInitializationService.cs b/main/src/addins/MonoDevelop.SourceEditor2/VSEditor/TextEditorInitializationService.cs index e5e07bf5ee..6567740e6b 100644 --- a/main/src/addins/MonoDevelop.SourceEditor2/VSEditor/TextEditorInitializationService.cs +++ b/main/src/addins/MonoDevelop.SourceEditor2/VSEditor/TextEditorInitializationService.cs @@ -66,6 +66,9 @@ namespace Microsoft.VisualStudio.Text.Editor.Implementation internal ITextSearchService2 TextSearchService { get; set; }
[Import]
+ internal IFeatureServiceFactory FeatureServiceFactory { get; set; }
+
+ [Import]
internal ITextStructureNavigatorSelectorService TextStructureNavigatorSelectorService { get; set; }
[Import]
@@ -140,6 +143,8 @@ namespace Microsoft.VisualStudio.Text.Editor.Implementation view.Initialize(viewModel, roles, this.EditorOptionsFactoryService.GlobalOptions, this);
view.Properties.AddProperty(typeof(MonoDevelop.Ide.Editor.TextEditor), textEditor);
+ FeatureServiceFactory.GetOrCreate(view).Disable(PredefinedEditorFeatureNames.AsyncCompletion, EmptyFeatureController.Instance);
+
this.TextViewCreated?.Invoke(this, new TextViewCreatedEventArgs(view));
return view;
@@ -191,5 +196,14 @@ namespace Microsoft.VisualStudio.Text.Editor.Implementation this.OrderedSpaceReservationManagerDefinitions.Add(orderedManagers[i].Metadata.Name, i);
}
}
+
+ sealed class EmptyFeatureController : IFeatureController
+ {
+ internal static readonly EmptyFeatureController Instance = new EmptyFeatureController();
+
+ private EmptyFeatureController()
+ {
+ }
+ }
}
}
diff --git a/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor.Cocoa/Properties/MonoDevelop.TextEditor.Cocoa.addin.xml b/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor.Cocoa/Properties/MonoDevelop.TextEditor.Cocoa.addin.xml index 7ec39438a2..3295568c79 100644 --- a/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor.Cocoa/Properties/MonoDevelop.TextEditor.Cocoa.addin.xml +++ b/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor.Cocoa/Properties/MonoDevelop.TextEditor.Cocoa.addin.xml @@ -87,8 +87,10 @@ <StockIcon stockid="vs-signature-help-next" resource="go-down-16.png" size="Menu" imageid="{95fdedcb-dc13-48a8-8165-ed1fff877d9a}#2" /> </Extension> <Extension path = "/MonoDevelop/TextEditor/CommandMapping"> + <!-- + Don't re-add this! See bug 937834 for more details. Basically let native editor handle this. <Map id="MonoDevelop.Ide.Commands.EditCommands.DeleteKey" argsType="Microsoft.VisualStudio.Text.Editor.Commanding.Commands.BackspaceKeyCommandArgs" /> - + --> <Map id="MonoDevelop.Ide.Commands.SearchCommands.Find" argsType="Microsoft.VisualStudio.Text.Editor.Commanding.Commands.FindCommandArgs" /> <Map id="MonoDevelop.Ide.Commands.SearchCommands.FindNext" argsType="Microsoft.VisualStudio.Text.Editor.Commanding.Commands.FindNextCommandArgs" /> <Map id="MonoDevelop.Ide.Commands.SearchCommands.FindPrevious" argsType="Microsoft.VisualStudio.Text.Editor.Commanding.Commands.FindPreviousCommandArgs" /> diff --git a/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor/TextViewContent.cs b/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor/TextViewContent.cs index 45214893dc..5618666b3a 100644 --- a/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor/TextViewContent.cs +++ b/main/src/addins/MonoDevelop.TextEditor/MonoDevelop.TextEditor/TextViewContent.cs @@ -238,12 +238,6 @@ namespace MonoDevelop.TextEditor textBufferRegistration = IdeServices.TypeSystemService.RegisterOpenDocument (Owner, FilePath, TextBuffer); } - protected override void OnGrabFocus (DocumentView view) - { - DefaultSourceEditorOptions.SetUseAsyncCompletion (true); - base.OnGrabFocus (view); - } - protected override void OnFileNameChanged () { base.OnFileNameChanged (); diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProject.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProject.cs index d103fe3864..b971b89aa9 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProject.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProject.cs @@ -1091,7 +1091,7 @@ namespace MonoDevelop.Projects context.LogVerbosity = MSBuildVerbosity.Quiet; context.GlobalProperties.SetValue ("Silent", true); - var result = await RunTarget (monitor, "ResolveAssemblyReferences", configuration, context); + var result = await RunTargetInternal (monitor, "ResolveAssemblyReferences", configuration, context); refs = result.Items.Select (i => new AssemblyReference (i.Include, i.Metadata)).ToList (); @@ -1152,7 +1152,7 @@ namespace MonoDevelop.Projects context.LoadReferencedProjects = false; context.LogVerbosity = MSBuildVerbosity.Quiet; - var result = await RunTarget (monitor, "ResolvePackageDependenciesDesignTime", configuration, context); + var result = await RunTargetInternal (monitor, "ResolvePackageDependenciesDesignTime", configuration, context); if (result == null) return new List<PackageDependency> (); diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs index e53cda474c..7e62055fe7 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs @@ -706,7 +706,7 @@ namespace MonoDevelop.Projects ctx.BuilderQueue = BuilderQueue.ShortOperations; ctx.LogVerbosity = MSBuildVerbosity.Quiet; - var evalResult = await project.RunTarget (monitor, dependsList, config.Selector, ctx); + var evalResult = await project.RunTargetInternal (monitor, dependsList, config.Selector, ctx); if (evalResult != null && evalResult.Items != null) { result = ProcessMSBuildItems (evalResult.Items, project); } @@ -1251,6 +1251,13 @@ namespace MonoDevelop.Projects /// </param> public Task<TargetEvaluationResult> RunTarget (ProgressMonitor monitor, string target, ConfigurationSelector configuration, TargetEvaluationContext context = null) { + return BindTask<TargetEvaluationResult> (cancelToken => { + return RunTargetInternal (monitor.WithCancellationToken (cancelToken), target, configuration, context); + }); + } + + internal Task<TargetEvaluationResult> RunTargetInternal (ProgressMonitor monitor, string target, ConfigurationSelector configuration, TargetEvaluationContext context = null) + { // Initialize the evaluation context. This initialization is shared with FastCheckNeedsBuild. // Extenders will override OnConfigureTargetEvaluationContext to add custom properties and do other // initializations required by MSBuild. @@ -1865,7 +1872,7 @@ namespace MonoDevelop.Projects protected override async Task<BuildResult> OnBuild (ProgressMonitor monitor, ConfigurationSelector configuration, OperationContext operationContext) { var newContext = operationContext as TargetEvaluationContext ?? new TargetEvaluationContext (operationContext); - return (await RunTarget (monitor, "Build", configuration, newContext)).BuildResult; + return (await RunTargetInternal (monitor, "Build", configuration, newContext)).BuildResult; } async Task<TargetEvaluationResult> RunBuildTarget (ProgressMonitor monitor, ConfigurationSelector configuration, TargetEvaluationContext context) @@ -2250,7 +2257,7 @@ namespace MonoDevelop.Projects protected override async Task<BuildResult> OnClean (ProgressMonitor monitor, ConfigurationSelector configuration, OperationContext buildSession) { var newContext = buildSession as TargetEvaluationContext ?? new TargetEvaluationContext (buildSession); - return (await RunTarget (monitor, "Clean", configuration, newContext)).BuildResult; + return (await RunTargetInternal (monitor, "Clean", configuration, newContext)).BuildResult; } Task<TargetEvaluationResult> RunCleanTarget (ProgressMonitor monitor, ConfigurationSelector configuration, TargetEvaluationContext context) diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/IdeTheme.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/IdeTheme.cs index 04f317bced..49299ad156 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/IdeTheme.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/IdeTheme.cs @@ -71,9 +71,7 @@ namespace MonoDevelop.Components #if MAC // Early init Cocoa through xwt - var path = Path.GetDirectoryName (typeof (IdeTheme).Assembly.Location); - System.Reflection.Assembly.LoadFrom (Path.Combine (path, "Xwt.XamMac.dll")); - var loaded = Xwt.Toolkit.Load (Xwt.ToolkitType.XamMac); + var loaded = NativeToolkitHelper.LoadCocoa (); var disableA11y = Environment.GetEnvironmentVariable ("DISABLE_ATKCOCOA"); if (Platform.IsMac && (NSUserDefaults.StandardUserDefaults.BoolForKey ("com.monodevelop.AccessibilityEnabled") && string.IsNullOrEmpty (disableA11y))) { diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/NativeToolkitHelper.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/NativeToolkitHelper.cs new file mode 100644 index 0000000000..b20bb6c584 --- /dev/null +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/NativeToolkitHelper.cs @@ -0,0 +1,65 @@ +// +// NativeToolkitHelper.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. + +#if MAC +using System; +using System.IO; + +using AppKit; +using Foundation; + +using MonoDevelop.Core; +using MonoDevelop.Ide; + +namespace MonoDevelop.Components.Mac +{ + internal static class NativeToolkitHelper + { + static Xwt.Toolkit toolkit; + internal static Xwt.Toolkit LoadCocoa () + { + if (toolkit != null) { + return toolkit; + } + + var path = Path.GetDirectoryName (typeof (IdeTheme).Assembly.Location); + System.Reflection.Assembly.LoadFrom (Path.Combine (path, "Xwt.XamMac.dll")); + toolkit = Xwt.Toolkit.Load (Xwt.ToolkitType.XamMac); + + NSNotificationCenter.DefaultCenter.AddObserver (NSApplication.DidFinishLaunchingNotification, (note) => { + if (note.UserInfo.TryGetValue (NSApplication.LaunchIsDefaultLaunchKey, out var val)) { + if (val is NSNumber num) { + IdeApp.LaunchReason = num.BoolValue ? IdeApp.LaunchType.Normal : IdeApp.LaunchType.LaunchedFromFileManager; + LoggingService.LogDebug ($"Startup was {IdeApp.LaunchReason}"); + } + } + }); + + return toolkit; + } + } +} +#endif
\ No newline at end of file diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Desktop/PlatformService.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Desktop/PlatformService.cs index f7ba28cf59..f7c685f6e4 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Desktop/PlatformService.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Desktop/PlatformService.cs @@ -107,7 +107,9 @@ namespace MonoDevelop.Ide.Desktop if (Path.IsPathRooted (uri) && File.Exists (uri) && !Core.Text.TextFileUtility.IsBinary (uri)) { return "text/plain"; } - } catch (IOException) {} + }
+ catch (UnauthorizedAccessException) {}
+ catch (IOException) {} return "application/octet-stream"; } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/DefaultSourceEditorOptions.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/DefaultSourceEditorOptions.cs index 2757ac63c8..3d812dfa67 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/DefaultSourceEditorOptions.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/DefaultSourceEditorOptions.cs @@ -993,20 +993,6 @@ namespace MonoDevelop.Ide.Editor } public event EventHandler Changed; - - /// <summary> - /// This is to allow setting UseAsyncCompletion to true for the Cocoa editor and to false for the Gtk editor. - /// Currently Roslyn doesn't allow setting this option per view, so we have to work around. - /// See here for details: https://github.com/dotnet/roslyn/issues/33807 - /// </summary> - internal static void SetUseAsyncCompletion(bool useAsyncCompletion) - { - var asyncCompletionService = Composition.CompositionManager.Instance.GetExportedValue<Microsoft.CodeAnalysis.Editor.IAsyncCompletionService> (); - var field = asyncCompletionService.GetType ().GetField ( - "_newCompletionAPIEnabled", - System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); - field.SetValue (asyncCompletionService, useAsyncCompletion); - } } } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/TextEditorViewContent.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/TextEditorViewContent.cs index 62b604c931..b262e0c3cf 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/TextEditorViewContent.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/TextEditorViewContent.cs @@ -409,11 +409,6 @@ namespace MonoDevelop.Ide.Editor protected override void OnGrabFocus (DocumentView view) { textEditor.GrabFocus (); - try { - DefaultSourceEditorOptions.SetUseAsyncCompletion (false); - } catch (Exception e) { - LoggingService.LogInternalError ("Error while setting up async completion.", e); - } } } }
\ No newline at end of file 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 ef1f5c361f..c01448bdb4 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 @@ -658,10 +658,11 @@ namespace MonoDevelop.Ide.Gui.Documents var offset = info.Offset; if (offset < 0) { var line = textView.TextSnapshot.GetLineFromLineNumber (info.Line - 1); - if (info.Column >= 1) - offset = line.Start + info.Column - 1; - else + if (info.Column >= 1) { + offset = line.Start + Math.Min (info.Column - 1, line.Length); + } else { offset = line.Start; + } } if (editorOperationsFactoryService != null) { var editorOperations = editorOperationsFactoryService.GetEditorOperations (textView); diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Tasks/CommentTasksProvider.Legacy.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Tasks/CommentTasksProvider.Legacy.cs index 044917dd90..b0fa0146e3 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Tasks/CommentTasksProvider.Legacy.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Tasks/CommentTasksProvider.Legacy.cs @@ -156,21 +156,27 @@ namespace MonoDevelop.Ide.Tasks void Context_DocumentParsed (object sender, EventArgs e) { - var pd = context.ParsedDocument; - var project = Controller.Owner as Project; - if (project == null || !(Controller is FileDocumentController fileController)) - return; - ProjectCommentTags tags; - if (!CommentTasksProvider.Legacy.ProjectTags.TryGetValue (project, out tags)) - return; - var token = CommentTasksProvider.Legacy.CancellationToken; - var file = fileController.FilePath; - Task.Run (async () => { - try { - tags.UpdateTags (project, file, await pd.GetTagCommentsAsync (token).ConfigureAwait (false)); - } catch (OperationCanceledException) { - } - }); + try { + var pd = context.ParsedDocument; + if (pd == null) + return; + if (!(Controller is FileDocumentController fileController) || !(Controller.Owner is Project project)) + return; + if (!CommentTasksProvider.Legacy.ProjectTags.TryGetValue (project, out var tags)) + return; + var token = CommentTasksProvider.Legacy.CancellationToken; + var file = fileController.FilePath; + Task.Run (async () => { + try { + tags.UpdateTags (project, file, await pd.GetTagCommentsAsync (token).ConfigureAwait (false)); + } catch (OperationCanceledException) { + } catch (Exception ex) { + LoggingService.LogError ("Error while updating comment tags.", ex); + } + }).Ignore (); + } catch (Exception ex) { + LoggingService.LogInternalError (ex); + } } } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TextPolicyDocumentOptionsProvider.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TextPolicyDocumentOptionsProvider.cs index 1b05fd4fe9..5bc70be2cf 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TextPolicyDocumentOptionsProvider.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TextPolicyDocumentOptionsProvider.cs @@ -68,7 +68,7 @@ namespace MonoDevelop.Ide.TypeSystem this.policy = policy; } - public bool TryGetDocumentOption (OptionKey option, OptionSet underlyingOptions, out object value) + public bool TryGetDocumentOption (OptionKey option, out object value) { if (option.Option == FormattingOptions.UseTabs) { value = !policy.TabsToSpaces; diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.WelcomePage/IWelcomeWindowProvider.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.WelcomePage/IWelcomeWindowProvider.cs index 32ffa1fed5..87cc92387a 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.WelcomePage/IWelcomeWindowProvider.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.WelcomePage/IWelcomeWindowProvider.cs @@ -52,7 +52,7 @@ namespace MonoDevelop.Ide.WelcomePage public interface IWelcomeWindowProvider { Task ShowWindow (WelcomeWindowShowOptions options); - void HideWindow (); + Task HideWindow (); bool IsWindowVisible { get; } Window WindowInstance { get; } } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.WelcomePage/WelcomePageService.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.WelcomePage/WelcomePageService.cs index 31e09571d6..8699251b76 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.WelcomePage/WelcomePageService.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.WelcomePage/WelcomePageService.cs @@ -81,7 +81,14 @@ namespace MonoDevelop.Ide.WelcomePage if (!hideWelcomePage && HasWindowImplementation) { await Runtime.GetService<DesktopService> (); var commandManager = await Runtime.GetService<CommandManager> (); - await ShowWelcomeWindow (new WelcomeWindowShowOptions (false)); + + var reason = await IdeApp.LaunchCompletionSource.Task; + + if (IdeApp.LaunchReason == IdeApp.LaunchType.Normal) { + await ShowWelcomeWindow (new WelcomeWindowShowOptions (false)); + } else if (IdeApp.LaunchReason == IdeApp.LaunchType.Unknown) { + LoggingService.LogInternalError ("LaunchCompletion is still Unknown", new Exception ()); + } } } @@ -105,14 +112,13 @@ namespace MonoDevelop.Ide.WelcomePage } } - public static void HideWelcomePageOrWindow () + public static async void HideWelcomePageOrWindow () { if (WelcomeWindowProvider != null) { - WelcomeWindowProvider.HideWindow (); + await WelcomeWindowProvider.HideWindow (); } else { HideWelcomePage (true); } - visible = false; } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj index eea0b0b9c2..35329ccb92 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj @@ -4251,6 +4251,7 @@ <Compile Include="MonoDevelop.Components.Docking\SplitterWidgetWrapper.cs" /> <Compile Include="MonoDevelop.Components.Docking\SplitterMacHostWidget.cs" /> <Compile Include="MonoDevelop.Components\Mac\DragEventTrapView.cs" /> + <Compile Include="MonoDevelop.Components\Mac\NativeToolkitHelper.cs" /> </ItemGroup> <ItemGroup Condition="'$(Configuration)' == 'DebugMac' OR '$(Configuration)' == 'ReleaseMac'"> <Compile Include="MonoDevelop.Components\Mac\KeyCodes.cs" /> diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/Ide.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/Ide.cs index 6be545748b..da8982d467 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/Ide.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/Ide.cs @@ -180,6 +180,27 @@ namespace MonoDevelop.Ide } } + public enum LaunchType + { + Unknown, + Normal, + LaunchedFromFileManager + } + + static LaunchType launchType = LaunchType.Unknown; + public static LaunchType LaunchReason { + get => launchType; + internal set { + launchType = value; + + if (!LaunchCompletionSource.TrySetResult (value)) { + LoggingService.LogWarning ($"LaunchReason is already set to {launchType}."); + } + } + } + + internal static TaskCompletionSource<LaunchType> LaunchCompletionSource { get; } = new TaskCompletionSource<LaunchType>(); + public static async Task Initialize (ProgressMonitor monitor, bool hideWelcomePage = false) { // Already done in IdeSetup, but called again since unit tests don't use IdeSetup. @@ -295,6 +316,11 @@ namespace MonoDevelop.Ide AddinManager.AddExtensionNodeHandler ("/MonoDevelop/Ide/StartupHandlers", OnExtensionChanged); } + public static Task EnsureInitializedAsync () + { + return initializationTask.Task; + } + public static void BringToFront () { Initialized += (sender, e) => { diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeStartup.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeStartup.cs index 0a1444164a..e4318f6f7b 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeStartup.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeStartup.cs @@ -117,6 +117,13 @@ namespace MonoDevelop.Ide IdeTheme.InitializeGtk (BrandingService.ApplicationName, ref args); startupInfo = new StartupInfo (options, args); + if (startupInfo.HasFiles) { + // If files are present, consider started from the commandline as being the same as file manager. + // On macOS, we need to wait until the DidFinishLaunching notification to find out we were launched from the Finder + IdeApp.LaunchReason = IdeApp.LaunchType.LaunchedFromFileManager; + } else if (!Platform.IsMac) { + IdeApp.LaunchReason = IdeApp.LaunchType.Normal; + } IdeApp.Customizer = options.IdeCustomizer ?? new IdeCustomizer (); try { |