import { CancellationToken , CodeAction , CodeActionKind , CodeActionParams , Command , Connection , ExecuteCommandParams , WorkDoneProgressServerReporter , } from 'vscode-languageserver' ; import { AnalysisResults } from './analyzer/analysis' ; import { ImportResolver } from './analyzer/importResolver' ; import { isPythonBinary } from './analyzer/pythonPathUtils' ; import { BackgroundAnalysis } from './backgroundAnalysis' ; import { BackgroundAnalysisBase } from './backgroundAnalysisBase' ; import { CommandController } from './commands/commandController' ; import { getCancellationFolderName } from './common/cancellationUtils' ; import { ConfigOptions } from './common/configOptions' ; import { ConsoleWithLogLevel , LogLevel } from './common/console' ; import { isDebugMode , isString } from './common/core' ; import { FileBasedCancellationProvider } from './common/fileBasedCancellationUtils' ; import { FileSystem } from './common/fileSystem' ; import { FullAccessHost } from './common/fullAccessHost' ; import { Host } from './common/host' ; import { resolvePaths } from './common/pathUtils' ; import { ProgressReporter } from './common/progressReporter' ; import { createFromRealFileSystem , WorkspaceFileWatcherProvider } from './common/realFileSystem' ; import { UriParser } from './common/uriParser' ; import { LanguageServerBase , ServerSettings , WorkspaceServiceInstance } from './languageServerBase' ; import { CodeActionProvider } from './languageService/codeActionProvider' ; import { PyrightFileSystem } from './pyrightFileSystem' ; import { WorkspaceMap } from './workspaceMap' ; const maxAnalysisTimeInForeground = { openFilesTimeInMs : 50 , noOpenFilesTimeInMs : 200 } ; export class PyrightServer extends LanguageServerBase { private _controller : CommandController ; constructor ( connection ) { const version = require ( '../package.json' ) . version || '' ; const rootDirectory = ( global as any ) . __rootDirectory || __dirname ; const console = new ConsoleWithLogLevel ( connection . console ) ; const workspaceMap = new WorkspaceMap ( ) ; const fileWatcherProvider = new WorkspaceFileWatcherProvider ( workspaceMap , console ) ; const fileSystem = createFromRealFileSystem ( console , fileWatcherProvider ) ; const pyrightFileSystem = new PyrightFileSystem ( fileSystem ) ; super ( { productName : 'Pyright' , rootDirectory , version , workspaceMap , fileSystem : pyrightFileSystem , fileWatcherProvider , cancellationProvider : new FileBasedCancellationProvider ( 'bg' ) , maxAnalysisTimeInForeground , supportedCodeActions : [ CodeActionKind . QuickFix , CodeActionKind . SourceOrganizeImports ] , uriParser : new UriParser ( pyrightFileSystem ) , } , connection , console ) ; this . _controller = new CommandController ( this ) ; } async getSettings ( workspace ) { const serverSettings = { watchForSourceChanges : true , watchForLibraryChanges : true , watchForConfigChanges : true , openFilesOnly : true , useLibraryCodeForTypes : false , disableLanguageServices : false , disableOrganizeImports : false , typeCheckingMode : 'basic' , diagnosticSeverityOverrides : { } , logLevel : LogLevel . Info , autoImportCompletions : true , } ; try { const pythonSection = await this . getConfiguration ( workspace . rootUri , 'python' ) ; if ( pythonSection ) { const pythonPath = pythonSection . pythonPath ; if ( pythonPath && isString ( pythonPath ) && ! isPythonBinary ( pythonPath ) ) { serverSettings . pythonPath = resolvePaths ( workspace . rootPath , this . expandPathVariables ( workspace . rootPath , pythonPath ) ) ; } const venvPath = pythonSection . venvPath ; if ( venvPath && isString ( venvPath ) ) { serverSettings . venvPath = resolvePaths ( workspace . rootPath , this . expandPathVariables ( workspace . rootPath , venvPath ) ) ; } } const pythonAnalysisSection = await this . getConfiguration ( workspace . rootUri , 'python.analysis' ) ; if ( pythonAnalysisSection ) { const typeshedPaths = pythonAnalysisSection . typeshedPaths ; if ( typeshedPaths && Array . isArray ( typeshedPaths ) && typeshedPaths . length > 0 ) { const typeshedPath = typeshedPaths [ 0 ] ; if ( typeshedPath && isString ( typeshedPath ) ) { serverSettings . typeshedPath = resolvePaths ( workspace . rootPath , this . expandPathVariables ( workspace . rootPath , typeshedPath ) ) ; } } const stubPath = pythonAnalysisSection . stubPath ; if ( stubPath && isString ( stubPath ) ) { serverSettings . stubPath = resolvePaths ( workspace . rootPath , this . expandPathVariables ( workspace . rootPath , stubPath ) ) ; } const diagnosticSeverityOverrides = pythonAnalysisSection . diagnosticSeverityOverrides ; if ( diagnosticSeverityOverrides ) { for ( const [ name , value ] of Object . entries ( diagnosticSeverityOverrides ) ) { const ruleName = this . getDiagnosticRuleName ( name ) ; const severity = this . getSeverityOverrides ( value as string ) ; if ( ruleName && severity ) { serverSettings . diagnosticSeverityOverrides ! [ ruleName ] = severity ! ; } } } if ( pythonAnalysisSection . diagnosticMode !== undefined ) { serverSettings . openFilesOnly = this . isOpenFilesOnly ( pythonAnalysisSection . diagnosticMode ) ; } else if ( pythonAnalysisSection . openFilesOnly !== undefined ) { serverSettings . openFilesOnly = ! ! pythonAnalysisSection . openFilesOnly ; } if ( pythonAnalysisSection . useLibraryCodeForTypes !== undefined ) { serverSettings . useLibraryCodeForTypes = ! ! pythonAnalysisSection . useLibraryCodeForTypes ; } serverSettings . logLevel = this . convertLogLevel ( pythonAnalysisSection . logLevel ) ; serverSettings . autoSearchPaths = ! ! pythonAnalysisSection . autoSearchPaths ; const extraPaths = pythonAnalysisSection . extraPaths ; if ( extraPaths && Array . isArray ( extraPaths ) && extraPaths . length > 0 ) { serverSettings . extraPaths = extraPaths . filter ( ( p ) => p && isString ( p ) ) . map ( ( p ) => resolvePaths ( workspace . rootPath , this . expandPathVariables ( workspace . rootPath , p ) ) ) ; } if ( pythonAnalysisSection . typeCheckingMode !== undefined ) { serverSettings . typeCheckingMode = pythonAnalysisSection . typeCheckingMode ; } if ( pythonAnalysisSection . autoImportCompletions !== undefined ) { serverSettings . autoImportCompletions = pythonAnalysisSection . autoImportCompletions ; } if ( serverSettings . logLevel === LogLevel . Log && pythonAnalysisSection . logTypeEvaluationTime !== undefined ) { serverSettings . logTypeEvaluationTime = pythonAnalysisSection . logTypeEvaluationTime ; } if ( pythonAnalysisSection . typeEvaluationTimeThreshold !== undefined ) { serverSettings . typeEvaluationTimeThreshold = pythonAnalysisSection . typeEvaluationTimeThreshold ; } } else { serverSettings . autoSearchPaths = true ; } const pyrightSection = await this . getConfiguration ( workspace . rootUri , 'pyright' ) ; if ( pyrightSection ) { if ( pyrightSection . openFilesOnly !== undefined ) { serverSettings . openFilesOnly = ! ! pyrightSection . openFilesOnly ; } if ( pyrightSection . useLibraryCodeForTypes !== undefined ) { serverSettings . useLibraryCodeForTypes = ! ! pyrightSection . useLibraryCodeForTypes ; } serverSettings . disableLanguageServices = ! ! pyrightSection . disableLanguageServices ; serverSettings . disableOrganizeImports = ! ! pyrightSection . disableOrganizeImports ; const typeCheckingMode = pyrightSection . typeCheckingMode ; if ( typeCheckingMode && isString ( typeCheckingMode ) ) { serverSettings . typeCheckingMode = typeCheckingMode ; } } } catch ( error ) { this . console . error ( `Error reading settings: ${ error }` ) ; } return serverSettings ; } createBackgroundAnalysis ( ) { if ( isDebugMode ( ) || ! getCancellationFolderName ( ) ) { return undefined ; } return new BackgroundAnalysis ( this . console ) ; } protected override createHost ( ) { return new FullAccessHost ( this . fs ) ; } protected override createImportResolver ( fs , options , host ) { return new ImportResolver ( fs , options , host ) ; } protected executeCommand ( params , token ) { return this . _controller . execute ( params , token ) ; } protected isLongRunningCommand ( command ) { return this . _controller . isLongRunningCommand ( command ) ; } protected async executeCodeAction ( params , token ) { this . recordUserInteractionTime ( ) ; const filePath = this . _uriParser . decodeTextDocumentUri ( params . textDocument . uri ) ; const workspace = await this . getWorkspaceForFile ( filePath ) ; return CodeActionProvider . getCodeActionsForPosition ( workspace , filePath , params . range , token ) ; } protected createProgressReporter ( ) { let workDoneProgress ; return { isEnabled : ( data ) => true , begin : ( ) => { if ( this . client . hasWindowProgressCapability ) { workDoneProgress = this . _connection . window . createWorkDoneProgress ( ) ; workDoneProgress . then ( ( progress ) => { progress . begin ( '' ) ; } ) . ignoreErrors ( ) ; } else { this . _connection . sendNotification ( 'pyright/beginProgress' ) ; } } , report : ( message ) => { if ( workDoneProgress ) { workDoneProgress . then ( ( progress ) => { progress . report ( message ) ; } ) . ignoreErrors ( ) ; } else { this . _connection . sendNotification ( 'pyright/reportProgress' , message ) ; } } , end : ( ) => { if ( workDoneProgress ) { workDoneProgress . then ( ( progress ) => { progress . done ( ) ; } ) . ignoreErrors ( ) ; workDoneProgress = undefined ; } else { this . _connection . sendNotification ( 'pyright/endProgress' ) ; } } , } ; } }