mirror of
https://github.com/Myriad-Dreamin/tinymist.git
synced 2025-12-23 08:47:50 +00:00
feat: eject preview panel to browser (#1575)
* feat: eject preview panel to browser * refactor global state * fix typo for kind * await kill preview * add isNotPrimary launch option * fix isNotPrimary for eject * fix async syntax error in compat
This commit is contained in:
parent
9d38c8fd38
commit
5b42231a77
5 changed files with 155 additions and 13 deletions
|
|
@ -1204,6 +1204,12 @@
|
|||
"icon": "$(open-preview)",
|
||||
"when": "resourceLangId == typst && editorTextFocus"
|
||||
},
|
||||
{
|
||||
"command": "typst-preview.eject",
|
||||
"title": "%extension.tinymist.command.typst-preview.eject%",
|
||||
"description": "Eject the preview panel to browser to get better performance",
|
||||
"icon": "$(link-external)"
|
||||
},
|
||||
{
|
||||
"command": "typst-preview.sync",
|
||||
"title": "%extension.tinymist.command.typst-preview.sync%",
|
||||
|
|
@ -1255,6 +1261,10 @@
|
|||
{
|
||||
"command": "tinymist.restartServer",
|
||||
"when": "ext.tinymistActivated"
|
||||
},
|
||||
{
|
||||
"command": "typst-preview.eject",
|
||||
"when": "activeWebviewPanelId == 'typst-preview'"
|
||||
}
|
||||
],
|
||||
"editor/title": [
|
||||
|
|
@ -1267,6 +1277,11 @@
|
|||
"command": "typst-preview.preview",
|
||||
"when": "resourceLangId == typst",
|
||||
"group": "navigation"
|
||||
},
|
||||
{
|
||||
"command": "typst-preview.eject",
|
||||
"when": "activeWebviewPanelId == 'typst-preview'",
|
||||
"group": "navigation"
|
||||
}
|
||||
],
|
||||
"editor/title/run": [
|
||||
|
|
|
|||
|
|
@ -329,10 +329,10 @@ export const launchPreviewCompat = async (task: LaunchInBrowserTask | LaunchInWe
|
|||
activeEditor,
|
||||
dataPlanePort,
|
||||
webviewPanel,
|
||||
panelDispose() {
|
||||
async panelDispose() {
|
||||
activeTask.delete(bindDocument);
|
||||
serverProcess.kill();
|
||||
contentPreviewProvider.then((p) => p.postDeactivate(connectUrl));
|
||||
await contentPreviewProvider.then((p) => p.postDeactivate(connectUrl));
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
@ -678,3 +678,7 @@ export const revealDocumentCompat = async (args: any) => {
|
|||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const ejectPreviewPanelCompat = async () => {
|
||||
vscode.window.showWarningMessage("Eject is not supported in compat mode");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import {
|
|||
LaunchInWebViewTask,
|
||||
LaunchInBrowserTask,
|
||||
getPreviewHtml,
|
||||
ejectPreviewPanelCompat,
|
||||
} from "./preview-compat";
|
||||
import {
|
||||
PanelScrollOrCursorMoveRequest,
|
||||
|
|
@ -26,12 +27,21 @@ import {
|
|||
} from "../lsp";
|
||||
import { l10nMsg } from "../l10n";
|
||||
import { IContext } from "../context";
|
||||
import { extensionState } from "../state";
|
||||
|
||||
/**
|
||||
* The launch preview implementation which depends on `isCompat` of previewActivate.
|
||||
*/
|
||||
let launchImpl: typeof launchPreviewLsp;
|
||||
|
||||
/**
|
||||
* The state corresponding to the focusing preview panel.
|
||||
*/
|
||||
export interface PreviewPanelContext {
|
||||
panel: vscode.WebviewPanel;
|
||||
state: PersistPreviewState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Preload the preview resources to reduce the latency of the first preview.
|
||||
* @param context The extension context.
|
||||
|
|
@ -94,6 +104,7 @@ export function previewActivate(context: vscode.ExtensionContext, isCompat: bool
|
|||
vscode.commands.registerCommand("typst-preview.browser", launch("browser", "doc")),
|
||||
vscode.commands.registerCommand("typst-preview.preview-slide", launch("webview", "slide")),
|
||||
vscode.commands.registerCommand("typst-preview.browser-slide", launch("browser", "slide")),
|
||||
vscode.commands.registerCommand("typst-preview.eject", isCompat ? ejectPreviewPanelCompat : ejectPreviewPanelLsp),
|
||||
vscode.commands.registerCommand("tinymist.previewDev", launchDevPreview),
|
||||
vscode.commands.registerCommand(
|
||||
"typst-preview.revealDocument",
|
||||
|
|
@ -142,7 +153,7 @@ export function previewActivate(context: vscode.ExtensionContext, isCompat: bool
|
|||
interface LaunchOpts {
|
||||
isBrowsing?: boolean;
|
||||
isDev?: boolean;
|
||||
// isDev = false
|
||||
isNotPrimary?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -168,11 +179,57 @@ export function previewActivate(context: vscode.ExtensionContext, isCompat: bool
|
|||
mode,
|
||||
isBrowsing: opts?.isBrowsing || false,
|
||||
isDev: opts?.isDev || false,
|
||||
isNotPrimary: opts?.isNotPrimary || false,
|
||||
}).catch((e) => {
|
||||
vscode.window.showErrorMessage(`failed to launch preview: ${e}`);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
async function launchForURI(uri: vscode.Uri, kind: "browser" | "webview", mode: "doc" | "slide", opts?: LaunchOpts) {
|
||||
const doc =
|
||||
vscode.workspace.textDocuments.find((doc) => {
|
||||
return doc.uri.toString() === uri.toString();
|
||||
}) || (await vscode.workspace.openTextDocument(uri));
|
||||
const editor = await vscode.window.showTextDocument(doc, getSensibleTextEditorColumn(), true);
|
||||
|
||||
const bindDocument = editor.document;
|
||||
const isBrowsing = opts?.isBrowsing;
|
||||
const isDev = opts?.isDev;
|
||||
const isNotPrimary = opts?.isNotPrimary;
|
||||
|
||||
await launchImpl({
|
||||
kind,
|
||||
context,
|
||||
editor,
|
||||
bindDocument,
|
||||
mode,
|
||||
isBrowsing,
|
||||
isDev,
|
||||
isNotPrimary,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Ejects the preview panel to the external browser.
|
||||
*/
|
||||
async function ejectPreviewPanelLsp() {
|
||||
const focusingContext = extensionState.getFocusingPreviewPanelContext();
|
||||
if (!focusingContext) {
|
||||
vscode.window.showWarningMessage("No active preview panel");
|
||||
return;
|
||||
}
|
||||
const { panel, state } = focusingContext;
|
||||
|
||||
// Close the preview panel, basically kill the previous preview task.
|
||||
panel.dispose();
|
||||
|
||||
await launchForURI(vscode.Uri.parse(state.uri), "browser", state.mode, {
|
||||
isBrowsing: state.isBrowsing,
|
||||
isDev: state.isDev,
|
||||
isNotPrimary: state.isNotPrimary,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function previewDeactivate() {
|
||||
|
|
@ -220,7 +277,7 @@ interface OpenPreviewInWebViewArgs {
|
|||
/**
|
||||
* Additional cleanup routine when the webview panel is disposed.
|
||||
*/
|
||||
panelDispose: () => void;
|
||||
panelDispose: () => Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -253,20 +310,38 @@ export async function openPreviewInWebView({
|
|||
},
|
||||
);
|
||||
|
||||
const previewState: PersistPreviewState = {
|
||||
mode: task.mode,
|
||||
isNotPrimary: !!task.isNotPrimary,
|
||||
isBrowsing: !!task.isBrowsing,
|
||||
isDev: !!task.isDev,
|
||||
uri: activeEditor.document.uri.toString(),
|
||||
};
|
||||
|
||||
const updateActivePanel =() => {
|
||||
if (panel.active) {
|
||||
extensionState.mut.focusingPreviewPanelContext = {
|
||||
panel,
|
||||
state: previewState,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// NOTE: To avoid missing the auto revealing of webview initialization.
|
||||
updateActivePanel();
|
||||
panel.onDidChangeViewState(updateActivePanel);
|
||||
|
||||
// todo: bind Document.onDidDispose, but we did not find a similar way.
|
||||
panel.onDidDispose(async () => {
|
||||
panelDispose();
|
||||
if (extensionState.getFocusingPreviewPanelContext()?.panel === panel) {
|
||||
extensionState.mut.focusingPreviewPanelContext = undefined;
|
||||
}
|
||||
await panelDispose();
|
||||
console.log("killed preview services");
|
||||
});
|
||||
|
||||
// Determines arguments for the preview HTML.
|
||||
const previewMode = task.mode === "doc" ? "Doc" : "Slide";
|
||||
const previewState: PersistPreviewState = {
|
||||
mode: task.mode,
|
||||
isNotPrimary: !!task.isNotPrimary,
|
||||
isBrowsing: !!task.isBrowsing,
|
||||
uri: activeEditor.document.uri.toString(),
|
||||
};
|
||||
const previewStateEncoded = Buffer.from(JSON.stringify(previewState), "utf-8").toString("base64");
|
||||
|
||||
// Substitutes arguments in the HTML content.
|
||||
|
|
@ -359,9 +434,9 @@ async function launchPreviewLsp(task: LaunchInBrowserTask | LaunchInWebViewTask)
|
|||
activeEditor: editor,
|
||||
dataPlanePort,
|
||||
webviewPanel,
|
||||
panelDispose() {
|
||||
async panelDispose() {
|
||||
disposes.dispose();
|
||||
tinymist.killPreview(taskId);
|
||||
await tinymist.killPreview(taskId);
|
||||
},
|
||||
});
|
||||
break;
|
||||
|
|
@ -754,6 +829,7 @@ interface PersistPreviewState {
|
|||
mode: "doc" | "slide";
|
||||
isNotPrimary: boolean;
|
||||
isBrowsing: boolean;
|
||||
isDev: boolean;
|
||||
uri: string;
|
||||
}
|
||||
|
||||
|
|
@ -785,6 +861,7 @@ class TypstPreviewSerializer implements vscode.WebviewPanelSerializer<PersistPre
|
|||
const mode = state.mode;
|
||||
const isNotPrimary = state.isNotPrimary;
|
||||
const isBrowsing = state.isBrowsing;
|
||||
const isDev = state.isDev;
|
||||
|
||||
await launchImpl({
|
||||
kind: "webview",
|
||||
|
|
@ -794,6 +871,7 @@ class TypstPreviewSerializer implements vscode.WebviewPanelSerializer<PersistPre
|
|||
mode,
|
||||
webviewPanel,
|
||||
isBrowsing,
|
||||
isDev,
|
||||
isNotPrimary,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import * as vscode from "vscode";
|
||||
import { PreviewPanelContext } from "./features/preview";
|
||||
|
||||
export type ExtensionContext = vscode.ExtensionContext;
|
||||
|
||||
|
|
@ -25,9 +26,11 @@ interface ExtensionState {
|
|||
mut: {
|
||||
focusingFile: string | undefined;
|
||||
focusingDoc: vscode.TextDocument | undefined;
|
||||
focusingPreviewPanelContext: PreviewPanelContext | undefined;
|
||||
};
|
||||
getFocusingFile(): string | undefined;
|
||||
getFocusingDoc(): vscode.TextDocument | undefined;
|
||||
getFocusingPreviewPanelContext(): PreviewPanelContext | undefined;
|
||||
}
|
||||
|
||||
export const extensionState: ExtensionState = {
|
||||
|
|
@ -53,6 +56,7 @@ export const extensionState: ExtensionState = {
|
|||
mut: {
|
||||
focusingFile: undefined,
|
||||
focusingDoc: undefined,
|
||||
focusingPreviewPanelContext: undefined,
|
||||
},
|
||||
getFocusingFile() {
|
||||
return extensionState.mut.focusingFile;
|
||||
|
|
@ -60,4 +64,7 @@ export const extensionState: ExtensionState = {
|
|||
getFocusingDoc() {
|
||||
return extensionState.mut.focusingDoc;
|
||||
},
|
||||
getFocusingPreviewPanelContext() {
|
||||
return extensionState.mut.focusingPreviewPanelContext;
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -893,6 +893,44 @@ vi = "Typst Preview: Xem trước tệp đã mở trong trình duyệt và chế
|
|||
zh = "Typst 预览:在浏览器和幻灯片模式下预览已打开的文件"
|
||||
zh-TW = "Typst 預覽:在瀏覽器和幻燈片模式下預覽已打開的文件"
|
||||
|
||||
[extension.tinymist.command.typst-preview.eject]
|
||||
en = "Typst Preview: Eject Preview Panel"
|
||||
ar = "Typst Preview: إخراج لوحة المعاينة"
|
||||
bg = "Typst Preview: Изхвърляне на панела за преглед"
|
||||
ca = "Typst Preview: Expulsar el panell de previsualització"
|
||||
cs = "Typst Preview: Vysunout panel náhledu"
|
||||
da = "Typst Preview: Skub preview-panelet ud"
|
||||
de = "Typst Preview: Vorschaufenster auswerfen"
|
||||
el = "Typst Preview: Εξαγωγή του πλαισίου προεπισκόπησης"
|
||||
es = "Typst Preview: Expulsar el panel de vista previa"
|
||||
et = "Typst Preview: Eemalda eelvaate paneel"
|
||||
eu = "Typst Preview: Kanporatu aurrebistaren panela"
|
||||
fi = "Typst Preview: Poista esikatselupaneeli"
|
||||
fr = "Typst Preview: Éjecter le panneau d'aperçu"
|
||||
gl = "Typst Preview: Expulsar o panel de vista previa"
|
||||
he = "Typst Preview: פלט את לוח התצוגה המקדימה"
|
||||
hu = "Typst Preview: Előnézeti panel kidobása"
|
||||
is = "Typst Preview: Spyrja út forsýningarspjaldið"
|
||||
it = "Typst Preview: Espelli il pannello di anteprima"
|
||||
ja = "Typst Preview: プレビュー・パネルを排出"
|
||||
la = "Typst Preview: Praevideo tabulam eicere"
|
||||
nb = "Typst Preview: Løs ut forhåndsvisningspanelet"
|
||||
nl = "Typst Preview: Voorbeeldpaneel uitwerpen"
|
||||
nn = "Typst Preview: Løys ut førehandsvisingspanelet"
|
||||
pl = "Typst Preview: Wyłącz panel podglądu"
|
||||
pt-PT = "Typst Preview: Ejetar o painel de pré-visualização"
|
||||
ro = "Typst Preview: Scoate panoul de previzualizare"
|
||||
ru = "Typst Preview: Отключить панель предпросмотра"
|
||||
sl = "Typst Preview: Odstrani ploščo za predogled"
|
||||
sq = "Typst Preview: Nxjerr panelin e parapamjes"
|
||||
sr = "Typst Preview: Извади панел за преглед"
|
||||
sv = "Typst Preview: Stäng av förhandsgranskningspanelen"
|
||||
tr = "Typst Preview: Önizleme Panelini Çıkart"
|
||||
uk = "Typst Preview: Відключити панель попереднього перегляду"
|
||||
vi = "Typst Preview: Đẩy bảng xem trước ra"
|
||||
zh = "Typst 预览:弹出预览面板"
|
||||
zh-TW = "Typst 預覽:彈出預覽面板"
|
||||
|
||||
[extension.tinymist.command.typst-preview.sync]
|
||||
en = "Typst Preview: Sync Preview with Current Cursor"
|
||||
ar = "Typst Preview: مزامنة المعاينة مع المؤشر الحالي"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue