diff --git a/README.md b/README.md index 80069d8d..55660676 100644 --- a/README.md +++ b/README.md @@ -592,6 +592,7 @@ The `$/typescriptVersion` notification params include two properties: - [x] textDocument/formatting - [x] textDocument/hover - [x] textDocument/inlayHint (no support for `inlayHint/resolve` or `workspace/inlayHint/refresh`) +- [x] textDocument/linkedEditingRange - [x] textDocument/prepareCallHierarchy - [x] callHierarchy/incomingCalls - [x] callHierarchy/outgoingCalls diff --git a/package.json b/package.json index 763125fc..53435f21 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "typescript-language-server", - "version": "3.3.2", + "version": "3.3.3-0", "description": "Language Server Protocol (LSP) implementation for TypeScript using tsserver", "author": "TypeFox and others", "license": "Apache-2.0", diff --git a/src/cli.ts b/src/cli.ts index f8bbe907..d4c11dff 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -21,6 +21,7 @@ const program = new Command('typescript-language-server') .option('--tsserver-log-verbosity ', '[deprecated] Specify a tsserver log verbosity (terse, normal, verbose). Defaults to `normal`.' + ' example: --tsserver-log-verbosity verbose') .option('--tsserver-path ', '[deprecated] Specify path to tsserver.js or the lib directory. example: --tsserver-path=/Users/me/typescript/lib/tsserver.js') + .option('--log-directory ', 'Directory for LSP logs') .parse(process.argv); const options = program.opts(); @@ -37,5 +38,6 @@ if (options.logLevel) { createLspConnection({ cmdLineTsserverPath: options.tsserverPath as string, cmdLineTsserverLogVerbosity: TsServerLogLevel.fromString(options.tsserverLogVerbosity), + logDirectory: options.logDirectory, showMessageLevel: logLevel as lsp.MessageType, }).listen(); diff --git a/src/lsp-connection.ts b/src/lsp-connection.ts index 319d605a..67096709 100644 --- a/src/lsp-connection.ts +++ b/src/lsp-connection.ts @@ -6,7 +6,7 @@ */ import lsp from 'vscode-languageserver/node.js'; -import { LspClientLogger } from './utils/logger.js'; +import { FileLogger, LspClientLogger } from './utils/logger.js'; import { LspServer } from './lsp-server.js'; import { LspClientImpl } from './lsp-client.js'; import type { TsServerLogLevel } from './utils/configuration.js'; @@ -14,13 +14,16 @@ import type { TsServerLogLevel } from './utils/configuration.js'; export interface LspConnectionOptions { cmdLineTsserverPath: string; cmdLineTsserverLogVerbosity: TsServerLogLevel; + logDirectory?: string; showMessageLevel: lsp.MessageType; } export function createLspConnection(options: LspConnectionOptions): lsp.Connection { const connection = lsp.createConnection(lsp.ProposedFeatures.all); const lspClient = new LspClientImpl(connection); - const logger = new LspClientLogger(lspClient, options.showMessageLevel); + const logger = options.logDirectory + ? new FileLogger(options.logDirectory, options.showMessageLevel) + : new LspClientLogger(lspClient, options.showMessageLevel); const server: LspServer = new LspServer({ logger, lspClient, diff --git a/src/lsp-server.ts b/src/lsp-server.ts index 75858f2f..756cd5d1 100644 --- a/src/lsp-server.ts +++ b/src/lsp-server.ts @@ -961,6 +961,7 @@ export class LspServer { } } + this.logger.log(`codeAction returned with ${actions.length} actions`); return actions; } protected async getCodeFixes(fileRangeArgs: ts.server.protocol.FileRangeRequestArgs, context: lsp.CodeActionContext, token?: lsp.CancellationToken): Promise { diff --git a/src/tsServer/tracer.ts b/src/tsServer/tracer.ts index 23eff8a2..6dfbf4db 100644 --- a/src/tsServer/tracer.ts +++ b/src/tsServer/tracer.ts @@ -68,7 +68,7 @@ export default class Tracer { if (this.trace === Trace.Verbose && response.body) { data = `Result: ${JSON.stringify(response.body, null, 4)}`; } - this.logTrace(serverId, `Response received: ${response.command} (${response.request_seq}). Request took ${Date.now() - meta.queuingStartTime} ms. Success: ${response.success} ${!response.success ? `. Message: ${response.message}` : ''}`, data); + this.logTrace(serverId, `Response received: ${response.command} (${response.request_seq}). Request took ${Date.now() - meta.queuingStartTime} ms. Success: ${response.success}${!response.success ? `. Message: ${response.message}` : ''}`, data); } public traceRequestCompleted(serverId: string, command: string, request_seq: number, meta: RequestExecutionMetadata): any { diff --git a/src/utils/logger.ts b/src/utils/logger.ts index f177f515..2d562e8e 100644 --- a/src/utils/logger.ts +++ b/src/utils/logger.ts @@ -11,6 +11,8 @@ /* eslint-disable @typescript-eslint/no-unnecessary-qualifier */ +import path from 'path'; +import fs from 'fs-extra'; import lsp from 'vscode-languageserver'; import type { LspClient } from '../lsp-client.js'; @@ -180,6 +182,82 @@ export class ConsoleLogger implements Logger { } } +export class FileLogger implements Logger { + private logFile: fs.WriteStream; + + constructor( + private logDirectory: string, + private level: lsp.MessageType, + ) { + console.error('Resolved logDirectory', path.resolve(this.logDirectory)); + if (!fs.pathExistsSync(this.logDirectory)) { + fs.mkdirSync(this.logDirectory); + } + this.logFile = fs.createWriteStream(path.join(this.logDirectory, 'debug.log'), { flags : 'w' }); + } + + private sendMessage(severity: lsp.MessageType, args: any[], options?: { overrideLevel?: boolean; }): void { + if (this.level >= severity || options?.overrideLevel) { + const [prefix, firstArg, ...rest] = this.toStrings(...args); + this.logFile.write(`${prefix} ${firstArg}`); + if (rest !== undefined) { + this.logFile.write(`\n${rest.join('\n')}`); + } + this.logFile.write('\n\n'); + } + } + + private toStrings(...args: any[]): string[] { + return args.map(a => { + const out = typeof a === 'string' ? a : JSON.stringify(a, null, 2); + if (out && out.length > 1000) { + return ` ${out.slice(0, 1000)}...`; + } + return out; + }); + } + + error(...args: any[]): void { + this.sendMessage(lsp.MessageType.Error, args); + } + + warn(...args: any[]): void { + this.sendMessage(lsp.MessageType.Warning, args); + } + + info(...args: any[]): void { + this.sendMessage(lsp.MessageType.Info, args); + } + + log(...args: any[]): void { + this.sendMessage(lsp.MessageType.Log, args); + } + + logIgnoringVerbosity(level: LogLevel, ...args: any[]): void { + this.sendMessage(this.logLevelToLspMessageType(level), args, { overrideLevel: true }); + } + + trace(level: TraceLevel, message: string, data?: any): void { + this.logIgnoringVerbosity(LogLevel.Log, `[${level} - ${now()}] ${message}`); + if (data) { + this.logIgnoringVerbosity(LogLevel.Log, data2String(data)); + } + } + + private logLevelToLspMessageType(level: LogLevel): lsp.MessageType { + switch (level) { + case LogLevel.Log: + return lsp.MessageType.Log; + case LogLevel.Info: + return lsp.MessageType.Info; + case LogLevel.Warning: + return lsp.MessageType.Warning; + case LogLevel.Error: + return lsp.MessageType.Error; + } + } +} + export class PrefixingLogger implements Logger { constructor( private logger: Logger, @@ -207,10 +285,7 @@ export class PrefixingLogger implements Logger { } trace(level: TraceLevel, message: string, data?: any): void { - this.logIgnoringVerbosity(LogLevel.Log, this.prefix, `[${level} - ${now()}] ${message}`); - if (data) { - this.logIgnoringVerbosity(LogLevel.Log, this.prefix, data2String(data)); - } + this.logIgnoringVerbosity(LogLevel.Log, `[${level} - ${now()}] ${message}`, data ? data2String(data) : undefined); } } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy