From 0db8b0bd69f962919dee95226f95194c14816933 Mon Sep 17 00:00:00 2001 From: Tetsuharu Ohzeki Date: Tue, 11 Jul 2023 01:12:44 +0900 Subject: [PATCH 1/7] editor/code: Sort the indent size --- editors/code/.prettierrc.js | 1 + editors/code/README.md | 18 +++++++++--------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/editors/code/.prettierrc.js b/editors/code/.prettierrc.js index cafb12f0e6dd..b38dc40bdb73 100644 --- a/editors/code/.prettierrc.js +++ b/editors/code/.prettierrc.js @@ -2,4 +2,5 @@ module.exports = { // use 100 because it's Rustfmt's default // https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#max_width printWidth: 100, + tabWidth: 4, }; diff --git a/editors/code/README.md b/editors/code/README.md index 36ab98188220..eeb6b65653ee 100644 --- a/editors/code/README.md +++ b/editors/code/README.md @@ -5,15 +5,15 @@ It is recommended over and replaces `rust-lang.rust`. ## Features -- [code completion] with [imports insertion] -- go to [definition], [implementation], [type definition] -- [find all references], [workspace symbol search], [symbol renaming] -- [types and documentation on hover] -- [inlay hints] for types and parameter names -- [semantic syntax highlighting] -- a lot of [assists (code actions)] -- apply suggestions from errors -- ... and many more, check out the [manual] to see them all +- [code completion] with [imports insertion] +- go to [definition], [implementation], [type definition] +- [find all references], [workspace symbol search], [symbol renaming] +- [types and documentation on hover] +- [inlay hints] for types and parameter names +- [semantic syntax highlighting] +- a lot of [assists (code actions)] +- apply suggestions from errors +- ... and many more, check out the [manual] to see them all [code completion]: https://rust-analyzer.github.io/manual.html#magic-completions [imports insertion]: https://rust-analyzer.github.io/manual.html#completion-with-autoimport From 6efe9cdd265ad381b4ac2dde6072e3bbfcf58f53 Mon Sep 17 00:00:00 2001 From: Tetsuharu Ohzeki Date: Tue, 11 Jul 2023 00:29:03 +0900 Subject: [PATCH 2/7] editor/code: Use build script invoking esbuild instead of invoking CLI --- editors/code/build.mjs | 60 +++++++++++++++++++++++++++++++ editors/code/package.json | 2 +- editors/code/tsconfig.eslint.json | 3 +- 3 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 editors/code/build.mjs diff --git a/editors/code/build.mjs b/editors/code/build.mjs new file mode 100644 index 000000000000..d21cfebf75e3 --- /dev/null +++ b/editors/code/build.mjs @@ -0,0 +1,60 @@ +import * as path from "node:path"; +import { parseArgs } from "node:util"; +import * as esbuild from "esbuild"; + +function parseCliOptions() { + const { values } = parseArgs({ + options: { + minify: { + type: "boolean", + default: false, + }, + sourcemap: { + type: "boolean", + default: false, + }, + watch: { + type: "boolean", + default: false, + }, + }, + strict: true, + }); + return { + shouldMinify: !!values.minify, + shouldEmitSourceMap: !!values.sourcemap, + isWatchMode: !!values.watch, + }; +} + +const { shouldMinify, shouldEmitSourceMap, isWatchMode } = parseCliOptions(); + +const OUT_DIR = "./out"; + +function createBuildOption(entryPoints) { + /** @type {esbuild.BuildOptions} */ + const options = { + entryPoints, + minify: shouldMinify, + sourcemap: shouldEmitSourceMap ? "external" : false, + bundle: true, + external: ["vscode"], + format: "cjs", + platform: "node", + target: "node16", + outdir: OUT_DIR, + }; + return options; +} + +async function bundleSource(options) { + if (!isWatchMode) { + return esbuild.build(options); + } + + const ctx = await esbuild.context(options); + return ctx.watch(); +} + +const extensionMain = bundleSource(createBuildOption(["src/main.ts"])); +await Promise.all([extensionMain]); diff --git a/editors/code/package.json b/editors/code/package.json index 76d7e91f3810..637fe3246ce5 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -32,7 +32,7 @@ "scripts": { "vscode:prepublish": "npm run build-base -- --minify", "package": "vsce package -o rust-analyzer.vsix", - "build-base": "esbuild ./src/main.ts --bundle --outfile=out/main.js --external:vscode --format=cjs --platform=node --target=node16", + "build-base": "node ./build.mjs", "build": "npm run build-base -- --sourcemap", "watch": "npm run build-base -- --sourcemap --watch", "format": "prettier --write .", diff --git a/editors/code/tsconfig.eslint.json b/editors/code/tsconfig.eslint.json index 5e2b33ca39f8..21f38c40c853 100644 --- a/editors/code/tsconfig.eslint.json +++ b/editors/code/tsconfig.eslint.json @@ -6,6 +6,7 @@ "src", "tests", // these are the eslint-only inclusions - ".eslintrc.js" + ".eslintrc.js", + "./build.mjs" ] } From 9f98c3308d149e32755d75e884ab617e95693fbb Mon Sep 17 00:00:00 2001 From: Tetsuharu Ohzeki Date: Tue, 11 Jul 2023 00:57:47 +0900 Subject: [PATCH 3/7] editor/code: Allow to Type Checking "view memory layout" webview code --- editors/code/.vscodeignore | 1 + editors/code/build.mjs | 38 ++- editors/code/src/commands.ts | 250 +----------------- editors/code/src/uri.ts | 12 + .../code/src/webview/view_memory_layout.css | 113 ++++++++ .../code/src/webview/view_memory_layout.ts | 152 +++++++++++ editors/code/tsconfig.json | 1 - 7 files changed, 321 insertions(+), 246 deletions(-) create mode 100644 editors/code/src/uri.ts create mode 100644 editors/code/src/webview/view_memory_layout.css create mode 100644 editors/code/src/webview/view_memory_layout.ts diff --git a/editors/code/.vscodeignore b/editors/code/.vscodeignore index 09dc27056b37..05954c4fd385 100644 --- a/editors/code/.vscodeignore +++ b/editors/code/.vscodeignore @@ -7,6 +7,7 @@ !node_modules/d3-graphviz/build/d3-graphviz.min.js !node_modules/d3/dist/d3.min.js !out/main.js +!out/webview/ !package-lock.json !package.json !ra_syntax_tree.tmGrammar.json diff --git a/editors/code/build.mjs b/editors/code/build.mjs index d21cfebf75e3..42a5ceb2699b 100644 --- a/editors/code/build.mjs +++ b/editors/code/build.mjs @@ -30,14 +30,20 @@ function parseCliOptions() { const { shouldMinify, shouldEmitSourceMap, isWatchMode } = parseCliOptions(); const OUT_DIR = "./out"; +const OUT_WEBVIEW_DIR = path.resolve(OUT_DIR, "webview"); + +/** @type {esbuild.BuildOptions} */ +const BASE_OPTIONS = { + minify: shouldMinify, + sourcemap: shouldEmitSourceMap ? "external" : false, + bundle: true, +}; function createBuildOption(entryPoints) { /** @type {esbuild.BuildOptions} */ const options = { + ...BASE_OPTIONS, entryPoints, - minify: shouldMinify, - sourcemap: shouldEmitSourceMap ? "external" : false, - bundle: true, external: ["vscode"], format: "cjs", platform: "node", @@ -47,6 +53,21 @@ function createBuildOption(entryPoints) { return options; } +function createBuildOptionForWebView(entryPoints) { + /** @type {esbuild.BuildOptions} */ + const options = { + ...BASE_OPTIONS, + entryPoints, + format: "esm", + platform: "browser", + // VSCode v1.78 (Electron 22) uses Chromium 108. + // https://code.visualstudio.com/updates/v1_78 + target: "chrome108", + outdir: OUT_WEBVIEW_DIR, + }; + return options; +} + async function bundleSource(options) { if (!isWatchMode) { return esbuild.build(options); @@ -56,5 +77,12 @@ async function bundleSource(options) { return ctx.watch(); } -const extensionMain = bundleSource(createBuildOption(["src/main.ts"])); -await Promise.all([extensionMain]); +await Promise.all([ + bundleSource(createBuildOption(["src/main.ts"])), + bundleSource( + createBuildOptionForWebView([ + "src/webview/view_memory_layout.ts", + "src/webview/view_memory_layout.css", + ]), + ), +]); diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts index e21f536f26aa..7d958b7ed807 100644 --- a/editors/code/src/commands.ts +++ b/editors/code/src/commands.ts @@ -21,6 +21,7 @@ import type { LanguageClient } from "vscode-languageclient/node"; import { LINKED_COMMANDS } from "./client"; import type { DependencyId } from "./dependencies_provider"; import { unwrapUndefinable } from "./undefinable"; +import { getWebViewModulePath } from "./uri"; export * from "./ast_inspector"; export * from "./run"; @@ -1142,265 +1143,34 @@ export function viewMemoryLayout(ctx: CtxInit): Cmd { position, }); + const webviewModulePath = getWebViewModulePath(ctx); + const document = vscode.window.createWebviewPanel( "memory_layout", "[Memory Layout]", vscode.ViewColumn.Two, { enableScripts: true }, + { enableScripts: true, localResourceRoots: [webviewModulePath] }, ); + const uri = document.webview.asWebviewUri(webviewModulePath); + document.webview.html = ` - Document - +
- `; diff --git a/editors/code/src/uri.ts b/editors/code/src/uri.ts new file mode 100644 index 000000000000..80e459ffc3c1 --- /dev/null +++ b/editors/code/src/uri.ts @@ -0,0 +1,12 @@ +import * as path from "node:path"; +import { Uri } from "vscode"; +import type { CtxInit } from "./ctx"; + +function getBundledAssetsUri(ctx: CtxInit, pathname: string): Uri { + const resolved = path.join(ctx.extensionPath, pathname); + return Uri.file(resolved); +} + +export function getWebViewModulePath(ctx: CtxInit) { + return getBundledAssetsUri(ctx, "out/webview"); +} diff --git a/editors/code/src/webview/view_memory_layout.css b/editors/code/src/webview/view_memory_layout.css new file mode 100644 index 000000000000..a5df65dee252 --- /dev/null +++ b/editors/code/src/webview/view_memory_layout.css @@ -0,0 +1,113 @@ +* { + box-sizing: border-box; +} + +body { + margin: 0; + overflow: hidden; + min-height: 100%; + height: 100vh; + padding: 32px; + position: relative; + display: block; + + background-color: var(--vscode-editor-background); + font-family: var(--vscode-editor-font-family); + font-size: var(--vscode-editor-font-size); + color: var(--vscode-editor-foreground); +} + +.container { + position: relative; +} + +.trans { + transition: all 0.2s ease-in-out; +} + +.grid { + height: 100%; + position: relative; + color: var(--vscode-commandCenter-activeBorder); + pointer-events: none; +} + +.grid-line { + position: absolute; + width: 100%; + height: 1px; + background-color: var(--vscode-commandCenter-activeBorder); +} + +#tooltip { + position: fixed; + display: none; + z-index: 1; + pointer-events: none; + padding: 4px 8px; + z-index: 2; + + color: var(--vscode-editorHoverWidget-foreground); + background-color: var(--vscode-editorHoverWidget-background); + border: 1px solid var(--vscode-editorHoverWidget-border); +} + +#tooltip b { + color: var(--vscode-editorInlayHint-typeForeground); +} + +#tooltip ul { + margin-left: 0; + padding-left: 20px; +} + +table { + position: absolute; + transform: rotateZ(90deg) rotateX(180deg); + transform-origin: top left; + border-collapse: collapse; + table-layout: fixed; + left: 48px; + top: 0; + max-height: calc(100vw - 64px - 48px); + z-index: 1; +} + +td { + border: 1px solid var(--vscode-focusBorder); + writing-mode: vertical-rl; + text-orientation: sideways-right; + + height: 80px; +} + +td p { + height: calc(100% - 16px); + width: calc(100% - 8px); + margin: 8px 4px; + display: inline-block; + transform: rotateY(180deg); + pointer-events: none; + overflow: hidden; +} + +td p * { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + display: inline-block; + height: 100%; +} + +td p b { + color: var(--vscode-editorInlayHint-typeForeground); +} + +td:hover { + background-color: var(--vscode-editor-hoverHighlightBackground); +} + +td:empty { + visibility: hidden; + border: 0; +} diff --git a/editors/code/src/webview/view_memory_layout.ts b/editors/code/src/webview/view_memory_layout.ts new file mode 100644 index 000000000000..dd64676677c8 --- /dev/null +++ b/editors/code/src/webview/view_memory_layout.ts @@ -0,0 +1,152 @@ +// @ts-nocheck + +export function showMemoryLayout(data): void { + if (!(data && data.nodes.length)) { + document.body.innerText = "Not Available"; + return; + } + + data.nodes.map((n) => { + n.typename = n.typename + .replaceAll("&", "&") + .replaceAll("<", "<") + .replaceAll(">", ">") + .replaceAll('"', " & quot; ") + .replaceAll("'", "'"); + return n; + }); + + let height = window.innerHeight - 64; + + window.addEventListener("resize", (e) => { + const newHeight = window.innerHeight - 64; + height = newHeight; + container.classList.remove("trans"); + table.classList.remove("trans"); + locate(); + setTimeout(() => { + // give delay to redraw, annoying but needed + container.classList.add("trans"); + table.classList.add("trans"); + }, 0); + }); + + const container = document.createElement("div"); + container.classList.add("container"); + container.classList.add("trans"); + document.body.appendChild(container); + + const tooltip = document.getElementById("tooltip"); + + let y = 0; + let zoom = 1.0; + + const table = document.createElement("table"); + table.classList.add("trans"); + container.appendChild(table); + const rows = []; + + // eslint-disable-next-line camelcase + function node_t(idx, depth, offset) { + if (!rows[depth]) { + rows[depth] = { el: document.createElement("tr"), offset: 0 }; + } + + if (rows[depth].offset < offset) { + const pad = document.createElement("td"); + pad.colSpan = offset - rows[depth].offset; + rows[depth].el.appendChild(pad); + rows[depth].offset += offset - rows[depth].offset; + } + + const td = document.createElement("td"); + td.innerHTML = + "

" + + data.nodes[idx].itemName + + ": " + + data.nodes[idx].typename + + "

"; + + td.colSpan = data.nodes[idx].size; + + td.addEventListener("mouseover", (e) => { + const node = data.nodes[idx]; + tooltip.innerHTML = + node.itemName + + ": " + + node.typename + + "
" + + "
    " + + "
  • size = " + + node.size + + "
  • " + + "
  • align = " + + node.alignment + + "
  • " + + "
  • field offset = " + + node.offset + + "
  • " + + "
" + + "double click to focus"; + + tooltip.style.display = "block"; + }); + td.addEventListener("mouseleave", (_) => (tooltip.style.display = "none")); + // eslint-disable-next-line camelcase + const total_offset = rows[depth].offset; + td.addEventListener("dblclick", (e) => { + const node = data.nodes[idx]; + zoom = data.nodes[0].size / node.size; + // eslint-disable-next-line camelcase + y = (-total_offset / data.nodes[0].size) * zoom; + x = 0; + locate(); + }); + + rows[depth].el.appendChild(td); + rows[depth].offset += data.nodes[idx].size; + + // eslint-disable-next-line eqeqeq + if (data.nodes[idx].childrenStart != -1) { + for (let i = 0; i < data.nodes[idx].childrenLen; i++) { + if (data.nodes[data.nodes[idx].childrenStart + i].size) { + node_t( + data.nodes[idx].childrenStart + i, + depth + 1, + offset + data.nodes[data.nodes[idx].childrenStart + i].offset, + ); + } + } + } + } + + node_t(0, 0, 0); + + for (const row of rows) table.appendChild(row.el); + + const grid = document.createElement("div"); + grid.classList.add("grid"); + container.appendChild(grid); + + for (let i = 0; i < data.nodes[0].size / 8 + 1; i++) { + const el = document.createElement("div"); + el.classList.add("grid-line"); + el.style.top = (i / (data.nodes[0].size / 8)) * 100 + "%"; + el.innerText = i * 8; + grid.appendChild(el); + } + + window.addEventListener("mousemove", (e) => { + tooltip.style.top = e.clientY + 10 + "px"; + tooltip.style.left = e.clientX + 10 + "px"; + }); + + function locate() { + container.style.top = height * y + "px"; + container.style.height = height * zoom + "px"; + + table.style.width = container.style.height; + } + + locate(); +} diff --git a/editors/code/tsconfig.json b/editors/code/tsconfig.json index ee353c28dd67..f06a9d9111cc 100644 --- a/editors/code/tsconfig.json +++ b/editors/code/tsconfig.json @@ -6,7 +6,6 @@ "moduleResolution": "node16", "target": "es2021", "outDir": "out", - "lib": ["es2021"], "sourceMap": true, "rootDir": ".", "newLine": "LF", From a7d734377fbf574ae7a7fa3e967f6c60b1e35038 Mon Sep 17 00:00:00 2001 From: Tetsuharu Ohzeki Date: Tue, 11 Jul 2023 00:58:42 +0900 Subject: [PATCH 4/7] editor/code: Enable ESLint for editors/code/webview/view_memory_layout.ts --- editors/code/src/webview/view_memory_layout.ts | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/editors/code/src/webview/view_memory_layout.ts b/editors/code/src/webview/view_memory_layout.ts index dd64676677c8..60f5f4630c0e 100644 --- a/editors/code/src/webview/view_memory_layout.ts +++ b/editors/code/src/webview/view_memory_layout.ts @@ -46,8 +46,7 @@ export function showMemoryLayout(data): void { container.appendChild(table); const rows = []; - // eslint-disable-next-line camelcase - function node_t(idx, depth, offset) { + function nodeT(idx, depth, offset) { if (!rows[depth]) { rows[depth] = { el: document.createElement("tr"), offset: 0 }; } @@ -92,13 +91,12 @@ export function showMemoryLayout(data): void { tooltip.style.display = "block"; }); td.addEventListener("mouseleave", (_) => (tooltip.style.display = "none")); - // eslint-disable-next-line camelcase - const total_offset = rows[depth].offset; + + const totalOffset = rows[depth].offset; td.addEventListener("dblclick", (e) => { const node = data.nodes[idx]; zoom = data.nodes[0].size / node.size; - // eslint-disable-next-line camelcase - y = (-total_offset / data.nodes[0].size) * zoom; + y = (-totalOffset / data.nodes[0].size) * zoom; x = 0; locate(); }); @@ -106,11 +104,10 @@ export function showMemoryLayout(data): void { rows[depth].el.appendChild(td); rows[depth].offset += data.nodes[idx].size; - // eslint-disable-next-line eqeqeq - if (data.nodes[idx].childrenStart != -1) { + if (data.nodes[idx].childrenStart !== -1) { for (let i = 0; i < data.nodes[idx].childrenLen; i++) { if (data.nodes[data.nodes[idx].childrenStart + i].size) { - node_t( + nodeT( data.nodes[idx].childrenStart + i, depth + 1, offset + data.nodes[data.nodes[idx].childrenStart + i].offset, @@ -120,7 +117,7 @@ export function showMemoryLayout(data): void { } } - node_t(0, 0, 0); + nodeT(0, 0, 0); for (const row of rows) table.appendChild(row.el); From f32a2ea17490155ba36a0f7ee503feac750cc814 Mon Sep 17 00:00:00 2001 From: Tetsuharu Ohzeki Date: Fri, 14 Jul 2023 23:42:58 +0900 Subject: [PATCH 5/7] fixup! editor/code: Enable ESLint for editors/code/webview/view_memory_layout.ts --- editors/code/src/commands.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts index 7d958b7ed807..9fe20c4481e6 100644 --- a/editors/code/src/commands.ts +++ b/editors/code/src/commands.ts @@ -1149,7 +1149,6 @@ export function viewMemoryLayout(ctx: CtxInit): Cmd { "memory_layout", "[Memory Layout]", vscode.ViewColumn.Two, - { enableScripts: true }, { enableScripts: true, localResourceRoots: [webviewModulePath] }, ); From 47ee06c01be66e2e9be5a3d3a900b3141017b23d Mon Sep 17 00:00:00 2001 From: Tetsuharu Ohzeki Date: Tue, 11 Jul 2023 01:19:21 +0900 Subject: [PATCH 6/7] editor/code: Remove unnecessary `meta[http-equiv=X-UA-Compatible] --- editors/code/src/commands.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts index 9fe20c4481e6..d1f304102614 100644 --- a/editors/code/src/commands.ts +++ b/editors/code/src/commands.ts @@ -1158,7 +1158,6 @@ export function viewMemoryLayout(ctx: CtxInit): Cmd { - From 80ac389e111cd518168d13de7c00701f91ae1d77 Mon Sep 17 00:00:00 2001 From: Tetsuharu Ohzeki Date: Tue, 11 Jul 2023 01:27:48 +0900 Subject: [PATCH 7/7] editor/code: Allow to Type Checking "show crate graph" webview code --- editors/code/build.mjs | 6 +++ editors/code/src/commands.ts | 51 ++++++------------- editors/code/src/uri.ts | 4 ++ editors/code/src/webview/show_crate_graph.css | 27 ++++++++++ editors/code/src/webview/show_crate_graph.ts | 19 +++++++ 5 files changed, 71 insertions(+), 36 deletions(-) create mode 100644 editors/code/src/webview/show_crate_graph.css create mode 100644 editors/code/src/webview/show_crate_graph.ts diff --git a/editors/code/build.mjs b/editors/code/build.mjs index 42a5ceb2699b..0c4133cfe437 100644 --- a/editors/code/build.mjs +++ b/editors/code/build.mjs @@ -79,6 +79,12 @@ async function bundleSource(options) { await Promise.all([ bundleSource(createBuildOption(["src/main.ts"])), + bundleSource( + createBuildOptionForWebView([ + "src/webview/show_crate_graph.ts", + "src/webview/show_crate_graph.css", + ]), + ), bundleSource( createBuildOptionForWebView([ "src/webview/view_memory_layout.ts", diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts index d1f304102614..b78a8b916c6d 100644 --- a/editors/code/src/commands.ts +++ b/editors/code/src/commands.ts @@ -21,7 +21,7 @@ import type { LanguageClient } from "vscode-languageclient/node"; import { LINKED_COMMANDS } from "./client"; import type { DependencyId } from "./dependencies_provider"; import { unwrapUndefinable } from "./undefinable"; -import { getWebViewModulePath } from "./uri"; +import { getNodeModulePath, getWebViewModulePath } from "./uri"; export * from "./ast_inspector"; export * from "./run"; @@ -737,7 +737,8 @@ export function viewItemTree(ctx: CtxInit): Cmd { function crateGraph(ctx: CtxInit, full: boolean): Cmd { return async () => { - const nodeModulesPath = vscode.Uri.file(path.join(ctx.extensionPath, "node_modules")); + const nodeModulesPath = getNodeModulePath(ctx); + const webviewModulePath = getWebViewModulePath(ctx); const panel = vscode.window.createWebviewPanel( "rust-analyzer.crate-graph", @@ -746,7 +747,7 @@ function crateGraph(ctx: CtxInit, full: boolean): Cmd { { enableScripts: true, retainContextWhenHidden: true, - localResourceRoots: [nodeModulesPath], + localResourceRoots: [nodeModulesPath, webviewModulePath], }, ); const params = { @@ -754,47 +755,25 @@ function crateGraph(ctx: CtxInit, full: boolean): Cmd { }; const client = ctx.client; const dot = await client.sendRequest(ra.viewCrateGraph, params); - const uri = panel.webview.asWebviewUri(nodeModulesPath); + + const nodeModuleUri = panel.webview.asWebviewUri(nodeModulesPath); + const webviewModuleUri = panel.webview.asWebviewUri(webviewModulePath); const html = ` - + - - - + + +
- `; diff --git a/editors/code/src/uri.ts b/editors/code/src/uri.ts index 80e459ffc3c1..0cd6bea1fc6e 100644 --- a/editors/code/src/uri.ts +++ b/editors/code/src/uri.ts @@ -10,3 +10,7 @@ function getBundledAssetsUri(ctx: CtxInit, pathname: string): Uri { export function getWebViewModulePath(ctx: CtxInit) { return getBundledAssetsUri(ctx, "out/webview"); } + +export function getNodeModulePath(ctx: CtxInit) { + return getBundledAssetsUri(ctx, "node_modules"); +} diff --git a/editors/code/src/webview/show_crate_graph.css b/editors/code/src/webview/show_crate_graph.css new file mode 100644 index 000000000000..14a06d3ec1c9 --- /dev/null +++ b/editors/code/src/webview/show_crate_graph.css @@ -0,0 +1,27 @@ +/* Fill the entire view */ +html, +body { + margin: 0; + padding: 0; + overflow: hidden; +} +svg { + position: fixed; + top: 0; + left: 0; + height: 100%; + width: 100%; +} + +/* Disable the graphviz background and fill the polygons */ +.graph > polygon { + display: none; +} +:is(.node, .edge) polygon { + fill: white; +} + +/* Invert the line colours for dark themes */ +body:not(.vscode-light) .edge path { + stroke: white; +} diff --git a/editors/code/src/webview/show_crate_graph.ts b/editors/code/src/webview/show_crate_graph.ts new file mode 100644 index 000000000000..a05b1dac4695 --- /dev/null +++ b/editors/code/src/webview/show_crate_graph.ts @@ -0,0 +1,19 @@ +// @ts-nocheck +export function showCrateDependencyGraph(dot): void { + const graph = d3 + .select("#graph") + .graphviz({ useWorker: false, useSharedWorker: false }) + .fit(true) + .zoomScaleExtent([0.1, Infinity]) + .renderDot(dot); + + d3.select(window).on("click", (event) => { + if (event.ctrlKey) { + graph.resetZoom(d3.transition().duration(100)); + } + }); + d3.select(window).on("copy", (event) => { + event.clipboardData.setData("text/plain", dot); + event.preventDefault(); + }); +}