Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ node_modules
**/package.json
!/package.json
jupyterlab_cell_diff
.venv
57 changes: 49 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,66 @@
# JupyterLab Plugin: Show a Cell Diff
# jupyterlab-cell-diff

[![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)

A JupyterLab Extension for showing cell (git) diffs.

This extension is composed of a Python package named `jupyterlab_cell_diff`
for the server extension and a NPM package named `jupyterlab-cell-diff`
for the frontend extension.
A JupyterLab extension for showing cell diffs with multiple diffing strategies.

## Requirements

- JupyterLab >= 4.0.0

## Install
## Installation

To install the extension, execute:
### PyPI Installation

```bash
pip install jupyterlab_cell_diff
```

### Development Installation

```bash
# Clone the repository
git clone https://github.com/jupyter-ai-contrib/jupyterlab-cell-diff.git
cd jupyterlab-cell-diff

# Install the extension in development mode
pip install -e .
jupyter labextension develop . --overwrite
```

## Usage

### Commands

The extension provides several commands:

- `jupyterlab-cell-diff:show-codemirror` - Show diff using `@codemirror/merge`
- `jupyterlab-cell-diff:show-nbdime` - Show diff using NBDime

### Use with `@codemirror/merge`

https://github.com/user-attachments/assets/0dacd7f0-5963-4ebe-81da-2958f0117071

### Use with NBDime

https://github.com/user-attachments/assets/87e93eab-ad67-468c-b228-f5a0e93f8bea

### Programmatic Usage

```typescript
app.commands.execute('jupyterlab-cell-diff:show-codemirror', {
cellId: 'cell-id',
originalSource: 'print("Hello")',
newSource: 'print("Hello, World!")'
});

app.commands.execute('jupyterlab-cell-diff:show-nbdime', {
cellId: 'cell-id',
originalSource: 'print("Hello")',
newSource: 'print("Hello, World!")'
});
```

## Uninstall

To remove the extension, execute:
Expand Down
8 changes: 7 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
"files": [
"lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}",
"style/**/*.{css,js,eot,gif,html,jpg,json,png,svg,woff2,ttf}",
"src/**/*.{ts,tsx}"
"src/**/*.{ts,tsx}",
"schema/*.json"
],
"main": "lib/index.js",
"types": "lib/index.d.ts",
Expand Down Expand Up @@ -55,14 +56,19 @@
"watch:labextension": "jupyter labextension watch ."
},
"dependencies": {
"@codemirror/lang-python": "^6.2.1",
"@codemirror/merge": "^6.10.2",
"@codemirror/view": "^6.38.2",
"@jupyterlab/application": "^4.0.0",
"@jupyterlab/cells": "^4.0.0",
"@jupyterlab/codeeditor": "^4.0.0",
"@jupyterlab/codemirror": "^4.4.7",
"@jupyterlab/coreutils": "^6.0.0",
"@jupyterlab/notebook": "^4.0.0",
"@jupyterlab/services": "^7.0.0",
"@jupyterlab/ui-components": "^4.0.0",
"@lumino/widgets": "^2.0.0",
"codemirror": "^6.0.2",
"jupyterlab-cell-input-footer": "^0.3.0",
"nbdime": "^7.0.1"
},
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ classifiers = [
dependencies = [
"nbdime",
"jupyter_server>=2.4.0,<3",
"jupyterlab-eventlistener>=0.4.0",
"jupyterlab-cell-input-footer>=0.2.0"
"jupyterlab-eventlistener>=0.4.0,<0.5",
"jupyterlab-cell-input-footer>=0.3.1,<0.4"
]
dynamic = ["version", "description", "authors", "urls", "keywords"]

Expand Down
97 changes: 0 additions & 97 deletions src/command.ts

This file was deleted.

111 changes: 111 additions & 0 deletions src/diff/codemirror.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import { python } from '@codemirror/lang-python';
import { MergeView } from '@codemirror/merge';
import { EditorView } from '@codemirror/view';
import { jupyterTheme } from '@jupyterlab/codemirror';
import { Message } from '@lumino/messaging';
import { Widget } from '@lumino/widgets';
import { basicSetup } from 'codemirror';
import { IDiffWidgetOptions, BaseDiffWidget } from '../widget';

/**
* A Lumino widget that contains a CodeMirror diff view
*/
class CodeMirrorDiffWidget extends BaseDiffWidget {
/**
* Construct a new CodeMirrorDiffWidget.
*/
constructor(options: IDiffWidgetOptions) {
super(options);
this._originalCode = options.originalSource;
this._modifiedCode = options.newSource;
this.addClass('jp-DiffView');
}

/**
* Handle after-attach messages for the widget.
*/
protected onAfterAttach(msg: Message): void {
super.onAfterAttach(msg);
this._createMergeView();
}

/**
* Handle before-detach messages for the widget.
*/
protected onBeforeDetach(msg: Message): void {
this._destroyMergeView();
super.onBeforeDetach(msg);
}

/**
* Create the merge view with CodeMirror diff functionality.
*/
private _createMergeView(): void {
if (this._mergeView) {
return;
}

this._mergeView = new MergeView({
a: {
doc: this._originalCode,
extensions: [
basicSetup,
python(),
EditorView.editable.of(false),
jupyterTheme
]
},
b: {
doc: this._modifiedCode,
extensions: [
basicSetup,
python(),
EditorView.editable.of(false),
jupyterTheme
]
},
parent: this.node
});
}

/**
* Destroy the merge view and clean up resources.
*/
private _destroyMergeView(): void {
if (this._mergeView) {
this._mergeView.destroy();
this._mergeView = null;
}
}

private _originalCode: string;
private _modifiedCode: string;
private _mergeView: MergeView | null = null;
}

export async function createCodeMirrorDiffWidget(
options: IDiffWidgetOptions
): Promise<Widget> {
const {
cell,
cellFooterTracker,
originalSource,
newSource,
showActionButtons = true,
openDiff = true
} = options;

const diffWidget = new CodeMirrorDiffWidget({
originalSource,
newSource,
cell,
cellFooterTracker,
showActionButtons,
openDiff
});

diffWidget.addClass('jupyterlab-cell-diff');
diffWidget.addToFooter();

return diffWidget;
}
Loading