debt - reduce explicit any usage (#269814)

This commit is contained in:
Benjamin Pasero
2025-10-06 17:19:56 +02:00
committed by GitHub
parent f07e678c82
commit 7e8c7bef61
137 changed files with 646 additions and 584 deletions

10
.github/prompts/no-any.prompt.md vendored Normal file
View File

@@ -0,0 +1,10 @@
---
mode: agent
description: 'Remove any usage of the any type in TypeScript files'
---
I am trying to minimize the usage of `any` types in our TypeScript codebase.
Find usages of the TypeScript `any` type in this file and replace it with the right type based on usages in the file.
You are NOT allowed to disable ESLint rules or add `// @ts-ignore` comments to the code.
You are NOT allowed to add more `any` types to the code.

View File

@@ -187,6 +187,7 @@ export default tseslint.config(
'src/vs/base/browser/ui/scrollbar/**',
'src/vs/base/browser/ui/widget.ts',
'src/vs/base/common/extpath.ts',
'src/vs/base/common/fuzzyScorer.ts',
'src/vs/base/common/glob.ts',
'src/vs/base/common/path.ts',
'src/vs/base/common/stream.ts',
@@ -201,30 +202,32 @@ export default tseslint.config(
'src/vs/base/common/uriTransformer.ts',
'src/vs/base/common/worker/webWorker.ts',
'src/vs/base/node/pfs.ts',
'src/vs/base/node/unc.ts',
'src/vs/base/parts/contextmenu/**',
'src/vs/editor/browser/**',
'src/vs/editor/common/**',
// 'src/vs/base/parts/ipc/**',
// 'src/vs/base/parts/sandbox/**',
'src/vs/base/parts/sandbox/**',
'src/vs/base/parts/storage/**',
'src/vs/platform/auxiliaryWindow/**',
// 'src/vs/platform/backup/**',
// 'src/vs/platform/editor/**',
// 'src/vs/platform/environment/**',
// 'src/vs/platform/files/**',
// 'src/vs/platform/ipc/**',
// 'src/vs/platform/launch/**',
// 'src/vs/platform/lifecycle/**',
// 'src/vs/platform/menubar/**',
// 'src/vs/platform/native/**',
// 'src/vs/platform/sharedProcess/**',
// 'src/vs/platform/state/**',
// 'src/vs/platform/storage/**',
// 'src/vs/platform/utilityProcess/**',
// 'src/vs/platform/window/**',
// 'src/vs/platform/windows/**',
// 'src/vs/platform/workspace/**',
// 'src/vs/platform/workspaces/**',
'src/vs/platform/backup/**',
'src/vs/platform/editor/**',
'src/vs/platform/environment/**',
'src/vs/platform/dialogs/**',
'src/vs/platform/files/**',
'src/vs/platform/ipc/**',
'src/vs/platform/launch/**',
'src/vs/platform/lifecycle/**',
'src/vs/platform/menubar/**',
'src/vs/platform/native/**',
'src/vs/platform/sharedProcess/**',
'src/vs/platform/state/**',
'src/vs/platform/storage/**',
'src/vs/platform/utilityProcess/**',
'src/vs/platform/window/**',
'src/vs/platform/windows/**',
'src/vs/platform/workspace/**',
'src/vs/platform/workspaces/**',
'src/bootstrap-cli.ts',
'src/bootstrap-esm.ts',
'src/bootstrap-fork.ts',
@@ -243,7 +246,7 @@ export default tseslint.config(
'src/vs/workbench/services/contextmenu/**',
'src/vs/workbench/services/dialogs/**',
'src/vs/workbench/services/editor/**',
// 'src/vs/workbench/services/environment/**',
'src/vs/workbench/services/environment/**',
'src/vs/workbench/services/files/**',
'src/vs/workbench/services/filesConfiguration/**',
'src/vs/workbench/services/history/**',
@@ -254,19 +257,22 @@ export default tseslint.config(
'src/vs/workbench/services/notification/**',
'src/vs/workbench/services/path/**',
'src/vs/workbench/services/progress/**',
// 'src/vs/workbench/services/storage/**',
// 'src/vs/workbench/services/textfile/**',
// 'src/vs/workbench/services/textmodelResolver/**',
// 'src/vs/workbench/services/untitled/**',
// 'src/vs/workbench/services/utilityProcess/**',
// 'src/vs/workbench/services/views/**',
// 'src/vs/workbench/services/workingCopy/**',
// 'src/vs/workbench/services/workspaces/**',
// 'src/vs/workbench/common/**',
'src/vs/workbench/services/storage/**',
'src/vs/workbench/services/textfile/**',
'src/vs/workbench/services/textmodelResolver/**',
'src/vs/workbench/services/untitled/**',
'src/vs/workbench/services/utilityProcess/**',
'src/vs/workbench/services/views/**',
'src/vs/workbench/services/workingCopy/**',
'src/vs/workbench/services/workspaces/**',
'src/vs/workbench/common/**',
// 'src/vs/workbench/browser/**',
// 'src/vs/workbench/electron-browser/**',
// 'src/vs/workbench/contrib/files/**',
'src/vs/workbench/electron-browser/**',
'src/vs/workbench/contrib/files/**',
'src/vs/workbench/contrib/chat/browser/chatSetup.ts',
'src/vs/workbench/contrib/chat/browser/chatStatus.ts',
],
ignores: ['**/*.test.ts', '**/*.integrationTest.ts'],
languageOptions: {
parser: tseslint.parser,
},

View File

@@ -184,9 +184,9 @@ function configureCrashReporter(): void {
const crashReporterProcessType = process.env['VSCODE_CRASH_REPORTER_PROCESS_TYPE'];
if (crashReporterProcessType) {
try {
//@ts-ignore
//@ts-expect-error
if (process['crashReporter'] && typeof process['crashReporter'].addExtraParameter === 'function' /* Electron only */) {
//@ts-ignore
//@ts-expect-error
process['crashReporter'].addExtraParameter('processType', crashReporterProcessType);
}
} catch (error) {

View File

@@ -88,7 +88,7 @@ perf.mark('code/didStartCrashReporter');
// to ensure that no 'logs' folder is created on disk at a
// location outside of the portable directory
// (https://github.com/microsoft/vscode/issues/56651)
if (portable && portable.isPortable) {
if (portable.isPortable) {
app.setAppLogsPath(path.join(userDataPath, 'logs'));
}

View File

@@ -99,7 +99,7 @@ if (shouldSpawnCli) {
perf.mark('code/server/firstWebSocket');
}
const remoteExtensionHostAgentServer = await getRemoteExtensionHostAgentServer();
// @ts-ignore
// @ts-expect-error
return remoteExtensionHostAgentServer.handleUpgrade(req, socket);
});
server.on('error', async (err) => {

View File

@@ -359,14 +359,14 @@ export interface IPathWithLineAndColumn {
export function parseLineAndColumnAware(rawPath: string): IPathWithLineAndColumn {
const segments = rawPath.split(':'); // C:\file.txt:<line>:<column>
let path: string | undefined = undefined;
let line: number | undefined = undefined;
let column: number | undefined = undefined;
let path: string | undefined;
let line: number | undefined;
let column: number | undefined;
for (const segment of segments) {
const segmentAsNumber = Number(segment);
if (!isNumber(segmentAsNumber)) {
path = !!path ? [path, segment].join(':') : segment; // a colon can well be part of a path (e.g. C:\...)
path = path ? [path, segment].join(':') : segment; // a colon can well be part of a path (e.g. C:\...)
} else if (line === undefined) {
line = segmentAsNumber;
} else if (column === undefined) {

View File

@@ -508,7 +508,7 @@ function toRegExp(pattern: string): ParsedStringPattern {
return typeof path === 'string' && regExp.test(path) ? pattern : null;
};
} catch (error) {
} catch {
return NULL;
}
}

View File

@@ -72,7 +72,7 @@ async function rimrafMove(path: string, moveToPath = randomPath(tmpdir())): Prom
}
// Delete but do not return as promise
rimrafUnlink(moveToPath).catch(error => {/* ignore */ });
rimrafUnlink(moveToPath).catch(() => {/* ignore */ });
} catch (error) {
if (error.code !== 'ENOENT') {
throw error;
@@ -113,7 +113,7 @@ async function readdir(path: string, options?: { withFileTypes: true }): Promise
if (error.code === 'ENOENT' && isWindows && isRootOrDriveLetter(path)) {
try {
return await doReaddir(`${path}.`, options);
} catch (e) {
} catch {
// ignore
}
}
@@ -268,7 +268,7 @@ export namespace SymlinkSupport {
if (!lstats.isSymbolicLink()) {
return { stat: lstats };
}
} catch (error) {
} catch {
/* ignore - use stat() instead */
}
@@ -324,7 +324,7 @@ export namespace SymlinkSupport {
const { stat, symbolicLink } = await SymlinkSupport.stat(path);
return stat.isFile() && symbolicLink?.dangling !== true;
} catch (error) {
} catch {
// Ignore, path might not exist
}
@@ -346,7 +346,7 @@ export namespace SymlinkSupport {
const { stat, symbolicLink } = await SymlinkSupport.stat(path);
return stat.isDirectory() && symbolicLink?.dangling !== true;
} catch (error) {
} catch {
// Ignore, path might not exist
}
@@ -542,7 +542,7 @@ async function renameWithRetry(source: string, target: string, startTime: number
if (!stat.isFile()) {
abortRetry = true; // if target is not a file, EPERM error may be raised and we should not attempt to retry
}
} catch (error) {
} catch {
// Ignore
}
@@ -601,7 +601,7 @@ async function doCopy(source: string, target: string, payload: ICopyPayload): Pr
if (payload.options.preserveSymlinks) {
try {
return await doCopySymlink(source, target, payload);
} catch (error) {
} catch {
// in any case of an error fallback to normal copy via dereferencing
}
}
@@ -713,7 +713,7 @@ export async function realcase(path: string, token?: CancellationToken): Promise
}
}
}
} catch (error) {
} catch {
// silently ignore error
}
@@ -727,7 +727,7 @@ async function realpath(path: string): Promise<string> {
// drives to be resolved to their target on Windows
// https://github.com/microsoft/vscode/issues/118562
return await promisify(fs.realpath)(path);
} catch (error) {
} catch {
// We hit an error calling fs.realpath(). Since fs.realpath() is doing some path normalization
// we now do a similar normalization and then try again if we can access the path with read
@@ -748,7 +748,7 @@ async function realpath(path: string): Promise<string> {
export function realpathSync(path: string): string {
try {
return fs.realpathSync(path);
} catch (error) {
} catch {
// We hit an error calling fs.realpathSync(). Since fs.realpathSync() is doing some path normalization
// we now do a similar normalization and then try again if we can access the path with read

View File

@@ -12,13 +12,12 @@ export function getUNCHostAllowlist(): string[] {
return [];
}
function processUNCHostAllowlist(): Set<string> {
function processUNCHostAllowlist(): Set<string> | undefined {
// The property `process.uncHostAllowlist` is not available in official node.js
// releases, only in our own builds, so we have to probe for availability
// eslint-disable-next-line local/code-no-any-casts
return (process as any).uncHostAllowlist;
return (process as unknown as { uncHostAllowlist?: Set<string> }).uncHostAllowlist;
}
export function addUNCHostToAllowlist(allowedHost: string | string[]): void {
@@ -91,8 +90,7 @@ export function disableUNCAccessRestrictions(): void {
return;
}
// eslint-disable-next-line local/code-no-any-casts
(process as any).restrictUNCAccess = false;
(process as unknown as { restrictUNCAccess?: boolean }).restrictUNCAccess = false;
}
export function isUNCAccessRestrictionsDisabled(): boolean {
@@ -100,6 +98,5 @@ export function isUNCAccessRestrictionsDisabled(): boolean {
return true;
}
// eslint-disable-next-line local/code-no-any-casts
return (process as any).restrictUNCAccess === false;
return (process as unknown as { restrictUNCAccess?: boolean }).restrictUNCAccess === false;
}

View File

@@ -1107,7 +1107,7 @@ export namespace ProxyChannel {
export function fromService<TContext>(service: unknown, disposables: DisposableStore, options?: ICreateServiceChannelOptions): IServerChannel<TContext> {
const handler = service as { [key: string]: unknown };
const disableMarshalling = options && options.disableMarshalling;
const disableMarshalling = options?.disableMarshalling;
// Buffer any event that should be supported by
// iterating over all property keys and finding them
@@ -1184,7 +1184,7 @@ export namespace ProxyChannel {
}
export function toService<T extends object>(channel: IChannel, options?: ICreateProxyServiceOptions): T {
const disableMarshalling = options && options.disableMarshalling;
const disableMarshalling = options?.disableMarshalling;
return new Proxy({}, {
get(_target: T, propKey: PropertyKey) {

View File

@@ -93,7 +93,7 @@ export class Client implements IChannelClient, IDisposable {
readonly onDidProcessExit = this._onDidProcessExit.event;
constructor(private modulePath: string, private options: IIPCOptions) {
const timeout = options && options.timeout ? options.timeout : 60000;
const timeout = options.timeout || 60000;
this.disposeDelayer = new Delayer<void>(timeout);
this.child = null;
this._client = null;
@@ -174,24 +174,24 @@ export class Client implements IChannelClient, IDisposable {
private get client(): IPCClient {
if (!this._client) {
const args = this.options && this.options.args ? this.options.args : [];
const args = this.options.args || [];
const forkOpts: ForkOptions = Object.create(null);
forkOpts.env = { ...deepClone(process.env), 'VSCODE_PARENT_PID': String(process.pid) };
if (this.options && this.options.env) {
if (this.options.env) {
forkOpts.env = { ...forkOpts.env, ...this.options.env };
}
if (this.options && this.options.freshExecArgv) {
if (this.options.freshExecArgv) {
forkOpts.execArgv = [];
}
if (this.options && typeof this.options.debug === 'number') {
if (typeof this.options.debug === 'number') {
forkOpts.execArgv = ['--nolazy', '--inspect=' + this.options.debug];
}
if (this.options && typeof this.options.debugBrk === 'number') {
if (typeof this.options.debugBrk === 'number') {
forkOpts.execArgv = ['--nolazy', '--inspect-brk=' + this.options.debugBrk];
}
@@ -221,7 +221,7 @@ export class Client implements IChannelClient, IDisposable {
});
const sender = this.options.useQueue ? createQueuedSender(this.child) : this.child;
const send = (r: VSBuffer) => this.child && this.child.connected && sender.send((<Buffer>r.buffer).toString('base64'));
const send = (r: VSBuffer) => this.child?.connected && sender.send((<Buffer>r.buffer).toString('base64'));
const onMessage = onMessageEmitter.event;
const protocol = { send, onMessage };

View File

@@ -20,7 +20,7 @@ class Protocol implements IMessagePassingProtocol {
constructor(private port: MessagePortMain) {
this.onMessage = Event.fromNodeEventEmitter<VSBuffer>(this.port, 'message', (e: MessageEvent) => {
if (e.data) {
return VSBuffer.wrap(e.data);
return VSBuffer.wrap(e.data as Uint8Array);
}
return VSBuffer.alloc(0);
});

View File

@@ -27,7 +27,7 @@ export function upgradeToISocket(req: http.IncomingMessage, socket: Socket, {
skipWebSocketFrames?: boolean;
disableWebSocketCompression?: boolean;
}): NodeSocket | WebSocketNodeSocket | undefined {
if (req.headers['upgrade'] === undefined || req.headers['upgrade'].toLowerCase() !== 'websocket') {
if (req.headers.upgrade === undefined || req.headers.upgrade.toLowerCase() !== 'websocket') {
socket.end('HTTP/1.1 400 Bad Request');
return;
}

View File

@@ -31,7 +31,7 @@ export interface MessagePortMain extends NodeJS.EventEmitter {
* Sends a message from the port, and optionally, transfers ownership of objects to
* other browsing contexts.
*/
postMessage(message: any, transfer?: MessagePortMain[]): void;
postMessage(message: unknown, transfer?: MessagePortMain[]): void;
/**
* Starts the sending of messages queued on the port. Messages will be queued until
* this method is called.
@@ -40,7 +40,7 @@ export interface MessagePortMain extends NodeJS.EventEmitter {
}
export interface MessageEvent {
data: any;
data: unknown;
ports: MessagePortMain[];
}
@@ -60,7 +60,7 @@ export interface ParentPort extends NodeJS.EventEmitter {
/**
* Sends a message from the process to its parent.
*/
postMessage(message: any): void;
postMessage(message: unknown): void;
}
export interface UtilityNodeJSProcess extends NodeJS.Process {

View File

@@ -349,7 +349,7 @@ export class Storage extends Disposable implements IStorage {
// the DB is not healthy.
try {
await this.doFlush(0 /* as soon as possible */);
} catch (error) {
} catch {
// Ignore
}

View File

@@ -118,7 +118,7 @@ export class SQLiteStorageDatabase implements IStorageDatabase {
}
// DELETE
if (toDelete && toDelete.size) {
if (toDelete?.size) {
const keysChunks: (string[])[] = [];
keysChunks.push([]); // seed with initial empty chunk
@@ -291,7 +291,7 @@ export class SQLiteStorageDatabase implements IStorageDatabase {
await fs.promises.unlink(path);
try {
await Promises.rename(this.toBackupPath(path), path, false /* no retry */);
} catch (error) {
} catch {
// ignore
}

View File

@@ -474,7 +474,7 @@
const importMapScript = document.createElement('script');
importMapScript.type = 'importmap';
importMapScript.setAttribute('nonce', '0c6a828f1297');
// @ts-ignore
// @ts-expect-error
importMapScript.textContent = ttp?.createScript(importMapSrc) ?? importMapSrc;
window.document.head.appendChild(importMapScript);

View File

@@ -185,7 +185,7 @@ export async function main(argv: string[]): Promise<void> {
// Check for readonly status and chmod if so if we are told so
let targetMode: number = 0;
let restoreMode = false;
if (!!args['file-chmod']) {
if (args['file-chmod']) {
targetMode = statSync(target).mode;
if (!(targetMode & 0o200 /* File mode indicating writable by owner */)) {
chmodSync(target, targetMode | 0o200);

View File

@@ -247,7 +247,7 @@ class CliMain extends Disposable {
const appenders: ITelemetryAppender[] = [];
const isInternal = isInternalTelemetry(productService, configurationService);
if (supportsTelemetry(productService, environmentService)) {
if (productService.aiConfig && productService.aiConfig.ariaKey) {
if (productService.aiConfig?.ariaKey) {
appenders.push(new OneDataSystemAppender(requestService, isInternal, 'monacoworkbench', null, productService.aiConfig.ariaKey));
}

View File

@@ -19,9 +19,9 @@ export interface IFolderBackupInfo extends IBaseBackupInfo {
}
export function isFolderBackupInfo(curr: IWorkspaceBackupInfo | IFolderBackupInfo): curr is IFolderBackupInfo {
return curr && curr.hasOwnProperty('folderUri');
return curr?.hasOwnProperty('folderUri');
}
export function isWorkspaceBackupInfo(curr: IWorkspaceBackupInfo | IFolderBackupInfo): curr is IWorkspaceBackupInfo {
return curr && curr.hasOwnProperty('workspace');
return curr?.hasOwnProperty('workspace');
}

View File

@@ -347,11 +347,11 @@ export class BackupMainService implements IBackupMainService {
if (backupSchemaChildren.length > 0) {
return true;
}
} catch (error) {
} catch {
// invalid folder
}
}
} catch (error) {
} catch {
// backup path does not exist
}

View File

@@ -36,7 +36,7 @@ export function deserializeWorkspaceInfos(serializedBackupWorkspaces: ISerialize
}
));
}
} catch (e) {
} catch {
// ignore URI parsing exceptions
}
@@ -59,7 +59,7 @@ export function deserializeFolderInfos(serializedBackupWorkspaces: ISerializedBa
}
));
}
} catch (e) {
} catch {
// ignore URI parsing exceptions
}

View File

@@ -586,7 +586,7 @@ flakySuite('BackupMainService', () => {
try {
await fs.promises.mkdir(path.join(folderBackupPath, Schemas.file), { recursive: true });
await fs.promises.mkdir(path.join(workspaceBackupPath, Schemas.untitled), { recursive: true });
} catch (error) {
} catch {
// ignore - folder might exist already
}

View File

@@ -16,7 +16,7 @@ export class TestDialogService implements IDialogService {
constructor(
private defaultConfirmResult: IConfirmationResult | undefined = undefined,
private defaultPromptResult: IPromptResult<any> | undefined = undefined
private defaultPromptResult: IPromptResult<unknown> | undefined = undefined
) { }
private confirmResult: IConfirmationResult | undefined = undefined;
@@ -40,7 +40,7 @@ export class TestDialogService implements IDialogService {
prompt<T>(prompt: IPrompt<T>): Promise<IPromptResult<T>>;
async prompt<T>(prompt: IPrompt<T> | IPromptWithCustomCancel<T>): Promise<IPromptResult<T> | IPromptResultWithCancel<T>> {
if (this.defaultPromptResult) {
return this.defaultPromptResult;
return this.defaultPromptResult as IPromptResult<T>;
}
const promptButtons: IPromptBaseButton<T>[] = [...(prompt.buttons ?? [])];
if (prompt.cancelButton && typeof prompt.cancelButton !== 'string' && typeof prompt.cancelButton !== 'boolean') {

View File

@@ -214,7 +214,7 @@ export abstract class AbstractNativeEnvironmentService implements INativeEnviron
const result: [string, string][] = [];
for (const entry of this.args.log || []) {
const matches = EXTENSION_IDENTIFIER_WITH_LOG_REGEX.exec(entry);
if (matches && matches[1] && matches[2]) {
if (matches?.[1] && matches[2]) {
result.push([matches[1], matches[2]]);
}
}

View File

@@ -261,8 +261,8 @@ export function parseArgs<T>(args: string[], options: OptionDescriptions<T>, err
const alias: { [key: string]: string } = {};
const stringOptions: string[] = ['_'];
const booleanOptions: string[] = [];
const globalOptions: OptionDescriptions<any> = {};
let command: Subcommand<any> | undefined = undefined;
const globalOptions: Record<string, Option<'boolean'> | Option<'string'> | Option<'string[]'>> = {};
let command: Subcommand<Record<string, unknown>> | undefined = undefined;
for (const optionId in options) {
const o = options[optionId];
if (o.type === 'subcommand') {
@@ -291,13 +291,13 @@ export function parseArgs<T>(args: string[], options: OptionDescriptions<T>, err
}
}
if (command && firstPossibleCommand) {
const options = globalOptions;
const options: Record<string, Option<'boolean'> | Option<'string'> | Option<'string[]'> | Subcommand<Record<string, unknown>>> = globalOptions;
for (const optionId in command.options) {
options[optionId] = command.options[optionId];
}
const newArgs = args.filter(a => a !== firstPossibleCommand);
const reporter = errorReporter.getSubcommandReporter ? errorReporter.getSubcommandReporter(firstPossibleCommand) : undefined;
const subcommandOptions = parseArgs(newArgs, options, reporter);
const subcommandOptions = parseArgs(newArgs, options as OptionDescriptions<Record<string, unknown>>, reporter);
// eslint-disable-next-line local/code-no-dangerous-type-assertions
return <T>{
[firstPossibleCommand]: subcommandOptions,
@@ -309,8 +309,8 @@ export function parseArgs<T>(args: string[], options: OptionDescriptions<T>, err
// remove aliases to avoid confusion
const parsedArgs = minimist(args, { string: stringOptions, boolean: booleanOptions, alias });
const cleanedArgs: any = {};
const remainingArgs: any = parsedArgs;
const cleanedArgs: Record<string, unknown> = {};
const remainingArgs: Record<string, unknown> = parsedArgs;
// https://github.com/microsoft/vscode/issues/58177, https://github.com/microsoft/vscode/issues/106617
cleanedArgs._ = parsedArgs._.map(arg => String(arg)).filter(arg => arg.length > 0);
@@ -347,8 +347,8 @@ export function parseArgs<T>(args: string[], options: OptionDescriptions<T>, err
val = [val];
}
if (!o.allowEmptyValue) {
const sanitized = val.filter((v: string) => v.length > 0);
if (sanitized.length !== val.length) {
const sanitized = (val as string[]).filter((v: string) => v.length > 0);
if (sanitized.length !== (val as string[]).length) {
errorReporter.onEmptyValue(optionId);
val = sanitized.length > 0 ? sanitized : undefined;
}
@@ -356,7 +356,7 @@ export function parseArgs<T>(args: string[], options: OptionDescriptions<T>, err
} else if (o.type === 'string') {
if (Array.isArray(val)) {
val = val.pop(); // take the last
errorReporter.onMultipleValues(optionId, val);
errorReporter.onMultipleValues(optionId, val as string);
} else if (!val && !o.allowEmptyValue) {
errorReporter.onEmptyValue(optionId);
val = undefined;
@@ -375,10 +375,10 @@ export function parseArgs<T>(args: string[], options: OptionDescriptions<T>, err
errorReporter.onUnknownOption(key);
}
return cleanedArgs;
return cleanedArgs as T;
}
function formatUsage(optionId: string, option: Option<any>) {
function formatUsage(optionId: string, option: Option<'boolean'> | Option<'string'> | Option<'string[]'>) {
let args = '';
if (option.args) {
if (Array.isArray(option.args)) {
@@ -394,10 +394,10 @@ function formatUsage(optionId: string, option: Option<any>) {
}
// exported only for testing
export function formatOptions(options: OptionDescriptions<any>, columns: number): string[] {
export function formatOptions(options: OptionDescriptions<unknown> | Record<string, Option<'boolean'> | Option<'string'> | Option<'string[]'>>, columns: number): string[] {
const usageTexts: [string, string][] = [];
for (const optionId in options) {
const o = options[optionId];
const o = options[optionId as keyof typeof options] as Option<'boolean'> | Option<'string'> | Option<'string[]'>;
const usageText = formatUsage(optionId, o);
usageTexts.push([usageText, o.description!]);
}
@@ -443,7 +443,7 @@ function wrapText(text: string, columns: number): string[] {
return lines;
}
export function buildHelpMessage(productName: string, executableName: string, version: string, options: OptionDescriptions<any>, capabilities?: { noPipe?: boolean; noInputFiles?: boolean; isChat?: boolean }): string {
export function buildHelpMessage(productName: string, executableName: string, version: string, options: OptionDescriptions<unknown> | Record<string, Option<'boolean'> | Option<'string'> | Option<'string[]'> | Subcommand<Record<string, unknown>>>, capabilities?: { noPipe?: boolean; noInputFiles?: boolean; isChat?: boolean }): string {
const columns = (process.stdout).isTTY && (process.stdout).columns || 80;
const inputFiles = capabilities?.noInputFiles ? '' : capabilities?.isChat ? ` [${localize('cliPrompt', 'prompt')}]` : ` [${localize('paths', 'paths')}...]`;
const subcommand = capabilities?.isChat ? ' chat' : '';
@@ -456,18 +456,19 @@ export function buildHelpMessage(productName: string, executableName: string, ve
help.push(buildStdinMessage(executableName, capabilities?.isChat));
help.push('');
}
const optionsByCategory: { [P in keyof typeof helpCategories]?: OptionDescriptions<any> } = {};
const optionsByCategory: { [P in keyof typeof helpCategories]?: Record<string, Option<'boolean'> | Option<'string'> | Option<'string[]'>> } = {};
const subcommands: { command: string; description: string }[] = [];
for (const optionId in options) {
const o = options[optionId];
const o = options[optionId as keyof typeof options] as Option<'boolean'> | Option<'string'> | Option<'string[]'> | Subcommand<Record<string, unknown>>;
if (o.type === 'subcommand') {
if (o.description) {
subcommands.push({ command: optionId, description: o.description });
}
} else if (o.description && o.cat) {
let optionsByCat = optionsByCategory[o.cat];
const cat = o.cat as keyof typeof helpCategories;
let optionsByCat = optionsByCategory[cat];
if (!optionsByCat) {
optionsByCategory[o.cat] = optionsByCat = {};
optionsByCategory[cat] = optionsByCat = {};
}
optionsByCat[optionId] = o;
}

View File

@@ -12,7 +12,7 @@ import { resolveTerminalEncoding } from '../../../base/node/terminalEncoding.js'
export function hasStdinWithoutTty() {
try {
return !process.stdin.isTTY; // Via https://twitter.com/MylesBorins/status/782009479382626304
} catch (error) {
} catch {
// Windows workaround for https://github.com/nodejs/node/issues/11656
}
return false;

View File

@@ -308,7 +308,7 @@ export class HTMLFileSystemProvider extends Disposable implements IFileSystemPro
return;
}
// eslint-disable-next-line local/code-no-any-casts
// eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any
const observer = new (globalThis as any).FileSystemObserver((records: FileSystemObserverRecord[]) => {
if (disposables.isDisposed) {
return;

View File

@@ -221,58 +221,46 @@ export class IndexedDBFileSystemProvider extends Disposable implements IFileSyst
}
async readdir(resource: URI): Promise<DirEntry[]> {
try {
const entry = (await this.getFiletree()).read(resource.path);
if (!entry) {
// Dirs aren't saved to disk, so empty dirs will be lost on reload.
// Thus we have two options for what happens when you try to read a dir and nothing is found:
// - Throw FileSystemProviderErrorCode.FileNotFound
// - Return []
// We choose to return [] as creating a dir then reading it (even after reload) should not throw an error.
return [];
}
if (entry.type !== FileType.Directory) {
throw ERR_FILE_NOT_DIR;
}
else {
return [...entry.children.entries()].map(([name, node]) => [name, node.type]);
}
} catch (error) {
throw error;
const entry = (await this.getFiletree()).read(resource.path);
if (!entry) {
// Dirs aren't saved to disk, so empty dirs will be lost on reload.
// Thus we have two options for what happens when you try to read a dir and nothing is found:
// - Throw FileSystemProviderErrorCode.FileNotFound
// - Return []
// We choose to return [] as creating a dir then reading it (even after reload) should not throw an error.
return [];
}
if (entry.type !== FileType.Directory) {
throw ERR_FILE_NOT_DIR;
}
else {
return [...entry.children.entries()].map(([name, node]) => [name, node.type]);
}
}
async readFile(resource: URI): Promise<Uint8Array> {
try {
const result = await this.indexedDB.runInTransaction(this.store, 'readonly', objectStore => objectStore.get(resource.path));
if (result === undefined) {
throw ERR_FILE_NOT_FOUND;
}
const buffer = result instanceof Uint8Array ? result : isString(result) ? VSBuffer.fromString(result).buffer : undefined;
if (buffer === undefined) {
throw ERR_UNKNOWN_INTERNAL(`IndexedDB entry at "${resource.path}" in unexpected format`);
}
// update cache
const fileTree = await this.getFiletree();
fileTree.add(resource.path, { type: 'file', size: buffer.byteLength });
return buffer;
} catch (error) {
throw error;
const result = await this.indexedDB.runInTransaction(this.store, 'readonly', objectStore => objectStore.get(resource.path));
if (result === undefined) {
throw ERR_FILE_NOT_FOUND;
}
const buffer = result instanceof Uint8Array ? result : isString(result) ? VSBuffer.fromString(result).buffer : undefined;
if (buffer === undefined) {
throw ERR_UNKNOWN_INTERNAL(`IndexedDB entry at "${resource.path}" in unexpected format`);
}
// update cache
const fileTree = await this.getFiletree();
fileTree.add(resource.path, { type: 'file', size: buffer.byteLength });
return buffer;
}
async writeFile(resource: URI, content: Uint8Array, opts: IFileWriteOptions): Promise<void> {
try {
const existing = await this.stat(resource).catch(() => undefined);
if (existing?.type === FileType.Directory) {
throw ERR_FILE_IS_DIR;
}
await this.bulkWrite([[resource, content]]);
} catch (error) {
throw error;
const existing = await this.stat(resource).catch(() => undefined);
if (existing?.type === FileType.Directory) {
throw ERR_FILE_IS_DIR;
}
await this.bulkWrite([[resource, content]]);
}
async rename(from: URI, to: URI, opts: IFileOverwriteOptions): Promise<void> {

View File

@@ -10,8 +10,8 @@
*/
export namespace WebFileSystemAccess {
export function supported(obj: any & Window): boolean {
if (typeof obj?.showDirectoryPicker === 'function') {
export function supported(obj: typeof globalThis): boolean {
if (typeof (obj as typeof globalThis & { showDirectoryPicker?: unknown })?.showDirectoryPicker === 'function') {
return true;
}
@@ -38,8 +38,8 @@ export namespace WebFileSystemAccess {
export namespace WebFileSystemObserver {
export function supported(obj: any & Window): boolean {
return typeof obj?.FileSystemObserver === 'function';
export function supported(obj: typeof globalThis): boolean {
return typeof (obj as typeof globalThis & { FileSystemObserver?: unknown })?.FileSystemObserver === 'function';
}
}
@@ -85,3 +85,10 @@ export interface FileSystemObserverRecord {
*/
readonly relativePathMovedFrom?: string[];
}
export declare class FileSystemObserver {
constructor(callback: (records: FileSystemObserverRecord[], observer: FileSystemObserver) => void);
observe(handle: FileSystemHandle, options?: { recursive: boolean }): Promise<void>;
}

View File

@@ -21,8 +21,7 @@ import { localize } from '../../../nls.js';
import { createFileSystemProviderError, IFileAtomicReadOptions, IFileDeleteOptions, IFileOpenOptions, IFileOverwriteOptions, IFileReadStreamOptions, FileSystemProviderCapabilities, FileSystemProviderError, FileSystemProviderErrorCode, FileType, IFileWriteOptions, IFileSystemProviderWithFileAtomicReadCapability, IFileSystemProviderWithFileCloneCapability, IFileSystemProviderWithFileFolderCopyCapability, IFileSystemProviderWithFileReadStreamCapability, IFileSystemProviderWithFileReadWriteCapability, IFileSystemProviderWithOpenReadWriteCloseCapability, isFileOpenForWriteOptions, IStat, FilePermission, IFileSystemProviderWithFileAtomicWriteCapability, IFileSystemProviderWithFileAtomicDeleteCapability, IFileChange, IFileSystemProviderWithFileRealpathCapability } from '../common/files.js';
import { readFileIntoStream } from '../common/io.js';
import { AbstractNonRecursiveWatcherClient, AbstractUniversalWatcherClient, ILogMessage } from '../common/watcher.js';
import { ILogService } from '../../log/common/log.js';
import { AbstractDiskFileSystemProvider, IDiskFileSystemProviderOptions } from '../common/diskFileSystemProvider.js';
import { AbstractDiskFileSystemProvider } from '../common/diskFileSystemProvider.js';
import { UniversalWatcherClient } from './watcher/watcherClient.js';
import { NodeJSWatcherClient } from './watcher/nodejs/nodejsClient.js';
@@ -39,13 +38,6 @@ export class DiskFileSystemProvider extends AbstractDiskFileSystemProvider imple
private static TRACE_LOG_RESOURCE_LOCKS = false; // not enabled by default because very spammy
constructor(
logService: ILogService,
options?: IDiskFileSystemProviderOptions
) {
super(logService, options);
}
//#region File Capabilities
readonly onDidChangeCapabilities = Event.None;

View File

@@ -33,37 +33,37 @@ export abstract class AbstractDiskFileSystemProviderChannel<T> extends Disposabl
super();
}
call(ctx: T, command: string, arg?: any): Promise<any> {
call<TResult>(ctx: T, command: string, args: unknown[]): Promise<TResult> {
const uriTransformer = this.getUriTransformer(ctx);
switch (command) {
case 'stat': return this.stat(uriTransformer, arg[0]);
case 'realpath': return this.realpath(uriTransformer, arg[0]);
case 'readdir': return this.readdir(uriTransformer, arg[0]);
case 'open': return this.open(uriTransformer, arg[0], arg[1]);
case 'close': return this.close(arg[0]);
case 'read': return this.read(arg[0], arg[1], arg[2]);
case 'readFile': return this.readFile(uriTransformer, arg[0], arg[1]);
case 'write': return this.write(arg[0], arg[1], arg[2], arg[3], arg[4]);
case 'writeFile': return this.writeFile(uriTransformer, arg[0], arg[1], arg[2]);
case 'rename': return this.rename(uriTransformer, arg[0], arg[1], arg[2]);
case 'copy': return this.copy(uriTransformer, arg[0], arg[1], arg[2]);
case 'cloneFile': return this.cloneFile(uriTransformer, arg[0], arg[1]);
case 'mkdir': return this.mkdir(uriTransformer, arg[0]);
case 'delete': return this.delete(uriTransformer, arg[0], arg[1]);
case 'watch': return this.watch(uriTransformer, arg[0], arg[1], arg[2], arg[3]);
case 'unwatch': return this.unwatch(arg[0], arg[1]);
case 'stat': return this.stat(uriTransformer, args[0] as UriComponents) as Promise<TResult>;
case 'realpath': return this.realpath(uriTransformer, args[0] as UriComponents) as Promise<TResult>;
case 'readdir': return this.readdir(uriTransformer, args[0] as UriComponents) as Promise<TResult>;
case 'open': return this.open(uriTransformer, args[0] as UriComponents, args[1] as IFileOpenOptions) as Promise<TResult>;
case 'close': return this.close(args[0] as number) as Promise<TResult>;
case 'read': return this.read(args[0] as number, args[1] as number, args[2] as number) as Promise<TResult>;
case 'readFile': return this.readFile(uriTransformer, args[0] as UriComponents, args[1] as IFileAtomicReadOptions) as Promise<TResult>;
case 'write': return this.write(args[0] as number, args[1] as number, args[2] as VSBuffer, args[3] as number, args[4] as number) as Promise<TResult>;
case 'writeFile': return this.writeFile(uriTransformer, args[0] as UriComponents, args[1] as VSBuffer, args[2] as IFileWriteOptions) as Promise<TResult>;
case 'rename': return this.rename(uriTransformer, args[0] as UriComponents, args[1] as UriComponents, args[2] as IFileOverwriteOptions) as Promise<TResult>;
case 'copy': return this.copy(uriTransformer, args[0] as UriComponents, args[1] as UriComponents, args[2] as IFileOverwriteOptions) as Promise<TResult>;
case 'cloneFile': return this.cloneFile(uriTransformer, args[0] as UriComponents, args[1] as UriComponents) as Promise<TResult>;
case 'mkdir': return this.mkdir(uriTransformer, args[0] as UriComponents) as Promise<TResult>;
case 'delete': return this.delete(uriTransformer, args[0] as UriComponents, args[1] as IFileDeleteOptions) as Promise<TResult>;
case 'watch': return this.watch(uriTransformer, args[0] as string, args[1] as number, args[2] as UriComponents, args[3] as IWatchOptions) as Promise<TResult>;
case 'unwatch': return this.unwatch(args[0] as string, args[1] as number) as Promise<TResult>;
}
throw new Error(`IPC Command ${command} not found`);
}
listen(ctx: T, event: string, arg: any): Event<any> {
listen<TResult>(ctx: T, event: string, args: unknown[]): Event<TResult> {
const uriTransformer = this.getUriTransformer(ctx);
switch (event) {
case 'fileChange': return this.onFileChange(uriTransformer, arg[0]);
case 'readFileStream': return this.onReadFileStream(uriTransformer, arg[0], arg[1]);
case 'fileChange': return this.onFileChange(uriTransformer, args[0] as string) as Event<TResult>;
case 'readFileStream': return this.onReadFileStream(uriTransformer, args[0] as URI, args[1] as IFileReadStreamOptions) as Event<TResult>;
}
throw new Error(`Unknown event ${event}`);

View File

@@ -151,7 +151,7 @@ export class NodeJSWatcher extends BaseWatcher implements INonRecursiveWatcher {
requestsForCorrelation.set(path, request);
}
return Array.from(mapCorrelationtoRequests.values()).map(requests => Array.from(requests.values())).flat();
return Array.from(mapCorrelationtoRequests.values()).flatMap(requests => Array.from(requests.values()));
}
override async setVerboseLogging(enabled: boolean): Promise<void> {

View File

@@ -10,6 +10,7 @@ import { createDecorator, IInstantiationService, ServiceIdentifier } from '../..
import { IMainProcessService } from '../common/mainProcessService.js';
import { IRemoteService } from '../common/services.js';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type ChannelClientCtor<T> = { new(channel: IChannel, ...args: any[]): T };
type Remote = { getChannel(channelName: string): IChannel };

View File

@@ -138,7 +138,7 @@ export class LaunchMainService implements ILaunchMainService {
};
// Special case extension development
if (!!args.extensionDevelopmentPath) {
if (args.extensionDevelopmentPath) {
await this.windowsMainService.openExtensionDevelopmentHostWindow(args.extensionDevelopmentPath, baseConfig);
}

View File

@@ -528,17 +528,17 @@ export class Menubar extends Disposable {
menu.append(this.createMenuItem(item.label, item.id, false, item.checked));
}
} else {
menu.append(this.createMenuItem(item.label, item.id, item.enabled === false ? false : true, !!item.checked));
menu.append(this.createMenuItem(item.label, item.id, item.enabled !== false, !!item.checked));
}
} else {
menu.append(this.createMenuItem(item.label, item.id, item.enabled === false ? false : true, !!item.checked));
menu.append(this.createMenuItem(item.label, item.id, item.enabled !== false, !!item.checked));
}
}
});
}
private setMenuById(menu: Menu, menuId: string): void {
if (this.menubarMenus && this.menubarMenus[menuId]) {
if (this.menubarMenus?.[menuId]) {
this.setMenu(menu, this.menubarMenus[menuId].items);
}
}
@@ -586,7 +586,7 @@ export class Menubar extends Disposable {
return !!(event.triggeredByAccelerator || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey);
}
private createRoleMenuItem(label: string, commandId: string, role: any): MenuItem {
private createRoleMenuItem(label: string, commandId: string, role: 'undo' | 'redo' | 'cut' | 'copy' | 'paste' | 'pasteAndMatchStyle' | 'delete' | 'selectAll' | 'reload' | 'forceReload' | 'toggleDevTools' | 'resetZoom' | 'zoomIn' | 'zoomOut' | 'toggleSpellChecker' | 'togglefullscreen' | 'window' | 'minimize' | 'close' | 'help' | 'about' | 'services' | 'hide' | 'hideOthers' | 'unhide' | 'quit' | 'showSubstitutions' | 'toggleSmartQuotes' | 'toggleSmartDashes' | 'toggleTextReplacement' | 'startSpeaking' | 'stopSpeaking' | 'zoom' | 'front' | 'appMenu' | 'fileMenu' | 'editMenu' | 'viewMenu' | 'shareMenu' | 'recentDocuments' | 'toggleTabBar' | 'selectNextTab' | 'selectPreviousTab' | 'showAllTabs' | 'mergeAllWindows' | 'clearRecentDocuments' | 'moveTabToNewWindow' | 'windowMenu'): MenuItem {
const options: MenuItemConstructorOptions = {
label: this.mnemonicLabel(label),
role,
@@ -674,25 +674,18 @@ export class Menubar extends Disposable {
}
}
private createMenuItem(label: string, commandId: string | string[], enabled?: boolean, checked?: boolean): MenuItem;
private createMenuItem(label: string, click: () => void, enabled?: boolean, checked?: boolean): MenuItem;
private createMenuItem(arg1: string, arg2: any, arg3?: boolean, arg4?: boolean): MenuItem {
const label = this.mnemonicLabel(arg1);
const click: () => void = (typeof arg2 === 'function') ? arg2 : (menuItem: MenuItem & IMenuItemWithKeybinding, win: BrowserWindow, event: KeyboardEvent) => {
private createMenuItem(labelOpt: string, commandId: string, enabledOpt?: boolean, checkedOpt?: boolean): MenuItem {
const label = this.mnemonicLabel(labelOpt);
const click = (menuItem: MenuItem & IMenuItemWithKeybinding, window: BaseWindow | undefined, event: KeyboardEvent) => {
const userSettingsLabel = menuItem ? menuItem.userSettingsLabel : null;
let commandId = arg2;
if (Array.isArray(arg2)) {
commandId = this.isOptionClick(event) ? arg2[1] : arg2[0]; // support alternative action if we got multiple action Ids and the option key was pressed while invoking
}
if (userSettingsLabel && event.triggeredByAccelerator) {
this.runActionInRenderer({ type: 'keybinding', userSettingsLabel });
} else {
this.runActionInRenderer({ type: 'commandId', commandId });
}
};
const enabled = typeof arg3 === 'boolean' ? arg3 : this.windowsMainService.getWindowCount() > 0;
const checked = typeof arg4 === 'boolean' ? arg4 : false;
const enabled = typeof enabledOpt === 'boolean' ? enabledOpt : this.windowsMainService.getWindowCount() > 0;
const checked = typeof checkedOpt === 'boolean' ? checkedOpt : false;
const options: MenuItemConstructorOptions = {
label,
@@ -705,13 +698,6 @@ export class Menubar extends Disposable {
options.checked = checked;
}
let commandId: string | undefined;
if (typeof arg2 === 'string') {
commandId = arg2;
} else if (Array.isArray(arg2)) {
commandId = arg2[0];
}
if (isMacintosh) {
// Add role for special case menu items

View File

@@ -7,7 +7,7 @@ import { ProxyChannel } from '../../../base/parts/ipc/common/ipc.js';
import { IMainProcessService } from '../../ipc/common/mainProcessService.js';
import { INativeHostService } from './native.js';
// @ts-ignore: interface is implemented via proxy
// @ts-expect-error: interface is implemented via proxy
export class NativeHostService implements INativeHostService {
declare readonly _serviceBrand: undefined;

View File

@@ -148,11 +148,12 @@ export class SharedProcess extends Disposable {
this.utilityProcess = this._register(new UtilityProcess(this.logService, NullTelemetryService, this.lifecycleMainService));
// Install a log listener for very early shared process warnings and errors
this.utilityProcessLogListener = this.utilityProcess.onMessage((e: any) => {
if (typeof e.warning === 'string') {
this.logService.warn(e.warning);
} else if (typeof e.error === 'string') {
this.logService.error(e.error);
this.utilityProcessLogListener = this.utilityProcess.onMessage(e => {
const logValue = e as { warning?: unknown; error?: unknown };
if (typeof logValue.warning === 'string') {
this.logService.warn(logValue.warning);
} else if (typeof logValue.error === 'string') {
this.logService.error(logValue.error);
}
});

View File

@@ -131,10 +131,6 @@ export class ApplicationStorageDatabaseClient extends BaseProfileAwareStorageDat
export class ProfileStorageDatabaseClient extends BaseProfileAwareStorageDatabaseClient {
constructor(channel: IChannel, profile: UriDto<IUserDataProfile>) {
super(channel, profile);
}
async close(): Promise<void> {
// The profile storage database is shared across all instances of

View File

@@ -71,6 +71,7 @@ export class StorageDatabaseChannel extends Disposable implements IServerChannel
};
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
listen(_: unknown, event: string, arg: IBaseSerializableStorageRequest): Event<any> {
switch (event) {
case 'onDidChangeStorage': {
@@ -98,6 +99,7 @@ export class StorageDatabaseChannel extends Disposable implements IServerChannel
//#endregion
// eslint-disable-next-line @typescript-eslint/no-explicit-any
async call(_: unknown, command: string, arg: IBaseSerializableStorageRequest): Promise<any> {
const profile = arg.profile ? revive<IUserDataProfile>(arg.profile) : undefined;
const workspace = reviveIdentifier(arg.workspace);
@@ -134,6 +136,7 @@ export class StorageDatabaseChannel extends Disposable implements IServerChannel
if (typeof path === 'string') {
return this.storageMainService.isUsed(path);
}
return false;
}
default:

View File

@@ -310,14 +310,6 @@ class BaseProfileAwareStorageMain extends BaseStorageMain {
export class ProfileStorageMain extends BaseProfileAwareStorageMain {
constructor(
profile: IUserDataProfile,
options: IStorageMainOptions,
logService: ILogService,
fileService: IFileService
) {
super(profile, options, logService, fileService);
}
}
export class ApplicationStorageMain extends BaseProfileAwareStorageMain {

View File

@@ -261,8 +261,8 @@ export class UtilityProcess extends Disposable {
return true;
}
private createEnv(configuration: IUtilityProcessConfiguration): { [key: string]: any } {
const env: { [key: string]: any } = configuration.env ? { ...configuration.env } : { ...deepClone(process.env) };
private createEnv(configuration: IUtilityProcessConfiguration): NodeJS.ProcessEnv {
const env: NodeJS.ProcessEnv = configuration.env ? { ...configuration.env } : { ...deepClone(process.env) };
// Apply supported environment variables from config
env['VSCODE_ESM_ENTRYPOINT'] = configuration.entryPoint;

View File

@@ -395,7 +395,7 @@ export interface INativeOpenFileRequest extends IOpenFileRequest {
export interface INativeRunActionInWindowRequest {
readonly id: string;
readonly from: 'menu' | 'touchbar' | 'mouse';
readonly args?: any[];
readonly args?: unknown[];
}
export interface INativeRunKeybindingInWindowRequest {
@@ -471,7 +471,7 @@ export interface INativeWindowConfiguration extends IWindowConfiguration, Native
* https://github.com/electron/electron/blob/master/docs/api/web-contents.md#contentssetzoomlevellevel
*/
export function zoomLevelToZoomFactor(zoomLevel = 0): number {
return Math.pow(1.2, zoomLevel);
return 1.2 ** zoomLevel;
}
export const DEFAULT_EMPTY_WINDOW_SIZE = { width: 1200, height: 800 } as const;

View File

@@ -77,8 +77,8 @@ export interface ICodeWindow extends IBaseWindow {
getBounds(): electron.Rectangle;
send(channel: string, ...args: any[]): void;
sendWhenReady(channel: string, token: CancellationToken, ...args: any[]): void;
send(channel: string, ...args: unknown[]): void;
sendWhenReady(channel: string, token: CancellationToken, ...args: unknown[]): void;
updateTouchBar(items: ISerializableCommandAction[][]): void;

View File

@@ -902,7 +902,7 @@ export class CodeWindow extends BaseWindow implements ICodeWindow {
// Unresponsive
if (type === WindowError.UNRESPONSIVE) {
if (this.isExtensionDevelopmentHost || this.isExtensionTestHost || (this._win && this._win.webContents && this._win.webContents.isDevToolsOpened())) {
if (this.isExtensionDevelopmentHost || this.isExtensionTestHost || this._win?.webContents?.isDevToolsOpened()) {
// TODO@electron Workaround for https://github.com/microsoft/vscode/issues/56994
// In certain cases the window can report unresponsiveness because a breakpoint was hit
// and the process is stopped executing. The most typical cases are:
@@ -1473,7 +1473,7 @@ export class CodeWindow extends BaseWindow implements ICodeWindow {
this._win?.close();
}
sendWhenReady(channel: string, token: CancellationToken, ...args: any[]): void {
sendWhenReady(channel: string, token: CancellationToken, ...args: unknown[]): void {
if (this.isReady) {
this.send(channel, ...args);
} else {
@@ -1485,7 +1485,7 @@ export class CodeWindow extends BaseWindow implements ICodeWindow {
}
}
send(channel: string, ...args: any[]): void {
send(channel: string, ...args: unknown[]): void {
if (this._win) {
if (this._win.isDestroyed() || this._win.webContents.isDestroyed()) {
this.logService.warn(`Sending IPC message to channel '${channel}' for window that is destroyed`);

View File

@@ -42,9 +42,9 @@ export interface IWindowsMainService {
openExistingWindow(window: ICodeWindow, openConfig: IOpenConfiguration): void;
sendToFocused(channel: string, ...args: any[]): void;
sendToOpeningWindow(channel: string, ...args: any[]): void;
sendToAll(channel: string, payload?: any, windowIdsToIgnore?: number[]): void;
sendToFocused(channel: string, ...args: unknown[]): void;
sendToOpeningWindow(channel: string, ...args: unknown[]): void;
sendToAll(channel: string, payload?: unknown, windowIdsToIgnore?: number[]): void;
getWindows(): ICodeWindow[];
getWindowCount(): number;

View File

@@ -389,7 +389,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
// Otherwise, find a good window based on open params
else {
const focusLastActive = this.windowsStateHandler.state.lastActiveWindow && !openConfig.forceEmpty && !openConfig.cli._.length && !openConfig.cli['file-uri'] && !openConfig.cli['folder-uri'] && !(openConfig.urisToOpen && openConfig.urisToOpen.length);
const focusLastActive = this.windowsStateHandler.state.lastActiveWindow && !openConfig.forceEmpty && !openConfig.cli._.length && !openConfig.cli['file-uri'] && !openConfig.cli['folder-uri'] && !openConfig.urisToOpen?.length;
let focusLastOpened = true;
let focusLastWindow = true;
@@ -1410,7 +1410,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
cliArgs = cliArgs.filter(path => {
const uri = URI.file(path);
if (!!findWindowOnWorkspaceOrFolder(this.getWindows(), uri)) {
if (findWindowOnWorkspaceOrFolder(this.getWindows(), uri)) {
return false;
}
@@ -1419,7 +1419,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
folderUris = folderUris.filter(folderUriStr => {
const folderUri = this.cliArgToUri(folderUriStr);
if (folderUri && !!findWindowOnWorkspaceOrFolder(this.getWindows(), folderUri)) {
if (folderUri && findWindowOnWorkspaceOrFolder(this.getWindows(), folderUri)) {
return false;
}
@@ -1428,7 +1428,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
fileUris = fileUris.filter(fileUriStr => {
const fileUri = this.cliArgToUri(fileUriStr);
if (fileUri && !!findWindowOnWorkspaceOrFolder(this.getWindows(), fileUri)) {
if (fileUri && findWindowOnWorkspaceOrFolder(this.getWindows(), fileUri)) {
return false;
}
@@ -1609,7 +1609,6 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
configuration['disable-extensions'] = currentWindowConfig['disable-extensions'];
configuration['disable-extension'] = currentWindowConfig['disable-extension'];
}
configuration.loggers = configuration.loggers;
}
// Update window identifier and session now
@@ -1735,19 +1734,19 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
return getLastFocused(windows);
}
sendToFocused(channel: string, ...args: any[]): void {
sendToFocused(channel: string, ...args: unknown[]): void {
const focusedWindow = this.getFocusedWindow() || this.getLastActiveWindow();
focusedWindow?.sendWhenReady(channel, CancellationToken.None, ...args);
}
sendToOpeningWindow(channel: string, ...args: any[]): void {
sendToOpeningWindow(channel: string, ...args: unknown[]): void {
this._register(Event.once(this.onDidSignalReadyWindow)(window => {
window.sendWhenReady(channel, CancellationToken.None, ...args);
}));
}
sendToAll(channel: string, payload?: any, windowIdsToIgnore?: number[]): void {
sendToAll(channel: string, payload?: unknown, windowIdsToIgnore?: number[]): void {
for (const window of this.getWindows()) {
if (windowIdsToIgnore && windowIdsToIgnore.indexOf(window.id) >= 0) {
continue; // do not send if we are instructed to ignore it

View File

@@ -479,7 +479,7 @@ export function getWindowsStateStoreData(windowsState: IWindowsState): IWindowsS
function serializeWindowState(windowState: IWindowState): ISerializedWindowState {
return {
workspaceIdentifier: windowState.workspace && { id: windowState.workspace.id, configURIPath: windowState.workspace.configPath.toString() },
folder: windowState.folderUri && windowState.folderUri.toString(),
folder: windowState.folderUri?.toString(),
backupPath: windowState.backupPath,
remoteAuthority: windowState.remoteAuthority,
uiState: windowState.uiState

View File

@@ -30,7 +30,7 @@ suite('WindowsFinder', () => {
};
const testWorkspaceFolders = toWorkspaceFolders([{ path: join(fixturesFolder, 'vscode_workspace_1_folder') }, { path: join(fixturesFolder, 'vscode_workspace_2_folder') }], testWorkspace.configPath, extUriBiasedIgnorePathCase);
const localWorkspaceResolver = async (workspace: any) => { return workspace === testWorkspace ? { id: testWorkspace.id, configPath: workspace.configPath, folders: testWorkspaceFolders } : undefined; };
const localWorkspaceResolver = async (workspace: IWorkspaceIdentifier) => { return workspace === testWorkspace ? { id: testWorkspace.id, configPath: workspace.configPath, folders: testWorkspaceFolders } : undefined; };
function createTestCodeWindow(options: { lastFocusTime: number; openedFolderUri?: URI; openedWorkspace?: IWorkspaceIdentifier }): ICodeWindow {
return new class implements ICodeWindow {
@@ -64,8 +64,8 @@ suite('WindowsFinder', () => {
focus(options?: { mode: FocusMode }): void { throw new Error('Method not implemented.'); }
close(): void { throw new Error('Method not implemented.'); }
getBounds(): Electron.Rectangle { throw new Error('Method not implemented.'); }
send(channel: string, ...args: any[]): void { throw new Error('Method not implemented.'); }
sendWhenReady(channel: string, token: CancellationToken, ...args: any[]): void { throw new Error('Method not implemented.'); }
send(channel: string, ...args: unknown[]): void { throw new Error('Method not implemented.'); }
sendWhenReady(channel: string, token: CancellationToken, ...args: unknown[]): void { throw new Error('Method not implemented.'); }
toggleFullScreen(): void { throw new Error('Method not implemented.'); }
setRepresentedFilename(name: string): void { throw new Error('Method not implemented.'); }
getRepresentedFilename(): string | undefined { throw new Error('Method not implemented.'); }
@@ -75,7 +75,7 @@ suite('WindowsFinder', () => {
serializeWindowState(): IWindowState { throw new Error('Method not implemented'); }
updateWindowControls(options: { height?: number | undefined; backgroundColor?: string | undefined; foregroundColor?: string | undefined }): void { throw new Error('Method not implemented.'); }
notifyZoomLevel(level: number): void { throw new Error('Method not implemented.'); }
matches(webContents: any): boolean { throw new Error('Method not implemented.'); }
matches(webContents: Electron.WebContents): boolean { throw new Error('Method not implemented.'); }
dispose(): void { }
};
}

View File

@@ -316,16 +316,22 @@ interface ISerializedRecentlyOpened {
export type RecentlyOpenedStorageData = object;
function isSerializedRecentWorkspace(data: any): data is ISerializedRecentWorkspace {
return data.workspace && typeof data.workspace === 'object' && typeof data.workspace.id === 'string' && typeof data.workspace.configPath === 'string';
function isSerializedRecentWorkspace(data: unknown): data is ISerializedRecentWorkspace {
const candidate = data as ISerializedRecentWorkspace | undefined;
return typeof candidate?.workspace === 'object' && typeof candidate.workspace.id === 'string' && typeof candidate.workspace.configPath === 'string';
}
function isSerializedRecentFolder(data: any): data is ISerializedRecentFolder {
return typeof data.folderUri === 'string';
function isSerializedRecentFolder(data: unknown): data is ISerializedRecentFolder {
const candidate = data as ISerializedRecentFolder | undefined;
return typeof candidate?.folderUri === 'string';
}
function isSerializedRecentFile(data: any): data is ISerializedRecentFile {
return typeof data.fileUri === 'string';
function isSerializedRecentFile(data: unknown): data is ISerializedRecentFile {
const candidate = data as ISerializedRecentFile | undefined;
return typeof candidate?.fileUri === 'string';
}
export function restoreRecentlyOpened(data: RecentlyOpenedStorageData | undefined, logService: ILogService): IRecentlyOpened {

View File

@@ -169,7 +169,7 @@ function _createExtHostProtocol(): Promise<IMessagePassingProtocol> {
const withPorts = (ports: MessagePortMain[]) => {
const port = ports[0];
const onMessage = new BufferedEmitter<VSBuffer>();
port.on('message', (e) => onMessage.fire(VSBuffer.wrap(e.data)));
port.on('message', (e) => onMessage.fire(VSBuffer.wrap(e.data as Uint8Array)));
port.on('close', () => {
onTerminate('renderer closed the MessagePort');
});

View File

@@ -389,7 +389,7 @@ class ToggleScreencastModeAction extends Action2 {
const fromCommandsRegistry = CommandsRegistry.getCommand(commandId);
if (fromCommandsRegistry && fromCommandsRegistry.metadata?.description) {
if (fromCommandsRegistry?.metadata?.description) {
return { title: typeof fromCommandsRegistry.metadata.description === 'string' ? fromCommandsRegistry.metadata.description : fromCommandsRegistry.metadata.description.value };
}

View File

@@ -6,7 +6,7 @@
import { localize, localize2 } from '../../../nls.js';
import { IWindowOpenable } from '../../../platform/window/common/window.js';
import { IDialogService } from '../../../platform/dialogs/common/dialogs.js';
import { MenuRegistry, MenuId, Action2, registerAction2, IAction2Options } from '../../../platform/actions/common/actions.js';
import { MenuRegistry, MenuId, Action2, registerAction2 } from '../../../platform/actions/common/actions.js';
import { KeyChord, KeyCode, KeyMod } from '../../../base/common/keyCodes.js';
import { IsMainWindowFullscreenContext } from '../../common/contextkeys.js';
import { IsMacNativeContext, IsDevelopmentContext, IsWebContext, IsIOSContext } from '../../../platform/contextkey/common/contextkeys.js';
@@ -62,10 +62,6 @@ abstract class BaseOpenRecentAction extends Action2 {
tooltip: localize('dirtyRecentlyOpenedWorkspace', "Workspace With Unsaved Files"),
};
constructor(desc: Readonly<IAction2Options>) {
super(desc);
}
protected abstract isQuickNavigate(): boolean;
override async run(accessor: ServicesAccessor): Promise<void> {

View File

@@ -241,8 +241,8 @@ CommandsRegistry.registerCommand({
const commandService = accessor.get(ICommandService);
const commandOptions: IOpenEmptyWindowOptions = {
forceReuseWindow: options && options.reuseWindow,
remoteAuthority: options && options.remoteAuthority
forceReuseWindow: options?.reuseWindow,
remoteAuthority: options?.remoteAuthority
};
return commandService.executeCommand('_files.newWindow', commandOptions);

View File

@@ -31,7 +31,7 @@ import { IBaseActionViewItemOptions } from '../../base/browser/ui/actionbar/acti
* layout(), focus(), dispose(). During use of the workbench, a composite will often receive a setVisible,
* layout and focus call, but only one create and dispose call.
*/
export abstract class Composite extends Component implements IComposite {
export abstract class Composite<MementoType extends object = object> extends Component<MementoType> implements IComposite {
private readonly _onTitleAreaUpdate = this._register(new Emitter<void>());
readonly onTitleAreaUpdate = this._onTitleAreaUpdate.event;

View File

@@ -470,7 +470,7 @@ export class CompositeDragAndDropObserver extends Disposable {
private readDragData(type: ViewType): CompositeDragAndDropData | undefined {
if (this.transferData.hasData(type === 'view' ? DraggedViewIdentifier.prototype : DraggedCompositeIdentifier.prototype)) {
const data = this.transferData.getData(type === 'view' ? DraggedViewIdentifier.prototype : DraggedCompositeIdentifier.prototype);
if (data && data[0]) {
if (data?.[0]) {
return new CompositeDragAndDropData(type, data[0].id);
}
}

View File

@@ -24,7 +24,7 @@ import { VIEWPANE_FILTER_ACTION } from './parts/views/viewPane.js';
import { IBoundarySashes } from '../../base/browser/ui/sash/sash.js';
import { IBaseActionViewItemOptions } from '../../base/browser/ui/actionbar/actionViewItems.js';
export abstract class PaneComposite extends Composite implements IPaneComposite {
export abstract class PaneComposite<MementoType extends object = object> extends Composite<MementoType> implements IPaneComposite {
private viewPaneContainer?: ViewPaneContainer;

View File

@@ -30,7 +30,7 @@ export interface ILayoutContentResult {
* Parts are layed out in the workbench and have their own layout that
* arranges an optional title and mandatory content area to show content.
*/
export abstract class Part extends Component implements ISerializableView {
export abstract class Part<MementoType extends object = object> extends Component<MementoType> implements ISerializableView {
private _dimension: Dimension | undefined;
get dimension(): Dimension | undefined { return this._dimension; }
@@ -265,7 +265,7 @@ export interface IMultiWindowPart {
readonly element: HTMLElement;
}
export abstract class MultiWindowParts<T extends IMultiWindowPart> extends Component {
export abstract class MultiWindowParts<T extends IMultiWindowPart, MementoType extends object = object> extends Component<MementoType> {
protected readonly _parts = new Set<T>();
get parts() { return Array.from(this._parts); }

View File

@@ -63,12 +63,12 @@ export class AuxiliaryBarPart extends AbstractPaneCompositePart {
const activeComposite = this.getActivePaneComposite();
if (!activeComposite) {
return;
return undefined;
}
const width = activeComposite.getOptimalWidth();
if (typeof width !== 'number') {
return;
return undefined;
}
return Math.max(width, 300);

View File

@@ -71,7 +71,7 @@ export class CompositeDragAndDrop implements ICompositeDragAndDrop {
if (dragData.type === 'view') {
const viewToMove = this.viewDescriptorService.getViewDescriptorById(dragData.id)!;
if (viewToMove && viewToMove.canMoveView) {
if (viewToMove.canMoveView) {
this.viewDescriptorService.moveViewToLocation(viewToMove, this.targetContainerLocation, 'dnd');
const newContainer = this.viewDescriptorService.getViewContainerByViewId(viewToMove.id)!;

View File

@@ -56,7 +56,7 @@ interface CompositeItem {
readonly progress: IProgressIndicator;
}
export abstract class CompositePart<T extends Composite> extends Part {
export abstract class CompositePart<T extends Composite, MementoType extends object = object> extends Part<MementoType> {
protected readonly onDidCompositeOpen = this._register(new Emitter<{ composite: IComposite; focus: boolean }>());
protected readonly onDidCompositeClose = this._register(new Emitter<IComposite>());

View File

@@ -12,7 +12,7 @@ import { IWorkbenchLayoutService, Parts } from '../../../services/layout/browser
import { GoFilter, IHistoryService } from '../../../services/history/common/history.js';
import { IKeybindingService } from '../../../../platform/keybinding/common/keybinding.js';
import { ICommandService } from '../../../../platform/commands/common/commands.js';
import { CLOSE_EDITOR_COMMAND_ID, MOVE_ACTIVE_EDITOR_COMMAND_ID, SelectedEditorsMoveCopyArguments, SPLIT_EDITOR_LEFT, SPLIT_EDITOR_RIGHT, SPLIT_EDITOR_UP, SPLIT_EDITOR_DOWN, splitEditor, LAYOUT_EDITOR_GROUPS_COMMAND_ID, UNPIN_EDITOR_COMMAND_ID, COPY_ACTIVE_EDITOR_COMMAND_ID, SPLIT_EDITOR, TOGGLE_MAXIMIZE_EDITOR_GROUP, MOVE_EDITOR_INTO_NEW_WINDOW_COMMAND_ID, COPY_EDITOR_INTO_NEW_WINDOW_COMMAND_ID, MOVE_EDITOR_GROUP_INTO_NEW_WINDOW_COMMAND_ID, COPY_EDITOR_GROUP_INTO_NEW_WINDOW_COMMAND_ID, NEW_EMPTY_EDITOR_WINDOW_COMMAND_ID as NEW_EMPTY_EDITOR_WINDOW_COMMAND_ID, MOVE_EDITOR_INTO_RIGHT_GROUP, MOVE_EDITOR_INTO_LEFT_GROUP, MOVE_EDITOR_INTO_ABOVE_GROUP, MOVE_EDITOR_INTO_BELOW_GROUP } from './editorCommands.js';
import { CLOSE_EDITOR_COMMAND_ID, MOVE_ACTIVE_EDITOR_COMMAND_ID, SelectedEditorsMoveCopyArguments, SPLIT_EDITOR_LEFT, SPLIT_EDITOR_RIGHT, SPLIT_EDITOR_UP, SPLIT_EDITOR_DOWN, splitEditor, LAYOUT_EDITOR_GROUPS_COMMAND_ID, UNPIN_EDITOR_COMMAND_ID, COPY_ACTIVE_EDITOR_COMMAND_ID, SPLIT_EDITOR, TOGGLE_MAXIMIZE_EDITOR_GROUP, MOVE_EDITOR_INTO_NEW_WINDOW_COMMAND_ID, COPY_EDITOR_INTO_NEW_WINDOW_COMMAND_ID, MOVE_EDITOR_GROUP_INTO_NEW_WINDOW_COMMAND_ID, COPY_EDITOR_GROUP_INTO_NEW_WINDOW_COMMAND_ID, NEW_EMPTY_EDITOR_WINDOW_COMMAND_ID, MOVE_EDITOR_INTO_RIGHT_GROUP, MOVE_EDITOR_INTO_LEFT_GROUP, MOVE_EDITOR_INTO_ABOVE_GROUP, MOVE_EDITOR_INTO_BELOW_GROUP } from './editorCommands.js';
import { IEditorGroupsService, IEditorGroup, GroupsArrangement, GroupLocation, GroupDirection, preferredSideBySideGroupDirection, IFindGroupScope, GroupOrientation, EditorGroupLayout, GroupsOrder, MergeGroupMode } from '../../../services/editor/common/editorGroupsService.js';
import { IEditorService } from '../../../services/editor/common/editorService.js';
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';

View File

@@ -1276,7 +1276,7 @@ function registerOtherEditorCommands(): void {
const configurationService = accessor.get(IConfigurationService);
const currentSetting = configurationService.getValue('workbench.editor.enablePreview');
const newSetting = currentSetting === true ? false : true;
const newSetting = currentSetting !== true;
configurationService.updateValue('workbench.editor.enablePreview', newSetting);
}
});

View File

@@ -336,6 +336,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
case GroupModelChangeKind.EDITOR_CLOSE:
groupActiveEditorPinnedContext.set(this.model.activeEditor ? this.model.isPinned(this.model.activeEditor) : false);
groupActiveEditorStickyContext.set(this.model.activeEditor ? this.model.isSticky(this.model.activeEditor) : false);
break;
case GroupModelChangeKind.EDITOR_OPEN:
case GroupModelChangeKind.EDITOR_MOVE:
groupActiveEditorFirstContext.set(this.model.isFirst(this.model.activeEditor));
@@ -1802,7 +1803,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
// However, we only do this unless a custom confirm handler is installed
// that may not be fit to be asked a second time right after.
if (!editor.closeHandler && !this.shouldConfirmClose(editor)) {
return confirmation === ConfirmResult.CANCEL ? true : false;
return confirmation === ConfirmResult.CANCEL;
}
// Otherwise, handle accordingly

View File

@@ -16,7 +16,6 @@ import { URI } from '../../../../base/common/uri.js';
import { Emitter, Event } from '../../../../base/common/event.js';
import { isEmptyObject } from '../../../../base/common/types.js';
import { DEFAULT_EDITOR_MIN_DIMENSIONS, DEFAULT_EDITOR_MAX_DIMENSIONS } from './editor.js';
import { MementoObject } from '../../../common/memento.js';
import { joinPath, IExtUri, isEqual } from '../../../../base/common/resources.js';
import { indexOfPath } from '../../../../base/common/extpath.js';
import { Disposable, IDisposable } from '../../../../base/common/lifecycle.js';
@@ -47,7 +46,7 @@ import { getWindowById } from '../../../../base/browser/dom.js';
*
* This class is only intended to be subclassed and not instantiated.
*/
export abstract class EditorPane extends Composite implements IEditorPane {
export abstract class EditorPane<MementoType extends object = object> extends Composite<MementoType> implements IEditorPane {
//#region Events
@@ -220,7 +219,7 @@ export class EditorMemento<T> extends Disposable implements IEditorMemento<T> {
constructor(
readonly id: string,
private readonly key: string,
private readonly memento: MementoObject,
private readonly memento: T,
private readonly limit: number,
private readonly editorGroupService: IEditorGroupsService,
private readonly configurationService: ITextResourceConfigurationService
@@ -387,7 +386,7 @@ export class EditorMemento<T> extends Disposable implements IEditorMemento<T> {
this.cache = new LRUCache<string, MapGroupToMemento<T>>(this.limit);
// Restore from serialized map state
const rawEditorMemento = this.memento[this.key];
const rawEditorMemento = this.memento[this.key as keyof T];
if (Array.isArray(rawEditorMemento)) {
this.cache.fromJSON(rawEditorMemento);
}
@@ -405,7 +404,7 @@ export class EditorMemento<T> extends Disposable implements IEditorMemento<T> {
this.cleanedUp = true;
}
this.memento[this.key] = cache.toJSON();
(this.memento as Record<string, unknown>)[this.key] = cache.toJSON();
}
private cleanUp(): void {

View File

@@ -22,7 +22,7 @@ import { IStorageService, IStorageValueChangeEvent, StorageScope, StorageTarget
import { ISerializedEditorGroupModel, isSerializedEditorGroupModel } from '../../../common/editor/editorGroupModel.js';
import { EditorDropTarget } from './editorDropTarget.js';
import { Color } from '../../../../base/common/color.js';
import { CenteredViewLayout } from '../../../../base/browser/ui/centered/centeredViewLayout.js';
import { CenteredViewLayout, CenteredViewState } from '../../../../base/browser/ui/centered/centeredViewLayout.js';
import { onUnexpectedError } from '../../../../base/common/errors.js';
import { Parts, IWorkbenchLayoutService, Position } from '../../../services/layout/browser/layoutService.js';
import { DeepPartial, assertType } from '../../../../base/common/types.js';
@@ -43,6 +43,11 @@ export interface IEditorPartUIState {
readonly mostRecentActiveGroups: GroupIdentifier[];
}
interface IEditorPartMemento {
'editorpart.state'?: IEditorPartUIState;
'editorpart.centeredview'?: CenteredViewState;
}
class GridWidgetView<T extends IView> implements IView {
readonly element: HTMLElement = $('.grid-view-container');
@@ -83,7 +88,7 @@ class GridWidgetView<T extends IView> implements IView {
}
}
export class EditorPart extends Part implements IEditorPart, IEditorGroupsView {
export class EditorPart extends Part<IEditorPartMemento> implements IEditorPart, IEditorGroupsView {
private static readonly EDITOR_PART_UI_STATE_STORAGE_KEY = 'editorpart.state';
private static readonly EDITOR_PART_CENTERED_VIEW_STORAGE_KEY = 'editorpart.centeredview';

View File

@@ -43,7 +43,11 @@ interface IEditorWorkingSetState extends IEditorWorkingSet {
readonly auxiliary: IEditorPartsUIState;
}
export class EditorParts extends MultiWindowParts<EditorPart> implements IEditorGroupsService, IEditorPartsView {
interface IEditorPartsMemento {
'editorparts.state'?: IEditorPartsUIState;
}
export class EditorParts extends MultiWindowParts<EditorPart, IEditorPartsMemento> implements IEditorGroupsService, IEditorPartsView {
declare readonly _serviceBrand: undefined;
@@ -534,7 +538,7 @@ export class EditorParts extends MultiWindowParts<EditorPart> implements IEditor
break;
}
return parts.map(part => part.getGroups(order)).flat();
return parts.flatMap(part => part.getGroups(order));
}
return this.mainPart.getGroups(order);

View File

@@ -305,7 +305,7 @@ class TabFocusMode extends Disposable {
this.registerListeners();
const tabFocusModeConfig = configurationService.getValue<boolean>('editor.tabFocusMode') === true ? true : false;
const tabFocusModeConfig = configurationService.getValue<boolean>('editor.tabFocusMode') === true;
TabFocus.setTabFocusMode(tabFocusModeConfig);
}
@@ -314,7 +314,7 @@ class TabFocusMode extends Disposable {
this._register(this.configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('editor.tabFocusMode')) {
const tabFocusModeConfig = this.configurationService.getValue<boolean>('editor.tabFocusMode') === true ? true : false;
const tabFocusModeConfig = this.configurationService.getValue<boolean>('editor.tabFocusMode') === true;
TabFocus.setTabFocusMode(tabFocusModeConfig);
this._onDidChange.fire(tabFocusModeConfig);

View File

@@ -126,7 +126,7 @@ export abstract class AbstractEditorWithViewState<T extends object> extends Edit
// new editor: check with workbench.editor.restoreViewState setting
if (context?.newInGroup) {
return this.textResourceConfigurationService.getValue<boolean>(EditorResourceAccessor.getOriginalUri(input, { supportSideBySide: SideBySideEditor.PRIMARY }), 'workbench.editor.restoreViewState') === false ? false : true /* restore by default */;
return this.textResourceConfigurationService.getValue<boolean>(EditorResourceAccessor.getOriginalUri(input, { supportSideBySide: SideBySideEditor.PRIMARY }), 'workbench.editor.restoreViewState') !== false /* restore by default */;
}
// existing editor: always restore viewstate

View File

@@ -273,7 +273,7 @@ export class EditorsObserver extends Disposable {
// Remove from key map
const map = this.keyMap.get(group.id);
if (map && map.delete(key.editor) && map.size === 0) {
if (map?.delete(key.editor) && map.size === 0) {
this.keyMap.delete(group.id);
}

View File

@@ -13,7 +13,6 @@
.monaco-workbench .notifications-list-container .notification-list-item {
display: flex;
flex-direction: column;
flex-direction: column-reverse; /* the details row appears first in order for better keyboard access to notification buttons */
padding: 10px 5px;
height: 100%;

View File

@@ -65,7 +65,7 @@ export class NotificationsListDelegate implements IListVirtualDelegate<INotifica
}
// Last row: source and buttons if we have any
if (notification.source || isNonEmptyArray(notification.actions && notification.actions.primary)) {
if (notification.source || isNonEmptyArray(notification.actions?.primary)) {
expandedHeight += NotificationsListDelegate.ROW_HEIGHT;
}
@@ -88,7 +88,7 @@ export class NotificationsListDelegate implements IListVirtualDelegate<INotifica
if (notification.canCollapse) {
actions++; // expand/collapse
}
if (isNonEmptyArray(notification.actions && notification.actions.secondary)) {
if (isNonEmptyArray(notification.actions?.secondary)) {
actions++; // secondary actions
}
this.offsetHelper.style.width = `${450 /* notifications container width */ - (10 /* padding */ + 30 /* severity icon */ + (actions * 30) /* actions */ - (Math.max(actions - 1, 0) * 4) /* less padding for actions > 1 */)}px`;

View File

@@ -324,7 +324,7 @@ export abstract class AbstractPaneCompositePart extends CompositePart<PaneCompos
else if (dragData.type === 'view') {
const viewToMove = this.viewDescriptorService.getViewDescriptorById(dragData.id)!;
if (viewToMove && viewToMove.canMoveView) {
if (viewToMove.canMoveView) {
this.viewDescriptorService.moveViewToLocation(viewToMove, this.location, 'dnd');
const newContainer = this.viewDescriptorService.getViewContainerByViewId(viewToMove.id)!;

View File

@@ -51,12 +51,12 @@ export class PanelPart extends AbstractPaneCompositePart {
const activeComposite = this.getActivePaneComposite();
if (!activeComposite) {
return;
return undefined;
}
const width = activeComposite.getOptimalWidth();
if (typeof width !== 'number') {
return;
return undefined;
}
return Math.max(width, 300);

View File

@@ -51,12 +51,12 @@ export class SidebarPart extends AbstractPaneCompositePart {
const viewlet = this.getActivePaneComposite();
if (!viewlet) {
return;
return undefined;
}
const width = viewlet.getOptimalWidth();
if (typeof width !== 'number') {
return;
return undefined;
}
return Math.max(width, 300);

View File

@@ -24,7 +24,7 @@ import { IInstantiationService, ServicesAccessor } from '../../../../platform/in
import { Emitter, Event } from '../../../../base/common/event.js';
import { IStorageService, StorageScope } from '../../../../platform/storage/common/storage.js';
import { Parts, IWorkbenchLayoutService, ActivityBarPosition, LayoutSettings, EditorActionsLocation, EditorTabsMode } from '../../../services/layout/browser/layoutService.js';
import { createActionViewItem, fillInActionBarActions as fillInActionBarActions } from '../../../../platform/actions/browser/menuEntryActionViewItem.js';
import { createActionViewItem, fillInActionBarActions } from '../../../../platform/actions/browser/menuEntryActionViewItem.js';
import { Action2, IMenu, IMenuService, MenuId, registerAction2 } from '../../../../platform/actions/common/actions.js';
import { IContextKey, IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js';
import { IHostService } from '../../../services/host/browser/host.js';

View File

@@ -180,7 +180,7 @@ function commandPreconditions(commandId: string): ContextKeyExpression | undefin
const command = CommandsRegistry.getCommand(commandId);
if (command) {
const commandAction = MenuRegistry.getCommand(command.id);
return commandAction && commandAction.precondition;
return commandAction?.precondition;
}
return undefined;
}
@@ -404,7 +404,7 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
async getChildrenBatch(nodes?: ITreeItem[]): Promise<ITreeItem[][]> {
let childrenGroups: ITreeItem[][];
let checkboxesUpdated: ITreeItem[] = [];
if (nodes && nodes.every((node): node is Required<ITreeItem & { children: ITreeItem[] }> => !!node.children)) {
if (nodes?.every((node): node is Required<ITreeItem & { children: ITreeItem[] }> => !!node.children)) {
childrenGroups = nodes.map(node => node.children);
} else {
nodes = nodes ?? [self.root];
@@ -1331,7 +1331,7 @@ class TreeRenderer extends Disposable implements ITreeRenderer<ITreeItem, FuzzyS
const treeItemLabel: ITreeItemLabel | undefined = node.label ? node.label : (resource ? { label: basename(resource) } : undefined);
const description = isString(node.description) ? node.description : resource && node.description === true ? this.labelService.getUriLabel(dirname(resource), { relative: true }) : undefined;
const label = treeItemLabel ? treeItemLabel.label : undefined;
const matches = (treeItemLabel && treeItemLabel.highlights && label) ? treeItemLabel.highlights.map(([start, end]) => {
const matches = (treeItemLabel?.highlights && label) ? treeItemLabel.highlights.map(([start, end]) => {
if (start < 0) {
start = label.length + start;
}

View File

@@ -245,7 +245,7 @@ class ViewWelcomeController {
if (linkedText.nodes.length === 1 && typeof linkedText.nodes[0] !== 'string') {
const node = linkedText.nodes[0];
const buttonContainer = append(this.element!, $('.button-container'));
const button = new Button(buttonContainer, { title: node.title, supportIcons: true, secondary: renderSecondaryButtons && buttonsCount > 0 ? true : false, ...defaultButtonStyles, });
const button = new Button(buttonContainer, { title: node.title, supportIcons: true, secondary: !!(renderSecondaryButtons && buttonsCount > 0), ...defaultButtonStyles, });
button.label = node.label;
button.onDidClick(_ => {
this.openerService.open(node.href, { allowCommands: true });

View File

@@ -288,7 +288,7 @@ class ViewPaneDropOverlay extends Themable {
}
}
export class ViewPaneContainer extends Component implements IViewPaneContainer {
export class ViewPaneContainer<MementoType extends object = object> extends Component<MementoType> implements IViewPaneContainer {
readonly viewContainer: ViewContainer;
private lastFocusedPane: ViewPane | undefined;
@@ -424,7 +424,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
this._register(CompositeDragAndDropObserver.INSTANCE.registerTarget(parent, {
onDragEnter: (e) => {
bounds = getOverlayBounds();
if (overlay && overlay.disposed) {
if (overlay?.disposed) {
overlay = undefined;
}
@@ -453,7 +453,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
}
},
onDragOver: (e) => {
if (overlay && overlay.disposed) {
if (overlay?.disposed) {
overlay = undefined;
}

View File

@@ -3,15 +3,15 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Memento, MementoObject } from './memento.js';
import { Memento } from './memento.js';
import { IThemeService, Themable } from '../../platform/theme/common/themeService.js';
import { IStorageService, IStorageValueChangeEvent, StorageScope, StorageTarget } from '../../platform/storage/common/storage.js';
import { DisposableStore } from '../../base/common/lifecycle.js';
import { Event } from '../../base/common/event.js';
export class Component extends Themable {
export class Component<MementoType extends object = object> extends Themable {
private readonly memento: Memento;
private readonly memento: Memento<MementoType>;
constructor(
private readonly id: string,
@@ -36,12 +36,12 @@ export class Component extends Themable {
return this.id;
}
protected getMemento(scope: StorageScope, target: StorageTarget): MementoObject {
protected getMemento(scope: StorageScope, target: StorageTarget): Partial<MementoType> {
return this.memento.getMemento(scope, target);
}
protected reloadMemento(scope: StorageScope): void {
return this.memento.reloadMemento(scope);
this.memento.reloadMemento(scope);
}
protected onDidChangeMementoValue(scope: StorageScope, disposables: DisposableStore): Event<IStorageValueChangeEvent> {

View File

@@ -58,8 +58,9 @@ export const Extensions = {
ConfigurationMigration: 'base.contributions.configuration.migration'
};
export type ConfigurationValue = { value: any | undefined /* Remove */ };
type ConfigurationValue = { value: unknown | undefined /* Remove */ };
export type ConfigurationKeyValuePairs = [string, ConfigurationValue][];
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type ConfigurationMigrationFn = (value: any, valueAccessor: (key: string) => any) => ConfigurationValue | ConfigurationKeyValuePairs | Promise<ConfigurationValue | ConfigurationKeyValuePairs>;
export type ConfigurationMigration = { key: string; migrateFn: ConfigurationMigrationFn };
@@ -115,7 +116,7 @@ export class ConfigurationMigrationWorkbenchContribution extends Disposable impl
private async migrateConfigurationsForFolderAndOverride(migration: ConfigurationMigration, resource?: URI): Promise<void> {
const inspectData = this.configurationService.inspect(migration.key, { resource });
const targetPairs: [keyof IConfigurationValue<any>, ConfigurationTarget][] = this.workspaceService.getWorkbenchState() === WorkbenchState.WORKSPACE ? [
const targetPairs: [keyof IConfigurationValue<unknown>, ConfigurationTarget][] = this.workspaceService.getWorkbenchState() === WorkbenchState.WORKSPACE ? [
['user', ConfigurationTarget.USER],
['userLocal', ConfigurationTarget.USER_LOCAL],
['userRemote', ConfigurationTarget.USER_REMOTE],
@@ -128,7 +129,7 @@ export class ConfigurationMigrationWorkbenchContribution extends Disposable impl
['workspace', ConfigurationTarget.WORKSPACE],
];
for (const [dataKey, target] of targetPairs) {
const inspectValue = inspectData[dataKey] as IInspectValue<any> | undefined;
const inspectValue = inspectData[dataKey] as IInspectValue<unknown> | undefined;
if (!inspectValue) {
continue;
}
@@ -159,10 +160,10 @@ export class ConfigurationMigrationWorkbenchContribution extends Disposable impl
}
}
private async runMigration(migration: ConfigurationMigration, dataKey: keyof IConfigurationValue<any>, value: any, resource: URI | undefined, overrideIdentifiers: string[] | undefined): Promise<ConfigurationKeyValuePairs | undefined> {
private async runMigration(migration: ConfigurationMigration, dataKey: keyof IConfigurationValue<unknown>, value: unknown, resource: URI | undefined, overrideIdentifiers: string[] | undefined): Promise<ConfigurationKeyValuePairs | undefined> {
const valueAccessor = (key: string) => {
const inspectData = this.configurationService.inspect(key, { resource });
const inspectValue = inspectData[dataKey] as IInspectValue<any> | undefined;
const inspectValue = inspectData[dataKey] as IInspectValue<unknown> | undefined;
if (!inspectValue) {
return undefined;
}
@@ -271,7 +272,7 @@ export class DynamicWindowConfiguration extends Disposable implements IWorkbench
'type': ['string', 'null'],
'default': null,
'enum': [...this.userDataProfilesService.profiles.map(profile => profile.name), null],
'enumItemLabels': [...this.userDataProfilesService.profiles.map(p => ''), localize('active window', "Active Window")],
'enumItemLabels': [...this.userDataProfilesService.profiles.map(() => ''), localize('active window', "Active Window")],
'description': localize('newWindowProfile', "Specifies the profile to use when opening a new window. If a profile name is provided, the new window will use that profile. If no profile name is provided, the new window will use the profile of the active window or the Default profile if no active window exists."),
'scope': ConfigurationScope.APPLICATION,
}

View File

@@ -640,7 +640,7 @@ export class EditorGroupModel extends Disposable implements IEditorGroupModel {
}
setActive(candidate: EditorInput | undefined): EditorInput | undefined {
let result: EditorInput | undefined = undefined;
let result: EditorInput | undefined;
if (!candidate) {
this.setGroupActive();
@@ -1231,7 +1231,7 @@ export class EditorGroupModel extends Disposable implements IEditorGroupModel {
}
this.editors = coalesce(data.editors.map((e, index) => {
let editor: EditorInput | undefined = undefined;
let editor: EditorInput | undefined;
const editorSerializer = registry.getEditorSerializer(e.id);
if (editorSerializer) {

View File

@@ -198,7 +198,7 @@ export abstract class AbstractResourceEditorInput extends EditorInput implements
// resource scheme.
const defaultSizeLimit = getLargeFileConfirmationLimit(this.resource);
let configuredSizeLimit: number | undefined = undefined;
let configuredSizeLimit: number | undefined;
const configuredSizeLimitMb = this.textResourceConfigurationService.inspect<number>(this.resource, null, 'workbench.editorLargeFileConfirmation');
if (isConfigured(configuredSizeLimitMb)) {

View File

@@ -9,13 +9,11 @@ import { onUnexpectedError } from '../../base/common/errors.js';
import { DisposableStore } from '../../base/common/lifecycle.js';
import { Event } from '../../base/common/event.js';
export type MementoObject = { [key: string]: any };
export class Memento<T extends object> {
export class Memento {
private static readonly applicationMementos = new Map<string, ScopedMemento>();
private static readonly profileMementos = new Map<string, ScopedMemento>();
private static readonly workspaceMementos = new Map<string, ScopedMemento>();
private static readonly applicationMementos = new Map<string, ScopedMemento<unknown>>();
private static readonly profileMementos = new Map<string, ScopedMemento<unknown>>();
private static readonly workspaceMementos = new Map<string, ScopedMemento<unknown>>();
private static readonly COMMON_PREFIX = 'memento/';
@@ -25,7 +23,7 @@ export class Memento {
this.id = Memento.COMMON_PREFIX + id;
}
getMemento(scope: StorageScope, target: StorageTarget): MementoObject {
getMemento(scope: StorageScope, target: StorageTarget): Partial<T> {
switch (scope) {
case StorageScope.WORKSPACE: {
let workspaceMemento = Memento.workspaceMementos.get(this.id);
@@ -70,7 +68,7 @@ export class Memento {
}
reloadMemento(scope: StorageScope): void {
let memento: ScopedMemento | undefined;
let memento: ScopedMemento<unknown> | undefined;
switch (scope) {
case StorageScope.APPLICATION:
memento = Memento.applicationMementos.get(this.id);
@@ -101,17 +99,17 @@ export class Memento {
}
}
class ScopedMemento {
class ScopedMemento<T> {
private mementoObj: MementoObject;
private mementoObj: Partial<T>;
constructor(private id: string, private scope: StorageScope, private target: StorageTarget, private storageService: IStorageService) {
this.mementoObj = this.doLoad();
}
private doLoad(): MementoObject {
private doLoad(): Partial<T> {
try {
return this.storageService.getObject<MementoObject>(this.id, this.scope, {});
return this.storageService.getObject(this.id, this.scope, {});
} catch (error) {
// Seeing reports from users unable to open editors
// from memento parsing exceptions. Log the contents
@@ -123,7 +121,7 @@ class ScopedMemento {
return {};
}
getMemento(): MementoObject {
getMemento(): Partial<T> {
return this.mementoObj;
}
@@ -131,7 +129,7 @@ class ScopedMemento {
// Clear old
for (const name of Object.getOwnPropertyNames(this.mementoObj)) {
delete this.mementoObj[name];
delete this.mementoObj[name as keyof Partial<T>];
}
// Assign new

View File

@@ -736,8 +736,8 @@ export class NotificationViewItem extends Disposable implements INotificationVie
return false;
}
const primaryActions = (this._actions && this._actions.primary) || [];
const otherPrimaryActions = (other.actions && other.actions.primary) || [];
const primaryActions = this._actions?.primary || [];
const otherPrimaryActions = other.actions?.primary || [];
return equals(primaryActions, otherPrimaryActions, (action, otherAction) => (action.id + action.label) === (otherAction.id + otherAction.label));
}
}

View File

@@ -660,7 +660,7 @@ export interface ITreeView extends IDisposable {
readonly onDidChangeCheckboxState: Event<readonly ITreeItem[]>;
readonly container: any | undefined;
readonly container: unknown /* HTMLElement */ | undefined;
// checkboxesChanged is a subset of treeItems
refresh(treeItems?: readonly ITreeItem[], checkboxesChanged?: readonly ITreeItem[]): Promise<void>;
@@ -685,7 +685,7 @@ export interface ITreeView extends IDisposable {
setFocus(item?: ITreeItem): void;
show(container: any): void;
show(container: unknown /* HTMLElement */): void;
}
export interface IRevealOptions {

View File

@@ -48,7 +48,7 @@ export class ChatEditor extends EditorPane {
return this._scopedContextKeyService;
}
private _memento: Memento | undefined;
private _memento: Memento<IChatViewState> | undefined;
private _viewState: IChatViewState | undefined;
private dimension = new dom.Dimension(0, 0);
@@ -169,7 +169,7 @@ export class ChatEditor extends EditorPane {
private updateModel(model: IChatModel, viewState?: IChatViewState): void {
this._memento = new Memento('interactive-session-editor-' + CHAT_PROVIDER_ID, this.storageService);
this._viewState = viewState ?? this._memento.getMemento(StorageScope.WORKSPACE, StorageTarget.MACHINE) as IChatViewState;
this._viewState = viewState ?? this._memento.getMemento(StorageScope.WORKSPACE, StorageTarget.MACHINE);
this.widget.setModel(model, { ...this._viewState });
}

View File

@@ -610,7 +610,7 @@ class ChatStatusDashboard extends Disposable {
}
}
private runCommandAndClose(commandOrFn: string | Function, ...args: any[]): void {
private runCommandAndClose(commandOrFn: string | Function, ...args: unknown[]): void {
if (typeof commandOrFn === 'function') {
commandOrFn(...args);
} else {

View File

@@ -50,7 +50,7 @@ export class ChatViewPane extends ViewPane implements IViewWelcomeDelegate {
get widget(): ChatWidget { return this._widget; }
private readonly modelDisposables = this._register(new DisposableStore());
private memento: Memento;
private memento: Memento<IViewPaneState>;
private readonly viewState: IViewPaneState;
private _restoringSession: Promise<void> | undefined;
@@ -78,11 +78,11 @@ export class ChatViewPane extends ViewPane implements IViewWelcomeDelegate {
// View state for the ViewPane is currently global per-provider basically, but some other strictly per-model state will require a separate memento.
this.memento = new Memento('interactive-session-view-' + CHAT_PROVIDER_ID, this.storageService);
this.viewState = this.memento.getMemento(StorageScope.WORKSPACE, StorageTarget.MACHINE) as IViewPaneState;
this.viewState = this.memento.getMemento(StorageScope.WORKSPACE, StorageTarget.MACHINE);
if (this.chatOptions.location === ChatAgentLocation.Chat && !this.viewState.hasMigratedCurrentSession) {
const editsMemento = new Memento('interactive-session-view-' + CHAT_PROVIDER_ID + `-edits`, this.storageService);
const lastEditsState = editsMemento.getMemento(StorageScope.WORKSPACE, StorageTarget.MACHINE) as IViewPaneState;
const editsMemento = new Memento<IViewPaneState>('interactive-session-view-' + CHAT_PROVIDER_ID + `-edits`, this.storageService);
const lastEditsState = editsMemento.getMemento(StorageScope.WORKSPACE, StorageTarget.MACHINE);
if (lastEditsState.sessionId) {
this.logService.trace(`ChatViewPane: last edits session was ${lastEditsState.sessionId}`);
if (!this.chatService.isPersistedSessionEmpty(lastEditsState.sessionId)) {

View File

@@ -29,7 +29,7 @@ export interface IChatTodoListService {
}
export class ChatTodoListStorage implements IChatTodoListStorage {
private memento: Memento;
private memento: Memento<Record<string, IChatTodo[]>>;
constructor(@IStorageService storageService: IStorageService) {
this.memento = new Memento('chat-todo-list', storageService);

View File

@@ -43,7 +43,7 @@ export interface IChatWidgetHistoryService {
}
interface IChatHistory {
history: { [providerId: string]: IChatHistoryEntry[] };
history?: { [providerId: string]: IChatHistoryEntry[] };
}
export const ChatInputHistoryMaxEntries = 40;
@@ -51,7 +51,7 @@ export const ChatInputHistoryMaxEntries = 40;
export class ChatWidgetHistoryService implements IChatWidgetHistoryService {
_serviceBrand: undefined;
private memento: Memento;
private memento: Memento<IChatHistory>;
private viewState: IChatHistory;
private readonly _onDidClearHistory = new Emitter<void>();
@@ -60,8 +60,8 @@ export class ChatWidgetHistoryService implements IChatWidgetHistoryService {
constructor(
@IStorageService storageService: IStorageService
) {
this.memento = new Memento('interactive-session', storageService);
const loadedState = this.memento.getMemento(StorageScope.WORKSPACE, StorageTarget.MACHINE) as IChatHistory;
this.memento = new Memento<IChatHistory>('interactive-session', storageService);
const loadedState = this.memento.getMemento(StorageScope.WORKSPACE, StorageTarget.MACHINE);
for (const provider in loadedState.history) {
// Migration from old format
loadedState.history[provider] = loadedState.history[provider].map(entry => typeof entry === 'string' ? { text: entry } : entry);

View File

@@ -24,7 +24,7 @@ import { IOpenerService } from '../../../../platform/opener/common/opener.js';
import { IUriIdentityService } from '../../../../platform/uriIdentity/common/uriIdentity.js';
import { CommentsViewFilterFocusContextKey, ICommentsView } from './comments.js';
import { CommentsFilters, CommentsFiltersChangeEvent, CommentsSortOrder } from './commentsViewActions.js';
import { Memento, MementoObject } from '../../../common/memento.js';
import { Memento } from '../../../common/memento.js';
import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js';
import { FilterOptions } from './commentsFilterOptions.js';
import { CommentThreadApplicability, CommentThreadState } from '../../../../editor/common/languages.js';
@@ -45,6 +45,14 @@ export const CONTEXT_KEY_SOME_COMMENTS_EXPANDED = new RawContextKey<boolean>('co
export const CONTEXT_KEY_COMMENT_FOCUSED = new RawContextKey<boolean>('commentsView.commentFocused', false);
const VIEW_STORAGE_ID = 'commentsViewState';
interface CommentsViewState {
filter?: string;
filterHistory?: string[];
showResolved?: boolean;
showUnresolved?: boolean;
sortBy?: CommentsSortOrder;
}
type CommentsTreeNode = CommentsModel | ResourceWithCommentThreads | CommentNode;
function createResourceCommentsIterator(model: ICommentsModel): Iterable<ITreeElement<CommentsTreeNode>> {
@@ -78,8 +86,8 @@ export class CommentsPanel extends FilterViewPane implements ICommentsView {
private currentHeight = 0;
private currentWidth = 0;
private readonly viewState: MementoObject;
private readonly stateMemento: Memento;
private readonly viewState: CommentsViewState;
private readonly stateMemento: Memento<CommentsViewState>;
private cachedFilterStats: { total: number; filtered: number } | undefined = undefined;
readonly onDidChangeVisibility = this.onDidChangeBodyVisibility;
@@ -152,15 +160,15 @@ export class CommentsPanel extends FilterViewPane implements ICommentsView {
@IStorageService storageService: IStorageService,
@IPathService private readonly pathService: IPathService,
) {
const stateMemento = new Memento(VIEW_STORAGE_ID, storageService);
const stateMemento = new Memento<CommentsViewState>(VIEW_STORAGE_ID, storageService);
const viewState = stateMemento.getMemento(StorageScope.WORKSPACE, StorageTarget.MACHINE);
super({
...options,
filterOptions: {
placeholder: nls.localize('comments.filter.placeholder', "Filter (e.g. text, author)"),
ariaLabel: nls.localize('comments.filter.ariaLabel', "Filter comments"),
history: viewState['filterHistory'] || [],
text: viewState['filter'] || '',
history: viewState.filterHistory || [],
text: viewState.filter || '',
focusContextKey: CommentsViewFilterFocusContextKey.key
}
}, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, hoverService);
@@ -171,9 +179,9 @@ export class CommentsPanel extends FilterViewPane implements ICommentsView {
this.viewState = viewState;
this.filters = this._register(new CommentsFilters({
showResolved: this.viewState['showResolved'] !== false,
showUnresolved: this.viewState['showUnresolved'] !== false,
sortBy: this.viewState['sortBy'] ?? CommentsSortOrder.ResourceAscending,
showResolved: this.viewState.showResolved !== false,
showUnresolved: this.viewState.showUnresolved !== false,
sortBy: this.viewState.sortBy ?? CommentsSortOrder.ResourceAscending,
}, this.contextKeyService));
this.filter = new Filter(new FilterOptions(this.filterWidget.getFilterText(), this.filters.showResolved, this.filters.showUnresolved));
@@ -189,11 +197,11 @@ export class CommentsPanel extends FilterViewPane implements ICommentsView {
}
override saveState(): void {
this.viewState['filter'] = this.filterWidget.getFilterText();
this.viewState['filterHistory'] = this.filterWidget.getHistory();
this.viewState['showResolved'] = this.filters.showResolved;
this.viewState['showUnresolved'] = this.filters.showUnresolved;
this.viewState['sortBy'] = this.filters.sortBy;
this.viewState.filter = this.filterWidget.getFilterText();
this.viewState.filterHistory = this.filterWidget.getHistory();
this.viewState.showResolved = this.filters.showResolved;
this.viewState.showUnresolved = this.filters.showUnresolved;
this.viewState.sortBy = this.filters.sortBy;
this.stateMemento.saveMemento();
super.saveState();
}

View File

@@ -15,13 +15,17 @@ import { customEditorsExtensionPoint, ICustomEditorsExtensionPoint } from './ext
import { RegisteredEditorPriority } from '../../../services/editor/common/editorResolverService.js';
import { IExtensionPointUser } from '../../../services/extensions/common/extensionsRegistry.js';
interface CustomEditorsMemento {
editors?: CustomEditorDescriptor[];
}
export class ContributedCustomEditors extends Disposable {
private static readonly CUSTOM_EDITORS_STORAGE_ID = 'customEditors';
private static readonly CUSTOM_EDITORS_ENTRY_ID = 'editors';
private readonly _editors = new Map<string, CustomEditorInfo>();
private readonly _memento: Memento;
private readonly _memento: Memento<CustomEditorsMemento>;
constructor(storageService: IStorageService) {
super();

View File

@@ -45,7 +45,6 @@ import { alert } from '../../../../base/browser/ui/aria/aria.js';
import { EXTENSION_CATEGORIES } from '../../../../platform/extensions/common/extensions.js';
import { Registry } from '../../../../platform/registry/common/platform.js';
import { ILabelService } from '../../../../platform/label/common/label.js';
import { MementoObject } from '../../../common/memento.js';
import { SyncDescriptor } from '../../../../platform/instantiation/common/descriptors.js';
import { IPreferencesService } from '../../../services/preferences/common/preferences.js';
import { SIDE_BAR_DRAG_AND_DROP_BACKGROUND } from '../../../common/theme.js';
@@ -92,6 +91,10 @@ export const ExtensionsSearchValueContext = new RawContextKey<string>('extension
const REMOTE_CATEGORY: ILocalizedString = localize2({ key: 'remote', comment: ['Remote as in remote machine'] }, "Remote");
interface IExtensionsViewletState {
'query.value'?: string;
}
export class ExtensionsViewletViewsContribution extends Disposable implements IWorkbenchContribution {
private readonly container: ViewContainer;
@@ -506,7 +509,7 @@ export class ExtensionsViewletViewsContribution extends Disposable implements IW
}
export class ExtensionsViewPaneContainer extends ViewPaneContainer implements IExtensionsViewPaneContainer {
export class ExtensionsViewPaneContainer extends ViewPaneContainer<IExtensionsViewletState> implements IExtensionsViewPaneContainer {
private readonly extensionsSearchValueContextKey: IContextKey<string>;
private readonly defaultViewsContextKey: IContextKey<boolean>;
@@ -534,7 +537,7 @@ export class ExtensionsViewPaneContainer extends ViewPaneContainer implements IE
private header: HTMLElement | undefined;
private searchBox: SuggestEnabledInput | undefined;
private notificationContainer: HTMLElement | undefined;
private readonly searchViewletState: MementoObject;
private readonly searchViewletState: IExtensionsViewletState;
private extensionGalleryManifest: IExtensionGalleryManifest | null = null;
constructor(

View File

@@ -16,7 +16,7 @@ interface RegisteredExternalOpener {
}
interface OpenersMemento {
[id: string]: RegisteredExternalOpener;
[id: string]: RegisteredExternalOpener | undefined;
}
export class ContributedExternalUriOpenersStore extends Disposable {
@@ -24,7 +24,7 @@ export class ContributedExternalUriOpenersStore extends Disposable {
private static readonly STORAGE_ID = 'externalUriOpeners';
private readonly _openers = new Map<string, RegisteredExternalOpener>();
private readonly _memento: Memento;
private readonly _memento: Memento<OpenersMemento>;
private _mementoObject: OpenersMemento;
constructor(
@@ -36,7 +36,9 @@ export class ContributedExternalUriOpenersStore extends Disposable {
this._memento = new Memento(ContributedExternalUriOpenersStore.STORAGE_ID, storageService);
this._mementoObject = this._memento.getMemento(StorageScope.PROFILE, StorageTarget.MACHINE);
for (const [id, value] of Object.entries(this._mementoObject || {})) {
this.add(id, value.extensionId, { isCurrentlyRegistered: false });
if (value) {
this.add(id, value.extensionId, { isCurrentlyRegistered: false });
}
}
this.invalidateOpenersOnExtensionsChanged();

View File

@@ -446,7 +446,7 @@ export class ExplorerService implements IExplorerService {
if (item === undefined || ignore) {
return true;
}
if (this.revealExcludeMatcher.matches(item.resource, name => !!(item.parent && item.parent.getChild(name)))) {
if (this.revealExcludeMatcher.matches(item.resource, name => !!(item.parent?.getChild(name)))) {
return false;
}
const root = item.root;
@@ -521,7 +521,7 @@ function doesFileEventAffect(item: ExplorerItem, view: IExplorerView, events: Fi
}
function getRevealExcludes(configuration: IFilesConfiguration): IExpression {
const revealExcludes = configuration && configuration.explorer && configuration.explorer.autoRevealExclude;
const revealExcludes = configuration?.explorer?.autoRevealExclude;
if (!revealExcludes) {
return {};

View File

@@ -196,7 +196,7 @@ export class ExplorerViewPaneContainer extends ViewPaneContainer {
let delay = 0;
const config = this.configurationService.getValue<IFilesConfiguration>();
if (!!config.workbench?.editor?.enablePreview) {
if (config.workbench?.editor?.enablePreview) {
// delay open editors view when preview is enabled
// to accomodate for the user doing a double click
// to pin the editor.

View File

@@ -78,14 +78,6 @@ export const UPLOAD_LABEL = nls.localize('upload', "Upload...");
const CONFIRM_DELETE_SETTING_KEY = 'explorer.confirmDelete';
const MAX_UNDO_FILE_SIZE = 5000000; // 5mb
function onError(notificationService: INotificationService, error: any): void {
if (error.message === 'string') {
error = error.message;
}
notificationService.error(toErrorMessage(error, false));
}
async function refreshIfSeparator(value: string, explorerService: IExplorerService): Promise<void> {
if (value && ((value.indexOf('/') >= 0) || (value.indexOf('\\') >= 0))) {
// New input contains separator, multiple resources will get created workaround for #68204
@@ -600,7 +592,7 @@ abstract class BaseSaveAllAction extends Action {
try {
await this.doRun(context);
} catch (error) {
onError(this.notificationService, error);
this.notificationService.error(toErrorMessage(error, false));
}
}
}
@@ -1281,7 +1273,7 @@ export const pasteFileHandler = async (accessor: ServicesAccessor, fileList?: Fi
}
}
} catch (e) {
onError(notificationService, new Error(nls.localize('fileDeleted', "The file(s) to paste have been deleted or moved since you copied them. {0}", getErrorMessage(e))));
notificationService.error(toErrorMessage(new Error(nls.localize('fileDeleted', "The file(s) to paste have been deleted or moved since you copied them. {0}", getErrorMessage(e))), false));
} finally {
if (pasteShouldMove) {
// Cut is done. Make sure to clear cut state.

View File

@@ -280,7 +280,7 @@ export class BrowserFileUpload {
operation.filesTotal += childEntries.length;
// Split up files from folders to upload
const folderTarget = target && target.getChild(entry.name) || undefined;
const folderTarget = target?.getChild(entry.name) || undefined;
const fileChildEntries: IWebkitDataTransferItemEntry[] = [];
const folderChildEntries: IWebkitDataTransferItemEntry[] = [];
for (const childEntry of childEntries) {

View File

@@ -159,7 +159,7 @@ export function getMultiSelectedResources(commandArg: unknown, listService: ILis
}
const result = getResourceForCommand(commandArg, editorSerice, listService);
return !!result ? [result] : [];
return result ? [result] : [];
}
export function getOpenEditorsViewMultiSelection(accessor: ServicesAccessor): Array<IEditorIdentifier> | undefined {

Some files were not shown because too many files have changed in this diff Show More