Skip to content

Commit 981a916

Browse files
wip
1 parent b4b92c2 commit 981a916

File tree

20 files changed

+431
-57
lines changed

20 files changed

+431
-57
lines changed

packages/core/src/diff-file.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1411,6 +1411,7 @@ export class DiffFile {
14111411
return this.#newFileSyntaxLines?.[lineNumber];
14121412
};
14131413

1414+
// TODO improve
14141415
subscribe = (listener: (() => void) & { isSyncExternal?: boolean }) => {
14151416
this.#listeners.push(listener);
14161417

@@ -1578,7 +1579,7 @@ export class DiffFile {
15781579
}
15791580
};
15801581

1581-
_getHighlighterName = () => this.#highlighterName;
1582+
_getHighlighterName = () => this.#highlighterName || '';
15821583

15831584
_getIsPureDiffRender = () => this.#composeByDiff;
15841585

packages/core/src/parse/change-range.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ function checkNewLineSymbolChange(
9393

9494
const hasNewLineChanged = addition.noTrailingNewLine !== deletion.noTrailingNewLine;
9595

96-
if (aSymbol === bSymbol) {
96+
if (aSymbol === bSymbol && !hasNewLineChanged) {
9797
return { addSymbol: undefined, addString: stringA, delSymbol: undefined, delString: stringB };
9898
}
9999

packages/react/src/components/DiffView.tsx

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* eslint-disable @typescript-eslint/no-unnecessary-type-constraint */
22
/* eslint-disable @typescript-eslint/ban-ts-comment */
33
import { DiffFile, _cacheMap, SplitSide } from "@git-diff-view/core";
4-
import { diffFontSizeName } from "@git-diff-view/utils";
4+
import { diffFontSizeName, DiffModeEnum } from "@git-diff-view/utils";
55
import { memo, useEffect, useMemo, forwardRef, useImperativeHandle, useRef } from "react";
66
import * as React from "react";
77

@@ -20,16 +20,7 @@ import type { CSSProperties, ForwardedRef, ReactNode } from "react";
2020

2121
_cacheMap.name = "@git-diff-view/react";
2222

23-
export { SplitSide };
24-
25-
export enum DiffModeEnum {
26-
// github like
27-
SplitGitHub = 1,
28-
// gitlab like
29-
SplitGitLab = 2,
30-
Split = 1 | 2,
31-
Unified = 4,
32-
}
23+
export { SplitSide, DiffModeEnum };
3324

3425
export type DiffViewProps<T> = {
3526
data?: {

packages/solid/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@
4343
"@types/hast": "^3.0.0",
4444
"highlight.js": "^11.11.0",
4545
"lowlight": "^3.3.0",
46-
"fast-diff": "^1.3.0"
46+
"fast-diff": "^1.3.0",
47+
"reactivity-store": "^0.3.11"
4748
},
4849
"devDependencies": {
4950
"solid-js": "^1.9.0",

packages/solid/src/components/DiffContent.tsx

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import {
1515
getSymbol,
1616
NewLineSymbol,
1717
} from "@git-diff-view/utils";
18-
import { createEffect, For, Show } from "solid-js";
18+
import { createMemo, For, Show } from "solid-js";
1919

2020
import { DiffNoNewLine } from "./DiffNoNewLine";
2121

@@ -59,9 +59,7 @@ const DiffString = (props: {
5959
};
6060

6161
// eslint-disable-next-line solid/reactivity
62-
initTemplateIfNeed();
63-
64-
createEffect(initTemplateIfNeed);
62+
createMemo(initTemplateIfNeed);
6563

6664
return (
6765
<Show
@@ -174,9 +172,7 @@ const DiffSyntax = (props: {
174172
};
175173

176174
// eslint-disable-next-line solid/reactivity
177-
initTemplateIfNeed();
178-
179-
createEffect(initTemplateIfNeed);
175+
createMemo(initTemplateIfNeed);
180176

181177
return (
182178
<Show
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { Show } from "solid-js";
2+
3+
import { useEnableWrap } from "../hooks";
4+
5+
import { DiffSplitViewNormal } from "./DiffSplitViewNormal";
6+
import { DiffSplitViewWrap } from "./DiffSplitViewWrap";
7+
8+
import type { DiffFile } from "@git-diff-view/core";
9+
10+
export const DiffSplitView = (props: { diffFile: DiffFile }) => {
11+
const enableWrap = useEnableWrap();
12+
13+
return (
14+
<Show when={enableWrap()} fallback={<DiffSplitViewNormal diffFile={props.diffFile} />}>
15+
<DiffSplitViewWrap diffFile={props.diffFile} />
16+
</Show>
17+
);
18+
};
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import type { DiffFile } from "@git-diff-view/core";
2+
3+
export const DiffSplitViewNormal = (props: { diffFile: DiffFile }) => {
4+
return <div>12</div>;
5+
};
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { getSplitContentLines, type DiffFile } from "@git-diff-view/core";
2+
import { createSignal } from "solid-js";
3+
4+
export const DiffSplitViewWrap = (props: { diffFile: DiffFile }) => {
5+
const [] = createSignal(getSplitContentLines(props.diffFile));
6+
7+
const [] = createSignal(props.diffFile.splitLineLength.toString());
8+
9+
10+
11+
return <div>12</div>;
12+
};
File renamed without changes.

packages/solid/src/components/DiffView.tsx

Lines changed: 188 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,26 @@
1-
import { DiffFile } from "@git-diff-view/core";
2-
import { type JSXElement, type JSX, createSignal, createRenderEffect } from "solid-js";
1+
/* eslint-disable @typescript-eslint/no-unnecessary-type-constraint */
2+
import { _cacheMap, DiffFile, SplitSide } from "@git-diff-view/core";
3+
import { diffFontSizeName, DiffModeEnum } from "@git-diff-view/utils";
4+
import { type JSXElement, type JSX, createSignal, createEffect, createMemo, onCleanup } from "solid-js";
5+
6+
import { DiffViewContext } from "./DiffViewContext";
7+
import { DiffWidgetContext } from "./DiffWidgetContext";
8+
import { createDiffConfigStore } from "./tools";
39

410
import type { DiffHighlighter, DiffHighlighterLang } from "@git-diff-view/core";
511

6-
export enum DiffModeEnum {
7-
// github like
8-
SplitGitHub = 1,
9-
// gitlab like
10-
SplitGitLab = 2,
11-
Split = 1 | 2,
12-
Unified = 4,
13-
}
12+
_cacheMap.name = "@git-diff-view/solid";
13+
14+
export { SplitSide, DiffModeEnum };
1415

1516
export type DiffViewProps<T> = {
1617
data?: {
1718
oldFile?: { fileName?: string | null; fileLang?: DiffHighlighterLang | string | null; content?: string | null };
1819
newFile?: { fileName?: string | null; fileLang?: DiffHighlighterLang | string | null; content?: string | null };
1920
hunks: string[];
2021
};
21-
extendData?: { oldFile?: Record<string, { data: T }>; newFile?: Record<string, { data: T }> };
22+
extendData?: { oldFile?: Record<string, { data: T } | undefined>; newFile?: Record<string, { data: T } | undefined> };
23+
initialWidgetState?: { side: SplitSide; lineNumber: number };
2224
diffFile?: DiffFile;
2325
class?: string;
2426
style?: JSX.CSSProperties;
@@ -56,15 +58,30 @@ export type DiffViewProps<T> = {
5658
onAddWidgetClick?: (lineNumber: number, side: SplitSide) => void;
5759
};
5860

59-
export const DiffView = <T extends unknown>(props: DiffViewProps<T>) => {
61+
type DiffViewProps_1<T> = Omit<DiffViewProps<T>, "data"> & {
62+
data?: {
63+
oldFile?: { fileName?: string | null; fileLang?: DiffHighlighterLang | null; content?: string | null };
64+
newFile?: { fileName?: string | null; fileLang?: DiffHighlighterLang | null; content?: string | null };
65+
hunks: string[];
66+
};
67+
};
68+
69+
type DiffViewProps_2<T> = Omit<DiffViewProps<T>, "data"> & {
70+
data?: {
71+
oldFile?: { fileName?: string | null; fileLang?: string | null; content?: string | null };
72+
newFile?: { fileName?: string | null; fileLang?: string | null; content?: string | null };
73+
hunks: string[];
74+
};
75+
};
76+
77+
const InternalDiffView = <T extends unknown>(props: DiffViewProps<T>) => {
6078
const getInstance = () => {
79+
let diffFile: DiffFile | null = null;
6180
if (props.diffFile) {
62-
const diffFile = DiffFile.createInstance({});
81+
diffFile = DiffFile.createInstance({});
6382
diffFile._mergeFullBundle(props.diffFile._getFullBundle());
64-
return diffFile;
65-
}
66-
if (props.data)
67-
return new DiffFile(
83+
} else if (props.data) {
84+
diffFile = new DiffFile(
6885
props.data.oldFile?.fileName || "",
6986
props.data.oldFile?.content || "",
7087
props.data.newFile?.fileName || "",
@@ -73,16 +90,164 @@ export const DiffView = <T extends unknown>(props: DiffViewProps<T>) => {
7390
props.data.oldFile?.fileLang || "",
7491
props.data.newFile?.fileLang || ""
7592
);
76-
return null;
93+
}
94+
95+
onCleanup(() => diffFile?.clear?.());
96+
97+
return diffFile;
7798
};
7899

79-
const [diffFile, setDiffFile] = createSignal(getInstance());
100+
let wrapperRef: HTMLDivElement | undefined;
101+
102+
const diffFile = createMemo(getInstance);
103+
104+
const [isMounted, setIsMounted] = createSignal(false);
105+
106+
createEffect(() => {
107+
setIsMounted(true);
108+
});
109+
110+
const [widgetState, setWidgetState] = createSignal<{ side?: SplitSide; lineNumber?: number }>({
111+
side: props.initialWidgetState?.side,
112+
lineNumber: props.initialWidgetState?.lineNumber,
113+
});
114+
115+
const reactiveHook = createDiffConfigStore(props, diffFile()?.getId() || "");
116+
117+
createEffect(() => {
118+
const {
119+
setId,
120+
setEnableAddWidget,
121+
setEnableHighlight,
122+
setEnableWrap,
123+
setExtendData,
124+
setFontSize,
125+
setIsIsMounted,
126+
setMode,
127+
setOnAddWidgetClick,
128+
setRenderExtendLine,
129+
setRenderWidgetLine,
130+
} = reactiveHook.getReadonlyState();
131+
const currentDiffFile = diffFile();
132+
133+
setId(currentDiffFile?.getId() || "");
134+
135+
setEnableAddWidget(!!props.diffViewAddWidget);
136+
137+
setEnableHighlight(!!props.diffViewHighlight);
138+
139+
setEnableWrap(!!props.diffViewWrap);
80140

81-
createRenderEffect(() => {
82-
diffFile()?.clear();
141+
setFontSize(props.diffViewFontSize || 14);
83142

84-
setDiffFile(getInstance());
143+
setIsIsMounted(isMounted());
144+
145+
setMode(props.diffViewMode || DiffModeEnum.Split);
146+
147+
setOnAddWidgetClick({ current: props.onAddWidgetClick });
148+
149+
setRenderExtendLine(props.renderExtendLine);
150+
151+
setRenderWidgetLine(props.renderWidgetLine);
152+
153+
setExtendData(props.extendData);
154+
});
155+
156+
createEffect(() => {
157+
if (props.initialWidgetState) {
158+
setWidgetState({
159+
side: props.initialWidgetState.side,
160+
lineNumber: props.initialWidgetState.lineNumber,
161+
});
162+
}
85163
});
86164

87-
return <div>DiffView</div>;
165+
const initSubscribe = () => {
166+
const mounted = isMounted();
167+
const currentDiffFile = diffFile();
168+
if (mounted && props.diffFile && currentDiffFile) {
169+
props.diffFile._addClonedInstance(currentDiffFile);
170+
onCleanup(() => props.diffFile?._delClonedInstance(currentDiffFile));
171+
}
172+
};
173+
174+
const initDiff = () => {
175+
const mounted = isMounted();
176+
const currentDiffFile = diffFile();
177+
if (mounted && currentDiffFile) {
178+
currentDiffFile.initTheme(props.diffViewTheme);
179+
currentDiffFile.initRaw();
180+
currentDiffFile.buildSplitDiffLines();
181+
currentDiffFile.buildUnifiedDiffLines();
182+
}
183+
};
184+
185+
const initSyntax = () => {
186+
const mounted = isMounted();
187+
const currentDiffFile = diffFile();
188+
if (mounted && currentDiffFile && props.diffViewHighlight) {
189+
currentDiffFile.initSyntax({ registerHighlighter: props.registerHighlighter });
190+
currentDiffFile.notifyAll();
191+
}
192+
};
193+
194+
const initAttribute = () => {
195+
const mounted = isMounted();
196+
const currentDiffFile = diffFile();
197+
if (mounted && currentDiffFile && wrapperRef) {
198+
const cb = currentDiffFile.subscribe(() => {
199+
wrapperRef?.setAttribute("data-theme", currentDiffFile._getTheme() || "light");
200+
wrapperRef?.setAttribute("data-highlighter", currentDiffFile._getHighlighterName());
201+
});
202+
203+
onCleanup(() => cb());
204+
}
205+
};
206+
207+
createEffect(initSubscribe);
208+
209+
createEffect(initDiff);
210+
211+
createEffect(initSyntax);
212+
213+
createEffect(initAttribute);
214+
215+
onCleanup(() => reactiveHook.clear());
216+
217+
return (
218+
<div
219+
class="diff-tailwindcss-wrapper"
220+
data-component="git-diff-view"
221+
data-theme={diffFile()?._getTheme?.() || "light"}
222+
data-version={__VERSION__}
223+
data-highlighter={diffFile()?._getHighlighterName?.()}
224+
ref={wrapperRef}
225+
>
226+
<DiffViewContext.Provider value={reactiveHook}>
227+
<DiffWidgetContext.Provider value={widgetState}>
228+
<div class="diff-style-root" style={{ [diffFontSizeName]: (props.diffViewFontSize || 14) + "px" }}>
229+
<div
230+
id={isMounted() ? `diff-root${diffFile()?.getId()}` : undefined}
231+
class={"diff-view-wrapper" + (props.class ? ` ${props.class}` : "")}
232+
style={props.style}
233+
>
234+
{/* {!props.diffViewMode || props.diffViewMode & DiffModeEnum.Split ? (
235+
<DiffSplitView key={DiffModeEnum.Split} diffFile={diffFile.value as DiffFile} />
236+
) : (
237+
<DiffUnifiedView key={DiffModeEnum.Unified} diffFile={diffFile.value as DiffFile} />
238+
)} */}
239+
</div>
240+
</div>
241+
</DiffWidgetContext.Provider>
242+
</DiffViewContext.Provider>
243+
</div>
244+
);
88245
};
246+
247+
function SolidDiffView<T>(props: DiffViewProps_1<T>): JSXElement;
248+
function SolidDiffView<T>(props: DiffViewProps_2<T>): JSXElement;
249+
function SolidDiffView<T>(props: DiffViewProps<T>): JSXElement {
250+
return <InternalDiffView {...props} />;
251+
}
252+
253+
export const DiffView = SolidDiffView;

0 commit comments

Comments
 (0)