/// 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(); } } } }
/// <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; }
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); } }
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); }
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); }
// 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)); }
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); }
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); }
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)); }
private IList <TextChange> BuildChangeList(string oldText, string newText) { return(TextChanges.BuildChangeList(oldText, newText, int.MaxValue)); }
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); }