public override async Task <CompletionContext> GetCompletionContextAsync(IAsyncCompletionSession session, CompletionTrigger trigger, SnapshotPoint triggerLocation, SnapshotSpan applicableToSpan, CancellationToken token) { var context = await GetSessionContext(session, triggerLocation, token); var rr = context.rr; var doc = context.doc; var spine = context.spine; if (rr?.LanguageElement != null) { if (ExpressionCompletion.IsPossibleExpressionCompletionContext(spine)) { string expression = GetAttributeOrElementValueToCaret(spine, triggerLocation); var triggerState = ExpressionCompletion.GetTriggerState( expression, trigger.Character, rr.IsCondition(), out int triggerLength, out ExpressionNode triggerExpression, out var listKind, out IReadOnlyList <ExpressionNode> comparandVariables ); if (triggerState != ExpressionCompletion.TriggerState.None) { var info = rr.GetElementOrAttributeValueInfo(doc); if (info != null && info.ValueKind != MSBuildValueKind.Nothing) { return(await GetExpressionCompletionsAsync(info, triggerState, listKind, triggerLength, triggerExpression, comparandVariables, rr, triggerLocation, doc, token)); } } } } return(await base.GetCompletionContextAsync(session, trigger, triggerLocation, applicableToSpan, token)); }
public override CompletionStartData InitializeCompletion(CompletionTrigger trigger, SnapshotPoint triggerLocation, CancellationToken token) { //we don't care need a real document here we're doing very basic resolution for triggering var spine = GetSpineParser(triggerLocation); var rr = MSBuildResolver.Resolve(spine, triggerLocation.Snapshot.GetTextSource(), MSBuildRootDocument.Empty, null); if (rr?.LanguageElement != null) { if (ExpressionCompletion.IsPossibleExpressionCompletionContext(spine)) { string expression = GetAttributeOrElementValueToCaret(spine, triggerLocation); var triggerState = ExpressionCompletion.GetTriggerState( expression, trigger.Character, rr.IsCondition(), out int triggerLength, out ExpressionNode triggerExpression, out var listKind, out IReadOnlyList <ExpressionNode> comparandVariables ); if (triggerState != ExpressionCompletion.TriggerState.None) { return(new CompletionStartData(CompletionParticipation.ProvidesItems, new SnapshotSpan(triggerLocation.Snapshot, triggerLocation.Position - triggerLength, triggerLength))); } } } return(base.InitializeCompletion(trigger, triggerLocation, token)); }
async Task <CompletionContext> GetExpressionCompletionsAsync( IAsyncCompletionSession session, ValueInfo info, TriggerState triggerState, ListKind listKind, int triggerLength, ExpressionNode triggerExpression, IReadOnlyList <ExpressionNode> comparandVariables, MSBuildResolveResult rr, SnapshotPoint triggerLocation, MSBuildRootDocument doc, CancellationToken token) { var kind = info.InferValueKindIfUnknown(); if (!ValidateListPermitted(listKind, kind)) { return(CompletionContext.Empty); } bool allowExpressions = kind.AllowExpressions(); kind = kind.GetScalarType(); if (kind == MSBuildValueKind.Data || kind == MSBuildValueKind.Nothing) { return(CompletionContext.Empty); } bool isValue = triggerState == TriggerState.Value; var items = new List <CompletionItem> (); if (comparandVariables != null && isValue) { foreach (var ci in ExpressionCompletion.GetComparandCompletions(doc, comparandVariables)) { items.Add(CreateCompletionItem(ci, XmlCompletionItemKind.AttributeValue)); } } if (isValue) { switch (kind) { case MSBuildValueKind.NuGetID: if (triggerExpression is ExpressionText t) { var packageNameItems = await GetPackageNameCompletions(session, doc, t.Value, token); if (packageNameItems != null) { items.AddRange(packageNameItems); } } break; case MSBuildValueKind.NuGetVersion: { var packageVersionItems = await GetPackageVersionCompletions(doc, rr, token); if (packageVersionItems != null) { items.AddRange(packageVersionItems); } break; } case MSBuildValueKind.Sdk: case MSBuildValueKind.SdkWithVersion: { var sdkItems = await GetSdkCompletions(doc, token); if (sdkItems != null) { items.AddRange(sdkItems); } break; } case MSBuildValueKind.Guid: items.Add(CreateSpecialItem("New GUID", "Inserts a new GUID", KnownImages.Add, MSBuildSpecialCommitKind.NewGuid)); break; case MSBuildValueKind.Lcid: items.AddRange(GetLcidCompletions()); break; } } //TODO: better metadata support IEnumerable <BaseInfo> cinfos; if (info.CustomType != null && info.CustomType.Values.Count > 0 && isValue) { cinfos = info.CustomType.Values; } else { //FIXME: can we avoid awaiting this unless we actually need to resolve a function? need to propagate async downwards await provider.FunctionTypeProvider.EnsureInitialized(token); cinfos = ExpressionCompletion.GetCompletionInfos(rr, triggerState, kind, triggerExpression, triggerLength, doc, provider.FunctionTypeProvider); } if (cinfos != null) { foreach (var ci in cinfos) { items.Add(CreateCompletionItem(ci, XmlCompletionItemKind.AttributeValue)); } } if ((allowExpressions && isValue) || triggerState == TriggerState.BareFunctionArgumentValue) { items.Add(CreateSpecialItem("$(", "Property reference", KnownImages.MSBuildProperty, MSBuildSpecialCommitKind.PropertyReference)); } if (allowExpressions && isValue) { items.Add(CreateSpecialItem("@(", "Item reference", KnownImages.MSBuildItem, MSBuildSpecialCommitKind.ItemReference)); if (IsMetadataAllowed(triggerExpression, rr)) { items.Add(CreateSpecialItem("%(", "Metadata reference", KnownImages.MSBuildItem, MSBuildSpecialCommitKind.MetadataReference)); } } if (items.Count > 0) { return(CreateCompletionContext(items)); } return(CompletionContext.Empty); }
Task <ICompletionDataList> HandleExpressionCompletion(MSBuildResolveResult rr, CancellationToken token) { var doc = GetDocument(); if (!ExpressionCompletion.IsPossibleExpressionCompletionContext(Tracker.Engine)) { return(null); } string expression = GetAttributeOrElementTextToCaret(); var triggerState = ExpressionCompletion.GetTriggerState( expression, rr.IsCondition(), out int triggerLength, out ExpressionNode triggerExpression, out IReadOnlyList <ExpressionNode> comparandVariables ); if (triggerState == ExpressionCompletion.TriggerState.None) { return(null); } var info = rr.GetElementOrAttributeValueInfo(doc); if (info == null) { return(null); } var kind = MSBuildCompletionExtensions.InferValueKindIfUnknown(info); if (!ExpressionCompletion.ValidateListPermitted(ref triggerState, kind)) { return(null); } bool allowExpressions = kind.AllowExpressions(); kind = kind.GetScalarType(); if (kind == MSBuildValueKind.Data || kind == MSBuildValueKind.Nothing) { return(null); } var list = new CompletionDataList { TriggerWordLength = triggerLength, AutoSelect = false }; if (comparandVariables != null && triggerState == ExpressionCompletion.TriggerState.Value) { foreach (var ci in ExpressionCompletion.GetComparandCompletions(doc, comparandVariables)) { list.Add(new MSBuildCompletionData(ci, doc, rr, XmlCompletionData.DataType.XmlAttributeValue)); } } if (triggerState == ExpressionCompletion.TriggerState.Value) { switch (kind) { case MSBuildValueKind.NuGetID: return(GetPackageNameCompletions(doc, Editor.CaretOffset - triggerLength, triggerLength)); case MSBuildValueKind.NuGetVersion: return(GetPackageVersionCompletions(doc, rr, Editor.CaretOffset - triggerLength, triggerLength)); case MSBuildValueKind.Sdk: case MSBuildValueKind.SdkWithVersion: return(GetSdkCompletions(triggerLength, token)); case MSBuildValueKind.Guid: list.Add(new GenerateGuidCompletionData()); break; case MSBuildValueKind.Lcid: foreach (var culture in System.Globalization.CultureInfo.GetCultures(System.Globalization.CultureTypes.AllCultures)) { string name = culture.Name; string id = culture.LCID.ToString(); string display = culture.DisplayName; //insert multiple versions for matching on both the name and the number list.Add(new CompletionData(id, null, display)); list.Add(new CompletionData(display, null, id, id)); } break; } } //TODO: better metadata support IEnumerable <BaseInfo> cinfos; if (info.Values != null && info.Values.Count > 0 && triggerState == ExpressionCompletion.TriggerState.Value) { cinfos = info.Values; } else { cinfos = ExpressionCompletion.GetCompletionInfos(rr, triggerState, kind, triggerExpression, triggerLength, doc); } if (cinfos != null) { foreach (var ci in cinfos) { list.Add(new MSBuildCompletionData(ci, doc, rr, XmlCompletionData.DataType.XmlAttributeValue)); } } if (allowExpressions && triggerState == ExpressionCompletion.TriggerState.Value) { list.Add(new CompletionDataWithSkipCharAndRetrigger("$(", "md-variable", "Property value reference", "$(|)", ')')); list.Add(new CompletionDataWithSkipCharAndRetrigger("@(", "md-variable", "Item list reference", "@(|)", ')')); } if (list.Count > 0) { return(Task.FromResult <ICompletionDataList> (list)); } return(null); }