mirror of
https://github.com/microsoft/vscode.git
synced 2026-08-28 23:58:23 +01:00
Merge branch 'main' into merogge/xterm-acc
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
FROM mcr.microsoft.com/devcontainers/typescript-node:16-bullseye
|
||||
FROM mcr.microsoft.com/devcontainers/typescript-node:18-bookworm
|
||||
|
||||
ADD install-vscode.sh /root/
|
||||
RUN /root/install-vscode.sh
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
"--vscode-charts-purple",
|
||||
"--vscode-charts-red",
|
||||
"--vscode-charts-yellow",
|
||||
"--vscode-chat-requestBackground",
|
||||
"--vscode-chat-requestBorder",
|
||||
"--vscode-chat-slashCommandBackground",
|
||||
"--vscode-chat-slashCommandForeground",
|
||||
@@ -703,7 +702,6 @@
|
||||
"--background-light",
|
||||
"--dropdown-padding-bottom",
|
||||
"--dropdown-padding-top",
|
||||
"--hover-maxWidth",
|
||||
"--insert-border-color",
|
||||
"--last-tab-margin-right",
|
||||
"--monaco-monospace-font",
|
||||
@@ -733,6 +731,9 @@
|
||||
"--vscode-editorCodeLens-fontSize",
|
||||
"--vscode-editorCodeLens-lineHeight",
|
||||
"--vscode-explorer-align-offset-margin-left",
|
||||
"--vscode-hover-maxWidth",
|
||||
"--vscode-hover-sourceWhiteSpace",
|
||||
"--vscode-hover-whiteSpace",
|
||||
"--vscode-inline-chat-cropped",
|
||||
"--vscode-inline-chat-expanded",
|
||||
"--vscode-interactive-session-foreground",
|
||||
@@ -766,4 +767,4 @@
|
||||
"--z-index-notebook-sticky-scroll",
|
||||
"--zoom-factor"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
"envShellEvent",
|
||||
"testCoverage",
|
||||
"testObserver",
|
||||
"testMessageContextValue",
|
||||
"textSearchProvider",
|
||||
"timeline",
|
||||
"tokenInformation",
|
||||
|
||||
+8
-8
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "code-oss-dev",
|
||||
"version": "1.82.0",
|
||||
"distro": "b61a76db7be19cb1582c2a9a7157d098e1850562",
|
||||
"distro": "510a8d740286d6895197995d1edc978ffe23cadf",
|
||||
"author": {
|
||||
"name": "Microsoft Corporation"
|
||||
},
|
||||
@@ -95,14 +95,14 @@
|
||||
"vscode-oniguruma": "1.7.0",
|
||||
"vscode-regexpp": "^3.1.0",
|
||||
"vscode-textmate": "9.0.0",
|
||||
"xterm": "5.3.0-beta.28",
|
||||
"xterm-addon-canvas": "0.5.0-beta.8",
|
||||
"xterm-addon-image": "0.5.0",
|
||||
"xterm-addon-search": "0.13.0-beta.4",
|
||||
"xterm-addon-serialize": "0.11.0-beta.6",
|
||||
"xterm": "5.3.0-beta.39",
|
||||
"xterm-addon-canvas": "0.5.0-beta.9",
|
||||
"xterm-addon-image": "0.6.0-beta.1",
|
||||
"xterm-addon-search": "0.13.0-beta.7",
|
||||
"xterm-addon-serialize": "0.11.0-beta.7",
|
||||
"xterm-addon-unicode11": "0.5.0",
|
||||
"xterm-addon-webgl": "0.16.0-beta.7",
|
||||
"xterm-headless": "5.3.0-beta.28",
|
||||
"xterm-addon-webgl": "0.16.0-beta.13",
|
||||
"xterm-headless": "5.3.0-beta.39",
|
||||
"yauzl": "^2.9.2",
|
||||
"yazl": "^2.4.3"
|
||||
},
|
||||
|
||||
+7
-7
@@ -27,14 +27,14 @@
|
||||
"vscode-oniguruma": "1.7.0",
|
||||
"vscode-regexpp": "^3.1.0",
|
||||
"vscode-textmate": "9.0.0",
|
||||
"xterm": "5.3.0-beta.28",
|
||||
"xterm-addon-canvas": "0.5.0-beta.8",
|
||||
"xterm-addon-image": "0.5.0",
|
||||
"xterm-addon-search": "0.13.0-beta.4",
|
||||
"xterm-addon-serialize": "0.11.0-beta.6",
|
||||
"xterm": "5.3.0-beta.39",
|
||||
"xterm-addon-canvas": "0.5.0-beta.9",
|
||||
"xterm-addon-image": "0.6.0-beta.1",
|
||||
"xterm-addon-search": "0.13.0-beta.7",
|
||||
"xterm-addon-serialize": "0.11.0-beta.7",
|
||||
"xterm-addon-unicode11": "0.5.0",
|
||||
"xterm-addon-webgl": "0.16.0-beta.7",
|
||||
"xterm-headless": "5.3.0-beta.28",
|
||||
"xterm-addon-webgl": "0.16.0-beta.13",
|
||||
"xterm-headless": "5.3.0-beta.39",
|
||||
"yauzl": "^2.9.2",
|
||||
"yazl": "^2.4.3"
|
||||
}
|
||||
|
||||
@@ -11,11 +11,11 @@
|
||||
"tas-client-umd": "0.1.8",
|
||||
"vscode-oniguruma": "1.7.0",
|
||||
"vscode-textmate": "9.0.0",
|
||||
"xterm": "5.3.0-beta.28",
|
||||
"xterm-addon-canvas": "0.5.0-beta.8",
|
||||
"xterm-addon-image": "0.5.0",
|
||||
"xterm-addon-search": "0.13.0-beta.4",
|
||||
"xterm": "5.3.0-beta.39",
|
||||
"xterm-addon-canvas": "0.5.0-beta.9",
|
||||
"xterm-addon-image": "0.6.0-beta.1",
|
||||
"xterm-addon-search": "0.13.0-beta.7",
|
||||
"xterm-addon-unicode11": "0.5.0",
|
||||
"xterm-addon-webgl": "0.16.0-beta.7"
|
||||
"xterm-addon-webgl": "0.16.0-beta.13"
|
||||
}
|
||||
}
|
||||
|
||||
+20
-20
@@ -90,32 +90,32 @@ vscode-textmate@9.0.0:
|
||||
resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-9.0.0.tgz#313c6c8792b0507aef35aeb81b6b370b37c44d6c"
|
||||
integrity sha512-Cl65diFGxz7gpwbav10HqiY/eVYTO1sjQpmRmV991Bj7wAoOAjGQ97PpQcXorDE2Uc4hnGWLY17xme+5t6MlSg==
|
||||
|
||||
xterm-addon-canvas@0.5.0-beta.8:
|
||||
version "0.5.0-beta.8"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.5.0-beta.8.tgz#243d1161cc68441a1d531f25e9c4f1d6b3cbe79d"
|
||||
integrity sha512-gCqoqFqfc4N8YZLlj3U5+247r3pjLc9ERRHpuBWSJF2GF623LLk4aSjexnEE0M1b7rIDa3xSKo5limHQXx2mWg==
|
||||
xterm-addon-canvas@0.5.0-beta.9:
|
||||
version "0.5.0-beta.9"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.5.0-beta.9.tgz#d4a9536cf586f78a54527751e03abf6445613886"
|
||||
integrity sha512-AMyFctHbIWx0aLcACINuZqFFNoz4ndGtIAb4pQguIl9t8r+2otiV11MY4FJmPM0kUzEzoLWzVFJaGxOzykCWuw==
|
||||
|
||||
xterm-addon-image@0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-image/-/xterm-addon-image-0.5.0.tgz#3c9bb332a3de55ab200dbefd3411e3b0d985314f"
|
||||
integrity sha512-bWXUBeDzhisYh0clVKx4JgQrZjpn+/QRMRwNsfnRpjCMhgmZ+SL3Bivktd7q03O4uKMMcAOe6bSmppwP9/um0Q==
|
||||
xterm-addon-image@0.6.0-beta.1:
|
||||
version "0.6.0-beta.1"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-image/-/xterm-addon-image-0.6.0-beta.1.tgz#058c171a4866f1cde7608e3b00050476b55ece4c"
|
||||
integrity sha512-vLxUEo/KAsEaRhMshJ4uxnfc/Si8YfT3kilaK5WuiJflVODzQjytzZrl2iLeZaWKiqQp0NR6AEhuXlYASK675A==
|
||||
|
||||
xterm-addon-search@0.13.0-beta.4:
|
||||
version "0.13.0-beta.4"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.13.0-beta.4.tgz#a9817600cc0a71dee524d0f025e88e013f87f14a"
|
||||
integrity sha512-A9Ps7iqGVUSphLCVrGYrfua1ADjtm9ff5CLs8cpiZnMK45X1FTIrXxEWvFccoiwtmZINEDJPGvbfIIqu8ZkXyg==
|
||||
xterm-addon-search@0.13.0-beta.7:
|
||||
version "0.13.0-beta.7"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.13.0-beta.7.tgz#2f9bf9d8380c4c40f021c47dc583aa32bea8796e"
|
||||
integrity sha512-Dnuws0ThaqzxRDo8TjkSb5WlMYycONVDSr/irx2pk2I4vC5RuSpOifmD46ALlryNSDkMasjfCLjHPILHsFDCfw==
|
||||
|
||||
xterm-addon-unicode11@0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.5.0.tgz#41c0d96acc1e3bb6c6596eee64e163b6bca74be7"
|
||||
integrity sha512-Jm4/g4QiTxiKiTbYICQgC791ubhIZyoIwxAIgOW8z8HWFNY+lwk+dwaKEaEeGBfM48Vk8fklsUW9u/PlenYEBg==
|
||||
|
||||
xterm-addon-webgl@0.16.0-beta.7:
|
||||
version "0.16.0-beta.7"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.16.0-beta.7.tgz#d9febd140e2020e05c39e66214dae685769144ed"
|
||||
integrity sha512-g657v/ah5JSjeTnHL3myCxiqPx0cA1J70kWXCqP4rsb1nPPlXtbq69cH5AsV/mNN5jnXjd6vHPa7CWt3ptOSgQ==
|
||||
xterm-addon-webgl@0.16.0-beta.13:
|
||||
version "0.16.0-beta.13"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.16.0-beta.13.tgz#ffacd22b8d86ca7f9ba903a64bc85654523955fb"
|
||||
integrity sha512-1avJBoAKl+0dOjRK0pvu2im6gaXyP/6oJcEBQXCTz3V8YlgcG/jom8A6FEQSEDGZ/4dnyDvnLbsg3+aLZIr6gw==
|
||||
|
||||
xterm@5.3.0-beta.28:
|
||||
version "5.3.0-beta.28"
|
||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.3.0-beta.28.tgz#1a5176fa6d9f424913a85dd0371d7384d2f882db"
|
||||
integrity sha512-WA7aX2nE+ptxU4EConXGf0vKwkRisaXNt8ExEw/MRnfDudpZo2J30raJ2SQV2n/xWCGoeVIE5njYmR/hhiGOQA==
|
||||
xterm@5.3.0-beta.39:
|
||||
version "5.3.0-beta.39"
|
||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.3.0-beta.39.tgz#b64da3fd1b374fd535db61294a49c16453dbb77e"
|
||||
integrity sha512-Z1r0ijTgad5MjFoz8qZ+2Qc3bgjG6kYY/kZI3DTA1pibArHeOMDYk9+IeCb9adF74zvZurjytRfXKJgX6M9hwg==
|
||||
|
||||
+28
-28
@@ -899,45 +899,45 @@ wrappy@1:
|
||||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
|
||||
|
||||
xterm-addon-canvas@0.5.0-beta.8:
|
||||
version "0.5.0-beta.8"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.5.0-beta.8.tgz#243d1161cc68441a1d531f25e9c4f1d6b3cbe79d"
|
||||
integrity sha512-gCqoqFqfc4N8YZLlj3U5+247r3pjLc9ERRHpuBWSJF2GF623LLk4aSjexnEE0M1b7rIDa3xSKo5limHQXx2mWg==
|
||||
xterm-addon-canvas@0.5.0-beta.9:
|
||||
version "0.5.0-beta.9"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.5.0-beta.9.tgz#d4a9536cf586f78a54527751e03abf6445613886"
|
||||
integrity sha512-AMyFctHbIWx0aLcACINuZqFFNoz4ndGtIAb4pQguIl9t8r+2otiV11MY4FJmPM0kUzEzoLWzVFJaGxOzykCWuw==
|
||||
|
||||
xterm-addon-image@0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-image/-/xterm-addon-image-0.5.0.tgz#3c9bb332a3de55ab200dbefd3411e3b0d985314f"
|
||||
integrity sha512-bWXUBeDzhisYh0clVKx4JgQrZjpn+/QRMRwNsfnRpjCMhgmZ+SL3Bivktd7q03O4uKMMcAOe6bSmppwP9/um0Q==
|
||||
xterm-addon-image@0.6.0-beta.1:
|
||||
version "0.6.0-beta.1"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-image/-/xterm-addon-image-0.6.0-beta.1.tgz#058c171a4866f1cde7608e3b00050476b55ece4c"
|
||||
integrity sha512-vLxUEo/KAsEaRhMshJ4uxnfc/Si8YfT3kilaK5WuiJflVODzQjytzZrl2iLeZaWKiqQp0NR6AEhuXlYASK675A==
|
||||
|
||||
xterm-addon-search@0.13.0-beta.4:
|
||||
version "0.13.0-beta.4"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.13.0-beta.4.tgz#a9817600cc0a71dee524d0f025e88e013f87f14a"
|
||||
integrity sha512-A9Ps7iqGVUSphLCVrGYrfua1ADjtm9ff5CLs8cpiZnMK45X1FTIrXxEWvFccoiwtmZINEDJPGvbfIIqu8ZkXyg==
|
||||
xterm-addon-search@0.13.0-beta.7:
|
||||
version "0.13.0-beta.7"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.13.0-beta.7.tgz#2f9bf9d8380c4c40f021c47dc583aa32bea8796e"
|
||||
integrity sha512-Dnuws0ThaqzxRDo8TjkSb5WlMYycONVDSr/irx2pk2I4vC5RuSpOifmD46ALlryNSDkMasjfCLjHPILHsFDCfw==
|
||||
|
||||
xterm-addon-serialize@0.11.0-beta.6:
|
||||
version "0.11.0-beta.6"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.11.0-beta.6.tgz#2533a2f6bf41327cfcc51a92fca79404499cffe2"
|
||||
integrity sha512-wXx3j9Nf+JOxoBW8iZElEPVEBD6LRDlnrGhfe4oSEa+wDJX+8iORcIKH06mNBlwSApajawrDhpcugwAhjvSOHg==
|
||||
xterm-addon-serialize@0.11.0-beta.7:
|
||||
version "0.11.0-beta.7"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.11.0-beta.7.tgz#934a48a4490c2ca94a5cfcdd646fb0813b4e56d0"
|
||||
integrity sha512-TwYsEHq6TflY0vmq3yAI2VKNqzEAZ0gCm3TThDMPrPQiv4LcewQSeGu9RujEqF9RAhujhceaM3GajBxySAWyqQ==
|
||||
|
||||
xterm-addon-unicode11@0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.5.0.tgz#41c0d96acc1e3bb6c6596eee64e163b6bca74be7"
|
||||
integrity sha512-Jm4/g4QiTxiKiTbYICQgC791ubhIZyoIwxAIgOW8z8HWFNY+lwk+dwaKEaEeGBfM48Vk8fklsUW9u/PlenYEBg==
|
||||
|
||||
xterm-addon-webgl@0.16.0-beta.7:
|
||||
version "0.16.0-beta.7"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.16.0-beta.7.tgz#d9febd140e2020e05c39e66214dae685769144ed"
|
||||
integrity sha512-g657v/ah5JSjeTnHL3myCxiqPx0cA1J70kWXCqP4rsb1nPPlXtbq69cH5AsV/mNN5jnXjd6vHPa7CWt3ptOSgQ==
|
||||
xterm-addon-webgl@0.16.0-beta.13:
|
||||
version "0.16.0-beta.13"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.16.0-beta.13.tgz#ffacd22b8d86ca7f9ba903a64bc85654523955fb"
|
||||
integrity sha512-1avJBoAKl+0dOjRK0pvu2im6gaXyP/6oJcEBQXCTz3V8YlgcG/jom8A6FEQSEDGZ/4dnyDvnLbsg3+aLZIr6gw==
|
||||
|
||||
xterm-headless@5.3.0-beta.28:
|
||||
version "5.3.0-beta.28"
|
||||
resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.3.0-beta.28.tgz#c0307c7363fe290fc5edb68b81135d6c37c76f67"
|
||||
integrity sha512-2zZFNa6AOpoAcMEgzzV7ilSv2qUecs8gSJbfxVV9D4lbNuwWYW5AV8VEdfKnD8TRPbsC/5Uc4RZ82qhJNYOC1g==
|
||||
xterm-headless@5.3.0-beta.39:
|
||||
version "5.3.0-beta.39"
|
||||
resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.3.0-beta.39.tgz#84a509dbe1dc9b2229b5274ae3430ce968986346"
|
||||
integrity sha512-Q4vfqAaYoWh7/T4HearlLlKkn9vjN5EugsNyuPd6hq+Ug1FwJIJYj+I9vY67+Rqxr24XGnrQdXfvvEas29KXsw==
|
||||
|
||||
xterm@5.3.0-beta.28:
|
||||
version "5.3.0-beta.28"
|
||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.3.0-beta.28.tgz#1a5176fa6d9f424913a85dd0371d7384d2f882db"
|
||||
integrity sha512-WA7aX2nE+ptxU4EConXGf0vKwkRisaXNt8ExEw/MRnfDudpZo2J30raJ2SQV2n/xWCGoeVIE5njYmR/hhiGOQA==
|
||||
xterm@5.3.0-beta.39:
|
||||
version "5.3.0-beta.39"
|
||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.3.0-beta.39.tgz#b64da3fd1b374fd535db61294a49c16453dbb77e"
|
||||
integrity sha512-Z1r0ijTgad5MjFoz8qZ+2Qc3bgjG6kYY/kZI3DTA1pibArHeOMDYk9+IeCb9adF74zvZurjytRfXKJgX6M9hwg==
|
||||
|
||||
yallist@^4.0.0:
|
||||
version "4.0.0"
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
box-sizing: border-box;
|
||||
animation: fadein 100ms linear;
|
||||
line-height: 1.5em;
|
||||
white-space: var(--vscode-hover-whiteSpace, normal);
|
||||
}
|
||||
|
||||
.monaco-hover.hidden {
|
||||
@@ -27,7 +28,7 @@
|
||||
}
|
||||
|
||||
.monaco-hover .markdown-hover > .hover-contents:not(.code-hover-contents) {
|
||||
max-width: var(--hover-maxWidth, 500px);
|
||||
max-width: var(--vscode-hover-maxWidth, 500px);
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
@@ -105,7 +106,7 @@
|
||||
}
|
||||
|
||||
.monaco-hover .monaco-tokenized-source {
|
||||
white-space: pre-wrap;
|
||||
white-space: var(--vscode-hover-sourceWhiteSpace, pre-wrap);
|
||||
}
|
||||
|
||||
.monaco-hover .hover-row.status-bar {
|
||||
|
||||
@@ -96,6 +96,6 @@ export class HoverAction extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
export function getHoverAriaLabel(shouldHaveHint?: boolean, keybinding?: string | null): string | undefined {
|
||||
export function getHoverAccessibleViewHint(shouldHaveHint?: boolean, keybinding?: string | null): string | undefined {
|
||||
return shouldHaveHint && keybinding ? localize('acessibleViewHint', "Inspect this in the accessible view with {0}.", keybinding) : shouldHaveHint ? localize('acessibleViewHintNoKbOpen', "Inspect this in the accessible view via the command Open Accessible View which is currently not triggerable via keybinding.") : '';
|
||||
}
|
||||
|
||||
@@ -20,5 +20,6 @@ export const enum MarshalledId {
|
||||
NotebookCellActionContext,
|
||||
NotebookActionContext,
|
||||
TestItemContext,
|
||||
Date
|
||||
Date,
|
||||
TestMessageMenuArgs,
|
||||
}
|
||||
|
||||
@@ -119,13 +119,18 @@ export class OverviewRulerPart extends Disposable {
|
||||
.map(r => {
|
||||
const start = vm.coordinatesConverter.convertModelPositionToViewPosition(new Position(r.startLineNumber, 1));
|
||||
const end = vm.coordinatesConverter.convertModelPositionToViewPosition(new Position(r.endLineNumberExclusive, 1));
|
||||
|
||||
return new OverviewRulerZone(start.lineNumber, end.lineNumber, 0, color.toString());
|
||||
// By computing the lineCount, we won't ask the view model later for the bottom vertical position.
|
||||
// (The view model will take into account the alignment viewzones, which will give
|
||||
// modifications and deletetions always the same height.)
|
||||
const lineCount = end.lineNumber - start.lineNumber;
|
||||
return new OverviewRulerZone(start.lineNumber, end.lineNumber, lineCount, color.toString());
|
||||
});
|
||||
}
|
||||
|
||||
originalOverviewRuler?.setZones(createZones((diff || []).map(d => d.lineRangeMapping.originalRange), colors.removeColor, this._editors.original));
|
||||
modifiedOverviewRuler?.setZones(createZones((diff || []).map(d => d.lineRangeMapping.modifiedRange), colors.insertColor, this._editors.modified));
|
||||
const originalZones = createZones((diff || []).map(d => d.lineRangeMapping.originalRange), colors.removeColor, this._editors.original);
|
||||
const modifiedZones = createZones((diff || []).map(d => d.lineRangeMapping.modifiedRange), colors.insertColor, this._editors.modified);
|
||||
originalOverviewRuler?.setZones(originalZones);
|
||||
modifiedOverviewRuler?.setZones(modifiedZones);
|
||||
}));
|
||||
|
||||
store.add(autorun(reader => {
|
||||
|
||||
@@ -41,6 +41,15 @@ export class WorkerBasedDocumentDiffProvider implements IDocumentDiffProvider, I
|
||||
|
||||
// This significantly speeds up the case when the original file is empty
|
||||
if (original.getLineCount() === 1 && original.getLineMaxColumn(1) === 1) {
|
||||
if (modified.getLineCount() === 1 && modified.getLineMaxColumn(1) === 1) {
|
||||
return {
|
||||
changes: [],
|
||||
identical: true,
|
||||
quitEarly: false,
|
||||
moves: [],
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
changes: [
|
||||
new LineRangeMapping(
|
||||
|
||||
@@ -110,6 +110,7 @@ const editorConfiguration: IConfigurationNode = {
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: nls.localize('editor.experimental.asyncTokenizationVerification', "Controls whether async tokenization should be verified against legacy background tokenization. Might slow down tokenization. For debugging only."),
|
||||
tags: ['experimental'],
|
||||
},
|
||||
'editor.language.brackets': {
|
||||
type: ['array', 'null'],
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { compareBy, findLastIndex, numberComparator, reverseOrder } from 'vs/base/common/arrays';
|
||||
import { compareBy, equals, findLastIndex, numberComparator, reverseOrder } from 'vs/base/common/arrays';
|
||||
import { assertFn, checkAdjacentItems } from 'vs/base/common/assert';
|
||||
import { CharCode } from 'vs/base/common/charCode';
|
||||
import { SetMap } from 'vs/base/common/collections';
|
||||
@@ -22,23 +22,23 @@ export class StandardLinesDiffComputer implements ILinesDiffComputer {
|
||||
private readonly myersDiffingAlgorithm = new MyersDiffAlgorithm();
|
||||
|
||||
computeDiff(originalLines: string[], modifiedLines: string[], options: ILinesDiffComputerOptions): LinesDiff {
|
||||
if (originalLines.length <= 1 && equals(originalLines, modifiedLines, (a, b) => a === b)) {
|
||||
return new LinesDiff([], [], false);
|
||||
}
|
||||
|
||||
if (originalLines.length === 1 && originalLines[0].length === 0 || modifiedLines.length === 1 && modifiedLines[0].length === 0) {
|
||||
return {
|
||||
changes: [
|
||||
new LineRangeMapping(
|
||||
new LineRange(1, originalLines.length + 1),
|
||||
new LineRange(1, modifiedLines.length + 1),
|
||||
[
|
||||
new RangeMapping(
|
||||
new Range(1, 1, originalLines.length, originalLines[0].length + 1),
|
||||
new Range(1, 1, modifiedLines.length, modifiedLines[0].length + 1)
|
||||
)
|
||||
]
|
||||
)
|
||||
],
|
||||
hitTimeout: false,
|
||||
moves: [],
|
||||
};
|
||||
return new LinesDiff([
|
||||
new LineRangeMapping(
|
||||
new LineRange(1, originalLines.length + 1),
|
||||
new LineRange(1, modifiedLines.length + 1),
|
||||
[
|
||||
new RangeMapping(
|
||||
new Range(1, 1, originalLines.length, originalLines[0].length + 1),
|
||||
new Range(1, 1, modifiedLines.length, modifiedLines[0].length + 1)
|
||||
)
|
||||
]
|
||||
)
|
||||
], [], false);
|
||||
}
|
||||
|
||||
const timeout = options.maxComputationTimeMs === 0 ? InfiniteTimeout.instance : new DateTimeout(options.maxComputationTimeMs);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { HoverAction, HoverWidget, getHoverAriaLabel } from 'vs/base/browser/ui/hover/hoverWidget';
|
||||
import { HoverAction, HoverWidget, getHoverAccessibleViewHint } from 'vs/base/browser/ui/hover/hoverWidget';
|
||||
import { coalesce } from 'vs/base/common/arrays';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
@@ -474,7 +474,7 @@ export class ContentHoverWidget extends ResizableContentWidget {
|
||||
private _visibleData: ContentHoverVisibleData | undefined;
|
||||
private _positionPreference: ContentWidgetPositionPreference | undefined;
|
||||
private _minimumSize: dom.Dimension;
|
||||
private _contentWidth: number;
|
||||
private _contentWidth: number | undefined;
|
||||
|
||||
private readonly _hover: HoverWidget = this._register(new HoverWidget());
|
||||
private readonly _hoverVisibleKey: IContextKey<boolean>;
|
||||
@@ -508,7 +508,6 @@ export class ContentHoverWidget extends ResizableContentWidget {
|
||||
const minimumSize = new dom.Dimension(minimumWidth, minimumHeight);
|
||||
super(editor, minimumSize);
|
||||
this._minimumSize = minimumSize;
|
||||
this._contentWidth = minimumWidth; // we initially assume the content width to be the minimum width
|
||||
this._hoverVisibleKey = EditorContextKeys.hoverVisible.bindTo(contextKeyService);
|
||||
this._hoverFocusedKey = EditorContextKeys.hoverFocused.bindTo(contextKeyService);
|
||||
|
||||
@@ -531,8 +530,6 @@ export class ContentHoverWidget extends ResizableContentWidget {
|
||||
this._setHoverData(undefined);
|
||||
this._layout();
|
||||
this._editor.addContentWidget(this);
|
||||
|
||||
this._hover.containerDomNode.ariaLabel = getHoverAriaLabel(this._configurationService.getValue('accessibility.verbosity.hover') === true && this._accessibilityService.isScreenReaderOptimized(), this._keybindingService.lookupKeybinding('editor.action.accessibleView')?.getAriaLabel()) ?? '';
|
||||
}
|
||||
|
||||
public override dispose(): void {
|
||||
@@ -578,7 +575,7 @@ export class ContentHoverWidget extends ResizableContentWidget {
|
||||
private _setHoverWidgetMaxDimensions(width: number | string, height: number | string): void {
|
||||
ContentHoverWidget._applyMaxDimensions(this._hover.contentsDomNode, width, height);
|
||||
ContentHoverWidget._applyMaxDimensions(this._hover.containerDomNode, width, height);
|
||||
this._hover.containerDomNode.style.setProperty('--hover-maxWidth', typeof width === 'number' ? `${width}px` : width);
|
||||
this._hover.containerDomNode.style.setProperty('--vscode-hover-maxWidth', typeof width === 'number' ? `${width}px` : width);
|
||||
this._layoutContentWidget();
|
||||
}
|
||||
|
||||
@@ -608,7 +605,7 @@ export class ContentHoverWidget extends ResizableContentWidget {
|
||||
}
|
||||
}
|
||||
|
||||
private _setResizableNodeMaxDimensions(): void {
|
||||
private _updateResizableNodeMaxDimensions(): void {
|
||||
const maxRenderingWidth = this._findMaximumRenderingWidth() ?? Infinity;
|
||||
const maxRenderingHeight = this._findMaximumRenderingHeight() ?? Infinity;
|
||||
this._resizableNode.maxSize = new dom.Dimension(maxRenderingWidth, maxRenderingHeight);
|
||||
@@ -619,7 +616,7 @@ export class ContentHoverWidget extends ResizableContentWidget {
|
||||
ContentHoverWidget._lastDimensions = new dom.Dimension(size.width, size.height);
|
||||
this._setAdjustedHoverWidgetDimensions(size);
|
||||
this._resizableNode.layout(size.height, size.width);
|
||||
this._setResizableNodeMaxDimensions();
|
||||
this._updateResizableNodeMaxDimensions();
|
||||
this._hover.scrollbar.scanDomNode();
|
||||
this._editor.layoutContentWidget(this);
|
||||
this._visibleData?.colorPicker?.layout();
|
||||
@@ -649,13 +646,41 @@ export class ContentHoverWidget extends ResizableContentWidget {
|
||||
return Math.min(availableSpace, maximumHeight);
|
||||
}
|
||||
|
||||
private _isHoverTextOverflowing(): boolean {
|
||||
// To find out if the text is overflowing, we will disable wrapping, check the widths, and then re-enable wrapping
|
||||
this._hover.containerDomNode.style.setProperty('--vscode-hover-whiteSpace', 'nowrap');
|
||||
this._hover.containerDomNode.style.setProperty('--vscode-hover-sourceWhiteSpace', 'nowrap');
|
||||
|
||||
const overflowing = Array.from(this._hover.contentsDomNode.children).some((hoverElement) => {
|
||||
return hoverElement.scrollWidth > hoverElement.clientWidth;
|
||||
});
|
||||
|
||||
this._hover.containerDomNode.style.removeProperty('--vscode-hover-whiteSpace');
|
||||
this._hover.containerDomNode.style.removeProperty('--vscode-hover-sourceWhiteSpace');
|
||||
|
||||
return overflowing;
|
||||
}
|
||||
|
||||
private _findMaximumRenderingWidth(): number | undefined {
|
||||
if (!this._editor || !this._editor.hasModel()) {
|
||||
return;
|
||||
}
|
||||
const bodyBoxWidth = dom.getClientArea(document.body).width;
|
||||
const horizontalPadding = 14;
|
||||
return bodyBoxWidth - horizontalPadding;
|
||||
|
||||
const overflowing = this._isHoverTextOverflowing();
|
||||
|
||||
const initialWidth = (
|
||||
typeof this._contentWidth === 'undefined'
|
||||
? 0
|
||||
: this._contentWidth - 2 // - 2 for the borders
|
||||
);
|
||||
|
||||
if (overflowing || this._hover.containerDomNode.clientWidth < initialWidth) {
|
||||
const bodyBoxWidth = dom.getClientArea(document.body).width;
|
||||
const horizontalPadding = 14;
|
||||
return bodyBoxWidth - horizontalPadding;
|
||||
} else {
|
||||
return this._hover.containerDomNode.clientWidth + 2;
|
||||
}
|
||||
}
|
||||
|
||||
public isMouseGettingCloser(posx: number, posy: number): boolean {
|
||||
@@ -758,6 +783,12 @@ export class ContentHoverWidget extends ResizableContentWidget {
|
||||
this._hover.containerDomNode.focus();
|
||||
}
|
||||
hoverData.colorPicker?.layout();
|
||||
|
||||
// The aria label overrides the label, so if we add to it, add the contents of the hover
|
||||
const accessibleViewHint = getHoverAccessibleViewHint(this._configurationService.getValue('accessibility.verbosity.hover') === true && this._accessibilityService.isScreenReaderOptimized(), this._keybindingService.lookupKeybinding('editor.action.accessibleView')?.getAriaLabel() ?? '');
|
||||
if (accessibleViewHint) {
|
||||
this._hover.contentsDomNode.ariaLabel = this._hover.contentsDomNode.textContent + ', ' + accessibleViewHint;
|
||||
}
|
||||
}
|
||||
|
||||
public hide(): void {
|
||||
@@ -800,8 +831,13 @@ export class ContentHoverWidget extends ResizableContentWidget {
|
||||
}
|
||||
|
||||
private _updateMinimumWidth(): void {
|
||||
const width = (
|
||||
typeof this._contentWidth === 'undefined'
|
||||
? this._minimumSize.width
|
||||
: Math.min(this._contentWidth, this._minimumSize.width)
|
||||
);
|
||||
// We want to avoid that the hover is artificially large, so we use the content width as minimum width
|
||||
this._resizableNode.minSize = new dom.Dimension(Math.min(this._contentWidth, this._minimumSize.width), this._minimumSize.height);
|
||||
this._resizableNode.minSize = new dom.Dimension(width, this._minimumSize.height);
|
||||
}
|
||||
|
||||
public onContentsChanged(): void {
|
||||
@@ -818,6 +854,7 @@ export class ContentHoverWidget extends ResizableContentWidget {
|
||||
width = dom.getTotalWidth(containerDomNode);
|
||||
this._contentWidth = width;
|
||||
this._updateMinimumWidth();
|
||||
this._updateResizableNodeMaxDimensions();
|
||||
this._resizableNode.layout(height, width);
|
||||
|
||||
if (this._hasHorizontalScrollbar()) {
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { $, append, clearNode } from 'vs/base/browser/dom';
|
||||
import { Widget } from 'vs/base/browser/ui/widget';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { Disposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
|
||||
import { IMenu, IMenuService, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { asCssVariable, asCssVariableWithDefault, buttonBackground, buttonForeground, contrastBorder, editorBackground, editorForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
|
||||
export class FloatingClickWidget extends Widget {
|
||||
|
||||
private readonly _onClick = this._register(new Emitter<void>());
|
||||
readonly onClick = this._onClick.event;
|
||||
|
||||
private _domNode: HTMLElement;
|
||||
|
||||
constructor(private label: string) {
|
||||
super();
|
||||
|
||||
this._domNode = $('.floating-click-widget');
|
||||
this._domNode.style.padding = '6px 11px';
|
||||
this._domNode.style.borderRadius = '2px';
|
||||
this._domNode.style.cursor = 'pointer';
|
||||
this._domNode.style.zIndex = '1';
|
||||
}
|
||||
|
||||
getDomNode(): HTMLElement {
|
||||
return this._domNode;
|
||||
}
|
||||
|
||||
render() {
|
||||
clearNode(this._domNode);
|
||||
this._domNode.style.backgroundColor = asCssVariableWithDefault(buttonBackground, asCssVariable(editorBackground));
|
||||
this._domNode.style.color = asCssVariableWithDefault(buttonForeground, asCssVariable(editorForeground));
|
||||
this._domNode.style.border = `1px solid ${asCssVariable(contrastBorder)}`;
|
||||
|
||||
append(this._domNode, $('')).textContent = this.label;
|
||||
|
||||
this.onclick(this._domNode, () => this._onClick.fire());
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class AbstractFloatingClickMenu extends Disposable {
|
||||
private readonly renderEmitter = new Emitter<FloatingClickWidget>();
|
||||
protected readonly onDidRender = this.renderEmitter.event;
|
||||
private readonly menu: IMenu;
|
||||
|
||||
constructor(
|
||||
menuId: MenuId,
|
||||
@IMenuService menuService: IMenuService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService
|
||||
) {
|
||||
super();
|
||||
this.menu = this._register(menuService.createMenu(menuId, contextKeyService));
|
||||
}
|
||||
|
||||
/** Should be called in implementation constructors after they initialized */
|
||||
protected render() {
|
||||
const menuDisposables = this._register(new DisposableStore());
|
||||
const renderMenuAsFloatingClickBtn = () => {
|
||||
menuDisposables.clear();
|
||||
if (!this.isVisible()) {
|
||||
return;
|
||||
}
|
||||
const actions: IAction[] = [];
|
||||
createAndFillInActionBarActions(this.menu, { renderShortTitle: true, shouldForwardArgs: true }, actions);
|
||||
if (actions.length === 0) {
|
||||
return;
|
||||
}
|
||||
// todo@jrieken find a way to handle N actions, like showing a context menu
|
||||
const [first] = actions;
|
||||
const widget = this.createWidget(first, menuDisposables);
|
||||
menuDisposables.add(widget);
|
||||
menuDisposables.add(widget.onClick(() => first.run(this.getActionArg())));
|
||||
widget.render();
|
||||
};
|
||||
this._register(this.menu.onDidChange(renderMenuAsFloatingClickBtn));
|
||||
renderMenuAsFloatingClickBtn();
|
||||
}
|
||||
|
||||
protected abstract createWidget(action: IAction, disposables: DisposableStore): FloatingClickWidget;
|
||||
|
||||
protected getActionArg(): unknown {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
protected isVisible() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export class FloatingClickMenu extends AbstractFloatingClickMenu {
|
||||
|
||||
constructor(
|
||||
private readonly options: {
|
||||
/** Element the menu should be rendered into. */
|
||||
container: HTMLElement;
|
||||
/** Menu to show. If no actions are present, the button is hidden. */
|
||||
menuId: MenuId;
|
||||
/** Argument provided to the menu action */
|
||||
getActionArg: () => void;
|
||||
},
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@IMenuService menuService: IMenuService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService
|
||||
) {
|
||||
super(options.menuId, menuService, contextKeyService);
|
||||
this.render();
|
||||
}
|
||||
|
||||
protected override createWidget(action: IAction, disposable: DisposableStore): FloatingClickWidget {
|
||||
const w = this.instantiationService.createInstance(FloatingClickWidget, action.label);
|
||||
const node = w.getDomNode();
|
||||
this.options.container.appendChild(node);
|
||||
disposable.add(toDisposable(() => this.options.container.removeChild(node)));
|
||||
return w;
|
||||
}
|
||||
|
||||
protected override getActionArg(): unknown {
|
||||
return this.options.getActionArg();
|
||||
}
|
||||
}
|
||||
@@ -114,6 +114,8 @@ export class MenuId {
|
||||
static readonly StickyScrollContext = new MenuId('StickyScrollContext');
|
||||
static readonly TestItem = new MenuId('TestItem');
|
||||
static readonly TestItemGutter = new MenuId('TestItemGutter');
|
||||
static readonly TestMessageContext = new MenuId('TestMessageContext');
|
||||
static readonly TestMessageContent = new MenuId('TestMessageContent');
|
||||
static readonly TestPeekElement = new MenuId('TestPeekElement');
|
||||
static readonly TestPeekTitle = new MenuId('TestPeekTitle');
|
||||
static readonly TouchBarContext = new MenuId('TouchBarContext');
|
||||
|
||||
@@ -64,6 +64,7 @@ export const enum TerminalSettingId {
|
||||
FontWeightBold = 'terminal.integrated.fontWeightBold',
|
||||
CursorBlinking = 'terminal.integrated.cursorBlinking',
|
||||
CursorStyle = 'terminal.integrated.cursorStyle',
|
||||
CursorStyleInactive = 'terminal.integrated.cursorStyleInactive',
|
||||
CursorWidth = 'terminal.integrated.cursorWidth',
|
||||
Scrollback = 'terminal.integrated.scrollback',
|
||||
DetectLocale = 'terminal.integrated.detectLocale',
|
||||
|
||||
@@ -61,7 +61,7 @@ export interface TunnelProviderFeatures {
|
||||
}
|
||||
|
||||
export interface ITunnelProvider {
|
||||
forwardPort(tunnelOptions: TunnelOptions, tunnelCreationOptions: TunnelCreationOptions): Promise<RemoteTunnel | undefined> | undefined;
|
||||
forwardPort(tunnelOptions: TunnelOptions, tunnelCreationOptions: TunnelCreationOptions): Promise<RemoteTunnel | string | undefined> | undefined;
|
||||
}
|
||||
|
||||
export function isTunnelProvider(addressOrTunnelProvider: IAddressProvider | ITunnelProvider): addressOrTunnelProvider is ITunnelProvider {
|
||||
@@ -114,7 +114,7 @@ export interface ITunnel {
|
||||
export interface ISharedTunnelsService {
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
openTunnel(authority: string, addressProvider: IAddressProvider | undefined, remoteHost: string | undefined, remotePort: number, localHost: string, localPort?: number, elevateIfNeeded?: boolean, privacy?: string, protocol?: string): Promise<RemoteTunnel | undefined> | undefined;
|
||||
openTunnel(authority: string, addressProvider: IAddressProvider | undefined, remoteHost: string | undefined, remotePort: number, localHost: string, localPort?: number, elevateIfNeeded?: boolean, privacy?: string, protocol?: string): Promise<RemoteTunnel | string | undefined> | undefined;
|
||||
}
|
||||
|
||||
export interface ITunnelService {
|
||||
@@ -130,8 +130,8 @@ export interface ITunnelService {
|
||||
readonly onAddedTunnelProvider: Event<void>;
|
||||
|
||||
canTunnel(uri: URI): boolean;
|
||||
openTunnel(addressProvider: IAddressProvider | undefined, remoteHost: string | undefined, remotePort: number, localHost?: string, localPort?: number, elevateIfNeeded?: boolean, privacy?: string, protocol?: string): Promise<RemoteTunnel | undefined> | undefined;
|
||||
getExistingTunnel(remoteHost: string, remotePort: number): Promise<RemoteTunnel | undefined>;
|
||||
openTunnel(addressProvider: IAddressProvider | undefined, remoteHost: string | undefined, remotePort: number, localHost?: string, localPort?: number, elevateIfNeeded?: boolean, privacy?: string, protocol?: string): Promise<RemoteTunnel | string | undefined> | undefined;
|
||||
getExistingTunnel(remoteHost: string, remotePort: number): Promise<RemoteTunnel | string | undefined>;
|
||||
setEnvironmentTunnel(remoteHost: string, remotePort: number, localAddress: string, privacy: string, protocol: string): void;
|
||||
closeTunnel(remoteHost: string, remotePort: number): Promise<void>;
|
||||
setTunnelProvider(provider: ITunnelProvider | undefined): IDisposable;
|
||||
@@ -205,7 +205,7 @@ export abstract class AbstractTunnelService implements ITunnelService {
|
||||
public onTunnelClosed: Event<{ host: string; port: number }> = this._onTunnelClosed.event;
|
||||
private _onAddedTunnelProvider: Emitter<void> = new Emitter();
|
||||
public onAddedTunnelProvider: Event<void> = this._onAddedTunnelProvider.event;
|
||||
protected readonly _tunnels = new Map</*host*/ string, Map</* port */ number, { refcount: number; readonly value: Promise<RemoteTunnel | undefined> }>>();
|
||||
protected readonly _tunnels = new Map</*host*/ string, Map</* port */ number, { refcount: number; readonly value: Promise<RemoteTunnel | string | undefined> }>>();
|
||||
protected _tunnelProvider: ITunnelProvider | undefined;
|
||||
protected _canElevate: boolean = false;
|
||||
private _privacyOptions: TunnelPrivacy[] = [];
|
||||
@@ -275,7 +275,7 @@ export abstract class AbstractTunnelService implements ITunnelService {
|
||||
const portArray = Array.from(portMap.values());
|
||||
for (const x of portArray) {
|
||||
const tunnelValue = await x.value;
|
||||
if (tunnelValue) {
|
||||
if (tunnelValue && (typeof tunnelValue !== 'string')) {
|
||||
tunnels.push(tunnelValue);
|
||||
}
|
||||
}
|
||||
@@ -286,7 +286,7 @@ export abstract class AbstractTunnelService implements ITunnelService {
|
||||
async dispose(): Promise<void> {
|
||||
for (const portMap of this._tunnels.values()) {
|
||||
for (const { value } of portMap.values()) {
|
||||
await value.then(tunnel => tunnel?.dispose());
|
||||
await value.then(tunnel => typeof tunnel !== 'string' ? tunnel?.dispose() : undefined);
|
||||
}
|
||||
portMap.clear();
|
||||
}
|
||||
@@ -304,7 +304,7 @@ export abstract class AbstractTunnelService implements ITunnelService {
|
||||
}));
|
||||
}
|
||||
|
||||
async getExistingTunnel(remoteHost: string, remotePort: number): Promise<RemoteTunnel | undefined> {
|
||||
async getExistingTunnel(remoteHost: string, remotePort: number): Promise<RemoteTunnel | string | undefined> {
|
||||
if (isAllInterfaces(remoteHost) || isLocalhost(remoteHost)) {
|
||||
remoteHost = LOCALHOST_ADDRESSES[0];
|
||||
}
|
||||
@@ -317,7 +317,7 @@ export abstract class AbstractTunnelService implements ITunnelService {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
openTunnel(addressProvider: IAddressProvider | undefined, remoteHost: string | undefined, remotePort: number, localHost?: string, localPort?: number, elevateIfNeeded: boolean = false, privacy?: string, protocol?: string): Promise<RemoteTunnel | undefined> | undefined {
|
||||
openTunnel(addressProvider: IAddressProvider | undefined, remoteHost: string | undefined, remotePort: number, localHost?: string, localPort?: number, elevateIfNeeded: boolean = false, privacy?: string, protocol?: string): Promise<RemoteTunnel | string | undefined> | undefined {
|
||||
this.logService.trace(`ForwardedPorts: (TunnelService) openTunnel request for ${remoteHost}:${remotePort} on local port ${localPort}.`);
|
||||
const addressOrTunnelProvider = this._tunnelProvider ?? addressProvider;
|
||||
if (!addressOrTunnelProvider) {
|
||||
@@ -346,8 +346,12 @@ export abstract class AbstractTunnelService implements ITunnelService {
|
||||
return resolvedTunnel.then(tunnel => {
|
||||
if (!tunnel) {
|
||||
this.logService.trace('ForwardedPorts: (TunnelService) New tunnel is undefined.');
|
||||
this.removeEmptyTunnelFromMap(remoteHost!, remotePort);
|
||||
this.removeEmptyOrErrorTunnelFromMap(remoteHost!, remotePort);
|
||||
return undefined;
|
||||
} else if (typeof tunnel === 'string') {
|
||||
this.logService.trace('ForwardedPorts: (TunnelService) The tunnel provider returned an error when creating the tunnel.');
|
||||
this.removeEmptyOrErrorTunnelFromMap(remoteHost!, remotePort);
|
||||
return tunnel;
|
||||
}
|
||||
this.logService.trace('ForwardedPorts: (TunnelService) New tunnel established.');
|
||||
const newTunnel = this.makeTunnel(tunnel);
|
||||
@@ -384,11 +388,11 @@ export abstract class AbstractTunnelService implements ITunnelService {
|
||||
};
|
||||
}
|
||||
|
||||
private async tryDisposeTunnel(remoteHost: string, remotePort: number, tunnel: { refcount: number; readonly value: Promise<RemoteTunnel | undefined> }): Promise<void> {
|
||||
private async tryDisposeTunnel(remoteHost: string, remotePort: number, tunnel: { refcount: number; readonly value: Promise<RemoteTunnel | string | undefined> }): Promise<void> {
|
||||
if (tunnel.refcount <= 0) {
|
||||
this.logService.trace(`ForwardedPorts: (TunnelService) Tunnel is being disposed ${remoteHost}:${remotePort}.`);
|
||||
const disposePromise: Promise<void> = tunnel.value.then(async (tunnel) => {
|
||||
if (tunnel) {
|
||||
if (tunnel && (typeof tunnel !== 'string')) {
|
||||
await tunnel.dispose(true);
|
||||
this._onTunnelClosed.fire({ host: tunnel.tunnelRemoteHost, port: tunnel.tunnelRemotePort });
|
||||
}
|
||||
@@ -410,19 +414,19 @@ export abstract class AbstractTunnelService implements ITunnelService {
|
||||
}
|
||||
}
|
||||
|
||||
protected addTunnelToMap(remoteHost: string, remotePort: number, tunnel: Promise<RemoteTunnel | undefined>) {
|
||||
protected addTunnelToMap(remoteHost: string, remotePort: number, tunnel: Promise<RemoteTunnel | string | undefined>) {
|
||||
if (!this._tunnels.has(remoteHost)) {
|
||||
this._tunnels.set(remoteHost, new Map());
|
||||
}
|
||||
this._tunnels.get(remoteHost)!.set(remotePort, { refcount: 1, value: tunnel });
|
||||
}
|
||||
|
||||
private async removeEmptyTunnelFromMap(remoteHost: string, remotePort: number) {
|
||||
private async removeEmptyOrErrorTunnelFromMap(remoteHost: string, remotePort: number) {
|
||||
const hostMap = this._tunnels.get(remoteHost);
|
||||
if (hostMap) {
|
||||
const tunnel = hostMap.get(remotePort);
|
||||
const tunnelResult = tunnel ? await tunnel.value : undefined;
|
||||
if (!tunnelResult) {
|
||||
if (!tunnelResult || (typeof tunnelResult === 'string')) {
|
||||
hostMap.delete(remotePort);
|
||||
}
|
||||
if (hostMap.size === 0) {
|
||||
@@ -431,7 +435,7 @@ export abstract class AbstractTunnelService implements ITunnelService {
|
||||
}
|
||||
}
|
||||
|
||||
protected getTunnelFromMap(remoteHost: string, remotePort: number): { refcount: number; readonly value: Promise<RemoteTunnel | undefined> } | undefined {
|
||||
protected getTunnelFromMap(remoteHost: string, remotePort: number): { refcount: number; readonly value: Promise<RemoteTunnel | string | undefined> } | undefined {
|
||||
const hosts = [remoteHost];
|
||||
// Order matters. We want the original host to be first.
|
||||
if (isLocalhost(remoteHost)) {
|
||||
@@ -459,9 +463,9 @@ export abstract class AbstractTunnelService implements ITunnelService {
|
||||
|
||||
public abstract isPortPrivileged(port: number): boolean;
|
||||
|
||||
protected abstract retainOrCreateTunnel(addressProvider: IAddressProvider | ITunnelProvider, remoteHost: string, remotePort: number, localHost: string, localPort: number | undefined, elevateIfNeeded: boolean, privacy?: string, protocol?: string): Promise<RemoteTunnel | undefined> | undefined;
|
||||
protected abstract retainOrCreateTunnel(addressProvider: IAddressProvider | ITunnelProvider, remoteHost: string, remotePort: number, localHost: string, localPort: number | undefined, elevateIfNeeded: boolean, privacy?: string, protocol?: string): Promise<RemoteTunnel | string | undefined> | undefined;
|
||||
|
||||
protected createWithProvider(tunnelProvider: ITunnelProvider, remoteHost: string, remotePort: number, localPort: number | undefined, elevateIfNeeded: boolean, privacy?: string, protocol?: string): Promise<RemoteTunnel | undefined> | undefined {
|
||||
protected createWithProvider(tunnelProvider: ITunnelProvider, remoteHost: string, remotePort: number, localPort: number | undefined, elevateIfNeeded: boolean, privacy?: string, protocol?: string): Promise<RemoteTunnel | string | undefined> | undefined {
|
||||
this.logService.trace(`ForwardedPorts: (TunnelService) Creating tunnel with provider ${remoteHost}:${remotePort} on local port ${localPort}.`);
|
||||
const key = remotePort;
|
||||
this._factoryInProgress.add(key);
|
||||
|
||||
@@ -75,7 +75,7 @@ export class SharedProcessTunnelService extends Disposable implements ISharedPro
|
||||
const tunnelData = new TunnelData();
|
||||
|
||||
const tunnel = await Promise.resolve(this._tunnelService.openTunnel(authority, tunnelData, tunnelRemoteHost, tunnelRemotePort, tunnelLocalHost, tunnelLocalPort, elevateIfNeeded));
|
||||
if (!tunnel) {
|
||||
if (!tunnel || (typeof tunnel === 'string')) {
|
||||
this._logService.info(`[SharedProcessTunnelService] Could not create a tunnel to ${tunnelRemoteHost}:${tunnelRemotePort} (remote).`);
|
||||
tunnelData.dispose();
|
||||
throw new Error(`Could not create tunnel`);
|
||||
|
||||
@@ -168,7 +168,7 @@ export class BaseTunnelService extends AbstractTunnelService {
|
||||
return isPortPrivileged(port, this.defaultTunnelHost, OS, os.release());
|
||||
}
|
||||
|
||||
protected retainOrCreateTunnel(addressOrTunnelProvider: IAddressProvider | ITunnelProvider, remoteHost: string, remotePort: number, localHost: string, localPort: number | undefined, elevateIfNeeded: boolean, privacy?: string, protocol?: string): Promise<RemoteTunnel | undefined> | undefined {
|
||||
protected retainOrCreateTunnel(addressOrTunnelProvider: IAddressProvider | ITunnelProvider, remoteHost: string, remotePort: number, localHost: string, localPort: number | undefined, elevateIfNeeded: boolean, privacy?: string, protocol?: string): Promise<RemoteTunnel | string | undefined> | undefined {
|
||||
const existing = this.getTunnelFromMap(remoteHost, remotePort);
|
||||
if (existing) {
|
||||
++existing.refcount;
|
||||
@@ -223,7 +223,7 @@ export class SharedTunnelsService extends Disposable implements ISharedTunnelsSe
|
||||
super();
|
||||
}
|
||||
|
||||
async openTunnel(authority: string, addressProvider: IAddressProvider | undefined, remoteHost: string | undefined, remotePort: number, localHost: string, localPort?: number, elevateIfNeeded?: boolean, privacy?: string, protocol?: string): Promise<RemoteTunnel | undefined> {
|
||||
async openTunnel(authority: string, addressProvider: IAddressProvider | undefined, remoteHost: string | undefined, remotePort: number, localHost: string, localPort?: number, elevateIfNeeded?: boolean, privacy?: string, protocol?: string): Promise<RemoteTunnel | string | undefined> {
|
||||
this.logService.trace(`ForwardedPorts: (SharedTunnelService) openTunnel request for ${remoteHost}:${remotePort} on local port ${localPort}.`);
|
||||
if (!this._tunnelServices.has(authority)) {
|
||||
const tunnelService = new TunnelService(this.remoteSocketFactoryService, this.logService, this.signService, this.productService, this.configurationService);
|
||||
|
||||
@@ -72,7 +72,11 @@ export class WebviewPortMappingManager implements IDisposable {
|
||||
if (existing) {
|
||||
return existing;
|
||||
}
|
||||
const tunnel = await this.tunnelService.openTunnel({ getAddress: async () => remoteAuthority }, undefined, remotePort);
|
||||
const tunnelOrError = await this.tunnelService.openTunnel({ getAddress: async () => remoteAuthority }, undefined, remotePort);
|
||||
let tunnel: RemoteTunnel | undefined;
|
||||
if (typeof tunnelOrError === 'string') {
|
||||
tunnel = undefined;
|
||||
}
|
||||
if (tunnel) {
|
||||
this._tunnels.set(remotePort, tunnel);
|
||||
}
|
||||
|
||||
@@ -109,19 +109,19 @@ export class MainThreadTunnelService extends Disposable implements MainThreadTun
|
||||
},
|
||||
elevateIfNeeded: false
|
||||
});
|
||||
if (tunnel) {
|
||||
if (!this.elevateionRetry
|
||||
&& (tunnelOptions.localAddressPort !== undefined)
|
||||
&& (tunnel.tunnelLocalPort !== undefined)
|
||||
&& this.tunnelService.isPortPrivileged(tunnelOptions.localAddressPort)
|
||||
&& (tunnel.tunnelLocalPort !== tunnelOptions.localAddressPort)
|
||||
&& this.tunnelService.canElevate) {
|
||||
|
||||
this.elevationPrompt(tunnelOptions, tunnel, source);
|
||||
}
|
||||
return TunnelDtoConverter.fromServiceTunnel(tunnel);
|
||||
if (!tunnel || (typeof tunnel === 'string')) {
|
||||
return undefined;
|
||||
}
|
||||
return undefined;
|
||||
if (!this.elevateionRetry
|
||||
&& (tunnelOptions.localAddressPort !== undefined)
|
||||
&& (tunnel.tunnelLocalPort !== undefined)
|
||||
&& this.tunnelService.isPortPrivileged(tunnelOptions.localAddressPort)
|
||||
&& (tunnel.tunnelLocalPort !== tunnelOptions.localAddressPort)
|
||||
&& this.tunnelService.canElevate) {
|
||||
|
||||
this.elevationPrompt(tunnelOptions, tunnel, source);
|
||||
}
|
||||
return TunnelDtoConverter.fromServiceTunnel(tunnel);
|
||||
}
|
||||
|
||||
private async elevationPrompt(tunnelOptions: TunnelOptions, tunnel: RemoteTunnel, source: string) {
|
||||
@@ -170,11 +170,15 @@ export class MainThreadTunnelService extends Disposable implements MainThreadTun
|
||||
const tunnelProvider: ITunnelProvider = {
|
||||
forwardPort: (tunnelOptions: TunnelOptions, tunnelCreationOptions: TunnelCreationOptions) => {
|
||||
const forward = this._proxy.$forwardPort(tunnelOptions, tunnelCreationOptions);
|
||||
return forward.then(tunnel => {
|
||||
this.logService.trace(`ForwardedPorts: (MainThreadTunnelService) New tunnel established by tunnel provider: ${tunnel?.remoteAddress.host}:${tunnel?.remoteAddress.port}`);
|
||||
if (!tunnel) {
|
||||
return forward.then(tunnelOrError => {
|
||||
if (!tunnelOrError) {
|
||||
return undefined;
|
||||
} else if (typeof tunnelOrError === 'string') {
|
||||
return tunnelOrError;
|
||||
}
|
||||
const tunnel = tunnelOrError;
|
||||
this.logService.trace(`ForwardedPorts: (MainThreadTunnelService) New tunnel established by tunnel provider: ${tunnel?.remoteAddress.host}:${tunnel?.remoteAddress.port}`);
|
||||
|
||||
return {
|
||||
tunnelRemotePort: tunnel.remoteAddress.port,
|
||||
tunnelRemoteHost: tunnel.remoteAddress.host,
|
||||
|
||||
@@ -1521,8 +1521,8 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
LinkedEditingRanges: extHostTypes.LinkedEditingRanges,
|
||||
TestResultState: extHostTypes.TestResultState,
|
||||
TestRunRequest: extHostTypes.TestRunRequest,
|
||||
TestRunRequest2: extHostTypes.TestRunRequest2,
|
||||
TestMessage: extHostTypes.TestMessage,
|
||||
TestMessage2: extHostTypes.TestMessage,
|
||||
TestTag: extHostTypes.TestTag,
|
||||
TestRunProfileKind: extHostTypes.TestRunProfileKind,
|
||||
TextSearchCompleteMessageType: TextSearchCompleteMessageType,
|
||||
|
||||
@@ -2445,7 +2445,7 @@ export interface TunnelDto {
|
||||
|
||||
|
||||
export interface ExtHostTunnelServiceShape {
|
||||
$forwardPort(tunnelOptions: TunnelOptions, tunnelCreationOptions: TunnelCreationOptions): Promise<TunnelDto | undefined>;
|
||||
$forwardPort(tunnelOptions: TunnelOptions, tunnelCreationOptions: TunnelCreationOptions): Promise<TunnelDto | string | undefined>;
|
||||
$closeTunnel(remote: { host: string; port: number }, silent?: boolean): Promise<void>;
|
||||
$onDidTunnelsChange(): Promise<void>;
|
||||
$registerCandidateFinder(enable: boolean): Promise<void>;
|
||||
|
||||
@@ -17,7 +17,7 @@ import { MarshalledId } from 'vs/base/common/marshallingIds';
|
||||
import { deepFreeze } from 'vs/base/common/objects';
|
||||
import { isDefined } from 'vs/base/common/types';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { IExtensionDescription, IRelaxedExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtHostTestingShape, ILocationDto, MainContext, MainThreadTestingShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
@@ -28,13 +28,15 @@ import { TestRunProfileKind, TestRunRequest } from 'vs/workbench/api/common/extH
|
||||
import { TestCommandId } from 'vs/workbench/contrib/testing/common/constants';
|
||||
import { TestId, TestIdPathParts, TestPosition } from 'vs/workbench/contrib/testing/common/testId';
|
||||
import { InvalidTestItemError } from 'vs/workbench/contrib/testing/common/testItemCollection';
|
||||
import { AbstractIncrementalTestCollection, CoverageDetails, ICallProfileRunHandler, IFileCoverage, ISerializedTestResults, IStartControllerTests, IStartControllerTestsResult, ITestItem, ITestItemContext, IncrementalChangeCollector, IncrementalTestCollectionItem, InternalTestItem, TestResultState, TestRunProfileBitset, TestsDiff, TestsDiffOp, isStartControllerTests } from 'vs/workbench/contrib/testing/common/testTypes';
|
||||
import { AbstractIncrementalTestCollection, CoverageDetails, ICallProfileRunHandler, IFileCoverage, ISerializedTestResults, IStartControllerTests, IStartControllerTestsResult, ITestErrorMessage, ITestItem, ITestItemContext, ITestMessageMenuArgs, IncrementalChangeCollector, IncrementalTestCollectionItem, InternalTestItem, TestResultState, TestRunProfileBitset, TestsDiff, TestsDiffOp, isStartControllerTests } from 'vs/workbench/contrib/testing/common/testTypes';
|
||||
import { checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import type * as vscode from 'vscode';
|
||||
|
||||
interface ControllerInfo {
|
||||
controller: vscode.TestController;
|
||||
profiles: Map<number, vscode.TestRunProfile>;
|
||||
collection: ExtHostTestItemCollection;
|
||||
extension: Readonly<IRelaxedExtensionDescription>;
|
||||
}
|
||||
|
||||
export class ExtHostTesting implements ExtHostTestingShape {
|
||||
@@ -58,14 +60,22 @@ export class ExtHostTesting implements ExtHostTestingShape {
|
||||
|
||||
commands.registerArgumentProcessor({
|
||||
processArgument: arg => {
|
||||
if (arg?.$mid !== MarshalledId.TestItemContext) {
|
||||
return arg;
|
||||
switch (arg?.$mid) {
|
||||
case MarshalledId.TestItemContext: {
|
||||
const cast = arg as ITestItemContext;
|
||||
const targetTest = cast.tests[cast.tests.length - 1].item.extId;
|
||||
const controller = this.controllers.get(TestId.root(targetTest));
|
||||
return controller?.collection.tree.get(targetTest)?.actual ?? toItemFromContext(arg);
|
||||
}
|
||||
case MarshalledId.TestMessageMenuArgs: {
|
||||
const { extId, message } = arg as ITestMessageMenuArgs;
|
||||
return {
|
||||
test: this.controllers.get(TestId.root(extId))?.collection.tree.get(extId)?.actual,
|
||||
message: Convert.TestMessage.to(message as ITestErrorMessage.Serialized),
|
||||
};
|
||||
}
|
||||
default: return arg;
|
||||
}
|
||||
|
||||
const cast = arg as ITestItemContext;
|
||||
const targetTest = cast.tests[cast.tests.length - 1].item.extId;
|
||||
const controller = this.controllers.get(TestId.root(targetTest));
|
||||
return controller?.collection.tree.get(targetTest)?.actual ?? toItemFromContext(arg);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -137,7 +147,7 @@ export class ExtHostTesting implements ExtHostTestingShape {
|
||||
return new TestItemImpl(controllerId, id, label, uri);
|
||||
},
|
||||
createTestRun: (request, name, persist = true) => {
|
||||
return this.runTracker.createTestRun(controllerId, collection, request, name, persist);
|
||||
return this.runTracker.createTestRun(extension, controllerId, collection, request, name, persist);
|
||||
},
|
||||
invalidateTestResults: items => {
|
||||
if (items === undefined) {
|
||||
@@ -161,7 +171,7 @@ export class ExtHostTesting implements ExtHostTestingShape {
|
||||
proxy.$registerTestController(controllerId, label, !!refreshHandler);
|
||||
disposable.add(toDisposable(() => proxy.$unregisterTestController(controllerId)));
|
||||
|
||||
const info: ControllerInfo = { controller, collection, profiles: profiles };
|
||||
const info: ControllerInfo = { controller, collection, profiles: profiles, extension };
|
||||
this.controllers.set(controllerId, info);
|
||||
disposable.add(toDisposable(() => this.controllers.delete(controllerId)));
|
||||
|
||||
@@ -310,7 +320,7 @@ export class ExtHostTesting implements ExtHostTestingShape {
|
||||
return {};
|
||||
}
|
||||
|
||||
const { collection, profiles } = lookup;
|
||||
const { collection, profiles, extension } = lookup;
|
||||
const profile = profiles.get(req.profileId);
|
||||
if (!profile) {
|
||||
return {};
|
||||
@@ -341,6 +351,7 @@ export class ExtHostTesting implements ExtHostTestingShape {
|
||||
const tracker = isStartControllerTests(req) && this.runTracker.prepareForMainThreadTestRun(
|
||||
publicReq,
|
||||
TestRunDto.fromInternal(req, lookup.collection),
|
||||
extension,
|
||||
token,
|
||||
);
|
||||
|
||||
@@ -410,7 +421,12 @@ class TestRunTracker extends Disposable {
|
||||
return this.dto.id;
|
||||
}
|
||||
|
||||
constructor(private readonly dto: TestRunDto, private readonly proxy: MainThreadTestingShape, parentToken?: CancellationToken) {
|
||||
constructor(
|
||||
private readonly dto: TestRunDto,
|
||||
private readonly proxy: MainThreadTestingShape,
|
||||
private readonly extension: Readonly<IRelaxedExtensionDescription>,
|
||||
parentToken?: CancellationToken,
|
||||
) {
|
||||
super();
|
||||
this.cts = this._register(new CancellationTokenSource(parentToken));
|
||||
|
||||
@@ -460,6 +476,10 @@ class TestRunTracker extends Disposable {
|
||||
? messages.map(Convert.TestMessage.from)
|
||||
: [Convert.TestMessage.from(messages)];
|
||||
|
||||
if (converted.some(c => c.contextValue !== undefined)) {
|
||||
checkProposedApiEnabled(this.extension, 'testMessageContextValue');
|
||||
}
|
||||
|
||||
if (test.uri && test.range) {
|
||||
const defaultLocation: ILocationDto = { range: Convert.Range.from(test.range), uri: test.uri };
|
||||
for (const message of converted) {
|
||||
@@ -606,8 +626,8 @@ export class TestRunCoordinator {
|
||||
* `$startedExtensionTestRun` is not invoked. The run must eventually
|
||||
* be cancelled manually.
|
||||
*/
|
||||
public prepareForMainThreadTestRun(req: vscode.TestRunRequest, dto: TestRunDto, token: CancellationToken) {
|
||||
return this.getTracker(req, dto, token);
|
||||
public prepareForMainThreadTestRun(req: vscode.TestRunRequest, dto: TestRunDto, extension: Readonly<IRelaxedExtensionDescription>, token: CancellationToken) {
|
||||
return this.getTracker(req, dto, extension, token);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -635,7 +655,7 @@ export class TestRunCoordinator {
|
||||
/**
|
||||
* Implements the public `createTestRun` API.
|
||||
*/
|
||||
public createTestRun(controllerId: string, collection: ExtHostTestItemCollection, request: vscode.TestRunRequest, name: string | undefined, persist: boolean): vscode.TestRun {
|
||||
public createTestRun(extension: IRelaxedExtensionDescription, controllerId: string, collection: ExtHostTestItemCollection, request: vscode.TestRunRequest, name: string | undefined, persist: boolean): vscode.TestRun {
|
||||
const existing = this.tracked.get(request);
|
||||
if (existing) {
|
||||
return existing.createRun(name);
|
||||
@@ -655,7 +675,7 @@ export class TestRunCoordinator {
|
||||
persist
|
||||
});
|
||||
|
||||
const tracker = this.getTracker(request, dto);
|
||||
const tracker = this.getTracker(request, dto, extension);
|
||||
tracker.onEnd(() => {
|
||||
this.proxy.$finishedExtensionTestRun(dto.id);
|
||||
tracker.dispose();
|
||||
@@ -664,8 +684,8 @@ export class TestRunCoordinator {
|
||||
return tracker.createRun(name);
|
||||
}
|
||||
|
||||
private getTracker(req: vscode.TestRunRequest, dto: TestRunDto, token?: CancellationToken) {
|
||||
const tracker = new TestRunTracker(dto, this.proxy, token);
|
||||
private getTracker(req: vscode.TestRunRequest, dto: TestRunDto, extension: IRelaxedExtensionDescription, token?: CancellationToken) {
|
||||
const tracker = new TestRunTracker(dto, this.proxy, extension, token);
|
||||
this.tracked.set(req, tracker);
|
||||
tracker.onEnd(() => this.tracked.delete(req));
|
||||
return tracker;
|
||||
|
||||
@@ -227,7 +227,7 @@ export class ExtHostTunnelService extends Disposable implements IExtHostTunnelSe
|
||||
this._onDidChangeTunnels.fire();
|
||||
}
|
||||
|
||||
async $forwardPort(tunnelOptions: TunnelOptions, tunnelCreationOptions: TunnelCreationOptions): Promise<TunnelDto | undefined> {
|
||||
async $forwardPort(tunnelOptions: TunnelOptions, tunnelCreationOptions: TunnelCreationOptions): Promise<TunnelDto | string | undefined> {
|
||||
if (this._forwardPortProvider) {
|
||||
try {
|
||||
this.logService.trace('ForwardedPorts: (ExtHostTunnelService) Getting tunnel from provider.');
|
||||
@@ -254,6 +254,9 @@ export class ExtHostTunnelService extends Disposable implements IExtHostTunnelSe
|
||||
}
|
||||
} catch (e) {
|
||||
this.logService.trace('ForwardedPorts: (ExtHostTunnelService) tunnel provider error');
|
||||
if (e instanceof Error) {
|
||||
return e.message;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
|
||||
@@ -1799,20 +1799,22 @@ export namespace NotebookRendererScript {
|
||||
}
|
||||
|
||||
export namespace TestMessage {
|
||||
export function from(message: vscode.TestMessage): ITestErrorMessage.Serialized {
|
||||
export function from(message: vscode.TestMessage2): ITestErrorMessage.Serialized {
|
||||
return {
|
||||
message: MarkdownString.fromStrict(message.message) || '',
|
||||
type: TestMessageType.Error,
|
||||
expected: message.expectedOutput,
|
||||
actual: message.actualOutput,
|
||||
contextValue: message.contextValue,
|
||||
location: message.location && ({ range: Range.from(message.location.range), uri: message.location.uri }),
|
||||
};
|
||||
}
|
||||
|
||||
export function to(item: ITestErrorMessage.Serialized): vscode.TestMessage {
|
||||
export function to(item: ITestErrorMessage.Serialized): vscode.TestMessage2 {
|
||||
const message = new types.TestMessage(typeof item.message === 'string' ? item.message : MarkdownString.to(item.message));
|
||||
message.actualOutput = item.actual;
|
||||
message.expectedOutput = item.expected;
|
||||
message.contextValue = item.contextValue;
|
||||
message.location = item.location ? location.to(item.location) : undefined;
|
||||
return message;
|
||||
}
|
||||
|
||||
@@ -3884,15 +3884,13 @@ export class TestRunRequest implements vscode.TestRunRequest {
|
||||
) { }
|
||||
}
|
||||
|
||||
/** Back-compat for proposed API users */
|
||||
@es5ClassCompat
|
||||
export class TestRunRequest2 extends TestRunRequest { }
|
||||
|
||||
@es5ClassCompat
|
||||
export class TestMessage implements vscode.TestMessage {
|
||||
public expectedOutput?: string;
|
||||
public actualOutput?: string;
|
||||
public location?: vscode.Location;
|
||||
/** proposed: */
|
||||
public contextValue?: string;
|
||||
|
||||
public static diff(message: string | vscode.MarkdownString, expected: string, actual: string) {
|
||||
const msg = new TestMessage(message);
|
||||
|
||||
@@ -11,6 +11,7 @@ import { Iterable } from 'vs/base/common/iterator';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { mockObject, MockObject } from 'vs/base/test/common/mock';
|
||||
import * as editorRange from 'vs/editor/common/core/range';
|
||||
import { IRelaxedExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { MainThreadTestingShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
import { TestRunCoordinator, TestRunDto, TestRunProfileImpl } from 'vs/workbench/api/common/extHostTesting';
|
||||
@@ -594,6 +595,7 @@ suite('ExtHost Testing', () => {
|
||||
let req: TestRunRequest;
|
||||
|
||||
let dto: TestRunDto;
|
||||
const ext: IRelaxedExtensionDescription = {} as any;
|
||||
|
||||
setup(async () => {
|
||||
proxy = mockObject<MainThreadTestingShape>()();
|
||||
@@ -621,11 +623,11 @@ suite('ExtHost Testing', () => {
|
||||
});
|
||||
|
||||
test('tracks a run started from a main thread request', () => {
|
||||
const tracker = c.prepareForMainThreadTestRun(req, dto, cts.token);
|
||||
const tracker = c.prepareForMainThreadTestRun(req, dto, ext, cts.token);
|
||||
assert.strictEqual(tracker.hasRunningTasks, false);
|
||||
|
||||
const task1 = c.createTestRun('ctrl', single, req, 'run1', true);
|
||||
const task2 = c.createTestRun('ctrl', single, req, 'run2', true);
|
||||
const task1 = c.createTestRun(ext, 'ctrl', single, req, 'run1', true);
|
||||
const task2 = c.createTestRun(ext, 'ctrl', single, req, 'run2', true);
|
||||
assert.strictEqual(proxy.$startedExtensionTestRun.called, false);
|
||||
assert.strictEqual(tracker.hasRunningTasks, true);
|
||||
|
||||
@@ -646,8 +648,8 @@ suite('ExtHost Testing', () => {
|
||||
test('run cancel force ends after a timeout', () => {
|
||||
const clock = sinon.useFakeTimers();
|
||||
try {
|
||||
const tracker = c.prepareForMainThreadTestRun(req, dto, cts.token);
|
||||
const task = c.createTestRun('ctrl', single, req, 'run1', true);
|
||||
const tracker = c.prepareForMainThreadTestRun(req, dto, ext, cts.token);
|
||||
const task = c.createTestRun(ext, 'ctrl', single, req, 'run1', true);
|
||||
const onEnded = sinon.stub();
|
||||
tracker.onEnd(onEnded);
|
||||
|
||||
@@ -671,8 +673,8 @@ suite('ExtHost Testing', () => {
|
||||
});
|
||||
|
||||
test('run cancel force ends on second cancellation request', () => {
|
||||
const tracker = c.prepareForMainThreadTestRun(req, dto, cts.token);
|
||||
const task = c.createTestRun('ctrl', single, req, 'run1', true);
|
||||
const tracker = c.prepareForMainThreadTestRun(req, dto, ext, cts.token);
|
||||
const task = c.createTestRun(ext, 'ctrl', single, req, 'run1', true);
|
||||
const onEnded = sinon.stub();
|
||||
tracker.onEnd(onEnded);
|
||||
|
||||
@@ -690,7 +692,7 @@ suite('ExtHost Testing', () => {
|
||||
});
|
||||
|
||||
test('tracks a run started from an extension request', () => {
|
||||
const task1 = c.createTestRun('ctrl', single, req, 'hello world', false);
|
||||
const task1 = c.createTestRun(ext, 'ctrl', single, req, 'hello world', false);
|
||||
|
||||
const tracker = Iterable.first(c.trackers)!;
|
||||
assert.strictEqual(tracker.hasRunningTasks, true);
|
||||
@@ -706,8 +708,8 @@ suite('ExtHost Testing', () => {
|
||||
}]
|
||||
]);
|
||||
|
||||
const task2 = c.createTestRun('ctrl', single, req, 'run2', true);
|
||||
const task3Detached = c.createTestRun('ctrl', single, { ...req }, 'task3Detached', true);
|
||||
const task2 = c.createTestRun(ext, 'ctrl', single, req, 'run2', true);
|
||||
const task3Detached = c.createTestRun(ext, 'ctrl', single, { ...req }, 'task3Detached', true);
|
||||
|
||||
task1.end();
|
||||
assert.strictEqual(proxy.$finishedExtensionTestRun.called, false);
|
||||
@@ -721,7 +723,7 @@ suite('ExtHost Testing', () => {
|
||||
});
|
||||
|
||||
test('adds tests to run smartly', () => {
|
||||
const task1 = c.createTestRun('ctrlId', single, req, 'hello world', false);
|
||||
const task1 = c.createTestRun(ext, 'ctrlId', single, req, 'hello world', false);
|
||||
const tracker = Iterable.first(c.trackers)!;
|
||||
const expectedArgs: unknown[][] = [];
|
||||
assert.deepStrictEqual(proxy.$addTestsToRun.args, expectedArgs);
|
||||
@@ -758,7 +760,7 @@ suite('ExtHost Testing', () => {
|
||||
const test2 = new TestItemImpl('ctrlId', 'id-d', 'test d', URI.file('/testd.txt'));
|
||||
test1.range = test2.range = new Range(new Position(0, 0), new Position(1, 0));
|
||||
single.root.children.replace([test1, test2]);
|
||||
const task = c.createTestRun('ctrlId', single, req, 'hello world', false);
|
||||
const task = c.createTestRun(ext, 'ctrlId', single, req, 'hello world', false);
|
||||
|
||||
const message1 = new TestMessage('some message');
|
||||
message1.location = new Location(URI.file('/a.txt'), new Position(0, 0));
|
||||
@@ -773,6 +775,7 @@ suite('ExtHost Testing', () => {
|
||||
message: 'some message',
|
||||
type: TestMessageType.Error,
|
||||
expected: undefined,
|
||||
contextValue: undefined,
|
||||
actual: undefined,
|
||||
location: convert.location.from(message1.location)
|
||||
}]
|
||||
@@ -787,6 +790,7 @@ suite('ExtHost Testing', () => {
|
||||
[{
|
||||
message: 'some message',
|
||||
type: TestMessageType.Error,
|
||||
contextValue: undefined,
|
||||
expected: undefined,
|
||||
actual: undefined,
|
||||
location: convert.location.from({ uri: test2.uri!, range: test2.range! }),
|
||||
@@ -795,7 +799,7 @@ suite('ExtHost Testing', () => {
|
||||
});
|
||||
|
||||
test('guards calls after runs are ended', () => {
|
||||
const task = c.createTestRun('ctrl', single, req, 'hello world', false);
|
||||
const task = c.createTestRun(ext, 'ctrl', single, req, 'hello world', false);
|
||||
task.end();
|
||||
|
||||
task.failed(single.root, new TestMessage('some message'));
|
||||
@@ -807,7 +811,7 @@ suite('ExtHost Testing', () => {
|
||||
});
|
||||
|
||||
test('excludes tests outside tree or explicitly excluded', () => {
|
||||
const task = c.createTestRun('ctrlId', single, {
|
||||
const task = c.createTestRun(ext, 'ctrlId', single, {
|
||||
profile: configuration,
|
||||
include: [single.root.children.get('id-a')!],
|
||||
exclude: [single.root.children.get('id-a')!.children.get('id-aa')!],
|
||||
@@ -835,7 +839,7 @@ suite('ExtHost Testing', () => {
|
||||
const childB = new TestItemImpl('ctrlId', 'id-child', 'child', undefined);
|
||||
testB!.children.replace([childB]);
|
||||
|
||||
const task1 = c.createTestRun('ctrl', single, new TestRunRequestImpl(), 'hello world', false);
|
||||
const task1 = c.createTestRun(ext, 'ctrl', single, new TestRunRequestImpl(), 'hello world', false);
|
||||
const tracker = Iterable.first(c.trackers)!;
|
||||
|
||||
task1.passed(childA);
|
||||
|
||||
@@ -3,28 +3,25 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Widget } from 'vs/base/browser/ui/widget';
|
||||
import { IOverlayWidget, ICodeEditor, IOverlayWidgetPosition, OverlayWidgetPositionPreference, isCodeEditor, isCompositeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { $, append, clearNode } from 'vs/base/browser/dom';
|
||||
import { buttonBackground, buttonForeground, editorBackground, editorForeground, contrastBorder, asCssVariableWithDefault, asCssVariable } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { IEditorContribution } from 'vs/editor/common/editorCommon';
|
||||
import { isEqual } from 'vs/base/common/resources';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition, OverlayWidgetPositionPreference, isCodeEditor, isCompositeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { EmbeddedCodeEditorWidget } from 'vs/editor/browser/widget/embeddedCodeEditorWidget';
|
||||
import { EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { IRange } from 'vs/editor/common/core/range';
|
||||
import { CursorChangeReason, ICursorPositionChangedEvent } from 'vs/editor/common/cursorEvents';
|
||||
import { IEditorContribution } from 'vs/editor/common/editorCommon';
|
||||
import { IModelDecorationsChangeAccessor, TrackedRangeStickiness } from 'vs/editor/common/model';
|
||||
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
|
||||
import { TrackedRangeStickiness, IModelDecorationsChangeAccessor } from 'vs/editor/common/model';
|
||||
import { EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { AbstractFloatingClickMenu, FloatingClickWidget } from 'vs/platform/actions/browser/floatingMenu';
|
||||
import { IMenuService, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import { EmbeddedCodeEditorWidget } from 'vs/editor/browser/widget/embeddedCodeEditorWidget';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
|
||||
export interface IRangeHighlightDecoration {
|
||||
resource: URI;
|
||||
@@ -134,106 +131,65 @@ export class RangeHighlightDecorations extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
export class FloatingClickWidget extends Widget implements IOverlayWidget {
|
||||
|
||||
private readonly _onClick = this._register(new Emitter<void>());
|
||||
readonly onClick = this._onClick.event;
|
||||
|
||||
private _domNode: HTMLElement;
|
||||
export class FloatingEditorClickWidget extends FloatingClickWidget implements IOverlayWidget {
|
||||
|
||||
constructor(
|
||||
private editor: ICodeEditor,
|
||||
private label: string,
|
||||
label: string,
|
||||
keyBindingAction: string | null,
|
||||
@IKeybindingService keybindingService: IKeybindingService
|
||||
) {
|
||||
super();
|
||||
|
||||
this._domNode = $('.floating-click-widget');
|
||||
this._domNode.style.padding = '6px 11px';
|
||||
this._domNode.style.borderRadius = '2px';
|
||||
this._domNode.style.cursor = 'pointer';
|
||||
this._domNode.style.zIndex = '1';
|
||||
|
||||
if (keyBindingAction) {
|
||||
const keybinding = keybindingService.lookupKeybinding(keyBindingAction);
|
||||
if (keybinding) {
|
||||
this.label += ` (${keybinding.getLabel()})`;
|
||||
}
|
||||
}
|
||||
super(
|
||||
keyBindingAction && keybindingService.lookupKeybinding(keyBindingAction)
|
||||
? `${label} (${keybindingService.lookupKeybinding(keyBindingAction)!.getLabel()})`
|
||||
: label
|
||||
);
|
||||
}
|
||||
|
||||
getId(): string {
|
||||
return 'editor.overlayWidget.floatingClickWidget';
|
||||
}
|
||||
|
||||
getDomNode(): HTMLElement {
|
||||
return this._domNode;
|
||||
}
|
||||
|
||||
getPosition(): IOverlayWidgetPosition {
|
||||
return {
|
||||
preference: OverlayWidgetPositionPreference.BOTTOM_RIGHT_CORNER
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
clearNode(this._domNode);
|
||||
this._domNode.style.backgroundColor = asCssVariableWithDefault(buttonBackground, asCssVariable(editorBackground));
|
||||
this._domNode.style.color = asCssVariableWithDefault(buttonForeground, asCssVariable(editorForeground));
|
||||
this._domNode.style.border = `1px solid ${asCssVariable(contrastBorder)}`;
|
||||
|
||||
append(this._domNode, $('')).textContent = this.label;
|
||||
|
||||
this.onclick(this._domNode, e => this._onClick.fire());
|
||||
|
||||
override render() {
|
||||
super.render();
|
||||
this.editor.addOverlayWidget(this);
|
||||
}
|
||||
|
||||
override dispose(): void {
|
||||
this.editor.removeOverlayWidget(this);
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class FloatingClickMenu extends Disposable implements IEditorContribution {
|
||||
|
||||
export class FloatingEditorClickMenu extends AbstractFloatingClickMenu implements IEditorContribution {
|
||||
static readonly ID = 'editor.contrib.floatingClickMenu';
|
||||
|
||||
constructor(
|
||||
editor: ICodeEditor,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
private readonly editor: ICodeEditor,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@IMenuService menuService: IMenuService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService
|
||||
) {
|
||||
super();
|
||||
super(MenuId.EditorContent, menuService, contextKeyService);
|
||||
this.render();
|
||||
}
|
||||
|
||||
// DISABLED for embedded editors. In the future we can use a different MenuId for embedded editors
|
||||
if (!(editor instanceof EmbeddedCodeEditorWidget)) {
|
||||
const menu = menuService.createMenu(MenuId.EditorContent, contextKeyService);
|
||||
const menuDisposables = new DisposableStore();
|
||||
const renderMenuAsFloatingClickBtn = () => {
|
||||
menuDisposables.clear();
|
||||
if (!editor.hasModel() || editor.getOption(EditorOption.inDiffEditor)) {
|
||||
return;
|
||||
}
|
||||
const actions: IAction[] = [];
|
||||
createAndFillInActionBarActions(menu, { renderShortTitle: true, shouldForwardArgs: true }, actions);
|
||||
if (actions.length === 0) {
|
||||
return;
|
||||
}
|
||||
// todo@jrieken find a way to handle N actions, like showing a context menu
|
||||
const [first] = actions;
|
||||
const widget = instantiationService.createInstance(FloatingClickWidget, editor, first.label, first.id);
|
||||
menuDisposables.add(widget);
|
||||
menuDisposables.add(widget.onClick(() => first.run(editor.getModel().uri)));
|
||||
widget.render();
|
||||
};
|
||||
this._store.add(menu);
|
||||
this._store.add(menuDisposables);
|
||||
this._store.add(menu.onDidChange(renderMenuAsFloatingClickBtn));
|
||||
renderMenuAsFloatingClickBtn();
|
||||
}
|
||||
protected override createWidget(action: IAction): FloatingClickWidget {
|
||||
return this.instantiationService.createInstance(FloatingEditorClickWidget, this.editor, action.label, action.id);
|
||||
}
|
||||
|
||||
protected override isVisible() {
|
||||
return !(this.editor instanceof EmbeddedCodeEditorWidget) && this.editor?.hasModel() && !this.editor.getOption(EditorOption.inDiffEditor);
|
||||
}
|
||||
|
||||
protected override getActionArg(): unknown {
|
||||
return this.editor.getModel()?.uri;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/co
|
||||
import { ContextKeyExpr, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
import { EditorContributionInstantiation, registerEditorContribution } from 'vs/editor/browser/editorExtensions';
|
||||
import { FloatingClickMenu } from 'vs/workbench/browser/codeeditor';
|
||||
import { FloatingEditorClickMenu } from 'vs/workbench/browser/codeeditor';
|
||||
import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions';
|
||||
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
||||
import { EditorAutoSave } from 'vs/workbench/browser/parts/editor/editorAutoSave';
|
||||
@@ -131,7 +131,7 @@ Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).regi
|
||||
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(UntitledTextEditorWorkingCopyEditorHandler, LifecyclePhase.Ready);
|
||||
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DynamicEditorConfigurations, LifecyclePhase.Ready);
|
||||
|
||||
registerEditorContribution(FloatingClickMenu.ID, FloatingClickMenu, EditorContributionInstantiation.AfterFirstRender);
|
||||
registerEditorContribution(FloatingEditorClickMenu.ID, FloatingEditorClickMenu, EditorContributionInstantiation.AfterFirstRender);
|
||||
//#endregion
|
||||
|
||||
//#region Quick Access
|
||||
|
||||
@@ -211,6 +211,10 @@ export class BrowserMain extends Disposable {
|
||||
protocol: tunnelOptions.protocol === TunnelProtocol.Https ? tunnelOptions.protocol : TunnelProtocol.Http
|
||||
}));
|
||||
|
||||
if (typeof tunnel === 'string') {
|
||||
throw new Error(tunnel);
|
||||
}
|
||||
|
||||
return new class extends DisposableTunnel implements ITunnel {
|
||||
declare localAddress: string;
|
||||
}({
|
||||
|
||||
@@ -311,7 +311,7 @@ class AccessibleView extends Disposable {
|
||||
let ariaLabel = '';
|
||||
let helpHint = '';
|
||||
const verbose = this._configurationService.getValue(provider.verbositySettingKey);
|
||||
if (verbose && provider.options.type === AccessibleViewType.View) {
|
||||
if (verbose && provider.options.type === AccessibleViewType.View && !showAccessibleViewHelp) {
|
||||
const accessibilityHelpKeybinding = this._keybindingService.lookupKeybinding(AccessibilityCommandId.OpenAccessibilityHelp)?.getLabel();
|
||||
if (accessibilityHelpKeybinding) {
|
||||
helpHint = localize('ariaAccessibilityHelp', "Use {0} for accessibility help", accessibilityHelpKeybinding);
|
||||
|
||||
@@ -270,18 +270,19 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
|
||||
const followupsHeight = this.followupsContainer.offsetHeight;
|
||||
|
||||
const inputPartBorder = 1;
|
||||
const inputPartPadding = 24;
|
||||
const inputEditorHeight = Math.min(this._inputEditor.getContentHeight(), height - followupsHeight - inputPartPadding - inputPartBorder, INPUT_EDITOR_MAX_HEIGHT);
|
||||
const inputPartHorizontalPadding = 40;
|
||||
const inputPartVerticalPadding = 24;
|
||||
const inputEditorHeight = Math.min(this._inputEditor.getContentHeight(), height - followupsHeight - inputPartHorizontalPadding - inputPartBorder, INPUT_EDITOR_MAX_HEIGHT);
|
||||
|
||||
const inputEditorBorder = 2;
|
||||
const inputPartHeight = followupsHeight + inputEditorHeight + inputPartPadding + inputPartBorder + inputEditorBorder;
|
||||
const inputPartHeight = followupsHeight + inputEditorHeight + inputPartVerticalPadding + inputPartBorder + inputEditorBorder;
|
||||
|
||||
const editorBorder = 2;
|
||||
const editorPadding = 8;
|
||||
const executeToolbarWidth = 25;
|
||||
|
||||
const initialEditorScrollWidth = this._inputEditor.getScrollWidth();
|
||||
this._inputEditor.layout({ width: width - inputPartPadding - editorBorder - editorPadding - executeToolbarWidth, height: inputEditorHeight });
|
||||
this._inputEditor.layout({ width: width - inputPartHorizontalPadding - editorBorder - editorPadding - executeToolbarWidth, height: inputEditorHeight });
|
||||
|
||||
if (allowRecurse && initialEditorScrollWidth < 10) {
|
||||
// This is probably the initial layout. Now that the editor is layed out with its correct width, it should report the correct contentHeight
|
||||
|
||||
@@ -124,7 +124,6 @@
|
||||
}
|
||||
|
||||
.interactive-request {
|
||||
background-color: var(--vscode-chat-requestBackground);
|
||||
border-bottom: 1px solid var(--vscode-chat-requestBorder);
|
||||
border-top: 1px solid var(--vscode-chat-requestBorder);
|
||||
}
|
||||
@@ -183,13 +182,12 @@
|
||||
display: flex;
|
||||
box-sizing: border-box;
|
||||
cursor: text;
|
||||
margin: 0px 12px;
|
||||
margin: 0px 20px;
|
||||
background-color: var(--vscode-input-background);
|
||||
border: 1px solid var(--vscode-input-border, transparent);
|
||||
border-radius: 2px;
|
||||
position: relative;
|
||||
padding: 0 4px;
|
||||
margin-bottom: 4px;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
@@ -297,8 +295,6 @@
|
||||
padding: 12px 0px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-top: solid 1px var(--vscode-chat-requestBorder);
|
||||
border-bottom: solid 1px var(--vscode-chat-requestBorder);
|
||||
}
|
||||
|
||||
.interactive-session-followups {
|
||||
|
||||
@@ -7,13 +7,6 @@ import { Color, RGBA } from 'vs/base/common/color';
|
||||
import { localize } from 'vs/nls';
|
||||
import { badgeBackground, badgeForeground, registerColor } from 'vs/platform/theme/common/colorRegistry';
|
||||
|
||||
|
||||
export const chatRequestBackground = registerColor(
|
||||
'chat.requestBackground',
|
||||
{ dark: new Color(new RGBA(255, 255, 255, 0.03)), light: new Color(new RGBA(0, 0, 0, 0.03)), hcDark: null, hcLight: null, },
|
||||
localize('chat.requestBackground', 'The background color of a chat request.')
|
||||
);
|
||||
|
||||
export const chatRequestBorder = registerColor(
|
||||
'chat.requestBorder',
|
||||
{ dark: new Color(new RGBA(255, 255, 255, 0.10)), light: new Color(new RGBA(0, 0, 0, 0.10)), hcDark: null, hcLight: null, },
|
||||
|
||||
@@ -18,7 +18,7 @@ import { ContextKeyEqualsExpr, ContextKeyExpr } from 'vs/platform/contextkey/com
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
||||
import { FloatingClickWidget } from 'vs/workbench/browser/codeeditor';
|
||||
import { FloatingEditorClickWidget } from 'vs/workbench/browser/codeeditor';
|
||||
import { AccessibilityVerbositySettingId } from 'vs/workbench/contrib/accessibility/browser/accessibilityConfiguration';
|
||||
import { AccessibleViewType, IAccessibleViewService } from 'vs/workbench/contrib/accessibility/browser/accessibleView';
|
||||
import { AccessibilityHelpAction } from 'vs/workbench/contrib/accessibility/browser/accessibleViewActions';
|
||||
@@ -47,7 +47,7 @@ class DiffEditorHelperContribution extends Disposable implements IDiffEditorCont
|
||||
/** @description update state */
|
||||
if (onlyWhiteSpaceChange.read(reader)) {
|
||||
const helperWidget = store.add(this._instantiationService.createInstance(
|
||||
FloatingClickWidget,
|
||||
FloatingEditorClickWidget,
|
||||
this._diffEditor.getModifiedEditor(),
|
||||
localize('hintWhitespace', "Show Whitespace Differences"),
|
||||
null
|
||||
|
||||
@@ -41,7 +41,7 @@ import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/c
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { registerColor } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity';
|
||||
import { FloatingClickWidget } from 'vs/workbench/browser/codeeditor';
|
||||
import { FloatingEditorClickWidget } from 'vs/workbench/browser/codeeditor';
|
||||
import { DebugHoverWidget, ShowDebugHoverResult } from 'vs/workbench/contrib/debug/browser/debugHover';
|
||||
import { ExceptionWidget } from 'vs/workbench/contrib/debug/browser/exceptionWidget';
|
||||
import { CONTEXT_EXCEPTION_WIDGET_VISIBLE, IDebugConfiguration, IDebugEditorContribution, IDebugService, IDebugSession, IExceptionInfo, IExpression, IStackFrame, State } from 'vs/workbench/contrib/debug/common/debug';
|
||||
@@ -219,7 +219,7 @@ export class DebugEditorContribution implements IDebugEditorContribution {
|
||||
private gutterIsHovered = false;
|
||||
|
||||
private exceptionWidget: ExceptionWidget | undefined;
|
||||
private configurationWidget: FloatingClickWidget | undefined;
|
||||
private configurationWidget: FloatingEditorClickWidget | undefined;
|
||||
private altListener: IDisposable | undefined;
|
||||
private altPressed = false;
|
||||
private oldDecorations = this.editor.createDecorationsCollection();
|
||||
|
||||
@@ -617,7 +617,6 @@ registerAction2(class ToggleCellOutputScrolling extends NotebookMultiCellAction
|
||||
const currentlyEnabled = cellMetadata['scrollable'] !== undefined ? cellMetadata['scrollable'] : globalScrollSetting;
|
||||
const shouldEnableScrolling = collapsed || !currentlyEnabled;
|
||||
cellMetadata['scrollable'] = shouldEnableScrolling;
|
||||
viewModel.model.bumpVersion();
|
||||
viewModel.resetRenderer();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ import { EditorExtensionsRegistry } from 'vs/editor/browser/editorExtensions';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { NotebookPerfMarks } from 'vs/workbench/contrib/notebook/common/notebookPerformance';
|
||||
import { BaseCellEditorOptions } from 'vs/workbench/contrib/notebook/browser/viewModel/cellEditorOptions';
|
||||
import { FloatingClickMenu } from 'vs/workbench/browser/codeeditor';
|
||||
import { FloatingEditorClickMenu } from 'vs/workbench/browser/codeeditor';
|
||||
import { IDimension } from 'vs/editor/common/core/dimension';
|
||||
import { CellFindMatchModel } from 'vs/workbench/contrib/notebook/browser/contrib/find/findModel';
|
||||
import { INotebookLoggingService } from 'vs/workbench/contrib/notebook/common/notebookLoggingService';
|
||||
@@ -107,7 +107,7 @@ export function getDefaultNotebookCreationOptions(): INotebookEditorCreationOpti
|
||||
// We inlined the id to avoid loading comment contrib in tests
|
||||
const skipContributions = [
|
||||
'editor.contrib.review',
|
||||
FloatingClickMenu.ID,
|
||||
FloatingEditorClickMenu.ID,
|
||||
'editor.contrib.dirtydiff',
|
||||
'editor.contrib.testingOutputPeek',
|
||||
'editor.contrib.testingDecorations',
|
||||
|
||||
@@ -55,6 +55,7 @@ export class CellOutputViewModel extends Disposable implements ICellOutputViewMo
|
||||
resetRenderer() {
|
||||
// reset the output renderer
|
||||
this._pickedMimeType = undefined;
|
||||
this.model.bumpVersion();
|
||||
this._onDidResetRendererEmitter.fire();
|
||||
}
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ export class NotebookCellOutputTextModel extends Disposable implements ICellOutp
|
||||
}
|
||||
}
|
||||
|
||||
toJSON(): IOutputDto {
|
||||
asDto(): IOutputDto {
|
||||
return {
|
||||
// data: this._data,
|
||||
metadata: this._rawOutput.metadata,
|
||||
|
||||
@@ -1066,7 +1066,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
||||
rawEvents: [{
|
||||
kind: NotebookCellsChangeType.Output,
|
||||
index: this._cells.indexOf(cell),
|
||||
outputs: cell.outputs ?? [],
|
||||
outputs: cell.outputs.map(output => output.asDto()) ?? [],
|
||||
append,
|
||||
transient: this.transientOptions.transientOutputs,
|
||||
}],
|
||||
|
||||
@@ -218,6 +218,7 @@ export interface ICellOutput {
|
||||
replaceData(items: IOutputDto): void;
|
||||
appendData(items: IOutputItemDto[]): void;
|
||||
appendedSinceVersion(versionId: number, mime: string): VSBuffer | undefined;
|
||||
asDto(): IOutputDto;
|
||||
bumpVersion(): void;
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,8 @@ export class ForwardedPortsView extends Disposable implements IWorkbenchContribu
|
||||
) {
|
||||
super();
|
||||
this._register(Registry.as<IViewsRegistry>(Extensions.ViewsRegistry).registerViewWelcomeContent(TUNNEL_VIEW_ID, {
|
||||
content: `No forwarded ports. Forward a port to access your running services locally.\n[Forward a Port](command:${ForwardPortAction.INLINE_ID})`,
|
||||
content: this.environmentService.remoteAuthority ? nls.localize('remoteNoPorts', "No forwarded ports. Forward a port to access your running services locally.\n[Forward a Port]({0})", `command:${ForwardPortAction.INLINE_ID}`)
|
||||
: nls.localize('noRemoteNoPorts', "No forwarded ports. Forward a port to access your locally running services over the internet.\n[Forward a Port]({0})", `command:${ForwardPortAction.INLINE_ID}`),
|
||||
}));
|
||||
this.enableBadgeAndStatusBar();
|
||||
this.enableForwardedPortsView();
|
||||
@@ -411,7 +412,7 @@ class OnAutoForwardedAction extends Disposable {
|
||||
elevateIfNeeded: true,
|
||||
source: AutoTunnelSource
|
||||
});
|
||||
if (!newTunnel) {
|
||||
if (!newTunnel || (typeof newTunnel === 'string')) {
|
||||
return;
|
||||
}
|
||||
this.lastNotification?.close();
|
||||
@@ -492,7 +493,7 @@ class OutputAutomaticPortForwarding extends Disposable {
|
||||
return;
|
||||
}
|
||||
const forwarded = await this.remoteExplorerService.forward({ remote: localUrl, source: AutoTunnelSource }, attributes ?? null);
|
||||
if (forwarded) {
|
||||
if (forwarded && (typeof forwarded !== 'string')) {
|
||||
this.notifier.doAction([forwarded]);
|
||||
}
|
||||
}));
|
||||
@@ -632,7 +633,7 @@ class ProcAutomaticPortForwarding extends Disposable {
|
||||
this.logService.trace(`ForwardedPorts: (ProcForwarding) Port ${value.port} has been notified`);
|
||||
this.notifiedOnly.add(address);
|
||||
}
|
||||
if (forwarded) {
|
||||
if (forwarded && (typeof forwarded !== 'string')) {
|
||||
allTunnels.push(forwarded);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ export class TunnelFactoryContribution extends Disposable implements IWorkbenchC
|
||||
}
|
||||
|
||||
this._register(tunnelService.setTunnelProvider({
|
||||
forwardPort: async (tunnelOptions: TunnelOptions, tunnelCreationOptions: TunnelCreationOptions): Promise<RemoteTunnel | undefined> => {
|
||||
forwardPort: async (tunnelOptions: TunnelOptions, tunnelCreationOptions: TunnelCreationOptions): Promise<RemoteTunnel | string | undefined> => {
|
||||
let tunnelPromise: Promise<ITunnel> | undefined;
|
||||
try {
|
||||
tunnelPromise = tunnelFactory(tunnelOptions, tunnelCreationOptions);
|
||||
@@ -64,6 +64,9 @@ export class TunnelFactoryContribution extends Disposable implements IWorkbenchC
|
||||
tunnel = await tunnelPromise;
|
||||
} catch (e) {
|
||||
logService.trace('tunnelFactory: tunnel provider promise error');
|
||||
if (e instanceof Error) {
|
||||
return e.message;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
const localAddress = tunnel.localAddress.startsWith('http') ? tunnel.localAddress : `http://${tunnel.localAddress}`;
|
||||
|
||||
@@ -1149,9 +1149,11 @@ export namespace ForwardPortAction {
|
||||
return null;
|
||||
}
|
||||
|
||||
function error(notificationService: INotificationService, tunnel: RemoteTunnel | void, host: string, port: number) {
|
||||
if (!tunnel) {
|
||||
function error(notificationService: INotificationService, tunnelOrError: RemoteTunnel | string | void, host: string, port: number) {
|
||||
if (!tunnelOrError) {
|
||||
notificationService.warn(nls.localize('remote.tunnel.forwardError', "Unable to forward {0}:{1}. The host may not be available or that remote port may already be forwarded", host, port));
|
||||
} else if (typeof tunnelOrError === 'string') {
|
||||
notificationService.warn(nls.localize('remote.tunnel.forwardErrorProvided', "Unable to forward {0}:{1}. {2}", host, port, tunnelOrError));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1168,7 +1170,7 @@ export namespace ForwardPortAction {
|
||||
remoteExplorerService.forward({
|
||||
remote: { host: parsed.host, port: parsed.port },
|
||||
elevateIfNeeded: true
|
||||
}).then(tunnel => error(notificationService, tunnel, parsed!.host, parsed!.port));
|
||||
}).then(tunnelOrError => error(notificationService, tunnelOrError, parsed!.host, parsed!.port));
|
||||
}
|
||||
},
|
||||
validationMessage: (value) => validateInput(remoteExplorerService, tunnelService, value, tunnelService.canElevate),
|
||||
@@ -1477,7 +1479,7 @@ namespace ChangeLocalPortAction {
|
||||
elevateIfNeeded: true,
|
||||
source: tunnelItem.source
|
||||
});
|
||||
if (newForward && newForward.tunnelLocalPort !== numberValue) {
|
||||
if (newForward && (typeof newForward !== 'string') && newForward.tunnelLocalPort !== numberValue) {
|
||||
notificationService.warn(nls.localize('remote.tunnel.changeLocalPortNumber', "The local port {0} is not available. Port number {1} has been used instead", value, newForward.tunnelLocalPort ?? newForward.localAddress));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +120,12 @@ if (Get-Module -Name PSReadLine) {
|
||||
}
|
||||
|
||||
# Set IsWindows property
|
||||
[Console]::Write("$([char]0x1b)]633;P;IsWindows=$($IsWindows)`a")
|
||||
if ($PSVersionTable.PSVersion -lt "6.0") {
|
||||
# Windows PowerShell is only available on Windows
|
||||
[Console]::Write("$([char]0x1b)]633;P;IsWindows=$true`a")
|
||||
} else {
|
||||
[Console]::Write("$([char]0x1b)]633;P;IsWindows=$IsWindows`a")
|
||||
}
|
||||
|
||||
# Set always on key handlers which map to default VS Code keybindings
|
||||
function Set-MappedKeyHandler {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import type { IBuffer, ITheme, Terminal as RawXtermTerminal, LogLevel as XtermLogLevel } from 'xterm';
|
||||
import type { IBuffer, ITerminalOptions, ITheme, Terminal as RawXtermTerminal, LogLevel as XtermLogLevel } from 'xterm';
|
||||
import type { CanvasAddon as CanvasAddonType } from 'xterm-addon-canvas';
|
||||
import type { ISearchOptions, SearchAddon as SearchAddonType } from 'xterm-addon-search';
|
||||
import type { Unicode11Addon as Unicode11AddonType } from 'xterm-addon-unicode11';
|
||||
@@ -17,7 +17,7 @@ import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/term
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
|
||||
import { IShellIntegration, ITerminalLogService, TerminalSettingId } from 'vs/platform/terminal/common/terminal';
|
||||
import { ITerminalFont } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { ITerminalFont, ITerminalConfiguration } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { isSafari } from 'vs/base/browser/browser';
|
||||
import { IMarkTracker, IInternalXtermTerminal, IXtermTerminal, ISuggestController, IXtermColorProvider, XtermTerminalConstants, IXtermAttachToElementOptions, IDetachedXtermTerminal } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||
import { LogLevel } from 'vs/platform/log/common/log';
|
||||
@@ -229,7 +229,8 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, ID
|
||||
minimumContrastRatio: config.minimumContrastRatio,
|
||||
tabStopWidth: config.tabStopWidth,
|
||||
cursorBlink: config.cursorBlinking,
|
||||
cursorStyle: config.cursorStyle === 'line' ? 'bar' : config.cursorStyle,
|
||||
cursorStyle: vscodeToXtermCursorStyle<'cursorStyle'>(config.cursorStyle),
|
||||
cursorInactiveStyle: vscodeToXtermCursorStyle(config.cursorStyleInactive),
|
||||
cursorWidth: config.cursorWidth,
|
||||
macOptionIsMeta: config.macOptionIsMeta,
|
||||
macOptionClickForcesSelection: config.macOptionClickForcesSelection,
|
||||
@@ -396,6 +397,7 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, ID
|
||||
this.raw.options.altClickMovesCursor = config.altClickMovesCursor;
|
||||
this._setCursorBlink(config.cursorBlinking);
|
||||
this._setCursorStyle(config.cursorStyle);
|
||||
this._setCursorStyleInactive(config.cursorStyleInactive);
|
||||
this._setCursorWidth(config.cursorWidth);
|
||||
this.raw.options.scrollback = config.scrollback;
|
||||
this.raw.options.drawBoldTextInBrightColors = config.drawBoldTextInBrightColors;
|
||||
@@ -653,10 +655,17 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, ID
|
||||
}
|
||||
}
|
||||
|
||||
private _setCursorStyle(style: 'block' | 'underline' | 'bar' | 'line'): void {
|
||||
if (this.raw.options.cursorStyle !== style) {
|
||||
// 'line' is used instead of bar in VS Code to be consistent with editor.cursorStyle
|
||||
this.raw.options.cursorStyle = (style === 'line') ? 'bar' : style;
|
||||
private _setCursorStyle(style: ITerminalConfiguration['cursorStyle']): void {
|
||||
const mapped = vscodeToXtermCursorStyle<'cursorStyle'>(style);
|
||||
if (this.raw.options.cursorStyle !== mapped) {
|
||||
this.raw.options.cursorStyle = mapped;
|
||||
}
|
||||
}
|
||||
|
||||
private _setCursorStyleInactive(style: ITerminalConfiguration['cursorStyleInactive']): void {
|
||||
const mapped = vscodeToXtermCursorStyle(style);
|
||||
if (this.raw.options.cursorInactiveStyle !== mapped) {
|
||||
this.raw.options.cursorInactiveStyle = mapped;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -962,3 +971,15 @@ function vscodeToXtermLogLevel(logLevel: LogLevel): XtermLogLevel {
|
||||
default: return 'off';
|
||||
}
|
||||
}
|
||||
|
||||
interface ICursorStyleVscodeToXtermMap {
|
||||
'cursorStyle': NonNullable<ITerminalOptions['cursorStyle']>;
|
||||
'cursorStyleInactive': NonNullable<ITerminalOptions['cursorInactiveStyle']>;
|
||||
}
|
||||
function vscodeToXtermCursorStyle<T extends 'cursorStyle' | 'cursorStyleInactive'>(style: ITerminalConfiguration[T]): ICursorStyleVscodeToXtermMap[T] {
|
||||
// 'line' is used instead of bar in VS Code to be consistent with editor.cursorStyle
|
||||
if (style === 'line') {
|
||||
return 'bar';
|
||||
}
|
||||
return style as ICursorStyleVscodeToXtermMap[T];
|
||||
}
|
||||
|
||||
@@ -22,12 +22,6 @@ export const TERMINAL_VIEW_ID = 'terminal';
|
||||
|
||||
export const TERMINAL_CREATION_COMMANDS = ['workbench.action.terminal.toggleTerminal', 'workbench.action.terminal.new', 'workbench.action.togglePanel', 'workbench.action.terminal.focus'];
|
||||
|
||||
export const TerminalCursorStyle = {
|
||||
BLOCK: 'block',
|
||||
LINE: 'line',
|
||||
UNDERLINE: 'underline'
|
||||
};
|
||||
|
||||
export const TERMINAL_CONFIG_SECTION = 'terminal.integrated';
|
||||
|
||||
export const DEFAULT_LETTER_SPACING = 0;
|
||||
@@ -145,6 +139,7 @@ export interface ITerminalConfiguration {
|
||||
rightClickBehavior: 'default' | 'copyPaste' | 'paste' | 'selectWord' | 'nothing';
|
||||
cursorBlinking: boolean;
|
||||
cursorStyle: 'block' | 'underline' | 'line';
|
||||
cursorStyleInactive: 'outline' | 'block' | 'underline' | 'line' | 'none';
|
||||
cursorWidth: number;
|
||||
drawBoldTextInBrightColors: boolean;
|
||||
fastScrollSensitivity: number;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { ConfigurationScope, Extensions, IConfigurationNode, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { localize } from 'vs/nls';
|
||||
import { DEFAULT_LETTER_SPACING, DEFAULT_LINE_HEIGHT, TerminalCursorStyle, DEFAULT_COMMANDS_TO_SKIP_SHELL, SUGGESTIONS_FONT_WEIGHT, MINIMUM_FONT_WEIGHT, MAXIMUM_FONT_WEIGHT, DEFAULT_LOCAL_ECHO_EXCLUDE } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { DEFAULT_LETTER_SPACING, DEFAULT_LINE_HEIGHT, DEFAULT_COMMANDS_TO_SKIP_SHELL, SUGGESTIONS_FONT_WEIGHT, MINIMUM_FONT_WEIGHT, MAXIMUM_FONT_WEIGHT, DEFAULT_LOCAL_ECHO_EXCLUDE } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { TerminalLocationString, TerminalSettingId } from 'vs/platform/terminal/common/terminal';
|
||||
import { isMacintosh, isWindows } from 'vs/base/common/platform';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
@@ -259,9 +259,14 @@ const terminalConfiguration: IConfigurationNode = {
|
||||
default: false
|
||||
},
|
||||
[TerminalSettingId.CursorStyle]: {
|
||||
description: localize('terminal.integrated.cursorStyle', "Controls the style of terminal cursor."),
|
||||
enum: [TerminalCursorStyle.BLOCK, TerminalCursorStyle.LINE, TerminalCursorStyle.UNDERLINE],
|
||||
default: TerminalCursorStyle.BLOCK
|
||||
description: localize('terminal.integrated.cursorStyle', "Controls the style of terminal cursor when the terminal is focused."),
|
||||
enum: ['block', 'line', 'underline'],
|
||||
default: 'block'
|
||||
},
|
||||
[TerminalSettingId.CursorStyleInactive]: {
|
||||
description: localize('terminal.integrated.cursorStyleInactive', "Controls the style of terminal cursor when the terminal is not focused."),
|
||||
enum: ['outline', 'block', 'line', 'underline', 'none'],
|
||||
default: 'outline'
|
||||
},
|
||||
[TerminalSettingId.CursorWidth]: {
|
||||
markdownDescription: localize('terminal.integrated.cursorWidth', "Controls the width of the cursor when {0} is set to {1}.", '`#terminal.integrated.cursorStyle#`', '`line`'),
|
||||
|
||||
@@ -71,11 +71,14 @@ function generateLinkSuffixRegex(eolOnly: boolean) {
|
||||
const lineAndColumnRegexClauses = [
|
||||
// foo:339
|
||||
// foo:339:12
|
||||
// foo:339.12
|
||||
// foo 339
|
||||
// foo 339:12 [#140780]
|
||||
// foo 339.12
|
||||
// "foo",339
|
||||
// "foo",339:12
|
||||
`(?::| |['"],)${r()}(:${c()})?` + eolSuffix,
|
||||
// "foo",339.12
|
||||
`(?::| |['"],)${r()}([:.]${c()})?` + eolSuffix,
|
||||
// The quotes below are optional [#171652]
|
||||
// "foo", line 339 [#40468]
|
||||
// "foo", line 339, col 12
|
||||
|
||||
+4
@@ -43,12 +43,15 @@ const testLinks: ITestLink[] = [
|
||||
{ link: 'foo', prefix: undefined, suffix: undefined, hasRow: false, hasCol: false },
|
||||
{ link: 'foo:339', prefix: undefined, suffix: ':339', hasRow: true, hasCol: false },
|
||||
{ link: 'foo:339:12', prefix: undefined, suffix: ':339:12', hasRow: true, hasCol: true },
|
||||
{ link: 'foo:339.12', prefix: undefined, suffix: ':339.12', hasRow: true, hasCol: true },
|
||||
{ link: 'foo 339', prefix: undefined, suffix: ' 339', hasRow: true, hasCol: false },
|
||||
{ link: 'foo 339:12', prefix: undefined, suffix: ' 339:12', hasRow: true, hasCol: true },
|
||||
{ link: 'foo 339.12', prefix: undefined, suffix: ' 339.12', hasRow: true, hasCol: true },
|
||||
|
||||
// Double quotes
|
||||
{ link: '"foo",339', prefix: '"', suffix: '",339', hasRow: true, hasCol: false },
|
||||
{ link: '"foo",339:12', prefix: '"', suffix: '",339:12', hasRow: true, hasCol: true },
|
||||
{ link: '"foo",339.12', prefix: '"', suffix: '",339.12', hasRow: true, hasCol: true },
|
||||
{ link: '"foo", line 339', prefix: '"', suffix: '", line 339', hasRow: true, hasCol: false },
|
||||
{ link: '"foo", line 339, col 12', prefix: '"', suffix: '", line 339, col 12', hasRow: true, hasCol: true },
|
||||
{ link: '"foo", line 339, column 12', prefix: '"', suffix: '", line 339, column 12', hasRow: true, hasCol: true },
|
||||
@@ -67,6 +70,7 @@ const testLinks: ITestLink[] = [
|
||||
// Single quotes
|
||||
{ link: '\'foo\',339', prefix: '\'', suffix: '\',339', hasRow: true, hasCol: false },
|
||||
{ link: '\'foo\',339:12', prefix: '\'', suffix: '\',339:12', hasRow: true, hasCol: true },
|
||||
{ link: '\'foo\',339.12', prefix: '\'', suffix: '\',339.12', hasRow: true, hasCol: true },
|
||||
{ link: '\'foo\', line 339', prefix: '\'', suffix: '\', line 339', hasRow: true, hasCol: false },
|
||||
{ link: '\'foo\', line 339, col 12', prefix: '\'', suffix: '\', line 339, col 12', hasRow: true, hasCol: true },
|
||||
{ link: '\'foo\', line 339, column 12', prefix: '\'', suffix: '\', line 339, column 12', hasRow: true, hasCol: true },
|
||||
|
||||
@@ -199,6 +199,12 @@
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.test-output-peek-message-container .floating-click-widget {
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
bottom: 10px;
|
||||
}
|
||||
|
||||
.test-output-peek-message-container,
|
||||
.test-output-peek-tree {
|
||||
height: 100%;
|
||||
|
||||
@@ -27,6 +27,7 @@ import { Iterable } from 'vs/base/common/iterator';
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import { Lazy } from 'vs/base/common/lazy';
|
||||
import { Disposable, DisposableStore, IDisposable, IReference, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { MarshalledId } from 'vs/base/common/marshallingIds';
|
||||
import { count } from 'vs/base/common/strings';
|
||||
import { ThemeIcon } from 'vs/base/common/themables';
|
||||
import { isDefined } from 'vs/base/common/types';
|
||||
@@ -48,6 +49,7 @@ import { MarkdownRenderer } from 'vs/editor/contrib/markdownRenderer/browser/mar
|
||||
import { IPeekViewService, PeekViewWidget, peekViewResultsBackground, peekViewTitleForeground, peekViewTitleInfoForeground } from 'vs/editor/contrib/peekView/browser/peekView';
|
||||
import { localize } from 'vs/nls';
|
||||
import { Categories } from 'vs/platform/action/common/actionCommonCategories';
|
||||
import { FloatingClickMenu } from 'vs/platform/actions/browser/floatingMenu';
|
||||
import { MenuEntryActionViewItem, createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
|
||||
import { Action2, IMenuService, MenuId, MenuItemAction } from 'vs/platform/actions/common/actions';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
@@ -88,7 +90,7 @@ import { ITestProfileService } from 'vs/workbench/contrib/testing/common/testPro
|
||||
import { ITaskRawOutput, ITestResult, ITestRunTaskResults, LiveTestResult, TestResultItemChange, TestResultItemChangeReason, maxCountPriority, resultItemParents } from 'vs/workbench/contrib/testing/common/testResult';
|
||||
import { ITestResultService, ResultChangeEvent } from 'vs/workbench/contrib/testing/common/testResultService';
|
||||
import { ITestService } from 'vs/workbench/contrib/testing/common/testService';
|
||||
import { IRichLocation, ITestErrorMessage, ITestItem, ITestMessage, ITestRunTask, ITestTaskState, TestMessageType, TestResultItem, TestResultState, TestRunProfileBitset, getMarkId } from 'vs/workbench/contrib/testing/common/testTypes';
|
||||
import { IRichLocation, ITestErrorMessage, ITestItem, ITestMessage, ITestMessageMenuArgs, ITestRunTask, ITestTaskState, TestMessageType, TestResultItem, TestResultState, TestRunProfileBitset, getMarkId } from 'vs/workbench/contrib/testing/common/testTypes';
|
||||
import { TestingContextKeys } from 'vs/workbench/contrib/testing/common/testingContextKeys';
|
||||
import { IShowResultOptions, ITestingPeekOpener } from 'vs/workbench/contrib/testing/common/testingPeekOpener';
|
||||
import { cmpPriority, isFailedState } from 'vs/workbench/contrib/testing/common/testingStates';
|
||||
@@ -98,20 +100,30 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
|
||||
class MessageSubject {
|
||||
public readonly test: ITestItem;
|
||||
public readonly message: ITestMessage;
|
||||
public readonly messages: ITestMessage[];
|
||||
public readonly expectedUri: URI;
|
||||
public readonly actualUri: URI;
|
||||
public readonly messageUri: URI;
|
||||
public readonly revealLocation: IRichLocation | undefined;
|
||||
|
||||
public get isDiffable() {
|
||||
const message = this.messages[this.messageIndex];
|
||||
return message.type === TestMessageType.Error && isDiffable(message);
|
||||
return this.message.type === TestMessageType.Error && isDiffable(this.message);
|
||||
}
|
||||
|
||||
public get contextValue() {
|
||||
return this.message.type === TestMessageType.Error ? this.message.contextValue : undefined;
|
||||
}
|
||||
|
||||
public get context(): ITestMessageMenuArgs {
|
||||
return {
|
||||
$mid: MarshalledId.TestMessageMenuArgs,
|
||||
extId: this.test.extId,
|
||||
message: ITestMessage.serialize(this.message),
|
||||
};
|
||||
}
|
||||
|
||||
constructor(public readonly resultId: string, test: TestResultItem, public readonly taskIndex: number, public readonly messageIndex: number) {
|
||||
this.test = test.item;
|
||||
this.messages = test.tasks[taskIndex].messages;
|
||||
const messages = test.tasks[taskIndex].messages;
|
||||
this.messageIndex = messageIndex;
|
||||
|
||||
const parts = { messageIndex, resultId, taskIndex, testExtId: test.item.extId };
|
||||
@@ -119,7 +131,7 @@ class MessageSubject {
|
||||
this.actualUri = buildTestUri({ ...parts, type: TestUriType.ResultActualOutput });
|
||||
this.messageUri = buildTestUri({ ...parts, type: TestUriType.ResultMessage });
|
||||
|
||||
const message = this.message = this.messages[this.messageIndex];
|
||||
const message = this.message = messages[this.messageIndex];
|
||||
this.revealLocation = message.location ?? (test.item.uri && test.item.range ? { uri: test.item.uri, range: Range.lift(test.item.range) } : undefined);
|
||||
}
|
||||
}
|
||||
@@ -148,7 +160,7 @@ type InspectSubject = MessageSubject | TaskSubject | TestOutputSubject;
|
||||
|
||||
const equalsSubject = (a: InspectSubject, b: InspectSubject) =>
|
||||
a.resultId === b.resultId && a.taskIndex === b.taskIndex && (
|
||||
(a instanceof MessageSubject && b instanceof MessageSubject && a.messageIndex === b.messageIndex) ||
|
||||
(a instanceof MessageSubject && b instanceof MessageSubject && a.message === b.message) ||
|
||||
(a instanceof TaskSubject && b instanceof TaskSubject) ||
|
||||
(a instanceof TestOutputSubject && b instanceof TestOutputSubject && a.test === b.test)
|
||||
);
|
||||
@@ -746,8 +758,10 @@ class TestResultsViewContent extends Disposable {
|
||||
private static lastSplitWidth?: number;
|
||||
|
||||
private readonly didReveal = this._register(new Emitter<{ subject: InspectSubject; preserveFocus: boolean }>());
|
||||
private readonly clickMenu = this._register(new MutableDisposable<FloatingClickMenu>());
|
||||
private dimension?: dom.Dimension;
|
||||
private splitView!: SplitView;
|
||||
private messageContainer!: HTMLElement;
|
||||
private contentProviders!: IPeekOutputRenderer[];
|
||||
private contentProvidersUpdateLimiter = this._register(new Limiter(1));
|
||||
|
||||
@@ -764,6 +778,7 @@ class TestResultsViewContent extends Disposable {
|
||||
},
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@ITextModelService protected readonly modelService: ITextModelService,
|
||||
@IContextKeyService private readonly contextKeyService: IContextKeyService,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
@@ -774,7 +789,7 @@ class TestResultsViewContent extends Disposable {
|
||||
|
||||
const { historyVisible, showRevealLocationOnMessages } = this.options;
|
||||
const isInPeekView = this.editor !== undefined;
|
||||
const messageContainer = dom.append(containerElement, dom.$('.test-output-peek-message-container'));
|
||||
const messageContainer = this.messageContainer = dom.append(containerElement, dom.$('.test-output-peek-message-container'));
|
||||
this.contentProviders = [
|
||||
this._register(this.instantiationService.createInstance(DiffContentProvider, this.editor, messageContainer)),
|
||||
this._register(this.instantiationService.createInstance(MarkdownTestMessagePeek, messageContainer)),
|
||||
@@ -834,14 +849,30 @@ class TestResultsViewContent extends Disposable {
|
||||
* Shows a message in-place without showing or changing the peek location.
|
||||
* This is mostly used if peeking a message without a location.
|
||||
*/
|
||||
public async reveal(opts: { subject: InspectSubject; preserveFocus: boolean }) {
|
||||
public reveal(opts: { subject: InspectSubject; preserveFocus: boolean }) {
|
||||
this.didReveal.fire(opts);
|
||||
|
||||
if (!this.current || !equalsSubject(this.current, opts.subject)) {
|
||||
this.current = opts.subject;
|
||||
await this.contentProvidersUpdateLimiter.queue(() => Promise.all(
|
||||
this.contentProviders.map(p => p.update(opts.subject))));
|
||||
if (this.current && equalsSubject(this.current, opts.subject)) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
this.current = opts.subject;
|
||||
return this.contentProvidersUpdateLimiter.queue(async () => {
|
||||
await Promise.all(this.contentProviders.map(p => p.update(opts.subject)));
|
||||
|
||||
if (opts.subject instanceof MessageSubject) {
|
||||
const contextOverlay = this.contextKeyService.createOverlay([[TestingContextKeys.testMessageContext.key, opts.subject.contextValue]]);
|
||||
this.clickMenu.value = this.instantiationService
|
||||
.createChild(new ServiceCollection([IContextKeyService, contextOverlay]))
|
||||
.createInstance(FloatingClickMenu, {
|
||||
container: this.messageContainer,
|
||||
menuId: MenuId.TestMessageContent,
|
||||
getActionArg: () => (opts.subject as MessageSubject).context,
|
||||
});
|
||||
} else {
|
||||
this.clickMenu.clear();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public onLayoutBody(height: number, width: number) {
|
||||
@@ -1507,11 +1538,15 @@ class TerminalMessagePeek extends Disposable implements IPeekOutputRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
const hintMessagePeekHeight = (msg: ITestMessage) =>
|
||||
isDiffable(msg)
|
||||
const hintMessagePeekHeight = (msg: ITestMessage) => {
|
||||
const msgHeight = isDiffable(msg)
|
||||
? Math.max(hintPeekStrHeight(msg.actual), hintPeekStrHeight(msg.expected))
|
||||
: hintPeekStrHeight(typeof msg.message === 'string' ? msg.message : msg.message.value);
|
||||
|
||||
// add 8ish lines for the size of the title and decorations in the peek.
|
||||
return msgHeight + 8;
|
||||
};
|
||||
|
||||
const firstLine = (str: string) => {
|
||||
const index = str.indexOf('\n');
|
||||
return index === -1 ? str : str.slice(0, index);
|
||||
@@ -1519,8 +1554,7 @@ const firstLine = (str: string) => {
|
||||
|
||||
const isMultiline = (str: string | undefined) => !!str && str.includes('\n');
|
||||
|
||||
// add 5ish lines for the size of the title and decorations in the peek.
|
||||
const hintPeekStrHeight = (str: string) => Math.min(count(str, '\n') + 5, 24);
|
||||
const hintPeekStrHeight = (str: string) => Math.min(count(str, '\n'), 24);
|
||||
|
||||
class SimpleDiffEditorModel extends EditorModel {
|
||||
public readonly original = this._original.object.textEditorModel;
|
||||
@@ -1671,13 +1705,23 @@ class TaskElement implements ITreeElement {
|
||||
|
||||
class TestMessageElement implements ITreeElement {
|
||||
public readonly type = 'message';
|
||||
public readonly context: URI;
|
||||
public readonly id: string;
|
||||
public readonly label: string;
|
||||
public readonly uri: URI;
|
||||
public readonly location?: IRichLocation;
|
||||
public readonly description?: string;
|
||||
public readonly onDidChange = Event.None;
|
||||
public readonly contextValue?: string;
|
||||
public readonly message: ITestMessage;
|
||||
|
||||
public get context(): ITestMessageMenuArgs {
|
||||
return {
|
||||
$mid: MarshalledId.TestMessageMenuArgs,
|
||||
extId: this.test.item.extId,
|
||||
message: ITestMessage.serialize(this.message),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
constructor(
|
||||
public readonly result: ITestResult,
|
||||
@@ -1685,10 +1729,11 @@ class TestMessageElement implements ITreeElement {
|
||||
public readonly taskIndex: number,
|
||||
public readonly messageIndex: number,
|
||||
) {
|
||||
const m = test.tasks[taskIndex].messages[messageIndex];
|
||||
const m = this.message = test.tasks[taskIndex].messages[messageIndex];
|
||||
|
||||
this.location = m.location;
|
||||
this.uri = this.context = buildTestUri({
|
||||
this.contextValue = m.type === TestMessageType.Error ? m.contextValue : undefined;
|
||||
this.uri = buildTestUri({
|
||||
type: TestUriType.ResultMessage,
|
||||
messageIndex,
|
||||
resultId: result.id,
|
||||
@@ -2084,7 +2129,7 @@ class TestRunElementRenderer implements ICompressibleTreeRenderer<ITreeElement,
|
||||
|
||||
const actions = this.treeActions.provideActionBar(element);
|
||||
templateData.actionBar.clear();
|
||||
templateData.actionBar.context = element;
|
||||
templateData.actionBar.context = element.context;
|
||||
templateData.actionBar.push(actions.primary, { icon: true, label: false });
|
||||
}
|
||||
}
|
||||
@@ -2103,130 +2148,134 @@ class TreeActionsProvider {
|
||||
public provideActionBar(element: ITreeElement) {
|
||||
const test = element instanceof TestCaseElement ? element.test : undefined;
|
||||
const capabilities = test ? this.testProfileService.capabilitiesForTest(test) : 0;
|
||||
const contextOverlay = this.contextKeyService.createOverlay([
|
||||
|
||||
const contextKeys: [string, unknown][] = [
|
||||
['peek', Testing.OutputPeekContributionId],
|
||||
[TestingContextKeys.peekItemType.key, element.type],
|
||||
...getTestItemContextOverlay(test, capabilities),
|
||||
]);
|
||||
const menu = this.menuService.createMenu(MenuId.TestPeekElement, contextOverlay);
|
||||
];
|
||||
|
||||
try {
|
||||
const primary: IAction[] = [];
|
||||
const secondary: IAction[] = [];
|
||||
let id = MenuId.TestPeekElement;
|
||||
const primary: IAction[] = [];
|
||||
const secondary: IAction[] = [];
|
||||
|
||||
if (element instanceof TaskElement) {
|
||||
if (element instanceof TaskElement) {
|
||||
primary.push(new Action(
|
||||
'testing.outputPeek.showResultOutput',
|
||||
localize('testing.showResultOutput', "Show Result Output"),
|
||||
ThemeIcon.asClassName(Codicon.terminal),
|
||||
undefined,
|
||||
() => this.requestReveal.fire(new TaskSubject(element.results.id, element.index)),
|
||||
));
|
||||
}
|
||||
|
||||
if (element instanceof TestResultElement) {
|
||||
// only show if there are no collapsed test nodes that have more specific choices
|
||||
if (element.value.tasks.length === 1) {
|
||||
primary.push(new Action(
|
||||
'testing.outputPeek.showResultOutput',
|
||||
localize('testing.showResultOutput', "Show Result Output"),
|
||||
ThemeIcon.asClassName(Codicon.terminal),
|
||||
undefined,
|
||||
() => this.requestReveal.fire(new TaskSubject(element.results.id, element.index)),
|
||||
() => this.requestReveal.fire(new TaskSubject(element.value.id, 0)),
|
||||
));
|
||||
}
|
||||
|
||||
if (element instanceof TestResultElement) {
|
||||
// only show if there are no collapsed test nodes that have more specific choices
|
||||
if (element.value.tasks.length === 1) {
|
||||
primary.push(new Action(
|
||||
'testing.outputPeek.showResultOutput',
|
||||
localize('testing.showResultOutput', "Show Result Output"),
|
||||
ThemeIcon.asClassName(Codicon.terminal),
|
||||
undefined,
|
||||
() => this.requestReveal.fire(new TaskSubject(element.value.id, 0)),
|
||||
));
|
||||
}
|
||||
primary.push(new Action(
|
||||
'testing.outputPeek.reRunLastRun',
|
||||
localize('testing.reRunLastRun', "Rerun Test Run"),
|
||||
ThemeIcon.asClassName(icons.testingRunIcon),
|
||||
undefined,
|
||||
() => this.commandService.executeCommand('testing.reRunLastRun', element.value.id),
|
||||
));
|
||||
|
||||
if (capabilities & TestRunProfileBitset.Debug) {
|
||||
primary.push(new Action(
|
||||
'testing.outputPeek.reRunLastRun',
|
||||
localize('testing.reRunLastRun', "Rerun Test Run"),
|
||||
'testing.outputPeek.debugLastRun',
|
||||
localize('testing.debugLastRun', "Debug Test Run"),
|
||||
ThemeIcon.asClassName(icons.testingDebugIcon),
|
||||
undefined,
|
||||
() => this.commandService.executeCommand('testing.debugLastRun', element.value.id),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if (element instanceof TestCaseElement) {
|
||||
const extId = element.test.item.extId;
|
||||
contextKeys.push(...getTestItemContextOverlay(element.test, capabilities));
|
||||
|
||||
primary.push(new Action(
|
||||
'testing.outputPeek.goToFile',
|
||||
localize('testing.goToFile', "Go to Source"),
|
||||
ThemeIcon.asClassName(Codicon.goToFile),
|
||||
undefined,
|
||||
() => this.commandService.executeCommand('vscode.revealTest', extId),
|
||||
));
|
||||
|
||||
if (element.test.tasks[element.taskIndex].messages.some(m => m.type === TestMessageType.Output)) {
|
||||
primary.push(new Action(
|
||||
'testing.outputPeek.showResultOutput',
|
||||
localize('testing.showResultOutput', "Show Result Output"),
|
||||
ThemeIcon.asClassName(Codicon.terminal),
|
||||
undefined,
|
||||
() => this.requestReveal.fire(element.outputSubject),
|
||||
));
|
||||
}
|
||||
|
||||
secondary.push(new Action(
|
||||
'testing.outputPeek.revealInExplorer',
|
||||
localize('testing.revealInExplorer', "Reveal in Test Explorer"),
|
||||
ThemeIcon.asClassName(Codicon.listTree),
|
||||
undefined,
|
||||
() => this.commandService.executeCommand('_revealTestInExplorer', extId),
|
||||
));
|
||||
|
||||
if (capabilities & TestRunProfileBitset.Run) {
|
||||
primary.push(new Action(
|
||||
'testing.outputPeek.runTest',
|
||||
localize('run test', 'Run Test'),
|
||||
ThemeIcon.asClassName(icons.testingRunIcon),
|
||||
undefined,
|
||||
() => this.commandService.executeCommand('testing.reRunLastRun', element.value.id),
|
||||
() => this.commandService.executeCommand('vscode.runTestsById', TestRunProfileBitset.Run, extId),
|
||||
));
|
||||
|
||||
if (capabilities & TestRunProfileBitset.Debug) {
|
||||
primary.push(new Action(
|
||||
'testing.outputPeek.debugLastRun',
|
||||
localize('testing.debugLastRun', "Debug Test Run"),
|
||||
ThemeIcon.asClassName(icons.testingDebugIcon),
|
||||
undefined,
|
||||
() => this.commandService.executeCommand('testing.debugLastRun', element.value.id),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if (element instanceof TestCaseElement) {
|
||||
const extId = element.test.item.extId;
|
||||
if (capabilities & TestRunProfileBitset.Debug) {
|
||||
primary.push(new Action(
|
||||
'testing.outputPeek.goToFile',
|
||||
localize('testing.goToFile', "Go to Source"),
|
||||
'testing.outputPeek.debugTest',
|
||||
localize('debug test', 'Debug Test'),
|
||||
ThemeIcon.asClassName(icons.testingDebugIcon),
|
||||
undefined,
|
||||
() => this.commandService.executeCommand('vscode.runTestsById', TestRunProfileBitset.Debug, extId),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if (element instanceof TestMessageElement) {
|
||||
id = MenuId.TestMessageContext;
|
||||
contextKeys.push([TestingContextKeys.testMessageContext.key, element.contextValue]);
|
||||
if (this.showRevealLocationOnMessages && element.location) {
|
||||
primary.push(new Action(
|
||||
'testing.outputPeek.goToError',
|
||||
localize('testing.goToError', "Go to Source"),
|
||||
ThemeIcon.asClassName(Codicon.goToFile),
|
||||
undefined,
|
||||
() => this.commandService.executeCommand('vscode.revealTest', extId),
|
||||
() => this.editorService.openEditor({
|
||||
resource: element.location!.uri,
|
||||
options: {
|
||||
selection: element.location!.range,
|
||||
preserveFocus: true,
|
||||
}
|
||||
}),
|
||||
));
|
||||
|
||||
if (element.test.tasks[element.taskIndex].messages.some(m => m.type === TestMessageType.Output)) {
|
||||
primary.push(new Action(
|
||||
'testing.outputPeek.showResultOutput',
|
||||
localize('testing.showResultOutput', "Show Result Output"),
|
||||
ThemeIcon.asClassName(Codicon.terminal),
|
||||
undefined,
|
||||
() => this.requestReveal.fire(element.outputSubject),
|
||||
));
|
||||
}
|
||||
|
||||
secondary.push(new Action(
|
||||
'testing.outputPeek.revealInExplorer',
|
||||
localize('testing.revealInExplorer', "Reveal in Test Explorer"),
|
||||
ThemeIcon.asClassName(Codicon.listTree),
|
||||
undefined,
|
||||
() => this.commandService.executeCommand('_revealTestInExplorer', extId),
|
||||
));
|
||||
|
||||
if (capabilities & TestRunProfileBitset.Run) {
|
||||
primary.push(new Action(
|
||||
'testing.outputPeek.runTest',
|
||||
localize('run test', 'Run Test'),
|
||||
ThemeIcon.asClassName(icons.testingRunIcon),
|
||||
undefined,
|
||||
() => this.commandService.executeCommand('vscode.runTestsById', TestRunProfileBitset.Run, extId),
|
||||
));
|
||||
}
|
||||
|
||||
if (capabilities & TestRunProfileBitset.Debug) {
|
||||
primary.push(new Action(
|
||||
'testing.outputPeek.debugTest',
|
||||
localize('debug test', 'Debug Test'),
|
||||
ThemeIcon.asClassName(icons.testingDebugIcon),
|
||||
undefined,
|
||||
() => this.commandService.executeCommand('vscode.runTestsById', TestRunProfileBitset.Debug, extId),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (element instanceof TestMessageElement) {
|
||||
if (this.showRevealLocationOnMessages && element.location) {
|
||||
primary.push(new Action(
|
||||
'testing.outputPeek.goToError',
|
||||
localize('testing.goToError', "Go to Source"),
|
||||
ThemeIcon.asClassName(Codicon.goToFile),
|
||||
undefined,
|
||||
() => this.editorService.openEditor({
|
||||
resource: element.location!.uri,
|
||||
options: {
|
||||
selection: element.location!.range,
|
||||
preserveFocus: true,
|
||||
}
|
||||
}),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
const result = { primary, secondary };
|
||||
createAndFillInActionBarActions(menu, {
|
||||
shouldForwardArgs: true,
|
||||
}, result, 'inline');
|
||||
|
||||
const contextOverlay = this.contextKeyService.createOverlay(contextKeys);
|
||||
const result = { primary, secondary };
|
||||
const menu = this.menuService.createMenu(id, contextOverlay);
|
||||
try {
|
||||
createAndFillInActionBarActions(menu, { arg: element.context }, result, 'inline');
|
||||
return result;
|
||||
} finally {
|
||||
menu.dispose();
|
||||
|
||||
@@ -156,6 +156,7 @@ export interface ITestErrorMessage {
|
||||
type: TestMessageType.Error;
|
||||
expected: string | undefined;
|
||||
actual: string | undefined;
|
||||
contextValue: string | undefined;
|
||||
location: IRichLocation | undefined;
|
||||
}
|
||||
|
||||
@@ -165,6 +166,7 @@ export namespace ITestErrorMessage {
|
||||
type: TestMessageType.Error;
|
||||
expected: string | undefined;
|
||||
actual: string | undefined;
|
||||
contextValue: string | undefined;
|
||||
location: IRichLocation.Serialize | undefined;
|
||||
}
|
||||
|
||||
@@ -173,6 +175,7 @@ export namespace ITestErrorMessage {
|
||||
type: TestMessageType.Error,
|
||||
expected: message.expected,
|
||||
actual: message.actual,
|
||||
contextValue: message.contextValue,
|
||||
location: message.location && IRichLocation.serialize(message.location),
|
||||
});
|
||||
|
||||
@@ -181,6 +184,7 @@ export namespace ITestErrorMessage {
|
||||
type: TestMessageType.Error,
|
||||
expected: message.expected,
|
||||
actual: message.actual,
|
||||
contextValue: message.contextValue,
|
||||
location: message.location && IRichLocation.deserialize(message.location),
|
||||
});
|
||||
}
|
||||
@@ -632,6 +636,18 @@ export interface ITestItemContext {
|
||||
tests: InternalTestItem.Serialized[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Context for actions taken in the test explorer view.
|
||||
*/
|
||||
export interface ITestMessageMenuArgs {
|
||||
/** Marshalling marker */
|
||||
$mid: MarshalledId.TestMessageMenuArgs;
|
||||
/** Tests ext ID */
|
||||
extId: string;
|
||||
/** Serialized test message */
|
||||
message: ITestMessage.Serialized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request from the ext host or main thread to indicate that tests have
|
||||
* changed. It's assumed that any item upserted *must* have its children
|
||||
|
||||
@@ -58,4 +58,8 @@ export namespace TestingContextKeys {
|
||||
type: 'boolean',
|
||||
description: localize('testing.testItemIsHidden', 'Boolean indicating whether the test item is hidden')
|
||||
});
|
||||
export const testMessageContext = new RawContextKey<string>('testMessage', undefined, {
|
||||
type: 'boolean',
|
||||
description: localize('testing.testMessage', 'Value set in `testMessage.contextValue`, available in editor/content and testing/message/context')
|
||||
});
|
||||
}
|
||||
|
||||
@@ -902,15 +902,16 @@ export class NativeWindow extends Disposable {
|
||||
}
|
||||
} : undefined;
|
||||
let tunnel = await this.tunnelService.getExistingTunnel(portMappingRequest.address, portMappingRequest.port);
|
||||
if (!tunnel) {
|
||||
if (!tunnel || (typeof tunnel === 'string')) {
|
||||
tunnel = await this.tunnelService.openTunnel(addressProvider, portMappingRequest.address, portMappingRequest.port);
|
||||
}
|
||||
if (tunnel) {
|
||||
const addressAsUri = URI.parse(tunnel.localAddress);
|
||||
const resolved = addressAsUri.scheme.startsWith(uri.scheme) ? addressAsUri : uri.with({ authority: tunnel.localAddress });
|
||||
if (tunnel && (typeof tunnel !== 'string')) {
|
||||
const constTunnel = tunnel;
|
||||
const addressAsUri = URI.parse(constTunnel.localAddress);
|
||||
const resolved = addressAsUri.scheme.startsWith(uri.scheme) ? addressAsUri : uri.with({ authority: constTunnel.localAddress });
|
||||
return {
|
||||
resolved,
|
||||
dispose: () => tunnel?.dispose(),
|
||||
dispose: () => constTunnel.dispose(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,6 +260,16 @@ const apiMenus: IAPIMenu[] = [
|
||||
id: MenuId.TestItemGutter,
|
||||
description: localize('testing.item.gutter.title', "The menu for a gutter decoration for a test item"),
|
||||
},
|
||||
{
|
||||
key: 'testing/message/context',
|
||||
id: MenuId.TestMessageContext,
|
||||
description: localize('testing.message.context.title', "A prominent button overlaying editor content where the message is displayed"),
|
||||
},
|
||||
{
|
||||
key: 'testing/message/content',
|
||||
id: MenuId.TestMessageContent,
|
||||
description: localize('testing.message.content.title', "Context menu for the message in the results tree"),
|
||||
},
|
||||
{
|
||||
key: 'extension/context',
|
||||
id: MenuId.ExtensionContext,
|
||||
|
||||
@@ -90,6 +90,7 @@ export const allApiProposals = Object.freeze({
|
||||
terminalQuickFixProvider: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.terminalQuickFixProvider.d.ts',
|
||||
terminalSelection: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.terminalSelection.d.ts',
|
||||
testCoverage: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.testCoverage.d.ts',
|
||||
testMessageContextValue: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.testMessageContextValue.d.ts',
|
||||
testObserver: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.testObserver.d.ts',
|
||||
textSearchProvider: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.textSearchProvider.d.ts',
|
||||
timeline: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.timeline.d.ts',
|
||||
|
||||
@@ -11,7 +11,7 @@ import { IHoverTarget, IHoverOptions } from 'vs/workbench/services/hover/browser
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { EDITOR_FONT_DEFAULTS, IEditorOptions } from 'vs/editor/common/config/editorOptions';
|
||||
import { HoverAction, HoverPosition, HoverWidget as BaseHoverWidget, getHoverAriaLabel } from 'vs/base/browser/ui/hover/hoverWidget';
|
||||
import { HoverAction, HoverPosition, HoverWidget as BaseHoverWidget, getHoverAccessibleViewHint } from 'vs/base/browser/ui/hover/hoverWidget';
|
||||
import { Widget } from 'vs/base/browser/ui/widget';
|
||||
import { AnchorPosition } from 'vs/base/browser/ui/contextview/contextview';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
@@ -21,6 +21,7 @@ import { isMarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { localize } from 'vs/nls';
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
|
||||
import { status } from 'vs/base/browser/ui/aria/aria';
|
||||
|
||||
const $ = dom.$;
|
||||
type TargetRect = {
|
||||
@@ -294,8 +295,11 @@ export class HoverWidget extends Widget {
|
||||
|
||||
public render(container: HTMLElement): void {
|
||||
container.appendChild(this._hoverContainer);
|
||||
this._hover.containerDomNode.ariaLabel = getHoverAriaLabel(this._configurationService.getValue('accessibility.verbosity.hover') === true && this._accessibilityService.isScreenReaderOptimized(), this._keybindingService.lookupKeybinding('editor.action.accessibleView')?.getAriaLabel()) ?? '';
|
||||
console.log('aria label', this._hover.containerDomNode.ariaLabel);
|
||||
const accessibleViewHint = getHoverAccessibleViewHint(this._configurationService.getValue('accessibility.verbosity.hover') === true && this._accessibilityService.isScreenReaderOptimized(), this._keybindingService.lookupKeybinding('editor.action.accessibleView')?.getAriaLabel());
|
||||
if (accessibleViewHint) {
|
||||
|
||||
status(accessibleViewHint);
|
||||
}
|
||||
this.layout();
|
||||
this.addFocusTrap();
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ export interface IRemoteExplorerService {
|
||||
onDidChangeEditable: Event<{ tunnel: ITunnelItem; editId: TunnelEditId } | undefined>;
|
||||
setEditable(tunnelItem: ITunnelItem | undefined, editId: TunnelEditId, data: IEditableData | null): void;
|
||||
getEditableData(tunnelItem: ITunnelItem | undefined, editId?: TunnelEditId): IEditableData | undefined;
|
||||
forward(tunnelProperties: TunnelProperties, attributes?: Attributes | null): Promise<RemoteTunnel | undefined>;
|
||||
forward(tunnelProperties: TunnelProperties, attributes?: Attributes | null): Promise<RemoteTunnel | string | undefined>;
|
||||
close(remote: { host: string; port: number }, reason: TunnelCloseReason): Promise<void>;
|
||||
setTunnelInformation(tunnelInformation: TunnelInformation | undefined): void;
|
||||
setCandidateFilter(filter: ((candidates: CandidatePort[]) => Promise<CandidatePort[]>) | undefined): IDisposable;
|
||||
@@ -118,7 +118,7 @@ class RemoteExplorerService implements IRemoteExplorerService {
|
||||
return this._tunnelModel;
|
||||
}
|
||||
|
||||
forward(tunnelProperties: TunnelProperties, attributes?: Attributes | null): Promise<RemoteTunnel | undefined> {
|
||||
forward(tunnelProperties: TunnelProperties, attributes?: Attributes | null): Promise<RemoteTunnel | string | undefined> {
|
||||
return this.tunnelModel.forward(tunnelProperties, attributes);
|
||||
}
|
||||
|
||||
|
||||
@@ -618,7 +618,7 @@ export class TunnelModel extends Disposable {
|
||||
return this.dialogService.info(mismatchString);
|
||||
}
|
||||
|
||||
async forward(tunnelProperties: TunnelProperties, attributes?: Attributes | null): Promise<RemoteTunnel | undefined> {
|
||||
async forward(tunnelProperties: TunnelProperties, attributes?: Attributes | null): Promise<RemoteTunnel | string | undefined> {
|
||||
await this.extensionService.activateByEvent(ACTIVATION_EVENT);
|
||||
|
||||
const existingTunnel = mapHasAddressLocalhostOrAllInterfaces(this.forwarded, tunnelProperties.remote.host, tunnelProperties.remote.port);
|
||||
@@ -627,7 +627,7 @@ export class TunnelModel extends Disposable {
|
||||
? (await this.getAttributes([tunnelProperties.remote]))?.get(tunnelProperties.remote.port)
|
||||
: undefined);
|
||||
const localPort = (tunnelProperties.local !== undefined) ? tunnelProperties.local : tunnelProperties.remote.port;
|
||||
|
||||
let noTunnelValue: string | undefined;
|
||||
if (!existingTunnel) {
|
||||
const authority = this.environmentService.remoteAuthority;
|
||||
const addressProvider: IAddressProvider | undefined = authority ? {
|
||||
@@ -639,7 +639,10 @@ export class TunnelModel extends Disposable {
|
||||
tunnelProperties = this.mergeCachedAndUnrestoredProperties(key, tunnelProperties);
|
||||
|
||||
const tunnel = await this.tunnelService.openTunnel(addressProvider, tunnelProperties.remote.host, tunnelProperties.remote.port, undefined, localPort, (!tunnelProperties.elevateIfNeeded) ? attributes?.elevateIfNeeded : tunnelProperties.elevateIfNeeded, tunnelProperties.privacy, attributes?.protocol);
|
||||
if (tunnel && tunnel.localAddress) {
|
||||
if (typeof tunnel === 'string') {
|
||||
// There was an error while creating the tunnel.
|
||||
noTunnelValue = tunnel;
|
||||
} else if (tunnel && tunnel.localAddress) {
|
||||
const matchingCandidate = mapHasAddressLocalhostOrAllInterfaces<CandidatePort>(this._candidates ?? new Map(), tunnelProperties.remote.host, tunnelProperties.remote.port);
|
||||
const protocol = (tunnel.protocol ?
|
||||
((tunnel.protocol === TunnelProtocol.Https) ? TunnelProtocol.Https : TunnelProtocol.Http)
|
||||
@@ -672,7 +675,7 @@ export class TunnelModel extends Disposable {
|
||||
return this.mergeAttributesIntoExistingTunnel(existingTunnel, tunnelProperties, attributes);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
return noTunnelValue;
|
||||
}
|
||||
|
||||
private mergeCachedAndUnrestoredProperties(key: string, tunnelProperties: TunnelProperties): TunnelProperties {
|
||||
|
||||
@@ -24,7 +24,7 @@ export class TunnelService extends AbstractTunnelService {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected retainOrCreateTunnel(tunnelProvider: IAddressProvider | ITunnelProvider, remoteHost: string, remotePort: number, _localHost: string, localPort: number | undefined, elevateIfNeeded: boolean, privacy?: string, protocol?: string): Promise<RemoteTunnel | undefined> | undefined {
|
||||
protected retainOrCreateTunnel(tunnelProvider: IAddressProvider | ITunnelProvider, remoteHost: string, remotePort: number, _localHost: string, localPort: number | undefined, elevateIfNeeded: boolean, privacy?: string, protocol?: string): Promise<RemoteTunnel | string | undefined> | undefined {
|
||||
const existing = this.getTunnelFromMap(remoteHost, remotePort);
|
||||
if (existing) {
|
||||
++existing.refcount;
|
||||
|
||||
@@ -79,7 +79,7 @@ export class TunnelService extends AbstractTunnelService {
|
||||
return isPortPrivileged(port, this.defaultTunnelHost, OS, this._nativeWorkbenchEnvironmentService.os.release);
|
||||
}
|
||||
|
||||
protected retainOrCreateTunnel(addressOrTunnelProvider: IAddressProvider | ITunnelProvider, remoteHost: string, remotePort: number, localHost: string, localPort: number | undefined, elevateIfNeeded: boolean, privacy?: string, protocol?: string): Promise<RemoteTunnel | undefined> | undefined {
|
||||
protected retainOrCreateTunnel(addressOrTunnelProvider: IAddressProvider | ITunnelProvider, remoteHost: string, remotePort: number, localHost: string, localPort: number | undefined, elevateIfNeeded: boolean, privacy?: string, protocol?: string): Promise<RemoteTunnel | string | undefined> | undefined {
|
||||
const existing = this.getTunnelFromMap(remoteHost, remotePort);
|
||||
if (existing) {
|
||||
++existing.refcount;
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
declare module 'vscode' {
|
||||
|
||||
// https://github.com/microsoft/vscode/issues/190277
|
||||
|
||||
export class TestMessage2 extends TestMessage {
|
||||
|
||||
/**
|
||||
* Context value of the test item. This can be used to contribute message-
|
||||
* specific actions to the test peek view. The value set here can be found
|
||||
* in the `testMessage` property of the following `menus` contribution points:
|
||||
*
|
||||
* - `testing/message/context` - context menu for the message in the results tree
|
||||
* - `testing/message/content` - a prominent button overlaying editor content where
|
||||
* the message is displayed.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* ```json
|
||||
* "contributes": {
|
||||
* "menus": {
|
||||
* "testing/message/content": [
|
||||
* {
|
||||
* "command": "extension.deleteCommentThread",
|
||||
* "when": "testMessage == canApplyRichDiff"
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* The command will be called with an object containing:
|
||||
* - `test`: the {@link TestItem} the message is associated with, *if* it
|
||||
* is still present in the {@link TestController.items} collection.
|
||||
* - `message`: the {@link TestMessage} instance.
|
||||
*/
|
||||
contextValue?: string;
|
||||
|
||||
// ...
|
||||
}
|
||||
}
|
||||
@@ -10781,45 +10781,45 @@ xtend@~2.1.1:
|
||||
dependencies:
|
||||
object-keys "~0.4.0"
|
||||
|
||||
xterm-addon-canvas@0.5.0-beta.8:
|
||||
version "0.5.0-beta.8"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.5.0-beta.8.tgz#243d1161cc68441a1d531f25e9c4f1d6b3cbe79d"
|
||||
integrity sha512-gCqoqFqfc4N8YZLlj3U5+247r3pjLc9ERRHpuBWSJF2GF623LLk4aSjexnEE0M1b7rIDa3xSKo5limHQXx2mWg==
|
||||
xterm-addon-canvas@0.5.0-beta.9:
|
||||
version "0.5.0-beta.9"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.5.0-beta.9.tgz#d4a9536cf586f78a54527751e03abf6445613886"
|
||||
integrity sha512-AMyFctHbIWx0aLcACINuZqFFNoz4ndGtIAb4pQguIl9t8r+2otiV11MY4FJmPM0kUzEzoLWzVFJaGxOzykCWuw==
|
||||
|
||||
xterm-addon-image@0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-image/-/xterm-addon-image-0.5.0.tgz#3c9bb332a3de55ab200dbefd3411e3b0d985314f"
|
||||
integrity sha512-bWXUBeDzhisYh0clVKx4JgQrZjpn+/QRMRwNsfnRpjCMhgmZ+SL3Bivktd7q03O4uKMMcAOe6bSmppwP9/um0Q==
|
||||
xterm-addon-image@0.6.0-beta.1:
|
||||
version "0.6.0-beta.1"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-image/-/xterm-addon-image-0.6.0-beta.1.tgz#058c171a4866f1cde7608e3b00050476b55ece4c"
|
||||
integrity sha512-vLxUEo/KAsEaRhMshJ4uxnfc/Si8YfT3kilaK5WuiJflVODzQjytzZrl2iLeZaWKiqQp0NR6AEhuXlYASK675A==
|
||||
|
||||
xterm-addon-search@0.13.0-beta.4:
|
||||
version "0.13.0-beta.4"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.13.0-beta.4.tgz#a9817600cc0a71dee524d0f025e88e013f87f14a"
|
||||
integrity sha512-A9Ps7iqGVUSphLCVrGYrfua1ADjtm9ff5CLs8cpiZnMK45X1FTIrXxEWvFccoiwtmZINEDJPGvbfIIqu8ZkXyg==
|
||||
xterm-addon-search@0.13.0-beta.7:
|
||||
version "0.13.0-beta.7"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.13.0-beta.7.tgz#2f9bf9d8380c4c40f021c47dc583aa32bea8796e"
|
||||
integrity sha512-Dnuws0ThaqzxRDo8TjkSb5WlMYycONVDSr/irx2pk2I4vC5RuSpOifmD46ALlryNSDkMasjfCLjHPILHsFDCfw==
|
||||
|
||||
xterm-addon-serialize@0.11.0-beta.6:
|
||||
version "0.11.0-beta.6"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.11.0-beta.6.tgz#2533a2f6bf41327cfcc51a92fca79404499cffe2"
|
||||
integrity sha512-wXx3j9Nf+JOxoBW8iZElEPVEBD6LRDlnrGhfe4oSEa+wDJX+8iORcIKH06mNBlwSApajawrDhpcugwAhjvSOHg==
|
||||
xterm-addon-serialize@0.11.0-beta.7:
|
||||
version "0.11.0-beta.7"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.11.0-beta.7.tgz#934a48a4490c2ca94a5cfcdd646fb0813b4e56d0"
|
||||
integrity sha512-TwYsEHq6TflY0vmq3yAI2VKNqzEAZ0gCm3TThDMPrPQiv4LcewQSeGu9RujEqF9RAhujhceaM3GajBxySAWyqQ==
|
||||
|
||||
xterm-addon-unicode11@0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.5.0.tgz#41c0d96acc1e3bb6c6596eee64e163b6bca74be7"
|
||||
integrity sha512-Jm4/g4QiTxiKiTbYICQgC791ubhIZyoIwxAIgOW8z8HWFNY+lwk+dwaKEaEeGBfM48Vk8fklsUW9u/PlenYEBg==
|
||||
|
||||
xterm-addon-webgl@0.16.0-beta.7:
|
||||
version "0.16.0-beta.7"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.16.0-beta.7.tgz#d9febd140e2020e05c39e66214dae685769144ed"
|
||||
integrity sha512-g657v/ah5JSjeTnHL3myCxiqPx0cA1J70kWXCqP4rsb1nPPlXtbq69cH5AsV/mNN5jnXjd6vHPa7CWt3ptOSgQ==
|
||||
xterm-addon-webgl@0.16.0-beta.13:
|
||||
version "0.16.0-beta.13"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.16.0-beta.13.tgz#ffacd22b8d86ca7f9ba903a64bc85654523955fb"
|
||||
integrity sha512-1avJBoAKl+0dOjRK0pvu2im6gaXyP/6oJcEBQXCTz3V8YlgcG/jom8A6FEQSEDGZ/4dnyDvnLbsg3+aLZIr6gw==
|
||||
|
||||
xterm-headless@5.3.0-beta.28:
|
||||
version "5.3.0-beta.28"
|
||||
resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.3.0-beta.28.tgz#c0307c7363fe290fc5edb68b81135d6c37c76f67"
|
||||
integrity sha512-2zZFNa6AOpoAcMEgzzV7ilSv2qUecs8gSJbfxVV9D4lbNuwWYW5AV8VEdfKnD8TRPbsC/5Uc4RZ82qhJNYOC1g==
|
||||
xterm-headless@5.3.0-beta.39:
|
||||
version "5.3.0-beta.39"
|
||||
resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.3.0-beta.39.tgz#84a509dbe1dc9b2229b5274ae3430ce968986346"
|
||||
integrity sha512-Q4vfqAaYoWh7/T4HearlLlKkn9vjN5EugsNyuPd6hq+Ug1FwJIJYj+I9vY67+Rqxr24XGnrQdXfvvEas29KXsw==
|
||||
|
||||
xterm@5.3.0-beta.28:
|
||||
version "5.3.0-beta.28"
|
||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.3.0-beta.28.tgz#1a5176fa6d9f424913a85dd0371d7384d2f882db"
|
||||
integrity sha512-WA7aX2nE+ptxU4EConXGf0vKwkRisaXNt8ExEw/MRnfDudpZo2J30raJ2SQV2n/xWCGoeVIE5njYmR/hhiGOQA==
|
||||
xterm@5.3.0-beta.39:
|
||||
version "5.3.0-beta.39"
|
||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.3.0-beta.39.tgz#b64da3fd1b374fd535db61294a49c16453dbb77e"
|
||||
integrity sha512-Z1r0ijTgad5MjFoz8qZ+2Qc3bgjG6kYY/kZI3DTA1pibArHeOMDYk9+IeCb9adF74zvZurjytRfXKJgX6M9hwg==
|
||||
|
||||
y18n@^3.2.1:
|
||||
version "3.2.2"
|
||||
|
||||
Reference in New Issue
Block a user