Skip to content

Commit 1c9b755

Browse files
committed
Adding Arrow button to revert a single block changes in cell
1 parent 249205b commit 1c9b755

File tree

2 files changed

+101
-9
lines changed

2 files changed

+101
-9
lines changed

src/diff/cell.ts

Lines changed: 92 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
import { python } from '@codemirror/lang-python';
2-
import { MergeView } from '@codemirror/merge';
3-
import { EditorView } from '@codemirror/view';
2+
import { MergeView, getChunks } from '@codemirror/merge';
3+
import {
4+
EditorView,
5+
Decoration,
6+
WidgetType,
7+
DecorationSet
8+
} from '@codemirror/view';
9+
import { StateEffect, StateField, RangeSetBuilder } from '@codemirror/state';
410
import { jupyterTheme } from '@jupyterlab/codemirror';
511
import { Message } from '@lumino/messaging';
612
import { Widget } from '@lumino/widgets';
@@ -52,37 +58,114 @@ class CodeMirrorSplitDiffWidget extends BaseDiffWidget {
5258
basicSetup,
5359
python(),
5460
EditorView.editable.of(false),
55-
jupyterTheme
61+
jupyterTheme,
62+
splitDiffDecorationField
5663
]
5764
},
5865
b: {
5966
doc: this._modifiedCode,
6067
extensions: [
6168
basicSetup,
6269
python(),
63-
EditorView.editable.of(false),
64-
jupyterTheme
70+
EditorView.editable.of(true),
71+
jupyterTheme,
72+
splitDiffDecorationField
6573
]
6674
},
67-
parent: this.node
75+
parent: this.node,
76+
gutter: true,
77+
highlightChanges: true
6878
});
79+
80+
this._renderMergeButtons();
6981
}
7082

7183
/**
72-
* Destroy the split view and clean up resources.
84+
* Render "merge change" buttons in the diff on left editor.
7385
*/
86+
private _renderMergeButtons(): void {
87+
const editorA = this._splitView.a;
88+
const editorB = this._splitView.b;
89+
90+
const result = getChunks(editorA.state);
91+
const chunks = result?.chunks;
92+
93+
if (!chunks || chunks.length === 0) {
94+
return;
95+
}
96+
97+
const builder = new RangeSetBuilder<Decoration>();
98+
99+
chunks.forEach((chunk: any) => {
100+
const { fromA, toA, fromB, toB } = chunk;
101+
102+
const arrowWidget = Decoration.widget({
103+
widget: new (class extends WidgetType {
104+
toDOM() {
105+
const btn = document.createElement('button');
106+
btn.textContent = '🡪';
107+
btn.className = 'jp-DiffMergeArrow';
108+
btn.onclick = () => {
109+
const origText = editorA.state.doc.sliceString(fromA, toA);
110+
111+
editorB.dispatch({
112+
changes: { from: fromB, to: toB, insert: origText }
113+
});
114+
editorA.dispatch({
115+
effects: addSplitDiffDecorations.of(
116+
editorA.state.field(splitDiffDecorationField).update({
117+
filter: (from, to, value) => from !== fromA
118+
})
119+
)
120+
});
121+
};
122+
return btn;
123+
}
124+
})(),
125+
side: 1
126+
});
127+
128+
builder.add(fromA, fromA, arrowWidget);
129+
});
130+
131+
editorA.dispatch({
132+
effects: addSplitDiffDecorations.of(builder.finish())
133+
});
134+
}
135+
74136
private _destroySplitView(): void {
75137
if (this._splitView) {
76138
this._splitView.destroy();
77-
this._splitView = null;
139+
this._splitView = null!;
78140
}
79141
}
80142

81143
private _originalCode: string;
82144
private _modifiedCode: string;
83-
private _splitView: MergeView | null = null;
145+
146+
private _splitView!: MergeView & {
147+
a: EditorView;
148+
b: EditorView;
149+
};
84150
}
85151

152+
const addSplitDiffDecorations = StateEffect.define<DecorationSet>();
153+
154+
const splitDiffDecorationField = StateField.define<DecorationSet>({
155+
create() {
156+
return Decoration.none;
157+
},
158+
update(deco, tr) {
159+
for (const ef of tr.effects) {
160+
if (ef.is(addSplitDiffDecorations)) {
161+
return ef.value;
162+
}
163+
}
164+
return deco.map(tr.changes);
165+
},
166+
provide: f => EditorView.decorations.from(f)
167+
});
168+
86169
export async function createCodeMirrorSplitDiffWidget(
87170
options: IDiffWidgetOptions
88171
): Promise<Widget> {

style/base.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,12 @@
7777
background-color: var(--jp-layout-color3);
7878
border-color: var(--jp-border-color1);
7979
}
80+
81+
.jp-DiffMergeArrow {
82+
padding: 2px 6px;
83+
border: none;
84+
background: none;
85+
font-size: 15px;
86+
cursor: pointer;
87+
margin-left: 4px;
88+
}

0 commit comments

Comments
 (0)