public static IEnumerable <BaseInfo> GetCompletionInfos( MSBuildResolveResult rr, TriggerState trigger, MSBuildValueKind kind, ExpressionNode triggerExpression, int triggerLength, MSBuildRootDocument doc) { switch (trigger) { case TriggerState.Value: return(MSBuildCompletionExtensions.GetValueCompletions(kind, doc, rr)); case TriggerState.Item: return(doc.GetItems()); case TriggerState.Metadata: return(doc.GetMetadata(null, true)); case TriggerState.Property: return(doc.GetProperties(true)); case TriggerState.MetadataOrItem: return(((IEnumerable <BaseInfo>)doc.GetItems()).Concat(doc.GetMetadata(null, true))); case TriggerState.DirectorySeparator: return(MSBuildCompletionExtensions.GetFilenameCompletions(kind, doc, triggerExpression, triggerLength));; case TriggerState.MethodName: return(FunctionCompletion.GetMethodNameCompletions(triggerExpression)); } throw new InvalidOperationException(); }
public static MSBuildNavigationResult GetNavigation( MSBuildRootDocument doc, DocumentLocation location, MSBuildResolveResult rr) { if (rr == null) { return(null); } //HACK: we should really use the ITextSource directly, but since the XML parser positions are //currently line/col, we need a TextDocument to convert to offsets var textDocument = doc.Text as IReadonlyTextDocument ?? TextEditorFactory.CreateNewReadonlyDocument( doc.Text, doc.Filename, MSBuildTextEditorExtension.MSBuildMimeType ); var annotations = GetAnnotationsAtLocation <NavigationAnnotation> (doc, location); var firstAnnotation = annotations.FirstOrDefault(); if (firstAnnotation != null) { var beginOffset = textDocument.LocationToOffset(firstAnnotation.Region.Begin); var endOffset = textDocument.LocationToOffset(firstAnnotation.Region.End); return(new MSBuildNavigationResult( annotations.Select(a => a.Path).ToArray(), beginOffset, endOffset - beginOffset + 1 )); } if (rr.ReferenceKind == MSBuildReferenceKind.Target) { return(new MSBuildNavigationResult( MSBuildReferenceKind.Target, (string)rr.Reference, rr.ReferenceOffset, rr.ReferenceLength )); } if (rr.ReferenceKind == MSBuildReferenceKind.FileOrFolder) { return(new MSBuildNavigationResult( (string[])rr.Reference, rr.ReferenceOffset, rr.ReferenceLength )); } if (rr.ReferenceKind == MSBuildReferenceKind.Task) { var task = doc.GetTask((string)rr.Reference); if (task.DeclaredInFile != null) { return(new MSBuildNavigationResult( MSBuildReferenceKind.Task, (string)rr.Reference, rr.ReferenceOffset, rr.ReferenceLength, task.DeclaredInFile, task.DeclaredAtLocation )); } } return(null); }
public static bool CanNavigate(MSBuildRootDocument doc, DocumentLocation location, MSBuildResolveResult rr) { if (rr == null) { return(false); } var annotations = GetAnnotationsAtLocation <NavigationAnnotation> (doc, location); if (annotations != null && annotations.Any()) { return(true); } if (rr.ReferenceKind == MSBuildReferenceKind.Target) { return(true); } if (rr.ReferenceKind == MSBuildReferenceKind.FileOrFolder) { return(true); } return(false); }
public static bool IsCondition(this MSBuildResolveResult rr) { return(rr.LanguageAttribute != null && rr.LanguageAttribute.ValueKind == MSBuildValueKind.Condition); }
public static MSBuildResolveResult Resolve( XmlParser parser, IReadonlyTextDocument document, MSBuildDocument context) { int offset = parser.Position; //clones and connects nodes to their parents parser = parser.GetTreeParser(); var nodePath = parser.Nodes.ToList(); nodePath.Reverse(); //capture incomplete names, attributes and element values int i = offset; if (parser.CurrentState is XmlRootState && parser.Nodes.Peek() is XElement unclosedEl) { while (i < document.Length && InRootOrClosingTagState() && !unclosedEl.IsClosed) { parser.Push(document.GetCharAt(i++)); } } else { while (i < document.Length && InNameOrAttributeState()) { parser.Push(document.GetCharAt(i++)); } } //if nodes are incomplete, they won't get connected //HACK: the only way to reconnect them is reflection if (nodePath.Count > 1) { for (int idx = 1; idx < nodePath.Count; idx++) { var node = nodePath [idx]; if (node.Parent == null) { var parent = nodePath [idx - 1]; ParentProp.SetValue(node, parent); } } } //need to look up element by walking how the path, since at each level, if the parent has special children, //then that gives us information to identify the type of its children MSBuildLanguageElement languageElement = null; MSBuildLanguageAttribute languageAttribute = null; XElement el = null; XAttribute att = null; foreach (var node in nodePath) { if (node is XAttribute xatt && xatt.Name.Prefix == null) { att = xatt; languageAttribute = languageElement?.GetAttribute(att.Name.Name); break; } //if children of parent is known to be arbitrary data, don't go into it if (languageElement != null && languageElement.ValueKind == MSBuildValueKind.Data) { break; } //code completion is forgiving, all we care about best guess resolve for deepest child if (node is XElement xel && xel.Name.Prefix == null) { el = xel; languageElement = MSBuildLanguageElement.Get(el.Name.Name, languageElement); if (languageElement != null) { continue; } } languageElement = null; } if (languageElement == null) { return(null); } var rr = new MSBuildResolveResult { LanguageElement = languageElement, LanguageAttribute = languageAttribute, XElement = el, XAttribute = att }; var rv = new MSBuildResolveVisitor(offset, rr); rv.Run(el, languageElement, document.FileName, document, context); return(rr); bool InNameOrAttributeState() => parser.CurrentState is XmlNameState || parser.CurrentState is XmlAttributeState || parser.CurrentState is XmlAttributeValueState; bool InRootOrClosingTagState() => parser.CurrentState is XmlRootState || parser.CurrentState is XmlNameState || parser.CurrentState is XmlClosingTagState; }
public MSBuildResolveVisitor(int offset, MSBuildResolveResult rr) { this.offset = offset; this.rr = rr; }