<commit_before>import * as vscode from 'vscode'
import * as fs from 'fs'
import * as path from 'path'
import * as opn from 'opn'
import * as WebSocket from 'ws'

import {Extension} from '../main'
import {SyncTeXRecord} from './locator'

interface Position {}

interface Client {
    type: 'viewer' | 'tab'
    prevType?: 'viewer' | 'tab'
    ws?: WebSocket
    position?: Position
}

export class Viewer {
    extension: Extension
    clients: {[key: string]: Client | undefined} = {}
    positions = {}

    constructor(extension: Extension) {
        this.extension = extension
    }

    refreshExistingViewer(sourceFile: string, type?: string) : boolean {
        const pdfFile = this.extension.manager.tex2pdf(sourceFile)
        const client = this.clients[pdfFile]
        if (client !== undefined &&
            (type === undefined || client.type === type) &&
            client.ws !== undefined) {
            this.extension.logger.addLogMessage(`Refresh PDF viewer for ${pdfFile}`)
            client.ws.send(JSON.stringify({type: "refresh"}))
            return true
        }
        this.extension.logger.addLogMessage(`No PDF viewer connected for ${pdfFile}`)
        return false
    }

    checkViewer(sourceFile: string, type: string) : string | undefined {
        if (this.refreshExistingViewer(sourceFile, type)) {
            return
        }
        const pdfFile = this.extension.manager.tex2pdf(sourceFile)
        if (!fs.existsSync(pdfFile)) {
            this.extension.logger.addLogMessage(`Cannot find PDF file ${pdfFile}`)
            return
        }
        if (this.extension.server.address === undefined) {
            this.extension.logger.addLogMessage(`Cannot establish server connection.`)
            return
        }
        const url = `http://${this.extension.server.address}/viewer.html?file=\\pdf:${encodeURIComponent(pdfFile)}`
        this.extension.logger.addLogMessage(`Serving PDF file at ${url}`)
        return url
    }

    openViewer(sourceFile: string) {
        const url = this.checkViewer(sourceFile, 'viewer')
        if (!url) {
            return
        }
        const pdfFile = this.extension.manager.tex2pdf(sourceFile)
        const client = this.clients[pdfFile]
        if (client !== undefined && client.ws !== undefined) {
            client.ws.close()
        }
        this.clients[pdfFile] = {type: 'viewer'}
        opn(url)
        this.extension.logger.addLogMessage(`Open PDF viewer for ${pdfFile}`)
        this.extension.logger.displayStatus('repo', 'statusBar.foreground', `Open PDF viewer for ${path.basename(pdfFile)}.`)
    }

    openTab(sourceFile: string) {
        const url = this.checkViewer(sourceFile, 'tab')
        if (!url) {
            return
        }
        const pdfFile = this.extension.manager.tex2pdf(sourceFile)
        const client = this.clients[pdfFile]
        const uri = vscode.Uri.file(pdfFile).with({scheme: 'latex-workshop-pdf'})
        let column = vscode.ViewColumn.Two
        if (vscode.window.activeTextEditor && vscode.window.activeTextEditor.viewColumn === vscode.ViewColumn.Two) {
            column = vscode.ViewColumn.Three
        }
        if (client !== undefined && client.ws !== undefined) {
            client.ws.close()
        }
        this.clients[pdfFile] = {type: 'tab'}
        vscode.commands.executeCommand("vscode.previewHtml", uri, column, path.basename(pdfFile))
        this.extension.logger.addLogMessage(`Open PDF tab for ${pdfFile}`)
        this.extension.logger.displayStatus('repo', 'statusBar.foreground', `Open PDF tab for ${path.basename(pdfFile)}.`)
    }

    handler(ws: WebSocket, msg: string) {
        const data = JSON.parse(msg)
        let client: Client | undefined
        switch (data.type) {
            case 'open':
                client = this.clients[decodeURIComponent(data.path)]
                if (client !== undefined) {
                    client.ws = ws
                    if (client.type === undefined && client.prevType !== undefined) {
                        client.type = client.prevType
                    }
                }
                break
            case 'close':
                for (const key in this.clients) {
                    client = this.clients[key]
                    if (client !== undefined && client.ws === ws) {
                        client.prevType = client.type
                        delete client.ws
                        delete client.type
                    }
                }
                break
            case 'position':
                for (const key in this.clients) {
                    client = this.clients[key]
                    if (client !== undefined && client.ws === ws) {
                        client.position = data
                    }
                }
                break
            case 'loaded':
                const pdfFile = decodeURIComponent(data.path)
                client = this.clients[pdfFile]
                if (client !== undefined && client.ws !== undefined) {
                    if (client.position !== undefined) {
                        client.ws.send(JSON.stringify(client.position))
                    } else {
                        const configuration = vscode.workspace.getConfiguration('latex-workshop')
                        client.ws.send(JSON.stringify({
                            type: "params",
                            scale: configuration.get('viewer.zoom'),
                            hand: configuration.get('viewer.hand')
                        }))
                    }
                }
                break
            case 'click':
                this.extension.locator.locate(data, decodeURIComponent(data.path))
                break
            default:
                this.extension.logger.addLogMessage(`Unknown websocket message: ${msg}`)
                break
        }
    }

    syncTeX(pdfFile: string, record: SyncTeXRecord | {[key: string]: string | number}) {
        const client = this.clients[pdfFile]
        if (client === undefined) {
            this.extension.logger.addLogMessage(`PDF is not viewed: ${pdfFile}`)
            return
        }
        if (client.ws !== undefined) {
            client.ws.send(JSON.stringify({type: "synctex", data: record}))
            this.extension.logger.addLogMessage(`Try to synctex ${pdfFile}`)
        }
    }
}

export class PDFProvider implements vscode.TextDocumentContentProvider {
    extension: Extension

    constructor(extension: Extension) {
        this.extension = extension
    }

    public provideTextDocumentContent(uri: vscode.Uri) : string {
        const url = `http://${this.extension.server.address}/viewer.html?file=\\pdf:${encodeURIComponent(uri.fsPath)}`
        return `
            <!DOCTYPE html><html><head></head>
            <body><iframe class="preview-panel" src="${url}" style="position:absolute; border: none; left: 0; top: 0; width: 100%; height: 100%;">
            </iframe></body></html>
        `
    }
}<commit_msg>Fix #211 Tab viewer support UNC address<commit_after>import * as vscode from 'vscode'
import * as fs from 'fs'
import * as path from 'path'
import * as opn from 'opn'
import * as WebSocket from 'ws'

import {Extension} from '../main'
import {SyncTeXRecord} from './locator'

interface Position {}

interface Client {
    type: 'viewer' | 'tab'
    prevType?: 'viewer' | 'tab'
    ws?: WebSocket
    position?: Position
}

export class Viewer {
    extension: Extension
    clients: {[key: string]: Client | undefined} = {}
    positions = {}

    constructor(extension: Extension) {
        this.extension = extension
    }

    refreshExistingViewer(sourceFile: string, type?: string) : boolean {
        const pdfFile = this.extension.manager.tex2pdf(sourceFile)
        const client = this.clients[pdfFile]
        if (client !== undefined &&
            (type === undefined || client.type === type) &&
            client.ws !== undefined) {
            this.extension.logger.addLogMessage(`Refresh PDF viewer for ${pdfFile}`)
            client.ws.send(JSON.stringify({type: "refresh"}))
            return true
        }
        this.extension.logger.addLogMessage(`No PDF viewer connected for ${pdfFile}`)
        return false
    }

    checkViewer(sourceFile: string, type: string) : string | undefined {
        if (this.refreshExistingViewer(sourceFile, type)) {
            return
        }
        const pdfFile = this.extension.manager.tex2pdf(sourceFile)
        if (!fs.existsSync(pdfFile)) {
            this.extension.logger.addLogMessage(`Cannot find PDF file ${pdfFile}`)
            return
        }
        if (this.extension.server.address === undefined) {
            this.extension.logger.addLogMessage(`Cannot establish server connection.`)
            return
        }
        const url = `http://${this.extension.server.address}/viewer.html?file=/pdf:${encodeURIComponent(pdfFile)}`
        this.extension.logger.addLogMessage(`Serving PDF file at ${url}`)
        return url
    }

    openViewer(sourceFile: string) {
        const url = this.checkViewer(sourceFile, 'viewer')
        if (!url) {
            return
        }
        const pdfFile = this.extension.manager.tex2pdf(sourceFile)
        const client = this.clients[pdfFile]
        if (client !== undefined && client.ws !== undefined) {
            client.ws.close()
        }
        this.clients[pdfFile] = {type: 'viewer'}
        opn(url)
        this.extension.logger.addLogMessage(`Open PDF viewer for ${pdfFile}`)
        this.extension.logger.displayStatus('repo', 'statusBar.foreground', `Open PDF viewer for ${path.basename(pdfFile)}.`)
    }

    openTab(sourceFile: string) {
        const url = this.checkViewer(sourceFile, 'tab')
        if (!url) {
            return
        }
        const pdfFile = this.extension.manager.tex2pdf(sourceFile)
        const client = this.clients[pdfFile]
        const uri = vscode.Uri.file(pdfFile).with({scheme: 'latex-workshop-pdf'})
        let column = vscode.ViewColumn.Two
        if (vscode.window.activeTextEditor && vscode.window.activeTextEditor.viewColumn === vscode.ViewColumn.Two) {
            column = vscode.ViewColumn.Three
        }
        if (client !== undefined && client.ws !== undefined) {
            client.ws.close()
        }
        this.clients[pdfFile] = {type: 'tab'}
        vscode.commands.executeCommand("vscode.previewHtml", uri, column, path.basename(pdfFile))
        this.extension.logger.addLogMessage(`Open PDF tab for ${pdfFile}`)
        this.extension.logger.displayStatus('repo', 'statusBar.foreground', `Open PDF tab for ${path.basename(pdfFile)}.`)
    }

    handler(ws: WebSocket, msg: string) {
        const data = JSON.parse(msg)
        let client: Client | undefined
        switch (data.type) {
            case 'open':
                client = this.clients[decodeURIComponent(data.path)]
                if (client !== undefined) {
                    client.ws = ws
                    if (client.type === undefined && client.prevType !== undefined) {
                        client.type = client.prevType
                    }
                }
                break
            case 'close':
                for (const key in this.clients) {
                    client = this.clients[key]
                    if (client !== undefined && client.ws === ws) {
                        client.prevType = client.type
                        delete client.ws
                        delete client.type
                    }
                }
                break
            case 'position':
                for (const key in this.clients) {
                    client = this.clients[key]
                    if (client !== undefined && client.ws === ws) {
                        client.position = data
                    }
                }
                break
            case 'loaded':
                const pdfFile = decodeURIComponent(data.path)
                client = this.clients[pdfFile]
                if (client !== undefined && client.ws !== undefined) {
                    if (client.position !== undefined) {
                        client.ws.send(JSON.stringify(client.position))
                    } else {
                        const configuration = vscode.workspace.getConfiguration('latex-workshop')
                        client.ws.send(JSON.stringify({
                            type: "params",
                            scale: configuration.get('viewer.zoom'),
                            hand: configuration.get('viewer.hand')
                        }))
                    }
                }
                break
            case 'click':
                this.extension.locator.locate(data, decodeURIComponent(data.path))
                break
            default:
                this.extension.logger.addLogMessage(`Unknown websocket message: ${msg}`)
                break
        }
    }

    syncTeX(pdfFile: string, record: SyncTeXRecord | {[key: string]: string | number}) {
        const client = this.clients[pdfFile]
        if (client === undefined) {
            this.extension.logger.addLogMessage(`PDF is not viewed: ${pdfFile}`)
            return
        }
        if (client.ws !== undefined) {
            client.ws.send(JSON.stringify({type: "synctex", data: record}))
            this.extension.logger.addLogMessage(`Try to synctex ${pdfFile}`)
        }
    }
}

export class PDFProvider implements vscode.TextDocumentContentProvider {
    extension: Extension

    constructor(extension: Extension) {
        this.extension = extension
    }

    public provideTextDocumentContent(uri: vscode.Uri) : string {
        const url = `http://${this.extension.server.address}/viewer.html?file=/pdf:${uri.authority ? `\\\\${uri.authority}` : ''}${encodeURIComponent(uri.fsPath)}`
        return `
            <!DOCTYPE html><html><head></head>
            <body><iframe class="preview-panel" src="${url}" style="position:absolute; border: none; left: 0; top: 0; width: 100%; height: 100%;">
            </iframe></body></html>
        `
    }
}
{'fraction_non_alphanumeric': 0.1205578366133371, 'fraction_numerical': 0.0019113691066119213, 'mean_word_length': 1.8441715321119387, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2326529', 'n_tokens_mistral': 3832, 'n_tokens_neox': 3699, 'n_words': 812}