11import * as vscode from 'vscode'
22import { OutputChannelLogger } from '../common/log'
33import { EsbonioClient } from './client'
4- import { Commands , Events , Notifications } from '../common/constants'
4+ import { Commands , Events } from '../common/constants'
55import { ShowDocumentParams , Range } from 'vscode-languageclient'
6+ import { URLSearchParams } from 'url'
67
78interface 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