/// Takes current text buffer and new text then builds list of changed
        /// regions and applies them to the buffer. This way we can avoid
        /// destruction of bookmarks and other markers. Complete
        /// buffer replacement deletes all markers which causes
        /// loss of bookmarks, breakpoints and other similar markers.
        public static void ApplyChange(
            ITextBuffer textBuffer,
            int position,
            int length,
            string newText,
            string transactionName,
            ISelectionTracker selectionTracker,
            int maxMilliseconds)
        {
            var    snapshot  = textBuffer.CurrentSnapshot;
            int    oldLength = Math.Min(length, snapshot.Length - position);
            string oldText   = snapshot.GetText(position, oldLength);

            var changes = TextChanges.BuildChangeList(oldText, newText, maxMilliseconds);

            if (changes != null && changes.Count > 0)
            {
                using (var selectionUndo = new SelectionUndo(selectionTracker, transactionName, automaticTracking: false)) {
                    using (ITextEdit edit = textBuffer.CreateEdit()) {
                        // Replace ranges in reverse so relative positions match
                        for (int i = changes.Count - 1; i >= 0; i--)
                        {
                            TextChange tc = changes[i];
                            edit.Replace(tc.Position + position, tc.Length, tc.NewText);
                        }

                        edit.Apply();
                    }
                }
            }
        }
Example #2
0
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="from">Start locatin</param>
 /// <param name="to">End location</param>
 /// <param name="size">Size of the change if Insert</param>
 public TextChangeInfo(TextChanges kind, int from, int to, int size = 0)
 {
     Kind = kind;
     From = from;
     To   = to;
     Size = size;
 }
Example #3
0
        public static async Task <IEnumerable <LinePositionSpanTextChange> > GetFormattingChanges(Document document, int start, int end, OmniSharpOptions omnisharpOptions, ILoggerFactory loggerFactory)
        {
            var optionSet = omnisharpOptions.FormattingOptions.EnableEditorConfigSupport
                ? await document.Project.Solution.Workspace.Options.WithEditorConfigOptions(document.FilePath, loggerFactory)
                : document.Project.Solution.Workspace.Options;

            var newDocument = await Formatter.FormatAsync(document, TextSpan.FromBounds(start, end), optionSet);

            return(await TextChanges.GetAsync(newDocument, document));
        }
        public async Task ExtendsTextChangeAtEnd()
        {
            var testFile = new TestFile("dummy.cs", "class {\n}");

            using (var host = CreateOmniSharpHost(testFile))
            {
                var document = host.Workspace.GetDocument(testFile.FileName);
                var text     = await document.GetTextAsync();

                var textChange = new TextChange(TextSpan.FromBounds(5, 7), "\r\n {\r");

                var adjustedTextChange = TextChanges.Convert(text, textChange);

                Assert.Equal("\r\n {\r\n", adjustedTextChange.NewText);
                Assert.Equal(0, adjustedTextChange.StartLine);
                Assert.Equal(5, adjustedTextChange.StartColumn);
                Assert.Equal(1, adjustedTextChange.EndLine);
                Assert.Equal(0, adjustedTextChange.EndColumn);
            }
        }
Example #5
0
        public async Task <RunCodeActionResponse> Handle(RunCodeActionRequest request)
        {
            var actions = new List <CodeAction>();
            var context = await GetContext(request, actions);

            await GetContextualCodeActions(context);

            if (request.CodeAction > actions.Count())
            {
                return(new RunCodeActionResponse());
            }

            var action = actions.ElementAt(request.CodeAction);

            var operations = await action.GetOperationsAsync(CancellationToken.None);

            foreach (var o in operations)
            {
                o.Apply(_workspace, CancellationToken.None);
            }

            var oldDocument = context.Value.Document;
            var newDocument = _workspace.CurrentSolution.GetDocument(oldDocument.Id);

            var response = new RunCodeActionResponse();

            if (!request.WantsTextChanges)
            {
                // return the text of the new document
                var newText = await newDocument.GetTextAsync();

                response.Text = newText.ToString();
            }
            else
            {
                // return the text changes
                response.Changes = await TextChanges.GetAsync(newDocument, oldDocument);
            }

            return(response);
        }
Example #6
0
        public async Task <FixUsingsResponse> Handle(FixUsingsRequest request)
        {
            var response = new FixUsingsResponse();

            var oldDocument = _workspace.GetDocument(request.FileName);

            if (oldDocument != null)
            {
                var fixUsingsResponse = await new FixUsingsWorker(_providers)
                                        .FixUsingsAsync(oldDocument);

                response.AmbiguousResults = fixUsingsResponse.AmbiguousResults;

                if (request.ApplyTextChanges)
                {
                    _workspace.TryApplyChanges(fixUsingsResponse.Document.Project.Solution);
                }

                var newDocument = fixUsingsResponse.Document;

                if (!request.WantsTextChanges)
                {
                    // return the text of the new document
                    var newText = await newDocument.GetTextAsync();

                    response.Buffer = newText.ToString();
                }
                else
                {
                    // return the text changes
                    response.Changes = await TextChanges.GetAsync(newDocument, oldDocument);
                }
            }

            return(response);
        }
Example #7
0
        // public static async Task<IEnumerable<LinePositionSpanTextChange>> GetFormattingChangesAfterKeystroke(Document document, int position, char character)
        // {
        //     if (character == '\n')
        //     {
        //         // format previous line on new line
        //         var text = await document.GetTextAsync();
        //         var lines = text.Lines;
        //         var targetLine = lines[lines.GetLineFromPosition(position).LineNumber - 1];
        //         if (!string.IsNullOrWhiteSpace(targetLine.Text.ToString(targetLine.Span)))
        //         {
        //             return await GetFormattingChanges(document, targetLine.Start, targetLine.End);
        //         }
        //     }
        //     else if (character == '}' || character == ';')
        //     {
        //         // format after ; and }
        //         var root = await document.GetSyntaxRootAsync();
        //         var node = FindFormatTarget(root, position);
        //         if (node != null)
        //         {
        //             return await GetFormattingChanges(document, node.FullSpan.Start, node.FullSpan.End);
        //         }
        //     }

        //     return Enumerable.Empty<LinePositionSpanTextChange>();
        // }

        // public static SyntaxNode FindFormatTarget(SyntaxNode root, int position)
        // {
        //     // todo@jo - refine this
        //     var token = root.FindToken(position);

        //     if (token.IsKind(SyntaxKind.EndOfFileToken))
        //     {
        //         token = token.GetPreviousToken();
        //     }

        //     switch (token.Kind())
        //     {
        //         // ; -> use the statement
        //         case SyntaxKind.SemicolonToken:
        //             return token.Parent;

        //         // } -> use the parent of the {}-block or
        //         // just the parent (XYZDeclaration etc)
        //         case SyntaxKind.CloseBraceToken:
        //             var parent = token.Parent;
        //             return parent.IsKind(SyntaxKind.Block)
        //                 ? parent.Parent
        //                 : parent;

        //         case SyntaxKind.CloseParenToken:
        //             if (token.GetPreviousToken().IsKind(SyntaxKind.SemicolonToken) &&
        //                 token.Parent.IsKind(SyntaxKind.ForStatement))
        //             {
        //                 return token.Parent;
        //             }

        //             break;
        //     }

        //     return null;
        // }

        // public static async Task<IEnumerable<LinePositionSpanTextChange>> GetFormattingChanges(Document document, int start, int end)
        // {
        //     var newDocument = await Formatter.FormatAsync(document, TextSpan.FromBounds(start, end), document.Project.Solution.Workspace.Options);

        //     return await TextChanges.GetAsync(newDocument, document);
        // }

        // public static async Task<string> GetFormattedText(Document document)
        // {
        //     var newDocument = await Formatter.FormatAsync(document, document.Project.Solution.Workspace.Options);
        //     var text = await newDocument.GetTextAsync();

        //     return text.ToString();
        // }

        public static async Task <IEnumerable <LinePositionSpanTextChange> > GetFormattedTextChanges(Document document)
        {
            var newDocument = await Formatter.FormatAsync(document, document.Project.Solution.Workspace.Options);

            return(await TextChanges.GetAsync(newDocument, document));
        }
        public static async Task <IEnumerable <LinePositionSpanTextChange> > GetFormattedTextChanges(Document document, OmniSharpOptions omnisharpOptions, ILoggerFactory loggerFactory)
        {
            var newDocument = await FormatDocument(document, omnisharpOptions, loggerFactory);

            return(await TextChanges.GetAsync(newDocument, document));
        }
        public static async Task <IEnumerable <LinePositionSpanTextChange> > GetFormattingChanges(Document document, int start, int end, OmniSharpOptions omnisharpOptions, ILoggerFactory loggerFactory)
        {
            var newDocument = await FormatDocument(document, omnisharpOptions, loggerFactory, TextSpan.FromBounds(start, end));

            return(await TextChanges.GetAsync(newDocument, document));
        }
Example #10
0
        private async Task <IEnumerable <ModifiedFileResponse> > GetFileChangesAsync(Solution newSolution, Solution oldSolution, string directory, bool wantTextChanges)
        {
            var filePathToResponseMap = new Dictionary <string, ModifiedFileResponse>();
            var solutionChanges       = newSolution.GetChanges(oldSolution);

            foreach (var projectChange in solutionChanges.GetProjectChanges())
            {
                // Handle added documents
                foreach (var documentId in projectChange.GetAddedDocuments())
                {
                    var newDocument = newSolution.GetDocument(documentId);
                    var text        = await newDocument.GetTextAsync();

                    var newFilePath = newDocument.FilePath == null || !Path.IsPathRooted(newDocument.FilePath)
                        ? Path.Combine(directory, newDocument.Name)
                        : newDocument.FilePath;

                    var modifiedFileResponse = new ModifiedFileResponse(newFilePath)
                    {
                        Changes = new[] {
                            new LinePositionSpanTextChange
                            {
                                NewText = text.ToString()
                            }
                        }
                    };

                    filePathToResponseMap[newFilePath] = modifiedFileResponse;

                    // We must add new files to the workspace to ensure that they're present when the host editor
                    // tries to modify them. This is a strange interaction because the workspace could be left
                    // in an incomplete state if the host editor doesn't apply changes to the new file, but it's
                    // what we've got today.
                    if (this.Workspace.GetDocument(newFilePath) == null)
                    {
                        var fileInfo = new FileInfo(newFilePath);
                        if (!fileInfo.Exists)
                        {
                            fileInfo.CreateText().Dispose();
                        }
                        else
                        {
                            // The file already exists on disk? Ensure that it's zero-length. If so, we can still use it.
                            if (fileInfo.Length > 0)
                            {
                                Logger.LogError($"File already exists on disk: '{newFilePath}'");
                                break;
                            }
                        }

                        this.Workspace.AddDocument(projectChange.ProjectId, newFilePath, newDocument.SourceCodeKind);
                    }
                    else
                    {
                        // The file already exists in the workspace? We're in a bad state.
                        Logger.LogError($"File already exists in workspace: '{newFilePath}'");
                    }
                }

                // Handle changed documents
                foreach (var documentId in projectChange.GetChangedDocuments())
                {
                    var newDocument = newSolution.GetDocument(documentId);
                    var filePath    = newDocument.FilePath;

                    if (!filePathToResponseMap.TryGetValue(filePath, out var modifiedFileResponse))
                    {
                        modifiedFileResponse            = new ModifiedFileResponse(filePath);
                        filePathToResponseMap[filePath] = modifiedFileResponse;
                    }

                    if (wantTextChanges)
                    {
                        var oldDocument = oldSolution.GetDocument(documentId);
                        var linePositionSpanTextChanges = await TextChanges.GetAsync(newDocument, oldDocument);

                        modifiedFileResponse.Changes = modifiedFileResponse.Changes != null
                            ? modifiedFileResponse.Changes.Union(linePositionSpanTextChanges)
                            : linePositionSpanTextChanges;
                    }
                    else
                    {
                        var text = await newDocument.GetTextAsync();

                        modifiedFileResponse.Buffer = text.ToString();
                    }
                }
            }

            return(filePathToResponseMap.Values);
        }
Example #11
0
        public async Task <RenameResponse> Handle(RenameRequest request)
        {
            var response = new RenameResponse();

            var document = _workspace.GetDocument(request.FileName);

            if (document != null)
            {
                var sourceText = await document.GetTextAsync();

                var position = sourceText.GetTextPosition(request);

                var symbol = await SymbolFinder.FindSymbolAtPositionAsync(document, position);

                Solution solution = _workspace.CurrentSolution;

                if (symbol != null)
                {
                    var options = new OmniSharpRenameOptions(
                        RenameOverloads: _omniSharpOptions.RenameOptions.RenameOverloads,
                        RenameInStrings: _omniSharpOptions.RenameOptions.RenameInStrings,
                        RenameInComments: _omniSharpOptions.RenameOptions.RenameInComments);

                    (solution, response.ErrorMessage) = await OmniSharpRenamer.RenameSymbolAsync(solution, symbol, request.RenameTo, options, nonConflictSymbols : null, CancellationToken.None);

                    if (response.ErrorMessage is not null)
                    {
                        // An error occurred. There are no changes to report.
                        return(response);
                    }
                }

                var changes         = new Dictionary <string, ModifiedFileResponse>();
                var solutionChanges = solution.GetChanges(_workspace.CurrentSolution);

                foreach (var projectChange in solutionChanges.GetProjectChanges())
                {
                    foreach (var changedDocumentId in projectChange.GetChangedDocuments())
                    {
                        var changedDocument = solution.GetDocument(changedDocumentId);

                        if (!changes.TryGetValue(changedDocument.FilePath, out var modifiedFileResponse))
                        {
                            modifiedFileResponse = new ModifiedFileResponse(changedDocument.FilePath);
                            changes[changedDocument.FilePath] = modifiedFileResponse;
                        }

                        if (!request.WantsTextChanges)
                        {
                            var changedText = await changedDocument.GetTextAsync();

                            modifiedFileResponse.Buffer = changedText.ToString();
                        }
                        else
                        {
                            var originalDocument            = _workspace.CurrentSolution.GetDocument(changedDocumentId);
                            var linePositionSpanTextChanges = await TextChanges.GetAsync(changedDocument, originalDocument);

                            modifiedFileResponse.Changes = modifiedFileResponse.Changes != null
                                ? modifiedFileResponse.Changes.Union(linePositionSpanTextChanges)
                                : linePositionSpanTextChanges;
                        }
                    }
                }

                if (request.ApplyTextChanges)
                {
                    // Attempt to update the workspace
                    if (_workspace.TryApplyChanges(solution))
                    {
                        response.Changes = changes.Values;
                    }
                }
                else
                {
                    response.Changes = changes.Values;
                }
            }

            return(response);
        }
Example #12
0
        public static async Task <IEnumerable <LinePositionSpanTextChange> > GetFormattingChanges(Document document, int start, int end)
        {
            var newDocument = await Formatter.FormatAsync(document, TextSpan.FromBounds(start, end), document.Project.Solution.Workspace.Options);

            return(await TextChanges.GetAsync(newDocument, document));
        }
Example #13
0
 private IList <TextChange> BuildChangeList(string oldText, string newText)
 {
     return(TextChanges.BuildChangeList(oldText, newText, int.MaxValue));
 }
Example #14
0
        public async Task <RenameResponse> Handle(RenameRequest request)
        {
            var response = new RenameResponse();

            var document = _workspace.GetDocument(request.FileName);

            if (document != null)
            {
                var sourceText = await document.GetTextAsync();

                var position = sourceText.Lines.GetPosition(new LinePosition(request.Line, request.Column));

                var symbol = await SymbolFinder.FindSymbolAtPositionAsync(document, position);

                Solution solution = _workspace.CurrentSolution;

                if (symbol != null)
                {
                    try
                    {
                        solution = await Renamer.RenameSymbolAsync(solution, symbol, request.RenameTo, _workspace.Options);
                    }
                    catch (ArgumentException e)
                    {
                        response.ErrorMessage = e.Message;
                    }
                }

                var changes         = new Dictionary <string, ModifiedFileResponse>();
                var solutionChanges = solution.GetChanges(_workspace.CurrentSolution);

                foreach (var projectChange in solutionChanges.GetProjectChanges())
                {
                    foreach (var changedDocumentId in projectChange.GetChangedDocuments())
                    {
                        var changedDocument = solution.GetDocument(changedDocumentId);

                        if (!changes.TryGetValue(changedDocument.FilePath, out var modifiedFileResponse))
                        {
                            modifiedFileResponse = new ModifiedFileResponse(changedDocument.FilePath);
                            changes[changedDocument.FilePath] = modifiedFileResponse;
                        }

                        if (!request.WantsTextChanges)
                        {
                            var changedText = await changedDocument.GetTextAsync();

                            modifiedFileResponse.Buffer = changedText.ToString();
                        }
                        else
                        {
                            var originalDocument            = _workspace.CurrentSolution.GetDocument(changedDocumentId);
                            var linePositionSpanTextChanges = await TextChanges.GetAsync(changedDocument, originalDocument);

                            modifiedFileResponse.Changes = modifiedFileResponse.Changes != null
                                ? modifiedFileResponse.Changes.Union(linePositionSpanTextChanges)
                                : linePositionSpanTextChanges;
                        }
                    }
                }

                if (request.ApplyTextChanges)
                {
                    // Attempt to update the workspace
                    if (_workspace.TryApplyChanges(solution))
                    {
                        response.Changes = changes.Values;
                    }
                }
                else
                {
                    response.Changes = changes.Values;
                }
            }

            return(response);
        }
 public void AddTextChange(Card c, TextChanges.TextChange<int> change)
 {
     if (cardTextChanges.ContainsKey(c))
     {
         cardTextChanges[c] = new TextChanges(cardTextChanges[c], change);
     }
     else
     {
         cardTextChanges[c] = new TextChanges(change);
     }
 }
        public bool Matches(BeatSaberQuestomConfig config)
        {
            if (this.Playlists.Count != config.Playlists.Count)
            {
                return(false);
            }

            for (int p = 0; p < Playlists.Count; p++)
            {
                var thisOne = Playlists[p];
                var thatOne = config.Playlists[p];
                if (thisOne.PlaylistID != thatOne.PlaylistID)
                {
                    return(false);
                }
                if (thisOne.PlaylistName != thatOne.PlaylistName)
                {
                    return(false);
                }
                if (thisOne.SongList.Count != thatOne.SongList.Count)
                {
                    return(false);
                }

                for (int s = 0; s < thisOne.SongList.Count; s++)
                {
                    var thisSong = thisOne.SongList[s];
                    var thatSong = thatOne.SongList[s];
                    if (thisSong.SongID != thatSong.SongID)
                    {
                        return(false);
                    }
                }
            }

            if (this.Saber?.SaberID != config.Saber?.SaberID)
            {
                return(false);
            }

            //lazy copy/paste.  Make a proper comparer
            if (this.LeftColor?.A != config?.LeftColor?.A || this.LeftColor?.R != config?.LeftColor?.R || this.LeftColor?.G != config?.LeftColor?.G || this.LeftColor?.B != config?.LeftColor?.B)
            {
                return(false);
            }
            if (this.RightColor?.A != config?.RightColor?.A || this.RightColor?.R != config?.RightColor?.R || this.RightColor?.G != config?.RightColor?.G || this.RightColor?.B != config?.RightColor?.B)
            {
                return(false);
            }
            if (this.TextChanges == null && config.TextChanges != null || this.TextChanges != null && config.TextChanges == null)
            {
                return(false);
            }
            if (this.TextChanges != null)
            {
                if (this.TextChanges.Count != config.TextChanges.Count)
                {
                    return(false);
                }
                //I think this is right...
                if (TextChanges.Any(x => !config.TextChanges.Any(y => y.Item1 == x.Item1 && y.Item2 == x.Item2)))
                {
                    return(false);
                }
            }
            if (this.Mods == null && config.Mods != null || this.Mods != null && config.Mods == null)
            {
                return(false);
            }
            if (this.Mods != null)
            {
                if (this.Mods.Count != config.Mods.Count)
                {
                    return(false);
                }
                if (this.Mods.Any(x => !config.Mods.Any(y => x.ID == y.ID && x.Status == y.Status)))
                {
                    return(false);
                }
            }
            return(true);
        }