private void UpdateAdornments() { _adornmentLayer.RemoveAllAdornments(); if (_renameService.ActiveSession != null && ViewIncludesBufferFromWorkspace(_textView, _renameService.ActiveSession.Workspace)) { _dashboardColorUpdater?.UpdateColors(); var useInlineAdornment = _globalOptionService.GetOption(InlineRenameExperimentationOptions.UseInlineAdornment); if (useInlineAdornment) { if (!_textView.HasAggregateFocus) { // For the rename flyout, the adornment is dismissed on focus lost. There's // no need to keep an adornment on every textview for show/hide behaviors return; } var adornment = new RenameFlyout( (RenameFlyoutViewModel)s_createdViewModels.GetValue(_renameService.ActiveSession, session => new RenameFlyoutViewModel(session)), _textView); _adornmentLayer.AddAdornment( AdornmentPositioningBehavior.ViewportRelative, null, // Set no visual span because we don't want the editor to automatically remove the adornment if the overlapping span changes tag: null, adornment, (tag, adornment) => ((InlineRenameAdornment)adornment).Dispose()); } else { var newAdornment = new RenameDashboard( (RenameDashboardViewModel)s_createdViewModels.GetValue(_renameService.ActiveSession, session => new RenameDashboardViewModel(session)), _editorFormatMapService, _textView); _adornmentLayer.AddAdornment(AdornmentPositioningBehavior.ViewportRelative, null, null, newAdornment, (tag, adornment) => ((RenameDashboard)adornment).Dispose()); } } }
public ISuggestedActionsSource?CreateSuggestedActionsSource(ITextView textView, ITextBuffer textBuffer) { Contract.ThrowIfNull(textView); Contract.ThrowIfNull(textBuffer); // Disable lightbulb points when running under the LSP editor. // The LSP client will interface with the editor to display our code actions. if (textBuffer.IsInLspEditorContext()) { return(null); } // if user has explicitly set the option defer to that. otherwise, we are enabled by default (unless our // A/B escape hatch disables us). var asyncEnabled = _globalOptions.GetOption(SuggestionsOptions.Asynchronous) is bool b ? b : !_globalOptions.GetOption(SuggestionsOptions.AsynchronousQuickActionsDisableFeatureFlag); return(asyncEnabled ? new AsyncSuggestedActionsSource(_threadingContext, _globalOptions, this, textView, textBuffer, _suggestedActionCategoryRegistry) : new SyncSuggestedActionsSource(_threadingContext, _globalOptions, this, textView, textBuffer, _suggestedActionCategoryRegistry)); }
public void ExecuteCommand(PasteCommandArgs args, Action nextCommandHandler, CommandExecutionContext executionContext) { // If the feature is not explicitly enabled we can exit early if (_globalOptions.GetOption(FeatureOnOffOptions.AddImportsOnPaste, args.SubjectBuffer.GetLanguageName()) != true) { nextCommandHandler(); return; } // Capture the pre-paste caret position var caretPosition = args.TextView.GetCaretPoint(args.SubjectBuffer); if (!caretPosition.HasValue) { nextCommandHandler(); return; } // Create a tracking span from the pre-paste caret position that will grow as text is inserted. var trackingSpan = caretPosition.Value.Snapshot.CreateTrackingSpan(caretPosition.Value.Position, 0, SpanTrackingMode.EdgeInclusive); // Perform the paste command before adding imports nextCommandHandler(); if (executionContext.OperationContext.UserCancellationToken.IsCancellationRequested) { return; } try { ExecuteCommandWorker(args, executionContext, trackingSpan); } catch (OperationCanceledException) { // According to Editor command handler API guidelines, it's best if we return early if cancellation // is requested instead of throwing. Otherwise, we could end up in an invalid state due to already // calling nextCommandHandler(). } }
private bool BeforeExecuteCommand(bool speculative, TypeCharCommandArgs args, CommandExecutionContext executionContext) { if (args.TypedChar != ';' || !args.TextView.Selection.IsEmpty) { return(false); } var caretOpt = args.TextView.GetCaretPoint(args.SubjectBuffer); if (!caretOpt.HasValue) { return(false); } if (!_globalOptions.GetOption(FeatureOnOffOptions.AutomaticallyCompleteStatementOnSemicolon)) { return(false); } var caret = caretOpt.Value; var document = caret.Snapshot.GetOpenDocumentInCurrentContextWithChanges(); if (document == null) { return(false); } var syntaxFacts = document.GetLanguageService <ISyntaxFactsService>(); var root = document.GetSyntaxRootSynchronously(executionContext.OperationContext.UserCancellationToken); var cancellationToken = executionContext.OperationContext.UserCancellationToken; if (!TryGetStartingNode(root, caret, out var currentNode, cancellationToken)) { return(false); } return(MoveCaretToSemicolonPosition(speculative, args, document, root, originalCaret: caret, caret, syntaxFacts, currentNode, isInsideDelimiters: false, cancellationToken)); }
protected override void TelemetrySessionInitialized() { _ = Task.Run(async() => { var client = await RemoteHostClient.TryGetClientAsync(_workspace, CancellationToken.None).ConfigureAwait(false); if (client == null) { return; } var settings = SerializeCurrentSessionSettings(); Contract.ThrowIfNull(settings); // Only log "delta" property for block end events if feature flag is enabled. var logDelta = _globalOptions.GetOption(DiagnosticOptions.LogTelemetryForBackgroundAnalyzerExecution); // initialize session in the remote service _ = await client.TryInvokeAsync <IRemoteProcessTelemetryService>( (service, cancellationToken) => service.InitializeTelemetrySessionAsync(Process.GetCurrentProcess().Id, settings, logDelta, cancellationToken), CancellationToken.None).ConfigureAwait(false); }); }
private void OnPropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName != nameof(ITaskList.CommentTokens)) { return; } var commentString = GetTaskTokenList(_taskList); var optionValue = _globalOptionService.GetOption(TodoCommentOptions.TokenList); if (optionValue == commentString) { return; } // cache last result _lastCommentTokenCache = commentString; // let people to know that comment string has changed _globalOptionService.RefreshOption(new OptionKey(TodoCommentOptions.TokenList), _lastCommentTokenCache); }
public bool IsRegistrationIdValid(string registrationId) { bool result = false; string Promocode = _globalOptionService.GetOption(SettingConstant.PromoCodeKey).OptionValue; try { var response = _softwareService.IsRegistrationKeyValid(registrationId, Promocode); if (response != null && !response.ImageUrl.IsEmpty()) { _globalOptionService.SetOption(SettingConstant.RegistrationKey, registrationId); result = true; } } catch (Exception ex) { Application.Current.MainPage.DisplayAlert("Registration Failed!", ex.Message, "Ok"); } return(result); }
public static IdeAnalyzerOptions GetIdeAnalyzerOptions(this IGlobalOptionService globalOptions, HostLanguageServices languageServices) { var language = languageServices.Language; var supportsLanguageSpecificOptions = languageServices.GetService <ISyntaxFormattingOptionsStorage>() != null; return(new() { CrashOnAnalyzerException = globalOptions.GetOption(CrashOnAnalyzerException), ReportInvalidPlaceholdersInStringDotFormatCalls = globalOptions.GetOption(ReportInvalidPlaceholdersInStringDotFormatCalls, language), ReportInvalidRegexPatterns = globalOptions.GetOption(ReportInvalidRegexPatterns, language), ReportInvalidJsonPatterns = globalOptions.GetOption(ReportInvalidJsonPatterns, language), DetectAndOfferEditorFeaturesForProbableJsonStrings = globalOptions.GetOption(DetectAndOfferEditorFeaturesForProbableJsonStrings, language), PreferSystemHashCode = globalOptions.GetOption(CodeStyleOptions2.PreferSystemHashCode, language), CleanCodeGenerationOptions = supportsLanguageSpecificOptions ? globalOptions.GetCleanCodeGenerationOptions(languageServices) : null, CodeStyleOptions = supportsLanguageSpecificOptions ? globalOptions.GetCodeStyleOptions(languageServices) : null, }); }
public UIElement?GenerateGlyph(IWpfTextViewLine line, IGlyphTag tag) { if (tag is not InheritanceMarginTag inheritanceMarginTag) { return(null); } // The life cycle of the glyphs in Indicator Margin is controlled by the editor, // so in order to get the glyphs removed when FeatureOnOffOptions.InheritanceMarginCombinedWithIndicatorMargin is off, // we need // 1. Generate tags when this option changes. // 2. Always return null here to force the editor to remove the glyphs. if (!_globalOptions.GetOption(FeatureOnOffOptions.InheritanceMarginCombinedWithIndicatorMargin)) { return(null); } if (_textView.TextBuffer.GetWorkspace() == null) { return(null); } var membersOnLine = inheritanceMarginTag.MembersOnLine; Contract.ThrowIfTrue(membersOnLine.IsEmpty); return(new InheritanceMarginGlyph( _workspace, _threadingContext, _streamingFindUsagesPresenter, _classificationTypeMap, _classificationFormatMap, _operationExecutor, inheritanceMarginTag, _textView, _listener)); }
protected internal override VSServerCapabilities GetCapabilities() => new VSServerCapabilities { SupportsDiagnosticRequests = _globalOptionService.GetOption(InternalDiagnosticsOptions.LspPullDiagnostics), };
public object?GetOption(OptionKey optionKey) => _globalOptionService.GetOption(optionKey);
public bool IsPrettyListingOn(string languageName) => _globalOptions.GetOption(FeatureOnOffOptions.PrettyListing, languageName);
private void AddOrRemoveDropdown() { if (_codeWindow is not IVsDropdownBarManager dropdownManager) { return; } if (ErrorHandler.Failed(_codeWindow.GetBuffer(out var buffer)) || buffer == null) { return; } var textBuffer = _languageService.EditorAdaptersFactoryService.GetDataBuffer(buffer); var document = textBuffer?.AsTextContainer()?.GetRelatedDocuments().FirstOrDefault(); // TODO - Remove the TS check once they move the liveshare navbar to LSP. Then we can also switch to LSP // for the local navbar implementation. // https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1163360 if (textBuffer?.IsInLspEditorContext() == true && document !.Project !.Language != InternalLanguageNames.TypeScript) { // Remove the existing dropdown bar if it is ours. if (IsOurDropdownBar(dropdownManager, out var _)) { RemoveDropdownBar(dropdownManager); } return; } var enabled = _globalOptions.GetOption(NavigationBarViewOptions.ShowNavigationBar, _languageService.RoslynLanguageName); if (enabled) { if (IsOurDropdownBar(dropdownManager, out var existingDropdownBar)) { // The dropdown bar is already one of ours, do nothing. return; } if (existingDropdownBar != null) { // Not ours, so remove the old one so that we can add ours. RemoveDropdownBar(dropdownManager); } else { Contract.ThrowIfFalse(_navigationBarController == null, "We shouldn't have a controller manager if there isn't a dropdown"); Contract.ThrowIfFalse(_dropdownBarClient == null, "We shouldn't have a dropdown client if there isn't a dropdown"); } AddDropdownBar(dropdownManager); } else { RemoveDropdownBar(dropdownManager); } bool IsOurDropdownBar(IVsDropdownBarManager dropdownBarManager, out IVsDropdownBar?existingDropdownBar) { existingDropdownBar = GetDropdownBar(dropdownBarManager); if (existingDropdownBar != null) { if (_dropdownBarClient != null && _dropdownBarClient == GetDropdownBarClient(existingDropdownBar)) { return(true); } } return(false); } }
protected bool AreSnippetsEnabled(EditorCommandArgs args) { return(GlobalOptions.GetOption(InternalFeatureOnOffOptions.Snippets) && // TODO (https://github.com/dotnet/roslyn/issues/5107): enable in interactive !(Workspace.TryGetWorkspace(args.SubjectBuffer.AsTextContainer(), out var workspace) && workspace.Kind == WorkspaceKind.Interactive)); }
public void ExecuteCommand(AutomaticLineEnderCommandArgs args, Action nextHandler, CommandExecutionContext context) { // get editor operation var operations = _editorOperationsFactoryService.GetEditorOperations(args.TextView); if (operations == null) { nextHandler(); return; } var document = args.SubjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); if (document == null) { NextAction(operations, nextHandler); return; } // feature off if (!GlobalOptions.GetOption(InternalFeatureOnOffOptions.AutomaticLineEnder)) { NextAction(operations, nextHandler); return; } using (context.OperationContext.AddScope(allowCancellation: true, EditorFeaturesResources.Automatically_completing)) { var cancellationToken = context.OperationContext.UserCancellationToken; // caret is not on the subject buffer. nothing we can do var caret = args.TextView.GetCaretPoint(args.SubjectBuffer); if (!caret.HasValue) { NextAction(operations, nextHandler); return; } var caretPosition = caret.Value; // special cases where we treat this command simply as Return. if (TreatAsReturn(document, caretPosition, cancellationToken)) { // leave it to the VS editor to handle this command. // VS editor's default implementation of SmartBreakLine is simply BreakLine, which inserts // a new line and positions the caret with smart indent. nextHandler(); return; } var subjectLineWhereCaretIsOn = caretPosition.GetContainingLine(); // Two possible operations // 1. Add/remove the brace for the selected syntax node (only for C#) // 2. Append an ending string to the line. (For C#, it is semicolon ';', For VB, it is underline '_') // Check if the node could be used to add/remove brace. var selectNodeAndOperationKind = GetValidNodeToModifyBraces(document, caretPosition, cancellationToken); if (selectNodeAndOperationKind != null) { var(selectedNode, addBrace) = selectNodeAndOperationKind.Value; using var transaction = args.TextView.CreateEditTransaction(EditorFeaturesResources.Automatic_Line_Ender, _undoRegistry, _editorOperationsFactoryService); ModifySelectedNode(args, document, selectedNode, addBrace, caretPosition, cancellationToken); NextAction(operations, nextHandler); transaction.Complete(); return; } // Check if we could find the ending position var endingInsertionPosition = GetInsertionPositionForEndingString(document, subjectLineWhereCaretIsOn, cancellationToken); if (endingInsertionPosition != null) { using var transaction = args.TextView.CreateEditTransaction(EditorFeaturesResources.Automatic_Line_Ender, _undoRegistry, _editorOperationsFactoryService); var formattingOptions = document.GetSyntaxFormattingOptionsAsync(GlobalOptions, cancellationToken).AsTask().WaitAndGetResult(cancellationToken); InsertEnding(args.TextView, document, endingInsertionPosition.Value, caretPosition, formattingOptions, cancellationToken); NextAction(operations, nextHandler); transaction.Complete(); return; } // Neither of the two operations could be performed using var editTransaction = args.TextView.CreateEditTransaction(EditorFeaturesResources.Automatic_Line_Ender, _undoRegistry, _editorOperationsFactoryService); NextAction(operations, nextHandler); editTransaction.Complete(); } }
/// <summary> /// Internal for testing purposes. /// </summary> internal async Task <ImmutableArray <CodeDefinitionWindowLocation> > GetContextFromPointAsync( Document document, int position, CancellationToken cancellationToken) { var workspace = document.Project.Solution.Workspace; var navigableItems = await GoToDefinitionHelpers.GetDefinitionsAsync(document, position, cancellationToken).ConfigureAwait(false); if (navigableItems?.Any() == true) { var navigationService = workspace.Services.GetRequiredService <IDocumentNavigationService>(); using var _ = PooledObjects.ArrayBuilder <CodeDefinitionWindowLocation> .GetInstance(out var builder); foreach (var item in navigableItems) { if (await navigationService.CanNavigateToSpanAsync(workspace, item.Document.Id, item.SourceSpan, cancellationToken).ConfigureAwait(false)) { var text = await item.Document.GetTextAsync(cancellationToken).ConfigureAwait(false); var linePositionSpan = text.Lines.GetLinePositionSpan(item.SourceSpan); if (item.Document.FilePath != null) { builder.Add(new CodeDefinitionWindowLocation(item.DisplayTaggedParts.JoinText(), item.Document.FilePath, linePositionSpan.Start)); } } } return(builder.ToImmutable()); } // We didn't have regular source references, but possibly: // 1. Another language (like XAML) will take over via ISymbolNavigationService // 2. There are no locations from source, so we'll try to generate a metadata as source file and use that var symbol = await SymbolFinder.FindSymbolAtPositionAsync( document, position, cancellationToken : cancellationToken).ConfigureAwait(false); if (symbol == null) { return(ImmutableArray <CodeDefinitionWindowLocation> .Empty); } var symbolNavigationService = workspace.Services.GetRequiredService <ISymbolNavigationService>(); var definitionItem = symbol.ToNonClassifiedDefinitionItem(document.Project.Solution, includeHiddenLocations: false); var result = await symbolNavigationService.GetExternalNavigationSymbolLocationAsync(definitionItem, cancellationToken).ConfigureAwait(false); if (result != null) { return(ImmutableArray.Create(new CodeDefinitionWindowLocation(symbol.ToDisplayString(), result.Value.filePath, result.Value.linePosition))); } else if (_metadataAsSourceFileService.IsNavigableMetadataSymbol(symbol)) { var allowDecompilation = _globalOptions.GetOption(FeatureOnOffOptions.NavigateToDecompiledSources); var declarationFile = await _metadataAsSourceFileService.GetGeneratedFileAsync(document.Project, symbol, signaturesOnly : false, allowDecompilation, cancellationToken).ConfigureAwait(false); var identifierSpan = declarationFile.IdentifierLocation.GetLineSpan().Span; return(ImmutableArray.Create(new CodeDefinitionWindowLocation(symbol.ToDisplayString(), declarationFile.FilePath, identifierSpan.Start))); } return(ImmutableArray <CodeDefinitionWindowLocation> .Empty); }
public bool IsInLspEditorContext() => _globalOptionsService.GetOption(LspOptions.LspEditorFeatureFlag);
public async Task <LSP.CompletionList?> HandleRequestAsync(LSP.CompletionParams request, RequestContext context, CancellationToken cancellationToken) { var document = context.Document; Contract.ThrowIfNull(document); // C# and VB share the same LSP language server, and thus share the same default trigger characters. // We need to ensure the trigger character is valid in the document's language. For example, the '{' // character, while a trigger character in VB, is not a trigger character in C#. if (request.Context != null && request.Context.TriggerKind == LSP.CompletionTriggerKind.TriggerCharacter && !char.TryParse(request.Context.TriggerCharacter, out var triggerCharacter) && !char.IsLetterOrDigit(triggerCharacter) && !IsValidTriggerCharacterForDocument(document, triggerCharacter)) { return(null); } var completionOptions = GetCompletionOptions(document); var completionService = document.GetRequiredLanguageService <CompletionService>(); var documentText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); var completionListResult = await GetFilteredCompletionListAsync(request, documentText, document, completionOptions, completionService, cancellationToken).ConfigureAwait(false); if (completionListResult == null) { return(null); } var(list, isIncomplete, resultId) = completionListResult.Value; var lspVSClientCapability = context.ClientCapabilities.HasVisualStudioLspCapability() == true; var snippetsSupported = context.ClientCapabilities.TextDocument?.Completion?.CompletionItem?.SnippetSupport ?? false; var commitCharactersRuleCache = new Dictionary <ImmutableArray <CharacterSetModificationRule>, string[]>(CommitCharacterArrayComparer.Instance); // Feature flag to enable the return of TextEdits instead of InsertTexts (will increase payload size). Contract.ThrowIfNull(context.Solution); var returnTextEdits = _globalOptions.GetOption(LspOptions.LspCompletionFeatureFlag); TextSpan?defaultSpan = null; LSP.Range?defaultRange = null; if (returnTextEdits) { // We want to compute the document's text just once. documentText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); // We use the first item in the completion list as our comparison point for span // and range for optimization when generating the TextEdits later on. var completionChange = await completionService.GetChangeAsync( document, list.Items.First(), cancellationToken : cancellationToken).ConfigureAwait(false); // If possible, we want to compute the item's span and range just once. // Individual items can override this range later. defaultSpan = completionChange.TextChange.Span; defaultRange = ProtocolConversions.TextSpanToRange(defaultSpan.Value, documentText); } var supportsCompletionListData = context.ClientCapabilities.HasCompletionListDataCapability(); var completionResolveData = new CompletionResolveData() { ResultId = resultId, }; var stringBuilder = new StringBuilder(); using var _ = ArrayBuilder <LSP.CompletionItem> .GetInstance(out var lspCompletionItems); foreach (var item in list.Items) { var completionItemResolveData = supportsCompletionListData ? null : completionResolveData; var lspCompletionItem = await CreateLSPCompletionItemAsync( request, document, item, completionItemResolveData, lspVSClientCapability, commitCharactersRuleCache, completionService, context.ClientName, returnTextEdits, snippetsSupported, stringBuilder, documentText, defaultSpan, defaultRange, cancellationToken).ConfigureAwait(false); lspCompletionItems.Add(lspCompletionItem); } var completionList = new LSP.VSInternalCompletionList { Items = lspCompletionItems.ToArray(), SuggestionMode = list.SuggestionModeItem != null, IsIncomplete = isIncomplete, }; if (supportsCompletionListData) { completionList.Data = completionResolveData; } if (context.ClientCapabilities.HasCompletionListCommitCharactersCapability()) { PromoteCommonCommitCharactersOntoList(completionList); } var optimizedCompletionList = new LSP.OptimizedVSCompletionList(completionList); return(optimizedCompletionList); // Local functions bool IsValidTriggerCharacterForDocument(Document document, char triggerCharacter) { if (document.Project.Language == LanguageNames.CSharp) { return(_csharpTriggerCharacters.Contains(triggerCharacter)); } else if (document.Project.Language == LanguageNames.VisualBasic) { return(_vbTriggerCharacters.Contains(triggerCharacter)); } // Typescript still calls into this for completion. // Since we don't know what their trigger characters are, just return true. return(true); }
// Local functions static BackgroundAnalysisScope?GetBackgroundAnalysisScope(Solution solution, IGlobalOptionService globalOptions) { var csharpAnalysisScope = globalOptions.GetOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp); var visualBasicAnalysisScope = globalOptions.GetOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.VisualBasic); var containsCSharpProject = solution.Projects.Any(static project => project.Language == LanguageNames.CSharp);
public bool ExecuteCommand(ReturnKeyCommandArgs args, CommandExecutionContext context) { var textView = args.TextView; var subjectBuffer = args.SubjectBuffer; var spans = textView.Selection.GetSnapshotSpansOnBuffer(subjectBuffer); // Don't do anything special if there is multi-selection. It's not clear what sort of semantics that should have. if (spans.Count != 1) { return(false); } var snapshot = subjectBuffer.CurrentSnapshot; var document = snapshot.GetOpenDocumentInCurrentContextWithChanges(); if (document == null) { return(false); } if (!_globalOptions.GetOption(SplitCommentOptions.Enabled, document.Project.Language)) { return(false); } var splitCommentService = document.GetLanguageService <ISplitCommentService>(); if (splitCommentService == null) { return(false); } // If there is a selection, ensure that it's all on one-line. It's not clear what sort of semantics we // would want if this spanned multiple lines. var selectionSpan = spans[0].Span; var position = selectionSpan.Start; var line = subjectBuffer.CurrentSnapshot.GetLineFromPosition(position); var endLine = subjectBuffer.CurrentSnapshot.GetLineFromPosition(selectionSpan.End); if (line.LineNumber != endLine.LineNumber) { return(false); } // Quick check. If the line doesn't contain a comment in it before the caret, // then no point in doing any more expensive synchronous work. if (!LineProbablyContainsComment(splitCommentService, new SnapshotPoint(snapshot, position))) { return(false); } using (context.OperationContext.AddScope(allowCancellation: true, EditorFeaturesResources.Split_comment)) { var cancellationToken = context.OperationContext.UserCancellationToken; var parsedDocument = ParsedDocument.CreateSynchronously(document, cancellationToken); var result = SplitComment(parsedDocument, textView, subjectBuffer, new SnapshotSpan(snapshot, selectionSpan)); if (result == null) { return(false); } using var transaction = CaretPreservingEditTransaction.TryCreate( EditorFeaturesResources.Split_comment, textView, _undoHistoryRegistry, _editorOperationsFactoryService); subjectBuffer.Replace(result.Value.replacementSpan, result.Value.replacementText); transaction?.Complete(); return(true); } }
public async Task <ImmutableArray <InlineHint> > GetInlineHintsAsync( Document document, TextSpan textSpan, InlineTypeHintsOptions options, SymbolDescriptionOptions displayOptions, CancellationToken cancellationToken) { var displayAllOverride = _globalOptions.GetOption(InlineHintsGlobalStateOption.DisplayAllOverride); var enabledForTypes = options.EnabledForTypes; if (!enabledForTypes && !displayAllOverride) { return(ImmutableArray <InlineHint> .Empty); } var forImplicitVariableTypes = enabledForTypes && options.ForImplicitVariableTypes; var forLambdaParameterTypes = enabledForTypes && options.ForLambdaParameterTypes; var forImplicitObjectCreation = enabledForTypes && options.ForImplicitObjectCreation; if (!forImplicitVariableTypes && !forLambdaParameterTypes && !forImplicitObjectCreation && !displayAllOverride) { return(ImmutableArray <InlineHint> .Empty); } var anonymousTypeService = document.GetRequiredLanguageService <IStructuralTypeDisplayService>(); var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); using var _1 = ArrayBuilder <InlineHint> .GetInstance(out var result); foreach (var node in root.DescendantNodes(n => n.Span.IntersectsWith(textSpan))) { var hintOpt = TryGetTypeHint( semanticModel, node, displayAllOverride, forImplicitVariableTypes, forLambdaParameterTypes, forImplicitObjectCreation, cancellationToken); if (hintOpt == null) { continue; } var(type, span, textChange, prefix, suffix) = hintOpt.Value; using var _2 = ArrayBuilder <SymbolDisplayPart> .GetInstance(out var finalParts); finalParts.AddRange(prefix); var parts = type.ToDisplayParts(s_minimalTypeStyle); AddParts(anonymousTypeService, finalParts, parts, semanticModel, span.Start); // If we have nothing to show, then don't bother adding this hint. if (finalParts.All(p => string.IsNullOrWhiteSpace(p.ToString()))) { continue; } finalParts.AddRange(suffix); var taggedText = finalParts.ToTaggedText(); result.Add(new InlineHint( span, taggedText, textChange, InlineHintHelpers.GetDescriptionFunction(span.Start, type.GetSymbolKey(cancellationToken: cancellationToken), displayOptions))); } return(result.ToImmutable()); }
public async Task <bool> TryNavigateToSymbolAsync( ISymbol symbol, Project project, NavigationOptions options, CancellationToken cancellationToken) { if (project == null || symbol == null) { return(false); } symbol = symbol.OriginalDefinition; // Prefer visible source locations if possible. var sourceLocations = symbol.Locations.Where(loc => loc.IsInSource); var visibleSourceLocations = sourceLocations.Where(loc => loc.IsVisibleSourceLocation()); var sourceLocation = visibleSourceLocations.FirstOrDefault() ?? sourceLocations.FirstOrDefault(); if (sourceLocation != null) { var targetDocument = project.Solution.GetDocument(sourceLocation.SourceTree); if (targetDocument != null) { var editorWorkspace = targetDocument.Project.Solution.Workspace; var navigationService = editorWorkspace.Services.GetRequiredService <IDocumentNavigationService>(); return(await navigationService.TryNavigateToSpanAsync( editorWorkspace, targetDocument.Id, sourceLocation.SourceSpan, options, cancellationToken).ConfigureAwait(false)); } } // We don't have a source document, so show the Metadata as Source view in a preview tab. if (!_metadataAsSourceFileService.IsNavigableMetadataSymbol(symbol)) { return(false); } // Should we prefer navigating to the Object Browser over metadata-as-source? if (_globalOptions.GetOption(VisualStudioNavigationOptions.NavigateToObjectBrowser, project.Language)) { var libraryService = project.LanguageServices.GetService <ILibraryService>(); if (libraryService == null) { return(false); } var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); var navInfo = libraryService.NavInfoFactory.CreateForSymbol(symbol, project, compilation); if (navInfo == null) { navInfo = libraryService.NavInfoFactory.CreateForProject(project); } if (navInfo != null) { var navigationTool = IServiceProviderExtensions.GetService <SVsObjBrowser, IVsNavigationTool>(_serviceProvider); return(navigationTool.NavigateToNavInfo(navInfo) == VSConstants.S_OK); } // Note: we'll fallback to Metadata-As-Source if we fail to get IVsNavInfo, but that should never happen. } // Generate new source or retrieve existing source for the symbol in question return(await TryNavigateToMetadataAsync(project, symbol, options, cancellationToken).ConfigureAwait(false)); }
private void UpdateMarginVisibility() { _mainCanvas.Visibility = (_globalOptions.GetOption(FeatureOnOffOptions.ShowInheritanceMargin, _languageName) ?? true) && !_globalOptions.GetOption(FeatureOnOffOptions.InheritanceMarginCombinedWithIndicatorMargin) ? Visibility.Visible : Visibility.Collapsed; }
public static NamingStylePreferences GetNamingStylePreferences(this IGlobalOptionService globalOptions, string language) => globalOptions.GetOption(NamingStyleOptions.NamingPreferences, language);
public void ExecuteCommand(PasteCommandArgs args, Action nextCommandHandler, CommandExecutionContext executionContext) { Contract.ThrowIfFalse(_threadingContext.HasMainThread); var textView = args.TextView; var subjectBuffer = args.SubjectBuffer; var selectionsBeforePaste = textView.Selection.GetSnapshotSpansOnBuffer(subjectBuffer); var snapshotBeforePaste = subjectBuffer.CurrentSnapshot; // Always let the real paste go through. That way we always have a version of the document that doesn't // include our changes that we can undo back to. nextCommandHandler(); // If we don't even see any changes from the paste, there's nothing we can do. if (snapshotBeforePaste.Version.Changes is null) { return; } // If the user has the option off, then don't bother doing anything once we've sent the paste through. if (!_globalOptions.GetOption(FeatureOnOffOptions.AutomaticallyFixStringContentsOnPaste, LanguageNames.CSharp)) { return; } // if we're not even sure where the user caret/selection is on this buffer, we can't proceed. if (selectionsBeforePaste.Count == 0) { return; } var snapshotAfterPaste = subjectBuffer.CurrentSnapshot; // If there were multiple changes that already happened, then don't make any changes. Some other component // already did something advanced. if (snapshotAfterPaste.Version != snapshotBeforePaste.Version.Next) { return; } // Have to even be in a C# doc to be able to have special space processing here. var documentBeforePaste = snapshotBeforePaste.GetOpenDocumentInCurrentContextWithChanges(); var documentAfterPaste = snapshotAfterPaste.GetOpenDocumentInCurrentContextWithChanges(); if (documentBeforePaste == null || documentAfterPaste == null) { return; } var cancellationToken = executionContext.OperationContext.UserCancellationToken; var parsedDocumentBeforePaste = ParsedDocument.CreateSynchronously(documentBeforePaste, cancellationToken); // When pasting, only do anything special if the user selections were entirely inside a single string // token/expression. Otherwise, we have a multi-selection across token kinds which will be extremely // complex to try to reconcile. var stringExpressionBeforePaste = TryGetCompatibleContainingStringExpression(parsedDocumentBeforePaste, selectionsBeforePaste); if (stringExpressionBeforePaste == null) { return; } // Also ensure that all the changes the editor actually applied were inside a single string // token/expression. If the editor decided to make changes outside of the string, we definitely do not want // to do anything here. var stringExpressionBeforePasteFromChanges = TryGetCompatibleContainingStringExpression( parsedDocumentBeforePaste, new NormalizedSnapshotSpanCollection(snapshotBeforePaste, snapshotBeforePaste.Version.Changes.Select(c => c.OldSpan))); if (stringExpressionBeforePaste != stringExpressionBeforePasteFromChanges) { return; } var textChanges = GetEdits(cancellationToken); // If we didn't get any viable changes back, don't do anything. if (textChanges.IsDefaultOrEmpty) { return; } var newTextAfterChanges = snapshotBeforePaste.AsText().WithChanges(textChanges); // If we end up making the same changes as what the paste did, then no need to proceed. if (ContentsAreSame(snapshotBeforePaste, snapshotAfterPaste, stringExpressionBeforePaste, newTextAfterChanges)) { return; } // Create two edits to make the change. The first restores the buffer to the original snapshot (effectively // undoing the first set of changes). Then the second actually applies the change. // // Do this as direct edits, passing 'EditOptions.None' for the options, as we want to control the edits // precisely and don't want any strange interpretation of where the caret should end up. Other options // (like DefaultMinimalChange) will attempt to diff/merge edits oddly sometimes which can lead the caret // ending up before/after some merged change, which will no longer match the behavior of precise pastes. // // Wrap this all as a transaction so that these two edits appear to be one single change. This also allows // the user to do a single 'undo' that gets them back to the original paste made at the start of this // method. using var transaction = new CaretPreservingEditTransaction( CSharpEditorResources.Fixing_string_literal_after_paste, textView, _undoHistoryRegistry, _editorOperationsFactoryService); { var edit = subjectBuffer.CreateEdit(EditOptions.None, reiteratedVersionNumber: null, editTag: null); foreach (var change in snapshotBeforePaste.Version.Changes) { edit.Replace(change.NewSpan, change.OldText); } edit.Apply(); } { var edit = subjectBuffer.CreateEdit(EditOptions.None, reiteratedVersionNumber: null, editTag: null); foreach (var selection in selectionsBeforePaste) { edit.Replace(selection.Span, ""); } foreach (var change in textChanges) { edit.Replace(change.Span.ToSpan(), change.NewText); } edit.Apply(); } transaction.Complete(); return; ImmutableArray <TextChange> GetEdits(CancellationToken cancellationToken) { var newLine = textView.Options.GetNewLineCharacter(); var indentationWhitespace = DetermineIndentationWhitespace( parsedDocumentBeforePaste, subjectBuffer, snapshotBeforePaste.AsText(), stringExpressionBeforePaste, cancellationToken); // See if this is a paste of the last copy that we heard about. var edits = TryGetEditsFromKnownCopySource(newLine, indentationWhitespace); if (!edits.IsDefaultOrEmpty) { return(edits); } var pasteWasSuccessful = PasteWasSuccessful( snapshotBeforePaste, snapshotAfterPaste, documentAfterPaste, stringExpressionBeforePaste, cancellationToken); // If not, then just go through the fallback code path that applies more heuristics. var unknownPasteProcessor = new UnknownSourcePasteProcessor( newLine, indentationWhitespace, snapshotBeforePaste, snapshotAfterPaste, documentBeforePaste, documentAfterPaste, stringExpressionBeforePaste, pasteWasSuccessful); return(unknownPasteProcessor.GetEdits()); } ImmutableArray <TextChange> TryGetEditsFromKnownCopySource( string newLine, string indentationWhitespace) { // For simplicity, we only support smart copy/paste when we are pasting into a single contiguous region. if (selectionsBeforePaste.Count != 1) { return(default);
public bool TryNavigateToSymbol(ISymbol symbol, Project project, OptionSet?options, CancellationToken cancellationToken) { if (project == null || symbol == null) { return(false); } options ??= project.Solution.Options; symbol = symbol.OriginalDefinition; // Prefer visible source locations if possible. var sourceLocations = symbol.Locations.Where(loc => loc.IsInSource); var visibleSourceLocations = sourceLocations.Where(loc => loc.IsVisibleSourceLocation()); var sourceLocation = visibleSourceLocations.FirstOrDefault() ?? sourceLocations.FirstOrDefault(); if (sourceLocation != null) { var targetDocument = project.Solution.GetDocument(sourceLocation.SourceTree); if (targetDocument != null) { var editorWorkspace = targetDocument.Project.Solution.Workspace; var navigationService = editorWorkspace.Services.GetRequiredService <IDocumentNavigationService>(); return(navigationService.TryNavigateToSpan(editorWorkspace, targetDocument.Id, sourceLocation.SourceSpan, options, cancellationToken)); } } // We don't have a source document, so show the Metadata as Source view in a preview tab. var metadataLocation = symbol.Locations.Where(loc => loc.IsInMetadata).FirstOrDefault(); if (metadataLocation == null || !_metadataAsSourceFileService.IsNavigableMetadataSymbol(symbol)) { return(false); } // Should we prefer navigating to the Object Browser over metadata-as-source? if (_globalOptions.GetOption(VisualStudioNavigationOptions.NavigateToObjectBrowser, project.Language)) { var libraryService = project.LanguageServices.GetService <ILibraryService>(); if (libraryService == null) { return(false); } var compilation = project.GetCompilationAsync(cancellationToken).WaitAndGetResult(cancellationToken); var navInfo = libraryService.NavInfoFactory.CreateForSymbol(symbol, project, compilation); if (navInfo == null) { navInfo = libraryService.NavInfoFactory.CreateForProject(project); } if (navInfo != null) { var navigationTool = IServiceProviderExtensions.GetService <SVsObjBrowser, IVsNavigationTool>(_serviceProvider); return(navigationTool.NavigateToNavInfo(navInfo) == VSConstants.S_OK); } // Note: we'll fallback to Metadata-As-Source if we fail to get IVsNavInfo, but that should never happen. } // Generate new source or retrieve existing source for the symbol in question var allowDecompilation = false; // Check whether decompilation is supported for the project. We currently only support this for C# projects. if (project.LanguageServices.GetService <IDecompiledSourceService>() != null) { allowDecompilation = project.Solution.Workspace.Options.GetOption(FeatureOnOffOptions.NavigateToDecompiledSources) && !symbol.IsFromSource(); } var result = _metadataAsSourceFileService.GetGeneratedFileAsync(project, symbol, allowDecompilation, cancellationToken).WaitAndGetResult(cancellationToken); var vsRunningDocumentTable4 = IServiceProviderExtensions.GetService <SVsRunningDocumentTable, IVsRunningDocumentTable4>(_serviceProvider); var fileAlreadyOpen = vsRunningDocumentTable4.IsMonikerValid(result.FilePath); var openDocumentService = IServiceProviderExtensions.GetService <SVsUIShellOpenDocument, IVsUIShellOpenDocument>(_serviceProvider); openDocumentService.OpenDocumentViaProject(result.FilePath, VSConstants.LOGVIEWID.TextView_guid, out var localServiceProvider, out var hierarchy, out var itemId, out var windowFrame); var documentCookie = vsRunningDocumentTable4.GetDocumentCookie(result.FilePath); // The cast from dynamic to object doesn't change semantics, but avoids loading the dynamic binder // which saves us JIT time in this method. var vsTextBuffer = (IVsTextBuffer)(object)vsRunningDocumentTable4.GetDocumentData(documentCookie); var textBuffer = _editorAdaptersFactory.GetDataBuffer(vsTextBuffer); if (!fileAlreadyOpen) { ErrorHandler.ThrowOnFailure(windowFrame.SetProperty((int)__VSFPROPID5.VSFPROPID_IsProvisional, true)); ErrorHandler.ThrowOnFailure(windowFrame.SetProperty((int)__VSFPROPID5.VSFPROPID_OverrideCaption, result.DocumentTitle)); ErrorHandler.ThrowOnFailure(windowFrame.SetProperty((int)__VSFPROPID5.VSFPROPID_OverrideToolTip, result.DocumentTooltip)); } windowFrame.Show(); var openedDocument = textBuffer?.AsTextContainer().GetRelatedDocuments().FirstOrDefault(); if (openedDocument != null) { var editorWorkspace = openedDocument.Project.Solution.Workspace; var navigationService = editorWorkspace.Services.GetRequiredService <IDocumentNavigationService>(); return(navigationService.TryNavigateToSpan( editorWorkspace, openedDocument.Id, result.IdentifierLocation.SourceSpan, options.WithChangedOption(NavigationOptions.PreferProvisionalTab, true), cancellationToken)); } return(true); }
public bool IsInLspEditorContext() => IsLiveShareGuest() || IsCloudEnvironmentClient() || _globalOptions.GetOption(LspOptions.LspEditorFeatureFlag);