Exemplo n.º 1
0
        public async Task <TextEdit[]> HandleRequestAsync(DocumentOnTypeFormattingParams request, RequestContext context, CancellationToken cancellationToken)
        {
            var edits    = new ArrayBuilder <TextEdit>();
            var document = context.Document;

            if (document != null)
            {
                var formattingService = document.Project.LanguageServices.GetRequiredService <IEditorFormattingService>();
                var position          = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false);

                if (string.IsNullOrEmpty(request.Character))
                {
                    return(edits.ToArrayAndFree());
                }

                IList <TextChange>?textChanges;
                if (SyntaxFacts.IsNewLine(request.Character[0]))
                {
                    textChanges = await GetFormattingChangesOnReturnAsync(formattingService, document, position, cancellationToken).ConfigureAwait(false);
                }
                else
                {
                    textChanges = await GetFormattingChangesAsync(formattingService, document, request.Character[0], position, cancellationToken).ConfigureAwait(false);
                }

                var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

                if (textChanges != null)
                {
                    edits.AddRange(textChanges.Select(change => ProtocolConversions.TextChangeToTextEdit(change, text)));
                }
            }

            return(edits.ToArrayAndFree());
        }
Exemplo n.º 2
0
        public override async Task <TextEdit[]> HandleRequestAsync(DocumentOnTypeFormattingParams request, RequestContext context, CancellationToken cancellationToken)
        {
            var edits = new ArrayBuilder <TextEdit>();

            if (string.IsNullOrEmpty(request.Character))
            {
                return(edits.ToArrayAndFree());
            }

            var document          = context.Document;
            var formattingService = document?.Project.LanguageServices.GetService <IXamlFormattingService>();

            if (document != null && formattingService != null)
            {
                var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false);

                var options = new XamlFormattingOptions {
                    InsertSpaces = request.Options.InsertSpaces, TabSize = request.Options.TabSize, OtherOptions = request.Options.OtherOptions
                };
                var textChanges = await formattingService.GetFormattingChangesAsync(document, options, request.Character[0], position, cancellationToken).ConfigureAwait(false);

                if (textChanges != null)
                {
                    var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

                    edits.AddRange(textChanges.Select(change => ProtocolConversions.TextChangeToTextEdit(change, text)));
                }
            }

            return(edits.ToArrayAndFree());
        }
Exemplo n.º 3
0
        public override async Task <TextEdit[]?> HandleRequestAsync(
            DocumentOnTypeFormattingParams request,
            RequestContext context,
            CancellationToken cancellationToken)
        {
            var document = context.Document;

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

            var edits = new ArrayBuilder <TextEdit>();

            var formattingService = document.Project.LanguageServices.GetRequiredService <IFormattingInteractionService>();
            var position          = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false);

            if (string.IsNullOrEmpty(request.Character))
            {
                return(edits.ToArrayAndFree());
            }

            // We should use the options passed in by LSP instead of the document's options.
            var documentOptions = await ProtocolConversions.FormattingOptionsToDocumentOptionsAsync(
                request.Options, document, cancellationToken).ConfigureAwait(false);

            IList <TextChange>?textChanges;

            if (SyntaxFacts.IsNewLine(request.Character[0]))
            {
                textChanges = await GetFormattingChangesOnReturnAsync(
                    formattingService, document, position, documentOptions, cancellationToken).ConfigureAwait(false);
            }
            else
            {
                textChanges = await GetFormattingChangesAsync(
                    formattingService, document, request.Character[0], position, documentOptions, cancellationToken).ConfigureAwait(false);
            }

            var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

            if (textChanges != null)
            {
                edits.AddRange(textChanges.Select(change => ProtocolConversions.TextChangeToTextEdit(change, text)));
            }

            return(edits.ToArrayAndFree());
        }
        protected static async Task <LSP.TextEdit[]?> GetTextEditsAsync(
            RequestContext context,
            LSP.FormattingOptions options,
            IGlobalOptionService globalOptions,
            CancellationToken cancellationToken,
            LSP.Range?range = null)
        {
            var document = context.Document;

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

            var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

            var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var rangeSpan      = (range != null) ? ProtocolConversions.RangeToTextSpan(range, text) : new TextSpan(0, root.FullSpan.Length);
            var formattingSpan = CommonFormattingHelpers.GetFormattingSpan(root, rangeSpan);

            // We should use the options passed in by LSP instead of the document's options.
            var formattingOptions = await ProtocolConversions.GetFormattingOptionsAsync(options, document, globalOptions, cancellationToken).ConfigureAwait(false);

            var services    = document.Project.Solution.Services;
            var textChanges = Formatter.GetFormattedTextChanges(root, SpecializedCollections.SingletonEnumerable(formattingSpan), services, formattingOptions, rules: null, cancellationToken);

            var edits = new ArrayBuilder <LSP.TextEdit>();

            edits.AddRange(textChanges.Select(change => ProtocolConversions.TextChangeToTextEdit(change, text)));
            return(edits.ToArrayAndFree());
        }
Exemplo n.º 5
0
        public async Task <object[]> HandleAsync(object param, RequestContext <Solution> requestContext, CancellationToken cancellationToken)
        {
            var projects = new ArrayBuilder <CustomProtocol.Project>();
            var solution = requestContext.Context;

            foreach (var project in solution.Projects)
            {
                var externalUris = new ArrayBuilder <Uri>();
                foreach (var sourceFile in project.Documents)
                {
                    var uri = new Uri(sourceFile.FilePath);
#pragma warning disable 0612
                    if (!requestContext.ProtocolConverter.IsContainedInRootFolders(uri))
#pragma warning restore 0612
                    {
                        externalUris.Add(uri);
                    }
                }
#pragma warning disable 0612
                await requestContext.ProtocolConverter.RegisterExternalFilesAsync(externalUris.ToArrayAndFree()).ConfigureAwait(false);

#pragma warning restore 0612

                var lspProject = new CustomProtocol.Project
                {
                    Name        = project.Name,
                    SourceFiles = project.Documents.Select(d => requestContext.ProtocolConverter.ToProtocolUri(new Uri(d.FilePath))).ToArray(),
                    Language    = project.Language
                };

                projects.Add(lspProject);
            }

            return(projects.ToArrayAndFree());
        }
Exemplo n.º 6
0
        protected async Task <LSP.TextEdit[]?> GetTextEditsAsync(
            RequestContext context,
            LSP.FormattingOptions options,
            CancellationToken cancellationToken,
            LSP.Range?range = null)
        {
            var document = context.Document;

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

            var edits = new ArrayBuilder <LSP.TextEdit>();

            var formattingService = document.Project.LanguageServices.GetRequiredService <IFormattingInteractionService>();
            var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

            TextSpan?textSpan = null;

            if (range != null)
            {
                textSpan = ProtocolConversions.RangeToTextSpan(range, text);
            }

            // We should use the options passed in by LSP instead of the document's options.
            var documentOptions = await ProtocolConversions.FormattingOptionsToDocumentOptionsAsync(
                options, document, cancellationToken).ConfigureAwait(false);

            var textChanges = await GetFormattingChangesAsync(formattingService, document, textSpan, documentOptions, cancellationToken).ConfigureAwait(false);

            edits.AddRange(textChanges.Select(change => ProtocolConversions.TextChangeToTextEdit(change, text)));

            return(edits.ToArrayAndFree());
        }
Exemplo n.º 7
0
        private static ClassifiedTextElement GetSignatureClassifiedText(SignatureHelpItem item)
        {
            var taggedTexts = new ArrayBuilder <TaggedText>();

            taggedTexts.AddRange(item.PrefixDisplayParts);

            var separators = item.SeparatorDisplayParts;

            for (var i = 0; i < item.Parameters.Length; i++)
            {
                var param = item.Parameters[i];

                if (i > 0)
                {
                    taggedTexts.AddRange(separators);
                }

                taggedTexts.AddRange(param.PrefixDisplayParts);
                taggedTexts.AddRange(param.DisplayParts);
                taggedTexts.AddRange(param.SuffixDisplayParts);
            }

            taggedTexts.AddRange(item.SuffixDisplayParts);
            taggedTexts.AddRange(item.DescriptionParts);

            return(new ClassifiedTextElement(
                       taggedTexts
                       .ToArrayAndFree()
                       .Select(
                           part =>
                           new ClassifiedTextRun(part.Tag.ToClassificationTypeName(), part.Text)
                           )
                       ));
        }
Exemplo n.º 8
0
            private XNode[] RewriteMany(
                XNode[] nodes,
                string currentXmlFilePath,
                CSharpSyntaxNode originatingSyntax
                )
            {
                Debug.Assert(nodes != null);

                ArrayBuilder <XNode> builder = null;

                foreach (XNode child in nodes)
                {
                    if (builder == null)
                    {
                        builder = ArrayBuilder <XNode> .GetInstance();
                    }

                    builder.AddRange(Rewrite(child, currentXmlFilePath, originatingSyntax));
                }

                // Nodes returned by this method are going to be attached to a new parent, so it's
                // important that they don't already have parents.  If a node with a parent is
                // attached to a new parent, it is copied and its annotations are dropped.
                Debug.Assert(builder == null || builder.All(node => node.Parent == null));

                return(builder == null?Array.Empty <XNode>() : builder.ToArrayAndFree());
            }
Exemplo n.º 9
0
        private static void VerifySpans(
            DynamicAnalysisDataReader reader,
            DynamicAnalysisMethod methodData,
            string[] sourceLines,
            params SpanResult[] expected
            )
        {
            ArrayBuilder <string> expectedSpanSpellings = ArrayBuilder <string> .GetInstance(
                expected.Length
                );

            foreach (SpanResult expectedSpanResult in expected)
            {
                Assert.True(
                    sourceLines[expectedSpanResult.StartLine]
                    .Substring(expectedSpanResult.StartColumn)
                    .StartsWith(expectedSpanResult.TextStart)
                    );
                expectedSpanSpellings.Add(
                    string.Format(
                        "({0},{1})-({2},{3})",
                        expectedSpanResult.StartLine,
                        expectedSpanResult.StartColumn,
                        expectedSpanResult.EndLine,
                        expectedSpanResult.EndColumn
                        )
                    );
            }

            VerifySpans(reader, methodData, expectedSpanSpellings.ToArrayAndFree());
        }
Exemplo n.º 10
0
            private WarningStateMapEntry[] CoalesceBuilderEntries(ImmutableArray <WarningStateMapBuilderEntry> builderEntries)
            {
                var builder = new ArrayBuilder <WarningStateMapEntry>();

                int currentPosition = 0;
                var accumulatedSpecificWarningState = ImmutableDictionary <string, ReportDiagnostic> .Empty;

                foreach (var entry in builderEntries.Sort())
                {
                    if (entry.Position != currentPosition)
                    {
                        // Commit the previous map entry
                        builder.Add(new WarningStateMapEntry(currentPosition, ReportDiagnostic.Default, accumulatedSpecificWarningState));

                        // Start building up a new map entry
                        currentPosition = entry.Position;
                    }

                    accumulatedSpecificWarningState = accumulatedSpecificWarningState.SetItem(entry.Id, entry.SpecificWarningOption);
                }

                // Commit the final map entry
                builder.Add(new WarningStateMapEntry(currentPosition, ReportDiagnostic.Default, accumulatedSpecificWarningState));

                var entries = builder.ToArrayAndFree();

#if DEBUG
                // Make sure the entries array is correctly sorted.
                for (int i = 1; i < entries.Length - 1; ++i)
                {
                    Debug.Assert(entries[i].CompareTo(entries[i + 1]) < 0);
                }
#endif
                return(entries);
            }
            private ParameterInfo[] ParseParameterList()
            {
                // Consume the opening parenthesis or bracket
                Debug.Assert(PeekNextChar() == '(' || PeekNextChar() == '[');
                ++_index;

                var nextChar = PeekNextChar();

                if (nextChar == ')' || nextChar == ']')
                {
                    // Empty parameter list
                    ++_index;
                    return(s_noParameters);
                }

                var builder = new ArrayBuilder <ParameterInfo>();

                while (true)
                {
                    var parameter = ParseParameter();
                    if (parameter != null)
                    {
                        builder.Add(parameter.Value);
                    }
                    else
                    {
                        builder.Free();
                        return(null);
                    }

                    if (PeekNextChar() == ',')
                    {
                        ++_index;
                    }
                    else
                    {
                        break;
                    }
                }

                nextChar = PeekNextChar();
                if (nextChar == ')' || nextChar == ']')
                {
                    // Consume the closing parenthesis or bracket
                    ++_index;
                }
                else
                {
                    // Malformed parameter list: missing close parenthesis or bracket
                    builder.Free();
                    return(null);
                }

                return(builder.ToArrayAndFree());
            }
Exemplo n.º 12
0
        public async Task <WorkspaceEdit> HandleRequestAsync(Solution solution, RenameParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken)
        {
            WorkspaceEdit workspaceEdit = null;
            var           document      = solution.GetDocumentFromURI(request.TextDocument.Uri);

            if (document != null)
            {
                var renameService = document.Project.LanguageServices.GetService <IEditorInlineRenameService>();
                var position      = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false);

                var renameInfo = await renameService.GetRenameInfoAsync(document, position, cancellationToken).ConfigureAwait(false);

                if (!renameInfo.CanRename)
                {
                    return(workspaceEdit);
                }

                var renameLocationSet = await renameInfo.FindRenameLocationsAsync(solution.Workspace.Options, cancellationToken).ConfigureAwait(false);

                var renameReplacementInfo = await renameLocationSet.GetReplacementsAsync(request.NewName, solution.Workspace.Options, cancellationToken).ConfigureAwait(false);

                var newSolution      = renameReplacementInfo.NewSolution;
                var solutionChanges  = newSolution.GetChanges(solution);
                var changedDocuments = solutionChanges
                                       .GetProjectChanges()
                                       .SelectMany(p => p.GetChangedDocuments(onlyGetDocumentsWithTextChanges: true));

                var documentEdits = new ArrayBuilder <TextDocumentEdit>();
                foreach (var docId in changedDocuments)
                {
                    var oldDoc = solution.GetDocument(docId);
                    var newDoc = newSolution.GetDocument(docId);

                    var textChanges = await newDoc.GetTextChangesAsync(oldDoc, cancellationToken).ConfigureAwait(false);

                    var oldText = await oldDoc.GetTextAsync(cancellationToken).ConfigureAwait(false);

                    var textDocumentEdit = new TextDocumentEdit
                    {
                        TextDocument = new VersionedTextDocumentIdentifier {
                            Uri = newDoc.GetURI()
                        },
                        Edits = textChanges.Select(tc => ProtocolConversions.TextChangeToTextEdit(tc, oldText)).ToArray()
                    };
                    documentEdits.Add(textDocumentEdit);
                }

                workspaceEdit = new WorkspaceEdit {
                    DocumentChanges = documentEdits.ToArrayAndFree()
                };
            }

            return(workspaceEdit);
        }
Exemplo n.º 13
0
        private int[] ParseLineStarts()
        {
            int position = 0;
            int index    = 0;
            int lastCr   = -1;
            ArrayBuilder <int> arrayBuilder = ArrayBuilder <int> .GetInstance();

            // The following loop goes through every character in the text. It is highly
            // performance critical, and thus inlines knowledge about common line breaks
            // and non-line breaks.
            foreach (char[] chunk in _chunks)
            {
                foreach (char c in chunk)
                {
                    index++;

                    // Common case - ASCII & not a line break
                    const uint bias = '\r' + 1;
                    if (unchecked (c - bias) <= (127 - bias))
                    {
                        continue;
                    }

                    switch (c)
                    {
                    case '\r':
                        lastCr = index;
                        goto line_break;

                    case '\n':
                        // Assumes that the only 2-char line break sequence is CR+LF
                        if (lastCr == (index - 1))
                        {
                            position = index;
                            break;
                        }

                        goto line_break;

                    case '\u0085':
                    case '\u2028':
                    case '\u2029':
line_break:
                        arrayBuilder.Add(position);
                        position = index;
                        break;
                    }
                }
            }

            // Create a start for the final line.
            arrayBuilder.Add(position);
            return(arrayBuilder.ToArrayAndFree());
        }
Exemplo n.º 14
0
        private async Task <LSP.ReferenceGroup[]> GetReferenceGroupsAsync(LSP.ReferenceParams request, SimpleFindUsagesContext context, CancellationToken cancellationToken)
        {
            var definitionMap = new Dictionary <DefinitionItem, List <SourceReferenceItem> >();

            foreach (var reference in context.GetReferences())
            {
                if (!definitionMap.ContainsKey(reference.Definition))
                {
                    definitionMap.Add(reference.Definition, new List <SourceReferenceItem>());
                }

                definitionMap[reference.Definition].Add(reference);
            }

            var referenceGroups = ArrayBuilder <LSP.ReferenceGroup> .GetInstance();

            foreach (var keyValuePair in definitionMap)
            {
                var definition = keyValuePair.Key;
                var references = keyValuePair.Value;

                var referenceGroup = new LSP.ReferenceGroup();
                var text           = definition.GetClassifiedText();

                referenceGroup.Definition = await ProtocolConversions.DocumentSpanToLocationWithTextAsync(definition.SourceSpans.First(), text, cancellationToken).ConfigureAwait(false);

                referenceGroup.DefinitionIcon = new ImageElement(definition.Tags.GetFirstGlyph().GetImageId());

                var locationWithTexts = new ArrayBuilder <LSP.LocationWithText>();
                foreach (var reference in references)
                {
                    var classifiedSpansAndHighlightSpan = await ClassifiedSpansAndHighlightSpanFactory.ClassifyAsync(reference.SourceSpan, context.CancellationToken).ConfigureAwait(false);

                    var classifiedSpans   = classifiedSpansAndHighlightSpan.ClassifiedSpans;
                    var referenceLocation = await ProtocolConversions.DocumentSpanToLocationAsync(reference.SourceSpan, cancellationToken).ConfigureAwait(false);

                    var docText = await reference.SourceSpan.Document.GetTextAsync(context.CancellationToken).ConfigureAwait(false);

                    var classifiedText   = new ClassifiedTextElement(classifiedSpans.Select(cspan => new ClassifiedTextRun(cspan.ClassificationType, docText.ToString(cspan.TextSpan))));
                    var locationWithText = new LSP.LocationWithText {
                        Range = referenceLocation.Range, Uri = referenceLocation.Uri, Text = classifiedText
                    };
                    locationWithTexts.Add(locationWithText);
                }

                referenceGroup.References = locationWithTexts.ToArrayAndFree();
                referenceGroups.Add(referenceGroup);
            }

            return(referenceGroups.ToArrayAndFree());
        }
Exemplo n.º 15
0
        public async Task <TextEdit[]> HandleRequestAsync(Solution solution, DocumentOnTypeFormattingParams request, ClientCapabilities clientCapabilities,
                                                          CancellationToken cancellationToken, bool keepThreadContext = false)
        {
            var edits    = new ArrayBuilder <TextEdit>();
            var document = solution.GetDocumentFromURI(request.TextDocument.Uri);

            if (document != null)
            {
                var formattingService = document.Project.LanguageServices.GetService <IEditorFormattingService>();
                var position          = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(keepThreadContext);

                if (string.IsNullOrEmpty(request.Character))
                {
                    return(edits.ToArrayAndFree());
                }

                IList <TextChange> textChanges;
                if (SyntaxFacts.IsNewLine(request.Character[0]))
                {
                    textChanges = await formattingService.GetFormattingChangesOnReturnAsync(document, position, cancellationToken).ConfigureAwait(keepThreadContext);
                }
                else
                {
                    textChanges = await formattingService.GetFormattingChangesAsync(document, request.Character[0], position, cancellationToken).ConfigureAwait(keepThreadContext);
                }

                var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(keepThreadContext);

                if (textChanges != null)
                {
                    edits.AddRange(textChanges.Select(change => ProtocolConversions.TextChangeToTextEdit(change, text)));
                }
            }

            return(edits.ToArrayAndFree());
        }
        /// <summary>
        /// Read UTF8 string with null terminator.
        /// </summary>
        private static string ReadUtf8String(ImmutableArray <byte> bytes, ref int offset)
        {
            ArrayBuilder <byte> builder = ArrayBuilder <byte> .GetInstance();

            while (true)
            {
                byte b = ReadByte(bytes, ref offset);
                if (b == 0)
                {
                    break;
                }
                builder.Add(b);
            }
            byte[] block = builder.ToArrayAndFree();
            return(Encoding.UTF8.GetString(block, 0, block.Length));
        }
Exemplo n.º 17
0
        public async Task <TextEdit[]?> HandleRequestAsync(
            DocumentOnTypeFormattingParams request,
            RequestContext context,
            CancellationToken cancellationToken)
        {
            var document = context.Document;

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

            var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false);

            if (string.IsNullOrEmpty(request.Character) || SyntaxFacts.IsNewLine(request.Character[0]))
            {
                return(Array.Empty <TextEdit>());
            }

            var formattingService = document.Project.LanguageServices.GetRequiredService <ISyntaxFormattingService>();
            var documentSyntax    = await ParsedDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false);

            if (!formattingService.ShouldFormatOnTypedCharacter(documentSyntax, request.Character[0], position, cancellationToken))
            {
                return(Array.Empty <TextEdit>());
            }

            // We should use the options passed in by LSP instead of the document's options.
            var formattingOptions = await ProtocolConversions.GetFormattingOptionsAsync(request.Options, document, _globalOptions, cancellationToken).ConfigureAwait(false);

            var indentationOptions = new IndentationOptions(formattingOptions)
            {
                AutoFormattingOptions = _globalOptions.GetAutoFormattingOptions(document.Project.Language)
            };

            var textChanges = formattingService.GetFormattingChangesOnTypedCharacter(documentSyntax, position, indentationOptions, cancellationToken);

            if (textChanges.IsEmpty)
            {
                return(Array.Empty <TextEdit>());
            }

            var edits = new ArrayBuilder <TextEdit>();

            edits.AddRange(textChanges.Select(change => ProtocolConversions.TextChangeToTextEdit(change, documentSyntax.Text)));
            return(edits.ToArrayAndFree());
        }
Exemplo n.º 18
0
        public override async Task <LSP.SumType <LSP.Command, LSP.CodeAction>[]> HandleRequestAsync(LSP.CodeActionParams request, LSP.ClientCapabilities clientCapabilities,
                                                                                                    string?clientName, CancellationToken cancellationToken)
        {
            var document    = SolutionProvider.GetDocument(request.TextDocument, clientName);
            var codeActions = await GetCodeActionsAsync(document,
                                                        _codeFixService,
                                                        _codeRefactoringService,
                                                        request.Range,
                                                        cancellationToken).ConfigureAwait(false);

            // Filter out code actions with options since they'll show dialogs and we can't remote the UI and the options.
            codeActions = codeActions.Where(c => !(c is CodeActionWithOptions));

            var result = new ArrayBuilder <LSP.SumType <LSP.Command, LSP.CodeAction> >();

            foreach (var codeAction in codeActions)
            {
                // Always return the Command instead of a precalculated set of workspace edits.
                // The edits will be calculated when the code action is either previewed or
                // invoked.

                // It's safe for the client to pass back the range/filename in the command to run
                // on the server because the client will always re-issue a get code actions request
                // before invoking a preview or running the command on the server.

                result.Add(
                    new LSP.Command
                {
                    CommandIdentifier = RunCodeActionCommandName,
                    Title             = codeAction.Title,
                    Arguments         = new object[]
                    {
                        new RunCodeActionParams
                        {
                            CodeActionParams = request,
                            Title            = codeAction.Title
                        }
                    }
                });
            }

            return(result.ToArrayAndFree());
        }
        public async Task <SumType <Command, CodeAction>[]> HandleAsync(CodeActionParams param, RequestContext <Solution> requestContext, CancellationToken cancellationToken)
        {
            var result = await base.HandleRequestAsync(param, requestContext.GetClientCapabilities(), null, cancellationToken).ConfigureAwait(false);

            var commands = new ArrayBuilder <SumType <Command, CodeAction> >();

            foreach (var resultObj in result)
            {
                var commandArguments = resultObj;
                var title            = resultObj.Value is CodeAction codeAction ? codeAction.Title : ((Command)resultObj).Title;
                commands.Add(new Command
                {
                    Title = title,
                    // Overwrite the command identifier to match the expected liveshare remote command identifier.
                    CommandIdentifier = $"{RemoteCommandNamePrefix}.{ProviderName}",
                    Arguments         = new object[] { commandArguments }
                });
            }

            return(commands.ToArrayAndFree());
        }
            private TypeInfo[] ParseTypeArgumentList(ISymbol bindingContext)
            {
                Debug.Assert(PeekNextChar() == '<');
                ++_index;

                var builder = new ArrayBuilder <TypeInfo>();

                while (true)
                {
                    var type = ParseType(bindingContext);
                    if (type == null)
                    {
                        builder.Free();
                        return(null);
                    }

                    builder.Add(type.Value);

                    if (PeekNextChar() == ',')
                    {
                        ++_index;
                    }
                    else
                    {
                        break;
                    }
                }

                if (PeekNextChar() == '>')
                {
                    ++_index;
                }
                else
                {
                    builder.Free();
                    return(null);
                }

                return(builder.ToArrayAndFree());
            }
Exemplo n.º 21
0
        protected async Task <LSP.TextEdit[]> GetTextEdits(Solution solution, Uri documentUri, bool keepThreadContext, CancellationToken cancellationToken, LSP.Range range = null)
        {
            var edits    = new ArrayBuilder <LSP.TextEdit>();
            var document = solution.GetDocumentFromURI(documentUri);

            if (document != null)
            {
                var formattingService = document.Project.LanguageServices.GetService <IEditorFormattingService>();
                var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(keepThreadContext);

                TextSpan?textSpan = null;
                if (range != null)
                {
                    textSpan = ProtocolConversions.RangeToTextSpan(range, text);
                }

                var textChanges = await formattingService.GetFormattingChangesAsync(document, textSpan, cancellationToken).ConfigureAwait(keepThreadContext);

                edits.AddRange(textChanges.Select(change => ProtocolConversions.TextChangeToTextEdit(change, text)));
            }

            return(edits.ToArrayAndFree());
        }
        protected async Task <LSP.TextEdit[]> GetTextEditsAsync(RequestContext context, CancellationToken cancellationToken, LSP.Range?range = null)
        {
            var edits    = new ArrayBuilder <LSP.TextEdit>();
            var document = context.Document;

            if (document != null)
            {
                var formattingService = document.Project.LanguageServices.GetRequiredService <IEditorFormattingService>();
                var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

                TextSpan?textSpan = null;
                if (range != null)
                {
                    textSpan = ProtocolConversions.RangeToTextSpan(range, text);
                }

                var textChanges = await GetFormattingChangesAsync(formattingService, document, textSpan, cancellationToken).ConfigureAwait(false);

                edits.AddRange(textChanges.Select(change => ProtocolConversions.TextChangeToTextEdit(change, text)));
            }

            return(edits.ToArrayAndFree());
        }
Exemplo n.º 23
0
        public override async Task <LSP.SignatureHelp?> HandleRequestAsync(
            LSP.TextDocumentPositionParams request,
            RequestContext context,
            CancellationToken cancellationToken
            )
        {
            var document = context.Document;

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

            var position = await document
                           .GetPositionFromLinePositionAsync(
                ProtocolConversions.PositionToLinePosition(request.Position),
                cancellationToken
                )
                           .ConfigureAwait(false);

            var providers = _allProviders.Where(
                p => p.Metadata.Language == document.Project.Language
                );
            var triggerInfo = new SignatureHelpTriggerInfo(
                SignatureHelpTriggerReason.InvokeSignatureHelpCommand
                );

            foreach (var provider in providers)
            {
                var items = await provider.Value
                            .GetItemsAsync(document, position, triggerInfo, cancellationToken)
                            .ConfigureAwait(false);

                if (items != null)
                {
                    var sigInfos = new ArrayBuilder <LSP.SignatureInformation>();

                    foreach (var item in items.Items)
                    {
                        LSP.SignatureInformation sigInfo;
                        if (context.ClientCapabilities?.HasVisualStudioLspCapability() == true)
                        {
                            sigInfo = new LSP.VSSignatureInformation
                            {
                                ColorizedLabel = GetSignatureClassifiedText(item)
                            };
                        }
                        else
                        {
                            sigInfo = new LSP.SignatureInformation();
                        }

                        sigInfo.Label         = GetSignatureText(item);
                        sigInfo.Documentation = new LSP.MarkupContent
                        {
                            Kind  = LSP.MarkupKind.PlainText,
                            Value = item.DocumentationFactory(cancellationToken).GetFullText()
                        };
                        sigInfo.Parameters = item.Parameters
                                             .Select(
                            p =>
                            new LSP.ParameterInformation
                        {
                            Label         = p.Name,
                            Documentation = new LSP.MarkupContent
                            {
                                Kind  = LSP.MarkupKind.PlainText,
                                Value = p.DocumentationFactory(cancellationToken)
                                        .GetFullText()
                            }
                        }
                            )
                                             .ToArray();
                        sigInfos.Add(sigInfo);
                    }

                    var sigHelp = new LSP.SignatureHelp
                    {
                        ActiveSignature = GetActiveSignature(items),
                        ActiveParameter = items.ArgumentIndex,
                        Signatures      = sigInfos.ToArrayAndFree()
                    };

                    return(sigHelp);
                }
            }

            return(null);
        }
            private ParameterInfo[] ParseParameterList()
            {
                // Consume the opening parenthesis or bracket
                Debug.Assert(PeekNextChar() == '(' || PeekNextChar() == '[');
                ++_index;

                var nextChar = PeekNextChar();
                if (nextChar == ')' || nextChar == ']')
                {
                    // Empty parameter list
                    ++_index;
                    return s_noParameters;
                }

                var builder = new ArrayBuilder<ParameterInfo>();

                while (true)
                {
                    var parameter = ParseParameter();
                    if (parameter != null)
                    {
                        builder.Add(parameter.Value);
                    }
                    else
                    {
                        builder.Free();
                        return null;
                    }

                    if (PeekNextChar() == ',')
                    {
                        ++_index;
                    }
                    else
                    {
                        break;
                    }
                }

                nextChar = PeekNextChar();
                if (nextChar == ')' || nextChar == ']')
                {
                    // Consume the closing parenthesis or bracket
                    ++_index;
                }
                else
                {
                    // Malformed parameter list: missing close parenthesis or bracket
                    builder.Free();
                    return null;
                }

                return builder.ToArrayAndFree();
            }
            private TypeInfo[] ParseTypeArgumentList(ISymbol bindingContext)
            {
                Debug.Assert(PeekNextChar() == '<');
                ++_index;

                var builder = new ArrayBuilder<TypeInfo>();

                while (true)
                {
                    var type = ParseType(bindingContext);
                    if (type == null)
                    {
                        builder.Free();
                        return null;
                    }

                    builder.Add(type.Value);

                    if (PeekNextChar() == ',')
                    {
                        ++_index;
                    }
                    else
                    {
                        break;
                    }
                }

                if (PeekNextChar() == '>')
                {
                    ++_index;
                }
                else
                {
                    builder.Free();
                    return null;
                }

                return builder.ToArrayAndFree();
            }
Exemplo n.º 26
0
            /// <summary>
            /// Decodes a type name.  A type name is a string which is terminated by the end of the string or one of the
            /// delimiters '+', ',', '[', ']'. '+' separates nested classes. '[' and ']'
            /// enclosed generic type arguments.  ',' separates types.
            /// </summary>
            internal AssemblyQualifiedTypeName DecodeTypeName(bool isTypeArgument = false, bool isTypeArgumentWithAssemblyName = false)
            {
                Debug.Assert(!isTypeArgumentWithAssemblyName || isTypeArgument);

                string topLevelType = null;
                ArrayBuilder <string> nestedTypesBuilder = null;

                AssemblyQualifiedTypeName[] typeArguments = null;
                int pointerCount = 0;
                ArrayBuilder <int> arrayRanksBuilder = null;
                string             assemblyName      = null;
                bool decodingTopLevelType            = true;
                bool isGenericTypeName = false;

                var           pooledStrBuilder = PooledStringBuilder.GetInstance();
                StringBuilder typeNameBuilder  = pooledStrBuilder.Builder;

                while (!EndOfInput)
                {
                    int i = _input.IndexOfAny(s_typeNameDelimiters, _offset);
                    if (i >= 0)
                    {
                        char c = _input[i];

                        // Found name, which could be a generic name with arity.
                        // Generic type parameter count, if any, are handled in DecodeGenericName.
                        string decodedString = DecodeGenericName(i);
                        Debug.Assert(decodedString != null);

                        // Type name is generic if the decoded name of the top level type OR any of the outer types of a nested type had the '`' character.
                        isGenericTypeName = isGenericTypeName || decodedString.IndexOf(GenericTypeNameManglingChar) >= 0;
                        typeNameBuilder.Append(decodedString);

                        switch (c)
                        {
                        case '*':
                            if (arrayRanksBuilder != null)
                            {
                                // Error case, array shape must be specified at the end of the type name.
                                // Process as a regular character and continue.
                                typeNameBuilder.Append(c);
                            }
                            else
                            {
                                pointerCount++;
                            }

                            Advance();
                            break;

                        case '+':
                            if (arrayRanksBuilder != null || pointerCount > 0)
                            {
                                // Error case, array shape must be specified at the end of the type name.
                                // Process as a regular character and continue.
                                typeNameBuilder.Append(c);
                            }
                            else
                            {
                                // Type followed by nested type. Handle nested class separator and collect the nested types.
                                HandleDecodedTypeName(typeNameBuilder.ToString(), decodingTopLevelType, ref topLevelType, ref nestedTypesBuilder);
                                typeNameBuilder.Clear();
                                decodingTopLevelType = false;
                            }

                            Advance();
                            break;

                        case '[':
                            // Is type followed by generic type arguments?
                            if (isGenericTypeName && typeArguments == null)
                            {
                                Advance();
                                if (arrayRanksBuilder != null || pointerCount > 0)
                                {
                                    // Error case, array shape must be specified at the end of the type name.
                                    // Process as a regular character and continue.
                                    typeNameBuilder.Append(c);
                                }
                                else
                                {
                                    // Decode type arguments.
                                    typeArguments = DecodeTypeArguments();
                                }
                            }
                            else
                            {
                                // Decode array shape.
                                DecodeArrayShape(typeNameBuilder, ref arrayRanksBuilder);
                            }

                            break;

                        case ']':
                            if (isTypeArgument)
                            {
                                // End of type arguments.  This occurs when the last type argument is a type in the
                                // current assembly.
                                goto ExitDecodeTypeName;
                            }
                            else
                            {
                                // Error case, process as a regular character and continue.
                                typeNameBuilder.Append(c);
                                Advance();
                                break;
                            }

                        case ',':
                            // A comma may separate a type name from its assembly name or a type argument from
                            // another type argument.
                            // If processing non-type argument or a type argument with assembly name,
                            // process the characters after the comma as an assembly name.
                            if (!isTypeArgument || isTypeArgumentWithAssemblyName)
                            {
                                Advance();
                                if (!EndOfInput && Char.IsWhiteSpace(Current))
                                {
                                    Advance();
                                }

                                assemblyName = DecodeAssemblyName(isTypeArgumentWithAssemblyName);
                            }
                            goto ExitDecodeTypeName;

                        default:
                            throw ExceptionUtilities.UnexpectedValue(c);
                        }
                    }
                    else
                    {
                        typeNameBuilder.Append(DecodeGenericName(_input.Length));
                        goto ExitDecodeTypeName;
                    }
                }

ExitDecodeTypeName:
                HandleDecodedTypeName(typeNameBuilder.ToString(), decodingTopLevelType, ref topLevelType, ref nestedTypesBuilder);
                pooledStrBuilder.Free();

                return(new AssemblyQualifiedTypeName(
                           topLevelType,
                           nestedTypesBuilder?.ToArrayAndFree(),
                           typeArguments,
                           pointerCount,
                           arrayRanksBuilder?.ToArrayAndFree(),
                           assemblyName));
            }
Exemplo n.º 27
0
        /// <summary>
        /// Computes line starts faster given already computed line starts from text before the change.
        /// </summary>
        protected override TextLineCollection GetLinesCore()
        {
            if (!_info.WeakOldText.TryGetTarget(out SourceText oldText) || !oldText.TryGetLines(out TextLineCollection oldLineInfo))
            {
                // no old line starts? do it the hard way.
                return(base.GetLinesCore());
            }

            // compute line starts given changes and line starts already computed from previous text
            ArrayBuilder <int> lineStarts = ArrayBuilder <int> .GetInstance();

            lineStarts.Add(0);

            // position in the original document
            int position = 0;

            // delta generated by already processed changes (position in the new document = position + delta)
            int delta = 0;

            // true if last segment ends with CR and we need to check for CR+LF code below assumes that both CR and LF are also line breaks alone
            bool endsWithCR = false;

            foreach (TextChangeRange change in _info.ChangeRanges)
            {
                // include existing line starts that occur before this change
                if (change.Span.Start > position)
                {
                    if (endsWithCR && _newText[position + delta] == '\n')
                    {
                        // remove last added line start (it was due to previous CR)
                        // a new line start including the LF will be added next
                        lineStarts.RemoveLast();
                    }

                    LinePositionSpan lps = oldLineInfo.GetLinePositionSpan(TextSpan.FromBounds(position, change.Span.Start));
                    for (int i = lps.Start.Line + 1; i <= lps.End.Line; i++)
                    {
                        lineStarts.Add(oldLineInfo[i].Start + delta);
                    }

                    endsWithCR = oldText[change.Span.Start - 1] == '\r';

                    // in case change is inserted between CR+LF we treat CR as line break alone,
                    // but this line break might be retracted and replaced with new one in case LF is inserted
                    if (endsWithCR && change.Span.Start < oldText.Length && oldText[change.Span.Start] == '\n')
                    {
                        lineStarts.Add(change.Span.Start + delta);
                    }
                }

                // include line starts that occur within newly inserted text
                if (change.NewLength > 0)
                {
                    int        changeStart = change.Span.Start + delta;
                    SourceText text        = GetSubText(new TextSpan(changeStart, change.NewLength));

                    if (endsWithCR && text[0] == '\n')
                    {
                        // remove last added line start (it was due to previous CR)
                        // a new line start including the LF will be added next
                        lineStarts.RemoveLast();
                    }

                    // Skip first line (it is always at offset 0 and corresponds to the previous line)
                    for (int i = 1; i < text.Lines.Count; i++)
                    {
                        lineStarts.Add(changeStart + text.Lines[i].Start);
                    }

                    endsWithCR = text[change.NewLength - 1] == '\r';
                }

                position = change.Span.End;
                delta   += (change.NewLength - change.Span.Length);
            }

            // include existing line starts that occur after all changes
            if (position < oldText.Length)
            {
                if (endsWithCR && _newText[position + delta] == '\n')
                {
                    // remove last added line start (it was due to previous CR)
                    // a new line start including the LF will be added next
                    lineStarts.RemoveLast();
                }

                LinePositionSpan lps = oldLineInfo.GetLinePositionSpan(TextSpan.FromBounds(position, oldText.Length));
                for (int i = lps.Start.Line + 1; i <= lps.End.Line; i++)
                {
                    lineStarts.Add(oldLineInfo[i].Start + delta);
                }
            }

            return(new LineInfo(this, lineStarts.ToArrayAndFree()));
        }
Exemplo n.º 28
0
        public async Task <object[]> HandleRequestAsync(Solution solution, LSP.CodeActionParams request,
                                                        LSP.ClientCapabilities clientCapabilities, CancellationToken cancellationToken)
        {
            var codeActions = await GetCodeActionsAsync(solution,
                                                        request.TextDocument.Uri,
                                                        request.Range,
                                                        cancellationToken).ConfigureAwait(false);

            // Filter out code actions with options since they'll show dialogs and we can't remote the UI and the options.
            codeActions = codeActions.Where(c => !(c is CodeActionWithOptions));

            var commands = new ArrayBuilder <LSP.Command>();

            foreach (var codeAction in codeActions)
            {
                object[] remoteCommandArguments;
                // If we have a codeaction with a single applychangesoperation, we want to send the codeaction with the edits.
                var operations = await codeAction.GetOperationsAsync(cancellationToken).ConfigureAwait(false);

                var clientSupportsWorkspaceEdits = true;
                if (clientCapabilities?.Experimental is JObject clientCapabilitiesExtensions)
                {
                    clientSupportsWorkspaceEdits = clientCapabilitiesExtensions.SelectToken("supportsWorkspaceEdits")?.Value <bool>() ?? clientSupportsWorkspaceEdits;
                }

                if (clientSupportsWorkspaceEdits && operations.Length == 1 && operations.First() is ApplyChangesOperation applyChangesOperation)
                {
                    var workspaceEdit = new LSP.WorkspaceEdit {
                        Changes = new Dictionary <string, LSP.TextEdit[]>()
                    };
                    var changes          = applyChangesOperation.ChangedSolution.GetChanges(solution);
                    var changedDocuments = changes.GetProjectChanges().SelectMany(pc => pc.GetChangedDocuments());

                    foreach (var docId in changedDocuments)
                    {
                        var newDoc  = applyChangesOperation.ChangedSolution.GetDocument(docId);
                        var oldDoc  = solution.GetDocument(docId);
                        var oldText = await oldDoc.GetTextAsync(cancellationToken).ConfigureAwait(false);

                        var textChanges = await newDoc.GetTextChangesAsync(oldDoc).ConfigureAwait(false);

                        var edits = textChanges.Select(tc => new LSP.TextEdit
                        {
                            NewText = tc.NewText,
                            Range   = ProtocolConversions.TextSpanToRange(tc.Span, oldText)
                        });

                        workspaceEdit.Changes.Add(newDoc.FilePath, edits.ToArray());
                    }

                    remoteCommandArguments = new object[] { new LSP.CodeAction {
                                                                Title = codeAction.Title, Edit = workspaceEdit
                                                            } };
                }
                // Otherwise, send the original request to be executed on the host.
                else
                {
                    // Note that we can pass through the params for this
                    // request (like range, filename) because between getcodeaction and runcodeaction there can be no
                    // changes on the IDE side (it will requery for codeactions if there are changes).
                    remoteCommandArguments = new object[]
                    {
                        new LSP.Command
                        {
                            CommandIdentifier = RunCodeActionCommandName,
                            Title             = codeAction.Title,
                            Arguments         = new object[]
                            {
                                new RunCodeActionParams
                                {
                                    CodeActionParams = request,
                                    Title            = codeAction.Title
                                }
                            }
                        }
                    };
                }

                // We need to return a command that is a generic wrapper that VS Code can execute.
                // The argument to this wrapper will either be a RunCodeAction command which will carry
                // enough information to run the command or a CodeAction with the edits.
                var command = new LSP.Command
                {
                    Title             = codeAction.Title,
                    CommandIdentifier = $"{RemoteCommandNamePrefix}.{ProviderName}",
                    Arguments         = remoteCommandArguments
                };

                commands.Add(command);
            }

            return(commands.ToArrayAndFree());
        }
Exemplo n.º 29
0
        private int[] ParseLineStarts()
        {
            // Corner case check
            if (0 == this.Length)
            {
                return(new[] { 0 });
            }

            ArrayBuilder <int> lineStarts = ArrayBuilder <int> .GetInstance();

            lineStarts.Add(0); // there is always the first line

            bool lastWasCR = false;

            // The following loop goes through every character in the text. It is highly
            // performance critical, and thus inlines knowledge about common line breaks
            // and non-line breaks.
            EnumerateChars((int position, char[] buffer, int length) =>
            {
                int index = 0;
                if (lastWasCR)
                {
                    if (length > 0 && buffer[0] == '\n')
                    {
                        index++;
                    }

                    lineStarts.Add(position + index);
                    lastWasCR = false;
                }

                while (index < length)
                {
                    char c = buffer[index];
                    index++;

                    // Common case - ASCII & not a line break
                    // if (c > '\r' && c <= 127)
                    // if (c >= ('\r'+1) && c <= 127)
                    const uint bias = '\r' + 1;
                    if (unchecked (c - bias) <= (127 - bias))
                    {
                        continue;
                    }

                    // Assumes that the only 2-char line break sequence is CR+LF
                    if (c == '\r')
                    {
                        if (index < length && buffer[index] == '\n')
                        {
                            index++;
                        }
                        else if (index >= length)
                        {
                            lastWasCR = true;
                            continue;
                        }
                    }
                    else if (!TextUtilities.IsAnyLineBreakCharacter(c))
                    {
                        continue;
                    }

                    // next line starts at index
                    lineStarts.Add(position + index);
                }
            });

            return(lineStarts.ToArrayAndFree());
        }
Exemplo n.º 30
0
        public async Task <WorkspaceEdit> HandleAsync(RenameParams request, RequestContext <Solution> requestContext, CancellationToken cancellationToken)
        {
            var           solution      = requestContext.Context;
            WorkspaceEdit workspaceEdit = null;
            var           document      = solution.GetDocumentFromURI(request.TextDocument.Uri);

            if (document != null)
            {
                var renameService = document.Project.LanguageServices.GetService <IEditorInlineRenameService>();
                var position      = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false);

                // We need to be on the UI thread to call GetRenameInfo which computes the rename locations.
                // This is because Roslyn reads the readonly regions of the buffer to compute the locations in the document.
                // This is typically quick. It's marked configureawait(false) so that the bulk of the rename operation can happen
                // in background threads.
                await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);

                var renameInfo = await renameService.GetRenameInfoAsync(document, position, cancellationToken).ConfigureAwait(false);

                if (!renameInfo.CanRename)
                {
                    return(workspaceEdit);
                }

                var renameLocationSet = await renameInfo.FindRenameLocationsAsync(solution.Workspace.Options, cancellationToken).ConfigureAwait(false);

                var renameReplacementInfo = await renameLocationSet.GetReplacementsAsync(request.NewName, solution.Workspace.Options, cancellationToken).ConfigureAwait(false);

                var newSolution      = renameReplacementInfo.NewSolution;
                var solutionChanges  = newSolution.GetChanges(solution);
                var changedDocuments = solutionChanges
                                       .GetProjectChanges()
                                       .SelectMany(p => p.GetChangedDocuments(onlyGetDocumentsWithTextChanges: true));

                var documentEdits = new ArrayBuilder <TextDocumentEdit>();
                foreach (var docId in changedDocuments)
                {
                    var oldDoc = solution.GetDocument(docId);
                    var newDoc = newSolution.GetDocument(docId);

                    var textChanges = await newDoc.GetTextChangesAsync(oldDoc, cancellationToken).ConfigureAwait(false);

                    var oldText = await oldDoc.GetTextAsync(cancellationToken).ConfigureAwait(false);

                    var textDocumentEdit = new TextDocumentEdit
                    {
                        TextDocument = new VersionedTextDocumentIdentifier {
                            Uri = newDoc.GetURI()
                        },
                        Edits = textChanges.Select(tc => ProtocolConversions.TextChangeToTextEdit(tc, oldText)).ToArray()
                    };
                    documentEdits.Add(textDocumentEdit);
                }

                workspaceEdit = new WorkspaceEdit {
                    DocumentChanges = documentEdits.ToArrayAndFree()
                };
            }

            return(workspaceEdit);
        }