diff --git a/package-lock.json b/package-lock.json
index 890cc30d..1022a75c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,9 +9,13 @@
"version": "2.5.0",
"license": "GPL-2.0-or-later",
"dependencies": {
+ "@codemirror/basic-setup": "^0.20.0",
"@codemirror/lang-json": "^6.0.1",
+ "@codemirror/state": "^6.4.1",
+ "@codemirror/view": "^6.33.0",
"@uiw/react-codemirror": "^4.23.1",
"@wordpress/icons": "^10.7.0",
+ "diff": "^7.0.0",
"lib-font": "^2.4.3"
},
"devDependencies": {
@@ -1981,6 +1985,112 @@
"@lezer/common": "^1.0.0"
}
},
+ "node_modules/@codemirror/basic-setup": {
+ "version": "0.20.0",
+ "resolved": "https://registry.npmjs.org/@codemirror/basic-setup/-/basic-setup-0.20.0.tgz",
+ "integrity": "sha512-W/ERKMLErWkrVLyP5I8Yh8PXl4r+WFNkdYVSzkXYPQv2RMPSkWpr2BgggiSJ8AHF/q3GuApncDD8I4BZz65fyg==",
+ "deprecated": "In version 6.0, this package has been renamed to just 'codemirror'",
+ "dependencies": {
+ "@codemirror/autocomplete": "^0.20.0",
+ "@codemirror/commands": "^0.20.0",
+ "@codemirror/language": "^0.20.0",
+ "@codemirror/lint": "^0.20.0",
+ "@codemirror/search": "^0.20.0",
+ "@codemirror/state": "^0.20.0",
+ "@codemirror/view": "^0.20.0"
+ }
+ },
+ "node_modules/@codemirror/basic-setup/node_modules/@codemirror/autocomplete": {
+ "version": "0.20.3",
+ "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-0.20.3.tgz",
+ "integrity": "sha512-lYB+NPGP+LEzAudkWhLfMxhTrxtLILGl938w+RcFrGdrIc54A+UgmCoz+McE3IYRFp4xyQcL4uFJwo+93YdgHw==",
+ "dependencies": {
+ "@codemirror/language": "^0.20.0",
+ "@codemirror/state": "^0.20.0",
+ "@codemirror/view": "^0.20.0",
+ "@lezer/common": "^0.16.0"
+ }
+ },
+ "node_modules/@codemirror/basic-setup/node_modules/@codemirror/commands": {
+ "version": "0.20.0",
+ "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-0.20.0.tgz",
+ "integrity": "sha512-v9L5NNVA+A9R6zaFvaTbxs30kc69F6BkOoiEbeFw4m4I0exmDEKBILN6mK+GksJtvTzGBxvhAPlVFTdQW8GB7Q==",
+ "dependencies": {
+ "@codemirror/language": "^0.20.0",
+ "@codemirror/state": "^0.20.0",
+ "@codemirror/view": "^0.20.0",
+ "@lezer/common": "^0.16.0"
+ }
+ },
+ "node_modules/@codemirror/basic-setup/node_modules/@codemirror/language": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-0.20.2.tgz",
+ "integrity": "sha512-WB3Bnuusw0xhVvhBocieYKwJm04SOk5bPoOEYksVHKHcGHFOaYaw+eZVxR4gIqMMcGzOIUil0FsCmFk8yrhHpw==",
+ "dependencies": {
+ "@codemirror/state": "^0.20.0",
+ "@codemirror/view": "^0.20.0",
+ "@lezer/common": "^0.16.0",
+ "@lezer/highlight": "^0.16.0",
+ "@lezer/lr": "^0.16.0",
+ "style-mod": "^4.0.0"
+ }
+ },
+ "node_modules/@codemirror/basic-setup/node_modules/@codemirror/lint": {
+ "version": "0.20.3",
+ "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-0.20.3.tgz",
+ "integrity": "sha512-06xUScbbspZ8mKoODQCEx6hz1bjaq9m8W8DxdycWARMiiX1wMtfCh/MoHpaL7ws/KUMwlsFFfp2qhm32oaCvVA==",
+ "dependencies": {
+ "@codemirror/state": "^0.20.0",
+ "@codemirror/view": "^0.20.2",
+ "crelt": "^1.0.5"
+ }
+ },
+ "node_modules/@codemirror/basic-setup/node_modules/@codemirror/search": {
+ "version": "0.20.1",
+ "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-0.20.1.tgz",
+ "integrity": "sha512-ROe6gRboQU5E4z6GAkNa2kxhXqsGNbeLEisbvzbOeB7nuDYXUZ70vGIgmqPu0tB+1M3F9yWk6W8k2vrFpJaD4Q==",
+ "dependencies": {
+ "@codemirror/state": "^0.20.0",
+ "@codemirror/view": "^0.20.0",
+ "crelt": "^1.0.5"
+ }
+ },
+ "node_modules/@codemirror/basic-setup/node_modules/@codemirror/state": {
+ "version": "0.20.1",
+ "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-0.20.1.tgz",
+ "integrity": "sha512-ms0tlV5A02OK0pFvTtSUGMLkoarzh1F8mr6jy1cD7ucSC2X/VLHtQCxfhdSEGqTYlQF2hoZtmLv+amqhdgbwjQ=="
+ },
+ "node_modules/@codemirror/basic-setup/node_modules/@codemirror/view": {
+ "version": "0.20.7",
+ "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-0.20.7.tgz",
+ "integrity": "sha512-pqEPCb9QFTOtHgAH5XU/oVy9UR/Anj6r+tG5CRmkNVcqSKEPmBU05WtN/jxJCFZBXf6HumzWC9ydE4qstO3TxQ==",
+ "dependencies": {
+ "@codemirror/state": "^0.20.0",
+ "style-mod": "^4.0.0",
+ "w3c-keyname": "^2.2.4"
+ }
+ },
+ "node_modules/@codemirror/basic-setup/node_modules/@lezer/common": {
+ "version": "0.16.1",
+ "resolved": "https://registry.npmjs.org/@lezer/common/-/common-0.16.1.tgz",
+ "integrity": "sha512-qPmG7YTZ6lATyTOAWf8vXE+iRrt1NJd4cm2nJHK+v7X9TsOF6+HtuU/ctaZy2RCrluxDb89hI6KWQ5LfQGQWuA=="
+ },
+ "node_modules/@codemirror/basic-setup/node_modules/@lezer/highlight": {
+ "version": "0.16.0",
+ "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-0.16.0.tgz",
+ "integrity": "sha512-iE5f4flHlJ1g1clOStvXNLbORJoiW4Kytso6ubfYzHnaNo/eo5SKhxs4wv/rtvwZQeZrK3we8S9SyA7OGOoRKQ==",
+ "dependencies": {
+ "@lezer/common": "^0.16.0"
+ }
+ },
+ "node_modules/@codemirror/basic-setup/node_modules/@lezer/lr": {
+ "version": "0.16.3",
+ "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-0.16.3.tgz",
+ "integrity": "sha512-pau7um4eAw94BEuuShUIeQDTf3k4Wt6oIUOYxMmkZgDHdqtIcxWND4LRxi8nI9KuT4I1bXQv67BCapkxt7Ywqw==",
+ "dependencies": {
+ "@lezer/common": "^0.16.0"
+ }
+ },
"node_modules/@codemirror/commands": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.5.0.tgz",
@@ -2051,9 +2161,9 @@
}
},
"node_modules/@codemirror/view": {
- "version": "6.26.3",
- "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.26.3.tgz",
- "integrity": "sha512-gmqxkPALZjkgSxIeeweY/wGQXBfwTUaLs8h7OKtSwfbj9Ct3L11lD+u1sS7XHppxFQoMDiMDp07P9f3I2jWOHw==",
+ "version": "6.33.0",
+ "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.33.0.tgz",
+ "integrity": "sha512-AroaR3BvnjRW8fiZBalAaK+ZzB5usGgI014YKElYZvQdNH5ZIidHlO+cyf/2rWzyBFRkvG6VhiXeAEbC53P2YQ==",
"dependencies": {
"@codemirror/state": "^6.4.0",
"style-mod": "^4.1.0",
@@ -8683,6 +8793,14 @@
"integrity": "sha512-oD9vGBV2wTc7fAzAM6KC0chSgs234V8+qDEeK+mcbRj2UvcuA7lgBztGi/opj/iahcXD3BSj8Ymvib628yy9FA==",
"dev": true
},
+ "node_modules/diff": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz",
+ "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==",
+ "engines": {
+ "node": ">=0.3.1"
+ }
+ },
"node_modules/diff-sequences": {
"version": "29.6.3",
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz",
diff --git a/package.json b/package.json
index f016b13e..7422df34 100644
--- a/package.json
+++ b/package.json
@@ -19,9 +19,13 @@
"npm": ">=10.2.3"
},
"dependencies": {
+ "@codemirror/basic-setup": "^0.20.0",
"@codemirror/lang-json": "^6.0.1",
+ "@codemirror/state": "^6.4.1",
+ "@codemirror/view": "^6.33.0",
"@uiw/react-codemirror": "^4.23.1",
"@wordpress/icons": "^10.7.0",
+ "diff": "^7.0.0",
"lib-font": "^2.4.3"
},
"devDependencies": {
diff --git a/src/editor-sidebar/code-mirror-diff-viewer.js b/src/editor-sidebar/code-mirror-diff-viewer.js
new file mode 100644
index 00000000..9d765b9a
--- /dev/null
+++ b/src/editor-sidebar/code-mirror-diff-viewer.js
@@ -0,0 +1,133 @@
+/**
+ * External dependencies
+ */
+import CodeMirror from '@uiw/react-codemirror';
+import { EditorView, ViewPlugin, Decoration } from '@codemirror/view';
+import { EditorState, RangeSetBuilder } from '@codemirror/state';
+import { basicSetup } from '@codemirror/basic-setup';
+import { json } from '@codemirror/lang-json';
+import { diffLines } from 'diff';
+
+/**
+ * WordPress dependencies
+ */
+import { __, sprintf } from '@wordpress/i18n';
+import { useState, useEffect } from '@wordpress/element';
+
+export function CodeMirrorDiffViewer({ oldCode, newCode }) {
+ const [diff, setDiff] = useState([]);
+
+ useEffect(() => {
+ // override for testing
+ const oldCode = {
+ "hello": "123",
+ "world": "456",
+ "foo": "bar"
+ };
+ const newCode = {
+ "hello": "123",
+ "world": "456",
+ "foo": "baz"
+ };
+
+ setDiff(diffLines(JSON.stringify(oldCode, null, 4), JSON.stringify(newCode, null, 4)));
+ }, [oldCode, newCode]);
+
+ const diffDecorations = EditorView.decorations.compute([], (state) => getDiffDecorations(diff));
+ // const diffDecorations = (diff) => {
+ // const builder = new RangeSetBuilder();
+ // diff.forEach((part, index) => {
+ // if (part.added || part.removed) {
+ // const className = part.added ? 'added' : 'removed';
+ // const decoration = Decoration.mark({
+ // class: className,
+ // });
+ // builder.add(index, index + part.value.length, decoration);
+ // }
+ // });
+ // return builder.finish();
+ // };
+
+ // const diffPlugin = ViewPlugin.fromClass(class {
+ // constructor(view) {
+ // this.decorations = diffDecorations(diff);
+ // }
+ // update(update) {
+ // if (update.docChanged || update.viewportChanged) {
+ // this.decorations = diffDecorations(diff);
+ // }
+ // }
+ // }, {
+ // decorations: v => v.decorations
+ // });
+
+ // const state = EditorState.create({
+ // doc: newCode,
+ // extensions: [basicSetup, json(), diffPlugin]
+ // });
+
+ // return