public void AugmentCompletionSession(ICompletionSession session, IList<CompletionSet> completionSets) { var tokens = classifier.Tokens; if (tokens != null) { // find current token var cursorPosition = session.TextView.Caret.Position.BufferPosition; var currentToken = tokens.FirstOrDefault(t => t.StartPosition <= cursorPosition && t.StartPosition + t.Length >= cursorPosition); if (currentToken != null) { // prepare the context var items = Enumerable.Empty<SimpleRwHtmlCompletion>(); var context = GetCompletionContext(); context.CurrentTokenIndex = classifier.Tokens.IndexOf(currentToken); context.CurrentNode = parser.Root.FindNodeByPosition(session.TextView.Caret.Position.BufferPosition.Position - 1); var combineWithHtmlCompletions = false; TriggerPoint triggerPoint = TriggerPoint.None; if (currentToken.Type == RwHtmlTokenType.DirectiveStart) { // directive name completion triggerPoint = TriggerPoint.DirectiveName; items = sourceProvider.CompletionProviders.Where(p => p.TriggerPoint == triggerPoint).SelectMany(p => p.GetItems(context)); } else if (currentToken.Type == RwHtmlTokenType.WhiteSpace) { if (context.CurrentNode is RwHtmlDirectiveNode && context.CurrentTokenIndex >= 2 && tokens[context.CurrentTokenIndex - 2].Type == RwHtmlTokenType.DirectiveStart) { // directive value triggerPoint = TriggerPoint.DirectiveValue; items = sourceProvider.CompletionProviders.Where(p => p.TriggerPoint == triggerPoint).SelectMany(p => p.GetItems(context)); } else if (context.CurrentNode is RwHtmlElementNode || context.CurrentNode is RwHtmlAttributeNode) { // attribute name triggerPoint = TriggerPoint.TagAttributeName; items = sourceProvider.CompletionProviders.Where(p => p.TriggerPoint == triggerPoint).SelectMany(p => p.GetItems(context)); combineWithHtmlCompletions = sourceProvider.CompletionProviders.OfType<MainTagAttributeNameCompletionProvider>().Single().CombineWithHtmlCompletions; } } else if (currentToken.Type == RwHtmlTokenType.OpenTag) { // element name triggerPoint = TriggerPoint.TagName; items = sourceProvider.CompletionProviders.Where(p => p.TriggerPoint == triggerPoint).SelectMany(p => p.GetItems(context)); combineWithHtmlCompletions = true; } else if (currentToken.Type == RwHtmlTokenType.SingleQuote || currentToken.Type == RwHtmlTokenType.DoubleQuote || currentToken.Type == RwHtmlTokenType.Equals) { // attribute value triggerPoint = TriggerPoint.TagAttributeValue; items = sourceProvider.CompletionProviders.Where(p => p.TriggerPoint == triggerPoint).SelectMany(p => p.GetItems(context)); combineWithHtmlCompletions = true; } else if (currentToken.Type == RwHtmlTokenType.OpenBinding) { // binding name triggerPoint = TriggerPoint.BindingName; items = sourceProvider.CompletionProviders.Where(p => p.TriggerPoint == triggerPoint).SelectMany(p => p.GetItems(context)); } else if (currentToken.Type == RwHtmlTokenType.Colon) { if (context.CurrentNode is RwHtmlBindingNode) { // binding value triggerPoint = TriggerPoint.BindingValue; items = sourceProvider.CompletionProviders.Where(p => p.TriggerPoint == triggerPoint).SelectMany(p => p.GetItems(context)); } else { // element name triggerPoint = TriggerPoint.TagName; items = sourceProvider.CompletionProviders.Where(p => p.TriggerPoint == triggerPoint).SelectMany(p => p.GetItems(context)); combineWithHtmlCompletions = true; } } var results = items.OrderBy(v => v.DisplayText).Distinct(CompletionEqualityComparer.Instance).ToList(); // show the session if (!results.Any()) { session.Dismiss(); } else { // handle duplicate sessions (sometimes this method is called twice (e.g. when space key is pressed) so we need to make sure that we'll display only one session lock (activeSessions) { if (activeSessions.Count > 0) { session.Dismiss(); return; } activeSessions.Add(session); session.Dismissed += (s, a) => { lock (activeSessions) { activeSessions.Remove((ICompletionSession)s); } }; session.Committed += (s, a) => { lock (activeSessions) { activeSessions.Remove((ICompletionSession)s); } }; } // show the session var newCompletionSet = new CustomCompletionSet("HTML", "HTML", FindTokenSpanAtPosition(session), results, null); if (combineWithHtmlCompletions && completionSets.Any()) { newCompletionSet = MergeCompletionSets(completionSets, newCompletionSet); } else { completionSets.Clear(); } completionSets.Add(newCompletionSet); } } } }
private static CustomCompletionSet MergeCompletionSets(IList<CompletionSet> completionSets, CustomCompletionSet newCompletions) { var htmlCompletionsSet = completionSets.First(); // if we are in an element with tagPrefix, VS adds all HTML elements with the same prefix in the completion - we don't want it var originalCompletions = htmlCompletionsSet.Completions.Where(c => !c.DisplayText.Contains(":")); // merge var mergedCompletionSet = new CustomCompletionSet( htmlCompletionsSet.Moniker, htmlCompletionsSet.DisplayName, htmlCompletionsSet.ApplicableTo, newCompletions.Completions.Concat(originalCompletions).OrderBy(n => n.DisplayText).Distinct(CompletionEqualityComparer.Instance), htmlCompletionsSet.CompletionBuilders); completionSets.Remove(htmlCompletionsSet); return mergedCompletionSet; }