public void Run(XElement element, MSBuildLanguageElement resolvedElement, string filename, ITextSource textDocument, MSBuildDocument document, int offset = 0, int length = 0) { Filename = filename; Document = document; Extension = System.IO.Path.GetExtension(filename); //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 TextDocument = textDocument as IReadonlyTextDocument ?? TextEditorFactory.CreateNewReadonlyDocument( textDocument, filename, MSBuildTextEditorExtension.MSBuildMimeType ); range = new DocumentRegion( TextDocument.OffsetToLocation(offset), length > 0 ? TextDocument.OffsetToLocation(length + offset) : new DocumentLocation(int.MaxValue, int.MaxValue)); if (resolvedElement != null) { VisitResolvedElement(element, resolvedElement); } else if (element != null) { ResolveAndVisit(element, null); } }
void LoadTasks( HashSet <string> importedFiles, MSBuildDocument previous, string filename, PropertyValueCollector propVals, TaskMetadataBuilder taskBuilder, MSBuildSchemaProvider schemaProvider, CancellationToken token) { try { var import = GetCachedOrParse(importedFiles, previous, filename, null, File.GetLastWriteTimeUtc(filename), Filename, propVals, taskBuilder, schemaProvider, token); Imports.Add(filename, import); } catch (Exception ex) { LoggingService.LogError($"Error loading tasks file {filename}", ex); } }
Import GetCachedOrParse( HashSet <string> importedFiles, MSBuildDocument oldDoc, string filename, string sdk, DateTime mtimeUtc, string projectPath, PropertyValueCollector propVals, TaskMetadataBuilder taskBuilder, MSBuildSchemaProvider schemaProvider, CancellationToken token) { if (oldDoc != null && oldDoc.Imports.TryGetValue(filename, out Import oldImport) && oldImport.TimeStampUtc == mtimeUtc) { //TODO: check mtimes of descendent imports too return(oldImport); } else { //TODO: guard against cyclic imports return(ParseImport(importedFiles, new Import(filename, sdk, mtimeUtc), projectPath, propVals, taskBuilder, schemaProvider, token)); } }
public void Run(XElement element, MSBuildLanguageElement resolvedElement, string filename, ITextSource textDocument, MSBuildDocument document) { Filename = filename; Document = document; //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 TextDocument = textDocument as IReadonlyTextDocument ?? TextEditorFactory.CreateNewReadonlyDocument( textDocument, filename, MSBuildTextEditorExtension.MSBuildMimeType ); if (resolvedElement != null) { VisitResolvedElement(element, resolvedElement); } else if (element != null) { ResolveAndVisit(element, null); } }
public void Run(XDocument xDocument, string filename, ITextSource textDocument, MSBuildDocument doc, int offset = 0, int length = 0) { Run(xDocument.RootElement, null, filename, textDocument, doc, offset, length); }
public void Run(XDocument xDocument, string filename, ITextSource textDocument, MSBuildDocument doc) { Run(xDocument.RootElement, null, filename, textDocument, doc); }
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; }