JSON Language Server output channel appears twice (#206877)

This commit is contained in:
Martin Aeschlimann
2024-03-05 10:01:55 +01:00
committed by GitHub
parent 6c9d5b3df6
commit 8aca9a5331
3 changed files with 23 additions and 52 deletions

View File

@@ -3,9 +3,9 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Disposable, ExtensionContext, Uri, l10n } from 'vscode';
import { Disposable, ExtensionContext, Uri, l10n, window } from 'vscode';
import { LanguageClientOptions } from 'vscode-languageclient';
import { startClient, LanguageClientConstructor, SchemaRequestService, AsyncDisposable } from '../jsonClient';
import { startClient, LanguageClientConstructor, SchemaRequestService, AsyncDisposable, languageServerDescription } from '../jsonClient';
import { LanguageClient } from 'vscode-languageclient/browser';
declare const Worker: {
@@ -43,7 +43,10 @@ export async function activate(context: ExtensionContext) {
}
};
client = await startClient(context, newLanguageClient, { schemaRequests, timer });
const logOutputChannel = window.createOutputChannel(languageServerDescription, { log: true });
context.subscriptions.push(logOutputChannel);
client = await startClient(context, newLanguageClient, { schemaRequests, timer, logOutputChannel });
} catch (e) {
console.log(e);

View File

@@ -6,7 +6,7 @@
export type JSONLanguageStatus = { schemas: string[] };
import {
workspace, window, languages, commands, OutputChannel, ExtensionContext, extensions, Uri, ColorInformation,
workspace, window, languages, commands, LogOutputChannel, ExtensionContext, extensions, Uri, ColorInformation,
Diagnostic, StatusBarAlignment, TextEditor, TextDocument, FormattingOptions, CancellationToken, FoldingRange,
ProviderResult, TextEdit, Range, Position, Disposable, CompletionItem, CompletionList, CompletionContext, Hover, MarkdownString, FoldingContext, DocumentSymbol, SymbolInformation, l10n
} from 'vscode';
@@ -130,6 +130,7 @@ export interface Runtime {
readonly timer: {
setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): Disposable;
};
logOutputChannel: LogOutputChannel;
}
export interface SchemaRequestService {
@@ -150,12 +151,10 @@ export interface AsyncDisposable {
}
export async function startClient(context: ExtensionContext, newLanguageClient: LanguageClientConstructor, runtime: Runtime): Promise<AsyncDisposable> {
const outputChannel = window.createOutputChannel(languageServerDescription);
const languageParticipants = getLanguageParticipants();
context.subscriptions.push(languageParticipants);
let client: Disposable | undefined = await startClientWithParticipants(context, languageParticipants, newLanguageClient, outputChannel, runtime);
let client: Disposable | undefined = await startClientWithParticipants(context, languageParticipants, newLanguageClient, runtime);
let restartTrigger: Disposable | undefined;
languageParticipants.onDidChange(() => {
@@ -164,12 +163,12 @@ export async function startClient(context: ExtensionContext, newLanguageClient:
}
restartTrigger = runtime.timer.setTimeout(async () => {
if (client) {
outputChannel.appendLine('Extensions have changed, restarting JSON server...');
outputChannel.appendLine('');
runtime.logOutputChannel.info('Extensions have changed, restarting JSON server...');
runtime.logOutputChannel.info('');
const oldClient = client;
client = undefined;
await oldClient.dispose();
client = await startClientWithParticipants(context, languageParticipants, newLanguageClient, outputChannel, runtime);
client = await startClientWithParticipants(context, languageParticipants, newLanguageClient, runtime);
}
}, 2000);
});
@@ -178,12 +177,11 @@ export async function startClient(context: ExtensionContext, newLanguageClient:
dispose: async () => {
restartTrigger?.dispose();
await client?.dispose();
outputChannel.dispose();
}
};
}
async function startClientWithParticipants(context: ExtensionContext, languageParticipants: LanguageParticipants, newLanguageClient: LanguageClientConstructor, outputChannel: OutputChannel, runtime: Runtime): Promise<AsyncDisposable> {
async function startClientWithParticipants(context: ExtensionContext, languageParticipants: LanguageParticipants, newLanguageClient: LanguageClientConstructor, runtime: Runtime): Promise<AsyncDisposable> {
const toDispose: Disposable[] = [];
@@ -348,7 +346,7 @@ async function startClientWithParticipants(context: ExtensionContext, languagePa
}
};
clientOptions.outputChannel = outputChannel;
clientOptions.outputChannel = runtime.logOutputChannel;
// Create the language client and start the client.
const client = newLanguageClient('json', languageServerDescription, clientOptions);
client.registerProposedFeatures();

View File

@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Disposable, ExtensionContext, OutputChannel, window, workspace, l10n, env } from 'vscode';
import { Disposable, ExtensionContext, LogOutputChannel, window, l10n, env, LogLevel } from 'vscode';
import { startClient, LanguageClientConstructor, SchemaRequestService, languageServerDescription, AsyncDisposable } from '../jsonClient';
import { ServerOptions, TransportKind, LanguageClientOptions, LanguageClient } from 'vscode-languageclient/node';
@@ -14,15 +14,16 @@ import { xhr, XHRResponse, getErrorStatusDescription, Headers } from 'request-li
import TelemetryReporter from '@vscode/extension-telemetry';
import { JSONSchemaCache } from './schemaCache';
let telemetry: TelemetryReporter | undefined;
let client: AsyncDisposable | undefined;
// this method is called when vs code is activated
export async function activate(context: ExtensionContext) {
const clientPackageJSON = await getPackageInfo(context);
telemetry = new TelemetryReporter(clientPackageJSON.aiKey);
const telemetry = new TelemetryReporter(clientPackageJSON.aiKey);
context.subscriptions.push(telemetry);
const outputChannel = window.createOutputChannel(languageServerDescription);
const logOutputChannel = window.createOutputChannel(languageServerDescription, { log: true });
context.subscriptions.push(logOutputChannel);
const serverMain = `./server/${clientPackageJSON.main.indexOf('/dist/') !== -1 ? 'dist' : 'out'}/node/jsonServerMain`;
const serverModule = context.asAbsolutePath(serverMain);
@@ -38,11 +39,8 @@ export async function activate(context: ExtensionContext) {
};
const newLanguageClient: LanguageClientConstructor = (id: string, name: string, clientOptions: LanguageClientOptions) => {
clientOptions.outputChannel = outputChannel;
return new LanguageClient(id, name, serverOptions, clientOptions);
};
const log = getLog(outputChannel);
context.subscriptions.push(log);
const timer = {
setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): Disposable {
@@ -54,9 +52,9 @@ export async function activate(context: ExtensionContext) {
// pass the location of the localization bundle to the server
process.env['VSCODE_L10N_BUNDLE_LOCATION'] = l10n.uri?.toString() ?? '';
const schemaRequests = await getSchemaRequestService(context, log);
const schemaRequests = await getSchemaRequestService(context, logOutputChannel);
client = await startClient(context, newLanguageClient, { schemaRequests, telemetry, timer });
client = await startClient(context, newLanguageClient, { schemaRequests, telemetry, timer, logOutputChannel });
}
export async function deactivate(): Promise<any> {
@@ -64,7 +62,6 @@ export async function deactivate(): Promise<any> {
await client.dispose();
client = undefined;
}
telemetry?.dispose();
}
interface IPackageInfo {
@@ -84,36 +81,9 @@ async function getPackageInfo(context: ExtensionContext): Promise<IPackageInfo>
}
}
interface Log {
trace(message: string): void;
isTrace(): boolean;
dispose(): void;
}
const traceSetting = 'json.trace.server';
function getLog(outputChannel: OutputChannel): Log {
let trace = workspace.getConfiguration().get(traceSetting) === 'verbose';
const configListener = workspace.onDidChangeConfiguration(e => {
if (e.affectsConfiguration(traceSetting)) {
trace = workspace.getConfiguration().get(traceSetting) === 'verbose';
}
});
return {
trace(message: string) {
if (trace) {
outputChannel.appendLine(message);
}
},
isTrace() {
return trace;
},
dispose: () => configListener.dispose()
};
}
const retryTimeoutInHours = 2 * 24; // 2 days
async function getSchemaRequestService(context: ExtensionContext, log: Log): Promise<SchemaRequestService> {
async function getSchemaRequestService(context: ExtensionContext, log: LogOutputChannel): Promise<SchemaRequestService> {
let cache: JSONSchemaCache | undefined = undefined;
const globalStorage = context.globalStorageUri;
@@ -191,7 +161,7 @@ async function getSchemaRequestService(context: ExtensionContext, log: Log): Pro
if (cache && /^https?:\/\/json\.schemastore\.org\//.test(uri)) {
const content = await cache.getSchemaIfUpdatedSince(uri, retryTimeoutInHours);
if (content) {
if (log.isTrace()) {
if (log.logLevel === LogLevel.Trace) {
log.trace(`[json schema cache] Schema ${uri} from cache without request (last accessed ${cache.getLastUpdatedInHours(uri)} hours ago)`);
}