private void XmlEditor_TextChanged(DependencyObject sender, DependencyProperty dp) { // Text changed, we need to clear everything and re-parse XmlEditor.Decorations.Clear(); // Actually invoke the XmlParser Parser _lastRoot = Parser.ParseText(XmlEditor.Text); // Translate our parsed tree to our set of UI-ready nodes var list = new List <XmlSyntaxData>(); list.Add(XmlSyntaxData.FromNode(_lastRoot)); RootNodes = list; // Update our current location's status UpdateCurrentInfo(); }
/// <summary> /// This function just provides a bit of info about the Xml Node that's at the caret position in the Editor. /// </summary> private async void UpdateCurrentInfo() { // Figure out where we are. CurrentPosition = await XmlEditor.GetPositionAsync(); if (CurrentPosition == null) { return; } // Break this down to convert between the Monaco editor and the index our Xml Parser knows about. var index = XmlEditor.Text.GetCharacterIndex((int)CurrentPosition.LineNumber, (int)CurrentPosition.Column); if (index == -1) { return; } // Use the caret position (as index) to find the corresponding Xml Node from our parsed tree. var raw_node = _lastRoot.FindNode(index + 1); var node = XmlSyntaxData.FromNode(raw_node, false); // Translate to our UI-Friendly object XmlSyntaxData parent = null; if (raw_node.Parent != null) { parent = XmlSyntaxData.FromNode(raw_node.Parent, false); // Do the same for the Parent (if we have one) } TreeView_ScrollNode(raw_node); // Show Item in Tree if (node != null) { // Refetch proper line/col from start of token (as it may start earlier than where the caret is) var(line_s, col_s) = XmlEditor.Text.GetLineColumnIndex(node.SpanStart); // Translate from Xml Parser to Monaco positions. var(line_e, col_e) = XmlEditor.Text.GetLineColumnIndex(node.SpanEnd - 1); // Provide info in our UI box. ElementInfo = node.Text + Environment.NewLine; ElementInfo += node.Type + Environment.NewLine; ElementInfo += "Parent:" + parent?.Type + Environment.NewLine; ElementInfo += "Parent Element:" + raw_node?.ParentElement?.Name + Environment.NewLine; } }
/// <summary> /// Reads in a <see cref="SyntaxNode"/> and returns a <see cref="XmlSyntaxData"/> /// </summary> /// <param name="node">Parsed Xml Node</param> /// <param name="withChildren">Include children in this new node.</param> /// <returns>UI ready data.</returns> public static XmlSyntaxData FromNode(SyntaxNode node, bool withChildren = true) { return(new XmlSyntaxData() { HashId = node.GetHashCode(), Type = node.IsList ? "SyntaxList" : node.GetType().Name, TypeClass = node.IsList ? "list" : (node.IsToken ? "token" : "syntax"), Text = node.IsToken ? (node as SyntaxToken).Text : string.Empty, Errors = node.ContainsDiagnostics ? node.GetDiagnostics().Select(d => new XmlSyntaxError() { Id = d.ErrorID, Description = d.GetDescription() }).ToList() : Array.Empty <XmlSyntaxError>().ToList(), SpanStart = node.FullSpan.Start, SpanEnd = node.FullSpan.End, Children = withChildren ? node.ChildNodes.Select(child => XmlSyntaxData.FromNode(child)).ToList() : Array.Empty <XmlSyntaxData>().ToList() }); }
private async void XmlEditor_Loading(object sender, RoutedEventArgs e) { var languages = new Monaco.LanguagesHelper(XmlEditor); await languages.RegisterHoverProviderAsync("xml", (model, position) => { return(AsyncInfo.Run(async delegate(CancellationToken cancelationToken) { // Figure out where we our in relation to our Xml Tree var index = XmlEditor.Text.GetCharacterIndex((int)position.LineNumber, (int)position.Column); if (index == -1) { return default; } // Get that node from the Xml Parser and wrap it in a friendly container. var node = XmlSyntaxData.FromNode(_lastRoot.FindNode(index + 1), false); if (node != null) { // Refetch proper line/col from start of token var(line_s, col_s) = XmlEditor.Text.GetLineColumnIndex(node.SpanStart); var(line_e, col_e) = XmlEditor.Text.GetLineColumnIndex(node.SpanEnd - 1); // Provide nice UI on hover to show more info about the node. return new Hover(new string[] { "*" + node.Type + "* " + node.Text + " [" + node.SpanStart + ".." + node.SpanEnd + ")", "Line: " + line_s + " Col: " + col_s + " Length: " + node.Length }, new Range((uint)line_s, (uint)col_s, (uint)line_e, (uint)col_e + 1)); } return default; })); });