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)))
                    {
                        if (!TryGetBraceCompletionContext(out var context, CancellationToken.None))
                        {
                            return;
                        }

                        var indentationOptions = SubjectBuffer.GetIndentationOptions(_editorOptionsService, context.Document.LanguageServices, explicitFormat: false);
                        var changesAfterReturn = _service.GetTextChangeAfterReturn(context, indentationOptions, CancellationToken.None);
                        if (changesAfterReturn != null)
                        {
                            using var caretPreservingTransaction = new CaretPreservingEditTransaction(EditorFeaturesResources.Brace_Completion, _undoHistory, _editorOperations);
                            ApplyBraceCompletionResult(changesAfterReturn.Value);
                            caretPreservingTransaction.Complete();
                        }
                    }
                }
            }
        /// <returns>The tracking span of the inserted "/**/" if there is an $end$ location, null
        /// otherwise.</returns>
        protected override ITrackingSpan InsertEmptyCommentAndGetEndPositionTrackingSpan()
        {
            VsTextSpan[] endSpanInSurfaceBuffer = new VsTextSpan[1];
            if (ExpansionSession.GetEndSpan(endSpanInSurfaceBuffer) != VSConstants.S_OK)
            {
                return(null);
            }

            SnapshotSpan subjectBufferEndSpan;

            if (!TryGetSubjectBufferSpan(endSpanInSurfaceBuffer[0], out subjectBufferEndSpan))
            {
                return(null);
            }

            var endPosition = subjectBufferEndSpan.Start.Position;

            string commentString = "/**/";

            SubjectBuffer.Insert(endPosition, commentString);

            var commentSpan = new Span(endPosition, commentString.Length);

            return(SubjectBuffer.CurrentSnapshot.CreateTrackingSpan(commentSpan, SpanTrackingMode.EdgeExclusive));
        }
Exemple #3
0
            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();
                    }
                }
            }
Exemple #4
0
            private void OnWorkspaceChanged(object?sender, WorkspaceChangeEventArgs e)
            {
                if (e.Kind == WorkspaceChangeKind.ProjectChanged)
                {
                    RoslynDebug.AssertNotNull(e.ProjectId);
                    var oldProject = e.OldSolution.GetRequiredProject(e.ProjectId);
                    var newProject = e.NewSolution.GetRequiredProject(e.ProjectId);

                    if (!object.Equals(oldProject.ParseOptions, newProject.ParseOptions))
                    {
                        var workspace  = e.NewSolution.Workspace;
                        var documentId = workspace.GetDocumentIdInCurrentContext(
                            SubjectBuffer.AsTextContainer()
                            );
                        if (documentId != null)
                        {
                            var relatedDocumentIds = e.NewSolution.GetRelatedDocumentIds(
                                documentId
                                );

                            if (relatedDocumentIds.Any(d => d.ProjectId == e.ProjectId))
                            {
                                RaiseChanged();
                            }
                        }
                    }
                }
            }
Exemple #5
0
        private void OnDisconnect()
        {
            this.DataBuffer.Changed -= OnDataBufferChanged;
            this.Project.RemoveSourceTextContainer(SubjectBuffer.AsTextContainer());

            this.ContainedDocument.Dispose();
        }
            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));
            }
Exemple #7
0
        public override async Task<object> GetPreviewAsync(CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            // Light bulb will always invoke this function on the UI thread.
            AssertIsForeground();

            var previewPaneService = Workspace.Services.GetService<IPreviewPaneService>();
            if (previewPaneService == null)
            {
                return null;
            }

            // after this point, this method should only return at GetPreviewPane. otherwise, DifferenceViewer will leak
            // since there is no one to close the viewer
            var preferredDocumentId = Workspace.GetDocumentIdInCurrentContext(
                SubjectBuffer.AsTextContainer()
            );
            var preferredProjectId = preferredDocumentId?.ProjectId;

            var extensionManager = this.Workspace.Services.GetService<IExtensionManager>();
            var previewContents = await extensionManager
                .PerformFunctionAsync(
                    Provider,
                    async () =>
                    {
                        // We need to stay on UI thread after GetPreviewResultAsync() so that TakeNextPreviewAsync()
                        // below can execute on UI thread. We use ConfigureAwait(true) to stay on the UI thread.
                        var previewResult = await GetPreviewResultAsync(cancellationToken)
                            .ConfigureAwait(true);
                        if (previewResult == null)
                        {
                            return null;
                        }
                        else
                        {
                            // TakeNextPreviewAsync() needs to run on UI thread.
                            AssertIsForeground();
                            return await previewResult
                                .GetPreviewsAsync(
                                    preferredDocumentId,
                                    preferredProjectId,
                                    cancellationToken
                                )
                                .ConfigureAwait(true);
                        }
                        // GetPreviewPane() below needs to run on UI thread. We use ConfigureAwait(true) to stay on the UI thread.
                    },
                    defaultValue: null
                )
                .ConfigureAwait(true);

            // GetPreviewPane() needs to run on the UI thread.
            AssertIsForeground();

            return previewPaneService.GetPreviewPane(GetDiagnostic(), previewContents);
        }
Exemple #8
0
            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();
                                }
                            }
                        }
                    }
                }
            }
            private void OnDocumentActiveContextChanged(object sender, DocumentEventArgs e)
            {
                var document = SubjectBuffer.AsTextContainer().GetOpenDocumentInCurrentContext();

                if (document != null && document.Id == e.Document.Id)
                {
                    this.RaiseChanged();
                }
            }
Exemple #10
0
        internal ContainedLanguage(
            IVsTextBufferCoordinator bufferCoordinator,
            IComponentModel componentModel,
            VisualStudioProject project,
            IVsHierarchy hierarchy,
            uint itemid,
            VisualStudioProjectTracker projectTrackerOpt,
            ProjectId projectId,
            TLanguageService languageService,
            AbstractFormattingRule vbHelperFormattingRule = null)
        {
            this.BufferCoordinator = bufferCoordinator;
            this.ComponentModel    = componentModel;
            this.Project           = project;
            _languageService       = languageService;

            this.Workspace = projectTrackerOpt?.Workspace ?? componentModel.GetService <VisualStudioWorkspace>();

            _editorAdaptersFactoryService = componentModel.GetService <IVsEditorAdaptersFactoryService>();
            _diagnosticAnalyzerService    = componentModel.GetService <IDiagnosticAnalyzerService>();

            // Get the ITextBuffer for the secondary buffer
            Marshal.ThrowExceptionForHR(bufferCoordinator.GetSecondaryBuffer(out var secondaryTextLines));
            var secondaryVsTextBuffer = (IVsTextBuffer)secondaryTextLines;

            SubjectBuffer = _editorAdaptersFactoryService.GetDocumentBuffer(secondaryVsTextBuffer);

            // Get the ITextBuffer for the primary buffer
            Marshal.ThrowExceptionForHR(bufferCoordinator.GetPrimaryBuffer(out var primaryTextLines));
            DataBuffer = _editorAdaptersFactoryService.GetDataBuffer((IVsTextBuffer)primaryTextLines);

            // Create our tagger
            var bufferTagAggregatorFactory = ComponentModel.GetService <IBufferTagAggregatorFactoryService>();

            _bufferTagAggregator = bufferTagAggregatorFactory.CreateTagAggregator <ITag>(SubjectBuffer);

            if (!ErrorHandler.Succeeded(((IVsProject)hierarchy).GetMkDocument(itemid, out var filePath)))
            {
                // we couldn't look up the document moniker from an hierarchy for an itemid.
                // Since we only use this moniker as a key, we could fall back to something else, like the document name.
                Debug.Assert(false, "Could not get the document moniker for an item from its hierarchy.");
                if (!hierarchy.TryGetItemName(itemid, out filePath))
                {
                    FatalError.Report(new System.Exception("Failed to get document moniker for a contained document"));
                }
            }

            DocumentId documentId;

            if (this.Project != null)
            {
                documentId = this.Project.AddSourceTextContainer(
                    SubjectBuffer.AsTextContainer(), filePath,
                    sourceCodeKind: SourceCodeKind.Regular, folders: default,
Exemple #11
0
        internal ContainedLanguage(
            IVsTextBufferCoordinator bufferCoordinator,
            IComponentModel componentModel,
            Workspace workspace,
            ProjectId projectId,
            VisualStudioProject?project,
            string filePath,
            Guid languageServiceGuid,
            AbstractFormattingRule?vbHelperFormattingRule = null
            )
        {
            this.BufferCoordinator = bufferCoordinator;
            this.ComponentModel    = componentModel;
            this.Project           = project;
            _languageServiceGuid   = languageServiceGuid;

            this.Workspace = workspace;

            _editorAdaptersFactoryService =
                componentModel.GetService <IVsEditorAdaptersFactoryService>();
            _diagnosticAnalyzerService = componentModel.GetService <IDiagnosticAnalyzerService>();

            // Get the ITextBuffer for the secondary buffer
            Marshal.ThrowExceptionForHR(
                bufferCoordinator.GetSecondaryBuffer(out var secondaryTextLines)
                );
            SubjectBuffer = _editorAdaptersFactoryService.GetDocumentBuffer(secondaryTextLines) !;

            // Get the ITextBuffer for the primary buffer
            Marshal.ThrowExceptionForHR(
                bufferCoordinator.GetPrimaryBuffer(out var primaryTextLines)
                );
            DataBuffer = _editorAdaptersFactoryService.GetDataBuffer(primaryTextLines) !;

            // Create our tagger
            var bufferTagAggregatorFactory =
                ComponentModel.GetService <IBufferTagAggregatorFactoryService>();

            _bufferTagAggregator = bufferTagAggregatorFactory.CreateTagAggregator <ITag>(
                SubjectBuffer
                );

            DocumentId documentId;

            if (this.Project != null)
            {
                documentId = this.Project.AddSourceTextContainer(
                    SubjectBuffer.AsTextContainer(),
                    filePath,
                    sourceCodeKind: SourceCodeKind.Regular,
                    folders: default,
            private void OnSemanticChanged(object sender, Document d)
            {
                var workspace = this.CurrentWorkspace;

                if (d.Project.Solution.Workspace != workspace)
                {
                    return;
                }

                var documentIds = workspace.GetRelatedDocumentIds(SubjectBuffer.AsTextContainer());

                if (documentIds.Contains(d.Id))
                {
                    this.RaiseChanged();
                }
            }
        protected override ITrackingSpan InsertEmptyCommentAndGetEndPositionTrackingSpan()
        {
            var endSpanInSurfaceBuffer = ExpansionSession.EndSpan;

            if (!TryGetSubjectBufferSpan(endSpanInSurfaceBuffer, out var subjectBufferEndSpan))
            {
                return(null);
            }

            var endPosition = subjectBufferEndSpan.End.Position;

            var commentString = "/**/";

            SubjectBuffer.Insert(endPosition, commentString);

            var commentSpan = new Span(endPosition, commentString.Length);

            return(SubjectBuffer.CurrentSnapshot.CreateTrackingSpan(commentSpan, SpanTrackingMode.EdgeExclusive));
        }
            private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs e)
            {
                if (e.Kind == WorkspaceChangeKind.ProjectChanged)
                {
                    var oldProject = e.OldSolution.GetProject(e.ProjectId);
                    var newProject = e.NewSolution.GetProject(e.ProjectId);

                    if (!object.Equals(oldProject.ParseOptions, newProject.ParseOptions))
                    {
                        var workspace   = e.NewSolution.Workspace;
                        var documentIds = workspace.GetRelatedDocumentIds(SubjectBuffer.AsTextContainer());

                        if (documentIds.Any(d => d.ProjectId == e.ProjectId))
                        {
                            this.RaiseChanged();
                        }
                    }
                }
            }
Exemple #15
0
        private void OnDisconnect()
        {
            this.DataBuffer.Changed -= OnDataBufferChanged;

            if (this.Project != null)
            {
                this.Project.RemoveSourceTextContainer(SubjectBuffer.AsTextContainer());
            }
            else
            {
                // It's possible the host of the workspace might have already removed the entire project
                if (Workspace.CurrentSolution.ContainsDocument(ContainedDocument.Id))
                {
                    Workspace.OnDocumentRemoved(ContainedDocument.Id);
                }
            }

            this.ContainedDocument.Dispose();
        }
            private void OnOpenedDocumentSemanticChanged(object sender, Document document)
            {
                var workspace = this.CurrentWorkspace;

                if (document.Project.Solution.Workspace != workspace)
                {
                    return;
                }

                var documentIds = workspace.GetRelatedDocumentIds(SubjectBuffer.AsTextContainer());

                if (!documentIds.Contains(document.Id))
                {
                    return;
                }

                // Semantics may change for a document for two reasons.  One is a top level change
                // outside of this document.  The other is that a change happened inside the document.
                // In the latter case we do *not* want to report a change because we'll already have
                // done so inside of OnSubjectBufferChanged.
                //
                // Note: although we're passing CancellationToken.None here, this should never actually
                // block.  This is because we would have only gotten this notification if this value
                // was already computed.  In which case retrieving it again should happen immediately.
                var documentVersion = document.GetTopLevelChangeTextVersionAsync(CancellationToken.None).WaitAndGetResult_CanCallOnBackground(CancellationToken.None);
                var projectVersion  = document.Project.GetDependentSemanticVersionAsync(CancellationToken.None).WaitAndGetResult_CanCallOnBackground(CancellationToken.None);

                if (documentVersion == projectVersion)
                {
                    // The semantic version notification was caused by a change to this document.
                    // In which case we want to *ignore* it as we will have already processed its
                    // buffer change event.
                    return;
                }

                // The semantic version notification was caused by something else (a sibling document
                // changing at the top level, or a dependent project changing), we want to report this
                // so that this document can be retagged.
                this.RaiseChanged();
            }
Exemple #17
0
        public void PreBackspace(out bool handledCommand)
        {
            handledCommand = false;

            SnapshotPoint?caretPos = CaretPosition;
            ITextSnapshot snapshot = SubjectBuffer.CurrentSnapshot;

            if (caretPos.HasValue && caretPos.Value.Position > 0 && (caretPos.Value.Position - 1) == _openingPoint.GetPoint(snapshot).Position &&
                !HasForwardTyping)
            {
                using (ITextUndoTransaction undo = CreateUndoTransaction())
                {
                    using (ITextEdit edit = SubjectBuffer.CreateEdit())
                    {
                        SnapshotSpan 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");
                            // just let this backspace proceed normally
                        }
                        else
                        {
                            // handle the command so the backspace does
                            // not go through since we've already cleared the braces
                            handledCommand = true;
                            edit.Apply();
                            undo.Complete();
                            EndSession();
                        }
                    }
                }
            }
        }
Exemple #18
0
        private void ExecuteBackspaceOrDelete(ITextView textView, Action nextHandler, bool isDelete)
        {
            AssertIsForeground();

            char?deletedChar;
            var  subjectBufferCaretPoint = GetCaretPointInSubjectBuffer();
            var  viewBufferCaretPoint    = GetCaretPointInViewBuffer();

            if (isDelete)
            {
                deletedChar = viewBufferCaretPoint.Position >= 0 && viewBufferCaretPoint.Position < textView.TextBuffer.CurrentSnapshot.Length
                    ? textView.TextBuffer.CurrentSnapshot[viewBufferCaretPoint.Position]
                    : default;
            }
            else
            {
                // backspace
                deletedChar = viewBufferCaretPoint > 0
                    ? textView.TextBuffer.CurrentSnapshot[viewBufferCaretPoint - 1]
                    : default;
            }

            if (sessionOpt == null)
            {
                // No computation. Disconnect from caret position changes, send the backspace through,
                // and start a computation.
                this.TextView.TextBuffer.PostChanged -= OnTextViewBufferPostChanged;
                this.TextView.Caret.PositionChanged  -= OnCaretPositionChanged;
                try
                {
                    nextHandler();
                }
                finally
                {
                    this.TextView.TextBuffer.PostChanged += OnTextViewBufferPostChanged;
                    this.TextView.Caret.PositionChanged  += OnCaretPositionChanged;
                }

                var trigger           = CompletionTrigger.CreateDeletionTrigger(deletedChar.GetValueOrDefault());
                var completionService = this.GetCompletionService();

                if (completionService != null)
                {
                    this.StartNewModelComputation(completionService, trigger);
                }

                return;
            }
            else
            {
                var textBeforeDeletion     = SubjectBuffer.AsTextContainer().CurrentText;
                var documentBeforeDeletion = textBeforeDeletion.GetDocumentWithFrozenPartialSemantics(CancellationToken.None);

                this.TextView.TextBuffer.PostChanged -= OnTextViewBufferPostChanged;
                this.TextView.Caret.PositionChanged  -= OnCaretPositionChanged;
                try
                {
                    nextHandler();
                }
                finally
                {
                    this.TextView.TextBuffer.PostChanged += OnTextViewBufferPostChanged;
                    this.TextView.Caret.PositionChanged  += OnCaretPositionChanged;
                }

                var model = sessionOpt.Computation.InitialUnfilteredModel;

                if ((model == null && CaretHasLeftDefaultTrackingSpan(subjectBufferCaretPoint, documentBeforeDeletion)) ||
                    (model != null && this.IsCaretOutsideAllItemBounds(model, this.GetCaretPointInViewBuffer())) ||
                    (model != null && model.OriginalList.Rules.DismissIfLastCharacterDeleted && AllFilterTextsEmpty(model, GetCaretPointInViewBuffer())))
                {
                    // If the caret moved out of bounds of our items, then we want to dismiss the list.
                    this.DismissSessionIfActive();
                    return;
                }
                else if (model != null)
                {
                    sessionOpt.FilterModel(CompletionFilterReason.Deletion, filterState: null);
                }
            }
        }
        private void ExecuteBackspaceOrDelete(ITextView textView, Action nextHandler, bool isDelete)
        {
            AssertIsForeground();

            char?deletedChar;
            var  subjectBufferCaretPoint = GetCaretPointInSubjectBuffer();
            var  viewBufferCaretPoint    = GetCaretPointInViewBuffer();

            if (isDelete)
            {
                deletedChar = viewBufferCaretPoint.Position >= 0 && viewBufferCaretPoint.Position < textView.TextBuffer.CurrentSnapshot.Length
                    ? textView.TextBuffer.CurrentSnapshot[viewBufferCaretPoint.Position]
                    : default(char?);
            }
            else
            {
                // backspace
                deletedChar = viewBufferCaretPoint > 0
                    ? textView.TextBuffer.CurrentSnapshot[viewBufferCaretPoint - 1]
                    : default(char?);
            }

            if (sessionOpt == null)
            {
                // No computation. Disconnect from caret position changes, send the backspace through,
                // and start a computation.
                this.TextView.TextBuffer.PostChanged -= OnTextViewBufferPostChanged;
                this.TextView.Caret.PositionChanged  -= OnCaretPositionChanged;
                try
                {
                    nextHandler();
                }
                finally
                {
                    this.TextView.TextBuffer.PostChanged += OnTextViewBufferPostChanged;
                    this.TextView.Caret.PositionChanged  += OnCaretPositionChanged;
                }

                var trigger           = CompletionTrigger.CreateDeletionTrigger(deletedChar.GetValueOrDefault());
                var completionService = this.GetCompletionService();

                if (completionService != null)
                {
                    this.StartNewModelComputation(
                        completionService, trigger, filterItems: false, dismissIfEmptyAllowed: true);
                }

                return;
            }
            else
            {
                var textBeforeDeletion     = SubjectBuffer.AsTextContainer().CurrentText;
                var documentBeforeDeletion = textBeforeDeletion.GetDocumentWithFrozenPartialSemanticsAsync(CancellationToken.None)
                                             .WaitAndGetResult(CancellationToken.None);

                this.TextView.TextBuffer.PostChanged -= OnTextViewBufferPostChanged;
                this.TextView.Caret.PositionChanged  -= OnCaretPositionChanged;
                try
                {
                    nextHandler();
                }
                finally
                {
                    this.TextView.TextBuffer.PostChanged += OnTextViewBufferPostChanged;
                    this.TextView.Caret.PositionChanged  += OnCaretPositionChanged;
                }

                var model = sessionOpt.Computation.InitialUnfilteredModel;

                if ((model == null && CaretHasLeftDefaultTrackingSpan(subjectBufferCaretPoint, documentBeforeDeletion)) ||
                    (model != null && this.IsCaretOutsideAllItemBounds(model, this.GetCaretPointInViewBuffer())) ||
                    (model != null && model.OriginalList.Rules.DismissIfLastCharacterDeleted && AllFilterTextsEmpty(model, GetCaretPointInViewBuffer())))
                {
                    // If the caret moved out of bounds of our items, then we want to dismiss the list.
                    this.StopModelComputation();
                    return;
                }
                else if (model != null)
                {
                    // If we were triggered on backspace/delete, and we're still deleting,
                    // then we don't want to filter out items (i.e. we still want all items).
                    // However, we do still want to run the code to figure out what the best
                    // item is to select from all those items.
                    FilterToSomeOrAllItems(
                        filterItems: model.Trigger.Kind != CompletionTriggerKind.Deletion,
                        dismissIfEmptyAllowed: true,
                        filterReason: CompletionFilterReason.BackspaceOrDelete);
                }
            }
        }
Exemple #20
0
            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();
                }
            }
Exemple #21
0
        public ContainedLanguage(
            IVsTextBufferCoordinator bufferCoordinator,
            IComponentModel componentModel,
            VisualStudioProject project,
            IVsHierarchy hierarchy,
            uint itemid,
            TLanguageService languageService,
            IFormattingRule vbHelperFormattingRule = null)
        {
            this.BufferCoordinator = bufferCoordinator;
            this.ComponentModel    = componentModel;
            this.Project           = project;
            _languageService       = languageService;

            this.Workspace = componentModel.GetService <VisualStudioWorkspace>();

            _editorAdaptersFactoryService = componentModel.GetService <IVsEditorAdaptersFactoryService>();
            _diagnosticAnalyzerService    = componentModel.GetService <IDiagnosticAnalyzerService>();

            // Get the ITextBuffer for the secondary buffer
            Marshal.ThrowExceptionForHR(bufferCoordinator.GetSecondaryBuffer(out var secondaryTextLines));
            var secondaryVsTextBuffer = (IVsTextBuffer)secondaryTextLines;

            SubjectBuffer = _editorAdaptersFactoryService.GetDocumentBuffer(secondaryVsTextBuffer);

            // Get the ITextBuffer for the primary buffer
            Marshal.ThrowExceptionForHR(bufferCoordinator.GetPrimaryBuffer(out var primaryTextLines));
            DataBuffer = _editorAdaptersFactoryService.GetDataBuffer((IVsTextBuffer)primaryTextLines);

            // Create our tagger
            var bufferTagAggregatorFactory = ComponentModel.GetService <IBufferTagAggregatorFactoryService>();

            _bufferTagAggregator = bufferTagAggregatorFactory.CreateTagAggregator <ITag>(SubjectBuffer);

            if (!ErrorHandler.Succeeded(((IVsProject)hierarchy).GetMkDocument(itemid, out var filePath)))
            {
                // we couldn't look up the document moniker from an hierarchy for an itemid.
                // Since we only use this moniker as a key, we could fall back to something else, like the document name.
                Debug.Assert(false, "Could not get the document moniker for an item from its hierarchy.");
                if (!hierarchy.TryGetItemName(itemid, out filePath))
                {
                    FatalError.Report(new System.Exception("Failed to get document moniker for a contained document"));
                }
            }

            var documentId = this.Project.AddSourceTextContainer(SubjectBuffer.AsTextContainer(), filePath);

            this.ContainedDocument = new ContainedDocument(
                componentModel.GetService <IThreadingContext>(),
                documentId,
                subjectBuffer: SubjectBuffer,
                dataBuffer: DataBuffer,
                bufferCoordinator,
                this.Workspace,
                project,
                hierarchy,
                itemid,
                componentModel,
                vbHelperFormattingRule);

            // TODO: Can contained documents be linked or shared?
            this.DataBuffer.Changed += OnDataBufferChanged;
        }
        private void ExecuteBackspaceOrDelete(ITextView textView, Action nextHandler, bool isDelete)
        {
            AssertIsForeground();

            char?deletedChar;
            var  caretPoint = GetCaretPointInViewBuffer().Position;

            if (isDelete)
            {
                deletedChar = GetCaretPointInViewBuffer().Position >= 0 && GetCaretPointInViewBuffer().Position < textView.TextBuffer.CurrentSnapshot.Length
                    ? textView.TextBuffer.CurrentSnapshot[GetCaretPointInViewBuffer().Position]
                    : default(char?);
            }
            else
            {
                // backspace
                deletedChar = caretPoint > 0
                    ? textView.TextBuffer.CurrentSnapshot[caretPoint - 1]
                    : default(char?);
            }

            if (sessionOpt == null)
            {
                // No computation. Disconnect from caret position changes, send the backspace through,
                // and start a computation.
                this.TextView.TextBuffer.PostChanged -= OnTextViewBufferPostChanged;
                this.TextView.Caret.PositionChanged  -= OnCaretPositionChanged;
                try
                {
                    nextHandler();
                }
                finally
                {
                    this.TextView.TextBuffer.PostChanged += OnTextViewBufferPostChanged;
                    this.TextView.Caret.PositionChanged  += OnCaretPositionChanged;
                }

                var triggerInfo       = CompletionTriggerInfo.CreateBackspaceTriggerInfo(deletedChar);
                var completionService = this.CreateCompletionService();

                this.StartNewModelComputation(completionService, triggerInfo, filterItems: false);

                return;
            }
            else
            {
                var textBeforeDeletion     = SubjectBuffer.AsTextContainer().CurrentText;
                var documentBeforeDeletion = textBeforeDeletion.GetDocumentWithFrozenPartialSemanticsAsync(CancellationToken.None)
                                             .WaitAndGetResult(CancellationToken.None);

                this.TextView.TextBuffer.PostChanged -= OnTextViewBufferPostChanged;
                this.TextView.Caret.PositionChanged  -= OnCaretPositionChanged;
                try
                {
                    nextHandler();
                }
                finally
                {
                    this.TextView.TextBuffer.PostChanged += OnTextViewBufferPostChanged;
                    this.TextView.Caret.PositionChanged  += OnCaretPositionChanged;
                }

                var model = sessionOpt.Computation.InitialUnfilteredModel;

                if ((model == null && CaretHasLeftDefaultTrackingSpan(caretPoint, documentBeforeDeletion)) ||
                    (model != null && this.IsCaretOutsideAllItemBounds(model, this.GetCaretPointInViewBuffer())) ||
                    (model != null && CreateCompletionService().DismissIfLastFilterCharacterDeleted&& AllFilterTextsEmpty(model, GetCaretPointInViewBuffer())))
                {
                    // If the caret moved out of bounds of our items, then we want to dismiss the list.
                    this.StopModelComputation();
                    return;
                }
                else if (model != null && model.TriggerInfo.TriggerReason != CompletionTriggerReason.BackspaceOrDeleteCommand)
                {
                    // Filter the model if it wasn't invoked on backspace.
                    sessionOpt.FilterModel(CompletionFilterReason.BackspaceOrDelete);
                }
            }
        }
            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);
            }
            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));
                }
            }