bool ExpandSelection(List <XObject> nodePath, XmlSpineParser spine, SnapshotSpan activeSpan, ref int index, ref SelectionLevel level) { if (index - 1 < 0) { return(false); } //if an index is selected, we may need to transition level rather than transitioning index if (index < nodePath.Count) { var current = nodePath[index]; if (current is XElement element) { switch (level) { case SelectionLevel.Self: if (spine != null && !spine.AdvanceUntilClosed(element, activeSpan.Snapshot, 5000)) { return(false); } if (!element.IsSelfClosing) { level = SelectionLevel.OuterElement; return(true); } break; case SelectionLevel.Content: level = SelectionLevel.OuterElement; return(true); case SelectionLevel.Name: level = SelectionLevel.Self; return(true); case SelectionLevel.Attributes: level = SelectionLevel.Self; return(true); } } else if (current is XAttribute) { switch (level) { case SelectionLevel.Name: case SelectionLevel.Content: level = SelectionLevel.Self; return(true); } } else if (level == SelectionLevel.Name) { level = SelectionLevel.Self; return(true); } else if (level == SelectionLevel.Document) { return(false); } } //advance up the node path index--; var newNode = nodePath[index]; //determine the starting selection level for the new node if (newNode is XDocument) { level = SelectionLevel.Document; return(true); } if (spine != null && !spine.AdvanceUntilEnded(newNode, activeSpan.Snapshot, 5000)) { return(false); } bool ContainsSelection(TextSpan span) => activeSpan.Start >= span.Start && activeSpan.End <= span.End; if (ContainsSelection(newNode.Span)) { if ((newNode as INamedXObject)?.NameSpan is TextSpan nr && ContainsSelection(nr)) { level = SelectionLevel.Name; return(true); } if (newNode is XAttribute attribute) { var valRegion = attribute.ValueSpan; if (ContainsSelection(valRegion)) { level = SelectionLevel.Content; return(true); } } if (newNode is XText) { level = SelectionLevel.Content; return(true); } if (newNode is XElement xElement && xElement.Attributes.Count > 1) { if (xElement.GetAttributesSpan() is TextSpan attsSpan && ContainsSelection(attsSpan)) { level = SelectionLevel.Attributes; return(true); } } level = SelectionLevel.Self; return(true); } if (spine != null && !spine.AdvanceUntilClosed(newNode, activeSpan.Snapshot, 5000)) { return(false); } if (newNode is XElement el && el.ClosingTag != null) { if (el.IsSelfClosing) { level = SelectionLevel.Self; return(true); } if (ContainsSelection((TextSpan)el.InnerSpan)) { level = SelectionLevel.Content; return(true); } level = SelectionLevel.OuterElement; return(true); } level = SelectionLevel.Self; return(true); }
/// <summary> /// Advances the parser until the specified object is ended. /// </summary> /// <param name="parser">A spine parser. Its state will be modified.</param> /// <param name="ob">The object to complete</param> /// <param name="snapshot"></param> /// <param name="snapshot">The text snapshot corresponding to the parser.</param> /// <param name="maximumReadahead">Maximum number of characters to advance before giving up.</param> /// <returns>Whether the object was successfully completed</returns> public static bool AdvanceUntilEnded(this XmlSpineParser parser, XObject ob, ITextSnapshot snapshot, int maximumReadahead = DEFAULT_READAHEAD_LIMIT) => parser.AdvanceUntilEnded(ob, new SnapshotTextSource(snapshot), maximumReadahead);