Skip to content

Commit 663966a

Browse files
feat(code): add hide whitespace changes toggle to diff viewer (#1385)
1 parent 83f6f64 commit 663966a

3 files changed

Lines changed: 39 additions & 1 deletion

File tree

apps/code/src/renderer/features/code-editor/components/CodeMirrorDiffEditor.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ export function CodeMirrorDiffEditor({
3232
const toggleLoadFullFiles = useDiffViewerStore((s) => s.toggleLoadFullFiles);
3333
const wordDiffs = useDiffViewerStore((s) => s.wordDiffs);
3434
const toggleWordDiffs = useDiffViewerStore((s) => s.toggleWordDiffs);
35+
const hideWhitespaceChanges = useDiffViewerStore(
36+
(s) => s.hideWhitespaceChanges,
37+
);
38+
const toggleHideWhitespaceChanges = useDiffViewerStore(
39+
(s) => s.toggleHideWhitespaceChanges,
40+
);
3541
const extensions = useEditorExtensions(filePath, !onContentChange, true);
3642
const options = useMemo(
3743
() => ({
@@ -41,6 +47,7 @@ export function CodeMirrorDiffEditor({
4147
mode: viewMode,
4248
loadFullFiles,
4349
wordDiffs,
50+
hideWhitespaceChanges,
4451
filePath,
4552
onContentChange,
4653
}),
@@ -51,6 +58,7 @@ export function CodeMirrorDiffEditor({
5158
viewMode,
5259
loadFullFiles,
5360
wordDiffs,
61+
hideWhitespaceChanges,
5462
filePath,
5563
onContentChange,
5664
],
@@ -127,6 +135,11 @@ export function CodeMirrorDiffEditor({
127135
{wordDiffs ? "Disable word diffs" : "Enable word diffs"}
128136
</Text>
129137
</DropdownMenu.Item>
138+
<DropdownMenu.Item onSelect={toggleHideWhitespaceChanges}>
139+
<Text size="1">
140+
{hideWhitespaceChanges ? "Show whitespace" : "Hide whitespace"}
141+
</Text>
142+
</DropdownMenu.Item>
130143

131144
{onRefresh && (
132145
<>

apps/code/src/renderer/features/code-editor/hooks/useCodeMirror.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
import { MergeView, unifiedMergeView } from "@codemirror/merge";
1+
import {
2+
diff as defaultDiff,
3+
MergeView,
4+
unifiedMergeView,
5+
} from "@codemirror/merge";
26
import { EditorState, type Extension } from "@codemirror/state";
37
import { EditorView } from "@codemirror/view";
48
import { workspaceApi } from "@features/workspace/hooks/useWorkspace";
@@ -24,6 +28,7 @@ interface DiffOptions extends UseCodeMirrorOptions {
2428
mode: "split" | "unified";
2529
loadFullFiles?: boolean;
2630
wordDiffs?: boolean;
31+
hideWhitespaceChanges?: boolean;
2732
onContentChange?: (content: string) => void;
2833
}
2934

@@ -62,15 +67,28 @@ const createMergeControls = (onReject?: () => void) => {
6267
};
6368
};
6469

70+
const whitespaceIgnoringDiff = (a: string, b: string) => {
71+
const changes = defaultDiff(a, b);
72+
return changes.filter((change) => {
73+
const textA = a.slice(change.fromA, change.toA);
74+
const textB = b.slice(change.fromB, change.toB);
75+
return textA.replace(/\s/g, "") !== textB.replace(/\s/g, "");
76+
});
77+
};
78+
6579
const collapseExtension = (loadFullFiles?: boolean): Extension =>
6680
loadFullFiles ? [] : gradualCollapseUnchanged({ margin: 3, minSize: 4 });
6781

6882
const getBaseDiffConfig = (
83+
hideWhitespaceChanges?: boolean,
6984
onReject?: () => void,
7085
): Partial<Parameters<typeof unifiedMergeView>[0]> => ({
7186
highlightChanges: false,
7287
gutter: true,
7388
mergeControls: createMergeControls(onReject),
89+
diffConfig: hideWhitespaceChanges
90+
? { override: whitespaceIgnoringDiff }
91+
: undefined,
7492
});
7593

7694
export function useCodeMirror(options: SingleDocOptions | DiffOptions) {
@@ -93,6 +111,7 @@ export function useCodeMirror(options: SingleDocOptions | DiffOptions) {
93111
});
94112
} else if (options.mode === "split") {
95113
const diffConfig = getBaseDiffConfig(
114+
options.hideWhitespaceChanges,
96115
options.onContentChange
97116
? () => {
98117
if (instanceRef.current instanceof MergeView) {
@@ -143,6 +162,7 @@ export function useCodeMirror(options: SingleDocOptions | DiffOptions) {
143162
});
144163
} else {
145164
const diffConfig = getBaseDiffConfig(
165+
options.hideWhitespaceChanges,
146166
options.onContentChange
147167
? () => {
148168
if (instanceRef.current instanceof EditorView) {

apps/code/src/renderer/features/code-editor/stores/diffViewerStore.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ interface DiffViewerStoreState {
88
wordWrap: boolean;
99
loadFullFiles: boolean;
1010
wordDiffs: boolean;
11+
hideWhitespaceChanges: boolean;
1112
}
1213

1314
interface DiffViewerStoreActions {
@@ -16,6 +17,7 @@ interface DiffViewerStoreActions {
1617
toggleWordWrap: () => void;
1718
toggleLoadFullFiles: () => void;
1819
toggleWordDiffs: () => void;
20+
toggleHideWhitespaceChanges: () => void;
1921
}
2022

2123
type DiffViewerStore = DiffViewerStoreState & DiffViewerStoreActions;
@@ -27,6 +29,7 @@ export const useDiffViewerStore = create<DiffViewerStore>()(
2729
wordWrap: true,
2830
loadFullFiles: false,
2931
wordDiffs: false,
32+
hideWhitespaceChanges: false,
3033
setViewMode: (mode) => set({ viewMode: mode }),
3134
toggleViewMode: () =>
3235
set((s) => ({
@@ -36,6 +39,8 @@ export const useDiffViewerStore = create<DiffViewerStore>()(
3639
toggleLoadFullFiles: () =>
3740
set((s) => ({ loadFullFiles: !s.loadFullFiles })),
3841
toggleWordDiffs: () => set((s) => ({ wordDiffs: !s.wordDiffs })),
42+
toggleHideWhitespaceChanges: () =>
43+
set((s) => ({ hideWhitespaceChanges: !s.hideWhitespaceChanges })),
3944
}),
4045
{
4146
name: "diff-viewer-storage",

0 commit comments

Comments
 (0)