Exemple #1
0
        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().
            }
        }
Exemple #4
0
        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));
        }
Exemple #5
0
        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);
        }
Exemple #7
0
        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),
 };
Exemple #11
0
 public object?GetOption(OptionKey optionKey) => _globalOptionService.GetOption(optionKey);
Exemple #12
0
 public bool IsPrettyListingOn(string languageName)
 => _globalOptions.GetOption(FeatureOnOffOptions.PrettyListing, languageName);
Exemple #13
0
            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);
        }
Exemple #17
0
 public bool IsInLspEditorContext() => _globalOptionsService.GetOption(LspOptions.LspEditorFeatureFlag);
Exemple #18
0
        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);
Exemple #20
0
        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());
        }
Exemple #22
0
        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);
Exemple #25
0
        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);
Exemple #26
0
        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);
        }
Exemple #27
0
 public bool IsInLspEditorContext()
 => IsLiveShareGuest() || IsCloudEnvironmentClient() || _globalOptions.GetOption(LspOptions.LspEditorFeatureFlag);