diff --git a/src/components/server.ts b/src/components/server.ts index 2b5fb9a4..ac9dbb4a 100644 --- a/src/components/server.ts +++ b/src/components/server.ts @@ -103,7 +103,7 @@ export class Server { if (viewerPort === 0 && currentSessionPort) { const {sessionId, port} = currentSessionPort if (sessionId === vscode.env.sessionId) { - this.extension.logger.info(`[Server] Restoring server port of current session: ${inspectCompact(currentSessionPort)}`) + this.extension.logger.info(`[Server] Restoring the server port of the current session: ${inspectCompact(currentSessionPort)}`) viewerPort = port } } diff --git a/src/components/viewerlib/pdfviewermanager.ts b/src/components/viewerlib/pdfviewermanager.ts index f1ac9fa0..61e41c17 100644 --- a/src/components/viewerlib/pdfviewermanager.ts +++ b/src/components/viewerlib/pdfviewermanager.ts @@ -5,15 +5,35 @@ import { toKey } from '../../utils/tokey.js' import type { Client } from './client.js' import type { PdfViewerPanel } from './pdfviewerpanel.js' import type { Manager } from '../manager.js' +import type { Logger } from '../logger.js' +import { inspectCompact } from '../../utils/inspect.js' +interface CurrentSessionClientKeys { + sessionId: string + clientKeys: string[] +} export class PdfViewerManagerService { private readonly webviewPanelMap = new Map>() + private readonly clientSetKey = 'pdfviewer.clientset' readonly clientMap = new Map>() constructor(private readonly extension: { + readonly extensionContext: vscode.ExtensionContext, + readonly logger: Logger, readonly manager: Manager - }) { } + }) { + const currentSessionClientKeys = this.extension.extensionContext.workspaceState.get(this.clientSetKey) + if (currentSessionClientKeys) { + const { sessionId, clientKeys } = currentSessionClientKeys + if (sessionId === vscode.env.sessionId) { + this.extension.logger.info(`Restoring the client set from the current session: ${inspectCompact(currentSessionClientKeys)}`) + clientKeys.forEach(key => { + this.createClientSetFromKey(key) + }) + } + } + } dispose() { this.webviewPanelMap.forEach(panelSet => { @@ -23,8 +43,18 @@ export class PdfViewerManagerService { }) } + /** + * Make the manager treat the PDF file as an output of a LaTeX file. + * @param pdfFileUri The URI of a PDF file. + */ createClientSet(pdfFileUri: vscode.Uri): void { const key = toKey(pdfFileUri) + this.createClientSetFromKey(key) + const currentSessionClientKeys = { sessionId: vscode.env.sessionId, clientKeys: Array.from(this.clientMap.keys()) } + void this.extension.extensionContext.workspaceState.update(this.clientSetKey, currentSessionClientKeys) + } + + private createClientSetFromKey(key: string): void { if (!this.clientMap.has(key)) { this.clientMap.set(key, new Set()) } diff --git a/viewer/components/extensionconnection.ts b/viewer/components/extensionconnection.ts index 9c43c472..04746faf 100644 --- a/viewer/components/extensionconnection.ts +++ b/viewer/components/extensionconnection.ts @@ -7,16 +7,40 @@ import { ExternalPromise } from '../utils/externalpromise.js' export class ExtensionConnection { private readonly lwApp: ILatexToyboxPdfViewer private connectionPort = new ConnectionPort() + private readonly disconnectedNotificationDom = document.createElement('div') + private readonly reconnectedNotificationDom = document.createElement('div') constructor(lwApp: ILatexToyboxPdfViewer) { this.lwApp = lwApp this.setupConnectionPort() + this.setupDoms() } send(message: ClientRequest) { void this.connectionPort.send(message) } + private setupDoms() { + this.disconnectedNotificationDom.id = 'notify-disconnected' + this.disconnectedNotificationDom.textContent = 'Disconnected from LaTeX Toybox. Trying to reconnect...' + this.disconnectedNotificationDom.classList.add('hide') + document.body.appendChild(this.disconnectedNotificationDom) + this.reconnectedNotificationDom.id = 'notify-reconnected' + this.reconnectedNotificationDom.textContent = 'Reconnected to LaTeX Toybox. Happy TeXing!' + this.reconnectedNotificationDom.classList.add('hide') + document.body.appendChild(this.reconnectedNotificationDom) + } + + private notifyDisconnected() { + this.disconnectedNotificationDom.classList.remove('hide') + } + + private notifyReconnected() { + this.disconnectedNotificationDom.classList.add('hide') + this.reconnectedNotificationDom.classList.remove('hide') + setTimeout(() => this.reconnectedNotificationDom.classList.add('hide'), 3000) + } + private setupConnectionPort() { const openPack: ClientRequest = { type: 'open', @@ -42,7 +66,7 @@ export class ExtensionConnection { }) void this.connectionPort.onDidClose(async () => { - document.title = `[Disconnected] ${this.lwApp.documentTitle}` + this.notifyDisconnected() console.log('Closed: WebScocket to LaTeX Toybox.') // Since WebSockets are disconnected when PC resumes from sleep, @@ -53,7 +77,7 @@ export class ExtensionConnection { try { this.connectionPort = new ConnectionPort() await this.connectionPort.readyPromise - document.title = this.lwApp.documentTitle + this.notifyReconnected() this.setupConnectionPort() console.log('Reconnected: WebScocket to LaTeX Toybox.') return diff --git a/viewer/latextoybox.css b/viewer/latextoybox.css index 16b21bc5..e99624a9 100644 --- a/viewer/latextoybox.css +++ b/viewer/latextoybox.css @@ -197,3 +197,28 @@ html[dir='rtl'] .findbar { #autoReloadOffButton::before { display: none; } + +#notify-disconnected { + position: fixed; + top: 0; + left: 0; + z-index: 100000; + border: 3px solid red; +} + +#notify-disconnected[class="hide"] { + opacity: 0; +} + +#notify-reconnected { + position: fixed; + top: 0; + left: 0; + z-index: 100000; + border: 3px solid green; +} + +#notify-reconnected[class="hide"] { + opacity: 0; + transition: opacity 0.5s ease-in-out; +}