mirror of
https://github.com/silvanocerza/github-gitless-sync.git
synced 2026-07-22 05:41:36 +00:00
More progress
This commit is contained in:
parent
6d7c0c8772
commit
9f62324c2a
5 changed files with 401 additions and 81 deletions
|
|
@ -1,20 +1,23 @@
|
||||||
import { App } from "obsidian";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { useEffect, useRef } from "react";
|
|
||||||
import { EditorView } from "@codemirror/view";
|
import { EditorView } from "@codemirror/view";
|
||||||
import { EditorState } from "@codemirror/state";
|
import { EditorState } from "@codemirror/state";
|
||||||
import { markdown } from "@codemirror/lang-markdown";
|
import { markdown } from "@codemirror/lang-markdown";
|
||||||
import diff from "./diff";
|
import diff from "./diff";
|
||||||
import { createDiffHighlightPlugin } from "./diff-highlight-plugin";
|
import { createDiffHighlightPlugin } from "./diff-highlight-plugin";
|
||||||
|
import DiffConnections from "./diff-connections";
|
||||||
|
|
||||||
// Add styles for diff highlighting
|
// Add styles for diff highlighting
|
||||||
const styles = document.createElement("style");
|
const styles = document.createElement("style");
|
||||||
styles.innerHTML = `
|
styles.innerHTML = `
|
||||||
.diff-remove-background {
|
.diff-modify-background {
|
||||||
background-color: rgba(var(--background-modifier-error-rgb), 0.1);
|
background-color: rgba(var(--color-yellow-rgb), 0.1);
|
||||||
}
|
}
|
||||||
.diff-add-background {
|
.diff-add-background {
|
||||||
background-color: rgba(var(--color-green-rgb), 0.1);
|
background-color: rgba(var(--color-green-rgb), 0.1);
|
||||||
}
|
}
|
||||||
|
.diff-remove-background {
|
||||||
|
background-color: rgba(var(--color-red-rgb), 0.1);
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
document.head.appendChild(styles);
|
document.head.appendChild(styles);
|
||||||
|
|
||||||
|
|
@ -22,15 +25,14 @@ interface DiffViewProps {
|
||||||
oldText: string;
|
oldText: string;
|
||||||
newText: string;
|
newText: string;
|
||||||
onResolve: (resolvedText: string) => void;
|
onResolve: (resolvedText: string) => void;
|
||||||
app: App;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const DiffView: React.FC<DiffViewProps> = ({
|
const DiffView: React.FC<DiffViewProps> = ({ oldText, newText, onResolve }) => {
|
||||||
oldText,
|
const [originalEditorView, setOriginalEditorView] =
|
||||||
newText,
|
useState<EditorView | null>(null);
|
||||||
onResolve,
|
const [modifiedEditorView, setModifiedEditorView] =
|
||||||
app,
|
useState<EditorView | null>(null);
|
||||||
}) => {
|
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
const editorViewsRef = useRef<EditorView[]>([]);
|
const editorViewsRef = useRef<EditorView[]>([]);
|
||||||
|
|
||||||
|
|
@ -92,6 +94,12 @@ const DiffView: React.FC<DiffViewProps> = ({
|
||||||
parent: container,
|
parent: container,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (isOriginal) {
|
||||||
|
setOriginalEditorView(view);
|
||||||
|
} else if (readOnly) {
|
||||||
|
setModifiedEditorView(view);
|
||||||
|
}
|
||||||
|
|
||||||
editorViewsRef.current.push(view);
|
editorViewsRef.current.push(view);
|
||||||
return view;
|
return view;
|
||||||
};
|
};
|
||||||
|
|
@ -128,7 +136,7 @@ const DiffView: React.FC<DiffViewProps> = ({
|
||||||
ref={containerRef}
|
ref={containerRef}
|
||||||
style={{
|
style={{
|
||||||
display: "grid",
|
display: "grid",
|
||||||
gridTemplateColumns: "1fr 1fr",
|
gridTemplateColumns: "1fr auto 1fr",
|
||||||
gridTemplateRows: "1fr 1fr",
|
gridTemplateRows: "1fr 1fr",
|
||||||
gap: "10px",
|
gap: "10px",
|
||||||
height: "100%",
|
height: "100%",
|
||||||
|
|
@ -136,17 +144,39 @@ const DiffView: React.FC<DiffViewProps> = ({
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="original-editor"
|
className="original-editor"
|
||||||
style={{ border: "1px solid var(--background-modifier-border)" }}
|
style={{
|
||||||
|
border: "1px solid var(--background-modifier-border)",
|
||||||
|
backgroundColor: "var(--background-primary)",
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
|
<div
|
||||||
|
className="diff-overlay"
|
||||||
|
style={{
|
||||||
|
gridRow: "1 / 2",
|
||||||
|
gridColumn: "2 / 3",
|
||||||
|
position: "relative",
|
||||||
|
width: "50px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DiffConnections
|
||||||
|
differences={diff(oldText, newText)}
|
||||||
|
originalEditor={originalEditorView}
|
||||||
|
modifiedEditor={modifiedEditorView}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
className="modified-editor"
|
className="modified-editor"
|
||||||
style={{ border: "1px solid var(--background-modifier-border)" }}
|
style={{
|
||||||
|
border: "1px solid var(--background-modifier-border)",
|
||||||
|
backgroundColor: "var(--background-primary)",
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
className="result-editor"
|
className="result-editor"
|
||||||
style={{
|
style={{
|
||||||
gridColumn: "1 / span 2",
|
gridColumn: "1 / 4",
|
||||||
border: "1px solid var(--background-modifier-border)",
|
border: "1px solid var(--background-modifier-border)",
|
||||||
|
backgroundColor: "var(--background-primary)",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
273
src/views/conflicts-resolution/diff-connections.tsx
Normal file
273
src/views/conflicts-resolution/diff-connections.tsx
Normal file
|
|
@ -0,0 +1,273 @@
|
||||||
|
import { setIcon } from "obsidian";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { EditorView } from "@codemirror/view";
|
||||||
|
import { DiffResult } from "./diff";
|
||||||
|
|
||||||
|
interface DiffConnectionProps {
|
||||||
|
differences: DiffResult[];
|
||||||
|
originalEditor: EditorView | null;
|
||||||
|
modifiedEditor: EditorView | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConnectionType = "add" | "remove" | "modify";
|
||||||
|
|
||||||
|
type ConnectionChunk = {
|
||||||
|
startTop: number;
|
||||||
|
startBottom: number;
|
||||||
|
endTop: number;
|
||||||
|
endBottom: number;
|
||||||
|
type: ConnectionType;
|
||||||
|
};
|
||||||
|
|
||||||
|
const DiffConnections: React.FC<DiffConnectionProps> = ({
|
||||||
|
differences,
|
||||||
|
originalEditor,
|
||||||
|
modifiedEditor,
|
||||||
|
}) => {
|
||||||
|
const [connections, setConnections] = useState<ConnectionChunk[]>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!originalEditor || !modifiedEditor) return;
|
||||||
|
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
const originalContainer =
|
||||||
|
originalEditor.scrollDOM.getBoundingClientRect();
|
||||||
|
const modifiedContainer =
|
||||||
|
modifiedEditor.scrollDOM.getBoundingClientRect();
|
||||||
|
|
||||||
|
// Group consecutive diffs into chunks
|
||||||
|
const chunks: ConnectionChunk[] = [];
|
||||||
|
let currentChunk: DiffResult[] = [];
|
||||||
|
|
||||||
|
differences.forEach((diff, i) => {
|
||||||
|
if (diff.type === "equal") {
|
||||||
|
if (currentChunk.length > 0) {
|
||||||
|
// Process the chunk
|
||||||
|
const chunk = processChunk(
|
||||||
|
currentChunk,
|
||||||
|
originalEditor,
|
||||||
|
modifiedEditor,
|
||||||
|
originalContainer,
|
||||||
|
modifiedContainer,
|
||||||
|
);
|
||||||
|
if (chunk) chunks.push(chunk);
|
||||||
|
currentChunk = [];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
currentChunk.push(diff);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Process last chunk if exists
|
||||||
|
if (currentChunk.length > 0) {
|
||||||
|
const chunk = processChunk(
|
||||||
|
currentChunk,
|
||||||
|
originalEditor,
|
||||||
|
modifiedEditor,
|
||||||
|
originalContainer,
|
||||||
|
modifiedContainer,
|
||||||
|
);
|
||||||
|
if (chunk) chunks.push(chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
setConnections(chunks);
|
||||||
|
});
|
||||||
|
}, [differences, originalEditor, modifiedEditor]);
|
||||||
|
|
||||||
|
const processChunk = (
|
||||||
|
chunk: DiffResult[],
|
||||||
|
originalEditor: EditorView,
|
||||||
|
modifiedEditor: EditorView,
|
||||||
|
originalContainer: DOMRect,
|
||||||
|
modifiedContainer: DOMRect,
|
||||||
|
): ConnectionChunk | null => {
|
||||||
|
let startTop = Infinity;
|
||||||
|
let startBottom = -Infinity;
|
||||||
|
let endTop = Infinity;
|
||||||
|
let endBottom = -Infinity;
|
||||||
|
|
||||||
|
chunk.forEach((diff) => {
|
||||||
|
if (diff.type === "modify" || diff.type === "remove") {
|
||||||
|
// Find position in original editor
|
||||||
|
const line = findLineByContent(
|
||||||
|
originalEditor,
|
||||||
|
diff.oldValue || diff.value,
|
||||||
|
);
|
||||||
|
if (line) {
|
||||||
|
startTop = Math.min(startTop, line.top - originalContainer.top);
|
||||||
|
startBottom = Math.max(
|
||||||
|
startBottom,
|
||||||
|
line.bottom - originalContainer.top,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (diff.type === "modify" || diff.type === "add") {
|
||||||
|
// Find position in modified editor
|
||||||
|
const line = findLineByContent(modifiedEditor, diff.value);
|
||||||
|
if (line) {
|
||||||
|
endTop = Math.min(endTop, line.top - modifiedContainer.top);
|
||||||
|
endBottom = Math.max(endBottom, line.bottom - modifiedContainer.top);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (startTop === Infinity && endTop === Infinity) return null;
|
||||||
|
|
||||||
|
// For pure additions, position start at the previous equal line's bottom
|
||||||
|
if (startTop === Infinity) {
|
||||||
|
const prevEqual = findPreviousEqual(differences, chunk[0]);
|
||||||
|
if (prevEqual) {
|
||||||
|
const line = findLineByContent(originalEditor, prevEqual.value);
|
||||||
|
if (line) {
|
||||||
|
startTop = startBottom = line.bottom - originalContainer.top;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
startTop: startTop === Infinity ? endTop : startTop,
|
||||||
|
startBottom: startBottom === -Infinity ? endBottom : startBottom,
|
||||||
|
endTop: endTop === Infinity ? startTop : endTop,
|
||||||
|
endBottom: endBottom === -Infinity ? startBottom : endBottom,
|
||||||
|
type: (chunk.some((d) => d.type === "modify")
|
||||||
|
? "modify"
|
||||||
|
: chunk[0].type) as ConnectionType,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
style={{
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
position: "absolute",
|
||||||
|
overflow: "visible",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{connections.map((chunk, i) => {
|
||||||
|
const color = getConnectionStyle(chunk.type);
|
||||||
|
return (
|
||||||
|
<g key={i}>
|
||||||
|
<path
|
||||||
|
d={`
|
||||||
|
M 0 ${chunk.startTop}
|
||||||
|
C 20 ${chunk.startTop}, 30 ${chunk.endTop}, 50 ${chunk.endTop}
|
||||||
|
L 50 ${chunk.endBottom}
|
||||||
|
C 30 ${chunk.endBottom}, 20 ${chunk.startBottom}, 0 ${chunk.startBottom}
|
||||||
|
Z
|
||||||
|
`}
|
||||||
|
fill={color}
|
||||||
|
fillOpacity="0.1"
|
||||||
|
stroke={color}
|
||||||
|
strokeWidth="1"
|
||||||
|
/>
|
||||||
|
<ConnectionButtons
|
||||||
|
chunk={chunk}
|
||||||
|
onAction={(action) => {
|
||||||
|
console.log("Action:", action, "for chunk:", chunk);
|
||||||
|
// TODO: Implement actual resolution actions
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const findLineByContent = (
|
||||||
|
editor: EditorView,
|
||||||
|
content?: string,
|
||||||
|
): { top: number; bottom: number } | null => {
|
||||||
|
if (!content) return null;
|
||||||
|
|
||||||
|
const doc = editor.state.doc;
|
||||||
|
for (let i = 1; i <= doc.lines; i++) {
|
||||||
|
const line = doc.line(i);
|
||||||
|
if (line.text === content) {
|
||||||
|
const fromCoords = editor.coordsAtPos(line.from);
|
||||||
|
const toCoords = editor.coordsAtPos(line.to);
|
||||||
|
if (fromCoords && toCoords) {
|
||||||
|
return {
|
||||||
|
top: fromCoords.top,
|
||||||
|
bottom: toCoords.bottom,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const findPreviousEqual = (
|
||||||
|
differences: DiffResult[],
|
||||||
|
currentDiff: DiffResult,
|
||||||
|
): DiffResult | null => {
|
||||||
|
const currentIndex = differences.findIndex((d) => d === currentDiff);
|
||||||
|
if (currentIndex === -1) return null;
|
||||||
|
|
||||||
|
for (let i = currentIndex - 1; i >= 0; i--) {
|
||||||
|
if (differences[i].type === "equal") {
|
||||||
|
return differences[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getConnectionStyle = (type: ConnectionType): string => {
|
||||||
|
switch (type) {
|
||||||
|
case "add":
|
||||||
|
return "var(--color-green)";
|
||||||
|
case "remove":
|
||||||
|
return "var(--color-red)";
|
||||||
|
case "modify":
|
||||||
|
return "var(--color-yellow)";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const ConnectionButtons: React.FC<{
|
||||||
|
chunk: ConnectionChunk;
|
||||||
|
onAction: (action: "left" | "right") => void;
|
||||||
|
}> = ({ chunk, onAction }) => {
|
||||||
|
const centerY =
|
||||||
|
(chunk.startTop + chunk.startBottom + chunk.endTop + chunk.endBottom) / 4;
|
||||||
|
|
||||||
|
const showLeftArrow = chunk.type === "modify" || chunk.type === "add";
|
||||||
|
const showRightArrow = chunk.type === "modify" || chunk.type === "remove";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<foreignObject x="0" y={centerY - 8} width="50" height="16">
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
justifyContent:
|
||||||
|
showLeftArrow && showRightArrow
|
||||||
|
? "space-between"
|
||||||
|
: showLeftArrow
|
||||||
|
? "flex-end"
|
||||||
|
: "flex-start",
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{showRightArrow && (
|
||||||
|
<div
|
||||||
|
style={{ cursor: "pointer", width: 16, height: 16 }}
|
||||||
|
onClick={() => onAction("right")}
|
||||||
|
ref={(node) => node && setIcon(node, "arrow-right")}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{showLeftArrow && (
|
||||||
|
<div
|
||||||
|
style={{ cursor: "pointer", width: 16, height: 16 }}
|
||||||
|
onClick={() => onAction("left")}
|
||||||
|
ref={(node) => node && setIcon(node, "arrow-left")}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</foreignObject>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DiffConnections;
|
||||||
|
|
@ -24,26 +24,36 @@ export function createDiffHighlightPlugin(spec: DiffHighlightPluginSpec) {
|
||||||
const decorations = [];
|
const decorations = [];
|
||||||
const doc = view.state.doc;
|
const doc = view.state.doc;
|
||||||
|
|
||||||
// Go through the document line by line
|
|
||||||
for (let i = 1; i <= doc.lines; i++) {
|
for (let i = 1; i <= doc.lines; i++) {
|
||||||
const line = doc.line(i);
|
const line = doc.line(i);
|
||||||
const lineText = line.text;
|
const diffResult = spec.diff.find((d) => {
|
||||||
|
if (spec.isOriginal) {
|
||||||
|
return (
|
||||||
|
d.oldValue === line.text ||
|
||||||
|
(d.type === "remove" && d.value === line.text)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return d.type !== "remove" && d.value === line.text;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Find matching diff for this line
|
if (diffResult && diffResult.type !== "equal") {
|
||||||
const diff = spec.diff.find((d) => d.value === lineText);
|
let className = "";
|
||||||
|
if (diffResult.type === "modify") {
|
||||||
|
className = "diff-modify-background";
|
||||||
|
} else if (diffResult.type === "add" && !spec.isOriginal) {
|
||||||
|
className = "diff-add-background";
|
||||||
|
} else if (diffResult.type === "remove" && spec.isOriginal) {
|
||||||
|
className = "diff-remove-background";
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (className) {
|
||||||
diff &&
|
decorations.push(
|
||||||
((spec.isOriginal && diff.type === "remove") ||
|
Decoration.line({
|
||||||
(!spec.isOriginal && diff.type === "add"))
|
class: className,
|
||||||
) {
|
}).range(line.from),
|
||||||
decorations.push(
|
);
|
||||||
Decoration.mark({
|
}
|
||||||
class: spec.isOriginal
|
|
||||||
? "diff-remove-background"
|
|
||||||
: "diff-add-background",
|
|
||||||
}).range(line.from, line.to),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,69 +1,77 @@
|
||||||
export type DiffResult = {
|
type DiffType = "add" | "remove" | "modify" | "equal";
|
||||||
type: "add" | "remove" | "equal";
|
|
||||||
|
export interface DiffResult {
|
||||||
|
type: DiffType;
|
||||||
value: string;
|
value: string;
|
||||||
|
oldValue?: string; // For modifications, store both values
|
||||||
|
newValue?: string;
|
||||||
from: number;
|
from: number;
|
||||||
to: number;
|
to: number;
|
||||||
};
|
}
|
||||||
|
|
||||||
export default function diff(oldText: string, newText: string): DiffResult[] {
|
function diff(oldText: string, newText: string): DiffResult[] {
|
||||||
const oldLines = oldText.split("\n");
|
const oldLines = oldText.split("\n");
|
||||||
const newLines = newText.split("\n");
|
const newLines = newText.split("\n");
|
||||||
|
|
||||||
const matrix = Array(oldLines.length + 1)
|
|
||||||
.fill(null)
|
|
||||||
.map(() => Array(newLines.length + 1).fill(0));
|
|
||||||
|
|
||||||
// Fill the matrix
|
|
||||||
for (let i = 1; i <= oldLines.length; i++) {
|
|
||||||
for (let j = 1; j <= newLines.length; j++) {
|
|
||||||
if (oldLines[i - 1] === newLines[j - 1]) {
|
|
||||||
matrix[i][j] = matrix[i - 1][j - 1] + 1;
|
|
||||||
} else {
|
|
||||||
matrix[i][j] = Math.max(matrix[i - 1][j], matrix[i][j - 1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Backtrack to find differences
|
|
||||||
const result: DiffResult[] = [];
|
const result: DiffResult[] = [];
|
||||||
let i = oldLines.length;
|
|
||||||
let j = newLines.length;
|
|
||||||
let position = 0;
|
let position = 0;
|
||||||
|
|
||||||
while (i > 0 || j > 0) {
|
// First pass: find exact matches and obvious modifications
|
||||||
if (i > 0 && j > 0 && oldLines[i - 1] === newLines[j - 1]) {
|
for (let i = 0; i < Math.max(oldLines.length, newLines.length); i++) {
|
||||||
const value = oldLines[i - 1];
|
const oldLine = oldLines[i];
|
||||||
result.unshift({
|
const newLine = newLines[i];
|
||||||
type: "equal",
|
|
||||||
value,
|
if (!oldLine && newLine) {
|
||||||
from: position,
|
// Pure addition
|
||||||
to: position + value.length,
|
result.push({
|
||||||
});
|
|
||||||
position += value.length + 1; // +1 for newline
|
|
||||||
i--;
|
|
||||||
j--;
|
|
||||||
} else if (j > 0 && (i === 0 || matrix[i][j - 1] >= matrix[i - 1][j])) {
|
|
||||||
const value = newLines[j - 1];
|
|
||||||
result.unshift({
|
|
||||||
type: "add",
|
type: "add",
|
||||||
value,
|
value: newLine,
|
||||||
from: position,
|
from: position,
|
||||||
to: position + value.length,
|
to: position + newLine.length,
|
||||||
});
|
});
|
||||||
position += value.length + 1;
|
} else if (oldLine && !newLine) {
|
||||||
j--;
|
// Pure removal
|
||||||
} else if (i > 0 && (j === 0 || matrix[i][j - 1] < matrix[i - 1][j])) {
|
result.push({
|
||||||
const value = oldLines[i - 1];
|
|
||||||
result.unshift({
|
|
||||||
type: "remove",
|
type: "remove",
|
||||||
value,
|
value: oldLine,
|
||||||
from: position,
|
from: position,
|
||||||
to: position + value.length,
|
to: position + oldLine.length,
|
||||||
|
});
|
||||||
|
} else if (oldLine === newLine) {
|
||||||
|
// Exact match
|
||||||
|
result.push({
|
||||||
|
type: "equal",
|
||||||
|
value: oldLine,
|
||||||
|
from: position,
|
||||||
|
to: position + oldLine.length,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Different content at same line number - treat as modification
|
||||||
|
result.push({
|
||||||
|
type: "modify",
|
||||||
|
value: newLine,
|
||||||
|
oldValue: oldLine,
|
||||||
|
newValue: newLine,
|
||||||
|
from: position,
|
||||||
|
to: position + Math.max(oldLine.length, newLine.length),
|
||||||
});
|
});
|
||||||
position += value.length + 1;
|
|
||||||
i--;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
position +=
|
||||||
|
Math.max(oldLine ? oldLine.length : 0, newLine ? newLine.length : 0) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function similarity(s1: string, s2: string): number {
|
||||||
|
if (s1 === s2) return 1.0;
|
||||||
|
|
||||||
|
// Simple word-based similarity
|
||||||
|
const words1 = s1.split(/\s+/);
|
||||||
|
const words2 = s2.split(/\s+/);
|
||||||
|
|
||||||
|
const commonWords = words1.filter((w) => words2.includes(w)).length;
|
||||||
|
return commonWords / Math.max(words1.length, words2.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default diff;
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,6 @@ export class ConflictsResolutionView extends ItemView {
|
||||||
<DiffView
|
<DiffView
|
||||||
oldText={oldText1}
|
oldText={oldText1}
|
||||||
newText={newText1}
|
newText={newText1}
|
||||||
app={this.app}
|
|
||||||
onResolve={(text) => console.log("Resolved:", text)}
|
onResolve={(text) => console.log("Resolved:", text)}
|
||||||
// registerExtension={(ext) => this.plugin.registerEditorExtension(ext)}
|
// registerExtension={(ext) => this.plugin.registerEditorExtension(ext)}
|
||||||
/>,
|
/>,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue