import { Disposable } from '../utils/dispose' ; import * as vscode from 'vscode' ; import TelemetryReporter from 'vscode-extension-telemetry' ; import { EndpointManager } from '../infoManagers/endpointManager' ; import { URL } from 'url' ; import { WorkspaceManager } from '../infoManagers/workspaceManager' ; import { SETTINGS_SECTION_ID } from '../utils/settingsUtil' ; import { ConnectionManager } from '../infoManagers/connectionManager' ; description export class serverTaskLinkProvider extends Disposable implements vscode . TerminalLinkProvider { private readonly _onRequestOpenEditorToSide = this . _register ( new vscode . EventEmitter < vscode . Uri > ( ) ) ; public readonly onRequestOpenEditorToSide = this . _onRequestOpenEditorToSide . event ; constructor ( public terminalName , private readonly _reporter , private readonly _endpointManager , private readonly _workspaceManager , private readonly _connectionManager ) { super ( ) ; vscode . window . registerTerminalLinkProvider ( this ) ; } public async provideTerminalLinks ( context , token ) { const links = new Array < vscode . TerminalLink > ( ) ; if ( ! context . terminal . creationOptions . name || ! this . _isLivePreviewTerminal ( context . terminal . creationOptions . name ) ) { return links ; } this . _findFullLinkRegex ( context . line , links ) ; this . _findPathnameRegex ( context . line , links ) ; return links ; } public async handleTerminalLink ( link ) { this . _reporter . sendTelemetryEvent ( 'task.terminal.handleTerminalLink' ) ; if ( link . inEditor ) { this . _openRelativeLinkInWorkspace ( link . data , link . isDir ) ; } else { vscode . commands . executeCommand ( `${ SETTINGS_SECTION_ID }.start.preview.atFile` , link . data ) ; } } param { string } terminalName returns private _isLivePreviewTerminal ( terminalName ) { return ( this . terminalName != '' && terminalName . indexOf ( this . terminalName ) != - 1 ) ; } param { string } input param { Array < vscode . TerminalLink > } links private _findPathnameRegex ( input , links ) { const partialLinkRegex = new RegExp ( `(?<=\\s)\\/([:/(\\w%\\-.:@)]*)\\?*[\\w=]*` , 'g' ) ; let partialLinkMatches ; do { partialLinkMatches = partialLinkRegex . exec ( input ) ; if ( partialLinkMatches ) { for ( let i = 0 ; i < partialLinkMatches . length ; i ++ ) { if ( partialLinkMatches [ i ] ) { const queryIndex = partialLinkMatches [ i ] . lastIndexOf ( '?' ) ; const link = queryIndex == - 1 ? partialLinkMatches [ i ] : partialLinkMatches [ i ] . substr ( 0 , queryIndex ) ; const isDir = link . endsWith ( '/' ) ; const tooltip = isDir ? 'Reveal Folder ' : 'Open File ' ; const tl = { startIndex : partialLinkMatches . index , length : partialLinkMatches [ i ] . length , tooltip : tooltip , data : link , inEditor : true , isDir : isDir , } ; links . push ( tl ) ; } } } } while ( partialLinkMatches ) ; } param { string } input param { Array < vscode . TerminalLink > } links private _findFullLinkRegex ( input , links ) { const fullLinkRegex = new RegExp ( `\\b\\w{2,20}:\\/\\/(?:localhost|${ this . _connectionManager . host }|:\\d{2,5})[\\w\\-.~:/?#[\\]@!$&()*+,;=]*` , 'g' ) ; let fullURLMatches ; do { fullURLMatches = fullLinkRegex . exec ( input ) ; if ( fullURLMatches ) { for ( let i = 0 ; i < fullURLMatches . length ; i ++ ) { if ( fullURLMatches [ i ] ) { const url = new URL ( fullURLMatches [ i ] ) ; const tl = { startIndex : fullURLMatches . index , length : fullURLMatches [ i ] . length , tooltip : `Open in Preview ` , data : url . pathname + url . search , inEditor : false , } ; links . push ( tl ) ; } } } } while ( fullURLMatches ) ; } param { string } file param { boolean } isDir private _openRelativeLinkInWorkspace ( file , isDir ) { file = unescape ( file ) ; const isWorkspaceFile = this . _workspaceManager . pathExistsRelativeToAnyWorkspace ( file ) ; const fullPath = isWorkspaceFile ? this . _workspaceManager . workspace ?. uri + file : 'file:///' + this . _endpointManager . decodeLooseFileEndpoint ( file ) ; const uri = vscode . Uri . parse ( fullPath ) ; if ( isDir ) { if ( ! this . _workspaceManager . absPathInAnyWorkspace ( uri . fsPath ) ) { vscode . window . showErrorMessage ( 'Cannot reveal folder. It is not in the open workspace.' ) ; } else { vscode . commands . executeCommand ( 'revealInExplorer' , uri ) ; } } else { this . _onRequestOpenEditorToSide . fire ( uri ) ; } } }