/// <summary> /// This can use input files with an (optionally) annotated span 'Selection' and a cursor position ($$), /// and use it to create a selected span in the TextView. /// /// For instance, the following will create a TextView that has a multiline selection with the cursor at the end. /// /// Sub Goo /// {|Selection:SomeMethodCall() /// AnotherMethodCall()$$|} /// End Sub /// /// You can use multiple selection spans to create box selections. /// /// Sub Goo /// {|Selection:$$box|}11111 /// {|Selection:sel|}111 /// {|Selection:ect|}1 /// {|Selection:ion|}1111111 /// End Sub /// </summary> public AbstractCommandHandlerTestState( XElement workspaceElement, ExportProvider exportProvider, string workspaceKind, XElement cursorDocumentElement = null, ImmutableArray <string> roles = default) { this.Workspace = TestWorkspace.CreateWorkspace( workspaceElement, exportProvider: exportProvider, workspaceKind: workspaceKind); TestHostDocument cursorDocument; if (cursorDocumentElement == null) { cursorDocument = this.Workspace.Documents.First(d => d.CursorPosition.HasValue); } else { var languageName = Workspace.Projects.First().Language; cursorDocument = TestWorkspace.CreateDocument(cursorDocumentElement, exportProvider, Workspace.Services.GetLanguageServices(languageName), roles); } _textView = cursorDocument.GetTextView(); _subjectBuffer = cursorDocument.GetTextBuffer(); if (cursorDocument.AnnotatedSpans.TryGetValue("Selection", out var selectionSpanList)) { var firstSpan = selectionSpanList.First(); var lastSpan = selectionSpanList.Last(); var cursorPosition = cursorDocument.CursorPosition.Value; Assert.True(cursorPosition == firstSpan.Start || cursorPosition == firstSpan.End || cursorPosition == lastSpan.Start || cursorPosition == lastSpan.End, "cursorPosition wasn't at an endpoint of the 'Selection' annotated span"); _textView.Selection.Mode = selectionSpanList.Length > 1 ? TextSelectionMode.Box : TextSelectionMode.Stream; SnapshotPoint boxSelectionStart, boxSelectionEnd; bool isReversed; if (cursorPosition == firstSpan.Start || cursorPosition == lastSpan.End) { // Top-left and bottom-right corners used as anchor points. boxSelectionStart = new SnapshotPoint(_subjectBuffer.CurrentSnapshot, firstSpan.Start); boxSelectionEnd = new SnapshotPoint(_subjectBuffer.CurrentSnapshot, lastSpan.End); isReversed = cursorPosition == firstSpan.Start; } else { // Top-right and bottom-left corners used as anchor points. boxSelectionStart = new SnapshotPoint(_subjectBuffer.CurrentSnapshot, firstSpan.End); boxSelectionEnd = new SnapshotPoint(_subjectBuffer.CurrentSnapshot, lastSpan.Start); isReversed = cursorPosition == firstSpan.End; } _textView.Selection.Select( new SnapshotSpan(boxSelectionStart, boxSelectionEnd), isReversed: isReversed); } else { _textView.Caret.MoveTo( new SnapshotPoint( _textView.TextBuffer.CurrentSnapshot, cursorDocument.CursorPosition.Value)); } this.EditorOperations = GetService <IEditorOperationsFactoryService>().GetEditorOperations(_textView); this.UndoHistoryRegistry = GetService <ITextUndoHistoryRegistry>(); }