Skip to content

Commit bf80a2c

Browse files
authored
Merge pull request #6 from jtpio/codemirror-merge
Allow diffing with `@codemirror/merge`
2 parents b80878c + 900fc52 commit bf80a2c

File tree

13 files changed

+1082
-520
lines changed

13 files changed

+1082
-520
lines changed

.prettierignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ node_modules
44
**/package.json
55
!/package.json
66
jupyterlab_cell_diff
7+
.venv

README.md

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,66 @@
1-
# JupyterLab Plugin: Show a Cell Diff
1+
# jupyterlab-cell-diff
22

33
[![Github Actions Status](https://github.com/jupyter-ai-contrib/jupyterlab-cell-diff/workflows/Build/badge.svg)](https://github.com/jupyter-ai-contrib/jupyterlab-cell-diff/actions/workflows/build.yml)
44

5-
A JupyterLab Extension for showing cell (git) diffs.
6-
7-
This extension is composed of a Python package named `jupyterlab_cell_diff`
8-
for the server extension and a NPM package named `jupyterlab-cell-diff`
9-
for the frontend extension.
5+
A JupyterLab extension for showing cell diffs with multiple diffing strategies.
106

117
## Requirements
128

139
- JupyterLab >= 4.0.0
1410

15-
## Install
11+
## Installation
1612

17-
To install the extension, execute:
13+
### PyPI Installation
1814

1915
```bash
2016
pip install jupyterlab_cell_diff
2117
```
2218

19+
### Development Installation
20+
21+
```bash
22+
# Clone the repository
23+
git clone https://github.com/jupyter-ai-contrib/jupyterlab-cell-diff.git
24+
cd jupyterlab-cell-diff
25+
26+
# Install the extension in development mode
27+
pip install -e .
28+
jupyter labextension develop . --overwrite
29+
```
30+
31+
## Usage
32+
33+
### Commands
34+
35+
The extension provides several commands:
36+
37+
- `jupyterlab-cell-diff:show-codemirror` - Show diff using `@codemirror/merge`
38+
- `jupyterlab-cell-diff:show-nbdime` - Show diff using NBDime
39+
40+
### Use with `@codemirror/merge`
41+
42+
https://github.com/user-attachments/assets/0dacd7f0-5963-4ebe-81da-2958f0117071
43+
44+
### Use with NBDime
45+
46+
https://github.com/user-attachments/assets/87e93eab-ad67-468c-b228-f5a0e93f8bea
47+
48+
### Programmatic Usage
49+
50+
```typescript
51+
app.commands.execute('jupyterlab-cell-diff:show-codemirror', {
52+
cellId: 'cell-id',
53+
originalSource: 'print("Hello")',
54+
newSource: 'print("Hello, World!")'
55+
});
56+
57+
app.commands.execute('jupyterlab-cell-diff:show-nbdime', {
58+
cellId: 'cell-id',
59+
originalSource: 'print("Hello")',
60+
newSource: 'print("Hello, World!")'
61+
});
62+
```
63+
2364
## Uninstall
2465

2566
To remove the extension, execute:

package.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
"files": [
2020
"lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}",
2121
"style/**/*.{css,js,eot,gif,html,jpg,json,png,svg,woff2,ttf}",
22-
"src/**/*.{ts,tsx}"
22+
"src/**/*.{ts,tsx}",
23+
"schema/*.json"
2324
],
2425
"main": "lib/index.js",
2526
"types": "lib/index.d.ts",
@@ -55,14 +56,19 @@
5556
"watch:labextension": "jupyter labextension watch ."
5657
},
5758
"dependencies": {
59+
"@codemirror/lang-python": "^6.2.1",
60+
"@codemirror/merge": "^6.10.2",
61+
"@codemirror/view": "^6.38.2",
5862
"@jupyterlab/application": "^4.0.0",
5963
"@jupyterlab/cells": "^4.0.0",
6064
"@jupyterlab/codeeditor": "^4.0.0",
65+
"@jupyterlab/codemirror": "^4.4.7",
6166
"@jupyterlab/coreutils": "^6.0.0",
6267
"@jupyterlab/notebook": "^4.0.0",
6368
"@jupyterlab/services": "^7.0.0",
6469
"@jupyterlab/ui-components": "^4.0.0",
6570
"@lumino/widgets": "^2.0.0",
71+
"codemirror": "^6.0.2",
6672
"jupyterlab-cell-input-footer": "^0.3.0",
6773
"nbdime": "^7.0.1"
6874
},

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ classifiers = [
2525
dependencies = [
2626
"nbdime",
2727
"jupyter_server>=2.4.0,<3",
28-
"jupyterlab-eventlistener>=0.4.0",
29-
"jupyterlab-cell-input-footer>=0.2.0"
28+
"jupyterlab-eventlistener>=0.4.0,<0.5",
29+
"jupyterlab-cell-input-footer>=0.3.1,<0.4"
3030
]
3131
dynamic = ["version", "description", "authors", "urls", "keywords"]
3232

src/command.ts

Lines changed: 0 additions & 97 deletions
This file was deleted.

src/diff/codemirror.ts

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import { python } from '@codemirror/lang-python';
2+
import { MergeView } from '@codemirror/merge';
3+
import { EditorView } from '@codemirror/view';
4+
import { jupyterTheme } from '@jupyterlab/codemirror';
5+
import { Message } from '@lumino/messaging';
6+
import { Widget } from '@lumino/widgets';
7+
import { basicSetup } from 'codemirror';
8+
import { IDiffWidgetOptions, BaseDiffWidget } from '../widget';
9+
10+
/**
11+
* A Lumino widget that contains a CodeMirror diff view
12+
*/
13+
class CodeMirrorDiffWidget extends BaseDiffWidget {
14+
/**
15+
* Construct a new CodeMirrorDiffWidget.
16+
*/
17+
constructor(options: IDiffWidgetOptions) {
18+
super(options);
19+
this._originalCode = options.originalSource;
20+
this._modifiedCode = options.newSource;
21+
this.addClass('jp-DiffView');
22+
}
23+
24+
/**
25+
* Handle after-attach messages for the widget.
26+
*/
27+
protected onAfterAttach(msg: Message): void {
28+
super.onAfterAttach(msg);
29+
this._createMergeView();
30+
}
31+
32+
/**
33+
* Handle before-detach messages for the widget.
34+
*/
35+
protected onBeforeDetach(msg: Message): void {
36+
this._destroyMergeView();
37+
super.onBeforeDetach(msg);
38+
}
39+
40+
/**
41+
* Create the merge view with CodeMirror diff functionality.
42+
*/
43+
private _createMergeView(): void {
44+
if (this._mergeView) {
45+
return;
46+
}
47+
48+
this._mergeView = new MergeView({
49+
a: {
50+
doc: this._originalCode,
51+
extensions: [
52+
basicSetup,
53+
python(),
54+
EditorView.editable.of(false),
55+
jupyterTheme
56+
]
57+
},
58+
b: {
59+
doc: this._modifiedCode,
60+
extensions: [
61+
basicSetup,
62+
python(),
63+
EditorView.editable.of(false),
64+
jupyterTheme
65+
]
66+
},
67+
parent: this.node
68+
});
69+
}
70+
71+
/**
72+
* Destroy the merge view and clean up resources.
73+
*/
74+
private _destroyMergeView(): void {
75+
if (this._mergeView) {
76+
this._mergeView.destroy();
77+
this._mergeView = null;
78+
}
79+
}
80+
81+
private _originalCode: string;
82+
private _modifiedCode: string;
83+
private _mergeView: MergeView | null = null;
84+
}
85+
86+
export async function createCodeMirrorDiffWidget(
87+
options: IDiffWidgetOptions
88+
): Promise<Widget> {
89+
const {
90+
cell,
91+
cellFooterTracker,
92+
originalSource,
93+
newSource,
94+
showActionButtons = true,
95+
openDiff = true
96+
} = options;
97+
98+
const diffWidget = new CodeMirrorDiffWidget({
99+
originalSource,
100+
newSource,
101+
cell,
102+
cellFooterTracker,
103+
showActionButtons,
104+
openDiff
105+
});
106+
107+
diffWidget.addClass('jupyterlab-cell-diff');
108+
diffWidget.addToFooter();
109+
110+
return diffWidget;
111+
}

0 commit comments

Comments
 (0)