public void TryCloseTag(ITextChange textChange, IList <TextManipulation> manipulations) { var currentTag = _state.ParseCurrentTagName(); if (textChange.NewText == "/" && !string.IsNullOrEmpty(currentTag) && currentTag != "/") { var text = _text.Span; int pos = _state.ParserPos; char c = ' '; while (char.IsWhiteSpace(c) && text.Length > pos + 1) { pos++; c = text[pos]; } bool tagAlreadyClosed = c == '>'; if (!tagAlreadyClosed) { manipulations.Add(TextManipulation.Insert(_position + 1, $">")); } else { var closingTagPos = FindClosingTag(currentTag, pos + 1); if (closingTagPos != null) { manipulations.Add(TextManipulation.Insert(_position + 1, $">")); manipulations.Add(TextManipulation.Delete(_position + 1, closingTagPos.Value - _position)); } } } }
private void SynchronizeStartAndEndTag(ITextChange textChange, List <TextManipulation> maniplations) { if (!textChange.NewText.All(n => char.IsLetterOrDigit(n) || XmlNameSpecialCharacters.Contains(n))) { return; } string startTag = _state.ParseCurrentTagName(); int? maybeTagStart = _state.CurrentValueStart; if (maybeTagStart == null) { return; } int startPos = maybeTagStart.Value; // add 1 to take opening < into account if (startTag.EndsWith("/")) { return; // start tag is self-closing } if (textChange.NewPosition < startPos || textChange.NewPosition > startPos + startTag.Length) { return; //we are not editing tag name } XmlParser searchEndTag = _state.Clone(); if (searchEndTag.SeekClosingTag()) { string endTag = searchEndTag.ParseCurrentTagName(); if (endTag[0] != '/') { return; } maybeTagStart = searchEndTag.CurrentValueStart; if (maybeTagStart == null) { return; } int endPos = maybeTagStart.Value; // add 1 to take opening < into account // reverse change to start tag startTag = textChange.ReverseOn(startTag, startPos); bool isTheSameTag = endTag.Length > 0 && endTag.Substring(1) == startTag; if (isTheSameTag) { maniplations.AddRange(textChange.AsManipulations(endPos - startPos)); } } }