mirror of
https://github.com/friebetill/obsidian-file-diff.git
synced 2026-07-22 07:40:25 +00:00
Fix showing duplicate lines
This commit is contained in:
parent
92b7a25737
commit
37319e5c5d
4 changed files with 105 additions and 87 deletions
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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[]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue