diff --git a/packages/engine.vscode/.eslintrc.js b/packages/engine.vscode/.eslintrc.js new file mode 100644 index 00000000..f96bb0f1 --- /dev/null +++ b/packages/engine.vscode/.eslintrc.js @@ -0,0 +1,23 @@ +/**@type {import('eslint').Linter.Config} */ +// eslint-disable-next-line no-undef +module.exports = { + root: true, + parser: '@typescript-eslint/parser', + plugins: [ + '@typescript-eslint', + ], + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + ], + ignorePatterns: [ + 'media' + ], + rules: { + 'semi': [2, "always"], + '@typescript-eslint/no-unused-vars': 0, + '@typescript-eslint/no-explicit-any': 0, + '@typescript-eslint/explicit-module-boundary-types': 0, + '@typescript-eslint/no-non-null-assertion': 0, + } +}; \ No newline at end of file diff --git a/packages/engine.vscode/.vscode/extensions.json b/packages/engine.vscode/.vscode/extensions.json new file mode 100644 index 00000000..af515502 --- /dev/null +++ b/packages/engine.vscode/.vscode/extensions.json @@ -0,0 +1,9 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + + // List of extensions which should be recommended for users of this workspace. + "recommendations": [ + "dbaeumer.vscode-eslint" + ] +} \ No newline at end of file diff --git a/packages/engine.vscode/.vscode/launch.json b/packages/engine.vscode/.vscode/launch.json new file mode 100644 index 00000000..461f3da0 --- /dev/null +++ b/packages/engine.vscode/.vscode/launch.json @@ -0,0 +1,18 @@ +// A launch configuration that compiles the extension and then opens it inside a new window +// Use IntelliSense to learn about possible attributes. +// Hover to view descriptions of existing attributes. +// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Run Extension", + "type": "extensionHost", + "request": "launch", + "runtimeExecutable": "${execPath}", + "args": ["--extensionDevelopmentPath=${workspaceRoot}"], + "outFiles": ["${workspaceFolder}/out/**/*.js"], + "preLaunchTask": "npm: watch" + } + ] +} diff --git a/packages/engine.vscode/.vscode/settings.json b/packages/engine.vscode/.vscode/settings.json new file mode 100644 index 00000000..8d047dad --- /dev/null +++ b/packages/engine.vscode/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "editor.insertSpaces": false +} \ No newline at end of file diff --git a/packages/engine.vscode/.vscode/tasks.json b/packages/engine.vscode/.vscode/tasks.json new file mode 100644 index 00000000..3b17e53b --- /dev/null +++ b/packages/engine.vscode/.vscode/tasks.json @@ -0,0 +1,20 @@ +// See https://go.microsoft.com/fwlink/?LinkId=733558 +// for the documentation about the tasks.json format +{ + "version": "2.0.0", + "tasks": [ + { + "type": "npm", + "script": "watch", + "problemMatcher": "$tsc-watch", + "isBackground": true, + "presentation": { + "reveal": "never" + }, + "group": { + "kind": "build", + "isDefault": true + } + } + ] +} diff --git a/packages/engine.vscode/README.md b/packages/engine.vscode/README.md new file mode 100644 index 00000000..1e2ea222 --- /dev/null +++ b/packages/engine.vscode/README.md @@ -0,0 +1,34 @@ +# Cat Coding — A Webview API Sample + +Demonstrates VS Code's [webview API](https://code.visualstudio.com/api/extension-guides/webview). This includes: + +- Creating and showing a basic webview. +- Dynamically updating a webview's content. +- Loading local content in a webview. +- Running scripts in a webview. +- Sending message from an extension to a webview. +- Sending messages from a webview to an extension. +- Using a basic content security policy. +- Webview lifecycle and handling dispose. +- Saving and restoring state when the panel goes into the background. +- Serialization and persistence across VS Code reboots. + +## Demo + +![demo](demo.gif) + +## VS Code API + +### `vscode` module + +- [`window.createWebviewPanel`](https://code.visualstudio.com/api/references/vscode-api#window.createWebviewPanel) +- [`window.registerWebviewPanelSerializer`](https://code.visualstudio.com/api/references/vscode-api#window.registerWebviewPanelSerializer) + +## Running the example + +- Open this example in VS Code 1.47+ +- `npm install` +- `npm run watch` or `npm run compile` +- `F5` to start debugging + +Run the `Cat Coding: Start cat coding session` to create the webview. diff --git a/packages/engine.vscode/demo.gif b/packages/engine.vscode/demo.gif new file mode 100644 index 00000000..13b39b44 Binary files /dev/null and b/packages/engine.vscode/demo.gif differ diff --git a/packages/engine.vscode/media/cat.gif b/packages/engine.vscode/media/cat.gif new file mode 100644 index 00000000..8a164826 Binary files /dev/null and b/packages/engine.vscode/media/cat.gif differ diff --git a/packages/engine.vscode/media/jsconfig.json b/packages/engine.vscode/media/jsconfig.json new file mode 100644 index 00000000..3a2cf036 --- /dev/null +++ b/packages/engine.vscode/media/jsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es2020", + "jsx": "preserve", + "checkJs": true, + "strict": true, + "strictFunctionTypes": true, + "lib": [ + "dom" + ] + }, + "exclude": [ + "node_modules", + "**/node_modules/*" + ], + "typeAcquisition": { + "include": [ + "@types/vscode-webview" + ] + } +} \ No newline at end of file diff --git a/packages/engine.vscode/media/main.js b/packages/engine.vscode/media/main.js new file mode 100644 index 00000000..e7914da9 --- /dev/null +++ b/packages/engine.vscode/media/main.js @@ -0,0 +1,61 @@ +// This script will be run within the webview itself +// It cannot access the main VS Code APIs directly. + +(function () { + const vscode = acquireVsCodeApi(); + + //@ts-ignore + function insertIframe(addr) { + var iframe = document.createElement('iframe') + iframe.setAttribute('src', addr.value); + iframe.setAttribute('width', '100%'); + iframe.setAttribute('height', '650px'); + document.body.appendChild(iframe) + localStorage.setItem("address", addr.value) + } + + const address = localStorage.getItem("address") + if(address) { + insertIframe({value: address}) + } + + window.addEventListener('message', event => { + const message = event.data; // The json data that the extension sent + insertIframe("bla") + }); + + const oldState = /** @type {{ count: number} | undefined} */ (vscode.getState()); + + const counter = /** @type {HTMLElement} */ (document.getElementById('lines-of-code-counter')); + console.log('Initial state', oldState); + + let currentCount = (oldState && oldState.count) || 0; + counter.textContent = `${currentCount}`; + + setInterval(() => { + counter.textContent = `${currentCount++} `; + + // Update state + vscode.setState({ count: currentCount }); + + // Alert the extension when the cat introduces a bug + if (Math.random() < Math.min(0.001 * currentCount, 0.05)) { + // Send a message back to the extension + vscode.postMessage({ + command: 'alert', + text: '🐛 on line ' + currentCount + }); + } + }, 100); + + // Handle messages sent from the extension to the webview + window.addEventListener('message', event => { + const message = event.data; // The json data that the extension sent + switch (message.command) { + case 'refactor': + currentCount = Math.ceil(currentCount * 0.5); + counter.textContent = `${currentCount}`; + break; + } + }); +}()); diff --git a/packages/engine.vscode/media/reset.css b/packages/engine.vscode/media/reset.css new file mode 100644 index 00000000..92d02910 --- /dev/null +++ b/packages/engine.vscode/media/reset.css @@ -0,0 +1,30 @@ +html { + box-sizing: border-box; + font-size: 13px; +} + +*, +*:before, +*:after { + box-sizing: inherit; +} + +body, +h1, +h2, +h3, +h4, +h5, +h6, +p, +ol, +ul { + margin: 0; + padding: 0; + font-weight: normal; +} + +img { + max-width: 100%; + height: auto; +} diff --git a/packages/engine.vscode/media/vscode.css b/packages/engine.vscode/media/vscode.css new file mode 100644 index 00000000..606bdec3 --- /dev/null +++ b/packages/engine.vscode/media/vscode.css @@ -0,0 +1,91 @@ +:root { + --container-padding: 20px; + --input-padding-vertical: 6px; + --input-padding-horizontal: 4px; + --input-margin-vertical: 4px; + --input-margin-horizontal: 0; +} + +body { + padding: 0 var(--container-padding); + color: var(--vscode-foreground); + font-size: var(--vscode-font-size); + font-weight: var(--vscode-font-weight); + font-family: var(--vscode-font-family); + background-color: var(--vscode-editor-background); +} + +ol, +ul { + padding-left: var(--container-padding); +} + +body > *, +form > * { + margin-block-start: var(--input-margin-vertical); + margin-block-end: var(--input-margin-vertical); +} + +*:focus { + outline-color: var(--vscode-focusBorder) !important; +} + +a { + color: var(--vscode-textLink-foreground); +} + +a:hover, +a:active { + color: var(--vscode-textLink-activeForeground); +} + +code { + font-size: var(--vscode-editor-font-size); + font-family: var(--vscode-editor-font-family); +} + +button { + border: none; + padding: var(--input-padding-vertical) var(--input-padding-horizontal); + width: 100%; + text-align: center; + outline: 1px solid transparent; + outline-offset: 2px !important; + color: var(--vscode-button-foreground); + background: var(--vscode-button-background); +} + +button:hover { + cursor: pointer; + background: var(--vscode-button-hoverBackground); +} + +button:focus { + outline-color: var(--vscode-focusBorder); +} + +button.secondary { + color: var(--vscode-button-secondaryForeground); + background: var(--vscode-button-secondaryBackground); +} + +button.secondary:hover { + background: var(--vscode-button-secondaryHoverBackground); +} + +input:not([type='checkbox']), +textarea { + display: block; + width: 100%; + border: none; + font-family: var(--vscode-font-family); + padding: var(--input-padding-vertical) var(--input-padding-horizontal); + color: var(--vscode-input-foreground); + outline-color: var(--vscode-input-border); + background-color: var(--vscode-input-background); +} + +input::placeholder, +textarea::placeholder { + color: var(--vscode-input-placeholderForeground); +} diff --git a/packages/engine.vscode/out/extension.js b/packages/engine.vscode/out/extension.js new file mode 100644 index 00000000..833152be --- /dev/null +++ b/packages/engine.vscode/out/extension.js @@ -0,0 +1,172 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.activate = void 0; +const vscode = require("vscode"); +const init_1 = require("./init"); +function activate(context) { + (0, init_1.default)(context); + context.subscriptions.push(vscode.commands.registerCommand('engine.dashboard.start', () => { + EngineDashboardPanel.createOrShow(context.extensionUri); + })); + context.subscriptions.push(vscode.commands.registerCommand('extension.refreshButtons', () => { + (0, init_1.default)(context); + })); + // context.subscriptions.push( + // vscode.commands.registerCommand('catCoding.doRefactor', () => { + // if (CatCodingPanel.currentPanel) { + // CatCodingPanel.currentPanel.doRefactor(); + // } + // }) + // ); + if (vscode.window.registerWebviewPanelSerializer) { + // Make sure we register a serializer in activation event + vscode.window.registerWebviewPanelSerializer(EngineDashboardPanel.viewType, { + async deserializeWebviewPanel(webviewPanel, state) { + console.log(`Got state: ${state}`); + // Reset the webview options so we use latest uri for `localResourceRoots`. + webviewPanel.webview.options = getWebviewOptions(context.extensionUri); + EngineDashboardPanel.revive(webviewPanel, context.extensionUri); + } + }); + } +} +exports.activate = activate; +function getWebviewOptions(extensionUri) { + return { + // Enable javascript in the webview + enableScripts: true, + // And restrict the webview to only loading content from our extension's `media` directory. + localResourceRoots: [vscode.Uri.joinPath(extensionUri, 'media')] + }; +} +/** + * Manages cat coding webview panels + */ +class EngineDashboardPanel { + constructor(panel, extensionUri) { + this._disposables = []; + this._panel = panel; + this._extensionUri = extensionUri; + // Set the webview's initial html content + this._update(); + // Listen for when the panel is disposed + // This happens when the user closes the panel or when the panel is closed programmatically + this._panel.onDidDispose(() => this.dispose(), null, this._disposables); + // Update the content based on view changes + this._panel.onDidChangeViewState(e => { + if (this._panel.visible) { + this._update(); + } + }, null, this._disposables); + // Handle messages from the webview + this._panel.webview.onDidReceiveMessage(message => { + switch (message.command) { + case 'alert': + vscode.window.showErrorMessage(message.text); + return; + } + }, null, this._disposables); + } + static createOrShow(extensionUri) { + const column = vscode.window.activeTextEditor + ? vscode.window.activeTextEditor.viewColumn + : undefined; + // If we already have a panel, show it. + if (EngineDashboardPanel.currentPanel) { + EngineDashboardPanel.currentPanel._panel.reveal(column); + return; + } + // Otherwise, create a new panel. + const panel = vscode.window.createWebviewPanel(EngineDashboardPanel.viewType, 'Engine Dashboard', column || vscode.ViewColumn.One, { + enableScripts: true, + retainContextWhenHidden: true, + localResourceRoots: [vscode.Uri.joinPath(extensionUri, 'media')] + }); + EngineDashboardPanel.currentPanel = new EngineDashboardPanel(panel, extensionUri); + } + static revive(panel, extensionUri) { + EngineDashboardPanel.currentPanel = new EngineDashboardPanel(panel, extensionUri); + } + doRefactor() { + // Send a message to the webview webview. + // You can send any JSON serializable data. + this._panel.webview.postMessage({ command: 'refactor' }); + } + dispose() { + EngineDashboardPanel.currentPanel = undefined; + // Clean up our resources + this._panel.dispose(); + while (this._disposables.length) { + const x = this._disposables.pop(); + if (x) { + x.dispose(); + } + } + } + _update() { + const webview = this._panel.webview; + // Vary the webview's content based on where it is located in the editor. + switch (this._panel.viewColumn) { + // case vscode.ViewColumn.Two: + // this._updateForCat(webview, 'Compiling Cat'); + // return; + // case vscode.ViewColumn.Three: + // this._updateForCat(webview, 'Testing Cat'); + // return; + // case vscode.ViewColumn.One: + default: + this._updateForCat(webview, 'Engine Dashboard'); + return; + } + } + _updateForCat(webview, catName) { + this._panel.title = catName; + this._panel.webview.html = this._getHtmlForWebview(webview, catName); + } + _getHtmlForWebview(webview, catGifPath) { + // Local path to main script run in the webview + const scriptPathOnDisk = vscode.Uri.joinPath(this._extensionUri, 'media', 'main.js'); + // And the uri we use to load this script in the webview + const scriptUri = webview.asWebviewUri(scriptPathOnDisk); + // Local path to css styles + const styleResetPath = vscode.Uri.joinPath(this._extensionUri, 'media', 'reset.css'); + const stylesPathMainPath = vscode.Uri.joinPath(this._extensionUri, 'media', 'vscode.css'); + // Uri to load styles into webview + const stylesResetUri = webview.asWebviewUri(styleResetPath); + const stylesMainUri = webview.asWebviewUri(stylesPathMainPath); + // Use a nonce to only allow specific scripts to be run + const nonce = getNonce(); + return ` + + + + + + + + + Engine Dashboard + + + + +

0

+ + + + `; + } +} +EngineDashboardPanel.viewType = 'engineDashboard'; +function getNonce() { + let text = ''; + const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + for (let i = 0; i < 32; i++) { + text += possible.charAt(Math.floor(Math.random() * possible.length)); + } + return text; +} +//# sourceMappingURL=extension.js.map \ No newline at end of file diff --git a/packages/engine.vscode/out/extension.js.map b/packages/engine.vscode/out/extension.js.map new file mode 100644 index 00000000..16f71005 --- /dev/null +++ b/packages/engine.vscode/out/extension.js.map @@ -0,0 +1 @@ +{"version":3,"file":"extension.js","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/engine.vscode/out/init.js b/packages/engine.vscode/out/init.js new file mode 100644 index 00000000..15c46a38 --- /dev/null +++ b/packages/engine.vscode/out/init.js @@ -0,0 +1,146 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const packageJson_1 = require("./packageJson"); +const vscode = require("vscode"); +const path = require("path"); +const registerCommand = vscode.commands.registerCommand; +const disposables = []; +const init = async (context) => { + disposables.forEach(d => d.dispose()); + const config = vscode.workspace.getConfiguration('actionButtons'); + const defaultColor = config.get('defaultColor') || "green"; + const cmds = config.get('commands'); + // const reloadButton = config.get('reloadButton') + const loadNpmCommands = config.get('loadNpmCommands'); + const reloadButton = true; + // const defaultColor = "green" + // const cmds: Array = [ { + // // "cwd": "/home/custom_folder", // Terminal initial folder ${workspaceFolder} and os user home as defaults + // "name": "Start Engine Dashboard", + // "color": "green", + // "singleInstance": true, + // "command": "yarn dashboard", // This is executed in the terminal. + // "tooltip": "" + // }] + const commands = []; + if (reloadButton !== null) { + loadButton({ + command: 'extension.refreshButtons', + name: "Refresh commands", + tooltip: 'Refreshes the action buttons', + color: defaultColor + }); + } + else { + const onCfgChange = vscode.workspace.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('actionButtons')) { + vscode.commands.executeCommand('extension.refreshButtons'); + } + }); + context.subscriptions.push(onCfgChange); + disposables.push(onCfgChange); + } + if (cmds && cmds.length) { + commands.push(...cmds); + } + // if (loadNpmCommands !== false) + commands.push(...(await (0, packageJson_1.buildConfigFromPackageJson)(defaultColor))); + if (commands.length) { + const terminals = {}; + commands.forEach(({ cwd, saveAll, command, name, tooltip, color, singleInstance, focus, useVsCodeApi, args }) => { + const vsCommand = `extension.${name.replace(' ', '')}`; + const disposable = registerCommand(vsCommand, async () => { + const vars = { + // - the path of the folder opened in VS Code + workspaceFolder: vscode.workspace.rootPath, + // - the name of the folder opened in VS Code without any slashes (/) + workspaceFolderBasename: (vscode.workspace.rootPath) ? path.basename(vscode.workspace.rootPath) : null, + // - the current opened file + file: (vscode.window.activeTextEditor) ? vscode.window.activeTextEditor.document.fileName : null, + // - the current opened file relative to workspaceFolder + relativeFile: (vscode.window.activeTextEditor && vscode.workspace.rootPath) ? path.relative(vscode.workspace.rootPath, vscode.window.activeTextEditor.document.fileName) : null, + // - the current opened file's basename + fileBasename: (vscode.window.activeTextEditor) ? path.basename(vscode.window.activeTextEditor.document.fileName) : null, + // - the current opened file's basename with no file extension + fileBasenameNoExtension: (vscode.window.activeTextEditor) ? path.parse(path.basename(vscode.window.activeTextEditor.document.fileName)).name : null, + // - the current opened file's dirname + fileDirname: (vscode.window.activeTextEditor) ? path.dirname(vscode.window.activeTextEditor.document.fileName) : null, + // - the current opened file's extension + fileExtname: (vscode.window.activeTextEditor) ? path.parse(path.basename(vscode.window.activeTextEditor.document.fileName)).ext : null, + // - the task runner's current working directory on startup + cwd: cwd || vscode.workspace.rootPath || require('os').homedir(), + //- the current selected line number in the active file + lineNumber: (vscode.window.activeTextEditor) ? vscode.window.activeTextEditor.selection.active.line + 1 : null, + // - the current selected text in the active file + selectedText: (vscode.window.activeTextEditor) ? vscode.window.activeTextEditor.document.getText(vscode.window.activeTextEditor.selection) : null, + // - the path to the running VS Code executable + execPath: process.execPath + }; + if (!command) { + vscode.window.showErrorMessage('No command to execute for this action'); + return; + } + if (saveAll) { + vscode.commands.executeCommand('workbench.action.files.saveAll'); + } + if (useVsCodeApi) { + vscode.commands.executeCommand(command, ...(args || [])); + } + else { + let assocTerminal = terminals[vsCommand]; + if (!assocTerminal) { + assocTerminal = vscode.window.createTerminal({ name, cwd: vars.cwd }); + terminals[vsCommand] = assocTerminal; + } + else { + if (singleInstance) { + delete terminals[vsCommand]; + assocTerminal.dispose(); + assocTerminal = vscode.window.createTerminal({ name, cwd: vars.cwd }); + terminals[vsCommand] = assocTerminal; + } + else { + assocTerminal.sendText('clear'); + } + } + assocTerminal.show(!focus); + assocTerminal.sendText(interpolateString(command, vars)); + } + }); + context.subscriptions.push(disposable); + disposables.push(disposable); + loadButton({ + command: vsCommand, + name, + tooltip: tooltip || command, + color: color || defaultColor, + }); + }); + } + else { + vscode.window.setStatusBarMessage('VsCode Action Buttons: You have no run commands.', 4000); + } +}; +function loadButton({ command, name, tooltip, color, }) { + const runButton = vscode.window.createStatusBarItem(1, 0); + runButton.text = name; + runButton.color = color; + runButton.tooltip = tooltip; + runButton.command = command; + runButton.show(); + disposables.push(runButton); +} +function interpolateString(tpl, data) { + let re = /\$\{([^\}]+)\}/g, match; + while (match = re.exec(tpl)) { + let path = match[1].split('.').reverse(); + //@ts-ignore + let obj = data[path.pop()]; + while (path.length) + obj = obj[path.pop()]; + tpl = tpl.replace(match[0], obj); + } + return tpl; +} +exports.default = init; +//# sourceMappingURL=init.js.map \ No newline at end of file diff --git a/packages/engine.vscode/out/init.js.map b/packages/engine.vscode/out/init.js.map new file mode 100644 index 00000000..5aae82a9 --- /dev/null +++ b/packages/engine.vscode/out/init.js.map @@ -0,0 +1 @@ +{"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/engine.vscode/out/packageJson.js b/packages/engine.vscode/out/packageJson.js new file mode 100644 index 00000000..fd5fb487 --- /dev/null +++ b/packages/engine.vscode/out/packageJson.js @@ -0,0 +1,30 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.buildConfigFromPackageJson = exports.getPackageJson = void 0; +const vscode_1 = require("vscode"); +const getPackageJson = async () => new Promise(resolve => { + const cwd = vscode_1.workspace.rootPath; + try { + const packageJson = require(`${cwd}/package.json`); + resolve(packageJson); + } + catch (e) { + resolve(undefined); + } +}); +exports.getPackageJson = getPackageJson; +const buildConfigFromPackageJson = async (defaultColor) => { + const pkg = await (0, exports.getPackageJson)(); + if (!pkg) { + return []; + } + const { scripts } = pkg; + return Object.keys(scripts).map(key => ({ + command: `npm run ${key}`, + color: defaultColor || 'white', + name: key, + singleInstance: true + })); +}; +exports.buildConfigFromPackageJson = buildConfigFromPackageJson; +//# sourceMappingURL=packageJson.js.map \ No newline at end of file diff --git a/packages/engine.vscode/out/packageJson.js.map b/packages/engine.vscode/out/packageJson.js.map new file mode 100644 index 00000000..dce0d3d4 --- /dev/null +++ b/packages/engine.vscode/out/packageJson.js.map @@ -0,0 +1 @@ +{"version":3,"file":"packageJson.js","sourceRoot":"","sources":["../src/packageJson.ts"],"names":[],"mappings":";;;AACA,mCAAkC;AAE3B,MAAM,cAAc,GAAG,KAAK,IAA8B,EAAE,CAClE,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE;IACrB,MAAM,GAAG,GAAG,kBAAS,CAAC,QAAQ,CAAA;IAE9B,IAAI;QACH,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,GAAG,eAAe,CAAC,CAAA;QAElD,OAAO,CAAC,WAAW,CAAC,CAAA;KACpB;IAAC,OAAO,CAAC,EAAE;QACX,OAAO,CAAC,SAAS,CAAC,CAAA;KAClB;AACF,CAAC,CAAC,CAAA;AAXU,QAAA,cAAc,kBAWxB;AAEI,MAAM,0BAA0B,GAAG,KAAK,EAAE,YAAoB,EAAE,EAAE;IACxE,MAAM,GAAG,GAAG,MAAM,IAAA,sBAAc,GAAE,CAAA;IAClC,IAAI,CAAC,GAAG,EAAE;QACT,OAAO,EAAE,CAAA;KACT;IACD,MAAM,EAAE,OAAO,EAAE,GAAG,GAAG,CAAA;IAEvB,OAAO,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACvC,OAAO,EAAE,WAAW,GAAG,EAAE;QACzB,KAAK,EAAE,YAAY,IAAI,OAAO;QAC9B,IAAI,EAAE,GAAG;QACT,cAAc,EAAE,IAAI;KACpB,CAAC,CAAkB,CAAA;AACrB,CAAC,CAAA;AAbY,QAAA,0BAA0B,8BAatC"} \ No newline at end of file diff --git a/packages/engine.vscode/out/types.js b/packages/engine.vscode/out/types.js new file mode 100644 index 00000000..11e638d1 --- /dev/null +++ b/packages/engine.vscode/out/types.js @@ -0,0 +1,3 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/packages/engine.vscode/out/types.js.map b/packages/engine.vscode/out/types.js.map new file mode 100644 index 00000000..c768b790 --- /dev/null +++ b/packages/engine.vscode/out/types.js.map @@ -0,0 +1 @@ +{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/packages/engine.vscode/package.json b/packages/engine.vscode/package.json new file mode 100644 index 00000000..4e67d69d --- /dev/null +++ b/packages/engine.vscode/package.json @@ -0,0 +1,144 @@ +{ + "name": "@c11/engine.vscode", + "description": "Visual Studio Code for @c11/engine.dashboard", + "version": "0.0.1", + "private": true, + "license": "MIT", + "engines": { + "vscode": "^1.47.0" + }, + "categories": [ + "Other" + ], + "activationEvents": [ + "*" + ], + "main": "./out/extension.js", + "contributes": { + "commands": [ + { + "command": "engine.dashboard.start", + "title": "Start engine dashboard", + "category": "Engine Dashboard" + }, + { + "command": "extension.refreshButtons", + "title": "Refresh Action Buttons" + } + ], + "configuration": { + "type": "object", + "title": "VsCode Action Buttons", + "properties": { + "actionButtons": { + "type": "object", + "additionalProperties": false, + "default": { + "commands": [], + "defaultColor": "white", + "reloadButton": "↻", + "loadNpmCommands": false + }, + "properties": { + "commands": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "name", + "command" + ], + "properties": { + "name": { + "type": "string", + "markdownDescription": "Name of the action button" + }, + "saveAll": { + "type": "boolean", + "markdownDescription": "Save all open files before execute command" + }, + "command": { + "type": "string", + "markdownDescription": "Command to execute when action is activated.\n\nIf `useVsCodeApi` is `true`, this is the VS Code command to execute. Otherwise, this specifies the command to execute in the terminal" + }, + "tooltip": { + "type": "string", + "markdownDescription": "Tooltip text to display when hovering over the button" + }, + "color": { + "type": "string", + "markdownDescription": "Specifies the action button text color" + }, + "cwd": { + "type": "string", + "markdownDescription": "Start directory when executing terminal command\n\nOnly valid when `useVsCodeApi` is `false`" + }, + "singleInstance": { + "type": "boolean", + "default": false, + "markdownDescription": "Reopen associated terminal each time this action is activated\n\nOnly valid when `useVsCodeApi` is `false`" + }, + "focus": { + "type": "boolean", + "default": false, + "markdownDescription": "Focus the terminal after executing the command.\n\nOnly valid when `useVsCodeApi` is `false`" + }, + "useVsCodeApi": { + "type": "boolean", + "default": false, + "markdownDescription": "Specifies whether to execute a VS Code command or terminal command" + }, + "args": { + "type": "array", + "items": { + "type": "string" + }, + "default": [], + "markdownDescription": "List of arguments passed to VS Code command\n\nOnly valid when `useVsCodeApi` is `true`" + } + } + } + }, + "defaultColor": { + "type": "string", + "required": false, + "default": "white", + "markdownDescription": "Default color to use for action button text" + }, + "reloadButton": { + "type": [ + "string", + "null" + ], + "required": false, + "default": "↻", + "markdownDescription": "Reload button text. If `null`, button is disabled" + }, + "loadNpmCommands": { + "type": "boolean", + "required": false, + "default": false, + "markdownDescription": "Specifies whether to automatically generate buttons from npm commands listed in `package.json`" + } + } + } + } + } + }, + "scripts": { + "vscode:prepublish": "npm run compile", + "compile": "tsc -p ./", + "lint": "eslint . --ext .ts,.tsx", + "watch": "tsc -w -p ./" + }, + "devDependencies": { + "@types/node": "^16.11.7", + "@types/vscode": "^1.47.0", + "@types/vscode-webview": "^1.57.0", + "@typescript-eslint/eslint-plugin": "^5.30.0", + "@typescript-eslint/parser": "^5.30.0", + "eslint": "^8.13.0", + "typescript": "^4.7.2" + } +} \ No newline at end of file diff --git a/packages/engine.vscode/src/bla.html b/packages/engine.vscode/src/bla.html new file mode 100644 index 00000000..759ab09a --- /dev/null +++ b/packages/engine.vscode/src/bla.html @@ -0,0 +1,27 @@ + + + + + + + + Engine Dashboard + + + + + + + + \ No newline at end of file diff --git a/packages/engine.vscode/src/extension.ts b/packages/engine.vscode/src/extension.ts new file mode 100644 index 00000000..a84b0125 --- /dev/null +++ b/packages/engine.vscode/src/extension.ts @@ -0,0 +1,227 @@ +import * as vscode from 'vscode'; +import init from './init' + +export function activate(context: vscode.ExtensionContext) { + init(context) + + context.subscriptions.push( + vscode.commands.registerCommand('engine.dashboard.start', () => { + EngineDashboardPanel.createOrShow(context.extensionUri); + }) + ); + + context.subscriptions.push(vscode.commands.registerCommand( + 'extension.refreshButtons', + () => { + init(context) + } + )) + + // context.subscriptions.push( + // vscode.commands.registerCommand('catCoding.doRefactor', () => { + // if (CatCodingPanel.currentPanel) { + // CatCodingPanel.currentPanel.doRefactor(); + // } + // }) + // ); + + if (vscode.window.registerWebviewPanelSerializer) { + // Make sure we register a serializer in activation event + vscode.window.registerWebviewPanelSerializer(EngineDashboardPanel.viewType, { + async deserializeWebviewPanel(webviewPanel: vscode.WebviewPanel, state: any) { + console.log(`Got state: ${state}`); + // Reset the webview options so we use latest uri for `localResourceRoots`. + webviewPanel.webview.options = getWebviewOptions(context.extensionUri); + EngineDashboardPanel.revive(webviewPanel, context.extensionUri); + } + }); + } +} + +function getWebviewOptions(extensionUri: vscode.Uri): vscode.WebviewOptions { + return { + // Enable javascript in the webview + enableScripts: true, + + // And restrict the webview to only loading content from our extension's `media` directory. + localResourceRoots: [vscode.Uri.joinPath(extensionUri, 'media')] + }; +} + +/** + * Manages cat coding webview panels + */ +class EngineDashboardPanel { + /** + * Track the currently panel. Only allow a single panel to exist at a time. + */ + public static currentPanel: EngineDashboardPanel | undefined; + + public static readonly viewType = 'engineDashboard'; + + private readonly _panel: vscode.WebviewPanel; + private readonly _extensionUri: vscode.Uri; + private _disposables: vscode.Disposable[] = []; + + public static createOrShow(extensionUri: vscode.Uri) { + const column = vscode.window.activeTextEditor + ? vscode.window.activeTextEditor.viewColumn + : undefined; + + // If we already have a panel, show it. + if (EngineDashboardPanel.currentPanel) { + EngineDashboardPanel.currentPanel._panel.reveal(column); + return; + } + + // Otherwise, create a new panel. + const panel = vscode.window.createWebviewPanel( + EngineDashboardPanel.viewType, + 'Engine Dashboard', + column || vscode.ViewColumn.One, + { + enableScripts: true, + retainContextWhenHidden: true, + localResourceRoots: [vscode.Uri.joinPath(extensionUri, 'media')] + } + ); + + EngineDashboardPanel.currentPanel = new EngineDashboardPanel(panel, extensionUri); + } + + public static revive(panel: vscode.WebviewPanel, extensionUri: vscode.Uri) { + EngineDashboardPanel.currentPanel = new EngineDashboardPanel(panel, extensionUri); + } + + private constructor(panel: vscode.WebviewPanel, extensionUri: vscode.Uri) { + this._panel = panel; + this._extensionUri = extensionUri; + + // Set the webview's initial html content + this._update(); + + // Listen for when the panel is disposed + // This happens when the user closes the panel or when the panel is closed programmatically + this._panel.onDidDispose(() => this.dispose(), null, this._disposables); + + // Update the content based on view changes + this._panel.onDidChangeViewState( + e => { + if (this._panel.visible) { + this._update(); + } + }, + null, + this._disposables + ); + + // Handle messages from the webview + this._panel.webview.onDidReceiveMessage( + message => { + switch (message.command) { + case 'alert': + vscode.window.showErrorMessage(message.text); + return; + } + }, + null, + this._disposables + ); + } + + public doRefactor() { + // Send a message to the webview webview. + // You can send any JSON serializable data. + this._panel.webview.postMessage({ command: 'refactor' }); + } + + public dispose() { + EngineDashboardPanel.currentPanel = undefined; + + // Clean up our resources + this._panel.dispose(); + + while (this._disposables.length) { + const x = this._disposables.pop(); + if (x) { + x.dispose(); + } + } + } + + private _update() { + const webview = this._panel.webview; + + // Vary the webview's content based on where it is located in the editor. + switch (this._panel.viewColumn) { + // case vscode.ViewColumn.Two: + // this._updateForCat(webview, 'Compiling Cat'); + // return; + + // case vscode.ViewColumn.Three: + // this._updateForCat(webview, 'Testing Cat'); + // return; + + // case vscode.ViewColumn.One: + default: + this._updateForCat(webview, 'Engine Dashboard'); + return; + } + } + + private _updateForCat(webview: vscode.Webview, catName: string) { + this._panel.title = catName; + this._panel.webview.html = this._getHtmlForWebview(webview, catName); + } + + private _getHtmlForWebview(webview: vscode.Webview, catGifPath: string) { + // Local path to main script run in the webview + const scriptPathOnDisk = vscode.Uri.joinPath(this._extensionUri, 'media', 'main.js'); + + // And the uri we use to load this script in the webview + const scriptUri = webview.asWebviewUri(scriptPathOnDisk); + + // Local path to css styles + const styleResetPath = vscode.Uri.joinPath(this._extensionUri, 'media', 'reset.css'); + const stylesPathMainPath = vscode.Uri.joinPath(this._extensionUri, 'media', 'vscode.css'); + + // Uri to load styles into webview + const stylesResetUri = webview.asWebviewUri(styleResetPath); + const stylesMainUri = webview.asWebviewUri(stylesPathMainPath); + + // Use a nonce to only allow specific scripts to be run + const nonce = getNonce(); + + return ` + + + + + + + + + Engine Dashboard + + + + +

0

+ + + + `; + } +} + +function getNonce() { + let text = ''; + const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + for (let i = 0; i < 32; i++) { + text += possible.charAt(Math.floor(Math.random() * possible.length)); + } + return text; +} diff --git a/packages/engine.vscode/src/init.ts b/packages/engine.vscode/src/init.ts new file mode 100644 index 00000000..62df622b --- /dev/null +++ b/packages/engine.vscode/src/init.ts @@ -0,0 +1,182 @@ +import { buildConfigFromPackageJson } from './packageJson' +import * as vscode from 'vscode' +import { ButtonOpts, CommandOpts } from './types' +import * as path from 'path' + +const registerCommand = vscode.commands.registerCommand + +const disposables: Array = [] + +const init = async (context: vscode.ExtensionContext) => { + disposables.forEach(d => d.dispose()) + const config = vscode.workspace.getConfiguration('actionButtons') + const defaultColor = config.get('defaultColor') || "green" + const cmds = config.get('commands') + // const reloadButton = config.get('reloadButton') + const loadNpmCommands = config.get('loadNpmCommands') + const reloadButton = true + // const defaultColor = "green" + // const cmds: Array = [ { + // // "cwd": "/home/custom_folder", // Terminal initial folder ${workspaceFolder} and os user home as defaults + // "name": "Start Engine Dashboard", + // "color": "green", + // "singleInstance": true, + // "command": "yarn dashboard", // This is executed in the terminal. + // "tooltip": "" + // }] + const commands: CommandOpts[] = [] + + if (reloadButton !== null) { + loadButton({ + command: 'extension.refreshButtons', + name: "Refresh commands", + tooltip: 'Refreshes the action buttons', + color: defaultColor + }) + } + else { + const onCfgChange:vscode.Disposable = vscode.workspace.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('actionButtons')) { + vscode.commands.executeCommand('extension.refreshButtons'); + } + }); + context.subscriptions.push(onCfgChange) + disposables.push(onCfgChange); + } + + if (cmds && cmds.length) { + commands.push(...cmds) + } + + // if (loadNpmCommands !== false) + commands.push(...(await buildConfigFromPackageJson(defaultColor))) + + if (commands.length) { + const terminals: { [name: string]: vscode.Terminal } = {} + commands.forEach( + ({ cwd, saveAll, command, name, tooltip, color, singleInstance, focus, useVsCodeApi, args }: CommandOpts) => { + const vsCommand = `extension.${name.replace(' ', '')}` + + const disposable = registerCommand(vsCommand, async () => { + const vars = { + + // - the path of the folder opened in VS Code + workspaceFolder: vscode.workspace.rootPath, + + // - the name of the folder opened in VS Code without any slashes (/) + workspaceFolderBasename: (vscode.workspace.rootPath)? path.basename(vscode.workspace.rootPath) : null, + + // - the current opened file + file: (vscode.window.activeTextEditor) ? vscode.window.activeTextEditor.document.fileName : null, + + // - the current opened file relative to workspaceFolder + relativeFile: (vscode.window.activeTextEditor && vscode.workspace.rootPath) ? path.relative( + vscode.workspace.rootPath, + vscode.window.activeTextEditor.document.fileName + ) : null, + + // - the current opened file's basename + fileBasename: (vscode.window.activeTextEditor) ? path.basename(vscode.window.activeTextEditor.document.fileName) : null, + + // - the current opened file's basename with no file extension + fileBasenameNoExtension: (vscode.window.activeTextEditor) ? path.parse(path.basename(vscode.window.activeTextEditor.document.fileName)).name : null, + + // - the current opened file's dirname + fileDirname: (vscode.window.activeTextEditor) ? path.dirname(vscode.window.activeTextEditor.document.fileName) : null, + + // - the current opened file's extension + fileExtname: (vscode.window.activeTextEditor) ? path.parse(path.basename(vscode.window.activeTextEditor.document.fileName)).ext : null, + + // - the task runner's current working directory on startup + cwd: cwd || vscode.workspace.rootPath || require('os').homedir(), + + //- the current selected line number in the active file + lineNumber: (vscode.window.activeTextEditor) ? vscode.window.activeTextEditor.selection.active.line + 1 : null, + + // - the current selected text in the active file + selectedText: (vscode.window.activeTextEditor) ? vscode.window.activeTextEditor.document.getText(vscode.window.activeTextEditor.selection) : null, + + // - the path to the running VS Code executable + execPath: process.execPath + } + + if (!command) { + vscode.window.showErrorMessage('No command to execute for this action'); + return; + } + + if (saveAll) { + vscode.commands.executeCommand('workbench.action.files.saveAll'); + } + + if (useVsCodeApi) { + vscode.commands.executeCommand(command, ...(args || [])); + } else { + let assocTerminal = terminals[vsCommand] + if (!assocTerminal) { + assocTerminal = vscode.window.createTerminal({ name, cwd: vars.cwd }); + terminals[vsCommand] = assocTerminal; + } else { + if (singleInstance) { + delete terminals[vsCommand]; + assocTerminal.dispose(); + assocTerminal = vscode.window.createTerminal({ name, cwd: vars.cwd }); + terminals[vsCommand] = assocTerminal; + } else { + assocTerminal.sendText('clear'); + } + } + assocTerminal.show(!focus); + assocTerminal.sendText(interpolateString(command, vars)); + } + }) + + context.subscriptions.push(disposable) + + disposables.push(disposable) + + loadButton({ + command: vsCommand, + name, + tooltip: tooltip || command, + color: color || defaultColor, + }) + } + ) + } else { + vscode.window.setStatusBarMessage( + 'VsCode Action Buttons: You have no run commands.', + 4000 + ) + } +} + +function loadButton({ + command, + name, + tooltip, + color, +}: ButtonOpts) { + const runButton = vscode.window.createStatusBarItem(1, 0) + runButton.text = name + runButton.color = color + runButton.tooltip = tooltip + + runButton.command = command + runButton.show() + disposables.push(runButton) +} + +function interpolateString(tpl: string, data: object): string { + let re = /\$\{([^\}]+)\}/g, match; + while (match = re.exec(tpl)) { + let path = match[1].split('.').reverse(); + //@ts-ignore + let obj = data[path.pop()]; + while (path.length) obj = obj[path.pop()]; + tpl = tpl.replace(match[0], obj) + } + return tpl; +} + +export default init \ No newline at end of file diff --git a/packages/engine.vscode/src/packageJson.ts b/packages/engine.vscode/src/packageJson.ts new file mode 100644 index 00000000..91c8a814 --- /dev/null +++ b/packages/engine.vscode/src/packageJson.ts @@ -0,0 +1,30 @@ +import { CommandOpts } from './types' +import { workspace } from 'vscode' + +export const getPackageJson = async (): Promise => + new Promise(resolve => { + const cwd = workspace.rootPath + + try { + const packageJson = require(`${cwd}/package.json`) + + resolve(packageJson) + } catch (e) { + resolve(undefined) + } + }) + +export const buildConfigFromPackageJson = async (defaultColor: string) => { + const pkg = await getPackageJson() + if (!pkg) { + return [] + } + const { scripts } = pkg + + return Object.keys(scripts).map(key => ({ + command: `npm run ${key}`, + color: defaultColor || 'white', + name: key, + singleInstance: true + })) as CommandOpts[] +} \ No newline at end of file diff --git a/packages/engine.vscode/src/types.ts b/packages/engine.vscode/src/types.ts new file mode 100644 index 00000000..6bb6d587 --- /dev/null +++ b/packages/engine.vscode/src/types.ts @@ -0,0 +1,19 @@ +export interface CommandOpts { + cwd?: string + saveAll?: boolean + command: string + singleInstance?: boolean + name: string + tooltip: string + color: string + focus?: boolean + useVsCodeApi?: boolean + args?: string[] +} + +export interface ButtonOpts { + command: string + tooltip: string + name: string + color: string +} \ No newline at end of file diff --git a/packages/engine.vscode/tsconfig.json b/packages/engine.vscode/tsconfig.json new file mode 100644 index 00000000..9a3f5254 --- /dev/null +++ b/packages/engine.vscode/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es2020", + "lib": ["es2020"], + "outDir": "out", + "sourceMap": true, + "strict": true, + "rootDir": "src" + }, + "exclude": ["node_modules", ".vscode-test"] +}