mirror of
https://github.com/silvanocerza/github-gitless-sync.git
synced 2026-07-22 12:10:28 +00:00
Bad attempt at diff apply
This commit is contained in:
parent
5edb8ca742
commit
63f9afe738
4 changed files with 202 additions and 34 deletions
|
|
@ -4,7 +4,7 @@ import { EditorState } from "@codemirror/state";
|
|||
import { markdown } from "@codemirror/lang-markdown";
|
||||
import diff from "./diff";
|
||||
import { createDiffHighlightPlugin } from "./diff-highlight-plugin";
|
||||
import DiffConnections from "./diff-connections";
|
||||
import DiffConnections, { ConnectionChunk } from "./diff-connections";
|
||||
|
||||
// Add styles for diff highlighting
|
||||
const styles = document.createElement("style");
|
||||
|
|
@ -45,7 +45,7 @@ const DiffView: React.FC<DiffViewProps> = ({ oldText, newText, onResolve }) => {
|
|||
readOnly: boolean = false,
|
||||
isOriginal: boolean = false,
|
||||
) => {
|
||||
const differences = diff(oldText, newText);
|
||||
const differences = diff(oldText || "", newText || "");
|
||||
|
||||
const highlightPlugin = createDiffHighlightPlugin({
|
||||
diff: differences,
|
||||
|
|
@ -62,7 +62,7 @@ const DiffView: React.FC<DiffViewProps> = ({ oldText, newText, onResolve }) => {
|
|||
]
|
||||
: [];
|
||||
|
||||
const state = EditorState.create({
|
||||
const editorState = EditorState.create({
|
||||
doc: content,
|
||||
extensions: [
|
||||
// basicSetup minus line numbers
|
||||
|
|
@ -90,7 +90,7 @@ const DiffView: React.FC<DiffViewProps> = ({ oldText, newText, onResolve }) => {
|
|||
});
|
||||
|
||||
const view = new EditorView({
|
||||
state,
|
||||
state: editorState,
|
||||
parent: container,
|
||||
});
|
||||
|
||||
|
|
@ -131,6 +131,96 @@ const DiffView: React.FC<DiffViewProps> = ({ oldText, newText, onResolve }) => {
|
|||
};
|
||||
}, [oldText, newText]);
|
||||
|
||||
const handleMerge = (direction: "left" | "right", chunk: ConnectionChunk) => {
|
||||
if (!originalEditorView || !modifiedEditorView) {
|
||||
return;
|
||||
}
|
||||
|
||||
const sourceEditor =
|
||||
direction === "left" ? modifiedEditorView : originalEditorView;
|
||||
const targetEditor =
|
||||
direction === "left" ? originalEditorView : modifiedEditorView;
|
||||
|
||||
const sourceLine =
|
||||
direction === "left" ? chunk.targetStartLine : chunk.startLine;
|
||||
const sourceEndLine =
|
||||
direction === "left" ? chunk.targetEndLine : chunk.endLine;
|
||||
const targetLine =
|
||||
direction === "left" ? chunk.startLine : chunk.targetStartLine;
|
||||
const targetEndLine =
|
||||
direction === "left" ? chunk.endLine : chunk.targetEndLine;
|
||||
|
||||
const sourceDoc = sourceEditor.state.doc;
|
||||
const targetDoc = targetEditor.state.doc;
|
||||
|
||||
// Handle source content
|
||||
let contentToInsert = "";
|
||||
if (sourceLine > sourceDoc.lines) {
|
||||
// Adding new lines at the end
|
||||
contentToInsert = "\n" + chunk.content.join("\n");
|
||||
} else {
|
||||
const sourceFrom = sourceDoc.line(sourceLine).from;
|
||||
const sourceTo =
|
||||
sourceEndLine <= sourceDoc.lines
|
||||
? sourceDoc.line(sourceEndLine).to
|
||||
: sourceDoc.length;
|
||||
contentToInsert = sourceEditor.state.sliceDoc(sourceFrom, sourceTo);
|
||||
}
|
||||
|
||||
// Handle target position
|
||||
let targetFrom = 0;
|
||||
let targetTo = 0;
|
||||
|
||||
if (targetLine > targetDoc.lines) {
|
||||
// Appending to end of file
|
||||
targetFrom = targetTo = targetDoc.length;
|
||||
if (!contentToInsert.startsWith("\n") && targetDoc.length > 0) {
|
||||
contentToInsert = "\n" + contentToInsert;
|
||||
}
|
||||
} else {
|
||||
targetFrom = targetDoc.line(targetLine).from;
|
||||
targetTo =
|
||||
targetEndLine <= targetDoc.lines
|
||||
? targetDoc.line(targetEndLine).to
|
||||
: targetDoc.length;
|
||||
}
|
||||
|
||||
// Apply the change
|
||||
const change = {
|
||||
from: targetFrom,
|
||||
to: targetTo,
|
||||
insert: contentToInsert,
|
||||
};
|
||||
|
||||
targetEditor.dispatch({ changes: change });
|
||||
|
||||
// Update result editor if it exists
|
||||
// if (resultEditor) {
|
||||
// const resultDoc = resultEditor.state.doc;
|
||||
// let resultFrom = targetFrom;
|
||||
// let resultTo = targetTo;
|
||||
|
||||
// // Handle case where result editor might have different content length
|
||||
// if (resultFrom > resultDoc.length) {
|
||||
// resultFrom = resultTo = resultDoc.length;
|
||||
// if (!contentToInsert.startsWith("\n") && resultDoc.length > 0) {
|
||||
// contentToInsert = "\n" + contentToInsert;
|
||||
// }
|
||||
// }
|
||||
|
||||
// resultEditor.dispatch({
|
||||
// changes: {
|
||||
// from: resultFrom,
|
||||
// to: resultTo,
|
||||
// insert: contentToInsert,
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
|
||||
// Notify parent
|
||||
onResolve(targetEditor.state.doc.toString());
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={containerRef}
|
||||
|
|
@ -162,6 +252,7 @@ const DiffView: React.FC<DiffViewProps> = ({ oldText, newText, onResolve }) => {
|
|||
differences={diff(oldText, newText)}
|
||||
originalEditor={originalEditorView}
|
||||
modifiedEditor={modifiedEditorView}
|
||||
onMerge={handleMerge}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { App, setIcon } from "obsidian";
|
||||
import { setIcon } from "obsidian";
|
||||
import { useEffect, useState } from "react";
|
||||
import { EditorView } from "@codemirror/view";
|
||||
import { DiffResult } from "./diff";
|
||||
|
|
@ -8,22 +8,31 @@ interface DiffConnectionProps {
|
|||
differences: DiffResult[];
|
||||
originalEditor: EditorView | null;
|
||||
modifiedEditor: EditorView | null;
|
||||
onMerge: (from: "left" | "right", chunk: ConnectionChunk) => void;
|
||||
}
|
||||
|
||||
type ConnectionType = "add" | "remove" | "modify";
|
||||
|
||||
type ConnectionChunk = {
|
||||
export type ConnectionChunk = {
|
||||
// For rendering
|
||||
startTop: number;
|
||||
startBottom: number;
|
||||
endTop: number;
|
||||
endBottom: number;
|
||||
// For merging
|
||||
startLine: number;
|
||||
endLine: number;
|
||||
targetStartLine: number;
|
||||
targetEndLine: number;
|
||||
type: ConnectionType;
|
||||
content: string[];
|
||||
};
|
||||
|
||||
const DiffConnections: React.FC<DiffConnectionProps> = ({
|
||||
differences,
|
||||
originalEditor,
|
||||
modifiedEditor,
|
||||
onMerge,
|
||||
}) => {
|
||||
const [connections, setConnections] = useState<ConnectionChunk[]>([]);
|
||||
const plugin = usePlugin();
|
||||
|
|
@ -33,7 +42,10 @@ const DiffConnections: React.FC<DiffConnectionProps> = ({
|
|||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!originalEditor || !modifiedEditor) return;
|
||||
if (!originalEditor || !modifiedEditor) {
|
||||
// Editors still not initialized
|
||||
return;
|
||||
}
|
||||
|
||||
const updateConnections = () => {
|
||||
requestAnimationFrame(() => {
|
||||
|
|
@ -153,15 +165,90 @@ const DiffConnections: React.FC<DiffConnectionProps> = ({
|
|||
}
|
||||
}
|
||||
|
||||
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,
|
||||
// Track actual content and line numbers
|
||||
const firstDiff = chunk[0];
|
||||
const lastDiff = chunk[chunk.length - 1];
|
||||
|
||||
// For original (left) content
|
||||
const originalDoc = originalEditor.state.doc;
|
||||
let startLine = 0;
|
||||
let endLine = 0;
|
||||
if (firstDiff.type === "remove" || firstDiff.type === "modify") {
|
||||
for (let i = 1; i <= originalDoc.lines + 1; i++) {
|
||||
if (i <= originalDoc.lines) {
|
||||
const line = originalDoc.line(i);
|
||||
const content = firstDiff.oldValue || firstDiff.value;
|
||||
if (line.text === content) {
|
||||
startLine = i;
|
||||
break;
|
||||
}
|
||||
} else if (startLine === 0) {
|
||||
// Content should be added at the end
|
||||
startLine = originalDoc.lines + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (lastDiff.type === "remove" || lastDiff.type === "modify") {
|
||||
endLine =
|
||||
startLine +
|
||||
chunk.filter((d) => d.type === "remove" || d.type === "modify")
|
||||
.length -
|
||||
1;
|
||||
} else {
|
||||
endLine = startLine;
|
||||
}
|
||||
}
|
||||
|
||||
// For modified (right) content
|
||||
const modifiedDoc = modifiedEditor.state.doc;
|
||||
let targetStartLine = 0;
|
||||
let targetEndLine = 0;
|
||||
if (firstDiff.type === "add" || firstDiff.type === "modify") {
|
||||
for (let i = 1; i <= modifiedDoc.lines + 1; i++) {
|
||||
if (i <= modifiedDoc.lines) {
|
||||
const line = modifiedDoc.line(i);
|
||||
if (line.text === firstDiff.value) {
|
||||
targetStartLine = i;
|
||||
break;
|
||||
}
|
||||
} else if (targetStartLine === 0) {
|
||||
// Content should be added at the end
|
||||
targetStartLine = modifiedDoc.lines + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (lastDiff.type === "add" || lastDiff.type === "modify") {
|
||||
targetEndLine =
|
||||
targetStartLine +
|
||||
chunk.filter((d) => d.type === "add" || d.type === "modify").length -
|
||||
1;
|
||||
} else {
|
||||
targetEndLine = targetStartLine;
|
||||
}
|
||||
}
|
||||
|
||||
// Collect the actual content
|
||||
const content = chunk
|
||||
.filter((d) => d.type === "add" || d.type === "modify")
|
||||
.map((d) => d.value);
|
||||
|
||||
const res = {
|
||||
startTop,
|
||||
startBottom,
|
||||
endTop,
|
||||
endBottom,
|
||||
startLine,
|
||||
endLine,
|
||||
targetStartLine,
|
||||
targetEndLine,
|
||||
type: chunk[0].type as ConnectionType,
|
||||
content,
|
||||
};
|
||||
|
||||
console.log("ProcessChunk Result");
|
||||
console.log(res);
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
@ -192,10 +279,7 @@ const DiffConnections: React.FC<DiffConnectionProps> = ({
|
|||
/>
|
||||
<ConnectionButtons
|
||||
chunk={chunk}
|
||||
onAction={(action) => {
|
||||
console.log("Action:", action, "for chunk:", chunk);
|
||||
// TODO: Implement actual resolution actions
|
||||
}}
|
||||
onAction={(direction) => onMerge(direction, chunk)}
|
||||
/>
|
||||
</g>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ function diff(oldText: string, newText: string): DiffResult[] {
|
|||
const oldLines = oldText.split("\n");
|
||||
const newLines = newText.split("\n");
|
||||
const result: DiffResult[] = [];
|
||||
// This is an index in oldText
|
||||
let position = 0;
|
||||
|
||||
// First pass: find exact matches and obvious modifications
|
||||
|
|
@ -56,22 +57,12 @@ function diff(oldText: string, newText: string): DiffResult[] {
|
|||
});
|
||||
}
|
||||
|
||||
position +=
|
||||
Math.max(oldLine ? oldLine.length : 0, newLine ? newLine.length : 0) + 1;
|
||||
const oldLineLength = oldLine ? oldLine.length : 0;
|
||||
const newLineLength = newLine ? newLine.length : 0;
|
||||
position += Math.max(oldLineLength, newLineLength) + 1;
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -10,13 +10,15 @@ export const CONFLICTS_RESOLUTION_VIEW_TYPE = "conflicts-resolution-view";
|
|||
const oldText1 = `# My Document
|
||||
This is a test
|
||||
Some content here
|
||||
Some line
|
||||
Another line
|
||||
Final line`;
|
||||
|
||||
const newText1 = `# My Document
|
||||
This is a modified test
|
||||
Some new content here
|
||||
Final line
|
||||
Added line`;
|
||||
Some line
|
||||
Final line`;
|
||||
|
||||
// Test Case 2: Markdown with formatting
|
||||
const oldText2 = `# Title
|
||||
|
|
|
|||
Loading…
Reference in a new issue