mirror of
https://github.com/silvanocerza/github-gitless-sync.git
synced 2026-07-22 12:10:28 +00:00
Adjust some stuff
This commit is contained in:
parent
132ffff36e
commit
08d5d05331
1 changed files with 69 additions and 190 deletions
|
|
@ -1,23 +1,7 @@
|
|||
import * as React from "react";
|
||||
import CodeMirror, {
|
||||
EditorState,
|
||||
RangeSetBuilder,
|
||||
StateEffect,
|
||||
StateField,
|
||||
} from "@uiw/react-codemirror";
|
||||
import { unifiedMergeView } from "@codemirror/merge";
|
||||
import {
|
||||
Decoration,
|
||||
DecorationSet,
|
||||
EditorView,
|
||||
GutterMarker,
|
||||
keymap,
|
||||
ViewPlugin,
|
||||
ViewUpdate,
|
||||
WidgetType,
|
||||
} from "@codemirror/view";
|
||||
import { ChangeSet, Prec, RangeSet, Text } from "@codemirror/state";
|
||||
import { markdown } from "@codemirror/lang-markdown";
|
||||
import CodeMirror, { RangeSetBuilder, StateField } from "@uiw/react-codemirror";
|
||||
import { Decoration, EditorView } from "@codemirror/view";
|
||||
|
||||
import diff, { DiffChunk } from "./diff";
|
||||
|
||||
const styles = document.createElement("style");
|
||||
|
|
@ -170,152 +154,21 @@ const createUnifiedDocument = (
|
|||
return { doc: result.join("\n"), mapping: lineMappings };
|
||||
};
|
||||
|
||||
const getLineDecoration = (mapping: LineMapping) => {
|
||||
if (mapping.oldLine !== null && mapping.newLine !== null) {
|
||||
// No decoration for this case
|
||||
return null;
|
||||
}
|
||||
|
||||
if (mapping.oldLine === null) {
|
||||
// The line comes from the new document, it's an addition
|
||||
return Decoration.line({ class: "cm-addedLine" });
|
||||
} else if (mapping.newLine === null) {
|
||||
// The line comes from the old document, it's a deletion
|
||||
return Decoration.line({ class: "cm-deletedLine" });
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
function findMappingsRanges(mappings: LineMapping[]): number[][] {
|
||||
const ranges: number[][] = [];
|
||||
let currentRange: number[] | null = null;
|
||||
|
||||
for (const mapping of mappings) {
|
||||
// If either oldLine or newLine is null
|
||||
if (mapping.oldLine === null || mapping.newLine === null) {
|
||||
if (!currentRange) {
|
||||
currentRange = [mapping.finalLine, mapping.finalLine];
|
||||
} else {
|
||||
currentRange[1] = mapping.finalLine;
|
||||
}
|
||||
} else if (currentRange) {
|
||||
ranges.push(currentRange);
|
||||
currentRange = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentRange) {
|
||||
ranges.push(currentRange);
|
||||
}
|
||||
|
||||
// Return the first range found
|
||||
return ranges;
|
||||
}
|
||||
|
||||
const buildDecorations = (mappings: LineMapping[]) => {
|
||||
return ViewPlugin.fromClass(
|
||||
class {
|
||||
decorations: DecorationSet;
|
||||
mappings: LineMapping[];
|
||||
|
||||
constructor(view: EditorView) {
|
||||
this.mappings = mappings;
|
||||
this.decorations = this.buildDecorations(view);
|
||||
}
|
||||
|
||||
update(update: ViewUpdate) {
|
||||
if (!update.docChanged) {
|
||||
// Ignore non text changes
|
||||
return;
|
||||
}
|
||||
// console.log("Previous selection\n", update.startState.selection);
|
||||
// console.log("Current selection\n", update.state.selection);
|
||||
const ranges = findMappingsRanges(this.mappings);
|
||||
const affectedRanges = ranges.filter((range) => {
|
||||
return (
|
||||
update.changes.touchesRange(
|
||||
update.startState.doc.line(range[0]).from,
|
||||
update.startState.doc.line(range[1]).to,
|
||||
) !== false
|
||||
);
|
||||
});
|
||||
console.log(affectedRanges);
|
||||
// update.changes.touchesRange(from);
|
||||
|
||||
update.changes.iterChanges(
|
||||
(
|
||||
fromA: number,
|
||||
toA: number,
|
||||
fromB: number,
|
||||
toB: number,
|
||||
inserted: Text,
|
||||
) => {
|
||||
// update.startState.doc.lineAt(fromA);
|
||||
// update.startState.doc.lineAt(toA);
|
||||
// console.log("fromA", fromA);
|
||||
// console.log("toA", toA);
|
||||
// console.log("fromB", fromB);
|
||||
// console.log("toB", toB);
|
||||
// console.log("inserted", inserted);
|
||||
},
|
||||
);
|
||||
this.decorations = this.buildDecorations(update.view);
|
||||
}
|
||||
|
||||
buildDecorations(view: EditorView): DecorationSet {
|
||||
const decorations = [];
|
||||
const doc = view.state.doc;
|
||||
for (let lineNumber = 1; lineNumber <= doc.lines; lineNumber++) {
|
||||
const mapping = this.mappings.find((m) => m.finalLine === lineNumber);
|
||||
if (!mapping) {
|
||||
// Unlikely
|
||||
continue;
|
||||
}
|
||||
const deco = getLineDecoration(mapping);
|
||||
if (deco) {
|
||||
const line = doc.line(lineNumber);
|
||||
decorations.push(deco.range(line.from));
|
||||
}
|
||||
}
|
||||
return Decoration.set(decorations, true);
|
||||
}
|
||||
},
|
||||
{ decorations: (v) => v.decorations },
|
||||
);
|
||||
};
|
||||
|
||||
interface ConflictRange {
|
||||
from: number;
|
||||
to: number;
|
||||
source: "old" | "new" | "both"; // where the content originated
|
||||
}
|
||||
|
||||
const UnifiedDiffView: React.FC<UnifiedDiffViewProps> = ({
|
||||
initialOldText,
|
||||
initialNewText,
|
||||
onConflictResolved,
|
||||
}) => {
|
||||
const diffChunks = diff(initialOldText, initialNewText);
|
||||
const { doc: unified, mapping } = createUnifiedDocument(
|
||||
initialOldText,
|
||||
initialNewText,
|
||||
diffChunks,
|
||||
);
|
||||
|
||||
const unifiedLines = unified.split("\n");
|
||||
|
||||
const initialRanges: ConflictRange[] = mapping.map((m) => {
|
||||
const createInitialRanges = (
|
||||
doc: string,
|
||||
mappings: LineMapping[],
|
||||
): ConflictRange[] => {
|
||||
const lines = doc.split("\n");
|
||||
return mappings.map((m) => {
|
||||
// Calculate line positions directly from text
|
||||
const lineStartPos = unifiedLines
|
||||
.slice(0, m.finalLine - 1)
|
||||
.join("\n").length;
|
||||
const lineStartPos = lines.slice(0, m.finalLine - 1).join("\n").length;
|
||||
// Add 1 for the newline except for first line
|
||||
const fromPos = m.finalLine > 1 ? lineStartPos + 1 : 0;
|
||||
const toPos = fromPos + unifiedLines[m.finalLine - 1].length;
|
||||
const from = m.finalLine > 1 ? lineStartPos + 1 : 0;
|
||||
const to = from + lines[m.finalLine - 1].length;
|
||||
|
||||
return {
|
||||
from: fromPos,
|
||||
to: toPos,
|
||||
from,
|
||||
to,
|
||||
source:
|
||||
m.oldLine !== null && m.newLine !== null
|
||||
? "both"
|
||||
|
|
@ -324,8 +177,12 @@ const UnifiedDiffView: React.FC<UnifiedDiffViewProps> = ({
|
|||
: "new",
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const conflictRangesField = StateField.define<ConflictRange[]>({
|
||||
const createRangesStateField = (
|
||||
initialRanges: ConflictRange[],
|
||||
): StateField<ConflictRange[]> => {
|
||||
return StateField.define<ConflictRange[]>({
|
||||
create: () => initialRanges,
|
||||
update: (ranges, tr) => {
|
||||
if (!tr.docChanged) {
|
||||
|
|
@ -348,41 +205,64 @@ const UnifiedDiffView: React.FC<UnifiedDiffViewProps> = ({
|
|||
return newRanges;
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const buildDecorationsAlternate = EditorView.decorations.compute(
|
||||
["doc", conflictRangesField],
|
||||
(state) => {
|
||||
const ranges = state.field(conflictRangesField);
|
||||
const builder = new RangeSetBuilder<Decoration>();
|
||||
const createDecorationsExtension = (
|
||||
rangesStateField: StateField<ConflictRange[]>,
|
||||
) => {
|
||||
return EditorView.decorations.compute(["doc", rangesStateField], (state) => {
|
||||
const ranges = state.field(rangesStateField);
|
||||
const builder = new RangeSetBuilder<Decoration>();
|
||||
|
||||
for (const range of ranges) {
|
||||
const startLine = state.doc.lineAt(range.from);
|
||||
const endLine = state.doc.lineAt(range.to);
|
||||
for (let i = 0; i <= endLine.number - startLine.number; i += 1) {
|
||||
const line = state.doc.line(startLine.number + i);
|
||||
if (range.source === "old") {
|
||||
builder.add(
|
||||
line.from,
|
||||
line.from,
|
||||
Decoration.line({ class: "cm-deletedLine" }),
|
||||
);
|
||||
} else if (range.source === "new") {
|
||||
builder.add(
|
||||
line.from,
|
||||
line.from,
|
||||
Decoration.line({ class: "cm-addedLine" }),
|
||||
);
|
||||
}
|
||||
for (const range of ranges) {
|
||||
const startLine = state.doc.lineAt(range.from);
|
||||
const endLine = state.doc.lineAt(range.to);
|
||||
for (let i = 0; i <= endLine.number - startLine.number; i += 1) {
|
||||
const line = state.doc.line(startLine.number + i);
|
||||
if (range.source === "old") {
|
||||
builder.add(
|
||||
line.from,
|
||||
line.from,
|
||||
Decoration.line({ class: "cm-deletedLine" }),
|
||||
);
|
||||
} else if (range.source === "new") {
|
||||
builder.add(
|
||||
line.from,
|
||||
line.from,
|
||||
Decoration.line({ class: "cm-addedLine" }),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return builder.finish();
|
||||
},
|
||||
return builder.finish();
|
||||
});
|
||||
};
|
||||
|
||||
interface ConflictRange {
|
||||
from: number;
|
||||
to: number;
|
||||
source: "old" | "new" | "both"; // where the content originated
|
||||
}
|
||||
|
||||
const UnifiedDiffView: React.FC<UnifiedDiffViewProps> = ({
|
||||
initialOldText,
|
||||
initialNewText,
|
||||
onConflictResolved,
|
||||
}) => {
|
||||
const diffChunks = diff(initialOldText, initialNewText);
|
||||
const { doc, mapping } = createUnifiedDocument(
|
||||
initialOldText,
|
||||
initialNewText,
|
||||
diffChunks,
|
||||
);
|
||||
|
||||
const initialRanges = createInitialRanges(doc, mapping);
|
||||
const conflictRangesField = createRangesStateField(initialRanges);
|
||||
|
||||
const extensions = [
|
||||
conflictRangesField,
|
||||
buildDecorationsAlternate,
|
||||
createDecorationsExtension(conflictRangesField),
|
||||
EditorView.editable.of(true),
|
||||
EditorView.theme({
|
||||
"&": {
|
||||
|
|
@ -410,8 +290,7 @@ const UnifiedDiffView: React.FC<UnifiedDiffViewProps> = ({
|
|||
return (
|
||||
<div style={{ width: "100%", height: "100%", overflow: "hidden" }}>
|
||||
<CodeMirror
|
||||
// value={newText}
|
||||
value={unified}
|
||||
value={doc}
|
||||
height="100%"
|
||||
theme="none"
|
||||
basicSetup={false}
|
||||
|
|
|
|||
Loading…
Reference in a new issue