Merge branch 'main' into joh/intense-heron

This commit is contained in:
Johannes
2024-06-04 08:21:12 +02:00
59 changed files with 667 additions and 476 deletions
+1 -1
View File
@@ -21,8 +21,8 @@ jobs:
uses: ./actions/locker
with:
daysSinceClose: 45
appInsightsKey: ${{secrets.TRIAGE_ACTIONS_APP_INSIGHTS}}
daysSinceUpdate: 3
ignoredLabel: "*out-of-scope,accessibility"
ignoreLabelUntil: "author-verification-requested"
ignoredMilestones: "Backlog Candidates"
labelUntil: "verified"
+10 -1
View File
@@ -135,13 +135,22 @@ steps:
- script: |
set -e
AZURE_STORAGE_ACCOUNT="ticino" \
AZURE_STORAGE_ACCOUNT="vscodeweb" \
AZURE_TENANT_ID="$(AZURE_TENANT_ID)" \
AZURE_CLIENT_ID="$(AZURE_CLIENT_ID)" \
AZURE_CLIENT_SECRET="$(AZURE_CLIENT_SECRET)" \
node build/azure-pipelines/upload-sourcemaps
displayName: Upload sourcemaps to Azure
- script: |
set -e
AZURE_STORAGE_ACCOUNT="ticino" \
AZURE_TENANT_ID="$(AZURE_TENANT_ID)" \
AZURE_CLIENT_ID="$(AZURE_CLIENT_ID)" \
AZURE_CLIENT_SECRET="$(AZURE_CLIENT_SECRET)" \
node build/azure-pipelines/upload-sourcemaps
displayName: Upload sourcemaps to Azure (Deprecated)
- script: ./build/azure-pipelines/common/extract-telemetry.sh
displayName: Generate lists of telemetry events
@@ -129,6 +129,15 @@ steps:
node build/azure-pipelines/upload-cdn
displayName: Upload to CDN
- script: |
set -e
AZURE_STORAGE_ACCOUNT="vscodeweb" \
AZURE_TENANT_ID="$(AZURE_TENANT_ID)" \
AZURE_CLIENT_ID="$(AZURE_CLIENT_ID)" \
AZURE_CLIENT_SECRET="$(AZURE_CLIENT_SECRET)" \
node build/azure-pipelines/upload-sourcemaps out-vscode-web-min out-vscode-web-min/vs/workbench/workbench.web.main.js.map
displayName: Upload sourcemaps (Web)
# upload only the workbench.web.main.js source maps because
# we just compiled these bits in the previous step and the
# general task to upload source maps has already been run
@@ -139,7 +148,7 @@ steps:
AZURE_CLIENT_ID="$(AZURE_CLIENT_ID)" \
AZURE_CLIENT_SECRET="$(AZURE_CLIENT_SECRET)" \
node build/azure-pipelines/upload-sourcemaps out-vscode-web-min out-vscode-web-min/vs/workbench/workbench.web.main.js.map
displayName: Upload sourcemaps (Web)
displayName: Upload sourcemaps (Deprecated)
- script: |
set -e
+1 -1
View File
@@ -71,7 +71,7 @@ const compilations = [
'.vscode/extensions/vscode-selfhost-test-provider/tsconfig.json',
];
const getBaseUrl = out => `https://ticino.blob.core.windows.net/sourcemaps/${commit}/${out}`;
const getBaseUrl = out => `https://main.vscode-cdn.net/sourcemaps/${commit}/${out}`;
const tasks = compilations.map(function (tsconfigFile) {
const absolutePath = path.join(root, tsconfigFile);
+1 -1
View File
@@ -439,7 +439,7 @@ function tweakProductForServerWeb(product) {
const minifyTask = task.define(`minify-vscode-${type}`, task.series(
optimizeTask,
util.rimraf(`out-vscode-${type}-min`),
optimize.minifyTask(`out-vscode-${type}`, `https://ticino.blob.core.windows.net/sourcemaps/${commit}/core`)
optimize.minifyTask(`out-vscode-${type}`, `https://main.vscode-cdn.net/sourcemaps/${commit}/core`)
));
gulp.task(minifyTask);
+1 -1
View File
@@ -133,7 +133,7 @@ const optimizeVSCodeTask = task.define('optimize-vscode', task.series(
));
gulp.task(optimizeVSCodeTask);
const sourceMappingURLBase = `https://ticino.blob.core.windows.net/sourcemaps/${commit}`;
const sourceMappingURLBase = `https://main.vscode-cdn.net/sourcemaps/${commit}`;
const minifyVSCodeTask = task.define('minify-vscode', task.series(
optimizeVSCodeTask,
util.rimraf('out-vscode-min'),
+1 -1
View File
@@ -175,7 +175,7 @@ const optimizeVSCodeWebTask = task.define('optimize-vscode-web', task.series(
const minifyVSCodeWebTask = task.define('minify-vscode-web', task.series(
optimizeVSCodeWebTask,
util.rimraf('out-vscode-web-min'),
optimize.minifyTask('out-vscode-web', `https://ticino.blob.core.windows.net/sourcemaps/${commit}/core`)
optimize.minifyTask('out-vscode-web', `https://main.vscode-cdn.net/sourcemaps/${commit}/core`)
));
gulp.task(minifyVSCodeWebTask);
+1 -1
View File
@@ -34,7 +34,7 @@ const getVersion_1 = require("./getVersion");
const fetch_1 = require("./fetch");
const root = path.dirname(path.dirname(__dirname));
const commit = (0, getVersion_1.getVersion)(root);
const sourceMappingURLBase = `https://ticino.blob.core.windows.net/sourcemaps/${commit}`;
const sourceMappingURLBase = `https://main.vscode-cdn.net/sourcemaps/${commit}`;
function minifyExtensionResources(input) {
const jsonFilter = filter(['**/*.json', '**/*.code-snippets'], { restore: true });
return input
+1 -1
View File
@@ -28,7 +28,7 @@ import { fetchUrls, fetchGithub } from './fetch';
const root = path.dirname(path.dirname(__dirname));
const commit = getVersion(root);
const sourceMappingURLBase = `https://ticino.blob.core.windows.net/sourcemaps/${commit}`;
const sourceMappingURLBase = `https://main.vscode-cdn.net/sourcemaps/${commit}`;
function minifyExtensionResources(input: Stream): Stream {
const jsonFilter = filter(['**/*.json', '**/*.code-snippets'], { restore: true });
+1 -1
View File
@@ -3401,7 +3401,7 @@
"@vscode/iconv-lite-umd": "0.7.0",
"byline": "^5.0.0",
"file-type": "16.5.4",
"jschardet": "3.0.0",
"jschardet": "3.1.2",
"picomatch": "2.3.1",
"vscode-uri": "^2.0.0",
"which": "4.0.0"
+4 -4
View File
@@ -182,10 +182,10 @@ isexe@^3.1.1:
resolved "https://registry.yarnpkg.com/isexe/-/isexe-3.1.1.tgz#4a407e2bd78ddfb14bea0c27c6f7072dde775f0d"
integrity sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==
jschardet@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-3.0.0.tgz#898d2332e45ebabbdb6bf2feece9feea9a99e882"
integrity sha512-lJH6tJ77V8Nzd5QWRkFYCLc13a3vADkh3r/Fi8HupZGWk2OVVDfnZP8V/VgQgZ+lzW0kG2UGb5hFgt3V3ndotQ==
jschardet@3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-3.1.2.tgz#9bf4364deba0677fe9e3bd9e29eda57febf2e9db"
integrity sha512-mw3CBZGzW8nUBPYhFU2ztZ/kJ6NClQUQVpyzvFMfznZsoC///ZQ30J2RCUanNsr5yF22LqhgYr/lj807/ZleWA==
peek-readable@^4.1.0:
version "4.1.0"
+1 -1
View File
@@ -4,7 +4,7 @@
"license": "MIT",
"description": "Dependencies shared by all extensions",
"dependencies": {
"typescript": "5.4.5"
"typescript": "^5.5.0-dev.20240603"
},
"scripts": {
"postinstall": "node ./postinstall.mjs"
@@ -191,7 +191,6 @@ export default class FileConfigurationManager extends Disposable {
includeCompletionsWithClassMemberSnippets: config.get<boolean>('suggest.classMemberSnippets.enabled', true),
includeCompletionsWithObjectLiteralMethodSnippets: config.get<boolean>('suggest.objectLiteralMethodSnippets.enabled', true),
autoImportFileExcludePatterns: this.getAutoImportFileExcludePatternsPreference(preferencesConfig, vscode.workspace.getWorkspaceFolder(document.uri)?.uri),
// @ts-expect-error until 5.3 #56090
preferTypeOnlyAutoImports: preferencesConfig.get<boolean>('preferTypeOnlyAutoImports', false),
useLabelDetailsInCompletionEntries: true,
allowIncompleteCompletions: true,
@@ -19,70 +19,5 @@ declare module '../../../../node_modules/typescript/lib/typescript' {
interface Response {
readonly _serverType?: ServerType;
}
//#region MapCode
export interface MapCodeRequestArgs extends FileRequestArgs {
/**
* The files and changes to try and apply/map.
*/
mapping: MapCodeRequestDocumentMapping;
}
export interface MapCodeRequestDocumentMapping {
/**
* The specific code to map/insert/replace in the file.
*/
contents: string[];
/**
* Areas of "focus" to inform the code mapper with. For example, cursor
* location, current selection, viewport, etc. Nested arrays denote
* priority: toplevel arrays are more important than inner arrays, and
* inner array priorities are based on items within that array. Items
* earlier in the arrays have higher priority.
*/
focusLocations?: TextSpan[][];
}
export interface MapCodeRequest extends FileRequest {
command: 'mapCode';
arguments: MapCodeRequestArgs;
}
export interface MapCodeResponse extends Response {
body: FileCodeEdits[]
}
//#endregion
//#region Paste
export interface GetPasteEditsRequest extends Request {
command: 'getPasteEdits';
arguments: GetPasteEditsRequestArgs;
}
export interface GetPasteEditsRequestArgs extends FileRequestArgs {
/** The text that gets pasted in a file. */
pastedText: string[];
/** Locations of where the `pastedText` gets added in a file. If the length of the `pastedText` and `pastedLocations` are not the same,
* then the `pastedText` is combined into one and added at all the `pastedLocations`.
*/
pasteLocations: TextSpan[];
/** The source location of each `pastedText`. If present, the length of `spans` must be equal to the length of `pastedText`. */
copiedFrom?: {
file: string;
spans: TextSpan[];
};
}
export interface GetPasteEditsResponse extends Response {
body: PasteEditsAction;
}
export interface PasteEditsAction {
edits: FileCodeEdits[];
fixId?: {};
}
//#endregion
}
}
+4 -4
View File
@@ -234,10 +234,10 @@ to-regex-range@^5.0.1:
dependencies:
is-number "^7.0.0"
typescript@5.4.5:
version "5.4.5"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.5.tgz#42ccef2c571fdbd0f6718b1d1f5e6e5ef006f611"
integrity sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==
typescript@^5.5.0-dev.20240603:
version "5.5.0-dev.20240603"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.0-dev.20240603.tgz#a1b7311df5039a8abbaaa2213c21cac6ec547490"
integrity sha512-gdm3Sh1A+Pjj9ZlfBEJY3o2rs3tvpcSbu3vYqcCijMe09BePQBtZlsuShuPn+zCnP+qBLxdKjFiw5v1tkna3tA==
vscode-grammar-updater@^1.1.0:
version "1.1.0"
+9 -9
View File
@@ -82,17 +82,17 @@
"@vscode/windows-mutex": "^0.5.0",
"@vscode/windows-process-tree": "^0.6.0",
"@vscode/windows-registry": "^1.1.0",
"@xterm/addon-image": "0.9.0-beta.17",
"@xterm/addon-search": "0.16.0-beta.17",
"@xterm/addon-serialize": "0.14.0-beta.17",
"@xterm/addon-unicode11": "0.9.0-beta.17",
"@xterm/addon-webgl": "0.19.0-beta.17",
"@xterm/headless": "5.6.0-beta.17",
"@xterm/xterm": "5.6.0-beta.17",
"@xterm/addon-image": "0.9.0-beta.19",
"@xterm/addon-search": "0.16.0-beta.19",
"@xterm/addon-serialize": "0.14.0-beta.19",
"@xterm/addon-unicode11": "0.9.0-beta.19",
"@xterm/addon-webgl": "0.19.0-beta.19",
"@xterm/headless": "5.6.0-beta.19",
"@xterm/xterm": "5.6.0-beta.19",
"graceful-fs": "4.2.11",
"http-proxy-agent": "^7.0.0",
"https-proxy-agent": "^7.0.2",
"jschardet": "3.0.0",
"jschardet": "3.1.2",
"kerberos": "^2.0.1",
"minimist": "^1.2.6",
"native-is-elevated": "0.7.0",
@@ -208,7 +208,7 @@
"ts-loader": "^9.4.2",
"ts-node": "^10.9.1",
"tsec": "0.2.7",
"typescript": "^5.5.0-dev.20240521",
"typescript": "^5.5.0-dev.20240603",
"util": "^0.12.4",
"vscode-nls-dev": "^3.3.1",
"webpack": "^5.91.0",
+8 -8
View File
@@ -14,18 +14,18 @@
"@vscode/vscode-languagedetection": "1.0.21",
"@vscode/windows-process-tree": "^0.6.0",
"@vscode/windows-registry": "^1.1.0",
"@xterm/addon-image": "0.9.0-beta.17",
"@xterm/addon-search": "0.16.0-beta.17",
"@xterm/addon-serialize": "0.14.0-beta.17",
"@xterm/addon-unicode11": "0.9.0-beta.17",
"@xterm/addon-webgl": "0.19.0-beta.17",
"@xterm/headless": "5.6.0-beta.17",
"@xterm/xterm": "5.6.0-beta.17",
"@xterm/addon-image": "0.9.0-beta.19",
"@xterm/addon-search": "0.16.0-beta.19",
"@xterm/addon-serialize": "0.14.0-beta.19",
"@xterm/addon-unicode11": "0.9.0-beta.19",
"@xterm/addon-webgl": "0.19.0-beta.19",
"@xterm/headless": "5.6.0-beta.19",
"@xterm/xterm": "5.6.0-beta.19",
"cookie": "^0.4.0",
"graceful-fs": "4.2.11",
"http-proxy-agent": "^7.0.0",
"https-proxy-agent": "^7.0.2",
"jschardet": "3.0.0",
"jschardet": "3.1.2",
"kerberos": "^2.0.1",
"minimist": "^1.2.6",
"native-watchdog": "^1.4.1",
+7 -7
View File
@@ -7,13 +7,13 @@
"@microsoft/1ds-post-js": "^3.2.13",
"@vscode/iconv-lite-umd": "0.7.0",
"@vscode/vscode-languagedetection": "1.0.21",
"@xterm/addon-image": "0.9.0-beta.17",
"@xterm/addon-search": "0.16.0-beta.17",
"@xterm/addon-serialize": "0.14.0-beta.17",
"@xterm/addon-unicode11": "0.9.0-beta.17",
"@xterm/addon-webgl": "0.19.0-beta.17",
"@xterm/xterm": "5.6.0-beta.17",
"jschardet": "3.0.0",
"@xterm/addon-image": "0.9.0-beta.19",
"@xterm/addon-search": "0.16.0-beta.19",
"@xterm/addon-serialize": "0.14.0-beta.19",
"@xterm/addon-unicode11": "0.9.0-beta.19",
"@xterm/addon-webgl": "0.19.0-beta.19",
"@xterm/xterm": "5.6.0-beta.19",
"jschardet": "3.1.2",
"tas-client-umd": "0.2.0",
"vscode-oniguruma": "1.7.0",
"vscode-textmate": "9.0.0"
+28 -28
View File
@@ -48,40 +48,40 @@
resolved "https://registry.yarnpkg.com/@vscode/vscode-languagedetection/-/vscode-languagedetection-1.0.21.tgz#89b48f293f6aa3341bb888c1118d16ff13b032d3"
integrity sha512-zSUH9HYCw5qsCtd7b31yqkpaCU6jhtkKLkvOOA8yTrIRfBSOFb8PPhgmMicD7B/m+t4PwOJXzU1XDtrM9Fd3/g==
"@xterm/addon-image@0.9.0-beta.17":
version "0.9.0-beta.17"
resolved "https://registry.yarnpkg.com/@xterm/addon-image/-/addon-image-0.9.0-beta.17.tgz#343d0665a6060d4f893b4f2d32de6ccbbd00bb63"
integrity sha512-g0r2hpBcLABY5as4llsMP36RHtkWooEn7tf+7U0/hTndJoCAvs4uGDqZNQigFgeAM3lJ4PnRYh4lfnEh9bGt8A==
"@xterm/addon-image@0.9.0-beta.19":
version "0.9.0-beta.19"
resolved "https://registry.yarnpkg.com/@xterm/addon-image/-/addon-image-0.9.0-beta.19.tgz#3823382e5c55268998f0e0d8d77e8b7810925830"
integrity sha512-LX9g03po3mXYE/HZFoKbdnIRvdD56Qw84FpQ9LCJGDsyx9SFIf47DXLS+lXCEpJ2hjKIing46BQxP+MDEayXDw==
"@xterm/addon-search@0.16.0-beta.17":
version "0.16.0-beta.17"
resolved "https://registry.yarnpkg.com/@xterm/addon-search/-/addon-search-0.16.0-beta.17.tgz#7cb01c7f498405909d37040884ee22d1889a36d2"
integrity sha512-wBfxmWOeqG6HHHE5mVamDJ75zBdHC35ERNy5/aTpQsQsyxrnV0Ks76c8ZVTaTu9wyBCAyx7UmZT42Ot80khY/g==
"@xterm/addon-search@0.16.0-beta.19":
version "0.16.0-beta.19"
resolved "https://registry.yarnpkg.com/@xterm/addon-search/-/addon-search-0.16.0-beta.19.tgz#46b3374eb312a1bff974a5df188b1ebf777ff49d"
integrity sha512-iTJVUEsKSdL8SyhcDBqN6gYxhqv0wrwtP1QCUGLKNAAVDI7HKVgig3V9wToqRxYfOnu/anyU+u0qFUoKCRLnCg==
"@xterm/addon-serialize@0.14.0-beta.17":
version "0.14.0-beta.17"
resolved "https://registry.yarnpkg.com/@xterm/addon-serialize/-/addon-serialize-0.14.0-beta.17.tgz#1cb8e35c0d118060a807adb340624fa7f80dd9c5"
integrity sha512-/c3W39kdRgGGYDoYjXb5HrUC421qwPn6NryAT4WJuJWnyMtFbe2DPwKsTfHuCBPiPyovS3a9j950Md3O3YXDZA==
"@xterm/addon-serialize@0.14.0-beta.19":
version "0.14.0-beta.19"
resolved "https://registry.yarnpkg.com/@xterm/addon-serialize/-/addon-serialize-0.14.0-beta.19.tgz#c7a0a0e5f5b1bd94a35a775ec6224ba42282556c"
integrity sha512-D+BiXQfuxDb3azAIBq1RJTQGZlvo459V6U/2s/3dKpTAvRybqCRMazuf8cLoffUoNcjTb3uSWpii9+MVVvHIrQ==
"@xterm/addon-unicode11@0.9.0-beta.17":
version "0.9.0-beta.17"
resolved "https://registry.yarnpkg.com/@xterm/addon-unicode11/-/addon-unicode11-0.9.0-beta.17.tgz#b5558148029a796c6a6d78e2a8b7255f92a51530"
integrity sha512-z7v8uojFVrO1aLSWtnz5MzSrfWRT8phde7kh9ufqHLBv7YYtMHxlPVjSuW8PZ2h4eY1LOZf6icUAzrmyJmJ7Kg==
"@xterm/addon-unicode11@0.9.0-beta.19":
version "0.9.0-beta.19"
resolved "https://registry.yarnpkg.com/@xterm/addon-unicode11/-/addon-unicode11-0.9.0-beta.19.tgz#529d8b22d9378cff8c31df1b7e76250b2f8079c3"
integrity sha512-0Umiu9GkjwL/jaT85Rcfka9HVyJw3UhJsnOVOVZd/3YBZqMY2SZMHqz73W/qpXl5nz6vvyCWKbpkfddsJhpToA==
"@xterm/addon-webgl@0.19.0-beta.17":
version "0.19.0-beta.17"
resolved "https://registry.yarnpkg.com/@xterm/addon-webgl/-/addon-webgl-0.19.0-beta.17.tgz#68ad9e68dd1cf581b391971de33f5c04966b0d8e"
integrity sha512-X8ObRgoZl7UZTgdndM+mpSO3hLzAhWKoXXrGvUQg/7XabRKAPrQ2XvdyZm04nYwibE6Tpit2h5kkxjlVqupIig==
"@xterm/addon-webgl@0.19.0-beta.19":
version "0.19.0-beta.19"
resolved "https://registry.yarnpkg.com/@xterm/addon-webgl/-/addon-webgl-0.19.0-beta.19.tgz#655d1e27b1249c19352c65a8ea1d0bf319397b35"
integrity sha512-Y5efISx8X5hpFAsPOTza1Fp0xiD8x+l3MuH+mv68v1El8tpna/MW5EM4oX25qYOsPDZY00mpmkBmPbAT5loMEg==
"@xterm/xterm@5.6.0-beta.17":
version "5.6.0-beta.17"
resolved "https://registry.yarnpkg.com/@xterm/xterm/-/xterm-5.6.0-beta.17.tgz#67ce2e2ff45bd6cc9f26d455d5522c6c4a122ed9"
integrity sha512-+wAv8PhaGQSN9yXWIa8EFtT33pbrA4lZakMB1P05fr+DQ7zoH66QOAUoDY95uOf/4+S6Ihz8wzP2+FH8zETQEA==
"@xterm/xterm@5.6.0-beta.19":
version "5.6.0-beta.19"
resolved "https://registry.yarnpkg.com/@xterm/xterm/-/xterm-5.6.0-beta.19.tgz#2cc292fc93b25c7c655ed6d1f0425a636b36747d"
integrity sha512-mGoJxrUxAL4dueZEqw2e23KCrGNSvYaw5twTnccKqK7lITK/hDrosWCxb1jL1AjFf7bBzMxw9/dZdhWncKQQmw==
jschardet@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-3.0.0.tgz#898d2332e45ebabbdb6bf2feece9feea9a99e882"
integrity sha512-lJH6tJ77V8Nzd5QWRkFYCLc13a3vADkh3r/Fi8HupZGWk2OVVDfnZP8V/VgQgZ+lzW0kG2UGb5hFgt3V3ndotQ==
jschardet@3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-3.1.2.tgz#9bf4364deba0677fe9e3bd9e29eda57febf2e9db"
integrity sha512-mw3CBZGzW8nUBPYhFU2ztZ/kJ6NClQUQVpyzvFMfznZsoC///ZQ30J2RCUanNsr5yF22LqhgYr/lj807/ZleWA==
tas-client-umd@0.2.0:
version "0.2.0"
+32 -32
View File
@@ -122,40 +122,40 @@
resolved "https://registry.yarnpkg.com/@vscode/windows-registry/-/windows-registry-1.1.0.tgz#03dace7c29c46f658588b9885b9580e453ad21f9"
integrity sha512-5AZzuWJpGscyiMOed0IuyEwt6iKmV5Us7zuwCDCFYMIq7tsvooO9BUiciywsvuthGz6UG4LSpeDeCxvgMVhnIw==
"@xterm/addon-image@0.9.0-beta.17":
version "0.9.0-beta.17"
resolved "https://registry.yarnpkg.com/@xterm/addon-image/-/addon-image-0.9.0-beta.17.tgz#343d0665a6060d4f893b4f2d32de6ccbbd00bb63"
integrity sha512-g0r2hpBcLABY5as4llsMP36RHtkWooEn7tf+7U0/hTndJoCAvs4uGDqZNQigFgeAM3lJ4PnRYh4lfnEh9bGt8A==
"@xterm/addon-image@0.9.0-beta.19":
version "0.9.0-beta.19"
resolved "https://registry.yarnpkg.com/@xterm/addon-image/-/addon-image-0.9.0-beta.19.tgz#3823382e5c55268998f0e0d8d77e8b7810925830"
integrity sha512-LX9g03po3mXYE/HZFoKbdnIRvdD56Qw84FpQ9LCJGDsyx9SFIf47DXLS+lXCEpJ2hjKIing46BQxP+MDEayXDw==
"@xterm/addon-search@0.16.0-beta.17":
version "0.16.0-beta.17"
resolved "https://registry.yarnpkg.com/@xterm/addon-search/-/addon-search-0.16.0-beta.17.tgz#7cb01c7f498405909d37040884ee22d1889a36d2"
integrity sha512-wBfxmWOeqG6HHHE5mVamDJ75zBdHC35ERNy5/aTpQsQsyxrnV0Ks76c8ZVTaTu9wyBCAyx7UmZT42Ot80khY/g==
"@xterm/addon-search@0.16.0-beta.19":
version "0.16.0-beta.19"
resolved "https://registry.yarnpkg.com/@xterm/addon-search/-/addon-search-0.16.0-beta.19.tgz#46b3374eb312a1bff974a5df188b1ebf777ff49d"
integrity sha512-iTJVUEsKSdL8SyhcDBqN6gYxhqv0wrwtP1QCUGLKNAAVDI7HKVgig3V9wToqRxYfOnu/anyU+u0qFUoKCRLnCg==
"@xterm/addon-serialize@0.14.0-beta.17":
version "0.14.0-beta.17"
resolved "https://registry.yarnpkg.com/@xterm/addon-serialize/-/addon-serialize-0.14.0-beta.17.tgz#1cb8e35c0d118060a807adb340624fa7f80dd9c5"
integrity sha512-/c3W39kdRgGGYDoYjXb5HrUC421qwPn6NryAT4WJuJWnyMtFbe2DPwKsTfHuCBPiPyovS3a9j950Md3O3YXDZA==
"@xterm/addon-serialize@0.14.0-beta.19":
version "0.14.0-beta.19"
resolved "https://registry.yarnpkg.com/@xterm/addon-serialize/-/addon-serialize-0.14.0-beta.19.tgz#c7a0a0e5f5b1bd94a35a775ec6224ba42282556c"
integrity sha512-D+BiXQfuxDb3azAIBq1RJTQGZlvo459V6U/2s/3dKpTAvRybqCRMazuf8cLoffUoNcjTb3uSWpii9+MVVvHIrQ==
"@xterm/addon-unicode11@0.9.0-beta.17":
version "0.9.0-beta.17"
resolved "https://registry.yarnpkg.com/@xterm/addon-unicode11/-/addon-unicode11-0.9.0-beta.17.tgz#b5558148029a796c6a6d78e2a8b7255f92a51530"
integrity sha512-z7v8uojFVrO1aLSWtnz5MzSrfWRT8phde7kh9ufqHLBv7YYtMHxlPVjSuW8PZ2h4eY1LOZf6icUAzrmyJmJ7Kg==
"@xterm/addon-unicode11@0.9.0-beta.19":
version "0.9.0-beta.19"
resolved "https://registry.yarnpkg.com/@xterm/addon-unicode11/-/addon-unicode11-0.9.0-beta.19.tgz#529d8b22d9378cff8c31df1b7e76250b2f8079c3"
integrity sha512-0Umiu9GkjwL/jaT85Rcfka9HVyJw3UhJsnOVOVZd/3YBZqMY2SZMHqz73W/qpXl5nz6vvyCWKbpkfddsJhpToA==
"@xterm/addon-webgl@0.19.0-beta.17":
version "0.19.0-beta.17"
resolved "https://registry.yarnpkg.com/@xterm/addon-webgl/-/addon-webgl-0.19.0-beta.17.tgz#68ad9e68dd1cf581b391971de33f5c04966b0d8e"
integrity sha512-X8ObRgoZl7UZTgdndM+mpSO3hLzAhWKoXXrGvUQg/7XabRKAPrQ2XvdyZm04nYwibE6Tpit2h5kkxjlVqupIig==
"@xterm/addon-webgl@0.19.0-beta.19":
version "0.19.0-beta.19"
resolved "https://registry.yarnpkg.com/@xterm/addon-webgl/-/addon-webgl-0.19.0-beta.19.tgz#655d1e27b1249c19352c65a8ea1d0bf319397b35"
integrity sha512-Y5efISx8X5hpFAsPOTza1Fp0xiD8x+l3MuH+mv68v1El8tpna/MW5EM4oX25qYOsPDZY00mpmkBmPbAT5loMEg==
"@xterm/headless@5.6.0-beta.17":
version "5.6.0-beta.17"
resolved "https://registry.yarnpkg.com/@xterm/headless/-/headless-5.6.0-beta.17.tgz#bff1d67c9c061c57adff22571e733d54e3aba2b7"
integrity sha512-ehS7y/XRqX1ppx4RPiYc0vu0SdIQ91aA4lSN/2XNOf3IGdP0A38Q7a0T6mzqxRGZKiiyA0kTR1szr78wnY+wmA==
"@xterm/headless@5.6.0-beta.19":
version "5.6.0-beta.19"
resolved "https://registry.yarnpkg.com/@xterm/headless/-/headless-5.6.0-beta.19.tgz#dbbd4dd420e24e9bdee6e533153f405bfc1ba89b"
integrity sha512-zFTcftonaaMEbMqfQnFwos1YQCmqWnvIzSNXwmfIymkEvSxhsB03oynEjFwm48dT2filTcJXpYT91io4qvR+3g==
"@xterm/xterm@5.6.0-beta.17":
version "5.6.0-beta.17"
resolved "https://registry.yarnpkg.com/@xterm/xterm/-/xterm-5.6.0-beta.17.tgz#67ce2e2ff45bd6cc9f26d455d5522c6c4a122ed9"
integrity sha512-+wAv8PhaGQSN9yXWIa8EFtT33pbrA4lZakMB1P05fr+DQ7zoH66QOAUoDY95uOf/4+S6Ihz8wzP2+FH8zETQEA==
"@xterm/xterm@5.6.0-beta.19":
version "5.6.0-beta.19"
resolved "https://registry.yarnpkg.com/@xterm/xterm/-/xterm-5.6.0-beta.19.tgz#2cc292fc93b25c7c655ed6d1f0425a636b36747d"
integrity sha512-mGoJxrUxAL4dueZEqw2e23KCrGNSvYaw5twTnccKqK7lITK/hDrosWCxb1jL1AjFf7bBzMxw9/dZdhWncKQQmw==
agent-base@^7.0.1, agent-base@^7.0.2, agent-base@^7.1.0:
version "7.1.0"
@@ -347,10 +347,10 @@ is-number@^7.0.0:
resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
jschardet@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-3.0.0.tgz#898d2332e45ebabbdb6bf2feece9feea9a99e882"
integrity sha512-lJH6tJ77V8Nzd5QWRkFYCLc13a3vADkh3r/Fi8HupZGWk2OVVDfnZP8V/VgQgZ+lzW0kG2UGb5hFgt3V3ndotQ==
jschardet@3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-3.1.2.tgz#9bf4364deba0677fe9e3bd9e29eda57febf2e9db"
integrity sha512-mw3CBZGzW8nUBPYhFU2ztZ/kJ6NClQUQVpyzvFMfznZsoC///ZQ30J2RCUanNsr5yF22LqhgYr/lj807/ZleWA==
jsonfile@^6.0.1:
version "6.1.0"
+51
View File
@@ -18,6 +18,7 @@ import * as platform from 'vs/base/common/platform';
import { URI } from 'vs/base/common/uri';
import { hash } from 'vs/base/common/hash';
import { CodeWindow, ensureCodeWindow, mainWindow } from 'vs/base/browser/window';
import { isPointWithinTriangle } from 'vs/base/common/numbers';
export interface IRegisteredCodeWindow {
readonly window: CodeWindow;
@@ -2408,3 +2409,53 @@ export function trackAttributes(from: Element, to: Element, filter?: string[]):
return disposables;
}
/**
* Helper for calculating the "safe triangle" occluded by hovers to avoid early dismissal.
* @see https://www.smashingmagazine.com/2023/08/better-context-menus-safe-triangles/ for example
*/
export class SafeTriangle {
// 4 triangles, 2 points (x, y) stored for each
private triangles: number[] = [];
constructor(
private readonly originX: number,
private readonly originY: number,
target: HTMLElement
) {
const { top, left, right, bottom } = target.getBoundingClientRect();
const t = this.triangles;
let i = 0;
t[i++] = left;
t[i++] = top;
t[i++] = right;
t[i++] = top;
t[i++] = left;
t[i++] = top;
t[i++] = left;
t[i++] = bottom;
t[i++] = right;
t[i++] = top;
t[i++] = right;
t[i++] = bottom;
t[i++] = left;
t[i++] = bottom;
t[i++] = right;
t[i++] = bottom;
}
public contains(x: number, y: number) {
const { triangles, originX, originY } = this;
for (let i = 0; i < 4; i++) {
if (isPointWithinTriangle(x, y, originX, originY, triangles[2 * i], triangles[2 * i + 1], triangles[2 * i + 2], triangles[2 * i + 3])) {
return true;
}
}
return false;
}
}
+3 -2
View File
@@ -44,9 +44,10 @@ export namespace Iterable {
return iterable[Symbol.iterator]().next().value;
}
export function some<T>(iterable: Iterable<T>, predicate: (t: T) => unknown): boolean {
export function some<T>(iterable: Iterable<T>, predicate: (t: T, i: number) => unknown): boolean {
let i = 0;
for (const element of iterable) {
if (predicate(element)) {
if (predicate(element, i++)) {
return true;
}
}
+27
View File
@@ -69,3 +69,30 @@ export class SlidingWindowAverage {
return this._val;
}
}
/** Returns whether the point is within the triangle formed by the following 6 x/y point pairs */
export function isPointWithinTriangle(
x: number, y: number,
ax: number, ay: number,
bx: number, by: number,
cx: number, cy: number
) {
const v0x = cx - ax;
const v0y = cy - ay;
const v1x = bx - ax;
const v1y = by - ay;
const v2x = x - ax;
const v2y = y - ay;
const dot00 = v0x * v0x + v0y * v0y;
const dot01 = v0x * v1x + v0y * v1y;
const dot02 = v0x * v2x + v0y * v2y;
const dot11 = v1x * v1x + v1y * v1y;
const dot12 = v1x * v2x + v1y * v2y;
const invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
const u = (dot11 * dot02 - dot01 * dot12) * invDenom;
const v = (dot00 * dot12 - dot01 * dot02) * invDenom;
return u >= 0 && v >= 0 && u + v < 1;
}
+27
View File
@@ -0,0 +1,27 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { isPointWithinTriangle } from 'vs/base/common/numbers';
import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils';
suite('isPointWithinTriangle', () => {
ensureNoDisposablesAreLeakedInTestSuite();
test('should return true if the point is within the triangle', () => {
const result = isPointWithinTriangle(0.25, 0.25, 0, 0, 1, 0, 0, 1);
assert.ok(result);
});
test('should return false if the point is outside the triangle', () => {
const result = isPointWithinTriangle(2, 2, 0, 0, 1, 0, 0, 1);
assert.ok(!result);
});
test('should return true if the point is on the edge of the triangle', () => {
const result = isPointWithinTriangle(0.5, 0, 0, 0, 1, 0, 0, 1);
assert.ok(result);
});
});
@@ -123,5 +123,5 @@ function detectLanguageId(modelService: IModelService, languageService: ILanguag
}
function cssEscape(str: string): string {
return str.replace(/[\11\12\14\15\40]/g, '/'); // HTML class names can not contain certain whitespace characters, use / instead, which doesn't exist in file names.
return str.replace(/[\x11\x12\x14\x15\x40]/g, '/'); // HTML class names can not contain certain whitespace characters, use / instead, which doesn't exist in file names.
}
@@ -51,7 +51,7 @@ export class StickyScrollController extends Disposable implements IEditorContrib
private readonly _sessionStore: DisposableStore = new DisposableStore();
private _widgetState: StickyScrollWidgetState;
private _foldingModel: FoldingModel | null = null;
private _foldingModel: FoldingModel | undefined;
private _maxStickyLines: number = Number.MAX_SAFE_INTEGER;
private _stickyRangeProjectedOnEditor: IRange | undefined;
@@ -67,7 +67,7 @@ export class StickyScrollController extends Disposable implements IEditorContrib
private _positionRevealed = false;
private _onMouseDown = false;
private _endLineNumbers: number[] = [];
private _showEndForLine: number | null = null;
private _showEndForLine: number | undefined;
constructor(
private readonly _editor: ICodeEditor,
@@ -84,7 +84,7 @@ export class StickyScrollController extends Disposable implements IEditorContrib
this._register(this._stickyScrollWidget);
this._register(this._stickyLineCandidateProvider);
this._widgetState = new StickyScrollWidgetState([], [], 0);
this._widgetState = StickyScrollWidgetState.Empty;
this._onDidResize();
this._readConfiguration();
const stickyScrollDomNode = this._stickyScrollWidget.getDomNode();
@@ -291,14 +291,14 @@ export class StickyScrollController extends Disposable implements IEditorContrib
this._renderStickyScroll();
return;
}
if (this._showEndForLine !== null) {
this._showEndForLine = null;
if (this._showEndForLine !== undefined) {
this._showEndForLine = undefined;
this._renderStickyScroll();
}
}));
this._register(dom.addDisposableListener(stickyScrollWidgetDomNode, dom.EventType.MOUSE_LEAVE, (e) => {
if (this._showEndForLine !== null) {
this._showEndForLine = null;
if (this._showEndForLine !== undefined) {
this._showEndForLine = undefined;
this._renderStickyScroll();
}
}));
@@ -415,14 +415,14 @@ export class StickyScrollController extends Disposable implements IEditorContrib
this._editor.addOverlayWidget(this._stickyScrollWidget);
this._sessionStore.add(this._editor.onDidScrollChange((e) => {
if (e.scrollTopChanged) {
this._showEndForLine = null;
this._showEndForLine = undefined;
this._renderStickyScroll();
}
}));
this._sessionStore.add(this._editor.onDidLayoutChange(() => this._onDidResize()));
this._sessionStore.add(this._editor.onDidChangeModelTokens((e) => this._onTokensChange(e)));
this._sessionStore.add(this._stickyLineCandidateProvider.onDidChangeStickyScroll(() => {
this._showEndForLine = null;
this._showEndForLine = undefined;
this._renderStickyScroll();
}));
this._enabled = true;
@@ -431,7 +431,7 @@ export class StickyScrollController extends Disposable implements IEditorContrib
const lineNumberOption = this._editor.getOption(EditorOption.lineNumbers);
if (lineNumberOption.renderType === RenderLineNumbersType.Relative) {
this._sessionStore.add(this._editor.onDidChangeCursorPosition(() => {
this._showEndForLine = null;
this._showEndForLine = undefined;
this._renderStickyScroll(0);
}));
}
@@ -479,32 +479,28 @@ export class StickyScrollController extends Disposable implements IEditorContrib
this._maxStickyLines = Math.round(theoreticalLines * .25);
}
private async _renderStickyScroll(rebuildFromLine?: number) {
private async _renderStickyScroll(rebuildFromLine?: number): Promise<void> {
const model = this._editor.getModel();
if (!model || model.isTooLargeForTokenization()) {
this._foldingModel = null;
this._stickyScrollWidget.setState(undefined, null);
this._resetState();
return;
}
const stickyLineVersion = this._stickyLineCandidateProvider.getVersionId();
if (stickyLineVersion === undefined || stickyLineVersion === model.getVersionId()) {
this._foldingModel = await FoldingController.get(this._editor)?.getFoldingModel() ?? null;
this._widgetState = this.findScrollWidgetState();
this._stickyScrollVisibleContextKey.set(!(this._widgetState.startLineNumbers.length === 0));
const stickyWidgetVersion = this._stickyLineCandidateProvider.getVersionId();
const shouldUpdateState = stickyWidgetVersion === undefined || stickyWidgetVersion === model.getVersionId();
if (shouldUpdateState) {
if (!this._focused) {
this._stickyScrollWidget.setState(this._widgetState, this._foldingModel, rebuildFromLine);
await this._updateState(rebuildFromLine);
} else {
// Suppose that previously the sticky scroll widget had height 0, then if there are visible lines, set the last line as focused
if (this._focusedStickyElementIndex === -1) {
this._stickyScrollWidget.setState(this._widgetState, this._foldingModel, rebuildFromLine);
await this._updateState(rebuildFromLine);
this._focusedStickyElementIndex = this._stickyScrollWidget.lineNumberCount - 1;
if (this._focusedStickyElementIndex !== -1) {
this._stickyScrollWidget.focusLineWithIndex(this._focusedStickyElementIndex);
}
} else {
const focusedStickyElementLineNumber = this._stickyScrollWidget.lineNumbers[this._focusedStickyElementIndex];
this._stickyScrollWidget.setState(this._widgetState, this._foldingModel, rebuildFromLine);
await this._updateState(rebuildFromLine);
// Suppose that after setting the state, there are no sticky lines, set the focused index to -1
if (this._stickyScrollWidget.lineNumberCount === 0) {
this._focusedStickyElementIndex = -1;
@@ -522,6 +518,20 @@ export class StickyScrollController extends Disposable implements IEditorContrib
}
}
}
private async _updateState(rebuildFromLine?: number): Promise<void> {
this._foldingModel = await FoldingController.get(this._editor)?.getFoldingModel() ?? undefined;
this._widgetState = this.findScrollWidgetState();
const stickyWidgetHasLines = this._widgetState.startLineNumbers.length > 0;
this._stickyScrollVisibleContextKey.set(stickyWidgetHasLines);
this._stickyScrollWidget.setState(this._widgetState, this._foldingModel, rebuildFromLine);
}
private async _resetState(): Promise<void> {
this._foldingModel = undefined;
this._widgetState = StickyScrollWidgetState.Empty;
this._stickyScrollVisibleContextKey.set(false);
this._stickyScrollWidget.setState(undefined, undefined);
}
findScrollWidgetState(): StickyScrollWidgetState {
const lineHeight: number = this._editor.getOption(EditorOption.lineHeight);
@@ -35,6 +35,10 @@ export class StickyScrollWidgetState {
&& equals(this.startLineNumbers, other.startLineNumbers)
&& equals(this.endLineNumbers, other.endLineNumbers);
}
static get Empty() {
return new StickyScrollWidgetState([], [], 0);
}
}
const _ttPolicy = createTrustedTypesPolicy('stickyScrollViewLayer', { createHTML: value => value });
@@ -126,7 +130,7 @@ export class StickyScrollWidget extends Disposable implements IOverlayWidget {
return this._lineNumbers;
}
setState(_state: StickyScrollWidgetState | undefined, foldingModel: FoldingModel | null, _rebuildFromLine?: number): void {
setState(_state: StickyScrollWidgetState | undefined, foldingModel: FoldingModel | undefined, _rebuildFromLine?: number): void {
if (_rebuildFromLine === undefined &&
((!this._previousState && !_state) || (this._previousState && this._previousState.equals(_state)))
) {
@@ -205,7 +209,7 @@ export class StickyScrollWidget extends Disposable implements IOverlayWidget {
}
}
private async _renderRootNode(state: StickyScrollWidgetState | undefined, foldingModel: FoldingModel | null, rebuildFromLine: number): Promise<void> {
private async _renderRootNode(state: StickyScrollWidgetState | undefined, foldingModel: FoldingModel | undefined, rebuildFromLine: number): Promise<void> {
this._clearStickyLinesFromLine(rebuildFromLine);
if (!state) {
return;
@@ -258,7 +262,7 @@ export class StickyScrollWidget extends Disposable implements IOverlayWidget {
}));
}
private _renderChildNode(index: number, line: number, foldingModel: FoldingModel | null, layoutInfo: EditorLayoutInfo): RenderedStickyLine | undefined {
private _renderChildNode(index: number, line: number, foldingModel: FoldingModel | undefined, layoutInfo: EditorLayoutInfo): RenderedStickyLine | undefined {
const viewModel = this._editor._getViewModel();
if (!viewModel) {
return;
@@ -358,7 +362,7 @@ export class StickyScrollWidget extends Disposable implements IOverlayWidget {
return stickyLine;
}
private _renderFoldingIconForLine(foldingModel: FoldingModel | null, line: number): StickyFoldingIcon | undefined {
private _renderFoldingIconForLine(foldingModel: FoldingModel | undefined, line: number): StickyFoldingIcon | undefined {
const showFoldingControls: 'mouseover' | 'always' | 'never' = this._editor.getOption(EditorOption.showFoldingControls);
if (!foldingModel || showFoldingControls === 'never') {
return;
+5 -5
View File
@@ -5003,8 +5003,8 @@ declare namespace monaco.editor {
screenReaderAnnounceInlineSuggestion: IEditorOption<EditorOption.screenReaderAnnounceInlineSuggestion, boolean>;
autoClosingBrackets: IEditorOption<EditorOption.autoClosingBrackets, 'always' | 'languageDefined' | 'beforeWhitespace' | 'never'>;
autoClosingComments: IEditorOption<EditorOption.autoClosingComments, 'always' | 'languageDefined' | 'beforeWhitespace' | 'never'>;
autoClosingDelete: IEditorOption<EditorOption.autoClosingDelete, 'always' | 'never' | 'auto'>;
autoClosingOvertype: IEditorOption<EditorOption.autoClosingOvertype, 'always' | 'never' | 'auto'>;
autoClosingDelete: IEditorOption<EditorOption.autoClosingDelete, 'auto' | 'always' | 'never'>;
autoClosingOvertype: IEditorOption<EditorOption.autoClosingOvertype, 'auto' | 'always' | 'never'>;
autoClosingQuotes: IEditorOption<EditorOption.autoClosingQuotes, 'always' | 'languageDefined' | 'beforeWhitespace' | 'never'>;
autoIndent: IEditorOption<EditorOption.autoIndent, EditorAutoIndentStrategy>;
automaticLayout: IEditorOption<EditorOption.automaticLayout, boolean>;
@@ -5016,7 +5016,7 @@ declare namespace monaco.editor {
codeLensFontFamily: IEditorOption<EditorOption.codeLensFontFamily, string>;
codeLensFontSize: IEditorOption<EditorOption.codeLensFontSize, number>;
colorDecorators: IEditorOption<EditorOption.colorDecorators, boolean>;
colorDecoratorActivatedOn: IEditorOption<EditorOption.colorDecoratorsActivatedOn, 'clickAndHover' | 'click' | 'hover'>;
colorDecoratorActivatedOn: IEditorOption<EditorOption.colorDecoratorsActivatedOn, 'hover' | 'clickAndHover' | 'click'>;
colorDecoratorsLimit: IEditorOption<EditorOption.colorDecoratorsLimit, number>;
columnSelection: IEditorOption<EditorOption.columnSelection, boolean>;
comments: IEditorOption<EditorOption.comments, Readonly<Required<IEditorCommentsOptions>>>;
@@ -5124,13 +5124,13 @@ declare namespace monaco.editor {
tabCompletion: IEditorOption<EditorOption.tabCompletion, 'on' | 'off' | 'onlySnippets'>;
tabIndex: IEditorOption<EditorOption.tabIndex, number>;
unicodeHighlight: IEditorOption<EditorOption.unicodeHighlighting, any>;
unusualLineTerminators: IEditorOption<EditorOption.unusualLineTerminators, 'auto' | 'off' | 'prompt'>;
unusualLineTerminators: IEditorOption<EditorOption.unusualLineTerminators, 'off' | 'auto' | 'prompt'>;
useShadowDOM: IEditorOption<EditorOption.useShadowDOM, boolean>;
useTabStops: IEditorOption<EditorOption.useTabStops, boolean>;
wordBreak: IEditorOption<EditorOption.wordBreak, 'normal' | 'keepAll'>;
wordSegmenterLocales: IEditorOption<EditorOption.wordSegmenterLocales, {}>;
wordSeparators: IEditorOption<EditorOption.wordSeparators, string>;
wordWrap: IEditorOption<EditorOption.wordWrap, 'on' | 'off' | 'wordWrapColumn' | 'bounded'>;
wordWrap: IEditorOption<EditorOption.wordWrap, 'wordWrapColumn' | 'on' | 'off' | 'bounded'>;
wordWrapBreakAfterCharacters: IEditorOption<EditorOption.wordWrapBreakAfterCharacters, string>;
wordWrapBreakBeforeCharacters: IEditorOption<EditorOption.wordWrapBreakBeforeCharacters, string>;
wordWrapColumn: IEditorOption<EditorOption.wordWrapColumn, number>;
+5 -4
View File
@@ -5,7 +5,7 @@
import { CancellationToken } from 'vs/base/common/cancellation';
import { Emitter, Event } from 'vs/base/common/event';
import { IDisposable } from 'vs/base/common/lifecycle';
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
import { OperatingSystem } from 'vs/base/common/platform';
import { URI } from 'vs/base/common/uri';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
@@ -215,7 +215,7 @@ export class DisposableTunnel {
}
}
export abstract class AbstractTunnelService implements ITunnelService {
export abstract class AbstractTunnelService extends Disposable implements ITunnelService {
declare readonly _serviceBrand: undefined;
private _onTunnelOpened: Emitter<RemoteTunnel> = new Emitter();
@@ -234,7 +234,7 @@ export abstract class AbstractTunnelService implements ITunnelService {
public constructor(
@ILogService protected readonly logService: ILogService,
@IConfigurationService protected readonly configurationService: IConfigurationService
) { }
) { super(); }
get hasTunnelProvider(): boolean {
return !!this._tunnelProvider;
@@ -308,7 +308,8 @@ export abstract class AbstractTunnelService implements ITunnelService {
return tunnels;
}
async dispose(): Promise<void> {
override async dispose(): Promise<void> {
super.dispose();
for (const portMap of this._tunnels.values()) {
for (const { value } of portMap.values()) {
await value.then(tunnel => typeof tunnel !== 'string' ? tunnel?.dispose() : undefined);
@@ -5,10 +5,7 @@
import { DisposableMap } from 'vs/base/common/lifecycle';
import { revive } from 'vs/base/common/marshalling';
import { URI } from 'vs/base/common/uri';
import { Location } from 'vs/editor/common/languages';
import { ExtHostChatVariablesShape, ExtHostContext, IChatVariableResolverProgressDto, MainContext, MainThreadChatVariablesShape } from 'vs/workbench/api/common/extHost.protocol';
import { ChatAgentLocation } from 'vs/workbench/contrib/chat/common/chatAgents';
import { IChatRequestVariableValue, IChatVariableData, IChatVariableResolverProgress, IChatVariablesService } from 'vs/workbench/contrib/chat/common/chatVariables';
import { IExtHostContext, extHostNamedCustomer } from 'vs/workbench/services/extensions/common/extHostCustomers';
@@ -50,8 +47,4 @@ export class MainThreadChatVariables implements MainThreadChatVariablesShape {
$unregisterVariable(handle: number): void {
this._variables.deleteAndDispose(handle);
}
$attachContext(name: string, value: string | URI | Location | unknown, location: ChatAgentLocation.Panel): void {
this._chatVariablesService.attachContext(name, revive(value), location);
}
}
@@ -1429,10 +1429,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
createDynamicChatParticipant(id: string, dynamicProps: vscode.DynamicChatParticipantProps, handler: vscode.ChatExtendedRequestHandler): vscode.ChatParticipant {
checkProposedApiEnabled(extension, 'chatParticipantPrivate');
return extHostChatAgents2.createDynamicChatAgent(extension, id, dynamicProps, handler);
},
attachContext(name: string, value: string | vscode.Uri | vscode.Location | unknown, location: vscode.ChatLocation.Panel) {
checkProposedApiEnabled(extension, 'chatVariableResolver');
return extHostChatVariables.attachContext(name, value, location);
}
};
@@ -6,7 +6,6 @@
import { VSBuffer } from 'vs/base/common/buffer';
import { CancellationToken } from 'vs/base/common/cancellation';
import { IRemoteConsoleLog } from 'vs/base/common/console';
import { Location } from 'vs/editor/common/languages';
import { SerializedError } from 'vs/base/common/errors';
import { IRelativePattern } from 'vs/base/common/glob';
import { IMarkdownString } from 'vs/base/common/htmlContent';
@@ -1291,7 +1290,6 @@ export interface MainThreadChatVariablesShape extends IDisposable {
$registerVariable(handle: number, data: IChatVariableData): void;
$handleProgressChunk(requestId: string, progress: IChatVariableResolverProgressDto): Promise<number | void>;
$unregisterVariable(handle: number): void;
$attachContext(name: string, value: string | Dto<Location> | URI | unknown, location: ChatAgentLocation): void;
}
export type IChatRequestVariableValueDto = Dto<IChatRequestVariableValue>;
@@ -64,10 +64,6 @@ export class ExtHostChatVariables implements ExtHostChatVariablesShape {
this._proxy.$unregisterVariable(handle);
});
}
attachContext(name: string, value: string | vscode.Location | vscode.Uri | unknown, location: vscode.ChatLocation.Panel) {
this._proxy.$attachContext(name, extHostTypes.Location.isLocation(value) ? typeConvert.Location.from(value) : value, typeConvert.ChatLocation.from(location));
}
}
class ChatVariableResolverResponseStream {
@@ -171,118 +171,77 @@ const configuration: IConfigurationNode = {
type: 'boolean',
default: true
},
'accessibility.signalOptions': {
description: 'Configures the behavior of signals (audio cues and announcements) in the workbench. Includes volume, debounce position changes, and delays for different types of signals.',
type: 'object',
additionalProperties: false,
properties: {
'volume': {
'description': localize('accessibility.signalOptions.volume', "The volume of the sounds in percent (0-100)."),
'accessibility.signalOptions.volume': {
'description': localize('accessibility.signalOptions.volume', "The volume of the sounds in percent (0-100)."),
'type': 'number',
'minimum': 0,
'maximum': 100,
'default': 70,
'tags': ['accessibility']
},
'accessibility.signalOptions.debouncePositionChanges': {
'description': localize('accessibility.signalOptions.debouncePositionChanges', "Whether or not position changes should be debounced"),
'type': 'boolean',
'default': false,
'tags': ['accessibility']
},
'accessibility.signalOptions.experimental.delays.general': {
'type': 'object',
'description': 'Delays for all signals besides error and warning at position',
'additionalProperties': false,
'properties': {
'announcement': {
'description': localize('accessibility.signalOptions.delays.general.announcement', "The delay in milliseconds before an announcement is made."),
'type': 'number',
'minimum': 0,
'maximum': 100,
'default': 70,
'default': 3000
},
'debouncePositionChanges': {
'description': localize('accessibility.signalOptions.debouncePositionChanges', "Whether or not position changes should be debounced"),
'type': 'boolean',
'default': false,
},
'experimental.delays': {
'type': 'object',
'additionalProperties': false,
'properties': {
'general': {
'type': 'object',
'description': 'Delays for all signals besides error and warning at position',
'additionalProperties': false,
'properties': {
'announcement': {
'description': localize('accessibility.signalOptions.delays.general.announcement', "The delay in milliseconds before an announcement is made."),
'type': 'number',
'minimum': 0,
'default': 3000
},
'sound': {
'description': localize('accessibility.signalOptions.delays.general.sound', "The delay in milliseconds before a sound is played."),
'type': 'number',
'minimum': 0,
'default': 400
}
},
},
'warningAtPosition': {
'type': 'object',
'additionalProperties': false,
'properties': {
'announcement': {
'description': localize('accessibility.signalOptions.delays.warningAtPosition.announcement', "The delay in milliseconds before an announcement is made when there's a warning at the position."),
'type': 'number',
'minimum': 0,
'default': 3000
},
'sound': {
'description': localize('accessibility.signalOptions.delays.warningAtPosition.sound', "The delay in milliseconds before a sound is played when there's a warning at the position."),
'type': 'number',
'minimum': 0,
'default': 1000
}
},
},
'errorAtPosition': {
'type': 'object',
'additionalProperties': false,
'properties': {
'announcement': {
'description': localize('accessibility.signalOptions.delays.errorAtPosition.announcement', "The delay in milliseconds before an announcement is made when there's an error at the position."),
'type': 'number',
'minimum': 0,
'default': 3000
},
'sound': {
'description': localize('accessibility.signalOptions.delays.errorAtPosition.sound', "The delay in milliseconds before a sound is played when there's an error at the position."),
'type': 'number',
'minimum': 0,
'default': 1000
}
},
},
},
'default': {
'general': {
'announcement': 3000,
'sound': 400
},
'warningAtPosition': {
'announcement': 3000,
'sound': 1000
},
'errorAtPosition': {
'announcement': 3000,
'sound': 1000
}
}
},
},
'default': {
'volume': 70,
'debouncePositionChanges': false,
'delays': {
'general': {
'announcement': 3000,
'sound': 400
},
'warningAtPosition': {
'announcement': 3000,
'sound': 1000
},
'errorAtPosition': {
'announcement': 3000,
'sound': 1000
}
'sound': {
'description': localize('accessibility.signalOptions.delays.general.sound', "The delay in milliseconds before a sound is played."),
'type': 'number',
'minimum': 0,
'default': 400
}
},
tags: ['accessibility']
'tags': ['accessibility']
},
'accessibility.signalOptions.experimental.delays.warningAtPosition': {
'type': 'object',
'additionalProperties': false,
'properties': {
'announcement': {
'description': localize('accessibility.signalOptions.delays.warningAtPosition.announcement', "The delay in milliseconds before an announcement is made when there's a warning at the position."),
'type': 'number',
'minimum': 0,
'default': 3000
},
'sound': {
'description': localize('accessibility.signalOptions.delays.warningAtPosition.sound', "The delay in milliseconds before a sound is played when there's a warning at the position."),
'type': 'number',
'minimum': 0,
'default': 1000
}
},
'tags': ['accessibility']
},
'accessibility.signalOptions.experimental.delays.errorAtPosition': {
'type': 'object',
'additionalProperties': false,
'properties': {
'announcement': {
'description': localize('accessibility.signalOptions.delays.errorAtPosition.announcement', "The delay in milliseconds before an announcement is made when there's an error at the position."),
'type': 'number',
'minimum': 0,
'default': 3000
},
'sound': {
'description': localize('accessibility.signalOptions.delays.errorAtPosition.sound', "The delay in milliseconds before a sound is played when there's an error at the position."),
'type': 'number',
'minimum': 0,
'default': 1000
}
},
'tags': ['accessibility']
},
'accessibility.signals.lineHasBreakpoint': {
...signalFeatureBase,
@@ -804,10 +763,9 @@ export class DynamicSpeechAccessibilityConfiguration extends Disposable implemen
Registry.as<IConfigurationMigrationRegistry>(WorkbenchExtensions.ConfigurationMigration)
.registerConfigurationMigrations([{
key: 'audioCues.volume',
migrateFn: (volume, accessor) => {
const debouncePositionChanges = getDebouncePositionChangesFromConfig(accessor);
migrateFn: (value, accessor) => {
return [
['accessibility.signalOptions', { value: debouncePositionChanges !== undefined ? { volume, debouncePositionChanges } : { volume } }],
['accessibility.signalOptions.volume', { value }],
['audioCues.volume', { value: undefined }]
];
}
@@ -816,10 +774,9 @@ Registry.as<IConfigurationMigrationRegistry>(WorkbenchExtensions.ConfigurationMi
Registry.as<IConfigurationMigrationRegistry>(WorkbenchExtensions.ConfigurationMigration)
.registerConfigurationMigrations([{
key: 'audioCues.debouncePositionChanges',
migrateFn: (debouncePositionChanges, accessor) => {
const volume = getVolumeFromConfig(accessor);
migrateFn: (value) => {
return [
['accessibility.signalOptions', { value: volume !== undefined ? { volume, debouncePositionChanges } : { debouncePositionChanges } }],
['accessibility.signalOptions.debouncePositionChanges', { value }],
['audioCues.debouncePositionChanges', { value: undefined }]
];
}
@@ -829,12 +786,18 @@ Registry.as<IConfigurationMigrationRegistry>(WorkbenchExtensions.ConfigurationMi
.registerConfigurationMigrations([{
key: 'accessibility.signalOptions',
migrateFn: (value, accessor) => {
const delays = value.delays;
if (!delays) {
return [];
}
const delayGeneral = getDelaysFromConfig(accessor, 'general');
const delayError = getDelaysFromConfig(accessor, 'errorAtPosition');
const delayWarning = getDelaysFromConfig(accessor, 'warningAtPosition');
const volume = getVolumeFromConfig(accessor);
const debouncePositionChanges = getDebouncePositionChangesFromConfig(accessor);
return [
['accessibility.signalOptions', { value: { ...value, 'experimental.delays': delays, 'delays': undefined } }],
['accessibility.signalOptions.volume', { value: volume }],
['accessibility.signalOptions.debouncePositionChanges', { value: debouncePositionChanges }],
['accessibility.signalOptions.experimental.delays.general', { value: delayGeneral }],
['accessibility.signalOptions.experimental.delays.errorAtPosition', { value: delayError }],
['accessibility.signalOptions.experimental.delays.warningAtPosition', { value: delayWarning }],
['accessibility.signalOptions', { value: undefined }],
];
}
}]);
@@ -843,10 +806,9 @@ Registry.as<IConfigurationMigrationRegistry>(WorkbenchExtensions.ConfigurationMi
Registry.as<IConfigurationMigrationRegistry>(WorkbenchExtensions.ConfigurationMigration)
.registerConfigurationMigrations([{
key: 'accessibility.signals.sounds.volume',
migrateFn: (volume, accessor) => {
const debouncePositionChanges = getDebouncePositionChangesFromConfig(accessor);
migrateFn: (value) => {
return [
['accessibility.signalOptions', { value: debouncePositionChanges !== undefined ? { volume, debouncePositionChanges } : { volume } }],
['accessibility.signalOptions.volume', { value }],
['accessibility.signals.sounds.volume', { value: undefined }]
];
}
@@ -855,21 +817,24 @@ Registry.as<IConfigurationMigrationRegistry>(WorkbenchExtensions.ConfigurationMi
Registry.as<IConfigurationMigrationRegistry>(WorkbenchExtensions.ConfigurationMigration)
.registerConfigurationMigrations([{
key: 'accessibility.signals.debouncePositionChanges',
migrateFn: (debouncePositionChanges, accessor) => {
const volume = getVolumeFromConfig(accessor);
migrateFn: (value) => {
return [
['accessibility.signalOptions', { value: volume !== undefined ? { volume, debouncePositionChanges } : { debouncePositionChanges } }],
['accessibility.signalOptions.debouncePositionChanges', { value }],
['accessibility.signals.debouncePositionChanges', { value: undefined }]
];
}
}]);
function getDelaysFromConfig(accessor: (key: string) => any, type: 'general' | 'errorAtPosition' | 'warningAtPosition'): { announcement: number; sound: number } | undefined {
return accessor(`accessibility.signalOptions.experimental.delays.${type}`) || accessor('accessibility.signalOptions')?.['experimental.delays']?.[`${type}`] || accessor('accessibility.signalOptions')?.['delays']?.[`${type}`];
}
function getVolumeFromConfig(accessor: (key: string) => any): string | undefined {
return accessor('accessibility.signalOptions')?.volume || accessor('accessibility.signals.sounds.volume') || accessor('audioCues.volume');
return accessor('accessibility.signalOptions.volume') || accessor('accessibility.signalOptions')?.volume || accessor('accessibility.signals.sounds.volume') || accessor('audioCues.volume');
}
function getDebouncePositionChangesFromConfig(accessor: (key: string) => any): number | undefined {
return accessor('accessibility.signalOptions')?.debouncePositionChanges || accessor('accessibility.signals.debouncePositionChanges') || accessor('audioCues.debouncePositionChanges');
return accessor('accessibility.signalOptions.debouncePositionChanges') || accessor('accessibility.signalOptions')?.debouncePositionChanges || accessor('accessibility.signals.debouncePositionChanges') || accessor('audioCues.debouncePositionChanges');
}
Registry.as<IConfigurationMigrationRegistry>(WorkbenchExtensions.ConfigurationMigration)
@@ -30,9 +30,13 @@ import { IChatVariablesService } from 'vs/workbench/contrib/chat/common/chatVari
import { AnythingQuickAccessProvider } from 'vs/workbench/contrib/search/browser/anythingQuickAccess';
import { ISymbolQuickPickItem, SymbolsQuickAccessProvider } from 'vs/workbench/contrib/search/browser/symbolsQuickAccess';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { EditorType } from 'vs/editor/common/editorCommon';
export function registerChatContextActions() {
registerAction2(AttachContextAction);
registerAction2(AttachFileAction);
registerAction2(AttachSelectionAction);
}
export type IChatContextQuickPickItem = IFileQuickPickItem | IDynamicVariableQuickPickItem | IStaticVariableQuickPickItem | IGotoSymbolQuickPickItem | ISymbolQuickPickItem | IQuickAccessQuickPickItem;
@@ -77,6 +81,58 @@ export interface IQuickAccessQuickPickItem extends IQuickPickItem {
prefix: string;
}
class AttachFileAction extends Action2 {
static readonly ID = 'workbench.action.chat.attachFile';
constructor() {
super({
id: AttachFileAction.ID,
title: localize2('workbench.action.chat.attachFile.label', "Attach File"),
category: CHAT_CATEGORY,
f1: false
});
}
override async run(accessor: ServicesAccessor, ...args: any[]): Promise<void> {
const variablesService = accessor.get(IChatVariablesService);
const textEditorService = accessor.get(IEditorService);
const activeUri = textEditorService.activeEditor?.resource;
if (textEditorService.activeTextEditorControl?.getEditorType() === EditorType.ICodeEditor && activeUri && [Schemas.file, Schemas.vscodeRemote].includes(activeUri.scheme)) {
variablesService.attachContext('file', activeUri, ChatAgentLocation.Panel);
}
}
}
class AttachSelectionAction extends Action2 {
static readonly ID = 'workbench.action.chat.attachSelection';
constructor() {
super({
id: AttachSelectionAction.ID,
title: localize2('workbench.action.chat.attachSelection.label', "Add Selection to Chat"),
category: CHAT_CATEGORY,
f1: false
});
}
override async run(accessor: ServicesAccessor, ...args: any[]): Promise<void> {
const variablesService = accessor.get(IChatVariablesService);
const textEditorService = accessor.get(IEditorService);
const activeEditor = textEditorService.activeTextEditorControl;
const activeUri = textEditorService.activeEditor?.resource;
if (textEditorService.activeTextEditorControl?.getEditorType() === EditorType.ICodeEditor && activeUri && [Schemas.file, Schemas.vscodeRemote].includes(activeUri.scheme)) {
const selection = activeEditor?.getSelection();
if (selection) {
variablesService.attachContext('file', { uri: activeUri, range: selection }, ChatAgentLocation.Panel);
}
}
}
}
class AttachContextAction extends Action2 {
static readonly ID = 'workbench.action.chat.attachContext';
@@ -105,6 +105,10 @@ interface IItemHeightChangeParams {
height: number;
}
interface IChatMarkdownRenderResult extends IMarkdownRenderResult {
codeBlockCount: number;
}
const forceVerboseLayoutTracing = false;
export interface IChatRendererDelegate {
@@ -481,11 +485,12 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
this.renderContentReferencesIfNeeded(element, templateData, templateData.elementDisposables);
let fileTreeIndex = 0;
let codeBlockIndex = 0;
value.forEach((data, index) => {
const result = data.kind === 'treeData'
? this.renderTreeData(data.treeData, element, templateData, fileTreeIndex++)
: data.kind === 'markdownContent'
? this.renderMarkdown(data.content, element, templateData, fillInIncompleteTokens)
? this.renderMarkdown(data.content, element, templateData, fillInIncompleteTokens, codeBlockIndex)
: data.kind === 'progressMessage' && onlyProgressMessagesAfterI(value, index) ? this.renderProgressMessage(data, false) // TODO render command
: data.kind === 'progressTask' ? this.renderProgressTask(data, false, element, templateData)
: data.kind === 'command' ? this.renderCommandButton(element, data)
@@ -497,6 +502,10 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
if (result) {
templateData.value.appendChild(result.element);
templateData.elementDisposables.add(result);
if ('codeBlockCount' in result) {
codeBlockIndex += (result as IChatMarkdownRenderResult).codeBlockCount;
}
}
});
@@ -1119,13 +1128,13 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
};
}
private renderMarkdown(markdown: IMarkdownString, element: ChatTreeItem, templateData: IChatListItemTemplate, fillInIncompleteTokens = false): IMarkdownRenderResult {
private renderMarkdown(markdown: IMarkdownString, element: ChatTreeItem, templateData: IChatListItemTemplate, fillInIncompleteTokens = false, codeBlockStartIndex = 0): IChatMarkdownRenderResult {
const disposables = new DisposableStore();
// We release editors in order so that it's more likely that the same editor will be assigned if this element is re-rendered right away, like it often is during progressive rendering
const orderedDisposablesList: IDisposable[] = [];
const codeblocks: IChatCodeBlockInfo[] = [];
let codeBlockIndex = 0;
let codeBlockIndex = codeBlockStartIndex;
const result = this.renderer.render(markdown, {
fillInIncompleteTokens,
codeBlockRendererSync: (languageId, text) => {
@@ -1193,6 +1202,7 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
orderedDisposablesList.reverse().forEach(d => disposables.add(d));
return {
codeBlockCount: codeBlockIndex - codeBlockStartIndex,
element: result.element,
dispose() {
result.dispose();
@@ -29,8 +29,6 @@ import { KeybindingLabel } from 'vs/base/browser/ui/keybindingLabel/keybindingLa
import { OS } from 'vs/base/common/platform';
import { status } from 'vs/base/browser/ui/aria/aria';
import { AccessibilityVerbositySettingId } from 'vs/workbench/contrib/accessibility/browser/accessibilityConfiguration';
import { Registry } from 'vs/platform/registry/common/platform';
import { Extensions, IConfigurationMigrationRegistry } from 'vs/workbench/common/configuration';
import { LOG_MODE_ID, OUTPUT_MODE_ID } from 'vs/workbench/services/output/common/output';
import { SEARCH_RESULT_LANGUAGE_ID } from 'vs/workbench/services/search/common/search';
import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegateFactory';
@@ -39,23 +37,6 @@ import { ChatAgentLocation, IChatAgent, IChatAgentService } from 'vs/workbench/c
const $ = dom.$;
// TODO@joyceerhl remove this after a few iterations
Registry.as<IConfigurationMigrationRegistry>(Extensions.ConfigurationMigration)
.registerConfigurationMigrations([{
key: 'workbench.editor.untitled.hint',
migrateFn: (value, _accessor) => ([
[emptyTextEditorHintSetting, { value }],
['workbench.editor.untitled.hint', { value: undefined }]
])
},
{
key: 'accessibility.verbosity.untitledHint',
migrateFn: (value, _accessor) => ([
[AccessibilityVerbositySettingId.EmptyEditorHint, { value }],
['accessibility.verbosity.untitledHint', { value: undefined }]
])
}]);
export interface IEmptyTextEditorHintOptions {
readonly clickable?: boolean;
}
@@ -218,6 +199,12 @@ class EmptyTextEditorHintContentWidget implements IContentWidget {
return EmptyTextEditorHintContentWidget.ID;
}
private _disableHint() {
this.configurationService.updateValue(emptyTextEditorHintSetting, 'hidden');
this.dispose();
this.editor.focus();
}
private _getHintInlineChat(providers: IChatAgent[]) {
const providerName = (providers.length === 1 ? providers[0].fullName : undefined) ?? this.productService.nameShort;
@@ -257,6 +244,7 @@ class EmptyTextEditorHintContentWidget implements IContentWidget {
const hintPart = $('a', undefined, fragment);
hintPart.style.fontStyle = 'italic';
hintPart.style.cursor = 'pointer';
this.toDispose.add(dom.addDisposableListener(label.element, dom.EventType.CONTEXT_MENU, () => this._disableHint()));
this.toDispose.add(dom.addDisposableListener(hintPart, dom.EventType.CLICK, handleClick));
return hintPart;
} else {
@@ -275,6 +263,7 @@ class EmptyTextEditorHintContentWidget implements IContentWidget {
if (this.options.clickable) {
label.element.style.cursor = 'pointer';
this.toDispose.add(dom.addDisposableListener(label.element, dom.EventType.CONTEXT_MENU, () => this._disableHint()));
this.toDispose.add(dom.addDisposableListener(label.element, dom.EventType.CLICK, handleClick));
}
@@ -297,7 +286,7 @@ class EmptyTextEditorHintContentWidget implements IContentWidget {
hintElement.appendChild(rendered);
}
return { ariaLabel, hintHandler, hintElement };
return { ariaLabel, hintElement };
}
private _getHintDefault() {
@@ -315,7 +304,7 @@ class EmptyTextEditorHintContentWidget implements IContentWidget {
chooseEditorOnClickOrTap(event.browserEvent);
break;
case '3':
dontShowOnClickOrTap();
this._disableHint();
break;
}
}
@@ -360,12 +349,6 @@ class EmptyTextEditorHintContentWidget implements IContentWidget {
}
};
const dontShowOnClickOrTap = () => {
this.configurationService.updateValue(emptyTextEditorHintSetting, 'hidden');
this.dispose();
this.editor.focus();
};
const hintMsg = localize({
key: 'message',
comment: [
@@ -264,7 +264,7 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi
}
private createTriggerBreakpointInput(container: HTMLElement) {
const breakpoints = this.debugService.getModel().getBreakpoints().filter(bp => bp !== this.breakpoint);
const breakpoints = this.debugService.getModel().getBreakpoints().filter(bp => bp !== this.breakpoint && !bp.logMessage);
const breakpointOptions: ISelectOptionItem[] = [
{ text: nls.localize('noTriggerByBreakpoint', 'None'), isDisabled: true },
...breakpoints.map(bp => ({
@@ -433,12 +433,12 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi
if (success) {
// if there is already a breakpoint on this location - remove it.
let condition = this.breakpoint?.condition;
let hitCondition = this.breakpoint?.hitCondition;
let logMessage = this.breakpoint?.logMessage;
let triggeredBy = this.breakpoint?.triggeredBy;
let mode = this.breakpoint?.mode;
let modeLabel = this.breakpoint?.modeLabel;
let condition: string | undefined = undefined;
let hitCondition: string | undefined = undefined;
let logMessage: string | undefined = undefined;
let triggeredBy: string | undefined = undefined;
let mode: string | undefined = undefined;
let modeLabel: string | undefined = undefined;
this.rememberInput();
@@ -1643,7 +1643,7 @@ registerAction2(class extends Action2 {
} else if (breakpoint instanceof DataBreakpoint) {
await debugService.removeDataBreakpoints(breakpoint.getId());
} else if (breakpoint instanceof InstructionBreakpoint) {
await debugService.removeInstructionBreakpoints(breakpoint.instructionReference);
await debugService.removeInstructionBreakpoints(breakpoint.instructionReference, breakpoint.offset);
}
}
});
@@ -6,6 +6,7 @@
import { addDisposableListener, isKeyboardEvent } from 'vs/base/browser/dom';
import { DomEmitter } from 'vs/base/browser/event';
import { IKeyboardEvent, StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
import { distinct } from 'vs/base/common/arrays';
import { RunOnceScheduler } from 'vs/base/common/async';
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
@@ -208,7 +209,7 @@ export class DebugEditorContribution implements IDebugEditorContribution {
private toDispose: IDisposable[];
private hoverWidget: DebugHoverWidget;
private hoverPosition: Position | null = null;
private hoverPosition?: { position: Position; event: IMouseEvent };
private mouseDown = false;
private exceptionWidgetVisible: IContextKey<boolean>;
private gutterIsHovered = false;
@@ -341,7 +342,7 @@ export class DebugEditorContribution implements IDebugEditorContribution {
if (debugHoverWasVisible && this.hoverPosition) {
// If the debug hover was visible immediately show the editor hover for the alt transition to be smooth
this.showEditorHover(this.hoverPosition, false);
this.showEditorHover(this.hoverPosition.position, false);
}
const onKeyUp = new DomEmitter(ownerDocument, 'keyup');
@@ -361,14 +362,14 @@ export class DebugEditorContribution implements IDebugEditorContribution {
});
}
async showHover(position: Position, focus: boolean): Promise<void> {
async showHover(position: Position, focus: boolean, mouseEvent?: IMouseEvent): Promise<void> {
// normally will already be set in `showHoverScheduler`, but public callers may hit this directly:
this.preventDefaultEditorHover();
const sf = this.debugService.getViewModel().focusedStackFrame;
const model = this.editor.getModel();
if (sf && model && this.uriIdentityService.extUri.isEqual(sf.source.uri, model.uri)) {
const result = await this.hoverWidget.showAt(position, focus);
const result = await this.hoverWidget.showAt(position, focus, mouseEvent);
if (result === ShowDebugHoverResult.NOT_AVAILABLE) {
// When no expression available fallback to editor hover
this.showEditorHover(position, focus);
@@ -438,7 +439,7 @@ export class DebugEditorContribution implements IDebugEditorContribution {
private get showHoverScheduler() {
const scheduler = new RunOnceScheduler(() => {
if (this.hoverPosition && !this.altPressed) {
this.showHover(this.hoverPosition, false);
this.showHover(this.hoverPosition.position, false, this.hoverPosition.event);
}
}, this.hoverDelay);
this.toDispose.push(scheduler);
@@ -493,8 +494,8 @@ export class DebugEditorContribution implements IDebugEditorContribution {
}
if (target.type === MouseTargetType.CONTENT_TEXT) {
if (target.position && !Position.equals(target.position, this.hoverPosition)) {
this.hoverPosition = target.position;
if (target.position && !Position.equals(target.position, this.hoverPosition?.position || null) && !this.hoverWidget.isInSafeTriangle(mouseEvent.event.posx, mouseEvent.event.posy)) {
this.hoverPosition = { position: target.position, event: mouseEvent.event };
// Disable the editor hover during the request to avoid flickering
this.preventDefaultEditorHover();
this.showHoverScheduler.schedule(this.hoverDelay);
@@ -5,6 +5,7 @@
import * as dom from 'vs/base/browser/dom';
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
import { IListAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
@@ -83,6 +84,7 @@ export class DebugHoverWidget implements IContentWidget {
readonly allowEditorOverflow = true;
private _isVisible: boolean;
private safeTriangle?: dom.SafeTriangle;
private showCancellationSource?: CancellationTokenSource;
private domNode!: HTMLElement;
private tree!: AsyncDataTree<IExpression, IExpression, any>;
@@ -228,7 +230,15 @@ export class DebugHoverWidget implements IContentWidget {
return this.domNode;
}
async showAt(position: Position, focus: boolean): Promise<void | ShowDebugHoverResult> {
/**
* Gets whether the given coordinates are in the safe triangle formed from
* the position at which the hover was initiated.
*/
isInSafeTriangle(x: number, y: number) {
return this._isVisible && !!this.safeTriangle?.contains(x, y);
}
async showAt(position: Position, focus: boolean, mouseEvent?: IMouseEvent): Promise<void | ShowDebugHoverResult> {
this.showCancellationSource?.cancel();
const cancellationSource = this.showCancellationSource = new CancellationTokenSource();
const session = this.debugService.getViewModel().focusedSession;
@@ -269,7 +279,7 @@ export class DebugHoverWidget implements IContentWidget {
options: DebugHoverWidget._HOVER_HIGHLIGHT_DECORATION_OPTIONS
}]);
return this.doShow(result.range.getStartPosition(), expression, focus);
return this.doShow(result.range.getStartPosition(), expression, focus, mouseEvent);
}
private static readonly _HOVER_HIGHLIGHT_DECORATION_OPTIONS = ModelDecorationOptions.register({
@@ -277,7 +287,7 @@ export class DebugHoverWidget implements IContentWidget {
className: 'hoverHighlight'
});
private async doShow(position: Position, expression: IExpression, focus: boolean, forceValueHover = false): Promise<void> {
private async doShow(position: Position, expression: IExpression, focus: boolean, mouseEvent: IMouseEvent | undefined): Promise<void> {
if (!this.domNode) {
this.create();
}
@@ -285,7 +295,7 @@ export class DebugHoverWidget implements IContentWidget {
this.showAtPosition = position;
this._isVisible = true;
if (!expression.hasChildren || forceValueHover) {
if (!expression.hasChildren) {
this.complexValueContainer.hidden = true;
this.valueContainer.hidden = false;
renderExpressionValue(expression, this.valueContainer, {
@@ -312,6 +322,7 @@ export class DebugHoverWidget implements IContentWidget {
this.tree.scrollTop = 0;
this.tree.scrollLeft = 0;
this.complexValueContainer.hidden = false;
this.safeTriangle = mouseEvent && new dom.SafeTriangle(mouseEvent.posx, mouseEvent.posy, this.domNode);
if (focus) {
this.editor.render();
@@ -816,7 +816,7 @@ Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration).regis
},
['interactiveWindow.executeWithShiftEnter']: {
type: 'boolean',
default: true,
default: false,
markdownDescription: localize('interactiveWindow.executeWithShiftEnter', "Execute the interactive window (REPL) input box with shift+enter, so that enter can be used to create a newline.")
}
}
@@ -697,6 +697,14 @@ export class NotebookService extends Disposable implements INotebookService {
return result;
}
tryGetDataProviderSync(viewType: string): SimpleNotebookProviderInfo | undefined {
const selected = this.notebookProviderInfoStore.get(viewType);
if (!selected) {
return undefined;
}
return this._notebookProviders.get(selected.id);
}
private _persistMementos(): void {
this._memento.saveMemento();
@@ -436,7 +436,7 @@ export class BackLayerWebView<T extends ICommonCellInfo> extends Themable {
}
table, thead, tr, th, td, tbody {
border: none !important;
border: none;
border-color: transparent;
border-spacing: 0;
border-collapse: collapse;
@@ -15,6 +15,7 @@ import { assertType } from 'vs/base/common/types';
import { URI } from 'vs/base/common/uri';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IWriteFileOptions, IFileStatWithMetadata } from 'vs/platform/files/common/files';
import { ILogService } from 'vs/platform/log/common/log';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IRevertOptions, ISaveOptions, IUntypedEditorInput } from 'vs/workbench/common/editor';
import { EditorModel } from 'vs/workbench/common/editor/editorModel';
@@ -197,7 +198,8 @@ export class NotebookFileWorkingCopyModel extends Disposable implements IStoredF
private readonly _notebookModel: NotebookTextModel,
private readonly _notebookService: INotebookService,
private readonly _configurationService: IConfigurationService,
private readonly _telemetryService: ITelemetryService
private readonly _telemetryService: ITelemetryService,
private readonly _logService: ILogService
) {
super();
@@ -237,13 +239,22 @@ export class NotebookFileWorkingCopyModel extends Disposable implements IStoredF
}
private async setSaveDelegate() {
const serializer = await this.getNotebookSerializer();
this.save = async (options: IWriteFileOptions, token: CancellationToken) => {
if (token.isCancellationRequested) {
throw new CancellationError();
}
// make sure we wait for a serializer to resolve before we try to handle saves in the EH
await this.getNotebookSerializer();
this.save = async (options: IWriteFileOptions, token: CancellationToken) => {
try {
let serializer = this._notebookService.tryGetDataProviderSync(this.notebookModel.viewType)?.serializer;
if (!serializer) {
this._logService.warn('No serializer found for notebook model, checking if provider still needs to be resolved');
serializer = await this.getNotebookSerializer();
}
if (token.isCancellationRequested) {
throw new CancellationError();
}
const stat = await serializer.save(this._notebookModel.uri, this._notebookModel.versionId, options, token);
return stat;
} catch (error) {
@@ -358,7 +369,8 @@ export class NotebookFileWorkingCopyModelFactory implements IStoredFileWorkingCo
private readonly _viewType: string,
@INotebookService private readonly _notebookService: INotebookService,
@IConfigurationService private readonly _configurationService: IConfigurationService,
@ITelemetryService private readonly _telemetryService: ITelemetryService
@ITelemetryService private readonly _telemetryService: ITelemetryService,
@ILogService private readonly _logService: ILogService
) { }
async createModel(resource: URI, stream: VSBufferReadableStream, token: CancellationToken): Promise<NotebookFileWorkingCopyModel> {
@@ -376,7 +388,7 @@ export class NotebookFileWorkingCopyModelFactory implements IStoredFileWorkingCo
}
const notebookModel = this._notebookService.createNotebookTextModel(info.viewType, resource, data, info.serializer.options);
return new NotebookFileWorkingCopyModel(notebookModel, this._notebookService, this._configurationService, this._telemetryService);
return new NotebookFileWorkingCopyModel(notebookModel, this._notebookService, this._configurationService, this._telemetryService, this._logService);
}
}
@@ -70,7 +70,7 @@ class NotebookModelReferenceCollection extends ReferenceCollection<Promise<IReso
const workingCopyTypeId = NotebookWorkingCopyTypeIdentifier.create(viewType);
let workingCopyManager = this._workingCopyManagers.get(workingCopyTypeId);
if (!workingCopyManager) {
const factory = new NotebookFileWorkingCopyModelFactory(viewType, this._notebookService, this._configurationService, this._telemetryService);
const factory = new NotebookFileWorkingCopyModelFactory(viewType, this._notebookService, this._configurationService, this._telemetryService, this._logService);
workingCopyManager = <IFileWorkingCopyManager<NotebookFileWorkingCopyModel, NotebookFileWorkingCopyModel>><any>this._instantiationService.createInstance(
FileWorkingCopyManager,
workingCopyTypeId,
@@ -65,6 +65,7 @@ export interface INotebookService {
registerNotebookSerializer(viewType: string, extensionData: NotebookExtensionDescription, serializer: INotebookSerializer): IDisposable;
withNotebookDataProvider(viewType: string): Promise<SimpleNotebookProviderInfo>;
tryGetDataProviderSync(viewType: string): SimpleNotebookProviderInfo | undefined;
getOutputMimeTypeInfo(textModel: NotebookTextModel, kernelProvides: readonly string[] | undefined, output: IOutputDto): readonly IOrderedMimeType[];
@@ -15,6 +15,7 @@ import { TestConfigurationService } from 'vs/platform/configuration/test/common/
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { IFileStatWithMetadata } from 'vs/platform/files/common/files';
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
import { ILogService } from 'vs/platform/log/common/log';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
import { CellKind, IOutputDto, NotebookData, NotebookSetting, TransientOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon';
@@ -28,7 +29,10 @@ suite('NotebookFileWorkingCopyModel', function () {
let disposables: DisposableStore;
let instantiationService: TestInstantiationService;
const configurationService = new TestConfigurationService();
const telemetryService = new class extends mock<ITelemetryService>() { };
const telemetryService = new class extends mock<ITelemetryService>() {
override publicLogError2() { }
};
const logservice = new class extends mock<ILogService>() { };
teardown(() => disposables.dispose());
@@ -65,7 +69,8 @@ suite('NotebookFileWorkingCopyModel', function () {
}
),
configurationService,
telemetryService
telemetryService,
logservice
));
await model.snapshot(SnapshotContext.Save, CancellationToken.None);
@@ -88,7 +93,8 @@ suite('NotebookFileWorkingCopyModel', function () {
}
),
configurationService,
telemetryService
telemetryService,
logservice
));
await model.snapshot(SnapshotContext.Save, CancellationToken.None);
assert.strictEqual(callCount, 1);
@@ -123,7 +129,8 @@ suite('NotebookFileWorkingCopyModel', function () {
}
),
configurationService,
telemetryService
telemetryService,
logservice
));
await model.snapshot(SnapshotContext.Save, CancellationToken.None);
@@ -147,6 +154,7 @@ suite('NotebookFileWorkingCopyModel', function () {
),
configurationService,
telemetryService,
logservice
));
await model.snapshot(SnapshotContext.Save, CancellationToken.None);
@@ -181,7 +189,8 @@ suite('NotebookFileWorkingCopyModel', function () {
}
),
configurationService,
telemetryService
telemetryService,
logservice
));
await model.snapshot(SnapshotContext.Save, CancellationToken.None);
@@ -204,7 +213,8 @@ suite('NotebookFileWorkingCopyModel', function () {
}
),
configurationService,
telemetryService
telemetryService,
logservice
));
await model.snapshot(SnapshotContext.Save, CancellationToken.None);
assert.strictEqual(callCount, 1);
@@ -239,7 +249,8 @@ suite('NotebookFileWorkingCopyModel', function () {
}
),
configurationService,
telemetryService
telemetryService,
logservice
));
try {
@@ -282,7 +293,8 @@ suite('NotebookFileWorkingCopyModel', function () {
notebook,
notebookService,
configurationService,
telemetryService
telemetryService,
logservice
));
// the save method should not be set if the serializer is not yet resolved
@@ -299,11 +311,25 @@ suite('NotebookFileWorkingCopyModel', function () {
function mockNotebookService(notebook: NotebookTextModel, notebookSerializer: Promise<INotebookSerializer> | INotebookSerializer) {
return new class extends mock<INotebookService>() {
private serializer: INotebookSerializer | undefined = undefined;
override async withNotebookDataProvider(viewType: string): Promise<SimpleNotebookProviderInfo> {
const serializer = await notebookSerializer;
this.serializer = await notebookSerializer;
return new SimpleNotebookProviderInfo(
notebook.viewType,
serializer,
this.serializer,
{
id: new ExtensionIdentifier('test'),
location: undefined
}
);
}
override tryGetDataProviderSync(viewType: string): SimpleNotebookProviderInfo | undefined {
if (!this.serializer) {
return undefined;
}
return new SimpleNotebookProviderInfo(
notebook.viewType,
this.serializer,
{
id: new ExtensionIdentifier('test'),
location: undefined
@@ -136,7 +136,7 @@ export class FolderMatchRenderer extends Disposable implements ICompressibleTree
SearchContext.FileFocusKey.bindTo(contextKeyServiceMain).set(false);
SearchContext.FolderFocusKey.bindTo(contextKeyServiceMain).set(true);
const instantiationService = this.instantiationService.createChild(new ServiceCollection([IContextKeyService, contextKeyServiceMain]));
const instantiationService = this._register(this.instantiationService.createChild(new ServiceCollection([IContextKeyService, contextKeyServiceMain])));
const actions = disposables.add(instantiationService.createInstance(MenuWorkbenchToolBar, actionBarContainer, MenuId.SearchActionMenu, {
menuOptions: {
shouldForwardArgs: true
@@ -237,8 +237,8 @@ export class SearchView extends ViewPane {
this.inputPatternExclusionsFocused = Constants.SearchContext.PatternExcludesFocusedKey.bindTo(this.contextKeyService);
this.isEditableItem = Constants.SearchContext.IsEditableItemKey.bindTo(this.contextKeyService);
this.instantiationService = this.instantiationService.createChild(
new ServiceCollection([IContextKeyService, this.contextKeyService]));
this.instantiationService = this._register(this.instantiationService.createChild(
new ServiceCollection([IContextKeyService, this.contextKeyService])));
this._register(this.configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('search.sortOrder')) {
@@ -141,7 +141,7 @@ export class SearchEditor extends AbstractTextCodeEditor<SearchEditorViewState>
this.createQueryEditor(
this.queryEditorContainer,
this.instantiationService.createChild(new ServiceCollection([IContextKeyService, scopedContextKeyService])),
this._register(this.instantiationService.createChild(new ServiceCollection([IContextKeyService, scopedContextKeyService]))),
SearchContext.InputBoxFocusedKey.bindTo(scopedContextKeyService)
);
}
@@ -269,6 +269,9 @@ export async function showRunRecentQuickPick(
return;
}
const [item] = quickPick.activeItems;
if (!item) {
return;
}
if ('command' in item && item.command && item.command.marker) {
if (!terminalScrollStateSaved) {
xterm.markTracker.saveScrollState();
@@ -29,9 +29,14 @@ import { TerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal
import 'vs/css!./media/terminalInitialHint';
import { TerminalInitialHintSettingId } from 'vs/workbench/contrib/terminalContrib/chat/common/terminalInitialHintConfiguration';
import { ChatAgentLocation, IChatAgent, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
const $ = dom.$;
const enum Constants {
InitialHintHideStorageKey = 'terminal.initialHint.hide'
}
export class InitialHintAddon extends Disposable implements ITerminalAddon {
private readonly _onDidRequestCreateHint = this._register(new Emitter<void>());
get onDidRequestCreateHint(): Event<void> { return this._onDidRequestCreateHint.event; }
@@ -90,11 +95,22 @@ export class TerminalInitialHintContribution extends Disposable implements ITerm
@ITerminalGroupService private readonly _terminalGroupService: ITerminalGroupService,
@ITerminalEditorService private readonly _terminalEditorService: ITerminalEditorService,
@IChatAgentService private readonly _chatAgentService: IChatAgentService,
@IStorageService private readonly _storageService: IStorageService,
) {
super();
// Reset hint state when config changes
this._register(this._configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration(TerminalInitialHintSettingId.Enabled)) {
this._storageService.remove(Constants.InitialHintHideStorageKey, StorageScope.APPLICATION);
}
}));
}
xtermOpen(xterm: IXtermTerminal & { raw: RawXtermTerminal }): void {
if (this._storageService.getBoolean(Constants.InitialHintHideStorageKey, StorageScope.APPLICATION, false)) {
return;
}
if (this._terminalGroupService.instances.length + this._terminalEditorService.instances.length !== 1) {
// only show for the first terminal
return;
@@ -108,7 +124,7 @@ export class TerminalInitialHintContribution extends Disposable implements ITerm
private _createHint(): void {
const instance = this._instance instanceof TerminalInstance ? this._instance : undefined;
const commandDetectionCapability = instance?.capabilities.get(TerminalCapability.CommandDetection);
if (!instance || !this._xterm || this._hintWidget || !commandDetectionCapability || commandDetectionCapability.promptInputModel.value || instance.reconnectionProperties) {
if (!instance || !this._xterm || this._hintWidget || !commandDetectionCapability || commandDetectionCapability.promptInputModel.value || !!instance.shellLaunchConfig.attachPersistentProcess) {
return;
}
@@ -199,7 +215,8 @@ class TerminalInitialHintWidget extends Disposable {
@IKeybindingService private readonly keybindingService: IKeybindingService,
@ITelemetryService private readonly telemetryService: ITelemetryService,
@IProductService private readonly productService: IProductService,
@ITerminalService private readonly terminalService: ITerminalService
@ITerminalService private readonly terminalService: ITerminalService,
@IStorageService private readonly _storageService: IStorageService
) {
super();
this.toDispose.add(_instance.onDidFocus(() => {
@@ -229,6 +246,7 @@ class TerminalInitialHintWidget extends Disposable {
let ariaLabel = `Ask ${providerName} something or start typing to dismiss.`;
const handleClick = () => {
this._storageService.store(Constants.InitialHintHideStorageKey, true, StorageScope.APPLICATION, StorageTarget.USER);
this.telemetryService.publicLog2<WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification>('workbenchActionExecuted', {
id: 'terminalInlineChat.hintAction',
from: 'hint'
@@ -223,9 +223,11 @@ export class TreeProjection extends Disposable implements ITestTreeProjection {
break;
}
// The first element will cause the root to be hidden
// Removing the first element will cause the root to be hidden.
// Changing first-level elements will need the root to re-render if
// there are no other controllers with items.
const parent = toRemove.parent;
const affectsRootElement = toRemove.depth === 1 && parent?.children.size === 1;
const affectsRootElement = toRemove.depth === 1 && (parent?.children.size === 1 || !Iterable.some(this.rootsWithChildren, (_, i) => i === 1));
this.changedParents.add(affectsRootElement ? null : parent);
const queue: Iterable<TestExplorerTreeElement>[] = [[toRemove]];
@@ -267,4 +267,52 @@ suite('Workbench - Testing Explorer Hierarchal by Location Projection', () => {
]);
});
test('fixes #213316 (single root)', async () => {
harness.flush();
assert.deepStrictEqual(harness.tree.getRendered(), [
{ e: 'a' }, { e: 'b' }
]);
harness.pushDiff({
op: TestDiffOpType.Remove,
itemId: new TestId(['ctrlId', 'id-a']).toString(),
});
harness.flush();
assert.deepStrictEqual(harness.tree.getRendered(), [
{ e: 'b' }
]);
});
test('fixes #213316 (multi root)', async () => {
harness.pushDiff({
op: TestDiffOpType.Add,
item: { controllerId: 'ctrl2', expand: TestItemExpandState.Expanded, item: new TestTestItem(new TestId(['ctrlId2']), 'c').toTestItem() },
}, {
op: TestDiffOpType.Add,
item: { controllerId: 'ctrl2', expand: TestItemExpandState.NotExpandable, item: new TestTestItem(new TestId(['ctrlId2', 'id-c']), 'ca').toTestItem() },
});
harness.flush();
assert.deepStrictEqual(harness.flush(), [
{ e: 'c', children: [{ e: 'ca' }] },
{ e: 'root', children: [{ e: 'a' }, { e: 'b' }] }
]);
harness.pushDiff({
op: TestDiffOpType.Remove,
itemId: new TestId(['ctrlId', 'id-a']).toString(),
});
harness.flush();
assert.deepStrictEqual(harness.tree.getRendered(), [
{ e: 'c', children: [{ e: 'ca' }] },
{ e: 'root', children: [{ e: 'b' }] }
]);
harness.pushDiff({
op: TestDiffOpType.Remove,
itemId: new TestId(['ctrlId', 'id-b']).toString(),
});
harness.flush();
assert.deepStrictEqual(harness.tree.getRendered(), [
{ e: 'ca' }
]);
});
});
@@ -465,6 +465,6 @@ function handleParentFolder(key: string, selectors: string[]): string {
}
function escapeCSS(str: string) {
str = str.replace(/[\11\12\14\15\40]/g, '/'); // HTML class names can not contain certain whitespace characters, use / instead, which doesn't exist in file names.
str = str.replace(/[\x11\x12\x14\x15\x40]/g, '/'); // HTML class names can not contain certain whitespace characters, use / instead, which doesn't exist in file names.
return mainWindow.CSS.escape(str);
}
@@ -68,11 +68,11 @@ export class TunnelService extends AbstractTunnelService {
super(logService, configurationService);
// Destroy any shared process tunnels that might still be active
lifecycleService.onDidShutdown(() => {
this._register(lifecycleService.onDidShutdown(() => {
this._activeSharedProcessTunnels.forEach((id) => {
this._sharedProcessTunnelService.destroyTunnel(id);
});
});
}));
}
public isPortPrivileged(port: number): boolean {
@@ -19,15 +19,6 @@ declare module 'vscode' {
* @param icon An icon to display when selecting context in the picker UI.
*/
export function registerChatVariableResolver(id: string, name: string, userDescription: string, modelDescription: string | undefined, isSlow: boolean | undefined, resolver: ChatVariableResolver, fullName?: string, icon?: ThemeIcon): Disposable;
/**
* Attaches a chat context with the specified name, value, and location.
*
* @param name - The name of the chat context.
* @param value - The value of the chat context.
* @param location - The location of the chat context.
*/
export function attachContext(name: string, value: string | Uri | Location | unknown, location: ChatLocation.Panel): void;
}
export interface ChatVariableValue {
+36 -36
View File
@@ -1982,40 +1982,40 @@
resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-2.0.5.tgz#325db42395cd49fe6c14057f9a900e427df8810e"
integrity sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==
"@xterm/addon-image@0.9.0-beta.17":
version "0.9.0-beta.17"
resolved "https://registry.yarnpkg.com/@xterm/addon-image/-/addon-image-0.9.0-beta.17.tgz#343d0665a6060d4f893b4f2d32de6ccbbd00bb63"
integrity sha512-g0r2hpBcLABY5as4llsMP36RHtkWooEn7tf+7U0/hTndJoCAvs4uGDqZNQigFgeAM3lJ4PnRYh4lfnEh9bGt8A==
"@xterm/addon-image@0.9.0-beta.19":
version "0.9.0-beta.19"
resolved "https://registry.yarnpkg.com/@xterm/addon-image/-/addon-image-0.9.0-beta.19.tgz#3823382e5c55268998f0e0d8d77e8b7810925830"
integrity sha512-LX9g03po3mXYE/HZFoKbdnIRvdD56Qw84FpQ9LCJGDsyx9SFIf47DXLS+lXCEpJ2hjKIing46BQxP+MDEayXDw==
"@xterm/addon-search@0.16.0-beta.17":
version "0.16.0-beta.17"
resolved "https://registry.yarnpkg.com/@xterm/addon-search/-/addon-search-0.16.0-beta.17.tgz#7cb01c7f498405909d37040884ee22d1889a36d2"
integrity sha512-wBfxmWOeqG6HHHE5mVamDJ75zBdHC35ERNy5/aTpQsQsyxrnV0Ks76c8ZVTaTu9wyBCAyx7UmZT42Ot80khY/g==
"@xterm/addon-search@0.16.0-beta.19":
version "0.16.0-beta.19"
resolved "https://registry.yarnpkg.com/@xterm/addon-search/-/addon-search-0.16.0-beta.19.tgz#46b3374eb312a1bff974a5df188b1ebf777ff49d"
integrity sha512-iTJVUEsKSdL8SyhcDBqN6gYxhqv0wrwtP1QCUGLKNAAVDI7HKVgig3V9wToqRxYfOnu/anyU+u0qFUoKCRLnCg==
"@xterm/addon-serialize@0.14.0-beta.17":
version "0.14.0-beta.17"
resolved "https://registry.yarnpkg.com/@xterm/addon-serialize/-/addon-serialize-0.14.0-beta.17.tgz#1cb8e35c0d118060a807adb340624fa7f80dd9c5"
integrity sha512-/c3W39kdRgGGYDoYjXb5HrUC421qwPn6NryAT4WJuJWnyMtFbe2DPwKsTfHuCBPiPyovS3a9j950Md3O3YXDZA==
"@xterm/addon-serialize@0.14.0-beta.19":
version "0.14.0-beta.19"
resolved "https://registry.yarnpkg.com/@xterm/addon-serialize/-/addon-serialize-0.14.0-beta.19.tgz#c7a0a0e5f5b1bd94a35a775ec6224ba42282556c"
integrity sha512-D+BiXQfuxDb3azAIBq1RJTQGZlvo459V6U/2s/3dKpTAvRybqCRMazuf8cLoffUoNcjTb3uSWpii9+MVVvHIrQ==
"@xterm/addon-unicode11@0.9.0-beta.17":
version "0.9.0-beta.17"
resolved "https://registry.yarnpkg.com/@xterm/addon-unicode11/-/addon-unicode11-0.9.0-beta.17.tgz#b5558148029a796c6a6d78e2a8b7255f92a51530"
integrity sha512-z7v8uojFVrO1aLSWtnz5MzSrfWRT8phde7kh9ufqHLBv7YYtMHxlPVjSuW8PZ2h4eY1LOZf6icUAzrmyJmJ7Kg==
"@xterm/addon-unicode11@0.9.0-beta.19":
version "0.9.0-beta.19"
resolved "https://registry.yarnpkg.com/@xterm/addon-unicode11/-/addon-unicode11-0.9.0-beta.19.tgz#529d8b22d9378cff8c31df1b7e76250b2f8079c3"
integrity sha512-0Umiu9GkjwL/jaT85Rcfka9HVyJw3UhJsnOVOVZd/3YBZqMY2SZMHqz73W/qpXl5nz6vvyCWKbpkfddsJhpToA==
"@xterm/addon-webgl@0.19.0-beta.17":
version "0.19.0-beta.17"
resolved "https://registry.yarnpkg.com/@xterm/addon-webgl/-/addon-webgl-0.19.0-beta.17.tgz#68ad9e68dd1cf581b391971de33f5c04966b0d8e"
integrity sha512-X8ObRgoZl7UZTgdndM+mpSO3hLzAhWKoXXrGvUQg/7XabRKAPrQ2XvdyZm04nYwibE6Tpit2h5kkxjlVqupIig==
"@xterm/addon-webgl@0.19.0-beta.19":
version "0.19.0-beta.19"
resolved "https://registry.yarnpkg.com/@xterm/addon-webgl/-/addon-webgl-0.19.0-beta.19.tgz#655d1e27b1249c19352c65a8ea1d0bf319397b35"
integrity sha512-Y5efISx8X5hpFAsPOTza1Fp0xiD8x+l3MuH+mv68v1El8tpna/MW5EM4oX25qYOsPDZY00mpmkBmPbAT5loMEg==
"@xterm/headless@5.6.0-beta.17":
version "5.6.0-beta.17"
resolved "https://registry.yarnpkg.com/@xterm/headless/-/headless-5.6.0-beta.17.tgz#bff1d67c9c061c57adff22571e733d54e3aba2b7"
integrity sha512-ehS7y/XRqX1ppx4RPiYc0vu0SdIQ91aA4lSN/2XNOf3IGdP0A38Q7a0T6mzqxRGZKiiyA0kTR1szr78wnY+wmA==
"@xterm/headless@5.6.0-beta.19":
version "5.6.0-beta.19"
resolved "https://registry.yarnpkg.com/@xterm/headless/-/headless-5.6.0-beta.19.tgz#dbbd4dd420e24e9bdee6e533153f405bfc1ba89b"
integrity sha512-zFTcftonaaMEbMqfQnFwos1YQCmqWnvIzSNXwmfIymkEvSxhsB03oynEjFwm48dT2filTcJXpYT91io4qvR+3g==
"@xterm/xterm@5.6.0-beta.17":
version "5.6.0-beta.17"
resolved "https://registry.yarnpkg.com/@xterm/xterm/-/xterm-5.6.0-beta.17.tgz#67ce2e2ff45bd6cc9f26d455d5522c6c4a122ed9"
integrity sha512-+wAv8PhaGQSN9yXWIa8EFtT33pbrA4lZakMB1P05fr+DQ7zoH66QOAUoDY95uOf/4+S6Ihz8wzP2+FH8zETQEA==
"@xterm/xterm@5.6.0-beta.19":
version "5.6.0-beta.19"
resolved "https://registry.yarnpkg.com/@xterm/xterm/-/xterm-5.6.0-beta.19.tgz#2cc292fc93b25c7c655ed6d1f0425a636b36747d"
integrity sha512-mGoJxrUxAL4dueZEqw2e23KCrGNSvYaw5twTnccKqK7lITK/hDrosWCxb1jL1AjFf7bBzMxw9/dZdhWncKQQmw==
"@xtuc/ieee754@^1.2.0":
version "1.2.0"
@@ -6229,10 +6229,10 @@ js-yaml@^3.13.0:
argparse "^1.0.7"
esprima "^4.0.0"
jschardet@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-3.0.0.tgz#898d2332e45ebabbdb6bf2feece9feea9a99e882"
integrity sha512-lJH6tJ77V8Nzd5QWRkFYCLc13a3vADkh3r/Fi8HupZGWk2OVVDfnZP8V/VgQgZ+lzW0kG2UGb5hFgt3V3ndotQ==
jschardet@3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-3.1.2.tgz#9bf4364deba0677fe9e3bd9e29eda57febf2e9db"
integrity sha512-mw3CBZGzW8nUBPYhFU2ztZ/kJ6NClQUQVpyzvFMfznZsoC///ZQ30J2RCUanNsr5yF22LqhgYr/lj807/ZleWA==
jsdoc-type-pratt-parser@~4.0.0:
version "4.0.0"
@@ -10055,10 +10055,10 @@ typescript@^4.7.4:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.4.tgz#c464abca159669597be5f96b8943500b238e60e6"
integrity sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==
typescript@^5.5.0-dev.20240521:
version "5.5.0-dev.20240521"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.0-dev.20240521.tgz#a53f71ad2f5e4c4401a56c35993474b77813364c"
integrity sha512-52WLKX9mbRmStK1lb30KM78dSo5ssgQT8WQERYiv8JihXir4HUgwlgTz4crExojzpsGjFGFJROL/bZrhXUiOEQ==
typescript@^5.5.0-dev.20240603:
version "5.5.0-dev.20240603"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.0-dev.20240603.tgz#a1b7311df5039a8abbaaa2213c21cac6ec547490"
integrity sha512-gdm3Sh1A+Pjj9ZlfBEJY3o2rs3tvpcSbu3vYqcCijMe09BePQBtZlsuShuPn+zCnP+qBLxdKjFiw5v1tkna3tA==
typical@^4.0.0:
version "4.0.0"