diff --git a/Readme.md b/Readme.md index 119aec0..03ffc52 100644 --- a/Readme.md +++ b/Readme.md @@ -128,6 +128,10 @@ for guide of coc.nvim's configuration. - `tsserver.disableAutomaticTypeAcquisition`:Disable download of typings, default: `false` - `tsserver.useBatchedBufferSync`: use batched buffer synchronize support, default: `true` +- `tsserver.enableTracing`: Enables tracing TS server performance to a + directory. These trace files can be used to diagnose TS Server performance + issues. The log may contain file paths, source code, and other potentially + sensitive information from your project, default: `false` - `typescript.updateImportsOnFileMove.enable`:Enable update imports on file move., default: `true` - `typescript.implementationsCodeLens.enable`:Enable codeLens for diff --git a/package.json b/package.json index 191f5d7..4b5ed22 100644 --- a/package.json +++ b/package.json @@ -224,6 +224,12 @@ ], "description": "Trace level of tsserver" }, + "tsserver.enableTracing": { + "type": "boolean", + "default": false, + "description": "Enables tracing TS server performance to a directory. These trace files can be used to diagnose TS Server performance issues. The log may contain file paths, source code, and other potentially sensitive information from your project.", + "scope": "window" + }, "tsserver.pluginPaths": { "type": "array", "default": [], diff --git a/src/server/typescriptServiceClient.ts b/src/server/typescriptServiceClient.ts index b1fb75d..6e99388 100644 --- a/src/server/typescriptServiceClient.ts +++ b/src/server/typescriptServiceClient.ts @@ -20,7 +20,7 @@ import { ExecConfig, ITypeScriptServiceClient, ServerResponse } from './typescri import API from './utils/api' import { TsServerLogLevel, TypeScriptServiceConfiguration } from './utils/configuration' import Logger from './utils/logger' -import { fork, getTempDirectory, getTempFile, IForkOptions, makeRandomHexString } from './utils/process' +import { fork, getTempDirectory, createTempDirectory, getTempFile, IForkOptions, makeRandomHexString } from './utils/process' import Tracer from './utils/tracer' import { inferredProjectConfig } from './utils/tsconfig' import { TypeScriptVersion, TypeScriptVersionProvider } from './utils/versionProvider' @@ -843,6 +843,7 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient private async getTsServerArgs(currentVersion: TypeScriptVersion): Promise { const args: string[] = [] + args.push('--allowLocalPluginLoads') if (this.apiVersion.gte(API.v250)) { @@ -860,10 +861,10 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient args.push('--cancellationPipeName', this.cancellationPipeName + '*') } + const logDir = getTempDirectory() if (this.apiVersion.gte(API.v222)) { const isRoot = process.getuid && process.getuid() == 0 if (this._configuration.tsServerLogLevel !== TsServerLogLevel.Off && !isRoot) { - const logDir = getTempDirectory() if (logDir) { this.tsServerLogFile = path.join(logDir, `tsserver.log`) this.info('TSServer log file :', this.tsServerLogFile) @@ -882,6 +883,16 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient } } + if (this._configuration.enableTsServerTracing) { + let tsServerTraceDirectory = createTempDirectory(`tsserver-trace-${makeRandomHexString(5)}`) + if (tsServerTraceDirectory) { + args.push('--traceDirectory', tsServerTraceDirectory) + this.info('TSServer trace directory :', tsServerTraceDirectory) + } else { + this.error('Could not create TSServer trace directory') + } + } + if (this.apiVersion.gte(API.v230)) { const pluginNames = this.pluginManager.plugins.map(x => x.name) let pluginPaths = this._configuration.tsServerPluginPaths diff --git a/src/server/utils/configuration.ts b/src/server/utils/configuration.ts index ec6b6ee..f6ae787 100644 --- a/src/server/utils/configuration.ts +++ b/src/server/utils/configuration.ts @@ -51,6 +51,10 @@ export class TypeScriptServiceConfiguration { }) } + public get enableTsServerTracing(): boolean { + return this._configuration.get('enableTracing', false) + } + public get includePackageJsonAutoImports(): 'auto' | 'on' | 'off' { return this._includePackageJsonAutoImports } diff --git a/src/server/utils/process.ts b/src/server/utils/process.ts index 3b8c6fd..ba2c2bb 100644 --- a/src/server/utils/process.ts +++ b/src/server/utils/process.ts @@ -24,10 +24,14 @@ export function makeRandomHexString(length: number): string { return result } -export function getTempDirectory(): string { +export function getTempDirectory(): string | undefined { let dir = path.join(os.tmpdir(), `coc.nvim-${process.pid}`) - if (!fs.existsSync(dir)) { - fs.mkdirSync(dir) + try { + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir) + } + } catch (e) { + return undefined } return dir } @@ -36,19 +40,34 @@ function generatePipeName(): string { return getPipeName(makeRandomHexString(40)) } -function getPipeName(name: string): string { +function getPipeName(name: string): string | undefined { const fullName = 'coc-tsc-' + name if (process.platform === 'win32') { return '\\\\.\\pipe\\' + fullName + '-sock' } const tmpdir = getTempDirectory() + if (!tmpdir) return undefined // Mac/Unix: use socket file return path.join(tmpdir, fullName + '.sock') } -export function getTempFile(name: string): string { +export function getTempFile(name: string): string | undefined { const fullName = 'coc-nvim-' + name - return path.join(getTempDirectory(), fullName + '.sock') + let dir = getTempDirectory() + if (!dir) return undefined + return path.join(dir, fullName + '.sock') +} + +export function createTempDirectory(name: string) { + let dir = getTempDirectory() + if (!dir) return undefined + let res = path.join(dir, name) + try { + fs.mkdirSync(res) + } catch (e) { + return undefined + } + return res } function generatePatchedEnv(