mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-20 00:28:52 +01:00
@@ -11,7 +11,7 @@ import type * as Proto from '../../tsServer/protocol/protocol';
|
||||
import * as PConst from '../../tsServer/protocol/protocol.const';
|
||||
import * as typeConverters from '../../typeConverters';
|
||||
import { ClientCapability, ITypeScriptServiceClient } from '../../typescriptService';
|
||||
import { readUnifiedConfig, unifiedConfigSection } from '../../utils/configuration';
|
||||
import { ResourceUnifiedConfigValue } from '../../utils/configuration';
|
||||
import { conditionalRegistration, requireHasModifiedUnifiedConfig, requireSomeCapability } from '../util/dependentRegistration';
|
||||
import { ReferencesCodeLens, TypeScriptBaseCodeLensProvider, getSymbolRange } from './baseCodeLensProvider';
|
||||
import { ExecutionTarget } from '../../tsServer/server';
|
||||
@@ -23,31 +23,29 @@ const Config = Object.freeze({
|
||||
});
|
||||
|
||||
export default class TypeScriptImplementationsCodeLensProvider extends TypeScriptBaseCodeLensProvider {
|
||||
|
||||
private readonly _enabled: ResourceUnifiedConfigValue<boolean>;
|
||||
private readonly _showOnInterfaceMethods: ResourceUnifiedConfigValue<boolean>;
|
||||
private readonly _showOnAllClassMethods: ResourceUnifiedConfigValue<boolean>;
|
||||
|
||||
public constructor(
|
||||
client: ITypeScriptServiceClient,
|
||||
protected _cachedResponse: CachedResponse<Proto.NavTreeResponse>,
|
||||
private readonly language: LanguageDescription
|
||||
) {
|
||||
super(client, _cachedResponse);
|
||||
this._register(
|
||||
vscode.workspace.onDidChangeConfiguration(evt => {
|
||||
if (
|
||||
evt.affectsConfiguration(`${unifiedConfigSection}.${Config.enabled}`) ||
|
||||
evt.affectsConfiguration(`${language.id}.${Config.enabled}`) ||
|
||||
evt.affectsConfiguration(`${unifiedConfigSection}.${Config.showOnInterfaceMethods}`) ||
|
||||
evt.affectsConfiguration(`${language.id}.${Config.showOnInterfaceMethods}`) ||
|
||||
evt.affectsConfiguration(`${unifiedConfigSection}.${Config.showOnAllClassMethods}`) ||
|
||||
evt.affectsConfiguration(`${language.id}.${Config.showOnAllClassMethods}`)
|
||||
) {
|
||||
this.changeEmitter.fire();
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
this._enabled = this._register(new ResourceUnifiedConfigValue<boolean>(Config.enabled, false));
|
||||
this._register(this._enabled.onDidChange(() => this.changeEmitter.fire()));
|
||||
|
||||
this._showOnInterfaceMethods = this._register(new ResourceUnifiedConfigValue<boolean>(Config.showOnInterfaceMethods, false));
|
||||
this._register(this._showOnInterfaceMethods.onDidChange(() => this.changeEmitter.fire()));
|
||||
|
||||
this._showOnAllClassMethods = this._register(new ResourceUnifiedConfigValue<boolean>(Config.showOnAllClassMethods, false));
|
||||
this._register(this._showOnAllClassMethods.onDidChange(() => this.changeEmitter.fire()));
|
||||
}
|
||||
|
||||
|
||||
override async provideCodeLenses(document: vscode.TextDocument, token: vscode.CancellationToken): Promise<ReferencesCodeLens[]> {
|
||||
const enabled = readUnifiedConfig<boolean>(Config.enabled, false, { scope: document, fallbackSection: this.language.id });
|
||||
const enabled = this._enabled.getValue(document);
|
||||
if (!enabled) {
|
||||
return [];
|
||||
}
|
||||
@@ -131,7 +129,7 @@ export default class TypeScriptImplementationsCodeLensProvider extends TypeScrip
|
||||
if (
|
||||
item.kind === PConst.Kind.method &&
|
||||
parent?.kind === PConst.Kind.interface &&
|
||||
readUnifiedConfig<boolean>('implementationsCodeLens.showOnInterfaceMethods', false, { scope: document, fallbackSection: this.language.id })
|
||||
this._showOnInterfaceMethods.getValue(document)
|
||||
) {
|
||||
return getSymbolRange(document, item);
|
||||
}
|
||||
@@ -141,7 +139,7 @@ export default class TypeScriptImplementationsCodeLensProvider extends TypeScrip
|
||||
if (
|
||||
item.kind === PConst.Kind.method &&
|
||||
parent?.kind === PConst.Kind.class &&
|
||||
readUnifiedConfig<boolean>('implementationsCodeLens.showOnAllClassMethods', false, { scope: document, fallbackSection: this.language.id })
|
||||
this._showOnAllClassMethods.getValue(document)
|
||||
) {
|
||||
// But not private ones as these can never be overridden
|
||||
if (/\bprivate\b/.test(item.kindModifiers ?? '')) {
|
||||
@@ -165,6 +163,6 @@ export function register(
|
||||
requireSomeCapability(client, ClientCapability.Semantic),
|
||||
], () => {
|
||||
return vscode.languages.registerCodeLensProvider(selector.semantic,
|
||||
new TypeScriptImplementationsCodeLensProvider(client, cachedResponse, language));
|
||||
new TypeScriptImplementationsCodeLensProvider(client, cachedResponse));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import * as PConst from '../../tsServer/protocol/protocol.const';
|
||||
import { ExecutionTarget } from '../../tsServer/server';
|
||||
import * as typeConverters from '../../typeConverters';
|
||||
import { ClientCapability, ITypeScriptServiceClient } from '../../typescriptService';
|
||||
import { readUnifiedConfig, unifiedConfigSection } from '../../utils/configuration';
|
||||
import { ResourceUnifiedConfigValue } from '../../utils/configuration';
|
||||
import { conditionalRegistration, requireHasModifiedUnifiedConfig, requireSomeCapability } from '../util/dependentRegistration';
|
||||
import { ReferencesCodeLens, TypeScriptBaseCodeLensProvider, getSymbolRange } from './baseCodeLensProvider';
|
||||
|
||||
@@ -22,28 +22,25 @@ const Config = Object.freeze({
|
||||
});
|
||||
|
||||
export class TypeScriptReferencesCodeLensProvider extends TypeScriptBaseCodeLensProvider {
|
||||
|
||||
private readonly _enabled: ResourceUnifiedConfigValue<boolean>;
|
||||
private readonly _showOnAllFunctions: ResourceUnifiedConfigValue<boolean>;
|
||||
|
||||
public constructor(
|
||||
client: ITypeScriptServiceClient,
|
||||
protected _cachedResponse: CachedResponse<Proto.NavTreeResponse>,
|
||||
private readonly language: LanguageDescription
|
||||
) {
|
||||
super(client, _cachedResponse);
|
||||
this._register(
|
||||
vscode.workspace.onDidChangeConfiguration(evt => {
|
||||
if (
|
||||
evt.affectsConfiguration(`${unifiedConfigSection}.${Config.enabled}`) ||
|
||||
evt.affectsConfiguration(`${language.id}.${Config.enabled}`) ||
|
||||
evt.affectsConfiguration(`${unifiedConfigSection}.${Config.showOnAllFunctions}`) ||
|
||||
evt.affectsConfiguration(`${language.id}.${Config.showOnAllFunctions}`)
|
||||
) {
|
||||
this.changeEmitter.fire();
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
this._enabled = this._register(new ResourceUnifiedConfigValue<boolean>(Config.enabled, false));
|
||||
this._register(this._enabled.onDidChange(() => this.changeEmitter.fire()));
|
||||
|
||||
this._showOnAllFunctions = this._register(new ResourceUnifiedConfigValue<boolean>(Config.showOnAllFunctions, false));
|
||||
this._register(this._showOnAllFunctions.onDidChange(() => this.changeEmitter.fire()));
|
||||
}
|
||||
|
||||
override async provideCodeLenses(document: vscode.TextDocument, token: vscode.CancellationToken): Promise<ReferencesCodeLens[]> {
|
||||
const enabled = readUnifiedConfig<boolean>(Config.enabled, false, { scope: document, fallbackSection: this.language.id });
|
||||
const enabled = this._enabled.getValue(document);
|
||||
if (!enabled) {
|
||||
return [];
|
||||
}
|
||||
@@ -95,7 +92,7 @@ export class TypeScriptReferencesCodeLensProvider extends TypeScriptBaseCodeLens
|
||||
|
||||
switch (item.kind) {
|
||||
case PConst.Kind.function: {
|
||||
const showOnAllFunctions = readUnifiedConfig<boolean>(Config.showOnAllFunctions, false, { scope: document, fallbackSection: this.language.id });
|
||||
const showOnAllFunctions = this._showOnAllFunctions.getValue(document);
|
||||
if (showOnAllFunctions && item.nameSpan) {
|
||||
return getSymbolRange(document, item);
|
||||
}
|
||||
@@ -160,6 +157,6 @@ export function register(
|
||||
requireSomeCapability(client, ClientCapability.Semantic),
|
||||
], () => {
|
||||
return vscode.languages.registerCodeLensProvider(selector.semantic,
|
||||
new TypeScriptReferencesCodeLensProvider(client, cachedResponse, language));
|
||||
new TypeScriptReferencesCodeLensProvider(client, cachedResponse));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ import { ClientCapability } from './typescriptService';
|
||||
import TypeScriptServiceClient from './typescriptServiceClient';
|
||||
import TypingsStatus from './ui/typingsStatus';
|
||||
import { Disposable } from './utils/dispose';
|
||||
import { readUnifiedConfig } from './utils/configuration';
|
||||
import { UnifiedConfigValue } from './utils/configuration';
|
||||
import { isWeb, isWebAndHasSharedArrayBuffers, supportsReadableByteStreams } from './utils/platform';
|
||||
|
||||
|
||||
@@ -34,8 +34,16 @@ export default class LanguageProvider extends Disposable {
|
||||
private readonly onCompletionAccepted: (item: vscode.CompletionItem) => void,
|
||||
) {
|
||||
super();
|
||||
vscode.workspace.onDidChangeConfiguration(this.configurationChanged, this, this._disposables);
|
||||
this.configurationChanged();
|
||||
|
||||
const scope: vscode.ConfigurationScope = { languageId: this.description.languageIds[0] };
|
||||
|
||||
const validateConfig = this._register(new UnifiedConfigValue<boolean>('validate.enabled', true, { scope, fallbackSection: this.id, fallbackSubSectionNameOverride: 'validate.enable' }));
|
||||
this.updateValidate(validateConfig.getValue());
|
||||
this._register(validateConfig.onDidChange(value => this.updateValidate(value)));
|
||||
|
||||
const suggestionsConfig = this._register(new UnifiedConfigValue<boolean>('suggestionActions.enabled', true, { scope, fallbackSection: this.id }));
|
||||
this.updateSuggestionDiagnostics(suggestionsConfig.getValue());
|
||||
this._register(suggestionsConfig.onDidChange(value => this.updateSuggestionDiagnostics(value)));
|
||||
|
||||
client.onReady(() => this.registerProviders());
|
||||
}
|
||||
@@ -91,12 +99,6 @@ export default class LanguageProvider extends Disposable {
|
||||
]);
|
||||
}
|
||||
|
||||
private configurationChanged(): void {
|
||||
const scope: vscode.ConfigurationScope = { languageId: this.description.languageIds[0] };
|
||||
this.updateValidate(readUnifiedConfig<boolean>('validate.enabled', true, { scope, fallbackSection: this.id, fallbackSubSectionNameOverride: 'validate.enable' }));
|
||||
this.updateSuggestionDiagnostics(readUnifiedConfig<boolean>('suggestionActions.enabled', true, { scope, fallbackSection: this.id }));
|
||||
}
|
||||
|
||||
public handlesUri(resource: vscode.Uri): boolean {
|
||||
const ext = extname(resource.path).slice(1).toLowerCase();
|
||||
return this.description.standardFileExtensions.includes(ext) || this.handlesConfigFile(resource);
|
||||
|
||||
@@ -10,7 +10,7 @@ import * as typeConverters from '../typeConverters';
|
||||
import { ClientCapability, ITypeScriptServiceClient } from '../typescriptService';
|
||||
import { inMemoryResourcePrefix } from '../typescriptServiceClient';
|
||||
import { coalesce } from '../utils/arrays';
|
||||
import { readUnifiedConfig, unifiedConfigSection } from '../utils/configuration';
|
||||
import { ResourceUnifiedConfigValue } from '../utils/configuration';
|
||||
import { Delayer, setImmediate } from '../utils/async';
|
||||
import { nulToken } from '../utils/cancellation';
|
||||
import { Disposable } from '../utils/dispose';
|
||||
@@ -471,6 +471,8 @@ export default class BufferSyncSupport extends Disposable {
|
||||
private listening: boolean = false;
|
||||
private readonly synchronizer: BufferSynchronizer;
|
||||
|
||||
private readonly _validate: ResourceUnifiedConfigValue<boolean>;
|
||||
|
||||
private readonly _tabResources: TabResourceTracker;
|
||||
|
||||
constructor(
|
||||
@@ -482,6 +484,8 @@ export default class BufferSyncSupport extends Disposable {
|
||||
this.client = client;
|
||||
this.modeIds = new Set<string>(modeIds);
|
||||
|
||||
this._validate = this._register(new ResourceUnifiedConfigValue<boolean>('validate.enabled', true, { fallbackSubSectionNameOverride: 'validate.enable' }));
|
||||
|
||||
this.diagnosticDelayer = new Delayer<any>(300);
|
||||
|
||||
const pathNormalizer = (path: vscode.Uri) => this.client.toTsFilePath(path);
|
||||
@@ -511,14 +515,7 @@ export default class BufferSyncSupport extends Disposable {
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(vscode.workspace.onDidChangeConfiguration((e) => {
|
||||
if (e.affectsConfiguration(`${unifiedConfigSection}.validate.enabled`)
|
||||
|| e.affectsConfiguration('typescript.validate.enable')
|
||||
|| e.affectsConfiguration('javascript.validate.enable')
|
||||
) {
|
||||
this.requestAllDiagnostics();
|
||||
}
|
||||
}));
|
||||
this._register(this._validate.onDidChange(() => this.requestAllDiagnostics()));
|
||||
}
|
||||
|
||||
private readonly _onDelete = this._register(new vscode.EventEmitter<vscode.Uri>());
|
||||
@@ -769,9 +766,6 @@ export default class BufferSyncSupport extends Disposable {
|
||||
return false;
|
||||
}
|
||||
|
||||
const fallbackSection = (buffer.languageId === languageModeIds.javascript || buffer.languageId === languageModeIds.javascriptreact)
|
||||
? 'javascript'
|
||||
: 'typescript';
|
||||
return readUnifiedConfig<boolean>('validate.enabled', true, { scope: buffer.document, fallbackSection, fallbackSubSectionNameOverride: 'validate.enable' });
|
||||
return this._validate.getValue(buffer.document);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,16 +4,17 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { Disposable } from './dispose';
|
||||
|
||||
export type UnifiedConfigurationScope = vscode.ConfigurationScope | null | undefined;
|
||||
|
||||
export const unifiedConfigSection = 'js/ts';
|
||||
|
||||
export type ReadUnifiedConfigOptions = {
|
||||
readonly scope?: UnifiedConfigurationScope;
|
||||
export interface ReadUnifiedConfigOptions<Scope = UnifiedConfigurationScope> {
|
||||
readonly scope?: Scope;
|
||||
readonly fallbackSection: string;
|
||||
readonly fallbackSubSectionNameOverride?: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a configuration value, checking the unified `js/ts` setting first,
|
||||
@@ -75,3 +76,122 @@ export function hasModifiedUnifiedConfig(
|
||||
const languageConfig = vscode.workspace.getConfiguration(options.fallbackSection, options.scope);
|
||||
return hasModifiedValue(languageConfig.inspect(subSectionName));
|
||||
}
|
||||
|
||||
/**
|
||||
* A cached, observable unified configuration value.
|
||||
*/
|
||||
export class UnifiedConfigValue<T> extends Disposable {
|
||||
|
||||
private _value: T;
|
||||
|
||||
private readonly _onDidChange = this._register(new vscode.EventEmitter<T>());
|
||||
public get onDidChange() { return this._onDidChange.event; }
|
||||
|
||||
constructor(
|
||||
private readonly subSectionName: string,
|
||||
private readonly defaultValue: T,
|
||||
private readonly options: ReadUnifiedConfigOptions<{ languageId: string }>,
|
||||
) {
|
||||
super();
|
||||
|
||||
this._value = this.read();
|
||||
|
||||
this._register(vscode.workspace.onDidChangeConfiguration(e => {
|
||||
if (e.affectsConfiguration(`${unifiedConfigSection}.${subSectionName}`, options.scope ?? undefined) ||
|
||||
e.affectsConfiguration(`${options.fallbackSection}.${options.fallbackSubSectionNameOverride ?? subSectionName}`, options.scope ?? undefined)
|
||||
) {
|
||||
const newValue = this.read();
|
||||
if (newValue !== this._value) {
|
||||
this._value = newValue;
|
||||
this._onDidChange.fire(newValue);
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private read(): T {
|
||||
return readUnifiedConfig<T>(this.subSectionName, this.defaultValue, this.options);
|
||||
}
|
||||
|
||||
public getValue(): T {
|
||||
return this._value;
|
||||
}
|
||||
}
|
||||
|
||||
export interface ResourceUnifiedConfigScope {
|
||||
readonly uri: vscode.Uri;
|
||||
readonly languageId: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* A cached, observable unified configuration value that varies per workspace folder.
|
||||
*
|
||||
* Values are keyed by the workspace folder the resource belongs to, with a separate
|
||||
* entry for resources outside any workspace folder.
|
||||
*/
|
||||
export class ResourceUnifiedConfigValue<T> extends Disposable {
|
||||
|
||||
private readonly _cache = new Map</* workspace folder */ string, T>();
|
||||
|
||||
private readonly _onDidChange = this._register(new vscode.EventEmitter<void>());
|
||||
public readonly onDidChange = this._onDidChange.event;
|
||||
|
||||
constructor(
|
||||
private readonly subSectionName: string,
|
||||
private readonly defaultValue: T,
|
||||
private readonly options?: {
|
||||
readonly fallbackSubSectionNameOverride?: string;
|
||||
},
|
||||
) {
|
||||
super();
|
||||
|
||||
const fallbackName = options?.fallbackSubSectionNameOverride ?? subSectionName;
|
||||
|
||||
this._register(vscode.workspace.onDidChangeConfiguration(e => {
|
||||
if (e.affectsConfiguration(`${unifiedConfigSection}.${subSectionName}`) ||
|
||||
e.affectsConfiguration(`javascript.${fallbackName}`) ||
|
||||
e.affectsConfiguration(`typescript.${fallbackName}`)
|
||||
) {
|
||||
this._cache.clear();
|
||||
this._onDidChange.fire();
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(vscode.workspace.onDidChangeWorkspaceFolders(() => {
|
||||
this._cache.clear();
|
||||
this._onDidChange.fire();
|
||||
}));
|
||||
}
|
||||
|
||||
public getValue(scope: ResourceUnifiedConfigScope): T {
|
||||
const key = this.keyFor(scope);
|
||||
const cached = this._cache.get(key);
|
||||
if (cached !== undefined) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
const fallbackSection = this.fallbackSectionFor(scope.languageId);
|
||||
const value = readUnifiedConfig<T>(this.subSectionName, this.defaultValue, {
|
||||
scope: { uri: scope.uri, languageId: scope.languageId },
|
||||
fallbackSection,
|
||||
fallbackSubSectionNameOverride: this.options?.fallbackSubSectionNameOverride,
|
||||
});
|
||||
this._cache.set(key, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
private fallbackSectionFor(languageId: string): string {
|
||||
switch (languageId) {
|
||||
case 'javascript':
|
||||
case 'javascriptreact':
|
||||
return 'javascript';
|
||||
default:
|
||||
return 'typescript';
|
||||
}
|
||||
}
|
||||
|
||||
private keyFor(scope: ResourceUnifiedConfigScope): string {
|
||||
const folder = vscode.workspace.getWorkspaceFolder(scope.uri);
|
||||
return folder ? folder.uri.toString() : '';
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user