mirror of
https://github.com/microsoft/vscode.git
synced 2026-07-07 23:36:03 +01:00
Merge branch 'main' into issue186399
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
parameters:
|
||||
- name: channel
|
||||
type: string
|
||||
default: 1.65.0
|
||||
default: 1.71.0
|
||||
- name: targets
|
||||
default: []
|
||||
type: object
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
parameters:
|
||||
- name: channel
|
||||
type: string
|
||||
default: 1.65.0
|
||||
default: 1.71.0
|
||||
- name: targets
|
||||
default: []
|
||||
type: object
|
||||
|
||||
Generated
+31
-54
@@ -183,17 +183,6 @@ version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3"
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi 0.1.19",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
@@ -301,11 +290,8 @@ checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5"
|
||||
dependencies = [
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"serde",
|
||||
"time 0.1.44",
|
||||
"wasm-bindgen",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
@@ -356,7 +342,6 @@ name = "code-cli"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"atty",
|
||||
"base64 0.21.2",
|
||||
"bytes",
|
||||
"cfg-if",
|
||||
@@ -536,9 +521,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cxx"
|
||||
version = "1.0.78"
|
||||
version = "1.0.97"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19f39818dcfc97d45b03953c1292efc4e80954e1583c4aa770bac1383e2310a4"
|
||||
checksum = "e88abab2f5abbe4c56e8f1fb431b784d710b709888f35755a160e62e33fe38e8"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cxxbridge-flags",
|
||||
@@ -548,9 +533,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cxx-build"
|
||||
version = "1.0.78"
|
||||
version = "1.0.97"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e580d70777c116df50c390d1211993f62d40302881e54d4b79727acb83d0199"
|
||||
checksum = "5c0c11acd0e63bae27dcd2afced407063312771212b7a823b4fd72d633be30fb"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"codespan-reporting",
|
||||
@@ -558,24 +543,24 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"scratch",
|
||||
"syn 1.0.103",
|
||||
"syn 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxxbridge-flags"
|
||||
version = "1.0.78"
|
||||
version = "1.0.97"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56a46460b88d1cec95112c8c363f0e2c39afdb237f60583b0b36343bf627ea9c"
|
||||
checksum = "8d3816ed957c008ccd4728485511e3d9aaf7db419aa321e3d2c5a2f3411e36c8"
|
||||
|
||||
[[package]]
|
||||
name = "cxxbridge-macro"
|
||||
version = "1.0.78"
|
||||
version = "1.0.97"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "747b608fecf06b0d72d440f27acc99288207324b793be2c17991839f3d4995ea"
|
||||
checksum = "a26acccf6f445af85ea056362561a24ef56cdc15fcc685f03aec50b9c702cb6d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.103",
|
||||
"syn 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1069,23 +1054,23 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.51"
|
||||
version = "0.1.57"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f5a6ef98976b22b3b7f2f3a806f858cb862044cfa66805aa3ad84cb3d3b785ed"
|
||||
checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
"iana-time-zone-haiku",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"winapi",
|
||||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone-haiku"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fde6edd6cef363e9359ed3c98ba64590ba9eecba2293eb5a723ab32aee8926aa"
|
||||
checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca"
|
||||
dependencies = [
|
||||
"cxx",
|
||||
"cxx-build",
|
||||
@@ -1234,9 +1219,9 @@ checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1"
|
||||
|
||||
[[package]]
|
||||
name = "link-cplusplus"
|
||||
version = "1.0.7"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369"
|
||||
checksum = "9d240c6f7e1ba3a28b0249f774e6a9dd0175054b52dfbb61b16eb8505c3785c9"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
@@ -1996,9 +1981,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "scratch"
|
||||
version = "1.0.2"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898"
|
||||
checksum = "a3cf7c11c38cb994f3d40e8a8cde3bbd1f72a435e4c49e85d6553d8312306152"
|
||||
|
||||
[[package]]
|
||||
name = "secret-service"
|
||||
@@ -2271,9 +2256,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.1.3"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
|
||||
checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
@@ -2298,17 +2283,6 @@ dependencies = [
|
||||
"syn 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi 0.10.0+wasi-snapshot-preview1",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.21"
|
||||
@@ -2649,12 +2623,6 @@ version = "0.9.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.10.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
@@ -2790,6 +2758,15 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
|
||||
dependencies = [
|
||||
"windows-targets 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.36.1"
|
||||
@@ -3100,7 +3077,7 @@ dependencies = [
|
||||
"crc32fast",
|
||||
"crossbeam-utils",
|
||||
"flate2",
|
||||
"time 0.3.21",
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
+1
-2
@@ -29,10 +29,9 @@ rmp-serde = "1.1.1"
|
||||
uuid = { version = "1.3.3", features = ["serde", "v4"] }
|
||||
dirs = "5.0.1"
|
||||
rand = "0.8.5"
|
||||
atty = "0.2.14"
|
||||
opentelemetry = { version = "0.19.0", features = ["rt-tokio"] }
|
||||
serde_bytes = "0.11.9"
|
||||
chrono = { version = "0.4.26", features = ["serde"] }
|
||||
chrono = { version = "0.4.26", features = ["serde", "std", "clock"], default-features = false }
|
||||
gethostname = "0.4.3"
|
||||
libc = "0.2.144"
|
||||
tunnels = { git = "https://github.com/microsoft/dev-tunnels", rev = "2621784a9ad72aa39500372391332a14bad581a3", default-features = false, features = ["connections"] }
|
||||
|
||||
@@ -465,20 +465,17 @@ pub async fn forward(
|
||||
|
||||
// #region singleton handler
|
||||
let auth = Auth::new(&ctx.paths, ctx.log.clone());
|
||||
println!("preauth {:?}", forward_args.login);
|
||||
if let (Some(p), Some(at)) = (
|
||||
forward_args.login.provider.take(),
|
||||
forward_args.login.access_token.take(),
|
||||
) {
|
||||
auth.login(Some(p.into()), Some(at)).await?;
|
||||
}
|
||||
println!("auth done");
|
||||
|
||||
let mut tunnels = DevTunnels::new_port_forwarding(&ctx.log, auth, &ctx.paths);
|
||||
let tunnel = tunnels
|
||||
.start_new_launcher_tunnel(None, true, &forward_args.ports)
|
||||
.await?;
|
||||
println!("made tunnel");
|
||||
|
||||
forwarding::server(ctx.log, tunnel, server, own_ports_rx, shutdown).await?;
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::{collections::HashMap, io::IsTerminal};
|
||||
|
||||
use const_format::concatcp;
|
||||
use lazy_static::lazy_static;
|
||||
@@ -119,7 +119,7 @@ lazy_static! {
|
||||
option_env!("VSCODE_CLI_SERVER_NAME_MAP").and_then(|s| serde_json::from_str(s).unwrap());
|
||||
|
||||
/// Whether i/o interactions are allowed in the current CLI.
|
||||
pub static ref IS_A_TTY: bool = atty::is(atty::Stream::Stdin);
|
||||
pub static ref IS_A_TTY: bool = std::io::stdin().is_terminal();
|
||||
|
||||
/// Whether i/o interactions are allowed in the current CLI.
|
||||
pub static ref COLORS_ENABLED: bool = *IS_A_TTY && std::env::var(NO_COLOR_ENV).is_err();
|
||||
|
||||
@@ -541,6 +541,15 @@ impl<'a> ServerBuilder<'a> {
|
||||
|
||||
debug!(self.logger, "Starting server with command... {:?}", cmd);
|
||||
|
||||
// On Windows spawning a code-server binary will run cmd.exe /c C:\path\to\code-server.cmd...
|
||||
// This spawns a cmd.exe window for the user, which if they close will kill the code-server process
|
||||
// and disconnect the tunnel. To prevent this, pass the CREATE_NO_WINDOW flag to the Command
|
||||
// only on Windows.
|
||||
// Original issue: https://github.com/microsoft/vscode/issues/184058
|
||||
// Partial fix: https://github.com/microsoft/vscode/pull/184621
|
||||
#[cfg(target_os = "windows")]
|
||||
let cmd = cmd.creation_flags(winapi::um::winbase::CREATE_NO_WINDOW);
|
||||
|
||||
let child = cmd
|
||||
.stderr(std::process::Stdio::piped())
|
||||
.stdout(std::process::Stdio::piped())
|
||||
|
||||
@@ -200,10 +200,11 @@ table > tbody > tr + tr > td {
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 0 7px 0 5px;
|
||||
padding: 0 16px 0 10px;
|
||||
margin: 0;
|
||||
padding: 2px 16px 0 10px;
|
||||
border-left-width: 5px;
|
||||
border-left-style: solid;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
code {
|
||||
@@ -232,6 +233,7 @@ pre code {
|
||||
|
||||
pre {
|
||||
background-color: var(--vscode-textCodeBlock-background);
|
||||
border: 1px solid var(--vscode-widget-border);
|
||||
}
|
||||
|
||||
.vscode-high-contrast h1 {
|
||||
|
||||
@@ -3,130 +3,123 @@
|
||||
"name": "Default Dark Modern",
|
||||
"include": "./dark_plus.json",
|
||||
"colors": {
|
||||
"activityBar.activeBorder": "#0078d4",
|
||||
"activityBar.activeBorder": "#0078D4",
|
||||
"activityBar.background": "#181818",
|
||||
"activityBar.border": "#ffffff15",
|
||||
"activityBar.foreground": "#d7d7d7",
|
||||
"activityBar.inactiveForeground": "#ffffff80",
|
||||
"activityBarBadge.background": "#0078d4",
|
||||
"activityBarBadge.foreground": "#ffffff",
|
||||
"badge.background": "#4D4D4D",
|
||||
"badge.foreground": "#f2f2f2",
|
||||
"button.background": "#0078d4",
|
||||
"button.border": "#ffffff12",
|
||||
"button.foreground": "#ffffff",
|
||||
"button.hoverBackground": "#0078d4e6",
|
||||
"button.secondaryBackground": "#FFFFFF0F",
|
||||
"button.secondaryForeground": "#cccccc",
|
||||
"button.secondaryHoverBackground": "#ffffff15",
|
||||
"activityBar.border": "#2B2B2B",
|
||||
"activityBar.foreground": "#D7D7D7",
|
||||
"activityBar.inactiveForeground": "#868686",
|
||||
"activityBarBadge.background": "#0078D4",
|
||||
"activityBarBadge.foreground": "#FFFFFF",
|
||||
"badge.background": "#616161",
|
||||
"badge.foreground": "#F8F8F8",
|
||||
"button.background": "#0078D4",
|
||||
"button.border": "#FFFFFF12",
|
||||
"button.foreground": "#FFFFFF",
|
||||
"button.hoverBackground": "#026EC1",
|
||||
"button.secondaryBackground": "#1F1F1F",
|
||||
"button.secondaryForeground": "#CCCCCC",
|
||||
"button.secondaryHoverBackground": "#2B2B2B",
|
||||
"checkbox.background": "#313131",
|
||||
"checkbox.border": "#ffffff1f",
|
||||
"checkbox.border": "#3C3C3C",
|
||||
"debugToolBar.background": "#181818",
|
||||
"descriptionForeground": "#8b949e",
|
||||
"descriptionForeground": "#9D9D9D",
|
||||
"dropdown.background": "#313131",
|
||||
"dropdown.border": "#ffffff1f",
|
||||
"dropdown.foreground": "#cccccc",
|
||||
"dropdown.listBackground": "#1f1f1f",
|
||||
"editor.background": "#1f1f1f",
|
||||
"editor.findMatchBackground": "#9e6a03",
|
||||
"editor.foreground": "#cccccc",
|
||||
"editorGroup.border": "#ffffff17",
|
||||
"dropdown.border": "#3C3C3C",
|
||||
"dropdown.foreground": "#CCCCCC",
|
||||
"dropdown.listBackground": "#1F1F1F",
|
||||
"editor.background": "#1F1F1F",
|
||||
"editor.findMatchBackground": "#9E6A03",
|
||||
"editor.foreground": "#CCCCCC",
|
||||
"editorGroup.border": "#FFFFFF17",
|
||||
"editorGroupHeader.tabsBackground": "#181818",
|
||||
"editorGroupHeader.tabsBorder": "#ffffff15",
|
||||
"editorGutter.addedBackground": "#2ea043",
|
||||
"editorGutter.deletedBackground": "#f85149",
|
||||
"editorGutter.modifiedBackground": "#0078d4",
|
||||
"editorLineNumber.activeForeground": "#cccccc",
|
||||
"editorLineNumber.foreground": "#6e7681",
|
||||
"editorGroupHeader.tabsBorder": "#2B2B2B",
|
||||
"editorGutter.addedBackground": "#2EA043",
|
||||
"editorGutter.deletedBackground": "#F85149",
|
||||
"editorGutter.modifiedBackground": "#0078D4",
|
||||
"editorLineNumber.activeForeground": "#CCCCCC",
|
||||
"editorLineNumber.foreground": "#6E7681",
|
||||
"editorOverviewRuler.border": "#010409",
|
||||
"editorWidget.background": "#1f1f1f",
|
||||
"errorForeground": "#f85149",
|
||||
"focusBorder": "#0078d4",
|
||||
"foreground": "#cccccc",
|
||||
"icon.foreground": "#cccccc",
|
||||
"input.background": "#2a2a2a",
|
||||
"input.border": "#ffffff1f",
|
||||
"input.foreground": "#cccccc",
|
||||
"input.placeholderForeground": "#ffffff79",
|
||||
"inputOption.activeBackground": "#2489db82",
|
||||
"inputOption.activeBorder": "#2488db",
|
||||
"keybindingLabel.foreground": "#cccccc",
|
||||
"list.activeSelectionBackground": "#323232",
|
||||
"list.activeSelectionIconForeground": "#ffffff",
|
||||
"list.activeSelectionForeground": "#ffffff",
|
||||
"menu.background": "#1f1f1f",
|
||||
"notificationCenterHeader.background": "#1f1f1f",
|
||||
"notificationCenterHeader.foreground": "#cccccc",
|
||||
"notifications.background": "#1f1f1f",
|
||||
"notifications.border": "#ffffff15",
|
||||
"notifications.foreground": "#cccccc",
|
||||
"editorWidget.background": "#2B2B2B",
|
||||
"errorForeground": "#F85149",
|
||||
"focusBorder": "#0078D4",
|
||||
"foreground": "#CCCCCC",
|
||||
"icon.foreground": "#CCCCCC",
|
||||
"input.background": "#2A2A2A",
|
||||
"input.border": "#3C3C3C",
|
||||
"input.foreground": "#CCCCCC",
|
||||
"input.placeholderForeground": "#9D9D9D",
|
||||
"inputOption.activeBackground": "#2489DB82",
|
||||
"inputOption.activeBorder": "#2488DB",
|
||||
"keybindingLabel.foreground": "#CCCCCC",
|
||||
"menu.background": "#1F1F1F",
|
||||
"notificationCenterHeader.background": "#1F1F1F",
|
||||
"notificationCenterHeader.foreground": "#CCCCCC",
|
||||
"notifications.background": "#1F1F1F",
|
||||
"notifications.border": "#2B2B2B",
|
||||
"notifications.foreground": "#CCCCCC",
|
||||
"panel.background": "#181818",
|
||||
"panel.border": "#ffffff15",
|
||||
"panelInput.border": "#ffffff15",
|
||||
"panelTitle.activeBorder": "#0078d4",
|
||||
"panelTitle.activeForeground": "#cccccc",
|
||||
"panelTitle.inactiveForeground": "#8b949e",
|
||||
"peekViewEditor.background": "#1f1f1f",
|
||||
"peekViewEditor.matchHighlightBackground": "#bb800966",
|
||||
"peekViewResult.background": "#1f1f1f",
|
||||
"peekViewResult.matchHighlightBackground": "#bb800966",
|
||||
"pickerGroup.border": "#ffffff15",
|
||||
"pickerGroup.foreground": "#8b949e",
|
||||
"progressBar.background": "#0078d4",
|
||||
"quickInput.background": "#1f1f1f",
|
||||
"quickInput.foreground": "#cccccc",
|
||||
"scrollbar.shadow": "#484f5833",
|
||||
"scrollbarSlider.activeBackground": "#6e768187",
|
||||
"scrollbarSlider.background": "#6e768133",
|
||||
"scrollbarSlider.hoverBackground": "#6e768145",
|
||||
"panel.border": "#2B2B2B",
|
||||
"panelInput.border": "#2B2B2B",
|
||||
"panelTitle.activeBorder": "#0078D4",
|
||||
"panelTitle.activeForeground": "#CCCCCC",
|
||||
"panelTitle.inactiveForeground": "#9D9D9D",
|
||||
"peekViewEditor.background": "#1F1F1F",
|
||||
"peekViewEditor.matchHighlightBackground": "#BB800966",
|
||||
"peekViewResult.background": "#1F1F1F",
|
||||
"peekViewResult.matchHighlightBackground": "#BB800966",
|
||||
"pickerGroup.border": "#2B2B2B",
|
||||
"pickerGroup.foreground": "#8B949E",
|
||||
"progressBar.background": "#0078D4",
|
||||
"quickInput.background": "#2A2A2A",
|
||||
"quickInput.foreground": "#CCCCCC",
|
||||
"settings.dropdownBackground": "#313131",
|
||||
"settings.dropdownBorder": "#ffffff1f",
|
||||
"settings.headerForeground": "#ffffff",
|
||||
"settings.modifiedItemIndicator": "#bb800966",
|
||||
"settings.dropdownBorder": "#3C3C3C",
|
||||
"settings.headerForeground": "#FFFFFF",
|
||||
"settings.modifiedItemIndicator": "#BB800966",
|
||||
"sideBar.background": "#181818",
|
||||
"sideBar.border": "#ffffff15",
|
||||
"sideBar.foreground": "#cccccc",
|
||||
"sideBar.border": "#2B2B2B",
|
||||
"sideBar.foreground": "#CCCCCC",
|
||||
"sideBarSectionHeader.background": "#181818",
|
||||
"sideBarSectionHeader.border": "#ffffff15",
|
||||
"sideBarSectionHeader.foreground": "#cccccc",
|
||||
"sideBarTitle.foreground": "#cccccc",
|
||||
"sideBarSectionHeader.border": "#2B2B2B",
|
||||
"sideBarSectionHeader.foreground": "#CCCCCC",
|
||||
"sideBarTitle.foreground": "#CCCCCC",
|
||||
"statusBar.background": "#181818",
|
||||
"statusBar.border": "#ffffff15",
|
||||
"statusBar.debuggingBackground": "#0078d4",
|
||||
"statusBar.debuggingForeground": "#ffffff",
|
||||
"statusBar.focusBorder": "#0078d4",
|
||||
"statusBar.foreground": "#cccccc",
|
||||
"statusBar.noFolderBackground": "#1f1f1f",
|
||||
"statusBarItem.focusBorder": "#0078d4",
|
||||
"statusBarItem.prominentBackground": "#6e768166",
|
||||
"statusBarItem.remoteBackground": "#0078d4",
|
||||
"statusBarItem.remoteForeground": "#ffffff",
|
||||
"tab.activeBackground": "#1f1f1f",
|
||||
"tab.activeBorder": "#1f1f1f",
|
||||
"tab.activeBorderTop": "#0078d4",
|
||||
"tab.activeForeground": "#ffffff",
|
||||
"tab.border": "#ffffff15",
|
||||
"tab.hoverBackground": "#1f1f1f",
|
||||
"statusBar.border": "#2B2B2B",
|
||||
"statusBar.debuggingBackground": "#0078D4",
|
||||
"statusBar.debuggingForeground": "#FFFFFF",
|
||||
"statusBar.focusBorder": "#0078D4",
|
||||
"statusBar.foreground": "#CCCCCC",
|
||||
"statusBar.noFolderBackground": "#1F1F1F",
|
||||
"statusBarItem.focusBorder": "#0078D4",
|
||||
"statusBarItem.prominentBackground": "#6E768166",
|
||||
"statusBarItem.remoteBackground": "#0078D4",
|
||||
"statusBarItem.remoteForeground": "#FFFFFF",
|
||||
"tab.activeBackground": "#1F1F1F",
|
||||
"tab.activeBorder": "#1F1F1F",
|
||||
"tab.activeBorderTop": "#0078D4",
|
||||
"tab.activeForeground": "#FFFFFF",
|
||||
"tab.border": "#2B2B2B",
|
||||
"tab.hoverBackground": "#1F1F1F",
|
||||
"tab.inactiveBackground": "#181818",
|
||||
"tab.inactiveForeground": "#ffffff80",
|
||||
"tab.unfocusedActiveBorder": "#1f1f1f",
|
||||
"tab.unfocusedActiveBorderTop": "#ffffff15",
|
||||
"tab.unfocusedHoverBackground": "#6e76811a",
|
||||
"terminal.foreground": "#cccccc",
|
||||
"terminal.tab.activeBorder": "#0078d4",
|
||||
"textBlockQuote.background": "#010409",
|
||||
"textBlockQuote.border": "#ffffff14",
|
||||
"textCodeBlock.background": "#6e768166",
|
||||
"tab.inactiveForeground": "#9D9D9D",
|
||||
"tab.unfocusedActiveBorder": "#1F1F1F",
|
||||
"tab.unfocusedActiveBorderTop": "#2B2B2B",
|
||||
"tab.unfocusedHoverBackground": "#1F1F1F",
|
||||
"terminal.foreground": "#CCCCCC",
|
||||
"terminal.tab.activeBorder": "#0078D4",
|
||||
"textBlockQuote.background": "#2B2B2B",
|
||||
"textBlockQuote.border": "#616161",
|
||||
"textCodeBlock.background": "#2B2B2B",
|
||||
"textLink.activeForeground": "#40A6FF",
|
||||
"textLink.foreground": "#40A6FF",
|
||||
"textSeparator.foreground": "#21262d",
|
||||
"textSeparator.foreground": "#21262D",
|
||||
"titleBar.activeBackground": "#181818",
|
||||
"titleBar.activeForeground": "#cccccc",
|
||||
"titleBar.border": "#ffffff15",
|
||||
"titleBar.inactiveBackground": "#1f1f1f",
|
||||
"titleBar.inactiveForeground": "#8b949e",
|
||||
"welcomePage.tileBackground": "#ffffff0f",
|
||||
"welcomePage.progress.foreground": "#0078d4",
|
||||
"widget.border": "#ffffff15",
|
||||
"titleBar.activeForeground": "#CCCCCC",
|
||||
"titleBar.border": "#2B2B2B",
|
||||
"titleBar.inactiveBackground": "#1F1F1F",
|
||||
"titleBar.inactiveForeground": "#9D9D9D",
|
||||
"welcomePage.tileBackground": "#2B2B2B",
|
||||
"welcomePage.progress.foreground": "#0078D4",
|
||||
"widget.border": "#333333",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -4,141 +4,138 @@
|
||||
"include": "./light_plus.json",
|
||||
"colors": {
|
||||
"activityBar.activeBorder": "#005FB8",
|
||||
"activityBar.background": "#f8f8f8",
|
||||
"activityBar.border": "#0000001a",
|
||||
"activityBar.foreground": "#1f1f1f",
|
||||
"activityBar.inactiveForeground": "#0000009e",
|
||||
"activityBar.background": "#F8F8F8",
|
||||
"activityBar.border": "#E5E5E5",
|
||||
"activityBar.foreground": "#1F1F1F",
|
||||
"activityBar.inactiveForeground": "#616161",
|
||||
"activityBarBadge.background": "#005FB8",
|
||||
"activityBarBadge.foreground": "#ffffff",
|
||||
"activityBarBadge.foreground": "#FFFFFF",
|
||||
"badge.background": "#CCCCCC",
|
||||
"badge.foreground": "#3b3b3b",
|
||||
"badge.foreground": "#3B3B3B",
|
||||
"button.background": "#005FB8",
|
||||
"button.border": "#0000001a",
|
||||
"button.foreground": "#ffffff",
|
||||
"button.hoverBackground": "#005FB8e6",
|
||||
"button.secondaryBackground": "#0000001a",
|
||||
"button.secondaryForeground": "#3b3b3b",
|
||||
"button.secondaryHoverBackground": "#00000034",
|
||||
"checkbox.background": "#f8f8f8",
|
||||
"button.foreground": "#FFFFFF",
|
||||
"button.hoverBackground": "#0258A8",
|
||||
"button.secondaryBackground": "#E5E5E5",
|
||||
"button.secondaryForeground": "#3B3B3B",
|
||||
"button.secondaryHoverBackground": "#CBCBCB",
|
||||
"checkbox.background": "#F8F8F8",
|
||||
"checkbox.border": "#CECECE",
|
||||
"descriptionForeground": "#3b3b3b",
|
||||
"dropdown.background": "#ffffff",
|
||||
"descriptionForeground": "#3B3B3B",
|
||||
"dropdown.background": "#FFFFFF",
|
||||
"dropdown.border": "#CECECE",
|
||||
"dropdown.foreground": "#3b3b3b",
|
||||
"dropdown.listBackground": "#ffffff",
|
||||
"editor.background": "#ffffff",
|
||||
"editor.foreground": "#3b3b3b",
|
||||
"dropdown.foreground": "#3B3B3B",
|
||||
"dropdown.listBackground": "#FFFFFF",
|
||||
"editor.background": "#FFFFFF",
|
||||
"editor.foreground": "#3B3B3B",
|
||||
"editor.inactiveSelectionBackground": "#E5EBF1",
|
||||
"editor.selectionHighlightBackground": "#ADD6FF80",
|
||||
"editorGroup.border": "#0000001a",
|
||||
"editorGroupHeader.tabsBackground": "#f8f8f8",
|
||||
"editorGroupHeader.tabsBorder": "#0000001a",
|
||||
"editorGutter.addedBackground": "#2ea043",
|
||||
"editorGutter.deletedBackground": "#f85149",
|
||||
"editorGroup.border": "#E5E5E5",
|
||||
"editorGroupHeader.tabsBackground": "#F8F8F8",
|
||||
"editorGroupHeader.tabsBorder": "#E5E5E5",
|
||||
"editorGutter.addedBackground": "#2EA043",
|
||||
"editorGutter.deletedBackground": "#F85149",
|
||||
"editorGutter.modifiedBackground": "#005FB8",
|
||||
"editorIndentGuide.background": "#D3D3D3",
|
||||
"editorLineNumber.activeForeground": "#171184",
|
||||
"editorLineNumber.foreground": "#6e7681",
|
||||
"editorOverviewRuler.border": "#0000001a",
|
||||
"editorSuggestWidget.background": "#f8f8f8",
|
||||
"editorWidget.background": "#ffffff",
|
||||
"errorForeground": "#f85149",
|
||||
"editorLineNumber.foreground": "#6E7681",
|
||||
"editorOverviewRuler.border": "#E5E5E5",
|
||||
"editorSuggestWidget.background": "#F8F8F8",
|
||||
"editorWidget.background": "#F8F8F8",
|
||||
"errorForeground": "#F85149",
|
||||
"focusBorder": "#005FB8",
|
||||
"foreground": "#3b3b3b",
|
||||
"icon.foreground": "#3b3b3b",
|
||||
"input.background": "#ffffff",
|
||||
"foreground": "#3B3B3B",
|
||||
"icon.foreground": "#3B3B3B",
|
||||
"input.background": "#FFFFFF",
|
||||
"input.border": "#CECECE",
|
||||
"input.foreground": "#3b3b3b",
|
||||
"input.placeholderForeground": "#00000079",
|
||||
"inputOption.activeBackground": "#005fb841",
|
||||
"input.foreground": "#3B3B3B",
|
||||
"input.placeholderForeground": "#868686",
|
||||
"inputOption.activeBackground": "#BED6ED",
|
||||
"inputOption.activeBorder": "#005FB8",
|
||||
"inputOption.activeForeground": "#000000",
|
||||
"keybindingLabel.foreground": "#3b3b3b",
|
||||
"list.activeSelectionBackground": "#e8e8e8",
|
||||
"keybindingLabel.foreground": "#3B3B3B",
|
||||
"list.activeSelectionBackground": "#E8E8E8",
|
||||
"list.activeSelectionForeground": "#000000",
|
||||
"list.activeSelectionIconForeground": "#000000",
|
||||
"list.hoverBackground": "#f2f2f2",
|
||||
"menu.border": "#D4D4D4",
|
||||
"notebook.cellBorderColor": "#E8E8E8",
|
||||
"notebook.selectedCellBackground": "#c8ddf150",
|
||||
"notificationCenterHeader.background": "#ffffff",
|
||||
"notificationCenterHeader.foreground": "#3b3b3b",
|
||||
"notifications.background": "#ffffff",
|
||||
"notifications.border": "#0000001a",
|
||||
"notifications.foreground": "#3b3b3b",
|
||||
"panel.background": "#f8f8f8",
|
||||
"panel.border": "#0000001a",
|
||||
"panelInput.border": "#0000001a",
|
||||
"list.hoverBackground": "#F2F2F2",
|
||||
"list.focusAndSelectionOutline": "#005FB8",
|
||||
"menu.border": "#CECECE",
|
||||
"notebook.cellBorderColor": "#E5E5E5",
|
||||
"notebook.selectedCellBackground": "#C8DDF150",
|
||||
"notificationCenterHeader.background": "#FFFFFF",
|
||||
"notificationCenterHeader.foreground": "#3B3B3B",
|
||||
"notifications.background": "#FFFFFF",
|
||||
"notifications.border": "#E5E5E5",
|
||||
"notifications.foreground": "#3B3B3B",
|
||||
"panel.background": "#F8F8F8",
|
||||
"panel.border": "#E5E5E5",
|
||||
"panelInput.border": "#E5E5E5",
|
||||
"panelTitle.activeBorder": "#005FB8",
|
||||
"panelTitle.activeForeground": "#3b3b3b",
|
||||
"panelTitle.inactiveForeground": "#3b3b3b",
|
||||
"peekViewEditor.matchHighlightBackground": "#bb800966",
|
||||
"peekViewResult.background": "#ffffff",
|
||||
"peekViewResult.matchHighlightBackground": "#bb800966",
|
||||
"pickerGroup.border": "#0000001a",
|
||||
"pickerGroup.foreground": "#8b949e",
|
||||
"panelTitle.activeForeground": "#3B3B3B",
|
||||
"panelTitle.inactiveForeground": "#3B3B3B",
|
||||
"peekViewEditor.matchHighlightBackground": "#BB800966",
|
||||
"peekViewResult.background": "#FFFFFF",
|
||||
"peekViewResult.matchHighlightBackground": "#BB800966",
|
||||
"pickerGroup.border": "#E5E5E5",
|
||||
"pickerGroup.foreground": "#8B949E",
|
||||
"ports.iconRunningProcessForeground": "#369432",
|
||||
"progressBar.background": "#005FB8",
|
||||
"quickInput.background": "#ffffff",
|
||||
"quickInput.foreground": "#3b3b3b",
|
||||
"scrollbar.shadow": "#484f5833",
|
||||
"scrollbarSlider.activeBackground": "#6e768187",
|
||||
"scrollbarSlider.background": "#6e768133",
|
||||
"scrollbarSlider.hoverBackground": "#6e768145",
|
||||
"quickInput.background": "#F8F8F8",
|
||||
"quickInput.foreground": "#3B3B3B",
|
||||
"searchEditor.textInputBorder": "#CECECE",
|
||||
"settings.dropdownBackground": "#ffffff",
|
||||
"settings.dropdownBackground": "#FFFFFF",
|
||||
"settings.dropdownBorder": "#CECECE",
|
||||
"settings.headerForeground": "#1f1f1f",
|
||||
"settings.modifiedItemIndicator": "#bb800966",
|
||||
"settings.headerForeground": "#1F1F1F",
|
||||
"settings.modifiedItemIndicator": "#BB800966",
|
||||
"settings.numberInputBorder": "#CECECE",
|
||||
"settings.textInputBorder": "#CECECE",
|
||||
"sideBar.background": "#f8f8f8",
|
||||
"sideBar.border": "#0000001a",
|
||||
"sideBar.foreground": "#3b3b3b",
|
||||
"sideBarSectionHeader.background": "#f8f8f8",
|
||||
"sideBarSectionHeader.border": "#0000001a",
|
||||
"sideBarSectionHeader.foreground": "#3b3b3b",
|
||||
"sideBarTitle.foreground": "#3b3b3b",
|
||||
"statusBar.background": "#f8f8f8",
|
||||
"statusBar.foreground": "#3b3b3b",
|
||||
"statusBar.border": "#0000001a",
|
||||
"statusBar.debuggingBackground": "#fd716c",
|
||||
"sideBar.background": "#F8F8F8",
|
||||
"sideBar.border": "#E5E5E5",
|
||||
"sideBar.foreground": "#3B3B3B",
|
||||
"sideBarSectionHeader.background": "#F8F8F8",
|
||||
"sideBarSectionHeader.border": "#E5E5E5",
|
||||
"sideBarSectionHeader.foreground": "#3B3B3B",
|
||||
"sideBarTitle.foreground": "#3B3B3B",
|
||||
"statusBar.background": "#F8F8F8",
|
||||
"statusBar.foreground": "#3B3B3B",
|
||||
"statusBar.border": "#E5E5E5",
|
||||
"statusBar.debuggingBackground": "#FD716C",
|
||||
"statusBar.debuggingForeground": "#000000",
|
||||
"statusBar.focusBorder": "#005FB8",
|
||||
"statusBar.noFolderBackground": "#f8f8f8",
|
||||
"statusBarItem.errorBackground": "#c72e0f",
|
||||
"statusBar.noFolderBackground": "#F8F8F8",
|
||||
"statusBarItem.errorBackground": "#C72E0F",
|
||||
"statusBarItem.focusBorder": "#005FB8",
|
||||
"statusBarItem.prominentBackground": "#6e768166",
|
||||
"statusBarItem.prominentBackground": "#6E768166",
|
||||
"statusBarItem.remoteBackground": "#005FB8",
|
||||
"statusBarItem.remoteForeground": "#ffffff",
|
||||
"tab.activeBackground": "#ffffff",
|
||||
"tab.activeBorder": "#f8f8f8",
|
||||
"statusBarItem.remoteForeground": "#FFFFFF",
|
||||
"tab.activeBackground": "#FFFFFF",
|
||||
"tab.activeBorder": "#F8F8F8",
|
||||
"tab.activeBorderTop": "#005FB8",
|
||||
"tab.activeForeground": "#3b3b3b",
|
||||
"tab.border": "#0000001a",
|
||||
"tab.hoverBackground": "#ffffff",
|
||||
"tab.inactiveBackground": "#f8f8f8",
|
||||
"tab.inactiveForeground": "#00000080",
|
||||
"tab.lastPinnedBorder": "#3b3b3b30",
|
||||
"tab.unfocusedActiveBorder": "#f8f8f8",
|
||||
"tab.unfocusedActiveBorderTop": "#00000015",
|
||||
"tab.unfocusedHoverBackground": "#6e76811a",
|
||||
"tab.activeForeground": "#3B3B3B",
|
||||
"tab.border": "#E5E5E5",
|
||||
"tab.hoverBackground": "#FFFFFF",
|
||||
"tab.inactiveBackground": "#F8F8F8",
|
||||
"tab.inactiveForeground": "#868686",
|
||||
"tab.lastPinnedBorder": "#D4D4D4",
|
||||
"tab.unfocusedActiveBorder": "#F8F8F8",
|
||||
"tab.unfocusedActiveBorderTop": "#E5E5E5",
|
||||
"tab.unfocusedHoverBackground": "#F8F8F8",
|
||||
"terminalCursor.foreground": "#005FB8",
|
||||
"terminal.foreground": "#3b3b3b",
|
||||
"terminal.foreground": "#3B3B3B",
|
||||
"terminal.inactiveSelectionBackground": "#E5EBF1",
|
||||
"terminal.tab.activeBorder": "#005fb8",
|
||||
"textBlockQuote.background": "#f8f8f8",
|
||||
"textBlockQuote.border": "#0000001a",
|
||||
"textCodeBlock.background": "#f2f2f2",
|
||||
"terminal.tab.activeBorder": "#005FB8",
|
||||
"textBlockQuote.background": "#F8F8F8",
|
||||
"textBlockQuote.border": "#E5E5E5",
|
||||
"textCodeBlock.background": "#F8F8F8",
|
||||
"textLink.activeForeground": "#005FB8",
|
||||
"textLink.foreground": "#005FB8",
|
||||
"textSeparator.foreground": "#21262d",
|
||||
"titleBar.activeBackground": "#f8f8f8",
|
||||
"titleBar.activeForeground": "#1e1e1e",
|
||||
"titleBar.border": "#0000001a",
|
||||
"titleBar.inactiveBackground": "#f8f8f8",
|
||||
"titleBar.inactiveForeground": "#8b949e",
|
||||
"welcomePage.tileBackground": "#f3f3f3",
|
||||
"widget.border": "#0000001a",
|
||||
"textSeparator.foreground": "#21262D",
|
||||
"titleBar.activeBackground": "#F8F8F8",
|
||||
"titleBar.activeForeground": "#1E1E1E",
|
||||
"titleBar.border": "#E5E5E5",
|
||||
"titleBar.inactiveBackground": "#F8F8F8",
|
||||
"titleBar.inactiveForeground": "#8B949E",
|
||||
"welcomePage.tileBackground": "#F3F3F3",
|
||||
"widget.border": "#E5E5E5"
|
||||
},
|
||||
}
|
||||
|
||||
@@ -707,6 +707,10 @@ export function tieBreakComparators<TItem>(...comparators: Comparator<TItem>[]):
|
||||
*/
|
||||
export const numberComparator: Comparator<number> = (a, b) => a - b;
|
||||
|
||||
export function reverseOrder<TItem>(comparator: Comparator<TItem>): Comparator<TItem> {
|
||||
return (a, b) => -comparator(a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first item that is equal to or greater than every other item.
|
||||
*/
|
||||
|
||||
@@ -142,9 +142,9 @@ class ViewModel extends Disposable {
|
||||
/** @description play audio-cue for diff */
|
||||
const currentViewItem = this.currentElement.read(reader);
|
||||
if (currentViewItem?.type === LineType.Deleted) {
|
||||
this._audioCueService.playAudioCue(AudioCue.diffLineDeleted);
|
||||
this._audioCueService.playAudioCue(AudioCue.diffLineDeleted, { source: 'accessibleDiffViewer.currentElementChanged' });
|
||||
} else if (currentViewItem?.type === LineType.Added) {
|
||||
this._audioCueService.playAudioCue(AudioCue.diffLineInserted);
|
||||
this._audioCueService.playAudioCue(AudioCue.diffLineInserted, { source: 'accessibleDiffViewer.currentElementChanged' });
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
@@ -255,11 +255,11 @@ export class DiffEditorWidget2 extends DelegatingEditor implements IDiffEditor {
|
||||
if (e?.reason === CursorChangeReason.Explicit) {
|
||||
const diff = this._diffModel.get()?.diff.get()?.mappings.find(m => m.lineRangeMapping.modifiedRange.contains(e.position.lineNumber));
|
||||
if (diff?.lineRangeMapping.modifiedRange.isEmpty) {
|
||||
this._audioCueService.playAudioCue(AudioCue.diffLineDeleted);
|
||||
this._audioCueService.playAudioCue(AudioCue.diffLineDeleted, { source: 'diffEditor.cursorPositionChanged' });
|
||||
} else if (diff?.lineRangeMapping.originalRange.isEmpty) {
|
||||
this._audioCueService.playAudioCue(AudioCue.diffLineInserted);
|
||||
this._audioCueService.playAudioCue(AudioCue.diffLineInserted, { source: 'diffEditor.cursorPositionChanged' });
|
||||
} else if (diff) {
|
||||
this._audioCueService.playAudioCue(AudioCue.diffLineModified);
|
||||
this._audioCueService.playAudioCue(AudioCue.diffLineModified, { source: 'diffEditor.cursorPositionChanged' });
|
||||
}
|
||||
}
|
||||
}));
|
||||
@@ -460,11 +460,11 @@ export class DiffEditorWidget2 extends DelegatingEditor implements IDiffEditor {
|
||||
this._goTo(diff);
|
||||
|
||||
if (diff.lineRangeMapping.modifiedRange.isEmpty) {
|
||||
this._audioCueService.playAudioCue(AudioCue.diffLineDeleted);
|
||||
this._audioCueService.playAudioCue(AudioCue.diffLineDeleted, { source: 'diffEditor.goToDiff' });
|
||||
} else if (diff.lineRangeMapping.originalRange.isEmpty) {
|
||||
this._audioCueService.playAudioCue(AudioCue.diffLineInserted);
|
||||
this._audioCueService.playAudioCue(AudioCue.diffLineInserted, { source: 'diffEditor.goToDiff' });
|
||||
} else if (diff) {
|
||||
this._audioCueService.playAudioCue(AudioCue.diffLineModified);
|
||||
this._audioCueService.playAudioCue(AudioCue.diffLineModified, { source: 'diffEditor.goToDiff' });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -286,7 +286,7 @@ export class ViewZoneManager extends Disposable {
|
||||
|
||||
for (const a of alignmentsSyncedMovedText.read(reader) ?? []) {
|
||||
if (!syncedMovedText?.lineRangeMapping.original.intersect(a.originalRange)
|
||||
&& !syncedMovedText?.lineRangeMapping.modified.intersect(a.modifiedRange)) {
|
||||
|| !syncedMovedText?.lineRangeMapping.modified.intersect(a.modifiedRange)) {
|
||||
// ignore unrelated alignments outside the synced moved text
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -224,11 +224,11 @@ export class DiffNavigator extends Disposable implements IDiffNavigator {
|
||||
}
|
||||
const insertedOrModified = modifiedEditor.getLineDecorations(lineNumber).find(l => l.options.className === 'line-insert');
|
||||
if (insertedOrModified) {
|
||||
this._audioCueService.playAudioCue(AudioCue.diffLineModified, true);
|
||||
this._audioCueService.playAudioCue(AudioCue.diffLineModified, { allowManyInParallel: true });
|
||||
} else if (jumpToChange) {
|
||||
// The modified editor does not include deleted lines, but when
|
||||
// we are moved to the area where lines were deleted, play this cue
|
||||
this._audioCueService.playAudioCue(AudioCue.diffLineDeleted, true);
|
||||
this._audioCueService.playAudioCue(AudioCue.diffLineDeleted, { allowManyInParallel: true });
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -325,9 +325,9 @@ export class DiffReview extends Disposable {
|
||||
}
|
||||
const element = !type ? current : type === 'next' ? current?.nextElementSibling : current?.previousElementSibling;
|
||||
if (element?.classList.contains(DiffEditorLineClasses.Insert)) {
|
||||
this._audioCueService.playAudioCue(AudioCue.diffLineInserted, true);
|
||||
this._audioCueService.playAudioCue(AudioCue.diffLineInserted, { allowManyInParallel: true });
|
||||
} else if (element?.classList.contains(DiffEditorLineClasses.Delete)) {
|
||||
this._audioCueService.playAudioCue(AudioCue.diffLineDeleted, true);
|
||||
this._audioCueService.playAudioCue(AudioCue.diffLineDeleted, { allowManyInParallel: true });
|
||||
}
|
||||
this.scrollbar.scanDomNode();
|
||||
}
|
||||
|
||||
@@ -3,8 +3,10 @@
|
||||
* 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 { assertFn, checkAdjacentItems } from 'vs/base/common/assert';
|
||||
import { CharCode } from 'vs/base/common/charCode';
|
||||
import { SetMap } from 'vs/base/common/collections';
|
||||
import { LineRange } from 'vs/editor/common/core/lineRange';
|
||||
import { OffsetRange } from 'vs/editor/common/core/offsetRange';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
@@ -137,37 +139,9 @@ export class StandardLinesDiffComputer implements ILinesDiffComputer {
|
||||
|
||||
const changes = lineRangeMappingFromRangeMappings(alignments, originalLines, modifiedLines);
|
||||
|
||||
const moves: MovedText[] = [];
|
||||
let moves: MovedText[] = [];
|
||||
if (options.computeMoves) {
|
||||
const deletions = changes
|
||||
.filter(c => c.modifiedRange.isEmpty && c.originalRange.length >= 3)
|
||||
.map(d => new LineRangeFragment(d.originalRange, originalLines));
|
||||
const insertions = new Set(changes
|
||||
.filter(c => c.originalRange.isEmpty && c.modifiedRange.length >= 3)
|
||||
.map(d => new LineRangeFragment(d.modifiedRange, modifiedLines)));
|
||||
|
||||
for (const deletion of deletions) {
|
||||
let highestSimilarity = -1;
|
||||
let best: LineRangeFragment | undefined;
|
||||
for (const insertion of insertions) {
|
||||
const similarity = deletion.computeSimilarity(insertion);
|
||||
if (similarity > highestSimilarity) {
|
||||
highestSimilarity = similarity;
|
||||
best = insertion;
|
||||
}
|
||||
}
|
||||
|
||||
if (highestSimilarity > 0.90 && best) {
|
||||
const moveChanges = this.refineDiff(originalLines, modifiedLines, new SequenceDiff(
|
||||
new OffsetRange(deletion.range.startLineNumber - 1, deletion.range.endLineNumberExclusive - 1),
|
||||
new OffsetRange(best.range.startLineNumber - 1, best.range.endLineNumberExclusive - 1),
|
||||
), timeout, considerWhitespaceChanges);
|
||||
const mappings = lineRangeMappingFromRangeMappings(moveChanges.mappings, originalLines, modifiedLines, true);
|
||||
|
||||
insertions.delete(best);
|
||||
moves.push(new MovedText(new SimpleLineRangeMapping(deletion.range, best.range), mappings));
|
||||
}
|
||||
}
|
||||
moves = this.computeMoves(changes, originalLines, modifiedLines, srcDocLines, tgtDocLines, timeout, considerWhitespaceChanges);
|
||||
}
|
||||
|
||||
// Make sure all ranges are valid
|
||||
@@ -202,6 +176,136 @@ export class StandardLinesDiffComputer implements ILinesDiffComputer {
|
||||
return new LinesDiff(changes, moves, hitTimeout);
|
||||
}
|
||||
|
||||
private computeMoves(changes: LineRangeMapping[], originalLines: string[], modifiedLines: string[], hashedOriginalLines: number[], hashedModifiedLines: number[], timeout: ITimeout, considerWhitespaceChanges: boolean): MovedText[] {
|
||||
const moves: MovedText[] = [];
|
||||
const deletions = changes
|
||||
.filter(c => c.modifiedRange.isEmpty && c.originalRange.length >= 3)
|
||||
.map(d => new LineRangeFragment(d.originalRange, originalLines, d));
|
||||
const insertions = new Set(changes
|
||||
.filter(c => c.originalRange.isEmpty && c.modifiedRange.length >= 3)
|
||||
.map(d => new LineRangeFragment(d.modifiedRange, modifiedLines, d)));
|
||||
|
||||
const excludedChanges = new Set<LineRangeMapping>();
|
||||
|
||||
for (const deletion of deletions) {
|
||||
let highestSimilarity = -1;
|
||||
let best: LineRangeFragment | undefined;
|
||||
for (const insertion of insertions) {
|
||||
const similarity = deletion.computeSimilarity(insertion);
|
||||
if (similarity > highestSimilarity) {
|
||||
highestSimilarity = similarity;
|
||||
best = insertion;
|
||||
}
|
||||
}
|
||||
|
||||
if (highestSimilarity > 0.90 && best) {
|
||||
const moveChanges = this.refineDiff(originalLines, modifiedLines, new SequenceDiff(
|
||||
new OffsetRange(deletion.range.startLineNumber - 1, deletion.range.endLineNumberExclusive - 1),
|
||||
new OffsetRange(best.range.startLineNumber - 1, best.range.endLineNumberExclusive - 1)
|
||||
), timeout, considerWhitespaceChanges);
|
||||
const mappings = lineRangeMappingFromRangeMappings(moveChanges.mappings, originalLines, modifiedLines, true);
|
||||
|
||||
insertions.delete(best);
|
||||
moves.push(new MovedText(new SimpleLineRangeMapping(deletion.range, best.range), mappings));
|
||||
excludedChanges.add(deletion.source);
|
||||
excludedChanges.add(best.source);
|
||||
}
|
||||
}
|
||||
|
||||
const original3LineHashes = new SetMap<string, { range: LineRange }>();
|
||||
|
||||
for (const change of changes) {
|
||||
if (excludedChanges.has(change)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (let i = change.originalRange.startLineNumber; i < change.originalRange.endLineNumberExclusive - 2; i++) {
|
||||
const key = `${hashedOriginalLines[i - 1]}:${hashedOriginalLines[i + 1 - 1]}:${hashedOriginalLines[i + 2 - 1]}`;
|
||||
original3LineHashes.add(key, { range: new LineRange(i, i + 3) });
|
||||
}
|
||||
}
|
||||
|
||||
interface PossibleMapping {
|
||||
modifiedLineRange: LineRange;
|
||||
originalLineRange: LineRange;
|
||||
}
|
||||
|
||||
const possibleMappings: PossibleMapping[] = [];
|
||||
|
||||
changes.sort(compareBy(c => c.modifiedRange.startLineNumber, numberComparator));
|
||||
|
||||
for (const change of changes) {
|
||||
if (excludedChanges.has(change)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let lastMappings: PossibleMapping[] = [];
|
||||
for (let i = change.modifiedRange.startLineNumber; i < change.modifiedRange.endLineNumberExclusive - 2; i++) {
|
||||
const key = `${hashedModifiedLines[i - 1]}:${hashedModifiedLines[i + 1 - 1]}:${hashedModifiedLines[i + 2 - 1]}`;
|
||||
|
||||
//const isWeakKey = (originalLines[i].trim().length + originalLines[i + 1].trim().length + originalLines[i + 2].trim().length < 20);
|
||||
|
||||
const currentModifiedRange = new LineRange(i, i + 3);
|
||||
|
||||
const nextMappings: PossibleMapping[] = [];
|
||||
original3LineHashes.forEach(key, ({ range }) => {
|
||||
for (const lastMapping of lastMappings) {
|
||||
// does this match extend some last match?
|
||||
if (lastMapping.originalLineRange.endLineNumberExclusive + 1 === range.endLineNumberExclusive &&
|
||||
lastMapping.modifiedLineRange.endLineNumberExclusive + 1 === currentModifiedRange.endLineNumberExclusive) {
|
||||
lastMapping.originalLineRange = new LineRange(lastMapping.originalLineRange.startLineNumber, range.endLineNumberExclusive);
|
||||
lastMapping.modifiedLineRange = new LineRange(lastMapping.modifiedLineRange.startLineNumber, currentModifiedRange.endLineNumberExclusive);
|
||||
nextMappings.push(lastMapping);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const mapping: PossibleMapping = {
|
||||
modifiedLineRange: currentModifiedRange,
|
||||
originalLineRange: range,
|
||||
};
|
||||
possibleMappings.push(mapping);
|
||||
nextMappings.push(mapping);
|
||||
});
|
||||
lastMappings = nextMappings;
|
||||
}
|
||||
}
|
||||
|
||||
possibleMappings.sort(reverseOrder(compareBy(m => m.modifiedLineRange.length, numberComparator)));
|
||||
|
||||
const modifiedSet = new LineRangeSet();
|
||||
const originalSet = new LineRangeSet();
|
||||
|
||||
for (const mapping of possibleMappings) {
|
||||
|
||||
const diffOrigToMod = mapping.modifiedLineRange.startLineNumber - mapping.originalLineRange.startLineNumber;
|
||||
const modifiedSections = modifiedSet.subtractFrom(mapping.modifiedLineRange);
|
||||
const originalTranslatedSections = originalSet.subtractFrom(mapping.originalLineRange).map(r => r.delta(diffOrigToMod));
|
||||
|
||||
const modifiedIntersectedSections = intersectRanges(modifiedSections, originalTranslatedSections);
|
||||
|
||||
for (const s of modifiedIntersectedSections) {
|
||||
if (s.length < 3) {
|
||||
continue;
|
||||
}
|
||||
const modifiedLineRange = s;
|
||||
const originalLineRange = s.delta(-diffOrigToMod);
|
||||
|
||||
const moveChanges = this.refineDiff(originalLines, modifiedLines, new SequenceDiff(
|
||||
new OffsetRange(originalLineRange.startLineNumber - 1, originalLineRange.endLineNumberExclusive - 1),
|
||||
new OffsetRange(modifiedLineRange.startLineNumber - 1, modifiedLineRange.endLineNumberExclusive - 1)
|
||||
), timeout, considerWhitespaceChanges);
|
||||
const mappings = lineRangeMappingFromRangeMappings(moveChanges.mappings, originalLines, modifiedLines, true);
|
||||
moves.push(new MovedText(new SimpleLineRangeMapping(originalLineRange, modifiedLineRange), mappings));
|
||||
|
||||
modifiedSet.addRange(modifiedLineRange);
|
||||
originalSet.addRange(originalLineRange);
|
||||
}
|
||||
}
|
||||
|
||||
return moves;
|
||||
}
|
||||
|
||||
private refineDiff(originalLines: string[], modifiedLines: string[], diff: SequenceDiff, timeout: ITimeout, considerWhitespaceChanges: boolean): { mappings: RangeMapping[]; hitTimeout: boolean } {
|
||||
const slice1 = new LinesSliceCharSequence(originalLines, diff.seq1Range, considerWhitespaceChanges);
|
||||
const slice2 = new LinesSliceCharSequence(modifiedLines, diff.seq2Range, considerWhitespaceChanges);
|
||||
@@ -233,6 +337,100 @@ export class StandardLinesDiffComputer implements ILinesDiffComputer {
|
||||
}
|
||||
}
|
||||
|
||||
function intersectRanges(ranges1: LineRange[], ranges2: LineRange[]): LineRange[] {
|
||||
const result: LineRange[] = [];
|
||||
|
||||
let i1 = 0;
|
||||
let i2 = 0;
|
||||
while (i1 < ranges1.length && i2 < ranges2.length) {
|
||||
const r1 = ranges1[i1];
|
||||
const r2 = ranges2[i2];
|
||||
|
||||
const i = r1.intersect(r2);
|
||||
if (i && !i.isEmpty) {
|
||||
result.push(i);
|
||||
}
|
||||
|
||||
if (r1.endLineNumberExclusive < r2.endLineNumberExclusive) {
|
||||
i1++;
|
||||
} else {
|
||||
i2++;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// TODO make this fast
|
||||
class LineRangeSet {
|
||||
private readonly _normalizedRanges: LineRange[] = [];
|
||||
|
||||
addRange(range: LineRange): void {
|
||||
// Idea: Find joinRange such that:
|
||||
// replaceRange = _normalizedRanges.replaceRange(joinRange, range.joinAll(joinRange.map(idx => this._normalizedRanges[idx])))
|
||||
|
||||
// idx of first element that touches range or that is after range
|
||||
const joinRangeStartIdx = mapMinusOne(this._normalizedRanges.findIndex(r => r.endLineNumberExclusive >= range.startLineNumber), this._normalizedRanges.length);
|
||||
// idx of element after { last element that touches range or that is before range }
|
||||
const joinRangeEndIdxExclusive = findLastIndex(this._normalizedRanges, r => r.startLineNumber <= range.endLineNumberExclusive) + 1;
|
||||
|
||||
if (joinRangeStartIdx === joinRangeEndIdxExclusive) {
|
||||
// If there is no element that touches range, then joinRangeStartIdx === joinRangeEndIdxExclusive and that value is the index of the element after range
|
||||
this._normalizedRanges.splice(joinRangeStartIdx, 0, range);
|
||||
} else if (joinRangeStartIdx === joinRangeEndIdxExclusive - 1) {
|
||||
// Else, there is an element that touches range and in this case it is both the first and last element. Thus we can replace it
|
||||
const joinRange = this._normalizedRanges[joinRangeStartIdx];
|
||||
this._normalizedRanges[joinRangeStartIdx] = joinRange.join(range);
|
||||
} else {
|
||||
// First and last element are different - we need to replace the entire range
|
||||
const joinRange = this._normalizedRanges[joinRangeStartIdx].join(this._normalizedRanges[joinRangeEndIdxExclusive - 1]).join(range);
|
||||
this._normalizedRanges.splice(joinRangeStartIdx, joinRangeEndIdxExclusive - joinRangeStartIdx, joinRange);
|
||||
}
|
||||
}
|
||||
|
||||
intersects(range: LineRange): boolean {
|
||||
for (const r of this._normalizedRanges) {
|
||||
if (r.intersectsStrict(range)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts all ranges in this set from `range` and returns the result.
|
||||
*/
|
||||
subtractFrom(range: LineRange): LineRange[] {
|
||||
// idx of first element that touches range or that is after range
|
||||
const joinRangeStartIdx = mapMinusOne(this._normalizedRanges.findIndex(r => r.endLineNumberExclusive >= range.startLineNumber), this._normalizedRanges.length);
|
||||
// idx of element after { last element that touches range or that is before range }
|
||||
const joinRangeEndIdxExclusive = findLastIndex(this._normalizedRanges, r => r.startLineNumber <= range.endLineNumberExclusive) + 1;
|
||||
|
||||
if (joinRangeStartIdx === joinRangeEndIdxExclusive) {
|
||||
return [range];
|
||||
}
|
||||
|
||||
const result: LineRange[] = [];
|
||||
let startLineNumber = range.startLineNumber;
|
||||
for (let i = joinRangeStartIdx; i < joinRangeEndIdxExclusive; i++) {
|
||||
const r = this._normalizedRanges[i];
|
||||
if (r.startLineNumber > startLineNumber) {
|
||||
result.push(new LineRange(startLineNumber, r.startLineNumber));
|
||||
}
|
||||
startLineNumber = r.endLineNumberExclusive;
|
||||
}
|
||||
if (startLineNumber < range.endLineNumberExclusive) {
|
||||
result.push(new LineRange(startLineNumber, range.endLineNumberExclusive));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
function mapMinusOne(idx: number, mapTo: number): number {
|
||||
return idx === -1 ? mapTo : idx;
|
||||
}
|
||||
|
||||
function coverFullWords(sequence1: LinesSliceCharSequence, sequence2: LinesSliceCharSequence, sequenceDiffs: SequenceDiff[]): SequenceDiff[] {
|
||||
const additional: SequenceDiff[] = [];
|
||||
|
||||
@@ -676,6 +874,7 @@ class LineRangeFragment {
|
||||
constructor(
|
||||
public readonly range: LineRange,
|
||||
public readonly lines: string[],
|
||||
public readonly source: LineRangeMapping,
|
||||
) {
|
||||
let counter = 0;
|
||||
for (let i = range.startLineNumber - 1; i < range.endLineNumberExclusive - 1; i++) {
|
||||
|
||||
@@ -1039,7 +1039,7 @@ class StandaloneContextMenuService extends ContextMenuService {
|
||||
|
||||
class StandaloneAudioService implements IAudioCueService {
|
||||
_serviceBrand: undefined;
|
||||
async playAudioCue(cue: AudioCue, allowManyInParallel?: boolean | undefined): Promise<void> {
|
||||
async playAudioCue(cue: AudioCue, options: {}): Promise<void> {
|
||||
}
|
||||
|
||||
async playAudioCues(cues: AudioCue[]): Promise<void> {
|
||||
|
||||
@@ -11,13 +11,14 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { localize } from 'vs/nls';
|
||||
import { observableFromEvent, derived } from 'vs/base/common/observable';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
|
||||
export const IAudioCueService = createDecorator<IAudioCueService>('audioCue');
|
||||
|
||||
export interface IAudioCueService {
|
||||
readonly _serviceBrand: undefined;
|
||||
playAudioCue(cue: AudioCue, allowManyInParallel?: boolean): Promise<void>;
|
||||
playAudioCues(cues: AudioCue[]): Promise<void>;
|
||||
playAudioCue(cue: AudioCue, options?: IAudioCueOptions): Promise<void>;
|
||||
playAudioCues(cues: (AudioCue | { cue: AudioCue; source: string })[]): Promise<void>;
|
||||
isEnabled(cue: AudioCue): boolean;
|
||||
onEnabledChanged(cue: AudioCue): Event<void>;
|
||||
|
||||
@@ -25,33 +26,72 @@ export interface IAudioCueService {
|
||||
playAudioCueLoop(cue: AudioCue, milliseconds: number): IDisposable;
|
||||
}
|
||||
|
||||
export interface IAudioCueOptions {
|
||||
allowManyInParallel?: boolean;
|
||||
source?: string;
|
||||
}
|
||||
|
||||
export class AudioCueService extends Disposable implements IAudioCueService {
|
||||
readonly _serviceBrand: undefined;
|
||||
sounds: Map<string, HTMLAudioElement> = new Map();
|
||||
private readonly sounds: Map<string, HTMLAudioElement> = new Map();
|
||||
private readonly screenReaderAttached = observableFromEvent(
|
||||
this.accessibilityService.onDidChangeScreenReaderOptimized,
|
||||
() => /** @description accessibilityService.onDidChangeScreenReaderOptimized */ this.accessibilityService.isScreenReaderOptimized()
|
||||
);
|
||||
private readonly sentTelemetry = new Set<string>();
|
||||
|
||||
constructor(
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@IAccessibilityService private readonly accessibilityService: IAccessibilityService
|
||||
@IAccessibilityService private readonly accessibilityService: IAccessibilityService,
|
||||
@ITelemetryService private readonly telemetryService: ITelemetryService,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
public async playAudioCue(cue: AudioCue, allowManyInParallel = false): Promise<void> {
|
||||
public async playAudioCue(cue: AudioCue, options: IAudioCueOptions = {}): Promise<void> {
|
||||
if (this.isEnabled(cue)) {
|
||||
await this.playSound(cue.sound.getSound(), allowManyInParallel);
|
||||
this.sendAudioCueTelemetry(cue, options.source);
|
||||
await this.playSound(cue.sound.getSound(), options.allowManyInParallel);
|
||||
}
|
||||
}
|
||||
|
||||
public async playAudioCues(cues: AudioCue[]): Promise<void> {
|
||||
public async playAudioCues(cues: (AudioCue | { cue: AudioCue; source: string })[]): Promise<void> {
|
||||
for (const cue of cues) {
|
||||
this.sendAudioCueTelemetry('cue' in cue ? cue.cue : cue, 'source' in cue ? cue.source : undefined);
|
||||
}
|
||||
|
||||
// Some audio cues might reuse sounds. Don't play the same sound twice.
|
||||
const sounds = new Set(cues.filter(cue => this.isEnabled(cue)).map(cue => cue.sound.getSound()));
|
||||
const sounds = new Set(cues.map(c => 'cue' in c ? c.cue : c).filter(cue => this.isEnabled(cue)).map(cue => cue.sound.getSound()));
|
||||
await Promise.all(Array.from(sounds).map(sound => this.playSound(sound, true)));
|
||||
}
|
||||
|
||||
private sendAudioCueTelemetry(cue: AudioCue, source: string | undefined): void {
|
||||
const isScreenReaderOptimized = this.accessibilityService.isScreenReaderOptimized();
|
||||
const key = cue.name + (source ? `::${source}` : '') + (isScreenReaderOptimized ? '{screenReaderOptimized}' : '');
|
||||
// Only send once per user session
|
||||
if (this.sentTelemetry.has(key) || this.getVolumeInPercent() === 0) {
|
||||
return;
|
||||
}
|
||||
this.sentTelemetry.add(key);
|
||||
|
||||
this.telemetryService.publicLog2<{
|
||||
audioCue: string;
|
||||
source: string;
|
||||
isScreenReaderOptimized: boolean;
|
||||
}, {
|
||||
owner: 'hediet';
|
||||
|
||||
audioCue: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The audio cue that was played.' };
|
||||
source: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The source that triggered the audio cue (e.g. "diffEditorNavigation").' };
|
||||
isScreenReaderOptimized: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether the user is using a screen reader' };
|
||||
|
||||
comment: 'This data is collected to understand how audio cues are used and if more audio cues should be added.';
|
||||
}>('audioCue.played', {
|
||||
audioCue: cue.name,
|
||||
source: source ?? '',
|
||||
isScreenReaderOptimized,
|
||||
});
|
||||
}
|
||||
|
||||
private getVolumeInPercent(): number {
|
||||
const volume = this.configurationService.getValue<number>('audioCues.volume');
|
||||
@@ -92,7 +132,7 @@ export class AudioCueService extends Disposable implements IAudioCueService {
|
||||
let playing = true;
|
||||
const playSound = () => {
|
||||
if (playing) {
|
||||
this.playAudioCue(cue, true).finally(() => {
|
||||
this.playAudioCue(cue, { allowManyInParallel: true }).finally(() => {
|
||||
setTimeout(() => {
|
||||
if (playing) {
|
||||
playSound();
|
||||
|
||||
@@ -236,6 +236,9 @@ export abstract class AbstractNativeEnvironmentService implements INativeEnviron
|
||||
@memoize
|
||||
get disableWorkspaceTrust(): boolean { return !!this.args['disable-workspace-trust']; }
|
||||
|
||||
@memoize
|
||||
get disableKeytar(): boolean { return !!this.args['disable-keytar']; }
|
||||
|
||||
@memoize
|
||||
get policyFile(): URI | undefined {
|
||||
if (this.args['__enable-file-policy']) {
|
||||
|
||||
@@ -59,9 +59,6 @@ export class EnvironmentMainService extends NativeEnvironmentService implements
|
||||
@memoize
|
||||
get disableUpdates(): boolean { return !!this.args['disable-updates']; }
|
||||
|
||||
@memoize
|
||||
get disableKeytar(): boolean { return !!this.args['disable-keytar']; }
|
||||
|
||||
@memoize
|
||||
get crossOriginIsolated(): boolean { return !!this.args['enable-coi']; }
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import { IStorageService, InMemoryStorageService, StorageScope, StorageTarget }
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { Lazy } from 'vs/base/common/lazy';
|
||||
|
||||
export const ISecretStorageService = createDecorator<ISecretStorageService>('secretStorageService');
|
||||
|
||||
@@ -39,28 +40,24 @@ export class BaseSecretStorageService implements ISecretStorageService {
|
||||
|
||||
private readonly _onDidChangeValueDisposable = new DisposableStore();
|
||||
|
||||
protected resolvedStorageService = this.initialize();
|
||||
|
||||
constructor(
|
||||
private readonly _useInMemoryStorage: boolean,
|
||||
@IStorageService private _storageService: IStorageService,
|
||||
@IEncryptionService protected _encryptionService: IEncryptionService,
|
||||
@ILogService protected readonly _logService: ILogService
|
||||
@ILogService protected readonly _logService: ILogService,
|
||||
) { }
|
||||
|
||||
/**
|
||||
* @Note initialize must be called first so that this can be resolved properly
|
||||
* otherwise it will return 'unknown'.
|
||||
*/
|
||||
get type() {
|
||||
return this._type;
|
||||
}
|
||||
|
||||
private onDidChangeValue(key: string): void {
|
||||
if (!key.startsWith(this._storagePrefix)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const secretKey = key.slice(this._storagePrefix.length);
|
||||
|
||||
this._logService.trace(`[SecretStorageService] Notifying change in value for secret: ${secretKey}`);
|
||||
this.onDidChangeSecretEmitter.fire(secretKey);
|
||||
private _lazyStorageService: Lazy<Promise<IStorageService>> = new Lazy(() => this.initialize());
|
||||
protected get resolvedStorageService() {
|
||||
return this._lazyStorageService.value;
|
||||
}
|
||||
|
||||
get(key: string): Promise<string | undefined> {
|
||||
@@ -127,6 +124,7 @@ export class BaseSecretStorageService implements ISecretStorageService {
|
||||
private async initialize(): Promise<IStorageService> {
|
||||
let storageService;
|
||||
if (!this._useInMemoryStorage && await this._encryptionService.isEncryptionAvailable()) {
|
||||
this._logService.trace(`[SecretStorageService] Encryption is available, using persisted storage`);
|
||||
this._type = 'persisted';
|
||||
storageService = this._storageService;
|
||||
} else {
|
||||
@@ -147,7 +145,18 @@ export class BaseSecretStorageService implements ISecretStorageService {
|
||||
}
|
||||
|
||||
protected reinitialize(): void {
|
||||
this.resolvedStorageService = this.initialize();
|
||||
this._lazyStorageService = new Lazy(() => this.initialize());
|
||||
}
|
||||
|
||||
private onDidChangeValue(key: string): void {
|
||||
if (!key.startsWith(this._storagePrefix)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const secretKey = key.slice(this._storagePrefix.length);
|
||||
|
||||
this._logService.trace(`[SecretStorageService] Notifying change in value for secret: ${secretKey}`);
|
||||
this.onDidChangeSecretEmitter.fire(secretKey);
|
||||
}
|
||||
|
||||
private getKey(key: string): string {
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
import * as assert from 'assert';
|
||||
import * as sinon from 'sinon';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
import { IEncryptionService, KnownStorageProvider } from 'vs/platform/encryption/common/encryptionService';
|
||||
import { NullLogService } from 'vs/platform/log/common/log';
|
||||
import { BaseSecretStorageService } from 'vs/platform/secrets/common/secrets';
|
||||
@@ -67,8 +66,10 @@ suite('secrets', () => {
|
||||
});
|
||||
|
||||
test('type', async () => {
|
||||
// allow initialization to complete
|
||||
await timeout(0);
|
||||
assert.strictEqual(service.type, 'unknown');
|
||||
// trigger lazy initialization
|
||||
await service.set('my-secret', 'my-secret-value');
|
||||
|
||||
assert.strictEqual(service.type, 'in-memory');
|
||||
});
|
||||
|
||||
@@ -122,8 +123,10 @@ suite('secrets', () => {
|
||||
});
|
||||
|
||||
test('type', async () => {
|
||||
// allow initialization to complete
|
||||
await timeout(0);
|
||||
assert.strictEqual(service.type, 'unknown');
|
||||
// trigger lazy initialization
|
||||
await service.set('my-secret', 'my-secret-value');
|
||||
|
||||
assert.strictEqual(service.type, 'persisted');
|
||||
});
|
||||
|
||||
@@ -177,8 +180,10 @@ suite('secrets', () => {
|
||||
});
|
||||
|
||||
test('type', async () => {
|
||||
// allow initialization to complete
|
||||
await timeout(0);
|
||||
assert.strictEqual(service.type, 'unknown');
|
||||
// trigger lazy initialization
|
||||
await service.set('my-secret', 'my-secret-value');
|
||||
|
||||
assert.strictEqual(service.type, 'in-memory');
|
||||
});
|
||||
|
||||
|
||||
@@ -41,6 +41,8 @@ import { IUserDataProfileService } from 'vs/workbench/services/userDataProfile/c
|
||||
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { ISecretStorageService } from 'vs/platform/secrets/common/secrets';
|
||||
import { ILifecycleService, LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
||||
import { runWhenIdle } from 'vs/base/common/async';
|
||||
|
||||
export class ViewContainerActivityAction extends ActivityAction {
|
||||
|
||||
@@ -239,6 +241,7 @@ export class AccountsActivityActionViewItem extends MenuActivityActionViewItem {
|
||||
colors: (theme: IColorTheme) => ICompositeBarColors,
|
||||
activityHoverOptions: IActivityHoverOptions,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@ILifecycleService private readonly lifecycleService: ILifecycleService,
|
||||
@IHoverService hoverService: IHoverService,
|
||||
@IContextMenuService contextMenuService: IContextMenuService,
|
||||
@IMenuService menuService: IMenuService,
|
||||
@@ -285,6 +288,16 @@ export class AccountsActivityActionViewItem extends MenuActivityActionViewItem {
|
||||
// This function exists to ensure that the accounts are added for auth providers that had already been registered
|
||||
// before the menu was created.
|
||||
private async initialize(): Promise<void> {
|
||||
// Resolving the menu doesn't need to happen immediately, so we can wait until after the workbench has been restored
|
||||
// and only run this when the system is idle.
|
||||
await this.lifecycleService.when(LifecyclePhase.Restored);
|
||||
const disposable = this._register(runWhenIdle(async () => {
|
||||
await this.doInitialize();
|
||||
disposable.dispose();
|
||||
}));
|
||||
}
|
||||
|
||||
private async doInitialize(): Promise<void> {
|
||||
const providerIds = this.authenticationService.getProviderIds();
|
||||
const results = await Promise.allSettled(providerIds.map(providerId => this.addAccountsFromProvider(providerId)));
|
||||
|
||||
|
||||
@@ -1499,15 +1499,7 @@ export function getMultiSelectedEditorContexts(editorContext: IEditorCommandsCon
|
||||
if (focus) {
|
||||
const selection: Array<IEditorIdentifier | IEditorGroup> = list.getSelectedElements().filter(onlyEditorGroupAndEditor);
|
||||
|
||||
// Only respect selection if it contains focused element
|
||||
if (selection?.some(s => {
|
||||
if (isEditorGroup(s)) {
|
||||
return s.id === focus.groupId;
|
||||
}
|
||||
|
||||
const group = editorGroupService.getGroup(s.groupId);
|
||||
return s.groupId === focus.groupId && (group ? group.getIndexOfEditor(s.editor) : -1) === focus.editorIndex;
|
||||
})) {
|
||||
if (selection.length > 0) {
|
||||
return selection.map(elementToContext);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,9 +27,11 @@ import { CodeActionController } from 'vs/editor/contrib/codeAction/browser/codeA
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { AccessibilityVerbositySettingId, accessibilityHelpIsShown, accessibleViewIsShown } from 'vs/workbench/contrib/accessibility/browser/accessibilityConfiguration';
|
||||
import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
|
||||
import { Action2, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions';
|
||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
|
||||
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { IPickerQuickAccessItem } from 'vs/platform/quickinput/browser/pickerQuickAccess';
|
||||
import { marked } from 'vs/base/common/marked/marked';
|
||||
|
||||
const enum DIMENSIONS {
|
||||
MAX_WIDTH = 600
|
||||
@@ -42,6 +44,10 @@ export interface IAccessibleContentProvider {
|
||||
onKeyDown?(e: IKeyboardEvent): void;
|
||||
previous?(): void;
|
||||
next?(): void;
|
||||
/**
|
||||
* When the language is markdown, this is provided by default.
|
||||
*/
|
||||
getSymbols?(): IAccessibleViewSymbol[];
|
||||
options: IAccessibleViewOptions;
|
||||
}
|
||||
|
||||
@@ -52,6 +58,7 @@ export interface IAccessibleViewService {
|
||||
show(provider: IAccessibleContentProvider): void;
|
||||
next(): void;
|
||||
previous(): void;
|
||||
goToSymbol(): void;
|
||||
/**
|
||||
* If the setting is enabled, provides the open accessible view hint as a localized string.
|
||||
* @param verbositySettingKey The setting key for the verbosity of the feature
|
||||
@@ -128,15 +135,21 @@ class AccessibleView extends Disposable {
|
||||
}));
|
||||
}
|
||||
|
||||
show(provider: IAccessibleContentProvider): void {
|
||||
show(provider?: IAccessibleContentProvider, symbol?: IAccessibleViewSymbol): void {
|
||||
if (!provider) {
|
||||
provider = this._currentProvider;
|
||||
}
|
||||
if (!provider) {
|
||||
return;
|
||||
}
|
||||
const delegate: IContextViewDelegate = {
|
||||
getAnchor: () => { return { x: (window.innerWidth / 2) - ((Math.min(this._layoutService.dimension.width * 0.62 /* golden cut */, DIMENSIONS.MAX_WIDTH)) / 2), y: this._layoutService.offset.quickPickTop }; },
|
||||
render: (container) => {
|
||||
container.classList.add('accessible-view-container');
|
||||
return this._render(provider, container);
|
||||
return this._render(provider!, container);
|
||||
},
|
||||
onHide: () => {
|
||||
if (provider.options.type === AccessibleViewType.Help) {
|
||||
if (provider!.options.type === AccessibleViewType.Help) {
|
||||
this._accessiblityHelpIsShown.reset();
|
||||
} else {
|
||||
this._accessibleViewIsShown.reset();
|
||||
@@ -150,6 +163,9 @@ class AccessibleView extends Disposable {
|
||||
} else {
|
||||
this._accessibleViewIsShown.set(true);
|
||||
}
|
||||
if (symbol && this._currentProvider) {
|
||||
this.showSymbol(this._currentProvider, symbol);
|
||||
}
|
||||
this._currentProvider = provider;
|
||||
}
|
||||
|
||||
@@ -167,6 +183,51 @@ class AccessibleView extends Disposable {
|
||||
this._currentProvider.next?.();
|
||||
}
|
||||
|
||||
goToSymbol(): void {
|
||||
this._instantiationService.createInstance(AccessibleViewSymbolQuickPick, this).show(this._currentProvider!);
|
||||
}
|
||||
|
||||
getSymbols(): IAccessibleViewSymbol[] | undefined {
|
||||
if (!this._currentProvider) {
|
||||
return;
|
||||
}
|
||||
const tokens = this._currentProvider.options.language && this._currentProvider.options.language !== 'markdown' ? this._currentProvider.getSymbols?.() : marked.lexer(this._currentProvider.provideContent());
|
||||
if (!tokens) {
|
||||
return;
|
||||
}
|
||||
const symbols: IAccessibleViewSymbol[] = [];
|
||||
for (const token of tokens) {
|
||||
let label: string | undefined = undefined;
|
||||
if ('type' in token) {
|
||||
switch (token.type) {
|
||||
case 'heading':
|
||||
case 'paragraph':
|
||||
case 'code':
|
||||
label = token.text;
|
||||
break;
|
||||
case 'list':
|
||||
label = token.items?.map(i => i.text).join(', ');
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
label = token.label;
|
||||
}
|
||||
if (label) {
|
||||
symbols.push({ info: label, label: localize('symbolLabel', "({0}) {1}", token.type, label), ariaLabel: localize('symbolLabelAria', "({0}) {1}", token.type, label) });
|
||||
}
|
||||
}
|
||||
return symbols;
|
||||
}
|
||||
|
||||
showSymbol(provider: IAccessibleContentProvider, symbol: IAccessibleViewSymbol): void {
|
||||
const index = provider.provideContent().split('\n').findIndex(line => line.includes(symbol.info.split('\n')[0])) ?? -1;
|
||||
if (index >= 0) {
|
||||
this.show(provider);
|
||||
this._editorWidget.revealLine(index + 1);
|
||||
this._editorWidget.setSelection({ startLineNumber: index + 1, startColumn: 1, endLineNumber: index + 1, endColumn: 1 });
|
||||
}
|
||||
}
|
||||
|
||||
private _render(provider: IAccessibleContentProvider, container: HTMLElement): IDisposable {
|
||||
this._currentProvider = provider;
|
||||
const settingKey = `accessibility.verbosity.${provider.verbositySettingKey}`;
|
||||
@@ -286,6 +347,9 @@ export class AccessibleViewService extends Disposable implements IAccessibleView
|
||||
previous(): void {
|
||||
this._accessibleView?.previous();
|
||||
}
|
||||
goToSymbol(): void {
|
||||
this._accessibleView?.goToSymbol();
|
||||
}
|
||||
getOpenAriaHint(verbositySettingKey: AccessibilityVerbositySettingId): string | null {
|
||||
if (!this._configurationService.getValue(verbositySettingKey)) {
|
||||
return null;
|
||||
@@ -300,7 +364,7 @@ class AccessibleViewNextAction extends Action2 {
|
||||
static id: 'editor.action.accessibleViewNext';
|
||||
constructor() {
|
||||
super({
|
||||
id: AccessibleViewNextAction.id,
|
||||
id: 'editor.action.accessibleViewNext',
|
||||
precondition: accessibleViewIsShown,
|
||||
keybinding: {
|
||||
primary: KeyMod.Alt | KeyCode.BracketRight,
|
||||
@@ -318,13 +382,38 @@ class AccessibleViewNextAction extends Action2 {
|
||||
accessor.get(IAccessibleViewService).next();
|
||||
}
|
||||
}
|
||||
registerAction2(AccessibleViewNextAction);
|
||||
|
||||
|
||||
class AccessibleViewGoToSymbolAction extends Action2 {
|
||||
static id: 'editor.action.accessibleViewGoToSymbol';
|
||||
constructor() {
|
||||
super({
|
||||
id: 'editor.action.accessibleViewGoToSymbol',
|
||||
precondition: accessibleViewIsShown,
|
||||
keybinding: {
|
||||
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyO,
|
||||
weight: KeybindingWeight.WorkbenchContrib + 10
|
||||
},
|
||||
menu: [{
|
||||
id: MenuId.CommandPalette,
|
||||
group: '',
|
||||
order: 1
|
||||
}],
|
||||
title: localize('editor.action.accessibleViewGoToSymbol', "Go To Symbol in Accessible View")
|
||||
});
|
||||
}
|
||||
run(accessor: ServicesAccessor, ...args: unknown[]): void {
|
||||
accessor.get(IAccessibleViewService).goToSymbol();
|
||||
}
|
||||
}
|
||||
registerAction2(AccessibleViewGoToSymbolAction);
|
||||
|
||||
class AccessibleViewPreviousAction extends Action2 {
|
||||
static id: 'editor.action.accessibleViewPrevious';
|
||||
constructor() {
|
||||
super({
|
||||
id: AccessibleViewPreviousAction.id,
|
||||
id: 'editor.action.accessibleViewPrevious',
|
||||
precondition: accessibleViewIsShown,
|
||||
keybinding: {
|
||||
primary: KeyMod.Alt | KeyCode.BracketLeft,
|
||||
@@ -339,10 +428,10 @@ class AccessibleViewPreviousAction extends Action2 {
|
||||
});
|
||||
}
|
||||
run(accessor: ServicesAccessor, ...args: unknown[]): void {
|
||||
accessor.get(IAccessibleViewService).next();
|
||||
accessor.get(IAccessibleViewService).previous();
|
||||
}
|
||||
}
|
||||
|
||||
registerAction2(AccessibleViewPreviousAction);
|
||||
|
||||
function registerCommand<T extends Command>(command: T): T {
|
||||
command.register();
|
||||
@@ -388,3 +477,33 @@ export const AccessibleViewAction = registerCommand(new MultiCommand({
|
||||
}],
|
||||
}));
|
||||
|
||||
|
||||
class AccessibleViewSymbolQuickPick {
|
||||
constructor(private _accessibleView: AccessibleView, @IQuickInputService private readonly _quickInputService: IQuickInputService) {
|
||||
|
||||
}
|
||||
show(provider: IAccessibleContentProvider): void {
|
||||
const quickPick = this._quickInputService.createQuickPick<IAccessibleViewSymbol>();
|
||||
const picks = [];
|
||||
const symbols = this._accessibleView.getSymbols();
|
||||
if (!symbols) {
|
||||
return;
|
||||
}
|
||||
for (const symbol of symbols) {
|
||||
picks.push({
|
||||
label: symbol.label,
|
||||
ariaLabel: symbol.ariaLabel
|
||||
});
|
||||
}
|
||||
quickPick.canSelectMany = false;
|
||||
quickPick.items = symbols;
|
||||
quickPick.show();
|
||||
quickPick.onDidAccept(() => {
|
||||
this._accessibleView.showSymbol(provider, quickPick.selectedItems[0]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
interface IAccessibleViewSymbol extends IPickerQuickAccessItem {
|
||||
info: string;
|
||||
}
|
||||
|
||||
@@ -3,12 +3,263 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { registerAction2 } from 'vs/platform/actions/common/actions';
|
||||
import { AskQuickQuestionAction } from 'vs/workbench/contrib/chat/browser/actions/quickQuestionActions/quickQuestionAction';
|
||||
|
||||
import 'vs/workbench/contrib/chat/browser/actions/quickQuestionActions/singleQuickQuestionAction';
|
||||
import 'vs/workbench/contrib/chat/browser/actions/quickQuestionActions/multipleByScrollQuickQuestionAction';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { ThemeIcon } from 'vs/base/common/themables';
|
||||
import { localize } from 'vs/nls';
|
||||
import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions';
|
||||
import { ContextKeyExpr, IContextKeyService, IScopedContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { IQuickInputService, IQuickPick, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { editorBackground, editorForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { CHAT_CATEGORY } from 'vs/workbench/contrib/chat/browser/actions/chatActions';
|
||||
import { IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat';
|
||||
import { IChatViewOptions } from 'vs/workbench/contrib/chat/browser/chatViewPane';
|
||||
import { ChatWidget } from 'vs/workbench/contrib/chat/browser/chatWidget';
|
||||
import { CONTEXT_PROVIDER_EXISTS } from 'vs/workbench/contrib/chat/common/chatContextKeys';
|
||||
import { ChatModel } from 'vs/workbench/contrib/chat/common/chatModel';
|
||||
import { IChatService } from 'vs/workbench/contrib/chat/common/chatService';
|
||||
|
||||
export const ASK_QUICK_QUESTION_ACTION_ID = 'chat.action.askQuickQuestion';
|
||||
export function registerChatQuickQuestionActions() {
|
||||
registerAction2(AskQuickQuestionAction);
|
||||
}
|
||||
|
||||
class AskQuickQuestionAction extends Action2 {
|
||||
private _currentTimer: any | undefined;
|
||||
private _input: IQuickPick<IQuickPickItem> | undefined;
|
||||
private _currentChat: QuickChat | undefined;
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: ASK_QUICK_QUESTION_ACTION_ID,
|
||||
title: { value: localize('chat', "Chat"), original: 'Chat' },
|
||||
precondition: CONTEXT_PROVIDER_EXISTS,
|
||||
icon: Codicon.commentDiscussion,
|
||||
f1: false,
|
||||
category: CHAT_CATEGORY,
|
||||
keybinding: {
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyI,
|
||||
linux: {
|
||||
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.KeyI
|
||||
}
|
||||
},
|
||||
menu: {
|
||||
id: MenuId.LayoutControlMenu,
|
||||
group: '0_workbench_toggles',
|
||||
when: ContextKeyExpr.notEquals('config.chat.experimental.defaultMode', 'chatView'),
|
||||
order: 0
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
override run(accessor: ServicesAccessor, query: string): void {
|
||||
const quickInputService = accessor.get(IQuickInputService);
|
||||
const chatService = accessor.get(IChatService);
|
||||
const instantiationService = accessor.get(IInstantiationService);
|
||||
|
||||
// First things first, clear the existing timer that will dispose the session
|
||||
clearTimeout(this._currentTimer);
|
||||
this._currentTimer = undefined;
|
||||
|
||||
// If the input is already shown, hide it. This provides a toggle behavior of the quick pick
|
||||
if (this._input !== undefined) {
|
||||
this._input.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if any providers are available. If not, show nothing
|
||||
// This shouldn't be needed because of the precondition, but just in case
|
||||
const providerInfo = chatService.getProviderInfos()[0];
|
||||
if (!providerInfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
const disposableStore = new DisposableStore();
|
||||
|
||||
//#region Setup quick pick
|
||||
|
||||
this._input = quickInputService.createQuickPick();
|
||||
disposableStore.add(this._input);
|
||||
this._input.hideInput = true;
|
||||
|
||||
|
||||
const containerSession = dom.$('.interactive-session');
|
||||
this._input.widget = containerSession;
|
||||
|
||||
this._currentChat ??= instantiationService.createInstance(QuickChat, {
|
||||
providerId: providerInfo.id,
|
||||
});
|
||||
// show needs to come before the current chat rendering
|
||||
this._input.show();
|
||||
this._currentChat.render(containerSession);
|
||||
|
||||
const clearButton = {
|
||||
iconClass: ThemeIcon.asClassName(Codicon.clearAll),
|
||||
tooltip: localize('clear', "Clear"),
|
||||
};
|
||||
this._input.buttons = [
|
||||
clearButton,
|
||||
{
|
||||
iconClass: ThemeIcon.asClassName(Codicon.commentDiscussion),
|
||||
tooltip: localize('openInChat', "Open In Chat View"),
|
||||
}
|
||||
];
|
||||
this._input.title = providerInfo.displayName;
|
||||
|
||||
disposableStore.add(this._input.onDidHide(() => {
|
||||
disposableStore.dispose();
|
||||
this._input = undefined;
|
||||
this._currentTimer = setTimeout(() => {
|
||||
this._currentChat?.dispose();
|
||||
this._currentChat = undefined;
|
||||
}, 1000 * 30); // 30 seconds
|
||||
}));
|
||||
|
||||
//#endregion
|
||||
|
||||
disposableStore.add(this._input.onDidAccept(() => {
|
||||
this._currentChat?.acceptInput();
|
||||
}));
|
||||
|
||||
disposableStore.add(this._input.onDidTriggerButton((e) => {
|
||||
if (e === clearButton) {
|
||||
this._currentChat?.clear();
|
||||
} else {
|
||||
this._currentChat?.openChatView();
|
||||
}
|
||||
}));
|
||||
|
||||
this._currentChat.focus();
|
||||
|
||||
if (query) {
|
||||
this._currentChat.setValue(query);
|
||||
this._currentChat.acceptInput();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class QuickChat extends Disposable {
|
||||
private widget!: ChatWidget;
|
||||
private model: ChatModel | undefined;
|
||||
private _currentQuery: string | undefined;
|
||||
|
||||
private _scopedContextKeyService!: IScopedContextKeyService;
|
||||
get scopedContextKeyService() {
|
||||
return this._scopedContextKeyService;
|
||||
}
|
||||
|
||||
constructor(
|
||||
private readonly _options: IChatViewOptions,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@IContextKeyService private readonly contextKeyService: IContextKeyService,
|
||||
@IChatService private readonly chatService: IChatService,
|
||||
@IChatWidgetService private readonly _chatWidgetService: IChatWidgetService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.model?.dispose();
|
||||
this.model = undefined;
|
||||
this.updateModel();
|
||||
this.widget.inputEditor.setValue('');
|
||||
}
|
||||
|
||||
focus(): void {
|
||||
if (this.widget) {
|
||||
this.widget.focusInput();
|
||||
}
|
||||
}
|
||||
|
||||
render(parent: HTMLElement): void {
|
||||
this._scopedContextKeyService?.dispose();
|
||||
this._scopedContextKeyService = this._register(this.contextKeyService.createScoped(parent));
|
||||
const scopedInstantiationService = this.instantiationService.createChild(new ServiceCollection([IContextKeyService, this.scopedContextKeyService]));
|
||||
this.widget?.dispose();
|
||||
this.widget = this._register(
|
||||
scopedInstantiationService.createInstance(
|
||||
ChatWidget,
|
||||
{ resource: true, renderInputOnTop: true },
|
||||
{
|
||||
listForeground: editorForeground,
|
||||
listBackground: editorBackground,
|
||||
inputEditorBackground: SIDE_BAR_BACKGROUND,
|
||||
resultEditorBackground: SIDE_BAR_BACKGROUND
|
||||
}));
|
||||
this.widget.render(parent);
|
||||
this.widget.setVisible(true);
|
||||
this.widget.setDynamicChatTreeItemLayout(2, 600);
|
||||
this.updateModel();
|
||||
if (this._currentQuery) {
|
||||
this.widget.inputEditor.setSelection({
|
||||
startLineNumber: 1,
|
||||
startColumn: 1,
|
||||
endLineNumber: 1,
|
||||
endColumn: this._currentQuery.length + 1
|
||||
});
|
||||
}
|
||||
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
this._register(this.widget.inputEditor.onDidChangeModelContent((e) => {
|
||||
this._currentQuery = this.widget.inputEditor.getValue();
|
||||
}));
|
||||
}
|
||||
|
||||
async acceptInput(): Promise<void> {
|
||||
if (this.widget.inputEditor.getValue().trim() === '/clear') {
|
||||
this.clear();
|
||||
} else {
|
||||
await this.widget.acceptInput();
|
||||
}
|
||||
}
|
||||
|
||||
async openChatView(): Promise<void> {
|
||||
const widget = await this._chatWidgetService.revealViewForProvider(this._options.providerId);
|
||||
if (!widget?.viewModel || !this.model) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const request of this.model.getRequests()) {
|
||||
if (request.response?.response.value || request.response?.errorDetails) {
|
||||
this.chatService.addCompleteRequest(widget.viewModel.sessionId,
|
||||
request.message as string,
|
||||
{
|
||||
message: request.response.response.value,
|
||||
errorDetails: request.response.errorDetails
|
||||
});
|
||||
} else if (request.message) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const value = this.widget.inputEditor.getValue();
|
||||
if (value) {
|
||||
widget.inputEditor.setValue(value);
|
||||
}
|
||||
widget.focusInput();
|
||||
}
|
||||
|
||||
setValue(value: string): void {
|
||||
this.widget.inputEditor.setValue(value);
|
||||
}
|
||||
|
||||
private updateModel(): void {
|
||||
this.model ??= this.chatService.startSession(this._options.providerId, CancellationToken.None);
|
||||
if (!this.model) {
|
||||
throw new Error('Could not start chat session');
|
||||
}
|
||||
|
||||
this.widget.setModel(this.model, { inputValue: this._currentQuery });
|
||||
}
|
||||
}
|
||||
|
||||
-280
@@ -1,280 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { ThemeIcon } from 'vs/base/common/themables';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IContextKeyService, IScopedContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { IQuickInputService, IQuickPick, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { editorForeground, editorBackground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { AskQuickQuestionAction, IQuickQuestionMode, QuickQuestionMode } from 'vs/workbench/contrib/chat/browser/actions/quickQuestionActions/quickQuestionAction';
|
||||
import { IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat';
|
||||
import { IChatViewOptions } from 'vs/workbench/contrib/chat/browser/chatViewPane';
|
||||
import { ChatWidget } from 'vs/workbench/contrib/chat/browser/chatWidget';
|
||||
import { ChatModel } from 'vs/workbench/contrib/chat/common/chatModel';
|
||||
import { IChatService } from 'vs/workbench/contrib/chat/common/chatService';
|
||||
|
||||
interface IChatQuickQuestionModeOptions {
|
||||
renderInputOnTop: boolean;
|
||||
useDynamicMessageLayout: boolean;
|
||||
}
|
||||
|
||||
class BaseChatQuickQuestionMode implements IQuickQuestionMode {
|
||||
private _currentTimer: any | undefined;
|
||||
private _input: IQuickPick<IQuickPickItem> | undefined;
|
||||
private _currentChat: QuickChat | undefined;
|
||||
|
||||
constructor(
|
||||
private readonly _options: IChatQuickQuestionModeOptions
|
||||
) { }
|
||||
|
||||
run(accessor: ServicesAccessor, query: string): void {
|
||||
const quickInputService = accessor.get(IQuickInputService);
|
||||
const chatService = accessor.get(IChatService);
|
||||
const instantiationService = accessor.get(IInstantiationService);
|
||||
|
||||
// First things first, clear the existing timer that will dispose the session
|
||||
clearTimeout(this._currentTimer);
|
||||
this._currentTimer = undefined;
|
||||
|
||||
// If the input is already shown, hide it. This provides a toggle behavior of the quick pick
|
||||
if (this._input !== undefined) {
|
||||
this._input.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if any providers are available. If not, show nothing
|
||||
// This shouldn't be needed because of the precondition, but just in case
|
||||
const providerInfo = chatService.getProviderInfos()[0];
|
||||
if (!providerInfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
const disposableStore = new DisposableStore();
|
||||
|
||||
//#region Setup quick pick
|
||||
|
||||
this._input = quickInputService.createQuickPick();
|
||||
disposableStore.add(this._input);
|
||||
this._input.hideInput = true;
|
||||
|
||||
|
||||
const containerSession = dom.$('.interactive-session');
|
||||
this._input.widget = containerSession;
|
||||
|
||||
this._currentChat ??= instantiationService.createInstance(QuickChat, {
|
||||
providerId: providerInfo.id,
|
||||
...this._options
|
||||
});
|
||||
// show needs to come before the current chat rendering
|
||||
this._input.show();
|
||||
this._currentChat.render(containerSession);
|
||||
|
||||
const clearButton = {
|
||||
iconClass: ThemeIcon.asClassName(Codicon.clearAll),
|
||||
tooltip: localize('clear', "Clear"),
|
||||
};
|
||||
this._input.buttons = [
|
||||
clearButton,
|
||||
{
|
||||
iconClass: ThemeIcon.asClassName(Codicon.commentDiscussion),
|
||||
tooltip: localize('openInChat', "Open In Chat View"),
|
||||
}
|
||||
];
|
||||
this._input.title = providerInfo.displayName;
|
||||
|
||||
disposableStore.add(this._input.onDidHide(() => {
|
||||
disposableStore.dispose();
|
||||
this._input = undefined;
|
||||
this._currentTimer = setTimeout(() => {
|
||||
this._currentChat?.dispose();
|
||||
this._currentChat = undefined;
|
||||
}, 1000 * 30); // 30 seconds
|
||||
}));
|
||||
|
||||
//#endregion
|
||||
|
||||
disposableStore.add(this._input.onDidAccept(() => {
|
||||
this._currentChat?.acceptInput();
|
||||
}));
|
||||
|
||||
disposableStore.add(this._input.onDidTriggerButton((e) => {
|
||||
if (e === clearButton) {
|
||||
this._currentChat?.clear();
|
||||
} else {
|
||||
this._currentChat?.openChatView();
|
||||
}
|
||||
}));
|
||||
|
||||
this._currentChat.layout();
|
||||
this._currentChat.focus();
|
||||
|
||||
if (query) {
|
||||
this._currentChat.setValue(query);
|
||||
this._currentChat.acceptInput();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class QuickChat extends Disposable {
|
||||
private widget!: ChatWidget;
|
||||
private model: ChatModel | undefined;
|
||||
private _currentQuery: string | undefined;
|
||||
|
||||
private _scopedContextKeyService!: IScopedContextKeyService;
|
||||
get scopedContextKeyService() {
|
||||
return this._scopedContextKeyService;
|
||||
}
|
||||
|
||||
private _currentParentElement?: HTMLElement;
|
||||
|
||||
constructor(
|
||||
private readonly _options: IChatViewOptions & IChatQuickQuestionModeOptions,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@IContextKeyService private readonly contextKeyService: IContextKeyService,
|
||||
@IChatService private readonly chatService: IChatService,
|
||||
@IChatWidgetService private readonly _chatWidgetService: IChatWidgetService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.model?.dispose();
|
||||
this.model = undefined;
|
||||
this.updateModel();
|
||||
this.widget.inputEditor.setValue('');
|
||||
}
|
||||
|
||||
focus(): void {
|
||||
if (this.widget) {
|
||||
this.widget.focusInput();
|
||||
}
|
||||
}
|
||||
|
||||
render(parent: HTMLElement): void {
|
||||
this._currentParentElement = parent;
|
||||
this._scopedContextKeyService?.dispose();
|
||||
this._scopedContextKeyService = this._register(this.contextKeyService.createScoped(parent));
|
||||
const scopedInstantiationService = this.instantiationService.createChild(new ServiceCollection([IContextKeyService, this.scopedContextKeyService]));
|
||||
this.widget?.dispose();
|
||||
this.widget = this._register(
|
||||
scopedInstantiationService.createInstance(
|
||||
ChatWidget,
|
||||
{ resource: true, renderInputOnTop: this._options.renderInputOnTop },
|
||||
{
|
||||
listForeground: editorForeground,
|
||||
listBackground: editorBackground,
|
||||
inputEditorBackground: SIDE_BAR_BACKGROUND,
|
||||
resultEditorBackground: SIDE_BAR_BACKGROUND
|
||||
}));
|
||||
this.widget.render(parent);
|
||||
this.widget.setVisible(true);
|
||||
if (this._options.useDynamicMessageLayout) {
|
||||
this.widget.setDynamicChatTreeItemLayout(2, 600);
|
||||
}
|
||||
this.updateModel();
|
||||
if (this._currentQuery) {
|
||||
this.widget.inputEditor.setSelection({
|
||||
startLineNumber: 1,
|
||||
startColumn: 1,
|
||||
endLineNumber: 1,
|
||||
endColumn: this._currentQuery.length + 1
|
||||
});
|
||||
}
|
||||
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
this._register(dom.addDisposableListener(parent, dom.EventType.RESIZE, () => this.layout()));
|
||||
this._register(this.widget.inputEditor.onDidChangeModelContent((e) => {
|
||||
this._currentQuery = this.widget.inputEditor.getValue();
|
||||
}));
|
||||
}
|
||||
|
||||
async acceptInput(): Promise<void> {
|
||||
if (this.widget.inputEditor.getValue().trim() === '/clear') {
|
||||
this.clear();
|
||||
} else {
|
||||
await this.widget.acceptInput();
|
||||
}
|
||||
this.layout();
|
||||
}
|
||||
|
||||
async openChatView(): Promise<void> {
|
||||
const widget = await this._chatWidgetService.revealViewForProvider(this._options.providerId);
|
||||
if (!widget?.viewModel || !this.model) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const request of this.model.getRequests()) {
|
||||
if (request.response?.response.value || request.response?.errorDetails) {
|
||||
this.chatService.addCompleteRequest(widget.viewModel.sessionId,
|
||||
request.message as string,
|
||||
{
|
||||
message: request.response.response.value,
|
||||
errorDetails: request.response.errorDetails
|
||||
});
|
||||
} else if (request.message) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const value = this.widget.inputEditor.getValue();
|
||||
if (value) {
|
||||
widget.inputEditor.setValue(value);
|
||||
}
|
||||
widget.focusInput();
|
||||
}
|
||||
|
||||
setValue(value: string): void {
|
||||
this.widget.inputEditor.setValue(value);
|
||||
}
|
||||
|
||||
layout(): void {
|
||||
if (!this._options.useDynamicMessageLayout && this._currentParentElement) {
|
||||
this.widget.layout(500, this._currentParentElement.offsetWidth);
|
||||
}
|
||||
}
|
||||
|
||||
private updateModel(): void {
|
||||
this.model ??= this.chatService.startSession(this._options.providerId, CancellationToken.None);
|
||||
if (!this.model) {
|
||||
throw new Error('Could not start chat session');
|
||||
}
|
||||
|
||||
this.widget.setModel(this.model, { inputValue: this._currentQuery });
|
||||
}
|
||||
}
|
||||
|
||||
AskQuickQuestionAction.registerMode(
|
||||
QuickQuestionMode.InputOnTopChat,
|
||||
class InputOnTopChatQuickQuestionMode extends BaseChatQuickQuestionMode {
|
||||
constructor() {
|
||||
super({
|
||||
renderInputOnTop: true,
|
||||
useDynamicMessageLayout: true
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
AskQuickQuestionAction.registerMode(
|
||||
QuickQuestionMode.InputOnBottomChat,
|
||||
class InputOnBottomChatQuickQuestionMode extends BaseChatQuickQuestionMode {
|
||||
constructor() {
|
||||
super({
|
||||
renderInputOnTop: false,
|
||||
useDynamicMessageLayout: false
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
-71
@@ -1,71 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import { Lazy } from 'vs/base/common/lazy';
|
||||
import { localize } from 'vs/nls';
|
||||
import { Action2, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { CHAT_CATEGORY } from 'vs/workbench/contrib/chat/browser/actions/chatActions';
|
||||
import { CONTEXT_PROVIDER_EXISTS } from 'vs/workbench/contrib/chat/common/chatContextKeys';
|
||||
|
||||
export const ASK_QUICK_QUESTION_ACTION_ID = 'chat.action.askQuickQuestion';
|
||||
|
||||
export const enum QuickQuestionMode {
|
||||
SingleQuestion = 'singleQuestion',
|
||||
InputOnTopChat = 'inputOnTopChat',
|
||||
InputOnBottomChat = 'inputOnBottomChat',
|
||||
}
|
||||
|
||||
export interface IQuickQuestionMode {
|
||||
run(accessor: ServicesAccessor, query: string): void;
|
||||
}
|
||||
|
||||
// TODO: This should be registered per chat-provider probably.
|
||||
export class AskQuickQuestionAction extends Action2 {
|
||||
|
||||
private static readonly modeRegistry: Map<QuickQuestionMode, Lazy<IQuickQuestionMode>> = new Map();
|
||||
static registerMode(mode: QuickQuestionMode, modeAction: { new(): IQuickQuestionMode }) {
|
||||
AskQuickQuestionAction.modeRegistry.set(mode, new Lazy(() => new modeAction()));
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: ASK_QUICK_QUESTION_ACTION_ID,
|
||||
title: { value: localize('chat', "Chat"), original: 'Chat' },
|
||||
precondition: CONTEXT_PROVIDER_EXISTS,
|
||||
icon: Codicon.commentDiscussion,
|
||||
f1: false,
|
||||
category: CHAT_CATEGORY,
|
||||
keybinding: {
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyI,
|
||||
linux: {
|
||||
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.KeyI
|
||||
}
|
||||
},
|
||||
menu: {
|
||||
id: MenuId.LayoutControlMenu,
|
||||
group: '0_workbench_toggles',
|
||||
when: ContextKeyExpr.notEquals('config.chat.experimental.defaultMode', 'chatView'),
|
||||
order: 0
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
override run(accessor: ServicesAccessor, query: string): void {
|
||||
const configurationService = accessor.get(IConfigurationService);
|
||||
|
||||
const mode = configurationService.getValue<QuickQuestionMode>('chat.experimental.quickQuestion.mode');
|
||||
const modeAction = AskQuickQuestionAction.modeRegistry.get(mode);
|
||||
if (modeAction) {
|
||||
modeAction.value.run(accessor, query);
|
||||
}
|
||||
}
|
||||
}
|
||||
-261
@@ -1,261 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { Toggle } from 'vs/base/browser/ui/toggle/toggle';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { ServicesAccessor } from 'vs/editor/browser/editorExtensions';
|
||||
import { localize } from 'vs/nls';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IQuickInputService, IQuickPick, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { asCssVariable, editorBackground, foreground, inputActiveOptionBackground, inputActiveOptionBorder, inputActiveOptionForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { ChatListItemRenderer } from 'vs/workbench/contrib/chat/browser/chatListRenderer';
|
||||
import { ChatEditorOptions } from 'vs/workbench/contrib/chat/browser/chatOptions';
|
||||
import { ChatModel } from 'vs/workbench/contrib/chat/common/chatModel';
|
||||
import { IChatReplyFollowup, IChatService } from 'vs/workbench/contrib/chat/common/chatService';
|
||||
import { ChatViewModel } from 'vs/workbench/contrib/chat/common/chatViewModel';
|
||||
import { IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat';
|
||||
import { AskQuickQuestionAction, IQuickQuestionMode, QuickQuestionMode } from 'vs/workbench/contrib/chat/browser/actions/quickQuestionActions/quickQuestionAction';
|
||||
|
||||
class AskSingleQuickQuestionMode implements IQuickQuestionMode {
|
||||
|
||||
private _currentSession: InteractiveQuickPickSession | undefined;
|
||||
private _currentQuery: string | undefined;
|
||||
private _lastAcceptedQuery: string | undefined;
|
||||
private _currentTimer: any | undefined;
|
||||
private _input: IQuickPick<IQuickPickItem> | undefined;
|
||||
|
||||
run(accessor: ServicesAccessor, query: string): void {
|
||||
const quickInputService = accessor.get(IQuickInputService);
|
||||
const chatService = accessor.get(IChatService);
|
||||
const instantiationService = accessor.get(IInstantiationService);
|
||||
|
||||
// First things first, clear the existing timer that will dispose the session
|
||||
clearTimeout(this._currentTimer);
|
||||
this._currentTimer = undefined;
|
||||
|
||||
// If the input is already shown, hide it. This provides a toggle behavior of the quick pick
|
||||
if (this._input !== undefined) {
|
||||
this._input.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if any providers are available. If not, show nothing
|
||||
const providerInfo = chatService.getProviderInfos()[0];
|
||||
if (!providerInfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
const disposableStore = new DisposableStore();
|
||||
|
||||
//#region Setup quick pick
|
||||
|
||||
this._input = quickInputService.createQuickPick();
|
||||
disposableStore.add(this._input);
|
||||
this._input.placeholder = localize('askabot', "Ask {0} a question...", providerInfo.displayName);
|
||||
|
||||
// Setup toggle that will be used to open the chat view
|
||||
const openInChat = new Toggle({
|
||||
title: 'Open In Chat View',
|
||||
icon: Codicon.commentDiscussion,
|
||||
isChecked: false,
|
||||
inputActiveOptionBorder: asCssVariable(inputActiveOptionBorder),
|
||||
inputActiveOptionForeground: asCssVariable(inputActiveOptionForeground),
|
||||
inputActiveOptionBackground: asCssVariable(inputActiveOptionBackground)
|
||||
});
|
||||
disposableStore.add(openInChat);
|
||||
disposableStore.add(openInChat.onChange(async () => {
|
||||
await this._currentSession?.openInChat(this._lastAcceptedQuery ?? this._input!.value);
|
||||
this._currentQuery = undefined;
|
||||
this._lastAcceptedQuery = undefined;
|
||||
this._currentSession?.dispose();
|
||||
this._currentSession = undefined;
|
||||
}));
|
||||
this._input.toggles = [openInChat];
|
||||
|
||||
// Setup the widget that will be used to render the chat response
|
||||
const containerList = dom.$('.interactive-list');
|
||||
const containerSession = dom.$('.interactive-session', undefined, containerList);
|
||||
containerList.style.position = 'relative';
|
||||
this._input.widget = containerSession;
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region quick pick events
|
||||
|
||||
disposableStore.add(this._input.onDidChangeValue((value) => {
|
||||
if (value !== this._currentQuery) {
|
||||
this._currentQuery = value;
|
||||
}
|
||||
}));
|
||||
disposableStore.add(this._input.onDidHide(() => {
|
||||
disposableStore.dispose();
|
||||
this._input = undefined;
|
||||
this._currentTimer = setTimeout(() => {
|
||||
this._currentQuery = undefined;
|
||||
this._lastAcceptedQuery = undefined;
|
||||
this._currentSession?.dispose();
|
||||
this._currentSession = undefined;
|
||||
}, 1000 * 30); // 30 seconds
|
||||
}));
|
||||
disposableStore.add(this._input.onDidAccept(async () => {
|
||||
await this._currentSession?.accept(this._input!.value);
|
||||
this._lastAcceptedQuery = this._input!.value;
|
||||
}));
|
||||
|
||||
//#endregion
|
||||
|
||||
// If we were given a query (via executeCommand), then clear past state
|
||||
if (query) {
|
||||
this._currentSession?.dispose();
|
||||
this._currentSession = undefined;
|
||||
}
|
||||
this._currentSession ??= instantiationService.createInstance(InteractiveQuickPickSession);
|
||||
this._input.show();
|
||||
// This line must come after showing the input so the offsetWidth is correct
|
||||
this._currentSession.createList(containerList, containerList.offsetWidth);
|
||||
|
||||
disposableStore.add(this._currentSession.onDidClickFollowup(async e => {
|
||||
this._input!.focusOnInput();
|
||||
this._input!.value = e.message;
|
||||
await this._currentSession?.accept(e.message);
|
||||
}));
|
||||
|
||||
// If we were given a query (via executeCommand), then accept it
|
||||
if (query) {
|
||||
this._input.value = query;
|
||||
this._input.valueSelection = [0, this._input.value.length];
|
||||
this._currentQuery = query;
|
||||
this._currentSession.accept(query);
|
||||
} else if (this._currentQuery) {
|
||||
this._input.value = this._currentQuery;
|
||||
this._input.valueSelection = [0, this._input.value.length];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class InteractiveQuickPickSession extends Disposable {
|
||||
|
||||
private _model: ChatModel;
|
||||
private _viewModel: ChatViewModel;
|
||||
|
||||
private readonly _onDidClickFollowup: Emitter<IChatReplyFollowup> = this._register(new Emitter<IChatReplyFollowup>());
|
||||
onDidClickFollowup: Event<IChatReplyFollowup> = this._onDidClickFollowup.event;
|
||||
|
||||
private _listDisposable: DisposableStore | undefined;
|
||||
|
||||
constructor(
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||
@IChatService private readonly _chatService: IChatService,
|
||||
@IChatWidgetService private readonly _chatWidgetService: IChatWidgetService
|
||||
) {
|
||||
super();
|
||||
|
||||
const providerInfo = _chatService.getProviderInfos()[0];
|
||||
this._model = this._register(_chatService.startSession(providerInfo.id, CancellationToken.None)!);
|
||||
this._viewModel = this._register(new ChatViewModel(this._model, _instantiationService));
|
||||
}
|
||||
|
||||
createList(container: HTMLElement, offsetWidth: number) {
|
||||
this._listDisposable?.dispose();
|
||||
this._listDisposable = new DisposableStore();
|
||||
const options = this._listDisposable.add(this._instantiationService.createInstance(ChatEditorOptions, 'quickpick-interactive', foreground, editorBackground, editorBackground));
|
||||
const list = this._listDisposable.add(this._instantiationService.createInstance(
|
||||
ChatListItemRenderer,
|
||||
options,
|
||||
{
|
||||
getListLength: () => {
|
||||
return 1;
|
||||
},
|
||||
getSlashCommands() {
|
||||
return [];
|
||||
},
|
||||
}
|
||||
));
|
||||
|
||||
const template = list.renderTemplate(container);
|
||||
list.layout(offsetWidth);
|
||||
this._listDisposable.add(this._viewModel.onDidChange(() => {
|
||||
const items = this._viewModel.getItems();
|
||||
const node = {
|
||||
element: items[items.length - 1],
|
||||
children: [],
|
||||
collapsed: false,
|
||||
collapsible: false,
|
||||
depth: 0,
|
||||
filterData: undefined,
|
||||
visible: true,
|
||||
visibleChildIndex: 0,
|
||||
visibleChildrenCount: 1,
|
||||
};
|
||||
list.disposeElement(node, 0, template);
|
||||
list.renderElement(node, 0, template);
|
||||
}));
|
||||
|
||||
if (this._viewModel.getItems().length) {
|
||||
const items = this._viewModel.getItems();
|
||||
const node = {
|
||||
element: items[items.length - 1],
|
||||
children: [],
|
||||
collapsed: false,
|
||||
collapsible: false,
|
||||
depth: 0,
|
||||
filterData: undefined,
|
||||
visible: true,
|
||||
visibleChildIndex: 0,
|
||||
visibleChildrenCount: 1,
|
||||
};
|
||||
list.disposeElement(node, 0, template);
|
||||
list.renderElement(node, 0, template);
|
||||
}
|
||||
|
||||
this._listDisposable.add(list.onDidClickFollowup(e => {
|
||||
this._onDidClickFollowup.fire(e);
|
||||
}));
|
||||
}
|
||||
|
||||
get providerId() {
|
||||
return this._model.providerId;
|
||||
}
|
||||
|
||||
get sessionId() {
|
||||
return this._model.sessionId;
|
||||
}
|
||||
|
||||
async accept(query: string) {
|
||||
await this._model.waitForInitialization();
|
||||
const requests = this._model.getRequests();
|
||||
const lastRequest = requests[requests.length - 1];
|
||||
if (lastRequest?.message && lastRequest?.message === query) {
|
||||
return;
|
||||
}
|
||||
if (this._model.requestInProgress) {
|
||||
this._chatService.cancelCurrentRequestForSession(this.sessionId);
|
||||
}
|
||||
await this._chatService.sendRequest(this.sessionId, query);
|
||||
}
|
||||
|
||||
async openInChat(value: string) {
|
||||
const widget = await this._chatWidgetService.revealViewForProvider(this.providerId);
|
||||
if (!widget?.viewModel) {
|
||||
return;
|
||||
}
|
||||
|
||||
const requests = this._model.getRequests().reverse();
|
||||
const response = requests.find(r => r.response?.response.value !== undefined);
|
||||
const message = response?.response?.response.value;
|
||||
if (message) {
|
||||
this._chatService.addCompleteRequest(widget.viewModel.sessionId, value, { message });
|
||||
} else if (value) {
|
||||
this._chatService.sendRequest(widget.viewModel.sessionId, value);
|
||||
}
|
||||
widget.focusInput();
|
||||
}
|
||||
}
|
||||
|
||||
AskQuickQuestionAction.registerMode(QuickQuestionMode.SingleQuestion, AskSingleQuickQuestionMode);
|
||||
@@ -42,9 +42,10 @@ import { isResponseVM } from 'vs/workbench/contrib/chat/common/chatViewModel';
|
||||
import { CONTEXT_IN_CHAT_SESSION } from 'vs/workbench/contrib/chat/common/chatContextKeys';
|
||||
import { ChatAccessibilityService } from 'vs/workbench/contrib/chat/browser/chatAccessibilityService';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { QuickQuestionMode } from 'vs/workbench/contrib/chat/browser/actions/quickQuestionActions/quickQuestionAction';
|
||||
import { alertFocusChange } from 'vs/workbench/contrib/accessibility/browser/accessibility.contribution';
|
||||
import { AccessibilityVerbositySettingId } from 'vs/workbench/contrib/accessibility/browser/accessibilityConfiguration';
|
||||
import { ChatWelcomeMessageModel } from 'vs/workbench/contrib/chat/common/chatModel';
|
||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||
|
||||
// Register configuration
|
||||
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);
|
||||
@@ -90,13 +91,6 @@ configurationRegistry.registerConfiguration({
|
||||
],
|
||||
description: nls.localize('interactiveSession.defaultMode', "Controls the default mode of the chat experience."),
|
||||
default: 'chatView'
|
||||
},
|
||||
'chat.experimental.quickQuestion.mode': {
|
||||
type: 'string',
|
||||
tags: ['experimental'],
|
||||
enum: [QuickQuestionMode.SingleQuestion, QuickQuestionMode.InputOnTopChat, QuickQuestionMode.InputOnBottomChat],
|
||||
description: nls.localize('interactiveSession.quickQuestion.mode', "Controls the mode of quick question chat experience."),
|
||||
default: QuickQuestionMode.InputOnTopChat,
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -171,8 +165,19 @@ class ChatAccessibleViewContribution extends Disposable {
|
||||
}
|
||||
|
||||
widget.focus(focusedItem);
|
||||
|
||||
const responseContent = isResponseVM(focusedItem) ? focusedItem.response.value : undefined;
|
||||
const isWelcome = focusedItem instanceof ChatWelcomeMessageModel;
|
||||
let responseContent = isResponseVM(focusedItem) ? focusedItem.response.value : undefined;
|
||||
if (isWelcome) {
|
||||
const welcomeReplyContents = [];
|
||||
for (const content of focusedItem.content) {
|
||||
if (Array.isArray(content)) {
|
||||
welcomeReplyContents.push(...content.map(m => m.message));
|
||||
} else {
|
||||
welcomeReplyContents.push((content as IMarkdownString).value);
|
||||
}
|
||||
}
|
||||
responseContent = welcomeReplyContents.join('\n');
|
||||
}
|
||||
if (!responseContent) {
|
||||
return false;
|
||||
}
|
||||
@@ -182,7 +187,7 @@ class ChatAccessibleViewContribution extends Disposable {
|
||||
|
||||
accessibleViewService.show({
|
||||
verbositySettingKey: AccessibilityVerbositySettingId.Chat,
|
||||
provideContent(): string { return responseContent; },
|
||||
provideContent(): string { return responseContent!; },
|
||||
onClose() {
|
||||
verifiedWidget.reveal(focusedItem);
|
||||
if (chatInputFocused) {
|
||||
|
||||
@@ -30,7 +30,7 @@ export class ChatAccessibilityService extends Disposable implements IChatAccessi
|
||||
}, CHAT_RESPONSE_PENDING_ALLOWANCE_MS));
|
||||
}
|
||||
acceptRequest(): void {
|
||||
this._audioCueService.playAudioCue(AudioCue.chatRequestSent, true);
|
||||
this._audioCueService.playAudioCue(AudioCue.chatRequestSent, { allowManyInParallel: true });
|
||||
this._runOnceScheduler.schedule();
|
||||
}
|
||||
acceptResponse(response?: IChatResponseViewModel | string): void {
|
||||
@@ -42,7 +42,7 @@ export class ChatAccessibilityService extends Disposable implements IChatAccessi
|
||||
if (this._lastResponse === responseContent) {
|
||||
return;
|
||||
}
|
||||
this._audioCueService.playAudioCue(AudioCue.chatResponseReceived, true);
|
||||
this._audioCueService.playAudioCue(AudioCue.chatResponseReceived, { allowManyInParallel: true });
|
||||
this._hasReceivedRequest = false;
|
||||
if (!response) {
|
||||
return;
|
||||
|
||||
@@ -555,6 +555,17 @@ export class ChatAccessibilityProvider implements IListAccessibilityProvider<Cha
|
||||
private _getLabelWithCodeBlockCount(element: IChatResponseViewModel): string {
|
||||
const accessibleViewHint = this._accessibleViewService.getOpenAriaHint(AccessibilityVerbositySettingId.Chat);
|
||||
let label: string = '';
|
||||
let commandFollowUpInfo;
|
||||
const commandFollowupLength = element.commandFollowups?.length ?? 0;
|
||||
switch (commandFollowupLength) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
commandFollowUpInfo = localize('commandFollowUpInfo', "Command: {0}", element.commandFollowups![0].title);
|
||||
break;
|
||||
default:
|
||||
commandFollowUpInfo = localize('commandFollowUpInfoMany', "Commands: {0}", element.commandFollowups!.map(followup => followup.title).join(', '));
|
||||
}
|
||||
const codeBlockCount = marked.lexer(element.response.value).filter(token => token.type === 'code')?.length ?? 0;
|
||||
switch (codeBlockCount) {
|
||||
case 0:
|
||||
@@ -567,7 +578,7 @@ export class ChatAccessibilityProvider implements IListAccessibilityProvider<Cha
|
||||
label = accessibleViewHint ? localize('multiCodeBlockHint', "{0} code blocks: {1}", codeBlockCount, element.response.value, accessibleViewHint) : localize('multiCodeBlock', "{0} code blocks", codeBlockCount, element.response.value);
|
||||
break;
|
||||
}
|
||||
return label;
|
||||
return commandFollowUpInfo ? commandFollowUpInfo + ', ' + label : label;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ import { isFirefox } from 'vs/base/browser/browser';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { ISemanticSimilarityService } from 'vs/workbench/services/semanticSimilarity/common/semanticSimilarityService';
|
||||
import { IChatService } from 'vs/workbench/contrib/chat/common/chatService';
|
||||
import { ASK_QUICK_QUESTION_ACTION_ID } from 'vs/workbench/contrib/chat/browser/actions/quickQuestionActions/quickQuestionAction';
|
||||
import { ASK_QUICK_QUESTION_ACTION_ID } from 'vs/workbench/contrib/chat/browser/actions/chatQuickInputActions';
|
||||
|
||||
export class CommandsQuickAccessProvider extends AbstractEditorCommandsQuickAccessProvider {
|
||||
|
||||
|
||||
@@ -662,13 +662,13 @@ async function playAudioCueForChange(change: IChange, audioCueService: IAudioCue
|
||||
const changeType = getChangeType(change);
|
||||
switch (changeType) {
|
||||
case ChangeType.Add:
|
||||
audioCueService.playAudioCue(AudioCue.diffLineInserted, true);
|
||||
audioCueService.playAudioCue(AudioCue.diffLineInserted, { allowManyInParallel: true, source: 'dirtyDiffDecoration' });
|
||||
break;
|
||||
case ChangeType.Delete:
|
||||
audioCueService.playAudioCue(AudioCue.diffLineDeleted, true);
|
||||
audioCueService.playAudioCue(AudioCue.diffLineDeleted, { allowManyInParallel: true, source: 'dirtyDiffDecoration' });
|
||||
break;
|
||||
case ChangeType.Modify:
|
||||
audioCueService.playAudioCue(AudioCue.diffLineModified, true);
|
||||
audioCueService.playAudioCue(AudioCue.diffLineModified, { allowManyInParallel: true, source: 'dirtyDiffDecoration' });
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -78,7 +78,7 @@ export class TerminalAccessibilityHelpContribution extends Disposable {
|
||||
return;
|
||||
}
|
||||
accessibleViewService.show(instantiationService.createInstance(TerminalAccessibleContentProvider, instance, terminal));
|
||||
}, TerminalContextKeys.focus));
|
||||
}, ContextKeyExpr.or(TerminalContextKeys.focus, TerminalContextKeys.accessibleBufferFocus)));
|
||||
}
|
||||
}
|
||||
registerTerminalContribution(TerminalAccessibilityHelpContribution.ID, TerminalAccessibilityHelpContribution);
|
||||
|
||||
+11
-2
@@ -7,6 +7,8 @@ import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { format } from 'vs/base/common/strings';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { ShellIntegrationStatus, WindowsShellType } from 'vs/platform/terminal/common/terminal';
|
||||
@@ -14,6 +16,7 @@ import { AccessibilityVerbositySettingId } from 'vs/workbench/contrib/accessibil
|
||||
import { AccessibleViewType, IAccessibleContentProvider, IAccessibleViewOptions } from 'vs/workbench/contrib/accessibility/browser/accessibleView';
|
||||
import { ITerminalInstance, IXtermTerminal } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||
import { TerminalCommandId } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { TerminalContextKeys } from 'vs/workbench/contrib/terminal/common/terminalContextKey';
|
||||
import type { Terminal } from 'xterm';
|
||||
|
||||
export const enum ClassName {
|
||||
@@ -27,7 +30,11 @@ export class TerminalAccessibleContentProvider extends Disposable implements IAc
|
||||
private readonly _hasShellIntegration: boolean = false;
|
||||
|
||||
onClose() {
|
||||
this._instance.focus();
|
||||
if (this._contextKeyService.getContextKeyValue<boolean>(TerminalContextKeys.accessibleBufferFocus.key) === true) {
|
||||
this._commandService.executeCommand(TerminalCommandId.FocusAccessibleBuffer);
|
||||
} else {
|
||||
this._instance.focus();
|
||||
}
|
||||
this.dispose();
|
||||
}
|
||||
options: IAccessibleViewOptions = {
|
||||
@@ -42,7 +49,9 @@ export class TerminalAccessibleContentProvider extends Disposable implements IAc
|
||||
_xterm: Pick<IXtermTerminal, 'getFont' | 'shellIntegration'> & { raw: Terminal },
|
||||
@IInstantiationService _instantiationService: IInstantiationService,
|
||||
@IKeybindingService private readonly _keybindingService: IKeybindingService,
|
||||
@IAccessibilityService private readonly _accessibilityService: IAccessibilityService
|
||||
@IAccessibilityService private readonly _accessibilityService: IAccessibilityService,
|
||||
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
|
||||
@ICommandService private readonly _commandService: ICommandService
|
||||
) {
|
||||
super();
|
||||
this._hasShellIntegration = _xterm.shellIntegration.status === ShellIntegrationStatus.VSCode;
|
||||
|
||||
+1
-1
@@ -147,7 +147,7 @@ export class AccessibleBufferWidget extends TerminalAccessibleWidget {
|
||||
return;
|
||||
}
|
||||
if (activeItem.exitCode) {
|
||||
this._audioCueService.playAudioCue(AudioCue.error, true);
|
||||
this._audioCueService.playAudioCue(AudioCue.error, { allowManyInParallel: true, source: 'accessibleBufferWidget' });
|
||||
}
|
||||
this.editorWidget.revealLine(activeItem.lineNumber, 0);
|
||||
});
|
||||
|
||||
@@ -489,9 +489,11 @@ class ResultSummaryView extends Disposable {
|
||||
const { results } = this.resultService;
|
||||
const { count, root, status, duration, rerun } = this.elements;
|
||||
if (!results.length) {
|
||||
this.container.removeChild(root);
|
||||
this.container.innerText = localize('noResults', 'No test results yet.');
|
||||
this.elementsWereAttached = false;
|
||||
if (this.elementsWereAttached) {
|
||||
this.container.removeChild(root);
|
||||
this.elementsWereAttached = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -255,7 +255,9 @@ export class EditorResolverService extends Disposable implements IEditorResolver
|
||||
|
||||
getAssociationsForResource(resource: URI): EditorAssociations {
|
||||
const associations = this.getAllUserAssociations();
|
||||
const matchingAssociations = associations.filter(association => association.filenamePattern && globMatchesResource(association.filenamePattern, resource));
|
||||
let matchingAssociations = associations.filter(association => association.filenamePattern && globMatchesResource(association.filenamePattern, resource));
|
||||
// Sort matching associations based on glob length as a longer glob will be more specific
|
||||
matchingAssociations = matchingAssociations.sort((a, b) => (b.filenamePattern?.length ?? 0) - (a.filenamePattern?.length ?? 0));
|
||||
const allEditors: RegisteredEditors = this._registeredEditors;
|
||||
// Ensure that the settings are valid editors
|
||||
return matchingAssociations.filter(association => allEditors.find(c => c.editorInfo.id === association.viewType));
|
||||
|
||||
@@ -43,7 +43,7 @@ export class NativeSecretStorageService extends BaseSecretStorageService {
|
||||
this._sequencer.queue(key, async () => {
|
||||
await this.resolvedStorageService;
|
||||
|
||||
if (this.type !== 'persisted') {
|
||||
if (this.type !== 'persisted' && !this._environmentService.disableKeytar) {
|
||||
this._logService.trace('[NativeSecretStorageService] Notifying user that secrets are not being stored on disk.');
|
||||
await this.notifyOfNoEncryptionOnce();
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -15980,7 +15980,7 @@ declare module 'vscode' {
|
||||
* @param id The unique identifier of the provider.
|
||||
* @param label The human-readable name of the provider.
|
||||
* @param provider The authentication provider provider.
|
||||
* @params options Additional options for the provider.
|
||||
* @param options Additional options for the provider.
|
||||
* @return A {@link Disposable} that unregisters this provider when being disposed.
|
||||
*/
|
||||
export function registerAuthenticationProvider(id: string, label: string, provider: AuthenticationProvider, options?: AuthenticationProviderOptions): Disposable;
|
||||
|
||||
Reference in New Issue
Block a user