diff options
author | Kirill Osenkov <github@osenkov.com> | 2018-03-30 03:43:14 +0300 |
---|---|---|
committer | Kirill Osenkov <github@osenkov.com> | 2018-03-30 03:43:14 +0300 |
commit | cf974b266fb428d846e2e16a25a4eeb8f635c26f (patch) | |
tree | e1eac97e4a4e2c2f53db710057f90f2fbf7c1369 | |
parent | 53c8aef50f2f742ebc9b8743d0ed3175adacc9aa (diff) |
Version 15.0.25
Update to Editor 15.7.153-preview-g7d0635149a
12 files changed, 165 insertions, 113 deletions
diff --git a/src/Core/Impl/ContentType/ContentTypeImpl.cs b/src/Core/Impl/ContentType/ContentTypeImpl.cs index 5a05136..1a6e3b9 100644 --- a/src/Core/Impl/ContentType/ContentTypeImpl.cs +++ b/src/Core/Impl/ContentType/ContentTypeImpl.cs @@ -14,8 +14,8 @@ namespace Microsoft.VisualStudio.Utilities.Implementation internal partial class ContentTypeImpl : IContentType { private readonly string name; - private readonly static IReadOnlyList<ContentTypeImpl> emptyBaseTypes = new ContentTypeImpl[0]; - private IReadOnlyList<ContentTypeImpl> baseTypeList = emptyBaseTypes; + private readonly static ContentTypeImpl[] emptyBaseTypes = Array.Empty<ContentTypeImpl>(); + private ContentTypeImpl[] baseTypeList = emptyBaseTypes; internal ContentTypeImpl(string name, string mimeType = null, IEnumerable<string> baseTypes = null) { @@ -38,15 +38,15 @@ namespace Microsoft.VisualStudio.Utilities.Implementation public bool IsOfType(string type) { - if (String.Compare(type, this.name, StringComparison.OrdinalIgnoreCase) == 0) + if (string.Compare(type, this.name, StringComparison.OrdinalIgnoreCase) == 0) { return true; } else { - foreach (IContentType baseType in this.baseTypeList) + for (int i = 0; i < this.baseTypeList.Length; i++) { - if (baseType.IsOfType(type)) + if (this.baseTypeList[i].IsOfType(type)) { return true; } @@ -114,7 +114,7 @@ namespace Microsoft.VisualStudio.Utilities.Implementation { try { - if (this.baseTypeList.Count != 0) + if (this.baseTypeList.Length != 0) { this.state = VisitState.Visiting; foreach (var baseType in this.baseTypeList) @@ -173,7 +173,7 @@ namespace Microsoft.VisualStudio.Utilities.Implementation get { return (this.UnprocessedBaseTypes == null) && (this.baseTypeList != null) && - ((this.baseTypeList.Count == 0) + ((this.baseTypeList.Length == 0) ? (object.ReferenceEquals(this.baseTypeList, ContentTypeImpl.emptyBaseTypes) && (this.state == VisitState.Visited)) : (this.state == VisitState.NotVisited)); } @@ -181,7 +181,7 @@ namespace Microsoft.VisualStudio.Utilities.Implementation internal bool IsCheckedForCycles { - get { return (this.state == VisitState.Visited) && (this.UnprocessedBaseTypes == null) && (object.ReferenceEquals(this.baseTypeList, ContentTypeImpl.emptyBaseTypes) || (this.baseTypeList.Count > 0)); } + get { return (this.state == VisitState.Visited) && (this.UnprocessedBaseTypes == null) && (object.ReferenceEquals(this.baseTypeList, ContentTypeImpl.emptyBaseTypes) || (this.baseTypeList.Length > 0)); } } #endif } diff --git a/src/Language/Impl/Language/Completion/AsyncCompletionBroker.cs b/src/Language/Impl/Language/Completion/AsyncCompletionBroker.cs index 6a91623..8ee9e35 100644 --- a/src/Language/Impl/Language/Completion/AsyncCompletionBroker.cs +++ b/src/Language/Impl/Language/Completion/AsyncCompletionBroker.cs @@ -34,24 +34,24 @@ namespace Microsoft.VisualStudio.Language.Intellisense.Implementation private ITextDocumentFactoryService TextDocumentFactoryService; [ImportMany] - private IEnumerable<Lazy<ICompletionPresenterProvider, IOrderableContentTypeMetadata>> UnorderedPresenterProviders; + private IEnumerable<Lazy<ICompletionPresenterProvider, IOrderableContentTypeAndOptionalTextViewRoleMetadata>> UnorderedPresenterProviders; [ImportMany] - private IEnumerable<Lazy<IAsyncCompletionItemSourceProvider, IOrderableContentTypeMetadata>> UnorderedCompletionItemSourceProviders; + private IEnumerable<Lazy<IAsyncCompletionItemSourceProvider, IOrderableContentTypeAndOptionalTextViewRoleMetadata>> UnorderedCompletionItemSourceProviders; [ImportMany] - private IEnumerable<Lazy<IAsyncCompletionServiceProvider, IOrderableContentTypeMetadata>> UnorderedCompletionServiceProviders; + private IEnumerable<Lazy<IAsyncCompletionServiceProvider, IOrderableContentTypeAndOptionalTextViewRoleMetadata>> UnorderedCompletionServiceProviders; - private IList<Lazy<ICompletionPresenterProvider, IOrderableContentTypeMetadata>> _orderedPresenterProviders; - private IList<Lazy<ICompletionPresenterProvider, IOrderableContentTypeMetadata>> OrderedPresenterProviders + private IList<Lazy<ICompletionPresenterProvider, IOrderableContentTypeAndOptionalTextViewRoleMetadata>> _orderedPresenterProviders; + private IList<Lazy<ICompletionPresenterProvider, IOrderableContentTypeAndOptionalTextViewRoleMetadata>> OrderedPresenterProviders => _orderedPresenterProviders ?? (_orderedPresenterProviders = Orderer.Order(UnorderedPresenterProviders)); - private IList<Lazy<IAsyncCompletionItemSourceProvider, IOrderableContentTypeMetadata>> _orderedCompletionItemSourceProviders; - private IList<Lazy<IAsyncCompletionItemSourceProvider, IOrderableContentTypeMetadata>> OrderedCompletionItemSourceProviders + private IList<Lazy<IAsyncCompletionItemSourceProvider, IOrderableContentTypeAndOptionalTextViewRoleMetadata>> _orderedCompletionItemSourceProviders; + private IList<Lazy<IAsyncCompletionItemSourceProvider, IOrderableContentTypeAndOptionalTextViewRoleMetadata>> OrderedCompletionItemSourceProviders => _orderedCompletionItemSourceProviders ?? (_orderedCompletionItemSourceProviders = Orderer.Order(UnorderedCompletionItemSourceProviders)); - private IList<Lazy<IAsyncCompletionServiceProvider, IOrderableContentTypeMetadata>> _orderedCompletionServiceProviders; - private IList<Lazy<IAsyncCompletionServiceProvider, IOrderableContentTypeMetadata>> OrderedCompletionServiceProviders + private IList<Lazy<IAsyncCompletionServiceProvider, IOrderableContentTypeAndOptionalTextViewRoleMetadata>> _orderedCompletionServiceProviders; + private IList<Lazy<IAsyncCompletionServiceProvider, IOrderableContentTypeAndOptionalTextViewRoleMetadata>> OrderedCompletionServiceProviders => _orderedCompletionServiceProviders ?? (_orderedCompletionServiceProviders = Orderer.Order(UnorderedCompletionServiceProviders)); private ImmutableDictionary<IContentType, ImmutableSortedSet<char>> _commitCharacters = ImmutableDictionary<IContentType, ImmutableSortedSet<char>>.Empty; @@ -90,8 +90,12 @@ namespace Microsoft.VisualStudio.Language.Intellisense.Implementation return session; } - var sourcesWithData = MetadataUtilities<IAsyncCompletionItemSourceProvider>.GetBuffersAndImports(textView, triggerLocation, GetCompletionItemSourceProviders); + var sourcesWithData = MetadataUtilities<IAsyncCompletionItemSourceProvider, IOrderableContentTypeAndOptionalTextViewRoleMetadata>.GetBuffersAndImports(textView, triggerLocation, GetCompletionItemSourceProviders); + + // We will pass this to the next TriggerCompletion. This feels hacky, refactor the way parts are collected and built var cachedData = new CompletionSourcesWithData(sourcesWithData); + + SnapshotSpan? applicableSpan = null; foreach (var sourceWithData in sourcesWithData) { var sourceProvider = GuardedOperations.InstantiateExtension(this, sourceWithData.import); // TODO: consider caching this @@ -102,14 +106,16 @@ namespace Microsoft.VisualStudio.Language.Intellisense.Implementation valueOnThrow: null ); - if (candidateSpan.HasValue) + // Assume that sources are ordered. If this source is the first one to provide span, map it to the view's top buffer and use it for completion, + if (applicableSpan == null && candidateSpan.HasValue) { var mappingSpan = textView.BufferGraph.CreateMappingSpan(candidateSpan.Value, SpanTrackingMode.EdgeInclusive); - var applicableSpan = mappingSpan.GetSpans(textView.TextBuffer)[0]; - return TriggerCompletion(textView, triggerLocation, applicableSpan, cachedData); + applicableSpan = mappingSpan.GetSpans(textView.TextBuffer)[0]; } } - return null; + return applicableSpan.HasValue + ? TriggerCompletion(textView, triggerLocation, applicableSpan.Value, cachedData) + : null; } private IAsyncCompletionSession TriggerCompletion(ITextView textView, SnapshotPoint triggerLocation, SnapshotSpan applicableSpan, CompletionSourcesWithData sources) @@ -126,9 +132,8 @@ namespace Microsoft.VisualStudio.Language.Intellisense.Implementation return null; } - //var sourcesWithLocations = new Dictionary<IAsyncCompletionItemSource, SnapshotPoint>(); var potentialCommitCharsBuilder = ImmutableArray.CreateBuilder<char>(); - var sourcesWithLocations = new Dictionary<IAsyncCompletionItemSource, SnapshotPoint>(); + var sourcesWithLocations = new List<(IAsyncCompletionItemSource, SnapshotPoint)>(); foreach (var sourceWithData in sources.Data) { var sourceProvider = GuardedOperations.InstantiateExtension(this, sourceWithData.import); // TODO: consider caching this @@ -138,14 +143,14 @@ namespace Microsoft.VisualStudio.Language.Intellisense.Implementation { var source = sourceProvider.GetOrCreate(textView); potentialCommitCharsBuilder.AddRange(source.GetPotentialCommitCharacters()); - sourcesWithLocations[source] = sourceWithData.point; + sourcesWithLocations.Add((source, sourceWithData.point)); }); } if (_contentTypeComparer == null) _contentTypeComparer = new StableContentTypeComparer(ContentTypeRegistryService); - var servicesWithLocations = MetadataUtilities<IAsyncCompletionServiceProvider>.GetOrderedBuffersAndImports(textView, triggerLocation, GetServiceProviders, _contentTypeComparer); + var servicesWithLocations = MetadataUtilities<IAsyncCompletionServiceProvider, IOrderableContentTypeAndOptionalTextViewRoleMetadata>.GetOrderedBuffersAndImports(textView, triggerLocation, GetServiceProviders, _contentTypeComparer); var bestServiceWithData = servicesWithLocations.FirstOrDefault(); var serviceProvider = GuardedOperations.InstantiateExtension(this, bestServiceWithData.import); // TODO: consider caching this var service = GuardedOperations.CallExtensionPoint(serviceProvider, () => serviceProvider.GetOrCreate(textView), null); @@ -155,7 +160,7 @@ namespace Microsoft.VisualStudio.Language.Intellisense.Implementation throw new InvalidOperationException("No completion services not found. Completion will be unavailable."); } - var presentationProvidersWithLocations = MetadataUtilities<ICompletionPresenterProvider>.GetOrderedBuffersAndImports(textView, triggerLocation, GetPresenters, _contentTypeComparer); + var presentationProvidersWithLocations = MetadataUtilities<ICompletionPresenterProvider, IOrderableContentTypeAndOptionalTextViewRoleMetadata>.GetOrderedBuffersAndImports(textView, triggerLocation, GetPresenters, _contentTypeComparer); var bestPresentationProviderWithLocation = presentationProvidersWithLocations.FirstOrDefault(); var presenterProvider = GuardedOperations.InstantiateExtension(this, bestPresentationProviderWithLocation.import); // TODO: consider caching this @@ -176,20 +181,17 @@ namespace Microsoft.VisualStudio.Language.Intellisense.Implementation return session; } - private IReadOnlyList<Lazy<IAsyncCompletionItemSourceProvider, IOrderableContentTypeMetadata>> GetCompletionItemSourceProviders(IContentType contentType, ITextViewRoleSet textViewRoles) + private IReadOnlyList<Lazy<IAsyncCompletionItemSourceProvider, IOrderableContentTypeAndOptionalTextViewRoleMetadata>> GetCompletionItemSourceProviders(IContentType contentType, ITextViewRoleSet textViewRoles) { - // TODO: Respect the text view roles - return OrderedCompletionItemSourceProviders.Where(n => n.Metadata.ContentTypes.Any(c => contentType.IsOfType(c))).ToList(); + return OrderedCompletionItemSourceProviders.Where(n => n.Metadata.ContentTypes.Any(c => contentType.IsOfType(c)) && (n.Metadata.TextViewRoles == null || textViewRoles.ContainsAny(n.Metadata.TextViewRoles))).ToList(); } - private IReadOnlyList<Lazy<IAsyncCompletionServiceProvider, IOrderableContentTypeMetadata>> GetServiceProviders(IContentType contentType, ITextViewRoleSet textViewRoles) + private IReadOnlyList<Lazy<IAsyncCompletionServiceProvider, IOrderableContentTypeAndOptionalTextViewRoleMetadata>> GetServiceProviders(IContentType contentType, ITextViewRoleSet textViewRoles) { - // TODO: Respect the text view roles - return OrderedCompletionServiceProviders.Where(n => n.Metadata.ContentTypes.Any(c => contentType.IsOfType(c))).OrderBy(n => n.Metadata.ContentTypes, _contentTypeComparer).ToList(); + return OrderedCompletionServiceProviders.Where(n => n.Metadata.ContentTypes.Any(c => contentType.IsOfType(c)) && (n.Metadata.TextViewRoles == null || textViewRoles.ContainsAny(n.Metadata.TextViewRoles))).OrderBy(n => n.Metadata.ContentTypes, _contentTypeComparer).ToList(); } - private IReadOnlyList<Lazy<ICompletionPresenterProvider, IOrderableContentTypeMetadata>> GetPresenters(IContentType contentType, ITextViewRoleSet textViewRoles) + private IReadOnlyList<Lazy<ICompletionPresenterProvider, IOrderableContentTypeAndOptionalTextViewRoleMetadata>> GetPresenters(IContentType contentType, ITextViewRoleSet textViewRoles) { - // TODO: Respect the text view roles - return OrderedPresenterProviders.Where(n => n.Metadata.ContentTypes.Any(c => contentType.IsOfType(c))).OrderBy(n => n.Metadata.ContentTypes, _contentTypeComparer).ToList(); + return OrderedPresenterProviders.Where(n => n.Metadata.ContentTypes.Any(c => contentType.IsOfType(c)) && (n.Metadata.TextViewRoles == null || textViewRoles.ContainsAny(n.Metadata.TextViewRoles))).OrderBy(n => n.Metadata.ContentTypes, _contentTypeComparer).ToList(); } // TODO: Evaluate the methods below and clean them up. We should have one reliable way to get parts in correct order @@ -312,9 +314,9 @@ namespace Microsoft.VisualStudio.Language.Intellisense.Implementation /// </summary> private struct CompletionSourcesWithData { - internal IEnumerable<(ITextBuffer buffer, SnapshotPoint point, Lazy<IAsyncCompletionItemSourceProvider, IOrderableContentTypeMetadata> import)> Data; + internal IEnumerable<(ITextBuffer buffer, SnapshotPoint point, Lazy<IAsyncCompletionItemSourceProvider, IOrderableContentTypeAndOptionalTextViewRoleMetadata> import)> Data; - public CompletionSourcesWithData(IEnumerable<(ITextBuffer buffer, SnapshotPoint point, Lazy<IAsyncCompletionItemSourceProvider, IOrderableContentTypeMetadata> import)> data) + public CompletionSourcesWithData(IEnumerable<(ITextBuffer buffer, SnapshotPoint point, Lazy<IAsyncCompletionItemSourceProvider, IOrderableContentTypeAndOptionalTextViewRoleMetadata> import)> data) { Data = data; } diff --git a/src/Language/Impl/Language/Completion/AsyncCompletionSession.cs b/src/Language/Impl/Language/Completion/AsyncCompletionSession.cs index 0469423..bda6905 100644 --- a/src/Language/Impl/Language/Completion/AsyncCompletionSession.cs +++ b/src/Language/Impl/Language/Completion/AsyncCompletionSession.cs @@ -19,10 +19,11 @@ namespace Microsoft.VisualStudio.Language.Intellisense.Implementation /// Holds a state of the session /// and a reference to the UI element /// </summary> - internal class AsyncCompletionSession : IAsyncCompletionSession, ICompletionComputationCallbackHandler<CompletionModel> + internal class AsyncCompletionSession : IAsyncCompletionSession, ICompletionComputationCallbackHandler<CompletionModel>, IPropertyOwner { // Available data and services - private readonly IDictionary<IAsyncCompletionItemSource, SnapshotPoint> _completionSources; + private readonly IList<(IAsyncCompletionItemSource Source, SnapshotPoint Point)> _completionSources; + private readonly IDictionary<IAsyncCompletionItemSource, SnapshotPoint> _completionSourcesWhoGaveItems; private readonly IAsyncCompletionService _completionService; private readonly SnapshotSpan _initialApplicableSpan; private readonly JoinableTaskFactory _jtf; @@ -72,8 +73,10 @@ namespace Microsoft.VisualStudio.Language.Intellisense.Implementation public bool IsDismissed => _isDismissed; + public PropertyCollection Properties { get; } + public AsyncCompletionSession(SnapshotSpan applicableSpan, ImmutableArray<char> potentialCommitChars, JoinableTaskFactory jtf, - ICompletionPresenterProvider presenterProvider, IDictionary<IAsyncCompletionItemSource, SnapshotPoint> completionSources, + ICompletionPresenterProvider presenterProvider, IList<(IAsyncCompletionItemSource, SnapshotPoint)> completionSources, IAsyncCompletionService completionService, AsyncCompletionBroker broker, ITextView view, CompletionTelemetryHost telemetryHost, IGuardedOperations guardedOperations) { _initialApplicableSpan = applicableSpan; @@ -81,13 +84,15 @@ namespace Microsoft.VisualStudio.Language.Intellisense.Implementation _jtf = jtf; _presenterProvider = presenterProvider; _broker = broker; - _completionSources = completionSources; + _completionSources = completionSources; // still prorotype at the momemnt. + _completionSourcesWhoGaveItems = new Dictionary<IAsyncCompletionItemSource, SnapshotPoint>(); // To be filled in GetInitialModel _completionService = completionService; _textView = view; _guardedOperations = guardedOperations; _telemetry = new CompletionSessionTelemetry(telemetryHost, completionService, presenterProvider); PageStepSize = presenterProvider?.ResultsPerPage ?? 1; _textView.Caret.PositionChanged += OnCaretPositionChanged; + Properties = new PropertyCollection(); } bool IAsyncCompletionSession.CommitIfUnique(CancellationToken token) @@ -171,7 +176,7 @@ namespace Microsoft.VisualStudio.Language.Intellisense.Implementation UiStopwatch.Restart(); // Pass appropriate buffer to the item's provider - var buffer = _completionSources[itemToCommit.Source].Snapshot.TextBuffer; + var buffer = _completionSourcesWhoGaveItems[itemToCommit.Source].Snapshot.TextBuffer; if (itemToCommit.UseCustomCommit) { result = _guardedOperations.CallExtensionPoint( @@ -350,7 +355,7 @@ namespace Microsoft.VisualStudio.Language.Intellisense.Implementation if (_potentialCommitChars.Contains(typeChar)) { var mappingPoint = _textView.BufferGraph.CreateMappingPoint(triggerLocation, PointTrackingMode.Negative); - return _completionSources + return _completionSourcesWhoGaveItems .Select(p => (p, mappingPoint.GetPoint(p.Value.Snapshot.TextBuffer, PositionAffinity.Predecessor))) .Where(n => n.Item2.HasValue) .Any(n => _guardedOperations.CallExtensionPoint( @@ -441,13 +446,27 @@ namespace Microsoft.VisualStudio.Language.Intellisense.Implementation private async Task<CompletionModel> GetInitialModel(ITextView view, CompletionTrigger trigger, SnapshotPoint triggerLocation, CancellationToken token) { // Map the trigger location to respective view for each completion provider - var nestedResults = await Task.WhenAll( - _completionSources.Select( - p => _guardedOperations.CallExtensionPointAsync<CompletionContext>( - errorSource: p.Key, - asyncCall: () => p.Key.GetCompletionContextAsync(trigger, triggerLocation, _initialApplicableSpan, token), + var getCompletionTasks = new Task<CompletionContext>[_completionSources.Count]; + for (int i = 0; i < _completionSources.Count; i++) + { + var index = i; // Capture current value of i + getCompletionTasks[i] = Task.Run(async () => + { + var source = _completionSources[index].Source; + var point = _completionSources[index].Point; + var context = await _guardedOperations.CallExtensionPointAsync( + errorSource: _completionSources[index].Source, + asyncCall: () => _completionSources[index].Source.GetCompletionContextAsync(trigger, point, _initialApplicableSpan, token), valueOnThrow: null - ))); + ); + if (context != null && !context.Items.IsDefaultOrEmpty) + { + _completionSourcesWhoGaveItems[source] = point; + } + return context; + }); + } + var nestedResults = await Task.WhenAll(getCompletionTasks); var initialCompletionItems = nestedResults.Where(n => n != null && !n.Items.IsDefaultOrEmpty).SelectMany(n => n.Items).ToImmutableArray(); // Do not continue with empty session @@ -471,7 +490,7 @@ namespace Microsoft.VisualStudio.Language.Intellisense.Implementation #if DEBUG Debug.WriteLine("Completion session got data."); - Debug.WriteLine("Sources: " + String.Join(", ", _completionSources.Select(n => n.Key.GetType()))); + Debug.WriteLine("Sources: " + String.Join(", ", _completionSources.Select(n => n.Source.GetType()))); Debug.WriteLine("Service: " + _completionService.GetType()); Debug.WriteLine("Filters: " + String.Join(", ", availableFilters.Select(n => n.Filter.DisplayText))); Debug.WriteLine("Span: " + _initialApplicableSpan.GetText()); @@ -552,10 +571,10 @@ namespace Microsoft.VisualStudio.Language.Intellisense.Implementation model.InitialItems, model.InitialTriggerReason, filterReason, - triggerLocation.Snapshot, + triggerLocation.Snapshot, // used exclusively to resolve applicable span model.ApplicableSpan, model.Filters, - _textView, + _textView, // Roslyn doesn't need it, and likely, can't use it token), valueOnThrow: null); diff --git a/src/Language/Impl/Language/Completion/CompletionCommandHandlers.cs b/src/Language/Impl/Language/Completion/CompletionCommandHandlers.cs index 45694ad..cdd8b07 100644 --- a/src/Language/Impl/Language/Completion/CompletionCommandHandlers.cs +++ b/src/Language/Impl/Language/Completion/CompletionCommandHandlers.cs @@ -14,7 +14,7 @@ namespace Microsoft.VisualStudio.Language.Intellisense.Implementation /// Reacts to the down arrow command and attempts to scroll the completion list. /// </summary> [Name(KnownCompletionNames.CompletionCommandHandlers)] - [ContentType("any")] + [ContentType("text")] [Export(typeof(ICommandHandler))] internal sealed class CompletionCommandHandlers : ICommandHandler<DownKeyCommandArgs>, @@ -86,10 +86,6 @@ namespace Microsoft.VisualStudio.Language.Intellisense.Implementation // Execute other commands in the chain to see the change in the buffer. nextCommandHandler(); - // We are only inteterested in the top buffer. Currently, commanding implementation calls us multiple times, once per each buffer. - if (args.TextView.BufferGraph.TopBuffer != args.SubjectBuffer) - return; - var session = Broker.GetSession(args.TextView); if (session != null) { @@ -193,10 +189,6 @@ namespace Microsoft.VisualStudio.Language.Intellisense.Implementation // Execute other commands in the chain to see the change in the buffer. nextCommandHandler(); - // We are only inteterested in the top buffer. Currently, commanding implementation calls us multiple times, once per each buffer. - if (args.TextView.BufferGraph.TopBuffer != args.SubjectBuffer) - return; - var session = Broker.GetSession(args.TextView); if (session != null) { @@ -256,9 +248,12 @@ namespace Microsoft.VisualStudio.Language.Intellisense.Implementation var session = Broker.GetSession(args.TextView); if (session != null) { - session.Commit(executionContext.OperationContext.UserCancellationToken); + var commitBehavior = session.Commit(executionContext.OperationContext.UserCancellationToken, '\n'); session.Dismiss(); - return true; + + // Mark this command as handled (return true), unless extender set the RaiseFurtherCommandHandlers flag. + if ((commitBehavior & CommitBehavior.RaiseFurtherCommandHandlers) == 0) + return true; } return false; } @@ -271,9 +266,12 @@ namespace Microsoft.VisualStudio.Language.Intellisense.Implementation var session = Broker.GetSession(args.TextView); if (session != null) { - session.Commit(executionContext.OperationContext.UserCancellationToken); + var commitBehavior = session.Commit(executionContext.OperationContext.UserCancellationToken, '\t'); session.Dismiss(); - return true; + + // Mark this command as handled (return true), unless extender set the RaiseFurtherCommandHandlers flag. + if ((commitBehavior & CommitBehavior.RaiseFurtherCommandHandlers) == 0) + return true; } return false; } @@ -308,12 +306,6 @@ namespace Microsoft.VisualStudio.Language.Intellisense.Implementation // Note regarding undo: This will be undone second nextCommandHandler(); - if (args.TextView.TextBuffer != args.SubjectBuffer) - { - // We are only inteterested in the top buffer. Currently, commanding implementation calls us multiple times, once per each buffer. - return; - } - // Pass location from before calling nextCommandHandler so that extenders // get the same view of the buffer in both ShouldCommit and Commit var sessionToCommit = Broker.GetSession(args.TextView); @@ -328,9 +320,9 @@ namespace Microsoft.VisualStudio.Language.Intellisense.Implementation UndoUtilities.RollbackToBeforeTypeChar(initialTextSnapshot, args.SubjectBuffer); // Now the buffer doesn't have the commit character nor the matching brace, if any - var customBehavior = sessionToCommit.Commit(executionContext.OperationContext.UserCancellationToken, args.TypedChar); + var commitBehavior = sessionToCommit.Commit(executionContext.OperationContext.UserCancellationToken, args.TypedChar); - if ((customBehavior & CommitBehavior.SuppressFurtherCommandHandlers) == 0) + if ((commitBehavior & CommitBehavior.SuppressFurtherCommandHandlers) == 0) nextCommandHandler(); // Replay the key, so that we get brace completion. // Complete the transaction before stopping it. diff --git a/src/Language/Impl/Language/Completion/CompletionUtilities.cs b/src/Language/Impl/Language/Completion/CompletionUtilities.cs index 17041c9..ec0d97f 100644 --- a/src/Language/Impl/Language/Completion/CompletionUtilities.cs +++ b/src/Language/Impl/Language/Completion/CompletionUtilities.cs @@ -10,7 +10,9 @@ using Microsoft.VisualStudio.Utilities; namespace Microsoft.VisualStudio.Language.Intellisense.Implementation { - internal class MetadataUtilities<T> where T : class + internal class MetadataUtilities<T, TMetadata> + where T : class + where TMetadata : IContentTypeMetadata { /// <summary> /// This method creates a collection of (T, SnapshotPoint) pairs where the SnapshotPoint is the originalPoint @@ -21,7 +23,7 @@ namespace Microsoft.VisualStudio.Language.Intellisense.Implementation /// <param name="originalPoint"></param> /// <param name="imports"></param> /// <returns></returns> - internal static IEnumerable<(ITextBuffer buffer, SnapshotPoint point, Lazy<T, IOrderableContentTypeMetadata> import)> GetOrderedBuffersAndImports(ITextView textView, SnapshotPoint location, Func<IContentType, ITextViewRoleSet, IReadOnlyList<Lazy<T, IOrderableContentTypeMetadata>>> getImports, IComparer<IEnumerable<string>> contentTypeComparer) + internal static IEnumerable<(ITextBuffer buffer, SnapshotPoint point, Lazy<T, TMetadata> import)> GetOrderedBuffersAndImports(ITextView textView, SnapshotPoint location, Func<IContentType, ITextViewRoleSet, IReadOnlyList<Lazy<T, TMetadata>>> getImports, IComparer<IEnumerable<string>> contentTypeComparer) { // This method is created based on EditorCommandHandlerService.GetOrderedBuffersAndCommandHandlers @@ -60,15 +62,15 @@ namespace Microsoft.VisualStudio.Language.Intellisense.Implementation // An array of per-buffer buckets, each containing cached list of matching imports, // ordered by [Order] and content type specificity - var importBuckets = new ImportBucket<T>[buffers.Length]; + var importBuckets = new ImportBucket<T, TMetadata>[buffers.Length]; for (int i = 0; i < buffers.Length; i++) { - importBuckets[i] = new ImportBucket<T>(getImports(buffers[i].ContentType, textView.Roles)); + importBuckets[i] = new ImportBucket<T, TMetadata>(getImports(buffers[i].ContentType, textView.Roles)); } while (true) { - Lazy<T, IOrderableContentTypeMetadata> currentImport = null; + Lazy<T, TMetadata> currentImport = null; int currentImportIndex = 0; for (int i = 0; i < importBuckets.Length; i++) @@ -125,7 +127,7 @@ namespace Microsoft.VisualStudio.Language.Intellisense.Implementation /// <param name="getImports"></param> /// <param name="contentTypeComparer"></param> /// <returns></returns> - internal static IEnumerable<(ITextBuffer buffer, SnapshotPoint point, Lazy<T, IOrderableContentTypeMetadata> import)> GetBuffersAndImports(ITextView textView, SnapshotPoint location, Func<IContentType, ITextViewRoleSet, IReadOnlyList<Lazy<T, IOrderableContentTypeMetadata>>> getImports) + internal static IEnumerable<(ITextBuffer buffer, SnapshotPoint point, Lazy<T, TMetadata> import)> GetBuffersAndImports(ITextView textView, SnapshotPoint location, Func<IContentType, ITextViewRoleSet, IReadOnlyList<Lazy<T, TMetadata>>> getImports) { var mappedPointsEnumeration = GetPointsOnAvailableBuffers(textView, location); if (!mappedPointsEnumeration.Any()) @@ -136,7 +138,7 @@ namespace Microsoft.VisualStudio.Language.Intellisense.Implementation // An array of per-buffer buckets, each containing cached list of matching imports, // ordered by [Order] and content type specificity - var importBuckets = new ImportBucket<T>[buffers.Length]; + var importBuckets = new ImportBucket<T, TMetadata>[buffers.Length]; for (int i = 0; i < buffers.Length; i++) { foreach (var import in getImports(buffers[i].ContentType, textView.Roles)) diff --git a/src/Language/Impl/Language/Completion/DefaultCompletionService.cs b/src/Language/Impl/Language/Completion/DefaultCompletionService.cs index 5b7066f..3cd3479 100644 --- a/src/Language/Impl/Language/Completion/DefaultCompletionService.cs +++ b/src/Language/Impl/Language/Completion/DefaultCompletionService.cs @@ -15,7 +15,7 @@ namespace Microsoft.VisualStudio.Language.Intellisense.Implementation { [Export(typeof(IAsyncCompletionServiceProvider))] [Name(KnownCompletionNames.DefaultCompletionService)] - [ContentType("any")] + [ContentType("text")] internal class DefaultCompletionServiceProvider : IAsyncCompletionServiceProvider { [Import] diff --git a/src/Language/Impl/Language/Completion/ImportBucket.cs b/src/Language/Impl/Language/Completion/ImportBucket.cs index ba631d0..9876600 100644 --- a/src/Language/Impl/Language/Completion/ImportBucket.cs +++ b/src/Language/Impl/Language/Completion/ImportBucket.cs @@ -4,42 +4,45 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.VisualStudio.Text.Utilities; +using Microsoft.VisualStudio.Utilities; namespace Microsoft.VisualStudio.Language.Intellisense.Implementation { /// <summary> /// Lightweight stack-like view over a readonly ordered list of command handlers. /// </summary> - internal class ImportBucket<T> + internal class ImportBucket<T, TMetadata> + where T : class + where TMetadata : IContentTypeMetadata { private int _currentImportSetting; - private readonly IReadOnlyList<Lazy<T, IOrderableContentTypeMetadata>> _imports; + private readonly IReadOnlyList<Lazy<T, TMetadata>> _imports; - public ImportBucket(IReadOnlyList<Lazy<T, IOrderableContentTypeMetadata>> imports) + public ImportBucket(IReadOnlyList<Lazy<T, TMetadata>> imports) { _imports = imports ?? throw new ArgumentNullException(nameof(imports)); } public bool IsEmpty => _currentImportSetting >= _imports.Count; - public Lazy<T, IOrderableContentTypeMetadata> Peek() + public Lazy<T, TMetadata> Peek() { if (!IsEmpty) { return _imports[_currentImportSetting]; } - throw new InvalidOperationException($"{nameof(ImportBucket<T>)} is empty."); + throw new InvalidOperationException($"{nameof(ImportBucket<T, TMetadata>)} is empty."); } - internal Lazy<T, IOrderableContentTypeMetadata> Pop() + internal Lazy<T, TMetadata> Pop() { if (!IsEmpty) { return _imports[_currentImportSetting++]; } - throw new InvalidOperationException($"{nameof(ImportBucket<T>)} is empty."); + throw new InvalidOperationException($"{nameof(ImportBucket<T, TMetadata>)} is empty."); } } } diff --git a/src/Microsoft.VisualStudio.Text.Implementation.csproj b/src/Microsoft.VisualStudio.Text.Implementation.csproj index 27cd98c..2757a7c 100644 --- a/src/Microsoft.VisualStudio.Text.Implementation.csproj +++ b/src/Microsoft.VisualStudio.Text.Implementation.csproj @@ -5,10 +5,10 @@ <SignAssembly>true</SignAssembly> <AssemblyOriginatorKeyFile>key.snk</AssemblyOriginatorKeyFile> <DelaySign>false</DelaySign> - <Version>15.0.21-pre</Version> + <Version>15.0.25-pre</Version> <AssemblyVersion>15.0.0.0</AssemblyVersion> - <NuGetVersionEditor>15.7.140-preview-gc7d2848231</NuGetVersionEditor> - <NuGetVersionLanguage>15.7.140-preview-gc7d2848231</NuGetVersionLanguage> + <NuGetVersionEditor>15.7.153-preview-g7d0635149a</NuGetVersionEditor> + <NuGetVersionLanguage>15.7.153-preview-g7d0635149a</NuGetVersionLanguage> </PropertyGroup> <PropertyGroup> diff --git a/src/Text/Def/TextLogic/Tagging/SimpleTagger.cs b/src/Text/Def/TextLogic/Tagging/SimpleTagger.cs index 37d845b..40048ea 100644 --- a/src/Text/Def/TextLogic/Tagging/SimpleTagger.cs +++ b/src/Text/Def/TextLogic/Tagging/SimpleTagger.cs @@ -198,7 +198,7 @@ namespace Microsoft.VisualStudio.Text.Tagging /// <returns>The set of <see cref="TrackingTagSpan<T>"/> objects that intersect the given span, in order.</returns> public IEnumerable<TrackingTagSpan<T>> GetTaggedSpans(SnapshotSpan span) { - IList<TrackingTagSpan<T>> tagSpanList = new List<TrackingTagSpan<T>>(_trackingTagSpans); + IList<TrackingTagSpan<T>> tagSpanList; lock (mutex) { @@ -230,25 +230,40 @@ namespace Microsoft.VisualStudio.Text.Tagging public IEnumerable<ITagSpan<T>> GetTags(NormalizedSnapshotSpanCollection spans) { if (spans.Count == 0) - yield break; + { + return Enumerable.Empty<ITagSpan<T>>(); + } - IList<TrackingTagSpan<T>> tagSpanList; + TrackingTagSpan<T>[] tagSpanList = null; lock (mutex) { - tagSpanList = new List<TrackingTagSpan<T>>(_trackingTagSpans); + if (_trackingTagSpans.Count > 0) + { + tagSpanList = _trackingTagSpans.ToArray(); + } } - foreach (var tagSpan in tagSpanList) + if (tagSpanList == null) { - SnapshotSpan tagSnapshotSpan = tagSpan.Span.GetSpan(spans[0].Snapshot); - - foreach (var querySpan in spans) + return Enumerable.Empty<ITagSpan<T>>(); + } + + return GetTagsImpl(tagSpanList, spans); + + IEnumerable<ITagSpan<T>> GetTagsImpl(TrackingTagSpan<T>[] tagSpans, NormalizedSnapshotSpanCollection querySpans) + { + for (int i = 0; i < tagSpans.Length; i++) { - if (tagSnapshotSpan.IntersectsWith(querySpan)) + SnapshotSpan tagSnapshotSpan = tagSpans[i].Span.GetSpan(querySpans[0].Snapshot); + + for (int j = 0; j < querySpans.Count; j++) { - yield return new TagSpan<T>(tagSnapshotSpan, tagSpan.Tag); - break; + if (tagSnapshotSpan.IntersectsWith(querySpans[j])) + { + yield return new TagSpan<T>(tagSnapshotSpan, tagSpans[i].Tag); + break; + } } } } diff --git a/src/Text/Def/TextUI/Adornments/ToolTipService/ToolTipParameters.cs b/src/Text/Def/TextUI/Adornments/ToolTipService/ToolTipParameters.cs index 2f7a31e..daad688 100644 --- a/src/Text/Def/TextUI/Adornments/ToolTipService/ToolTipParameters.cs +++ b/src/Text/Def/TextUI/Adornments/ToolTipService/ToolTipParameters.cs @@ -32,14 +32,13 @@ bool ignoreBufferChange = false, Func<bool> keepOpenFunc = null) { - this.TrackMouse = trackMouse; - this.IgnoreBufferChange = ignoreBufferChange; - - if (!trackMouse && ignoreBufferChange) + if (trackMouse && ignoreBufferChange) { throw new ArgumentException($"{nameof(ignoreBufferChange)} can only be true if {nameof(trackMouse)} is false"); } + this.TrackMouse = trackMouse; + this.IgnoreBufferChange = ignoreBufferChange; this.keepOpenFunc = keepOpenFunc; } diff --git a/src/Text/Impl/Commanding/EditorCommandHandlerServiceFactory.cs b/src/Text/Impl/Commanding/EditorCommandHandlerServiceFactory.cs index 241b3b6..f38a85c 100644 --- a/src/Text/Impl/Commanding/EditorCommandHandlerServiceFactory.cs +++ b/src/Text/Impl/Commanding/EditorCommandHandlerServiceFactory.cs @@ -65,12 +65,13 @@ namespace Microsoft.VisualStudio.UI.Text.Commanding.Implementation return GetService(textView); } - return subjectBuffer.Properties.GetOrCreateSingletonProperty(() => - { - return new EditorCommandHandlerService(textView, _commandHandlers, _uiThreadOperationExecutor, - _joinableTaskContext, _contentTypeComparer, - new SingleBufferResolver(subjectBuffer), _guardedOperations); - }); + // We cannot cache view/buffer affinitized service instance in the buffer property bag as the + // buffer can be used by another text view, see https://devdiv.visualstudio.com/DevDiv/_workitems/edit/563472. + // There is no good way to cache it without holding onto the buffer (which can be disconnected + // from the text view anytime). + return new EditorCommandHandlerService(textView, _commandHandlers, _uiThreadOperationExecutor, + _joinableTaskContext, _contentTypeComparer, + new SingleBufferResolver(subjectBuffer), _guardedOperations); } private IEnumerable<Lazy<ICommandHandler, ICommandHandlerMetadata>> OrderCommandHandlers(IEnumerable<Lazy<ICommandHandler, ICommandHandlerMetadata>> commandHandlers) diff --git a/src/Text/Util/TextUIUtil/IOrderableContentTypeAndOptionalTextViewRoleMetadata.cs b/src/Text/Util/TextUIUtil/IOrderableContentTypeAndOptionalTextViewRoleMetadata.cs new file mode 100644 index 0000000..d450fce --- /dev/null +++ b/src/Text/Util/TextUIUtil/IOrderableContentTypeAndOptionalTextViewRoleMetadata.cs @@ -0,0 +1,19 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// +using System.Collections.Generic; +using System.ComponentModel; +using Microsoft.VisualStudio.Utilities; + +namespace Microsoft.VisualStudio.Text.Utilities +{ + /// <summary> + /// Metadata which includes Content Types and Text View Roles + /// </summary> + public interface IOrderableContentTypeAndOptionalTextViewRoleMetadata : IContentTypeMetadata, IOrderable + { + [DefaultValue(null)] + IEnumerable<string> TextViewRoles { get; } + } +} |