Skip to content

Commit eb59a4d

Browse files
committed
code: Rewrite preview uri handling
1 parent fe1a642 commit eb59a4d

File tree

1 file changed

+51
-21
lines changed

1 file changed

+51
-21
lines changed

code/src/node/preview.ts

Lines changed: 51 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import * as vscode from 'vscode'
22
import { OutputChannelLogger } from '../common/log'
33
import { EsbonioClient } from './client'
4-
import { Commands, Events, Notifications } from '../common/constants'
4+
import { Commands, Events } from '../common/constants'
55
import { ShowDocumentParams, Range } from 'vscode-languageclient'
6+
import { URLSearchParams } from 'url'
67

78
interface PreviewFileParams {
89
uri: string
@@ -43,7 +44,7 @@ export class PreviewManager {
4344

4445
client.addHandler(
4546
"window/showDocument",
46-
(params: { params: ShowDocumentParams, default: any }) => this.showDocument(params)
47+
async (params: { params: ShowDocumentParams, default: any }) => await this.showDocument(params)
4748
)
4849

4950
client.addHandler(
@@ -131,7 +132,7 @@ export class PreviewManager {
131132
this.currentUri = editor.document.uri
132133
}
133134

134-
private showDocument(req: { params: ShowDocumentParams, default: any }) {
135+
private async showDocument(req: { params: ShowDocumentParams, default: any }) {
135136
let params = req.params
136137
if (!params.external) {
137138
return this.showInternalDocument(params)
@@ -142,25 +143,54 @@ export class PreviewManager {
142143
}
143144

144145
let panel = this.panel
145-
let uri = vscode.Uri.parse(params.uri)
146-
147-
// Needed so that previews work in Codespaces
148-
// see: https://github.com/swyddfa/esbonio/issues/896
149-
vscode.env.asExternalUri(uri).then(
150-
extUri => {
151-
// Annoyingly, asExternalUri doesn't preserve attributes like `path` or `query`
152-
let previewUri = uri.with({ scheme: extUri.scheme, authority: extUri.authority })
153-
let origin = `${previewUri.scheme}://${previewUri.authority}`
154-
this.logger.debug(`asExternalUri('${uri.toString(true)}') -> '${previewUri.toString(true)}'`)
155-
156-
panel.webview.html = this.getWebViewHTML(origin)
157-
panel.webview.postMessage({ 'show': previewUri.toString(true) })
158-
},
159-
err => {
160-
this.logger.error(`Unable to convert uri to an external uri: ${err}`)
161-
}
162-
)
163146

147+
let previewUri = vscode.Uri.parse(params.uri)
148+
let externalUri = await vscode.env.asExternalUri(previewUri)
149+
150+
// Annoyingly, asExternalUri doesn't preserve attributes like `path` or `query`
151+
previewUri = previewUri.with({ scheme: externalUri.scheme, authority: externalUri.authority })
152+
153+
let origin = `${previewUri.scheme}://${previewUri.authority}`
154+
panel.webview.html = this.getWebViewHTML(origin)
155+
156+
// Don't forget as also need an external uri for the websocket connection
157+
let queryParams = new URLSearchParams(previewUri.query)
158+
let ws = queryParams.get('ws')
159+
if (!ws) {
160+
this.logger.error("Missing websocket uri, features like sync scrolling will not be available.")
161+
this.displayUri(previewUri, queryParams)
162+
return
163+
}
164+
165+
// We need to also pass the websocket uri through `asExternalUri` however, it only works for
166+
// http(s) uris
167+
let wsUri = vscode.Uri.parse(ws)
168+
wsUri = await vscode.env.asExternalUri(wsUri.with({ scheme: 'http' }))
169+
wsUri = wsUri.with({ scheme: wsUri.scheme === 'https' ? 'wss' : 'ws' })
170+
queryParams.set('ws', wsUri.toString())
171+
172+
this.displayUri(previewUri, queryParams)
173+
}
174+
175+
/**
176+
* Display the given uri in the preview pane.
177+
*
178+
* @param uri The base uri to present
179+
* @param queryParams The query parameters to include
180+
* @returns
181+
*/
182+
private displayUri(uri: vscode.Uri, queryParams: URLSearchParams) {
183+
184+
// As far as I can tell, there isn't a way to convince vscode's URI type to encode the
185+
// uri in a way that does not break query parameters (since it converts ?x=y to ?x%3Dy).
186+
// It also appears to be intended behavior see: https://github.com/Microsoft/vscode/issues/8466
187+
//
188+
// So we need to do it ourselves.
189+
let query = queryParams.toString()
190+
let displayUri = `${uri.with({ query: '' })}?${query}`
191+
192+
this.logger.debug(`Displaying uri: ${displayUri}`)
193+
this.panel?.webview.postMessage({ 'show': displayUri })
164194
}
165195

166196
private showInternalDocument(params: ShowDocumentParams) {

0 commit comments

Comments
 (0)