public void PreBackspace(out bool handledCommand) { handledCommand = false; var caretPos = this.GetCaretPosition(); var snapshot = SubjectBuffer.CurrentSnapshot; if (caretPos.HasValue && caretPos.Value.Position > 0 && (caretPos.Value.Position - 1) == OpeningPoint.GetPoint(snapshot).Position && !HasForwardTyping) { using var undo = CreateUndoTransaction(); using var edit = SubjectBuffer.CreateEdit(); var span = new SnapshotSpan(OpeningPoint.GetPoint(snapshot), ClosingPoint.GetPoint(snapshot)); edit.Delete(span); if (edit.HasFailedChanges) { edit.Cancel(); undo.Cancel(); Debug.Fail("Unable to clear braces"); } else { // handle the command so the backspace does // not go through since we've already cleared the braces handledCommand = true; edit.ApplyAndLogExceptions(); undo.Complete(); EndSession(); } } }
public void PostReturn() { _threadingContext.ThrowIfNotOnUIThread(); if (this.GetCaretPosition().HasValue) { var closingSnapshotPoint = ClosingPoint.GetPoint(SubjectBuffer.CurrentSnapshot); if (closingSnapshotPoint.Position > 0 && HasNoForwardTyping(this.GetCaretPosition().Value, closingSnapshotPoint.Subtract(1))) { var context = GetBraceCompletionContext(); if (context == null) { return; } var indentationOptions = context.Value.Document.GetIndentationOptionsAsync(_globalOptions, CancellationToken.None).WaitAndGetResult(CancellationToken.None); var changesAfterReturn = _service.GetTextChangeAfterReturnAsync(context.Value, indentationOptions, CancellationToken.None).WaitAndGetResult(CancellationToken.None); if (changesAfterReturn != null) { using var caretPreservingTransaction = new CaretPreservingEditTransaction(EditorFeaturesResources.Brace_Completion, _undoHistory, _editorOperations); ApplyBraceCompletionResult(changesAfterReturn.Value); caretPreservingTransaction.Complete(); } } } }
private void ApplyBraceCompletionResult(BraceCompletionResult result) { _threadingContext.ThrowIfNotOnUIThread(); using var edit = SubjectBuffer.CreateEdit(); foreach (var change in result.TextChanges) { edit.Replace(change.Span.ToSpan(), change.NewText); } edit.ApplyAndLogExceptions(); try { Contract.ThrowIfFalse(SubjectBuffer.CurrentSnapshot[OpeningPoint.GetPosition(SubjectBuffer.CurrentSnapshot)] == OpeningBrace, "The opening point does not match the opening brace character"); Contract.ThrowIfFalse(SubjectBuffer.CurrentSnapshot[ClosingPoint.GetPosition(SubjectBuffer.CurrentSnapshot) - 1] == ClosingBrace, "The closing point does not match the closing brace character"); } catch (Exception e) when(FatalError.ReportAndCatch(e)) { return; } var caretLine = SubjectBuffer.CurrentSnapshot.GetLineFromLineNumber(result.CaretLocation.Line); TextView.TryMoveCaretToAndEnsureVisible(new VirtualSnapshotPoint(caretLine, result.CaretLocation.Character)); }
private bool TryStart(CancellationToken cancellationToken) { this.AssertIsForeground(); var closingSnapshotPoint = ClosingPoint.GetPoint(SubjectBuffer.CurrentSnapshot); if (closingSnapshotPoint.Position < 1) { Debug.Fail("The closing point was not found at the expected position."); return(false); } var openingSnapshotPoint = closingSnapshotPoint.Subtract(1); if (openingSnapshotPoint.GetChar() != OpeningBrace) { // there is a bug in editor brace completion engine on projection buffer that already fixed in vs_pro. until that is FIed to use // I will make this not to assert // Debug.Fail("The opening brace was not found at the expected position."); return(false); } OpeningPoint = SubjectBuffer.CurrentSnapshot.CreateTrackingPoint(openingSnapshotPoint, PointTrackingMode.Positive); var context = GetBraceCompletionContext(); if (context == null) { return(false); } var braceResult = _service.GetBraceCompletionAsync(context.Value, cancellationToken).WaitAndGetResult(cancellationToken); if (braceResult == null) { return(false); } using var caretPreservingTransaction = new CaretPreservingEditTransaction(EditorFeaturesResources.Brace_Completion, _undoHistory, _editorOperations); // Apply the change to complete the brace. ApplyBraceCompletionResult(braceResult.Value); // switch the closing point from positive to negative tracking so that the closing point stays against the closing brace ClosingPoint = SubjectBuffer.CurrentSnapshot.CreateTrackingPoint(ClosingPoint.GetPoint(SubjectBuffer.CurrentSnapshot), PointTrackingMode.Negative); var contextAfterStart = GetBraceCompletionContext(); if (contextAfterStart != null) { var options = IndentationOptions.FromDocumentAsync(contextAfterStart.Value.Document, cancellationToken).WaitAndGetResult(cancellationToken); var changesAfterStart = _service.GetTextChangesAfterCompletionAsync(contextAfterStart.Value, options, cancellationToken).WaitAndGetResult(cancellationToken); if (changesAfterStart != null) { ApplyBraceCompletionResult(changesAfterStart.Value); } } caretPreservingTransaction.Complete(); return(true); }
public void PreOverType(out bool handledCommand) { handledCommand = false; if (ClosingPoint == null) { return; } // Brace completion is not cancellable. var cancellationToken = CancellationToken.None; var snapshot = this.SubjectBuffer.CurrentSnapshot; var document = snapshot.GetOpenDocumentInCurrentContextWithChanges(); SnapshotPoint closingSnapshotPoint = ClosingPoint.GetPoint(snapshot); if (!HasForwardTyping && _session.AllowOverType(this, cancellationToken)) { SnapshotPoint?caretPos = this.GetCaretPosition(); Debug.Assert(caretPos.HasValue && caretPos.Value.Position < closingSnapshotPoint.Position); // ensure that we are within the session before clearing if (caretPos.HasValue && caretPos.Value.Position < closingSnapshotPoint.Position && closingSnapshotPoint.Position > 0) { using (ITextUndoTransaction undo = CreateUndoTransaction()) { _editorOperations.AddBeforeTextBufferChangePrimitive(); SnapshotSpan span = new SnapshotSpan(caretPos.Value, closingSnapshotPoint.Subtract(1)); using (ITextEdit edit = SubjectBuffer.CreateEdit()) { edit.Delete(span); if (edit.HasFailedChanges) { Debug.Fail("Unable to clear closing brace"); edit.Cancel(); undo.Cancel(); } else { handledCommand = true; edit.Apply(); MoveCaretToClosingPoint(); _editorOperations.AddAfterTextBufferChangePrimitive(); undo.Complete(); } } } } } }
public void PostReturn() { if (this.GetCaretPosition().HasValue) { SnapshotPoint closingSnapshotPoint = ClosingPoint.GetPoint(SubjectBuffer.CurrentSnapshot); if (closingSnapshotPoint.Position > 0 && HasNoForwardTyping(this.GetCaretPosition().Value, closingSnapshotPoint.Subtract(1))) { _session.AfterReturn(this, CancellationToken.None); } } }
private BraceCompletionContext GetBraceCompletionContext(ParsedDocument document) { _threadingContext.ThrowIfNotOnUIThread(); var snapshot = SubjectBuffer.CurrentSnapshot; var closingSnapshotPoint = ClosingPoint.GetPosition(snapshot); var openingSnapshotPoint = OpeningPoint.GetPosition(snapshot); // The user is actively typing so the caret position should not be null. var caretPosition = this.GetCaretPosition().Value.Position; return(new BraceCompletionContext(document, openingSnapshotPoint, closingSnapshotPoint, caretPosition)); }
private void MoveCaretToClosingPoint() { SnapshotPoint closingSnapshotPoint = ClosingPoint.GetPoint(SubjectBuffer.CurrentSnapshot); // find the position just after the closing brace in the view's text buffer SnapshotPoint?afterBrace = TextView.BufferGraph.MapUpToBuffer(closingSnapshotPoint, PointTrackingMode.Negative, PositionAffinity.Predecessor, TextView.TextBuffer); Debug.Assert(afterBrace.HasValue, "Unable to move caret to closing point"); if (afterBrace.HasValue) { TextView.Caret.MoveTo(afterBrace.Value); } }
private BraceCompletionContext?GetBraceCompletionContext() { this.AssertIsForeground(); var snapshot = SubjectBuffer.CurrentSnapshot; var document = snapshot.GetOpenDocumentInCurrentContextWithChanges(); if (document == null) { return(null); } var closingSnapshotPoint = ClosingPoint.GetPosition(snapshot); var openingSnapshotPoint = OpeningPoint.GetPosition(snapshot); // The user is actively typing so the caret position should not be null. var caretPosition = this.GetCaretPosition().Value.Position; return(new BraceCompletionContext(document, openingSnapshotPoint, closingSnapshotPoint, caretPosition)); }
private void Start(CancellationToken cancellationToken) { // this is where the caret should go after the change SnapshotPoint pos = TextView.Caret.Position.BufferPosition; ITrackingPoint beforeTrackingPoint = pos.Snapshot.CreateTrackingPoint(pos.Position, PointTrackingMode.Negative); ITextSnapshot snapshot = SubjectBuffer.CurrentSnapshot; SnapshotPoint closingSnapshotPoint = ClosingPoint.GetPoint(snapshot); if (closingSnapshotPoint.Position < 1) { Debug.Fail("The closing point was not found at the expected position."); EndSession(); return; } SnapshotPoint openingSnapshotPoint = closingSnapshotPoint.Subtract(1); if (openingSnapshotPoint.GetChar() != OpeningBrace) { // there is a bug in editor brace completion engine on projection buffer that already fixed in vs_pro. until that is FIed to use // I will make this not to assert // Debug.Fail("The opening brace was not found at the expected position."); EndSession(); return; } OpeningPoint = snapshot.CreateTrackingPoint(openingSnapshotPoint, PointTrackingMode.Positive); var document = snapshot.GetOpenDocumentInCurrentContextWithChanges(); if (!_session.CheckOpeningPoint(this, cancellationToken)) { EndSession(); return; } using (ITextUndoTransaction undo = CreateUndoTransaction()) { // insert the closing brace using (ITextEdit edit = SubjectBuffer.CreateEdit()) { edit.Insert(closingSnapshotPoint, ClosingBrace.ToString()); if (edit.HasFailedChanges) { Debug.Fail("Unable to insert closing brace"); // exit without setting the closing point which will take us off the stack edit.Cancel(); undo.Cancel(); return; } else { snapshot = edit.Apply(); } } SnapshotPoint beforePoint = beforeTrackingPoint.GetPoint(TextView.TextSnapshot); // switch from positive to negative tracking so it stays against the closing brace ClosingPoint = SubjectBuffer.CurrentSnapshot.CreateTrackingPoint(ClosingPoint.GetPoint(snapshot), PointTrackingMode.Negative); Debug.Assert(ClosingPoint.GetPoint(snapshot).Position > 0 && (new SnapshotSpan(ClosingPoint.GetPoint(snapshot).Subtract(1), 1)) .GetText().Equals(ClosingBrace.ToString()), "The closing point does not match the closing brace character"); // move the caret back between the braces TextView.Caret.MoveTo(beforePoint); _session.AfterStart(this, cancellationToken); undo.Complete(); } }
public void PreOverType(out bool handledCommand) { _threadingContext.ThrowIfNotOnUIThread(); handledCommand = false; if (ClosingPoint == null) { return; } // Brace completion is not cancellable. var cancellationToken = CancellationToken.None; var snapshot = this.SubjectBuffer.CurrentSnapshot; var closingSnapshotPoint = ClosingPoint.GetPoint(snapshot); if (!HasForwardTyping && AllowOverType()) { var caretPos = this.GetCaretPosition(); Debug.Assert(caretPos.HasValue && caretPos.Value.Position < closingSnapshotPoint.Position); // ensure that we are within the session before clearing if (caretPos.HasValue && caretPos.Value.Position < closingSnapshotPoint.Position && closingSnapshotPoint.Position > 0) { using var undo = CreateUndoTransaction(); _editorOperations.AddBeforeTextBufferChangePrimitive(); var span = new SnapshotSpan(caretPos.Value, closingSnapshotPoint.Subtract(1)); using var edit = SubjectBuffer.CreateEdit(); edit.Delete(span); if (edit.HasFailedChanges) { Debug.Fail("Unable to clear closing brace"); edit.Cancel(); undo.Cancel(); } else { handledCommand = true; edit.ApplyAndLogExceptions(); MoveCaretToClosingPoint(); _editorOperations.AddAfterTextBufferChangePrimitive(); undo.Complete(); } } } return; bool AllowOverType() { var context = GetBraceCompletionContext(); return(context != null && _service.AllowOverTypeAsync(context.Value, cancellationToken).WaitAndGetResult(cancellationToken)); } }
private bool TryStart(CancellationToken cancellationToken) { _threadingContext.ThrowIfNotOnUIThread(); var closingSnapshotPoint = ClosingPoint.GetPoint(SubjectBuffer.CurrentSnapshot); if (closingSnapshotPoint.Position < 1) { Debug.Fail("The closing point was not found at the expected position."); return(false); } var openingSnapshotPoint = closingSnapshotPoint.Subtract(1); if (openingSnapshotPoint.GetChar() != OpeningBrace) { // there is a bug in editor brace completion engine on projection buffer that already fixed in vs_pro. until that is FIed to use // I will make this not to assert // Debug.Fail("The opening brace was not found at the expected position."); return(false); } OpeningPoint = SubjectBuffer.CurrentSnapshot.CreateTrackingPoint(openingSnapshotPoint, PointTrackingMode.Positive); var document = SubjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); if (document == null) { return(false); } var parsedDocument = ParsedDocument.CreateSynchronously(document, cancellationToken); var context = GetBraceCompletionContext(parsedDocument); // Note: completes synchronously unless Semantic Model is needed to determine the result: if (!_service.HasBraceCompletionAsync(context, document, cancellationToken).WaitAndGetResult(cancellationToken)) { return(false); } var braceResult = _service.GetBraceCompletion(context); using var caretPreservingTransaction = new CaretPreservingEditTransaction(EditorFeaturesResources.Brace_Completion, _undoHistory, _editorOperations); // Apply the change to complete the brace. ApplyBraceCompletionResult(braceResult); // switch the closing point from positive to negative tracking so that the closing point stays against the closing brace ClosingPoint = SubjectBuffer.CurrentSnapshot.CreateTrackingPoint(ClosingPoint.GetPoint(SubjectBuffer.CurrentSnapshot), PointTrackingMode.Negative); if (TryGetBraceCompletionContext(out var contextAfterStart, cancellationToken)) { var indentationOptions = SubjectBuffer.GetIndentationOptions(_editorOptionsService, contextAfterStart.Document.LanguageServices, explicitFormat: false); var changesAfterStart = _service.GetTextChangesAfterCompletion(contextAfterStart, indentationOptions, cancellationToken); if (changesAfterStart != null) { ApplyBraceCompletionResult(changesAfterStart.Value); } } caretPreservingTransaction.Complete(); return(true); }