Fix showing duplicate lines

This commit is contained in:
friebetill 2023-02-07 16:01:58 +08:00
parent 92b7a25737
commit 37319e5c5d
4 changed files with 105 additions and 87 deletions

View file

@ -38,12 +38,8 @@ export class ActionLine {
build(container: HTMLDivElement): void {
const actionLine = container.createDiv({ cls: 'flex-row gap-2 py-2' })
const hasPlusLines = this.difference.lines.some((l) =>
l.startsWith('+')
)
const hasMinusLines = this.difference.lines.some((l) =>
l.startsWith('-')
)
const hasMinusLines = this.difference.file1Lines.length > 0
const hasPlusLines = this.difference.file2Lines.length > 0
if (hasPlusLines && hasMinusLines) {
new ActionLineButton({
@ -60,6 +56,7 @@ export class ActionLine {
text: 'Accept All',
onClick: (e) => this.acceptAllClick(e, this.difference),
}).build(actionLine)
// TODO(tillf): Add button to accept none of the changes
} else if (hasMinusLines) {
new ActionLineButton({
text: `Accept from ${this.file1.name}`,
@ -89,10 +86,7 @@ export class ActionLine {
): Promise<void> {
event.preventDefault()
const changedLines = difference.lines
.filter((line) => line.startsWith('-'))
.map((line) => line.slice(1, line.length))
.join('\n')
const changedLines = difference.file1Lines.join('\n')
const newContent = replaceLine({
fullText: this.file2Content,
newLine: changedLines,
@ -109,10 +103,7 @@ export class ActionLine {
): Promise<void> {
event.preventDefault()
const changedLines = difference.lines
.filter((line) => line.startsWith('+'))
.map((line) => line.slice(1, line.length))
.join('\n')
const changedLines = difference.file2Lines.join('\n')
const newContent = replaceLine({
fullText: this.file1Content,
newLine: changedLines,
@ -129,10 +120,10 @@ export class ActionLine {
): Promise<void> {
event.preventDefault()
const changedLines = difference.lines
.filter((line) => line.startsWith('-') || line.startsWith('+'))
.map((line) => line.slice(1, line.length))
.join('\n')
const changedLines = [
...difference.file1Lines,
...difference.file2Lines,
].join('\n')
const newFile1Content = replaceLine({
fullText: this.file1Content,
@ -160,7 +151,7 @@ export class ActionLine {
const newContent = deleteLines({
fullText: this.file1Content,
position: difference.file1Start,
count: difference.lines.length,
count: difference.file1Lines.length,
})
await app.vault.modify(this.file1, newContent)
@ -176,7 +167,7 @@ export class ActionLine {
const newContent = deleteLines({
fullText: this.file2Content,
position: difference.file2Start,
count: difference.lines.length,
count: difference.file2Lines.length,
})
await app.vault.modify(this.file2, newContent)

View file

@ -36,6 +36,8 @@ export class DifferencesView extends ItemView {
private file1Lines: string[]
private file2Lines: string[]
private lineCount: number
private wasDeleteModalShown = false
@ -57,25 +59,23 @@ export class DifferencesView extends ItemView {
// TODO(tillf): Find way to refresh state when one of the files changes
this.file1Content = await this.app.vault.read(this.file1)
this.file1Lines = this.file1Content.split('\n')
this.file2Content = await this.app.vault.read(this.file2)
this.fileDifferences = FileDifferences.fromParsedDiff(
structuredPatch(
this.file1.path,
this.file2.path,
// Streamline empty lines at the end as this remove edge cases
this.file1Content.trimEnd().concat('\n'),
this.file2Content.trimEnd().concat('\n')
)
)
// Find the highest line number we need to go through. This can be the
// highest number in the differences, because the second file can have
// more lines than the first file.
const parsedDiff = structuredPatch(
this.file1.path,
this.file2.path,
// Streamline empty lines at the end as this remove edge cases
this.file1Content.trimEnd().concat('\n'),
this.file2Content.trimEnd().concat('\n')
)
this.fileDifferences = FileDifferences.fromParsedDiff(parsedDiff)
this.file1Lines = this.file1Content.split('\n')
this.file2Lines = this.file2Content.split('\n')
this.lineCount = Math.max(
this.file1Lines.length,
...this.fileDifferences.differences.map((d) => d.file1Start)
this.file2Lines.length
)
}
@ -84,9 +84,26 @@ export class DifferencesView extends ItemView {
const container = this.contentEl.createDiv({ cls: 'container' })
for (let i = 0; i <= this.lineCount; i += 1) {
const line = i in this.file1Lines ? this.file1Lines[i] : null
this.buildLines(container)
this.scrollToFirstDifference()
if (
this.fileDifferences.differences.length === 0 &&
this.showMergeOption &&
!this.wasDeleteModalShown
) {
this.showDeleteModal()
}
}
private buildLines(container: HTMLDivElement): void {
let i = 0
while (i <= this.lineCount) {
const line =
i in this.file1Lines ? this.file1Lines[i] : this.file2Lines[i]
const difference = this.fileDifferences.differences.find(
// eslint-disable-next-line no-loop-func
(d) => d.file1Start === i
)
@ -95,39 +112,16 @@ export class DifferencesView extends ItemView {
cls: 'difference',
})
this.buildDifferenceVisualizer(differenceContainer, difference)
}
if (
line != null &&
(difference == null || !difference.hasChangesFromFile1())
) {
i += Math.max(difference.file1Lines.length, 1)
} else {
container.createDiv({
// Necessary to give the line a height when it's empty.
text: preventEmptyString(line),
cls: 'line',
})
i += 1
}
}
if (this.fileDifferences.differences.length > 0) {
const containerRect = this.contentEl
.getElementsByClassName('container')[0]
.getBoundingClientRect()
const elementRect = this.contentEl
.getElementsByClassName('difference')[0]
.getBoundingClientRect()
this.contentEl.scrollTo({
top: elementRect.top - containerRect.top - 100,
behavior: 'smooth',
})
}
if (
this.fileDifferences.differences.length === 0 &&
this.showMergeOption &&
!this.wasDeleteModalShown
) {
this.showDeleteModal()
}
}
private buildDifferenceVisualizer(
@ -150,20 +144,39 @@ export class DifferencesView extends ItemView {
}).build(container)
}
difference.lines.forEach((line) => {
if (line.startsWith('+')) {
container.createDiv({
// Necessary to give the line a height when it's empty.
text: preventEmptyString(line.slice(1, line.length)),
cls: 'line bg-turquoise-light',
})
} else if (line.startsWith('-')) {
container.createDiv({
// Necessary to give the line a height when it's empty.
text: preventEmptyString(line.slice(1, line.length)),
cls: 'line bg-blue-light',
})
}
for (let i = 0; i < difference.file1Lines.length; i += 1) {
const line = difference.file1Lines[i]
container.createDiv({
// Necessary to give the line a height when it's empty.
text: preventEmptyString(line),
cls: 'line bg-turquoise-light',
})
}
for (let i = 0; i < difference.file2Lines.length; i += 1) {
const line = difference.file2Lines[i]
container.createDiv({
// Necessary to give the line a height when it's empty.
text: preventEmptyString(line),
cls: 'line bg-blue-light',
})
}
}
private scrollToFirstDifference(): void {
if (this.fileDifferences.differences.length === 0) {
return
}
const containerRect = this.contentEl
.getElementsByClassName('container')[0]
.getBoundingClientRect()
const elementRect = this.contentEl
.getElementsByClassName('difference')[0]
.getBoundingClientRect()
this.contentEl.scrollTo({
top: elementRect.top - containerRect.top - 100,
behavior: 'smooth',
})
}

View file

@ -2,20 +2,20 @@ export class Difference {
constructor(args: {
file1Start: number
file2Start: number
lines: string[]
file1Lines: string[]
file2Lines: string[]
}) {
this.file1Start = args.file1Start
this.file2Start = args.file2Start
this.lines = args.lines
this.file1Lines = args.file1Lines
this.file2Lines = args.file2Lines
}
public readonly file1Start: number
public readonly file2Start: number
public readonly lines: string[]
public readonly file1Lines: string[]
hasChangesFromFile1(): boolean {
return this.lines.some((l) => l.startsWith('-'))
}
public readonly file2Lines: string[]
}

View file

@ -42,6 +42,8 @@ export class FileDifferences {
const differences: Difference[] = []
parsedDiff.hunks.forEach((hunk) => {
let line1Count = 0
let line2Count = 0
for (let i = 0; i < hunk.lines.length; i += 1) {
const line = hunk.lines[i]
@ -49,7 +51,7 @@ export class FileDifferences {
const start = i
// Find the end of the contiguous lines
let end = i
let end = start
while (
end < hunk.lines.length - 1 &&
(hunk.lines[end + 1].startsWith('+') ||
@ -59,13 +61,25 @@ export class FileDifferences {
}
// Add the contiguous lines to the differences
const file1Lines = hunk.lines
.slice(start, end + 1)
.filter((l) => l.startsWith('-'))
.map((l) => l.slice(1))
const file2Lines = hunk.lines
.slice(start, end + 1)
.filter((l) => l.startsWith('+'))
.map((l) => l.slice(1))
differences.push(
new Difference({
file1Start: hunk.oldStart + start - 1,
file2Start: hunk.newStart + start - 1,
lines: hunk.lines.slice(start, end + 1),
file1Start: hunk.oldStart + start - line2Count - 1,
file2Start: hunk.newStart + start - line1Count - 1,
file1Lines,
file2Lines,
})
)
line1Count += file1Lines.length
line2Count += file2Lines.length
i += end - start
}
}