diff --git a/README.md b/README.md
index 71d29a5..99c4800 100644
--- a/README.md
+++ b/README.md
@@ -28,12 +28,6 @@ Open _Command Palette_, choose `Live Code: Open Preview to the Side`, or simply
```json
{
- "liveCode.defaultPlatform": {
- "type": "string",
- "default": "browser",
- "description": "Set the execution environment of the preview",
- "enum": ["browser", "node"]
- },
"liveCode.renderJSX": {
"type": "boolean",
"default": true,
diff --git a/images/browser-plain.svg b/images/browser-plain.svg
new file mode 100644
index 0000000..4dbf06b
--- /dev/null
+++ b/images/browser-plain.svg
@@ -0,0 +1 @@
+
diff --git a/images/browser.svg b/images/browser.svg
new file mode 100644
index 0000000..2f20b8b
--- /dev/null
+++ b/images/browser.svg
@@ -0,0 +1 @@
+
diff --git a/images/electron.svg b/images/electron.svg
deleted file mode 100644
index 9492963..0000000
--- a/images/electron.svg
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/images/logo-plain.svg b/images/logo-plain.svg
new file mode 100644
index 0000000..f00adc9
--- /dev/null
+++ b/images/logo-plain.svg
@@ -0,0 +1,4 @@
+
diff --git a/images/node-plain.svg b/images/node-plain.svg
new file mode 100644
index 0000000..0b8d359
--- /dev/null
+++ b/images/node-plain.svg
@@ -0,0 +1 @@
+
diff --git a/package.json b/package.json
index 78ff854..bfe5753 100644
--- a/package.json
+++ b/package.json
@@ -27,34 +27,61 @@
"contributes": {
"commands": [
{
- "command": "liveCode.openPreviewToSide",
- "title": "Open Preview to the Side",
+ "command": "liveCode.choosePreviewToTheSide",
+ "title": "Choose A Runtime Preview to the Side",
"category": "Live Code",
- "icon": "images/logo.svg"
+ "icon": "images/logo-plain.svg"
},
{
- "command": "liveCode.changePlatform",
- "title": "Change Platform",
+ "command": "liveCode.openBrowserPreviewToSide",
+ "title": "Open Browser Preview to the Side",
"category": "Live Code",
- "icon": "$(notebook-kernel-select)"
+ "icon": "images/browser-plain.svg"
+ },
+ {
+ "command": "liveCode.openNodePreviewToSide",
+ "title": "Open Node.js Preview to the Side",
+ "category": "Live Code",
+ "icon": "images/node-plain.svg"
+ },
+ {
+ "command": "liveCode.changeCurrentRuntimeOfPreview",
+ "title": "Change Current Runtime of Preview",
+ "category": "Live Code",
+ "icon": "images/logo-plain.svg"
}
],
"menus": {
"editor/context": [
{
- "command": "liveCode.openPreviewToSide",
+ "command": "liveCode.openBrowserPreviewToSide",
+ "when": "editorLangId in liveCode.supportedLanguageIds",
+ "group": "liveCode"
+ },
+ {
+ "command": "liveCode.openNodePreviewToSide",
"when": "editorLangId in liveCode.supportedLanguageIds",
"group": "liveCode"
}
],
"editor/title": [
{
- "command": "liveCode.openPreviewToSide",
+ "command": "liveCode.openBrowserPreviewToSide",
"when": "editorLangId in liveCode.supportedLanguageIds",
"group": "navigation"
},
{
- "command": "liveCode.changePlatform",
+ "command": "liveCode.openNodePreviewToSide",
+ "when": "editorLangId in liveCode.supportedLanguageIds",
+ "group": "navigation"
+ },
+ {
+ "command": "liveCode.choosePreviewToTheSide",
+ "when": "editorLangId in liveCode.supportedLanguageIds",
+ "group": "navigation"
+ },
+ {
+ "command": "liveCode.changeCurrentRuntimeOfPreview",
"when": "liveCode.isPreviewFocus",
"group": "navigation"
}
@@ -62,7 +89,7 @@
},
"keybindings": [
{
- "command": "liveCode.openPreviewToSide",
+ "command": "liveCode.choosePreviewToTheSide",
"key": "ctrl+k l",
"mac": "cmd+k l",
"when": "editorLangId in liveCode.supportedLanguageIds && !liveCode.isPreviewFocus"
@@ -72,19 +99,6 @@
"type": "object",
"title": "Live Code",
"properties": {
- "liveCode.defaultPlatform": {
- "type": "string",
- "default": "browser",
- "description": "Set the execution environment for the preview",
- "enum": [
- "browser",
- "node"
- ],
- "enumDescriptions": [
- "Execute code in web browser",
- "Execute code in Node.js"
- ]
- },
"liveCode.renderJSX": {
"type": "boolean",
"default": true,
diff --git a/src/extension.ts b/src/extension.ts
index d69081f..5d7320a 100644
--- a/src/extension.ts
+++ b/src/extension.ts
@@ -2,7 +2,7 @@
import path from 'path'
import * as prettyFormat from 'pretty-format'
import * as vscode from 'vscode'
-import type {Platform, AnyFunction} from './types'
+import type {Runtime, AnyFunction, BuildPlatform} from './types'
import bundle from './extension/bundle'
import {install} from './extension/install'
import getWebviewContent from './extension/getWebviewContent'
@@ -37,7 +37,7 @@ const jsLanguageIds = [
'typescriptreact',
]
-const platformTitleMap: Record = {
+const runtimeTitleMap: Record = {
node: 'Node.js',
browser: 'browser',
}
@@ -49,7 +49,7 @@ const documentPanelMap = new Map()
const panelConfigMap = new WeakMap<
vscode.WebviewPanel,
{
- currentPlatform: Platform
+ currentRuntime: Runtime
}
>()
// instance data
@@ -99,42 +99,10 @@ export function activate(context: vscode.ExtensionContext) {
context.subscriptions.push(
// TODO: unregister if no panel is showing
- vscode.commands.registerCommand('liveCode.changePlatform', async () => {
- const entry = [...documentPanelMap].find(([, x]) => x.active)
- if (!entry) {
- return
- }
- const [document, panel] = entry
- const {currentPlatform} = panelConfigMap.get(panel)!
- const items: vscode.QuickPickItem[] = [
- {
- label: 'node',
- description: 'Node.js',
- },
- {
- label: 'browser',
- description: 'Web browser (VS Code built in)',
- },
- ]
- const result = await vscode.window.showQuickPick(
- items.map((x) => ({
- ...x,
- description: `${x.description as string}${
- x.label === currentPlatform ? ' - Current' : ''
- }`,
- })),
- {
- placeHolder: 'Change platform in current preivew of Live Code',
- }
- )
- if (result) {
- panelConfigMap.set(panel, {
- ...panelConfigMap.get(panel),
- currentPlatform: result.label as Platform,
- })
- void processDocument(document)
- }
- }),
+ vscode.commands.registerCommand(
+ 'liveCode.changeCurrentRuntimeOfPreview',
+ choosePreviewToTheSide
+ ),
vscode.commands.registerCommand('liveCode.reloadPreview', () => {
log('existingPanel reload')
const doc = vscode.window.activeTextEditor?.document
@@ -147,65 +115,123 @@ export function activate(context: vscode.ExtensionContext) {
return
}
}),
- vscode.commands.registerCommand('liveCode.openPreviewToSide', () => {
- const doc = vscode.window.activeTextEditor?.document
- if (!doc) {
- return
- }
- const existingPanel = documentPanelMap.get(doc)
- if (existingPanel) {
- existingPanel.reveal()
- return
- }
- const panel = vscode.window.createWebviewPanel(
- 'liveCode.preview',
- '',
- vscode.ViewColumn.Beside,
- {
- enableScripts: true,
- }
- )
- documentPanelMap.set(doc, panel)
- panelConfigMap.set(panel, {currentPlatform: getDefaultPlatform()})
- panelDataMap.set(panel, {workerRef: {current: null}})
- setPanelTitleAndIcon(panel, doc)
- setWebviewContent(panel.webview)
- panel.webview.onDidReceiveMessage((e: {type: string; data: unknown}) => {
- if (e.type !== 'timeMark') {
- log('onDidReceiveMessage', e)
- }
- if (e.type === 'ready') {
- void processDocument(doc)
- } else if (e.type === 'revealLine') {
- revealSourceLine(e.data)
- } else if (e.type === 'requestReload') {
- void vscode.commands.executeCommand('liveCode.reloadPreview')
- } else if (e.type === 'timeMark') {
- log(e.data)
- }
- })
- const setIsPreviewFocus = (value: boolean) => {
- void vscode.commands.executeCommand(
- 'setContext',
- 'liveCode.isPreviewFocus',
- value
- )
- }
- setIsPreviewFocus(true)
- panel.onDidChangeViewState((e) => {
- setIsPreviewFocus(e.webviewPanel.active)
- })
- panel.onDidDispose(() => {
- setIsPreviewFocus(false)
- documentPanelMap.delete(doc)
- panelConfigMap.delete(panel)
- panelDataMap.get(panel)?.workerRef?.current?.terminate()
- panelDataMap.delete(panel)
- })
+ vscode.commands.registerCommand(
+ 'liveCode.choosePreviewToTheSide',
+ choosePreviewToTheSide
+ ),
+ vscode.commands.registerCommand('liveCode.openBrowserPreviewToSide', () => {
+ openPreviewToSide('browser')
+ }),
+ vscode.commands.registerCommand('liveCode.openNodePreviewToSide', () => {
+ openPreviewToSide('node')
})
)
}
+async function showRuntimePick(currentRuntime?: Runtime) {
+ const items: vscode.QuickPickItem[] = [
+ {
+ label: 'node',
+ description: 'Node.js',
+ },
+ {
+ label: 'browser',
+ description: 'Web browser (VS Code built in)',
+ },
+ ]
+ const result = await vscode.window.showQuickPick(
+ items.map((x) => ({
+ ...x,
+ description: `${x.description as string}${
+ x.label === currentRuntime ? ' - Current' : ''
+ }`,
+ })),
+ {
+ placeHolder: `Choose a runtime for Live Code`,
+ }
+ )
+
+ return result ? (result.label as Runtime) : null
+}
+
+async function choosePreviewToTheSide() {
+ const entry = [...documentPanelMap].find(([, x]) => x.active)
+ if (!entry) {
+ const runtime = await showRuntimePick()
+ if (runtime) {
+ openPreviewToSide(runtime)
+ }
+ return
+ }
+ const [document, panel] = entry
+ const {currentRuntime} = panelConfigMap.get(panel)!
+ const runtime = await showRuntimePick(currentRuntime)
+ if (runtime) {
+ panelConfigMap.set(panel, {
+ ...panelConfigMap.get(panel),
+ currentRuntime: runtime,
+ })
+ void processDocument(document)
+ }
+}
+
+function openPreviewToSide(runtime: Runtime) {
+ const doc = vscode.window.activeTextEditor?.document
+ if (!doc) {
+ return
+ }
+ const existingPanel = documentPanelMap.get(doc)
+ if (existingPanel) {
+ existingPanel.reveal()
+ return
+ }
+ const panel = vscode.window.createWebviewPanel(
+ 'liveCode.preview',
+ '',
+ vscode.ViewColumn.Beside,
+ {
+ enableScripts: true,
+ }
+ )
+ documentPanelMap.set(doc, panel)
+ panelConfigMap.set(panel, {currentRuntime: runtime})
+ panelDataMap.set(panel, {workerRef: {current: null}})
+ setPanelTitleAndIcon(panel, doc)
+ setWebviewContent(panel.webview)
+ panel.webview.onDidReceiveMessage((e: {type: string; data: unknown}) => {
+ if (e.type !== 'timeMark') {
+ log('onDidReceiveMessage', e)
+ }
+ if (e.type === 'ready') {
+ void processDocument(doc)
+ } else if (e.type === 'revealLine') {
+ revealSourceLine(e.data)
+ } else if (e.type === 'requestReload') {
+ void vscode.commands.executeCommand('liveCode.reloadPreview')
+ } else if (e.type === 'timeMark') {
+ log(e.data)
+ }
+ })
+ const setIsPreviewFocus = (value: boolean) => {
+ void vscode.commands.executeCommand(
+ 'setContext',
+ 'liveCode.isPreviewFocus',
+ value
+ )
+ }
+ setIsPreviewFocus(true)
+ panel.onDidChangeViewState((e) => {
+ setIsPreviewFocus(e.webviewPanel.active)
+ })
+ panel.onDidDispose(() => {
+ setIsPreviewFocus(false)
+ documentPanelMap.delete(doc)
+ panelConfigMap.delete(panel)
+ panelDataMap.get(panel)?.workerRef?.current?.terminate()
+ panelDataMap.delete(panel)
+ })
+}
+
export function deactivate() {
itsContext = null
documentPanelMap.clear()
@@ -231,8 +257,8 @@ async function processDocument(
const workerRef = panelDataMap.get(panel)?.workerRef
await workerRef?.current?.terminate()
- const {currentPlatform} = panelConfigMap.get(panel)!
- const isBrowser = currentPlatform === 'browser'
+ const {currentRuntime} = panelConfigMap.get(panel)!
+ const isBrowser = currentRuntime === 'browser'
setPanelTitleAndIcon(panel, document)
let error: unknown
let code: string | void
@@ -242,7 +268,7 @@ async function processDocument(
const timer = timeMark<'bundle' | 'nodeVM' | 'postMessage'>()
timer.start('bundle')
;[error, code] = await of(
- bundleDocument(document, currentPlatform).then((r) => {
+ bundleDocument(document, currentRuntime).then((r) => {
if (isBrowser) {
css = r?.css
}
@@ -251,7 +277,7 @@ async function processDocument(
})
)
timer.end('bundle')
- if (code && currentPlatform === 'node') {
+ if (code && currentRuntime === 'node') {
timer.start('nodeVM')
;[error, {result, logs} = {}] = await of(
nodeVM.runInNewContext(code, {
@@ -276,7 +302,7 @@ async function processDocument(
type: shouldReload ? 'codeReload' : 'code',
// data should be serialized
data: {
- platform: currentPlatform,
+ platform: currentRuntime,
config: {...vscode.workspace.getConfiguration('liveCode')},
result,
logs,
@@ -300,8 +326,9 @@ function debounce>(fn: T, wait: number) {
}
// https://icon-sets.iconify.design/devicon/
-const iconMap: Record = {
- browser: 'images/electron.svg',
+// https://icon-sets.iconify.design/devicon-plain/
+const iconMap: Record = {
+ browser: 'images/browser.svg',
node: 'images/node.svg',
}
@@ -309,14 +336,14 @@ function setPanelTitleAndIcon(
panel: vscode.WebviewPanel,
document: vscode.TextDocument
) {
- const {currentPlatform} = panelConfigMap.get(panel)!
+ const {currentRuntime} = panelConfigMap.get(panel)!
panel.title =
`Preview` +
(document ? ' ' + path.basename(document.uri.fsPath) : '') +
- ` in ${platformTitleMap[currentPlatform]}`
+ ` in ${runtimeTitleMap[currentRuntime]}`
panel.iconPath = vscode.Uri.joinPath(
itsContext!.extensionUri,
- iconMap[currentPlatform]
+ iconMap[currentRuntime]
)
}
@@ -339,12 +366,15 @@ function setWebviewContent(webview: vscode.Webview) {
})
}
-function getDefaultPlatform() {
- const config = vscode.workspace.getConfiguration('liveCode')
- return (config.get('defaultPlatform') ?? 'browser') as Platform
-}
+// function getDefaultRuntime() {
+// const config = vscode.workspace.getConfiguration('liveCode')
+// return (config.get('defaultRuntime') ?? 'browser') as Runtime
+// }
-function bundleDocument(document: vscode.TextDocument, platform: Platform) {
+function bundleDocument(
+ document: vscode.TextDocument,
+ platform: BuildPlatform
+) {
return bundle(transform(document.getText()), {
platform,
filename: document.isUntitled ? undefined : document.uri.fsPath,
diff --git a/src/preview.tsx b/src/preview.tsx
index 757b08f..069e43a 100644
--- a/src/preview.tsx
+++ b/src/preview.tsx
@@ -13,7 +13,7 @@ import {IsDarkModeProvider, useIsDarkMode} from './preview/darkMode'
import ErrorBoundary from './preview/ErrorBoundary'
import Inspector from './preview/Inspector'
import {StyledConsole, Hook, Unhook, Message} from './preview/console'
-import {AppConfig, AnyFunction, Platform} from './types'
+import {AppConfig, AnyFunction, Runtime} from './types'
import timeMark from './utils/timeMark'
import {of} from './utils/promise'
@@ -97,14 +97,14 @@ declare global {
}
type Data = {
- platform: Platform
+ platform: Runtime
error?: unknown
code?: string
css?: string
result?: [string, ExpContext][]
logs: Message[]
config: {
- defaultPlatform: Platform
+ // defaultRuntime: Runtime
renderJSX: boolean
showLineNumbers: boolean
}
diff --git a/src/types.ts b/src/types.ts
index 8935a4e..23d439d 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -1,4 +1,13 @@
-export type Platform = 'browser' | 'node'
+import type {Platform} from 'esbuild'
+
+/**
+ * The runtime supported by extension
+ */
+export type Runtime = 'browser' | 'node'
+/**
+ * The platform supported by ESBuild
+ */
+export type BuildPlatform = Platform
export type AppConfig = {
timestamp?: number