From 47ecf09c2cd58a11aa1bc645bb8c6820f48d65e0 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Fri, 7 Apr 2023 13:09:42 +0200 Subject: [PATCH 1/5] Implements "set from ..." feature and updates some samples --- website/src/runner/index.ts | 36 ++++++++++++++++++- .../hello-diff-world/sample.js | 18 +++++++--- .../creating-the-editor/hello-world/sample.js | 6 ++-- .../pages/playground/PlaygroundModel.ts | 20 +++++++++++ .../playground/PlaygroundPageContent.tsx | 7 +++- .../src/website/pages/playground/Preview.tsx | 15 ++++++++ 6 files changed, 93 insertions(+), 9 deletions(-) diff --git a/website/src/runner/index.ts b/website/src/runner/index.ts index 8bc551be..ed1fdd07 100644 --- a/website/src/runner/index.ts +++ b/website/src/runner/index.ts @@ -51,8 +51,10 @@ async function initialize(state: IPreviewState) { document.body.innerHTML += state.html; + const js = massageJs(state.js); + try { - eval(state.js); + eval(js); } catch (err) { const pre = document.createElement("pre"); pre.appendChild( @@ -61,3 +63,35 @@ async function initialize(state: IPreviewState) { document.body.insertBefore(pre, document.body.firstChild); } } + +(globalThis as any).bindModelToCodeStr = function bindModel( + model: any, + codeStringName: string +) { + model.onDidChangeContent(() => { + const value = model.getValue(); + window.parent.postMessage( + { kind: "update-code-string", codeStringName, value }, + "*" + ); + }); +}; + +function massageJs(js: string) { + /* + Alternate experimental syntax: // bind to code string: `editor.getModel()` -> codeString + + const bindToCodeStringRegexp = /\/\/ bind to code string: `(.*?)` -> (.*?)(\n|$)/g; + js = js.replaceAll(bindToCodeStringRegexp, (match, p1, p2) => { + return `globalThis.bindModelToCodeStr(${p1}, ${JSON.stringify(p2)})\n`; + }); + */ + + const setFromRegexp = /\/*\Wset from `(.*?)`:\W*\//g; + for (const m of js.matchAll(setFromRegexp)) { + const p1 = m[1]; + const target = JSON.stringify("set from `" + p1 + "`"); + js += `\n try { globalThis.bindModelToCodeStr(${p1}, ${target}); } catch (e) { console.error(e); }`; + } + return js; +} diff --git a/website/src/website/data/playground-samples/creating-the-diffeditor/hello-diff-world/sample.js b/website/src/website/data/playground-samples/creating-the-diffeditor/hello-diff-world/sample.js index 83089074..84d8ba80 100644 --- a/website/src/website/data/playground-samples/creating-the-diffeditor/hello-diff-world/sample.js +++ b/website/src/website/data/playground-samples/creating-the-diffeditor/hello-diff-world/sample.js @@ -1,8 +1,18 @@ -var originalModel = monaco.editor.createModel("heLLo world!", "text/plain"); -var modifiedModel = monaco.editor.createModel("hello orlando!", "text/plain"); +const originalModel = monaco.editor.createModel( + /* set from `originalModel`: */ `hello world`, + "text/plain" +); +const modifiedModel = monaco.editor.createModel( + /* set from `modifiedModel`: */ `Hello World!`, + "text/plain" +); -var diffEditor = monaco.editor.createDiffEditor( - document.getElementById("container") +const diffEditor = monaco.editor.createDiffEditor( + document.getElementById("container"), + { + originalEditable: true, + automaticLayout: true, + } ); diffEditor.setModel({ original: originalModel, diff --git a/website/src/website/data/playground-samples/creating-the-editor/hello-world/sample.js b/website/src/website/data/playground-samples/creating-the-editor/hello-world/sample.js index c68ae059..7beb8e40 100644 --- a/website/src/website/data/playground-samples/creating-the-editor/hello-world/sample.js +++ b/website/src/website/data/playground-samples/creating-the-editor/hello-world/sample.js @@ -1,10 +1,10 @@ -const text = `function hello() { +const value = /* set from `myEditor.getModel()`: */ `function hello() { alert('Hello world!'); }`; // Hover on each property to see its docs! -monaco.editor.create(document.getElementById("container"), { - value: text, +const myEditor = monaco.editor.create(document.getElementById("container"), { + value, language: "javascript", automaticLayout: true, }); diff --git a/website/src/website/pages/playground/PlaygroundModel.ts b/website/src/website/pages/playground/PlaygroundModel.ts index 7cb6cbf0..7f049b34 100644 --- a/website/src/website/pages/playground/PlaygroundModel.ts +++ b/website/src/website/pages/playground/PlaygroundModel.ts @@ -222,6 +222,26 @@ export class PlaygroundModel { }); } + setCodeString(codeStringName: string, value: string) { + function escapeRegexpChars(str: string) { + return str.replace(/[-[\]/{}()*+?.\\^$|]/g, "\\$&"); + } + + const regexp = new RegExp( + "(\\b" + + escapeRegexpChars(codeStringName) + + ":[^\\w`]*`)([^`\\\\]|\\n|\\\\\\\\|\\\\`)*`" + ); + debugger; + const js = this.js; + const str = value.replaceAll("\\", "\\\\").replaceAll("`", "\\`"); + const newJs = js.replace(regexp, "$1" + str + "`"); + const autoReload = this.settings.autoReload; + this.settings.autoReload = false; + this.js = newJs; + this.settings.autoReload = autoReload; + } + public showSettingsDialog(): void { this.settingsDialogModel = new SettingsDialogModel( this.settings.settings diff --git a/website/src/website/pages/playground/PlaygroundPageContent.tsx b/website/src/website/pages/playground/PlaygroundPageContent.tsx index 3c1039d5..7355192b 100644 --- a/website/src/website/pages/playground/PlaygroundPageContent.tsx +++ b/website/src/website/pages/playground/PlaygroundPageContent.tsx @@ -448,7 +448,12 @@ class Editor extends React.Component<{ () => { const value = this.props.value.get(); if (!this.ignoreChange) { - this.editor!.setValue(value); + this.model.pushEditOperations(null, [ + { + range: this.model.getFullModelRange(), + text: value, + } + ], () => null); } }, { name: "update text" } diff --git a/website/src/website/pages/playground/Preview.tsx b/website/src/website/pages/playground/Preview.tsx index e893c472..a6abdca0 100644 --- a/website/src/website/pages/playground/Preview.tsx +++ b/website/src/website/pages/playground/Preview.tsx @@ -48,6 +48,21 @@ export class Preview targetOrigin: "*", }); }); + window.addEventListener("message", (e) => { + if (e.source !== iframe.contentWindow) { + return; + } + const data = e.data as + | { + kind: "update-code-string"; + codeStringName: string; + value: string; + } + | { kind: "" }; + if (data.kind === "update-code-string") { + this.props.model.setCodeString(data.codeStringName, data.value); + } + }); }; componentDidMount() { From 225be1f83c3b5d0665cb02cc2f5258e7024a6a27 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Fri, 7 Apr 2023 13:16:45 +0200 Subject: [PATCH 2/5] Fixes lockfile. --- package-lock.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 081ac824..6702c553 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "monaco-editor", - "version": "0.37.0", + "version": "0.37.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "monaco-editor", - "version": "0.37.0", + "version": "0.37.1", "hasInstallScript": true, "license": "MIT", "devDependencies": { From ce36afc6c50dc6f19d42db2504b2126fb96b886b Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Fri, 7 Apr 2023 13:17:26 +0200 Subject: [PATCH 3/5] Adds forgotten dispose & implements undo --- .../pages/playground/PlaygroundPageContent.tsx | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/website/src/website/pages/playground/PlaygroundPageContent.tsx b/website/src/website/pages/playground/PlaygroundPageContent.tsx index 7355192b..cdd953cf 100644 --- a/website/src/website/pages/playground/PlaygroundPageContent.tsx +++ b/website/src/website/pages/playground/PlaygroundPageContent.tsx @@ -448,12 +448,16 @@ class Editor extends React.Component<{ () => { const value = this.props.value.get(); if (!this.ignoreChange) { - this.model.pushEditOperations(null, [ - { - range: this.model.getFullModelRange(), - text: value, - } - ], () => null); + this.model.pushEditOperations( + null, + [ + { + range: this.model.getFullModelRange(), + text: value, + }, + ], + () => null + ); } }, { name: "update text" } @@ -463,6 +467,7 @@ class Editor extends React.Component<{ componentWillUnmount() { this.disposables.forEach((d) => d.dispose()); + this.model.dispose(); } } From ebfddbd4fb64fc02a6e5258dd077b3e2a940e375 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Fri, 7 Apr 2023 13:22:17 +0200 Subject: [PATCH 4/5] Adds reload action (Ctrl+Enter) --- .../pages/playground/PlaygroundModel.ts | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/website/src/website/pages/playground/PlaygroundModel.ts b/website/src/website/pages/playground/PlaygroundModel.ts index 7cb6cbf0..5d675caf 100644 --- a/website/src/website/pages/playground/PlaygroundModel.ts +++ b/website/src/website/pages/playground/PlaygroundModel.ts @@ -148,6 +148,17 @@ export class PlaygroundModel { constructor() { let lastState = this.state; + this.dispose.track( + monaco.editor.addEditorAction({ + id: "reload", + label: "Reload", + run: (editor, ...args) => { + this.reload(); + }, + keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter], + }) + ); + this.dispose.track({ dispose: reaction( () => ({ state: this.state }), @@ -162,13 +173,19 @@ export class PlaygroundModel { return; } } - this.debouncer.run(() => { + const action = () => { this.isDirty = false; lastState = state; for (const handler of this._previewHandlers) { handler.handlePreview(state); } - }); + }; + + if (state.key !== lastState.key) { + action(); // sync update + } else { + this.debouncer.run(action); + } }, { name: "update preview" } ), From 2b2cfac8fae0f97eb86b26b8f3540ddde796527e Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Fri, 7 Apr 2023 20:44:13 +0200 Subject: [PATCH 5/5] Fixes broken website. --- .../pages/playground/PlaygroundModel.ts | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/website/src/website/pages/playground/PlaygroundModel.ts b/website/src/website/pages/playground/PlaygroundModel.ts index 6b934f3e..85cb1313 100644 --- a/website/src/website/pages/playground/PlaygroundModel.ts +++ b/website/src/website/pages/playground/PlaygroundModel.ts @@ -148,17 +148,6 @@ export class PlaygroundModel { constructor() { let lastState = this.state; - this.dispose.track( - monaco.editor.addEditorAction({ - id: "reload", - label: "Reload", - run: (editor, ...args) => { - this.reload(); - }, - keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter], - }) - ); - this.dispose.track({ dispose: reaction( () => ({ state: this.state }), @@ -195,6 +184,17 @@ export class PlaygroundModel { let disposable: Disposable | undefined = undefined; waitForLoadedMonaco().then((m) => { + this.dispose.track( + monaco.editor.addEditorAction({ + id: "reload", + label: "Reload", + run: (editor, ...args) => { + this.reload(); + }, + keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter], + }) + ); + const options = monaco.languages.typescript.javascriptDefaults.getCompilerOptions(); monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions(