Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom Editor API #3961

Merged
merged 9 commits into from
Jul 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1420,14 +1420,16 @@
"browser",
"tab",
"singleton",
"external"
"external",
"customEditor"
],
"markdownDescription": "The default PDF viewer.",
"enumDescriptions": [
"Open PDF with the default web browser.",
"Open PDF with the built-in tab viewer.",
"Open PDF with the built-in tab viewer, reveal existing one if possible.",
"[Experimental] Open PDF with the external viewer set in \"View > Pdf > External: command\"."
"[Experimental] Open PDF with the external viewer set in \"View > Pdf > External: command\".",
"[Experimental] Open PDF with the built-in tab viewer, using the vscode custom editor API."
]
},
"latex-workshop.view.pdf.tab.editorGroup": {
Expand All @@ -1454,7 +1456,8 @@
"scope": "window",
"type": "number",
"default": 1000,
"markdownDescription": "Defines the delay in milliseconds to wait for a tab opening. Please increase the value if you encounter a focus issue after opening a tab."
"deprecationMessage": "Deprecated: This config has no use and has been removed.",
"markdownDeprecationMessage": "**Deprecated**: This config has no use and has been removed."
},
"latex-workshop.view.pdf.ref.viewer": {
"type": "string",
Expand Down
46 changes: 40 additions & 6 deletions src/components/viewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import { moveActiveEditor } from '../utils/webview'

const logger = getLogger('Viewer')

export type ViewerMode = 'tab' | 'browser' | 'singleton' | 'external' | 'customEditor'

export { pdfViewerHookProvider } from './viewerlib/pdfviewerhook'
export { pdfViewerPanelSerializer } from './viewerlib/pdfviewerpanel'

Expand Down Expand Up @@ -94,15 +96,20 @@ export class Viewer {
return (await lw.server.getViewerUrl(pdfUri)).url
}

async open(pdfFile: string, mode?: string): Promise<void> {
async open(pdfFile: string, mode?: 'tab' | 'browser' | 'external'): Promise<void> {
const configuration = vscode.workspace.getConfiguration('latex-workshop')
const tabEditorGroup = configuration.get('view.pdf.tab.editorGroup') as string
const viewer = mode ?? configuration.get<'tab' | 'browser' | 'singleton' | 'external'>('view.pdf.viewer', 'tab')
if (viewer === 'browser') {
let viewerMode: ViewerMode = mode ?? configuration.get<ViewerMode>('view.pdf.viewer', 'tab')
if (mode === 'tab' && configuration.get<ViewerMode>('view.pdf.viewer', 'tab') === 'customEditor') {
viewerMode = 'customEditor'
}
if (viewerMode === 'browser') {
return lw.viewer.openBrowser(pdfFile)
} else if (viewer === 'tab' || viewer === 'singleton') {
} else if (viewerMode === 'customEditor') {
return lw.viewer.openCustomEditor(pdfFile)
} else if (viewerMode === 'tab' || viewerMode === 'singleton') {
return lw.viewer.openTab(pdfFile, tabEditorGroup, true)
} else if (viewer === 'external') {
} else if (viewerMode === 'external') {
return lw.viewer.openExternal(pdfFile)
}
}
Expand Down Expand Up @@ -149,9 +156,36 @@ export class Viewer {
return this.openPdfInTab(pdfUri, tabEditorGroup, preserveFocus)
}

async openCustomEditor(pdfFile: string): Promise<void> {
const url = await this.checkViewer(pdfFile)
if (!url) {
return
}
const configuration = vscode.workspace.getConfiguration('latex-workshop')
const editorGroup = configuration.get('view.pdf.tab.editorGroup')
// Roughly translate editorGroup to vscode.ViewColumn
let viewColumn: vscode.ViewColumn
if (editorGroup === 'current') {
viewColumn = vscode.ViewColumn.Active
} else if (editorGroup === 'right') {
viewColumn = vscode.ViewColumn.Two
} else if (editorGroup === 'left') {
viewColumn = vscode.ViewColumn.One
} else {
// Other locations are not supported by the editor open API -> use right panel as default
viewColumn = vscode.ViewColumn.Two
}
const pdfUri = vscode.Uri.file(pdfFile)
const showOptions: vscode.TextDocumentShowOptions = {
viewColumn,
preserveFocus: true
}
await vscode.commands.executeCommand('vscode.openWith', pdfUri, 'latex-workshop-pdf-hook', showOptions)
}

async openPdfInTab(pdfUri: vscode.Uri, tabEditorGroup: string, preserveFocus: boolean): Promise<void> {
const configuration = vscode.workspace.getConfiguration('latex-workshop')
const singleton = configuration.get<'tab' | 'browser' | 'singleton' | 'external'>('view.pdf.viewer', 'tab') === 'singleton'
const singleton = configuration.get<ViewerMode>('view.pdf.viewer', 'tab') === 'singleton'
if (singleton) {
const panels = viewerManager.getPanelSet(pdfUri)
if (panels && panels.size > 0) {
Expand Down
26 changes: 20 additions & 6 deletions src/components/viewerlib/pdfviewerhook.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import type * as vscode from 'vscode'
import * as vscode from 'vscode'
import * as lw from '../../lw'
import { ViewerMode } from '../viewer'
import { viewerManager } from './pdfviewermanager'
import { populatePdfViewerPanel } from './pdfviewerpanel'

class PdfViewerHookProvider implements vscode.CustomReadonlyEditorProvider {
openCustomDocument(uri: vscode.Uri) {
Expand All @@ -9,12 +12,23 @@ class PdfViewerHookProvider implements vscode.CustomReadonlyEditorProvider {
}
}

resolveCustomEditor(document: vscode.CustomDocument, webviewPanel: vscode.WebviewPanel) {
webviewPanel.onDidChangeViewState(e => { e.webviewPanel.dispose() })
if (document.uri === undefined || !document.uri.fsPath.toLocaleLowerCase().endsWith('.pdf')) {
return
async resolveCustomEditor(document: vscode.CustomDocument, webviewPanel: vscode.WebviewPanel) {
const configuration = vscode.workspace.getConfiguration('latex-workshop')
const viewerLocation = configuration.get<ViewerMode>('view.pdf.viewer', 'tab')
if (viewerLocation === 'customEditor') {
webviewPanel.webview.options = {
...webviewPanel.webview.options,
enableScripts: true
}
const pdfPanel = await populatePdfViewerPanel(document.uri, webviewPanel)
void viewerManager.initiatePdfViewerPanel(pdfPanel)
} else {
webviewPanel.onDidChangeViewState(e => { e.webviewPanel.dispose() })
if (document.uri === undefined || !document.uri.fsPath.toLocaleLowerCase().endsWith('.pdf')) {
return
}
void lw.viewer.openPdfInTab(document.uri, 'current', false)
}
void lw.viewer.openPdfInTab(document.uri, 'current', false)
}
}

Expand Down
10 changes: 8 additions & 2 deletions src/components/viewerlib/pdfviewerpanel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,16 +85,22 @@ async function patchCodespaces(url: vscode.Uri) {
codespacesPatched = true
}

// Create a new vscode.WebviewPanel and in it a PdfViewerPanel
export async function createPdfViewerPanel(pdfUri: vscode.Uri, preserveFocus: boolean): Promise<PdfViewerPanel> {
await lw.server.serverStarted
const htmlContent = await getPDFViewerContent(pdfUri)
const panel = vscode.window.createWebviewPanel('latex-workshop-pdf', path.basename(pdfUri.path), {
viewColumn: vscode.ViewColumn.Active,
preserveFocus
}, {
enableScripts: true,
retainContextWhenHidden: true
})
return populatePdfViewerPanel(pdfUri, panel)
}

// Create a PdfViewerPanel inside an existing vscode.WebviewPanel
export async function populatePdfViewerPanel(pdfUri: vscode.Uri, panel: vscode.WebviewPanel): Promise<PdfViewerPanel>{
await lw.server.serverStarted
const htmlContent = await getPDFViewerContent(pdfUri)
panel.webview.html = htmlContent
const pdfPanel = new PdfViewerPanel(pdfUri, panel)
return pdfPanel
Expand Down
2 changes: 1 addition & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ function registerLatexWorkshopCommands() {
vscode.commands.registerCommand('latex-workshop.saveWithoutBuilding', () => lw.commander.saveActive()),
vscode.commands.registerCommand('latex-workshop.build', () => lw.commander.build()),
vscode.commands.registerCommand('latex-workshop.recipes', (recipe: string | undefined) => lw.commander.recipes(recipe)),
vscode.commands.registerCommand('latex-workshop.view', (mode: 'tab' | 'browser' | 'external' | vscode.Uri | undefined) => lw.commander.view(mode)),
vscode.commands.registerCommand('latex-workshop.view', (uri: vscode.Uri) => lw.commander.view(uri)),
vscode.commands.registerCommand('latex-workshop.refresh-viewer', () => lw.commander.refresh()),
vscode.commands.registerCommand('latex-workshop.tab', () => lw.commander.view('tab')),
vscode.commands.registerCommand('latex-workshop.viewInBrowser', () => lw.commander.view('browser')),
Expand Down
24 changes: 24 additions & 0 deletions test/suites/05_viewer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,30 @@ suite('PDF viewer test suite', () => {
assert.strictEqual(statuses.length, 2)
}, ['linux', 'darwin'])

test.run('view in custom editor tab', async (fixture: string) => {
await vscode.workspace.getConfiguration('latex-workshop').update('view.pdf.viewer', 'customEditor')
await test.load(fixture, [
{src: 'base.tex', dst: 'main.tex'}
], {skipCache: true})

await test.build(fixture, 'main.tex')
await test.view(fixture, 'main.pdf')
await test.sleep(250)
await lw.commander.view()
let statuses = lw.viewer.getViewerState(vscode.Uri.file(path.resolve(fixture, 'main.pdf')))
assert.strictEqual(statuses.length, 1) // Make sure a custom editor was opened
await test.sleep(250)
await lw.commander.view()
await test.sleep(250)
statuses = lw.viewer.getViewerState(vscode.Uri.file(path.resolve(fixture, 'main.pdf')))
assert.strictEqual(statuses.length, 1) // Make sure the custom editor got reused
await vscode.workspace.getConfiguration('latex-workshop').update('view.pdf.viewer', 'tab')
await lw.commander.view()
await test.sleep(250)
statuses = lw.viewer.getViewerState(vscode.Uri.file(path.resolve(fixture, 'main.pdf')))
assert.strictEqual(statuses.length, 2) // Make sure a non-customEditor viewer was opened
})

test.run('build main.tex and view it', async (fixture: string) => {
await vscode.workspace.getConfiguration().update('latex-workshop.latex.rootFile.doNotPrompt', true)
await vscode.workspace.getConfiguration().update('latex-workshop.latex.rootFile.useSubFile', false)
Expand Down