From da2ac232ff2f02547f7d65bd6727f07dff2ff189 Mon Sep 17 00:00:00 2001 From: Vadim Melnicuk Date: Tue, 24 Mar 2026 20:31:42 +0000 Subject: [PATCH] feat: enhance VSCode API compatibility with fallback state management --- webview/src/helpers/codeBlocks.ts | 29 +++++++++++++++++-- webview/src/index.ts | 48 ++++++++++++++++++++++++++++++- webview/src/types.d.ts | 4 +-- 3 files changed, 75 insertions(+), 6 deletions(-) diff --git a/webview/src/helpers/codeBlocks.ts b/webview/src/helpers/codeBlocks.ts index 2aba5dc..20efabd 100644 --- a/webview/src/helpers/codeBlocks.ts +++ b/webview/src/helpers/codeBlocks.ts @@ -707,6 +707,8 @@ export function addTopLinePillLabel(builder: any[], lineEnd: number, labelText: } const quotedFenceOpeningLineRegex = /^[ \t]{0,3}(?:>[ \t]?)*[ \t]{0,3}(?:`{3,}|~{3,})/; +const fenceLineRegex = /^[ \t]*[`~]{3,}.*$/; +const quotedFencePrefixRegex = /^[ \t]{0,3}((?:>[ \t]?)*)[ \t]{0,3}(?:`{3,}|~{3,})/; export function addFenceOpeningLineMarker(builder: any[], state: EditorState, from: number, activeLines: Set, addRange: Function, activeLineMarkerDeco: any, fenceMarkerDeco: any): void { const line = state.doc.lineAt(from); @@ -797,15 +799,15 @@ export function addMermaidDiagramBlock( export function addCopyCodeButton(builder: any[], state: EditorState, from: number, to: number): void { const startLine = state.doc.lineAt(from); const endLine = state.doc.lineAt(Math.max(to - 1, from)); + const quoteDepth = getQuotedFenceDepth(startLine.text); const codeLines: string[] = []; for (let lineNum = startLine.number + 1; lineNum <= endLine.number; lineNum += 1) { const line = state.doc.line(lineNum); - const lineText = line.text; + const lineText = stripLeadingQuotePrefix(line.text, quoteDepth); if (lineNum === endLine.number) { - const fenceMatch = /^[ \t]*[`~]{3,}.*$/.exec(lineText); - if (fenceMatch) { + if (fenceLineRegex.test(lineText)) { continue; } } @@ -820,3 +822,24 @@ export function addCopyCodeButton(builder: any[], state: EditorState, from: numb addTopLineCopyButton(builder, startLine.to, codeContent); } + +function getQuotedFenceDepth(lineText: string): number { + const match = quotedFencePrefixRegex.exec(lineText); + if (!match) { + return 0; + } + return (match[1].match(/>/g) ?? []).length; +} + +function stripLeadingQuotePrefix(lineText: string, quoteDepth: number): string { + if (quoteDepth <= 0) { + return lineText; + } + + const prefixRe = new RegExp(`^[ \\t]{0,3}(?:>[ \\t]?){${quoteDepth}}`); + const match = prefixRe.exec(lineText); + if (!match) { + return lineText; + } + return lineText.slice(match[0].length); +} diff --git a/webview/src/index.ts b/webview/src/index.ts index d33e194..9e3346d 100644 --- a/webview/src/index.ts +++ b/webview/src/index.ts @@ -14,7 +14,53 @@ import { createExportHandler, type ExportHandlerContext } from './helpers/export type CreateEditorFactory = (typeof import('./editor'))['createEditor']; -const vscode = acquireVsCodeApi(); +type CompatibleVsCodeWebviewApi = { + postMessage: (message: WebviewMessage) => void; + getState: () => unknown; + setState: (state: unknown) => void; +}; + +function createCompatibleVsCodeApi(): CompatibleVsCodeWebviewApi { + const hostApi = acquireVsCodeApi(); + let fallbackState: unknown; + + const getState = (): unknown => { + if (typeof hostApi.getState !== 'function') { + return fallbackState; + } + + try { + const hostState = hostApi.getState(); + if (hostState !== undefined) { + fallbackState = hostState; + } + return hostState; + } catch { + return fallbackState; + } + }; + + const setState = (state: unknown): void => { + fallbackState = state; + if (typeof hostApi.setState !== 'function') { + return; + } + + try { + hostApi.setState(state); + } catch { + // Keep session-local fallback state when host persistence is unavailable. + } + }; + + return { + postMessage: (message: WebviewMessage) => hostApi.postMessage(message), + getState, + setState + }; +} + +const vscode = createCompatibleVsCodeApi(); initializeImageHandling(vscode); initializeWikiLinkHandling(vscode); initializeLocalLinkHandling(vscode); diff --git a/webview/src/types.d.ts b/webview/src/types.d.ts index 9f45e9b..706ebb1 100644 --- a/webview/src/types.d.ts +++ b/webview/src/types.d.ts @@ -1,8 +1,8 @@ declare function acquireVsCodeApi(): VsCodeWebviewApi; interface VsCodeWebviewApi { - getState(): unknown; - setState(state: unknown): void; + getState?(): unknown; + setState?(state: unknown): void; postMessage(message: WebviewMessage): void; }