Beispiel #1
0
        protected static List <TextChange> CleanupDocument(FormattingContext context, Range range = null)
        {
            var text = context.SourceText;

            range ??= TextSpan.FromBounds(0, text.Length).AsRange(text);
            var csharpDocument = context.CodeDocument.GetCSharpDocument();

            var changes = new List <TextChange>();

            foreach (var mapping in csharpDocument.SourceMappings)
            {
                var mappingSpan  = new TextSpan(mapping.OriginalSpan.AbsoluteIndex, mapping.OriginalSpan.Length);
                var mappingRange = mappingSpan.AsRange(text);
                if (!range.LineOverlapsWith(mappingRange))
                {
                    // We don't care about this range. It didn't change.
                    continue;
                }

                CleanupSourceMappingStart(context, mappingRange, changes);

                CleanupSourceMappingEnd(context, mappingRange, changes);
            }

            return(changes);
        }
        public bool TryNavigateToSpan(Workspace workspace, DocumentId documentId, TextSpan textSpan, OptionSet options)
        {
            // Navigation should not change the context of linked files and Shared Projects.
            documentId = workspace.GetDocumentIdInCurrentContext(documentId);

            if (!IsForeground())
            {
                throw new InvalidOperationException(ServicesVSResources.Navigation_must_be_performed_on_the_foreground_thread);
            }

            var document = OpenDocument(workspace, documentId, options);

            if (document == null)
            {
                return(false);
            }

            var text       = document.GetTextAsync(CancellationToken.None).WaitAndGetResult(CancellationToken.None);
            var textBuffer = text.Container.GetTextBuffer();

            var vsTextSpan = text.GetVsTextSpanForSpan(textSpan);

            if (IsSecondaryBuffer(workspace, documentId) &&
                !vsTextSpan.TryMapSpanFromSecondaryBufferToPrimaryBuffer(workspace, documentId, out vsTextSpan))
            {
                return(false);
            }

            return(NavigateTo(textBuffer, vsTextSpan));
        }
        private bool TryGetDocumentWithFullyQualifiedTypeName(Document document, out TextSpan updatedTextSpan, out Document documentWithFullyQualifiedTypeName)
        {
            documentWithFullyQualifiedTypeName = null;
            updatedTextSpan = default(TextSpan);

            var surfaceBufferFieldSpan = new VsTextSpan[1];
            if (snippetExpansionClient.ExpansionSession.GetFieldSpan(_fieldName, surfaceBufferFieldSpan) != VSConstants.S_OK)
            {
                return false;
            }

            if (!snippetExpansionClient.TryGetSubjectBufferSpan(surfaceBufferFieldSpan[0], out var subjectBufferFieldSpan))
            {
                return false;
            }

            var originalTextSpan = new TextSpan(subjectBufferFieldSpan.Start, subjectBufferFieldSpan.Length);
            updatedTextSpan = new TextSpan(subjectBufferFieldSpan.Start, _fullyQualifiedName.Length);

            var textChange = new TextChange(originalTextSpan, _fullyQualifiedName);
            var newText = document.GetTextAsync(CancellationToken.None).WaitAndGetResult(CancellationToken.None).WithChanges(textChange);

            documentWithFullyQualifiedTypeName = document.WithText(newText);
            return true;
        }
Beispiel #4
0
        protected override bool TryGetSimplifiedTypeNameInCaseContext(Document document, string fullyQualifiedTypeName, string firstEnumMemberName, int startPosition, int endPosition, CancellationToken cancellationToken, out string simplifiedTypeName)
        {
            simplifiedTypeName = string.Empty;
            var typeAnnotation = new SyntaxAnnotation();

            var str                = "case " + fullyQualifiedTypeName + "." + firstEnumMemberName + ":" + Environment.NewLine + " break;";
            var textChange         = new TextChange(new TextSpan(startPosition, endPosition - startPosition), str);
            var typeSpanToAnnotate = new TextSpan(startPosition + "case ".Length, fullyQualifiedTypeName.Length);

            var textWithCaseAdded     = document.GetTextSynchronously(cancellationToken).WithChanges(textChange);
            var documentWithCaseAdded = document.WithText(textWithCaseAdded);

            var syntaxRoot    = documentWithCaseAdded.GetSyntaxRootSynchronously(cancellationToken);
            var nodeToReplace = syntaxRoot.DescendantNodes().FirstOrDefault(n => n.Span == typeSpanToAnnotate);

            if (nodeToReplace == null)
            {
                return(false);
            }

            var updatedRoot             = syntaxRoot.ReplaceNode(nodeToReplace, nodeToReplace.WithAdditionalAnnotations(typeAnnotation, Simplifier.Annotation));
            var documentWithAnnotations = documentWithCaseAdded.WithSyntaxRoot(updatedRoot);

            var simplifiedDocument = Simplifier.ReduceAsync(documentWithAnnotations, cancellationToken: cancellationToken).Result;

            simplifiedTypeName = simplifiedDocument.GetSyntaxRootSynchronously(cancellationToken).GetAnnotatedNodesAndTokens(typeAnnotation).Single().ToString();
            return(true);
        }
        private void NavigateToPXViewDelegate(Document document, IWpfTextView textView, ISymbol viewSymbol, INamedTypeSymbol graphSymbol,
                                              PXContext context)
        {
            var viewDelegates = GetDelegateByName(graphSymbol, viewSymbol.Name, context);

            if (!viewDelegates.IsSingle())
            {
                return;
            }

            IMethodSymbol viewDelegate = viewDelegates.First();
            ImmutableArray <SyntaxReference> syntaxReferences = viewDelegate.DeclaringSyntaxReferences;

            if (syntaxReferences.Length != 1)
            {
                return;
            }

            SyntaxReference syntaxReference = syntaxReferences[0];

            if (syntaxReference.SyntaxTree.FilePath != document.FilePath)
            {
                textView = OpenOtherDocumentForNavigationAndGetItsTextView(document, syntaxReference);
            }

            if (textView == null)
            {
                return;
            }

            MethodDeclarationSyntax methodNode = syntaxReference.GetSyntax() as MethodDeclarationSyntax;
            TextSpan textSpan = methodNode?.Identifier.Span ?? syntaxReferences[0].Span;

            SetNewPositionInTextView(textView, textSpan);
        }
        public bool CanNavigateToSpan(Workspace workspace, DocumentId documentId, TextSpan textSpan, CancellationToken cancellationToken)
        {
            // Navigation should not change the context of linked files and Shared Projects.
            documentId = workspace.GetDocumentIdInCurrentContext(documentId);

            if (!IsSecondaryBuffer(workspace, documentId))
            {
                return(true);
            }

            var document = workspace.CurrentSolution.GetDocument(documentId);
            var text     = document.GetTextSynchronously(cancellationToken);

            var boundedTextSpan = GetSpanWithinDocumentBounds(textSpan, text.Length);

            if (boundedTextSpan != textSpan)
            {
                try
                {
                    throw new ArgumentOutOfRangeException();
                }
                catch (ArgumentOutOfRangeException e) when(FatalError.ReportAndCatch(e))
                {
                }

                return(false);
            }

            var vsTextSpan = text.GetVsTextSpanForSpan(textSpan);

            return(CanMapFromSecondaryBufferToPrimaryBuffer(workspace, documentId, vsTextSpan));
        }
        private bool TryGetDocumentWithFullyQualifiedTypeName(Document document, out TextSpan updatedTextSpan, out Document documentWithFullyQualifiedTypeName)
        {
            documentWithFullyQualifiedTypeName = null;
            updatedTextSpan = default(TextSpan);

            var surfaceBufferFieldSpan = new VsTextSpan[1];

            if (snippetExpansionClient.ExpansionSession.GetFieldSpan(_fieldName, surfaceBufferFieldSpan) != VSConstants.S_OK)
            {
                return(false);
            }

            SnapshotSpan subjectBufferFieldSpan;

            if (!snippetExpansionClient.TryGetSubjectBufferSpan(surfaceBufferFieldSpan[0], out subjectBufferFieldSpan))
            {
                return(false);
            }

            var originalTextSpan = new TextSpan(subjectBufferFieldSpan.Start, subjectBufferFieldSpan.Length);

            updatedTextSpan = new TextSpan(subjectBufferFieldSpan.Start, _fullyQualifiedName.Length);

            var textChange = new TextChange(originalTextSpan, _fullyQualifiedName);
            var newText    = document.GetTextAsync(CancellationToken.None).WaitAndGetResult(CancellationToken.None).WithChanges(textChange);

            documentWithFullyQualifiedTypeName = document.WithText(newText);
            return(true);
        }
        private static TextSpan GetSelection(ITextView activeWpfTextView)
        {
            var visualStudioSpan = activeWpfTextView.Selection.StreamSelectionSpan.SnapshotSpan.Span;
            var roslynSpan       = new TextSpan(visualStudioSpan.Start, visualStudioSpan.Length);

            return(roslynSpan);
        }
Beispiel #9
0
 public bool TryNavigateToSpan(Workspace workspace, DocumentId documentId, TextSpan textSpan, OptionSet options)
 {
     return(TryNavigateToLocation(workspace,
                                  documentId,
                                  _ => textSpan,
                                  text => GetVsTextSpan(text, textSpan),
                                  options));
Beispiel #10
0
        private static TextSpan GetSpanIncludingPrecedingWhitespaceInLine(SourceText sourceText, int start, int end)
        {
            var line = sourceText.Lines.GetLineFromPosition(start);
            var precedingLineText         = sourceText.GetSubTextString(TextSpan.FromBounds(line.Start, start));
            var precedingWhitespaceLength = precedingLineText.GetTrailingWhitespace().Length;

            return(TextSpan.FromBounds(start - precedingWhitespaceLength, end));
        }
 public bool TryNavigateToSpan(Workspace workspace, DocumentId documentId, TextSpan textSpan, NavigationOptions options, bool allowInvalidSpan, CancellationToken cancellationToken)
 {
     return(TryNavigateToLocation(workspace,
                                  documentId,
                                  _ => textSpan,
                                  text => GetVsTextSpan(text, textSpan, allowInvalidSpan),
                                  options,
                                  cancellationToken));
        // This method handles adjusting of indentation of Razor blocks after C# formatter has finished formatting the document.
        // For instance, lines inside @code/@functions block should be reduced one level
        // and lines inside @{} should be reduced by two levels.
        protected static List <TextChange> AdjustCSharpIndentation(FormattingContext context, int startLine, int endLine)
        {
            if (context is null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            var sourceText   = context.SourceText;
            var editsToApply = new List <TextChange>();

            for (var i = startLine; i <= endLine; i++)
            {
                if (!context.Indentations[i].StartsInCSharpContext)
                {
                    // Not a CSharp line. Don't touch it.
                    continue;
                }

                var line = sourceText.Lines[i];
                if (line.Span.Length == 0)
                {
                    // Empty line. C# formatter didn't remove it so we won't either.
                    continue;
                }

                var leadingWhitespace       = line.GetLeadingWhitespace();
                var minCSharpIndentLevel    = context.Indentations[i].MinCSharpIndentLevel;
                var minCSharpIndentLength   = context.GetIndentationLevelString(minCSharpIndentLevel).Length;
                var desiredIndentationLevel = context.Indentations[i].IndentationLevel;
                if (leadingWhitespace.Length < minCSharpIndentLength)
                {
                    // For whatever reason, the C# formatter decided to not indent this. Leave it as is.
                    continue;
                }
                else
                {
                    // At this point we assume the C# formatter has relatively indented this line to the correct level.
                    // All we want to do at this point is to indent/unindent this line based on the absolute indentation of the block
                    // and the minimum C# indent level. We don't need to worry about the actual existing indentation here because it doesn't matter.
                    var effectiveDesiredIndentationLevel = desiredIndentationLevel - minCSharpIndentLevel;
                    var effectiveDesiredIndentation      = context.GetIndentationLevelString(Math.Abs(effectiveDesiredIndentationLevel));
                    if (effectiveDesiredIndentationLevel < 0)
                    {
                        // This means that we need to unindent.
                        var span = new TextSpan(line.Start, effectiveDesiredIndentation.Length);
                        editsToApply.Add(new TextChange(span, string.Empty));
                    }
                    else if (effectiveDesiredIndentationLevel > 0)
                    {
                        // This means that we need to indent.
                        var span = new TextSpan(line.Start, 0);
                        editsToApply.Add(new TextChange(span, effectiveDesiredIndentation));
                    }
                }
            }

            return(editsToApply);
        }
        protected override void CommandCallback(object sender, EventArgs e)
        {
            IWpfTextView textView = ServiceProvider.GetWpfTextView();

            if (textView == null)
            {
                return;
            }

            SnapshotPoint     caretPosition = textView.Caret.Position.BufferPosition;
            ITextSnapshotLine caretLine     = caretPosition.GetContainingLine();

            if (caretLine == null)
            {
                return;
            }

            Document document = caretPosition.Snapshot.GetOpenDocumentInCurrentContextWithChanges();

            if (document == null)
            {
                return;
            }

            (SyntaxNode syntaxRoot, SemanticModel semanticModel) = ThreadHelper.JoinableTaskFactory.Run(
                async() => (await document.GetSyntaxRootAsync(), await document.GetSemanticModelAsync()));

            if (syntaxRoot == null || semanticModel == null)
            {
                return;
            }

            TextSpan lineSpan   = TextSpan.FromBounds(caretLine.Start.Position, caretLine.End.Position);
            var      memberNode = syntaxRoot.FindNode(lineSpan) as MemberDeclarationSyntax;

            if (memberNode == null)
            {
                return;
            }

            PXContext context = new PXContext(semanticModel.Compilation);

            if (!context.IsPlatformReferenced)
            {
                return;
            }

            ISymbol memberSymbol = GetMemberSymbol(memberNode, semanticModel, caretPosition);

            if (!CheckMemberSymbol(memberSymbol, context))
            {
                return;
            }

            NavigateToHandlerOrDeclaration(document, textView, memberSymbol, memberNode, semanticModel, context);
        }
Beispiel #14
0
        private async Task SetNewPositionInTextViewAsync(IWpfTextView textView, TextSpan textSpan)
        {
            SnapshotSpan selectedSpan = new SnapshotSpan(textView.TextSnapshot, textSpan.Start, textSpan.Length);

            await ExpandAllRegionsContainingSpanAsync(selectedSpan, textView);

            textView.MoveCaretTo(textSpan.Start);
            textView.ViewScroller.EnsureSpanVisible(selectedSpan, EnsureSpanVisibleOptions.AlwaysCenter);
            textView.Selection.Select(selectedSpan, isReversed: false);
        }
Beispiel #15
0
        private void FormatCodeBlockEnd(FormattingContext context, SourceText changedText, RazorDirectiveBodySyntax directiveBody, SyntaxNode innerCodeBlock, List <TextEdit> edits)
        {
            var sourceText        = context.SourceText;
            var originalBodySpan  = TextSpan.FromBounds(directiveBody.Position, directiveBody.EndPosition);
            var originalBodyRange = originalBodySpan.AsRange(sourceText);

            if (context.Range.End.Line < originalBodyRange.End.Line)
            {
                return;
            }

            // Last line is within the selected range. Let's try and format the end.

            TrackChangeInSpan(sourceText, originalBodySpan, changedText, out var changedBodySpan, out _);
            var changedBodyRange = changedBodySpan.AsRange(changedText);

            var firstLine = changedText.Lines[(int)changedBodyRange.Start.Line];
            var desiredIndentationLevel = context.Indentations[firstLine.LineNumber].IndentationLevel;
            var desiredIndentation      = context.GetIndentationLevelString(desiredIndentationLevel);

            // we want to keep the close '}' on its own line. So bring it to the next line.
            var originalInnerCodeBlockSpan = TextSpan.FromBounds(innerCodeBlock.Position, innerCodeBlock.EndPosition);

            TrackChangeInSpan(sourceText, originalInnerCodeBlockSpan, changedText, out var changedInnerCodeBlockSpan, out _);
            var closeCurlyLocation       = changedInnerCodeBlockSpan.End;
            var closeCurlyLine           = changedText.Lines.GetLineFromPosition(closeCurlyLocation);
            var firstNonWhitespaceOffset = closeCurlyLine.GetFirstNonWhitespaceOffset() ?? 0;

            if (closeCurlyLine.Start + firstNonWhitespaceOffset != closeCurlyLocation)
            {
                // This means the '}' is on the same line as some C# code.
                // Bring it down to the next line and apply the desired indentation.
                var edit = new TextEdit()
                {
                    Range = new Range(
                        new Position(closeCurlyLine.LineNumber, closeCurlyLocation - closeCurlyLine.Start),
                        new Position(closeCurlyLine.LineNumber, closeCurlyLocation - closeCurlyLine.Start)),
                    NewText = Environment.NewLine + desiredIndentation
                };
                edits.Add(edit);
            }
            else if (firstNonWhitespaceOffset != desiredIndentation.Length)
            {
                // This means the '}' is on its own line but is not indented correctly. Correct it.
                var edit = new TextEdit()
                {
                    Range = new Range(
                        new Position(closeCurlyLine.LineNumber, 0),
                        new Position(closeCurlyLine.LineNumber, firstNonWhitespaceOffset)),
                    NewText = desiredIndentation
                };
                edits.Add(edit);
            }
        }
Beispiel #16
0
        private TextChange[] Diff(SourceText oldText, SourceText newText, TextSpan?spanToDiff = default)
        {
            // Once https://github.com/dotnet/roslyn/issues/41413 is fixed,
            // the following lines can be replaced with `newText.GetTextChanges(oldText)`.

            var spanToTrack = spanToDiff ?? TextSpan.FromBounds(0, oldText.Length);

            TrackChangeInSpan(oldText, spanToTrack, newText, out var changedSpanToTrack, out _);
            var change = new TextChange(spanToTrack, newText.GetSubText(changedSpanToTrack).ToString());

            return(new[] { change });
        }
        private int FormatWorker(IVsTextLayer textLayer, TextSpan[] selections, CancellationToken cancellationToken)
        {
            var textBuffer = this.EditorAdaptersFactoryService.GetDataBuffer((IVsTextBuffer)textLayer);

            if (textBuffer == null)
            {
                return(VSConstants.E_UNEXPECTED);
            }

            var document = textBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges();

            if (document == null)
            {
                return(VSConstants.E_FAIL);
            }

            var documentSyntax    = ParsedDocument.CreateSynchronously(document, cancellationToken);
            var text              = documentSyntax.Text;
            var root              = documentSyntax.Root;
            var formattingOptions = textBuffer.GetSyntaxFormattingOptions(EditorOptionsService, document.Project.LanguageServices, explicitFormat: true);

            var ts           = selections.Single();
            var start        = text.Lines[ts.iStartLine].Start + ts.iStartIndex;
            var end          = text.Lines[ts.iEndLine].Start + ts.iEndIndex;
            var adjustedSpan = GetFormattingSpan(root, start, end);

            // Since we know we are on the UI thread, lets get the base indentation now, so that there is less
            // cleanup work to do later in Venus.
            var ruleFactory = Workspace.Services.GetService <IHostDependentFormattingRuleFactoryService>();
            var rules       = ruleFactory.CreateRule(documentSyntax, start).Concat(Formatter.GetDefaultFormattingRules(document.Project.Services));

            // use formatting that return text changes rather than tree rewrite which is more expensive
            var formatter       = document.GetRequiredLanguageService <ISyntaxFormattingService>();
            var originalChanges = formatter.GetFormattingResult(root, SpecializedCollections.SingletonEnumerable(adjustedSpan), formattingOptions, rules, cancellationToken)
                                  .GetTextChanges(cancellationToken);

            var originalSpan     = RoslynTextSpan.FromBounds(start, end);
            var formattedChanges = ruleFactory.FilterFormattedChanges(document.Id, originalSpan, originalChanges);

            if (formattedChanges.IsEmpty())
            {
                return(VSConstants.S_OK);
            }

            // create new formatted document
            var formattedDocument = document.WithText(text.WithChanges(formattedChanges));

            Workspace.ApplyDocumentChanges(formattedDocument, cancellationToken);

            return(VSConstants.S_OK);
        }
        private void SetNewPositionInTextView(IWpfTextView textView, TextSpan textSpan)
        {
            SnapshotSpan selectedSpan = new SnapshotSpan(textView.TextSnapshot, textSpan.Start, textSpan.Length);

            ExpandAllRegionsContainingSpan(selectedSpan, textView);
            CaretPosition newCaretPosition = textView.MoveCaretTo(textSpan.Start);

            if (!textView.TextViewLines.ContainsBufferPosition(newCaretPosition.BufferPosition))
            {
                textView.ViewScroller.EnsureSpanVisible(selectedSpan, EnsureSpanVisibleOptions.AlwaysCenter);
            }

            textView.Selection.Select(selectedSpan, isReversed: false);
        }
Beispiel #19
0
        public async Task <INavigableLocation?> GetLocationForSpanAsync(
            Workspace workspace, DocumentId documentId, TextSpan textSpan, bool allowInvalidSpan, CancellationToken cancellationToken)
        {
            if (!await this.CanNavigateToSpanAsync(workspace, documentId, textSpan, allowInvalidSpan, cancellationToken).ConfigureAwait(false))
            {
                return(null);
            }

            return(await GetNavigableLocationAsync(workspace,
                                                   documentId,
                                                   _ => Task.FromResult(textSpan),
                                                   text => GetVsTextSpan(text, textSpan, allowInvalidSpan),
                                                   cancellationToken).ConfigureAwait(false));
        }
        private async Task <FunctionBreakpointNameFactory?> GetFunctionBreakpointNameFactoryAsync(CancellationToken cancellationToken)
        {
            ErrorHandler.ThrowOnFailure(textManager.GetActiveView(fMustHaveFocus: 1, pBuffer: null, out var view));
            var activeViewSelection = editorAdaptersFactoryService.GetWpfTextView(view).Selection;
            var document            = activeViewSelection.Start.Position.Snapshot.GetOpenDocumentInCurrentContextWithChanges();

            return(await FunctionBreakpointUtils.GetFunctionBreakpointNameFactoryAsync(
                       await document.GetSyntaxRootAsync(cancellationToken),
                       TextSpan.FromBounds(
                           activeViewSelection.Start.Position.Position,
                           activeViewSelection.End.Position.Position),
                       document.GetSemanticModelAsync,
                       cancellationToken));
        }
Beispiel #21
0
        protected virtual async Task CommandCallbackAsync()
        {
            IWpfTextView textView = await ServiceProvider.GetWpfTextViewAsync();

            if (textView == null)
            {
                return;
            }

            SnapshotPoint     caretPosition = textView.Caret.Position.BufferPosition;
            ITextSnapshotLine caretLine     = caretPosition.GetContainingLine();

            if (caretLine == null)
            {
                return;
            }

            Document document = caretPosition.Snapshot.GetOpenDocumentInCurrentContextWithChanges();

            if (document == null || !document.SupportsSyntaxTree /*|| document.SourceCodeKind ==*/)
            {
                return;
            }

            Task <SyntaxNode>    syntaxRootTask    = document.GetSyntaxRootAsync(Package.DisposalToken);
            Task <SemanticModel> semanticModelTask = document.GetSemanticModelAsync(Package.DisposalToken);
            await Task.WhenAll(syntaxRootTask, semanticModelTask);

#pragma warning disable VSTHRD002, VSTHRD103 // Avoid problematic synchronous waits - the results are already obtained
            SyntaxNode    syntaxRoot    = syntaxRootTask.Result;
            SemanticModel semanticModel = semanticModelTask.Result;
#pragma warning restore VSTHRD002, VSTHRD103

            if (syntaxRoot == null || semanticModel == null || !IsPlatformReferenced(semanticModel) ||
                Package.DisposalToken.IsCancellationRequested)
            {
                return;
            }

            TextSpan caretSpan = GetTextSpanFromCaret(caretPosition, caretLine);
            List <DiagnosticData> diagnosticData = await GetDiagnosticsAsync(document, caretSpan);

            SyntaxNode nodeWithDiagnostic = syntaxRoot.FindNode(caretSpan);

            if (nodeWithDiagnostic != null)
            {
                await SuppressDiagnosticsAsync(diagnosticData, document, syntaxRoot, semanticModel, nodeWithDiagnostic);
            }
        }
        public bool CanNavigateToSpan(Workspace workspace, DocumentId documentId, TextSpan textSpan)
        {
            // Navigation should not change the context of linked files and Shared Projects.
            documentId = workspace.GetDocumentIdInCurrentContext(documentId);

            if (!IsSecondaryBuffer(workspace, documentId))
            {
                return true;
            }

            var document = workspace.CurrentSolution.GetDocument(documentId);
            var text = document.GetTextAsync(CancellationToken.None).WaitAndGetResult(CancellationToken.None);
            var vsTextSpan = text.GetVsTextSpanForSpan(textSpan);

            return CanMapFromSecondaryBufferToPrimaryBuffer(workspace, documentId, vsTextSpan);
        }
        public bool CanNavigateToSpan(Workspace workspace, DocumentId documentId, TextSpan textSpan)
        {
            // Navigation should not change the context of linked files and Shared Projects.
            documentId = workspace.GetDocumentIdInCurrentContext(documentId);

            if (!IsSecondaryBuffer(workspace, documentId))
            {
                return(true);
            }

            var document   = workspace.CurrentSolution.GetDocument(documentId);
            var text       = document.GetTextAsync(CancellationToken.None).WaitAndGetResult(CancellationToken.None);
            var vsTextSpan = text.GetVsTextSpanForSpan(textSpan);

            return(CanMapFromSecondaryBufferToPrimaryBuffer(workspace, documentId, vsTextSpan));
        }
        private int FormatWorker(IVsTextLayer textLayer, TextSpan[] selections, CancellationToken cancellationToken)
        {
            var textBuffer = this.EditorAdaptersFactoryService.GetDataBuffer((IVsTextBuffer)textLayer);

            if (textBuffer == null)
            {
                return(VSConstants.E_UNEXPECTED);
            }

            var document = textBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges();

            if (document == null)
            {
                return(VSConstants.E_FAIL);
            }

            var text = document.GetTextAsync(cancellationToken).WaitAndGetResult(cancellationToken);
            var root = document.GetSyntaxRootAsync(cancellationToken).WaitAndGetResult(cancellationToken);

            var ts           = selections.Single();
            int start        = text.Lines[ts.iStartLine].Start + ts.iStartIndex;
            int end          = text.Lines[ts.iEndLine].Start + ts.iEndIndex;
            var adjustedSpan = GetFormattingSpan(root, start, end);

            // Since we know we are on the UI thread, lets get the base indentation now, so that there is less
            // cleanup work to do later in Venus.
            var ruleFactory = this.Workspace.Services.GetService <IHostDependentFormattingRuleFactoryService>();
            var rules       = ruleFactory.CreateRule(document, start).Concat(Formatter.GetDefaultFormattingRules(document));

            // use formatting that return text changes rather than tree rewrite which is more expensive
            var originalChanges = Formatter.GetFormattedTextChanges(root, adjustedSpan, document.Project.Solution.Workspace, rules: rules, cancellationToken: cancellationToken);

            var originalSpan     = RoslynTextSpan.FromBounds(start, end);
            var formattedChanges = ruleFactory.FilterFormattedChanges(document, originalSpan, originalChanges);

            if (formattedChanges.IsEmpty())
            {
                return(VSConstants.S_OK);
            }

            // create new formatted document
            var formattedDocument = document.WithText(text.WithChanges(formattedChanges));

            formattedDocument.Project.Solution.Workspace.ApplyDocumentChanges(formattedDocument, cancellationToken);

            return(VSConstants.S_OK);
        }
        // Returns the minimal TextSpan that encompasses all the differences between the old and the new text.
        protected static void TrackEncompassingChange(SourceText oldText, SourceText newText, out TextSpan spanBeforeChange, out TextSpan spanAfterChange)
        {
            if (oldText is null)
            {
                throw new ArgumentNullException(nameof(oldText));
            }

            if (newText is null)
            {
                throw new ArgumentNullException(nameof(newText));
            }

            var affectedRange = newText.GetEncompassingTextChangeRange(oldText);

            spanBeforeChange = affectedRange.Span;
            spanAfterChange  = new TextSpan(spanBeforeChange.Start, affectedRange.NewLength);
        }
Beispiel #26
0
        public static async Task <(IWpfTextView WpfTextView, CaretPosition CaretPosition)> NavigateToAsync(this ISymbol symbol,
                                                                                                           SyntaxReference reference, bool selectSpan = true,
                                                                                                           CancellationToken cToken = default)
        {
            symbol.ThrowOnNull(nameof(symbol));
            reference.ThrowOnNull(nameof(reference));
            var filePath = reference.SyntaxTree?.FilePath;

            await Shell.ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();

            var workspace = await AcuminatorVSPackage.Instance.GetVSWorkspaceAsync();

            TextSpan textSpanToNavigate = await GetTextSpanToNavigateFromSymbolAsync(symbol, reference, cToken);

            return(await AcuminatorVSPackage.Instance.OpenCodeFileAndNavigateToPositionAsync(workspace?.CurrentSolution, filePath,
                                                                                             textSpanToNavigate, selectSpan));
        }
Beispiel #27
0
 private TextSpan GetTextSpanFromCaret(SnapshotPoint caretPosition, ITextSnapshotLine caretLine)
 {
     if (caretLine.Length == 0)
     {
         return(TextSpan.FromBounds(caretLine.Start.Position, caretLine.End.Position));
     }
     else if (caretPosition.Position < caretLine.End.Position)
     {
         var nextPoint = caretPosition.Add(1);
         return(TextSpan.FromBounds(caretPosition.Position, nextPoint.Position));
     }
     else
     {
         var prevPoint = caretPosition.Add(-1);
         return(TextSpan.FromBounds(prevPoint.Position, caretPosition.Position));
     }
 }
            static VsTextSpan GetVsTextSpan(SourceText text, TextSpan textSpan)
            {
                var boundedTextSpan = GetSpanWithinDocumentBounds(textSpan, text.Length);

                if (boundedTextSpan != textSpan)
                {
                    try
                    {
                        throw new ArgumentOutOfRangeException();
                    }
                    catch (ArgumentOutOfRangeException e) when(FatalError.ReportAndCatch(e))
                    {
                    }
                }

                return(text.GetVsTextSpanForSpan(boundedTextSpan));
            }
        private static List <PropertyDeclarationSyntax> ExtractCSharpProperties(SourceText newText, IReadOnlyList <RazorDirectiveSyntax> codeBlocks)
        {
            var propertyList = new List <PropertyDeclarationSyntax>();

            for (var i = 0; i < codeBlocks.Count; i++)
            {
                var bodyRange    = ((RazorDirectiveBodySyntax)codeBlocks[i].Body).CSharpCode.Span;
                var bodyTextSpan = TextSpan.FromBounds(bodyRange.Start, bodyRange.End);
                var subText      = newText.GetSubText(bodyTextSpan);
                var parsedText   = CSharpSyntaxTree.ParseText(subText);
                var root         = parsedText.GetRoot();
                var childNodes   = root.ChildNodes();
                var properties   = childNodes.Where(node => node.Kind() == CodeAnalysis.CSharp.SyntaxKind.PropertyDeclaration).OfType <PropertyDeclarationSyntax>();
                propertyList.AddRange(properties);
            }

            return(propertyList);
        }
        public bool TryNavigateToSpan(Workspace workspace, DocumentId documentId, TextSpan textSpan, OptionSet options)
        {
            // Navigation should not change the context of linked files and Shared Projects.
            documentId = workspace.GetDocumentIdInCurrentContext(documentId);

            if (!IsForeground())
            {
                throw new InvalidOperationException(ServicesVSResources.Navigation_must_be_performed_on_the_foreground_thread);
            }

            using (OpenNewDocumentStateScope(options ?? workspace.Options))
            {
                var document = OpenDocument(workspace, documentId);
                if (document == null)
                {
                    return false;
                }

                var text = document.GetTextSynchronously(CancellationToken.None);
                var textBuffer = text.Container.GetTextBuffer();

                var boundedTextSpan = GetSpanWithinDocumentBounds(textSpan, text.Length);
                if (boundedTextSpan != textSpan)
                {
                    try
                    {
                        throw new ArgumentOutOfRangeException();
                    }
                    catch (ArgumentOutOfRangeException e) when (FatalError.ReportWithoutCrash(e))
                    {
                    }
                }

                var vsTextSpan = text.GetVsTextSpanForSpan(boundedTextSpan);

                if (IsSecondaryBuffer(workspace, documentId) &&
                    !vsTextSpan.TryMapSpanFromSecondaryBufferToPrimaryBuffer(workspace, documentId, out vsTextSpan))
                {
                    return false;
                }

                return NavigateTo(textBuffer, vsTextSpan);
            }
        }
Beispiel #31
0
        private bool TryGetDocumentWithFullyQualifiedTypeName(
            Document document,
            out TextSpan updatedTextSpan,
            [NotNullWhen(returnValue: true)] out Document?documentWithFullyQualifiedTypeName
            )
        {
            documentWithFullyQualifiedTypeName = null;
            updatedTextSpan = default;

            Contract.ThrowIfNull(_snippetExpansionClient.ExpansionSession);

            var surfaceBufferFieldSpan = _snippetExpansionClient.ExpansionSession.GetFieldSpan(
                _fieldName
                );

            if (
                !_snippetExpansionClient.TryGetSubjectBufferSpan(
                    surfaceBufferFieldSpan,
                    out var subjectBufferFieldSpan
                    )
                )
            {
                return(false);
            }

            var originalTextSpan = new TextSpan(
                subjectBufferFieldSpan.Start,
                subjectBufferFieldSpan.Length
                );

            updatedTextSpan = new TextSpan(
                subjectBufferFieldSpan.Start,
                _fullyQualifiedName.Length
                );

            var textChange = new TextChange(originalTextSpan, _fullyQualifiedName);
            var newText    = document
                             .GetTextSynchronously(CancellationToken.None)
                             .WithChanges(textChange);

            documentWithFullyQualifiedTypeName = document.WithText(newText);
            return(true);
        }
Beispiel #32
0
        private void TrackChangeInSpan(SourceText oldText, TextSpan originalSpan, SourceText newText, out TextSpan changedSpan, out TextSpan changeEncompassingSpan)
        {
            var affectedRange = newText.GetEncompassingTextChangeRange(oldText);

            // The span of text before the edit which is being changed
            changeEncompassingSpan = affectedRange.Span;

            if (!originalSpan.Contains(changeEncompassingSpan))
            {
                _logger.LogDebug($"The changed region {changeEncompassingSpan} was not a subset of the span {originalSpan} being tracked. This is unexpected.");
            }

            // We now know what was the range that changed and the length of that span after the change.
            // Let's now compute what the original span looks like after the change.
            // We know it still starts from the same location but could have grown or shrunk in length.
            // Compute the change in length and then update the original span.
            var changeInOriginalSpanLength = affectedRange.NewLength - changeEncompassingSpan.Length;

            changedSpan = TextSpan.FromBounds(originalSpan.Start, originalSpan.End + changeInOriginalSpanLength);
        }
 protected abstract bool TryGetSimplifiedTypeName(Document documentWithFullyQualifiedTypeName, TextSpan updatedTextSpan, CancellationToken cancellationToken, out string simplifiedTypeName);
        protected override bool TryGetSimplifiedTypeNameInCaseContext(Document document, string fullyQualifiedTypeName, string firstEnumMemberName, int startPosition, int endPosition, CancellationToken cancellationToken, out string simplifiedTypeName)
        {
            simplifiedTypeName = string.Empty;
            var typeAnnotation = new SyntaxAnnotation();

            var str = "case " + fullyQualifiedTypeName + "." + firstEnumMemberName + ":" + Environment.NewLine + " break;";
            var textChange = new TextChange(new TextSpan(startPosition, endPosition - startPosition), str);
            var typeSpanToAnnotate = new TextSpan(startPosition + "case ".Length, fullyQualifiedTypeName.Length);

            var textWithCaseAdded = document.GetTextAsync(cancellationToken).WaitAndGetResult(cancellationToken).WithChanges(textChange);
            var documentWithCaseAdded = document.WithText(textWithCaseAdded);

            var syntaxRoot = documentWithCaseAdded.GetSyntaxRootSynchronously(cancellationToken);
            var nodeToReplace = syntaxRoot.DescendantNodes().FirstOrDefault(n => n.Span == typeSpanToAnnotate);

            if (nodeToReplace == null)
            {
                return false;
            }

            var updatedRoot = syntaxRoot.ReplaceNode(nodeToReplace, nodeToReplace.WithAdditionalAnnotations(typeAnnotation, Simplifier.Annotation));
            var documentWithAnnotations = documentWithCaseAdded.WithSyntaxRoot(updatedRoot);

            var simplifiedDocument = Simplifier.ReduceAsync(documentWithAnnotations, cancellationToken: cancellationToken).Result;
            simplifiedTypeName = simplifiedDocument.GetSyntaxRootSynchronously(cancellationToken).GetAnnotatedNodesAndTokens(typeAnnotation).Single().ToString();
            return true;
        }
        public bool TryNavigateToSpan(Workspace workspace, DocumentId documentId, TextSpan textSpan, OptionSet options)
        {
            // Navigation should not change the context of linked files and Shared Projects.
            documentId = workspace.GetDocumentIdInCurrentContext(documentId);

            if (!IsForeground())
            {
                throw new InvalidOperationException(ServicesVSResources.Navigation_must_be_performed_on_the_foreground_thread);
            }

            var document = OpenDocument(workspace, documentId, options);
            if (document == null)
            {
                return false;
            }

            var text = document.GetTextAsync(CancellationToken.None).WaitAndGetResult(CancellationToken.None);
            var textBuffer = text.Container.GetTextBuffer();

            var vsTextSpan = text.GetVsTextSpanForSpan(textSpan);
            if (IsSecondaryBuffer(workspace, documentId) &&
                !vsTextSpan.TryMapSpanFromSecondaryBufferToPrimaryBuffer(workspace, documentId, out vsTextSpan))
            {
                return false;
            }

            return NavigateTo(textBuffer, vsTextSpan);
        }