mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
feat: compress terminal output with backspace characters (#2907)
Follow-up to #2562 adding support for backspace character compression. Optimizes terminal output by handling backspace characters similar to carriage returns, improving readability of progress spinners and other terminal output that uses backspace for animation. - Added processBackspaces function using efficient indexOf approach - Added comprehensive test suite for backspace handling - Integrated with terminal output compression pipeline Signed-off-by: Eric Wheeler <roo-code@z.ewheeler.org> Co-authored-by: Eric Wheeler <roo-code@z.ewheeler.org>
This commit is contained in:
parent
23aa3b636b
commit
5c2511e355
3 changed files with 116 additions and 3 deletions
|
|
@ -5,6 +5,7 @@ import {
|
|||
truncateOutput,
|
||||
applyRunLengthEncoding,
|
||||
processCarriageReturns,
|
||||
processBackspaces,
|
||||
} from "../extract-text"
|
||||
|
||||
describe("addLineNumbers", () => {
|
||||
|
|
@ -229,6 +230,69 @@ describe("truncateOutput", () => {
|
|||
expect(truncateOutput("single line", 10)).toBe("single line")
|
||||
})
|
||||
|
||||
describe("processBackspaces", () => {
|
||||
it("should handle basic backspace deletion", () => {
|
||||
const input = "abc\b\bxy"
|
||||
const expected = "axy"
|
||||
expect(processBackspaces(input)).toBe(expected)
|
||||
})
|
||||
|
||||
it("should handle backspaces at start of input", () => {
|
||||
const input = "\b\babc"
|
||||
const expected = "abc"
|
||||
expect(processBackspaces(input)).toBe(expected)
|
||||
})
|
||||
|
||||
it("should handle backspaces with newlines", () => {
|
||||
const input = "abc\b\n123\b\b"
|
||||
const expected = "ab\n1"
|
||||
expect(processBackspaces(input)).toBe(expected)
|
||||
})
|
||||
|
||||
it("should handle consecutive backspaces", () => {
|
||||
const input = "abcdef\b\b\b\bxy"
|
||||
const expected = "abxy"
|
||||
expect(processBackspaces(input)).toBe(expected)
|
||||
})
|
||||
|
||||
it("should handle backspaces at end of input", () => {
|
||||
const input = "abc\b\b"
|
||||
const expected = "a"
|
||||
expect(processBackspaces(input)).toBe(expected)
|
||||
})
|
||||
|
||||
it("should handle mixed backspaces and content", () => {
|
||||
const input = "abc\bx\byz\b\b123"
|
||||
const expected = "ab123"
|
||||
expect(processBackspaces(input)).toBe(expected)
|
||||
})
|
||||
|
||||
it("should handle multiple groups of consecutive backspaces", () => {
|
||||
const input = "abc\b\bdef\b\b\bghi\b\b\b\bjkl"
|
||||
const expected = "jkl"
|
||||
expect(processBackspaces(input)).toBe(expected)
|
||||
})
|
||||
|
||||
it("should handle backspaces with empty content between them", () => {
|
||||
const input = "abc\b\b\b\b\b\bdef"
|
||||
const expected = "def"
|
||||
expect(processBackspaces(input)).toBe(expected)
|
||||
})
|
||||
|
||||
it("should handle complex mixed content with backspaces", () => {
|
||||
const input = "Loading[\b\b\b\b\b\b\b\bProgress[\b\b\b\b\b\b\b\b\bStatus: \b\b\b\b\b\b\b\bDone!"
|
||||
// Technically terminal displays "Done!s: [" but we assume \b is destructive as an optimization
|
||||
const expected = "Done!"
|
||||
expect(processBackspaces(input)).toBe(expected)
|
||||
})
|
||||
|
||||
it("should handle backspaces with special characters", () => {
|
||||
const input = "abc😀\b\bdef🎉\b\b\bghi"
|
||||
const expected = "abcdeghi"
|
||||
expect(processBackspaces(input)).toBe(expected)
|
||||
})
|
||||
})
|
||||
|
||||
it("handles windows-style line endings", () => {
|
||||
// Create content with windows line endings
|
||||
const lines = Array.from({ length: 15 }, (_, i) => `line${i + 1}`)
|
||||
|
|
|
|||
|
|
@ -288,6 +288,53 @@ export function processCarriageReturns(input: string): string {
|
|||
return output
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes backspace characters (\b) in terminal output using index operations.
|
||||
* Uses indexOf to efficiently locate and handle backspaces.
|
||||
*
|
||||
* Technically terminal only moves the cursor and overwrites in-place,
|
||||
* but we assume \b is destructive as an optimization which is acceptable
|
||||
* for all progress spinner cases and most terminal output cases.
|
||||
*
|
||||
* @param input The terminal output to process
|
||||
* @returns The processed output with backspaces handled
|
||||
*/
|
||||
export function processBackspaces(input: string): string {
|
||||
let output = ""
|
||||
let pos = 0
|
||||
let bsPos = input.indexOf("\b")
|
||||
|
||||
while (bsPos !== -1) {
|
||||
// Fast path: exclude char before backspace
|
||||
output += input.substring(pos, bsPos - 1)
|
||||
|
||||
// Move past backspace
|
||||
pos = bsPos + 1
|
||||
|
||||
// Count consecutive backspaces
|
||||
let count = 0
|
||||
while (input[pos] === "\b") {
|
||||
count++
|
||||
pos++
|
||||
}
|
||||
|
||||
// Trim output mathematically for consecutive backspaces
|
||||
if (count > 0 && output.length > 0) {
|
||||
output = output.substring(0, Math.max(0, output.length - count))
|
||||
}
|
||||
|
||||
// Find next backspace
|
||||
bsPos = input.indexOf("\b", pos)
|
||||
}
|
||||
|
||||
// Add remaining content
|
||||
if (pos < input.length) {
|
||||
output += input.substring(pos)
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to process a single line with carriage returns.
|
||||
* Handles the overwrite logic for a line that contains one or more carriage returns (\r).
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import * as vscode from "vscode"
|
||||
import pWaitFor from "p-wait-for"
|
||||
import { ExitCodeDetails, mergePromise, TerminalProcess, TerminalProcessResultPromise } from "./TerminalProcess"
|
||||
import { truncateOutput, applyRunLengthEncoding, processCarriageReturns } from "../misc/extract-text"
|
||||
import { truncateOutput, applyRunLengthEncoding, processCarriageReturns, processBackspaces } from "../misc/extract-text"
|
||||
// Import TerminalRegistry here to avoid circular dependencies
|
||||
const { TerminalRegistry } = require("./TerminalRegistry")
|
||||
|
||||
|
|
@ -296,9 +296,11 @@ export class Terminal {
|
|||
public static compressTerminalOutput(input: string, lineLimit: number): string {
|
||||
// Apply carriage return processing if the feature is enabled
|
||||
let processedInput = input
|
||||
if (Terminal.compressProgressBar && input.includes("\r")) {
|
||||
processedInput = processCarriageReturns(input)
|
||||
if (Terminal.compressProgressBar) {
|
||||
processedInput = processCarriageReturns(processedInput)
|
||||
processedInput = processBackspaces(processedInput)
|
||||
}
|
||||
|
||||
return truncateOutput(applyRunLengthEncoding(processedInput), lineLimit)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue