/// <summary> /// PARAGRAPH /// </summary> /// <remarks>The parsing operation will always succeed.</remarks> private LineNode ParseCompactParagraph(LineNode lastNode) { var mergeTo = lastNode as Paragraph; if (mergeTo != null && !mergeTo.Compact) { mergeTo = null; } // Create a new paragraph, or merge the new line to the last unclosed paragraph. ParseStart(); if (mergeTo != null) { // This won't throw exception. See (A) in ParseLineEnd. var paraTail = (PlainText)mergeTo.Inlines.LastNode; paraTail.Content += "\n"; IWikitextLineInfo paraTailSpan = paraTail; Debug.Assert(((IWikitextLineInfo)mergeTo).EndLinePosition == paraTailSpan.EndLinePosition); paraTail.ExtendLineInfo(paraTailSpan.EndLineNumber + 1, 0); mergeTo.ExtendLineInfo(paraTailSpan.EndLineNumber + 1, 0); } var node = mergeTo ?? new Paragraph(); // Allows an empty paragraph/line. ParseRun(RunParsingMode.Run, node, false); if (mergeTo != null) { // Amend the line position lastNode.ExtendLineInfo(lineNumber, linePosition); return(ParseSuccessful(EMPTY_LINE_NODE, false)); } return(ParseSuccessful(node)); }
private Node TraceNode(Node root, Position position) { foreach (var node in root.EnumChildren()) { IWikitextLineInfo span = node; Debug.Assert(span.HasLineInfo); if (span.StartLineNumber > position.Line) { continue; } if (span.EndLineNumber < position.Line) { continue; } if (span.StartLineNumber == position.Line && span.StartLinePosition > position.Character) { continue; } if (span.EndLineNumber == position.Line && span.EndLinePosition < position.Character) { continue; } return(TraceNode(node, position)); } return(root); }
public Hover GetHover(Position position) { var node = TraceNode(position); if (node == null) { return(null); } Node prevNode = null; var nodeTrace = new List <string>(); IWikitextLineInfo focusNode = null; while (node != null) { switch (node) { case Template _: if (prevNode is TemplateArgument) { break; // We will show template name in NodeToMd(TemplateArgument) } goto SHOW_NODE; case TagNode _: if (prevNode is TagAttribute) { break; // We will show template name in NodeToMd(TagAttribute) } goto SHOW_NODE; case TemplateArgument _: case ArgumentReference _: case WikiLink _: case ExternalLink _: case FormatSwitch _: case TagAttribute _: case Comment _: SHOW_NODE: if (focusNode == null) { focusNode = node; } nodeTrace.Add(Utility.NodeToMd(node)); break; } prevNode = node; node = node.ParentNode; } if (focusNode == null) { return(null); } Debug.Assert(focusNode.HasLineInfo); nodeTrace.Reverse(); return(new Hover(string.Join(" → ", nodeTrace), focusNode.ToRange())); }
public static Range ToRange(this IWikitextLineInfo thisNode) { if (thisNode == null) { throw new ArgumentNullException(nameof(thisNode)); } Debug.Assert(thisNode.HasLineInfo); return(new Range(thisNode.StartLineNumber, thisNode.StartLinePosition, thisNode.EndLineNumber, thisNode.EndLinePosition)); }
/// <summary> /// Gets the text to the left-hand-side of the cart. Used for auto-completion. /// </summary> private string GetTypedLhsText(PlainText node, Position caretPosition) { IWikitextLineInfo li = node; Debug.Assert(li.HasLineInfo); var startPos = new Position(li.StartLineNumber, li.StartLinePosition); Debug.Assert(startPos <= caretPosition); Debug.Assert(new Position(li.EndLineNumber, li.EndLinePosition) >= caretPosition); return(TextDocument.GetRange(new Range(startPos, caretPosition))); }
public void EnumDescendantsTest() { // I'm lazy. That's all. var root = ParseAndAssert( "{{Translating|[[:en:Test]]|tpercent=20}}\n[[]]<div style=\"background: red\">{{T|Translating|source|3=tpercent=percentage of completion}}</div>", "P[{{Translating|P[[[:en:Test]]]|P[tpercent]=P[20]}}\n$[$[$]$]<div style=\"background: red\">P[{{T|P[Translating]|P[source]|P[3]=P[tpercent=percentage of completion]}}]</div>]"); Trace.WriteLine("Descendants Dump:"); foreach (var node in root.EnumDescendants()) { var si = (IWikitextLineInfo)node; Assert.True(si.HasLineInfo); Trace.WriteLine( $"{node.GetType().Name}\t({si.StartLineNumber},{si.StartLinePosition})-({si.EndLineNumber},{si.EndLinePosition})\t[|{node}|]"); if (node is IInlineContainer container) { IWikitextLineInfo lastChild = null; foreach (IWikitextLineInfo child in container.Inlines) { if (lastChild != null) { if (lastChild.EndLineNumber == child.StartLineNumber) { Assert.True(lastChild.EndLinePosition == child.StartLinePosition, "LineInfo of Inline sequence is not consequent."); } else { Assert.True(child.StartLinePosition == 0, "LineInfo of Inline sequence is not consequent."); } } lastChild = child; } } } var nn = root.Lines.FirstNode.NextNode; root.Lines.FirstNode.Remove(); Assert.Equal(root.Lines.FirstNode, nn); }