Port expand selection tests
This commit is contained in:
Родитель
5f73e5bcd5
Коммит
a2903de9e1
|
@ -53,16 +53,6 @@ namespace MonoDevelop.Xml.Dom
|
|||
}
|
||||
}
|
||||
|
||||
public IEnumerable<XObject> SelfAndParents {
|
||||
get {
|
||||
var next = this;
|
||||
while (next != null) {
|
||||
yield return next;
|
||||
next = next.Parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public TextSpan Span { get; protected set; }
|
||||
|
||||
public void End (int offset)
|
||||
|
|
|
@ -57,8 +57,8 @@ namespace MonoDevelop.Xml.Parser
|
|||
// so attach a node to the DOM and end the state
|
||||
var comment = (XComment) context.Nodes.Pop ();
|
||||
|
||||
comment.End (context.Position + 1);
|
||||
if (context.BuildTree) {
|
||||
comment.End (context.Position + 1);
|
||||
((XContainer) context.Nodes.Peek ()).AddChildNode (comment);
|
||||
}
|
||||
|
||||
|
|
|
@ -224,5 +224,6 @@ namespace MonoDevelop.Xml.Parser
|
|||
internal static bool MaybeDocType (XmlParser parser) => parser.CurrentState is XmlRootState && parser.GetContext ().StateTag == DOCTYPE;
|
||||
internal static bool MaybeComment (XmlParser parser) => parser.CurrentState is XmlRootState && parser.GetContext ().StateTag == COMMENT;
|
||||
internal static bool MaybeCDataOrCommentOrDocType (XmlParser parser) => parser.CurrentState is XmlRootState && parser.GetContext ().StateTag == BRACKET_EXCLAM;
|
||||
public static bool IsNotFree (XmlParser parser) => parser.CurrentState is XmlRootState && parser.GetContext ().StateTag != FREE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,8 +58,7 @@ namespace MonoDevelop.Xml.Editor.Completion
|
|||
// if we're completing an existing element, remove it from the path
|
||||
// so we don't get completions for its children instead
|
||||
if (nodePath.Count > 0) {
|
||||
var lastNode = nodePath[nodePath.Count - 1] as XElement;
|
||||
if (lastNode != null && lastNode.Name.Length == applicableToSpan.Length) {
|
||||
if (nodePath[nodePath.Count-1] is XElement leaf && leaf.Name.Length == applicableToSpan.Length) {
|
||||
nodePath.RemoveAt (nodePath.Count - 1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,16 +56,17 @@ namespace MonoDevelop.Xml.Editor.TextStructure
|
|||
XmlParser spine = null;
|
||||
if (lastParse != null && lastParse.TextSnapshot.Version.VersionNumber == activeSpan.Snapshot.Version.VersionNumber) {
|
||||
var n = lastParse.XDocument.FindAtOrBeforeOffset (activeSpan.Start.Position);
|
||||
nodePath = n.SelfAndParents.ToList ();
|
||||
nodePath = n.GetPath ();
|
||||
} else {
|
||||
spine = parser.GetSpineParser (activeSpan.End);
|
||||
nodePath = spine.GetNodePathWithCompleteLeafElement (activeSpan.Snapshot);
|
||||
//put spine parser in tree parser mode so it connects element closing nodes
|
||||
spine = parser.GetSpineParser (activeSpan.Start).GetTreeParser ();
|
||||
nodePath = spine.AdvanceToNodeEndAndGetNodePath (activeSpan.Snapshot);
|
||||
}
|
||||
|
||||
// this is a little odd because it was ported from MonoDevelop, where it has to maintain its own stack of state
|
||||
// for contract selection. it describes the current semantic selection as a node path, the index of the node in that path
|
||||
// that's selected, and the kind of selection that node has.
|
||||
int selectedNodeIndex = -1;
|
||||
int selectedNodeIndex = nodePath.Count;
|
||||
SelectionLevel selectionLevel = default;
|
||||
|
||||
// keep on expanding the selection until we find one that contains the current selection but is a little bigger
|
||||
|
@ -91,7 +92,7 @@ namespace MonoDevelop.Xml.Editor.TextStructure
|
|||
|
||||
TextSpan? GetSelectionSpan (ITextSnapshot snapshot, List<XObject> nodePath, ref int index, ref SelectionLevel level)
|
||||
{
|
||||
if (index < 0) {
|
||||
if (index < 0 || index >= nodePath.Count) {
|
||||
return null;
|
||||
}
|
||||
var current = nodePath[index];
|
||||
|
@ -124,16 +125,19 @@ namespace MonoDevelop.Xml.Editor.TextStructure
|
|||
|
||||
bool ExpandSelection (List<XObject> nodePath, XmlParser spine, SnapshotSpan activeSpan, ref int index, ref SelectionLevel level)
|
||||
{
|
||||
if (index + 1 == nodePath.Count) {
|
||||
if (index - 1 < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//if an index is selected, we may need to transition level rather than transitioning index
|
||||
if (index >= 0) {
|
||||
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;
|
||||
|
@ -165,7 +169,7 @@ namespace MonoDevelop.Xml.Editor.TextStructure
|
|||
}
|
||||
|
||||
//advance up the node path
|
||||
index++;
|
||||
index--;
|
||||
var newNode = nodePath[index];
|
||||
|
||||
//determine the starting selection level for the new node
|
||||
|
@ -174,7 +178,7 @@ namespace MonoDevelop.Xml.Editor.TextStructure
|
|||
return true;
|
||||
}
|
||||
|
||||
if (spine != null && !spine.AdvanceUntilClosed (newNode, activeSpan.Snapshot, 5000)) {
|
||||
if (spine != null && !spine.AdvanceUntilEnded (newNode, activeSpan.Snapshot, 5000)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -206,6 +210,10 @@ namespace MonoDevelop.Xml.Editor.TextStructure
|
|||
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;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.VisualStudio.Text;
|
||||
using MonoDevelop.Xml.Dom;
|
||||
using MonoDevelop.Xml.Parser;
|
||||
|
@ -12,6 +12,8 @@ namespace MonoDevelop.Xml.Editor
|
|||
{
|
||||
public static class XmlParserExtensions
|
||||
{
|
||||
const int DEFAULT_READAHEAD_LIMIT = 5000;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the XML name at the parser's position.
|
||||
/// </summary>
|
||||
|
@ -78,8 +80,12 @@ namespace MonoDevelop.Xml.Editor
|
|||
/// <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 AdvanceUntilClosed (this XmlParser parser, XObject ob, ITextSnapshot snapshot, int maximumReadahead = 500)
|
||||
public static bool AdvanceUntilClosed (this XmlParser parser, XObject ob, ITextSnapshot snapshot, int maximumReadahead = DEFAULT_READAHEAD_LIMIT)
|
||||
{
|
||||
if (!parser.GetContext().BuildTree) {
|
||||
throw new ArgumentException ("Parser must be in tree mode");
|
||||
}
|
||||
|
||||
var el = ob as XElement;
|
||||
if (el == null) {
|
||||
return AdvanceUntilEnded (parser, ob, snapshot, maximumReadahead);
|
||||
|
@ -93,7 +99,8 @@ namespace MonoDevelop.Xml.Editor
|
|||
if (el.IsClosed) {
|
||||
return true;
|
||||
}
|
||||
if (parser.Nodes.Count < startingDepth) {
|
||||
// just in case, bail if we pop out past the element's parent
|
||||
if (parser.Nodes.Count < startingDepth - 1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -109,7 +116,7 @@ namespace MonoDevelop.Xml.Editor
|
|||
/// <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 XmlParser parser, XObject ob, ITextSnapshot snapshot, int maximumReadahead = 500)
|
||||
public static bool AdvanceUntilEnded (this XmlParser parser, XObject ob, ITextSnapshot snapshot, int maximumReadahead = DEFAULT_READAHEAD_LIMIT)
|
||||
{
|
||||
var startingDepth = parser.Nodes.Count;
|
||||
|
||||
|
@ -127,97 +134,98 @@ namespace MonoDevelop.Xml.Editor
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the node path at the parser condition. Reads ahead to complete names, but does not complete the nodes.
|
||||
/// Gets the node path at the parser position without changing the parser state, ensuring that the deepest node has a complete name.
|
||||
/// </summary>
|
||||
/// <param name="parser">A spine parser. Its state will be modified.</param>
|
||||
/// <param name="parser">A spine parser. Its state will not be modified.</param>
|
||||
/// <param name="snapshot">The text snapshot corresponding to the parser.</param>
|
||||
public static List<XObject> GetNodePath (this XmlParser spine, ITextSnapshot snapshot)
|
||||
{
|
||||
var path = new List<XObject> (spine.Nodes);
|
||||
var path = spine.Nodes.ToNodePath ();
|
||||
|
||||
//remove the root XDocument
|
||||
path.RemoveAt (path.Count - 1);
|
||||
|
||||
//complete incomplete XName if present
|
||||
if (spine.CurrentState is XmlNameState && path[0] is INamedXObject) {
|
||||
path[0] = path[0].ShallowCopy ();
|
||||
//complete last node's name without altering the parser state
|
||||
int lastIdx = path.Count - 1;
|
||||
if (spine.CurrentState is XmlNameState && path[lastIdx] is INamedXObject) {
|
||||
XName completeName = GetCompleteName (spine, snapshot);
|
||||
((INamedXObject)path[0]).Name = completeName;
|
||||
var obj = path[lastIdx] = path[lastIdx].ShallowCopy ();
|
||||
((INamedXObject)obj).Name = completeName;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Advances the parser to end the node at the current position and gets that node's path.
|
||||
/// </summary>
|
||||
/// <param name="spine">A spine parser. Its state will be modified.</param>
|
||||
/// <param name="snapshot">The text snapshot corresponding to the parser.</param>
|
||||
/// <returns></returns>
|
||||
public static List<XObject> AdvanceToNodeEndAndGetNodePath (this XmlParser spine, ITextSnapshot snapshot, int maximumReadahead = DEFAULT_READAHEAD_LIMIT)
|
||||
{
|
||||
if (!spine.GetContext ().BuildTree) {
|
||||
throw new ArgumentException ("Parser must be in tree mode");
|
||||
}
|
||||
|
||||
int startOffset = spine.Position;
|
||||
int startDepth = spine.Nodes.Count;
|
||||
|
||||
//if in potential start of a state, advance into the next state
|
||||
var end = Math.Min (snapshot.Length - spine.Position, maximumReadahead) + spine.Position;
|
||||
if (spine.Position < end && (XmlRootState.IsNotFree (spine) || (spine.CurrentState is XmlRootState && snapshot[spine.Position] == '<'))) {
|
||||
do {
|
||||
spine.Push (snapshot[spine.Position]);
|
||||
} while (spine.Position < end && XmlRootState.IsNotFree (spine));
|
||||
|
||||
//if it transitioned to another state, eat until we get a new node on the stack
|
||||
if (spine.Position < end && !(spine.CurrentState is XmlRootState) && spine.Nodes.Count <= startDepth) {
|
||||
spine.Push (snapshot[spine.Position]);
|
||||
}
|
||||
}
|
||||
|
||||
var path = spine.Nodes.ToNodePath ();
|
||||
|
||||
// make sure the leaf node is ended
|
||||
if (path.Count > 0) {
|
||||
var leaf = path[path.Count-1];
|
||||
if (!(leaf is XDocument)) {
|
||||
AdvanceUntilEnded (spine, leaf, snapshot, maximumReadahead - (spine.Position - startOffset));
|
||||
}
|
||||
//the leaf node might have a child that's a better match for the offset
|
||||
if (leaf is XContainer c && c.FindAtOffset (startOffset) is XObject o) {
|
||||
path.Add (o);
|
||||
}
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
static List<XObject> ToNodePath (this NodeStack stack)
|
||||
{
|
||||
var path = new List<XObject> (stack);
|
||||
path.Reverse ();
|
||||
return path;
|
||||
}
|
||||
|
||||
public static List<XObject> GetPath (this XObject obj)
|
||||
{
|
||||
var path = new List<XObject> ();
|
||||
while (obj != null) {
|
||||
path.Add (obj);
|
||||
obj = obj.Parent;
|
||||
}
|
||||
path.Reverse ();
|
||||
return path;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the node path at the parser condition, ensuring that the deepest element is closed.
|
||||
/// </summary>
|
||||
/// <param name="parser">A spine parser. Its state will be modified.</param>
|
||||
/// <param name="snapshot">The text snapshot corresponding to the parser.</param>
|
||||
/// <returns></returns>
|
||||
public static List<XObject> GetNodePathWithCompleteLeafElement (this XmlParser parser, ITextSnapshot snapshot)
|
||||
public static void ConnectParents (this List<XObject> nodePath)
|
||||
{
|
||||
int offset = parser.Position;
|
||||
var length = snapshot.Length;
|
||||
int i = offset;
|
||||
|
||||
var nodePath = parser.Nodes.ToList ();
|
||||
|
||||
//if inside body of unclosed element, capture whole body
|
||||
if (parser.CurrentState is XmlRootState && parser.Nodes.Peek () is XElement unclosedEl) {
|
||||
while (i < length && InRootOrClosingTagState () && !unclosedEl.IsClosed) {
|
||||
parser.Push (snapshot[i++]);
|
||||
}
|
||||
}
|
||||
|
||||
//if in potential start of a state, capture it
|
||||
else if (parser.CurrentState is XmlRootState && GetStateTag () > 0) {
|
||||
//eat until we figure out whether it's a state transition
|
||||
while (i < length && GetStateTag () > 0) {
|
||||
parser.Push (snapshot[i++]);
|
||||
}
|
||||
//if it transitioned to another state, eat until we get a new node on the stack
|
||||
if (NotInRootState ()) {
|
||||
var newState = parser.CurrentState;
|
||||
while (i < length && NotInRootState () && parser.Nodes.Count <= nodePath.Count) {
|
||||
parser.Push (snapshot[i++]);
|
||||
}
|
||||
if (parser.Nodes.Count > nodePath.Count) {
|
||||
nodePath.Insert (0, parser.Nodes.Peek ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//ensure any unfinished names are captured
|
||||
while (i < length && InNameOrAttributeState ()) {
|
||||
parser.Push (snapshot[i++]);
|
||||
}
|
||||
|
||||
//if nodes are incomplete, they won't get connected
|
||||
if (nodePath.Count > 1) {
|
||||
for (int idx = 0; idx < nodePath.Count - 1; idx++) {
|
||||
var node = nodePath[idx];
|
||||
if (node.Parent == null) {
|
||||
var parent = nodePath[idx + 1];
|
||||
node.Parent = parent;
|
||||
}
|
||||
var parent = nodePath[nodePath.Count - 1];
|
||||
for (int i = nodePath.Count - 2; i >= 0; i--) {
|
||||
var node = nodePath[i];
|
||||
node.Parent = parent;
|
||||
parent = node;
|
||||
}
|
||||
}
|
||||
|
||||
return nodePath;
|
||||
|
||||
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;
|
||||
|
||||
int GetStateTag () => ((IXmlParserContext)parser).StateTag;
|
||||
|
||||
bool NotInRootState () => !(parser.CurrentState is XmlRootState);
|
||||
}
|
||||
|
||||
public static string GetIncompleteValue (this XmlParser spineAtCaret, ITextSnapshot snapshot)
|
||||
|
|
|
@ -56,5 +56,8 @@ namespace MonoDevelop.Xml.Tests.Completion
|
|||
|
||||
public IEditorCommandHandlerServiceFactory CommandServiceFactory
|
||||
=> Host.GetService<IEditorCommandHandlerServiceFactory> ();
|
||||
|
||||
public ITextStructureNavigatorSelectorService TextStructureNavigatorSelectorService
|
||||
=> Host.GetService<ITextStructureNavigatorSelectorService> ();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,13 +38,18 @@ namespace MonoDevelop.Xml.Tests.EditorTestHelpers
|
|||
|
||||
public virtual ITextView CreateTextView (string documentText, string filename = null)
|
||||
{
|
||||
var buffer = Catalog.BufferFactoryService.CreateTextBuffer (documentText, ContentType);
|
||||
var buffer = CreateTextBuffer (documentText);
|
||||
if (filename != null) {
|
||||
Catalog.TextDocumentFactoryService.CreateTextDocument (buffer, filename);
|
||||
}
|
||||
return Catalog.TextViewFactory.CreateTextView (buffer);
|
||||
}
|
||||
|
||||
public virtual ITextBuffer CreateTextBuffer (string documentText)
|
||||
{
|
||||
return Catalog.BufferFactoryService.CreateTextBuffer (documentText, ContentType);
|
||||
}
|
||||
|
||||
protected (string document, int caretOffset) ExtractCaret (string document, char caretMarkerChar)
|
||||
{
|
||||
var caretOffset = document.IndexOf (caretMarkerChar);
|
||||
|
|
|
@ -25,24 +25,25 @@
|
|||
// THE SOFTWARE.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MonoDevelop.Ide;
|
||||
using MonoDevelop.Ide.Editor;
|
||||
using MonoDevelop.Ide.Editor.Extension;
|
||||
using Microsoft.VisualStudio.MiniEditor;
|
||||
using Microsoft.VisualStudio.Text;
|
||||
using Microsoft.VisualStudio.Text.Operations;
|
||||
using MonoDevelop.Xml.Editor;
|
||||
using MonoDevelop.Xml.Editor.Completion;
|
||||
using MonoDevelop.Xml.Tests.Completion;
|
||||
using MonoDevelop.Xml.Tests.EditorTestHelpers;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace MonoDevelop.Xml.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class ExpandSelectionTests : TextEditorExtensionTestBase
|
||||
public class ExpandSelectionTests : EditorTestBase
|
||||
{
|
||||
public static EditorExtensionTestData XmlContentData = new EditorExtensionTestData (
|
||||
fileName: "/a.xml",
|
||||
language: "C#",
|
||||
mimeType: "application/xml",
|
||||
projectFileName: "test.csproj"
|
||||
);
|
||||
protected override string ContentTypeName => XmlContentTypeNames.XmlCore;
|
||||
|
||||
protected override (EditorEnvironment, EditorCatalog) InitializeEnvironment () => TestEnvironment.EnsureInitialized ();
|
||||
|
||||
const string Document = @"<!-- this is
|
||||
a comment-->
|
||||
|
@ -65,6 +66,8 @@ a comment-->";
|
|||
</bar>
|
||||
</foo>";
|
||||
|
||||
const string TextNode = "this is some text";
|
||||
|
||||
const string AttributesFoo = @"hello=""hi"" goodbye=""bye""";
|
||||
|
||||
const string AttributeHello = @"hello=""hi""";
|
||||
|
@ -93,13 +96,6 @@ a comment-->";
|
|||
|
||||
const string CommentBar = @"<!--another comment-->";
|
||||
|
||||
protected override EditorExtensionTestData GetContentData () => XmlContentData;
|
||||
|
||||
protected override IEnumerable<TextEditorExtension> GetEditorExtensions ()
|
||||
{
|
||||
yield return new XmlTextEditorExtension ();
|
||||
}
|
||||
|
||||
//args are line, col, then the expected sequence of expansions
|
||||
[Test]
|
||||
[TestCase (1, 2, CommentDoc)]
|
||||
|
@ -107,54 +103,53 @@ a comment-->";
|
|||
[TestCase (3, 3, "foo", ElementFoo, ElementWithBodyFoo)]
|
||||
[TestCase (3, 15, "hi", AttributeHello, AttributesFoo, ElementFoo, ElementWithBodyFoo)]
|
||||
[TestCase (3, 7, "hello", AttributeHello, AttributesFoo, ElementFoo, ElementWithBodyFoo)]
|
||||
[TestCase (4, 7, BodyFoo, ElementWithBodyFoo)]
|
||||
[TestCase (4, 7, TextNode, BodyFoo, ElementWithBodyFoo)]
|
||||
[TestCase (5, 22, "done", AttributeThing, ElementBaz, BodyBar, ElementWithBodyBar, BodyFoo, ElementWithBodyFoo)]
|
||||
[TestCase (6, 12, CommentBar, BodyBar, ElementWithBodyBar, BodyFoo, ElementWithBodyFoo)]
|
||||
public async Task TestExpandShrink (object[] args)
|
||||
{
|
||||
var loc = new DocumentLocation ((int)args [0], (int)args[1]);
|
||||
using (var testCase = await SetupTestCase (Document)) {
|
||||
var doc = testCase.Document;
|
||||
doc.Editor.SetCaretLocation (loc);
|
||||
var ext = doc.GetContent<BaseXmlEditorExtension> ();
|
||||
var buffer = CreateTextBuffer (Document);
|
||||
var parser = XmlBackgroundParser.GetParser<XmlBackgroundParser> ((ITextBuffer2)buffer);
|
||||
var snapshot = buffer.CurrentSnapshot;
|
||||
var navigator = Catalog.TextStructureNavigatorSelectorService.GetTextStructureNavigator (buffer);
|
||||
var line = snapshot.GetLineFromLineNumber ((int)args[0] - 1);
|
||||
var offset = line.Start + (int)args[1] - 1;
|
||||
|
||||
//check initial state
|
||||
Assert.IsFalse (doc.Editor.IsSomethingSelected);
|
||||
Assert.AreEqual (loc, doc.Editor.CaretLocation);
|
||||
// it's extremely unlikely the parser will hve an up to date parse result yet
|
||||
// so this should use the spine parser codepath
|
||||
|
||||
//check expanding causes correct selections
|
||||
for (int i = 2; i < args.Length; i++) {
|
||||
ext.ExpandSelection ();
|
||||
Assert.AreEqual (args [i], doc.Editor.SelectedText);
|
||||
}
|
||||
SnapshotSpan Span(int s, int l) => new SnapshotSpan (snapshot, s, l);
|
||||
|
||||
//check entire doc is selected
|
||||
ext.ExpandSelection ();
|
||||
var sel = doc.Editor.SelectionRange;
|
||||
Assert.AreEqual (0, sel.Offset);
|
||||
Assert.AreEqual (Document.Length, sel.Length);
|
||||
var span = Span (offset, 0);
|
||||
|
||||
//check expanding again does not change it
|
||||
ext.ExpandSelection ();
|
||||
Assert.AreEqual (0, sel.Offset);
|
||||
Assert.AreEqual (Document.Length, sel.Length);
|
||||
|
||||
//check shrinking causes correct selections
|
||||
for (int i = args.Length - 1; i >= 2; i--) {
|
||||
ext.ShrinkSelection ();
|
||||
Assert.AreEqual (args [i], doc.Editor.SelectedText);
|
||||
}
|
||||
|
||||
//final shrink back to a caret
|
||||
ext.ShrinkSelection ();
|
||||
Assert.IsFalse (doc.Editor.IsSomethingSelected);
|
||||
Assert.AreEqual (loc, doc.Editor.CaretLocation);
|
||||
|
||||
//check shrinking again does not change it
|
||||
ext.ShrinkSelection ();
|
||||
Assert.IsFalse (doc.Editor.IsSomethingSelected);
|
||||
Assert.AreEqual (loc, doc.Editor.CaretLocation);
|
||||
//check expanding causes correct selections
|
||||
for (int i = 2; i < args.Length; i++) {
|
||||
span = navigator.GetSpanOfEnclosing (span);
|
||||
var text = snapshot.GetText (span);
|
||||
Assert.AreEqual (args[i], text);
|
||||
}
|
||||
|
||||
//check entire doc is selected
|
||||
span = navigator.GetSpanOfEnclosing (span);
|
||||
Assert.AreEqual (0, span.Start.Position);
|
||||
Assert.AreEqual (snapshot.Length, span.Length);
|
||||
|
||||
// now repeat the tests with an up to date parse result
|
||||
await parser.GetOrParseAsync (snapshot, CancellationToken.None);
|
||||
|
||||
span = Span (offset, 0);
|
||||
|
||||
//check expanding causes correct selections
|
||||
for (int i = 2; i < args.Length; i++) {
|
||||
span = navigator.GetSpanOfEnclosing (span);
|
||||
var text = snapshot.GetText (span);
|
||||
Assert.AreEqual (args[i], text);
|
||||
}
|
||||
|
||||
//check entire doc is selected
|
||||
span = navigator.GetSpanOfEnclosing (span);
|
||||
Assert.AreEqual (0, span.Start.Position);
|
||||
Assert.AreEqual (snapshot.Length, span.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
|
@ -13,7 +13,6 @@
|
|||
<ProjectReference Include="..\external\MiniEditor\Microsoft.VisualStudio.MiniEditor\Microsoft.VisualStudio.MiniEditor.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Remove="ExpandSelectionTests.cs" />
|
||||
<Compile Remove="Schema\SchemaAssociationTests.cs" />
|
||||
<Compile Remove="Schema\XmlSchemaNamespaceTests.cs" />
|
||||
</ItemGroup>
|
||||
|
@ -26,7 +25,6 @@
|
|||
<EmbeddedResource Include="Schema\XMLSchema.xsd" LogicalName="XMLSchema.xsd" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="ExpandSelectionTests.cs" />
|
||||
<None Include="Schema\SchemaAssociationTests.cs" />
|
||||
<None Include="Schema\XmlSchemaNamespaceTests.cs" />
|
||||
</ItemGroup>
|
||||
|
|
Загрузка…
Ссылка в новой задаче