From 07032ddd01f04f429fad6f7ef7d85dec5d3ca24b Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Fri, 2 Aug 2024 17:36:01 -0700 Subject: [PATCH 1/4] Enable previewing chat codeblocks --- package.json | 2 +- src/editorPreview/previewManager.ts | 2 +- src/infoManagers/endpointManager.ts | 6 ++++-- src/server/httpServer.ts | 4 +--- src/server/serverUtils/contentLoader.ts | 6 +++++- 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index d89d2e3c..4b0232e8 100644 --- a/package.json +++ b/package.json @@ -126,7 +126,7 @@ }, { "command": "livePreview.setDefaultOpenFile", - "when": "resourceLangId == html", + "when": "resourceLangId == html && !inChat", "group": "1_livepreview@2" } ], diff --git a/src/editorPreview/previewManager.ts b/src/editorPreview/previewManager.ts index 8f2c714c..c23140b2 100644 --- a/src/editorPreview/previewManager.ts +++ b/src/editorPreview/previewManager.ts @@ -171,7 +171,7 @@ export class PreviewManager extends Disposable { let path = '/'; if (!connection?.workspace) { this._notifyLooseFileOpen(); - path = await this._endpointManager.encodeLooseFileEndpoint(file.fsPath); + path = await this._endpointManager.encodeLooseFileEndpoint(file.fsPath, file); if (!path.startsWith('/')) { path = `/${path}`; diff --git a/src/infoManagers/endpointManager.ts b/src/infoManagers/endpointManager.ts index b7e08d0d..fc092203 100644 --- a/src/infoManagers/endpointManager.ts +++ b/src/infoManagers/endpointManager.ts @@ -37,9 +37,11 @@ export class EndpointManager extends Disposable { * @param location the file location to encode. * @returns the encoded endpoint. */ - public async encodeLooseFileEndpoint(location: string): Promise { + public async encodeLooseFileEndpoint(location: string, file?: vscode.Uri): Promise { let fullParent = await PathUtil.GetParentDir(location); - const child = await PathUtil.GetFileName(location, true); + const child = file?.scheme === 'vscode-chat-code-block' ? + file.fsPath.slice(1) : + await PathUtil.GetFileName(location, true); fullParent = PathUtil.ConvertToPosixPath(fullParent); this.validEndpointRoots.add(fullParent); diff --git a/src/server/httpServer.ts b/src/server/httpServer.ts index b89f3f6f..458ca25c 100644 --- a/src/server/httpServer.ts +++ b/src/server/httpServer.ts @@ -215,9 +215,7 @@ export class HttpServer extends Disposable { let contentType = 'application/octet-stream'; if (basePath === '') { if (URLPathName.startsWith('/endpoint_unsaved')) { - const untitledFileName = URLPathName.substring( - URLPathName.lastIndexOf('/') + 1 - ); + const untitledFileName = URLPathName.slice('/endpoint_unsaved/'.length); const content = await this._contentLoader.getFileStream( untitledFileName, false diff --git a/src/server/serverUtils/contentLoader.ts b/src/server/serverUtils/contentLoader.ts index 7b3273c4..aba08458 100644 --- a/src/server/serverUtils/contentLoader.ts +++ b/src/server/serverUtils/contentLoader.ts @@ -293,7 +293,11 @@ export class ContentLoader extends Disposable { let contentLength = 0; while (i < workspaceDocuments.length) { - if (PathUtil.PathEquals(readPath, workspaceDocuments[i].fileName)) { + let docFileName = workspaceDocuments[i].fileName; + if (docFileName.startsWith('/') && !readPath.startsWith('/')) { + docFileName = docFileName.slice(1); + } + if (PathUtil.PathEquals(readPath, docFileName)) { if (inFilesystem && workspaceDocuments[i].isUntitled) { continue; } From f6dd76fd27221984eb2061875a220390cfe5b0d4 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Wed, 21 Aug 2024 19:46:42 -0700 Subject: [PATCH 2/4] Update src/infoManagers/endpointManager.ts Co-authored-by: Andrea Mah <31675041+andreamah@users.noreply.github.com> --- src/infoManagers/endpointManager.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/infoManagers/endpointManager.ts b/src/infoManagers/endpointManager.ts index fc092203..11513f18 100644 --- a/src/infoManagers/endpointManager.ts +++ b/src/infoManagers/endpointManager.ts @@ -40,7 +40,8 @@ export class EndpointManager extends Disposable { public async encodeLooseFileEndpoint(location: string, file?: vscode.Uri): Promise { let fullParent = await PathUtil.GetParentDir(location); const child = file?.scheme === 'vscode-chat-code-block' ? - file.fsPath.slice(1) : + PathUtil.ConvertToPosixPath(file.fsPath.slice(1)) : + await PathUtil.GetFileName(location, true); fullParent = PathUtil.ConvertToPosixPath(fullParent); From 9b96e9aa67aecd946608e5dd5572257447a1fe3e Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Wed, 21 Aug 2024 20:22:47 -0700 Subject: [PATCH 3/4] Another take --- src/editorPreview/previewManager.ts | 2 +- src/infoManagers/endpointManager.ts | 12 +++++++----- src/manager.ts | 1 + src/server/httpServer.ts | 20 ++++++++++++++++++-- src/server/serverUtils/contentLoader.ts | 6 +----- 5 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/editorPreview/previewManager.ts b/src/editorPreview/previewManager.ts index c23140b2..77a1590f 100644 --- a/src/editorPreview/previewManager.ts +++ b/src/editorPreview/previewManager.ts @@ -171,7 +171,7 @@ export class PreviewManager extends Disposable { let path = '/'; if (!connection?.workspace) { this._notifyLooseFileOpen(); - path = await this._endpointManager.encodeLooseFileEndpoint(file.fsPath, file); + path = await this._endpointManager.encodeLooseFileEndpoint(file); if (!path.startsWith('/')) { path = `/${path}`; diff --git a/src/infoManagers/endpointManager.ts b/src/infoManagers/endpointManager.ts index 11513f18..121307c4 100644 --- a/src/infoManagers/endpointManager.ts +++ b/src/infoManagers/endpointManager.ts @@ -37,12 +37,14 @@ export class EndpointManager extends Disposable { * @param location the file location to encode. * @returns the encoded endpoint. */ - public async encodeLooseFileEndpoint(location: string, file?: vscode.Uri): Promise { - let fullParent = await PathUtil.GetParentDir(location); - const child = file?.scheme === 'vscode-chat-code-block' ? - PathUtil.ConvertToPosixPath(file.fsPath.slice(1)) : + public async encodeLooseFileEndpoint(file: string | vscode.Uri): Promise { + if (typeof file !== 'string' && file.scheme === 'vscode-chat-code-block') { + return '/chatCodeBlock/' + encodeURIComponent(file.with({ fragment: '' }).toString()); + } - await PathUtil.GetFileName(location, true); + const location = typeof file === 'string' ? file : file.fsPath; + let fullParent = await PathUtil.GetParentDir(location); + const child = await PathUtil.GetFileName(location, true); fullParent = PathUtil.ConvertToPosixPath(fullParent); this.validEndpointRoots.add(fullParent); diff --git a/src/manager.ts b/src/manager.ts index 9938ca54..0a39b0e4 100644 --- a/src/manager.ts +++ b/src/manager.ts @@ -516,6 +516,7 @@ export class Manager extends Disposable { serverGrouping?: ServerGrouping ): Promise { if (file.scheme !== 'file') { + // Is this an error? console.error('Tried to open a non-file URI with file opener'); } if (!serverGrouping) { diff --git a/src/server/httpServer.ts b/src/server/httpServer.ts index 458ca25c..d2885bd0 100644 --- a/src/server/httpServer.ts +++ b/src/server/httpServer.ts @@ -214,8 +214,24 @@ export class HttpServer extends Disposable { let contentType = 'application/octet-stream'; if (basePath === '') { - if (URLPathName.startsWith('/endpoint_unsaved')) { - const untitledFileName = URLPathName.slice('/endpoint_unsaved/'.length); + if (URLPathName.startsWith('/chatCodeBlock')) { + const codeBlockUriStr = decodeURIComponent(URLPathName.slice('/chatCodeBlock/'.length)); + const content = await this._contentLoader.getFileStream( + codeBlockUriStr, + false + ); + if (content.Stream) { + stream = content.Stream; + contentType = content.ContentType ?? ''; + contentLength = content.ContentLength; + writeHeader(200, contentType, content.ContentLength); + stream.pipe(res); + return; + } + } else if (URLPathName.startsWith('/endpoint_unsaved')) { + const untitledFileName = URLPathName.substring( + URLPathName.lastIndexOf('/') + 1 + ); const content = await this._contentLoader.getFileStream( untitledFileName, false diff --git a/src/server/serverUtils/contentLoader.ts b/src/server/serverUtils/contentLoader.ts index aba08458..2c46ffb2 100644 --- a/src/server/serverUtils/contentLoader.ts +++ b/src/server/serverUtils/contentLoader.ts @@ -293,11 +293,7 @@ export class ContentLoader extends Disposable { let contentLength = 0; while (i < workspaceDocuments.length) { - let docFileName = workspaceDocuments[i].fileName; - if (docFileName.startsWith('/') && !readPath.startsWith('/')) { - docFileName = docFileName.slice(1); - } - if (PathUtil.PathEquals(readPath, docFileName)) { + if (PathUtil.PathEquals(readPath, workspaceDocuments[i].fileName) || (workspaceDocuments[i].uri.scheme === 'vscode-chat-code-block' && workspaceDocuments[i].uri.with({ fragment: '' }).toString() === readPath)) { if (inFilesystem && workspaceDocuments[i].isUntitled) { continue; } From 63d05144062e6ad13722f6acc33b400a7c58f9b8 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Wed, 21 Aug 2024 20:29:14 -0700 Subject: [PATCH 4/4] Simplify --- src/server/httpServer.ts | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/src/server/httpServer.ts b/src/server/httpServer.ts index d2885bd0..cc2a8216 100644 --- a/src/server/httpServer.ts +++ b/src/server/httpServer.ts @@ -136,7 +136,7 @@ export class HttpServer extends Disposable { ...(contentLength ? { 'Content-Length': contentLength } : {}), // add CORP header for codespaces // https://github.com/microsoft/vscode-livepreview/issues/560 - ...{'Cross-Origin-Resource-Policy': 'cross-origin'}, + ...{ 'Cross-Origin-Resource-Policy': 'cross-origin' }, ...this._defaultHeaders }); } catch (e) { @@ -214,26 +214,15 @@ export class HttpServer extends Disposable { let contentType = 'application/octet-stream'; if (basePath === '') { - if (URLPathName.startsWith('/chatCodeBlock')) { - const codeBlockUriStr = decodeURIComponent(URLPathName.slice('/chatCodeBlock/'.length)); - const content = await this._contentLoader.getFileStream( - codeBlockUriStr, - false - ); - if (content.Stream) { - stream = content.Stream; - contentType = content.ContentType ?? ''; - contentLength = content.ContentLength; - writeHeader(200, contentType, content.ContentLength); - stream.pipe(res); - return; + if (URLPathName.startsWith('/endpoint_unsaved') || URLPathName.startsWith('/chatCodeBlock')) { + let fileName: string; + if (URLPathName.startsWith('/endpoint_unsaved')) { + fileName = URLPathName.substring(URLPathName.lastIndexOf('/') + 1); + } else { + fileName = decodeURIComponent(URLPathName.slice('/chatCodeBlock/'.length)); } - } else if (URLPathName.startsWith('/endpoint_unsaved')) { - const untitledFileName = URLPathName.substring( - URLPathName.lastIndexOf('/') + 1 - ); const content = await this._contentLoader.getFileStream( - untitledFileName, + fileName, false ); if (content.Stream) {