diff --git a/.eslintignore b/.eslint-ignore similarity index 100% rename from .eslintignore rename to .eslint-ignore diff --git a/.eslintplugin/code-amd-node-module.ts b/.eslint-plugin-local/code-amd-node-module.ts similarity index 98% rename from .eslintplugin/code-amd-node-module.ts rename to .eslint-plugin-local/code-amd-node-module.ts index 35c89dcb21961..ff7ef6ab33b1d 100644 --- a/.eslintplugin/code-amd-node-module.ts +++ b/.eslint-plugin-local/code-amd-node-module.ts @@ -12,7 +12,8 @@ export = new class ApiProviderNaming implements eslint.Rule.RuleModule { readonly meta: eslint.Rule.RuleMetaData = { messages: { amdX: 'Use `import type` for import declarations, use `amdX#importAMDNodeModule` for import expressions' - } + }, + schema: false, }; create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener { diff --git a/.eslintplugin/code-declare-service-brand.ts b/.eslint-plugin-local/code-declare-service-brand.ts similarity index 96% rename from .eslintplugin/code-declare-service-brand.ts rename to .eslint-plugin-local/code-declare-service-brand.ts index 402d3638e7ad1..f2d28bbfc01de 100644 --- a/.eslintplugin/code-declare-service-brand.ts +++ b/.eslint-plugin-local/code-declare-service-brand.ts @@ -8,7 +8,8 @@ import * as eslint from 'eslint'; export = new class DeclareServiceBrand implements eslint.Rule.RuleModule { readonly meta: eslint.Rule.RuleMetaData = { - fixable: 'code' + fixable: 'code', + schema: false, }; create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener { diff --git a/.eslintplugin/code-ensure-no-disposables-leak-in-test.ts b/.eslint-plugin-local/code-ensure-no-disposables-leak-in-test.ts similarity index 97% rename from .eslintplugin/code-ensure-no-disposables-leak-in-test.ts rename to .eslint-plugin-local/code-ensure-no-disposables-leak-in-test.ts index 9d3044f50f418..56a1d4a70ad28 100644 --- a/.eslintplugin/code-ensure-no-disposables-leak-in-test.ts +++ b/.eslint-plugin-local/code-ensure-no-disposables-leak-in-test.ts @@ -13,7 +13,8 @@ export = new class EnsureNoDisposablesAreLeakedInTestSuite implements eslint.Rul messages: { ensure: 'Suites should include a call to `ensureNoDisposablesAreLeakedInTestSuite()` to ensure no disposables are leaked in tests.' }, - fixable: 'code' + fixable: 'code', + schema: false, }; create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener { diff --git a/.eslintplugin/code-import-patterns.ts b/.eslint-plugin-local/code-import-patterns.ts similarity index 99% rename from .eslintplugin/code-import-patterns.ts rename to .eslint-plugin-local/code-import-patterns.ts index f99cb0c7c9646..e4fe52412e673 100644 --- a/.eslintplugin/code-import-patterns.ts +++ b/.eslint-plugin-local/code-import-patterns.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as eslint from 'eslint'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; +import { TSESTree } from '@typescript-eslint/utils'; import * as path from 'path'; import minimatch from 'minimatch'; import { createImportRuleListener } from './utils'; @@ -50,7 +50,8 @@ export = new class implements eslint.Rule.RuleModule { }, docs: { url: 'https://github.com/microsoft/vscode/wiki/Source-Code-Organization' - } + }, + schema: false, }; create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener { diff --git a/.eslintplugin/code-layering.ts b/.eslint-plugin-local/code-layering.ts similarity index 93% rename from .eslintplugin/code-layering.ts rename to .eslint-plugin-local/code-layering.ts index cca72eeec71e4..f8b769a1bf63d 100644 --- a/.eslintplugin/code-layering.ts +++ b/.eslint-plugin-local/code-layering.ts @@ -20,7 +20,18 @@ export = new class implements eslint.Rule.RuleModule { }, docs: { url: 'https://github.com/microsoft/vscode/wiki/Source-Code-Organization' - } + }, + schema: [ + { + type: 'object', + additionalProperties: { + type: 'array', + items: { + type: 'string' + } + } + } + ] }; create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener { diff --git a/.eslintplugin/code-limited-top-functions.ts b/.eslint-plugin-local/code-limited-top-functions.ts similarity index 100% rename from .eslintplugin/code-limited-top-functions.ts rename to .eslint-plugin-local/code-limited-top-functions.ts diff --git a/.eslintplugin/code-must-use-result.ts b/.eslint-plugin-local/code-must-use-result.ts similarity index 91% rename from .eslintplugin/code-must-use-result.ts rename to .eslint-plugin-local/code-must-use-result.ts index 2127206f8c43e..e59b1920f2e81 100644 --- a/.eslintplugin/code-must-use-result.ts +++ b/.eslint-plugin-local/code-must-use-result.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as eslint from 'eslint'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; +import { TSESTree } from '@typescript-eslint/utils'; const VALID_USES = new Set([ TSESTree.AST_NODE_TYPES.AwaitExpression, @@ -12,6 +12,9 @@ const VALID_USES = new Set([ ]); export = new class MustUseResults implements eslint.Rule.RuleModule { + readonly meta: eslint.Rule.RuleMetaData = { + schema: false + } create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener { diff --git a/.eslintplugin/code-must-use-super-dispose.ts b/.eslint-plugin-local/code-must-use-super-dispose.ts similarity index 100% rename from .eslintplugin/code-must-use-super-dispose.ts rename to .eslint-plugin-local/code-must-use-super-dispose.ts diff --git a/.eslintplugin/code-no-dangerous-type-assertions.ts b/.eslint-plugin-local/code-no-dangerous-type-assertions.ts similarity index 95% rename from .eslintplugin/code-no-dangerous-type-assertions.ts rename to .eslint-plugin-local/code-no-dangerous-type-assertions.ts index eecd4048e43a9..233fae02c8223 100644 --- a/.eslintplugin/code-no-dangerous-type-assertions.ts +++ b/.eslint-plugin-local/code-no-dangerous-type-assertions.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as eslint from 'eslint'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; +import { TSESTree } from '@typescript-eslint/utils'; export = new class NoDangerousTypeAssertions implements eslint.Rule.RuleModule { diff --git a/.eslintplugin/code-no-global-document-listener.ts b/.eslint-plugin-local/code-no-global-document-listener.ts similarity index 100% rename from .eslintplugin/code-no-global-document-listener.ts rename to .eslint-plugin-local/code-no-global-document-listener.ts diff --git a/.eslintplugin/code-no-native-private.ts b/.eslint-plugin-local/code-no-native-private.ts similarity index 98% rename from .eslintplugin/code-no-native-private.ts rename to .eslint-plugin-local/code-no-native-private.ts index 4d6be23b8f3fb..e2d20694ca8f1 100644 --- a/.eslintplugin/code-no-native-private.ts +++ b/.eslint-plugin-local/code-no-native-private.ts @@ -10,7 +10,8 @@ export = new class ApiProviderNaming implements eslint.Rule.RuleModule { readonly meta: eslint.Rule.RuleMetaData = { messages: { slow: 'Native private fields are much slower and should only be used when needed. Ignore this warning if you know what you are doing, use compile-time private otherwise. See https://github.com/microsoft/vscode/issues/185991#issuecomment-1614468158 for details', - } + }, + schema: false, }; create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener { diff --git a/.eslintplugin/code-no-nls-in-standalone-editor.ts b/.eslint-plugin-local/code-no-nls-in-standalone-editor.ts similarity index 98% rename from .eslintplugin/code-no-nls-in-standalone-editor.ts rename to .eslint-plugin-local/code-no-nls-in-standalone-editor.ts index 90c80dee70c9d..19ad65ee87115 100644 --- a/.eslintplugin/code-no-nls-in-standalone-editor.ts +++ b/.eslint-plugin-local/code-no-nls-in-standalone-editor.ts @@ -12,7 +12,8 @@ export = new class NoNlsInStandaloneEditorRule implements eslint.Rule.RuleModule readonly meta: eslint.Rule.RuleMetaData = { messages: { noNls: 'Not allowed to import vs/nls in standalone editor modules. Use standaloneStrings.ts' - } + }, + schema: false, }; create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener { diff --git a/.eslintplugin/code-no-potentially-unsafe-disposables.ts b/.eslint-plugin-local/code-no-potentially-unsafe-disposables.ts similarity index 100% rename from .eslintplugin/code-no-potentially-unsafe-disposables.ts rename to .eslint-plugin-local/code-no-potentially-unsafe-disposables.ts diff --git a/.eslintplugin/code-no-runtime-import.ts b/.eslint-plugin-local/code-no-runtime-import.ts similarity index 100% rename from .eslintplugin/code-no-runtime-import.ts rename to .eslint-plugin-local/code-no-runtime-import.ts diff --git a/.eslintplugin/code-no-standalone-editor.ts b/.eslint-plugin-local/code-no-standalone-editor.ts similarity index 98% rename from .eslintplugin/code-no-standalone-editor.ts rename to .eslint-plugin-local/code-no-standalone-editor.ts index 898886d17d203..3fad6719581c6 100644 --- a/.eslintplugin/code-no-standalone-editor.ts +++ b/.eslint-plugin-local/code-no-standalone-editor.ts @@ -15,7 +15,8 @@ export = new class NoNlsInStandaloneEditorRule implements eslint.Rule.RuleModule }, docs: { url: 'https://github.com/microsoft/vscode/wiki/Source-Code-Organization' - } + }, + schema: false, }; create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener { diff --git a/.eslintplugin/code-no-static-self-ref.ts b/.eslint-plugin-local/code-no-static-self-ref.ts similarity index 86% rename from .eslintplugin/code-no-static-self-ref.ts rename to .eslint-plugin-local/code-no-static-self-ref.ts index 7c6e13032ae8c..52edfb254f602 100644 --- a/.eslintplugin/code-no-static-self-ref.ts +++ b/.eslint-plugin-local/code-no-static-self-ref.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as eslint from 'eslint'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; +import { TSESTree } from '@typescript-eslint/utils'; /** * WORKAROUND for https://github.com/evanw/esbuild/issues/3823 @@ -15,7 +15,7 @@ export = new class implements eslint.Rule.RuleModule { function checkProperty(inNode: any) { - const classDeclaration = context.getAncestors().find(node => node.type === 'ClassDeclaration'); + const classDeclaration = context.sourceCode.getAncestors(inNode).find(node => node.type === 'ClassDeclaration'); const propertyDefinition = inNode; if (!classDeclaration || !classDeclaration.id?.name) { @@ -33,7 +33,7 @@ export = new class implements eslint.Rule.RuleModule { } const name = classDeclaration.id.name; - const valueText = context.getSourceCode().getText(propertyDefinition.value) + const valueText = context.sourceCode.getText(propertyDefinition.value) if (valueText.includes(name + '.')) { diff --git a/.eslintplugin/code-no-test-async-suite.ts b/.eslint-plugin-local/code-no-test-async-suite.ts similarity index 94% rename from .eslintplugin/code-no-test-async-suite.ts rename to .eslint-plugin-local/code-no-test-async-suite.ts index 41d15d286365e..7d5fadfad0dd7 100644 --- a/.eslintplugin/code-no-test-async-suite.ts +++ b/.eslint-plugin-local/code-no-test-async-suite.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { TSESTree } from '@typescript-eslint/experimental-utils'; +import { TSESTree } from '@typescript-eslint/utils'; import * as eslint from 'eslint'; function isCallExpression(node: TSESTree.Node): node is TSESTree.CallExpression { diff --git a/.eslintplugin/code-no-test-only.ts b/.eslint-plugin-local/code-no-test-only.ts similarity index 100% rename from .eslintplugin/code-no-test-only.ts rename to .eslint-plugin-local/code-no-test-only.ts diff --git a/.eslintplugin/code-no-unexternalized-strings.ts b/.eslint-plugin-local/code-no-unexternalized-strings.ts similarity index 98% rename from .eslintplugin/code-no-unexternalized-strings.ts rename to .eslint-plugin-local/code-no-unexternalized-strings.ts index 17a8f900efdb0..abb3980eb54a2 100644 --- a/.eslintplugin/code-no-unexternalized-strings.ts +++ b/.eslint-plugin-local/code-no-unexternalized-strings.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as eslint from 'eslint'; -import { TSESTree, AST_NODE_TYPES } from '@typescript-eslint/experimental-utils'; +import { TSESTree, AST_NODE_TYPES } from '@typescript-eslint/utils'; function isStringLiteral(node: TSESTree.Node | null | undefined): node is TSESTree.StringLiteral { return !!node && node.type === AST_NODE_TYPES.Literal && typeof node.value === 'string'; @@ -24,7 +24,8 @@ export = new class NoUnexternalizedStrings implements eslint.Rule.RuleModule { badKey: 'The key \'{{key}}\' doesn\'t conform to a valid localize identifier.', duplicateKey: 'Duplicate key \'{{key}}\' with different message value.', badMessage: 'Message argument to \'{{message}}\' must be a string literal.' - } + }, + schema: false, }; create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener { diff --git a/.eslintplugin/code-no-unused-expressions.ts b/.eslint-plugin-local/code-no-unused-expressions.ts similarity index 97% rename from .eslintplugin/code-no-unused-expressions.ts rename to .eslint-plugin-local/code-no-unused-expressions.ts index 450365de2c615..14f2f53d47f34 100644 --- a/.eslintplugin/code-no-unused-expressions.ts +++ b/.eslint-plugin-local/code-no-unused-expressions.ts @@ -12,7 +12,7 @@ */ import * as eslint from 'eslint'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; +import { TSESTree } from '@typescript-eslint/utils'; import * as ESTree from 'estree'; //------------------------------------------------------------------------------ @@ -141,7 +141,7 @@ module.exports = { return { ExpressionStatement(node: TSESTree.ExpressionStatement) { - if (!isValidExpression(node.expression) && !isDirective(node, context.getAncestors())) { + if (!isValidExpression(node.expression) && !isDirective(node, context.sourceCode.getAncestors(node))) { context.report({ node: node, message: `Expected an assignment or function call and instead saw an expression. ${node.expression}` }); } } diff --git a/.eslintplugin/code-parameter-properties-must-have-explicit-accessibility.ts b/.eslint-plugin-local/code-parameter-properties-must-have-explicit-accessibility.ts similarity index 95% rename from .eslintplugin/code-parameter-properties-must-have-explicit-accessibility.ts rename to .eslint-plugin-local/code-parameter-properties-must-have-explicit-accessibility.ts index 458afd5b0ba31..c9837052fa52c 100644 --- a/.eslintplugin/code-parameter-properties-must-have-explicit-accessibility.ts +++ b/.eslint-plugin-local/code-parameter-properties-must-have-explicit-accessibility.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as eslint from 'eslint'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; +import { TSESTree } from '@typescript-eslint/utils'; /** * Enforces that all parameter properties have an explicit access modifier (public, protected, private). diff --git a/.eslintplugin/code-translation-remind.ts b/.eslint-plugin-local/code-translation-remind.ts similarity index 96% rename from .eslintplugin/code-translation-remind.ts rename to .eslint-plugin-local/code-translation-remind.ts index 1ce01107a72a5..cceaba4c419bd 100644 --- a/.eslintplugin/code-translation-remind.ts +++ b/.eslint-plugin-local/code-translation-remind.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as eslint from 'eslint'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; +import { TSESTree } from '@typescript-eslint/utils'; import { readFileSync } from 'fs'; import { createImportRuleListener } from './utils'; @@ -16,7 +16,8 @@ export = new class TranslationRemind implements eslint.Rule.RuleModule { readonly meta: eslint.Rule.RuleMetaData = { messages: { missing: 'Please add \'{{resource}}\' to ./build/lib/i18n.resources.json file to use translations here.' - } + }, + schema: false, }; create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener { diff --git a/.eslintplugin/index.js b/.eslint-plugin-local/index.js similarity index 100% rename from .eslintplugin/index.js rename to .eslint-plugin-local/index.js diff --git a/.eslintplugin/package.json b/.eslint-plugin-local/package.json similarity index 100% rename from .eslintplugin/package.json rename to .eslint-plugin-local/package.json diff --git a/.eslintplugin/tsconfig.json b/.eslint-plugin-local/tsconfig.json similarity index 100% rename from .eslintplugin/tsconfig.json rename to .eslint-plugin-local/tsconfig.json diff --git a/.eslintplugin/utils.ts b/.eslint-plugin-local/utils.ts similarity index 95% rename from .eslintplugin/utils.ts rename to .eslint-plugin-local/utils.ts index 428832e9cf97a..b7457884f8517 100644 --- a/.eslintplugin/utils.ts +++ b/.eslint-plugin-local/utils.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as eslint from 'eslint'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; +import { TSESTree } from '@typescript-eslint/utils'; export function createImportRuleListener(validateImport: (node: TSESTree.Literal, value: string) => any): eslint.Rule.RuleListener { diff --git a/.eslintplugin/vscode-dts-cancellation.ts b/.eslint-plugin-local/vscode-dts-cancellation.ts similarity index 92% rename from .eslintplugin/vscode-dts-cancellation.ts rename to .eslint-plugin-local/vscode-dts-cancellation.ts index 6e253a898ca28..5e8e875af212f 100644 --- a/.eslintplugin/vscode-dts-cancellation.ts +++ b/.eslint-plugin-local/vscode-dts-cancellation.ts @@ -4,14 +4,15 @@ *--------------------------------------------------------------------------------------------*/ import * as eslint from 'eslint'; -import { AST_NODE_TYPES, TSESTree } from '@typescript-eslint/experimental-utils'; +import { AST_NODE_TYPES, TSESTree } from '@typescript-eslint/utils'; export = new class ApiProviderNaming implements eslint.Rule.RuleModule { readonly meta: eslint.Rule.RuleMetaData = { messages: { noToken: 'Function lacks a cancellation token, preferable as last argument', - } + }, + schema: false, }; create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener { diff --git a/.eslintplugin/vscode-dts-create-func.ts b/.eslint-plugin-local/vscode-dts-create-func.ts similarity index 91% rename from .eslintplugin/vscode-dts-create-func.ts rename to .eslint-plugin-local/vscode-dts-create-func.ts index 295d099da7ce4..01db244ce76e5 100644 --- a/.eslintplugin/vscode-dts-create-func.ts +++ b/.eslint-plugin-local/vscode-dts-create-func.ts @@ -4,13 +4,14 @@ *--------------------------------------------------------------------------------------------*/ import * as eslint from 'eslint'; -import { TSESTree, AST_NODE_TYPES } from '@typescript-eslint/experimental-utils'; +import { TSESTree, AST_NODE_TYPES } from '@typescript-eslint/utils'; export = new class ApiLiteralOrTypes implements eslint.Rule.RuleModule { readonly meta: eslint.Rule.RuleMetaData = { docs: { url: 'https://github.com/microsoft/vscode/wiki/Extension-API-guidelines#creating-objects' }, - messages: { sync: '`createXYZ`-functions are constructor-replacements and therefore must return sync', } + messages: { sync: '`createXYZ`-functions are constructor-replacements and therefore must return sync', }, + schema: false, }; create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener { diff --git a/.eslintplugin/vscode-dts-event-naming.ts b/.eslint-plugin-local/vscode-dts-event-naming.ts similarity index 96% rename from .eslintplugin/vscode-dts-event-naming.ts rename to .eslint-plugin-local/vscode-dts-event-naming.ts index 5e767c6e25725..c27d934f4f989 100644 --- a/.eslintplugin/vscode-dts-event-naming.ts +++ b/.eslint-plugin-local/vscode-dts-event-naming.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as eslint from 'eslint'; -import { TSESTree, AST_NODE_TYPES } from '@typescript-eslint/experimental-utils'; +import { TSESTree, AST_NODE_TYPES } from '@typescript-eslint/utils'; export = new class ApiEventNaming implements eslint.Rule.RuleModule { @@ -19,7 +19,8 @@ export = new class ApiEventNaming implements eslint.Rule.RuleModule { verb: 'Unknown verb \'{{verb}}\' - is this really a verb? Iff so, then add this verb to the configuration', subject: 'Unknown subject \'{{subject}}\' - This subject has not been used before but it should refer to something in the API', unknown: 'UNKNOWN event declaration, lint-rule needs tweaking' - } + }, + schema: false, }; create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener { diff --git a/.eslintplugin/vscode-dts-interface-naming.ts b/.eslint-plugin-local/vscode-dts-interface-naming.ts similarity index 92% rename from .eslintplugin/vscode-dts-interface-naming.ts rename to .eslint-plugin-local/vscode-dts-interface-naming.ts index 59112bcb29d49..6b33f9c534335 100644 --- a/.eslintplugin/vscode-dts-interface-naming.ts +++ b/.eslint-plugin-local/vscode-dts-interface-naming.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as eslint from 'eslint'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; +import { TSESTree } from '@typescript-eslint/utils'; export = new class ApiInterfaceNaming implements eslint.Rule.RuleModule { @@ -13,7 +13,8 @@ export = new class ApiInterfaceNaming implements eslint.Rule.RuleModule { readonly meta: eslint.Rule.RuleMetaData = { messages: { naming: 'Interfaces must not be prefixed with uppercase `I`', - } + }, + schema: false, }; create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener { diff --git a/.eslintplugin/vscode-dts-literal-or-types.ts b/.eslint-plugin-local/vscode-dts-literal-or-types.ts similarity index 87% rename from .eslintplugin/vscode-dts-literal-or-types.ts rename to .eslint-plugin-local/vscode-dts-literal-or-types.ts index 01d1d1d858634..44ef0fd2a7cd5 100644 --- a/.eslintplugin/vscode-dts-literal-or-types.ts +++ b/.eslint-plugin-local/vscode-dts-literal-or-types.ts @@ -4,13 +4,14 @@ *--------------------------------------------------------------------------------------------*/ import * as eslint from 'eslint'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; +import { TSESTree } from '@typescript-eslint/utils'; export = new class ApiLiteralOrTypes implements eslint.Rule.RuleModule { readonly meta: eslint.Rule.RuleMetaData = { docs: { url: 'https://github.com/microsoft/vscode/wiki/Extension-API-guidelines#enums' }, - messages: { useEnum: 'Use enums, not literal-or-types', } + messages: { useEnum: 'Use enums, not literal-or-types', }, + schema: false, }; create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener { diff --git a/.eslintplugin/vscode-dts-provider-naming.ts b/.eslint-plugin-local/vscode-dts-provider-naming.ts similarity index 94% rename from .eslintplugin/vscode-dts-provider-naming.ts rename to .eslint-plugin-local/vscode-dts-provider-naming.ts index 284f123420fc7..db8350dd9bc3a 100644 --- a/.eslintplugin/vscode-dts-provider-naming.ts +++ b/.eslint-plugin-local/vscode-dts-provider-naming.ts @@ -4,14 +4,15 @@ *--------------------------------------------------------------------------------------------*/ import * as eslint from 'eslint'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; +import { TSESTree } from '@typescript-eslint/utils'; export = new class ApiProviderNaming implements eslint.Rule.RuleModule { readonly meta: eslint.Rule.RuleMetaData = { messages: { naming: 'A provider should only have functions like provideXYZ or resolveXYZ', - } + }, + schema: false, }; private static _providerFunctionNames = /^(provide|resolve|prepare).+/; diff --git a/.eslintplugin/vscode-dts-region-comments.ts b/.eslint-plugin-local/vscode-dts-region-comments.ts similarity index 98% rename from .eslintplugin/vscode-dts-region-comments.ts rename to .eslint-plugin-local/vscode-dts-region-comments.ts index 63139a50e3bb1..b08dc6357bbf8 100644 --- a/.eslintplugin/vscode-dts-region-comments.ts +++ b/.eslint-plugin-local/vscode-dts-region-comments.ts @@ -10,7 +10,8 @@ export = new class ApiEventNaming implements eslint.Rule.RuleModule { readonly meta: eslint.Rule.RuleMetaData = { messages: { comment: 'region comments should start with a camel case identifier, `:`, then either a GH issue link or owner, e.g #region myProposalName: https://github.com/microsoft/vscode/issues/', - } + }, + schema: false, }; create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener { diff --git a/.eslintplugin/vscode-dts-string-type-literals.ts b/.eslint-plugin-local/vscode-dts-string-type-literals.ts similarity index 79% rename from .eslintplugin/vscode-dts-string-type-literals.ts rename to .eslint-plugin-local/vscode-dts-string-type-literals.ts index 8c3ead14427f3..bca084c4af66c 100644 --- a/.eslintplugin/vscode-dts-string-type-literals.ts +++ b/.eslint-plugin-local/vscode-dts-string-type-literals.ts @@ -4,21 +4,21 @@ *--------------------------------------------------------------------------------------------*/ import * as eslint from 'eslint'; -import { TSESTree } from '@typescript-eslint/experimental-utils'; +import { TSESTree } from '@typescript-eslint/utils'; export = new class ApiTypeDiscrimination implements eslint.Rule.RuleModule { readonly meta: eslint.Rule.RuleMetaData = { docs: { url: 'https://github.com/microsoft/vscode/wiki/Extension-API-guidelines' }, messages: { - noTypeDiscrimination: 'Do not use type descrimination properties' - } + noTypeDiscrimination: 'Do not use type discrimination properties' + }, + schema: false, }; create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener { return { - ['TSPropertySignature[optional=undefined] TSTypeAnnotation TSLiteralType Literal']: (node: any) => { - + ['TSPropertySignature[optional=false] TSTypeAnnotation TSLiteralType Literal']: (node: any) => { const raw = String((node).raw) if (/^('|").*\1$/.test(raw)) { diff --git a/.eslintplugin/vscode-dts-use-thenable.ts b/.eslint-plugin-local/vscode-dts-use-thenable.ts similarity index 97% rename from .eslintplugin/vscode-dts-use-thenable.ts rename to .eslint-plugin-local/vscode-dts-use-thenable.ts index 5111248209966..683394ad11567 100644 --- a/.eslintplugin/vscode-dts-use-thenable.ts +++ b/.eslint-plugin-local/vscode-dts-use-thenable.ts @@ -10,7 +10,8 @@ export = new class ApiEventNaming implements eslint.Rule.RuleModule { readonly meta: eslint.Rule.RuleMetaData = { messages: { usage: 'Use the Thenable-type instead of the Promise type', - } + }, + schema: false, }; create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener { diff --git a/.eslintplugin/vscode-dts-vscode-in-comments.ts b/.eslint-plugin-local/vscode-dts-vscode-in-comments.ts similarity index 98% rename from .eslintplugin/vscode-dts-vscode-in-comments.ts rename to .eslint-plugin-local/vscode-dts-vscode-in-comments.ts index 8ced8eb25fd4e..80d3b7003d799 100644 --- a/.eslintplugin/vscode-dts-vscode-in-comments.ts +++ b/.eslint-plugin-local/vscode-dts-vscode-in-comments.ts @@ -11,7 +11,8 @@ export = new class ApiVsCodeInComments implements eslint.Rule.RuleModule { readonly meta: eslint.Rule.RuleMetaData = { messages: { comment: `Don't use the term 'vs code' in comments` - } + }, + schema: false, }; create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener { diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index cd41eaa33c499..0000000000000 --- a/.eslintrc.json +++ /dev/null @@ -1,1242 +0,0 @@ -{ - "root": true, - "parser": "@typescript-eslint/parser", - "parserOptions": { - "ecmaVersion": 2022, - "sourceType": "module" - }, - "plugins": [ - "@typescript-eslint", - "jsdoc", - "header", - "local" - ], - "rules": { - "constructor-super": "warn", - "curly": "warn", - "eqeqeq": "warn", - "prefer-const": [ - "warn", - { - "destructuring": "all" - } - ], - "no-buffer-constructor": "warn", - "no-caller": "warn", - "no-case-declarations": "warn", - "no-debugger": "warn", - "no-duplicate-case": "warn", - "no-duplicate-imports": "warn", - "no-eval": "warn", - "no-async-promise-executor": "warn", - "no-extra-semi": "warn", - "no-new-wrappers": "warn", - "no-redeclare": "off", - "no-sparse-arrays": "warn", - "no-throw-literal": "warn", - "no-unsafe-finally": "warn", - "no-unused-labels": "warn", - "no-restricted-globals": [ - "warn", - "name", - "length", - "event", - "closed", - "external", - "status", - "origin", - "orientation", - "context" - ], // non-complete list of globals that are easy to access unintentionally - "no-var": "warn", - "jsdoc/no-types": "warn", - "semi": "off", - "@typescript-eslint/semi": "warn", - "@typescript-eslint/member-delimiter-style": "warn", - "@typescript-eslint/naming-convention": [ - "warn", - { - "selector": "class", - "format": [ - "PascalCase" - ] - } - ], - "local/code-no-unused-expressions": [ - "warn", - { - "allowTernary": true - } - ], - "local/code-translation-remind": "warn", - "local/code-no-native-private": "warn", - "local/code-parameter-properties-must-have-explicit-accessibility": "warn", - "local/code-no-nls-in-standalone-editor": "warn", - "local/code-no-potentially-unsafe-disposables": "warn", - "local/code-no-dangerous-type-assertions": "off", - "local/code-no-standalone-editor": "warn", - "local/code-no-unexternalized-strings": "warn", - "local/code-must-use-super-dispose": "warn", - "local/code-declare-service-brand": "warn", - "local/code-layering": [ - "warn", - { - "common": [], - "node": [ - "common" - ], - "browser": [ - "common" - ], - "electron-sandbox": [ - "common", - "browser" - ], - "electron-utility": [ - "common", - "node" - ], - "electron-main": [ - "common", - "node", - "electron-utility" - ] - } - ], - "header/header": [ - 2, - "block", - [ - "---------------------------------------------------------------------------------------------", - " * Copyright (c) Microsoft Corporation. All rights reserved.", - " * Licensed under the MIT License. See License.txt in the project root for license information.", - " *--------------------------------------------------------------------------------------------" - ] - ] - }, - "overrides": [ - { - "files": [ - "*.js" - ], - "rules": { - "jsdoc/no-types": "off" - } - }, - { - "files": [ - "**/*.test.ts" - ], - "rules": { - "local/code-must-use-super-dispose": "off", - "local/code-no-test-only": "error", - "local/code-no-test-async-suite": "warn", - "local/code-no-unexternalized-strings": "off", - "local/code-must-use-result": [ - "warn", - [ - { - "message": "Expression must be awaited", - "functions": [ - "assertSnapshot", - "assertHeap" - ] - } - ] - ] - } - }, - { - "files": [ - "src/**/*.ts" - ], - "rules": { - "local/code-no-static-self-ref": "warn" - } - }, - { - "files": [ - "src/vs/**/*.test.ts" - ], - "rules": { - "local/code-ensure-no-disposables-leak-in-test": [ - "warn", - { - // Files should (only) be removed from the list they adopt the leak detector - "exclude": [ - "src/vs/editor/contrib/codeAction/test/browser/codeActionModel.test.ts", - "src/vs/platform/configuration/test/common/configuration.test.ts", - "src/vs/platform/opener/test/common/opener.test.ts", - "src/vs/platform/registry/test/common/platform.test.ts", - "src/vs/platform/workspace/test/common/workspace.test.ts", - "src/vs/platform/workspaces/test/electron-main/workspaces.test.ts", - "src/vs/workbench/api/test/browser/mainThreadConfiguration.test.ts", - "src/vs/workbench/api/test/node/extHostTunnelService.test.ts", - "src/vs/workbench/contrib/bulkEdit/test/browser/bulkCellEdits.test.ts", - "src/vs/workbench/contrib/chat/test/common/chatWordCounter.test.ts", - "src/vs/workbench/contrib/editSessions/test/browser/editSessions.test.ts", - "src/vs/workbench/contrib/extensions/test/common/extensionQuery.test.ts", - "src/vs/workbench/contrib/notebook/test/browser/notebookExecutionService.test.ts", - "src/vs/workbench/contrib/notebook/test/browser/notebookExecutionStateService.test.ts", - "src/vs/workbench/contrib/tasks/test/common/problemMatcher.test.ts", - "src/vs/workbench/contrib/tasks/test/common/taskConfiguration.test.ts", - "src/vs/workbench/services/commands/test/common/commandService.test.ts", - "src/vs/workbench/services/userActivity/test/browser/domActivityTracker.test.ts", - "src/vs/workbench/test/browser/quickAccess.test.ts" - ] - } - ] - } - }, - { - "files": [ - "**/vscode.d.ts", - "**/vscode.proposed.*.d.ts" - ], - "rules": { - "local/vscode-dts-create-func": "warn", - "local/vscode-dts-literal-or-types": "warn", - "local/vscode-dts-string-type-literals": "warn", - "local/vscode-dts-interface-naming": "warn", - "local/vscode-dts-cancellation": "warn", - "local/vscode-dts-use-thenable": "warn", - "local/vscode-dts-region-comments": "warn", - "local/vscode-dts-vscode-in-comments": "warn", - "local/vscode-dts-provider-naming": [ - "warn", - { - "allowed": [ - "FileSystemProvider", - "TreeDataProvider", - "TestProvider", - "CustomEditorProvider", - "CustomReadonlyEditorProvider", - "TerminalLinkProvider", - "AuthenticationProvider", - "NotebookContentProvider" - ] - } - ], - "local/vscode-dts-event-naming": [ - "warn", - { - "allowed": [ - "onCancellationRequested", - "event" - ], - "verbs": [ - "accept", - "change", - "close", - "collapse", - "create", - "delete", - "discover", - "dispose", - "drop", - "edit", - "end", - "execute", - "expand", - "grant", - "hide", - "invalidate", - "open", - "override", - "perform", - "receive", - "register", - "remove", - "rename", - "save", - "send", - "start", - "terminate", - "trigger", - "unregister", - "write" - ] - } - ] - } - }, - { - "files": [ - "**/vscode.d.ts" - ], - "rules": { - "jsdoc/tag-lines": "off", - "jsdoc/valid-types": "off", - "jsdoc/no-multi-asterisks": [ - "warn", - { - "allowWhitespace": true - } - ], - "jsdoc/require-jsdoc": [ - "warn", - { - "enableFixer": false, - "contexts": [ - "TSInterfaceDeclaration", - "TSPropertySignature", - "TSMethodSignature", - "TSDeclareFunction", - "ClassDeclaration", - "MethodDefinition", - "PropertyDeclaration", - "TSEnumDeclaration", - "TSEnumMember", - "ExportNamedDeclaration" - ] - } - ], - "jsdoc/check-param-names": [ - "warn", - { - "enableFixer": false, - "checkDestructured": false - } - ], - "jsdoc/require-returns": "warn" - } - }, - { - "files": [ - "src/**/{common,browser}/**/*.ts" - ], - "rules": { - "local/code-amd-node-module": "warn" - } - }, - { - "files": [ - "src/**/{browser,electron-sandbox}/**/*.ts" - ], - "rules": { - "local/code-no-global-document-listener": "warn", - "no-restricted-syntax": [ - "warn", - { - "selector": "BinaryExpression[operator='instanceof'][right.name='MouseEvent']", - "message": "Use DOM.isMouseEvent() to support multi-window scenarios." - }, - { - "selector": "BinaryExpression[operator='instanceof'][right.name=/^HTML\\w+/]", - "message": "Use DOM.isHTMLElement() and related methods to support multi-window scenarios." - }, - { - "selector": "BinaryExpression[operator='instanceof'][right.name='KeyboardEvent']", - "message": "Use DOM.isKeyboardEvent() to support multi-window scenarios." - }, - { - "selector": "BinaryExpression[operator='instanceof'][right.name='PointerEvent']", - "message": "Use DOM.isPointerEvent() to support multi-window scenarios." - }, - { - "selector": "BinaryExpression[operator='instanceof'][right.name='DragEvent']", - "message": "Use DOM.isDragEvent() to support multi-window scenarios." - }, - { - "selector": "MemberExpression[object.name='document'][property.name='activeElement']", - "message": "Use .document.activeElement to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "selector": "MemberExpression[object.name='document'][property.name='contains']", - "message": "Use .document.contains to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "selector": "MemberExpression[object.name='document'][property.name='styleSheets']", - "message": "Use .document.styleSheets to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "selector": "MemberExpression[object.name='document'][property.name='fullscreenElement']", - "message": "Use .document.fullscreenElement to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "selector": "MemberExpression[object.name='document'][property.name='body']", - "message": "Use .document.body to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "selector": "MemberExpression[object.name='document'][property.name='addEventListener']", - "message": "Use .document.addEventListener to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "selector": "MemberExpression[object.name='document'][property.name='removeEventListener']", - "message": "Use .document.removeEventListener to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "selector": "MemberExpression[object.name='document'][property.name='hasFocus']", - "message": "Use .document.hasFocus to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "selector": "MemberExpression[object.name='document'][property.name='head']", - "message": "Use .document.head to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "selector": "MemberExpression[object.name='document'][property.name='exitFullscreen']", - "message": "Use .document.exitFullscreen to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "selector": "MemberExpression[object.name='document'][property.name='getElementById']", - "message": "Use .document.getElementById to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "selector": "MemberExpression[object.name='document'][property.name='getElementsByClassName']", - "message": "Use .document.getElementsByClassName to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "selector": "MemberExpression[object.name='document'][property.name='getElementsByName']", - "message": "Use .document.getElementsByName to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "selector": "MemberExpression[object.name='document'][property.name='getElementsByTagName']", - "message": "Use .document.getElementsByTagName to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "selector": "MemberExpression[object.name='document'][property.name='getElementsByTagNameNS']", - "message": "Use .document.getElementsByTagNameNS to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "selector": "MemberExpression[object.name='document'][property.name='getSelection']", - "message": "Use .document.getSelection to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "selector": "MemberExpression[object.name='document'][property.name='open']", - "message": "Use .document.open to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "selector": "MemberExpression[object.name='document'][property.name='close']", - "message": "Use .document.close to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "selector": "MemberExpression[object.name='document'][property.name='documentElement']", - "message": "Use .document.documentElement to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "selector": "MemberExpression[object.name='document'][property.name='visibilityState']", - "message": "Use .document.visibilityState to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "selector": "MemberExpression[object.name='document'][property.name='querySelector']", - "message": "Use .document.querySelector to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "selector": "MemberExpression[object.name='document'][property.name='querySelectorAll']", - "message": "Use .document.querySelectorAll to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "selector": "MemberExpression[object.name='document'][property.name='elementFromPoint']", - "message": "Use .document.elementFromPoint to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "selector": "MemberExpression[object.name='document'][property.name='elementsFromPoint']", - "message": "Use .document.elementsFromPoint to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "selector": "MemberExpression[object.name='document'][property.name='onkeydown']", - "message": "Use .document.onkeydown to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "selector": "MemberExpression[object.name='document'][property.name='onkeyup']", - "message": "Use .document.onkeyup to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "selector": "MemberExpression[object.name='document'][property.name='onmousedown']", - "message": "Use .document.onmousedown to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "selector": "MemberExpression[object.name='document'][property.name='onmouseup']", - "message": "Use .document.onmouseup to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "selector": "MemberExpression[object.name='document'][property.name='execCommand']", - "message": "Use .document.execCommand to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - } - ], - "no-restricted-globals": [ - "warn", - "name", - "length", - "event", - "closed", - "external", - "status", - "origin", - "orientation", - "context", - { - "name": "setInterval", - "message": "Use .setInterval to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "name": "clearInterval", - "message": "Use .clearInterval to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "name": "requestAnimationFrame", - "message": "Use .requestAnimationFrame to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "name": "cancelAnimationFrame", - "message": "Use .cancelAnimationFrame to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "name": "requestIdleCallback", - "message": "Use .requestIdleCallback to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "name": "cancelIdleCallback", - "message": "Use .cancelIdleCallback to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "name": "window", - "message": "Use to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "name": "addEventListener", - "message": "Use .addEventListener to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "name": "removeEventListener", - "message": "Use .removeEventListener to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "name": "getComputedStyle", - "message": "Use .getComputedStyle to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "name": "focus", - "message": "Use .focus to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "name": "blur", - "message": "Use .blur to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "name": "close", - "message": "Use .close to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "name": "dispatchEvent", - "message": "Use .dispatchEvent to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "name": "getSelection", - "message": "Use .getSelection to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "name": "matchMedia", - "message": "Use .matchMedia to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "name": "open", - "message": "Use .open to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "name": "parent", - "message": "Use .parent to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "name": "postMessage", - "message": "Use .postMessage to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "name": "devicePixelRatio", - "message": "Use .devicePixelRatio to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "name": "frames", - "message": "Use .frames to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "name": "frameElement", - "message": "Use .frameElement to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "name": "innerHeight", - "message": "Use .innerHeight to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "name": "innerWidth", - "message": "Use .innerWidth to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "name": "outerHeight", - "message": "Use .outerHeight to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "name": "outerWidth", - "message": "Use .outerWidth to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "name": "opener", - "message": "Use .opener to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "name": "origin", - "message": "Use .origin to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "name": "screen", - "message": "Use .screen to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "name": "screenLeft", - "message": "Use .screenLeft to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "name": "screenTop", - "message": "Use .screenTop to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "name": "screenX", - "message": "Use .screenX to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "name": "screenY", - "message": "Use .screenY to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "name": "scrollX", - "message": "Use .scrollX to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "name": "scrollY", - "message": "Use .scrollY to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "name": "top", - "message": "Use .top to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - }, - { - "name": "visualViewport", - "message": "Use .visualViewport to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant." - } - ] - } - }, - { - "files": [ - "src/**/electron-utility/**/*.ts" - ], - "rules": { - "no-restricted-imports": [ - "warn", - { - "paths": [ - { - "name": "electron", - "importNames": [ - "app", - "autoUpdater", - "BaseWindow", - "BrowserWindow", - "contentTracing", - "desktopCapturer", - "dialog", - "globalShortcut", - "inAppPurchase", - "ipcMain", - "Menu", - "MenuItem", - "MessageChannelMain", - "MessagePortMain", - "nativeTheme", - "netLog", - "Notification", - "powerMonitor", - "powerSaveBlocker", - "protocol", - "pushNotifications", - "safeStorage", - "screen", - "session", - "ShareMenu", - "TouchBar", - "Tray", - "utilityProcess", - "View", - "webContents", - "webFrameMain", - "webContentsView", - "default" - ], - "message": "Only net and system-preferences are allowed to be imported from electron" - } - ] - } - ] - } - }, - { - "files": [ - "src/**/*.ts" - ], - "rules": { - "local/code-import-patterns": [ - "warn", - { - // imports that are allowed in all files of layers: - // - browser - // - electron-sandbox - "when": "hasBrowser", - "allow": [] - }, - { - // imports that are allowed in all files of layers: - // - node - // - electron-utility - // - electron-main - "when": "hasNode", - "allow": [ - "@parcel/watcher", - "@vscode/sqlite3", - "@vscode/vscode-languagedetection", - "@vscode/ripgrep", - "@vscode/iconv-lite-umd", - "@vscode/policy-watcher", - "@vscode/proxy-agent", - "@vscode/spdlog", - "@vscode/windows-process-tree", - "assert", - "child_process", - "console", - "cookie", - "crypto", - "dns", - "events", - "fs", - "fs/promises", - "http", - "https", - "minimist", - "node:module", - "native-keymap", - "native-watchdog", - "net", - "node-pty", - "os", - "path", - "perf_hooks", - "readline", - "stream", - "string_decoder", - "tas-client-umd", - "tls", - "url", - "util", - "v8-inspect-profiler", - "vscode-regexpp", - "vscode-textmate", - "worker_threads", - "@xterm/addon-clipboard", - "@xterm/addon-image", - "@xterm/addon-search", - "@xterm/addon-serialize", - "@xterm/addon-unicode11", - "@xterm/addon-webgl", - "@xterm/headless", - "@xterm/xterm", - "yauzl", - "yazl", - "zlib" - ] - }, - { - // imports that are allowed in all files of layers: - // - electron-utility - // - electron-main - "when": "hasElectron", - "allow": [ - "electron" - ] - }, - { - // imports that are allowed in all /test/ files - "when": "test", - "allow": [ - "assert", - "sinon", - "sinon-test" - ] - }, - // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - // !!! Do not relax these rules !!! - // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - // - // A path ending in /~ has a special meaning. It indicates a template position - // which will be substituted with one or more layers. - // - // When /~ is used in the target, the rule will be expanded to 14 distinct rules. - // e.g. "src/vs/base/~" will be expanded to: - // - src/vs/base/common - // - src/vs/base/worker - // - src/vs/base/browser - // - src/vs/base/electron-sandbox - // - src/vs/base/node - // - src/vs/base/electron-main - // - src/vs/base/test/common - // - src/vs/base/test/worker - // - src/vs/base/test/browser - // - src/vs/base/test/electron-sandbox - // - src/vs/base/test/node - // - src/vs/base/test/electron-main - // - // When /~ is used in the restrictions, it will be replaced with the correct - // layers that can be used e.g. "src/vs/base/electron-sandbox" will be able - // to import "{common,browser,electron-sanbox}", etc. - // - // It is possible to use /~ in the restrictions property even without using it in - // the target property by adding a layer property. - { - "target": "src/vs/base/~", - "restrictions": [ - "vs/base/~" - ] - }, - { - "target": "src/vs/base/parts/*/~", - "restrictions": [ - "vs/base/~", - "vs/base/parts/*/~" - ] - }, - { - "target": "src/vs/platform/*/~", - "restrictions": [ - "vs/base/~", - "vs/base/parts/*/~", - "vs/platform/*/~", - "tas-client-umd", // node module allowed even in /common/ - "@microsoft/1ds-core-js", // node module allowed even in /common/ - "@microsoft/1ds-post-js", // node module allowed even in /common/ - "@xterm/headless" // node module allowed even in /common/ - ] - }, - { - "target": "src/vs/editor/~", - "restrictions": [ - "vs/base/~", - "vs/base/parts/*/~", - "vs/platform/*/~", - "vs/editor/~", - "@vscode/tree-sitter-wasm" // node module allowed even in /common/ - ] - }, - { - "target": "src/vs/editor/contrib/*/~", - "restrictions": [ - "vs/base/~", - "vs/base/parts/*/~", - "vs/platform/*/~", - "vs/editor/~", - "vs/editor/contrib/*/~" - ] - }, - { - "target": "src/vs/editor/standalone/~", - "restrictions": [ - "vs/base/~", - "vs/base/parts/*/~", - "vs/platform/*/~", - "vs/editor/~", - "vs/editor/contrib/*/~", - "vs/editor/standalone/~", - "@vscode/tree-sitter-wasm" // type import - ] - }, - { - "target": "src/vs/editor/editor.all.ts", - "layer": "browser", - "restrictions": [ - "vs/base/~", - "vs/base/parts/*/~", - "vs/platform/*/~", - "vs/editor/~", - "vs/editor/contrib/*/~" - ] - }, - { - "target": "src/vs/editor/editor.worker.ts", - "layer": "worker", - "restrictions": [ - "vs/base/~", - "vs/base/parts/*/~", - "vs/platform/*/~", - "vs/editor/~" - ] - }, - { - "target": "src/vs/editor/{editor.api.ts,editor.main.ts}", - "layer": "browser", - "restrictions": [ - "vs/base/~", - "vs/base/parts/*/~", - "vs/editor/~", - "vs/editor/contrib/*/~", - "vs/editor/standalone/~", - "vs/editor/*" - ] - }, - { - "target": "src/vs/workbench/~", - "restrictions": [ - "vs/base/~", - "vs/base/parts/*/~", - "vs/platform/*/~", - "vs/editor/~", - "vs/editor/contrib/*/~", - "vs/workbench/~", - "vs/workbench/services/*/~", - "assert", - { - "when": "test", - "pattern": "vs/workbench/contrib/*/~" - } // TODO@layers - ] - }, - { - "target": "src/vs/workbench/api/~", - "restrictions": [ - "vscode", - "vs/base/~", - "vs/base/parts/*/~", - "vs/platform/*/~", - "vs/editor/~", - "vs/editor/contrib/*/~", - "vs/workbench/api/~", - "vs/workbench/~", - "vs/workbench/services/*/~", - "vs/workbench/contrib/*/~", - "vs/workbench/contrib/terminalContrib/*/~" - ] - }, - { - "target": "src/vs/workbench/services/*/~", - "restrictions": [ - "vs/base/~", - "vs/base/parts/*/~", - "vs/platform/*/~", - "vs/editor/~", - "vs/editor/contrib/*/~", - "vs/workbench/~", - "vs/workbench/services/*/~", - { - "when": "test", - "pattern": "vs/workbench/contrib/*/~" - }, // TODO@layers - "tas-client-umd", // node module allowed even in /common/ - "vscode-textmate", // node module allowed even in /common/ - "@vscode/vscode-languagedetection", // node module allowed even in /common/ - "@vscode/tree-sitter-wasm", // type import - { - "when": "hasBrowser", - "pattern": "@xterm/xterm" - } // node module allowed even in /browser/ - ] - }, - { - "target": "src/vs/workbench/contrib/*/~", - "restrictions": [ - "vs/base/~", - "vs/base/parts/*/~", - "vs/platform/*/~", - "vs/editor/~", - "vs/editor/contrib/*/~", - "vs/workbench/~", - "vs/workbench/services/*/~", - "vs/workbench/contrib/*/~", - "vs/workbench/contrib/terminal/terminalContribChatExports*", - "vs/workbench/contrib/terminal/terminalContribExports*", - "vscode-notebook-renderer", // Type only import - "@vscode/tree-sitter-wasm", // type import - { - "when": "hasBrowser", - "pattern": "@xterm/xterm" - }, // node module allowed even in /browser/ - { - "when": "hasBrowser", - "pattern": "@xterm/addon-*" - }, // node module allowed even in /browser/ - { - "when": "hasBrowser", - "pattern": "vscode-textmate" - } // node module allowed even in /browser/ - ] - }, - { - "target": "src/vs/workbench/contrib/terminalContrib/*/~", - "restrictions": [ - "vs/base/~", - "vs/base/parts/*/~", - "vs/platform/*/~", - "vs/editor/~", - "vs/editor/contrib/*/~", - "vs/workbench/~", - "vs/workbench/services/*/~", - "vs/workbench/contrib/*/~", - // Only allow terminalContrib to import from itself, this works because - // terminalContrib is one extra folder deep - "vs/workbench/contrib/terminalContrib/*/~", - "vscode-notebook-renderer", // Type only import - { - "when": "hasBrowser", - "pattern": "@xterm/xterm" - }, // node module allowed even in /browser/ - { - "when": "hasBrowser", - "pattern": "@xterm/addon-*" - }, // node module allowed even in /browser/ - { - "when": "hasBrowser", - "pattern": "vscode-textmate" - }, // node module allowed even in /browser/ - "@xterm/headless" // node module allowed even in /common/ and /browser/ - ] - }, - { - "target": "src/vs/code/~", - "restrictions": [ - "vs/base/~", - "vs/base/parts/*/~", - "vs/platform/*/~", - "vs/editor/~", - "vs/editor/contrib/*/~", - "vs/code/~", - { - "when": "hasBrowser", - "pattern": "vs/workbench/workbench.web.main.js" - }, - { - "when": "hasBrowser", - "pattern": "vs/workbench/workbench.web.main.internal.js" - }, - { - "when": "hasBrowser", - "pattern": "vs/workbench/~" - }, - { - "when": "hasBrowser", - "pattern": "vs/workbench/services/*/~" - } - ] - }, - { - "target": "src/vs/server/~", - "restrictions": [ - "vs/base/~", - "vs/base/parts/*/~", - "vs/platform/*/~", - "vs/workbench/~", - "vs/workbench/api/~", - "vs/workbench/services/*/~", - "vs/workbench/contrib/*/~", - "vs/server/~" - ] - }, - { - "target": "src/vs/workbench/contrib/terminal/terminal.all.ts", - "layer": "browser", - "restrictions": [ - "vs/workbench/contrib/**" - ] - }, - { - "target": "src/vs/workbench/contrib/terminal/terminalContribChatExports.ts", - "layer": "browser", - "restrictions": [ - "vs/workbench/contrib/terminalContrib/*/~" - ] - }, - { - "target": "src/vs/workbench/contrib/terminal/terminalContribExports.ts", - "layer": "browser", - "restrictions": [ - "vs/platform/*/~", - "vs/workbench/contrib/terminalContrib/*/~" - ] - }, - { - "target": "src/vs/workbench/workbench.common.main.ts", - "layer": "browser", - "restrictions": [ - "vs/base/~", - "vs/base/parts/*/~", - "vs/platform/*/~", - "vs/editor/~", - "vs/editor/contrib/*/~", - "vs/editor/editor.all.js", - "vs/workbench/~", - "vs/workbench/api/~", - "vs/workbench/services/*/~", - "vs/workbench/contrib/*/~", - "vs/workbench/contrib/terminal/terminal.all.js" - ] - }, - { - "target": "src/vs/workbench/workbench.web.main.ts", - "layer": "browser", - "restrictions": [ - "vs/base/~", - "vs/base/parts/*/~", - "vs/platform/*/~", - "vs/editor/~", - "vs/editor/contrib/*/~", - "vs/editor/editor.all.js", - "vs/workbench/~", - "vs/workbench/api/~", - "vs/workbench/services/*/~", - "vs/workbench/contrib/*/~", - "vs/workbench/workbench.common.main.js" - ] - }, - { - "target": "src/vs/workbench/workbench.web.main.internal.ts", - "layer": "browser", - "restrictions": [ - "vs/base/~", - "vs/base/parts/*/~", - "vs/platform/*/~", - "vs/editor/~", - "vs/editor/contrib/*/~", - "vs/editor/editor.all.js", - "vs/workbench/~", - "vs/workbench/api/~", - "vs/workbench/services/*/~", - "vs/workbench/contrib/*/~", - "vs/workbench/workbench.common.main.js" - ] - }, - { - "target": "src/vs/workbench/workbench.desktop.main.ts", - "layer": "electron-sandbox", - "restrictions": [ - "vs/base/*/~", - "vs/base/parts/*/~", - "vs/platform/*/~", - "vs/editor/~", - "vs/editor/contrib/*/~", - "vs/editor/editor.all.js", - "vs/workbench/~", - "vs/workbench/api/~", - "vs/workbench/services/*/~", - "vs/workbench/contrib/*/~", - "vs/workbench/workbench.common.main.js" - ] - }, - { - "target": "src/vs/amdX.ts", - "restrictions": [ - "vs/base/common/*" - ] - }, - { - "target": "src/vs/nls.ts", - "restrictions": [ - "vs/*" - ] - }, - { - "target": "src/vs/{monaco.d.ts,nls.ts,nls.messages.ts}", - "restrictions": [] - }, - { - "target": "src/vscode-dts/**", - "restrictions": [] - }, - { - "target": "src/bootstrap-window.ts", - "restrictions": [] - }, - { - "target": "src/{bootstrap-cli.ts,bootstrap-esm.ts,bootstrap-fork.ts,bootstrap-import.ts,bootstrap-meta.ts,bootstrap-node.ts,bootstrap-server.ts,cli.ts,main.ts,server-cli.ts,server-main.ts}", - "restrictions": [ - "vs/**/common/*", - "vs/**/node/*", - "vs/nls.js", - "src/*.js", - "*" // node.js - ] - } - ] - } - }, - { - "files": [ - "test/**/*.ts" - ], - "rules": { - "local/code-import-patterns": [ - "warn", - { - "target": "test/smoke/**", - "restrictions": [ - "test/automation", - "test/smoke/**", - "@vscode/*", - "@parcel/*", - "@playwright/*", - "*" // node modules - ] - }, - { - "target": "test/automation/**", - "restrictions": [ - "test/automation/**", - "@vscode/*", - "@parcel/*", - "playwright-core/**", - "@playwright/*", - "*" // node modules - ] - }, - { - "target": "test/integration/**", - "restrictions": [ - "test/integration/**", - "@vscode/*", - "@parcel/*", - "@playwright/*", - "*" // node modules - ] - }, - { - "target": "test/monaco/**", - "restrictions": [ - "test/monaco/**", - "@vscode/*", - "@parcel/*", - "@playwright/*", - "*" // node modules - ] - } - ] - } - }, - { - "files": [ - "src/vs/workbench/contrib/notebook/browser/view/renderers/*.ts" - ], - "rules": { - "local/code-no-runtime-import": [ - "error", - { - "src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts": [ - "**/*" - ] - } - ], - "local/code-limited-top-functions": [ - "error", - { - "src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts": [ - "webviewPreloads", - "preloadsScriptStr" - ] - } - ] - } - } - ] -} diff --git a/.vscode/notebooks/api.github-issues b/.vscode/notebooks/api.github-issues index 6b6a41f513548..35ea9042ef5c9 100644 --- a/.vscode/notebooks/api.github-issues +++ b/.vscode/notebooks/api.github-issues @@ -7,7 +7,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPO=repo:microsoft/vscode\n$MILESTONE=milestone:\"September 2024\"" + "value": "$REPO=repo:microsoft/vscode\n$MILESTONE=milestone:\"October 2024\"" }, { "kind": 1, diff --git a/.vscode/notebooks/my-work.github-issues b/.vscode/notebooks/my-work.github-issues index 5f54a2e5d91f8..c58ceae0d0105 100644 --- a/.vscode/notebooks/my-work.github-issues +++ b/.vscode/notebooks/my-work.github-issues @@ -7,7 +7,7 @@ { "kind": 2, "language": "github-issues", - "value": "// list of repos we work in\n$REPOS=repo:microsoft/lsprotocol repo:microsoft/monaco-editor repo:microsoft/vscode repo:microsoft/vscode-anycode repo:microsoft/vscode-autopep8 repo:microsoft/vscode-black-formatter repo:microsoft/vscode-copilot repo:microsoft/vscode-copilot-release repo:microsoft/vscode-dev repo:microsoft/vscode-dev-chrome-launcher repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-flake8 repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-hexeditor repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-isort repo:microsoft/vscode-js-debug repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-l10n repo:microsoft/vscode-livepreview repo:microsoft/vscode-markdown-languageservice repo:microsoft/vscode-markdown-tm-grammar repo:microsoft/vscode-mypy repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-pylint repo:microsoft/vscode-python repo:microsoft/vscode-python-debugger repo:microsoft/vscode-python-tools-extension-template repo:microsoft/vscode-references-view repo:microsoft/vscode-remote-release repo:microsoft/vscode-remote-repositories-github repo:microsoft/vscode-remote-tunnels repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-unpkg repo:microsoft/vscode-vsce\n\n// current milestone name\n$MILESTONE=milestone:\"September 2024\"\n" + "value": "// list of repos we work in\n$REPOS=repo:microsoft/lsprotocol repo:microsoft/monaco-editor repo:microsoft/vscode repo:microsoft/vscode-anycode repo:microsoft/vscode-autopep8 repo:microsoft/vscode-black-formatter repo:microsoft/vscode-copilot repo:microsoft/vscode-copilot-release repo:microsoft/vscode-dev repo:microsoft/vscode-dev-chrome-launcher repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-flake8 repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-hexeditor repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-isort repo:microsoft/vscode-js-debug repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-l10n repo:microsoft/vscode-livepreview repo:microsoft/vscode-markdown-languageservice repo:microsoft/vscode-markdown-tm-grammar repo:microsoft/vscode-mypy repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-pylint repo:microsoft/vscode-python repo:microsoft/vscode-python-debugger repo:microsoft/vscode-python-tools-extension-template repo:microsoft/vscode-references-view repo:microsoft/vscode-remote-release repo:microsoft/vscode-remote-repositories-github repo:microsoft/vscode-remote-tunnels repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-unpkg repo:microsoft/vscode-vsce\n\n// current milestone name\n$MILESTONE=milestone:\"October 2024\"\n" }, { "kind": 1, diff --git a/.vscode/settings.json b/.vscode/settings.json index 14236b479e267..75cbca16260be 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -168,5 +168,6 @@ }, "css.format.spaceAroundSelectorSeparator": true, "typescript.enablePromptUseWorkspaceTsdk": true, - "chat.commandCenter.enabled": true + "chat.commandCenter.enabled": true, + "eslint.useFlatConfig": true } diff --git a/build/azure-pipelines/product-build.yml b/build/azure-pipelines/product-build.yml index a061c23e8dc52..5bb4d61d188fa 100644 --- a/build/azure-pipelines/product-build.yml +++ b/build/azure-pipelines/product-build.yml @@ -193,7 +193,7 @@ extends: eslint: enabled: true enableExclusions: true - exclusionsFilePath: $(Build.SourcesDirectory)/.eslintignore + exclusionsFilePath: $(Build.SourcesDirectory)/.eslint-ignore sourceAnalysisPool: 1es-windows-2022-x64 createAdoIssuesForJustificationsForDisablement: false containers: diff --git a/build/filters.js b/build/filters.js index 5ccd69b024a32..1705d4b32c334 100644 --- a/build/filters.js +++ b/build/filters.js @@ -169,6 +169,7 @@ module.exports.copyrightFilter = [ '!extensions/markdown-language-features/media/highlight.css', '!extensions/markdown-math/notebook-out/**', '!extensions/ipynb/notebook-out/**', + '!extensions/simple-browser/media/codicon.css', '!extensions/typescript-language-features/node-maintainer/**', '!extensions/html-language-features/server/src/modes/typescript/*', '!extensions/*/server/bin/*', @@ -194,11 +195,13 @@ module.exports.tsFormattingFilter = [ module.exports.eslintFilter = [ '**/*.js', + '**/*.cjs', + '**/*.mjs', '**/*.ts', - ...readFileSync(join(__dirname, '../.eslintignore')) - .toString().split(/\r\n|\n/) - .filter(line => !line.startsWith('#')) - .filter(line => !!line) + ...readFileSync(join(__dirname, '..', '.eslint-ignore')) + .toString() + .split(/\r\n|\n/) + .filter(line => line && !line.startsWith('#')) .map(line => line.startsWith('!') ? line.slice(1) : `!${line}`) ]; diff --git a/build/gulp-eslint.js b/build/gulp-eslint.js index 3373171671b0f..902c7b47003ed 100644 --- a/build/gulp-eslint.js +++ b/build/gulp-eslint.js @@ -15,7 +15,7 @@ const fancyLog = require('fancy-log'); * @returns {stream} gulp file stream */ function eslint(action) { - const linter = new ESLint(); + const linter = new ESLint({}); const formatter = linter.loadFormatter('compact'); const results = []; diff --git a/build/gulpfile.editor.js b/build/gulpfile.editor.js index 99ec8a2c51ad9..739c37fc677b5 100644 --- a/build/gulpfile.editor.js +++ b/build/gulpfile.editor.js @@ -411,7 +411,6 @@ function createTscCompileTask(watch) { /** @type {NodeJS.ReadWriteStream | undefined} */ let report; - // eslint-disable-next-line no-control-regex const magic = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g; // https://stackoverflow.com/questions/25245716/remove-all-ansi-colors-styles-from-strings child.stdout.on('data', data => { diff --git a/build/hygiene.js b/build/hygiene.js index 2edd9470c0b01..fe32fe33e12ce 100644 --- a/build/hygiene.js +++ b/build/hygiene.js @@ -62,6 +62,7 @@ function hygiene(some, linting = true) { } } // Please do not add symbols that resemble ASCII letters! + // eslint-disable-next-line no-misleading-character-class const m = /([^\t\n\r\x20-\x7E⊃⊇✔︎✓🎯⚠️🛑🔴🚗🚙🚕🎉✨❗⇧⌥⌘×÷¦⋯…↑↓→→←↔⟷·•●◆▼⟪⟫┌└├⏎↩√φ]+)/g.exec(line); if (m) { console.error( diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000000000..53a377bbde79d --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,1392 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// @ts-check +import fs from 'fs'; +import path from 'path'; +import tseslint from 'typescript-eslint'; +import { fileURLToPath } from 'url'; + +import stylisticTs from '@stylistic/eslint-plugin-ts'; +import pluginLocal from 'eslint-plugin-local'; +import pluginJsdoc from 'eslint-plugin-jsdoc'; + +import pluginHeader from 'eslint-plugin-header'; +pluginHeader.rules.header.meta.schema = false; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const ignores = fs.readFileSync(path.join(__dirname, '.eslint-ignore'), 'utf8') + .toString() + .split(/\r\n|\n/) + .filter(line => line && !line.startsWith('#')); + +export default tseslint.config( + // Global ignores + { + ignores, + }, + // All files (JS and TS) + { + languageOptions: { + parser: tseslint.parser, + }, + plugins: { + 'local': pluginLocal, + 'header': pluginHeader, + }, + rules: { + 'constructor-super': 'warn', + 'curly': 'warn', + 'eqeqeq': 'warn', + 'prefer-const': [ + 'warn', + { + 'destructuring': 'all' + } + ], + 'no-buffer-constructor': 'warn', + 'no-caller': 'warn', + 'no-case-declarations': 'warn', + 'no-debugger': 'warn', + 'no-duplicate-case': 'warn', + 'no-duplicate-imports': 'warn', + 'no-eval': 'warn', + 'no-async-promise-executor': 'warn', + 'no-extra-semi': 'warn', + 'no-new-wrappers': 'warn', + 'no-redeclare': 'off', + 'no-sparse-arrays': 'warn', + 'no-throw-literal': 'warn', + 'no-unsafe-finally': 'warn', + 'no-unused-labels': 'warn', + 'no-misleading-character-class': 'warn', + 'no-restricted-globals': [ + 'warn', + 'name', + 'length', + 'event', + 'closed', + 'external', + 'status', + 'origin', + 'orientation', + 'context' + ], // non-complete list of globals that are easy to access unintentionally + 'no-var': 'warn', + 'semi': 'off', + 'local/code-translation-remind': 'warn', + 'local/code-no-native-private': 'warn', + 'local/code-parameter-properties-must-have-explicit-accessibility': 'warn', + 'local/code-no-nls-in-standalone-editor': 'warn', + 'local/code-no-potentially-unsafe-disposables': 'warn', + 'local/code-no-dangerous-type-assertions': 'warn', + 'local/code-no-standalone-editor': 'warn', + 'local/code-no-unexternalized-strings': 'warn', + 'local/code-must-use-super-dispose': 'warn', + 'local/code-declare-service-brand': 'warn', + 'local/code-layering': [ + 'warn', + { + 'common': [], + 'node': [ + 'common' + ], + 'browser': [ + 'common' + ], + 'electron-sandbox': [ + 'common', + 'browser' + ], + 'electron-utility': [ + 'common', + 'node' + ], + 'electron-main': [ + 'common', + 'node', + 'electron-utility' + ] + } + ], + 'header/header': [ + 2, + 'block', + [ + '---------------------------------------------------------------------------------------------', + ' * Copyright (c) Microsoft Corporation. All rights reserved.', + ' * Licensed under the MIT License. See License.txt in the project root for license information.', + ' *--------------------------------------------------------------------------------------------' + ] + ] + }, + }, + // TS + { + files: [ + '**/*.ts', + ], + languageOptions: { + parser: tseslint.parser, + }, + plugins: { + '@stylistic/ts': stylisticTs, + '@typescript-eslint': tseslint.plugin, + 'local': pluginLocal, + 'jsdoc': pluginJsdoc, + }, + rules: { + '@stylistic/ts/semi': 'warn', + '@stylistic/ts/member-delimiter-style': 'warn', + 'local/code-no-unused-expressions': [ + 'warn', + { + 'allowTernary': true + } + ], + 'jsdoc/no-types': 'warn', + 'local/code-no-static-self-ref': 'warn' + } + }, + // vscode TS + { + files: [ + 'src/**/*.ts', + ], + languageOptions: { + parser: tseslint.parser, + }, + plugins: { + '@typescript-eslint': tseslint.plugin, + }, + rules: { + '@typescript-eslint/naming-convention': [ + 'warn', + { + 'selector': 'class', + 'format': [ + 'PascalCase' + ] + } + ] + } + }, + // Tests + { + files: [ + '**/*.test.ts' + ], + languageOptions: { + parser: tseslint.parser, + }, + plugins: { + 'local': pluginLocal, + }, + rules: { + 'local/code-must-use-super-dispose': 'off', + 'local/code-no-test-only': 'error', + 'local/code-no-test-async-suite': 'warn', + 'local/code-no-unexternalized-strings': 'off', + 'local/code-must-use-result': [ + 'warn', + [ + { + 'message': 'Expression must be awaited', + 'functions': [ + 'assertSnapshot', + 'assertHeap' + ] + } + ] + ] + } + }, + // vscode tests specific rules + { + files: [ + 'src/vs/**/*.test.ts' + ], + languageOptions: { + parser: tseslint.parser, + }, + plugins: { + 'local': pluginLocal, + }, + rules: { + 'local/code-ensure-no-disposables-leak-in-test': [ + 'warn', + { + // Files should (only) be removed from the list they adopt the leak detector + 'exclude': [ + 'src/vs/editor/contrib/codeAction/test/browser/codeActionModel.test.ts', + 'src/vs/platform/configuration/test/common/configuration.test.ts', + 'src/vs/platform/opener/test/common/opener.test.ts', + 'src/vs/platform/registry/test/common/platform.test.ts', + 'src/vs/platform/workspace/test/common/workspace.test.ts', + 'src/vs/platform/workspaces/test/electron-main/workspaces.test.ts', + 'src/vs/workbench/api/test/browser/mainThreadConfiguration.test.ts', + 'src/vs/workbench/api/test/node/extHostTunnelService.test.ts', + 'src/vs/workbench/contrib/bulkEdit/test/browser/bulkCellEdits.test.ts', + 'src/vs/workbench/contrib/chat/test/common/chatWordCounter.test.ts', + 'src/vs/workbench/contrib/editSessions/test/browser/editSessions.test.ts', + 'src/vs/workbench/contrib/extensions/test/common/extensionQuery.test.ts', + 'src/vs/workbench/contrib/notebook/test/browser/notebookExecutionService.test.ts', + 'src/vs/workbench/contrib/notebook/test/browser/notebookExecutionStateService.test.ts', + 'src/vs/workbench/contrib/tasks/test/common/problemMatcher.test.ts', + 'src/vs/workbench/contrib/tasks/test/common/taskConfiguration.test.ts', + 'src/vs/workbench/services/commands/test/common/commandService.test.ts', + 'src/vs/workbench/services/userActivity/test/browser/domActivityTracker.test.ts', + 'src/vs/workbench/test/browser/quickAccess.test.ts' + ] + } + ] + } + }, + // vscode API + { + files: [ + '**/vscode.d.ts', + '**/vscode.proposed.*.d.ts' + ], + languageOptions: { + parser: tseslint.parser, + }, + plugins: { + 'local': pluginLocal, + }, + rules: { + 'local/vscode-dts-create-func': 'warn', + 'local/vscode-dts-literal-or-types': 'warn', + 'local/vscode-dts-string-type-literals': 'warn', + 'local/vscode-dts-interface-naming': 'warn', + 'local/vscode-dts-cancellation': 'warn', + 'local/vscode-dts-use-thenable': 'warn', + 'local/vscode-dts-region-comments': 'warn', + 'local/vscode-dts-vscode-in-comments': 'warn', + 'local/vscode-dts-provider-naming': [ + 'warn', + { + 'allowed': [ + 'FileSystemProvider', + 'TreeDataProvider', + 'TestProvider', + 'CustomEditorProvider', + 'CustomReadonlyEditorProvider', + 'TerminalLinkProvider', + 'AuthenticationProvider', + 'NotebookContentProvider' + ] + } + ], + 'local/vscode-dts-event-naming': [ + 'warn', + { + 'allowed': [ + 'onCancellationRequested', + 'event' + ], + 'verbs': [ + 'accept', + 'change', + 'close', + 'collapse', + 'create', + 'delete', + 'discover', + 'dispose', + 'drop', + 'edit', + 'end', + 'execute', + 'expand', + 'grant', + 'hide', + 'invalidate', + 'open', + 'override', + 'perform', + 'receive', + 'register', + 'remove', + 'rename', + 'save', + 'send', + 'start', + 'terminate', + 'trigger', + 'unregister', + 'write' + ] + } + ] + } + }, + // vscode.d.ts + { + files: [ + '**/vscode.d.ts' + ], + languageOptions: { + parser: tseslint.parser, + }, + rules: { + 'jsdoc/tag-lines': 'off', + 'jsdoc/valid-types': 'off', + 'jsdoc/no-multi-asterisks': [ + 'warn', + { + 'allowWhitespace': true + } + ], + 'jsdoc/require-jsdoc': [ + 'warn', + { + 'enableFixer': false, + 'contexts': [ + 'TSInterfaceDeclaration', + 'TSPropertySignature', + 'TSMethodSignature', + 'TSDeclareFunction', + 'ClassDeclaration', + 'MethodDefinition', + 'PropertyDeclaration', + 'TSEnumDeclaration', + 'TSEnumMember', + 'ExportNamedDeclaration' + ] + } + ], + 'jsdoc/check-param-names': [ + 'warn', + { + 'enableFixer': false, + 'checkDestructured': false + } + ], + 'jsdoc/require-returns': 'warn' + } + }, + { + files: [ + 'src/**/{common,browser}/**/*.ts' + ], + languageOptions: { + parser: tseslint.parser, + }, + plugins: { + 'local': pluginLocal, + }, + rules: { + 'local/code-amd-node-module': 'warn' + } + }, + { + files: [ + 'src/**/{browser,electron-sandbox}/**/*.ts' + ], + languageOptions: { + parser: tseslint.parser, + }, + plugins: { + 'local': pluginLocal, + }, + rules: { + 'local/code-no-global-document-listener': 'warn', + 'no-restricted-syntax': [ + 'warn', + { + 'selector': `BinaryExpression[operator='instanceof'][right.name='MouseEvent']`, + 'message': 'Use DOM.isMouseEvent() to support multi-window scenarios.' + }, + { + 'selector': `BinaryExpression[operator='instanceof'][right.name=/^HTML\\w+/]`, + 'message': 'Use DOM.isHTMLElement() and related methods to support multi-window scenarios.' + }, + { + 'selector': `BinaryExpression[operator='instanceof'][right.name=/^SVG\\w+/]`, + 'message': 'Use DOM.isSVGElement() and related methods to support multi-window scenarios.' + }, + { + 'selector': `BinaryExpression[operator='instanceof'][right.name='KeyboardEvent']`, + 'message': 'Use DOM.isKeyboardEvent() to support multi-window scenarios.' + }, + { + 'selector': `BinaryExpression[operator='instanceof'][right.name='PointerEvent']`, + 'message': 'Use DOM.isPointerEvent() to support multi-window scenarios.' + }, + { + 'selector': `BinaryExpression[operator='instanceof'][right.name='DragEvent']`, + 'message': 'Use DOM.isDragEvent() to support multi-window scenarios.' + }, + { + 'selector': `MemberExpression[object.name='document'][property.name='activeElement']`, + 'message': 'Use .document.activeElement to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'selector': `MemberExpression[object.name='document'][property.name='contains']`, + 'message': 'Use .document.contains to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'selector': `MemberExpression[object.name='document'][property.name='styleSheets']`, + 'message': 'Use .document.styleSheets to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'selector': `MemberExpression[object.name='document'][property.name='fullscreenElement']`, + 'message': 'Use .document.fullscreenElement to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'selector': `MemberExpression[object.name='document'][property.name='body']`, + 'message': 'Use .document.body to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'selector': `MemberExpression[object.name='document'][property.name='addEventListener']`, + 'message': 'Use .document.addEventListener to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'selector': `MemberExpression[object.name='document'][property.name='removeEventListener']`, + 'message': 'Use .document.removeEventListener to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'selector': `MemberExpression[object.name='document'][property.name='hasFocus']`, + 'message': 'Use .document.hasFocus to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'selector': `MemberExpression[object.name='document'][property.name='head']`, + 'message': 'Use .document.head to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'selector': `MemberExpression[object.name='document'][property.name='exitFullscreen']`, + 'message': 'Use .document.exitFullscreen to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'selector': `MemberExpression[object.name='document'][property.name='getElementById']`, + 'message': 'Use .document.getElementById to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'selector': `MemberExpression[object.name='document'][property.name='getElementsByClassName']`, + 'message': 'Use .document.getElementsByClassName to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'selector': `MemberExpression[object.name='document'][property.name='getElementsByName']`, + 'message': 'Use .document.getElementsByName to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'selector': `MemberExpression[object.name='document'][property.name='getElementsByTagName']`, + 'message': 'Use .document.getElementsByTagName to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'selector': `MemberExpression[object.name='document'][property.name='getElementsByTagNameNS']`, + 'message': 'Use .document.getElementsByTagNameNS to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'selector': `MemberExpression[object.name='document'][property.name='getSelection']`, + 'message': 'Use .document.getSelection to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'selector': `MemberExpression[object.name='document'][property.name='open']`, + 'message': 'Use .document.open to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'selector': `MemberExpression[object.name='document'][property.name='close']`, + 'message': 'Use .document.close to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'selector': `MemberExpression[object.name='document'][property.name='documentElement']`, + 'message': 'Use .document.documentElement to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'selector': `MemberExpression[object.name='document'][property.name='visibilityState']`, + 'message': 'Use .document.visibilityState to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'selector': `MemberExpression[object.name='document'][property.name='querySelector']`, + 'message': 'Use .document.querySelector to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'selector': `MemberExpression[object.name='document'][property.name='querySelectorAll']`, + 'message': 'Use .document.querySelectorAll to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'selector': `MemberExpression[object.name='document'][property.name='elementFromPoint']`, + 'message': 'Use .document.elementFromPoint to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'selector': `MemberExpression[object.name='document'][property.name='elementsFromPoint']`, + 'message': 'Use .document.elementsFromPoint to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'selector': `MemberExpression[object.name='document'][property.name='onkeydown']`, + 'message': 'Use .document.onkeydown to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'selector': `MemberExpression[object.name='document'][property.name='onkeyup']`, + 'message': 'Use .document.onkeyup to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'selector': `MemberExpression[object.name='document'][property.name='onmousedown']`, + 'message': 'Use .document.onmousedown to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'selector': `MemberExpression[object.name='document'][property.name='onmouseup']`, + 'message': 'Use .document.onmouseup to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'selector': `MemberExpression[object.name='document'][property.name='execCommand']`, + 'message': 'Use .document.execCommand to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + } + ], + 'no-restricted-globals': [ + 'warn', + 'name', + 'length', + 'event', + 'closed', + 'external', + 'status', + 'origin', + 'orientation', + 'context', + { + 'name': 'setInterval', + 'message': 'Use .setInterval to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'name': 'clearInterval', + 'message': 'Use .clearInterval to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'name': 'requestAnimationFrame', + 'message': 'Use .requestAnimationFrame to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'name': 'cancelAnimationFrame', + 'message': 'Use .cancelAnimationFrame to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'name': 'requestIdleCallback', + 'message': 'Use .requestIdleCallback to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'name': 'cancelIdleCallback', + 'message': 'Use .cancelIdleCallback to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'name': 'window', + 'message': 'Use to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'name': 'addEventListener', + 'message': 'Use .addEventListener to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'name': 'removeEventListener', + 'message': 'Use .removeEventListener to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'name': 'getComputedStyle', + 'message': 'Use .getComputedStyle to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'name': 'focus', + 'message': 'Use .focus to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'name': 'blur', + 'message': 'Use .blur to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'name': 'close', + 'message': 'Use .close to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'name': 'dispatchEvent', + 'message': 'Use .dispatchEvent to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'name': 'getSelection', + 'message': 'Use .getSelection to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'name': 'matchMedia', + 'message': 'Use .matchMedia to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'name': 'open', + 'message': 'Use .open to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'name': 'parent', + 'message': 'Use .parent to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'name': 'postMessage', + 'message': 'Use .postMessage to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'name': 'devicePixelRatio', + 'message': 'Use .devicePixelRatio to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'name': 'frames', + 'message': 'Use .frames to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'name': 'frameElement', + 'message': 'Use .frameElement to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'name': 'innerHeight', + 'message': 'Use .innerHeight to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'name': 'innerWidth', + 'message': 'Use .innerWidth to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'name': 'outerHeight', + 'message': 'Use .outerHeight to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'name': 'outerWidth', + 'message': 'Use .outerWidth to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'name': 'opener', + 'message': 'Use .opener to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'name': 'origin', + 'message': 'Use .origin to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'name': 'screen', + 'message': 'Use .screen to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'name': 'screenLeft', + 'message': 'Use .screenLeft to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'name': 'screenTop', + 'message': 'Use .screenTop to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'name': 'screenX', + 'message': 'Use .screenX to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'name': 'screenY', + 'message': 'Use .screenY to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'name': 'scrollX', + 'message': 'Use .scrollX to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'name': 'scrollY', + 'message': 'Use .scrollY to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'name': 'top', + 'message': 'Use .top to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + }, + { + 'name': 'visualViewport', + 'message': 'Use .visualViewport to support multi-window scenarios. Resolve targetWindow with DOM.getWindow(element) or DOM.getActiveWindow() or use the predefined mainWindow constant.' + } + ] + } + }, + { + files: [ + 'src/**/electron-utility/**/*.ts' + ], + languageOptions: { + parser: tseslint.parser, + }, + rules: { + 'no-restricted-imports': [ + 'warn', + { + 'paths': [ + { + 'name': 'electron', + 'allowImportNames': [ + 'net', + 'system-preferences', + ], + 'message': 'Only net and system-preferences are allowed to be imported from electron' + } + ] + } + ] + } + }, + { + files: [ + 'src/**/*.ts' + ], + languageOptions: { + parser: tseslint.parser, + }, + plugins: { + 'local': pluginLocal, + }, + rules: { + 'local/code-import-patterns': [ + 'warn', + { + // imports that are allowed in all files of layers: + // - browser + // - electron-sandbox + 'when': 'hasBrowser', + 'allow': [] + }, + { + // imports that are allowed in all files of layers: + // - node + // - electron-utility + // - electron-main + 'when': 'hasNode', + 'allow': [ + '@parcel/watcher', + '@vscode/sqlite3', + '@vscode/vscode-languagedetection', + '@vscode/ripgrep', + '@vscode/iconv-lite-umd', + '@vscode/policy-watcher', + '@vscode/proxy-agent', + '@vscode/spdlog', + '@vscode/windows-process-tree', + 'assert', + 'child_process', + 'console', + 'cookie', + 'crypto', + 'dns', + 'events', + 'fs', + 'fs/promises', + 'http', + 'https', + 'minimist', + 'node:module', + 'native-keymap', + 'native-watchdog', + 'net', + 'node-pty', + 'os', + 'path', + 'perf_hooks', + 'readline', + 'stream', + 'string_decoder', + 'tas-client-umd', + 'tls', + 'url', + 'util', + 'v8-inspect-profiler', + 'vscode-regexpp', + 'vscode-textmate', + 'worker_threads', + '@xterm/addon-clipboard', + '@xterm/addon-image', + '@xterm/addon-search', + '@xterm/addon-serialize', + '@xterm/addon-unicode11', + '@xterm/addon-webgl', + '@xterm/headless', + '@xterm/xterm', + 'yauzl', + 'yazl', + 'zlib' + ] + }, + { + // imports that are allowed in all files of layers: + // - electron-utility + // - electron-main + 'when': 'hasElectron', + 'allow': [ + 'electron' + ] + }, + { + // imports that are allowed in all /test/ files + 'when': 'test', + 'allow': [ + 'assert', + 'sinon', + 'sinon-test' + ] + }, + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + // !!! Do not relax these rules !!! + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + // + // A path ending in /~ has a special meaning. It indicates a template position + // which will be substituted with one or more layers. + // + // When /~ is used in the target, the rule will be expanded to 14 distinct rules. + // e.g. 'src/vs/base/~' will be expanded to: + // - src/vs/base/common + // - src/vs/base/worker + // - src/vs/base/browser + // - src/vs/base/electron-sandbox + // - src/vs/base/node + // - src/vs/base/electron-main + // - src/vs/base/test/common + // - src/vs/base/test/worker + // - src/vs/base/test/browser + // - src/vs/base/test/electron-sandbox + // - src/vs/base/test/node + // - src/vs/base/test/electron-main + // + // When /~ is used in the restrictions, it will be replaced with the correct + // layers that can be used e.g. 'src/vs/base/electron-sandbox' will be able + // to import '{common,browser,electron-sanbox}', etc. + // + // It is possible to use /~ in the restrictions property even without using it in + // the target property by adding a layer property. + { + 'target': 'src/vs/base/~', + 'restrictions': [ + 'vs/base/~' + ] + }, + { + 'target': 'src/vs/base/parts/*/~', + 'restrictions': [ + 'vs/base/~', + 'vs/base/parts/*/~' + ] + }, + { + 'target': 'src/vs/platform/*/~', + 'restrictions': [ + 'vs/base/~', + 'vs/base/parts/*/~', + 'vs/platform/*/~', + 'tas-client-umd', // node module allowed even in /common/ + '@microsoft/1ds-core-js', // node module allowed even in /common/ + '@microsoft/1ds-post-js', // node module allowed even in /common/ + '@xterm/headless' // node module allowed even in /common/ + ] + }, + { + 'target': 'src/vs/editor/~', + 'restrictions': [ + 'vs/base/~', + 'vs/base/parts/*/~', + 'vs/platform/*/~', + 'vs/editor/~', + '@vscode/tree-sitter-wasm' // node module allowed even in /common/ + ] + }, + { + 'target': 'src/vs/editor/contrib/*/~', + 'restrictions': [ + 'vs/base/~', + 'vs/base/parts/*/~', + 'vs/platform/*/~', + 'vs/editor/~', + 'vs/editor/contrib/*/~' + ] + }, + { + 'target': 'src/vs/editor/standalone/~', + 'restrictions': [ + 'vs/base/~', + 'vs/base/parts/*/~', + 'vs/platform/*/~', + 'vs/editor/~', + 'vs/editor/contrib/*/~', + 'vs/editor/standalone/~', + '@vscode/tree-sitter-wasm' // type import + ] + }, + { + 'target': 'src/vs/editor/editor.all.ts', + 'layer': 'browser', + 'restrictions': [ + 'vs/base/~', + 'vs/base/parts/*/~', + 'vs/platform/*/~', + 'vs/editor/~', + 'vs/editor/contrib/*/~' + ] + }, + { + 'target': 'src/vs/editor/editor.worker.ts', + 'layer': 'worker', + 'restrictions': [ + 'vs/base/~', + 'vs/base/parts/*/~', + 'vs/platform/*/~', + 'vs/editor/~' + ] + }, + { + 'target': 'src/vs/editor/{editor.api.ts,editor.main.ts}', + 'layer': 'browser', + 'restrictions': [ + 'vs/base/~', + 'vs/base/parts/*/~', + 'vs/editor/~', + 'vs/editor/contrib/*/~', + 'vs/editor/standalone/~', + 'vs/editor/*' + ] + }, + { + 'target': 'src/vs/workbench/~', + 'restrictions': [ + 'vs/base/~', + 'vs/base/parts/*/~', + 'vs/platform/*/~', + 'vs/editor/~', + 'vs/editor/contrib/*/~', + 'vs/workbench/~', + 'vs/workbench/services/*/~', + 'assert', + { + 'when': 'test', + 'pattern': 'vs/workbench/contrib/*/~' + } // TODO@layers + ] + }, + { + 'target': 'src/vs/workbench/api/~', + 'restrictions': [ + 'vscode', + 'vs/base/~', + 'vs/base/parts/*/~', + 'vs/platform/*/~', + 'vs/editor/~', + 'vs/editor/contrib/*/~', + 'vs/workbench/api/~', + 'vs/workbench/~', + 'vs/workbench/services/*/~', + 'vs/workbench/contrib/*/~', + 'vs/workbench/contrib/terminalContrib/*/~' + ] + }, + { + 'target': 'src/vs/workbench/services/*/~', + 'restrictions': [ + 'vs/base/~', + 'vs/base/parts/*/~', + 'vs/platform/*/~', + 'vs/editor/~', + 'vs/editor/contrib/*/~', + 'vs/workbench/~', + 'vs/workbench/services/*/~', + { + 'when': 'test', + 'pattern': 'vs/workbench/contrib/*/~' + }, // TODO@layers + 'tas-client-umd', // node module allowed even in /common/ + 'vscode-textmate', // node module allowed even in /common/ + '@vscode/vscode-languagedetection', // node module allowed even in /common/ + '@vscode/tree-sitter-wasm', // type import + { + 'when': 'hasBrowser', + 'pattern': '@xterm/xterm' + } // node module allowed even in /browser/ + ] + }, + { + 'target': 'src/vs/workbench/contrib/*/~', + 'restrictions': [ + 'vs/base/~', + 'vs/base/parts/*/~', + 'vs/platform/*/~', + 'vs/editor/~', + 'vs/editor/contrib/*/~', + 'vs/workbench/~', + 'vs/workbench/services/*/~', + 'vs/workbench/contrib/*/~', + 'vs/workbench/contrib/terminal/terminalContribChatExports*', + 'vs/workbench/contrib/terminal/terminalContribExports*', + 'vscode-notebook-renderer', // Type only import + '@vscode/tree-sitter-wasm', // type import + { + 'when': 'hasBrowser', + 'pattern': '@xterm/xterm' + }, // node module allowed even in /browser/ + { + 'when': 'hasBrowser', + 'pattern': '@xterm/addon-*' + }, // node module allowed even in /browser/ + { + 'when': 'hasBrowser', + 'pattern': 'vscode-textmate' + } // node module allowed even in /browser/ + ] + }, + { + 'target': 'src/vs/workbench/contrib/terminalContrib/*/~', + 'restrictions': [ + 'vs/base/~', + 'vs/base/parts/*/~', + 'vs/platform/*/~', + 'vs/editor/~', + 'vs/editor/contrib/*/~', + 'vs/workbench/~', + 'vs/workbench/services/*/~', + 'vs/workbench/contrib/*/~', + // Only allow terminalContrib to import from itself, this works because + // terminalContrib is one extra folder deep + 'vs/workbench/contrib/terminalContrib/*/~', + 'vscode-notebook-renderer', // Type only import + { + 'when': 'hasBrowser', + 'pattern': '@xterm/xterm' + }, // node module allowed even in /browser/ + { + 'when': 'hasBrowser', + 'pattern': '@xterm/addon-*' + }, // node module allowed even in /browser/ + { + 'when': 'hasBrowser', + 'pattern': 'vscode-textmate' + }, // node module allowed even in /browser/ + '@xterm/headless' // node module allowed even in /common/ and /browser/ + ] + }, + { + 'target': 'src/vs/code/~', + 'restrictions': [ + 'vs/base/~', + 'vs/base/parts/*/~', + 'vs/platform/*/~', + 'vs/editor/~', + 'vs/editor/contrib/*/~', + 'vs/code/~', + { + 'when': 'hasBrowser', + 'pattern': 'vs/workbench/workbench.web.main.js' + }, + { + 'when': 'hasBrowser', + 'pattern': 'vs/workbench/workbench.web.main.internal.js' + }, + { + 'when': 'hasBrowser', + 'pattern': 'vs/workbench/~' + }, + { + 'when': 'hasBrowser', + 'pattern': 'vs/workbench/services/*/~' + } + ] + }, + { + 'target': 'src/vs/server/~', + 'restrictions': [ + 'vs/base/~', + 'vs/base/parts/*/~', + 'vs/platform/*/~', + 'vs/workbench/~', + 'vs/workbench/api/~', + 'vs/workbench/services/*/~', + 'vs/workbench/contrib/*/~', + 'vs/server/~' + ] + }, + { + 'target': 'src/vs/workbench/contrib/terminal/terminal.all.ts', + 'layer': 'browser', + 'restrictions': [ + 'vs/workbench/contrib/**' + ] + }, + { + 'target': 'src/vs/workbench/contrib/terminal/terminalContribChatExports.ts', + 'layer': 'browser', + 'restrictions': [ + 'vs/workbench/contrib/terminalContrib/*/~' + ] + }, + { + 'target': 'src/vs/workbench/contrib/terminal/terminalContribExports.ts', + 'layer': 'browser', + 'restrictions': [ + 'vs/platform/*/~', + 'vs/workbench/contrib/terminalContrib/*/~' + ] + }, + { + 'target': 'src/vs/workbench/workbench.common.main.ts', + 'layer': 'browser', + 'restrictions': [ + 'vs/base/~', + 'vs/base/parts/*/~', + 'vs/platform/*/~', + 'vs/editor/~', + 'vs/editor/contrib/*/~', + 'vs/editor/editor.all.js', + 'vs/workbench/~', + 'vs/workbench/api/~', + 'vs/workbench/services/*/~', + 'vs/workbench/contrib/*/~', + 'vs/workbench/contrib/terminal/terminal.all.js' + ] + }, + { + 'target': 'src/vs/workbench/workbench.web.main.ts', + 'layer': 'browser', + 'restrictions': [ + 'vs/base/~', + 'vs/base/parts/*/~', + 'vs/platform/*/~', + 'vs/editor/~', + 'vs/editor/contrib/*/~', + 'vs/editor/editor.all.js', + 'vs/workbench/~', + 'vs/workbench/api/~', + 'vs/workbench/services/*/~', + 'vs/workbench/contrib/*/~', + 'vs/workbench/workbench.common.main.js' + ] + }, + { + 'target': 'src/vs/workbench/workbench.web.main.internal.ts', + 'layer': 'browser', + 'restrictions': [ + 'vs/base/~', + 'vs/base/parts/*/~', + 'vs/platform/*/~', + 'vs/editor/~', + 'vs/editor/contrib/*/~', + 'vs/editor/editor.all.js', + 'vs/workbench/~', + 'vs/workbench/api/~', + 'vs/workbench/services/*/~', + 'vs/workbench/contrib/*/~', + 'vs/workbench/workbench.common.main.js' + ] + }, + { + 'target': 'src/vs/workbench/workbench.desktop.main.ts', + 'layer': 'electron-sandbox', + 'restrictions': [ + 'vs/base/*/~', + 'vs/base/parts/*/~', + 'vs/platform/*/~', + 'vs/editor/~', + 'vs/editor/contrib/*/~', + 'vs/editor/editor.all.js', + 'vs/workbench/~', + 'vs/workbench/api/~', + 'vs/workbench/services/*/~', + 'vs/workbench/contrib/*/~', + 'vs/workbench/workbench.common.main.js' + ] + }, + { + 'target': 'src/vs/amdX.ts', + 'restrictions': [ + 'vs/base/common/*' + ] + }, + { + 'target': 'src/vs/{loader.d.ts,monaco.d.ts,nls.ts,nls.messages.ts}', + 'restrictions': [] + }, + { + 'target': 'src/vscode-dts/**', + 'restrictions': [] + }, + { + 'target': 'src/bootstrap-window.ts', + 'restrictions': [] + }, + { + 'target': 'src/vs/nls.ts', + 'restrictions': [ + 'vs/*' + ] + }, + { + 'target': 'src/{bootstrap-cli.ts,bootstrap-esm.ts,bootstrap-fork.ts,bootstrap-import.ts,bootstrap-meta.ts,bootstrap-node.ts,bootstrap-server.ts,cli.ts,main.ts,server-cli.ts,server-main.ts}', + 'restrictions': [ + 'vs/**/common/*', + 'vs/**/node/*', + 'vs/nls.js', + 'src/*.js', + '*' // node.js + ] + } + ] + } + }, + { + files: [ + 'test/**/*.ts' + ], + languageOptions: { + parser: tseslint.parser, + }, + plugins: { + 'local': pluginLocal, + }, + rules: { + 'local/code-import-patterns': [ + 'warn', + { + 'target': 'test/smoke/**', + 'restrictions': [ + 'test/automation', + 'test/smoke/**', + '@vscode/*', + '@parcel/*', + '@playwright/*', + '*' // node modules + ] + }, + { + 'target': 'test/automation/**', + 'restrictions': [ + 'test/automation/**', + '@vscode/*', + '@parcel/*', + 'playwright-core/**', + '@playwright/*', + '*' // node modules + ] + }, + { + 'target': 'test/integration/**', + 'restrictions': [ + 'test/integration/**', + '@vscode/*', + '@parcel/*', + '@playwright/*', + '*' // node modules + ] + }, + { + 'target': 'test/monaco/**', + 'restrictions': [ + 'test/monaco/**', + '@vscode/*', + '@parcel/*', + '@playwright/*', + '*' // node modules + ] + } + ] + } + }, + { + files: [ + 'src/vs/workbench/contrib/notebook/browser/view/renderers/*.ts' + ], + languageOptions: { + parser: tseslint.parser, + }, + plugins: { + 'local': pluginLocal, + }, + rules: { + 'local/code-no-runtime-import': [ + 'error', + { + 'src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts': [ + '**/*' + ] + } + ], + 'local/code-limited-top-functions': [ + 'error', + { + 'src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts': [ + 'webviewPreloads', + 'preloadsScriptStr' + ] + } + ] + } + }, + // Terminal + { + files: [ + 'src/vs/workbench/contrib/terminal/**/*.ts', + 'src/vs/workbench/contrib/terminalContrib/**/*.ts', + ], + languageOptions: { + parser: tseslint.parser, + }, + rules: { + '@typescript-eslint/naming-convention': [ + 'warn', + // variableLike + { 'selector': 'variable', 'format': ['camelCase', 'UPPER_CASE', 'PascalCase'] }, + { 'selector': 'variable', 'filter': '^I.+Service$', 'format': ['PascalCase'], 'prefix': ['I'] }, + // memberLike + { 'selector': 'memberLike', 'modifiers': ['private'], 'format': ['camelCase'], 'leadingUnderscore': 'require' }, + { 'selector': 'memberLike', 'modifiers': ['protected'], 'format': ['camelCase'], 'leadingUnderscore': 'require' }, + { 'selector': 'enumMember', 'format': ['PascalCase'] }, + // memberLike - Allow enum-like objects to use UPPER_CASE + { 'selector': 'method', 'modifiers': ['public'], 'format': ['camelCase', 'UPPER_CASE'] }, + // typeLike + { 'selector': 'typeLike', 'format': ['PascalCase'] }, + { 'selector': 'interface', 'format': ['PascalCase'] } + ], + 'comma-dangle': ['warn', 'only-multiline'] + } + }, + // markdown-language-features + { + files: [ + 'extensions/markdown-language-features/**/*.ts', + ], + languageOptions: { + parser: tseslint.parser, + }, + plugins: { + '@typescript-eslint': tseslint.plugin, + }, + rules: { + '@typescript-eslint/naming-convention': [ + 'warn', + { + 'selector': 'default', + 'modifiers': ['private'], + 'format': null, + 'leadingUnderscore': 'require' + }, + { + 'selector': 'default', + 'modifiers': ['public'], + 'format': null, + 'leadingUnderscore': 'forbid' + } + ] + } + }, + // typescript-language-features + { + files: [ + 'extensions/typescript-language-features/**/*.ts', + ], + languageOptions: { + parser: tseslint.parser, + parserOptions: { + project: [ + 'extensions/typescript-language-features/tsconfig.json', + 'extensions/typescript-language-features/web/tsconfig.json' + ], + } + }, + plugins: { + '@typescript-eslint': tseslint.plugin, + }, + rules: { + '@typescript-eslint/prefer-optional-chain': 'warn', + '@typescript-eslint/prefer-readonly': 'warn', + } + } +); diff --git a/extensions/markdown-language-features/.eslintignore b/extensions/markdown-language-features/.eslintignore deleted file mode 100644 index ab39cbce5a37e..0000000000000 --- a/extensions/markdown-language-features/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -server/ diff --git a/extensions/markdown-language-features/.eslintrc.json b/extensions/markdown-language-features/.eslintrc.json deleted file mode 100644 index 51ba9a41d8475..0000000000000 --- a/extensions/markdown-language-features/.eslintrc.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "rules": { - "@typescript-eslint/naming-convention": [ - "warn", - { - "selector": "default", - "modifiers": ["private"], - "format": null, - "leadingUnderscore": "require" - }, - { - "selector": "default", - "modifiers": ["public"], - "format": null, - "leadingUnderscore": "forbid" - } - ] - } -} diff --git a/extensions/package-lock.json b/extensions/package-lock.json index 82f695dc38f5d..aa07b93e52e89 100644 --- a/extensions/package-lock.json +++ b/extensions/package-lock.json @@ -10,7 +10,7 @@ "hasInstallScript": true, "license": "MIT", "dependencies": { - "typescript": "5.6.2" + "typescript": "5.6.3" }, "devDependencies": { "@parcel/watcher": "2.1.0", @@ -606,9 +606,9 @@ } }, "node_modules/typescript": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", - "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/extensions/package.json b/extensions/package.json index 7f3fad949be9d..a1a224947891b 100644 --- a/extensions/package.json +++ b/extensions/package.json @@ -4,7 +4,7 @@ "license": "MIT", "description": "Dependencies shared by all extensions", "dependencies": { - "typescript": "5.6.2" + "typescript": "5.6.3" }, "scripts": { "postinstall": "node ./postinstall.mjs" diff --git a/extensions/typescript-language-features/.eslintrc.js b/extensions/typescript-language-features/.eslintrc.js deleted file mode 100644 index e910c2f25102e..0000000000000 --- a/extensions/typescript-language-features/.eslintrc.js +++ /dev/null @@ -1,10 +0,0 @@ -module.exports = { - "parserOptions": { - "tsconfigRootDir": __dirname, - "project": "./tsconfig.json" - }, - "rules": { - "@typescript-eslint/prefer-optional-chain": "warn", - "@typescript-eslint/prefer-readonly": "warn" - } -}; diff --git a/extensions/typescript-language-features/src/languageFeatures/copilotRelated.ts b/extensions/typescript-language-features/src/languageFeatures/copilotRelated.ts new file mode 100644 index 0000000000000..f1ceac1a584a7 --- /dev/null +++ b/extensions/typescript-language-features/src/languageFeatures/copilotRelated.ts @@ -0,0 +1,86 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; +import { isSupportedLanguageMode } from '../configuration/languageIds'; +import { DocumentSelector } from '../configuration/documentSelector'; +import { API } from '../tsServer/api'; +import type * as Proto from '../tsServer/protocol/protocol'; +import { ITypeScriptServiceClient } from '../typescriptService'; +import { conditionalRegistration, requireMinVersion } from './util/dependentRegistration'; + +const minVersion = API.v570; + +export function register( + selector: DocumentSelector, + client: ITypeScriptServiceClient, +): vscode.Disposable { + return conditionalRegistration([ + requireMinVersion(client, minVersion), + ], () => { + const ext = vscode.extensions.getExtension('github.copilot'); + if (!ext) { + return new vscode.Disposable(() => { }); + } + const disposers: vscode.Disposable[] = []; + ext.activate().then(() => { + const relatedAPI = ext.exports as { + registerRelatedFilesProvider( + providerId: { extensionId: string; languageId: string }, + callback: ( + uri: vscode.Uri, + context: { flags: Record }, + cancellationToken: vscode.CancellationToken + ) => Promise<{ + entries: vscode.Uri[]; + traits?: Array<{ name: string; value: string; includeInPrompt?: boolean; promptTextOverride?: string }>; + }> + ): vscode.Disposable; + } | undefined; + if (relatedAPI?.registerRelatedFilesProvider) { + for (const syntax of selector.syntax) { + if (!syntax.language) { + continue; + } + const id = { + extensionId: 'vscode.typescript-language-features', + languageId: syntax.language + }; + disposers.push(relatedAPI.registerRelatedFilesProvider(id, async (uri, _context, token) => { + let document; + try { + document = await vscode.workspace.openTextDocument(uri); + } catch { + if (!vscode.window.activeTextEditor) { + vscode.window.showErrorMessage(vscode.l10n.t("Related files provider failed. No active text editor.")); + return { entries: [] }; + } + // something is REALLY wrong if you can't open the active text editor's document, so don't catch that + document = await vscode.workspace.openTextDocument(vscode.window.activeTextEditor.document.uri); + } + + if (!isSupportedLanguageMode(document)) { + vscode.window.showErrorMessage(vscode.l10n.t("Related files provider failed. Copilot requested file with unsupported language mode.")); + return { entries: [] }; + } + + const file = client.toOpenTsFilePath(document); + if (!file) { + return { entries: [] }; + } + // @ts-expect-error until ts5.7 + const response = await client.execute('copilotRelated', { file, }, token) as Proto.CopilotRelatedResponse; + if (response.type !== 'response' || !response.body) { + return { entries: [] }; + } + // @ts-expect-error until ts5.7 + return { entries: response.body.relatedFiles.map(f => client.toResource(f)), traits: [] }; + })); + } + } + }); + return vscode.Disposable.from(...disposers); + }); +} diff --git a/extensions/typescript-language-features/src/languageProvider.ts b/extensions/typescript-language-features/src/languageProvider.ts index 7b95591604bd0..09a4fe3ccc9c6 100644 --- a/extensions/typescript-language-features/src/languageProvider.ts +++ b/extensions/typescript-language-features/src/languageProvider.ts @@ -91,6 +91,7 @@ export default class LanguageProvider extends Disposable { import('./languageFeatures/sourceDefinition').then(provider => this._register(provider.register(this.client, this.commandManager))), import('./languageFeatures/tagClosing').then(provider => this._register(provider.register(selector, this.description, this.client))), import('./languageFeatures/typeDefinitions').then(provider => this._register(provider.register(selector, this.client))), + import('./languageFeatures/copilotRelated').then(provider => this._register(provider.register(selector, this.client))), ]); } diff --git a/extensions/typescript-language-features/src/typescriptService.ts b/extensions/typescript-language-features/src/typescriptService.ts index 90528ee47dc8c..33d89e1df8d5b 100644 --- a/extensions/typescript-language-features/src/typescriptService.ts +++ b/extensions/typescript-language-features/src/typescriptService.ts @@ -77,6 +77,8 @@ interface StandardTsServerRequests { 'getMoveToRefactoringFileSuggestions': [Proto.GetMoveToRefactoringFileSuggestionsRequestArgs, Proto.GetMoveToRefactoringFileSuggestions]; 'linkedEditingRange': [Proto.FileLocationRequestArgs, Proto.LinkedEditingRangeResponse]; 'mapCode': [Proto.MapCodeRequestArgs, Proto.MapCodeResponse]; + // @ts-expect-error until ts5.7 + 'copilotRelated': [Proto.FileRequestArgs, Proto.CopilotRelatedResponse]; 'getPasteEdits': [Proto.GetPasteEditsRequestArgs, Proto.GetPasteEditsResponse]; 'preparePasteEdits': [Proto.PreparePasteEditsRequestArgs, Proto.PreparePasteEditsResponse]; } diff --git a/extensions/typescript-language-features/src/utils/objects.ts b/extensions/typescript-language-features/src/utils/objects.ts index 88c5a435e1c88..a31467bd8d664 100644 --- a/extensions/typescript-language-features/src/utils/objects.ts +++ b/extensions/typescript-language-features/src/utils/objects.ts @@ -9,7 +9,6 @@ export function equals(one: any, other: any): boolean { if (one === other) { return true; } - // eslint-disable-next-line @typescript-eslint/prefer-optional-chain if (one === null || one === undefined || other === null || other === undefined) { return false; } diff --git a/extensions/typescript-language-features/web/.eslintrc.js b/extensions/typescript-language-features/web/.eslintrc.js deleted file mode 100644 index e910c2f25102e..0000000000000 --- a/extensions/typescript-language-features/web/.eslintrc.js +++ /dev/null @@ -1,10 +0,0 @@ -module.exports = { - "parserOptions": { - "tsconfigRootDir": __dirname, - "project": "./tsconfig.json" - }, - "rules": { - "@typescript-eslint/prefer-optional-chain": "warn", - "@typescript-eslint/prefer-readonly": "warn" - } -}; diff --git a/package-lock.json b/package-lock.json index e942c8fa8637f..401ea93ed10d0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "@microsoft/1ds-core-js": "^3.2.13", "@microsoft/1ds-post-js": "^3.2.13", "@parcel/watcher": "2.1.0", + "@types/semver": "^7.5.8", "@vscode/deviceid": "^0.1.1", "@vscode/iconv-lite-umd": "0.7.0", "@vscode/policy-watcher": "^1.1.8", @@ -54,9 +55,11 @@ }, "devDependencies": { "@playwright/test": "^1.46.1", + "@stylistic/eslint-plugin-ts": "^2.8.0", + "@swc/core": "1.3.62", "@types/cookie": "^0.3.3", "@types/debug": "^4.1.5", - "@types/eslint": "^8.56.10", + "@types/eslint": "^9.6.1", "@types/gulp-svgmin": "^1.2.1", "@types/http-proxy-agent": "^2.0.1", "@types/kerberos": "^1.1.2", @@ -73,9 +76,7 @@ "@types/winreg": "^1.2.30", "@types/yauzl": "^2.10.0", "@types/yazl": "^2.4.2", - "@typescript-eslint/eslint-plugin": "^6.21.0", - "@typescript-eslint/experimental-utils": "^5.57.0", - "@typescript-eslint/parser": "^6.21.0", + "@typescript-eslint/utils": "^8.8.0", "@vscode/gulp-electron": "^1.36.0", "@vscode/l10n-dev": "0.0.35", "@vscode/telemetry-extractor": "^1.10.2", @@ -83,7 +84,7 @@ "@vscode/test-electron": "^2.4.0", "@vscode/test-web": "^0.0.62", "@vscode/v8-heap-parser": "^0.1.0", - "@vscode/vscode-perf": "^0.0.14", + "@vscode/vscode-perf": "^0.0.19", "@webgpu/types": "^0.1.44", "ansi-colors": "^3.2.3", "asar": "^3.0.3", @@ -93,16 +94,20 @@ ======= "cookie": "^0.7.0", +======= + "cookie": "^0.7.2", +> "copy-webpack-plugin": "^11.0.0", "css-loader": "^6.9.1", "cssnano": "^6.0.3", "debounce": "^1.0.0", "deemon": "^1.8.0", "electron": "32.1.2", - "eslint": "8.36.0", + "eslint": "^9.11.1", + "eslint-formatter-compact": "^8.40.0", "eslint-plugin-header": "3.1.1", - "eslint-plugin-jsdoc": "^46.5.0", - "eslint-plugin-local": "^1.0.0", + "eslint-plugin-jsdoc": "^50.3.1", + "eslint-plugin-local": "^6.0.0", "event-stream": "3.3.4", "fancy-log": "^1.3.3", "file-loader": "^6.2.0", @@ -160,7 +165,8 @@ "ts-node": "^10.9.1", "tsec": "0.2.7", "tslib": "^2.6.3", - "typescript": "^5.7.0-dev.20240927", + "typescript": "^5.7.0-dev.20241007", + "typescript-eslint": "^8.8.0", "util": "^0.12.4", "webpack": "^5.94.0", "webpack-cli": "^5.1.4", @@ -1066,14 +1072,14 @@ } }, "node_modules/@es-joy/jsdoccomment": { - "version": "0.40.1", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.40.1.tgz", - "integrity": "sha512-YORCdZSusAlBrFpZ77pJjc5r1bQs5caPWtAu+WWmiSo+8XaUzseapVrfAtiRFbQWnrBxxLLEwF6f6ZG/UgCQCg==", + "version": "0.48.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.48.0.tgz", + "integrity": "sha512-G6QUWIcC+KvSwXNsJyDTHvqUdNoAVJPPgkc3+Uk4WBKqZvoXhlvazOgm9aL0HwihJLQf0l+tOE2UFzXBqCqgDw==", "dev": true, "dependencies": { - "comment-parser": "1.4.0", - "esquery": "^1.5.0", - "jsdoc-type-pratt-parser": "~4.0.0" + "comment-parser": "1.4.1", + "esquery": "^1.6.0", + "jsdoc-type-pratt-parser": "~4.1.0" }, "engines": { "node": ">=16" @@ -1103,16 +1109,39 @@ "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, + "node_modules/@eslint/config-array": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", + "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", + "dev": true, + "dependencies": { + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.6.0.tgz", + "integrity": "sha512-8I2Q8ykA4J0x0o7cg67FPVnehcqWTBehu/lmY+bolPFHGjh49YzGBMXTvpqVgEbBdvNCSxj6iFgiIyHzf03lzg==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", + "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", + "espree": "^10.0.1", + "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -1120,19 +1149,40 @@ "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/@eslint/js": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.36.0.tgz", - "integrity": "sha512-lxJ9R5ygVm8ZWgYdUweoq5ownDlJ4upvoWmO4eLxBYHdMo+vZ/Rx0EN6MbKWDJOSUGrqJy2Gt+Dyv/VKml0fjg==", + "version": "9.11.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.11.1.tgz", + "integrity": "sha512-/qu+TWz8WwPWc7/HcIJKi+c+MOm46GdVaSlTTQcaqaL53+GsoA6MxWp5PtTx48qbSP7ylM1Kn7nhvkugfJvRSA==", "dev": true, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", + "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.0.tgz", + "integrity": "sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig==", + "dev": true, + "dependencies": { + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@gulp-sourcemaps/identity-map": { @@ -1236,6 +1286,7 @@ "xtend": "~4.0.1" } }, + "node_modules/@gulpjs/messages": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@gulpjs/messages/-/messages-1.1.0.tgz", @@ -1272,6 +1323,7 @@ "node": ">=10.10.0" } }, +== "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -1285,12 +1337,18 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", - "dev": true + "node_modules/@humanwhocodes/retry": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", + "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, "node_modules/@isaacs/cliui": { "version": "8.0.2", @@ -1742,6 +1800,18 @@ "node": ">=14" } }, + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, "node_modules/@playwright/browser-chromium": { "version": "1.47.2", "resolved": "https://registry.npmjs.org/@playwright/browser-chromium/-/browser-chromium-1.47.2.tgz", @@ -1818,6 +1888,229 @@ "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", "dev": true }, + "node_modules/@stylistic/eslint-plugin-ts": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-ts/-/eslint-plugin-ts-2.8.0.tgz", + "integrity": "sha512-VukJqkRlC2psLKoIHJ+4R3ZxLJfWeizGGX+X5ZxunjXo4MbxRNtwu5UvXuerABg4s2RV6Z3LFTdm0WvI4+RAMQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/utils": "^8.4.0", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/@stylistic/eslint-plugin-ts/node_modules/eslint-visitor-keys": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz", + "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@swc/core": { + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.62.tgz", + "integrity": "sha512-J58hWY+/G8vOr4J6ZH9hLg0lMSijZtqIIf4HofZezGog/pVX6sJyBJ40dZ1ploFkDIlWTWvJyqtpesBKS73gkQ==", + "dev": true, + "hasInstallScript": true, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.3.62", + "@swc/core-darwin-x64": "1.3.62", + "@swc/core-linux-arm-gnueabihf": "1.3.62", + "@swc/core-linux-arm64-gnu": "1.3.62", + "@swc/core-linux-arm64-musl": "1.3.62", + "@swc/core-linux-x64-gnu": "1.3.62", + "@swc/core-linux-x64-musl": "1.3.62", + "@swc/core-win32-arm64-msvc": "1.3.62", + "@swc/core-win32-ia32-msvc": "1.3.62", + "@swc/core-win32-x64-msvc": "1.3.62" + }, + "peerDependencies": { + "@swc/helpers": "^0.5.0" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.62.tgz", + "integrity": "sha512-MmGilibITz68LEje6vJlKzc2gUUSgzvB3wGLSjEORikTNeM7P8jXVxE4A8fgZqDeudJUm9HVWrxCV+pHDSwXhA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-darwin-x64": { + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.62.tgz", + "integrity": "sha512-Xl93MMB3sCWVlYWuQIB+v6EQgzoiuQYK5tNt9lsHoIEVu2zLdkQjae+5FUHZb1VYqCXIiWcULFfVz0R4Sjb7JQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.62.tgz", + "integrity": "sha512-nJsp6O7kCtAjTTMcIjVB0g5y1JNiYAa5q630eiwrnaHUusEFoANDdORI3Z9vXeikMkng+6yIv9/V8Rb093xLjQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.62.tgz", + "integrity": "sha512-XGsV93vpUAopDt5y6vPwbK1Nc/MlL55L77bAZUPIiosWD1cWWPHNtNSpriE6+I+JiMHe0pqtfS/SSTk6ZkFQVw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.62.tgz", + "integrity": "sha512-ESUmJjSlTTkoBy9dMG49opcNn8BmviqStMhwyeD1G8XRnmRVCZZgoBOKdvCXmJhw8bQXDhZumeaTUB+OFUKVXg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.62.tgz", + "integrity": "sha512-wnHJkt3ZBrax3SFnUHDcncG6mrSg9ZZjMhQV9Mc3JL1x1s1Gy9rGZCoBNnV/BUZWTemxIBcQbANRSDut/WO+9A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.62.tgz", + "integrity": "sha512-9oRbuTC/VshB66Rgwi3pTq3sPxSTIb8k9L1vJjES+dDMKa29DAjPtWCXG/pyZ00ufpFZgkGEuAHH5uqUcr1JQg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.62.tgz", + "integrity": "sha512-zv14vlF2VRrxS061XkfzGjCYnOrEo5glKJjLK5PwUKysIoVrx/L8nAbFxjkX5cObdlyoqo+ekelyBPAO+4bS0w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.62.tgz", + "integrity": "sha512-8MC/PZQSsOP2iA/81tAfNRqMWyEqTS/8zKUI67vPuLvpx6NAjRn3E9qBv7iFqH79iqZNzqSMo3awnLrKZyFbcw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.62.tgz", + "integrity": "sha512-GJSmUJ95HKHZXAxiuPUmrcm/S3ivQvEzXhOZaIqYBIwUsm02vFZkClsV7eIKzWjso1t0+I/8MjrnUNaSWqh1rQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, "node_modules/@szmarczak/http-timer": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", @@ -1830,6 +2123,18 @@ "node": ">=10" } }, + "node_modules/@thisismanta/pessimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@thisismanta/pessimist/-/pessimist-1.2.0.tgz", + "integrity": "sha512-rm8/zjNMuO9hPYhEMavVIIxmvawJJB8mthvbVXd74XUW7V/SbgmtDBQjICbCWKjluvA+gh+cqi7dv85/jexknA==", + "dev": true, + "dependencies": { + "lodash": "^4.17.21" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/@tootallnate/once": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-3.0.0.tgz", @@ -1956,9 +2261,9 @@ } }, "node_modules/@types/eslint": { - "version": "8.56.12", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.12.tgz", - "integrity": "sha512-03ruubjWyOHlmljCVoxSuNDdmfZDzsrrz0P2LeJsOXr+ZwFQ+0yQIwNCwt/GYhV7Z31fgtXJTAEs+FYlEL851g==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", "dev": true, "dependencies": { "@types/estree": "*", @@ -2111,8 +2416,7 @@ "node_modules/@types/semver": { "version": "7.5.8", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", - "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", - "dev": true + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==" }, "node_modules/@types/sinon": { "version": "10.0.2", @@ -2216,261 +2520,30 @@ "@types/node": "*" } }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", - "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", - "dev": true, - "dependencies": { - "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/type-utils": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4", - "graphemer": "^1.4.0", - "ignore": "^5.2.4", - "natural-compare": "^1.4.0", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/experimental-utils": { - "version": "5.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.57.0.tgz", - "integrity": "sha512-0RnrwGQ7MmgtOSnzB/rSGYr2iXENi6L+CtPzX3g5ovo0HlruLukSEKcc4s+q0IEc+DLTDc7Edan0Y4WSQ/bFhw==", - "dev": true, - "dependencies": { - "@typescript-eslint/utils": "5.57.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/scope-manager": { - "version": "5.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.57.0.tgz", - "integrity": "sha512-NANBNOQvllPlizl9LatX8+MHi7bx7WGIWYjPHDmQe5Si/0YEYfxSljJpoTyTWFTgRy3X8gLYSE4xQ2U+aCozSw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.57.0", - "@typescript-eslint/visitor-keys": "5.57.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/types": { - "version": "5.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.57.0.tgz", - "integrity": "sha512-mxsod+aZRSyLT+jiqHw1KK6xrANm19/+VFALVFP5qa/aiJnlP38qpyaTd0fEKhWvQk6YeNZ5LGwI1pDpBRBhtQ==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.57.0.tgz", - "integrity": "sha512-LTzQ23TV82KpO8HPnWuxM2V7ieXW8O142I7hQTxWIHDcCEIjtkat6H96PFkYBQqGFLW/G/eVVOB9Z8rcvdY/Vw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.57.0", - "@typescript-eslint/visitor-keys": "5.57.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/utils": { - "version": "5.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.57.0.tgz", - "integrity": "sha512-ps/4WohXV7C+LTSgAL5CApxvxbMkl9B9AUZRtnEFonpIxZDIT7wC1xfvuJONMidrkB9scs4zhtRyIwHh4+18kw==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.57.0", - "@typescript-eslint/types": "5.57.0", - "@typescript-eslint/typescript-estree": "5.57.0", - "eslint-scope": "^5.1.1", - "semver": "^7.3.7" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.57.0.tgz", - "integrity": "sha512-ery2g3k0hv5BLiKpPuwYt9KBkAp2ugT6VvyShXdLOkax895EC55sP0Tx5L0fZaQueiK3fBLvHVvEl3jFS5ia+g==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.57.0", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", - "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", - "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", - "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.8.0.tgz", + "integrity": "sha512-EL8eaGC6gx3jDd8GwEFEV091210U97J0jeEHrAYvIYosmEGet4wJ+g0SYmLu+oRiAwbSA5AVrt6DxLHfdd+bUg==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" + "@typescript-eslint/types": "8.8.0", + "@typescript-eslint/visitor-keys": "8.8.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } } }, "node_modules/@typescript-eslint/types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", - "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.8.0.tgz", + "integrity": "sha512-QJwc50hRCgBd/k12sTykOJbESe1RrzmX6COk8Y525C9l7oweZ+1lw9JiU56im7Amm8swlz00DRIlxMYLizr2Vw==", "dev": true, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -2478,22 +2551,22 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", - "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.8.0.tgz", + "integrity": "sha512-ZaMJwc/0ckLz5DaAZ+pNLmHv8AMVGtfWxZe/x2JVEkD5LnmhWiQMMcYT7IY7gkdJuzJ9P14fRy28lUrlDSWYdw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", + "@typescript-eslint/types": "8.8.0", + "@typescript-eslint/visitor-keys": "8.8.0", "debug": "^4.3.4", - "globby": "^11.1.0", + "fast-glob": "^3.3.2", "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -2515,9 +2588,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -2530,41 +2603,38 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", - "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.8.0.tgz", + "integrity": "sha512-QE2MgfOTem00qrlPgyByaCHay9yb1+9BjnMFnSFkUKQfu7adBXDTnCAivURnuPPAG/qiB+kzKkZKmKfaMT0zVg==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "semver": "^7.5.4" + "@typescript-eslint/scope-manager": "8.8.0", + "@typescript-eslint/types": "8.8.0", + "@typescript-eslint/typescript-estree": "8.8.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^8.57.0 || ^9.0.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", - "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.8.0.tgz", + "integrity": "sha512-8mq51Lx6Hpmd7HnA2fcHQo3YgfX1qbccxQOgZcb4tvasu//zXRaA1j5ZRFeCw/VRAdFi4mRM9DnZw0Nu0Q2d1g==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.21.0", - "eslint-visitor-keys": "^3.4.1" + "@typescript-eslint/types": "8.8.0", + "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -3083,14 +3153,14 @@ } }, "node_modules/@vscode/vscode-perf": { - "version": "0.0.14", - "resolved": "https://registry.npmjs.org/@vscode/vscode-perf/-/vscode-perf-0.0.14.tgz", - "integrity": "sha512-mDJOIAVU3Ufj1FUX2/LZtLHobjl7zRA+oDKH3GSJYQ+RlfEvpFRoU1CRSwbE3u9fsKMX//uBDI4Q4B8+3s86uA==", + "version": "0.0.19", + "resolved": "https://registry.npmjs.org/@vscode/vscode-perf/-/vscode-perf-0.0.19.tgz", + "integrity": "sha512-E/I0S+71K3Jo4kiMYbeKM8mUG3K8cHlj5MFVfPYVAvlp7KuIZTM914E7osp+jx8XgMLN6fChxnFmntm1GtVrKA==", "dev": true, "dependencies": { "chalk": "^4.x", "commander": "^9.4.0", - "cookie": "^0.5.0", + "cookie": "^0.7.2", "js-base64": "^3.7.4", "node-fetch": "2.6.8", "playwright": "^1.29.2" @@ -3102,15 +3172,6 @@ "node": ">= 16" } }, - "node_modules/@vscode/vscode-perf/node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/@vscode/windows-ca-certs": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/@vscode/windows-ca-certs/-/windows-ca-certs-0.3.3.tgz", @@ -3765,6 +3826,7 @@ "node": ">=0.10.0" } }, + "node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", @@ -3772,6 +3834,20 @@ "dev": true, "engines": { "node": ">=8" +======= + "node_modules/array-sort": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-sort/-/array-sort-1.0.0.tgz", + "integrity": "sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==", + "dev": true, + "dependencies": { + "default-compare": "^1.0.0", + "get-value": "^2.0.6", + "kind-of": "^5.0.2" + }, + "engines": { + "node": ">=0.10.0" + } }, "node_modules/array-uniq": { @@ -4212,18 +4288,6 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, - "node_modules/builtin-modules": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", - "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", - "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -4777,9 +4841,9 @@ } }, "node_modules/comment-parser": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.0.tgz", - "integrity": "sha512-QLyTNiZ2KDOibvFPlZ6ZngVsZ/0gYnE6uTXi5aoDg8ed3AkJAz4sEje3Y8a29hQ1s6A99MZXe47fLAXQ1rTqaw==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", + "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", "dev": true, "engines": { "node": ">= 12.0.0" @@ -4896,6 +4960,7 @@ }, "node_modules/cookie": { + "version": "0.7.1", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", @@ -4904,6 +4969,11 @@ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.0.tgz", "integrity": "sha512-qCf+V4dtlNhSRXGAZatc1TasyFO6GjohcOul807YOb5ik3+kQSnb4d7iajeCL8QHaJ4uZEjCgiCJerKXwdRVlQ==", >> +======= + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "dev": true, "engines": { "node": ">= 0.6" @@ -5532,18 +5602,6 @@ "node": ">=8" } }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/dom-serializer": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", @@ -5874,9 +5932,9 @@ } }, "node_modules/es-module-lexer": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.0.tgz", - "integrity": "sha512-pqrTKmwEIgafsYZAGw9kszYzmagcE/n4dbgwGWLEXg7J4QFJVQRBld8j3Q3GNez79jzxZshq0bcT962QHOghjw==", + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", + "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", "dev": true }, "node_modules/es-to-primitive": { @@ -5981,60 +6039,74 @@ } }, "node_modules/eslint": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.36.0.tgz", - "integrity": "sha512-Y956lmS7vDqomxlaaQAHVmeb4tNMp2FWIvU/RnU5BD3IKMD/MJPr76xdyr68P8tV1iNMvN2mRK0yy3c+UjL+bw==", + "version": "9.11.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.11.1.tgz", + "integrity": "sha512-MobhYKIoAO1s1e4VUrgx1l1Sk2JBR/Gqjjgw8+mfgoLE2xwsHur4gdfTxyTgShrhvdVFTaJSgMiQBl1jv/AWxg==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.1", - "@eslint/js": "8.36.0", - "@humanwhocodes/config-array": "^0.11.8", + "@eslint-community/regexpp": "^4.11.0", + "@eslint/config-array": "^0.18.0", + "@eslint/core": "^0.6.0", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.11.1", + "@eslint/plugin-kit": "^0.2.0", "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.3.0", "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", - "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.5.0", - "esquery": "^1.4.2", + "eslint-scope": "^8.0.2", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.1.0", + "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", + "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", - "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", - "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", + "optionator": "^0.9.3", "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" }, "bin": { "eslint": "bin/eslint.js" }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-formatter-compact": { + "version": "8.40.0", + "resolved": "https://registry.npmjs.org/eslint-formatter-compact/-/eslint-formatter-compact-8.40.0.tgz", + "integrity": "sha512-cwGUs113TgmTQXecx5kfRjB7m0y2wkDLSadPTE2pK6M/wO4N8PjmUaoWOFNCP9MHgsiZwgqd5bZFnDCnszC56Q==", + "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-plugin-header": { @@ -6047,45 +6119,91 @@ } }, "node_modules/eslint-plugin-jsdoc": { - "version": "46.5.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.5.0.tgz", - "integrity": "sha512-aulXdA4I1dyWpzyS1Nh/GNoS6PavzeucxEapnMR4JUERowWvaEk2Y4A5irpHAcdXtBBHLVe8WIhdXNjoAlGQgA==", + "version": "50.3.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-50.3.1.tgz", + "integrity": "sha512-SY9oUuTMr6aWoJggUS40LtMjsRzJPB5ZT7F432xZIHK3EfHF+8i48GbUBpwanrtlL9l1gILNTHK9o8gEhYLcKA==", "dev": true, "dependencies": { - "@es-joy/jsdoccomment": "~0.40.1", + "@es-joy/jsdoccomment": "~0.48.0", "are-docs-informative": "^0.0.2", - "comment-parser": "1.4.0", - "debug": "^4.3.4", + "comment-parser": "1.4.1", + "debug": "^4.3.6", "escape-string-regexp": "^4.0.0", - "esquery": "^1.5.0", - "is-builtin-module": "^3.2.1", - "semver": "^7.5.4", - "spdx-expression-parse": "^3.0.1" + "espree": "^10.1.0", + "esquery": "^1.6.0", + "parse-imports": "^2.1.1", + "semver": "^7.6.3", + "spdx-expression-parse": "^4.0.0", + "synckit": "^0.9.1" }, "engines": { - "node": ">=16" + "node": ">=18" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" } }, - "node_modules/eslint-plugin-local": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-local/-/eslint-plugin-local-1.0.0.tgz", - "integrity": "sha512-bcwcQnKL/Iw5Vi/F2lG1he5oKD2OGjhsLmrcctkWrWq5TujgiaYb0cj3pZgr3XI54inNVnneOFdAx1daLoYLJQ==", + "node_modules/eslint-plugin-jsdoc/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-jsdoc/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, + "node_modules/eslint-plugin-jsdoc/node_modules/spdx-expression-parse": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", + "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/eslint-plugin-local": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-local/-/eslint-plugin-local-6.0.0.tgz", + "integrity": "sha512-pvy/pTTyanEKAqpYqy/SLfd4TdiAQ/yFO+GRXDGvGQa2vEUGtmlEjmWQXBDGSk790j4nrAB/7ipqPQY3nLduDg==", + "deprecated": "Since the coming of ESLint flat config file, you can specify local rules without the need of this package. For running ESLint rule unit tests, use eslint-rule-tester instead", + "dev": true, + "dependencies": { + "@thisismanta/pessimist": "^1.2.0", + "chalk": "^4.0.0" + }, + "bin": { + "eslint-plugin-local": "executable.js" + }, + "peerDependencies": { + "eslint": ">=9.0.0" + } + }, "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.1.0.tgz", + "integrity": "sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw==", "dev": true, "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -6103,6 +6221,18 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz", + "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/eslint/node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -6137,26 +6267,38 @@ "dev": true }, "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.2.0.tgz", + "integrity": "sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g==", "dev": true, "dependencies": { - "acorn": "^8.9.0", + "acorn": "^8.12.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "eslint-visitor-keys": "^4.1.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz", + "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, "dependencies": { "estraverse": "^5.1.0" @@ -6341,9 +6483,9 @@ "dev": true }, "node_modules/fast-glob": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", - "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -6392,15 +6534,15 @@ } }, "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, "dependencies": { - "flat-cache": "^3.0.4" + "flat-cache": "^4.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16.0.0" } }, "node_modules/file-loader": { @@ -6541,54 +6683,16 @@ } }, "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "dependencies": { "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flat-cache/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "keyv": "^4.5.4" }, "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/flat-cache/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=16" } }, "node_modules/flatted": { @@ -7101,15 +7205,12 @@ } }, "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -7131,26 +7232,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/glogg": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/glogg/-/glogg-2.2.0.tgz", @@ -7205,12 +7286,6 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", @@ -9241,21 +9316,6 @@ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "dev": true }, - "node_modules/is-builtin-module": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", - "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", - "dev": true, - "dependencies": { - "builtin-modules": "^3.3.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-callable": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", @@ -9829,16 +9889,6 @@ "mkdirp": "bin/cmd.js" } }, - "node_modules/js-sdsl": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.2.tgz", - "integrity": "sha512-dwXFwByc/ajSV6m5bcKAPwe4yDDF6D614pxmIi5odytzxRlwqF6nwoiCek80Ixc7Cvma5awClxrzFtxCQvcM8w==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -9872,9 +9922,9 @@ } }, "node_modules/jsdoc-type-pratt-parser": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", - "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.1.0.tgz", + "integrity": "sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==", "dev": true, "engines": { "node": ">=12.0.0" @@ -11963,6 +12013,19 @@ "node": ">=0.8" } }, + "node_modules/parse-imports": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/parse-imports/-/parse-imports-2.2.1.tgz", + "integrity": "sha512-OL/zLggRp8mFhKL0rNORUTR4yBYujK/uU+xZL+/0Rgm2QE4nLO9v8PzEweSJEbMGKmDRjJE4R3IMJlL2di4JeQ==", + "dev": true, + "dependencies": { + "es-module-lexer": "^1.5.3", + "slashes": "^3.0.12" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", @@ -13835,9 +13898,9 @@ n "dev": true }, "node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "bin": { "semver": "bin/semver.js" }, @@ -14104,14 +14167,11 @@ n "node": ">=8" } }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } + "node_modules/slashes": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/slashes/-/slashes-3.0.12.tgz", + "integrity": "sha512-Q9VME8WyGkc7pJf6QEkj3wE+2CnvZMI+XJhwdTPR8Z/kWQRXi7boAWLDibRPyHRTUTPx5FaU7MsyrjI3yLB4HA==", + "dev": true }, "node_modules/smart-buffer": { "version": "4.2.0", @@ -14778,6 +14838,22 @@ n "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/synckit": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.1.tgz", + "integrity": "sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==", + "dev": true, + "dependencies": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, "node_modules/tapable": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.0.tgz", @@ -15374,27 +15450,6 @@ n "node": ">=0.6.x" } }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, - "node_modules/tsutils/node_modules/tslib": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", - "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", - "dev": true - }, "node_modules/tunnel": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", @@ -15442,18 +15497,6 @@ n "node": ">=4" } }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -15468,9 +15511,9 @@ n } }, "node_modules/typescript": { - "version": "5.7.0-dev.20240927", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.0-dev.20240927.tgz", - "integrity": "sha512-IWKZHTHAlS8BglLp8iM4rUHhy0h79B9r9vj6b6zpa8U38ofctFS1fLiKY7okZ3JYeG15kUHuOwsLwOmvc5+e1Q==", + "version": "5.7.0-dev.20241007", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.0-dev.20241007.tgz", + "integrity": "sha512-oIOWWuGS7GI51GWoNlP9O/eKmV1P+lKbIzVzg2i8Ul6n8vWHjQISb8MkPBxDj+alhYG2sl+HxtFHHG/LCgN/hg==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -15480,6 +15523,114 @@ n "node": ">=14.17" } }, + "node_modules/typescript-eslint": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.8.0.tgz", + "integrity": "sha512-BjIT/VwJ8+0rVO01ZQ2ZVnjE1svFBiRczcpr1t1Yxt7sT25VSbPfrJtDsQ8uQTy2pilX5nI9gwxhUyLULNentw==", + "dev": true, + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.8.0", + "@typescript-eslint/parser": "8.8.0", + "@typescript-eslint/utils": "8.8.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.8.0.tgz", + "integrity": "sha512-wORFWjU30B2WJ/aXBfOm1LX9v9nyt9D3jsSOxC3cCaTQGCW5k4jNpmjFv3U7p/7s4yvdjHzwtv2Sd2dOyhjS0A==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.8.0", + "@typescript-eslint/type-utils": "8.8.0", + "@typescript-eslint/utils": "8.8.0", + "@typescript-eslint/visitor-keys": "8.8.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.8.0.tgz", + "integrity": "sha512-uEFUsgR+tl8GmzmLjRqz+VrDv4eoaMqMXW7ruXfgThaAShO9JTciKpEsB+TvnfFfbg5IpujgMXVV36gOJRLtZg==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "8.8.0", + "@typescript-eslint/types": "8.8.0", + "@typescript-eslint/typescript-estree": "8.8.0", + "@typescript-eslint/visitor-keys": "8.8.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/type-utils": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.8.0.tgz", + "integrity": "sha512-IKwJSS7bCqyCeG4NVGxnOP6lLT9Okc3Zj8hLO96bpMkJab+10HIfJbMouLrlpyOr3yrQ1cA413YPFiGd1mW9/Q==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "8.8.0", + "@typescript-eslint/utils": "8.8.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/typical": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", diff --git a/package.json b/package.json index bdda8fdeb0910..3a3b723637818 100644 --- a/package.json +++ b/package.json @@ -71,6 +71,7 @@ "@microsoft/1ds-core-js": "^3.2.13", "@microsoft/1ds-post-js": "^3.2.13", "@parcel/watcher": "2.1.0", + "@types/semver": "^7.5.8", "@vscode/deviceid": "^0.1.1", "@vscode/iconv-lite-umd": "0.7.0", "@vscode/policy-watcher": "^1.1.8", @@ -112,9 +113,11 @@ }, "devDependencies": { "@playwright/test": "^1.46.1", + "@stylistic/eslint-plugin-ts": "^2.8.0", + "@swc/core": "1.3.62", "@types/cookie": "^0.3.3", "@types/debug": "^4.1.5", - "@types/eslint": "^8.56.10", + "@types/eslint": "^9.6.1", "@types/gulp-svgmin": "^1.2.1", "@types/http-proxy-agent": "^2.0.1", "@types/kerberos": "^1.1.2", @@ -131,9 +134,7 @@ "@types/winreg": "^1.2.30", "@types/yauzl": "^2.10.0", "@types/yazl": "^2.4.2", - "@typescript-eslint/eslint-plugin": "^6.21.0", - "@typescript-eslint/experimental-utils": "^5.57.0", - "@typescript-eslint/parser": "^6.21.0", + "@typescript-eslint/utils": "^8.8.0", "@vscode/gulp-electron": "^1.36.0", "@vscode/l10n-dev": "0.0.35", "@vscode/telemetry-extractor": "^1.10.2", @@ -141,7 +142,7 @@ "@vscode/test-electron": "^2.4.0", "@vscode/test-web": "^0.0.62", "@vscode/v8-heap-parser": "^0.1.0", - "@vscode/vscode-perf": "^0.0.14", + "@vscode/vscode-perf": "^0.0.19", "@webgpu/types": "^0.1.44", "ansi-colors": "^3.2.3", "asar": "^3.0.3", @@ -151,16 +152,20 @@ ======= "cookie": "^0.7.0", +======= + "cookie": "^0.7.2", + "copy-webpack-plugin": "^11.0.0", "css-loader": "^6.9.1", "cssnano": "^6.0.3", "debounce": "^1.0.0", "deemon": "^1.8.0", "electron": "32.1.2", - "eslint": "8.36.0", + "eslint": "^9.11.1", + "eslint-formatter-compact": "^8.40.0", "eslint-plugin-header": "3.1.1", - "eslint-plugin-jsdoc": "^46.5.0", - "eslint-plugin-local": "^1.0.0", + "eslint-plugin-jsdoc": "^50.3.1", + "eslint-plugin-local": "^6.0.0", "event-stream": "3.3.4", "fancy-log": "^1.3.3", "file-loader": "^6.2.0", @@ -218,7 +223,8 @@ "ts-node": "^10.9.1", "tsec": "0.2.7", "tslib": "^2.6.3", - "typescript": "^5.7.0-dev.20240927", + "typescript": "^5.7.0-dev.20241007", + "typescript-eslint": "^8.8.0", "util": "^0.12.4", "webpack": "^5.94.0", "webpack-cli": "^5.1.4", diff --git a/src/bootstrap-window.ts b/src/bootstrap-window.ts index 1b2cedf68b4dd..3c1270026039a 100644 --- a/src/bootstrap-window.ts +++ b/src/bootstrap-window.ts @@ -3,8 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -/* eslint-disable no-restricted-globals */ - (function () { type ISandboxConfiguration = import('vs/base/parts/sandbox/common/sandboxTypes.js').ISandboxConfiguration; diff --git a/src/vs/amdX.ts b/src/vs/amdX.ts index 8646f0b7b9598..ee149951b548a 100644 --- a/src/vs/amdX.ts +++ b/src/vs/amdX.ts @@ -70,10 +70,8 @@ class AMDModuleImporter { (globalThis as any).define.amd = true; if (this._isRenderer) { - // eslint-disable-next-line no-restricted-globals this._amdPolicy = (globalThis as any)._VSCODE_WEB_PACKAGE_TTP ?? window.trustedTypes?.createPolicy('amdLoader', { createScriptURL(value) { - // eslint-disable-next-line no-restricted-globals if (value.startsWith(window.location.origin)) { return value; } @@ -162,7 +160,6 @@ class AMDModuleImporter { scriptSrc = this._amdPolicy.createScriptURL(scriptSrc) as any as string; } scriptElement.setAttribute('src', scriptSrc); - // eslint-disable-next-line no-restricted-globals window.document.getElementsByTagName('head')[0].appendChild(scriptElement); }); } diff --git a/src/vs/base/browser/ui/iconLabel/iconLabel.ts b/src/vs/base/browser/ui/iconLabel/iconLabel.ts index 7a3583f7c4030..f9804179a896b 100644 --- a/src/vs/base/browser/ui/iconLabel/iconLabel.ts +++ b/src/vs/base/browser/ui/iconLabel/iconLabel.ts @@ -24,6 +24,7 @@ export interface IIconLabelCreationOptions { readonly supportDescriptionHighlights?: boolean; readonly supportIcons?: boolean; readonly hoverDelegate?: IHoverDelegate; + readonly hoverTargetOverrride?: HTMLElement; } export interface IIconLabelValueOptions { @@ -209,6 +210,14 @@ export class IconLabel extends Disposable { return; } + let hoverTarget = htmlElement; + if (this.creationOptions?.hoverTargetOverrride) { + if (!dom.isAncestor(htmlElement, this.creationOptions.hoverTargetOverrride)) { + throw new Error('hoverTargetOverrride must be an ancestor of the htmlElement'); + } + hoverTarget = this.creationOptions.hoverTargetOverrride; + } + if (this.hoverDelegate.showNativeHover) { function setupNativeHover(htmlElement: HTMLElement, tooltip: string | IManagedHoverTooltipMarkdownString | undefined): void { if (isString(tooltip)) { @@ -220,9 +229,9 @@ export class IconLabel extends Disposable { htmlElement.removeAttribute('title'); } } - setupNativeHover(htmlElement, tooltip); + setupNativeHover(hoverTarget, tooltip); } else { - const hoverDisposable = getBaseLayerHoverDelegate().setupManagedHover(this.hoverDelegate, htmlElement, tooltip); + const hoverDisposable = getBaseLayerHoverDelegate().setupManagedHover(this.hoverDelegate, hoverTarget, tooltip); if (hoverDisposable) { this.customHovers.set(htmlElement, hoverDisposable); } diff --git a/src/vs/base/common/async.ts b/src/vs/base/common/async.ts index a270e41a213f7..98a68886677eb 100644 --- a/src/vs/base/common/async.ts +++ b/src/vs/base/common/async.ts @@ -126,6 +126,32 @@ export function raceTimeout(promise: Promise, timeout: number, onTimeout?: ]); } +export function raceFilter(promises: Promise[], filter: (result: T) => boolean): Promise { + return new Promise((resolve, reject) => { + if (promises.length === 0) { + resolve(undefined); + return; + } + + let resolved = false; + let unresolvedCount = promises.length; + for (const promise of promises) { + promise.then(result => { + unresolvedCount--; + if (!resolved) { + if (filter(result)) { + resolved = true; + resolve(result); + } else if (unresolvedCount === 0) { + // Last one has to resolve the promise + resolve(undefined); + } + } + }).catch(reject); + } + }); +} + export function asPromise(callback: () => T | Thenable): Promise { return new Promise((resolve, reject) => { const item = callback(); diff --git a/src/vs/base/common/errors.ts b/src/vs/base/common/errors.ts index 07e7b2acd91ee..fb18cb9b2e526 100644 --- a/src/vs/base/common/errors.ts +++ b/src/vs/base/common/errors.ts @@ -307,7 +307,6 @@ export class BugIndicatingError extends Error { // Because we know for sure only buggy code throws this, // we definitely want to break here and fix the bug. - // eslint-disable-next-line no-debugger // debugger; } } diff --git a/src/vs/base/common/types.ts b/src/vs/base/common/types.ts index 6025a90c711f0..6ad28eaece005 100644 --- a/src/vs/base/common/types.ts +++ b/src/vs/base/common/types.ts @@ -196,7 +196,7 @@ export function validateConstraint(arg: unknown, constraint: TypeConstraint | un * This can be used to make sure the argument correctly conforms to the subtype while still being able to pass it * to contexts that expects the supertype. */ -export function upcast(x: Sub): Base { +export function upcast(x: Sub): Base { return x; } diff --git a/src/vs/base/parts/ipc/common/ipc.ts b/src/vs/base/parts/ipc/common/ipc.ts index 3f75e084d2781..2f8819f2443e0 100644 --- a/src/vs/base/parts/ipc/common/ipc.ts +++ b/src/vs/base/parts/ipc/common/ipc.ts @@ -553,6 +553,7 @@ export class ChannelClient implements IChannelClient, IDisposable { getChannel(channelName: string): T { const that = this; + // eslint-disable-next-line local/code-no-dangerous-type-assertions return { call(command: string, arg?: any, cancellationToken?: CancellationToken) { if (that.isDisposed) { @@ -845,6 +846,7 @@ export class IPCServer implements IChannelServer, I getChannel(channelName: string, routerOrClientFilter: IClientRouter | ((client: Client) => boolean)): T { const that = this; + // eslint-disable-next-line local/code-no-dangerous-type-assertions return { call(command: string, arg?: any, cancellationToken?: CancellationToken): Promise { let connectionPromise: Promise>; @@ -994,6 +996,7 @@ export class IPCClient implements IChannelClient, IChannelSer } export function getDelayedChannel(promise: Promise): T { + // eslint-disable-next-line local/code-no-dangerous-type-assertions return { call(command: string, arg?: any, cancellationToken?: CancellationToken): Promise { return promise.then(c => c.call(command, arg, cancellationToken)); @@ -1010,6 +1013,7 @@ export function getDelayedChannel(promise: Promise): T { export function getNextTickChannel(channel: T): T { let didTick = false; + // eslint-disable-next-line local/code-no-dangerous-type-assertions return { call(command: string, arg?: any, cancellationToken?: CancellationToken): Promise { if (didTick) { diff --git a/src/vs/code/node/cli.ts b/src/vs/code/node/cli.ts index 6ca979ca03fbd..bb5f41975b285 100644 --- a/src/vs/code/node/cli.ts +++ b/src/vs/code/node/cli.ts @@ -138,14 +138,26 @@ export async function main(argv: string[]): Promise { // Write File else if (args['file-write']) { - const source = args._[0]; - const target = args._[1]; + const argsFile = args._[0]; + if (!argsFile || !isAbsolute(argsFile) || !existsSync(argsFile) || !statSync(argsFile).isFile()) { + throw new Error('Using --file-write with invalid arguments.'); + } + + let source: string | undefined; + let target: string | undefined; + try { + const argsContents = JSON.parse(readFileSync(argsFile, 'utf8')); + source = argsContents.source; + target = argsContents.target; + } catch (error) { + throw new Error('Using --file-write with invalid arguments.'); + } // Windows: set the paths as allowed UNC paths given // they are explicitly provided by the user as arguments if (isWindows) { for (const path of [source, target]) { - if (isUNC(path)) { + if (typeof path === 'string' && isUNC(path)) { addUNCHostToAllowlist(URI.file(path).authority); } } diff --git a/src/vs/editor/contrib/inlineCompletions/browser/controller/inlineCompletionsController.ts b/src/vs/editor/contrib/inlineCompletions/browser/controller/inlineCompletionsController.ts index 53e1dca17478f..fd5f6543ecb74 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/controller/inlineCompletionsController.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/controller/inlineCompletionsController.ts @@ -136,6 +136,7 @@ export class InlineCompletionsController extends Disposable { private readonly _playAccessibilitySignal = observableSignal(this); private readonly _fontFamily = this._editorObs.getOption(EditorOption.inlineSuggest).map(val => val.fontFamily); + private readonly _hideInlineEditOnSelectionChange = this._editorObs.getOption(EditorOption.inlineSuggest).map(val => true); constructor( public readonly editor: ICodeEditor, @@ -178,6 +179,9 @@ export class InlineCompletionsController extends Disposable { this._register(runOnChange(this._editorObs.selections, (_value, _, changes) => { if (changes.some(e => e.reason === CursorChangeReason.Explicit || e.source === 'api')) { + if (!this._hideInlineEditOnSelectionChange.get() && this.model.get()?.stateWithInlineEdit.get()?.kind === 'inlineEdit') { + return; + } this.model.get()?.stop(); } })); diff --git a/src/vs/editor/contrib/inlineCompletions/browser/model/inlineCompletionsSource.ts b/src/vs/editor/contrib/inlineCompletions/browser/model/inlineCompletionsSource.ts index 7031a4fb69815..4d97d184d6b00 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/model/inlineCompletionsSource.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/model/inlineCompletionsSource.ts @@ -115,6 +115,7 @@ export class InlineCompletionsSource extends Disposable { } if (source.token.isCancellationRequested || this._store.isDisposed || this._textModel.getVersionId() !== request.versionId) { + updatedCompletions.dispose(); return false; } diff --git a/src/vs/editor/contrib/inlineCompletions/browser/model/inlineEditsAdapter.ts b/src/vs/editor/contrib/inlineCompletions/browser/model/inlineEditsAdapter.ts index c03fb7bfa610b..c2016411b7a9a 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/model/inlineEditsAdapter.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/model/inlineEditsAdapter.ts @@ -84,6 +84,9 @@ export class InlineEditsAdapter extends Disposable { e.provider.freeInlineEdit(e.result); } } + toString(): string { + return 'InlineEditsAdapter'; + } })); })); } diff --git a/src/vs/editor/contrib/inlineCompletions/browser/model/provideInlineCompletions.ts b/src/vs/editor/contrib/inlineCompletions/browser/model/provideInlineCompletions.ts index fc7e6b42ee1c8..70ff7f7557a54 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/model/provideInlineCompletions.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/model/provideInlineCompletions.ts @@ -4,16 +4,16 @@ *--------------------------------------------------------------------------------------------*/ import { assertNever } from '../../../../../base/common/assert.js'; -import { DeferredPromise } from '../../../../../base/common/async.js'; -import { CancellationToken } from '../../../../../base/common/cancellation.js'; +import { DeferredPromise, raceFilter } from '../../../../../base/common/async.js'; +import { CancellationToken, CancellationTokenSource } from '../../../../../base/common/cancellation.js'; import { SetMap } from '../../../../../base/common/map.js'; import { onUnexpectedExternalError } from '../../../../../base/common/errors.js'; -import { IDisposable } from '../../../../../base/common/lifecycle.js'; +import { Disposable, IDisposable } from '../../../../../base/common/lifecycle.js'; import { ISingleEditOperation } from '../../../../common/core/editOperation.js'; import { Position } from '../../../../common/core/position.js'; import { Range } from '../../../../common/core/range.js'; import { LanguageFeatureRegistry } from '../../../../common/languageFeatureRegistry.js'; -import { Command, InlineCompletion, InlineCompletionContext, InlineCompletionProviderGroupId, InlineCompletions, InlineCompletionsProvider } from '../../../../common/languages.js'; +import { Command, InlineCompletion, InlineCompletionContext, InlineCompletionProviderGroupId, InlineCompletions, InlineCompletionsProvider, InlineCompletionTriggerKind } from '../../../../common/languages.js'; import { ILanguageConfigurationService } from '../../../../common/languages/languageConfigurationRegistry.js'; import { ITextModel } from '../../../../common/model.js'; import { fixBracketsInLine } from '../../../../common/model/bracketPairsTextModelPart/fixBrackets.js'; @@ -22,16 +22,19 @@ import { getReadonlyEmptyArray } from '../utils.js'; import { SnippetParser, Text } from '../../../snippet/browser/snippetParser.js'; import { LineEditWithAdditionalLines } from '../../../../common/tokenizationTextModelPart.js'; import { OffsetRange } from '../../../../common/core/offsetRange.js'; +import { isDefined } from '../../../../../base/common/types.js'; export async function provideInlineCompletions( registry: LanguageFeatureRegistry, positionOrRange: Position | Range, model: ITextModel, context: InlineCompletionContext, - token: CancellationToken = CancellationToken.None, + baseToken: CancellationToken = CancellationToken.None, languageConfigurationService?: ILanguageConfigurationService, ): Promise { - // Important: Don't use position after the await calls, as the model could have been changed in the meantime! + const tokenSource = new CancellationTokenSource(baseToken); + const token = tokenSource.token; + const defaultReplaceRange = positionOrRange instanceof Position ? getDefaultRange(positionOrRange, model) : positionOrRange; const providers = registry.all(model); @@ -54,11 +57,14 @@ export async function provideInlineCompletions( return result; } - type Result = Promise | null | undefined>; - const states = new Map>, Result>(); + type Result = Promise; + const states = new Map(); - const seen = new Set>>(); - function findPreferredProviderCircle(provider: InlineCompletionsProvider, stack: InlineCompletionsProvider[]): InlineCompletionsProvider[] | undefined { + const seen = new Set(); + function findPreferredProviderCircle( + provider: InlineCompletionsProvider, + stack: InlineCompletionsProvider[] + ): InlineCompletionsProvider[] | undefined { stack = [...stack, provider]; if (seen.has(provider)) { return stack; } @@ -75,65 +81,109 @@ export async function provideInlineCompletions( return undefined; } - function processProvider(provider: InlineCompletionsProvider): Result { + function queryProviderOrPreferredProvider(provider: InlineCompletionsProvider): Result { const state = states.get(provider); - if (state) { - return state; - } + if (state) { return state; } const circle = findPreferredProviderCircle(provider, []); if (circle) { - onUnexpectedExternalError(new Error(`Inline completions: cyclic yield-to dependency detected. Path: ${circle.map(s => s.toString ? s.toString() : ('' + s)).join(' -> ')}`)); + onUnexpectedExternalError(new Error(`Inline completions: cyclic yield-to dependency detected.` + + ` Path: ${circle.map(s => s.toString ? s.toString() : ('' + s)).join(' -> ')}`)); } - const deferredPromise = new DeferredPromise | null | undefined>(); + const deferredPromise = new DeferredPromise(); states.set(provider, deferredPromise.p); (async () => { if (!circle) { const preferred = getPreferredProviders(provider); for (const p of preferred) { - const result = await processProvider(p); - if (result && result.items.length > 0) { + const result = await queryProviderOrPreferredProvider(p); + if (result && result.inlineCompletions.items.length > 0) { // Skip provider return undefined; } } } - try { - if (positionOrRange instanceof Position) { - const completions = await provider.provideInlineCompletions(model, positionOrRange, context, token); - return completions; - } else { - const completions = await provider.provideInlineEditsForRange?.(model, positionOrRange, context, token); - return completions; - } - } catch (e) { - onUnexpectedExternalError(e); - return undefined; - } + return query(provider); })().then(c => deferredPromise.complete(c), e => deferredPromise.error(e)); return deferredPromise.p; } - const providerResults = await Promise.all(providers.map(async provider => ({ provider, completions: await processProvider(provider) }))); + async function query(provider: InlineCompletionsProvider): Promise { + let result: InlineCompletions | null | undefined; + try { + if (positionOrRange instanceof Position) { + result = await provider.provideInlineCompletions(model, positionOrRange, context, token); + } else { + result = await provider.provideInlineEditsForRange?.(model, positionOrRange, context, token); + } + } catch (e) { + onUnexpectedExternalError(e); + return undefined; + } + + if (!result) { return undefined; } + const list = new InlineCompletionList(result, provider); + + runWhenCancelled(token, () => list.removeRef()); + return list; + } + + const promises = providers.map(queryProviderOrPreferredProvider); + let inlineCompletionLists: (InlineCompletionList | undefined)[]; + if (context.triggerKind === InlineCompletionTriggerKind.Automatic) { + // in automatic mode, we only show the first result. + // When the user cycles through the completions, it will be an explicit request. + inlineCompletionLists = [await raceFilter(promises, result => !!result && result.inlineCompletions.items.length > 0)]; + } else { + inlineCompletionLists = await Promise.all(promises); + } + + if (token.isCancellationRequested) { + tokenSource.dispose(true); + // result has been disposed before we could call addRef! So we have to discard everything. + return new InlineCompletionProviderResult([], new Set(), []); + } + + const result = addRefAndCreateResult(inlineCompletionLists, defaultReplaceRange, model, languageConfigurationService); + tokenSource.dispose(true); // This disposes results that are not referenced. + return result; +} + +/** If the token does not leak, this will not leak either. */ +function runWhenCancelled(token: CancellationToken, callback: () => void): IDisposable { + if (token.isCancellationRequested) { + callback(); + return Disposable.None; + } else { + const listener = token.onCancellationRequested(() => { + listener.dispose(); + callback(); + }); + return { dispose: () => listener.dispose() }; + } +} + +function addRefAndCreateResult( + inlineCompletionLists: (InlineCompletionList | undefined)[], + defaultReplaceRange: Range, + model: ITextModel, + languageConfigurationService: ILanguageConfigurationService | undefined +): InlineCompletionProviderResult { + // for deduplication const itemsByHash = new Map(); - const lists: InlineCompletionList[] = []; - for (const result of providerResults) { - const completions = result.completions; - if (!completions) { - continue; - } - const list = new InlineCompletionList(completions, result.provider); - lists.push(list); - for (const item of completions.items) { + const lists = inlineCompletionLists.filter(isDefined); + for (const completions of lists) { + completions.addRef(); + for (const item of completions.inlineCompletions.items) { const inlineCompletionItem = InlineCompletionItem.from( item, - list, + completions, defaultReplaceRange, model, languageConfigurationService diff --git a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsView.ts b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsView.ts index fc42e61d8a8fa..be8bf442a7790 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsView.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsView.ts @@ -314,6 +314,7 @@ export class InlineEditsView extends Disposable { horizontal: 'hidden', }, readOnly: true, + wordWrap: 'off', }, { contributions: [], }, this._editor diff --git a/src/vs/editor/contrib/wordHighlighter/browser/wordHighlighter.ts b/src/vs/editor/contrib/wordHighlighter/browser/wordHighlighter.ts index 2aed6c9541ea4..d65e07ee22d71 100644 --- a/src/vs/editor/contrib/wordHighlighter/browser/wordHighlighter.ts +++ b/src/vs/editor/contrib/wordHighlighter/browser/wordHighlighter.ts @@ -18,6 +18,7 @@ import { IConfigurationService } from '../../../../platform/configuration/common import { IContextKey, IContextKeyService, RawContextKey } from '../../../../platform/contextkey/common/contextkey.js'; import { ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js'; import { KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js'; +import { ILogService } from '../../../../platform/log/common/log.js'; import { IActiveCodeEditor, ICodeEditor, isDiffEditor } from '../../../browser/editorBrowser.js'; import { EditorAction, EditorContributionInstantiation, IActionOptions, registerEditorAction, registerEditorContribution, registerModelAndPositionCommand } from '../../../browser/editorExtensions.js'; import { ICodeEditorService } from '../../../browser/services/codeEditorService.js'; @@ -213,6 +214,7 @@ class WordHighlighter { private readonly textModelService: ITextModelService; private readonly codeEditorService: ICodeEditorService; private readonly configurationService: IConfigurationService; + private readonly logService: ILogService; private occurrencesHighlightEnablement: string; private occurrencesHighlightDelay: number; @@ -241,6 +243,7 @@ class WordHighlighter { @ITextModelService textModelService: ITextModelService, @ICodeEditorService codeEditorService: ICodeEditorService, @IConfigurationService configurationService: IConfigurationService, + @ILogService logService: ILogService, ) { this.editor = editor; this.providers = providers; @@ -249,6 +252,7 @@ class WordHighlighter { this.codeEditorService = codeEditorService; this.textModelService = textModelService; this.configurationService = configurationService; + this.logService = logService; this._hasWordHighlights = ctxHasWordHighlights.bindTo(contextKeyService); this._ignorePositionChangeEvent = false; @@ -699,17 +703,23 @@ class WordHighlighter { if (!WordHighlighter.query || !WordHighlighter.query.modelInfo) { return; } + const queryModelRef = await this.textModelService.createModelReference(WordHighlighter.query.modelInfo.modelURI); - const queryModel = queryModelRef.object.textEditorModel; - this.workerRequest = this.computeWithModel(queryModel, WordHighlighter.query.modelInfo.selection, otherModelsToHighlight); - - this.workerRequest?.result.then(data => { - if (myRequestId === this.workerRequestTokenId) { - this.workerRequestCompleted = true; - this.workerRequestValue = data || []; - this._beginRenderDecorations(); - } - }, onUnexpectedError); + try { + this.workerRequest = this.computeWithModel(queryModelRef.object.textEditorModel, WordHighlighter.query.modelInfo.selection, otherModelsToHighlight); + this.workerRequest?.result.then(data => { + if (myRequestId === this.workerRequestTokenId) { + this.workerRequestCompleted = true; + this.workerRequestValue = data || []; + this._beginRenderDecorations(); + } + }, onUnexpectedError); + } catch (e) { + this.logService.error('Unexpected error during occurrence request. Log: ', e); + } finally { + queryModelRef.dispose(); + } + } else if (this.model.uri.scheme === Schemas.vscodeNotebookCell) { // new wordHighlighter coming from a different model, NOT the query model, need to create a textModel ref @@ -723,16 +733,20 @@ class WordHighlighter { } const queryModelRef = await this.textModelService.createModelReference(WordHighlighter.query.modelInfo.modelURI); - const queryModel = queryModelRef.object.textEditorModel; - this.workerRequest = this.computeWithModel(queryModel, WordHighlighter.query.modelInfo.selection, [this.model]); - - this.workerRequest?.result.then(data => { - if (myRequestId === this.workerRequestTokenId) { - this.workerRequestCompleted = true; - this.workerRequestValue = data || []; - this._beginRenderDecorations(noDelay); - } - }, onUnexpectedError); + try { + this.workerRequest = this.computeWithModel(queryModelRef.object.textEditorModel, WordHighlighter.query.modelInfo.selection, [this.model]); + this.workerRequest?.result.then(data => { + if (myRequestId === this.workerRequestTokenId) { + this.workerRequestCompleted = true; + this.workerRequestValue = data || []; + this._beginRenderDecorations(noDelay); + } + }, onUnexpectedError); + } catch (e) { + this.logService.error('Unexpected error during occurrence request. Log: ', e); + } finally { + queryModelRef.dispose(); + } } } @@ -828,13 +842,14 @@ export class WordHighlighterContribution extends Disposable implements IEditorCo @ILanguageFeaturesService languageFeaturesService: ILanguageFeaturesService, @ICodeEditorService codeEditorService: ICodeEditorService, @ITextModelService textModelService: ITextModelService, - @IConfigurationService configurationService: IConfigurationService + @IConfigurationService configurationService: IConfigurationService, + @ILogService logService: ILogService, ) { super(); this._wordHighlighter = null; const createWordHighlighterIfPossible = () => { if (editor.hasModel() && !editor.getModel().isTooLargeForTokenization()) { - this._wordHighlighter = new WordHighlighter(editor, languageFeaturesService.documentHighlightProvider, languageFeaturesService.multiDocumentHighlightProvider, contextKeyService, textModelService, codeEditorService, configurationService); + this._wordHighlighter = new WordHighlighter(editor, languageFeaturesService.documentHighlightProvider, languageFeaturesService.multiDocumentHighlightProvider, contextKeyService, textModelService, codeEditorService, configurationService, logService); } }; this._register(editor.onDidChangeModel((e) => { diff --git a/src/vs/nls.ts b/src/vs/nls.ts index 8cf5158f96a25..e730d0a761e05 100644 --- a/src/vs/nls.ts +++ b/src/vs/nls.ts @@ -3,7 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +// eslint-disable-next-line local/code-import-patterns import { getNLSLanguage, getNLSMessages } from './nls.messages.js'; +// eslint-disable-next-line local/code-import-patterns export { getNLSLanguage, getNLSMessages } from './nls.messages.js'; const isPseudo = getNLSLanguage() === 'pseudo' || (typeof document !== 'undefined' && document.location && typeof document.location.hash === 'string' && document.location.hash.indexOf('pseudo=true') >= 0); diff --git a/src/vs/platform/environment/node/argv.ts b/src/vs/platform/environment/node/argv.ts index f0cec3398a736..379e327c64629 100644 --- a/src/vs/platform/environment/node/argv.ts +++ b/src/vs/platform/environment/node/argv.ts @@ -272,6 +272,7 @@ export function parseArgs(args: string[], options: OptionDescriptions, err const newArgs = args.filter(a => a !== firstArg); const reporter = errorReporter.getSubcommandReporter ? errorReporter.getSubcommandReporter(firstArg) : undefined; const subcommandOptions = parseArgs(newArgs, options, reporter); + // eslint-disable-next-line local/code-no-dangerous-type-assertions return { [firstArg]: subcommandOptions, _: [] diff --git a/src/vs/platform/extensionManagement/node/extensionSignatureVerificationService.ts b/src/vs/platform/extensionManagement/node/extensionSignatureVerificationService.ts index 9af60c96ddcd9..fe7b99e5f99a4 100644 --- a/src/vs/platform/extensionManagement/node/extensionSignatureVerificationService.ts +++ b/src/vs/platform/extensionManagement/node/extensionSignatureVerificationService.ts @@ -24,11 +24,11 @@ export interface IExtensionSignatureVerificationService { /** * Verifies an extension file (.vsix) against a signature archive file. - * @param { string } extensionId The extension identifier. - * @param { string } version The extension version. - * @param { string } vsixFilePath The extension file path. - * @param { string } signatureArchiveFilePath The signature archive file path. - * @returns { Promise } returns the verification result or undefined if the verification was not executed. + * @param extensionId The extension identifier. + * @param version The extension version. + * @param vsixFilePath The extension file path. + * @param signatureArchiveFilePath The signature archive file path. + * @returns returns the verification result or undefined if the verification was not executed. */ verify(extensionId: string, version: string, vsixFilePath: string, signatureArchiveFilePath: string, clientTargetPlatform?: TargetPlatform): Promise; } diff --git a/src/vs/platform/extensions/common/extensionsApiProposals.ts b/src/vs/platform/extensions/common/extensionsApiProposals.ts index 0a045ca4d28e9..ac432211095fa 100644 --- a/src/vs/platform/extensions/common/extensionsApiProposals.ts +++ b/src/vs/platform/extensions/common/extensionsApiProposals.ts @@ -76,9 +76,6 @@ const _allApiProposals = { contribAccessibilityHelpContent: { proposal: 'https://github.com/raw/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribAccessibilityHelpContent.d.ts', }, - contribChatParticipantDetection: { - proposal: 'https://github.com/raw/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribChatParticipantDetection.d.ts', - }, contribCommentEditorActionsMenu: { proposal: 'https://github.com/raw/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribCommentEditorActionsMenu.d.ts', }, diff --git a/src/vs/platform/files/test/node/nodejsWatcher.test.ts b/src/vs/platform/files/test/node/nodejsWatcher.test.ts index 4b42b0b090085..a46279aaf50d0 100644 --- a/src/vs/platform/files/test/node/nodejsWatcher.test.ts +++ b/src/vs/platform/files/test/node/nodejsWatcher.test.ts @@ -30,8 +30,6 @@ import { TestParcelWatcher } from './parcelWatcher.test.js'; // mocha but generally). as such they will run only on demand // whenever we update the watcher library. -/* eslint-disable local/code-ensure-no-disposables-leak-in-test */ - suite.skip('File Watcher (node.js)', function () { this.timeout(10000); diff --git a/src/vs/platform/files/test/node/parcelWatcher.test.ts b/src/vs/platform/files/test/node/parcelWatcher.test.ts index c25c061fbedc7..7a9533e0d8ab6 100644 --- a/src/vs/platform/files/test/node/parcelWatcher.test.ts +++ b/src/vs/platform/files/test/node/parcelWatcher.test.ts @@ -65,8 +65,6 @@ export class TestParcelWatcher extends ParcelWatcher { // mocha but generally). as such they will run only on demand // whenever we update the watcher library. -/* eslint-disable local/code-ensure-no-disposables-leak-in-test */ - suite.skip('File Watcher (parcel)', function () { this.timeout(10000); diff --git a/src/vs/platform/list/browser/listService.ts b/src/vs/platform/list/browser/listService.ts index 7a03fcb4bab15..f93947e26bdba 100644 --- a/src/vs/platform/list/browser/listService.ts +++ b/src/vs/platform/list/browser/listService.ts @@ -1146,6 +1146,7 @@ function workbenchTreeDataPreamble /* only methods, not events */, number | undefined /* window ID */> { } @@ -568,35 +569,44 @@ export class NativeHostMainService extends Disposable implements INativeHostMain async writeElevated(windowId: number | undefined, source: URI, target: URI, options?: { unlock?: boolean }): Promise { const sudoPrompt = await import('@vscode/sudo-prompt'); - return new Promise((resolve, reject) => { - const sudoCommand: string[] = [`"${this.cliPath}"`]; - if (options?.unlock) { - sudoCommand.push('--file-chmod'); - } + const argsFile = randomPath(this.environmentMainService.userDataPath, 'code-elevated'); + await Promises.writeFile(argsFile, JSON.stringify({ source: source.fsPath, target: target.fsPath })); - sudoCommand.push('--file-write', `"${source.fsPath}"`, `"${target.fsPath}"`); + try { + await new Promise((resolve, reject) => { + const sudoCommand: string[] = [`"${this.cliPath}"`]; + if (options?.unlock) { + sudoCommand.push('--file-chmod'); + } - const promptOptions = { - name: this.productService.nameLong.replace('-', ''), - icns: (isMacintosh && this.environmentMainService.isBuilt) ? join(dirname(this.environmentMainService.appRoot), `${this.productService.nameShort}.icns`) : undefined - }; + sudoCommand.push('--file-write', `"${argsFile}"`); - sudoPrompt.exec(sudoCommand.join(' '), promptOptions, (error?, stdout?, stderr?) => { - if (stdout) { - this.logService.trace(`[sudo-prompt] received stdout: ${stdout}`); - } + const promptOptions = { + name: this.productService.nameLong.replace('-', ''), + icns: (isMacintosh && this.environmentMainService.isBuilt) ? join(dirname(this.environmentMainService.appRoot), `${this.productService.nameShort}.icns`) : undefined + }; - if (stderr) { - this.logService.trace(`[sudo-prompt] received stderr: ${stderr}`); - } + this.logService.trace(`[sudo-prompt] running command: ${sudoCommand.join(' ')}`); - if (error) { - reject(error); - } else { - resolve(undefined); - } + sudoPrompt.exec(sudoCommand.join(' '), promptOptions, (error?, stdout?, stderr?) => { + if (stdout) { + this.logService.trace(`[sudo-prompt] received stdout: ${stdout}`); + } + + if (stderr) { + this.logService.error(`[sudo-prompt] received stderr: ${stderr}`); + } + + if (error) { + reject(error); + } else { + resolve(undefined); + } + }); }); - }); + } finally { + await fs.promises.unlink(argsFile); + } } async isRunningUnderARM64Translation(): Promise { diff --git a/src/vs/platform/storage/test/electron-main/storageMainService.test.ts b/src/vs/platform/storage/test/electron-main/storageMainService.test.ts index caac031d74bda..e237c9ab15482 100644 --- a/src/vs/platform/storage/test/electron-main/storageMainService.test.ts +++ b/src/vs/platform/storage/test/electron-main/storageMainService.test.ts @@ -37,7 +37,6 @@ suite('StorageMainService', function () { const inMemoryProfile: IUserDataProfile = { id: 'id', name: 'inMemory', - shortName: 'inMemory', isDefault: false, location: inMemoryProfileRoot, globalStorageHome: joinPath(inMemoryProfileRoot, 'globalStorageHome'), diff --git a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts index fa4f13707ec28..2e3a89e914b14 100644 --- a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts +++ b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts @@ -44,6 +44,7 @@ export class CommandDetectionCapability extends Disposable implements ICommandDe // TODO: as is unsafe here and it duplicates behavor of executingCommand get executingCommandObject(): ITerminalCommand | undefined { if (this._currentCommand.commandStartMarker) { + // eslint-disable-next-line local/code-no-dangerous-type-assertions return { marker: this._currentCommand.commandStartMarker } as ITerminalCommand; } return undefined; @@ -430,6 +431,7 @@ export class CommandDetectionCapability extends Disposable implements ICommandDe this._currentCommand.commandStartX = e.startX; this._currentCommand.promptStartMarker = e.promptStartLine !== undefined ? this._terminal.registerMarker(e.promptStartLine - (buffer.baseY + buffer.cursorY)) : undefined; this._cwd = e.cwd; + // eslint-disable-next-line local/code-no-dangerous-type-assertions this._onCommandStarted.fire({ marker } as ITerminalCommand); continue; } @@ -511,6 +513,7 @@ class UnixPtyHeuristics extends Disposable { } this._hooks.commandMarkers.length = 0; + // eslint-disable-next-line local/code-no-dangerous-type-assertions this._hooks.onCommandStartedEmitter.fire({ marker: options?.marker || currentCommand.commandStartMarker, markProperties: options?.markProperties } as ITerminalCommand); this._logService.debug('CommandDetectionCapability#handleCommandStart', currentCommand.commandStartX, currentCommand.commandStartMarker?.line); } @@ -770,6 +773,7 @@ class WindowsPtyHeuristics extends Disposable { this._capability.currentCommand.commandStartLineContent = line.translateToString(true); } } + // eslint-disable-next-line local/code-no-dangerous-type-assertions this._hooks.onCommandStartedEmitter.fire({ marker: this._capability.currentCommand.commandStartMarker } as ITerminalCommand); this._logService.debug('CommandDetectionCapability#_handleCommandStartWindows', this._capability.currentCommand.commandStartX, this._capability.currentCommand.commandStartMarker?.line); } diff --git a/src/vs/platform/update/common/update.ts b/src/vs/platform/update/common/update.ts index 2b0253285aa86..199f433a462df 100644 --- a/src/vs/platform/update/common/update.ts +++ b/src/vs/platform/update/common/update.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Event } from '../../../base/common/event.js'; +import { upcast } from '../../../base/common/types.js'; import { createDecorator } from '../../instantiation/common/instantiation.js'; export interface IUpdate { @@ -73,12 +74,12 @@ export type Ready = { type: StateType.Ready; update: IUpdate }; export type State = Uninitialized | Disabled | Idle | CheckingForUpdates | AvailableForDownload | Downloading | Downloaded | Updating | Ready; export const State = { - Uninitialized: { type: StateType.Uninitialized } as Uninitialized, - Disabled: (reason: DisablementReason) => ({ type: StateType.Disabled, reason }) as Disabled, - Idle: (updateType: UpdateType, error?: string) => ({ type: StateType.Idle, updateType, error }) as Idle, + Uninitialized: upcast({ type: StateType.Uninitialized }), + Disabled: (reason: DisablementReason): Disabled => ({ type: StateType.Disabled, reason }), + Idle: (updateType: UpdateType, error?: string): Idle => ({ type: StateType.Idle, updateType, error }), CheckingForUpdates: (explicit: boolean): CheckingForUpdates => ({ type: StateType.CheckingForUpdates, explicit }), AvailableForDownload: (update: IUpdate): AvailableForDownload => ({ type: StateType.AvailableForDownload, update }), - Downloading: { type: StateType.Downloading } as Downloading, + Downloading: upcast({ type: StateType.Downloading }), Downloaded: (update: IUpdate): Downloaded => ({ type: StateType.Downloaded, update }), Updating: (update: IUpdate): Updating => ({ type: StateType.Updating, update }), Ready: (update: IUpdate): Ready => ({ type: StateType.Ready, update }), diff --git a/src/vs/platform/userDataProfile/browser/userDataProfile.ts b/src/vs/platform/userDataProfile/browser/userDataProfile.ts index f5da3f21f6f27..09d7963e21faf 100644 --- a/src/vs/platform/userDataProfile/browser/userDataProfile.ts +++ b/src/vs/platform/userDataProfile/browser/userDataProfile.ts @@ -88,17 +88,10 @@ export class BrowserUserDataProfilesService extends UserDataProfilesService impl } protected override getStoredProfileAssociations(): StoredProfileAssociations { - const migrateKey = 'profileAssociationsMigration'; try { const value = localStorage.getItem(UserDataProfilesService.PROFILE_ASSOCIATIONS_KEY); if (value) { - let associations: StoredProfileAssociations = JSON.parse(value); - if (!localStorage.getItem(migrateKey)) { - associations = this.migrateStoredProfileAssociations(associations); - this.saveStoredProfileAssociations(associations); - localStorage.setItem(migrateKey, 'true'); - } - return associations; + return JSON.parse(value); } } catch (error) { /* ignore */ diff --git a/src/vs/platform/userDataProfile/common/userDataProfile.ts b/src/vs/platform/userDataProfile/common/userDataProfile.ts index f9f1c6d133ddd..6b53a1d090123 100644 --- a/src/vs/platform/userDataProfile/common/userDataProfile.ts +++ b/src/vs/platform/userDataProfile/common/userDataProfile.ts @@ -40,7 +40,6 @@ export interface IUserDataProfile { readonly id: string; readonly isDefault: boolean; readonly name: string; - readonly shortName?: string; readonly icon?: string; readonly location: URI; readonly globalStorageHome: URI; @@ -85,7 +84,6 @@ export type WillRemoveProfileEvent = { }; export interface IUserDataProfileOptions { - readonly shortName?: string; readonly icon?: string; readonly useDefaultFlags?: UseDefaultProfileFlags; readonly transient?: boolean; @@ -127,7 +125,6 @@ export function reviveProfile(profile: UriDto, scheme: string) id: profile.id, isDefault: profile.isDefault, name: profile.name, - shortName: profile.shortName, icon: profile.icon, location: URI.revive(profile.location).with({ scheme }), globalStorageHome: URI.revive(profile.globalStorageHome).with({ scheme }), @@ -149,7 +146,6 @@ export function toUserDataProfile(id: string, name: string, location: URI, profi name, location, isDefault: false, - shortName: options?.shortName, icon: options?.icon, globalStorageHome: defaultProfile && options?.useDefaultFlags?.globalState ? defaultProfile.globalStorageHome : joinPath(location, 'globalStorage'), settingsResource: defaultProfile && options?.useDefaultFlags?.settings ? defaultProfile.settingsResource : joinPath(location, 'settings.json'), @@ -172,7 +168,6 @@ export type UserDataProfilesObject = { export type StoredUserDataProfile = { name: string; location: URI; - shortName?: string; icon?: string; useDefaultFlags?: UseDefaultProfileFlags; }; @@ -240,7 +235,7 @@ export class UserDataProfilesService extends Disposable implements IUserDataProf this.logService.warn('Skipping the invalid stored profile', storedProfile.location || storedProfile.name); continue; } - profiles.push(toUserDataProfile(basename(storedProfile.location), storedProfile.name, storedProfile.location, this.profilesCacheHome, { shortName: storedProfile.shortName, icon: storedProfile.icon, useDefaultFlags: storedProfile.useDefaultFlags }, defaultProfile)); + profiles.push(toUserDataProfile(basename(storedProfile.location), storedProfile.name, storedProfile.location, this.profilesCacheHome, { icon: storedProfile.icon, useDefaultFlags: storedProfile.useDefaultFlags }, defaultProfile)); } } catch (error) { this.logService.error(error); @@ -357,7 +352,6 @@ export class UserDataProfilesService extends Disposable implements IUserDataProf if (profile.id === existing.id) { if (!existing.isDefault) { profileToUpdate = toUserDataProfile(existing.id, options.name ?? existing.name, existing.location, this.profilesCacheHome, { - shortName: options.shortName ?? existing.shortName, icon: options.icon === null ? undefined : options.icon ?? existing.icon, transient: options.transient ?? existing.isTransient, useDefaultFlags: options.useDefaultFlags ?? existing.useDefaultFlags, @@ -605,7 +599,7 @@ export class UserDataProfilesService extends Disposable implements IUserDataProf continue; } if (!profile.isDefault) { - storedProfiles.push({ location: profile.location, name: profile.name, shortName: profile.shortName, icon: profile.icon, useDefaultFlags: profile.useDefaultFlags }); + storedProfiles.push({ location: profile.location, name: profile.name, icon: profile.icon, useDefaultFlags: profile.useDefaultFlags }); } if (profile.workspaces) { for (const workspace of profile.workspaces) { @@ -623,26 +617,6 @@ export class UserDataProfilesService extends Disposable implements IUserDataProf this._profilesObject = undefined; } - // TODO: @sandy081 Remove migration after couple of releases - protected migrateStoredProfileAssociations(storedProfileAssociations: StoredProfileAssociations): StoredProfileAssociations { - const workspaces: IStringDictionary = {}; - const defaultProfile = this.createDefaultProfile(); - if (storedProfileAssociations.workspaces) { - for (const [workspace, location] of Object.entries(storedProfileAssociations.workspaces)) { - const uri = URI.parse(location); - workspaces[workspace] = this.uriIdentityService.extUri.isEqual(uri, defaultProfile.location) ? defaultProfile.id : this.uriIdentityService.extUri.basename(uri); - } - } - const emptyWindows: IStringDictionary = {}; - if (storedProfileAssociations.emptyWindows) { - for (const [workspace, location] of Object.entries(storedProfileAssociations.emptyWindows)) { - const uri = URI.parse(location); - emptyWindows[workspace] = this.uriIdentityService.extUri.isEqual(uri, defaultProfile.location) ? defaultProfile.id : this.uriIdentityService.extUri.basename(uri); - } - } - return { workspaces, emptyWindows }; - } - protected getStoredProfiles(): StoredUserDataProfile[] { return []; } protected saveStoredProfiles(storedProfiles: StoredUserDataProfile[]): void { throw new Error('not implemented'); } diff --git a/src/vs/platform/userDataProfile/node/userDataProfile.ts b/src/vs/platform/userDataProfile/node/userDataProfile.ts index 24165365965ed..c1db01f750632 100644 --- a/src/vs/platform/userDataProfile/node/userDataProfile.ts +++ b/src/vs/platform/userDataProfile/node/userDataProfile.ts @@ -3,14 +3,13 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { URI, UriComponents, UriDto } from '../../../base/common/uri.js'; +import { URI, UriDto } from '../../../base/common/uri.js'; import { INativeEnvironmentService } from '../../environment/common/environment.js'; import { IFileService } from '../../files/common/files.js'; import { ILogService } from '../../log/common/log.js'; import { IStateReadService, IStateService } from '../../state/node/state.js'; import { IUriIdentityService } from '../../uriIdentity/common/uriIdentity.js'; import { IUserDataProfilesService, UserDataProfilesService as BaseUserDataProfilesService, StoredUserDataProfile, StoredProfileAssociations } from '../common/userDataProfile.js'; -import { IStringDictionary } from '../../../base/common/collections.js'; import { isString } from '../../../base/common/types.js'; import { SaveStrategy, StateService } from '../../state/node/stateService.js'; @@ -18,8 +17,6 @@ type StoredUserDataProfileState = StoredUserDataProfile & { location: URI | stri export class UserDataProfilesReadonlyService extends BaseUserDataProfilesService implements IUserDataProfilesService { - protected static readonly PROFILE_ASSOCIATIONS_MIGRATION_KEY = 'profileAssociationsMigration'; - constructor( @IStateReadService private readonly stateReadonlyService: IStateReadService, @IUriIdentityService uriIdentityService: IUriIdentityService, @@ -36,9 +33,7 @@ export class UserDataProfilesReadonlyService extends BaseUserDataProfilesService } protected override getStoredProfileAssociations(): StoredProfileAssociations { - const associations = this.stateReadonlyService.getItem(UserDataProfilesReadonlyService.PROFILE_ASSOCIATIONS_KEY, {}); - const migrated = this.stateReadonlyService.getItem(UserDataProfilesReadonlyService.PROFILE_ASSOCIATIONS_MIGRATION_KEY, false); - return migrated ? associations : this.migrateStoredProfileAssociations(associations); + return this.stateReadonlyService.getItem(UserDataProfilesReadonlyService.PROFILE_ASSOCIATIONS_KEY, {}); } protected override getDefaultProfileExtensionsLocation(): URI { @@ -67,15 +62,6 @@ export class UserDataProfilesService extends UserDataProfilesReadonlyService imp } } - protected override getStoredProfiles(): StoredUserDataProfile[] { - const storedProfiles = super.getStoredProfiles(); - if (!this.stateService.getItem('userDataProfilesMigration', false)) { - this.saveStoredProfiles(storedProfiles); - this.stateService.setItem('userDataProfilesMigration', true); - } - return storedProfiles; - } - protected override saveStoredProfileAssociations(storedProfileAssociations: StoredProfileAssociations): void { if (storedProfileAssociations.emptyWindows || storedProfileAssociations.workspaces) { this.stateService.setItem(UserDataProfilesService.PROFILE_ASSOCIATIONS_KEY, storedProfileAssociations); @@ -83,25 +69,6 @@ export class UserDataProfilesService extends UserDataProfilesReadonlyService imp this.stateService.removeItem(UserDataProfilesService.PROFILE_ASSOCIATIONS_KEY); } } - - protected override getStoredProfileAssociations(): StoredProfileAssociations { - const oldKey = 'workspaceAndProfileInfo'; - const storedWorkspaceInfos = this.stateService.getItem<{ workspace: UriComponents; profile: UriComponents }[]>(oldKey, undefined); - if (storedWorkspaceInfos) { - this.stateService.removeItem(oldKey); - const workspaces = storedWorkspaceInfos.reduce>((result, { workspace, profile }) => { - result[URI.revive(workspace).toString()] = URI.revive(profile).toString(); - return result; - }, {}); - this.stateService.setItem(UserDataProfilesService.PROFILE_ASSOCIATIONS_KEY, { workspaces } satisfies StoredProfileAssociations); - } - const associations = super.getStoredProfileAssociations(); - if (!this.stateService.getItem(UserDataProfilesService.PROFILE_ASSOCIATIONS_MIGRATION_KEY, false)) { - this.saveStoredProfileAssociations(associations); - this.stateService.setItem(UserDataProfilesService.PROFILE_ASSOCIATIONS_MIGRATION_KEY, true); - } - return associations; - } } export class ServerUserDataProfilesService extends UserDataProfilesService implements IUserDataProfilesService { diff --git a/src/vs/platform/userDataProfile/test/common/userDataProfileService.test.ts b/src/vs/platform/userDataProfile/test/common/userDataProfileService.test.ts index 31d0de50c8b4b..81edc45217c04 100644 --- a/src/vs/platform/userDataProfile/test/common/userDataProfileService.test.ts +++ b/src/vs/platform/userDataProfile/test/common/userDataProfileService.test.ts @@ -165,19 +165,6 @@ suite('UserDataProfileService (Common)', () => { assert.deepStrictEqual(testObject.profiles[1].id, profile.id); }); - test('short name', async () => { - const profile = await testObject.createNamedProfile('name', { shortName: 'short' }); - assert.strictEqual(profile.shortName, 'short'); - - await testObject.updateProfile(profile, { shortName: 'short changed' }); - - assert.deepStrictEqual(testObject.profiles.length, 2); - assert.deepStrictEqual(testObject.profiles[1].name, 'name'); - assert.deepStrictEqual(testObject.profiles[1].shortName, 'short changed'); - assert.deepStrictEqual(!!testObject.profiles[1].isTransient, false); - assert.deepStrictEqual(testObject.profiles[1].id, profile.id); - }); - test('profile using default profile for settings', async () => { const profile = await testObject.createNamedProfile('name', { useDefaultFlags: { settings: true } }); diff --git a/src/vs/platform/userDataSync/common/userDataProfilesManifestMerge.ts b/src/vs/platform/userDataSync/common/userDataProfilesManifestMerge.ts index 6e5b0108065b8..85e7cdec9a201 100644 --- a/src/vs/platform/userDataSync/common/userDataProfilesManifestMerge.ts +++ b/src/vs/platform/userDataSync/common/userDataProfilesManifestMerge.ts @@ -17,7 +17,6 @@ export type IMergeResult = Required; interface IUserDataProfileInfo { readonly id: string; readonly name: string; - readonly shortName?: string; readonly icon?: string; readonly useDefaultFlags?: UseDefaultProfileFlags; } @@ -120,14 +119,13 @@ function compare(from: IUserDataProfileInfo[] | null, to: IUserDataProfileInfo[] const removed = fromKeys.filter(key => !toKeys.includes(key)); const updated: string[] = []; - for (const { id, name, shortName, icon, useDefaultFlags } of from) { + for (const { id, name, icon, useDefaultFlags } of from) { if (removed.includes(id)) { continue; } const toProfile = to.find(p => p.id === id); if (!toProfile || toProfile.name !== name - || toProfile.shortName !== shortName || toProfile.icon !== icon || !equals(toProfile.useDefaultFlags, useDefaultFlags) ) { diff --git a/src/vs/platform/userDataSync/common/userDataProfilesManifestSync.ts b/src/vs/platform/userDataSync/common/userDataProfilesManifestSync.ts index 0cab7fc388944..438b76f47e04e 100644 --- a/src/vs/platform/userDataSync/common/userDataProfilesManifestSync.ts +++ b/src/vs/platform/userDataSync/common/userDataProfilesManifestSync.ts @@ -191,14 +191,14 @@ export class UserDataProfilesManifestSynchroniser extends AbstractSynchroniser i })); await Promise.all(local.added.map(async profile => { this.logService.trace(`${this.syncResourceLogLabel}: Creating '${profile.name}' profile...`); - await this.userDataProfilesService.createProfile(profile.id, profile.name, { shortName: profile.shortName, icon: profile.icon, useDefaultFlags: profile.useDefaultFlags }); + await this.userDataProfilesService.createProfile(profile.id, profile.name, { icon: profile.icon, useDefaultFlags: profile.useDefaultFlags }); this.logService.info(`${this.syncResourceLogLabel}: Created profile '${profile.name}'.`); })); await Promise.all(local.updated.map(async profile => { const localProfile = this.userDataProfilesService.profiles.find(p => p.id === profile.id); if (localProfile) { this.logService.trace(`${this.syncResourceLogLabel}: Updating '${profile.name}' profile...`); - await this.userDataProfilesService.updateProfile(localProfile, { name: profile.name, shortName: profile.shortName, icon: profile.icon, useDefaultFlags: profile.useDefaultFlags }); + await this.userDataProfilesService.updateProfile(localProfile, { name: profile.name, icon: profile.icon, useDefaultFlags: profile.useDefaultFlags }); this.logService.info(`${this.syncResourceLogLabel}: Updated profile '${profile.name}'.`); } else { this.logService.info(`${this.syncResourceLogLabel}: Could not find profile with id '${profile.id}' to update.`); @@ -214,7 +214,7 @@ export class UserDataProfilesManifestSynchroniser extends AbstractSynchroniser i for (const profile of remote?.added || []) { const collection = await this.userDataSyncStoreService.createCollection(this.syncHeaders); addedCollections.push(collection); - remoteProfiles.push({ id: profile.id, name: profile.name, collection, shortName: profile.shortName, icon: profile.icon, useDefaultFlags: profile.useDefaultFlags }); + remoteProfiles.push({ id: profile.id, name: profile.name, collection, icon: profile.icon, useDefaultFlags: profile.useDefaultFlags }); } } else { this.logService.info(`${this.syncResourceLogLabel}: Could not create remote profiles as there are too many profiles.`); @@ -225,7 +225,7 @@ export class UserDataProfilesManifestSynchroniser extends AbstractSynchroniser i for (const profile of remote?.updated || []) { const profileToBeUpdated = remoteProfiles.find(({ id }) => profile.id === id); if (profileToBeUpdated) { - remoteProfiles.splice(remoteProfiles.indexOf(profileToBeUpdated), 1, { ...profileToBeUpdated, id: profile.id, name: profile.name, shortName: profile.shortName, icon: profile.icon, useDefaultFlags: profile.useDefaultFlags }); + remoteProfiles.splice(remoteProfiles.indexOf(profileToBeUpdated), 1, { ...profileToBeUpdated, id: profile.id, name: profile.name, icon: profile.icon, useDefaultFlags: profile.useDefaultFlags }); } } diff --git a/src/vs/platform/userDataSync/common/userDataSync.ts b/src/vs/platform/userDataSync/common/userDataSync.ts index 05a93efd69b30..c3224e18bddb0 100644 --- a/src/vs/platform/userDataSync/common/userDataSync.ts +++ b/src/vs/platform/userDataSync/common/userDataSync.ts @@ -370,7 +370,6 @@ export interface ISyncUserDataProfile { readonly id: string; readonly collection: string; readonly name: string; - readonly shortName?: string; readonly icon?: string; readonly useDefaultFlags?: UseDefaultProfileFlags; } diff --git a/src/vs/platform/userDataSync/test/common/userDataProfilesManifestMerge.test.ts b/src/vs/platform/userDataSync/test/common/userDataProfilesManifestMerge.test.ts index c40b4781ee877..5479e19d7ac39 100644 --- a/src/vs/platform/userDataSync/test/common/userDataProfilesManifestMerge.test.ts +++ b/src/vs/platform/userDataSync/test/common/userDataProfilesManifestMerge.test.ts @@ -90,7 +90,7 @@ suite('UserDataProfilesManifestMerge', () => { const remoteProfiles: ISyncUserDataProfile[] = [ { id: '1', name: '1', collection: '1' }, { id: '2', name: '2', collection: '2' }, - { id: '3', name: '3', collection: '3', shortName: 'short 3' }, + { id: '3', name: '3', collection: '3' }, { id: '4', name: 'changed remote', collection: '4' }, { id: '5', name: '5', collection: '5' }, { id: '7', name: '7', collection: '7' }, @@ -103,7 +103,7 @@ suite('UserDataProfilesManifestMerge', () => { assert.deepStrictEqual(actual.local.added, [remoteProfiles[5], remoteProfiles[6]]); assert.deepStrictEqual(actual.local.removed, [localProfiles[4]]); - assert.deepStrictEqual(actual.local.updated, [remoteProfiles[2], remoteProfiles[3], remoteProfiles[7]]); + assert.deepStrictEqual(actual.local.updated, [remoteProfiles[3], remoteProfiles[7]]); assert.deepStrictEqual(actual.remote?.added, [localProfiles[5]]); assert.deepStrictEqual(actual.remote?.updated, [localProfiles[0], localProfiles[7]]); assert.deepStrictEqual(actual.remote?.removed, [remoteProfiles[1]]); diff --git a/src/vs/platform/userDataSync/test/common/userDataProfilesManifestSync.test.ts b/src/vs/platform/userDataSync/test/common/userDataProfilesManifestSync.test.ts index d52b6a0db1986..8448967c32fa9 100644 --- a/src/vs/platform/userDataSync/test/common/userDataProfilesManifestSync.test.ts +++ b/src/vs/platform/userDataSync/test/common/userDataProfilesManifestSync.test.ts @@ -110,7 +110,7 @@ suite('UserDataProfilesManifestSync', () => { assert.deepStrictEqual(testObject.conflicts.conflicts, []); const profiles = getLocalProfiles(testClient); - assert.deepStrictEqual(profiles, [{ id: '1', name: 'name 1', shortName: undefined, useDefaultFlags: undefined }]); + assert.deepStrictEqual(profiles, [{ id: '1', name: 'name 1', useDefaultFlags: undefined }]); }); }); @@ -125,7 +125,7 @@ suite('UserDataProfilesManifestSync', () => { assert.deepStrictEqual(testObject.conflicts.conflicts, []); const profiles = getLocalProfiles(testClient); - assert.deepStrictEqual(profiles, [{ id: '1', name: 'name 1', shortName: undefined, useDefaultFlags: undefined }, { id: '2', name: 'name 2', shortName: undefined, useDefaultFlags: undefined }]); + assert.deepStrictEqual(profiles, [{ id: '1', name: 'name 1', useDefaultFlags: undefined }, { id: '2', name: 'name 2', useDefaultFlags: undefined }]); const { content } = await testClient.read(testObject.resource); assert.ok(content !== null); @@ -146,7 +146,7 @@ suite('UserDataProfilesManifestSync', () => { assert.deepStrictEqual(testObject.conflicts.conflicts, []); const profiles = getLocalProfiles(testClient); - assert.deepStrictEqual(profiles, [{ id: '1', name: 'name 1', shortName: undefined, useDefaultFlags: undefined }]); + assert.deepStrictEqual(profiles, [{ id: '1', name: 'name 1', useDefaultFlags: undefined }]); const { content } = await testClient.read(testObject.resource); assert.ok(content !== null); @@ -157,7 +157,7 @@ suite('UserDataProfilesManifestSync', () => { test('sync adding a profile', async () => { await runWithFakedTimers({}, async () => { - await testClient.instantiationService.get(IUserDataProfilesService).createProfile('1', 'name 1', { shortName: 'short 1' }); + await testClient.instantiationService.get(IUserDataProfilesService).createProfile('1', 'name 1'); await testObject.sync(await testClient.getResourceManifest()); await client2.sync(); @@ -165,15 +165,15 @@ suite('UserDataProfilesManifestSync', () => { await testObject.sync(await testClient.getResourceManifest()); assert.strictEqual(testObject.status, SyncStatus.Idle); assert.deepStrictEqual(testObject.conflicts.conflicts, []); - assert.deepStrictEqual(getLocalProfiles(testClient), [{ id: '1', name: 'name 1', shortName: 'short 1', useDefaultFlags: undefined }, { id: '2', name: 'name 2', shortName: undefined, useDefaultFlags: undefined }]); + assert.deepStrictEqual(getLocalProfiles(testClient), [{ id: '1', name: 'name 1', useDefaultFlags: undefined }, { id: '2', name: 'name 2', useDefaultFlags: undefined }]); await client2.sync(); - assert.deepStrictEqual(getLocalProfiles(client2), [{ id: '1', name: 'name 1', shortName: 'short 1', useDefaultFlags: undefined }, { id: '2', name: 'name 2', shortName: undefined, useDefaultFlags: undefined }]); + assert.deepStrictEqual(getLocalProfiles(client2), [{ id: '1', name: 'name 1', useDefaultFlags: undefined }, { id: '2', name: 'name 2', useDefaultFlags: undefined }]); const { content } = await testClient.read(testObject.resource); assert.ok(content !== null); const actual = parseRemoteProfiles(content); - assert.deepStrictEqual(actual, [{ id: '1', name: 'name 1', collection: '1', shortName: 'short 1' }, { id: '2', name: 'name 2', collection: '2' }]); + assert.deepStrictEqual(actual, [{ id: '1', name: 'name 1', collection: '1' }, { id: '2', name: 'name 2', collection: '2' }]); }); }); @@ -183,19 +183,19 @@ suite('UserDataProfilesManifestSync', () => { await testObject.sync(await testClient.getResourceManifest()); await client2.sync(); - await testClient.instantiationService.get(IUserDataProfilesService).updateProfile(profile, { name: 'name 2', shortName: '2' }); + await testClient.instantiationService.get(IUserDataProfilesService).updateProfile(profile, { name: 'name 2' }); await testObject.sync(await testClient.getResourceManifest()); assert.strictEqual(testObject.status, SyncStatus.Idle); assert.deepStrictEqual(testObject.conflicts.conflicts, []); - assert.deepStrictEqual(getLocalProfiles(testClient), [{ id: '1', name: 'name 2', shortName: '2', useDefaultFlags: undefined }]); + assert.deepStrictEqual(getLocalProfiles(testClient), [{ id: '1', name: 'name 2', useDefaultFlags: undefined }]); await client2.sync(); - assert.deepStrictEqual(getLocalProfiles(client2), [{ id: '1', name: 'name 2', shortName: '2', useDefaultFlags: undefined }]); + assert.deepStrictEqual(getLocalProfiles(client2), [{ id: '1', name: 'name 2', useDefaultFlags: undefined }]); const { content } = await testClient.read(testObject.resource); assert.ok(content !== null); const actual = parseRemoteProfiles(content); - assert.deepStrictEqual(actual, [{ id: '1', name: 'name 2', collection: '1', shortName: '2' }]); + assert.deepStrictEqual(actual, [{ id: '1', name: 'name 2', collection: '1' }]); }); }); @@ -210,10 +210,10 @@ suite('UserDataProfilesManifestSync', () => { await testObject.sync(await testClient.getResourceManifest()); assert.strictEqual(testObject.status, SyncStatus.Idle); assert.deepStrictEqual(testObject.conflicts.conflicts, []); - assert.deepStrictEqual(getLocalProfiles(testClient), [{ id: '2', name: 'name 2', shortName: undefined, useDefaultFlags: undefined }]); + assert.deepStrictEqual(getLocalProfiles(testClient), [{ id: '2', name: 'name 2', useDefaultFlags: undefined }]); await client2.sync(); - assert.deepStrictEqual(getLocalProfiles(client2), [{ id: '2', name: 'name 2', shortName: undefined, useDefaultFlags: undefined }]); + assert.deepStrictEqual(getLocalProfiles(client2), [{ id: '2', name: 'name 2', useDefaultFlags: undefined }]); const { content } = await testClient.read(testObject.resource); assert.ok(content !== null); @@ -236,7 +236,7 @@ suite('UserDataProfilesManifestSync', () => { const actual = parseRemoteProfiles(content); assert.deepStrictEqual(actual, [{ id: '1', name: 'name 1', collection: '1', useDefaultFlags: { keybindings: true } }]); - assert.deepStrictEqual(getLocalProfiles(testClient), [{ id: '1', name: 'name 1', shortName: undefined, useDefaultFlags: { keybindings: true } }]); + assert.deepStrictEqual(getLocalProfiles(testClient), [{ id: '1', name: 'name 1', useDefaultFlags: { keybindings: true } }]); }); }); @@ -258,7 +258,7 @@ suite('UserDataProfilesManifestSync', () => { assert.ok(content !== null); const actual = parseRemoteProfiles(content); assert.deepStrictEqual(actual, [{ id: '1', name: 'name 1', collection: '1', useDefaultFlags: { keybindings: true } }]); - assert.deepStrictEqual(getLocalProfiles(testClient), [{ id: '1', name: 'name 1', shortName: undefined, useDefaultFlags: { keybindings: true } }]); + assert.deepStrictEqual(getLocalProfiles(testClient), [{ id: '1', name: 'name 1', useDefaultFlags: { keybindings: true } }]); }); }); @@ -281,7 +281,7 @@ suite('UserDataProfilesManifestSync', () => { const actual = parseRemoteProfiles(content); assert.deepStrictEqual(actual, [{ id: '1', name: 'name 1', collection: '1', useDefaultFlags: { keybindings: true } }]); - assert.deepStrictEqual(getLocalProfiles(testClient), [{ id: '1', name: 'name 1', shortName: undefined, useDefaultFlags: { keybindings: true } }]); + assert.deepStrictEqual(getLocalProfiles(testClient), [{ id: '1', name: 'name 1', useDefaultFlags: { keybindings: true } }]); }); }); @@ -290,10 +290,10 @@ suite('UserDataProfilesManifestSync', () => { return JSON.parse(syncData.content); } - function getLocalProfiles(client: UserDataSyncClient): { id: string; name: string; shortName?: string }[] { + function getLocalProfiles(client: UserDataSyncClient): { id: string; name: string }[] { return client.instantiationService.get(IUserDataProfilesService).profiles .slice(1).sort((a, b) => a.name.localeCompare(b.name)) - .map(profile => ({ id: profile.id, name: profile.name, shortName: profile.shortName, useDefaultFlags: profile.useDefaultFlags })); + .map(profile => ({ id: profile.id, name: profile.name, useDefaultFlags: profile.useDefaultFlags })); } diff --git a/src/vs/workbench/api/browser/mainThreadAuthentication.ts b/src/vs/workbench/api/browser/mainThreadAuthentication.ts index 24e7fdced8c9f..67ba984057628 100644 --- a/src/vs/workbench/api/browser/mainThreadAuthentication.ts +++ b/src/vs/workbench/api/browser/mainThreadAuthentication.ts @@ -210,11 +210,12 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu this._removeAccountPreference(extensionId, providerId, scopes); } - const matchingAccountPreferenceSession = this._getAccountPreference(extensionId, providerId, scopes, sessions) - // If account was specified, grab the first session since all sessions will be using that account (will be undefined if there are no sessions) - ?? options.account - ? sessions[0] - : undefined; + const matchingAccountPreferenceSession = + // If an account was passed in, that takes precedence over the account preference + options.account + // We only support one session per account per set of scopes so grab the first one here + ? sessions[0] + : this._getAccountPreference(extensionId, providerId, scopes, sessions); // Check if the sessions we have are valid if (!options.forceNewSession && sessions.length) { @@ -289,7 +290,7 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu if (session) { this.sendProviderUsageTelemetry(extensionId, providerId); - this.authenticationUsageService.addAccountUsage(providerId, session.account.label, extensionId, extensionName); + this.authenticationUsageService.addAccountUsage(providerId, session.account.label, scopes, extensionId, extensionName); } return session; diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 7afaa3492335b..83e055e89342d 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -1742,6 +1742,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I EditSessionIdentityMatch: EditSessionIdentityMatch, InteractiveSessionVoteDirection: extHostTypes.InteractiveSessionVoteDirection, ChatCopyKind: extHostTypes.ChatCopyKind, + ChatEditingSessionActionOutcome: extHostTypes.ChatEditingSessionActionOutcome, InteractiveEditorResponseFeedbackKind: extHostTypes.InteractiveEditorResponseFeedbackKind, DebugStackFrame: extHostTypes.DebugStackFrame, DebugThread: extHostTypes.DebugThread, diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index e67f9c22340a6..426f4128330bb 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -2795,7 +2795,7 @@ export namespace ChatPromptReference { range: variable.range && [variable.range.start, variable.range.endExclusive], value: isUriComponents(value) ? URI.revive(value) : value && typeof value === 'object' && 'uri' in value && 'range' in value && isUriComponents(value.uri) ? - Location.to(revive(value)) : variable.isImage ? new types.ChatReferenceBinaryData('image/*', () => Promise.resolve(new Uint8Array(Object.values(value)))) : value, + Location.to(revive(value)) : variable.isImage ? new types.ChatReferenceBinaryData(variable.mimeType ?? 'image/png', () => Promise.resolve(new Uint8Array(Object.values(value)))) : value, modelDescription: variable.modelDescription }; } @@ -2868,6 +2868,8 @@ export namespace ChatAgentUserActionEvent { return { action: followupAction, result: ehResult }; } else if (event.action.kind === 'inlineChat') { return { action: { kind: 'editor', accepted: event.action.action === 'accepted' }, result: ehResult }; + } else if (event.action.kind === 'chatEditingSessionAction') { + return { action: { kind: 'chatEditingSessionAction', outcome: event.action.outcome === 'accepted' ? types.ChatEditingSessionActionOutcome.Accepted : types.ChatEditingSessionActionOutcome.Rejected, uri: URI.revive(event.action.uri), hasRemainingEdits: event.action.hasRemainingEdits }, result: ehResult }; } else { return { action: event.action, result: ehResult }; } diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index 9f1ac00eab0da..956c9897bcb3b 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -4342,6 +4342,11 @@ export class ChatCompletionItem implements vscode.ChatCompletionItem { } } +export enum ChatEditingSessionActionOutcome { + Accepted = 1, + Rejected = 2 +} + //#endregion //#region Interactive Editor diff --git a/src/vs/workbench/browser/parts/editor/editorTabsControl.ts b/src/vs/workbench/browser/parts/editor/editorTabsControl.ts index ed6195328012d..7306519d4f79b 100644 --- a/src/vs/workbench/browser/parts/editor/editorTabsControl.ts +++ b/src/vs/workbench/browser/parts/editor/editorTabsControl.ts @@ -44,8 +44,6 @@ import { IAuxiliaryEditorPart, MergeGroupMode } from '../../../services/editor/c import { isMacintosh } from '../../../../base/common/platform.js'; import { IHostService } from '../../../services/host/browser/host.js'; import { ServiceCollection } from '../../../../platform/instantiation/common/serviceCollection.js'; -import { IHoverDelegate } from '../../../../base/browser/ui/hover/hoverDelegate.js'; -import { getDefaultHoverDelegate } from '../../../../base/browser/ui/hover/hoverDelegateFactory.js'; import { IBaseActionViewItemOptions } from '../../../../base/browser/ui/actionbar/actionViewItems.js'; import { MarkdownString } from '../../../../base/common/htmlContent.js'; import { IManagedHoverTooltipMarkdownString } from '../../../../base/browser/ui/hover/hover.js'; @@ -127,8 +125,6 @@ export abstract class EditorTabsControl extends Themable implements IEditorTabsC private renderDropdownAsChildElement: boolean; - private readonly tabsHoverDelegate: IHoverDelegate; - constructor( protected readonly parent: HTMLElement, protected readonly editorPartsView: IEditorPartsView, @@ -149,8 +145,6 @@ export abstract class EditorTabsControl extends Themable implements IEditorTabsC this.renderDropdownAsChildElement = false; - this.tabsHoverDelegate = getDefaultHoverDelegate('mouse'); - const container = this.create(parent); // Context Keys @@ -469,10 +463,6 @@ export abstract class EditorTabsControl extends Themable implements IEditorTabsC return title; } - protected getHoverDelegate(): IHoverDelegate { - return this.tabsHoverDelegate; - } - protected updateTabHeight(): void { this.parent.style.setProperty('--editor-group-tab-height', `${this.tabHeight}px`); } diff --git a/src/vs/workbench/browser/parts/editor/multiEditorTabsControl.ts b/src/vs/workbench/browser/parts/editor/multiEditorTabsControl.ts index 9fa9e9094851c..397d6204cc1a6 100644 --- a/src/vs/workbench/browser/parts/editor/multiEditorTabsControl.ts +++ b/src/vs/workbench/browser/parts/editor/multiEditorTabsControl.ts @@ -817,7 +817,7 @@ export class MultiEditorTabsControl extends EditorTabsControl { tabContainer.appendChild(tabBorderTopContainer); // Tab Editor Label - const editorLabel = this.tabResourceLabels.create(tabContainer, { hoverDelegate: this.getHoverDelegate() }); + const editorLabel = this.tabResourceLabels.create(tabContainer, { hoverTargetOverrride: tabContainer }); // Tab Actions const tabActionsContainer = document.createElement('div'); diff --git a/src/vs/workbench/browser/parts/editor/singleEditorTabsControl.ts b/src/vs/workbench/browser/parts/editor/singleEditorTabsControl.ts index 7f9446ac198d9..b8d31c0d171a5 100644 --- a/src/vs/workbench/browser/parts/editor/singleEditorTabsControl.ts +++ b/src/vs/workbench/browser/parts/editor/singleEditorTabsControl.ts @@ -51,7 +51,7 @@ export class SingleEditorTabsControl extends EditorTabsControl { titleContainer.appendChild(labelContainer); // Editor Label - this.editorLabel = this._register(this.instantiationService.createInstance(ResourceLabel, labelContainer, { hoverDelegate: this.getHoverDelegate() })).element; + this.editorLabel = this._register(this.instantiationService.createInstance(ResourceLabel, labelContainer, {})).element; this._register(addDisposableListener(this.editorLabel.element, EventType.CLICK, e => this.onTitleLabelClick(e))); // Breadcrumbs diff --git a/src/vs/workbench/contrib/authentication/browser/actions/manageAccountPreferencesForExtensionAction.ts b/src/vs/workbench/contrib/authentication/browser/actions/manageAccountPreferencesForExtensionAction.ts index bd24203b50247..e86aa27e10981 100644 --- a/src/vs/workbench/contrib/authentication/browser/actions/manageAccountPreferencesForExtensionAction.ts +++ b/src/vs/workbench/contrib/authentication/browser/actions/manageAccountPreferencesForExtensionAction.ts @@ -8,8 +8,9 @@ import { DisposableStore, IDisposable } from '../../../../../base/common/lifecyc import { localize, localize2 } from '../../../../../nls.js'; import { Action2 } from '../../../../../platform/actions/common/actions.js'; import { IInstantiationService, ServicesAccessor } from '../../../../../platform/instantiation/common/instantiation.js'; +import { ILogService } from '../../../../../platform/log/common/log.js'; import { IQuickInputService, IQuickPick, IQuickPickItem, QuickPickInput } from '../../../../../platform/quickinput/common/quickInput.js'; -import { IAuthenticationUsageService } from '../../../../services/authentication/browser/authenticationUsageService.js'; +import { IAccountUsage, IAuthenticationUsageService } from '../../../../services/authentication/browser/authenticationUsageService.js'; import { AuthenticationSessionAccount, IAuthenticationExtensionsService, IAuthenticationService } from '../../../../services/authentication/common/authentication.js'; import { IExtensionService } from '../../../../services/extensions/common/extensions.js'; @@ -28,8 +29,17 @@ export class ManageAccountPreferencesForExtensionAction extends Action2 { } } -interface AccountPreferenceQuickPickItem extends IQuickPickItem { +type AccountPreferenceQuickPickItem = NewAccountQuickPickItem | ExistingAccountQuickPickItem; + +interface NewAccountQuickPickItem extends IQuickPickItem { + account?: undefined; + scopes: string[]; + providerId: string; +} + +interface ExistingAccountQuickPickItem extends IQuickPickItem { account: AuthenticationSessionAccount; + scopes?: undefined; providerId: string; } @@ -39,7 +49,8 @@ class ManageAccountPreferenceForExtensionActionImpl { @IQuickInputService private readonly _quickInputService: IQuickInputService, @IAuthenticationUsageService private readonly _authenticationUsageService: IAuthenticationUsageService, @IAuthenticationExtensionsService private readonly _authenticationExtensionsService: IAuthenticationExtensionsService, - @IExtensionService private readonly _extensionService: IExtensionService + @IExtensionService private readonly _extensionService: IExtensionService, + @ILogService private readonly _logService: ILogService ) { } async run(extensionId?: string, providerId?: string) { @@ -52,7 +63,7 @@ class ManageAccountPreferenceForExtensionActionImpl { } const providerIds = new Array(); - const providerIdToAccounts = new Map>(); + const providerIdToAccounts = new Map>(); if (providerId) { providerIds.push(providerId); providerIdToAccounts.set(providerId, await this._authenticationService.getAccounts(providerId)); @@ -90,7 +101,27 @@ class ManageAccountPreferenceForExtensionActionImpl { } const currentAccountNamePreference = this._authenticationExtensionsService.getAccountPreference(extensionId, chosenProviderId); - const items: Array> = this._getItems(providerIdToAccounts.get(chosenProviderId)!, chosenProviderId, currentAccountNamePreference); + const accounts = providerIdToAccounts.get(chosenProviderId)!; + const items: Array> = this._getItems(accounts, chosenProviderId, currentAccountNamePreference); + + // If the provider supports multiple accounts, add an option to use a new account + const provider = this._authenticationService.getProvider(chosenProviderId); + if (provider.supportsMultipleAccounts) { + // Get the last used scopes for the last used account. This will be used to pre-fill the scopes when adding a new account. + // If there's no scopes, then don't add this option. + const lastUsedScopes = accounts + .flatMap(account => this._authenticationUsageService.readAccountUsages(chosenProviderId!, account.label).find(u => u.extensionId === extensionId.toLowerCase())) + .filter((usage): usage is IAccountUsage => !!usage) + .sort((a, b) => b.lastUsed - a.lastUsed)?.[0]?.scopes; + if (lastUsedScopes) { + items.push({ type: 'separator' }); + items.push({ + providerId: chosenProviderId, + scopes: lastUsedScopes, + label: localize('use new account', "Use a new account..."), + }); + } + } const disposables = new DisposableStore(); const picker = this._createQuickPick(disposables, extensionId, extension.displayName ?? extension.name); @@ -111,9 +142,9 @@ class ManageAccountPreferenceForExtensionActionImpl { picker.placeholder = localize('placeholder', "Manage '{0}' account preferences...", extensionLabel); picker.title = localize('title', "'{0}' Account Preferences For This Workspace", extensionLabel); picker.sortByLabel = false; - disposableStore.add(picker.onDidAccept(() => { - this._accept(extensionId, picker.selectedItems); + disposableStore.add(picker.onDidAccept(async () => { picker.hide(); + await this._accept(extensionId, picker.selectedItems); })); return picker; } @@ -142,9 +173,20 @@ class ManageAccountPreferenceForExtensionActionImpl { return Event.filter(picker.onDidTriggerButton, (e) => e === this._quickInputService.backButton)(() => this.run()); } - private _accept(extensionId: string, selectedItems: ReadonlyArray) { + private async _accept(extensionId: string, selectedItems: ReadonlyArray) { for (const item of selectedItems) { - const account = item.account; + let account: AuthenticationSessionAccount; + if (!item.account) { + try { + const session = await this._authenticationService.createSession(item.providerId, item.scopes); + account = session.account; + } catch (e) { + this._logService.error(e); + continue; + } + } else { + account = item.account; + } const providerId = item.providerId; const currentAccountName = this._authenticationExtensionsService.getAccountPreference(extensionId, providerId); if (currentAccountName === account.label) { diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatActions.ts index 01abc19098ac8..e272d68126fa7 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatActions.ts @@ -10,6 +10,7 @@ import { fromNowByDay } from '../../../../../base/common/date.js'; import { KeyCode, KeyMod } from '../../../../../base/common/keyCodes.js'; import { DisposableStore } from '../../../../../base/common/lifecycle.js'; import { ThemeIcon } from '../../../../../base/common/themables.js'; +import { URI } from '../../../../../base/common/uri.js'; import { ICodeEditor } from '../../../../../editor/browser/editorBrowser.js'; import { EditorAction2, ServicesAccessor } from '../../../../../editor/browser/editorExtensions.js'; import { Position } from '../../../../../editor/common/core/position.js'; @@ -55,6 +56,17 @@ export interface IChatViewOpenOptions { * Any previous chat requests and responses that should be shown in the chat view. */ previousRequests?: IChatViewOpenRequestEntry[]; + + /** + * The image(s) to include in the request + */ + images?: IChatImageAttachment[]; +} + +export interface IChatImageAttachment { + id: string; + name: string; + value: URI | Uint8Array; } export interface IChatViewOpenRequestEntry { @@ -101,6 +113,16 @@ class OpenChatGlobalAction extends Action2 { chatService.addCompleteRequest(chatWidget.viewModel.sessionId, request, undefined, 0, { message: response }); } } + if (opts?.images) { + chatWidget.attachmentModel.clear(); + for (const image of opts.images) { + chatWidget.attachmentModel.addContext({ + ...image, + isDynamic: true, + isImage: true + }); + } + } if (opts?.query) { if (opts.isPartialQuery) { chatWidget.setInput(opts.query); diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatContextActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatContextActions.ts index 5fa21cf0d348a..ab4664ef5e5f8 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatContextActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatContextActions.ts @@ -20,13 +20,18 @@ import { Action2, MenuId, registerAction2 } from '../../../../../platform/action import { IClipboardService } from '../../../../../platform/clipboard/common/clipboardService.js'; import { ICommandService } from '../../../../../platform/commands/common/commands.js'; import { IConfigurationService } from '../../../../../platform/configuration/common/configuration.js'; -import { ContextKeyExpr } from '../../../../../platform/contextkey/common/contextkey.js'; +import { ContextKeyExpr, IContextKeyService } from '../../../../../platform/contextkey/common/contextkey.js'; import { KeybindingWeight } from '../../../../../platform/keybinding/common/keybindingsRegistry.js'; +import { ILabelService } from '../../../../../platform/label/common/label.js'; import { AnythingQuickAccessProviderRunOptions } from '../../../../../platform/quickinput/common/quickAccess.js'; import { IQuickInputService, IQuickPickItem, IQuickPickItemWithResource, IQuickPickSeparator, QuickPickItem } from '../../../../../platform/quickinput/common/quickInput.js'; -import { CHAT_CATEGORY } from './chatActions.js'; -import { IChatWidget, IChatWidgetService, IQuickChatService, showChatView } from '../chat.js'; -import { isQuickChat } from '../chatWidget.js'; +import { ActiveEditorContext } from '../../../../common/contextkeys.js'; +import { IEditorService } from '../../../../services/editor/common/editorService.js'; +import { IViewsService } from '../../../../services/views/common/viewsService.js'; +import { AnythingQuickAccessProvider } from '../../../search/browser/anythingQuickAccess.js'; +import { ISymbolQuickPickItem, SymbolsQuickAccessProvider } from '../../../search/browser/symbolsQuickAccess.js'; +import { SearchContext } from '../../../search/common/constants.js'; +import { VIEW_ID as SEARCH_VIEW_ID } from '../../../../services/search/common/search.js'; import { ChatAgentLocation, IChatAgentService } from '../../common/chatAgents.js'; import { CONTEXT_CHAT_LOCATION, CONTEXT_IN_CHAT_INPUT } from '../../common/chatContextKeys.js'; import { IChatEditingService } from '../../common/chatEditingService.js'; @@ -34,12 +39,11 @@ import { IChatRequestVariableEntry } from '../../common/chatModel.js'; import { ChatRequestAgentPart } from '../../common/chatParserTypes.js'; import { IChatVariableData, IChatVariablesService } from '../../common/chatVariables.js'; import { ILanguageModelToolsService } from '../../common/languageModelToolsService.js'; -import { ISymbolQuickPickItem, SymbolsQuickAccessProvider } from '../../../search/browser/symbolsQuickAccess.js'; -import { IEditorService } from '../../../../services/editor/common/editorService.js'; -import { IViewsService } from '../../../../services/views/common/viewsService.js'; -import { ActiveEditorContext } from '../../../../common/contextkeys.js'; -import { imageToHash, isImage } from '../chatImagePaste.js'; -import { AnythingQuickAccessProvider } from '../../../search/browser/anythingQuickAccess.js'; +import { imageToHash, isImage } from '../chatPasteProviders.js'; +import { IChatWidget, IChatWidgetService, IQuickChatService, showChatView } from '../chat.js'; +import { isQuickChat } from '../chatWidget.js'; +import { CHAT_CATEGORY } from './chatActions.js'; +import { SearchView } from '../../../search/browser/searchView.js'; export function registerChatContextActions() { registerAction2(AttachContextAction); @@ -50,7 +54,7 @@ export function registerChatContextActions() { /** * We fill the quickpick with these types, and enable some quick access providers */ -type IAttachmentQuickPickItem = ICommandVariableQuickPickItem | IQuickAccessQuickPickItem | IToolQuickPickItem | IImageQuickPickItem | IVariableQuickPickItem; +type IAttachmentQuickPickItem = ICommandVariableQuickPickItem | IQuickAccessQuickPickItem | IToolQuickPickItem | IImageQuickPickItem | IVariableQuickPickItem | IOpenEditorsQuickPickItem | ISearchResultsQuickPickItem; /** * These are the types that we can get out of the quick pick @@ -79,6 +83,18 @@ function isIQuickPickItemWithResource(obj: unknown): obj is IQuickPickItemWithRe && URI.isUri((obj as IQuickPickItemWithResource).resource)); } +function isIOpenEditorsQuickPickItem(obj: unknown): obj is IOpenEditorsQuickPickItem { + return ( + typeof obj === 'object' + && (obj as IOpenEditorsQuickPickItem).id === 'open-editors'); +} + +function isISearchResultsQuickPickItem(obj: unknown): obj is ISearchResultsQuickPickItem { + return ( + typeof obj === 'object' + && (obj as ISearchResultsQuickPickItem).kind === 'search-results'); +} + interface IImageQuickPickItem extends IQuickPickItem { kind: 'image'; id: string; @@ -113,6 +129,18 @@ interface IQuickAccessQuickPickItem extends IQuickPickItem { prefix: string; } +interface IOpenEditorsQuickPickItem extends IQuickPickItem { + kind: 'open-editors'; + id: 'open-editors'; + icon?: ThemeIcon; +} + +interface ISearchResultsQuickPickItem extends IQuickPickItem { + kind: 'search-results'; + id: string; + icon?: ThemeIcon; +} + class AttachFileAction extends Action2 { static readonly ID = 'workbench.action.chat.attachFile'; @@ -230,7 +258,7 @@ export class AttachContextAction extends Action2 { `:${item.range.startLineNumber}`); } - private async _attachContext(widget: IChatWidget, commandService: ICommandService, clipboardService: IClipboardService, chatEditingService: IChatEditingService | undefined, ...picks: IChatContextQuickPickItem[]) { + private async _attachContext(widget: IChatWidget, commandService: ICommandService, clipboardService: IClipboardService, editorService: IEditorService, labelService: ILabelService, viewsService: IViewsService, chatEditingService: IChatEditingService | undefined, ...picks: IChatContextQuickPickItem[]) { const toAttach: IChatRequestVariableEntry[] = []; for (const pick of picks) { if (isISymbolQuickPickItem(pick) && pick.symbol) { @@ -273,6 +301,31 @@ export class AttachContextAction extends Action2 { name: pick.symbolName!, isDynamic: true }); + } else if (isIOpenEditorsQuickPickItem(pick)) { + for (const editor of editorService.editors) { + if (editor.resource) { + toAttach.push({ + id: this._getFileContextId({ resource: editor.resource }), + value: editor.resource, + name: labelService.getUriBasenameLabel(editor.resource), + isFile: true, + isDynamic: true + }); + chatEditingService?.addFileToWorkingSet(editor.resource); + } + } + } else if (isISearchResultsQuickPickItem(pick)) { + const searchView = viewsService.getViewWithId(SEARCH_VIEW_ID) as SearchView; + for (const result of searchView.model.searchResult.matches()) { + toAttach.push({ + id: this._getFileContextId({ resource: result.resource }), + value: result.resource, + name: labelService.getUriBasenameLabel(result.resource), + isFile: true, + isDynamic: true + }); + chatEditingService?.addFileToWorkingSet(result.resource); + } } else { // Anything else is an attachment const attachmentPick = pick as IAttachmentQuickPickItem; @@ -337,6 +390,11 @@ export class AttachContextAction extends Action2 { const quickChatService = accessor.get(IQuickChatService); const clipboardService = accessor.get(IClipboardService); const configurationService = accessor.get(IConfigurationService); + const editorService = accessor.get(IEditorService); + const labelService = accessor.get(ILabelService); + const contextKeyService = accessor.get(IContextKeyService); + const viewsService = accessor.get(IViewsService); + const context: { widget?: IChatWidget; showFilesOnly?: boolean; placeholder?: string } | undefined = args[0]; const widget = context?.widget ?? widgetService.lastFocusedWidget; if (!widget) { @@ -440,6 +498,23 @@ export class AttachContextAction extends Action2 { } }); } + } else if (context.showFilesOnly) { + if (editorService.count > 0) { + quickPickItems.push({ + kind: 'open-editors', + id: 'open-editors', + label: localize('chatContext.editors', 'Open Editors'), + iconClass: ThemeIcon.asClassName(Codicon.files), + }); + } + if (SearchContext.HasSearchResults.getValue(contextKeyService)) { + quickPickItems.push({ + kind: 'search-results', + id: 'search-results', + label: localize('chatContext.searchResults', 'Search Results'), + iconClass: ThemeIcon.asClassName(Codicon.search), + }); + } } function extractTextFromIconLabel(label: string | undefined): string { @@ -456,19 +531,19 @@ export class AttachContextAction extends Action2 { const second = extractTextFromIconLabel(b.label).toUpperCase(); return compare(first, second); - }), clipboardService, chatEditingService, '', context?.placeholder); + }), clipboardService, editorService, labelService, viewsService, chatEditingService, '', context?.placeholder); } - private _show(quickInputService: IQuickInputService, commandService: ICommandService, widget: IChatWidget, quickChatService: IQuickChatService, quickPickItems: (IChatContextQuickPickItem | QuickPickItem)[] | undefined, clipboardService: IClipboardService, chatEditingService: IChatEditingService | undefined, query: string = '', placeholder?: string) { + private _show(quickInputService: IQuickInputService, commandService: ICommandService, widget: IChatWidget, quickChatService: IQuickChatService, quickPickItems: (IChatContextQuickPickItem | QuickPickItem)[] | undefined, clipboardService: IClipboardService, editorService: IEditorService, labelService: ILabelService, viewsService: IViewsService, chatEditingService: IChatEditingService | undefined, query: string = '', placeholder?: string) { const providerOptions: AnythingQuickAccessProviderRunOptions = { handleAccept: (item: IChatContextQuickPickItem) => { if ('prefix' in item) { - this._show(quickInputService, commandService, widget, quickChatService, quickPickItems, clipboardService, chatEditingService, item.prefix, placeholder); + this._show(quickInputService, commandService, widget, quickChatService, quickPickItems, clipboardService, editorService, labelService, viewsService, chatEditingService, item.prefix, placeholder); } else { if (!clipboardService) { return; } - this._attachContext(widget, commandService, clipboardService, chatEditingService, item); + this._attachContext(widget, commandService, clipboardService, editorService, labelService, viewsService, chatEditingService, item); if (isQuickChat(widget)) { quickChatService.open(); } @@ -479,6 +554,16 @@ export class AttachContextAction extends Action2 { // Avoid attaching the same context twice const attachedContext = widget.attachmentModel.getAttachmentIDs(); + if (isIOpenEditorsQuickPickItem(item)) { + for (const editor of editorService.editors) { + // There is an open editor that hasn't yet been attached to the chat + if (editor.resource && !attachedContext.has(this._getFileContextId({ resource: editor.resource }))) { + return true; + } + } + return false; + } + if ('kind' in item && item.kind === 'image') { return !attachedContext.has(item.id); } diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatExecuteActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatExecuteActions.ts index 134ab33ddfbee..453d2c1d44290 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatExecuteActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatExecuteActions.ts @@ -12,7 +12,7 @@ import { ContextKeyExpr } from '../../../../../platform/contextkey/common/contex import { KeybindingWeight } from '../../../../../platform/keybinding/common/keybindingsRegistry.js'; import { ChatAgentLocation, IChatAgentService } from '../../common/chatAgents.js'; import { CONTEXT_CHAT_INPUT_HAS_AGENT, CONTEXT_CHAT_INPUT_HAS_TEXT, CONTEXT_CHAT_LOCATION, CONTEXT_CHAT_REQUEST_IN_PROGRESS, CONTEXT_IN_CHAT_INPUT, CONTEXT_LANGUAGE_MODELS_ARE_USER_SELECTABLE, CONTEXT_PARTICIPANT_SUPPORTS_MODEL_PICKER } from '../../common/chatContextKeys.js'; -import { applyingChatEditsContextKey } from '../../common/chatEditingService.js'; +import { applyingChatEditsContextKey, IChatEditingService } from '../../common/chatEditingService.js'; import { chatAgentLeader, extractAgentAndCommand } from '../../common/chatParserTypes.js'; import { IChatService } from '../../common/chatService.js'; import { IChatWidget, IChatWidgetService } from '../chat.js'; @@ -76,7 +76,7 @@ MenuRegistry.appendMenuItem(MenuId.ChatExecute, { }, order: 3, group: 'navigation', - when: ContextKeyExpr.and(CONTEXT_LANGUAGE_MODELS_ARE_USER_SELECTABLE, CONTEXT_PARTICIPANT_SUPPORTS_MODEL_PICKER, ContextKeyExpr.equals(CONTEXT_CHAT_LOCATION.key, 'panel')), + when: ContextKeyExpr.and(CONTEXT_LANGUAGE_MODELS_ARE_USER_SELECTABLE, CONTEXT_PARTICIPANT_SUPPORTS_MODEL_PICKER, ContextKeyExpr.or(ContextKeyExpr.equals(CONTEXT_CHAT_LOCATION.key, 'panel'), ContextKeyExpr.equals(CONTEXT_CHAT_LOCATION.key, ChatAgentLocation.EditingSession))), }); export class ChatSubmitSecondaryAgentAction extends Action2 { @@ -167,7 +167,7 @@ export class CancelAction extends Action2 { icon: Codicon.stopCircle, menu: { id: MenuId.ChatExecute, - when: ContextKeyExpr.and(CONTEXT_CHAT_REQUEST_IN_PROGRESS, CONTEXT_CHAT_LOCATION.notEqualsTo(ChatAgentLocation.EditingSession)), + when: ContextKeyExpr.or(CONTEXT_CHAT_REQUEST_IN_PROGRESS, ContextKeyExpr.and(CONTEXT_CHAT_LOCATION.isEqualTo(ChatAgentLocation.EditingSession), applyingChatEditsContextKey)), order: 4, group: 'navigation', }, @@ -192,6 +192,12 @@ export class CancelAction extends Action2 { if (widget.viewModel) { chatService.cancelCurrentRequestForSession(widget.viewModel.sessionId); } + + const chatEditingService = accessor.get(IChatEditingService); + const currentEditingSession = chatEditingService.currentEditingSession; + if (currentEditingSession && currentEditingSession?.chatSessionId === widget.viewModel?.sessionId) { + chatEditingService.currentAutoApplyOperation?.cancel(); + } } } diff --git a/src/vs/workbench/contrib/chat/browser/actions/codeBlockOperations.ts b/src/vs/workbench/contrib/chat/browser/actions/codeBlockOperations.ts index 161860a4efc64..a434980b9f4a5 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/codeBlockOperations.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/codeBlockOperations.ts @@ -390,7 +390,7 @@ function getChatConversation(context: ICodeBlockActionContext): (ConversationReq if (isResponseVM(context.element)) { return [{ type: 'response', - message: context.element.response.toMarkdown(), + message: context.element.response.getMarkdown(), references: getReferencesAsDocumentContext(context.element.contentReferences) }]; } else if (isRequestVM(context.element)) { diff --git a/src/vs/workbench/contrib/chat/browser/chat.contribution.ts b/src/vs/workbench/contrib/chat/browser/chat.contribution.ts index 66ed2d8841f45..0c1ceaa8b6bd8 100644 --- a/src/vs/workbench/contrib/chat/browser/chat.contribution.ts +++ b/src/vs/workbench/contrib/chat/browser/chat.contribution.ts @@ -34,7 +34,7 @@ import { IChatVariablesService } from '../common/chatVariables.js'; import { ChatWidgetHistoryService, IChatWidgetHistoryService } from '../common/chatWidgetHistoryService.js'; import { ILanguageModelsService, LanguageModelsService } from '../common/languageModels.js'; import { ILanguageModelStatsService, LanguageModelStatsService } from '../common/languageModelStats.js'; -import { ILanguageModelToolsService, LanguageModelToolsService } from '../common/languageModelToolsService.js'; +import { ILanguageModelToolsService } from '../common/languageModelToolsService.js'; import { LanguageModelToolsExtensionPointHandler } from '../common/tools/languageModelToolsContribution.js'; import { IVoiceChatService, VoiceChatService } from '../common/voiceChatService.js'; import { PanelChatAccessibilityHelp, QuickChatAccessibilityHelp } from './actions/chatAccessibilityHelp.js'; @@ -69,6 +69,12 @@ import './chatAttachmentModel.js'; import './contrib/chatInputCompletions.js'; import './contrib/chatInputEditorContrib.js'; import './contrib/chatInputEditorHover.js'; +import { EditorContributionInstantiation, registerEditorContribution } from '../../../../editor/browser/editorExtensions.js'; +import { ChatEditorController } from './chatEditorController.js'; +import { LanguageModelToolsService } from './languageModelToolsService.js'; +import { ChatEditorSaving } from './chatEditorSaving.js'; +import { registerChatEditorActions } from './chatEditorActions.js'; + // Register configuration const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); @@ -278,6 +284,8 @@ registerWorkbenchContribution2(LanguageModelToolsExtensionPointHandler.ID, Langu registerWorkbenchContribution2(ChatCompatibilityNotifier.ID, ChatCompatibilityNotifier, WorkbenchPhase.Eventually); registerWorkbenchContribution2(ChatGettingStartedContribution.ID, ChatGettingStartedContribution, WorkbenchPhase.Eventually); registerWorkbenchContribution2(ChatCommandCenterRendering.ID, ChatCommandCenterRendering, WorkbenchPhase.AfterRestored); +registerWorkbenchContribution2(ChatEditorSaving.ID, ChatEditorSaving, WorkbenchPhase.AfterRestored); + registerChatActions(); registerChatCopyActions(); @@ -292,8 +300,10 @@ registerMoveActions(); registerNewChatActions(); registerChatContextActions(); registerChatDeveloperActions(); +registerChatEditorActions(); registerEditorFeature(ChatPasteProvidersFeature); +registerEditorContribution(ChatEditorController.ID, ChatEditorController, EditorContributionInstantiation.Eventually); registerSingleton(IChatService, ChatService, InstantiationType.Delayed); registerSingleton(IChatWidgetService, ChatWidgetService, InstantiationType.Delayed); diff --git a/src/vs/workbench/contrib/chat/browser/chatAttachmentModel.ts b/src/vs/workbench/contrib/chat/browser/chatAttachmentModel.ts index 8af77ac3893c8..65a2f92965f33 100644 --- a/src/vs/workbench/contrib/chat/browser/chatAttachmentModel.ts +++ b/src/vs/workbench/contrib/chat/browser/chatAttachmentModel.ts @@ -5,6 +5,9 @@ import { Emitter } from '../../../../base/common/event.js'; import { Disposable } from '../../../../base/common/lifecycle.js'; +import { basename } from '../../../../base/common/resources.js'; +import { URI } from '../../../../base/common/uri.js'; +import { IRange } from '../../../../editor/common/core/range.js'; import { IChatRequestVariableEntry } from '../common/chatModel.js'; export class ChatAttachmentModel extends Disposable { @@ -34,6 +37,16 @@ export class ChatAttachmentModel extends Disposable { this._onDidChangeContext.fire(); } + addFile(uri: URI, range?: IRange) { + this.addContext({ + value: uri, + id: uri.toString() + (range?.toString() ?? ''), + name: basename(uri), + isFile: true, + isDynamic: true + }); + } + addContext(...attachments: IChatRequestVariableEntry[]) { for (const attachment of attachments) { if (!this._attachments.has(attachment.id)) { diff --git a/src/vs/workbench/contrib/chat/browser/chatContentParts/chatAttachmentsContentPart.ts b/src/vs/workbench/contrib/chat/browser/chatContentParts/chatAttachmentsContentPart.ts index cc15830cd2608..d6717ae83903d 100644 --- a/src/vs/workbench/contrib/chat/browser/chatContentParts/chatAttachmentsContentPart.ts +++ b/src/vs/workbench/contrib/chat/browser/chatContentParts/chatAttachmentsContentPart.ts @@ -18,7 +18,6 @@ import { ChatResponseReferencePartStatusKind, IChatContentReference } from '../. import { IOpenerService } from '../../../../../platform/opener/common/opener.js'; import { IHoverService } from '../../../../../platform/hover/browser/hover.js'; import { createInstantHoverDelegate } from '../../../../../base/browser/ui/hover/hoverDelegateFactory.js'; -import { IManagedHoverContentOrFactory } from '../../../../../base/browser/ui/hover/hover.js'; export class ChatAttachmentsContentPart extends Disposable { private readonly attachedContextDisposables = this._register(new DisposableStore()); @@ -48,7 +47,7 @@ export class ChatAttachmentsContentPart extends Disposable { this.variables.forEach(async (attachment) => { const widget = dom.append(container, dom.$('.chat-attached-context-attachment.show-file-icons')); - const label = this._contextResourceLabels.create(widget, { supportIcons: true, hoverDelegate }); + const label = this._contextResourceLabels.create(widget, { supportIcons: true, hoverDelegate, hoverTargetOverrride: widget }); const file = URI.isUri(attachment.value) ? attachment.value : attachment.value && typeof attachment.value === 'object' && 'uri' in attachment.value && URI.isUri(attachment.value.uri) ? attachment.value.uri : undefined; const range = attachment.value && typeof attachment.value === 'object' && 'range' in attachment.value && Range.isIRange(attachment.value.range) ? attachment.value.range : undefined; @@ -56,7 +55,6 @@ export class ChatAttachmentsContentPart extends Disposable { const isAttachmentOmitted = correspondingContentReference?.options?.status?.kind === ChatResponseReferencePartStatusKind.Omitted; const isAttachmentPartialOrOmitted = isAttachmentOmitted || correspondingContentReference?.options?.status?.kind === ChatResponseReferencePartStatusKind.Partial; - let hoverElement: IManagedHoverContentOrFactory; let ariaLabel: string | undefined; if (file && attachment.isFile) { @@ -72,8 +70,6 @@ export class ChatAttachmentsContentPart extends Disposable { ariaLabel = range ? localize('chat.fileAttachmentWithRange3', "Attached: {0}, line {1} to line {2}.", friendlyName, range.startLineNumber, range.endLineNumber) : localize('chat.fileAttachment3', "Attached: {0}.", friendlyName); } - hoverElement = file.fsPath; - label.setFile(file, { fileKind: FileKind.FILE, hidePath: true, @@ -83,7 +79,7 @@ export class ChatAttachmentsContentPart extends Disposable { } else if (attachment.isImage) { ariaLabel = localize('chat.imageAttachment', "Attached image, {0}", attachment.name); - hoverElement = dom.$('div.chat-attached-context-hover'); + const hoverElement = dom.$('div.chat-attached-context-hover'); hoverElement.setAttribute('aria-label', ariaLabel); // Custom label @@ -107,12 +103,14 @@ export class ChatAttachmentsContentPart extends Disposable { } widget.style.position = 'relative'; + if (!this.attachedContextDisposables.isDisposed) { + this.attachedContextDisposables.add(this.hoverService.setupManagedHover(hoverDelegate, widget, hoverElement)); + } } else { const attachmentLabel = attachment.fullName ?? attachment.name; const withIcon = attachment.icon?.id ? `$(${attachment.icon.id}) ${attachmentLabel}` : attachmentLabel; label.setLabel(withIcon, correspondingContentReference?.options?.status?.description); - hoverElement = attachmentLabel; ariaLabel = localize('chat.attachment3', "Attached context: {0}.", attachment.name); } @@ -122,7 +120,6 @@ export class ChatAttachmentsContentPart extends Disposable { const description = correspondingContentReference?.options?.status?.description; if (isAttachmentPartialOrOmitted) { ariaLabel = `${ariaLabel}${description ? ` ${description}` : ''}`; - hoverElement = description; for (const selector of ['.monaco-icon-suffix-container', '.monaco-icon-name-container']) { const element = label.element.querySelector(selector); if (element) { @@ -150,9 +147,6 @@ export class ChatAttachmentsContentPart extends Disposable { widget.ariaLabel = ariaLabel; widget.tabIndex = 0; - if (!this.attachedContextDisposables.isDisposed) { - this.attachedContextDisposables.add(this.hoverService.setupManagedHover(hoverDelegate, widget, hoverElement)); - } }); } diff --git a/src/vs/workbench/contrib/chat/browser/chatContentParts/chatToolInvocationPart.ts b/src/vs/workbench/contrib/chat/browser/chatContentParts/chatToolInvocationPart.ts index 2c460dd9a1cbf..9a91746ce7413 100644 --- a/src/vs/workbench/contrib/chat/browser/chatContentParts/chatToolInvocationPart.ts +++ b/src/vs/workbench/contrib/chat/browser/chatContentParts/chatToolInvocationPart.ts @@ -86,7 +86,6 @@ class ChatToolInvocationSubPart extends Disposable { toolInvocation.confirmed.complete(button.data); })); toolInvocation.confirmed.p.then(() => this._onNeedsRerender.fire()); - toolInvocation.isCompleteDeferred.p.then(() => this._onNeedsRerender.fire()); } else { const message = toolInvocation.invocationMessage + '…'; const progressMessage: IChatProgressMessage = { @@ -100,5 +99,9 @@ class ChatToolInvocationSubPart extends Disposable { const progressPart = this._register(instantiationService.createInstance(ChatProgressContentPart, progressMessage, renderer, context, undefined, true, iconOverride)); this.domNode = progressPart.domNode; } + + if (toolInvocation.kind === 'toolInvocation' && !toolInvocation.isComplete) { + toolInvocation.isCompleteDeferred.p.then(() => this._onNeedsRerender.fire()); + } } } diff --git a/src/vs/workbench/contrib/chat/browser/chatEditingActions.ts b/src/vs/workbench/contrib/chat/browser/chatEditingActions.ts index e3f9d62858ac0..4753c839422dd 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEditingActions.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEditingActions.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import { Codicon } from '../../../../base/common/codicons.js'; -import { KeyCode, KeyMod } from '../../../../base/common/keyCodes.js'; import { ResourceSet } from '../../../../base/common/map.js'; import { URI } from '../../../../base/common/uri.js'; import { ServicesAccessor } from '../../../../editor/browser/editorExtensions.js'; @@ -12,16 +11,11 @@ import { localize, localize2 } from '../../../../nls.js'; import { Action2, MenuId, registerAction2 } from '../../../../platform/actions/common/actions.js'; import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextkey.js'; import { EditorActivation } from '../../../../platform/editor/common/editor.js'; -import { KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js'; import { IListService } from '../../../../platform/list/browser/listService.js'; import { GroupsOrder, IEditorGroupsService } from '../../../services/editor/common/editorGroupsService.js'; import { IEditorService } from '../../../services/editor/common/editorService.js'; -import { ChatAgentLocation } from '../common/chatAgents.js'; -import { CONTEXT_CHAT_LOCATION, CONTEXT_CHAT_REQUEST_IN_PROGRESS } from '../common/chatContextKeys.js'; -import { applyingChatEditsContextKey, CHAT_EDITING_MULTI_DIFF_SOURCE_RESOLVER_SCHEME, chatEditingResourceContextKey, chatEditingWidgetFileStateContextKey, decidedChatEditingResourceContextKey, IChatEditingService, IChatEditingSession, inChatEditingSessionContextKey, WorkingSetEntryState } from '../common/chatEditingService.js'; -import { IChatService } from '../common/chatService.js'; +import { CHAT_EDITING_MULTI_DIFF_SOURCE_RESOLVER_SCHEME, chatEditingResourceContextKey, chatEditingWidgetFileStateContextKey, decidedChatEditingResourceContextKey, IChatEditingService, IChatEditingSession, inChatEditingSessionContextKey, WorkingSetEntryState } from '../common/chatEditingService.js'; import { CHAT_CATEGORY } from './actions/chatActions.js'; -import { IChatExecuteActionContext } from './actions/chatExecuteActions.js'; import { IChatWidget, IChatWidgetService } from './chat.js'; abstract class WorkingSetAction extends Action2 { @@ -279,45 +273,3 @@ registerAction2(class AddFilesToWorkingSetAction extends Action2 { } } }); - -registerAction2(class CancelAction extends Action2 { - static readonly ID = 'workbench.action.chat.editing.cancel'; - constructor() { - super({ - id: CancelAction.ID, - title: localize2('workbench.action.chat.editing.cancel.label', "Cancel"), - f1: false, - category: CHAT_CATEGORY, - icon: Codicon.stopCircle, - menu: { - id: MenuId.ChatExecute, - when: ContextKeyExpr.and(CONTEXT_CHAT_LOCATION.isEqualTo(ChatAgentLocation.EditingSession), ContextKeyExpr.or(CONTEXT_CHAT_REQUEST_IN_PROGRESS, applyingChatEditsContextKey)), - order: 4, - group: 'navigation', - }, - keybinding: { - weight: KeybindingWeight.WorkbenchContrib, - primary: KeyMod.CtrlCmd | KeyCode.Escape, - win: { primary: KeyMod.Alt | KeyCode.Backspace }, - } - }); - } - - run(accessor: ServicesAccessor, ...args: any[]) { - const context: IChatExecuteActionContext | undefined = args[0]; - - const widgetService = accessor.get(IChatWidgetService); - const widget = context?.widget ?? widgetService.lastFocusedWidget; - if (!widget) { - return; - } - - const chatService = accessor.get(IChatService); - if (widget.viewModel) { - chatService.cancelCurrentRequestForSession(widget.viewModel.sessionId); - } - - const chatEditingService = accessor.get(IChatEditingService); - chatEditingService.currentAutoApplyOperation?.cancel(); - } -}); diff --git a/src/vs/workbench/contrib/chat/browser/chatEditingService.ts b/src/vs/workbench/contrib/chat/browser/chatEditingService.ts index ddc744b2bd01b..05dae5ce02127 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEditingService.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEditingService.ts @@ -7,12 +7,13 @@ import { Sequencer } from '../../../../base/common/async.js'; import { CancellationToken, CancellationTokenSource } from '../../../../base/common/cancellation.js'; import { BugIndicatingError } from '../../../../base/common/errors.js'; import { Emitter } from '../../../../base/common/event.js'; -import { Disposable, DisposableStore, IDisposable, IReference, MutableDisposable } from '../../../../base/common/lifecycle.js'; +import { Disposable, DisposableStore, IDisposable, IReference } from '../../../../base/common/lifecycle.js'; import { ResourceSet } from '../../../../base/common/map.js'; import { derived, IObservable, ITransaction, observableValue, ValueWithChangeEventFromObservable } from '../../../../base/common/observable.js'; import { URI } from '../../../../base/common/uri.js'; import { isCodeEditor, isDiffEditor } from '../../../../editor/browser/editorBrowser.js'; import { IBulkEditService } from '../../../../editor/browser/services/bulkEditService.js'; +import { EditOperation } from '../../../../editor/common/core/editOperation.js'; import { TextEdit } from '../../../../editor/common/languages.js'; import { ILanguageService } from '../../../../editor/common/languages/language.js'; import { ITextModel } from '../../../../editor/common/model.js'; @@ -36,13 +37,14 @@ import { ICodeMapperResponse, ICodeMapperService } from '../common/chatCodeMappe import { applyingChatEditsContextKey, CHAT_EDITING_MULTI_DIFF_SOURCE_RESOLVER_SCHEME, chatEditingResourceContextKey, ChatEditingSessionState, decidedChatEditingResourceContextKey, IChatEditingService, IChatEditingSession, IChatEditingSessionStream, IModifiedFileEntry, inChatEditingSessionContextKey, WorkingSetEntryState } from '../common/chatEditingService.js'; import { IChatResponseModel } from '../common/chatModel.js'; import { IChatService } from '../common/chatService.js'; +import { IChatWidgetService } from './chat.js'; export class ChatEditingService extends Disposable implements IChatEditingService { _serviceBrand: undefined; private readonly _currentSessionObs = observableValue(this, null); - private readonly _currentSessionDisposeListener = this._register(new MutableDisposable()); + private readonly _currentSessionDisposables = this._register(new DisposableStore()); private readonly _currentAutoApplyOperationObs = observableValue(this, null); get currentAutoApplyOperation(): CancellationTokenSource | null { @@ -53,11 +55,14 @@ export class ChatEditingService extends Disposable implements IChatEditingServic return this._currentSessionObs.get(); } - private readonly _onDidCreateEditingSession = new Emitter(); + private readonly _onDidCreateEditingSession = this._register(new Emitter()); get onDidCreateEditingSession() { return this._onDidCreateEditingSession.event; } + private readonly _onDidChangeEditingSession = this._register(new Emitter()); + public readonly onDidChangeEditingSession = this._onDidChangeEditingSession.event; + constructor( @IEditorGroupsService private readonly _editorGroupsService: IEditorGroupsService, @IInstantiationService private readonly _instantiationService: IInstantiationService, @@ -67,6 +72,7 @@ export class ChatEditingService extends Disposable implements IChatEditingServic @IChatService private readonly _chatService: IChatService, @IProgressService private readonly _progressService: IProgressService, @ICodeMapperService private readonly _codeMapperService: ICodeMapperService, + @IEditorService private readonly _editorService: IEditorService, ) { super(); this._register(multiDiffSourceResolverService.registerResolver(_instantiationService.createInstance(ChatEditingMultiDiffSourceResolver, this._currentSessionObs))); @@ -93,6 +99,20 @@ export class ChatEditingService extends Disposable implements IChatEditingServic })); } + getEditingSession(resource: URI): IChatEditingSession | null { + const session = this.currentEditingSession; + if (!session) { + return null; + } + const entries = session.entries.get(); + for (const entry of entries) { + if (entry.modifiedURI.toString() === resource.toString()) { + return session; + } + } + return null; + } + async addFileToWorkingSet(resource: URI): Promise { const session = this._currentSessionObs.get(); if (session) { @@ -120,8 +140,10 @@ export class ChatEditingService extends Disposable implements IChatEditingServic throw new BugIndicatingError('Cannot have more than one active editing session'); } + this._currentSessionDisposables.clear(); + // listen for completed responses, run the code mapper and apply the edits to this edit session - this._register(this.installAutoApplyObserver(chatSessionId)); + this._currentSessionDisposables.add(this.installAutoApplyObserver(chatSessionId)); const input = MultiDiffEditorInput.fromResourceMultiDiffEditorInput({ multiDiffSource: ChatEditingMultiDiffSourceResolver.getMultiDiffSourceUri(), @@ -131,20 +153,25 @@ export class ChatEditingService extends Disposable implements IChatEditingServic const editorPane = options?.silent ? undefined : await this._editorGroupsService.activeGroup.openEditor(input, { pinned: true, activation: EditorActivation.ACTIVATE }) as MultiDiffEditor | undefined; const session = this._instantiationService.createInstance(ChatEditingSession, chatSessionId, editorPane); - this._currentSessionDisposeListener.value = session.onDidDispose(() => { - this._currentSessionDisposeListener.clear(); + this._currentSessionDisposables.add(session.onDidDispose(() => { + this._currentSessionDisposables.clear(); this._currentSessionObs.set(null, undefined); - }); + this._onDidChangeEditingSession.fire(); + })); + this._currentSessionDisposables.add(session.onDidChange(() => { + this._onDidChangeEditingSession.fire(); + })); this._currentSessionObs.set(session, undefined); this._onDidCreateEditingSession.fire(session); + this._onDidChangeEditingSession.fire(); return session; } public triggerEditComputation(responseModel: IChatResponseModel): Promise { return this._continueEditingSession(async (builder, token) => { const codeMapperResponse: ICodeMapperResponse = { - textEdit: (resource, edits) => builder.textEdits(resource, edits), + textEdit: (resource, edits) => builder.textEdits(resource, edits, responseModel), }; await this._codeMapperService.mapCodeFromResponse(responseModel, codeMapperResponse, token); }, { silent: true }); @@ -165,14 +192,24 @@ export class ChatEditingService extends Disposable implements IChatEditingServic } }; + const openCodeBlockUris = (responseModel: IChatResponseModel) => { + for (const part of responseModel.response.value) { + if (part.kind === 'codeblockUri') { + this._editorService.openEditor({ resource: part.uri, options: { inactive: true, preserveFocus: true, pinned: true } }); + } + } + }; + observerDisposables.add(chatModel.onDidChange(e => { if (e.kind === 'addRequest') { const responseModel = e.request.response; if (responseModel) { if (responseModel.isComplete) { + openCodeBlockUris(responseModel); onResponseComplete(responseModel); } else { const disposable = responseModel.onDidChange(() => { + openCodeBlockUris(responseModel); if (responseModel.isComplete) { onResponseComplete(responseModel); disposable.dispose(); @@ -210,8 +247,8 @@ export class ChatEditingService extends Disposable implements IChatEditingServic } const stream: IChatEditingSessionStream = { - textEdits: (resource: URI, textEdits: TextEdit[]) => { - session.acceptTextEdits(resource, textEdits); + textEdits: (resource: URI, textEdits: TextEdit[], responseModel: IChatResponseModel) => { + session.acceptTextEdits(resource, textEdits, responseModel); } }; session.acceptStreamingEditsStart(); @@ -397,17 +434,22 @@ class ChatEditingSession extends Disposable implements IChatEditingSession { @IBulkEditService public readonly _bulkEditService: IBulkEditService, @IEditorGroupsService private readonly _editorGroupsService: IEditorGroupsService, @IEditorService private readonly _editorService: IEditorService, + @IChatWidgetService chatWidgetService: IChatWidgetService, ) { super(); // Add the currently active editor to the working set + const widget = chatWidgetService.getWidgetBySessionId(chatSessionId); + let activeEditorControl = this._editorService.activeTextEditorControl; if (activeEditorControl) { if (isDiffEditor(activeEditorControl)) { activeEditorControl = activeEditorControl.getOriginalEditor().hasTextFocus() ? activeEditorControl.getOriginalEditor() : activeEditorControl.getModifiedEditor(); } if (isCodeEditor(activeEditorControl) && activeEditorControl.hasModel()) { - this._workingSet.add(activeEditorControl.getModel().uri); + const uri = activeEditorControl.getModel().uri; + this._workingSet.add(uri); + widget?.attachmentModel.addFile(uri); this._workingSetObs.set([...this._workingSet.values()], undefined); } } @@ -532,14 +574,14 @@ class ChatEditingSession extends Disposable implements IChatEditingSession { this._sequencer.queue(() => this._acceptStreamingEditsStart()); } - acceptTextEdits(resource: URI, textEdits: TextEdit[]): void { + acceptTextEdits(resource: URI, textEdits: TextEdit[], responseModel: IChatResponseModel): void { if (this._state.get() === ChatEditingSessionState.Disposed) { // we don't throw in this case because there could be a builder still connected to a disposed session return; } // ensure that the edits are processed sequentially - this._sequencer.queue(() => this._acceptTextEdits(resource, textEdits)); + this._sequencer.queue(() => this._acceptTextEdits(resource, textEdits, responseModel)); } resolve(): void { @@ -565,10 +607,10 @@ class ChatEditingSession extends Disposable implements IChatEditingSession { this._onDidChange.fire(); } - private async _acceptTextEdits(resource: URI, textEdits: TextEdit[]): Promise { - const entry = await this._getOrCreateModifiedFileEntry(resource); + private async _acceptTextEdits(resource: URI, textEdits: TextEdit[], responseModel: IChatResponseModel): Promise { + const entry = await this._getOrCreateModifiedFileEntry(resource, responseModel); entry.applyEdits(textEdits); - await this._editorService.openEditor({ original: { resource: entry.originalURI }, modified: { resource: entry.modifiedURI }, options: { inactive: true } }); + await this._editorService.openEditor({ resource: entry.modifiedURI, options: { inactive: true } }); } private async _resolve(): Promise { @@ -576,13 +618,13 @@ class ChatEditingSession extends Disposable implements IChatEditingSession { this._onDidChange.fire(); } - private async _getOrCreateModifiedFileEntry(resource: URI): Promise { + private async _getOrCreateModifiedFileEntry(resource: URI, responseModel: IChatResponseModel): Promise { const existingEntry = this._entries.find(e => e.resource.toString() === resource.toString()); if (existingEntry) { return existingEntry; } - const entry = await this._createModifiedFileEntry(resource); + const entry = await this._createModifiedFileEntry(resource, responseModel); this._register(entry); this._entries = [...this._entries, entry]; this._entriesObs.set(this._entries, undefined); @@ -591,17 +633,17 @@ class ChatEditingSession extends Disposable implements IChatEditingSession { return entry; } - private async _createModifiedFileEntry(resource: URI, mustExist = false): Promise { + private async _createModifiedFileEntry(resource: URI, responseModel: IChatResponseModel, mustExist = false): Promise { try { const ref = await this._textModelService.createModelReference(resource); - return this._instantiationService.createInstance(ModifiedFileEntry, resource, ref, { collapse: (transaction: ITransaction | undefined) => this._collapse(resource, transaction) }); + return this._instantiationService.createInstance(ModifiedFileEntry, resource, ref, { collapse: (transaction: ITransaction | undefined) => this._collapse(resource, transaction) }, responseModel); } catch (err) { if (mustExist) { throw err; } // this file does not exist yet, create it and try again await this._bulkEditService.apply({ edits: [{ newResource: resource }] }); - return this._createModifiedFileEntry(resource, true); + return this._createModifiedFileEntry(resource, responseModel, true); } } @@ -626,6 +668,10 @@ class ModifiedFileEntry extends Disposable implements IModifiedFileEntry { return this.docSnapshot.uri; } + get originalModel(): ITextModel { + return this.docSnapshot; + } + get modifiedURI(): URI { return this.doc.uri; } @@ -639,10 +685,12 @@ class ModifiedFileEntry extends Disposable implements IModifiedFileEntry { public readonly resource: URI, resourceRef: IReference, private readonly _multiDiffEntryDelegate: { collapse: (transaction: ITransaction | undefined) => void }, + private readonly _responseModel: IChatResponseModel, @IModelService modelService: IModelService, @ITextModelService textModelService: ITextModelService, @ILanguageService languageService: ILanguageService, - @IBulkEditService public readonly _bulkEditService: IBulkEditService, + @IBulkEditService public readonly bulkEditService: IBulkEditService, + @IChatService private readonly _chatService: IChatService, ) { super(); this.doc = resourceRef.object.textEditorModel; @@ -657,6 +705,7 @@ class ModifiedFileEntry extends Disposable implements IModifiedFileEntry { // Create a reference to this model to avoid it being disposed from under our nose (async () => { + // TODO: dispose manually if the outer object was disposed in the meantime this._register(await textModelService.createModelReference(docSnapshot.uri)); })(); @@ -673,9 +722,11 @@ class ModifiedFileEntry extends Disposable implements IModifiedFileEntry { // already accepted or rejected return; } + this.docSnapshot.setValue(this.doc.createSnapshot()); this._stateObs.set(WorkingSetEntryState.Accepted, transaction); await this.collapse(transaction); + this._notifyAction('accepted'); } async reject(transaction: ITransaction | undefined): Promise { @@ -683,12 +734,29 @@ class ModifiedFileEntry extends Disposable implements IModifiedFileEntry { // already accepted or rejected return; } - this.doc.setValue(this.docSnapshot.createSnapshot()); + + this.doc.pushStackElement(); + const edit = EditOperation.replace(this.doc.getFullModelRange(), this.docSnapshot.getValue()); + this.doc.pushEditOperations(null, [edit], () => null); + this.doc.pushStackElement(); + this._stateObs.set(WorkingSetEntryState.Rejected, transaction); await this.collapse(transaction); + this._notifyAction('rejected'); } async collapse(transaction: ITransaction | undefined): Promise { this._multiDiffEntryDelegate.collapse(transaction); } + + private _notifyAction(outcome: 'accepted' | 'rejected') { + this._chatService.notifyUserAction({ + action: { kind: 'chatEditingSessionAction', uri: this.resource, hasRemainingEdits: false, outcome }, + agentId: this._responseModel.agent?.id, + command: this._responseModel.slashCommand?.name, + sessionId: this._responseModel.session.sessionId, + requestId: this._responseModel.requestId, + result: this._responseModel.result + }); + } } diff --git a/src/vs/workbench/contrib/chat/browser/chatEditorActions.ts b/src/vs/workbench/contrib/chat/browser/chatEditorActions.ts new file mode 100644 index 0000000000000..4ba86bc67aa7a --- /dev/null +++ b/src/vs/workbench/contrib/chat/browser/chatEditorActions.ts @@ -0,0 +1,68 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +import { isCodeEditor } from '../../../../editor/browser/editorBrowser.js'; +import { localize2 } from '../../../../nls.js'; +import { ServicesAccessor } from '../../../../editor/browser/editorExtensions.js'; +import { Codicon } from '../../../../base/common/codicons.js'; +import { Action2, MenuId, registerAction2 } from '../../../../platform/actions/common/actions.js'; +import { KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js'; +import { KeyCode, KeyMod } from '../../../../base/common/keyCodes.js'; +import { CHAT_CATEGORY } from './actions/chatActions.js'; +import { ChatEditorController, ctxHasEditorModification } from './chatEditorController.js'; +import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextkey.js'; +import { EditorContextKeys } from '../../../../editor/common/editorContextKeys.js'; +import { IEditorService } from '../../../services/editor/common/editorService.js'; + +abstract class NavigateAction extends Action2 { + + constructor(readonly next: boolean) { + super({ + id: next + ? 'chat.action.navigateNext' + : 'chat.action.navigatePrevious', + title: next + ? localize2('next', 'Go to Next Chat Edit') + : localize2('prev', 'Go to Previous Chat Edit'), + category: CHAT_CATEGORY, + icon: next ? Codicon.arrowDown : Codicon.arrowUp, + keybinding: { + primary: next + ? KeyMod.Alt | KeyCode.F5 + : KeyMod.Alt | KeyMod.Shift | KeyCode.F5, + weight: KeybindingWeight.EditorContrib, + when: ContextKeyExpr.and(ctxHasEditorModification, EditorContextKeys.focus), + }, + f1: true, + menu: { + id: MenuId.EditorTitle, + group: 'navigation', + order: next ? -100 : -101, + when: ctxHasEditorModification + } + }); + } + + override run(accessor: ServicesAccessor) { + + const editor = accessor.get(IEditorService).activeTextEditorControl; + + if (!isCodeEditor(editor)) { + return; + } + + if (this.next) { + ChatEditorController.get(editor)?.revealNext(); + } else { + ChatEditorController.get(editor)?.revealPrevious(); + } + } + +} + + +export function registerChatEditorActions() { + registerAction2(class extends NavigateAction { constructor() { super(true); } }); + registerAction2(class extends NavigateAction { constructor() { super(false); } }); +} diff --git a/src/vs/workbench/contrib/chat/browser/chatEditorController.ts b/src/vs/workbench/contrib/chat/browser/chatEditorController.ts new file mode 100644 index 0000000000000..89326dea52521 --- /dev/null +++ b/src/vs/workbench/contrib/chat/browser/chatEditorController.ts @@ -0,0 +1,250 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { binarySearch, coalesceInPlace } from '../../../../base/common/arrays.js'; +import { Disposable, DisposableStore, toDisposable } from '../../../../base/common/lifecycle.js'; +import { Constants } from '../../../../base/common/uint.js'; +import { ICodeEditor, IViewZone } from '../../../../editor/browser/editorBrowser.js'; +import { LineSource, renderLines, RenderOptions } from '../../../../editor/browser/widget/diffEditor/components/diffEditorViewZones/renderLines.js'; +import { diffAddDecoration, diffDeleteDecoration, diffWholeLineAddDecoration } from '../../../../editor/browser/widget/diffEditor/registrations.contribution.js'; +import { EditorOption } from '../../../../editor/common/config/editorOptions.js'; +import { Range } from '../../../../editor/common/core/range.js'; +import { IDocumentDiff } from '../../../../editor/common/diff/documentDiffProvider.js'; +import { IEditorContribution, ScrollType } from '../../../../editor/common/editorCommon.js'; +import { IModelDeltaDecoration, ITextModel } from '../../../../editor/common/model.js'; +import { IEditorWorkerService } from '../../../../editor/common/services/editorWorker.js'; +import { InlineDecoration, InlineDecorationType } from '../../../../editor/common/viewModel.js'; +import { IChatEditingService, IChatEditingSession, IModifiedFileEntry, WorkingSetEntryState } from '../common/chatEditingService.js'; +import { localize } from '../../../../nls.js'; +import { IContextKey, IContextKeyService, RawContextKey } from '../../../../platform/contextkey/common/contextkey.js'; + +export const ctxHasEditorModification = new RawContextKey('chat.hasEditorModifications', undefined, localize('chat.hasEditorModifications', "The current editor contains chat modifications")); + +export class ChatEditorController extends Disposable implements IEditorContribution { + + public static readonly ID = 'editor.contrib.chatEditorController'; + + private readonly _sessionStore = this._register(new DisposableStore()); + private readonly _decorations = this._editor.createDecorationsCollection(); + private _viewZones: string[] = []; + private readonly _ctxHasEditorModification: IContextKey; + + static get(editor: ICodeEditor): ChatEditorController | null { + const controller = editor.getContribution(ChatEditorController.ID); + return controller; + } + + constructor( + private readonly _editor: ICodeEditor, + @IChatEditingService private readonly _chatEditingService: IChatEditingService, + @IEditorWorkerService private readonly _editorWorkerService: IEditorWorkerService, + @IContextKeyService contextKeyService: IContextKeyService, + ) { + super(); + this._register(this._editor.onDidChangeModel(() => this._update())); + this._register(this._chatEditingService.onDidChangeEditingSession(() => this._updateSessionDecorations())); + this._register(toDisposable(() => this._clearRendering())); + + this._ctxHasEditorModification = ctxHasEditorModification.bindTo(contextKeyService); + } + + override dispose(): void { + this._clearRendering(); + super.dispose(); + } + + private _update(): void { + this._sessionStore.clear(); + if (!this._editor.hasModel()) { + return; + } + if (this._editor.getOption(EditorOption.inDiffEditor)) { + return; + } + const model = this._editor.getModel(); + if (this._editor.getOption(EditorOption.inDiffEditor)) { + this._clearRendering(); + return; + } + this._sessionStore.add(model.onDidChangeContent(() => this._updateSessionDecorations())); + this._updateSessionDecorations(); + } + + private _updateSessionDecorations(): void { + if (!this._editor.hasModel()) { + this._clearRendering(); + return; + } + const model = this._editor.getModel(); + const editingSession = this._chatEditingService.getEditingSession(model.uri); + const entry = this._getEntry(editingSession, model); + + if (!entry || entry.state.get() !== WorkingSetEntryState.Modified) { + this._clearRendering(); + return; + } + + this._editorWorkerService.computeDiff( + entry.originalURI, + model.uri, + { + ignoreTrimWhitespace: false, + maxComputationTimeMs: Constants.MAX_SAFE_SMALL_INTEGER, + computeMoves: false + }, + 'advanced' + ).then(diff => { + if (!this._editor.hasModel()) { + this._clearRendering(); + return; + } + + const model = this._editor.getModel(); + const editingSession = this._chatEditingService.getEditingSession(model.uri); + const entry = this._getEntry(editingSession, model); + if (!entry) { + this._clearRendering(); + return; + } + + this._ctxHasEditorModification.set(true); + this._updateWithDiff(model, entry, diff); + }); + } + + private _getEntry(editingSession: IChatEditingSession | null, model: ITextModel): IModifiedFileEntry | null { + if (!editingSession) { + return null; + } + return editingSession.entries.get().find(e => e.modifiedURI.toString() === model.uri.toString()) || null; + } + + private _clearRendering() { + this._editor.changeViewZones((viewZoneChangeAccessor) => { + for (const id of this._viewZones) { + viewZoneChangeAccessor.removeZone(id); + } + }); + this._viewZones = []; + this._decorations.clear(); + this._ctxHasEditorModification.reset(); + } + + private _updateWithDiff(model: ITextModel, entry: IModifiedFileEntry, diff: IDocumentDiff | null): void { + if (!diff) { + this._clearRendering(); + return; + } + + const originalModel = entry.originalModel; + + // original view zone + + this._editor.changeViewZones((viewZoneChangeAccessor) => { + for (const id of this._viewZones) { + viewZoneChangeAccessor.removeZone(id); + } + this._viewZones = []; + const modifiedDecorations: IModelDeltaDecoration[] = []; + const mightContainNonBasicASCII = originalModel.mightContainNonBasicASCII(); + const mightContainRTL = originalModel.mightContainRTL(); + const renderOptions = RenderOptions.fromEditor(this._editor); + + for (const diffEntry of diff.changes) { + const originalRange = diffEntry.original; + originalModel.tokenization.forceTokenization(originalRange.endLineNumberExclusive - 1); + const source = new LineSource( + originalRange.mapToLineArray(l => originalModel.tokenization.getLineTokens(l)), + [], + mightContainNonBasicASCII, + mightContainRTL, + ); + const decorations: InlineDecoration[] = []; + for (const i of diffEntry.innerChanges || []) { + decorations.push(new InlineDecoration( + i.originalRange.delta(-(diffEntry.original.startLineNumber - 1)), + diffDeleteDecoration.className!, + InlineDecorationType.Regular + )); + modifiedDecorations.push({ range: i.modifiedRange, options: diffAddDecoration }); + } + if (!diffEntry.modified.isEmpty) { + modifiedDecorations.push({ range: diffEntry.modified.toInclusiveRange()!, options: diffWholeLineAddDecoration }); + } + const domNode = document.createElement('div'); + domNode.className = 'chat-editing-original-zone line-delete'; + const result = renderLines(source, renderOptions, decorations, domNode); + const viewZoneData: IViewZone = { + afterLineNumber: diffEntry.modified.startLineNumber - 1, + heightInLines: result.heightInLines, + domNode, + ordinal: 50000 + 2 // more than https://github.com/microsoft/vscode/blob/bf52a5cfb2c75a7327c9adeaefbddc06d529dcad/src/vs/workbench/contrib/inlineChat/browser/inlineChatZoneWidget.ts#L42 + }; + + this._viewZones.push(viewZoneChangeAccessor.addZone(viewZoneData)); + } + + this._decorations.set(modifiedDecorations); + }); + } + + revealNext() { + this._reveal(true); + } + + revealPrevious() { + this._reveal(false); + } + + private _reveal(next: boolean) { + const position = this._editor.getPosition(); + if (!position) { + return; + } + + const decorations: (Range | undefined)[] = this._decorations + .getRanges() + .sort((a, b) => Range.compareRangesUsingStarts(a, b)); + + // TODO@jrieken this is slow and should be done smarter, e.g being able to read + // only whole range decorations because the goal is to go from change to change, skipping + // over word level changes + for (let i = 0; i < decorations.length; i++) { + const decoration = decorations[i]; + for (let j = 0; j < decorations.length; j++) { + if (i !== j && decoration && decorations[j]?.containsRange(decoration)) { + decorations[i] = undefined; + break; + } + } + } + + coalesceInPlace(decorations); + + if (decorations.length === 0) { + return; + } + + let idx = binarySearch(decorations, Range.fromPositions(position), Range.compareRangesUsingStarts); + if (idx < 0) { + idx = ~idx; + } + + let target: number; + if (decorations[idx]?.containsPosition(position)) { + target = idx + (next ? 1 : -1); + } else { + target = next ? idx : idx - 1; + } + + target = (target + decorations.length) % decorations.length; + + + const targetPosition = decorations[target].getStartPosition(); + this._editor.setPosition(targetPosition); + this._editor.revealPosition(targetPosition, ScrollType.Smooth); + this._editor.focus(); + } +} diff --git a/src/vs/workbench/contrib/chat/browser/chatEditorSaving.ts b/src/vs/workbench/contrib/chat/browser/chatEditorSaving.ts new file mode 100644 index 0000000000000..a1991fc9fea26 --- /dev/null +++ b/src/vs/workbench/contrib/chat/browser/chatEditorSaving.ts @@ -0,0 +1,172 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Queue } from '../../../../base/common/async.js'; +import { Disposable, DisposableMap, DisposableStore, MutableDisposable } from '../../../../base/common/lifecycle.js'; +import { localize, localize2 } from '../../../../nls.js'; +import { Action2, registerAction2 } from '../../../../platform/actions/common/actions.js'; +import { IDialogService } from '../../../../platform/dialogs/common/dialogs.js'; +import { ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js'; +import { ILabelService } from '../../../../platform/label/common/label.js'; +import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js'; +import { IWorkbenchContribution } from '../../../common/contributions.js'; +import { SaveReason } from '../../../common/editor.js'; +import { IFilesConfigurationService } from '../../../services/filesConfiguration/common/filesConfigurationService.js'; +import { ITextFileService } from '../../../services/textfile/common/textfiles.js'; +import { ChatAgentLocation, IChatAgentService } from '../common/chatAgents.js'; +import { IChatEditingService, IChatEditingSession, WorkingSetEntryState } from '../common/chatEditingService.js'; +import { CHAT_CATEGORY } from './actions/chatActions.js'; + + +const _storageKey = 'workbench.chat.editorSaving'; + +export class ChatEditorSaving extends Disposable implements IWorkbenchContribution { + + static readonly ID: string = 'workbench.chat.editorSaving'; + + + private readonly _sessionStore = this._store.add(new DisposableMap()); + + constructor( + @IChatEditingService chatEditingService: IChatEditingService, + @IChatAgentService chatAgentService: IChatAgentService, + @ITextFileService textFileService: ITextFileService, + @ILabelService labelService: ILabelService, + @IDialogService private readonly _dialogService: IDialogService, + @IStorageService private readonly _storageService: IStorageService, + @IFilesConfigurationService private readonly _fileConfigService: IFilesConfigurationService, + ) { + super(); + + const store = this._store.add(new DisposableStore()); + + const queue = new Queue(); + + const update = () => { + + store.clear(); + + const alwaysAcceptOnSave = this._storageService.getBoolean(_storageKey, StorageScope.PROFILE, false); + if (alwaysAcceptOnSave) { + return; + } + + + store.add(chatEditingService.onDidCreateEditingSession(e => this._handleNewEditingSession(e))); + store.add(textFileService.files.addSaveParticipant({ + participate: async (workingCopy, context, progress, token) => { + + if (context.reason !== SaveReason.EXPLICIT) { + // all saves that we are concerned about are explicit + // because we have disabled auto-save for them + return; + } + + const session = chatEditingService.getEditingSession(workingCopy.resource); + if (!session) { + return; + } + + + if (!session.entries.get().find(e => e.state.get() === WorkingSetEntryState.Modified && e.modifiedURI.toString() === workingCopy.resource.toString())) { + return; + } + + // ensure one modal at the time + await queue.queue(async () => { + + // this might have changed in the meantime and there is checked again and acted upon + const alwaysAcceptOnSave = this._storageService.getBoolean(_storageKey, StorageScope.PROFILE, false); + if (alwaysAcceptOnSave) { + await session.accept(workingCopy.resource); + return; + } + + const agentName = chatAgentService.getDefaultAgent(ChatAgentLocation.EditingSession)?.fullName; + const filelabel = labelService.getUriBasenameLabel(workingCopy.resource); + + const message = agentName + ? localize('message.1', "Do you want to accept the changes {0} made in {1}?", agentName, filelabel) + : localize('message.2', "Do you want to accept the changes chat made in {1}?", filelabel); + + const result = await this._dialogService.confirm({ + message, + detail: localize('detail', "AI-generated changes may be incorect and should be reviewed before saving.", agentName), + primaryButton: localize('save', "Accept & Save"), + cancelButton: localize('discard', "Discard & Save"), + checkbox: { + label: localize('config', "Always accept edits when saving"), + checked: false + } + }); + + if (result.confirmed) { + await session.accept(workingCopy.resource); + + if (result.checkboxChecked) { + // remember choice + this._storageService.store(_storageKey, true, StorageScope.PROFILE, StorageTarget.USER); + } + + } else { + await session.reject(workingCopy.resource); + } + }); + } + })); + }; + + this._storageService.onDidChangeValue(StorageScope.PROFILE, _storageKey, this._store)(update); + update(); + } + + private _handleNewEditingSession(session: IChatEditingSession) { + + const store = new DisposableStore(); + + // disable auto save for those files involved in editing + const saveConfig = store.add(new MutableDisposable()); + const update = () => { + const store = new DisposableStore(); + const entries = session.entries.get(); + for (const entry of entries) { + if (entry.state.get() === WorkingSetEntryState.Modified) { + store.add(this._fileConfigService.disableAutoSave(entry.modifiedURI)); + } + } + saveConfig.value = store; + }; + + update(); + + this._sessionStore.set(session, store); + + store.add(session.onDidChange(() => { + update(); + })); + + store.add(session.onDidDispose(() => { + this._sessionStore.deleteAndDispose(session); + })); + } +} + + +registerAction2(class extends Action2 { + + constructor() { + super({ + id: 'workbench.action.resetChatEditorSaving', + title: localize2('resetChatEditorSaving', "Reset Choise for 'Always accept edits when saving'"), + category: CHAT_CATEGORY, + f1: true + }); + } + + run(accessor: ServicesAccessor) { + const storageService = accessor.get(IStorageService); + storageService.remove(_storageKey, StorageScope.PROFILE); + } +}); diff --git a/src/vs/workbench/contrib/chat/browser/chatInputPart.ts b/src/vs/workbench/contrib/chat/browser/chatInputPart.ts index 7223dee7cea85..91c4b0d94067b 100644 --- a/src/vs/workbench/contrib/chat/browser/chatInputPart.ts +++ b/src/vs/workbench/contrib/chat/browser/chatInputPart.ts @@ -9,7 +9,6 @@ import { IHistoryNavigationWidget } from '../../../../base/browser/history.js'; import { StandardKeyboardEvent } from '../../../../base/browser/keyboardEvent.js'; import * as aria from '../../../../base/browser/ui/aria/aria.js'; import { Button } from '../../../../base/browser/ui/button/button.js'; -import { IManagedHoverContentOrFactory } from '../../../../base/browser/ui/hover/hover.js'; import { IHoverDelegate } from '../../../../base/browser/ui/hover/hoverDelegate.js'; import { createInstantHoverDelegate } from '../../../../base/browser/ui/hover/hoverDelegateFactory.js'; import { renderLabelWithIcons } from '../../../../base/browser/ui/iconLabel/iconLabels.js'; @@ -672,9 +671,8 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge } const widget = dom.append(container, $('.chat-attached-context-attachment.show-file-icons')); - const label = this._contextResourceLabels.create(widget, { supportIcons: true, hoverDelegate }); + const label = this._contextResourceLabels.create(widget, { supportIcons: true, hoverDelegate, hoverTargetOverrride: widget }); - let hoverElement: IManagedHoverContentOrFactory; let ariaLabel: string | undefined; const file = URI.isUri(attachment.value) ? attachment.value : attachment.value && typeof attachment.value === 'object' && 'uri' in attachment.value && URI.isUri(attachment.value.uri) ? attachment.value.uri : undefined; @@ -685,7 +683,6 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge const friendlyName = `${fileBasename} ${fileDirname}`; ariaLabel = range ? localize('chat.fileAttachmentWithRange', "Attached file, {0}, line {1} to line {2}", friendlyName, range.startLineNumber, range.endLineNumber) : localize('chat.fileAttachment', "Attached file, {0}", friendlyName); - hoverElement = file.fsPath; label.setFile(file, { fileKind: FileKind.FILE, @@ -696,7 +693,7 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge } else if (attachment.isImage) { ariaLabel = localize('chat.imageAttachment', "Attached image, {0}", attachment.name); - hoverElement = dom.$('div.chat-attached-context-hover'); + const hoverElement = dom.$('div.chat-attached-context-hover'); hoverElement.setAttribute('aria-label', ariaLabel); // Custom label @@ -707,14 +704,12 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge let buffer: Uint8Array; try { + this.attachButtonAndDisposables(widget, index, attachment, hoverDelegate); if (attachment.value instanceof URI) { - this.attachButtonAndDisposables(widget, index, attachment, hoverDelegate); const readFile = await this.fileService.readFile(attachment.value); buffer = readFile.value.buffer; - } else { buffer = attachment.value as Uint8Array; - this.attachButtonAndDisposables(widget, index, attachment, hoverDelegate); } this.createImageElements(buffer, widget, hoverElement); } catch (error) { @@ -722,22 +717,21 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge } widget.style.position = 'relative'; + if (!this.attachedContextDisposables.isDisposed) { + this.attachedContextDisposables.add(this.hoverService.setupManagedHover(hoverDelegate, widget, hoverElement, { trapFocus: false })); + } } else { const attachmentLabel = attachment.fullName ?? attachment.name; const withIcon = attachment.icon?.id ? `$(${attachment.icon.id}) ${attachmentLabel}` : attachmentLabel; label.setLabel(withIcon, undefined); ariaLabel = localize('chat.attachment', "Attached context, {0}", attachment.name); - hoverElement = attachmentLabel; this.attachButtonAndDisposables(widget, index, attachment, hoverDelegate); } widget.tabIndex = 0; widget.ariaLabel = ariaLabel; - if (!this.attachedContextDisposables.isDisposed) { - this.attachedContextDisposables.add(this.hoverService.setupManagedHover(hoverDelegate, widget, hoverElement, { trapFocus: false })); - } }); if (oldHeight !== container.offsetHeight && !isLayout) { @@ -786,7 +780,6 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge private createImageElements(buffer: ArrayBuffer | Uint8Array, widget: HTMLElement, hoverElement: HTMLElement) { const blob = new Blob([buffer], { type: 'image/png' }); const url = URL.createObjectURL(blob); - const img = dom.$('img.chat-attached-context-image', { src: url, alt: '' }); const pillImg = dom.$('img.chat-attached-context-pill-image', { src: url, alt: '' }); const pill = dom.$('div.chat-attached-context-pill', {}, pillImg); @@ -795,8 +788,14 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge existingPill.replaceWith(pill); } + const hoverImage = dom.$('img.chat-attached-context-image', { src: url, alt: '' }); + // Update hover image - hoverElement.appendChild(img); + hoverElement.appendChild(hoverImage); + + hoverImage.onload = () => { + URL.revokeObjectURL(url); + }; } async renderChatEditingSessionState(chatEditingSession: IChatEditingSession | null, chatWidget?: IChatWidget) { @@ -807,15 +806,12 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge this._chatEditsDisposables.clear(); this._chatEditList = undefined; this._chatEditsProgress?.dispose(); - this._chatEditsProgress = undefined; return; } const currentChatEditingState = chatEditingSession.state.get(); - if (this._chatEditList && (currentChatEditingState === ChatEditingSessionState.Idle || currentChatEditingState === ChatEditingSessionState.Initial && !chatWidget?.viewModel?.requestInProgress)) { + if (this._chatEditList && !chatWidget?.viewModel?.requestInProgress && (currentChatEditingState === ChatEditingSessionState.Idle || currentChatEditingState === ChatEditingSessionState.Initial)) { this._chatEditsProgress?.stop(); - this._chatEditsProgress?.dispose(); - this._chatEditsProgress = undefined; } // Summary of number of files changed @@ -895,9 +891,9 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge return; } - if (!this._chatEditsProgress && (currentChatEditingState === ChatEditingSessionState.StreamingEdits || chatWidget?.viewModel?.requestInProgress)) { - this._chatEditsProgress = new ProgressBar(innerContainer); - this._chatEditsProgress.infinite().show(500); + if (currentChatEditingState === ChatEditingSessionState.StreamingEdits || chatWidget?.viewModel?.requestInProgress) { + this._chatEditsProgress ??= new ProgressBar(innerContainer); + this._chatEditsProgress?.infinite().show(500); } // Working set diff --git a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts index a4cfa6c53ddfe..b057c4ed0ae8c 100644 --- a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts +++ b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts @@ -590,30 +590,27 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer part === null); - if (isFullyRendered) { - if (element.isComplete) { - // Response is done and content is rendered, so do a normal render + const contentIsAlreadyRendered = partsToRender.every(part => part === null); + if (contentIsAlreadyRendered) { + if (contentForThisTurn.moreContentAvailable) { + // The content that we want to render in this turn is already rendered, but there is more content to render on the next tick + this.traceLayout('doNextProgressiveRender', 'not rendering any new content this tick, but more available'); + return false; + } else if (element.isComplete) { + // All content is rendered, and response is done, so do a normal render this.traceLayout('doNextProgressiveRender', `END progressive render, index=${index} and clearing renderData, response is complete`); element.renderData = undefined; this.basicRenderElement(element, index, templateData); return true; - } - - if (!contentForThisTurn.moreContentAvailable) { + } else { // Nothing new to render, stop rendering until next model update this.traceLayout('doNextProgressiveRender', 'caught up with the stream- no new content to render'); return true; } - - // The content that we want to render in this turn is already rendered, but there is more content to render on the next tick - this.traceLayout('doNextProgressiveRender', 'not rendering any new content this tick, but more available'); - return false; } // Do an actual progressive render @@ -686,34 +683,38 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer part.kind === 'markdownContent')) { + moreContentAvailable = true; + } break; } } else { @@ -730,7 +731,7 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer 0 }; + return { content: partsToRender, moreContentAvailable }; } private getDataForProgressiveRender(element: IChatResponseViewModel) { diff --git a/src/vs/workbench/contrib/chat/browser/chatParticipantContributions.ts b/src/vs/workbench/contrib/chat/browser/chatParticipantContributions.ts index 8f9a2e9195b97..e5e0949dab318 100644 --- a/src/vs/workbench/contrib/chat/browser/chatParticipantContributions.ts +++ b/src/vs/workbench/contrib/chat/browser/chatParticipantContributions.ts @@ -220,19 +220,17 @@ export class ChatExtensionPointHandler implements IWorkbenchContribution { examples: string[]; }[] = []; - if (isProposedApiEnabled(extension.description, 'contribChatParticipantDetection')) { - if (providerDescriptor.disambiguation?.length) { - participantsAndCommandsDisambiguation.push(...providerDescriptor.disambiguation.map((d) => ({ - ...d, category: d.category ?? d.categoryName - }))); - } - if (providerDescriptor.commands) { - for (const command of providerDescriptor.commands) { - if (command.disambiguation?.length) { - participantsAndCommandsDisambiguation.push(...command.disambiguation.map((d) => ({ - ...d, category: d.category ?? d.categoryName - }))); - } + if (providerDescriptor.disambiguation?.length) { + participantsAndCommandsDisambiguation.push(...providerDescriptor.disambiguation.map((d) => ({ + ...d, category: d.category ?? d.categoryName + }))); + } + if (providerDescriptor.commands) { + for (const command of providerDescriptor.commands) { + if (command.disambiguation?.length) { + participantsAndCommandsDisambiguation.push(...command.disambiguation.map((d) => ({ + ...d, category: d.category ?? d.categoryName + }))); } } } diff --git a/src/vs/workbench/contrib/chat/browser/chatPasteProviders.ts b/src/vs/workbench/contrib/chat/browser/chatPasteProviders.ts index a396f7674ef2c..1a9f25d3211d4 100644 --- a/src/vs/workbench/contrib/chat/browser/chatPasteProviders.ts +++ b/src/vs/workbench/contrib/chat/browser/chatPasteProviders.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { CancellationToken } from '../../../../base/common/cancellation.js'; -import { IReadonlyVSDataTransfer } from '../../../../base/common/dataTransfer.js'; +import { IDataTransferItem, IReadonlyVSDataTransfer } from '../../../../base/common/dataTransfer.js'; import { HierarchicalKind } from '../../../../base/common/hierarchicalKind.js'; import { IRange } from '../../../../editor/common/core/range.js'; import { DocumentPasteContext, DocumentPasteEditProvider, DocumentPasteEditsSession } from '../../../../editor/common/languages.js'; @@ -12,26 +12,137 @@ import { ITextModel } from '../../../../editor/common/model.js'; import { ILanguageFeaturesService } from '../../../../editor/common/services/languageFeatures.js'; import { Disposable } from '../../../../base/common/lifecycle.js'; import { ChatInputPart } from './chatInputPart.js'; - +import { IChatWidgetService } from './chat.js'; +import { Codicon } from '../../../../base/common/codicons.js'; +import { localize } from '../../../../nls.js'; +import { IChatRequestVariableEntry } from '../common/chatModel.js'; +import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; export class PasteImageProvider implements DocumentPasteEditProvider { public readonly kind = new HierarchicalKind('image'); public readonly pasteMimeTypes = ['image/*']; + constructor( + private readonly chatWidgetService: IChatWidgetService, + private readonly configurationService: IConfigurationService + ) { } async provideDocumentPasteEdits(_model: ITextModel, _ranges: readonly IRange[], dataTransfer: IReadonlyVSDataTransfer, context: DocumentPasteContext, token: CancellationToken): Promise { - // TODO: @justschen setup image data types - // const entry = dataTransfer.get('image/png') || dataTransfer.get('image/jpeg') || dataTransfer.get('image/gif') || dataTransfer.get('image/webp'); + if (!this.configurationService.getValue('chat.experimental.imageAttachments')) { + return; + } + + const supportedMimeTypes = [ + 'image/png', + 'image/jpeg', + 'image/jpg', + 'image/bmp', + 'image/gif', + 'image/tiff' + ]; + + let mimeType: string | undefined; + let imageItem: IDataTransferItem | undefined; + + // Find the first matching image type in the dataTransfer + for (const type of supportedMimeTypes) { + imageItem = dataTransfer.get(type); + if (imageItem) { + mimeType = type; + break; + } + } + + if (!imageItem || !mimeType) { + return; + } + const currClipboard = await imageItem.asFile()?.data(); + if (token.isCancellationRequested || !currClipboard) { + return; + } + + const widget = this.chatWidgetService.getWidgetByInputUri(_model.uri); + if (!widget) { + return; + } + + const attachedVariables = widget.attachmentModel.attachments; + const displayName = localize('pastedImageName', 'Pasted Image'); + let tempDisplayName = displayName; + + for (let appendValue = 2; attachedVariables.some(attachment => attachment.name === tempDisplayName); appendValue++) { + tempDisplayName = `${displayName} ${appendValue}`; + } + + const imageContext = await getImageAttachContext(currClipboard, mimeType, token, tempDisplayName); + + if (token.isCancellationRequested || !imageContext) { + return; + } + + // Make sure to attach only new contexts + const currentContextIds = widget.attachmentModel.getAttachmentIDs(); + if (currentContextIds.has(imageContext.id)) { + return; + } + + widget.attachmentModel.addContext(imageContext); + return; } } +async function getImageAttachContext(data: Uint8Array, mimeType: string, token: CancellationToken, displayName: string): Promise { + const imageHash = await imageToHash(data); + if (token.isCancellationRequested) { + return undefined; + } + + return { + value: data, + id: imageHash, + name: displayName, + isImage: true, + icon: Codicon.fileMedia, + isDynamic: true, + isFile: false, + mimeType + }; +} + +export async function imageToHash(data: Uint8Array): Promise { + const hashBuffer = await crypto.subtle.digest('SHA-256', data); + const hashArray = Array.from(new Uint8Array(hashBuffer)); + return hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); +} + +export function isImage(array: Uint8Array): boolean { + if (array.length < 4) { + return false; + } + + // Magic numbers (identification bytes) for various image formats + const identifier: { [key: string]: number[] } = { + png: [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A], + jpeg: [0xFF, 0xD8, 0xFF], + bmp: [0x42, 0x4D], + gif: [0x47, 0x49, 0x46, 0x38], + tiff: [0x49, 0x49, 0x2A, 0x00] + }; + + return Object.values(identifier).some((signature) => + signature.every((byte, index) => array[index] === byte) + ); +} + export class ChatPasteProvidersFeature extends Disposable { constructor( @ILanguageFeaturesService languageFeaturesService: ILanguageFeaturesService, + @IChatWidgetService chatWidgetService: IChatWidgetService, + @IConfigurationService configurationService: IConfigurationService ) { super(); - this._register(languageFeaturesService.documentPasteEditProvider.register({ scheme: ChatInputPart.INPUT_SCHEME, pattern: '*', hasAccessToAllModels: true }, new PasteImageProvider())); + this._register(languageFeaturesService.documentPasteEditProvider.register({ scheme: ChatInputPart.INPUT_SCHEME, pattern: '*', hasAccessToAllModels: true }, new PasteImageProvider(chatWidgetService, configurationService))); } } diff --git a/src/vs/workbench/contrib/chat/browser/chatVariables.ts b/src/vs/workbench/contrib/chat/browser/chatVariables.ts index e24841ebbcc18..4881e8715d2e5 100644 --- a/src/vs/workbench/contrib/chat/browser/chatVariables.ts +++ b/src/vs/workbench/contrib/chat/browser/chatVariables.ts @@ -8,7 +8,6 @@ import { CancellationToken } from '../../../../base/common/cancellation.js'; import { onUnexpectedExternalError } from '../../../../base/common/errors.js'; import { Iterable } from '../../../../base/common/iterator.js'; import { IDisposable, toDisposable } from '../../../../base/common/lifecycle.js'; -import { basename } from '../../../../base/common/path.js'; import { ThemeIcon } from '../../../../base/common/themables.js'; import { URI } from '../../../../base/common/uri.js'; import { Location } from '../../../../editor/common/languages.js'; @@ -175,7 +174,7 @@ export class ChatVariablesService implements IChatVariablesService { if (key === 'file' && typeof value !== 'string') { const uri = URI.isUri(value) ? value : value.uri; const range = 'range' in value ? value.range : undefined; - widget.attachmentModel.addContext({ value, id: uri.toString() + (range?.toString() ?? ''), name: basename(uri.path), isFile: true, isDynamic: true }); + widget.attachmentModel.addFile(uri, range); return; } diff --git a/src/vs/workbench/contrib/chat/browser/chatViewPane.ts b/src/vs/workbench/contrib/chat/browser/chatViewPane.ts index 401a4f0291a1f..9afcb80b2d7ff 100644 --- a/src/vs/workbench/contrib/chat/browser/chatViewPane.ts +++ b/src/vs/workbench/contrib/chat/browser/chatViewPane.ts @@ -124,6 +124,9 @@ export class ChatViewPane extends ViewPane { this.viewState.sessionId = model.sessionId; this._widget.setModel(model, { ...this.viewState }); + + // Update the toolbar context with new sessionId + this.updateActions(); } override shouldShowWelcome(): boolean { diff --git a/src/vs/workbench/contrib/chat/browser/chatWidget.ts b/src/vs/workbench/contrib/chat/browser/chatWidget.ts index dd462c2d65356..1fc8109968a5e 100644 --- a/src/vs/workbench/contrib/chat/browser/chatWidget.ts +++ b/src/vs/workbench/contrib/chat/browser/chatWidget.ts @@ -45,7 +45,6 @@ import { ChatTreeItem, IChatAccessibilityService, IChatCodeBlockInfo, IChatFileT import { ChatAccessibilityProvider } from './chatAccessibilityProvider.js'; import { ChatAttachmentModel } from './chatAttachmentModel.js'; import { ChatDragAndDrop } from './chatDragAndDrop.js'; -import { ChatImageDropAndPaste } from './chatImagePaste.js'; import { ChatInputPart } from './chatInputPart.js'; import { ChatListDelegate, ChatListItemRenderer, IChatRendererDelegate } from './chatListRenderer.js'; import { ChatEditorOptions } from './chatOptions.js'; @@ -425,7 +424,6 @@ export class ChatWidget extends Disposable implements IChatWidget { }).filter(isDefined); this._register(this.instantiationService.createInstance(ChatDragAndDrop, this.container, this.inputPart, this.styles)); - this._register(this.instantiationService.createInstance(ChatImageDropAndPaste, this.inputPart)); } getContrib(id: string): T | undefined { diff --git a/src/vs/workbench/contrib/chat/browser/languageModelToolsService.ts b/src/vs/workbench/contrib/chat/browser/languageModelToolsService.ts new file mode 100644 index 0000000000000..bf464385d97e0 --- /dev/null +++ b/src/vs/workbench/contrib/chat/browser/languageModelToolsService.ts @@ -0,0 +1,194 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { renderStringAsPlaintext } from '../../../../base/browser/markdownRenderer.js'; +import { RunOnceScheduler } from '../../../../base/common/async.js'; +import { CancellationToken } from '../../../../base/common/cancellation.js'; +import { CancellationError } from '../../../../base/common/errors.js'; +import { Emitter } from '../../../../base/common/event.js'; +import { Iterable } from '../../../../base/common/iterator.js'; +import { Disposable, IDisposable, toDisposable } from '../../../../base/common/lifecycle.js'; +import { localize } from '../../../../nls.js'; +import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; +import { IDialogService } from '../../../../platform/dialogs/common/dialogs.js'; +import { IExtensionService } from '../../../services/extensions/common/extensions.js'; +import { ChatModel } from '../common/chatModel.js'; +import { ChatToolInvocation } from '../common/chatProgressTypes/chatToolInvocation.js'; +import { IChatService } from '../common/chatService.js'; +import { CountTokensCallback, ILanguageModelToolsService, IToolData, IToolImpl, IToolInvocation, IToolResult } from '../common/languageModelToolsService.js'; + +interface IToolEntry { + data: IToolData; + impl?: IToolImpl; +} + +export class LanguageModelToolsService extends Disposable implements ILanguageModelToolsService { + _serviceBrand: undefined; + + private _onDidChangeTools = new Emitter(); + readonly onDidChangeTools = this._onDidChangeTools.event; + + /** Throttle tools updates because it sends all tools and runs on context key updates */ + private _onDidChangeToolsScheduler = new RunOnceScheduler(() => this._onDidChangeTools.fire(), 750); + + private _tools = new Map(); + private _toolContextKeys = new Set(); + + constructor( + @IExtensionService private readonly _extensionService: IExtensionService, + @IContextKeyService private readonly _contextKeyService: IContextKeyService, + @IChatService private readonly _chatService: IChatService, + @IDialogService private readonly _dialogService: IDialogService, + ) { + super(); + + this._register(this._contextKeyService.onDidChangeContext(e => { + if (e.affectsSome(this._toolContextKeys)) { + // Not worth it to compute a delta here unless we have many tools changing often + this._onDidChangeToolsScheduler.schedule(); + } + })); + } + + registerToolData(toolData: IToolData): IDisposable { + if (this._tools.has(toolData.id)) { + throw new Error(`Tool "${toolData.id}" is already registered.`); + } + + // Ensure that text/plain is supported + if (!toolData.supportedContentTypes.includes('text/plain')) { + toolData.supportedContentTypes.push('text/plain'); + } + + this._tools.set(toolData.id, { data: toolData }); + this._onDidChangeToolsScheduler.schedule(); + + toolData.when?.keys().forEach(key => this._toolContextKeys.add(key)); + + return toDisposable(() => { + this._tools.delete(toolData.id); + this._refreshAllToolContextKeys(); + this._onDidChangeToolsScheduler.schedule(); + }); + } + + private _refreshAllToolContextKeys() { + this._toolContextKeys.clear(); + for (const tool of this._tools.values()) { + tool.data.when?.keys().forEach(key => this._toolContextKeys.add(key)); + } + } + + registerToolImplementation(id: string, tool: IToolImpl): IDisposable { + const entry = this._tools.get(id); + if (!entry) { + throw new Error(`Tool "${id}" was not contributed.`); + } + + if (entry.impl) { + throw new Error(`Tool "${id}" already has an implementation.`); + } + + entry.impl = tool; + return toDisposable(() => { + entry.impl = undefined; + }); + } + + getTools(): Iterable> { + const toolDatas = Iterable.map(this._tools.values(), i => i.data); + return Iterable.filter(toolDatas, toolData => !toolData.when || this._contextKeyService.contextMatchesRules(toolData.when)); + } + + getTool(id: string): IToolData | undefined { + return this._getToolEntry(id)?.data; + } + + private _getToolEntry(id: string): IToolEntry | undefined { + const entry = this._tools.get(id); + if (entry && (!entry.data.when || this._contextKeyService.contextMatchesRules(entry.data.when))) { + return entry; + } else { + return undefined; + } + } + + getToolByName(name: string): IToolData | undefined { + for (const toolData of this.getTools()) { + if (toolData.name === name) { + return toolData; + } + } + return undefined; + } + + async invokeTool(dto: IToolInvocation, countTokens: CountTokensCallback, token: CancellationToken): Promise { + // When invoking a tool, don't validate the "when" clause. An extension may have invoked a tool just as it was becoming disabled, and just let it go through rather than throw and break the chat. + let tool = this._tools.get(dto.toolId); + if (!tool) { + throw new Error(`Tool ${dto.toolId} was not contributed`); + } + + if (!tool.impl) { + await this._extensionService.activateByEvent(`onLanguageModelTool:${dto.toolId}`); + + // Extension should activate and register the tool implementation + tool = this._tools.get(dto.toolId); + if (!tool?.impl) { + throw new Error(`Tool ${dto.toolId} does not have an implementation registered.`); + } + } + + // Shortcut to write to the model directly here, but could call all the way back to use the real stream. + let toolInvocation: ChatToolInvocation | undefined; + if (dto.context) { + const model = this._chatService.getSession(dto.context?.sessionId) as ChatModel; + const request = model.getRequests().at(-1)!; + + const participantName = request.response?.agent?.fullName ?? ''; // This should always be set in this scenario with a new live request + + const prepared = tool.impl.prepareToolInvocation ? + await tool.impl.prepareToolInvocation(participantName, dto.parameters, token) + : undefined; + const confirmationMessages = tool.data.requiresConfirmation ? + prepared?.confirmationMessages ?? { + title: localize('toolConfirmTitle', "Use {0}?", `"${tool.data.displayName ?? tool.data.id}"`), + message: localize('toolConfirmMessage', "{0} will use {1}.", participantName, `"${tool.data.displayName ?? tool.data.id}"`), + } + : undefined; + + const defaultMessage = localize('toolInvocationMessage', "Using {0}", `"${tool.data.displayName ?? tool.data.id}"`); + const invocationMessage = prepared?.invocationMessage ?? defaultMessage; + toolInvocation = new ChatToolInvocation(invocationMessage, confirmationMessages); + token.onCancellationRequested(() => { + toolInvocation!.confirmed.complete(false); + }); + model.acceptResponseProgress(request, toolInvocation); + if (tool.data.requiresConfirmation) { + const userConfirmed = await toolInvocation.confirmed.p; + if (!userConfirmed) { + throw new CancellationError(); + } + } + } else if (tool.data.requiresConfirmation) { + const prepared = tool.impl.prepareToolInvocation ? + await tool.impl.prepareToolInvocation('Some Extension', dto.parameters, token) + : undefined; + + const confirmationMessages = prepared?.confirmationMessages ?? { + title: localize('toolConfirmTitle', "Use {0}?", `"${tool.data.displayName ?? tool.data.id}"`), + message: localize('toolConfirmMessage', "{0} will use {1}.", 'Some Extension', `"${tool.data.displayName ?? tool.data.id}"`), + }; + + await this._dialogService.confirm({ message: confirmationMessages.title, detail: renderStringAsPlaintext(confirmationMessages.message) }); + } + + try { + return await tool.impl.invoke(dto, countTokens, token); + } finally { + toolInvocation?.isCompleteDeferred.complete(); + } + } +} diff --git a/src/vs/workbench/contrib/chat/browser/media/chat.css b/src/vs/workbench/contrib/chat/browser/media/chat.css index 7a61ca4705ca2..1328506739f24 100644 --- a/src/vs/workbench/contrib/chat/browser/media/chat.css +++ b/src/vs/workbench/contrib/chat/browser/media/chat.css @@ -1126,8 +1126,8 @@ have to be updated for changes to the rules above, or to support more deeply nes .chat-attached-context-hover .chat-attached-context-image { height: auto; - max-height: 500px; - max-width: 400px; + max-height: 512px; + max-width: 512px; width: 100%; display: block; } @@ -1136,7 +1136,7 @@ have to be updated for changes to the rules above, or to support more deeply nes font-size: 12px; display: inline-flex; align-items: center; - padding: 0 4px 0 2px; + padding: 2px 0 2px 0px; border-radius: 2px; margin-right: 1px; user-select: none; @@ -1145,8 +1145,8 @@ have to be updated for changes to the rules above, or to support more deeply nes } .chat-attached-context-attachment .chat-attached-context-pill-image { - width: 16px; - height: 16px; + width: 14px; + height: 14px; border-radius: 2px; } diff --git a/src/vs/workbench/contrib/chat/common/chatCodeMapperService.ts b/src/vs/workbench/contrib/chat/common/chatCodeMapperService.ts index bf1ae9d8c194a..097ca6d89157c 100644 --- a/src/vs/workbench/contrib/chat/common/chatCodeMapperService.ts +++ b/src/vs/workbench/contrib/chat/common/chatCodeMapperService.ts @@ -140,7 +140,7 @@ export class CodeMapperService implements ICodeMapperService { }); conversation.push({ type: 'response', - message: response.response.toMarkdown(), + message: response.response.getMarkdown(), result: response.result, references: getReferencesAsDocumentContext(response.contentReferences) }); diff --git a/src/vs/workbench/contrib/chat/common/chatEditingService.ts b/src/vs/workbench/contrib/chat/common/chatEditingService.ts index 43e8efe5f19fb..b5bdc4c743e15 100644 --- a/src/vs/workbench/contrib/chat/common/chatEditingService.ts +++ b/src/vs/workbench/contrib/chat/common/chatEditingService.ts @@ -8,6 +8,7 @@ import { Event } from '../../../../base/common/event.js'; import { IObservable, ITransaction } from '../../../../base/common/observable.js'; import { URI } from '../../../../base/common/uri.js'; import { TextEdit } from '../../../../editor/common/languages.js'; +import { ITextModel } from '../../../../editor/common/model.js'; import { localize } from '../../../../nls.js'; import { RawContextKey } from '../../../../platform/contextkey/common/contextkey.js'; import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js'; @@ -19,6 +20,10 @@ export interface IChatEditingService { _serviceBrand: undefined; readonly onDidCreateEditingSession: Event; + /** + * emitted when a session is created, changed or disposed + */ + readonly onDidChangeEditingSession: Event; readonly currentEditingSession: IChatEditingSession | null; readonly currentAutoApplyOperation: CancellationTokenSource | null; @@ -26,6 +31,7 @@ export interface IChatEditingService { startOrContinueEditingSession(chatSessionId: string, options?: { silent: boolean }): Promise; addFileToWorkingSet(resource: URI): Promise; triggerEditComputation(responseModel: IChatResponseModel): Promise; + getEditingSession(resource: URI): IChatEditingSession | null; } export interface IChatEditingSession { @@ -55,6 +61,7 @@ export const enum WorkingSetEntryState { export interface IModifiedFileEntry { readonly originalURI: URI; + readonly originalModel: ITextModel; readonly modifiedURI: URI; readonly state: IObservable; accept(transaction: ITransaction | undefined): Promise; @@ -62,7 +69,7 @@ export interface IModifiedFileEntry { } export interface IChatEditingSessionStream { - textEdits(resource: URI, textEdits: TextEdit[]): void; + textEdits(resource: URI, textEdits: TextEdit[], responseModel: IChatResponseModel): void; } export const enum ChatEditingSessionState { diff --git a/src/vs/workbench/contrib/chat/common/chatModel.ts b/src/vs/workbench/contrib/chat/common/chatModel.ts index c3b50f2e35da2..c7eaef0b5f1af 100644 --- a/src/vs/workbench/contrib/chat/common/chatModel.ts +++ b/src/vs/workbench/contrib/chat/common/chatModel.ts @@ -33,8 +33,12 @@ export interface IChatRequestVariableEntry { range?: IOffsetRange; value: IChatRequestVariableValue; references?: IChatContentReference[]; + mimeType?: string; // TODO are these just a 'kind'? + /** + * True if the variable has a value vs being a reference to a variable + */ isDynamic?: boolean; isFile?: boolean; isTool?: boolean; @@ -117,7 +121,7 @@ export type IChatProgressRenderableResponseContent = Exclude; - toMarkdown(): string; + getMarkdown(): string; toString(): string; } @@ -246,7 +250,10 @@ export class Response extends Disposable implements IResponse { return this._responseRepr; } - toMarkdown(): string { + /** + * _Just_ the content of markdown parts in the response + */ + getMarkdown(): string { return this._markdownContent; } @@ -358,7 +365,7 @@ export class Response extends Disposable implements IResponse { } }) .filter(s => s.length > 0) - .join('\n\n'); + .join(''); if (!quiet) { this._onDidChangeValue.fire(); diff --git a/src/vs/workbench/contrib/chat/common/chatService.ts b/src/vs/workbench/contrib/chat/common/chatService.ts index 8737fc42f2898..a0e452163164f 100644 --- a/src/vs/workbench/contrib/chat/common/chatService.ts +++ b/src/vs/workbench/contrib/chat/common/chatService.ts @@ -326,7 +326,15 @@ export interface IChatInlineChatCodeAction { action: 'accepted' | 'discarded'; } -export type ChatUserAction = IChatVoteAction | IChatCopyAction | IChatInsertAction | IChatApplyAction | IChatTerminalAction | IChatCommandAction | IChatFollowupAction | IChatBugReportAction | IChatInlineChatCodeAction; + +export interface IChatEditingSessionAction { + kind: 'chatEditingSessionAction'; + uri: URI; + hasRemainingEdits: boolean; + outcome: 'accepted' | 'rejected'; +} + +export type ChatUserAction = IChatVoteAction | IChatCopyAction | IChatInsertAction | IChatApplyAction | IChatTerminalAction | IChatCommandAction | IChatFollowupAction | IChatBugReportAction | IChatInlineChatCodeAction | IChatEditingSessionAction; export interface IChatUserActionEvent { action: ChatUserAction; diff --git a/src/vs/workbench/contrib/chat/common/chatViewModel.ts b/src/vs/workbench/contrib/chat/common/chatViewModel.ts index 4faeae41c0bdd..02cf44b3708a1 100644 --- a/src/vs/workbench/contrib/chat/common/chatViewModel.ts +++ b/src/vs/workbench/contrib/chat/common/chatViewModel.ts @@ -523,7 +523,7 @@ export class ChatResponseViewModel extends Disposable implements IChatResponseVi // This should be true, if the model is changing if (this._contentUpdateTimings) { const now = Date.now(); - const wordCount = countWords(_model.response.toString()); + const wordCount = countWords(_model.response.getMarkdown()); // Apply a min time difference, or the rate is typically too high for first few words const timeDiff = Math.max(now - this._contentUpdateTimings.firstWordTime, 250); diff --git a/src/vs/workbench/contrib/chat/common/chatWordCounter.ts b/src/vs/workbench/contrib/chat/common/chatWordCounter.ts index c1989d4f99796..bc58ea59b6b2c 100644 --- a/src/vs/workbench/contrib/chat/common/chatWordCounter.ts +++ b/src/vs/workbench/contrib/chat/common/chatWordCounter.ts @@ -50,7 +50,7 @@ export function getNWords(str: string, numWordsToCount: number): IWordCountResul const targetWords = allWordMatches.slice(0, numWordsToCount); - const endIndex = numWordsToCount > allWordMatches.length + const endIndex = numWordsToCount >= allWordMatches.length ? str.length // Reached end of string : targetWords.length ? targetWords.at(-1)!.index + targetWords.at(-1)![0].length : 0; diff --git a/src/vs/workbench/contrib/chat/common/languageModelToolsService.ts b/src/vs/workbench/contrib/chat/common/languageModelToolsService.ts index 1b8339e2afc87..ac0c2a4ef1fd7 100644 --- a/src/vs/workbench/contrib/chat/common/languageModelToolsService.ts +++ b/src/vs/workbench/contrib/chat/common/languageModelToolsService.ts @@ -3,23 +3,15 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { RunOnceScheduler } from '../../../../base/common/async.js'; import { CancellationToken } from '../../../../base/common/cancellation.js'; -import { CancellationError } from '../../../../base/common/errors.js'; -import { Emitter, Event } from '../../../../base/common/event.js'; +import { Event } from '../../../../base/common/event.js'; import { IMarkdownString } from '../../../../base/common/htmlContent.js'; -import { Iterable } from '../../../../base/common/iterator.js'; import { IJSONSchema } from '../../../../base/common/jsonSchema.js'; -import { Disposable, IDisposable, toDisposable } from '../../../../base/common/lifecycle.js'; +import { IDisposable } from '../../../../base/common/lifecycle.js'; import { ThemeIcon } from '../../../../base/common/themables.js'; import { URI } from '../../../../base/common/uri.js'; -import { localize } from '../../../../nls.js'; -import { ContextKeyExpression, IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; +import { ContextKeyExpression } from '../../../../platform/contextkey/common/contextkey.js'; import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js'; -import { IExtensionService } from '../../../services/extensions/common/extensions.js'; -import { ChatModel } from './chatModel.js'; -import { ChatToolInvocation } from './chatProgressTypes/chatToolInvocation.js'; -import { IChatService } from './chatService.js'; export interface IToolData { id: string; @@ -36,11 +28,6 @@ export interface IToolData { requiresConfirmation?: boolean; } -interface IToolEntry { - data: IToolData; - impl?: IToolImpl; -} - export interface IToolInvocation { callId: string; toolId: string; @@ -87,161 +74,3 @@ export interface ILanguageModelToolsService { getToolByName(name: string): IToolData | undefined; invokeTool(invocation: IToolInvocation, countTokens: CountTokensCallback, token: CancellationToken): Promise; } - -export class LanguageModelToolsService extends Disposable implements ILanguageModelToolsService { - _serviceBrand: undefined; - - private _onDidChangeTools = new Emitter(); - readonly onDidChangeTools = this._onDidChangeTools.event; - - /** Throttle tools updates because it sends all tools and runs on context key updates */ - private _onDidChangeToolsScheduler = new RunOnceScheduler(() => this._onDidChangeTools.fire(), 750); - - private _tools = new Map(); - private _toolContextKeys = new Set(); - - constructor( - @IExtensionService private readonly _extensionService: IExtensionService, - @IContextKeyService private readonly _contextKeyService: IContextKeyService, - @IChatService private readonly _chatService: IChatService, - ) { - super(); - - this._register(this._contextKeyService.onDidChangeContext(e => { - if (e.affectsSome(this._toolContextKeys)) { - // Not worth it to compute a delta here unless we have many tools changing often - this._onDidChangeToolsScheduler.schedule(); - } - })); - } - - registerToolData(toolData: IToolData): IDisposable { - if (this._tools.has(toolData.id)) { - throw new Error(`Tool "${toolData.id}" is already registered.`); - } - - // Ensure that text/plain is supported - if (!toolData.supportedContentTypes.includes('text/plain')) { - toolData.supportedContentTypes.push('text/plain'); - } - - this._tools.set(toolData.id, { data: toolData }); - this._onDidChangeToolsScheduler.schedule(); - - toolData.when?.keys().forEach(key => this._toolContextKeys.add(key)); - - return toDisposable(() => { - this._tools.delete(toolData.id); - this._refreshAllToolContextKeys(); - this._onDidChangeToolsScheduler.schedule(); - }); - } - - private _refreshAllToolContextKeys() { - this._toolContextKeys.clear(); - for (const tool of this._tools.values()) { - tool.data.when?.keys().forEach(key => this._toolContextKeys.add(key)); - } - } - - registerToolImplementation(id: string, tool: IToolImpl): IDisposable { - const entry = this._tools.get(id); - if (!entry) { - throw new Error(`Tool "${id}" was not contributed.`); - } - - if (entry.impl) { - throw new Error(`Tool "${id}" already has an implementation.`); - } - - entry.impl = tool; - return toDisposable(() => { - entry.impl = undefined; - }); - } - - getTools(): Iterable> { - const toolDatas = Iterable.map(this._tools.values(), i => i.data); - return Iterable.filter(toolDatas, toolData => !toolData.when || this._contextKeyService.contextMatchesRules(toolData.when)); - } - - getTool(id: string): IToolData | undefined { - return this._getToolEntry(id)?.data; - } - - private _getToolEntry(id: string): IToolEntry | undefined { - const entry = this._tools.get(id); - if (entry && (!entry.data.when || this._contextKeyService.contextMatchesRules(entry.data.when))) { - return entry; - } else { - return undefined; - } - } - - getToolByName(name: string): IToolData | undefined { - for (const toolData of this.getTools()) { - if (toolData.name === name) { - return toolData; - } - } - return undefined; - } - - async invokeTool(dto: IToolInvocation, countTokens: CountTokensCallback, token: CancellationToken): Promise { - // When invoking a tool, don't validate the "when" clause. An extension may have invoked a tool just as it was becoming disabled, and just let it go through rather than throw and break the chat. - let tool = this._tools.get(dto.toolId); - if (!tool) { - throw new Error(`Tool ${dto.toolId} was not contributed`); - } - - if (!tool.impl) { - await this._extensionService.activateByEvent(`onLanguageModelTool:${dto.toolId}`); - - // Extension should activate and register the tool implementation - tool = this._tools.get(dto.toolId); - if (!tool?.impl) { - throw new Error(`Tool ${dto.toolId} does not have an implementation registered.`); - } - } - - // Shortcut to write to the model directly here, but could call all the way back to use the real stream. - let toolInvocation: ChatToolInvocation | undefined; - if (dto.context) { - const model = this._chatService.getSession(dto.context?.sessionId) as ChatModel; - const request = model.getRequests().at(-1)!; - - // TODO if a tool requiresConfirmation but is not being invoked inside a chat session, we can show some other UI, like a modal notification - const participantName = request.response?.agent?.fullName ?? ''; // This should always be set in this scenario with a new live request - - const prepared = tool.impl.prepareToolInvocation ? - await tool.impl.prepareToolInvocation(participantName, dto.parameters, token) - : undefined; - const confirmationMessages = tool.data.requiresConfirmation ? - prepared?.confirmationMessages ?? { - title: localize('toolConfirmTitle', "Use {0}?", `"${tool.data.displayName ?? tool.data.id}"`), - message: localize('toolConfirmMessage', "{0} will use {1}.", participantName, `"${tool.data.displayName ?? tool.data.id}"`), - } - : undefined; - - const defaultMessage = localize('toolInvocationMessage', "Using {0}", `"${tool.data.displayName ?? tool.data.id}"`); - const invocationMessage = prepared?.invocationMessage ?? defaultMessage; - toolInvocation = new ChatToolInvocation(invocationMessage, confirmationMessages); - token.onCancellationRequested(() => { - toolInvocation!.confirmed.complete(false); - }); - model.acceptResponseProgress(request, toolInvocation); - if (tool.data.requiresConfirmation) { - const userConfirmed = await toolInvocation.confirmed.p; - if (!userConfirmed) { - throw new CancellationError(); - } - } - } - - try { - return await tool.impl.invoke(dto, countTokens, token); - } finally { - toolInvocation?.isCompleteDeferred.complete(); - } - } -} diff --git a/src/vs/workbench/contrib/chat/electron-sandbox/actions/voiceChatActions.ts b/src/vs/workbench/contrib/chat/electron-sandbox/actions/voiceChatActions.ts index e64635b13f79a..e89738779e8fe 100644 --- a/src/vs/workbench/contrib/chat/electron-sandbox/actions/voiceChatActions.ts +++ b/src/vs/workbench/contrib/chat/electron-sandbox/actions/voiceChatActions.ts @@ -607,7 +607,7 @@ export class StartVoiceChatAction extends Action2 { }, { id: MenuId.ChatExecute, - when: ContextKeyExpr.and(CONTEXT_CHAT_LOCATION.isEqualTo(ChatAgentLocation.Panel).negate(), menuCondition), + when: ContextKeyExpr.and(CONTEXT_CHAT_LOCATION.isEqualTo(ChatAgentLocation.Panel).negate(), CONTEXT_CHAT_LOCATION.isEqualTo(ChatAgentLocation.EditingSession).negate(), menuCondition), group: 'navigation', order: 2 }, @@ -919,7 +919,8 @@ export class ReadChatResponseAloud extends Action2 { ScopedChatSynthesisInProgress.negate(), // but not when already in progress CONTEXT_RESPONSE_FILTERED.negate(), // and not when response is filtered ), - group: 'navigation' + group: 'navigation', + order: -10 // first }, { id: MENU_INLINE_CHAT_WIDGET_SECONDARY, when: ContextKeyExpr.and( @@ -928,7 +929,8 @@ export class ReadChatResponseAloud extends Action2 { ScopedChatSynthesisInProgress.negate(), // but not when already in progress CONTEXT_RESPONSE_FILTERED.negate() // and not when response is filtered ), - group: 'navigation' + group: 'navigation', + order: -10 // first }] }); } @@ -1046,7 +1048,8 @@ export class StopReadChatItemAloud extends Action2 { CONTEXT_RESPONSE, // only for responses CONTEXT_RESPONSE_FILTERED.negate() // but not when response is filtered ), - group: 'navigation' + group: 'navigation', + order: -10 // first }, { id: MENU_INLINE_CHAT_WIDGET_SECONDARY, @@ -1055,7 +1058,8 @@ export class StopReadChatItemAloud extends Action2 { CONTEXT_RESPONSE, // only for responses CONTEXT_RESPONSE_FILTERED.negate() // but not when response is filtered ), - group: 'navigation' + group: 'navigation', + order: -10 // first } ] }); diff --git a/src/vs/workbench/contrib/chat/test/browser/languageModelToolsService.test.ts b/src/vs/workbench/contrib/chat/test/browser/languageModelToolsService.test.ts index c8dee0123b602..da7a5f3e5a1a0 100644 --- a/src/vs/workbench/contrib/chat/test/browser/languageModelToolsService.test.ts +++ b/src/vs/workbench/contrib/chat/test/browser/languageModelToolsService.test.ts @@ -10,8 +10,10 @@ import { TestConfigurationService } from '../../../../../platform/configuration/ import { ContextKeyService } from '../../../../../platform/contextkey/browser/contextKeyService.js'; import { ContextKeyEqualsExpr, IContextKeyService } from '../../../../../platform/contextkey/common/contextkey.js'; import { TestExtensionService } from '../../../../test/common/workbenchTestServices.js'; -import { IToolData, IToolImpl, IToolInvocation, LanguageModelToolsService } from '../../common/languageModelToolsService.js'; +import { IToolData, IToolImpl, IToolInvocation } from '../../common/languageModelToolsService.js'; import { MockChatService } from '../common/mockChatService.js'; +import { TestDialogService } from '../../../../../platform/dialogs/test/common/testDialogService.js'; +import { LanguageModelToolsService } from '../../browser/languageModelToolsService.js'; suite('LanguageModelToolsService', () => { const store = ensureNoDisposablesAreLeakedInTestSuite(); @@ -22,7 +24,7 @@ suite('LanguageModelToolsService', () => { setup(() => { const extensionService = new TestExtensionService(); contextKeyService = store.add(new ContextKeyService(new TestConfigurationService())); - service = store.add(new LanguageModelToolsService(extensionService, contextKeyService, new MockChatService())); + service = store.add(new LanguageModelToolsService(extensionService, contextKeyService, new MockChatService(), new TestDialogService())); }); test('registerToolData', () => { diff --git a/src/vs/workbench/contrib/chat/test/common/chatWordCounter.test.ts b/src/vs/workbench/contrib/chat/test/common/chatWordCounter.test.ts index b2d51fdf260fe..b538b4c0eb4d8 100644 --- a/src/vs/workbench/contrib/chat/test/common/chatWordCounter.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/chatWordCounter.test.ts @@ -5,7 +5,7 @@ import assert from 'assert'; import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js'; -import { getNWords } from '../../common/chatWordCounter.js'; +import { getNWords, IWordCountResult } from '../../common/chatWordCounter.js'; suite('ChatWordCounter', () => { ensureNoDisposablesAreLeakedInTestSuite(); @@ -23,15 +23,42 @@ suite('ChatWordCounter', () => { ['hello', 1, 'hello'], ['hello world', 0, ''], ['here\'s, some. punctuation?', 3, 'here\'s, some. punctuation?'], - ['| markdown | _table_ | header |', 3, '| markdown | _table_ | header'], + ['| markdown | _table_ | header |', 3, '| markdown | _table_ | header |'], ['| --- | --- | --- |', 1, '| ---'], - ['| --- | --- | --- |', 3, '| --- | --- | ---'], - [' \t some \n whitespace \n\n\nhere ', 3, ' \t some \n whitespace \n\n\nhere'], + ['| --- | --- | --- |', 3, '| --- | --- | --- |'], + [' \t some \n whitespace \n\n\nhere ', 3, ' \t some \n whitespace \n\n\nhere '], ]; cases.forEach(([str, nWords, result]) => doTest(str, nWords, result)); }); + test('whitespace', () => { + assert.deepStrictEqual( + getNWords('hello ', 1), + { + value: 'hello ', + returnedWordCount: 1, + isFullString: true, + totalWordCount: 1, + } satisfies IWordCountResult); + assert.deepStrictEqual( + getNWords('hello\n\n', 1), + { + value: 'hello\n\n', + returnedWordCount: 1, + isFullString: true, + totalWordCount: 1, + } satisfies IWordCountResult); + assert.deepStrictEqual( + getNWords('\nhello', 1), + { + value: '\nhello', + returnedWordCount: 1, + isFullString: true, + totalWordCount: 1, + } satisfies IWordCountResult); + }); + test('matching links', () => { const cases: [string, number, string][] = [ ['[hello](https://example.com) world', 1, '[hello](https://example.com)'], diff --git a/src/vs/workbench/contrib/editSessions/browser/editSessionsViews.ts b/src/vs/workbench/contrib/editSessions/browser/editSessionsViews.ts index 9f436178a2509..4ec70193efcb8 100644 --- a/src/vs/workbench/contrib/editSessions/browser/editSessionsViews.ts +++ b/src/vs/workbench/contrib/editSessions/browser/editSessionsViews.ts @@ -44,6 +44,7 @@ export class EditSessionsDataViews extends Disposable { treeView.dataProvider = this.instantiationService.createInstance(EditSessionDataViewDataProvider); const viewsRegistry = Registry.as(Extensions.ViewsRegistry); + // eslint-disable-next-line local/code-no-dangerous-type-assertions viewsRegistry.registerViews([{ id: viewId, name: EDIT_SESSIONS_TITLE, diff --git a/src/vs/workbench/contrib/extensions/electron-sandbox/debugExtensionHostAction.ts b/src/vs/workbench/contrib/extensions/electron-sandbox/debugExtensionHostAction.ts index 71291a40f8e15..65e957e880237 100644 --- a/src/vs/workbench/contrib/extensions/electron-sandbox/debugExtensionHostAction.ts +++ b/src/vs/workbench/contrib/extensions/electron-sandbox/debugExtensionHostAction.ts @@ -105,6 +105,7 @@ export class DebugExtensionsContribution extends Disposable implements IWorkbenc location: ProgressLocation.Notification, title: nls.localize('debugExtensionHost.progress', "Attaching Debugger To Extension Host"), }, async p => { + // eslint-disable-next-line local/code-no-dangerous-type-assertions await this._debugService.startDebugging(undefined, { type: 'node', name: nls.localize('debugExtensionHost.launch.name', "Attach Extension Host"), diff --git a/src/vs/workbench/contrib/markdown/browser/markedGfmHeadingIdPlugin.ts b/src/vs/workbench/contrib/markdown/browser/markedGfmHeadingIdPlugin.ts index 39ed0d952705a..1603f7b21ef4e 100644 --- a/src/vs/workbench/contrib/markdown/browser/markedGfmHeadingIdPlugin.ts +++ b/src/vs/workbench/contrib/markdown/browser/markedGfmHeadingIdPlugin.ts @@ -5,7 +5,7 @@ import * as marked from '../../../../base/common/marked/marked.js'; // Copied from https://github.com/Flet/github-slugger since we can't use esm yet. -// eslint-disable-next-line no-control-regex, no-misleading-character-class +// eslint-disable-next-line no-misleading-character-class const githubSlugReplaceRegex = /[\0-\x1F!-,\.\/:-@\[-\^`\{-\xA9\xAB-\xB4\xB6-\xB9\xBB-\xBF\xD7\xF7\u02C2-\u02C5\u02D2-\u02DF\u02E5-\u02EB\u02ED\u02EF-\u02FF\u0375\u0378\u0379\u037E\u0380-\u0385\u0387\u038B\u038D\u03A2\u03F6\u0482\u0530\u0557\u0558\u055A-\u055F\u0589-\u0590\u05BE\u05C0\u05C3\u05C6\u05C8-\u05CF\u05EB-\u05EE\u05F3-\u060F\u061B-\u061F\u066A-\u066D\u06D4\u06DD\u06DE\u06E9\u06FD\u06FE\u0700-\u070F\u074B\u074C\u07B2-\u07BF\u07F6-\u07F9\u07FB\u07FC\u07FE\u07FF\u082E-\u083F\u085C-\u085F\u086B-\u089F\u08B5\u08C8-\u08D2\u08E2\u0964\u0965\u0970\u0984\u098D\u098E\u0991\u0992\u09A9\u09B1\u09B3-\u09B5\u09BA\u09BB\u09C5\u09C6\u09C9\u09CA\u09CF-\u09D6\u09D8-\u09DB\u09DE\u09E4\u09E5\u09F2-\u09FB\u09FD\u09FF\u0A00\u0A04\u0A0B-\u0A0E\u0A11\u0A12\u0A29\u0A31\u0A34\u0A37\u0A3A\u0A3B\u0A3D\u0A43-\u0A46\u0A49\u0A4A\u0A4E-\u0A50\u0A52-\u0A58\u0A5D\u0A5F-\u0A65\u0A76-\u0A80\u0A84\u0A8E\u0A92\u0AA9\u0AB1\u0AB4\u0ABA\u0ABB\u0AC6\u0ACA\u0ACE\u0ACF\u0AD1-\u0ADF\u0AE4\u0AE5\u0AF0-\u0AF8\u0B00\u0B04\u0B0D\u0B0E\u0B11\u0B12\u0B29\u0B31\u0B34\u0B3A\u0B3B\u0B45\u0B46\u0B49\u0B4A\u0B4E-\u0B54\u0B58-\u0B5B\u0B5E\u0B64\u0B65\u0B70\u0B72-\u0B81\u0B84\u0B8B-\u0B8D\u0B91\u0B96-\u0B98\u0B9B\u0B9D\u0BA0-\u0BA2\u0BA5-\u0BA7\u0BAB-\u0BAD\u0BBA-\u0BBD\u0BC3-\u0BC5\u0BC9\u0BCE\u0BCF\u0BD1-\u0BD6\u0BD8-\u0BE5\u0BF0-\u0BFF\u0C0D\u0C11\u0C29\u0C3A-\u0C3C\u0C45\u0C49\u0C4E-\u0C54\u0C57\u0C5B-\u0C5F\u0C64\u0C65\u0C70-\u0C7F\u0C84\u0C8D\u0C91\u0CA9\u0CB4\u0CBA\u0CBB\u0CC5\u0CC9\u0CCE-\u0CD4\u0CD7-\u0CDD\u0CDF\u0CE4\u0CE5\u0CF0\u0CF3-\u0CFF\u0D0D\u0D11\u0D45\u0D49\u0D4F-\u0D53\u0D58-\u0D5E\u0D64\u0D65\u0D70-\u0D79\u0D80\u0D84\u0D97-\u0D99\u0DB2\u0DBC\u0DBE\u0DBF\u0DC7-\u0DC9\u0DCB-\u0DCE\u0DD5\u0DD7\u0DE0-\u0DE5\u0DF0\u0DF1\u0DF4-\u0E00\u0E3B-\u0E3F\u0E4F\u0E5A-\u0E80\u0E83\u0E85\u0E8B\u0EA4\u0EA6\u0EBE\u0EBF\u0EC5\u0EC7\u0ECE\u0ECF\u0EDA\u0EDB\u0EE0-\u0EFF\u0F01-\u0F17\u0F1A-\u0F1F\u0F2A-\u0F34\u0F36\u0F38\u0F3A-\u0F3D\u0F48\u0F6D-\u0F70\u0F85\u0F98\u0FBD-\u0FC5\u0FC7-\u0FFF\u104A-\u104F\u109E\u109F\u10C6\u10C8-\u10CC\u10CE\u10CF\u10FB\u1249\u124E\u124F\u1257\u1259\u125E\u125F\u1289\u128E\u128F\u12B1\u12B6\u12B7\u12BF\u12C1\u12C6\u12C7\u12D7\u1311\u1316\u1317\u135B\u135C\u1360-\u137F\u1390-\u139F\u13F6\u13F7\u13FE-\u1400\u166D\u166E\u1680\u169B-\u169F\u16EB-\u16ED\u16F9-\u16FF\u170D\u1715-\u171F\u1735-\u173F\u1754-\u175F\u176D\u1771\u1774-\u177F\u17D4-\u17D6\u17D8-\u17DB\u17DE\u17DF\u17EA-\u180A\u180E\u180F\u181A-\u181F\u1879-\u187F\u18AB-\u18AF\u18F6-\u18FF\u191F\u192C-\u192F\u193C-\u1945\u196E\u196F\u1975-\u197F\u19AC-\u19AF\u19CA-\u19CF\u19DA-\u19FF\u1A1C-\u1A1F\u1A5F\u1A7D\u1A7E\u1A8A-\u1A8F\u1A9A-\u1AA6\u1AA8-\u1AAF\u1AC1-\u1AFF\u1B4C-\u1B4F\u1B5A-\u1B6A\u1B74-\u1B7F\u1BF4-\u1BFF\u1C38-\u1C3F\u1C4A-\u1C4C\u1C7E\u1C7F\u1C89-\u1C8F\u1CBB\u1CBC\u1CC0-\u1CCF\u1CD3\u1CFB-\u1CFF\u1DFA\u1F16\u1F17\u1F1E\u1F1F\u1F46\u1F47\u1F4E\u1F4F\u1F58\u1F5A\u1F5C\u1F5E\u1F7E\u1F7F\u1FB5\u1FBD\u1FBF-\u1FC1\u1FC5\u1FCD-\u1FCF\u1FD4\u1FD5\u1FDC-\u1FDF\u1FED-\u1FF1\u1FF5\u1FFD-\u203E\u2041-\u2053\u2055-\u2070\u2072-\u207E\u2080-\u208F\u209D-\u20CF\u20F1-\u2101\u2103-\u2106\u2108\u2109\u2114\u2116-\u2118\u211E-\u2123\u2125\u2127\u2129\u212E\u213A\u213B\u2140-\u2144\u214A-\u214D\u214F-\u215F\u2189-\u24B5\u24EA-\u2BFF\u2C2F\u2C5F\u2CE5-\u2CEA\u2CF4-\u2CFF\u2D26\u2D28-\u2D2C\u2D2E\u2D2F\u2D68-\u2D6E\u2D70-\u2D7E\u2D97-\u2D9F\u2DA7\u2DAF\u2DB7\u2DBF\u2DC7\u2DCF\u2DD7\u2DDF\u2E00-\u2E2E\u2E30-\u3004\u3008-\u3020\u3030\u3036\u3037\u303D-\u3040\u3097\u3098\u309B\u309C\u30A0\u30FB\u3100-\u3104\u3130\u318F-\u319F\u31C0-\u31EF\u3200-\u33FF\u4DC0-\u4DFF\u9FFD-\u9FFF\uA48D-\uA4CF\uA4FE\uA4FF\uA60D-\uA60F\uA62C-\uA63F\uA673\uA67E\uA6F2-\uA716\uA720\uA721\uA789\uA78A\uA7C0\uA7C1\uA7CB-\uA7F4\uA828-\uA82B\uA82D-\uA83F\uA874-\uA87F\uA8C6-\uA8CF\uA8DA-\uA8DF\uA8F8-\uA8FA\uA8FC\uA92E\uA92F\uA954-\uA95F\uA97D-\uA97F\uA9C1-\uA9CE\uA9DA-\uA9DF\uA9FF\uAA37-\uAA3F\uAA4E\uAA4F\uAA5A-\uAA5F\uAA77-\uAA79\uAAC3-\uAADA\uAADE\uAADF\uAAF0\uAAF1\uAAF7-\uAB00\uAB07\uAB08\uAB0F\uAB10\uAB17-\uAB1F\uAB27\uAB2F\uAB5B\uAB6A-\uAB6F\uABEB\uABEE\uABEF\uABFA-\uABFF\uD7A4-\uD7AF\uD7C7-\uD7CA\uD7FC-\uD7FF\uE000-\uF8FF\uFA6E\uFA6F\uFADA-\uFAFF\uFB07-\uFB12\uFB18-\uFB1C\uFB29\uFB37\uFB3D\uFB3F\uFB42\uFB45\uFBB2-\uFBD2\uFD3E-\uFD4F\uFD90\uFD91\uFDC8-\uFDEF\uFDFC-\uFDFF\uFE10-\uFE1F\uFE30-\uFE32\uFE35-\uFE4C\uFE50-\uFE6F\uFE75\uFEFD-\uFF0F\uFF1A-\uFF20\uFF3B-\uFF3E\uFF40\uFF5B-\uFF65\uFFBF-\uFFC1\uFFC8\uFFC9\uFFD0\uFFD1\uFFD8\uFFD9\uFFDD-\uFFFF]|\uD800[\uDC0C\uDC27\uDC3B\uDC3E\uDC4E\uDC4F\uDC5E-\uDC7F\uDCFB-\uDD3F\uDD75-\uDDFC\uDDFE-\uDE7F\uDE9D-\uDE9F\uDED1-\uDEDF\uDEE1-\uDEFF\uDF20-\uDF2C\uDF4B-\uDF4F\uDF7B-\uDF7F\uDF9E\uDF9F\uDFC4-\uDFC7\uDFD0\uDFD6-\uDFFF]|\uD801[\uDC9E\uDC9F\uDCAA-\uDCAF\uDCD4-\uDCD7\uDCFC-\uDCFF\uDD28-\uDD2F\uDD64-\uDDFF\uDF37-\uDF3F\uDF56-\uDF5F\uDF68-\uDFFF]|\uD802[\uDC06\uDC07\uDC09\uDC36\uDC39-\uDC3B\uDC3D\uDC3E\uDC56-\uDC5F\uDC77-\uDC7F\uDC9F-\uDCDF\uDCF3\uDCF6-\uDCFF\uDD16-\uDD1F\uDD3A-\uDD7F\uDDB8-\uDDBD\uDDC0-\uDDFF\uDE04\uDE07-\uDE0B\uDE14\uDE18\uDE36\uDE37\uDE3B-\uDE3E\uDE40-\uDE5F\uDE7D-\uDE7F\uDE9D-\uDEBF\uDEC8\uDEE7-\uDEFF\uDF36-\uDF3F\uDF56-\uDF5F\uDF73-\uDF7F\uDF92-\uDFFF]|\uD803[\uDC49-\uDC7F\uDCB3-\uDCBF\uDCF3-\uDCFF\uDD28-\uDD2F\uDD3A-\uDE7F\uDEAA\uDEAD-\uDEAF\uDEB2-\uDEFF\uDF1D-\uDF26\uDF28-\uDF2F\uDF51-\uDFAF\uDFC5-\uDFDF\uDFF7-\uDFFF]|\uD804[\uDC47-\uDC65\uDC70-\uDC7E\uDCBB-\uDCCF\uDCE9-\uDCEF\uDCFA-\uDCFF\uDD35\uDD40-\uDD43\uDD48-\uDD4F\uDD74\uDD75\uDD77-\uDD7F\uDDC5-\uDDC8\uDDCD\uDDDB\uDDDD-\uDDFF\uDE12\uDE38-\uDE3D\uDE3F-\uDE7F\uDE87\uDE89\uDE8E\uDE9E\uDEA9-\uDEAF\uDEEB-\uDEEF\uDEFA-\uDEFF\uDF04\uDF0D\uDF0E\uDF11\uDF12\uDF29\uDF31\uDF34\uDF3A\uDF45\uDF46\uDF49\uDF4A\uDF4E\uDF4F\uDF51-\uDF56\uDF58-\uDF5C\uDF64\uDF65\uDF6D-\uDF6F\uDF75-\uDFFF]|\uD805[\uDC4B-\uDC4F\uDC5A-\uDC5D\uDC62-\uDC7F\uDCC6\uDCC8-\uDCCF\uDCDA-\uDD7F\uDDB6\uDDB7\uDDC1-\uDDD7\uDDDE-\uDDFF\uDE41-\uDE43\uDE45-\uDE4F\uDE5A-\uDE7F\uDEB9-\uDEBF\uDECA-\uDEFF\uDF1B\uDF1C\uDF2C-\uDF2F\uDF3A-\uDFFF]|\uD806[\uDC3B-\uDC9F\uDCEA-\uDCFE\uDD07\uDD08\uDD0A\uDD0B\uDD14\uDD17\uDD36\uDD39\uDD3A\uDD44-\uDD4F\uDD5A-\uDD9F\uDDA8\uDDA9\uDDD8\uDDD9\uDDE2\uDDE5-\uDDFF\uDE3F-\uDE46\uDE48-\uDE4F\uDE9A-\uDE9C\uDE9E-\uDEBF\uDEF9-\uDFFF]|\uD807[\uDC09\uDC37\uDC41-\uDC4F\uDC5A-\uDC71\uDC90\uDC91\uDCA8\uDCB7-\uDCFF\uDD07\uDD0A\uDD37-\uDD39\uDD3B\uDD3E\uDD48-\uDD4F\uDD5A-\uDD5F\uDD66\uDD69\uDD8F\uDD92\uDD99-\uDD9F\uDDAA-\uDEDF\uDEF7-\uDFAF\uDFB1-\uDFFF]|\uD808[\uDF9A-\uDFFF]|\uD809[\uDC6F-\uDC7F\uDD44-\uDFFF]|[\uD80A\uD80B\uD80E-\uD810\uD812-\uD819\uD824-\uD82B\uD82D\uD82E\uD830-\uD833\uD837\uD839\uD83D\uD83F\uD87B-\uD87D\uD87F\uD885-\uDB3F\uDB41-\uDBFF][\uDC00-\uDFFF]|\uD80D[\uDC2F-\uDFFF]|\uD811[\uDE47-\uDFFF]|\uD81A[\uDE39-\uDE3F\uDE5F\uDE6A-\uDECF\uDEEE\uDEEF\uDEF5-\uDEFF\uDF37-\uDF3F\uDF44-\uDF4F\uDF5A-\uDF62\uDF78-\uDF7C\uDF90-\uDFFF]|\uD81B[\uDC00-\uDE3F\uDE80-\uDEFF\uDF4B-\uDF4E\uDF88-\uDF8E\uDFA0-\uDFDF\uDFE2\uDFE5-\uDFEF\uDFF2-\uDFFF]|\uD821[\uDFF8-\uDFFF]|\uD823[\uDCD6-\uDCFF\uDD09-\uDFFF]|\uD82C[\uDD1F-\uDD4F\uDD53-\uDD63\uDD68-\uDD6F\uDEFC-\uDFFF]|\uD82F[\uDC6B-\uDC6F\uDC7D-\uDC7F\uDC89-\uDC8F\uDC9A-\uDC9C\uDC9F-\uDFFF]|\uD834[\uDC00-\uDD64\uDD6A-\uDD6C\uDD73-\uDD7A\uDD83\uDD84\uDD8C-\uDDA9\uDDAE-\uDE41\uDE45-\uDFFF]|\uD835[\uDC55\uDC9D\uDCA0\uDCA1\uDCA3\uDCA4\uDCA7\uDCA8\uDCAD\uDCBA\uDCBC\uDCC4\uDD06\uDD0B\uDD0C\uDD15\uDD1D\uDD3A\uDD3F\uDD45\uDD47-\uDD49\uDD51\uDEA6\uDEA7\uDEC1\uDEDB\uDEFB\uDF15\uDF35\uDF4F\uDF6F\uDF89\uDFA9\uDFC3\uDFCC\uDFCD]|\uD836[\uDC00-\uDDFF\uDE37-\uDE3A\uDE6D-\uDE74\uDE76-\uDE83\uDE85-\uDE9A\uDEA0\uDEB0-\uDFFF]|\uD838[\uDC07\uDC19\uDC1A\uDC22\uDC25\uDC2B-\uDCFF\uDD2D-\uDD2F\uDD3E\uDD3F\uDD4A-\uDD4D\uDD4F-\uDEBF\uDEFA-\uDFFF]|\uD83A[\uDCC5-\uDCCF\uDCD7-\uDCFF\uDD4C-\uDD4F\uDD5A-\uDFFF]|\uD83B[\uDC00-\uDDFF\uDE04\uDE20\uDE23\uDE25\uDE26\uDE28\uDE33\uDE38\uDE3A\uDE3C-\uDE41\uDE43-\uDE46\uDE48\uDE4A\uDE4C\uDE50\uDE53\uDE55\uDE56\uDE58\uDE5A\uDE5C\uDE5E\uDE60\uDE63\uDE65\uDE66\uDE6B\uDE73\uDE78\uDE7D\uDE7F\uDE8A\uDE9C-\uDEA0\uDEA4\uDEAA\uDEBC-\uDFFF]|\uD83C[\uDC00-\uDD2F\uDD4A-\uDD4F\uDD6A-\uDD6F\uDD8A-\uDFFF]|\uD83E[\uDC00-\uDFEF\uDFFA-\uDFFF]|\uD869[\uDEDE-\uDEFF]|\uD86D[\uDF35-\uDF3F]|\uD86E[\uDC1E\uDC1F]|\uD873[\uDEA2-\uDEAF]|\uD87A[\uDFE1-\uDFFF]|\uD87E[\uDE1E-\uDFFF]|\uD884[\uDF4B-\uDFFF]|\uDB40[\uDC00-\uDCFF\uDDF0-\uDFFF]/g; function slugify(heading: string): string { diff --git a/src/vs/workbench/contrib/notebook/browser/media/notebook.css b/src/vs/workbench/contrib/notebook/browser/media/notebook.css index 250ceaf80ef0c..345210b836144 100644 --- a/src/vs/workbench/contrib/notebook/browser/media/notebook.css +++ b/src/vs/workbench/contrib/notebook/browser/media/notebook.css @@ -646,3 +646,9 @@ .monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.markdown-cell-row.nb-chatGenerationHighlight { background-color: var(--vscode-notebook-selectedCellBackground) !important; } + +/** Avoid Zone Widget hide cell editor focus indicator partially **/ +.monaco-workbench .notebookOverlay .cell-list-container .monaco-editor .zone-widget { + margin-left: 1px; + margin-right: 1px; +} diff --git a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts index d8719d3ff1932..3c6e11132b310 100644 --- a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts +++ b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts @@ -2,6 +2,7 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +/* eslint-disable local/code-no-dangerous-type-assertions */ import './media/keybindingsEditor.css'; import { localize } from '../../../../nls.js'; diff --git a/src/vs/workbench/contrib/terminal/.eslintrc.json b/src/vs/workbench/contrib/terminal/.eslintrc.json deleted file mode 100644 index 46c627702dfa3..0000000000000 --- a/src/vs/workbench/contrib/terminal/.eslintrc.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "rules": { - "@typescript-eslint/naming-convention": [ - "warn", - // variableLike - { "selector": "variable", "format": ["camelCase", "UPPER_CASE", "PascalCase"] }, - { "selector": "variable", "filter": "^I.+Service$", "format": ["PascalCase"], "prefix": ["I"] }, - // memberLike - { "selector": "memberLike", "modifiers": ["private"], "format": ["camelCase"], "leadingUnderscore": "require" }, - { "selector": "memberLike", "modifiers": ["protected"], "format": ["camelCase"], "leadingUnderscore": "require" }, - { "selector": "enumMember", "format": ["PascalCase"] }, - // memberLike - Allow enum-like objects to use UPPER_CASE - { "selector": "method", "modifiers": ["public"], "format": ["camelCase", "UPPER_CASE"] }, - // typeLike - { "selector": "typeLike", "format": ["PascalCase"] }, - { "selector": "interface", "format": ["PascalCase"] } - ], - "comma-dangle": ["warn", "only-multiline"] - } -} diff --git a/src/vs/workbench/contrib/terminal/browser/terminalExtensions.ts b/src/vs/workbench/contrib/terminal/browser/terminalExtensions.ts index 80dc9f7c9b9fd..d37dcbd684db0 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalExtensions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalExtensions.ts @@ -42,6 +42,7 @@ export type ITerminalContributionDescription = { readonly id: string } & ( export function registerTerminalContribution(id: string, ctor: { new(ctx: ITerminalContributionContext, ...services: Services): ITerminalContribution }, canRunInDetachedTerminals?: false): void; export function registerTerminalContribution(id: string, ctor: { new(ctx: IDetachedCompatibleTerminalContributionContext, ...services: Services): ITerminalContribution }, canRunInDetachedTerminals: true): void; export function registerTerminalContribution(id: string, ctor: { new(ctx: any, ...services: Services): ITerminalContribution }, canRunInDetachedTerminals: boolean = false): void { + // eslint-disable-next-line local/code-no-dangerous-type-assertions TerminalContributionRegistry.INSTANCE.registerTerminalContribution({ id, ctor, canRunInDetachedTerminals } as ITerminalContributionDescription); } diff --git a/src/vs/workbench/contrib/terminalContrib/.eslintrc.json b/src/vs/workbench/contrib/terminalContrib/.eslintrc.json deleted file mode 100644 index 46c627702dfa3..0000000000000 --- a/src/vs/workbench/contrib/terminalContrib/.eslintrc.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "rules": { - "@typescript-eslint/naming-convention": [ - "warn", - // variableLike - { "selector": "variable", "format": ["camelCase", "UPPER_CASE", "PascalCase"] }, - { "selector": "variable", "filter": "^I.+Service$", "format": ["PascalCase"], "prefix": ["I"] }, - // memberLike - { "selector": "memberLike", "modifiers": ["private"], "format": ["camelCase"], "leadingUnderscore": "require" }, - { "selector": "memberLike", "modifiers": ["protected"], "format": ["camelCase"], "leadingUnderscore": "require" }, - { "selector": "enumMember", "format": ["PascalCase"] }, - // memberLike - Allow enum-like objects to use UPPER_CASE - { "selector": "method", "modifiers": ["public"], "format": ["camelCase", "UPPER_CASE"] }, - // typeLike - { "selector": "typeLike", "format": ["PascalCase"] }, - { "selector": "interface", "format": ["PascalCase"] } - ], - "comma-dangle": ["warn", "only-multiline"] - } -} diff --git a/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatController.ts b/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatController.ts index 4af266b4bb625..1c8a5228db606 100644 --- a/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatController.ts +++ b/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatController.ts @@ -251,7 +251,7 @@ export class TerminalChatController extends Disposable implements ITerminalContr })); } await responsePromise.p; - this._lastResponseContent = response?.response.toMarkdown(); + this._lastResponseContent = response?.response.getMarkdown(); return response; } catch { this._lastResponseContent = undefined; diff --git a/src/vs/workbench/electron-sandbox/desktop.contribution.ts b/src/vs/workbench/electron-sandbox/desktop.contribution.ts index 72527bf9ba539..b63874842dd2f 100644 --- a/src/vs/workbench/electron-sandbox/desktop.contribution.ts +++ b/src/vs/workbench/electron-sandbox/desktop.contribution.ts @@ -239,7 +239,8 @@ import { MAX_ZOOM_LEVEL, MIN_ZOOM_LEVEL } from '../../platform/window/electron-s 'type': 'boolean', 'included': isLinux, 'markdownDescription': localize('window.experimentalControlOverlay', "Show the native window controls when {0} is set to `custom` (Linux only).", '`#window.titleBarStyle#`'), - 'default': true + 'default': true, + 'scope': ConfigurationScope.APPLICATION, }, 'window.customTitleBarVisibility': { 'type': 'string', diff --git a/src/vs/workbench/services/authentication/browser/authenticationExtensionsService.ts b/src/vs/workbench/services/authentication/browser/authenticationExtensionsService.ts index df7c921e67a0b..12a87e9b79d46 100644 --- a/src/vs/workbench/services/authentication/browser/authenticationExtensionsService.ts +++ b/src/vs/workbench/services/authentication/browser/authenticationExtensionsService.ts @@ -372,7 +372,7 @@ export class AuthenticationExtensionsService extends Disposable implements IAuth } if (session) { - this._authenticationUsageService.addAccountUsage(provider.id, session.account.label, extensionId, extensionName); + this._authenticationUsageService.addAccountUsage(provider.id, session.account.label, session.scopes, extensionId, extensionName); } } diff --git a/src/vs/workbench/services/authentication/browser/authenticationUsageService.ts b/src/vs/workbench/services/authentication/browser/authenticationUsageService.ts index a261d57ac38e1..514e1ce72da75 100644 --- a/src/vs/workbench/services/authentication/browser/authenticationUsageService.ts +++ b/src/vs/workbench/services/authentication/browser/authenticationUsageService.ts @@ -16,6 +16,7 @@ export interface IAccountUsage { extensionId: string; extensionName: string; lastUsed: number; + scopes?: string[]; } export const IAuthenticationUsageService = createDecorator('IAuthenticationUsageService'); @@ -49,7 +50,7 @@ export interface IAuthenticationUsageService { * @param extensionId The id of the extension to add a usage for * @param extensionName The name of the extension to add a usage for */ - addAccountUsage(providerId: string, accountName: string, extensionId: string, extensionName: string): void; + addAccountUsage(providerId: string, accountName: string, scopes: ReadonlyArray, extensionId: string, extensionName: string): void; } export class AuthenticationUsageService extends Disposable implements IAuthenticationUsageService { @@ -116,7 +117,7 @@ export class AuthenticationUsageService extends Disposable implements IAuthentic this._storageService.remove(accountKey, StorageScope.APPLICATION); } - addAccountUsage(providerId: string, accountName: string, extensionId: string, extensionName: string): void { + addAccountUsage(providerId: string, accountName: string, scopes: string[], extensionId: string, extensionName: string): void { const accountKey = `${providerId}-${accountName}-usages`; const usages = this.readAccountUsages(providerId, accountName); @@ -125,12 +126,14 @@ export class AuthenticationUsageService extends Disposable implements IAuthentic usages.splice(existingUsageIndex, 1, { extensionId, extensionName, + scopes, lastUsed: Date.now() }); } else { usages.push({ extensionId, extensionName, + scopes, lastUsed: Date.now() }); } diff --git a/src/vs/workbench/services/files/electron-sandbox/elevatedFileService.ts b/src/vs/workbench/services/files/electron-sandbox/elevatedFileService.ts index 09f67aba17c9f..158a5ac0f4c6a 100644 --- a/src/vs/workbench/services/files/electron-sandbox/elevatedFileService.ts +++ b/src/vs/workbench/services/files/electron-sandbox/elevatedFileService.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { localize } from '../../../../nls.js'; import { VSBuffer, VSBufferReadable, VSBufferReadableStream } from '../../../../base/common/buffer.js'; import { randomPath } from '../../../../base/common/extpath.js'; import { Schemas } from '../../../../base/common/network.js'; @@ -10,9 +11,11 @@ import { URI } from '../../../../base/common/uri.js'; import { IFileService, IFileStatWithMetadata, IWriteFileOptions } from '../../../../platform/files/common/files.js'; import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js'; import { INativeHostService } from '../../../../platform/native/common/native.js'; +import { IWorkspaceTrustRequestService } from '../../../../platform/workspace/common/workspaceTrust.js'; import { INativeWorkbenchEnvironmentService } from '../../environment/electron-sandbox/environmentService.js'; import { IElevatedFileService } from '../common/elevatedFileService.js'; - +import { isWindows } from '../../../../base/common/platform.js'; +import { ILabelService } from '../../../../platform/label/common/label.js'; export class NativeElevatedFileService implements IElevatedFileService { readonly _serviceBrand: undefined; @@ -20,7 +23,9 @@ export class NativeElevatedFileService implements IElevatedFileService { constructor( @INativeHostService private readonly nativeHostService: INativeHostService, @IFileService private readonly fileService: IFileService, - @INativeWorkbenchEnvironmentService private readonly environmentService: INativeWorkbenchEnvironmentService + @INativeWorkbenchEnvironmentService private readonly environmentService: INativeWorkbenchEnvironmentService, + @IWorkspaceTrustRequestService private readonly workspaceTrustRequestService: IWorkspaceTrustRequestService, + @ILabelService private readonly labelService: ILabelService ) { } isSupported(resource: URI): boolean { @@ -32,6 +37,13 @@ export class NativeElevatedFileService implements IElevatedFileService { } async writeFileElevated(resource: URI, value: VSBuffer | VSBufferReadable | VSBufferReadableStream, options?: IWriteFileOptions): Promise { + const trusted = await this.workspaceTrustRequestService.requestWorkspaceTrust({ + message: isWindows ? localize('fileNotTrustedMessageWindows', "You are about to save '{0}' as admin.", this.labelService.getUriLabel(resource)) : localize('fileNotTrustedMessagePosix', "You are about to save '{0}' as super user.", this.labelService.getUriLabel(resource)), + }); + if (!trusted) { + throw new Error(localize('fileNotTrusted', "Workspace is not trusted.")); + } + const source = URI.file(randomPath(this.environmentService.userDataPath, 'code-elevated')); try { // write into a tmp file first diff --git a/src/vs/workbench/services/keybinding/browser/keybindingService.ts b/src/vs/workbench/services/keybinding/browser/keybindingService.ts index 671f9552963ca..bb41a6d570598 100644 --- a/src/vs/workbench/services/keybinding/browser/keybindingService.ts +++ b/src/vs/workbench/services/keybinding/browser/keybindingService.ts @@ -955,7 +955,7 @@ class KeybindingsJsonSchema { for (const [commandId, command] of allCommands) { const commandMetadata = command.metadata; - addKnownCommand(commandId, commandMetadata?.description); + addKnownCommand(commandId, commandMetadata?.description ?? MenuRegistry.getCommand(commandId)?.title); if (!commandMetadata || !commandMetadata.args || commandMetadata.args.length !== 1 || !commandMetadata.args[0].schema) { continue; diff --git a/src/vs/workbench/services/preferences/browser/keybindingsEditorModel.ts b/src/vs/workbench/services/preferences/browser/keybindingsEditorModel.ts index 6f20836a58476..ef7326a0b281b 100644 --- a/src/vs/workbench/services/preferences/browser/keybindingsEditorModel.ts +++ b/src/vs/workbench/services/preferences/browser/keybindingsEditorModel.ts @@ -273,6 +273,7 @@ export class KeybindingsEditorModel extends EditorModel { const extensionId = keybindingItem.extensionId ?? (keybindingItem.resolvedKeybinding ? undefined : menuCommand?.source?.id); source = extensionId ? extensions.get(extensionId) ?? SOURCE_EXTENSION : SOURCE_SYSTEM; } + // eslint-disable-next-line local/code-no-dangerous-type-assertions return { keybinding: keybindingItem.resolvedKeybinding, keybindingItem, diff --git a/src/vs/workbench/services/search/common/search.ts b/src/vs/workbench/services/search/common/search.ts index 04a26c0a549f7..07edf2a24a569 100644 --- a/src/vs/workbench/services/search/common/search.ts +++ b/src/vs/workbench/services/search/common/search.ts @@ -49,6 +49,7 @@ export interface ISearchService { getAIName(): Promise; textSearchSplitSyncAsync(query: ITextQuery, token?: CancellationToken | undefined, onProgress?: ((result: ISearchProgressItem) => void) | undefined, notebookFilesToIgnore?: ResourceSet, asyncNotebookFilesToIgnore?: Promise): { syncResults: ISearchComplete; asyncResults: Promise }; fileSearch(query: IFileQuery, token?: CancellationToken): Promise; + schemeHasFileSearchProvider(scheme: string): boolean; clearCache(cacheKey: string): Promise; registerSearchResultProvider(scheme: string, type: SearchProviderType, provider: ISearchResultProvider): IDisposable; } diff --git a/src/vs/workbench/services/search/common/searchService.ts b/src/vs/workbench/services/search/common/searchService.ts index 6873277ee73f4..b5ae676f41e60 100644 --- a/src/vs/workbench/services/search/common/searchService.ts +++ b/src/vs/workbench/services/search/common/searchService.ts @@ -165,6 +165,10 @@ export class SearchService extends Disposable implements ISearchService { return this.doSearch(query, token); } + schemeHasFileSearchProvider(scheme: string): boolean { + return this.fileSearchProviders.has(scheme); + } + private doSearch(query: ISearchQuery, token?: CancellationToken, onProgress?: (item: ISearchProgressItem) => void): Promise { this.logService.trace('SearchService#search', JSON.stringify(query)); diff --git a/src/vs/workbench/services/storage/test/browser/storageService.test.ts b/src/vs/workbench/services/storage/test/browser/storageService.test.ts index f9fae4931680c..aa076784de97b 100644 --- a/src/vs/workbench/services/storage/test/browser/storageService.test.ts +++ b/src/vs/workbench/services/storage/test/browser/storageService.test.ts @@ -36,7 +36,6 @@ async function createStorageService(): Promise<[DisposableStore, BrowserStorageS const inMemoryExtraProfile: IUserDataProfile = { id: 'id', name: 'inMemory', - shortName: 'inMemory', isDefault: false, location: inMemoryExtraProfileRoot, globalStorageHome: joinPath(inMemoryExtraProfileRoot, 'globalStorageHome'), diff --git a/src/vs/workbench/services/textfile/common/textFileSaveParticipant.ts b/src/vs/workbench/services/textfile/common/textFileSaveParticipant.ts index ce80ac6c5ced6..80f5d3a27cbd4 100644 --- a/src/vs/workbench/services/textfile/common/textFileSaveParticipant.ts +++ b/src/vs/workbench/services/textfile/common/textFileSaveParticipant.ts @@ -32,23 +32,23 @@ export class TextFileSaveParticipant extends Disposable { } async participate(model: ITextFileEditorModel, context: ITextFileSaveParticipantContext, progress: IProgress, token: CancellationToken): Promise { + const cts = new CancellationTokenSource(token); // undoStop before participation model.textEditorModel?.pushStackElement(); - const cts = new CancellationTokenSource(token); - + // report to the "outer" progress progress.report({ message: localize('saveParticipants1', "Running Code Actions and Formatters...") }); + // create an "inner" progress to allow to skip over long running save participants await this.progressService.withProgress({ priority: NotificationPriority.URGENT, location: ProgressLocation.Notification, cancellable: localize('skip', "Skip"), delay: model.isDirty() ? 5000 : 3000 }, async progress => { - for (const saveParticipant of this.saveParticipants) { if (cts.token.isCancellationRequested || !model.textEditorModel /* disposed */) { break; diff --git a/src/vs/workbench/services/userDataProfile/browser/userDataProfileImportExportService.ts b/src/vs/workbench/services/userDataProfile/browser/userDataProfileImportExportService.ts index 183112673fd72..7a0b652b68907 100644 --- a/src/vs/workbench/services/userDataProfile/browser/userDataProfileImportExportService.ts +++ b/src/vs/workbench/services/userDataProfile/browser/userDataProfileImportExportService.ts @@ -743,7 +743,6 @@ class UserDataProfileExportState extends UserDataProfileImportExportState { name: profile.name, location: profile.location, isDefault: profile.isDefault, - shortName: profile.shortName, icon: profile.icon, globalStorageHome: profile.globalStorageHome, settingsResource: profile.settingsResource.with({ scheme: USER_DATA_PROFILE_EXPORT_SCHEME }), diff --git a/src/vs/workbench/services/userDataProfile/common/remoteUserDataProfiles.ts b/src/vs/workbench/services/userDataProfile/common/remoteUserDataProfiles.ts index 65ca63829ecb5..1281d1f717b3d 100644 --- a/src/vs/workbench/services/userDataProfile/common/remoteUserDataProfiles.ts +++ b/src/vs/workbench/services/userDataProfile/common/remoteUserDataProfiles.ts @@ -106,7 +106,6 @@ class RemoteUserDataProfilesService extends Disposable implements IRemoteUserDat let profile = remoteUserDataProfilesService.profiles.find(p => p.id === localProfile.id); if (!profile) { profile = await remoteUserDataProfilesService.createProfile(localProfile.id, localProfile.name, { - shortName: localProfile.shortName, transient: localProfile.isTransient, useDefaultFlags: localProfile.useDefaultFlags, }); @@ -161,8 +160,8 @@ class RemoteUserDataProfilesService extends Disposable implements IRemoteUserDat } const localProfile = this.userDataProfilesService.profiles.find(p => p.id === profileId); if (localProfile) { - if (localProfile.name !== remoteProfile.name || localProfile.shortName !== remoteProfile.shortName) { - await this.remoteUserDataProfilesService?.updateProfile(remoteProfile, { name: localProfile.name, shortName: localProfile.shortName }); + if (localProfile.name !== remoteProfile.name) { + await this.remoteUserDataProfilesService?.updateProfile(remoteProfile, { name: localProfile.name }); } associatedRemoteProfiles.push(profileId); continue; diff --git a/src/vs/workbench/services/userDataProfile/common/userDataProfile.ts b/src/vs/workbench/services/userDataProfile/common/userDataProfile.ts index 47035fabb6ecd..d11d4ab371e84 100644 --- a/src/vs/workbench/services/userDataProfile/common/userDataProfile.ts +++ b/src/vs/workbench/services/userDataProfile/common/userDataProfile.ts @@ -29,7 +29,6 @@ export interface IUserDataProfileService { readonly currentProfile: IUserDataProfile; readonly onDidChangeCurrentProfile: Event; updateCurrentProfile(currentProfile: IUserDataProfile): Promise; - getShortName(profile: IUserDataProfile): string; } export interface IProfileTemplateInfo { diff --git a/src/vs/workbench/services/userDataProfile/common/userDataProfileService.ts b/src/vs/workbench/services/userDataProfile/common/userDataProfileService.ts index 3010d122d2785..0f80b7c0a676b 100644 --- a/src/vs/workbench/services/userDataProfile/common/userDataProfileService.ts +++ b/src/vs/workbench/services/userDataProfile/common/userDataProfileService.ts @@ -7,9 +7,8 @@ import { Promises } from '../../../../base/common/async.js'; import { Emitter } from '../../../../base/common/event.js'; import { Disposable } from '../../../../base/common/lifecycle.js'; import { equals } from '../../../../base/common/objects.js'; -import { ThemeIcon } from '../../../../base/common/themables.js'; import { IUserDataProfile } from '../../../../platform/userDataProfile/common/userDataProfile.js'; -import { defaultUserDataProfileIcon, DidChangeUserDataProfileEvent, IUserDataProfileService } from './userDataProfile.js'; +import { DidChangeUserDataProfileEvent, IUserDataProfileService } from './userDataProfile.js'; export class UserDataProfileService extends Disposable implements IUserDataProfileService { @@ -44,12 +43,4 @@ export class UserDataProfileService extends Disposable implements IUserDataProfi }); await Promises.settled(joiners); } - - getShortName(profile: IUserDataProfile): string { - if (!profile.isDefault && profile.shortName && ThemeIcon.fromId(profile.shortName)) { - return profile.shortName; - } - return `$(${defaultUserDataProfileIcon.id})`; - } - } diff --git a/src/vs/workbench/services/workingCopy/common/storedFileWorkingCopySaveParticipant.ts b/src/vs/workbench/services/workingCopy/common/storedFileWorkingCopySaveParticipant.ts index 07e73acc3286f..77990e3b3118c 100644 --- a/src/vs/workbench/services/workingCopy/common/storedFileWorkingCopySaveParticipant.ts +++ b/src/vs/workbench/services/workingCopy/common/storedFileWorkingCopySaveParticipant.ts @@ -4,56 +4,80 @@ *--------------------------------------------------------------------------------------------*/ import { raceCancellation } from '../../../../base/common/async.js'; -import { CancellationToken } from '../../../../base/common/cancellation.js'; +import { CancellationToken, CancellationTokenSource } from '../../../../base/common/cancellation.js'; import { ILogService } from '../../../../platform/log/common/log.js'; -import { IProgress, IProgressStep } from '../../../../platform/progress/common/progress.js'; +import { IProgress, IProgressService, IProgressStep, ProgressLocation } from '../../../../platform/progress/common/progress.js'; import { IDisposable, Disposable, toDisposable } from '../../../../base/common/lifecycle.js'; -import { insert } from '../../../../base/common/arrays.js'; import { IStoredFileWorkingCopySaveParticipant, IStoredFileWorkingCopySaveParticipantContext } from './workingCopyFileService.js'; import { IStoredFileWorkingCopy, IStoredFileWorkingCopyModel } from './storedFileWorkingCopy.js'; +import { LinkedList } from '../../../../base/common/linkedList.js'; +import { isCancellationError } from '../../../../base/common/errors.js'; +import { NotificationPriority } from '../../../../platform/notification/common/notification.js'; +import { localize } from '../../../../nls.js'; export class StoredFileWorkingCopySaveParticipant extends Disposable { - private readonly saveParticipants: IStoredFileWorkingCopySaveParticipant[] = []; + private readonly saveParticipants = new LinkedList(); - get length(): number { return this.saveParticipants.length; } + get length(): number { return this.saveParticipants.size; } constructor( - @ILogService private readonly logService: ILogService + @ILogService private readonly logService: ILogService, + @IProgressService private readonly progressService: IProgressService, ) { super(); } addSaveParticipant(participant: IStoredFileWorkingCopySaveParticipant): IDisposable { - const remove = insert(this.saveParticipants, participant); + const remove = this.saveParticipants.push(participant); return toDisposable(() => remove()); } async participate(workingCopy: IStoredFileWorkingCopy, context: IStoredFileWorkingCopySaveParticipantContext, progress: IProgress, token: CancellationToken): Promise { + const cts = new CancellationTokenSource(token); // undoStop before participation workingCopy.model?.pushStackElement(); - for (const saveParticipant of this.saveParticipants) { - if (token.isCancellationRequested || workingCopy.isDisposed()) { - break; - } + // report to the "outer" progress + progress.report({ + message: localize('saveParticipants1', "Running Code Actions and Formatters...") + }); + + // create an "inner" progress to allow to skip over long running save participants + await this.progressService.withProgress({ + priority: NotificationPriority.URGENT, + location: ProgressLocation.Notification, + cancellable: localize('skip', "Skip"), + delay: workingCopy.isDirty() ? 5000 : 3000 + }, async progress => { + for (const saveParticipant of this.saveParticipants) { + if (cts.token.isCancellationRequested || workingCopy.isDisposed()) { + break; + } - try { - const promise = saveParticipant.participate(workingCopy, context, progress, token); - await raceCancellation(promise, token); - } catch (err) { - this.logService.warn(err); + try { + const promise = saveParticipant.participate(workingCopy, context, progress, cts.token); + await raceCancellation(promise, cts.token); + } catch (err) { + if (!isCancellationError(err)) { + this.logService.error(err); + } + } } - } + }, () => { + cts.cancel(); + }); // undoStop after participation workingCopy.model?.pushStackElement(); + + cts.dispose(); } override dispose(): void { - this.saveParticipants.splice(0, this.saveParticipants.length); + this.saveParticipants.clear(); super.dispose(); } diff --git a/src/vs/workbench/test/browser/workbenchTestServices.ts b/src/vs/workbench/test/browser/workbenchTestServices.ts index eb42c86a596f7..d5d65dcc3327a 100644 --- a/src/vs/workbench/test/browser/workbenchTestServices.ts +++ b/src/vs/workbench/test/browser/workbenchTestServices.ts @@ -2241,7 +2241,6 @@ export class TestUserDataProfileService implements IUserDataProfileService { readonly onDidChangeCurrentProfile = Event.None; readonly currentProfile = toUserDataProfile('test', 'test', URI.file('tests').with({ scheme: 'vscode-tests' }), URI.file('tests').with({ scheme: 'vscode-tests' })); async updateCurrentProfile(): Promise { } - getShortName(profile: IUserDataProfile): string { return profile.shortName ?? profile.name; } } export class TestWebExtensionsScannerService implements IWebExtensionsScannerService { diff --git a/src/vscode-dts/vscode.d.ts b/src/vscode-dts/vscode.d.ts index b00b7506cab7d..ec203e749da48 100644 --- a/src/vscode-dts/vscode.d.ts +++ b/src/vscode-dts/vscode.d.ts @@ -3655,6 +3655,7 @@ declare module 'vscode' { * * @param document The document in which the command was invoked. * @param position The position at which the command was invoked. + * @param context Additional information about the references request. * @param token A cancellation token. * * @returns An array of locations or a thenable that resolves to such. The lack of a result can be @@ -7505,7 +7506,7 @@ declare module 'vscode' { * must be activated. Check whether {@link TerminalShellExecution.exitCode} is rejected to * verify whether it was successful. * - * @param command A command to run. + * @param executable A command to run. * @param args Arguments to launch the executable with which will be automatically escaped * based on the executable type. * @@ -11693,8 +11694,8 @@ declare module 'vscode' { * * Extensions should fire {@link TreeDataProvider.onDidChangeTreeData onDidChangeTreeData} for any elements that need to be refreshed. * - * @param dataTransfer The data transfer items of the source of the drag. * @param target The target tree element that the drop is occurring on. When undefined, the target is the root. + * @param dataTransfer The data transfer items of the source of the drag. * @param token A cancellation token indicating that the drop has been cancelled. */ handleDrop?(target: T | undefined, dataTransfer: DataTransfer, token: CancellationToken): Thenable | void; @@ -17780,7 +17781,7 @@ declare module 'vscode' { * runs which may still be ongoing, will be marked as outdated and deprioritized * in the editor's UI. * - * @param item Item to mark as outdated. If undefined, all the controller's items are marked outdated. + * @param items Item to mark as outdated. If undefined, all the controller's items are marked outdated. */ invalidateTestResults(items?: TestItem | readonly TestItem[]): void; @@ -18966,7 +18967,9 @@ declare module 'vscode' { export interface ChatFollowupProvider { /** * Provide followups for the given result. + * * @param result This object has the same properties as the result returned from the participant callback, including `metadata`, but is not the same instance. + * @param context Extra context passed to a participant. * @param token A cancellation token. */ provideFollowups(result: ChatResult, context: ChatContext, token: CancellationToken): ProviderResult; diff --git a/src/vscode-dts/vscode.proposed.chatParticipantAdditions.d.ts b/src/vscode-dts/vscode.proposed.chatParticipantAdditions.d.ts index ac61fa015829d..de74f6e015d8e 100644 --- a/src/vscode-dts/vscode.proposed.chatParticipantAdditions.d.ts +++ b/src/vscode-dts/vscode.proposed.chatParticipantAdditions.d.ts @@ -353,13 +353,27 @@ declare module 'vscode' { } export interface ChatEditorAction { + // eslint-disable-next-line local/vscode-dts-string-type-literals kind: 'editor'; accepted: boolean; } + export interface ChatEditingSessionAction { + // eslint-disable-next-line local/vscode-dts-string-type-literals + kind: 'chatEditingSessionAction'; + uri: Uri; + hasRemainingEdits: boolean; + outcome: ChatEditingSessionActionOutcome; + } + + export enum ChatEditingSessionActionOutcome { + Accepted = 1, + Rejected = 2 + } + export interface ChatUserActionEvent { readonly result: ChatResult; - readonly action: ChatCopyAction | ChatInsertAction | ChatApplyAction | ChatTerminalAction | ChatCommandAction | ChatFollowupAction | ChatBugReportAction | ChatEditorAction; + readonly action: ChatCopyAction | ChatInsertAction | ChatApplyAction | ChatTerminalAction | ChatCommandAction | ChatFollowupAction | ChatBugReportAction | ChatEditorAction | ChatEditingSessionAction; } export interface ChatPromptReference { diff --git a/src/vscode-dts/vscode.proposed.contribChatParticipantDetection.d.ts b/src/vscode-dts/vscode.proposed.contribChatParticipantDetection.d.ts deleted file mode 100644 index 6de04ce23900b..0000000000000 --- a/src/vscode-dts/vscode.proposed.contribChatParticipantDetection.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -// empty placeholder declaration for the `chatParticipantDetection`-contribution point -// https://github.com/microsoft/vscode/issues/227699 diff --git a/src/vscode-dts/vscode.proposed.lmTools.d.ts b/src/vscode-dts/vscode.proposed.lmTools.d.ts index 5f12e3df2d258..86b39748dbf50 100644 --- a/src/vscode-dts/vscode.proposed.lmTools.d.ts +++ b/src/vscode-dts/vscode.proposed.lmTools.d.ts @@ -30,6 +30,7 @@ declare module 'vscode' { } // LM -> USER: function that should be used + // TODO@API NAME: LanguageModelChatMessageToolCallPart, LanguageModelToolCallPart export class LanguageModelChatResponseToolCallPart { name: string; toolCallId: string; @@ -39,6 +40,7 @@ declare module 'vscode' { } // LM -> USER: text chunk + // TODO@API NAME: LanguageModelChatMessageTextPart, LanguageModelTextPart export class LanguageModelChatResponseTextPart { value: string; @@ -51,6 +53,7 @@ declare module 'vscode' { // USER -> LM: the result of a function call + // TODO@API NAME: LanguageModelChatMessageToolResultPart, LanguageModelToolResultPart export class LanguageModelChatMessageToolResultPart { toolCallId: string; content: string; @@ -76,6 +79,7 @@ declare module 'vscode' { /** * A result returned from a tool invocation. */ + // TODO@API should we align this with NotebookCellOutput and NotebookCellOutputItem export interface LanguageModelToolResult { /** * The result can contain arbitrary representations of the content. A tool user can set @@ -94,7 +98,8 @@ declare module 'vscode' { export namespace lm { /** * Register a LanguageModelTool. The tool must also be registered in the package.json `languageModelTools` contribution - * point. A registered tool is available in the {@link lm.tools} list for any extension to invoke. + * point. A registered tool is available in the {@link lm.tools} list for any extension to see. But in order for it to + * be seen by a language model, it must be passed in the list of available tools in {@link LanguageModelChatRequestOptions.tools}. */ export function registerTool(id: string, tool: LanguageModelTool): Disposable; diff --git a/src/vscode-dts/vscode.proposed.mappedEditsProvider.d.ts b/src/vscode-dts/vscode.proposed.mappedEditsProvider.d.ts index 69061d64ffd1e..7cc3c7ff45a4e 100644 --- a/src/vscode-dts/vscode.proposed.mappedEditsProvider.d.ts +++ b/src/vscode-dts/vscode.proposed.mappedEditsProvider.d.ts @@ -12,11 +12,13 @@ declare module 'vscode' { } export interface ConversationRequest { + // eslint-disable-next-line local/vscode-dts-string-type-literals readonly type: 'request'; readonly message: string; } export interface ConversationResponse { + // eslint-disable-next-line local/vscode-dts-string-type-literals readonly type: 'response'; readonly message: string; readonly result?: ChatResult; diff --git a/src/vscode-dts/vscode.proposed.notebookExecution.d.ts b/src/vscode-dts/vscode.proposed.notebookExecution.d.ts index 59f9174768fa2..0b8f8b825467e 100644 --- a/src/vscode-dts/vscode.proposed.notebookExecution.d.ts +++ b/src/vscode-dts/vscode.proposed.notebookExecution.d.ts @@ -31,7 +31,7 @@ declare module 'vscode' { * a cell execution or another NotebookExecution is created while another is still active. * * This should be used to indicate the {@link NotebookController notebook controller} is busy even though user may not have executed any cell though the UI. - * @param {NotebookDocument} notebook + * @param notebook * @returns A notebook execution. */ createNotebookExecution(notebook: NotebookDocument): NotebookExecution;