Skip to content

Commit c29f24d

Browse files
committed
feat: Split printing logic for file diff another file + fixed bugs with logic
1 parent 5924bbf commit c29f24d

File tree

3 files changed

+122
-82
lines changed

3 files changed

+122
-82
lines changed

src/ui/file-diff-pretty-printer.ts

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import chalk from 'chalk';
2+
import * as Diff from 'diff'
3+
4+
export function prettyFormatFileDiff(before: string, after: string): string {
5+
const diff = Diff.diffLines(before, after);
6+
7+
console.log(diff);
8+
9+
const changeList: Array<{ added: boolean; removed: boolean; lineNumber: number }> = []
10+
diff
11+
.reduce((lineNumber, change) => {
12+
const changes = change.value.split(/\n/).filter(Boolean).map((l, idx) => ({
13+
added: change.added,
14+
removed: change.removed,
15+
lineNumber: lineNumber + idx + 1,
16+
}));
17+
changeList.push(...changes);
18+
19+
return lineNumber + ((change.added || (!change.added && !change.removed)) ? (change.count ?? 0) : 0)
20+
}, 0)
21+
22+
const snippetGroups = createSnippetGroups(changeList);
23+
24+
let diffString = '';
25+
diff.forEach((part) => {
26+
diffString += part.added ? chalk.green(part.value) :
27+
part.removed ? chalk.red(part.value) :
28+
part.value;
29+
});
30+
31+
const diffLines = diffString.split(/\n/);
32+
const result = [];
33+
34+
for (const group of snippetGroups) {
35+
const numberWidth = group.end.toString().length;
36+
37+
const snippet = diffLines.slice(group.start, group.end).map((l, idx) => {
38+
const change = changeList[group.start + idx];
39+
return formatLine(l, change.lineNumber, numberWidth, change.added, change.removed)
40+
}).join('\n')
41+
42+
result.push(`${chalk.bold(`Lines ${changeList[group.start].lineNumber} to line ${changeList[group.end].lineNumber}:`)}
43+
${snippet}`
44+
);
45+
}
46+
47+
return result.join('\n\n');
48+
}
49+
50+
function createSnippetGroups(changeList: Array<{ added: boolean; removed: boolean }>) {
51+
const snippetGroups = [];
52+
let pointerStart = -1;
53+
54+
for (let counter = 0; counter < changeList.length; counter++) {
55+
const changeAhead = changeList.slice(counter, counter + 5).some((change) => change.added || change.removed);
56+
const changeBehind = changeList.slice(counter - 5, counter).some((change) => change.added || change.removed);
57+
58+
if (pointerStart === -1 && changeAhead) {
59+
pointerStart = counter;
60+
continue;
61+
}
62+
63+
if (pointerStart !== -1 && !changeAhead && !changeBehind) {
64+
snippetGroups.push({ start: pointerStart, end: counter })
65+
pointerStart = -1;
66+
continue;
67+
}
68+
69+
if (pointerStart !== -1 && counter === changeList.length - 1) {
70+
snippetGroups.push({ start: pointerStart, end: counter })
71+
}
72+
}
73+
74+
return snippetGroups;
75+
}
76+
77+
function formatLine(line: string, lineNumber: number, numberWidth: number, added = false, removed = false) {
78+
if (added && removed) {
79+
return `${chalk.gray((lineNumber).toString().padEnd(numberWidth, ' '))} ${chalk.yellow('~')}${line}`
80+
}
81+
82+
if (added) {
83+
return `${chalk.gray((lineNumber).toString().padEnd(numberWidth, ' '))} ${chalk.green('+')}${line}`
84+
}
85+
86+
if (removed) {
87+
return `${chalk.gray((lineNumber).toString().padEnd(numberWidth, ' '))} ${chalk.red('-')}${line}`
88+
}
89+
90+
return `${chalk.gray((lineNumber).toString().padEnd(numberWidth, ' '))} ${line}`
91+
92+
// return line;
93+
}

src/utils/file-modification-calculator.test.ts

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -417,23 +417,32 @@ describe('File modification calculator tests', () => {
417417
resource: modifiedResource2,
418418
}])
419419

420-
// expect(result.newFile).to.eq('[\n' +
421-
// ' {\n' +
422-
// ' "type": "project",\n' +
423-
// ' "plugins": {\n' +
424-
// ' "default": "latest"\n' +
425-
// ' }\n' +
426-
// ' },\n' +
427-
// ' {\n' +
428-
// ' "type": "resource1",\n' +
429-
// ' "param2": [\n' +
430-
// ' "a",\n' +
431-
// ' "b",\n' +
432-
// ' "c",\n' +
433-
// ' "d"\n' +
434-
// ' ]\n' +
435-
// ' }\n' +
436-
// ']')
420+
expect(result.newFile).to.eq('[\n' +
421+
' {\n' +
422+
' "type": "project",\n' +
423+
' "plugins": {\n' +
424+
' "default": "latest"\n' +
425+
' }\n' +
426+
' },\n' +
427+
' {\n' +
428+
' "type": "resource1",\n' +
429+
' "param2": [\n' +
430+
' "a",\n' +
431+
' "b",\n' +
432+
' "c",\n' +
433+
' "d"\n' +
434+
' ]\n' +
435+
' },\n' +
436+
' {\n' +
437+
' "type": "resource2",\n' +
438+
' "param2": [\n' +
439+
' "a",\n' +
440+
' "b",\n' +
441+
' "c",\n' +
442+
' "d"\n' +
443+
' ]\n' +
444+
' }\n' +
445+
']',)
437446
console.log(result)
438447
console.log(result.diff)
439448
})

src/utils/file-modification-calculator.ts

Lines changed: 3 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
import chalk from 'chalk';
21
import { ResourceConfig } from '../entities/resource-config.js';
3-
import * as Diff from 'diff'
2+
43
import * as jsonSourceMap from 'json-source-map';
54

65
import { FileType, InMemoryFile } from '../parser/entities.js';
76
import { SourceMap, SourceMapCache } from '../parser/source-maps.js';
87
import detectIndent from 'detect-indent';
98
import { Project } from '../entities/project.js';
109
import { ProjectConfig } from '../entities/project-config.js';
10+
import { prettyFormatFileDiff } from '../ui/file-diff-pretty-printer.js';
1111

1212
export enum ModificationType {
1313
INSERT_OR_UPDATE,
@@ -84,7 +84,7 @@ export class FileModificationCalculator {
8484

8585
return {
8686
newFile: newFile,
87-
diff: this.diff(this.existingFile.contents, newFile),
87+
diff: prettyFormatFileDiff(this.existingFile.contents, newFile),
8888
}
8989
}
9090

@@ -119,68 +119,6 @@ export class FileModificationCalculator {
119119
}
120120
}
121121

122-
diff(a: string, b: string): string {
123-
const diff = Diff.diffChars(a, b);
124-
125-
const diffedLines = Diff.diffLines(a, b)
126-
.flatMap((change) => change.value.split(/\n/).map(l => ({ added: change.added, removed: change.removed})))
127-
128-
let diffGroups = [];
129-
let pointerStart = -1;
130-
131-
for (let counter = 0; counter < diffedLines.length; counter++) {
132-
const changeAhead = diffedLines.slice(counter, counter + 5).some((change) => change.added || change.removed);
133-
const changeBehind = diffedLines.slice(counter - 5, counter).some((change) => change.added || change.removed);
134-
135-
if (pointerStart === -1 && changeAhead) {
136-
pointerStart = counter;
137-
continue;
138-
}
139-
140-
if (pointerStart !== -1 && !changeAhead && !changeBehind) {
141-
diffGroups.push({ start: pointerStart, end: counter })
142-
pointerStart = -1;
143-
continue;
144-
}
145-
146-
if (pointerStart !== -1 && counter === diffedLines.length - 1) {
147-
diffGroups.push({ start: pointerStart, end: counter })
148-
}
149-
}
150-
151-
let diffString = '';
152-
diff.forEach((part) => {
153-
diffString += part.added ? chalk.green(part.value) :
154-
part.removed ? chalk.red(part.value) :
155-
part.value;
156-
});
157-
158-
const diffLines = diffString.split(/\n/);
159-
const result = [];
160-
161-
for (const group of diffGroups) {
162-
const maxLineNumberWidth = group.end.toString().length;
163-
164-
result.push(`${chalk.bold(`Lines ${group.start} to line ${group.end}:`)}
165-
${diffLines.slice(group.start, group.end).map((l, idx) => {
166-
const change = diffedLines[group.start + idx];
167-
168-
if (change.added && change.removed) {
169-
return `${chalk.gray((group.start + idx).toString().padEnd(maxLineNumberWidth, ' '))} ${chalk.yellow('~')}${l}`
170-
} else if (change.added) {
171-
return `${chalk.gray((group.start + idx).toString().padEnd(maxLineNumberWidth, ' '))} ${chalk.green('+')}${l}`
172-
} else if (change.removed) {
173-
return `${chalk.gray((group.start + idx.toString()).padEnd(maxLineNumberWidth, ' '))} ${chalk.red('-')}${l}`
174-
} else {
175-
return `${chalk.gray((group.start + idx).toString().padEnd(maxLineNumberWidth, ' '))} ${l}`
176-
}
177-
}).join('\n')}`
178-
);
179-
}
180-
181-
return result.join('\n\n');
182-
}
183-
184122
// Insert always works at the end
185123
private insert(
186124
file: string,

0 commit comments

Comments
 (0)