Skip to content

Commit

Permalink
feat: open in file in embeded vscode (#207)
Browse files Browse the repository at this point in the history
  • Loading branch information
antfu committed Apr 30, 2023
1 parent 89ffc5e commit 9f17662
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 10 deletions.
2 changes: 1 addition & 1 deletion packages/devtools-kit/src/_types/rpc.ts
Expand Up @@ -47,7 +47,7 @@ export interface ServerFunctions {
// Actions
customTabAction(name: string, action: number): Promise<boolean>
runWizard<T extends WizardActions>(name: T, ...args: GetWizardArgs<T>): Promise<void>
openInEditor(filepath: string): void
openInEditor(filepath: string): Promise<boolean>
restartNuxt(hard?: boolean): Promise<void>
}

Expand Down
5 changes: 5 additions & 0 deletions packages/devtools-kit/src/_types/server-ctx.ts
Expand Up @@ -12,6 +12,11 @@ export interface NuxtDevtoolsServerContext {

rpc: BirpcGroup<ClientFunctions, ServerFunctions>

/**
* Hook to open file in editor
*/
openInEditorHooks: ((filepath: string) => boolean | void | Promise<boolean | void>)[]

/**
* Invalidate client cache for a function and ask for re-fetching
*/
Expand Down
3 changes: 2 additions & 1 deletion packages/devtools/client/setup/client-rpc.ts
Expand Up @@ -21,7 +21,8 @@ export function setupClientRPC() {
nuxt.hooks.callHookParallel('devtools:terminal:exit', data)
},
async navigateTo(path: string) {
router.push(path)
if (router.currentRoute.value.path !== path)
router.push(path)
},
} satisfies ClientFunctions)
}
42 changes: 39 additions & 3 deletions packages/devtools/src/integrations/vscode.ts
@@ -1,4 +1,7 @@
import { hostname } from 'node:os'
import { resolve } from 'node:path'
import fs from 'node:fs/promises'
import { existsSync } from 'node:fs'
import { logger } from '@nuxt/kit'
import { execa } from 'execa'
import { checkPort, getPort } from 'get-port-please'
Expand All @@ -8,7 +11,7 @@ import { startSubprocess } from '@nuxt/devtools-kit'
import { LOG_PREFIX } from '../logger'
import type { NuxtDevtoolsServerContext } from '../types'

export async function setup({ nuxt, options }: NuxtDevtoolsServerContext) {
export async function setup({ nuxt, options, openInEditorHooks, rpc }: NuxtDevtoolsServerContext) {
const installed = !!await which('code-server').catch(() => null)

const vsOptions = options?.vscode || {}
Expand All @@ -19,20 +22,53 @@ export async function setup({ nuxt, options }: NuxtDevtoolsServerContext) {
let promise: Promise<void> | null = null
const mode = vsOptions?.mode || 'local-serve'
const computerHostName = vsOptions.tunnel?.name || hostname().split('.').join('')
const root = nuxt.options.rootDir
const vscodeServerControllerFile = resolve(root, '.vscode', '.server-controller-port.log')

openInEditorHooks.push(async (file) => {
if (!existsSync(vscodeServerControllerFile))
return false

// With vscode-server-controller,
// we can open files in VS Code Server
try {
const { port } = JSON.parse(await fs.readFile(vscodeServerControllerFile, 'utf-8')) as any
const url = `http://localhost:${port}/open?path=${encodeURIComponent(file)}`
await fetch(url)
rpc.broadcast.navigateTo('/modules/custom-builtin-vscode')
return true
}
catch (e) {
console.error(e)
return false
}
})

async function startCodeServer() {
if (existsSync(vscodeServerControllerFile))
await fs.rm(vscodeServerControllerFile, { force: true })

if (vsOptions?.reuseExistingServer && !(await checkPort(port))) {
loaded = true
url = `http://localhost:${port}/?folder=${encodeURIComponent(nuxt.options.rootDir)}`
url = `http://localhost:${port}/?folder=${encodeURIComponent(root)}`
logger.info(LOG_PREFIX, `Existing VS Code Server found at port ${port}...`)
return
}

port = await getPort({ port })
url = `http://localhost:${port}/?folder=${encodeURIComponent(nuxt.options.rootDir)}`
url = `http://localhost:${port}/?folder=${encodeURIComponent(root)}`

logger.info(LOG_PREFIX, `Starting VS Code Server at ${url} ...`)

// Install VS Code Server Controller
// https://github.com/antfu/vscode-server-controller
execa('code-server', [
'serve-local',
'--accept-server-license-terms',
'--install-extension',
'antfu.vscode-server-controller',
], { stderr: 'inherit', stdout: 'ignore', reject: false })

startSubprocess(
{
command: 'code-server',
Expand Down
2 changes: 1 addition & 1 deletion packages/devtools/src/runtime/plugins/view/Frame.vue
Expand Up @@ -108,8 +108,8 @@ function updateClient() {
if (componentInspector) {
componentInspector.openInEditor = async (baseUrl, file, line, column) => {
await props.client!.hooks.callHook('host:inspector:click', baseUrl, file, line, column)
disableComponentInspector()
await props.client!.hooks.callHook('host:inspector:click', baseUrl, file, line, column)
}
componentInspector.onUpdated = () => {
props.client!.hooks.callHook('host:inspector:update', {
Expand Down
21 changes: 17 additions & 4 deletions packages/devtools/src/server-rpc/general.ts
Expand Up @@ -8,7 +8,7 @@ import { logger } from '@nuxt/kit'
import type { HookInfo, NuxtDevtoolsServerContext, ServerFunctions } from '../types'
import { setupHooksDebug } from '../runtime/shared/hooks'

export function setupGeneralRPC({ nuxt, refresh }: NuxtDevtoolsServerContext) {
export function setupGeneralRPC({ nuxt, refresh, openInEditorHooks }: NuxtDevtoolsServerContext) {
const components: Component[] = []
const imports: Import[] = []
const importPresets: Import[] = []
Expand Down Expand Up @@ -118,12 +118,25 @@ export function setupGeneralRPC({ nuxt, refresh }: NuxtDevtoolsServerContext) {
`${input}.mjs`,
`${input}.ts`,
].find(i => existsSync(i))
if (path) {

if (!path) {
console.error('File not found:', input)
return false
}

try {
for (const hook of openInEditorHooks) {
const result = await hook(path)
if (result)
return true
}
// @ts-expect-error missin types
await import('launch-editor').then(r => (r.default || r)(path + suffix))
return true
}
else {
console.error('File not found:', input)
catch (e) {
console.error(e)
return false
}
},
restartNuxt(hard = true) {
Expand Down
1 change: 1 addition & 0 deletions packages/devtools/src/server-rpc/index.ts
Expand Up @@ -63,6 +63,7 @@ export function setupRPC(nuxt: Nuxt, options: ModuleOptions) {
rpc,
refresh,
extendServerRpc,
openInEditorHooks: [],
}

// @ts-expect-error untyped
Expand Down

0 comments on commit 9f17662

Please sign in to comment.