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; }
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); }
public bool TryNavigateToSpan(Workspace workspace, DocumentId documentId, TextSpan textSpan, OptionSet options) { return(TryNavigateToLocation(workspace, documentId, _ => textSpan, text => GetVsTextSpan(text, textSpan), options));
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); }
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); }
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); } }
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); }
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)); }
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); }
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)); }
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); } }
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); }
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); }