/// <summary> /// Applies the provided FileChange to the file's contents /// </summary> /// <param name="fileChange">The FileChange to apply to the file's contents.</param> public void ApplyChange(FileChange fileChange) { // TODO: Verify offsets are in range // Break up the change lines string[] changeLines = fileChange.InsertString.Split('\n'); // Get the first fragment of the first line string firstLineFragment = this.FileLines[fileChange.Line - 1] .Substring(0, fileChange.Offset - 1); // Get the last fragment of the last line string endLine = this.FileLines[fileChange.EndLine - 1]; string lastLineFragment = endLine.Substring( fileChange.EndOffset - 1, (this.FileLines[fileChange.EndLine - 1].Length - fileChange.EndOffset) + 1); // Remove the old lines for (int i = 0; i <= fileChange.EndLine - fileChange.Line; i++) { this.FileLines.RemoveAt(fileChange.Line - 1); } // Build and insert the new lines int currentLineNumber = fileChange.Line; for (int changeIndex = 0; changeIndex < changeLines.Length; changeIndex++) { // Since we split the lines above using \n, make sure to // trim the ending \r's off as well. string finalLine = changeLines[changeIndex].TrimEnd('\r'); // Should we add first or last line fragments? if (changeIndex == 0) { // Append the first line fragment finalLine = firstLineFragment + finalLine; } if (changeIndex == changeLines.Length - 1) { // Append the last line fragment finalLine = finalLine + lastLineFragment; } this.FileLines.Insert(currentLineNumber - 1, finalLine); currentLineNumber++; } // Parse the script again to be up-to-date this.ParseFileContents(); }
/// <summary> /// Applies the provided FileChange to the file's contents /// </summary> /// <param name="fileChange">The FileChange to apply to the file's contents.</param> public void ApplyChange(FileChange fileChange) { // Break up the change lines string[] changeLines = fileChange.InsertString.Split('\n'); if (fileChange.IsReload) { this.FileLines.Clear(); foreach (var changeLine in changeLines) { this.FileLines.Add(changeLine); } } else { // VSCode sometimes likes to give the change start line as (FileLines.Count + 1). // This used to crash EditorServices, but we now treat it as an append. // See https://github.com/PowerShell/vscode-powershell/issues/1283 if (fileChange.Line == this.FileLines.Count + 1) { foreach (string addedLine in changeLines) { string finalLine = addedLine.TrimEnd('\r'); this.FileLines.Add(finalLine); } } // Similarly, when lines are deleted from the end of the file, // VSCode likes to give the end line as (FileLines.Count + 1). else if (fileChange.EndLine == this.FileLines.Count + 1 && String.Empty.Equals(fileChange.InsertString)) { int lineIndex = fileChange.Line - 1; this.FileLines.RemoveRange(lineIndex, this.FileLines.Count - lineIndex); } // Otherwise, the change needs to go between existing content else { this.ValidatePosition(fileChange.Line, fileChange.Offset); this.ValidatePosition(fileChange.EndLine, fileChange.EndOffset); // Get the first fragment of the first line string firstLineFragment = this.FileLines[fileChange.Line - 1] .Substring(0, fileChange.Offset - 1); // Get the last fragment of the last line string endLine = this.FileLines[fileChange.EndLine - 1]; string lastLineFragment = endLine.Substring( fileChange.EndOffset - 1, (this.FileLines[fileChange.EndLine - 1].Length - fileChange.EndOffset) + 1); // Remove the old lines for (int i = 0; i <= fileChange.EndLine - fileChange.Line; i++) { this.FileLines.RemoveAt(fileChange.Line - 1); } // Build and insert the new lines int currentLineNumber = fileChange.Line; for (int changeIndex = 0; changeIndex < changeLines.Length; changeIndex++) { // Since we split the lines above using \n, make sure to // trim the ending \r's off as well. string finalLine = changeLines[changeIndex].TrimEnd('\r'); // Should we add first or last line fragments? if (changeIndex == 0) { // Append the first line fragment finalLine = firstLineFragment + finalLine; } if (changeIndex == changeLines.Length - 1) { // Append the last line fragment finalLine = finalLine + lastLineFragment; } this.FileLines.Insert(currentLineNumber - 1, finalLine); currentLineNumber++; } } } // Parse the script again to be up-to-date this.ParseFileContents(); }
private void AssertFileChange( string initialString, string expectedString, FileChange fileChange) { using (StringReader stringReader = new StringReader(initialString)) { // Create an in-memory file from the StringReader ScriptFile fileToChange = new ScriptFile("TestFile.ps1", "TestFile.ps1", stringReader); // Apply the FileChange and assert the resulting contents fileToChange.ApplyChange(fileChange); Assert.Equal(expectedString, fileToChange.Contents); } }