Skip to content

Commit 131f9ad

Browse files
author
Eric Wheeler
committed
feat: add run-length encoding for repeated lines
Implement applyRunLengthEncoding function to compress repeated lines in text output: - Add line repetition compression with count message - Focus on single line repetitions - Only compress when beneficial - Add tests for empty input and single line repetitions Signed-off-by: Eric Wheeler <[email protected]>
1 parent 269ddf9 commit 131f9ad

File tree

2 files changed

+88
-1
lines changed

2 files changed

+88
-1
lines changed

src/integrations/misc/__tests__/extract-text.test.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import { addLineNumbers, everyLineHasLineNumbers, stripLineNumbers, truncateOutput } from "../extract-text"
1+
import {
2+
addLineNumbers,
3+
everyLineHasLineNumbers,
4+
stripLineNumbers,
5+
truncateOutput,
6+
applyRunLengthEncoding,
7+
} from "../extract-text"
28

39
describe("addLineNumbers", () => {
410
it("should add line numbers starting from 1 by default", () => {
@@ -165,3 +171,22 @@ describe("truncateOutput", () => {
165171
expect(resultLines).toEqual(expectedLines)
166172
})
167173
})
174+
175+
describe("applyRunLengthEncoding", () => {
176+
it("should handle empty input", () => {
177+
expect(applyRunLengthEncoding("")).toBe("")
178+
expect(applyRunLengthEncoding(null as any)).toBe(null as any)
179+
expect(applyRunLengthEncoding(undefined as any)).toBe(undefined as any)
180+
})
181+
182+
it("should compress repeated single lines when beneficial", () => {
183+
const input = "longerline\nlongerline\nlongerline\nlongerline\nlongerline\nlongerline\n"
184+
const expected = "longerline\n<previous line repeated 5 additional times>\n"
185+
expect(applyRunLengthEncoding(input)).toBe(expected)
186+
})
187+
188+
it("should not compress when not beneficial", () => {
189+
const input = "y\ny\ny\ny\ny\n"
190+
expect(applyRunLengthEncoding(input)).toBe(input)
191+
})
192+
})

src/integrations/misc/extract-text.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,3 +149,65 @@ export function truncateOutput(content: string, lineLimit?: number): string {
149149
const endSection = content.slice(endStartPos)
150150
return startSection + `\n[...${omittedLines} lines omitted...]\n\n` + endSection
151151
}
152+
153+
/**
154+
* Applies run-length encoding to compress repeated lines in text.
155+
* Only compresses when the compression description is shorter than the repeated content.
156+
*
157+
* @param content The text content to compress
158+
* @returns The compressed text with run-length encoding applied
159+
*/
160+
export function applyRunLengthEncoding(content: string): string {
161+
if (!content) {
162+
return content
163+
}
164+
165+
let result = ""
166+
let pos = 0
167+
let repeatCount = 0
168+
let prevLine = null
169+
let firstOccurrence = true
170+
171+
while (pos < content.length) {
172+
const nextNewlineIdx = content.indexOf("\n", pos)
173+
const currentLine = nextNewlineIdx === -1 ? content.slice(pos) : content.slice(pos, nextNewlineIdx + 1)
174+
175+
if (prevLine === null) {
176+
prevLine = currentLine
177+
} else if (currentLine === prevLine) {
178+
repeatCount++
179+
} else {
180+
if (repeatCount > 0) {
181+
const compressionDesc = `<previous line repeated ${repeatCount} additional times>\n`
182+
if (compressionDesc.length < prevLine.length * (repeatCount + 1)) {
183+
result += prevLine + compressionDesc
184+
} else {
185+
for (let i = 0; i <= repeatCount; i++) {
186+
result += prevLine
187+
}
188+
}
189+
repeatCount = 0
190+
} else {
191+
result += prevLine
192+
}
193+
prevLine = currentLine
194+
}
195+
196+
pos = nextNewlineIdx === -1 ? content.length : nextNewlineIdx + 1
197+
}
198+
199+
if (repeatCount > 0 && prevLine !== null) {
200+
const compressionDesc = `<previous line repeated ${repeatCount} additional times>\n`
201+
if (compressionDesc.length < prevLine.length * repeatCount) {
202+
result += prevLine + compressionDesc
203+
} else {
204+
for (let i = 0; i <= repeatCount; i++) {
205+
result += prevLine
206+
}
207+
}
208+
} else if (prevLine !== null) {
209+
result += prevLine
210+
}
211+
212+
return result
213+
}

0 commit comments

Comments
 (0)