import { CancellationToken , Command , Disposable , Hover , HoverProvider , languages , MarkdownString , Position , ProviderResult , TextDocument , Uri , window } from "vscode" ; import { instrumentOperationAsVsCodeCommand } from "vscode-extension-telemetry-wrapper" ; import { JAVA_LANGID } from "./constants" ; import { startDebugging } from "./debugCodeLensProvider" ; import { resolveElementAtSelection } from "./languageServerPlugin" ; const JAVA_HOVER_RUN_COMMAND = "java.debug.runHover" ; const MAIN_METHOD_REGEX = /^(public|static|final|synchronized|\s+){4,}void\s+main\s*\(\s*String\s*\[\s*\]\s*\w+\s*\)\s*($|\{)/ ; export function initializeHoverProvider ( ) { return new DebugHoverProvider ( ) ; } class DebugHoverProvider implements Disposable { private runHoverCommand : Disposable ; private hoverProvider : Disposable | undefined ; constructor ( ) { this . runHoverCommand = instrumentOperationAsVsCodeCommand ( JAVA_HOVER_RUN_COMMAND , async ( noDebug , uri , position ) => { const element = await resolveElementAtSelection ( uri , position . line , position . character ) ; if ( element && element . hasMainMethod ) { startDebugging ( element . declaringType , element . projectName , Uri . parse ( uri ) , noDebug ) ; } else { window . showErrorMessage ( "The hovered element is not a main method." ) ; } } ) ; this . hoverProvider = languages . registerHoverProvider ( JAVA_LANGID , new InternalDebugHoverProvider ( ) ) ; } public dispose ( ) { if ( this . runHoverCommand ) { this . runHoverCommand . dispose ( ) ; } if ( this . hoverProvider ) { this . hoverProvider . dispose ( ) ; } } } class InternalDebugHoverProvider implements HoverProvider { public provideHover ( document , position , _token ) { const range = document . getWordRangeAtPosition ( position , /\w+/ ) ; if ( ! range || document . getText ( range ) !== "main" ) { return undefined ; } const line = document . lineAt ( position ) ; if ( MAIN_METHOD_REGEX . test ( line . text . trim ( ) ) && this . isMainMethod ( line . text . trim ( ) ) ) { const commands = [ { title : "Run" , command : JAVA_HOVER_RUN_COMMAND , tooltip : "Run Java Program" , arguments : [ true , document . uri . toString ( ) , { line : position . line , character : position . character } ] , } , { title : "Debug" , command : JAVA_HOVER_RUN_COMMAND , tooltip : "Debug Java Program" , arguments : [ false , document . uri . toString ( ) , { line : position . line , character : position . character } ] , } , ] ; const contributed = new MarkdownString ( commands . map ( ( command ) => this . convertCommandToMarkdown ( command ) ) . join ( " | " ) ) ; contributed . isTrusted = true ; return new Hover ( contributed ) ; } return undefined ; } private isMainMethod ( line ) { const modifier = line . substring ( 0 , line . indexOf ( "main" ) ) ; const modifiers = modifier . split ( /\s+/ ) ; return modifiers . indexOf ( "public" ) >= 0 && modifiers . indexOf ( "static" ) >= 0 ; } private convertCommandToMarkdown ( command ) { return `[${ command . title }](command:${ command . command }?` + `${ encodeURIComponent ( JSON . stringify ( command . arguments || [ ] ) ) } "${ command . tooltip || command . command }")` ; } }