Merge remote-tracking branch 'origin/main' into alexd/yummy-bug

This commit is contained in:
Alex Dima
2023-09-12 16:31:25 +02:00
535 changed files with 12675 additions and 8264 deletions
+1 -1
View File
@@ -7,7 +7,7 @@
{
"kind": 2,
"language": "github-issues",
"value": "$repo=repo:microsoft/vscode\n$milestone=milestone:\"August 2023\""
"value": "$repo=repo:microsoft/vscode\n$milestone=milestone:\"September 2023\""
},
{
"kind": 1,
+1 -1
View File
@@ -7,7 +7,7 @@
{
"kind": 2,
"language": "github-issues",
"value": "// list of repos we work in\n$repos=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-unpkg repo:microsoft/vscode-references-view repo:microsoft/vscode-anycode repo:microsoft/vscode-hexeditor repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-livepreview repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remote-repositories-github repo:microsoft/monaco-editor repo:microsoft/vscode-vsce repo:microsoft/vscode-dev-chrome-launcher repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-l10n repo:microsoft/vscode-remote-tunnels repo:microsoft/vscode-markdown-tm-grammar repo:microsoft/vscode-markdown-languageservice repo:microsoft/vscode-copilot repo:microsoft/vscode-copilot-release\n\n// current milestone name\n$milestone=milestone:\"August 2023\""
"value": "// list of repos we work in\n$repos=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-unpkg repo:microsoft/vscode-references-view repo:microsoft/vscode-anycode repo:microsoft/vscode-hexeditor repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-livepreview repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remote-repositories-github repo:microsoft/monaco-editor repo:microsoft/vscode-vsce repo:microsoft/vscode-dev-chrome-launcher repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-l10n repo:microsoft/vscode-remote-tunnels repo:microsoft/vscode-markdown-tm-grammar repo:microsoft/vscode-markdown-languageservice repo:microsoft/vscode-copilot repo:microsoft/vscode-copilot-release\n\n// current milestone name\n$milestone=milestone:\"September 2023\""
},
{
"kind": 1,
@@ -34,7 +34,7 @@ steps:
displayName: Download openssl prebuilt
inputs:
command: custom
customCommand: pack @vscode-internal/openssl-prebuilt@0.0.8
customCommand: pack @vscode-internal/openssl-prebuilt@0.0.10
customRegistry: useFeed
customFeed: "Monaco/openssl-prebuilt"
workingDir: $(Build.ArtifactStagingDirectory)
@@ -42,7 +42,7 @@ steps:
- script: |
set -e
mkdir $(Build.ArtifactStagingDirectory)/openssl
tar -xvzf $(Build.ArtifactStagingDirectory)/vscode-internal-openssl-prebuilt-0.0.8.tgz --strip-components=1 --directory=$(Build.ArtifactStagingDirectory)/openssl
tar -xvzf $(Build.ArtifactStagingDirectory)/vscode-internal-openssl-prebuilt-0.0.10.tgz --strip-components=1 --directory=$(Build.ArtifactStagingDirectory)/openssl
displayName: Extract openssl prebuilt
# inspired by: https://github.com/emk/rust-musl-builder/blob/main/Dockerfile
@@ -23,7 +23,7 @@ steps:
displayName: Download openssl prebuilt
inputs:
command: custom
customCommand: pack @vscode-internal/openssl-prebuilt@0.0.8
customCommand: pack @vscode-internal/openssl-prebuilt@0.0.10
customRegistry: useFeed
customFeed: "Monaco/openssl-prebuilt"
workingDir: $(Build.ArtifactStagingDirectory)
@@ -31,7 +31,7 @@ steps:
- script: |
set -e
mkdir $(Build.ArtifactStagingDirectory)/openssl
tar -xvzf $(Build.ArtifactStagingDirectory)/vscode-internal-openssl-prebuilt-0.0.8.tgz --strip-components=1 --directory=$(Build.ArtifactStagingDirectory)/openssl
tar -xvzf $(Build.ArtifactStagingDirectory)/vscode-internal-openssl-prebuilt-0.0.10.tgz --strip-components=1 --directory=$(Build.ArtifactStagingDirectory)/openssl
displayName: Extract openssl prebuilt
- template: ../cli/install-rust-posix.yml
@@ -26,7 +26,7 @@ steps:
displayName: Download openssl prebuilt
inputs:
command: custom
customCommand: pack @vscode-internal/openssl-prebuilt@0.0.8
customCommand: pack @vscode-internal/openssl-prebuilt@0.0.10
customRegistry: useFeed
customFeed: "Monaco/openssl-prebuilt"
workingDir: $(Build.ArtifactStagingDirectory)
@@ -34,7 +34,7 @@ steps:
- script: |
set -e
mkdir $(Build.ArtifactStagingDirectory)/openssl
tar -xvzf $(Build.ArtifactStagingDirectory)/vscode-internal-openssl-prebuilt-0.0.8.tgz --strip-components=1 --directory=$(Build.ArtifactStagingDirectory)/openssl
tar -xvzf $(Build.ArtifactStagingDirectory)/vscode-internal-openssl-prebuilt-0.0.10.tgz --strip-components=1 --directory=$(Build.ArtifactStagingDirectory)/openssl
displayName: Extract openssl prebuilt
- ${{ if eq(parameters.VSCODE_BUILD_LINUX_ARMHF, true) }}:
@@ -26,14 +26,14 @@ steps:
displayName: Download openssl prebuilt
inputs:
command: custom
customCommand: pack @vscode-internal/openssl-prebuilt@0.0.8
customCommand: pack @vscode-internal/openssl-prebuilt@0.0.10
customRegistry: useFeed
customFeed: "Monaco/openssl-prebuilt"
workingDir: $(Build.ArtifactStagingDirectory)
- powershell: |
mkdir $(Build.ArtifactStagingDirectory)/openssl
tar -xvzf $(Build.ArtifactStagingDirectory)/vscode-internal-openssl-prebuilt-0.0.8.tgz --strip-components=1 --directory=$(Build.ArtifactStagingDirectory)/openssl
tar -xvzf $(Build.ArtifactStagingDirectory)/vscode-internal-openssl-prebuilt-0.0.10.tgz --strip-components=1 --directory=$(Build.ArtifactStagingDirectory)/openssl
displayName: Extract openssl prebuilt
- template: ../cli/install-rust-win32.yml
@@ -54,8 +54,8 @@ steps:
VSCODE_CLI_ARTIFACT: unsigned_vscode_cli_win32_x64_cli
VSCODE_CHECK_ONLY: ${{ parameters.VSCODE_CHECK_ONLY }}
VSCODE_CLI_ENV:
OPENSSL_LIB_DIR: $(Build.ArtifactStagingDirectory)/openssl/x64-windows-static-md/lib
OPENSSL_INCLUDE_DIR: $(Build.ArtifactStagingDirectory)/openssl/x64-windows-static-md/include
OPENSSL_LIB_DIR: $(Build.ArtifactStagingDirectory)/openssl/x64-windows-static/lib
OPENSSL_INCLUDE_DIR: $(Build.ArtifactStagingDirectory)/openssl/x64-windows-static/include
RUSTFLAGS: "-C target-feature=+crt-static"
- ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}:
@@ -66,8 +66,8 @@ steps:
VSCODE_CLI_ARTIFACT: unsigned_vscode_cli_win32_arm64_cli
VSCODE_CHECK_ONLY: ${{ parameters.VSCODE_CHECK_ONLY }}
VSCODE_CLI_ENV:
OPENSSL_LIB_DIR: $(Build.ArtifactStagingDirectory)/openssl/arm64-windows-static-md/lib
OPENSSL_INCLUDE_DIR: $(Build.ArtifactStagingDirectory)/openssl/arm64-windows-static-md/include
OPENSSL_LIB_DIR: $(Build.ArtifactStagingDirectory)/openssl/arm64-windows-static/lib
OPENSSL_INCLUDE_DIR: $(Build.ArtifactStagingDirectory)/openssl/arm64-windows-static/include
RUSTFLAGS: "-C target-feature=+crt-static"
- ${{ if eq(parameters.VSCODE_BUILD_WIN32_32BIT, true) }}:
@@ -78,6 +78,6 @@ steps:
VSCODE_CLI_ARTIFACT: unsigned_vscode_cli_win32_ia32_cli
VSCODE_CHECK_ONLY: ${{ parameters.VSCODE_CHECK_ONLY }}
VSCODE_CLI_ENV:
OPENSSL_LIB_DIR: $(Build.ArtifactStagingDirectory)/openssl/x86-windows-static-md/lib
OPENSSL_INCLUDE_DIR: $(Build.ArtifactStagingDirectory)/openssl/x86-windows-static-md/include
OPENSSL_LIB_DIR: $(Build.ArtifactStagingDirectory)/openssl/x86-windows-static/lib
OPENSSL_INCLUDE_DIR: $(Build.ArtifactStagingDirectory)/openssl/x86-windows-static/include
RUSTFLAGS: "-C target-feature=+crt-static"
@@ -734,7 +734,7 @@
"--tab-sizing-current-width",
"--tab-sizing-fixed-min-width",
"--tab-sizing-fixed-max-width",
"--editor-group-title-height",
"--editor-group-tab-height",
"--testMessageDecorationFontFamily",
"--testMessageDecorationFontSize",
"--title-border-bottom-color",
+7 -1
View File
@@ -278,8 +278,8 @@ fn make_socket_rpc(
port_forwarding: Option<PortForwarding>,
requires_auth: AuthRequired,
platform: Platform,
http_requests: HttpRequestsMap,
) -> RpcDispatcher<MsgPackSerializer, HandlerContext> {
let http_requests = Arc::new(std::sync::Mutex::new(HashMap::new()));
let server_bridges = ServerMultiplexer::new();
let mut rpc = RpcBuilder::new(MsgPackSerializer {}).methods(HandlerContext {
did_update: Arc::new(AtomicBool::new(false)),
@@ -377,7 +377,10 @@ fn make_socket_rpc(
);
rpc.register_sync("httpheaders", |p: HttpHeadersParams, c| {
if let Some(req) = c.http_requests.lock().unwrap().get(&p.req_id) {
trace!(c.log, "got {} response for req {}", p.status_code, p.req_id);
req.initial_response(p.status_code, p.headers);
} else {
warning!(c.log, "got response for unknown req {}", p.req_id);
}
Ok(EmptyObject {})
});
@@ -388,6 +391,7 @@ fn make_socket_rpc(
req.body(p.segment);
}
if p.complete {
trace!(c.log, "delegated request {} completed", p.req_id);
reqs.remove(&p.req_id);
}
}
@@ -441,6 +445,7 @@ async fn process_socket(
port_forwarding,
requires_auth,
platform,
http_requests.clone(),
);
{
@@ -497,6 +502,7 @@ async fn process_socket(
}),
})
.unwrap();
http_requests.lock().unwrap().insert(id, r);
tx_counter += serialized.len();
+6
View File
@@ -16,6 +16,7 @@ use serde::{Deserialize, Serialize};
#[allow(non_camel_case_types)]
pub enum ClientRequestMethod<'a> {
servermsg(RefServerMessageParams<'a>),
serverclose(ServerClosedParams),
serverlog(ServerLog<'a>),
makehttpreq(HttpRequestParams<'a>),
version(VersionResponse),
@@ -89,6 +90,11 @@ pub struct ServerMessageParams {
pub body: Vec<u8>,
}
#[derive(Serialize, Debug)]
pub struct ServerClosedParams {
pub i: u16,
}
#[derive(Serialize, Debug)]
pub struct RefServerMessageParams<'a> {
pub i: u16,
+1
View File
@@ -32,6 +32,7 @@ impl ServerBridge {
match read.read(&mut read_buf).await {
Err(_) => return,
Ok(0) => {
let _ = target.server_closed().await;
return; // EOF
}
Ok(s) => {
+24 -6
View File
@@ -9,7 +9,7 @@ use tokio::sync::mpsc;
use crate::msgpack_rpc::MsgPackCaller;
use super::{
protocol::{ClientRequestMethod, RefServerMessageParams, ToClientRequest},
protocol::{ClientRequestMethod, RefServerMessageParams, ServerClosedParams, ToClientRequest},
server_multiplexer::ServerMultiplexer,
};
@@ -81,25 +81,43 @@ impl ServerMessageSink {
}
}
pub async fn server_closed(&mut self) -> Result<(), mpsc::error::SendError<SocketSignal>> {
self.server_message_or_closed(None).await
}
pub async fn server_message(
&mut self,
body: &[u8],
) -> Result<(), mpsc::error::SendError<SocketSignal>> {
let id = self.id;
self.server_message_or_closed(Some(body)).await
}
async fn server_message_or_closed(
&mut self,
body: Option<&[u8]>,
) -> Result<(), mpsc::error::SendError<SocketSignal>> {
let i = self.id;
let mut tx = self.tx.take().unwrap();
let body = self.get_server_msg_content(body);
let msg = RefServerMessageParams { i: id, body };
let msg = body
.map(|b| self.get_server_msg_content(b))
.map(|body| RefServerMessageParams { i, body });
let r = match &mut tx {
ServerMessageDestination::Channel(tx) => {
tx.send(SocketSignal::from_message(&ToClientRequest {
id: None,
params: ClientRequestMethod::servermsg(msg),
params: match msg {
Some(msg) => ClientRequestMethod::servermsg(msg),
None => ClientRequestMethod::serverclose(ServerClosedParams { i }),
},
}))
.await
}
ServerMessageDestination::Rpc(caller) => {
caller.notify("servermsg", msg);
match msg {
Some(msg) => caller.notify("servermsg", msg),
None => caller.notify("serverclose", ServerClosedParams { i }),
};
Ok(())
}
};
@@ -23,7 +23,7 @@
"watch": "gulp watch-extension:configuration-editing"
},
"dependencies": {
"jsonc-parser": "^2.2.1",
"jsonc-parser": "^3.2.0",
"@octokit/rest": "19.0.4",
"tunnel": "^0.0.6"
},
+50 -40
View File
@@ -3,41 +3,39 @@
"@octokit/auth-token@^3.0.0":
version "3.0.2"
resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-3.0.2.tgz#a0fc8de149fd15876e1ac78f6525c1c5ab48435f"
integrity sha512-pq7CwIMV1kmzkFTimdwjAINCXKTajZErLB4wMLYapR2nuB/Jpr66+05wOTZMSCBXP6n4DdDWT2W19Bm17vU69Q==
dependencies:
"@octokit/types" "^8.0.0"
version "3.0.4"
resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-3.0.4.tgz#70e941ba742bdd2b49bdb7393e821dea8520a3db"
integrity sha512-TWFX7cZF2LXoCvdmJWY7XVPi74aSY0+FfBZNSXEXFkMpjcqsQwDSYVv5FhRFaI0V1ECnwbz4j59T/G+rXNWaIQ==
"@octokit/core@^4.0.0":
version "4.1.0"
resolved "https://registry.yarnpkg.com/@octokit/core/-/core-4.1.0.tgz#b6b03a478f1716de92b3f4ec4fd64d05ba5a9251"
integrity sha512-Czz/59VefU+kKDy+ZfDwtOIYIkFjExOKf+HA92aiTZJ6EfWpFzYQWw0l54ji8bVmyhc+mGaLUbSUmXazG7z5OQ==
version "4.2.4"
resolved "https://registry.yarnpkg.com/@octokit/core/-/core-4.2.4.tgz#d8769ec2b43ff37cc3ea89ec4681a20ba58ef907"
integrity sha512-rYKilwgzQ7/imScn3M9/pFfUf4I1AZEH3KhyJmtPdE2zfaXAn2mFfUy4FbKewzc2We5y/LlKLj36fWJLKC2SIQ==
dependencies:
"@octokit/auth-token" "^3.0.0"
"@octokit/graphql" "^5.0.0"
"@octokit/request" "^6.0.0"
"@octokit/request-error" "^3.0.0"
"@octokit/types" "^8.0.0"
"@octokit/types" "^9.0.0"
before-after-hook "^2.2.0"
universal-user-agent "^6.0.0"
"@octokit/endpoint@^7.0.0":
version "7.0.3"
resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-7.0.3.tgz#0b96035673a9e3bedf8bab8f7335de424a2147ed"
integrity sha512-57gRlb28bwTsdNXq+O3JTQ7ERmBTuik9+LelgcLIVfYwf235VHbN9QNo4kXExtp/h8T423cR5iJThKtFYxC7Lw==
version "7.0.6"
resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-7.0.6.tgz#791f65d3937555141fb6c08f91d618a7d645f1e2"
integrity sha512-5L4fseVRUsDFGR00tMWD/Trdeeihn999rTMGRMC1G/Ldi1uWlWJzI98H4Iak5DB/RVvQuyMYKqSK/R6mbSOQyg==
dependencies:
"@octokit/types" "^8.0.0"
"@octokit/types" "^9.0.0"
is-plain-object "^5.0.0"
universal-user-agent "^6.0.0"
"@octokit/graphql@^5.0.0":
version "5.0.4"
resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-5.0.4.tgz#519dd5c05123868276f3ae4e50ad565ed7dff8c8"
integrity sha512-amO1M5QUQgYQo09aStR/XO7KAl13xpigcy/kI8/N1PnZYSS69fgte+xA4+c2DISKqUZfsh0wwjc2FaCt99L41A==
version "5.0.6"
resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-5.0.6.tgz#9eac411ac4353ccc5d3fca7d76736e6888c5d248"
integrity sha512-Fxyxdy/JH0MnIB5h+UQ3yCoh1FG4kWXfFKkpWqjZHw/p+Kc8Y44Hu/kCgNBT6nU1shNumEchmW/sUO1JuQnPcw==
dependencies:
"@octokit/request" "^6.0.0"
"@octokit/types" "^8.0.0"
"@octokit/types" "^9.0.0"
universal-user-agent "^6.0.0"
"@octokit/openapi-types@^13.11.0":
@@ -50,6 +48,11 @@
resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-14.0.0.tgz#949c5019028c93f189abbc2fb42f333290f7134a"
integrity sha512-HNWisMYlR8VCnNurDU6os2ikx0s0VyEjDYHNS/h4cgb8DeOxQ0n72HyinUtdDVxJhFy3FWLGl0DJhfEWk3P5Iw==
"@octokit/openapi-types@^18.0.0":
version "18.0.0"
resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-18.0.0.tgz#f43d765b3c7533fd6fb88f3f25df079c24fccf69"
integrity sha512-V8GImKs3TeQRxRtXFpG2wl19V7444NIOTDF24AWuIbmNaNYOQMWRbjcGDXV5B+0n887fgDcuMNOmlul+k+oJtw==
"@octokit/plugin-paginate-rest@^4.0.0":
version "4.3.1"
resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-4.3.1.tgz#553e653ee0318605acd23bf3a799c8bfafdedae3"
@@ -63,30 +66,30 @@
integrity sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==
"@octokit/plugin-rest-endpoint-methods@^6.0.0":
version "6.7.0"
resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-6.7.0.tgz#2f6f17f25b6babbc8b41d2bb0a95a8839672ce7c"
integrity sha512-orxQ0fAHA7IpYhG2flD2AygztPlGYNAdlzYz8yrD8NDgelPfOYoRPROfEyIe035PlxvbYrgkfUZIhSBKju/Cvw==
version "6.8.1"
resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-6.8.1.tgz#97391fda88949eb15f68dc291957ccbe1d3e8ad1"
integrity sha512-QrlaTm8Lyc/TbU7BL/8bO49vp+RZ6W3McxxmmQTgYxf2sWkO8ZKuj4dLhPNJD6VCUW1hetCmeIM0m6FTVpDiEg==
dependencies:
"@octokit/types" "^8.0.0"
"@octokit/types" "^8.1.1"
deprecation "^2.3.1"
"@octokit/request-error@^3.0.0":
version "3.0.2"
resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-3.0.2.tgz#f74c0f163d19463b87528efe877216c41d6deb0a"
integrity sha512-WMNOFYrSaX8zXWoJg9u/pKgWPo94JXilMLb2VManNOby9EZxrQaBe/QSC4a1TzpAlpxofg2X/jMnCyZgL6y7eg==
version "3.0.3"
resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-3.0.3.tgz#ef3dd08b8e964e53e55d471acfe00baa892b9c69"
integrity sha512-crqw3V5Iy2uOU5Np+8M/YexTlT8zxCfI+qu+LxUB7SZpje4Qmx3mub5DfEKSO8Ylyk0aogi6TYdf6kxzh2BguQ==
dependencies:
"@octokit/types" "^8.0.0"
"@octokit/types" "^9.0.0"
deprecation "^2.0.0"
once "^1.4.0"
"@octokit/request@^6.0.0":
version "6.2.2"
resolved "https://registry.yarnpkg.com/@octokit/request/-/request-6.2.2.tgz#a2ba5ac22bddd5dcb3f539b618faa05115c5a255"
integrity sha512-6VDqgj0HMc2FUX2awIs+sM6OwLgwHvAi4KCK3mT2H2IKRt6oH9d0fej5LluF5mck1lRR/rFWN0YIDSYXYSylbw==
version "6.2.8"
resolved "https://registry.yarnpkg.com/@octokit/request/-/request-6.2.8.tgz#aaf480b32ab2b210e9dadd8271d187c93171d8eb"
integrity sha512-ow4+pkVQ+6XVVsekSYBzJC0VTVvh/FCTUUgTsboGq+DTeWdyIFV8WSCdo0RIxk6wSkBTHqIK1mYuY7nOBXOchw==
dependencies:
"@octokit/endpoint" "^7.0.0"
"@octokit/request-error" "^3.0.0"
"@octokit/types" "^8.0.0"
"@octokit/types" "^9.0.0"
is-plain-object "^5.0.0"
node-fetch "^2.6.7"
universal-user-agent "^6.0.0"
@@ -108,13 +111,20 @@
dependencies:
"@octokit/openapi-types" "^13.11.0"
"@octokit/types@^8.0.0":
version "8.1.1"
resolved "https://registry.yarnpkg.com/@octokit/types/-/types-8.1.1.tgz#92e304e0f00d563667dfdbe0ae6b52e70d5149bb"
integrity sha512-7tjk+6DyhYAmei8FOEwPfGKc0VE1x56CKPJ+eE44zhDbOyMT+9yan8apfQFxo8oEFsy+0O7PiBtH8w0Yo0Y9Kw==
"@octokit/types@^8.1.1":
version "8.2.1"
resolved "https://registry.yarnpkg.com/@octokit/types/-/types-8.2.1.tgz#a6de091ae68b5541f8d4fcf9a12e32836d4648aa"
integrity sha512-8oWMUji8be66q2B9PmEIUyQm00VPDPun07umUWSaCwxmeaquFBro4Hcc3ruVoDo3zkQyZBlRvhIMEYS3pBhanw==
dependencies:
"@octokit/openapi-types" "^14.0.0"
"@octokit/types@^9.0.0":
version "9.3.2"
resolved "https://registry.yarnpkg.com/@octokit/types/-/types-9.3.2.tgz#3f5f89903b69f6a2d196d78ec35f888c0013cac5"
integrity sha512-D4iHGTdAnEEVsB8fl95m1hiz7D5YiRdQ9b/OEb3BYRVwbLsGHcRVPz+u+BgRLNk0Q0/4iZCBqDN96j2XNxfXrA==
dependencies:
"@octokit/openapi-types" "^18.0.0"
"@types/node@18.x":
version "18.15.13"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.13.tgz#f64277c341150c979e42b00e4ac289290c9df469"
@@ -135,15 +145,15 @@ is-plain-object@^5.0.0:
resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344"
integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==
jsonc-parser@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.2.1.tgz#db73cd59d78cce28723199466b2a03d1be1df2bc"
integrity sha512-o6/yDBYccGvTz1+QFevz6l6OBZ2+fMVu2JZ9CIhzsYRX4mjaK5IyX9eldUdCmga16zlgQxyrj5pt9kzuj2C02w==
jsonc-parser@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76"
integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==
node-fetch@^2.6.7:
version "2.6.8"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.8.tgz#a68d30b162bc1d8fd71a367e81b997e1f4d4937e"
integrity sha512-RZ6dBYuj8dRSfxpUSu+NsdF1dpPpluJxwOp+6IoDp/sH2QNDSvurYsAa+F1WxY2RjA1iP93xhcsUoYbF2XBqVg==
version "2.7.0"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d"
integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==
dependencies:
whatwg-url "^5.0.0"
+1 -1
View File
@@ -6,7 +6,7 @@
"git": {
"name": "dotnet/csharp-tmLanguage",
"repositoryUrl": "https://github.com/dotnet/csharp-tmLanguage",
"commitHash": "772323937fedd65c6dc1c8ce6ea41d97415ed7d1"
"commitHash": "525e628edad54c0f7aa15b015310df240803ea66"
}
},
"license": "MIT",
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -25,8 +25,8 @@ export async function updateTag(tagName: string | undefined): Promise<boolean |
return;
}
const rangesToUpdate = Array.from(editor.selections).reverse()
.reduce<TagRange[]>((prev, selection) =>
const rangesToUpdate = editor.selections
.reduceRight<TagRange[]>((prev, selection) =>
prev.concat(getRangesToUpdate(document, selection, rootNode)), []);
if (!rangesToUpdate.length) {
return;
+1 -1
View File
@@ -26,7 +26,7 @@
"watch": "gulp watch-extension:extension-editing"
},
"dependencies": {
"jsonc-parser": "^2.2.1",
"jsonc-parser": "^3.2.0",
"markdown-it": "^12.3.2",
"parse5": "^3.0.2"
},
@@ -0,0 +1,9 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { l10n } from 'vscode';
export const implicitActivationEvent = l10n.t("This activation event cannot be explicitly listed by your extension.");
export const redundantImplicitActivationEvent = l10n.t("This activation event can be removed as VS Code generates these automatically from your package.json contribution declarations.");
@@ -12,10 +12,12 @@ export function activate(context: vscode.ExtensionContext) {
//package.json suggestions
context.subscriptions.push(registerPackageDocumentCompletions());
//package.json code actions for lint warnings
context.subscriptions.push(registerCodeActionsProvider());
context.subscriptions.push(new ExtensionLinter());
}
function registerPackageDocumentCompletions(): vscode.Disposable {
return vscode.languages.registerCompletionItemProvider({ language: 'json', pattern: '**/package.json' }, {
provideCompletionItems(document, position, token) {
@@ -23,3 +25,11 @@ function registerPackageDocumentCompletions(): vscode.Disposable {
}
});
}
function registerCodeActionsProvider(): vscode.Disposable {
return vscode.languages.registerCodeActionsProvider({ language: 'json', pattern: '**/package.json' }, {
provideCodeActions(document, range, context, token) {
return new PackageDocument(document).provideCodeActions(range, context, token);
}
});
}
@@ -13,6 +13,7 @@ import * as MarkdownItType from 'markdown-it';
import { commands, languages, workspace, Disposable, TextDocument, Uri, Diagnostic, Range, DiagnosticSeverity, Position, env, l10n } from 'vscode';
import { INormalizedVersion, normalizeVersion, parseVersion } from './extensionEngineValidation';
import { JsonStringScanner } from './jsonReconstruct';
import { implicitActivationEvent, redundantImplicitActivationEvent } from './constants';
const product = JSON.parse(fs.readFileSync(path.join(env.appRoot, 'product.json'), { encoding: 'utf-8' }));
const allowedBadgeProviders: string[] = (product.extensionAllowedBadgeProviders || []).map((s: string) => s.toLowerCase());
@@ -32,8 +33,6 @@ const dataUrlsNotValid = l10n.t("Data URLs are not a valid image source.");
const relativeUrlRequiresHttpsRepository = l10n.t("Relative image URLs require a repository with HTTPS protocol to be specified in the package.json.");
const relativeBadgeUrlRequiresHttpsRepository = l10n.t("Relative badge URLs require a repository with HTTPS protocol to be specified in this package.json.");
const apiProposalNotListed = l10n.t("This proposal cannot be used because for this extension the product defines a fixed set of API proposals. You can test your extension but before publishing you MUST reach out to the VS Code team.");
const implicitActivationEvent = l10n.t("This activation event cannot be explicitly listed by your extension.");
const redundantImplicitActivationEvent = l10n.t("This activation event can be removed as VS Code generates these automatically from your package.json contribution declarations.");
const bumpEngineForImplicitActivationEvents = l10n.t("This activation event can be removed for extensions targeting engine version ^1.75 as VS Code will generate these automatically from your package.json contribution declarations.");
const starActivation = l10n.t("Using '*' activation is usually a bad idea as it impacts performance.");
const parsingErrorHeader = l10n.t("Error parsing the when-clause:");
@@ -128,7 +127,7 @@ export class ExtensionLinter {
const tree = parseTree(document.getText());
const info = this.readPackageJsonInfo(this.getUriFolder(document.uri), tree);
if (info.isExtension) {
if (tree && info.isExtension) {
const icon = findNodeAtLocation(tree, ['icon']);
if (icon && icon.type === 'string') {
@@ -5,6 +5,7 @@
import * as vscode from 'vscode';
import { getLocation, Location } from 'jsonc-parser';
import { implicitActivationEvent, redundantImplicitActivationEvent } from './constants';
export class PackageDocument {
@@ -21,6 +22,24 @@ export class PackageDocument {
return undefined;
}
public provideCodeActions(_range: vscode.Range, context: vscode.CodeActionContext, _token: vscode.CancellationToken): vscode.ProviderResult<vscode.CodeAction[]> {
const codeActions: vscode.CodeAction[] = [];
for (const diagnostic of context.diagnostics) {
if (diagnostic.message === implicitActivationEvent || diagnostic.message === redundantImplicitActivationEvent) {
const codeAction = new vscode.CodeAction(vscode.l10n.t("Remove activation event"), vscode.CodeActionKind.QuickFix);
codeAction.edit = new vscode.WorkspaceEdit();
const rangeForCharAfter = diagnostic.range.with(diagnostic.range.end, diagnostic.range.end.translate(0, 1));
if (this.document.getText(rangeForCharAfter) === ',') {
codeAction.edit.delete(this.document.uri, diagnostic.range.with(undefined, diagnostic.range.end.translate(0, 1)));
} else {
codeAction.edit.delete(this.document.uri, diagnostic.range);
}
codeActions.push(codeAction);
}
}
return codeActions;
}
private provideLanguageOverridesCompletionItems(location: Location, position: vscode.Position): vscode.ProviderResult<vscode.CompletionItem[]> {
let range = this.getReplaceRange(location, position);
const text = this.document.getText(range);
+7 -7
View File
@@ -27,15 +27,15 @@ entities@~2.1.0:
resolved "https://registry.yarnpkg.com/entities/-/entities-2.1.0.tgz#992d3129cf7df6870b96c57858c249a120f8b8b5"
integrity sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==
jsonc-parser@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.2.1.tgz#db73cd59d78cce28723199466b2a03d1be1df2bc"
integrity sha512-o6/yDBYccGvTz1+QFevz6l6OBZ2+fMVu2JZ9CIhzsYRX4mjaK5IyX9eldUdCmga16zlgQxyrj5pt9kzuj2C02w==
jsonc-parser@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76"
integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==
linkify-it@^3.0.1:
version "3.0.2"
resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-3.0.2.tgz#f55eeb8bc1d3ae754049e124ab3bb56d97797fb8"
integrity sha512-gDBO4aHNZS6coiZCKVhSNh43F9ioIL4JwRjLZPkoLIY4yZFwg264Y5lu2x6rb1Js42Gh6Yqm2f6L2AJcnkzinQ==
version "3.0.3"
resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-3.0.3.tgz#a98baf44ce45a550efb4d49c769d07524cc2fa2e"
integrity sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==
dependencies:
uc.micro "^1.0.1"
+2 -2
View File
@@ -2465,7 +2465,7 @@
"null"
],
"default": 50,
"description": "%config.inputValidationSubjectLength%"
"markdownDescription": "%config.inputValidationSubjectLength%"
},
"git.detectSubmodules": {
"type": "boolean",
@@ -2659,7 +2659,7 @@
"description": "%config.useIntegratedAskPass%"
},
"git.githubAuthentication": {
"deprecationMessage": "This setting is now deprecated, please use `github.gitAuthentication` instead."
"markdownDeprecationMessage": "This setting is now deprecated, please use `#github.gitAuthentication#` instead."
},
"git.timeline.date": {
"type": "string",
+1 -1
View File
@@ -191,7 +191,7 @@
"config.showPushSuccessNotification": "Controls whether to show a notification when a push is successful.",
"config.inputValidation": "Controls when to show commit message input validation.",
"config.inputValidationLength": "Controls the commit message length threshold for showing a warning.",
"config.inputValidationSubjectLength": "Controls the commit message subject length threshold for showing a warning. Unset it to inherit the value of `config.inputValidationLength`.",
"config.inputValidationSubjectLength": "Controls the commit message subject length threshold for showing a warning. Unset it to inherit the value of `#git.inputValidationLength#`.",
"config.detectSubmodules": "Controls whether to automatically detect git submodules.",
"config.detectSubmodulesLimit": "Controls the limit of git submodules detected.",
"config.alwaysShowStagedChangesResourceGroup": "Always show the Staged Changes resource group.",
+1 -1
View File
@@ -495,7 +495,7 @@ export class Model implements IRepositoryResolver, IBranchProtectionProviderRegi
this.logger.trace(`Opening repository: ${repoPath}`);
const existingRepository = await this.getRepositoryExact(repoPath);
if (existingRepository) {
this.logger.trace(`Repository for path ${repoPath} already exists: ${existingRepository.root})`);
this.logger.trace(`Repository for path ${repoPath} already exists: ${existingRepository.root}`);
return;
}
@@ -54,7 +54,7 @@
"%html.completion.attributeDefaultValue.empty%"
],
"default": "doublequotes",
"description": "%html.completion.attributeDefaultValue%"
"markdownDescription": "%html.completion.attributeDefaultValue%"
},
"html.customData": {
"type": "array",
@@ -21,7 +21,7 @@
"html.format.wrapAttributes.preservealigned": "Preserve wrapping of attributes but align.",
"html.format.templating.desc": "Honor django, erb, handlebars and php templating language tags.",
"html.format.unformattedContentDelimiter.desc": "Keep text content together between this string.",
"html.format.wrapAttributesIndentSize.desc": "Indent wrapped attributes to after N characters. Use `null` to use the default indent size. Ignored if `#html.format.wrapAttributes#` is set to 'aligned'.",
"html.format.wrapAttributesIndentSize.desc": "Indent wrapped attributes to after N characters. Use `null` to use the default indent size. Ignored if `#html.format.wrapAttributes#` is set to `aligned`.",
"html.suggest.html5.desc": "Controls whether the built-in HTML language support suggests HTML5 tags, properties and values.",
"html.trace.server.desc": "Traces the communication between VS Code and the HTML language server.",
"html.validate.scripts": "Controls whether the built-in HTML language support validates embedded scripts.",
+2 -4
View File
@@ -24,7 +24,7 @@ type NotebookMetadata = {
pygments_lexer?: string;
[propName: string]: unknown;
};
orig_nbformat: number;
orig_nbformat?: number;
[propName: string]: unknown;
};
@@ -76,9 +76,7 @@ export function activate(context: vscode.ExtensionContext) {
data.metadata = {
custom: {
cells: [],
metadata: {
orig_nbformat: 4
},
metadata: {},
nbformat: 4,
nbformat_minor: 2
}
+4 -4
View File
@@ -63,7 +63,7 @@ export class NotebookSerializer implements vscode.NotebookSerializer {
// For notebooks without metadata default the language in metadata to the preferred language.
if (!json.metadata || (!json.metadata.kernelspec && !json.metadata.language_info)) {
json.metadata = json.metadata || { orig_nbformat: defaultNotebookFormat.major };
json.metadata = json.metadata || {};
json.metadata.language_info = json.metadata.language_info || { name: preferredCellLanguage };
}
@@ -101,8 +101,8 @@ export class NotebookSerializer implements vscode.NotebookSerializer {
export function getNotebookMetadata(document: vscode.NotebookDocument | vscode.NotebookData) {
const notebookContent: Partial<nbformat.INotebookContent> = document.metadata?.custom || {};
notebookContent.cells = notebookContent.cells || [];
notebookContent.nbformat = notebookContent.nbformat || 4;
notebookContent.nbformat_minor = notebookContent.nbformat_minor ?? 2;
notebookContent.metadata = notebookContent.metadata || { orig_nbformat: 4 };
notebookContent.nbformat = notebookContent.nbformat || defaultNotebookFormat.major;
notebookContent.nbformat_minor = notebookContent.nbformat_minor ?? defaultNotebookFormat.minor;
notebookContent.metadata = notebookContent.metadata || {};
return notebookContent;
}
+2 -2
View File
@@ -6,7 +6,7 @@
"git": {
"name": "redhat-developer/vscode-java",
"repositoryUrl": "https://github.com/redhat-developer/vscode-java",
"commitHash": "5fb57e8e1c5d776b21be13cd7227b25b87edf4a6"
"commitHash": "5d224a552cf5f0f8ebccf69e43e2575ed2c13839"
}
},
"license": "MIT",
@@ -44,7 +44,7 @@
"suitability for any purpose."
],
"description": "This grammar was derived from https://github.com/atom/language-java/blob/master/grammars/java.cson.",
"version": "1.21.0"
"version": "1.22.0"
}
],
"version": 1
@@ -4,7 +4,7 @@
"If you want to provide a fix or improvement, please create a pull request against the original repository.",
"Once accepted there, we are happy to receive an update request."
],
"version": "https://github.com/redhat-developer/vscode-java/commit/5fb57e8e1c5d776b21be13cd7227b25b87edf4a6",
"version": "https://github.com/redhat-developer/vscode-java/commit/5d224a552cf5f0f8ebccf69e43e2575ed2c13839",
"name": "Java",
"scopeName": "source.java",
"patterns": [
+1 -1
View File
@@ -6,7 +6,7 @@
"git": {
"name": "JuliaEditorSupport/atom-language-julia",
"repositoryUrl": "https://github.com/JuliaEditorSupport/atom-language-julia",
"commitHash": "ccc0277c9ee9af34a0b50e5fa27a6f5191601b8c"
"commitHash": "7cbe6a7c4f2c8275e15f5b6e0722d285730ffb99"
}
},
"license": "MIT",
@@ -4,7 +4,7 @@
"If you want to provide a fix or improvement, please create a pull request against the original repository.",
"Once accepted there, we are happy to receive an update request."
],
"version": "https://github.com/JuliaEditorSupport/atom-language-julia/commit/ccc0277c9ee9af34a0b50e5fa27a6f5191601b8c",
"version": "https://github.com/JuliaEditorSupport/atom-language-julia/commit/7cbe6a7c4f2c8275e15f5b6e0722d285730ffb99",
"name": "Julia",
"scopeName": "source.julia",
"comment": "This grammar is used by Atom (Oniguruma), GitHub (PCRE), and VSCode (Oniguruma),\nso all regexps must be compatible with both engines.\n\nSpecs:\n- https://github.com/kkos/oniguruma/blob/master/doc/RE\n- https://www.pcre.org/current/doc/html/",
@@ -356,13 +356,16 @@
"name": "keyword.operator.shift.julia"
},
{
"match": "(?:\\s*(::|>:|<:)\\s*((?:(?:Union)?\\([^)]*\\)|[[:alpha:]_$∇][[:word:]⁺-ₜ!\\.]*(?:(?:{(?:[^{}]|{(?:[^{}]|{[^{}]*})*})*})|(?:\".+?(?<!\\\\)\"))?)))(?:\\.\\.\\.)?",
"match": "(?:\\s*(::|>:|<:)\\s*((?:(?:Union)?\\([^)]*\\)|[[:alpha:]_$∇][[:word:]⁺-ₜ!\\.]*(?:(?:{(?:[^{}]|{(?:[^{}]|{[^{}]*})*})*})|(?:\".+?(?<!\\\\)\"))?)))(?:\\.\\.\\.)?((?:\\.)?'*)",
"captures": {
"1": {
"name": "keyword.operator.relation.types.julia"
},
"2": {
"name": "support.type.julia"
},
"3": {
"name": "keyword.operator.transpose.julia"
}
}
},
+2 -2
View File
@@ -6,11 +6,11 @@
"git": {
"name": "jlelong/vscode-latex-basics",
"repositoryUrl": "https://github.com/jlelong/vscode-latex-basics",
"commitHash": "30d04562e592305b6f6d41a539b3ccf326888aaf"
"commitHash": "3ae82b457c28f0368cbbb47024b0245ef1ff3d33"
}
},
"license": "MIT",
"version": "1.5.3",
"version": "1.5.2",
"description": "The files in syntaxes/ were originally part of https://github.com/James-Yu/LaTeX-Workshop. They have been extracted in the hope that they can useful outside of the LaTeX-Workshop extension.",
"licenseDetail": [
"Copyright (c) vscode-latex-basics authors",
+86 -166
View File
@@ -4,30 +4,74 @@
"If you want to provide a fix or improvement, please create a pull request against the original repository.",
"Once accepted there, we are happy to receive an update request."
],
"version": "https://github.com/jlelong/vscode-latex-basics/commit/7adad0868ecafbb1df978f1e052d6c3c85c38732",
"version": "https://github.com/jlelong/vscode-latex-basics/commit/36411b38cf4ed18e02050249e2162b1316488686",
"name": "BibTeX",
"scopeName": "text.bibtex",
"comment": "Grammar based on description from http://artis.imag.fr/~Xavier.Decoret/resources/xdkbibtex/bibtex_summary.html#comment\n\t\n\tTODO: Does not support @preamble\n\t",
"comment": "Grammar based on description from https://github.com/aclements/biblib\n",
"patterns": [
{
"begin": "@Comment",
"beginCaptures": {
"match": "@(?i:comment)(?=[\\s{(])",
"captures": {
"0": {
"name": "punctuation.definition.comment.bibtex"
}
},
"end": "$\\n?",
"name": "comment.line.at-sign.bibtex"
"name": "comment.block.at-sign.bibtex"
},
{
"begin": "((@)(?i:preamble))\\s*(\\{)\\s*",
"beginCaptures": {
"1": {
"name": "keyword.other.preamble.bibtex"
},
"2": {
"name": "punctuation.definition.keyword.bibtex"
},
"3": {
"name": "punctuation.section.preamble.begin.bibtex"
}
},
"end": "\\}",
"endCaptures": {
"0": {
"name": "punctuation.section.preamble.end.bibtex"
}
},
"name": "meta.preamble.braces.bibtex",
"patterns": [
{
"include": "#percentage_comment"
"include": "#field_value"
}
]
},
{
"begin": "((@)(?i:string))\\s*(\\{)\\s*([a-zA-Z0-9\\!\\$\\&\\*\\+\\-\\.\\/\\:\\;\\<\\>\\?\\[\\]\\^\\_\\`\\|]+)",
"begin": "((@)(?i:preamble))\\s*(\\()\\s*",
"beginCaptures": {
"1": {
"name": "keyword.other.preamble.bibtex"
},
"2": {
"name": "punctuation.definition.keyword.bibtex"
},
"3": {
"name": "punctuation.section.preamble.begin.bibtex"
}
},
"end": "\\)",
"endCaptures": {
"0": {
"name": "punctuation.section.preamble.end.bibtex"
}
},
"name": "meta.preamble.parenthesis.bibtex",
"patterns": [
{
"include": "#field_value"
}
]
},
{
"begin": "((@)(?i:string))\\s*(\\{)\\s*([a-zA-Z!$&*+\\-./:;<>?@\\[\\\\\\]^_`|~][a-zA-Z0-9!$&*+\\-./:;<>?@\\[\\\\\\]^_`|~]*)",
"beginCaptures": {
"1": {
"name": "keyword.other.string-constant.bibtex"
@@ -51,12 +95,12 @@
"name": "meta.string-constant.braces.bibtex",
"patterns": [
{
"include": "#string_content"
"include": "#field_value"
}
]
},
{
"begin": "((@)(?i:string))\\s*(\\()\\s*([a-zA-Z0-9\\!\\$\\&\\*\\+\\-\\.\\/\\:\\;\\<\\>\\?\\[\\]\\^\\_\\`\\|]+)",
"begin": "((@)(?i:string))\\s*(\\()\\s*([a-zA-Z!$&*+\\-./:;<>?@\\[\\\\\\]^_`|~][a-zA-Z0-9!$&*+\\-./:;<>?@\\[\\\\\\]^_`|~]*)",
"beginCaptures": {
"1": {
"name": "keyword.other.string-constant.bibtex"
@@ -80,12 +124,12 @@
"name": "meta.string-constant.parenthesis.bibtex",
"patterns": [
{
"include": "#string_content"
"include": "#field_value"
}
]
},
{
"begin": "((@)[a-zA-Z]+)\\s*(\\{)\\s*([^\\s,]*)",
"begin": "((@)[a-zA-Z!$&*+\\-./:;<>?@\\[\\\\\\]^_`|~][a-zA-Z0-9!$&*+\\-./:;<>?@\\[\\\\\\]^_`|~]*)\\s*(\\{)\\s*([^\\s,}]*)",
"beginCaptures": {
"1": {
"name": "keyword.other.entry-type.bibtex"
@@ -109,13 +153,7 @@
"name": "meta.entry.braces.bibtex",
"patterns": [
{
"include": "#percentage_comment"
},
{
"include": "#url_field"
},
{
"begin": "([a-zA-Z0-9\\!\\$\\&\\*\\+\\-\\.\\/\\:\\;\\<\\>\\?\\[\\]\\^\\_\\`\\|]+)\\s*(\\=)",
"begin": "([a-zA-Z!$&*+\\-./:;<>?@\\[\\\\\\]^_`|~][a-zA-Z0-9!$&*+\\-./:;<>?@\\[\\\\\\]^_`|~]*)\\s*(\\=)",
"beginCaptures": {
"1": {
"name": "support.function.key.bibtex"
@@ -128,23 +166,14 @@
"name": "meta.key-assignment.bibtex",
"patterns": [
{
"include": "#percentage_comment"
},
{
"include": "#integer"
},
{
"include": "#string_content"
},
{
"include": "#string_var"
"include": "#field_value"
}
]
}
]
},
{
"begin": "((@)[a-zA-Z]+)\\s*(\\()\\s*([^\\s,]*)",
"begin": "((@)[a-zA-Z!$&*+\\-./:;<>?@\\[\\\\\\]^_`|~][a-zA-Z0-9!$&*+\\-./:;<>?@\\[\\\\\\]^_`|~]*)\\s*(\\()\\s*([^\\s,]*)",
"beginCaptures": {
"1": {
"name": "keyword.other.entry-type.bibtex"
@@ -168,13 +197,7 @@
"name": "meta.entry.parenthesis.bibtex",
"patterns": [
{
"include": "#percentage_comment"
},
{
"include": "#url_field"
},
{
"begin": "([a-zA-Z0-9\\!\\$\\&\\*\\+\\-\\.\\/\\:\\;\\<\\>\\?\\[\\]\\^\\_\\`\\|]+)\\s*(\\=)",
"begin": "([a-zA-Z!$&*+\\-./:;<>?@\\[\\\\\\]^_`|~][a-zA-Z0-9!$&*+\\-./:;<>?@\\[\\\\\\]^_`|~]*)\\s*(\\=)",
"beginCaptures": {
"1": {
"name": "support.function.key.bibtex"
@@ -187,16 +210,7 @@
"name": "meta.key-assignment.bibtex",
"patterns": [
{
"include": "#percentage_comment"
},
{
"include": "#integer"
},
{
"include": "#string_content"
},
{
"include": "#string_var"
"include": "#field_value"
}
]
}
@@ -209,6 +223,23 @@
}
],
"repository": {
"field_value": {
"patterns": [
{
"include": "#string_content"
},
{
"include": "#integer"
},
{
"include": "#string_var"
},
{
"name": "keyword.operator.bibtex",
"match": "#"
}
]
},
"integer": {
"match": "\\s*(\\d+)\\s*",
"captures": {
@@ -218,13 +249,13 @@
}
},
"nested_braces": {
"begin": "(?<!\\\\)\\{",
"begin": "\\{",
"beginCaptures": {
"0": {
"name": "punctuation.definition.group.begin.bibtex"
}
},
"end": "(?<!\\\\)\\}",
"end": "\\}",
"endCaptures": {
"0": {
"name": "punctuation.definition.group.end.bibtex"
@@ -237,16 +268,10 @@
]
},
"string_var": {
"match": "(#)?\\s*([a-zA-Z0-9\\!\\$\\&\\*\\+\\-\\.\\/\\:\\;\\<\\>\\?\\[\\]\\^\\_\\`\\|]+)\\s*(#)?",
"match": "[a-zA-Z!$&*+\\-./:;<>?@\\[\\\\\\]^_`|~][a-zA-Z0-9!$&*+\\-./:;<>?@\\[\\\\\\]^_`|~]*",
"captures": {
"1": {
"name": "keyword.operator.bibtex"
},
"2": {
"0": {
"name": "support.variable.bibtex"
},
"3": {
"name": "keyword.operator.bibtex"
}
}
},
@@ -259,23 +284,13 @@
"name": "punctuation.definition.string.begin.bibtex"
}
},
"end": "(\\})(?=(?:,?\\s*\\}?\\s*\\n)|(?:\\s*#))",
"end": "\\}",
"endCaptures": {
"1": {
"0": {
"name": "punctuation.definition.string.end.bibtex"
}
},
"patterns": [
{
"include": "#url_cmd"
},
{
"include": "#percentage_comment"
},
{
"match": "@",
"name": "invalid.illegal.at-sign.bibtex"
},
{
"include": "#nested_braces"
}
@@ -288,7 +303,7 @@
"name": "punctuation.definition.string.begin.bibtex"
}
},
"end": "\"(?=(?:,?\\s*\\}?\\s*\\n)|(?:\\s*#))",
"end": "\"",
"endCaptures": {
"0": {
"name": "punctuation.definition.string.end.bibtex"
@@ -296,106 +311,11 @@
},
"patterns": [
{
"include": "#url_cmd"
},
{
"include": "#percentage_comment"
},
{
"match": "@",
"name": "invalid.illegal.at-sign.bibtex"
"include": "#nested_braces"
}
]
}
]
},
"string_url": {
"patterns": [
{
"begin": "\\{|\"",
"beginCaptures": {
"0": {
"name": "punctuation.definition.string.begin.bibtex"
}
},
"end": "(\\}|\")(?=(?:,?\\s*\\}?\\s*\\n)|(?:\\s*#))",
"endCaptures": {
"1": {
"name": "punctuation.definition.string.end.bibtex"
}
},
"contentName": "meta.url.bibtex",
"patterns": [
{
"include": "#url_cmd"
}
]
}
]
},
"percentage_comment": {
"patterns": [
{
"begin": "(^[ \\t]+)?(?=%)",
"beginCaptures": {
"1": {
"name": "punctuation.whitespace.comment.leading.bibtex"
}
},
"end": "(?!\\G)",
"patterns": [
{
"begin": "(?<!\\\\)%",
"beginCaptures": {
"0": {
"name": "punctuation.definition.comment.bibtex"
}
},
"end": "$\\n?",
"name": "comment.line.percentage.bibtex"
}
]
}
]
},
"url_cmd": {
"captures": {
"1": {
"name": "support.function.url.bibtex"
},
"2": {
"name": "punctuation.definition.function.bibtex"
},
"3": {
"name": "punctuation.definition.arguments.begin.bibtex"
},
"4": {
"name": "markup.underline.link.bibtex"
},
"5": {
"name": "punctuation.definition.arguments.end.bibtex"
}
},
"match": "(?:\\s*)((\\\\)(?:url|href))(\\{)([^}]*)(\\})",
"name": "meta.function.link.url.bibtex"
},
"url_field": {
"begin": "(url)\\s*(\\=)",
"beginCaptures": {
"1": {
"name": "support.function.key.bibtex"
},
"2": {
"name": "punctuation.separator.key-value.bibtex"
}
},
"end": "(?=[,}])",
"name": "meta.key-assignment.url.bibtex",
"patterns": [
{
"include": "#string_url"
}
]
}
}
}
@@ -4,7 +4,7 @@
"If you want to provide a fix or improvement, please create a pull request against the original repository.",
"Once accepted there, we are happy to receive an update request."
],
"version": "https://github.com/jlelong/vscode-latex-basics/commit/30d04562e592305b6f6d41a539b3ccf326888aaf",
"version": "https://github.com/jlelong/vscode-latex-basics/commit/66ea1422ac817ff7704359b8ec4934a987024aaa",
"name": "LaTeX",
"scopeName": "text.tex.latex",
"patterns": [
@@ -2356,7 +2356,7 @@
"name": "meta.definition.label.latex",
"patterns": [
{
"match": "[a-zA-Z0-9\\.,:/*!^_-]",
"match": "[\\p{Alphabetic}\\p{Number}\\.,:/*!^_-]",
"name": "variable.parameter.definition.label.latex"
}
]
@@ -5,7 +5,8 @@
import * as vscode from 'vscode';
import * as path from 'path';
import { isSupportedEnvironment } from './utils';
import { isSupportedEnvironment } from './common/uri';
import { IntervalTimer, SequencerByKey } from './common/async';
import { generateCodeChallenge, generateCodeVerifier, randomUUID } from './cryptoUtils';
import { BetterTokenStorage, IDidChangeInOtherWindowEvent } from './betterSecretStorage';
import { LoopbackAuthServer } from './node/authServer';
@@ -86,9 +87,9 @@ export class AzureActiveDirectoryService {
// For details on why this is set to 2/3... see https://github.com/microsoft/vscode/issues/133201#issuecomment-966668197
private static REFRESH_TIMEOUT_MODIFIER = 1000 * 2 / 3;
private static POLLING_CONSTANT = 1000 * 60 * 30;
private _tokens: IToken[] = [];
private _refreshTimeouts: Map<string, NodeJS.Timeout> = new Map<string, NodeJS.Timeout>();
private _refreshingPromise: Promise<any> | undefined;
private _sessionChangeEmitter: vscode.EventEmitter<vscode.AuthenticationProviderAuthenticationSessionsChangeEvent> = new vscode.EventEmitter<vscode.AuthenticationProviderAuthenticationSessionsChangeEvent>();
// Used to keep track of current requests when not using the local server approach.
@@ -96,6 +97,12 @@ export class AzureActiveDirectoryService {
private _codeExchangePromises = new Map<string, Promise<vscode.AuthenticationSession>>();
private _codeVerfifiers = new Map<string, string>();
// Used to keep track of tokens that we need to store but can't because we aren't the focused window.
private _pendingTokensToStore: Map<string, IToken> = new Map<string, IToken>();
// Used to sequence requests to the same scope.
private _sequencer = new SequencerByKey<string>();
constructor(
private readonly _logger: vscode.LogOutputChannel,
_context: vscode.ExtensionContext,
@@ -105,15 +112,24 @@ export class AzureActiveDirectoryService {
private readonly _env: Environment
) {
_context.subscriptions.push(this._tokenStorage.onDidChangeInOtherWindow((e) => this.checkForUpdates(e)));
_context.subscriptions.push(vscode.window.onDidChangeWindowState(async (e) => e.focused && await this.storePendingTokens()));
// In the event that a window isn't focused for a long time, we should still try to store the tokens at some point.
const timer = new IntervalTimer();
timer.cancelAndSet(
() => !vscode.window.state.focused && this.storePendingTokens(),
// 5 hours + random extra 0-30 seconds so that each window doesn't try to store at the same time
(18000000) + Math.floor(Math.random() * 30000));
_context.subscriptions.push(timer);
}
public async initialize(): Promise<void> {
this._logger.info('Reading sessions from secret storage...');
this._logger.trace('Reading sessions from secret storage...');
const sessions = await this._tokenStorage.getAll(item => this.sessionMatchesEndpoint(item));
this._logger.info(`Got ${sessions.length} stored sessions`);
this._logger.trace(`Got ${sessions.length} stored sessions`);
const refreshes = sessions.map(async session => {
this._logger.trace(`Read the following stored session with scopes: ${session.scope}`);
this._logger.trace(`[${session.scope}] '${session.id}' Read stored session`);
const scopes = session.scope.split(' ');
const scopeData: IScopeData = {
scopes,
@@ -187,12 +203,12 @@ export class AzureActiveDirectoryService {
return this._sessionChangeEmitter.event;
}
async getSessions(scopes?: string[]): Promise<vscode.AuthenticationSession[]> {
public getSessions(scopes?: string[]): Promise<vscode.AuthenticationSession[]> {
if (!scopes) {
this._logger.info('Getting sessions for all scopes...');
const sessions = this._tokens.map(token => this.convertToSessionSync(token));
this._logger.info(`Got ${sessions.length} sessions for all scopes...`);
return sessions;
return Promise.resolve(sessions);
}
let modifiedScopes = [...scopes];
@@ -210,32 +226,7 @@ export class AzureActiveDirectoryService {
}
modifiedScopes = modifiedScopes.sort();
let modifiedScopesStr = modifiedScopes.join(' ');
this._logger.info(`Getting sessions for the following scopes: ${modifiedScopesStr}`);
if (this._refreshingPromise) {
this._logger.info('Refreshing in progress. Waiting for completion before continuing.');
try {
await this._refreshingPromise;
} catch (e) {
// this will get logged in the refresh function.
}
}
let matchingTokens = this._tokens.filter(token => token.scope === modifiedScopesStr);
// The user may still have a token that doesn't have the openid & email scopes so check for that as well.
// Eventually, we should remove this and force the user to re-log in so that we don't have any sessions
// without an idtoken.
if (!matchingTokens.length) {
const fallbackOrderedScopes = scopes.sort().join(' ');
this._logger.trace(`No session found with idtoken scopes... Using fallback scope list of: ${fallbackOrderedScopes}`);
matchingTokens = this._tokens.filter(token => token.scope === fallbackOrderedScopes);
if (matchingTokens.length) {
modifiedScopesStr = fallbackOrderedScopes;
}
}
const modifiedScopesStr = modifiedScopes.join(' ');
const clientId = this.getClientId(scopes);
const scopeData: IScopeData = {
clientId,
@@ -247,31 +238,43 @@ export class AzureActiveDirectoryService {
tenant: this.getTenantId(scopes),
};
this._logger.trace(`[${scopeData.scopeStr}] Queued getting sessions`);
return this._sequencer.queue(modifiedScopesStr, () => this.doGetSessions(scopeData));
}
private async doGetSessions(scopeData: IScopeData): Promise<vscode.AuthenticationSession[]> {
this._logger.info(`[${scopeData.scopeStr}] Getting sessions`);
const matchingTokens = this._tokens.filter(token => token.scope === scopeData.scopeStr);
// If we still don't have a matching token try to get a new token from an existing token by using
// the refreshToken. This is documented here:
// https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow#refresh-the-access-token
// "Refresh tokens are valid for all permissions that your client has already received consent for."
if (!matchingTokens.length) {
// Get a token with the correct client id.
const token = clientId === DEFAULT_CLIENT_ID
const token = scopeData.clientId === DEFAULT_CLIENT_ID
? this._tokens.find(t => t.refreshToken && !t.scope.includes('VSCODE_CLIENT_ID'))
: this._tokens.find(t => t.refreshToken && t.scope.includes(`VSCODE_CLIENT_ID:${clientId}`));
: this._tokens.find(t => t.refreshToken && t.scope.includes(`VSCODE_CLIENT_ID:${scopeData.clientId}`));
if (token) {
this._logger.trace(`[${scopeData.scopeStr}] '${token.sessionId}' Found a matching token with a different scopes '${token.scope}'. Attempting to get a new session using the existing session.`);
try {
const itoken = await this.refreshToken(token.refreshToken, scopeData);
const itoken = await this.doRefreshToken(token.refreshToken, scopeData);
matchingTokens.push(itoken);
} catch (err) {
this._logger.error(`Attempted to get a new session for scopes '${scopeData.scopeStr}' using the existing session with scopes '${token.scope}' but it failed due to: ${err.message ?? err}`);
this._logger.error(`[${scopeData.scopeStr}] Attempted to get a new session using the existing session with scopes '${token.scope}' but it failed due to: ${err.message ?? err}`);
}
}
}
this._logger.info(`Got ${matchingTokens.length} sessions for scopes: ${modifiedScopesStr}`);
return Promise.all(matchingTokens.map(token => this.convertToSession(token, scopeData)));
this._logger.info(`[${scopeData.scopeStr}] Got ${matchingTokens.length} sessions`);
const results = await Promise.allSettled(matchingTokens.map(token => this.convertToSession(token, scopeData)));
return results
.filter(result => result.status === 'fulfilled')
.map(result => (result as PromiseFulfilledResult<vscode.AuthenticationSession>).value);
}
public async createSession(scopes: string[]): Promise<vscode.AuthenticationSession> {
public createSession(scopes: string[]): Promise<vscode.AuthenticationSession> {
let modifiedScopes = [...scopes];
if (!modifiedScopes.includes('openid')) {
modifiedScopes.push('openid');
@@ -296,7 +299,12 @@ export class AzureActiveDirectoryService {
tenant: this.getTenantId(scopes),
};
this._logger.info(`Logging in for the following scopes: ${scopeData.scopeStr}`);
this._logger.trace(`[${scopeData.scopeStr}] Queued creating session`);
return this._sequencer.queue(scopeData.scopeStr, () => this.doCreateSession(scopeData));
}
private async doCreateSession(scopeData: IScopeData): Promise<vscode.AuthenticationSession> {
this._logger.info(`[${scopeData.scopeStr}] Creating session`);
const runsRemote = vscode.env.remoteName !== undefined;
const runsServerless = vscode.env.remoteName === undefined && vscode.env.uiKind === vscode.UIKind.Web;
@@ -312,7 +320,7 @@ export class AzureActiveDirectoryService {
try {
return await this.createSessionWithLocalServer(scopeData);
} catch (e) {
this._logger.error(`Error creating session for scopes: ${scopeData.scopeStr} Error: ${e}`);
this._logger.error(`[${scopeData.scopeStr}] Error creating session: ${e}`);
// If the error was about starting the server, try directly hitting the login endpoint instead
if (e.message === 'Error listening to server' || e.message === 'Closed' || e.message === 'Timeout waiting for port') {
@@ -324,6 +332,7 @@ export class AzureActiveDirectoryService {
}
private async createSessionWithLocalServer(scopeData: IScopeData) {
this._logger.trace(`[${scopeData.scopeStr}] Starting login flow with local server`);
const codeVerifier = generateCodeVerifier();
const codeChallenge = await generateCodeChallenge(codeVerifier);
const qs = new URLSearchParams({
@@ -352,11 +361,14 @@ export class AzureActiveDirectoryService {
}
const session = await this.exchangeCodeForSession(codeToExchange, codeVerifier, scopeData);
this._logger.trace(`[${scopeData.scopeStr}] '${session.id}' Sending change event for added session`);
this._sessionChangeEmitter.fire({ added: [session], removed: [], changed: [] });
this._logger.info(`[${scopeData.scopeStr}] '${session.id}' session successfully created!`);
return session;
}
private async createSessionWithoutLocalServer(scopeData: IScopeData): Promise<vscode.AuthenticationSession> {
this._logger.trace(`[${scopeData.scopeStr}] Starting login flow without local server`);
let callbackUri = await vscode.env.asExternalUri(vscode.Uri.parse(`${vscode.env.uriScheme}://vscode.microsoft-authentication`));
const nonce = generateCodeVerifier();
const callbackQuery = new URLSearchParams(callbackUri.query);
@@ -418,25 +430,19 @@ export class AzureActiveDirectoryService {
}
public async removeSessionById(sessionId: string, writeToDisk: boolean = true): Promise<vscode.AuthenticationSession | undefined> {
this._logger.info(`Logging out of session '${sessionId}'`);
const tokenIndex = this._tokens.findIndex(token => token.sessionId === sessionId);
if (tokenIndex === -1) {
this._logger.info(`Session not found '${sessionId}'`);
this._logger.warn(`'${sessionId}' Session not found to remove`);
return Promise.resolve(undefined);
}
const token = this._tokens.splice(tokenIndex, 1)[0];
const session = await this.removeSessionByIToken(token, writeToDisk);
if (session) {
this._sessionChangeEmitter.fire({ added: [], removed: [session], changed: [] });
}
return session;
this._logger.trace(`[${token.scope}] '${sessionId}' Queued removing session`);
return this._sequencer.queue(token.scope, () => this.removeSessionByIToken(token, writeToDisk));
}
public async clearSessions() {
this._logger.info('Logging out of all sessions');
this._logger.trace('Logging out of all sessions');
this._tokens = [];
await this._tokenStorage.deleteAll(item => this.sessionMatchesEndpoint(item));
@@ -445,9 +451,11 @@ export class AzureActiveDirectoryService {
});
this._refreshTimeouts.clear();
this._logger.trace('All sessions logged out');
}
private async removeSessionByIToken(token: IToken, writeToDisk: boolean = true): Promise<vscode.AuthenticationSession | undefined> {
this._logger.info(`[${token.scope}] '${token.sessionId}' Logging out of session`);
this.removeSessionTimeout(token.sessionId);
if (writeToDisk) {
@@ -460,9 +468,9 @@ export class AzureActiveDirectoryService {
}
const session = this.convertToSessionSync(token);
this._logger.info(`Sending change event for session that was removed with scopes: ${token.scope}`);
this._logger.trace(`[${token.scope}] '${token.sessionId}' Sending change event for session that was removed`);
this._sessionChangeEmitter.fire({ added: [], removed: [session], changed: [] });
this._logger.info(`Logged out of session '${token.sessionId}' with scopes: ${token.scope}`);
this._logger.info(`[${token.scope}] '${token.sessionId}' Logged out of session successfully!`);
return session;
}
@@ -471,12 +479,14 @@ export class AzureActiveDirectoryService {
//#region timeout
private setSessionTimeout(sessionId: string, refreshToken: string, scopeData: IScopeData, timeout: number) {
this._logger.trace(`[${scopeData.scopeStr}] '${sessionId}' Setting refresh timeout for ${timeout} milliseconds`);
this.removeSessionTimeout(sessionId);
this._refreshTimeouts.set(sessionId, setTimeout(async () => {
try {
const refreshedToken = await this.refreshToken(refreshToken, scopeData, sessionId);
this._logger.info('Triggering change session event...');
this._logger.trace(`[${scopeData.scopeStr}] '${sessionId}' Sending change event for session that was refreshed`);
this._sessionChangeEmitter.fire({ added: [], removed: [], changed: [this.convertToSessionSync(refreshedToken)] });
this._logger.trace(`[${scopeData.scopeStr}] '${sessionId}' refresh timeout complete`);
} catch (e) {
if (e.message !== REFRESH_NETWORK_FAILURE) {
vscode.window.showErrorMessage(vscode.l10n.t('You have been signed out because reading stored authentication information failed.'));
@@ -500,12 +510,13 @@ export class AzureActiveDirectoryService {
private convertToTokenSync(json: ITokenResponse, scopeData: IScopeData, existingId?: string): IToken {
let claims = undefined;
this._logger.trace(`[${scopeData.scopeStr}] '${existingId ?? 'new'}' Attempting to parse token response.`);
try {
if (json.id_token) {
claims = JSON.parse(base64Decode(json.id_token.split('.')[1]));
} else {
this._logger.info('Attempting to parse access_token instead since no id_token was included in the response.');
this._logger.warn(`[${scopeData.scopeStr}] '${existingId ?? 'new'}' Attempting to parse access_token instead since no id_token was included in the response.`);
claims = JSON.parse(base64Decode(json.access_token.split('.')[1]));
}
} catch (e) {
@@ -520,6 +531,8 @@ export class AzureActiveDirectoryService {
}
const id = `${claims.tid}/${(claims.oid ?? (claims.altsecid ?? '' + claims.ipd ?? ''))}`;
const sessionId = existingId || `${id}/${randomUUID()}`;
this._logger.trace(`[${scopeData.scopeStr}] '${sessionId}' Token response parsed successfully.`);
return {
expiresIn: json.expires_in,
expiresAt: json.expires_in ? Date.now() + json.expires_in * 1000 : undefined,
@@ -527,7 +540,7 @@ export class AzureActiveDirectoryService {
idToken: json.id_token,
refreshToken: json.refresh_token,
scope: scopeData.scopeStr,
sessionId: existingId || `${id}/${randomUUID()}`,
sessionId,
account: {
label,
id,
@@ -552,9 +565,7 @@ export class AzureActiveDirectoryService {
private async convertToSession(token: IToken, scopeData: IScopeData): Promise<vscode.AuthenticationSession> {
if (token.accessToken && (!token.expiresAt || token.expiresAt > Date.now())) {
token.expiresAt
? this._logger.info(`Token available from cache (for scopes ${token.scope}), expires in ${token.expiresAt - Date.now()} milliseconds`)
: this._logger.info('Token available from cache (for scopes ${token.scope})');
this._logger.trace(`[${scopeData.scopeStr}] '${token.sessionId}' Token available from cache${token.expiresAt ? `, expires in ${token.expiresAt - Date.now()} milliseconds` : ''}.`);
return {
id: token.sessionId,
accessToken: token.accessToken,
@@ -565,7 +576,7 @@ export class AzureActiveDirectoryService {
}
try {
this._logger.info(`Token expired or unavailable (for scopes ${token.scope}), trying refresh`);
this._logger.trace(`[${scopeData.scopeStr}] '${token.sessionId}' Token expired or unavailable, trying refresh`);
const refreshedToken = await this.refreshToken(token.refreshToken, scopeData, token.sessionId);
if (refreshedToken.accessToken) {
return {
@@ -588,18 +599,13 @@ export class AzureActiveDirectoryService {
//#region refresh logic
private async refreshToken(refreshToken: string, scopeData: IScopeData, sessionId?: string): Promise<IToken> {
this._refreshingPromise = this.doRefreshToken(refreshToken, scopeData, sessionId);
try {
const result = await this._refreshingPromise;
return result;
} finally {
this._refreshingPromise = undefined;
}
private refreshToken(refreshToken: string, scopeData: IScopeData, sessionId?: string): Promise<IToken> {
this._logger.trace(`[${scopeData.scopeStr}] '${sessionId ?? 'new'}' Queued refreshing token`);
return this._sequencer.queue(scopeData.scopeStr, () => this.doRefreshToken(refreshToken, scopeData, sessionId));
}
private async doRefreshToken(refreshToken: string, scopeData: IScopeData, sessionId?: string): Promise<IToken> {
this._logger.info(`Refreshing token for scopes: ${scopeData.scopeStr}`);
this._logger.trace(`[${scopeData.scopeStr}] '${sessionId ?? 'new'}' Refreshing token`);
const postData = new URLSearchParams({
refresh_token: refreshToken,
client_id: scopeData.clientId,
@@ -614,7 +620,7 @@ export class AzureActiveDirectoryService {
this.setSessionTimeout(token.sessionId, token.refreshToken, scopeData, token.expiresIn * AzureActiveDirectoryService.REFRESH_TIMEOUT_MODIFIER);
}
this.setToken(token, scopeData);
this._logger.info(`Token refresh success for scopes: ${token.scope}`);
this._logger.trace(`[${scopeData.scopeStr}] '${token.sessionId}' Token refresh success`);
return token;
} catch (e) {
if (e.message === REFRESH_NETWORK_FAILURE) {
@@ -625,7 +631,7 @@ export class AzureActiveDirectoryService {
}
throw e;
}
this._logger.error(`Refreshing token failed (for scopes: ${scopeData.scopeStr}): ${e.message}`);
this._logger.error(`[${scopeData.scopeStr}] '${sessionId ?? 'new'}' Refreshing token failed: ${e.message}`);
throw e;
}
}
@@ -690,6 +696,7 @@ export class AzureActiveDirectoryService {
const session = await this.exchangeCodeForSession(code, verifier, scopeData);
this._sessionChangeEmitter.fire({ added: [session], removed: [], changed: [] });
this._logger.info(`[${scopeData.scopeStr}] '${session.id}' session successfully created!`);
resolve(session);
} catch (err) {
reject(err);
@@ -705,6 +712,7 @@ export class AzureActiveDirectoryService {
}
private async handleCodeInputBox(inputBox: vscode.InputBox, verifier: string, scopeData: IScopeData): Promise<vscode.AuthenticationSession> {
this._logger.trace(`[${scopeData.scopeStr}] Starting login flow with input box`);
inputBox.ignoreFocusOut = true;
inputBox.title = vscode.l10n.t('Microsoft Authentication');
inputBox.prompt = vscode.l10n.t('Provide the authorization code to complete the sign in flow.');
@@ -716,7 +724,9 @@ export class AzureActiveDirectoryService {
if (code) {
inputBox.dispose();
const session = await this.exchangeCodeForSession(code, verifier, scopeData);
this._logger.trace(`[${scopeData.scopeStr}] '${session.id}' sending session changed event because session was added.`);
this._sessionChangeEmitter.fire({ added: [session], removed: [], changed: [] });
this._logger.trace(`[${scopeData.scopeStr}] '${session.id}' session successfully created!`);
resolve(session);
}
});
@@ -730,7 +740,7 @@ export class AzureActiveDirectoryService {
}
private async exchangeCodeForSession(code: string, codeVerifier: string, scopeData: IScopeData): Promise<vscode.AuthenticationSession> {
this._logger.info(`Exchanging login code for token for scopes: ${scopeData.scopeStr}`);
this._logger.trace(`[${scopeData.scopeStr}] Exchanging login code for session`);
let token: IToken | undefined;
try {
const postData = new URLSearchParams({
@@ -743,10 +753,10 @@ export class AzureActiveDirectoryService {
}).toString();
const json = await this.fetchTokenResponse(postData, scopeData);
this._logger.info(`Exchanging login code for token (for scopes: ${scopeData.scopeStr}) succeeded!`);
this._logger.trace(`[${scopeData.scopeStr}] Exchanging code for token succeeded!`);
token = this.convertToTokenSync(json, scopeData);
} catch (e) {
this._logger.error(`Error exchanging code for token (for scopes ${scopeData.scopeStr}): ${e}`);
this._logger.error(`[${scopeData.scopeStr}] Error exchanging code for token: ${e}`);
throw e;
}
@@ -754,7 +764,7 @@ export class AzureActiveDirectoryService {
this.setSessionTimeout(token.sessionId, token.refreshToken, scopeData, token.expiresIn * AzureActiveDirectoryService.REFRESH_TIMEOUT_MODIFIER);
}
this.setToken(token, scopeData);
this._logger.info(`Login successful for scopes: ${scopeData.scopeStr}`);
this._logger.trace(`[${scopeData.scopeStr}] '${token.sessionId}' Exchanging login code for session succeeded!`);
return await this.convertToSession(token, scopeData);
}
@@ -789,7 +799,7 @@ export class AzureActiveDirectoryService {
if (!result || result.status > 499) {
if (attempts > 3) {
this._logger.error(`Fetching token failed for scopes (${scopeData.scopeStr}): ${result ? await result.text() : errorMessage}`);
this._logger.error(`[${scopeData.scopeStr}] Fetching token failed: ${result ? await result.text() : errorMessage}`);
break;
}
// Exponential backoff
@@ -813,7 +823,7 @@ export class AzureActiveDirectoryService {
//#region storage operations
private setToken(token: IToken, scopeData: IScopeData): void {
this._logger.info(`Setting token for scopes: ${scopeData.scopeStr}`);
this._logger.trace(`[${scopeData.scopeStr}] '${token.sessionId}' Setting token`);
const existingTokenIndex = this._tokens.findIndex(t => t.sessionId === token.sessionId);
if (existingTokenIndex > -1) {
@@ -823,41 +833,18 @@ export class AzureActiveDirectoryService {
}
// Don't await because setting the token is only useful for any new windows that open.
this.storeToken(token, scopeData);
void this.storeToken(token, scopeData);
}
private async storeToken(token: IToken, scopeData: IScopeData): Promise<void> {
if (!vscode.window.state.focused) {
const shouldStore = await new Promise((resolve, _) => {
// To handle the case where the window is not focused for a long time. We want to store the token
// at some point so that the next time they _do_ interact with VS Code, they don't have to sign in again.
const timer = setTimeout(
() => resolve(true),
// 5 hours + random extra 0-30 seconds so that each window doesn't try to store at the same time
(18000000) + Math.floor(Math.random() * 30000)
);
const dispose = vscode.Disposable.from(
vscode.window.onDidChangeWindowState(e => {
if (e.focused) {
resolve(true);
dispose.dispose();
clearTimeout(timer);
}
}),
this._tokenStorage.onDidChangeInOtherWindow(e => {
if (e.updated.includes(token.sessionId)) {
resolve(false);
dispose.dispose();
clearTimeout(timer);
}
})
);
});
if (!shouldStore) {
this._logger.info(`Not storing token for scopes ${scopeData.scopeStr} because it was added in another window`);
return;
if (this._pendingTokensToStore.has(token.sessionId)) {
this._logger.trace(`[${scopeData.scopeStr}] '${token.sessionId}' Window is not focused, replacing token to be stored`);
} else {
this._logger.trace(`[${scopeData.scopeStr}] '${token.sessionId}' Window is not focused, pending storage of token`);
}
this._pendingTokensToStore.set(token.sessionId, token);
return;
}
await this._tokenStorage.store(token.sessionId, {
@@ -867,7 +854,31 @@ export class AzureActiveDirectoryService {
account: token.account,
endpoint: this._env.activeDirectoryEndpointUrl,
});
this._logger.info(`Stored token for scopes: ${scopeData.scopeStr}`);
this._logger.trace(`[${scopeData.scopeStr}] '${token.sessionId}' Stored token`);
}
private async storePendingTokens(): Promise<void> {
if (this._pendingTokensToStore.size === 0) {
this._logger.trace('No pending tokens to store');
return;
}
const tokens = [...this._pendingTokensToStore.values()];
this._pendingTokensToStore.clear();
this._logger.trace(`Storing ${tokens.length} pending tokens...`);
await Promise.allSettled(tokens.map(async token => {
this._logger.trace(`[${token.scope}] '${token.sessionId}' Storing pending token`);
await this._tokenStorage.store(token.sessionId, {
id: token.sessionId,
refreshToken: token.refreshToken,
scope: token.scope,
account: token.account,
endpoint: this._env.activeDirectoryEndpointUrl,
});
this._logger.trace(`[${token.scope}] '${token.sessionId}' Stored pending token`);
}));
this._logger.trace('Done storing pending tokens');
}
private async checkForUpdates(e: IDidChangeInOtherWindowEvent<IStoredSession>): Promise<void> {
@@ -875,7 +886,7 @@ export class AzureActiveDirectoryService {
const session = await this._tokenStorage.get(key);
if (!session) {
this._logger.error('session not found that was apparently just added');
return;
continue;
}
if (!this.sessionMatchesEndpoint(session)) {
@@ -895,36 +906,46 @@ export class AzureActiveDirectoryService {
clientId: this.getClientId(scopes),
tenant: this.getTenantId(scopes),
};
this._logger.info(`Session added in another window with scopes: ${session.scope}`);
this._logger.trace(`[${scopeData.scopeStr}] '${session.id}' Session added in another window`);
const token = await this.refreshToken(session.refreshToken, scopeData, session.id);
this._logger.info(`Sending change event for session that was added with scopes: ${scopeData.scopeStr}`);
this._logger.trace(`[${scopeData.scopeStr}] '${token.sessionId}' Sending change event for session that was added`);
this._sessionChangeEmitter.fire({ added: [this.convertToSessionSync(token)], removed: [], changed: [] });
return;
this._logger.trace(`[${scopeData.scopeStr}] '${token.sessionId}' Session added in another window added here`);
continue;
} catch (e) {
// Network failures will automatically retry on next poll.
if (e.message !== REFRESH_NETWORK_FAILURE) {
vscode.window.showErrorMessage(vscode.l10n.t('You have been signed out because reading stored authentication information failed.'));
await this.removeSessionById(session.id);
}
return;
continue;
}
}
}
for (const { value } of e.removed) {
this._logger.trace(`[${value.scope}] '${value.id}' Session removed in another window`);
if (!this.sessionMatchesEndpoint(value)) {
// If the session wasn't made for this login endpoint, ignore this update
this._logger.trace(`[${value.scope}] '${value.id}' Session doesn't match endpoint. Skipping...`);
continue;
}
this._logger.info(`Session removed in another window with scopes: ${value.scope}`);
await this.removeSessionById(value.id, false);
this._logger.trace(`[${value.scope}] '${value.id}' Session removed in another window removed here`);
}
// NOTE: We don't need to handle changed sessions because all that really would give us is a new refresh token
// because access tokens are not stored in Secret Storage due to their short lifespan. This new refresh token
// is not useful in this window because we really only care about the lifetime of the _access_ token which we
// are already managing (see usages of `setSessionTimeout`).
// However, in order to minimize the amount of times we store tokens, if a token was stored via another window,
// we cancel any pending token storage operations.
for (const sessionId of e.updated) {
if (this._pendingTokensToStore.delete(sessionId)) {
this._logger.trace(`'${sessionId}' Cancelled pending token storage because token was updated in another window`);
}
}
}
private sessionMatchesEndpoint(session: IStoredSession): boolean {
@@ -0,0 +1,49 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Disposable } from 'vscode';
export class SequencerByKey<TKey> {
private promiseMap = new Map<TKey, Promise<unknown>>();
queue<T>(key: TKey, promiseTask: () => Promise<T>): Promise<T> {
const runningPromise = this.promiseMap.get(key) ?? Promise.resolve();
const newPromise = runningPromise
.catch(() => { })
.then(promiseTask)
.finally(() => {
if (this.promiseMap.get(key) === newPromise) {
this.promiseMap.delete(key);
}
});
this.promiseMap.set(key, newPromise);
return newPromise;
}
}
export class IntervalTimer extends Disposable {
private _token: any;
constructor() {
super(() => this.cancel());
this._token = -1;
}
cancel(): void {
if (this._token !== -1) {
clearInterval(this._token);
this._token = -1;
}
}
cancelAndSet(runner: () => void, interval: number): void {
this.cancel();
this._token = setInterval(() => {
runner();
}, interval);
}
}
@@ -72,7 +72,7 @@ async function initMicrosoftSovereignCloudAuthProvider(context: vscode.Extension
scopes: JSON.stringify(scopes.map(s => s.replace(/[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}/i, '{guid}'))),
});
return await aadService.createSession(scopes.sort());
return await aadService.createSession(scopes);
} catch (e) {
/* __GDPR__
"loginFailed" : { "owner": "TylerLeonhardt", "comment": "Used to determine how often users run into issues with the login flow." }
@@ -138,7 +138,7 @@ export async function activate(context: vscode.ExtensionContext) {
scopes: JSON.stringify(scopes.map(s => s.replace(/[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}/i, '{guid}'))),
});
return await loginService.createSession(scopes.sort());
return await loginService.createSession(scopes);
} catch (e) {
/* __GDPR__
"loginFailed" : { "owner": "TylerLeonhardt", "comment": "Used to determine how often users run into issues with the login flow." }
+3 -1
View File
@@ -228,7 +228,9 @@ function onKeypressHandler(e: KeyboardEvent) {
if (e.ctrlKey || e.shiftKey) {
return;
}
if (e.code === 'ArrowDown' || e.code === 'End' || e.code === 'ArrowUp' || e.code === 'Home') {
if (e.code === 'ArrowDown' || e.code === 'ArrowUp' ||
e.code === 'End' || e.code === 'Home' ||
e.code === 'PageUp' || e.code === 'PageDown') {
// These should change the scroll position, not adjust the selected cell in the notebook
e.stopPropagation();
}
+12 -7
View File
@@ -9,7 +9,7 @@
"vscode": "*"
},
"scripts": {
"update-grammar": "node ../node_modules/vscode-grammar-updater/bin textmate/perl.tmbundle Syntaxes/Perl.plist ./syntaxes/perl.tmLanguage.json Syntaxes/Perl%%206.tmLanguage ./syntaxes/perl6.tmLanguage.json"
"update-grammar": "node ../node_modules/vscode-grammar-updater/bin textmate/perl.tmbundle Syntaxes/Perl.plist ./syntaxes/perl.tmLanguage.json Syntaxes/Perl%206.tmLanguage ./syntaxes/perl6.tmLanguage.json"
},
"contributes": {
"languages": [
@@ -31,18 +31,23 @@
"configuration": "./perl.language-configuration.json"
},
{
"id": "perl6",
"id": "raku",
"aliases": [
"Perl 6",
"Raku",
"Perl6",
"perl6"
],
"extensions": [
".raku",
".rakumod",
".rakutest",
".rakudoc",
".nqp",
".p6",
".pl6",
".pm6",
".nqp"
".pm6"
],
"firstLine": "(^#!.*\\bperl6\\b)|use\\s+v6",
"firstLine": "(^#!.*\\bperl6\\b)|use\\s+v6|raku|=begin\\spod|my\\sclass",
"configuration": "./perl6.language-configuration.json"
}
],
@@ -56,7 +61,7 @@
]
},
{
"language": "perl6",
"language": "raku",
"scopeName": "source.perl.6",
"path": "./syntaxes/perl6.tmLanguage.json"
}
@@ -278,18 +278,14 @@
}
],
"colors": {
"editor.background": "#000c18",
"editor.foreground": "#6688cc",
// Base
// "foreground": "",
"focusBorder": "#596F99",
// "contrastActiveBorder": "",
// "contrastBorder": "",
// "widget.shadow": "",
"input.background": "#181f2f",
// "input.border": "",
// "input.foreground": "",
@@ -300,17 +296,13 @@
"inputValidation.warningBorder": "#5B7E7A",
"inputValidation.errorBackground": "#A22D44",
"inputValidation.errorBorder": "#AB395B",
"badge.background": "#0063a5",
"progressBar.background": "#0063a5",
"dropdown.background": "#181f2f",
// "dropdown.foreground": "",
// "dropdown.border": "",
"button.background": "#2B3C5D",
// "button.foreground": "",
"list.activeSelectionBackground": "#08286b",
// "list.activeSelectionForeground": "",
"quickInputList.focusBackground": "#08286b",
@@ -318,12 +310,10 @@
"list.inactiveSelectionBackground": "#152037",
"list.dropBackground": "#041D52",
"list.highlightForeground": "#0063a5",
"scrollbar.shadow": "#515E91AA",
"scrollbarSlider.activeBackground": "#3B3F5188",
"scrollbarSlider.background": "#1F2230AA",
"scrollbarSlider.hoverBackground": "#3B3F5188",
// Editor
"editorWidget.background": "#262641",
"editorCursor.foreground": "#ddbb88",
@@ -350,14 +340,12 @@
// "editor.selectionHighlightBackground": "",
// "editor.wordHighlightBackground": "",
// "editor.wordHighlightStrongBackground": "",
// Editor: Suggest Widget
// "editorSuggestWidget.background": "",
// "editorSuggestWidget.border": "",
// "editorSuggestWidget.foreground": "",
// "editorSuggestWidget.highlightForeground": "",
// "editorSuggestWidget.selectedBackground": "",
// Editor: Peek View
"peekViewResult.background": "#060621",
// "peekViewResult.lineForeground": "",
@@ -371,7 +359,6 @@
"peekViewResult.matchHighlightBackground": "#eeeeee44",
// "peekViewTitleLabel.foreground": "",
// "peekViewTitleDescription.foreground": "",
// Ports
"ports.iconRunningProcessForeground": "#80a2c2",
// Editor: Diff
@@ -379,23 +366,18 @@
// "diffEditor.insertedTextBorder": "",
"diffEditor.removedTextBackground": "#892F4688",
// "diffEditor.removedTextBorder": "",
// Editor: Minimap
"minimap.selectionHighlight": "#750000",
// Workbench: Title
"titleBar.activeBackground": "#10192c",
// "titleBar.activeForeground": "",
// "titleBar.inactiveBackground": "",
// "titleBar.inactiveForeground": "",
// Workbench: Editors
// "editorGroupHeader.noTabsBackground": "",
"editorGroup.border": "#2b2b4a",
"editorGroup.dropBackground": "#25375daa",
"editorGroupHeader.tabsBackground": "#1c1c2a",
// Workbench: Tabs
"tab.border": "#2b2b4a",
// "tab.activeBackground": "",
@@ -403,26 +385,21 @@
// "tab.activeForeground": "",
// "tab.inactiveForeground": "",
"tab.lastPinnedBorder": "#2b3c5d",
// Workbench: Activity Bar
"activityBar.background": "#051336",
// "activityBar.foreground": "",
// "activityBarBadge.background": "",
// "activityBarBadge.foreground": "",
"activityBarItem.profilesBackground": "#082877",
// Workbench: Panel
// "panel.background": "",
"panel.border": "#2b2b4a",
// "panelTitle.activeBorder": "",
// "panelTitle.activeForeground": "",
// "panelTitle.inactiveForeground": "",
// Workbench: Side Bar
"sideBar.background": "#060621",
// "sideBarTitle.foreground": "",
"sideBarSectionHeader.background": "#10192c",
// Workbench: Status Bar
"statusBar.background": "#10192c",
"statusBar.noFolderBackground": "#10192c",
@@ -433,20 +410,16 @@
"statusBarItem.prominentHoverBackground": "#0063a5dd",
// "statusBarItem.activeBackground": "",
// "statusBarItem.hoverBackground": "",
// Workbench: Debug
"debugToolBar.background": "#051336",
"debugExceptionWidget.background": "#051336",
"debugExceptionWidget.border": "#AB395B",
// Workbench: Quick Open
"pickerGroup.border": "#596F99",
"pickerGroup.foreground": "#596F99",
// Workbench: Extensions
"extensionButton.prominentBackground": "#5f8b3b",
"extensionButton.prominentHoverBackground": "#5f8b3bbb",
// Workbench: Terminal
"terminal.ansiBlack": "#111111",
"terminal.ansiRed": "#ff9da4",
@@ -77,6 +77,7 @@
"source.cpp keyword.operator.new",
"keyword.operator.delete",
"keyword.other.using",
"keyword.other.directive.using",
"keyword.other.operator",
"entity.name.operator"
],
@@ -406,6 +406,7 @@
"source.cpp keyword.operator.new",
"source.cpp keyword.operator.delete",
"keyword.other.using",
"keyword.other.directive.using",
"keyword.other.operator"
],
"settings": {
@@ -442,6 +442,7 @@
"source.cpp keyword.operator.new",
"source.cpp keyword.operator.delete",
"keyword.other.using",
"keyword.other.directive.using",
"keyword.other.operator",
"entity.name.operator"
],
@@ -77,6 +77,7 @@
"source.cpp keyword.operator.new",
"source.cpp keyword.operator.delete",
"keyword.other.using",
"keyword.other.directive.using",
"keyword.other.operator",
"entity.name.operator"
],
@@ -32,7 +32,6 @@
"ports.iconRunningProcessForeground": "#369432",
"activityBar.background": "#221a0f",
"activityBar.foreground": "#d3af86",
"activityBarItem.profilesBackground": "#47351d",
"sideBar.background": "#362712",
"menu.background": "#362712",
"menu.foreground": "#CCCCCC",
@@ -124,6 +123,7 @@
"keyword.operator.new.cpp",
"keyword.operator.delete.cpp",
"keyword.other.using",
"keyword.other.directive.using",
"keyword.other.operator"
],
"settings": {
@@ -269,6 +269,7 @@
"keyword.operator.new.cpp",
"keyword.operator.delete.cpp",
"keyword.other.using",
"keyword.other.directive.using",
"keyword.other.operator"
],
"settings": {
@@ -36,7 +36,6 @@
"statusBar.noFolderBackground": "#001126",
"statusBar.debuggingBackground": "#001126",
"activityBar.background": "#001733",
"activityBarItem.profilesBackground": "#003271",
"progressBar.background": "#bbdaffcc",
"badge.background": "#bbdaffcc",
"badge.foreground": "#001733",
+36 -3
View File
@@ -67,7 +67,7 @@ export async function activate(context: vscode.ExtensionContext) {
}
const logger = new Logger(vscode.l10n.t('Port Forwarding'));
const provider = new TunnelProvider(logger);
const provider = new TunnelProvider(logger, context);
context.subscriptions.push(
vscode.commands.registerCommand('tunnel-forwarding.showLog', () => logger.show()),
@@ -120,6 +120,8 @@ class Logger {
}
}
const didWarnPublicKey = 'didWarnPublic';
class TunnelProvider implements vscode.TunnelProvider {
private readonly tunnels = new Set<Tunnel>();
private readonly stateChange = new vscode.EventEmitter<StateT>();
@@ -136,10 +138,16 @@ class TunnelProvider implements vscode.TunnelProvider {
public readonly onDidStateChange = this.stateChange.event;
constructor(private readonly logger: Logger) { }
constructor(private readonly logger: Logger, private readonly context: vscode.ExtensionContext) { }
/** @inheritdoc */
public async provideTunnel(tunnelOptions: vscode.TunnelOptions): Promise<vscode.Tunnel> {
public async provideTunnel(tunnelOptions: vscode.TunnelOptions): Promise<vscode.Tunnel | undefined> {
if (tunnelOptions.privacy === TunnelPrivacyId.Public) {
if (!(await this.consentPublicPort(tunnelOptions.remoteAddress.port))) {
return;
}
}
const tunnel = new Tunnel(
tunnelOptions.remoteAddress,
(tunnelOptions.privacy as TunnelPrivacyId) || TunnelPrivacyId.Private,
@@ -184,6 +192,31 @@ class TunnelProvider implements vscode.TunnelProvider {
this.updateActivePortsIfRunning();
}
private async consentPublicPort(portNumber: number) {
const didWarn = this.context.globalState.get(didWarnPublicKey, false);
if (didWarn) {
return true;
}
const continueOpt = vscode.l10n.t('Continue');
const dontShowAgain = vscode.l10n.t("Don't show again");
const r = await vscode.window.showWarningMessage(
vscode.l10n.t("You're about to create a publicly forwarded port. Anyone on the internet will be able to connect to the service listening on port {0}. You should only proceed if this service is secure and non-sensitive.", portNumber),
{ modal: true },
continueOpt,
dontShowAgain,
);
if (r === continueOpt) {
// continue
} else if (r === dontShowAgain) {
await this.context.globalState.update(didWarnPublicKey, true);
} else {
return false;
}
return true;
}
private isInStateWithProcess(process: ChildProcessWithoutNullStreams) {
return (
(this.state.state === State.Starting || this.state.state === State.Active) &&
@@ -21,7 +21,8 @@
"restrictedConfigurations": [
"typescript.tsdk",
"typescript.tsserver.pluginPaths",
"typescript.npm"
"typescript.npm",
"typescript.tsserver.nodePath"
]
}
},
@@ -1132,7 +1133,7 @@
"typescript.tsserver.maxTsServerMemory": {
"type": "number",
"default": 3072,
"description": "%configuration.tsserver.maxTsServerMemory%",
"markdownDescription": "%configuration.tsserver.maxTsServerMemory%",
"scope": "window"
},
"typescript.tsserver.experimental.enableProjectDiagnostics": {
@@ -1251,6 +1252,11 @@
"description": "%configuration.tsserver.web.projectWideIntellisense.suppressSemanticErrors%",
"scope": "window"
},
"typescript.tsserver.nodePath": {
"type": "string",
"description": "%configuration.tsserver.nodePath%",
"scope": "window"
},
"typescript.experimental.tsserver.web.typeAcquisition.enabled": {
"type": "boolean",
"default": false,
@@ -70,7 +70,7 @@
"configuration.tsserver.useSyntaxServer.always": "Use a lighter weight syntax server to handle all IntelliSense operations. This syntax server can only provide IntelliSense for opened files.",
"configuration.tsserver.useSyntaxServer.never": "Don't use a dedicated syntax server. Use a single server to handle all IntelliSense operations.",
"configuration.tsserver.useSyntaxServer.auto": "Spawn both a full server and a lighter weight server dedicated to syntax operations. The syntax server is used to speed up syntax operations and provide IntelliSense while projects are loading.",
"configuration.tsserver.maxTsServerMemory": "The maximum amount of memory (in MB) to allocate to the TypeScript server process.",
"configuration.tsserver.maxTsServerMemory": "The maximum amount of memory (in MB) to allocate to the TypeScript server process. To use a memory limit greater than 4 GB, use `#typescript.tsserver.nodePath#` to run TS Server with a custom Node installation.",
"configuration.tsserver.experimental.enableProjectDiagnostics": "(Experimental) Enables project wide error reporting.",
"typescript.locale": "Sets the locale used to report JavaScript and TypeScript errors. Defaults to use VS Code's locale.",
"configuration.implicitProjectConfig.module": "Sets the module system for the program. See more: https://www.typescriptlang.org/tsconfig#module.",
@@ -213,6 +213,7 @@
"configuration.suggest.objectLiteralMethodSnippets.enabled": "Enable/disable snippet completions for methods in object literals. Requires using TypeScript 4.7+ in the workspace.",
"configuration.tsserver.web.projectWideIntellisense.enabled": "Enable/disable project-wide IntelliSense on web. Requires that VS Code is running in a trusted context.",
"configuration.tsserver.web.projectWideIntellisense.suppressSemanticErrors": "Suppresses semantic errors. This is needed when using external packages as these can't be included analyzed on web.",
"configuration.tsserver.nodePath": "Run TS Server on a custom Node installation. This can be a path to a Node executable, or 'node' if you want VS Code to detect a Node installation.",
"configuration.experimental.tsserver.web.typeAcquisition.enabled": "Enable/disable package acquisition on the web.",
"walkthroughs.nodejsWelcome.title": "Get started with JavaScript and Node.js",
"walkthroughs.nodejsWelcome.description": "Make the most of Visual Studio Code's first-class JavaScript experience.",
@@ -16,4 +16,13 @@ export class BrowserServiceConfigurationProvider extends BaseServiceConfiguratio
protected readLocalTsdk(_configuration: vscode.WorkspaceConfiguration): string | null {
return null;
}
// On browsers, we don't run TSServer on Node
protected readLocalNodePath(_configuration: vscode.WorkspaceConfiguration): string | null {
return null;
}
protected override readGlobalNodePath(_configuration: vscode.WorkspaceConfiguration): string | null {
return null;
}
}
@@ -6,7 +6,10 @@
import * as os from 'os';
import * as path from 'path';
import * as vscode from 'vscode';
import * as child_process from 'child_process';
import * as fs from 'fs';
import { BaseServiceConfigurationProvider } from './configuration';
import { RelativeWorkspacePathResolver } from '../utils/relativePathResolver';
export class ElectronServiceConfigurationProvider extends BaseServiceConfigurationProvider {
@@ -35,4 +38,65 @@ export class ElectronServiceConfigurationProvider extends BaseServiceConfigurati
}
return null;
}
protected readLocalNodePath(configuration: vscode.WorkspaceConfiguration): string | null {
return this.validatePath(this.readLocalNodePathWorker(configuration));
}
private readLocalNodePathWorker(configuration: vscode.WorkspaceConfiguration): string | null {
const inspect = configuration.inspect('typescript.tsserver.nodePath');
if (inspect?.workspaceValue && typeof inspect.workspaceValue === 'string') {
if (inspect.workspaceValue === 'node') {
return this.findNodePath();
}
const fixedPath = this.fixPathPrefixes(inspect.workspaceValue);
if (!path.isAbsolute(fixedPath)) {
const workspacePath = RelativeWorkspacePathResolver.asAbsoluteWorkspacePath(fixedPath);
return workspacePath || null;
}
return fixedPath;
}
return null;
}
protected readGlobalNodePath(configuration: vscode.WorkspaceConfiguration): string | null {
return this.validatePath(this.readGlobalNodePathWorker(configuration));
}
private readGlobalNodePathWorker(configuration: vscode.WorkspaceConfiguration): string | null {
const inspect = configuration.inspect('typescript.tsserver.nodePath');
if (inspect?.globalValue && typeof inspect.globalValue === 'string') {
if (inspect.globalValue === 'node') {
return this.findNodePath();
}
const fixedPath = this.fixPathPrefixes(inspect.globalValue);
if (path.isAbsolute(fixedPath)) {
return fixedPath;
}
}
return null;
}
private findNodePath(): string | null {
try {
const out = child_process.execFileSync('node', ['-e', 'console.log(process.execPath)'], {
windowsHide: true,
timeout: 2000,
cwd: vscode.workspace.workspaceFolders?.[0].uri.fsPath,
encoding: 'utf-8',
});
return out.trim();
} catch (error) {
vscode.window.showWarningMessage(vscode.l10n.t("Could not detect a Node installation to run TS Server."));
return null;
}
}
private validatePath(nodePath: string | null): string | null {
if (nodePath && (!fs.existsSync(nodePath) || fs.lstatSync(nodePath).isDirectory())) {
vscode.window.showWarningMessage(vscode.l10n.t("The path {0} doesn\'t point to a valid Node installation to run TS Server. Falling back to bundled Node.", nodePath));
return null;
}
return nodePath;
}
}
@@ -120,6 +120,8 @@ export interface TypeScriptServiceConfiguration {
readonly watchOptions: Proto.WatchOptions | undefined;
readonly includePackageJsonAutoImports: 'auto' | 'on' | 'off' | undefined;
readonly enableTsServerTracing: boolean;
readonly localNodePath: string | null;
readonly globalNodePath: string | null;
}
export function areServiceConfigurationsEqual(a: TypeScriptServiceConfiguration, b: TypeScriptServiceConfiguration): boolean {
@@ -154,11 +156,15 @@ export abstract class BaseServiceConfigurationProvider implements ServiceConfigu
watchOptions: this.readWatchOptions(configuration),
includePackageJsonAutoImports: this.readIncludePackageJsonAutoImports(configuration),
enableTsServerTracing: this.readEnableTsServerTracing(configuration),
localNodePath: this.readLocalNodePath(configuration),
globalNodePath: this.readGlobalNodePath(configuration),
};
}
protected abstract readGlobalTsdk(configuration: vscode.WorkspaceConfiguration): string | null;
protected abstract readLocalTsdk(configuration: vscode.WorkspaceConfiguration): string | null;
protected abstract readLocalNodePath(configuration: vscode.WorkspaceConfiguration): string | null;
protected abstract readGlobalNodePath(configuration: vscode.WorkspaceConfiguration): string | null;
protected readTsServerLogLevel(configuration: vscode.WorkspaceConfiguration): TsServerLogLevel {
const setting = configuration.get<string>('typescript.tsserver.log', 'off');
@@ -0,0 +1,149 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import { TypeScriptServiceConfiguration } from '../configuration/configuration';
import { setImmediate } from '../utils/async';
import { Disposable } from '../utils/dispose';
const useWorkspaceNodeStorageKey = 'typescript.useWorkspaceNode';
const lastKnownWorkspaceNodeStorageKey = 'typescript.lastKnownWorkspaceNode';
type UseWorkspaceNodeState = undefined | boolean;
type LastKnownWorkspaceNodeState = undefined | string;
export class NodeVersionManager extends Disposable {
private _currentVersion: string | undefined;
public constructor(
private configuration: TypeScriptServiceConfiguration,
private readonly workspaceState: vscode.Memento
) {
super();
this._currentVersion = this.configuration.globalNodePath || undefined;
if (vscode.workspace.isTrusted) {
const workspaceVersion = this.configuration.localNodePath;
if (workspaceVersion) {
const useWorkspaceNode = this.canUseWorkspaceNode(workspaceVersion);
if (useWorkspaceNode === undefined) {
setImmediate(() => {
this.promptAndSetWorkspaceNode();
});
}
else if (useWorkspaceNode) {
this._currentVersion = workspaceVersion;
}
}
}
else {
this._disposables.push(vscode.workspace.onDidGrantWorkspaceTrust(() => {
const workspaceVersion = this.configuration.localNodePath;
if (workspaceVersion) {
const useWorkspaceNode = this.canUseWorkspaceNode(workspaceVersion);
if (useWorkspaceNode === undefined) {
setImmediate(() => {
this.promptAndSetWorkspaceNode();
});
}
else if (useWorkspaceNode) {
this.updateActiveVersion(workspaceVersion);
}
}
}));
}
}
private readonly _onDidPickNewVersion = this._register(new vscode.EventEmitter<void>());
public readonly onDidPickNewVersion = this._onDidPickNewVersion.event;
public get currentVersion(): string | undefined {
return this._currentVersion;
}
public async updateConfiguration(nextConfiguration: TypeScriptServiceConfiguration) {
const oldConfiguration = this.configuration;
this.configuration = nextConfiguration;
if (oldConfiguration.globalNodePath !== nextConfiguration.globalNodePath
|| oldConfiguration.localNodePath !== nextConfiguration.localNodePath) {
await this.computeNewVersion();
}
}
private async computeNewVersion() {
let version = this.configuration.globalNodePath || undefined;
const workspaceVersion = this.configuration.localNodePath;
if (vscode.workspace.isTrusted && workspaceVersion) {
const useWorkspaceNode = this.canUseWorkspaceNode(workspaceVersion);
if (useWorkspaceNode === undefined) {
version = await this.promptUseWorkspaceNode() || version;
}
else if (useWorkspaceNode) {
version = workspaceVersion;
}
}
this.updateActiveVersion(version);
}
private async promptUseWorkspaceNode(): Promise<string | undefined> {
const workspaceVersion = this.configuration.localNodePath;
if (workspaceVersion === null) {
throw new Error('Could not prompt to use workspace Node installation because no workspace Node installation is specified');
}
const allow = vscode.l10n.t("Yes");
const disallow = vscode.l10n.t("No");
const dismiss = vscode.l10n.t("Not now");
const result = await vscode.window.showInformationMessage(vscode.l10n.t("This workspace wants to use the Node installation at '{0}' to run TS Server. Would you like to use it?", workspaceVersion),
allow,
disallow,
dismiss,
);
let version = undefined;
switch (result) {
case allow:
await this.setUseWorkspaceNodeState(true, workspaceVersion);
version = workspaceVersion;
break;
case disallow:
await this.setUseWorkspaceNodeState(false, workspaceVersion);
break;
case dismiss:
await this.setUseWorkspaceNodeState(undefined, workspaceVersion);
break;
}
return version;
}
private async promptAndSetWorkspaceNode(): Promise<void> {
const version = await this.promptUseWorkspaceNode();
if (version !== undefined) {
this.updateActiveVersion(version);
}
}
private updateActiveVersion(pickedVersion: string | undefined): void {
const oldVersion = this.currentVersion;
this._currentVersion = pickedVersion;
if (oldVersion !== pickedVersion) {
this._onDidPickNewVersion.fire();
}
}
private canUseWorkspaceNode(nodeVersion: string): boolean | undefined {
const lastKnownWorkspaceNode = this.workspaceState.get<LastKnownWorkspaceNodeState>(lastKnownWorkspaceNodeStorageKey);
if (lastKnownWorkspaceNode === nodeVersion) {
return this.workspaceState.get<UseWorkspaceNodeState>(useWorkspaceNodeStorageKey);
}
return undefined;
}
private async setUseWorkspaceNodeState(allow: boolean | undefined, nodeVersion: string) {
await this.workspaceState.update(lastKnownWorkspaceNodeStorageKey, nodeVersion);
await this.workspaceState.update(useWorkspaceNodeStorageKey, allow);
}
}
@@ -19,6 +19,7 @@ import type * as Proto from './protocol/protocol';
import { EventName } from './protocol/protocol.const';
import { TypeScriptVersionManager } from './versionManager';
import { TypeScriptVersion } from './versionProvider';
import { NodeVersionManager } from './nodeManager';
export enum ExecutionTarget {
Semantic,
@@ -70,6 +71,7 @@ export interface TsServerProcessFactory {
kind: TsServerProcessKind,
configuration: TypeScriptServiceConfiguration,
versionManager: TypeScriptVersionManager,
nodeVersionManager: NodeVersionManager,
tsServerLog: TsServerLog | undefined,
): TsServerProcess;
}
@@ -13,6 +13,7 @@ import type * as Proto from './protocol/protocol';
import { TsServerLog, TsServerProcess, TsServerProcessFactory, TsServerProcessKind } from './server';
import { TypeScriptVersionManager } from './versionManager';
import { TypeScriptVersion } from './versionProvider';
import { NodeVersionManager } from './nodeManager';
type BrowserWatchEvent = {
type: 'watchDirectory' | 'watchFile';
@@ -40,6 +41,7 @@ export class WorkerServerProcessFactory implements TsServerProcessFactory {
kind: TsServerProcessKind,
_configuration: TypeScriptServiceConfiguration,
_versionManager: TypeScriptVersionManager,
_nodeVersionManager: NodeVersionManager,
tsServerLog: TsServerLog | undefined,
) {
const tsServerPath = version.tsServerPath;
@@ -15,6 +15,7 @@ import type * as Proto from './protocol/protocol';
import { TsServerLog, TsServerProcess, TsServerProcessFactory, TsServerProcessKind } from './server';
import { TypeScriptVersionManager } from './versionManager';
import { TypeScriptVersion } from './versionProvider';
import { NodeVersionManager } from './nodeManager';
const defaultSize: number = 8192;
@@ -134,10 +135,12 @@ class Reader<T> extends Disposable {
}
}
function generatePatchedEnv(env: any, modulePath: string): any {
function generatePatchedEnv(env: any, modulePath: string, hasExecPath: boolean): any {
const newEnv = Object.assign({}, env);
newEnv['ELECTRON_RUN_AS_NODE'] = '1';
if (!hasExecPath) {
newEnv['ELECTRON_RUN_AS_NODE'] = '1';
}
newEnv['NODE_PATH'] = path.join(modulePath, '..', '..', '..');
// Ensure we always have a PATH set
@@ -253,6 +256,7 @@ export class ElectronServiceProcessFactory implements TsServerProcessFactory {
kind: TsServerProcessKind,
configuration: TypeScriptServiceConfiguration,
versionManager: TypeScriptVersionManager,
nodeVersionManager: NodeVersionManager,
_tsserverLog: TsServerLog | undefined,
): TsServerProcess {
let tsServerPath = version.tsServerPath;
@@ -263,20 +267,30 @@ export class ElectronServiceProcessFactory implements TsServerProcessFactory {
tsServerPath = versionManager.currentVersion.tsServerPath;
}
const useIpc = version.apiVersion?.gte(API.v460);
const execPath = nodeVersionManager.currentVersion;
const env = generatePatchedEnv(process.env, tsServerPath, !!execPath);
const runtimeArgs = [...args];
const execArgv = getExecArgv(kind, configuration);
const useIpc = !execPath && version.apiVersion?.gte(API.v460);
if (useIpc) {
runtimeArgs.push('--useNodeIpc');
}
const childProcess = child_process.fork(tsServerPath, runtimeArgs, {
silent: true,
cwd: undefined,
env: generatePatchedEnv(process.env, tsServerPath),
execArgv: getExecArgv(kind, configuration),
stdio: useIpc ? ['pipe', 'pipe', 'pipe', 'ipc'] : undefined,
});
const childProcess = execPath ?
child_process.spawn(execPath, [...execArgv, tsServerPath, ...runtimeArgs], {
shell: true,
windowsHide: true,
cwd: undefined,
env,
}) :
child_process.fork(tsServerPath, runtimeArgs, {
silent: true,
cwd: undefined,
env,
execArgv,
stdio: useIpc ? ['pipe', 'pipe', 'pipe', 'ipc'] : undefined,
});
return useIpc ? new IpcChildServerProcess(childProcess) : new StdioChildServerProcess(childProcess);
}
@@ -19,6 +19,7 @@ import { PluginManager } from './plugins';
import { GetErrRoutingTsServer, ITypeScriptServer, SingleTsServer, SyntaxRoutingTsServer, TsServerDelegate, TsServerLog, TsServerProcessFactory, TsServerProcessKind } from './server';
import { TypeScriptVersionManager } from './versionManager';
import { ITypeScriptVersionProvider, TypeScriptVersion } from './versionProvider';
import { NodeVersionManager } from './nodeManager';
const enum CompositeServerType {
/** Run a single server that handles all commands */
@@ -44,6 +45,7 @@ export class TypeScriptServerSpawner {
public constructor(
private readonly _versionProvider: ITypeScriptVersionProvider,
private readonly _versionManager: TypeScriptVersionManager,
private readonly _nodeVersionManager: NodeVersionManager,
private readonly _logDirectoryProvider: ILogDirectoryProvider,
private readonly _pluginPathsProvider: TypeScriptPluginPathsProvider,
private readonly _logger: Logger,
@@ -160,7 +162,7 @@ export class TypeScriptServerSpawner {
}
this._logger.info(`<${kind}> Forking...`);
const process = this._factory.fork(version, args, kind, configuration, this._versionManager, tsServerLog);
const process = this._factory.fork(version, args, kind, configuration, this._versionManager, this._nodeVersionManager, tsServerLog);
this._logger.info(`<${kind}> Starting...`);
return new SingleTsServer(
@@ -30,6 +30,7 @@ import { TelemetryProperties, TelemetryReporter, VSCodeTelemetryReporter } from
import Tracer from './logging/tracer';
import { ProjectType, inferredProjectCompilerOptions } from './tsconfig';
import { Schemes } from './configuration/schemes';
import { NodeVersionManager } from './tsServer/nodeManager';
export interface TsDiagnostics {
@@ -103,6 +104,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType
private _configuration: TypeScriptServiceConfiguration;
private readonly pluginPathsProvider: TypeScriptPluginPathsProvider;
private readonly _versionManager: TypeScriptVersionManager;
private readonly _nodeVersionManager: NodeVersionManager;
private readonly logger: Logger;
private readonly tracer: Tracer;
@@ -173,6 +175,11 @@ export default class TypeScriptServiceClient extends Disposable implements IType
this.restartTsServer();
}));
this._nodeVersionManager = this._register(new NodeVersionManager(this._configuration, context.workspaceState));
this._register(this._nodeVersionManager.onDidPickNewVersion(() => {
this.restartTsServer();
}));
this.bufferSyncSupport = new BufferSyncSupport(this, allModeIds, onCaseInsenitiveFileSystem);
this.onReady(() => { this.bufferSyncSupport.listen(); });
@@ -192,6 +199,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType
this.versionProvider.updateConfiguration(this._configuration);
this._versionManager.updateConfiguration(this._configuration);
this.pluginPathsProvider.updateConfiguration(this._configuration);
this._nodeVersionManager.updateConfiguration(this._configuration);
if (this.serverState.type === ServerState.Type.Running) {
if (!this._configuration.implicitProjectConfiguration.isEqualTo(oldConfiguration.implicitProjectConfiguration)) {
@@ -212,8 +220,9 @@ export default class TypeScriptServiceClient extends Disposable implements IType
}
return this.apiVersion.fullVersionString;
});
this.diagnosticsManager = new DiagnosticsManager('typescript', this._configuration, this.telemetryReporter, onCaseInsenitiveFileSystem);
this.typescriptServerSpawner = new TypeScriptServerSpawner(this.versionProvider, this._versionManager, this.logDirectoryProvider, this.pluginPathsProvider, this.logger, this.telemetryReporter, this.tracer, this.processFactory);
this.typescriptServerSpawner = new TypeScriptServerSpawner(this.versionProvider, this._versionManager, this._nodeVersionManager, this.logDirectoryProvider, this.pluginPathsProvider, this.logger, this.telemetryReporter, this.tracer, this.processFactory);
this._register(this.pluginManager.onDidUpdateConfig(update => {
this.configurePlugin(update.pluginId, update.config);
@@ -387,6 +396,10 @@ export default class TypeScriptServiceClient extends Disposable implements IType
}
this.info(`Using tsserver from: ${version.path}`);
const nodePath = this._nodeVersionManager.currentVersion;
if (nodePath) {
this.info(`Using Node installation from ${nodePath} to run TS Server`);
}
const apiVersion = version.apiVersion || API.defaultVersion;
const mytoken = ++this.token;
+1 -1
View File
@@ -9,7 +9,7 @@
"vscode": "*"
},
"scripts": {
"update-grammar": "node ../node_modules/vscode-grammar-updater/bin textmate/asp.vb.net.tmbundle Syntaxes/ASP%%20VB.net.plist ./syntaxes/asp-vb-net.tmlanguage.json"
"update-grammar": "node ../node_modules/vscode-grammar-updater/bin textmate/asp.vb.net.tmbundle Syntaxes/ASP%20VB.net.plist ./syntaxes/asp-vb-net.tmlanguage.json"
},
"contributes": {
"languages": [
@@ -17,7 +17,7 @@
"vscode:prepublish": "node ../../node_modules/gulp/bin/gulp.js --gulpfile ../../build/gulpfile.extensions.js compile-extension:vscode-colorize-tests ./tsconfig.json"
},
"dependencies": {
"jsonc-parser": "2.2.1"
"jsonc-parser": "^3.2.0"
},
"devDependencies": {
"@types/node": "18.x"
@@ -0,0 +1,27 @@
# Example taken from https://en.wikipedia.org/wiki/Raku_(programming_language)
class Point is rw {
has $.x;
has $.y;
method distance( Point $p ) {
sqrt(($!x - $p.x) ** 2 + ($!y - $p.y) ** 2)
}
method distance-to-center {
self.distance: Point.new(x => 0, y => 0)
}
}
my $point = Point.new( x => 1.2, y => -3.7 );
say "Point's location: (", $point.x, ', ', $point.y, ')';
# OUTPUT: Point's location: (1.2, -3.7)
# Changing x and y (note methods "x" and "y" used as lvalues):
$point.x = 3;
$point.y = 4;
say "Point's location: (", $point.x, ', ', $point.y, ')';
# OUTPUT: Point's location: (3, 4)
my $other-point = Point.new(x => -5, y => 10);
$point.distance($other-point); #=> 10
$point.distance-to-center; #=> 5
@@ -1,21 +1,7 @@
[
{
"c": "%",
"t": "text.bibtex comment.line.percentage.bibtex punctuation.definition.comment.bibtex",
"r": {
"dark_plus": "comment: #6A9955",
"light_plus": "comment: #008000",
"dark_vs": "comment: #6A9955",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668",
"dark_modern": "comment: #6A9955",
"hc_light": "comment: #515151",
"light_modern": "comment: #008000"
}
},
{
"c": " a sample bibliography file",
"t": "text.bibtex comment.line.percentage.bibtex",
"c": "% a sample bibliography file",
"t": "text.bibtex comment.block.bibtex",
"r": {
"dark_plus": "comment: #6A9955",
"light_plus": "comment: #008000",
@@ -29,7 +15,7 @@
},
{
"c": "%",
"t": "text.bibtex comment.line.percentage.bibtex punctuation.definition.comment.bibtex",
"t": "text.bibtex comment.block.bibtex",
"r": {
"dark_plus": "comment: #6A9955",
"light_plus": "comment: #008000",
@@ -1386,8 +1372,8 @@
}
},
{
"c": "%",
"t": "text.bibtex comment.line.percentage.bibtex punctuation.definition.comment.bibtex",
"c": "% The authors mentioned here are almost, but not quite,",
"t": "text.bibtex comment.block.bibtex",
"r": {
"dark_plus": "comment: #6A9955",
"light_plus": "comment: #008000",
@@ -1400,36 +1386,8 @@
}
},
{
"c": " The authors mentioned here are almost, but not quite,",
"t": "text.bibtex comment.line.percentage.bibtex",
"r": {
"dark_plus": "comment: #6A9955",
"light_plus": "comment: #008000",
"dark_vs": "comment: #6A9955",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668",
"dark_modern": "comment: #6A9955",
"hc_light": "comment: #515151",
"light_modern": "comment: #008000"
}
},
{
"c": "%",
"t": "text.bibtex comment.line.percentage.bibtex punctuation.definition.comment.bibtex",
"r": {
"dark_plus": "comment: #6A9955",
"light_plus": "comment: #008000",
"dark_vs": "comment: #6A9955",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668",
"dark_modern": "comment: #6A9955",
"hc_light": "comment: #515151",
"light_modern": "comment: #008000"
}
},
{
"c": " entirely unrelated to Matt Groening.",
"t": "text.bibtex comment.line.percentage.bibtex",
"c": "% entirely unrelated to Matt Groening.",
"t": "text.bibtex comment.block.bibtex",
"r": {
"dark_plus": "comment: #6A9955",
"light_plus": "comment: #008000",
@@ -1,16 +1,16 @@
[
{
"c": "using",
"t": "source.cs keyword.other.using.cs",
"t": "source.cs keyword.other.directive.using.cs",
"r": {
"dark_plus": "keyword.other.using: #C586C0",
"light_plus": "keyword.other.using: #AF00DB",
"dark_plus": "keyword.other.directive.using: #C586C0",
"light_plus": "keyword.other.directive.using: #AF00DB",
"dark_vs": "keyword: #569CD6",
"light_vs": "keyword: #0000FF",
"hc_black": "keyword.other.using: #C586C0",
"dark_modern": "keyword.other.using: #C586C0",
"hc_light": "keyword.other.using: #B5200D",
"light_modern": "keyword.other.using: #AF00DB"
"hc_black": "keyword.other.directive.using: #C586C0",
"dark_modern": "keyword.other.directive.using: #C586C0",
"hc_light": "keyword.other.directive.using: #B5200D",
"light_modern": "keyword.other.directive.using: #AF00DB"
}
},
{
@@ -57,16 +57,16 @@
},
{
"c": "namespace",
"t": "source.cs keyword.other.namespace.cs",
"t": "source.cs storage.type.namespace.cs",
"r": {
"dark_plus": "keyword: #569CD6",
"light_plus": "keyword: #0000FF",
"dark_vs": "keyword: #569CD6",
"light_vs": "keyword: #0000FF",
"hc_black": "keyword: #569CD6",
"dark_modern": "keyword: #569CD6",
"hc_light": "keyword: #0F4A85",
"light_modern": "keyword: #0000FF"
"dark_plus": "storage.type: #569CD6",
"light_plus": "storage.type: #0000FF",
"dark_vs": "storage.type: #569CD6",
"light_vs": "storage.type: #0000FF",
"hc_black": "storage.type: #569CD6",
"dark_modern": "storage.type: #569CD6",
"hc_light": "storage.type: #0F4A85",
"light_modern": "storage.type: #0000FF"
}
},
{
@@ -127,16 +127,16 @@
},
{
"c": "class",
"t": "source.cs keyword.other.class.cs",
"t": "source.cs storage.type.class.cs",
"r": {
"dark_plus": "keyword: #569CD6",
"light_plus": "keyword: #0000FF",
"dark_vs": "keyword: #569CD6",
"light_vs": "keyword: #0000FF",
"hc_black": "keyword: #569CD6",
"dark_modern": "keyword: #569CD6",
"hc_light": "keyword: #0F4A85",
"light_modern": "keyword: #0000FF"
"dark_plus": "storage.type: #569CD6",
"light_plus": "storage.type: #0000FF",
"dark_vs": "storage.type: #569CD6",
"light_vs": "storage.type: #0000FF",
"hc_black": "storage.type: #569CD6",
"dark_modern": "storage.type: #569CD6",
"hc_light": "storage.type: #0F4A85",
"light_modern": "storage.type: #0000FF"
}
},
{
@@ -211,7 +211,7 @@
},
{
"c": "static",
"t": "source.cs storage.modifier.cs",
"t": "source.cs storage.modifier.static.cs",
"r": {
"dark_plus": "storage.modifier: #569CD6",
"light_plus": "storage.modifier: #0000FF",
@@ -239,7 +239,7 @@
},
{
"c": "void",
"t": "source.cs keyword.type.cs",
"t": "source.cs keyword.type.void.cs",
"r": {
"dark_plus": "keyword: #569CD6",
"light_plus": "keyword: #0000FF",
@@ -295,7 +295,7 @@
},
{
"c": "string",
"t": "source.cs keyword.type.cs",
"t": "source.cs keyword.type.string.cs",
"r": {
"dark_plus": "keyword: #569CD6",
"light_plus": "keyword: #0000FF",
@@ -421,7 +421,7 @@
},
{
"c": "int",
"t": "source.cs keyword.type.cs",
"t": "source.cs keyword.type.int.cs",
"r": {
"dark_plus": "keyword: #569CD6",
"light_plus": "keyword: #0000FF",
@@ -799,7 +799,7 @@
},
{
"c": "const",
"t": "source.cs storage.modifier.cs",
"t": "source.cs storage.modifier.const.cs",
"r": {
"dark_plus": "storage.modifier: #569CD6",
"light_plus": "storage.modifier: #0000FF",
@@ -827,7 +827,7 @@
},
{
"c": "double",
"t": "source.cs keyword.type.cs",
"t": "source.cs keyword.type.double.cs",
"r": {
"dark_plus": "keyword: #569CD6",
"light_plus": "keyword: #0000FF",
@@ -1023,7 +1023,7 @@
},
{
"c": "int",
"t": "source.cs keyword.type.cs",
"t": "source.cs keyword.type.int.cs",
"r": {
"dark_plus": "keyword: #569CD6",
"light_plus": "keyword: #0000FF",
@@ -1177,7 +1177,7 @@
},
{
"c": "double",
"t": "source.cs keyword.type.cs",
"t": "source.cs keyword.type.double.cs",
"r": {
"dark_plus": "keyword: #569CD6",
"light_plus": "keyword: #0000FF",
@@ -1429,16 +1429,16 @@
},
{
"c": " ",
"t": "source.cs punctuation.whitespace.comment.leading.cs",
"t": "source.cs comment.line.double-slash.cs punctuation.whitespace.comment.leading.cs",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF",
"dark_modern": "default: #CCCCCC",
"hc_light": "default: #292929",
"light_modern": "default: #3B3B3B"
"dark_plus": "comment: #6A9955",
"light_plus": "comment: #008000",
"dark_vs": "comment: #6A9955",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668",
"dark_modern": "comment: #6A9955",
"hc_light": "comment: #515151",
"light_modern": "comment: #008000"
}
},
{
@@ -1751,7 +1751,7 @@
},
{
"c": "public",
"t": "source.cs storage.modifier.cs",
"t": "source.cs storage.modifier.public.cs",
"r": {
"dark_plus": "storage.modifier: #569CD6",
"light_plus": "storage.modifier: #0000FF",
@@ -1779,7 +1779,7 @@
},
{
"c": "void",
"t": "source.cs keyword.type.cs",
"t": "source.cs keyword.type.void.cs",
"r": {
"dark_plus": "keyword: #569CD6",
"light_plus": "keyword: #0000FF",
@@ -1947,16 +1947,16 @@
},
{
"c": "new",
"t": "source.cs keyword.other.new.cs",
"t": "source.cs keyword.operator.expression.new.cs",
"r": {
"dark_plus": "keyword: #569CD6",
"light_plus": "keyword: #0000FF",
"dark_vs": "keyword: #569CD6",
"light_vs": "keyword: #0000FF",
"hc_black": "keyword: #569CD6",
"dark_modern": "keyword: #569CD6",
"hc_light": "keyword: #0F4A85",
"light_modern": "keyword: #0000FF"
"dark_plus": "keyword.operator.expression: #569CD6",
"light_plus": "keyword.operator.expression: #0000FF",
"dark_vs": "keyword.operator.expression: #569CD6",
"light_vs": "keyword.operator.expression: #0000FF",
"hc_black": "keyword.operator.expression: #569CD6",
"dark_modern": "keyword.operator.expression: #569CD6",
"hc_light": "keyword.operator.expression: #0F4A85",
"light_modern": "keyword.operator.expression: #0000FF"
}
},
{
@@ -2003,7 +2003,7 @@
},
{
"c": "int",
"t": "source.cs keyword.type.cs",
"t": "source.cs keyword.type.int.cs",
"r": {
"dark_plus": "keyword: #569CD6",
"light_plus": "keyword: #0000FF",
@@ -2115,7 +2115,7 @@
},
{
"c": "int",
"t": "source.cs keyword.type.cs",
"t": "source.cs keyword.type.int.cs",
"r": {
"dark_plus": "keyword: #569CD6",
"light_plus": "keyword: #0000FF",
@@ -2255,16 +2255,16 @@
},
{
"c": "new",
"t": "source.cs keyword.other.new.cs",
"t": "source.cs keyword.operator.expression.new.cs",
"r": {
"dark_plus": "keyword: #569CD6",
"light_plus": "keyword: #0000FF",
"dark_vs": "keyword: #569CD6",
"light_vs": "keyword: #0000FF",
"hc_black": "keyword: #569CD6",
"dark_modern": "keyword: #569CD6",
"hc_light": "keyword: #0F4A85",
"light_modern": "keyword: #0000FF"
"dark_plus": "keyword.operator.expression: #569CD6",
"light_plus": "keyword.operator.expression: #0000FF",
"dark_vs": "keyword.operator.expression: #569CD6",
"light_vs": "keyword.operator.expression: #0000FF",
"hc_black": "keyword.operator.expression: #569CD6",
"dark_modern": "keyword.operator.expression: #569CD6",
"hc_light": "keyword.operator.expression: #0F4A85",
"light_modern": "keyword.operator.expression: #0000FF"
}
},
{
@@ -2311,7 +2311,7 @@
},
{
"c": "int",
"t": "source.cs keyword.type.cs",
"t": "source.cs keyword.type.int.cs",
"r": {
"dark_plus": "keyword: #569CD6",
"light_plus": "keyword: #0000FF",
@@ -2423,7 +2423,7 @@
},
{
"c": "int",
"t": "source.cs keyword.type.cs",
"t": "source.cs keyword.type.int.cs",
"r": {
"dark_plus": "keyword: #569CD6",
"light_plus": "keyword: #0000FF",
@@ -2521,16 +2521,16 @@
},
{
"c": "new",
"t": "source.cs keyword.other.new.cs",
"t": "source.cs keyword.operator.expression.new.cs",
"r": {
"dark_plus": "keyword: #569CD6",
"light_plus": "keyword: #0000FF",
"dark_vs": "keyword: #569CD6",
"light_vs": "keyword: #0000FF",
"hc_black": "keyword: #569CD6",
"dark_modern": "keyword: #569CD6",
"hc_light": "keyword: #0F4A85",
"light_modern": "keyword: #0000FF"
"dark_plus": "keyword.operator.expression: #569CD6",
"light_plus": "keyword.operator.expression: #0000FF",
"dark_vs": "keyword.operator.expression: #569CD6",
"light_vs": "keyword.operator.expression: #0000FF",
"hc_black": "keyword.operator.expression: #569CD6",
"dark_modern": "keyword.operator.expression: #569CD6",
"hc_light": "keyword.operator.expression: #0F4A85",
"light_modern": "keyword.operator.expression: #0000FF"
}
},
{
@@ -2577,7 +2577,7 @@
},
{
"c": "int",
"t": "source.cs keyword.type.cs",
"t": "source.cs keyword.type.int.cs",
"r": {
"dark_plus": "keyword: #569CD6",
"light_plus": "keyword: #0000FF",
@@ -43,16 +43,16 @@
},
{
"c": "var",
"t": "text.html.cshtml meta.structure.razor.codeblock source.cs keyword.other.var.cs",
"t": "text.html.cshtml meta.structure.razor.codeblock source.cs storage.type.var.cs",
"r": {
"dark_plus": "keyword: #569CD6",
"light_plus": "keyword: #0000FF",
"dark_vs": "keyword: #569CD6",
"light_vs": "keyword: #0000FF",
"hc_black": "keyword: #569CD6",
"dark_modern": "keyword: #569CD6",
"hc_light": "keyword: #0F4A85",
"light_modern": "keyword: #0000FF"
"dark_plus": "storage.type: #569CD6",
"light_plus": "storage.type: #0000FF",
"dark_vs": "storage.type: #569CD6",
"light_vs": "storage.type: #0000FF",
"hc_black": "storage.type: #569CD6",
"dark_modern": "storage.type: #569CD6",
"hc_light": "storage.type: #0F4A85",
"light_modern": "storage.type: #0000FF"
}
},
{
@@ -169,16 +169,16 @@
},
{
"c": "var",
"t": "text.html.cshtml meta.structure.razor.codeblock source.cs keyword.other.var.cs",
"t": "text.html.cshtml meta.structure.razor.codeblock source.cs storage.type.var.cs",
"r": {
"dark_plus": "keyword: #569CD6",
"light_plus": "keyword: #0000FF",
"dark_vs": "keyword: #569CD6",
"light_vs": "keyword: #0000FF",
"hc_black": "keyword: #569CD6",
"dark_modern": "keyword: #569CD6",
"hc_light": "keyword: #0F4A85",
"light_modern": "keyword: #0000FF"
"dark_plus": "storage.type: #569CD6",
"light_plus": "storage.type: #0000FF",
"dark_vs": "storage.type: #569CD6",
"light_vs": "storage.type: #0000FF",
"hc_black": "storage.type: #569CD6",
"dark_modern": "storage.type: #569CD6",
"hc_light": "storage.type: #0F4A85",
"light_modern": "storage.type: #0000FF"
}
},
{
@@ -505,16 +505,16 @@
},
{
"c": " ",
"t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock punctuation.whitespace.comment.leading.cs",
"t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock comment.line.double-slash.cs punctuation.whitespace.comment.leading.cs",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF",
"dark_modern": "default: #CCCCCC",
"hc_light": "default: #292929",
"light_modern": "default: #3B3B3B"
"dark_plus": "comment: #6A9955",
"light_plus": "comment: #008000",
"dark_vs": "comment: #6A9955",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668",
"dark_modern": "comment: #6A9955",
"hc_light": "comment: #515151",
"light_modern": "comment: #008000"
}
},
{
@@ -561,16 +561,16 @@
},
{
"c": "var",
"t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock keyword.other.var.cs",
"t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock storage.type.var.cs",
"r": {
"dark_plus": "keyword: #569CD6",
"light_plus": "keyword: #0000FF",
"dark_vs": "keyword: #569CD6",
"light_vs": "keyword: #0000FF",
"hc_black": "keyword: #569CD6",
"dark_modern": "keyword: #569CD6",
"hc_light": "keyword: #0F4A85",
"light_modern": "keyword: #0000FF"
"dark_plus": "storage.type: #569CD6",
"light_plus": "storage.type: #0000FF",
"dark_vs": "storage.type: #569CD6",
"light_vs": "storage.type: #0000FF",
"hc_black": "storage.type: #569CD6",
"dark_modern": "storage.type: #569CD6",
"hc_light": "storage.type: #0F4A85",
"light_modern": "storage.type: #0000FF"
}
},
{
@@ -757,16 +757,16 @@
},
{
"c": "var",
"t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock keyword.other.var.cs",
"t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock storage.type.var.cs",
"r": {
"dark_plus": "keyword: #569CD6",
"light_plus": "keyword: #0000FF",
"dark_vs": "keyword: #569CD6",
"light_vs": "keyword: #0000FF",
"hc_black": "keyword: #569CD6",
"dark_modern": "keyword: #569CD6",
"hc_light": "keyword: #0F4A85",
"light_modern": "keyword: #0000FF"
"dark_plus": "storage.type: #569CD6",
"light_plus": "storage.type: #0000FF",
"dark_vs": "storage.type: #569CD6",
"light_vs": "storage.type: #0000FF",
"hc_black": "storage.type: #569CD6",
"dark_modern": "storage.type: #569CD6",
"hc_light": "storage.type: #0F4A85",
"light_modern": "storage.type: #0000FF"
}
},
{
@@ -939,16 +939,16 @@
},
{
"c": " ",
"t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock punctuation.whitespace.comment.leading.cs",
"t": "text.html.cshtml meta.structure.razor.codeblock source.cs meta.statement.if.razor meta.structure.razor.csharp.codeblock comment.line.double-slash.cs punctuation.whitespace.comment.leading.cs",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF",
"dark_modern": "default: #CCCCCC",
"hc_light": "default: #292929",
"light_modern": "default: #3B3B3B"
"dark_plus": "comment: #6A9955",
"light_plus": "comment: #008000",
"dark_vs": "comment: #6A9955",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668",
"dark_modern": "comment: #6A9955",
"hc_light": "comment: #515151",
"light_modern": "comment: #008000"
}
},
{
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -7,7 +7,7 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.13.tgz#f64277c341150c979e42b00e4ac289290c9df469"
integrity sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==
jsonc-parser@2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.2.1.tgz#db73cd59d78cce28723199466b2a03d1be1df2bc"
integrity sha512-o6/yDBYccGvTz1+QFevz6l6OBZ2+fMVu2JZ9CIhzsYRX4mjaK5IyX9eldUdCmga16zlgQxyrj5pt9kzuj2C02w==
jsonc-parser@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76"
integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==
+9 -9
View File
@@ -94,14 +94,14 @@
"vscode-oniguruma": "1.7.0",
"vscode-regexpp": "^3.1.0",
"vscode-textmate": "9.0.0",
"xterm": "5.3.0-beta.61",
"xterm-addon-canvas": "0.5.0-beta.22",
"xterm-addon-image": "0.6.0-beta.14",
"xterm-addon-search": "0.13.0-beta.20",
"xterm-addon-serialize": "0.11.0-beta.20",
"xterm-addon-unicode11": "0.6.0-beta.12",
"xterm-addon-webgl": "0.16.0-beta.30",
"xterm-headless": "5.3.0-beta.61",
"xterm": "5.4.0-beta.17",
"xterm-addon-canvas": "0.6.0-beta.16",
"xterm-addon-image": "0.6.0-beta.21",
"xterm-addon-search": "0.14.0-beta.15",
"xterm-addon-serialize": "0.12.0-beta.15",
"xterm-addon-unicode11": "0.7.0-beta.15",
"xterm-addon-webgl": "0.17.0-beta.15",
"xterm-headless": "5.4.0-beta.17",
"yauzl": "^2.9.2",
"yazl": "^2.4.3"
},
@@ -210,7 +210,7 @@
"ts-loader": "^9.4.2",
"ts-node": "^10.9.1",
"tsec": "0.2.7",
"typescript": "^5.3.0-dev.20230905",
"typescript": "^5.3.0-dev.20230911",
"typescript-formatter": "7.1.0",
"underscore": "^1.12.1",
"util": "^0.12.4",
+8 -8
View File
@@ -26,14 +26,14 @@
"vscode-oniguruma": "1.7.0",
"vscode-regexpp": "^3.1.0",
"vscode-textmate": "9.0.0",
"xterm": "5.3.0-beta.61",
"xterm-addon-canvas": "0.5.0-beta.22",
"xterm-addon-image": "0.6.0-beta.14",
"xterm-addon-search": "0.13.0-beta.20",
"xterm-addon-serialize": "0.11.0-beta.20",
"xterm-addon-unicode11": "0.6.0-beta.12",
"xterm-addon-webgl": "0.16.0-beta.30",
"xterm-headless": "5.3.0-beta.61",
"xterm": "5.4.0-beta.17",
"xterm-addon-canvas": "0.6.0-beta.16",
"xterm-addon-image": "0.6.0-beta.21",
"xterm-addon-search": "0.14.0-beta.15",
"xterm-addon-serialize": "0.12.0-beta.15",
"xterm-addon-unicode11": "0.7.0-beta.15",
"xterm-addon-webgl": "0.17.0-beta.15",
"xterm-headless": "5.4.0-beta.17",
"yauzl": "^2.9.2",
"yazl": "^2.4.3"
}
+6 -6
View File
@@ -11,11 +11,11 @@
"tas-client-umd": "0.1.8",
"vscode-oniguruma": "1.7.0",
"vscode-textmate": "9.0.0",
"xterm": "5.3.0-beta.61",
"xterm-addon-canvas": "0.5.0-beta.22",
"xterm-addon-image": "0.6.0-beta.14",
"xterm-addon-search": "0.13.0-beta.20",
"xterm-addon-unicode11": "0.6.0-beta.12",
"xterm-addon-webgl": "0.16.0-beta.30"
"xterm": "5.4.0-beta.17",
"xterm-addon-canvas": "0.6.0-beta.16",
"xterm-addon-image": "0.6.0-beta.21",
"xterm-addon-search": "0.14.0-beta.15",
"xterm-addon-unicode11": "0.7.0-beta.15",
"xterm-addon-webgl": "0.17.0-beta.15"
}
}
+24 -24
View File
@@ -68,32 +68,32 @@ vscode-textmate@9.0.0:
resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-9.0.0.tgz#313c6c8792b0507aef35aeb81b6b370b37c44d6c"
integrity sha512-Cl65diFGxz7gpwbav10HqiY/eVYTO1sjQpmRmV991Bj7wAoOAjGQ97PpQcXorDE2Uc4hnGWLY17xme+5t6MlSg==
xterm-addon-canvas@0.5.0-beta.22:
version "0.5.0-beta.22"
resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.5.0-beta.22.tgz#513f0c2b7cf96073f47627b27e8965c1b1a22431"
integrity sha512-9F6ZI0DMRgffVfHkLkDwl5n8VscvCaV10tWI3skXOX7Y7Aws6OEeglkOPoU3IllofCU792kHKM4pPoToUxTltg==
xterm-addon-canvas@0.6.0-beta.16:
version "0.6.0-beta.16"
resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.6.0-beta.16.tgz#6d6a475824c3c0129f3cb38eaea69cf12386cc31"
integrity sha512-uh90h+uozwrZbc/yMhbRnKIY7J34CTse6njibajdeK+0hQvj09HnBXgkvALImR/sEwyIz8SVtSL+OOZTlmAHIQ==
xterm-addon-image@0.6.0-beta.14:
version "0.6.0-beta.14"
resolved "https://registry.yarnpkg.com/xterm-addon-image/-/xterm-addon-image-0.6.0-beta.14.tgz#75fc3f824123183a4bbb5306e22f8b2c6966b0a6"
integrity sha512-D5Gh5JTKhHaPt1KwQNf6diF37KA4eToJw3XId1wy62tWmSqfq+QflhOGTfd+SnSQYCktU05ETzM+0tncIU62pQ==
xterm-addon-image@0.6.0-beta.21:
version "0.6.0-beta.21"
resolved "https://registry.yarnpkg.com/xterm-addon-image/-/xterm-addon-image-0.6.0-beta.21.tgz#e3708bc504c56a23ff31f12a2eeb335331a92aac"
integrity sha512-8/PTaXVPa4kQ0xzVeuZZk10OpbZBj2cgfwhM2B0ChSPvwrk0lX+ksnXdtDKH3tg+JYvo7fIhNXtkr4NwWt7VJQ==
xterm-addon-search@0.13.0-beta.20:
version "0.13.0-beta.20"
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.13.0-beta.20.tgz#8ddd0513e2a70fcefa325722100d2e1bfaf3b9cb"
integrity sha512-wrx6187cJ1UenGL6ZeYv3jFvRPhhENTfbC+Hv1Fnww8LmsKhcj+0+Pm6yInNjX/9hNVsNzdqKyqNeEMoykyoyA==
xterm-addon-search@0.14.0-beta.15:
version "0.14.0-beta.15"
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.14.0-beta.15.tgz#fcea611a04a8f4fd5dd3ec5e3403cce9cde72f0a"
integrity sha512-wPk3FzOFIeEAgVMjNL6CHoAfPcmk3DWwf28AtICfJ512JVJ3d0o9mUEh853m08/eaJJikAMXMEgTGRgjNtZU3Q==
xterm-addon-unicode11@0.6.0-beta.12:
version "0.6.0-beta.12"
resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.6.0-beta.12.tgz#ac6df9d635325dc692e4c602e74a2fc27a09405c"
integrity sha512-9wWWf/5nFafYgq0pn9EgAWnXaXGleVxfjNOqavpLRYFv0nw42QbaYyGvnGcxyYHM5Aqx/8rYE/DDVWZBqQZdYA==
xterm-addon-unicode11@0.7.0-beta.15:
version "0.7.0-beta.15"
resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.7.0-beta.15.tgz#07359424a862aedc456f35f95126739cd4fbe7de"
integrity sha512-CdPuahtDiacsBO618XTNc+z3diWPVzvpVlk0NcIsUpcdsF+44rgRBFaD7mT4tfAFU1w1ibTzTfOakrFlYZuM0A==
xterm-addon-webgl@0.16.0-beta.30:
version "0.16.0-beta.30"
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.16.0-beta.30.tgz#820d5c65f868b14ec4177bfb8a294931a53616bf"
integrity sha512-39qPHPFmNENxcHf8/CzGHS6wzKMMegoRkHB1+scqtBhSxFaD8tX5Ye33HZIEdQ9nXe9xtr4FWVp77T+n9hdrew==
xterm-addon-webgl@0.17.0-beta.15:
version "0.17.0-beta.15"
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.17.0-beta.15.tgz#53e15a170e4e9d8ddafb8971b2e63b4c596b9744"
integrity sha512-3JJ8KumPzFut1yloNhIrvObBwqp8kbqBI/up77MIyGE/6WiGhgecUFPmT8rYUCv4g/GBXoMan755yOEUNkKtcg==
xterm@5.3.0-beta.61:
version "5.3.0-beta.61"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.3.0-beta.61.tgz#a6c27d90a5314da51d80deeb32f3bd77f1e1c8f6"
integrity sha512-rJHpCc48GSpHnu0SSERynQ80D5ikvFVsqhv6JdmeONTrnAFRr134OglJRIpbi2YK8UPbV6F6Dfqm/AQh+9GZzA==
xterm@5.4.0-beta.17:
version "5.4.0-beta.17"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.4.0-beta.17.tgz#7e7841b09339670c5ada967b73a1416d1b3dc9f7"
integrity sha512-hTSJHkyH/m26nQJt1oNI1KJU18JVJpOy41pP9WRRFQx1KoHhYq4HMRl7LO42SJt6Vs0mig0UYkbEnRWfT4FCww==
+32 -32
View File
@@ -667,45 +667,45 @@ wrappy@1:
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
xterm-addon-canvas@0.5.0-beta.22:
version "0.5.0-beta.22"
resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.5.0-beta.22.tgz#513f0c2b7cf96073f47627b27e8965c1b1a22431"
integrity sha512-9F6ZI0DMRgffVfHkLkDwl5n8VscvCaV10tWI3skXOX7Y7Aws6OEeglkOPoU3IllofCU792kHKM4pPoToUxTltg==
xterm-addon-canvas@0.6.0-beta.16:
version "0.6.0-beta.16"
resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.6.0-beta.16.tgz#6d6a475824c3c0129f3cb38eaea69cf12386cc31"
integrity sha512-uh90h+uozwrZbc/yMhbRnKIY7J34CTse6njibajdeK+0hQvj09HnBXgkvALImR/sEwyIz8SVtSL+OOZTlmAHIQ==
xterm-addon-image@0.6.0-beta.14:
version "0.6.0-beta.14"
resolved "https://registry.yarnpkg.com/xterm-addon-image/-/xterm-addon-image-0.6.0-beta.14.tgz#75fc3f824123183a4bbb5306e22f8b2c6966b0a6"
integrity sha512-D5Gh5JTKhHaPt1KwQNf6diF37KA4eToJw3XId1wy62tWmSqfq+QflhOGTfd+SnSQYCktU05ETzM+0tncIU62pQ==
xterm-addon-image@0.6.0-beta.21:
version "0.6.0-beta.21"
resolved "https://registry.yarnpkg.com/xterm-addon-image/-/xterm-addon-image-0.6.0-beta.21.tgz#e3708bc504c56a23ff31f12a2eeb335331a92aac"
integrity sha512-8/PTaXVPa4kQ0xzVeuZZk10OpbZBj2cgfwhM2B0ChSPvwrk0lX+ksnXdtDKH3tg+JYvo7fIhNXtkr4NwWt7VJQ==
xterm-addon-search@0.13.0-beta.20:
version "0.13.0-beta.20"
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.13.0-beta.20.tgz#8ddd0513e2a70fcefa325722100d2e1bfaf3b9cb"
integrity sha512-wrx6187cJ1UenGL6ZeYv3jFvRPhhENTfbC+Hv1Fnww8LmsKhcj+0+Pm6yInNjX/9hNVsNzdqKyqNeEMoykyoyA==
xterm-addon-search@0.14.0-beta.15:
version "0.14.0-beta.15"
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.14.0-beta.15.tgz#fcea611a04a8f4fd5dd3ec5e3403cce9cde72f0a"
integrity sha512-wPk3FzOFIeEAgVMjNL6CHoAfPcmk3DWwf28AtICfJ512JVJ3d0o9mUEh853m08/eaJJikAMXMEgTGRgjNtZU3Q==
xterm-addon-serialize@0.11.0-beta.20:
version "0.11.0-beta.20"
resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.11.0-beta.20.tgz#e879b34d214761403f1081833f9221c6903bf0c3"
integrity sha512-OXnC1SATaz7kEFjFWhyv9MJaXi8yHdPjazpGLNi11h33CRTKtCQiqqPBHU87dztnXmpEX6Jw0/jr3zlyXuAmnw==
xterm-addon-serialize@0.12.0-beta.15:
version "0.12.0-beta.15"
resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.12.0-beta.15.tgz#8e210d566c03b616823317a31dbce474a728b3c9"
integrity sha512-4iF9pQ/q6831ayADPlngAM0aa/mhzvZ4XEd4UNJIgW7mpgoSTvnbh6d6lb37pNkpdDFIRLJv6rlqDjlh6EkoJg==
xterm-addon-unicode11@0.6.0-beta.12:
version "0.6.0-beta.12"
resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.6.0-beta.12.tgz#ac6df9d635325dc692e4c602e74a2fc27a09405c"
integrity sha512-9wWWf/5nFafYgq0pn9EgAWnXaXGleVxfjNOqavpLRYFv0nw42QbaYyGvnGcxyYHM5Aqx/8rYE/DDVWZBqQZdYA==
xterm-addon-unicode11@0.7.0-beta.15:
version "0.7.0-beta.15"
resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.7.0-beta.15.tgz#07359424a862aedc456f35f95126739cd4fbe7de"
integrity sha512-CdPuahtDiacsBO618XTNc+z3diWPVzvpVlk0NcIsUpcdsF+44rgRBFaD7mT4tfAFU1w1ibTzTfOakrFlYZuM0A==
xterm-addon-webgl@0.16.0-beta.30:
version "0.16.0-beta.30"
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.16.0-beta.30.tgz#820d5c65f868b14ec4177bfb8a294931a53616bf"
integrity sha512-39qPHPFmNENxcHf8/CzGHS6wzKMMegoRkHB1+scqtBhSxFaD8tX5Ye33HZIEdQ9nXe9xtr4FWVp77T+n9hdrew==
xterm-addon-webgl@0.17.0-beta.15:
version "0.17.0-beta.15"
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.17.0-beta.15.tgz#53e15a170e4e9d8ddafb8971b2e63b4c596b9744"
integrity sha512-3JJ8KumPzFut1yloNhIrvObBwqp8kbqBI/up77MIyGE/6WiGhgecUFPmT8rYUCv4g/GBXoMan755yOEUNkKtcg==
xterm-headless@5.3.0-beta.61:
version "5.3.0-beta.61"
resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.3.0-beta.61.tgz#28654550cb572709b99ea3eb8672d4568ae141c9"
integrity sha512-yfkbPLUtKjE4K7DsZ204A1BuOKpu6Usqi6rIYWT4XRMi+LjnkTbBjGr2BSjyJ3Gmtm+cSgBD0SvRN+V3xNxbxA==
xterm-headless@5.4.0-beta.17:
version "5.4.0-beta.17"
resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.4.0-beta.17.tgz#cb779eba8da66ecad6f4be41af649453bb3260e9"
integrity sha512-ax2asr5QS4EnJAmRnKDDnAqESst+r2G/MckaYdxTDgX0pc997TU4B/JQ6c5BhxVLQvRwmotTm11/n909HiHadQ==
xterm@5.3.0-beta.61:
version "5.3.0-beta.61"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.3.0-beta.61.tgz#a6c27d90a5314da51d80deeb32f3bd77f1e1c8f6"
integrity sha512-rJHpCc48GSpHnu0SSERynQ80D5ikvFVsqhv6JdmeONTrnAFRr134OglJRIpbi2YK8UPbV6F6Dfqm/AQh+9GZzA==
xterm@5.4.0-beta.17:
version "5.4.0-beta.17"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.4.0-beta.17.tgz#7e7841b09339670c5ada967b73a1416d1b3dc9f7"
integrity sha512-hTSJHkyH/m26nQJt1oNI1KJU18JVJpOy41pP9WRRFQx1KoHhYq4HMRl7LO42SJt6Vs0mig0UYkbEnRWfT4FCww==
yallist@^4.0.0:
version "4.0.0"
+1 -1
View File
@@ -35,7 +35,7 @@ if %errorlevel% neq 0 exit /b %errorlevel%
:: Tests in the extension host
set API_TESTS_EXTRA_ARGS=--disable-telemetry --skip-welcome --skip-release-notes --crash-reporter-directory=%VSCODECRASHDIR% --logsPath=%VSCODELOGSDIR% --no-cached-data --disable-updates --disable-keytar --disable-extensions --disable-workspace-trust --user-data-dir=%VSCODEUSERDATADIR%
set API_TESTS_EXTRA_ARGS=--disable-telemetry --skip-welcome --skip-release-notes --crash-reporter-directory=%VSCODECRASHDIR% --logsPath=%VSCODELOGSDIR% --no-cached-data --disable-updates --use-inmemory-secretstorage --disable-extensions --disable-workspace-trust --user-data-dir=%VSCODEUSERDATADIR%
echo.
echo ### API tests (folder)
+1 -1
View File
@@ -44,7 +44,7 @@ echo
# Tests in the extension host
API_TESTS_EXTRA_ARGS="--disable-telemetry --skip-welcome --skip-release-notes --crash-reporter-directory=$VSCODECRASHDIR --logsPath=$VSCODELOGSDIR --no-cached-data --disable-updates --disable-keytar --disable-extensions --disable-workspace-trust --user-data-dir=$VSCODEUSERDATADIR"
API_TESTS_EXTRA_ARGS="--disable-telemetry --skip-welcome --skip-release-notes --crash-reporter-directory=$VSCODECRASHDIR --logsPath=$VSCODELOGSDIR --no-cached-data --disable-updates --use-inmemory-secretstorage --disable-extensions --disable-workspace-trust --user-data-dir=$VSCODEUSERDATADIR"
if [ -z "$INTEGRATION_TEST_APP_NAME" ]; then
kill_app() { true; }
+1 -1
View File
@@ -55,7 +55,7 @@ echo Storing log files into '%VSCODELOGSDIR%'
:: Tests in the extension host
set API_TESTS_EXTRA_ARGS=--disable-telemetry --skip-welcome --skip-release-notes --crash-reporter-directory=%VSCODECRASHDIR% --logsPath=%VSCODELOGSDIR% --no-cached-data --disable-updates --disable-keytar --disable-inspect --disable-workspace-trust --user-data-dir=%VSCODEUSERDATADIR%
set API_TESTS_EXTRA_ARGS=--disable-telemetry --skip-welcome --skip-release-notes --crash-reporter-directory=%VSCODECRASHDIR% --logsPath=%VSCODELOGSDIR% --no-cached-data --disable-updates --use-inmemory-secretstorage --disable-inspect --disable-workspace-trust --user-data-dir=%VSCODEUSERDATADIR%
echo.
echo ### API tests (folder)
+1 -1
View File
@@ -68,7 +68,7 @@ else
kill_app() { killall $INTEGRATION_TEST_APP_NAME || true; }
fi
API_TESTS_EXTRA_ARGS="--disable-telemetry --skip-welcome --skip-release-notes --crash-reporter-directory=$VSCODECRASHDIR --logsPath=$VSCODELOGSDIR --no-cached-data --disable-updates --disable-keytar --disable-workspace-trust --user-data-dir=$VSCODEUSERDATADIR"
API_TESTS_EXTRA_ARGS="--disable-telemetry --skip-welcome --skip-release-notes --crash-reporter-directory=$VSCODECRASHDIR --logsPath=$VSCODELOGSDIR --no-cached-data --disable-updates --use-inmemory-secretstorage --disable-workspace-trust --user-data-dir=$VSCODEUSERDATADIR"
echo "Storing crash reports into '$VSCODECRASHDIR'."
echo "Storing log files into '$VSCODELOGSDIR'."
+23
View File
@@ -123,3 +123,26 @@ export class IframeUtils {
};
}
}
/**
* Returns a sha-256 composed of `parentOrigin` and `salt` converted to base 32
*/
export async function parentOriginHash(parentOrigin: string, salt: string): Promise<string> {
// This same code is also inlined at `src/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.html`
if (!crypto.subtle) {
throw new Error(`'crypto.subtle' is not available so webviews will not work. This is likely because the editor is not running in a secure context (https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts).`);
}
const strData = JSON.stringify({ parentOrigin, salt });
const encoder = new TextEncoder();
const arrData = encoder.encode(strData);
const hash = await crypto.subtle.digest('sha-256', arrData);
return sha256AsBase32(hash);
}
function sha256AsBase32(bytes: ArrayBuffer): string {
const array = Array.from(new Uint8Array(bytes));
const hexArray = array.map(b => b.toString(16).padStart(2, '0')).join('');
// sha256 has 256 bits, so we need at most ceil(lg(2^256-1)/lg(32)) = 52 chars to represent it in base 32
return BigInt(`0x${hexArray}`).toString(32).padStart(52, '0');
}
+3 -3
View File
@@ -6,7 +6,7 @@
import * as DomUtils from 'vs/base/browser/dom';
import * as arrays from 'vs/base/common/arrays';
import { memoize } from 'vs/base/common/decorators';
import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { Disposable, IDisposable, markAsSingleton, toDisposable } from 'vs/base/common/lifecycle';
import { LinkedList } from 'vs/base/common/linkedList';
export namespace EventType {
@@ -99,7 +99,7 @@ export class Gesture extends Disposable {
return Disposable.None;
}
if (!Gesture.INSTANCE) {
Gesture.INSTANCE = new Gesture();
Gesture.INSTANCE = markAsSingleton(new Gesture());
}
const remove = Gesture.INSTANCE.targets.push(element);
@@ -111,7 +111,7 @@ export class Gesture extends Disposable {
return Disposable.None;
}
if (!Gesture.INSTANCE) {
Gesture.INSTANCE = new Gesture();
Gesture.INSTANCE = markAsSingleton(new Gesture());
}
const remove = Gesture.INSTANCE.ignoreTargets.push(element);
+44 -17
View File
@@ -248,7 +248,7 @@ class BranchNode implements ISplitView<ILayoutContext>, IDisposable {
readonly element: HTMLElement;
readonly children: Node[] = [];
private splitview: SplitView<ILayoutContext>;
private splitview: SplitView<ILayoutContext, Node>;
private _size: number;
get size(): number { return this._size; }
@@ -511,14 +511,27 @@ class BranchNode implements ISplitView<ILayoutContext>, IDisposable {
this.onDidChildrenChange();
}
removeChild(index: number, sizing?: Sizing): void {
removeChild(index: number, sizing?: Sizing): Node {
index = validateIndex(index, this.children.length);
this.splitview.removeView(index, sizing);
const result = this.splitview.removeView(index, sizing);
this.children.splice(index, 1);
this.updateBoundarySashes();
this.onDidChildrenChange();
return result;
}
removeAllChildren(): Node[] {
const result = this.splitview.removeAllViews();
this.children.splice(0, this.children.length);
this.updateBoundarySashes();
this.onDidChildrenChange();
return result;
}
moveChild(from: number, to: number): void {
@@ -904,7 +917,10 @@ export interface INodeDescriptor {
visible?: boolean;
}
function flipNode<T extends Node>(node: T, size: number, orthogonalSize: number): T {
function flipNode(node: BranchNode, size: number, orthogonalSize: number): BranchNode;
function flipNode(node: LeafNode, size: number, orthogonalSize: number): LeafNode;
function flipNode(node: Node, size: number, orthogonalSize: number): Node;
function flipNode(node: Node, size: number, orthogonalSize: number): Node {
if (node instanceof BranchNode) {
const result = new BranchNode(orthogonal(node.orientation), node.layoutController, node.styles, node.splitviewProportionalLayout, size, orthogonalSize, node.edgeSnapping);
@@ -925,9 +941,12 @@ function flipNode<T extends Node>(node: T, size: number, orthogonalSize: number)
result.addChild(flipNode(child, orthogonalSize, newSize), newSize, 0, true);
}
return result as T;
node.dispose();
return result;
} else {
return new LeafNode((node as LeafNode).view, orthogonal(node.orientation), node.layoutController, orthogonalSize) as T;
const result = new LeafNode(node.view, orthogonal(node.orientation), node.layoutController, orthogonalSize);
node.dispose();
return result;
}
}
@@ -1162,8 +1181,13 @@ export class GridView implements IDisposable {
if (parent instanceof BranchNode) {
const node = new LeafNode(view, orthogonal(parent.orientation), this.layoutController, parent.orthogonalSize);
parent.addChild(node, size, index);
try {
parent.addChild(node, size, index);
} catch (err) {
node.dispose();
throw err;
}
} else {
const [, grandParent] = tail(pathToParent);
const [, parentIndex] = tail(rest);
@@ -1175,7 +1199,8 @@ export class GridView implements IDisposable {
newSiblingSize = Sizing.Invisible(newSiblingCachedVisibleSize);
}
grandParent.removeChild(parentIndex);
const oldChild = grandParent.removeChild(parentIndex);
oldChild.dispose();
const newParent = new BranchNode(parent.orientation, parent.layoutController, this.styles, this.proportionalLayout, parent.size, parent.orthogonalSize, grandParent.edgeSnapping);
grandParent.addChild(newParent, parent.size, parentIndex);
@@ -1218,6 +1243,7 @@ export class GridView implements IDisposable {
}
parent.removeChild(index, sizing);
node.dispose();
if (parent.children.length === 0) {
throw new Error('Invalid grid state');
@@ -1237,6 +1263,7 @@ export class GridView implements IDisposable {
// we must promote sibling to be the new root
parent.removeChild(0);
parent.dispose();
this.root = sibling;
this.boundarySashes = this.boundarySashes;
this.trySet2x2();
@@ -1246,19 +1273,20 @@ export class GridView implements IDisposable {
const [, grandParent] = tail(pathToParent);
const [, parentIndex] = tail(rest);
const sibling = parent.children[0];
const isSiblingVisible = parent.isChildVisible(0);
parent.removeChild(0);
const sibling = parent.removeChild(0);
const sizes = grandParent.children.map((_, i) => grandParent.getChildSize(i));
grandParent.removeChild(parentIndex, sizing);
parent.dispose();
if (sibling instanceof BranchNode) {
sizes.splice(parentIndex, 1, ...sibling.children.map(c => c.size));
for (let i = 0; i < sibling.children.length; i++) {
const child = sibling.children[i];
grandParent.addChild(child, child.size, parentIndex + i);
const siblingChildren = sibling.removeAllChildren();
for (let i = 0; i < siblingChildren.length; i++) {
grandParent.addChild(siblingChildren[i], siblingChildren[i].size, parentIndex + i);
}
} else {
const newSibling = new LeafNode(sibling.view, orthogonal(sibling.orientation), this.layoutController, sibling.size);
@@ -1266,6 +1294,8 @@ export class GridView implements IDisposable {
grandParent.addChild(newSibling, sizing, parentIndex);
}
sibling.dispose();
for (let i = 0; i < sizes.length; i++) {
grandParent.resizeChild(i, sizes[i]);
}
@@ -1654,9 +1684,6 @@ export class GridView implements IDisposable {
dispose(): void {
this.onDidSashResetRelay.dispose();
this.root.dispose();
if (this.element && this.element.parentElement) {
this.element.parentElement.removeChild(this.element);
}
this.element.parentElement?.removeChild(this.element);
}
}
+41 -16
View File
@@ -119,7 +119,7 @@ export interface IView<TLayoutContext = undefined> {
/**
* A descriptor for a {@link SplitView} instance.
*/
export interface ISplitViewDescriptor<TLayoutContext = undefined> {
export interface ISplitViewDescriptor<TLayoutContext = undefined, TView extends IView<TLayoutContext> = IView<TLayoutContext>> {
/**
* The layout size of the {@link SplitView}.
@@ -150,11 +150,11 @@ export interface ISplitViewDescriptor<TLayoutContext = undefined> {
*
* @defaultValue `true`
*/
readonly view: IView<TLayoutContext>;
readonly view: TView;
}[];
}
export interface ISplitViewOptions<TLayoutContext = undefined> {
export interface ISplitViewOptions<TLayoutContext = undefined, TView extends IView<TLayoutContext> = IView<TLayoutContext>> {
/**
* Which axis the views align on.
@@ -184,7 +184,7 @@ export interface ISplitViewOptions<TLayoutContext = undefined> {
* An initial description of this {@link SplitView} instance, allowing
* to initialze all views within the ctor.
*/
readonly descriptor?: ISplitViewDescriptor<TLayoutContext>;
readonly descriptor?: ISplitViewDescriptor<TLayoutContext, TView>;
/**
* The scrollbar visibility setting for whenever the views within
@@ -207,7 +207,7 @@ interface ISashEvent {
type ViewItemSize = number | { cachedVisibleSize: number };
abstract class ViewItem<TLayoutContext> {
abstract class ViewItem<TLayoutContext, TView extends IView<TLayoutContext>> {
private _size: number;
set size(size: number) {
@@ -259,7 +259,7 @@ abstract class ViewItem<TLayoutContext> {
constructor(
protected container: HTMLElement,
readonly view: IView<TLayoutContext>,
readonly view: TView,
size: ViewItemSize,
private disposable: IDisposable
) {
@@ -285,7 +285,7 @@ abstract class ViewItem<TLayoutContext> {
}
}
class VerticalViewItem<TLayoutContext> extends ViewItem<TLayoutContext> {
class VerticalViewItem<TLayoutContext, TView extends IView<TLayoutContext>> extends ViewItem<TLayoutContext, TView> {
layoutContainer(offset: number): void {
this.container.style.top = `${offset}px`;
@@ -293,7 +293,7 @@ class VerticalViewItem<TLayoutContext> extends ViewItem<TLayoutContext> {
}
}
class HorizontalViewItem<TLayoutContext> extends ViewItem<TLayoutContext> {
class HorizontalViewItem<TLayoutContext, TView extends IView<TLayoutContext>> extends ViewItem<TLayoutContext, TView> {
layoutContainer(offset: number): void {
this.container.style.left = `${offset}px`;
@@ -413,7 +413,7 @@ export namespace Sizing {
* - View swap/move support
* - Alt key modifier behavior, macOS style
*/
export class SplitView<TLayoutContext = undefined> extends Disposable {
export class SplitView<TLayoutContext = undefined, TView extends IView<TLayoutContext> = IView<TLayoutContext>> extends Disposable {
/**
* This {@link SplitView}'s orientation.
@@ -433,7 +433,7 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
private layoutContext: TLayoutContext | undefined;
private contentSize = 0;
private proportions: (number | undefined)[] | undefined = undefined;
private viewItems: ViewItem<TLayoutContext>[] = [];
private viewItems: ViewItem<TLayoutContext, TView>[] = [];
sashItems: ISashItem[] = []; // used in tests
private sashDragState: ISashDragState | undefined;
private state: State = State.Idle;
@@ -549,7 +549,7 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
/**
* Create a new {@link SplitView} instance.
*/
constructor(container: HTMLElement, options: ISplitViewOptions<TLayoutContext> = {}) {
constructor(container: HTMLElement, options: ISplitViewOptions<TLayoutContext, TView> = {}) {
super();
this.orientation = options.orientation ?? Orientation.VERTICAL;
@@ -636,7 +636,7 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
* @param index The index to insert the view on.
* @param skipLayout Whether layout should be skipped.
*/
addView(view: IView<TLayoutContext>, size: number | Sizing, index = this.viewItems.length, skipLayout?: boolean): void {
addView(view: TView, size: number | Sizing, index = this.viewItems.length, skipLayout?: boolean): void {
this.doAddView(view, size, index, skipLayout);
}
@@ -646,7 +646,7 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
* @param index The index where the {@link IView view} is located.
* @param sizing Whether to distribute other {@link IView view}'s sizes.
*/
removeView(index: number, sizing?: Sizing): IView<TLayoutContext> {
removeView(index: number, sizing?: Sizing): TView {
if (this.state !== State.Idle) {
throw new Error('Cant modify splitview');
}
@@ -695,6 +695,31 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
return result;
}
removeAllViews(): TView[] {
if (this.state !== State.Idle) {
throw new Error('Cant modify splitview');
}
this.state = State.Busy;
const viewItems = this.viewItems.splice(0, this.viewItems.length);
for (const viewItem of viewItems) {
viewItem.dispose();
}
const sashItems = this.sashItems.splice(0, this.sashItems.length);
for (const sashItem of sashItems) {
sashItem.disposable.dispose();
}
this.relayout();
this.state = State.Idle;
return viewItems.map(i => i.view);
}
/**
* Move a {@link IView view} to a different index.
*
@@ -951,7 +976,7 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
}
}
private onViewChange(item: ViewItem<TLayoutContext>, size: number | undefined): void {
private onViewChange(item: ViewItem<TLayoutContext, TView>, size: number | undefined): void {
const index = this.viewItems.indexOf(item);
if (index < 0 || index >= this.viewItems.length) {
@@ -1024,7 +1049,7 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
* Distribute the entire {@link SplitView} size among all {@link IView views}.
*/
distributeViewSizes(): void {
const flexibleViewItems: ViewItem<TLayoutContext>[] = [];
const flexibleViewItems: ViewItem<TLayoutContext, TView>[] = [];
let flexibleSize = 0;
for (const item of this.viewItems) {
@@ -1058,7 +1083,7 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
return this.viewItems[index].size;
}
private doAddView(view: IView<TLayoutContext>, size: number | Sizing, index = this.viewItems.length, skipLayout?: boolean): void {
private doAddView(view: TView, size: number | Sizing, index = this.viewItems.length, skipLayout?: boolean): void {
if (this.state !== State.Idle) {
throw new Error('Cant modify splitview');
}
+3 -3
View File
@@ -5,7 +5,7 @@
import { Comparator } from './arrays';
export function findLast<T>(array: readonly T[], predicate: (item: T) => boolean): T | undefined {
export function findLast<T>(array: readonly T[], predicate: (item: T) => boolean, fromIdx?: number): T | undefined {
const idx = findLastIdx(array, predicate);
if (idx === -1) {
return undefined;
@@ -13,8 +13,8 @@ export function findLast<T>(array: readonly T[], predicate: (item: T) => boolean
return array[idx];
}
export function findLastIdx<T>(array: readonly T[], predicate: (item: T) => boolean): number {
for (let i = array.length - 1; i >= 0; i--) {
export function findLastIdx<T>(array: readonly T[], predicate: (item: T) => boolean, fromIndex = array.length - 1): number {
for (let i = fromIndex; i >= 0; i--) {
const element = array[i];
if (predicate(element)) {
+21 -3
View File
@@ -6,7 +6,7 @@
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
import { CancellationError } from 'vs/base/common/errors';
import { Emitter, Event } from 'vs/base/common/event';
import { Disposable, IDisposable, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { Disposable, DisposableMap, IDisposable, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { extUri as defaultExtUri, IExtUri } from 'vs/base/common/resources';
import { URI } from 'vs/base/common/uri';
import { setTimeout0 } from 'vs/base/common/platform';
@@ -182,7 +182,7 @@ export class Throttler implements IDisposable {
queue<T>(promiseFactory: ITask<Promise<T>>): Promise<T> {
if (this.isDisposed) {
throw new Error('Throttler is disposed');
return Promise.reject(new Error('Throttler is disposed'));
}
if (this.activePromise) {
@@ -717,6 +717,9 @@ export class ResourceQueue implements IDisposable {
private readonly drainers = new Set<DeferredPromise<void>>();
private drainListeners: DisposableMap<number> | undefined = undefined;
private drainListenerCount = 0;
async whenDrained(): Promise<void> {
if (this.isDrained()) {
return;
@@ -744,12 +747,25 @@ export class ResourceQueue implements IDisposable {
let queue = this.queues.get(key);
if (!queue) {
queue = new Queue<void>();
Event.once(queue.onDrained)(() => {
const drainListenerId = this.drainListenerCount++;
const drainListener = Event.once(queue.onDrained)(() => {
queue?.dispose();
this.queues.delete(key);
this.onDidQueueDrain();
this.drainListeners?.deleteAndDispose(drainListenerId);
if (this.drainListeners?.size === 0) {
this.drainListeners.dispose();
this.drainListeners = undefined;
}
});
if (!this.drainListeners) {
this.drainListeners = new DisposableMap();
}
this.drainListeners.set(drainListenerId, drainListener);
this.queues.set(key, queue);
}
@@ -786,6 +802,8 @@ export class ResourceQueue implements IDisposable {
// promises when the resource queue is being
// disposed.
this.releaseDrainers();
this.drainListeners?.dispose();
}
}
+12 -1
View File
@@ -394,7 +394,7 @@ export namespace Event {
* this.onInstallExtension = Event.buffer(service.onInstallExtension, true);
* ```
*/
export function buffer<T>(event: Event<T>, flushAfterTimeout = false, _buffer: T[] = []): Event<T> {
export function buffer<T>(event: Event<T>, flushAfterTimeout = false, _buffer: T[] = [], disposable?: DisposableStore): Event<T> {
let buffer: T[] | null = _buffer.slice();
let listener: IDisposable | null = event(e => {
@@ -405,6 +405,10 @@ export namespace Event {
}
});
if (disposable) {
disposable.add(listener);
}
const flush = () => {
buffer?.forEach(e => emitter.fire(e));
buffer = null;
@@ -414,6 +418,9 @@ export namespace Event {
onWillAddFirstListener() {
if (!listener) {
listener = event(e => emitter.fire(e));
if (disposable) {
disposable.add(listener);
}
}
},
@@ -435,6 +442,10 @@ export namespace Event {
}
});
if (disposable) {
disposable.add(emitter);
}
return emitter.event;
}
/**
+4
View File
@@ -539,6 +539,10 @@ export class DisposableMap<K, V extends IDisposable = IDisposable> implements ID
return this._store.has(key);
}
get size(): number {
return this._store.size;
}
get(key: K): V | undefined {
return this._store.get(key);
}
+12 -2
View File
@@ -58,6 +58,7 @@ export interface IObservable<T, TChange = unknown> {
* (see {@link ConvenientObservable.map}).
*/
map<TNew>(fn: (value: T, reader: IReader) => TNew): IObservable<TNew>;
map<TNew>(owner: object, fn: (value: T, reader: IReader) => TNew): IObservable<TNew>;
/**
* A human-readable name for debugging purposes.
@@ -165,9 +166,15 @@ export abstract class ConvenientObservable<T, TChange> implements IObservable<T,
}
/** @sealed */
public map<TNew>(fn: (value: T, reader: IReader) => TNew): IObservable<TNew> {
public map<TNew>(fn: (value: T, reader: IReader) => TNew): IObservable<TNew>;
public map<TNew>(owner: object, fn: (value: T, reader: IReader) => TNew): IObservable<TNew>;
public map<TNew>(fnOrOwner: object | ((value: T, reader: IReader) => TNew), fnOrUndefined?: (value: T, reader: IReader) => TNew): IObservable<TNew> {
const owner = fnOrUndefined === undefined ? undefined : fnOrOwner as object;
const fn = fnOrUndefined === undefined ? fnOrOwner as (value: T, reader: IReader) => TNew : fnOrUndefined;
return _derived(
{
owner,
debugName: () => {
const name = getFunctionName(fn);
if (name !== undefined) {
@@ -180,7 +187,10 @@ export abstract class ConvenientObservable<T, TChange> implements IObservable<T,
if (match) {
return `${this.debugName}.${match[2]}`;
}
return `${this.debugName} (mapped)`;
if (!owner) {
return `${this.debugName} (mapped)`;
}
return undefined;
},
},
(reader) => fn(this.read(reader), reader),
@@ -26,7 +26,7 @@ export function derived<T>(computeFnOrOwner: ((reader: IReader) => T) | object,
export function derivedOpts<T>(
options: {
owner?: object;
debugName?: string | (() => string);
debugName?: string | (() => string | undefined);
equalityComparer?: EqualityComparer<T>;
},
computeFn: (reader: IReader) => T
+3 -2
View File
@@ -118,7 +118,7 @@ export class PagedModel<T> implements IPagedModel<T> {
});
}
cancellationToken.onCancellationRequested(() => {
const listener = cancellationToken.onCancellationRequested(() => {
if (!page.cts) {
return;
}
@@ -132,7 +132,8 @@ export class PagedModel<T> implements IPagedModel<T> {
page.promiseIndexes.add(index);
return page.promise.then(() => page.elements[indexInPage]);
return page.promise.then(() => page.elements[indexInPage])
.finally(() => listener.dispose());
}
}
+4
View File
@@ -622,11 +622,15 @@ export function peekStream<T>(stream: ReadableStream<T>, maxChunks: number): Pro
// Error Listener
const errorListener = (error: Error) => {
streamListeners.dispose();
return reject(error);
};
// End Listener
const endListener = () => {
streamListeners.dispose();
return resolve({ stream, buffer, ended: true });
};
+3 -3
View File
@@ -107,12 +107,12 @@ function extractZip(zipfile: ZipFile, targetPath: string, options: IOptions, tok
let last = createCancelablePromise<void>(() => Promise.resolve());
let extractedEntriesCount = 0;
token.onCancellationRequested(() => {
const listener = token.onCancellationRequested(() => {
last.cancel();
zipfile.close();
});
return new Promise((c, e) => {
return new Promise<void>((c, e) => {
const throttler = new Sequencer();
const readNextEntry = (token: CancellationToken) => {
@@ -158,7 +158,7 @@ function extractZip(zipfile: ZipFile, targetPath: string, options: IOptions, tok
last = createCancelablePromise(token => throttler.queue(() => stream.then(stream => extractEntry(stream, fileName, mode, targetPath, options, token).then(() => readNextEntry(token)))).then(null, e));
});
});
}).finally(() => listener.dispose());
}
function openZip(zipFile: string, lazy: boolean = false): Promise<ZipFile> {
+29 -16
View File
@@ -427,7 +427,6 @@ export class ChannelServer<TContext = string> implements IChannelServer<TContext
promise.then(data => {
this.sendResponse(<IRawResponse>{ id, data, type: ResponseType.PromiseSuccess });
this.activeRequests.delete(request.id);
}, err => {
if (err instanceof Error) {
this.sendResponse(<IRawResponse>{
@@ -440,7 +439,8 @@ export class ChannelServer<TContext = string> implements IChannelServer<TContext
} else {
this.sendResponse(<IRawResponse>{ id, data: err, type: ResponseType.PromiseErrorObj });
}
}).finally(() => {
disposable.dispose();
this.activeRequests.delete(request.id);
});
@@ -639,7 +639,10 @@ export class ChannelClient implements IChannelClient, IDisposable {
this.activeRequests.add(disposable);
});
return result.finally(() => { this.activeRequests.delete(disposable); });
return result.finally(() => {
disposable.dispose();
this.activeRequests.delete(disposable);
});
}
private requestEvent(channelName: string, name: string, arg?: any): Event<any> {
@@ -795,6 +798,8 @@ export class IPCServer<TContext = string> implements IChannelServer<TContext>, I
private readonly _onDidRemoveConnection = new Emitter<Connection<TContext>>();
readonly onDidRemoveConnection: Event<Connection<TContext>> = this._onDidRemoveConnection.event;
private disposables = new DisposableStore();
get connections(): Connection<TContext>[] {
const result: Connection<TContext>[] = [];
this._connections.forEach(ctx => result.push(ctx));
@@ -802,10 +807,10 @@ export class IPCServer<TContext = string> implements IChannelServer<TContext>, I
}
constructor(onDidClientConnect: Event<ClientConnectionEvent>) {
onDidClientConnect(({ protocol, onDidClientDisconnect }) => {
this.disposables.add(onDidClientConnect(({ protocol, onDidClientDisconnect }) => {
const onFirstMessage = Event.once(protocol.onMessage);
onFirstMessage(msg => {
this.disposables.add(onFirstMessage(msg => {
const reader = new BufferReader(msg);
const ctx = deserialize(reader) as TContext;
@@ -818,14 +823,14 @@ export class IPCServer<TContext = string> implements IChannelServer<TContext>, I
this._connections.add(connection);
this._onDidAddConnection.fire(connection);
onDidClientDisconnect(() => {
this.disposables.add(onDidClientDisconnect(() => {
channelServer.dispose();
channelClient.dispose();
this._connections.delete(connection);
this._onDidRemoveConnection.fire(connection);
});
});
});
}));
}));
}));
}
/**
@@ -879,7 +884,7 @@ export class IPCServer<TContext = string> implements IChannelServer<TContext>, I
private getMulticastEvent<T extends IChannel>(channelName: string, clientFilter: (client: Client<TContext>) => boolean, eventName: string, arg: any): Event<T> {
const that = this;
let disposables = new DisposableStore();
let disposables: DisposableStore | undefined;
// Create an emitter which hooks up to all clients
// as soon as first listener is added. It also
@@ -922,7 +927,8 @@ export class IPCServer<TContext = string> implements IChannelServer<TContext>, I
disposables.add(eventMultiplexer);
},
onDidRemoveLastListener: () => {
disposables.dispose();
disposables?.dispose();
disposables = undefined;
}
});
@@ -932,14 +938,21 @@ export class IPCServer<TContext = string> implements IChannelServer<TContext>, I
registerChannel(channelName: string, channel: IServerChannel<TContext>): void {
this.channels.set(channelName, channel);
this._connections.forEach(connection => {
for (const connection of this._connections) {
connection.channelServer.registerChannel(channelName, channel);
});
}
}
dispose(): void {
this.channels.clear();
this.disposables.dispose();
for (const connection of this._connections) {
connection.channelClient.dispose();
connection.channelServer.dispose();
}
this._connections.clear();
this.channels.clear();
this._onDidAddConnection.dispose();
this._onDidRemoveConnection.dispose();
}
@@ -1074,7 +1087,7 @@ export namespace ProxyChannel {
export interface ICreateServiceChannelOptions extends IProxyOptions { }
export function fromService<TContext>(service: unknown, options?: ICreateServiceChannelOptions): IServerChannel<TContext> {
export function fromService<TContext>(service: unknown, disposables: DisposableStore, options?: ICreateServiceChannelOptions): IServerChannel<TContext> {
const handler = service as { [key: string]: unknown };
const disableMarshalling = options && options.disableMarshalling;
@@ -1083,7 +1096,7 @@ export namespace ProxyChannel {
const mapEventNameToEvent = new Map<string, Event<unknown>>();
for (const key in handler) {
if (propertyIsEvent(key)) {
mapEventNameToEvent.set(key, Event.buffer(handler[key] as Event<unknown>, true));
mapEventNameToEvent.set(key, Event.buffer(handler[key] as Event<unknown>, true, undefined, disposables));
}
}
+40 -38
View File
@@ -9,9 +9,11 @@ import { VSBuffer } from 'vs/base/common/buffer';
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
import { canceled } from 'vs/base/common/errors';
import { Emitter, Event } from 'vs/base/common/event';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { isEqual } from 'vs/base/common/resources';
import { URI } from 'vs/base/common/uri';
import { BufferReader, BufferWriter, ClientConnectionEvent, deserialize, IChannel, IMessagePassingProtocol, IPCClient, IPCServer, IServerChannel, ProxyChannel, serialize } from 'vs/base/parts/ipc/common/ipc';
import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils';
class QueueProtocol implements IMessagePassingProtocol {
@@ -111,6 +113,8 @@ interface ITestService {
class TestService implements ITestService {
private disposables = new DisposableStore();
private readonly _onPong = new Emitter<string>();
readonly onPong = this._onPong.event;
@@ -131,7 +135,7 @@ class TestService implements ITestService {
return Promise.reject(canceled());
}
return new Promise((_, e) => cancellationToken.onCancellationRequested(() => e(canceled())));
return new Promise((_, e) => this.disposables.add(cancellationToken.onCancellationRequested(() => e(canceled()))));
}
buffersLength(buffers: VSBuffer[]): Promise<number> {
@@ -149,6 +153,10 @@ class TestService implements ITestService {
context(context?: unknown): Promise<unknown> {
return Promise.resolve(context);
}
dispose() {
this.disposables.dispose();
}
}
class TestChannel implements IServerChannel {
@@ -213,6 +221,8 @@ class TestChannelClient implements ITestService {
suite('Base IPC', function () {
const store = ensureNoDisposablesAreLeakedInTestSuite();
test('createProtocolPair', async function () {
const [clientProtocol, serverProtocol] = createProtocolPair();
@@ -236,21 +246,16 @@ suite('Base IPC', function () {
let ipcService: ITestService;
setup(function () {
service = new TestService();
const testServer = new TestIPCServer();
service = store.add(new TestService());
const testServer = store.add(new TestIPCServer());
server = testServer;
server.registerChannel(TestChannelId, new TestChannel(service));
client = testServer.createConnection('client1');
client = store.add(testServer.createConnection('client1'));
ipcService = new TestChannelClient(client.getChannel(TestChannelId));
});
teardown(function () {
client.dispose();
server.dispose();
});
test('call success', async function () {
const r = await ipcService.marco();
return assert.strictEqual(r, 'polo');
@@ -301,7 +306,7 @@ suite('Base IPC', function () {
test('listen to events', async function () {
const messages: string[] = [];
ipcService.onPong(msg => messages.push(msg));
store.add(ipcService.onPong(msg => messages.push(msg)));
await timeout(0);
assert.deepStrictEqual(messages, []);
@@ -343,20 +348,21 @@ suite('Base IPC', function () {
let service: TestService;
let ipcService: ITestService;
const disposables = new DisposableStore();
setup(function () {
service = new TestService();
const testServer = new TestIPCServer();
service = store.add(new TestService());
const testServer = disposables.add(new TestIPCServer());
server = testServer;
server.registerChannel(TestChannelId, ProxyChannel.fromService(service));
server.registerChannel(TestChannelId, ProxyChannel.fromService(service, disposables));
client = testServer.createConnection('client1');
client = disposables.add(testServer.createConnection('client1'));
ipcService = ProxyChannel.toService(client.getChannel(TestChannelId));
});
teardown(function () {
client.dispose();
server.dispose();
disposables.clear();
});
test('call success', async function () {
@@ -376,7 +382,7 @@ suite('Base IPC', function () {
test('listen to events', async function () {
const messages: string[] = [];
ipcService.onPong(msg => messages.push(msg));
disposables.add(ipcService.onPong(msg => messages.push(msg)));
await timeout(0);
assert.deepStrictEqual(messages, []);
@@ -409,20 +415,21 @@ suite('Base IPC', function () {
let service: TestService;
let ipcService: ITestService;
const disposables = new DisposableStore();
setup(function () {
service = new TestService();
const testServer = new TestIPCServer();
service = store.add(new TestService());
const testServer = disposables.add(new TestIPCServer());
server = testServer;
server.registerChannel(TestChannelId, ProxyChannel.fromService(service));
server.registerChannel(TestChannelId, ProxyChannel.fromService(service, disposables));
client = testServer.createConnection('client1');
client = disposables.add(testServer.createConnection('client1'));
ipcService = ProxyChannel.toService(client.getChannel(TestChannelId), { context: 'Super Context' });
});
teardown(function () {
client.dispose();
server.dispose();
disposables.clear();
});
test('call extra context', async function () {
@@ -433,20 +440,20 @@ suite('Base IPC', function () {
suite('one to many', function () {
test('all clients get pinged', async function () {
const service = new TestService();
const service = store.add(new TestService());
const channel = new TestChannel(service);
const server = new TestIPCServer();
const server = store.add(new TestIPCServer());
server.registerChannel('channel', channel);
let client1GotPinged = false;
const client1 = server.createConnection('client1');
const client1 = store.add(server.createConnection('client1'));
const ipcService1 = new TestChannelClient(client1.getChannel('channel'));
ipcService1.onPong(() => client1GotPinged = true);
store.add(ipcService1.onPong(() => client1GotPinged = true));
let client2GotPinged = false;
const client2 = server.createConnection('client2');
const client2 = store.add(server.createConnection('client2'));
const ipcService2 = new TestChannelClient(client2.getChannel('channel'));
ipcService2.onPong(() => client2GotPinged = true);
store.add(ipcService2.onPong(() => client2GotPinged = true));
await timeout(1);
service.ping('hello');
@@ -454,24 +461,20 @@ suite('Base IPC', function () {
await timeout(1);
assert(client1GotPinged, 'client 1 got pinged');
assert(client2GotPinged, 'client 2 got pinged');
client1.dispose();
client2.dispose();
server.dispose();
});
test('server gets pings from all clients (broadcast channel)', async function () {
const server = new TestIPCServer();
const server = store.add(new TestIPCServer());
const client1 = server.createConnection('client1');
const clientService1 = new TestService();
const clientService1 = store.add(new TestService());
const clientChannel1 = new TestChannel(clientService1);
client1.registerChannel('channel', clientChannel1);
const pings: string[] = [];
const channel = server.getChannel('channel', () => true);
const service = new TestChannelClient(channel);
service.onPong(msg => pings.push(msg));
store.add(service.onPong(msg => pings.push(msg)));
await timeout(1);
clientService1.ping('hello 1');
@@ -480,7 +483,7 @@ suite('Base IPC', function () {
assert.deepStrictEqual(pings, ['hello 1']);
const client2 = server.createConnection('client2');
const clientService2 = new TestService();
const clientService2 = store.add(new TestService());
const clientChannel2 = new TestChannel(clientService2);
client2.registerChannel('channel', clientChannel2);
@@ -503,7 +506,6 @@ suite('Base IPC', function () {
assert.deepStrictEqual(pings, ['hello 1', 'hello 2', 'hello again 2']);
client2.dispose();
server.dispose();
});
});
});
+5 -7
View File
@@ -123,7 +123,7 @@ export class Storage extends Disposable implements IStorage {
private cache = new Map<string, string>();
private readonly flushDelayer = new ThrottledDelayer<void>(Storage.DEFAULT_FLUSH_DELAY);
private readonly flushDelayer = this._register(new ThrottledDelayer<void>(Storage.DEFAULT_FLUSH_DELAY));
private pendingDeletes = new Set<string>();
private pendingInserts = new Map<string, string>();
@@ -392,6 +392,10 @@ export class Storage extends Disposable implements IStorage {
}
private async doFlush(delay?: number): Promise<void> {
if (this.options.hint === StorageHint.STORAGE_IN_MEMORY) {
return this.flushPending(); // return early if in-memory
}
return this.flushDelayer.trigger(() => this.flushPending(), delay);
}
@@ -406,12 +410,6 @@ export class Storage extends Disposable implements IStorage {
isInMemory(): boolean {
return this.options.hint === StorageHint.STORAGE_IN_MEMORY;
}
override dispose(): void {
this.flushDelayer.dispose();
super.dispose();
}
}
export class InMemoryStorageDatabase implements IStorageDatabase {
+8 -5
View File
@@ -6,16 +6,19 @@
import * as assert from 'assert';
import { ActionBar, prepareActions } from 'vs/base/browser/ui/actionbar/actionbar';
import { Action, Separator } from 'vs/base/common/actions';
import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils';
suite('Actionbar', () => {
const store = ensureNoDisposablesAreLeakedInTestSuite();
test('prepareActions()', function () {
const a1 = new Separator();
const a2 = new Separator();
const a3 = new Action('a3');
const a3 = store.add(new Action('a3'));
const a4 = new Separator();
const a5 = new Separator();
const a6 = new Action('a6');
const a6 = store.add(new Action('a6'));
const a7 = new Separator();
const actions = prepareActions([a1, a2, a3, a4, a5, a6, a7]);
@@ -27,10 +30,10 @@ suite('Actionbar', () => {
test('hasAction()', function () {
const container = document.createElement('div');
const actionbar = new ActionBar(container);
const actionbar = store.add(new ActionBar(container));
const a1 = new Action('a1');
const a2 = new Action('a2');
const a1 = store.add(new Action('a1'));
const a2 = store.add(new Action('a2'));
actionbar.push(a1);
assert.strictEqual(actionbar.hasAction(a1), true);
@@ -5,6 +5,7 @@
import * as assert from 'assert';
import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel';
import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils';
suite('HighlightedLabel', () => {
let label: HighlightedLabel;
@@ -58,6 +59,7 @@ suite('HighlightedLabel', () => {
escaped = HighlightedLabel.escapeNewLines('ACTION\r\n_TYPE2', highlights);
assert.strictEqual(escaped, 'ACTION\u23CE_TYPE2');
assert.deepStrictEqual(highlights, [{ start: 5, end: 8 }, { start: 10, end: 11 }]);
});
ensureNoDisposablesAreLeakedInTestSuite();
});
@@ -5,6 +5,7 @@
import * as assert from 'assert';
import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar';
import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils';
suite('ProgressBar', () => {
let fixture: HTMLElement;
@@ -29,4 +30,6 @@ suite('ProgressBar', () => {
bar.dispose();
});
ensureNoDisposablesAreLeakedInTestSuite();
});
+137 -130
View File
@@ -8,6 +8,8 @@ import { createSerializedGrid, Direction, getRelativeLocation, Grid, GridNode, G
import { Event } from 'vs/base/common/event';
import { deepClone } from 'vs/base/common/objects';
import { nodesToArrays, TestView } from './util';
import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils';
import { DisposableStore } from 'vs/base/common/lifecycle';
// Simple example:
//
@@ -30,6 +32,8 @@ import { nodesToArrays, TestView } from './util';
// +-3
suite('Grid', function () {
const store = ensureNoDisposablesAreLeakedInTestSuite();
let container: HTMLElement;
setup(function () {
@@ -72,8 +76,8 @@ suite('Grid', function () {
});
test('empty', () => {
const view1 = new TestView(100, Number.MAX_VALUE, 100, Number.MAX_VALUE);
const gridview = new Grid(view1);
const view1 = store.add(new TestView(100, Number.MAX_VALUE, 100, Number.MAX_VALUE));
const gridview = store.add(new Grid(view1));
container.appendChild(gridview.element);
gridview.layout(800, 600);
@@ -81,59 +85,59 @@ suite('Grid', function () {
});
test('two views vertically', function () {
const view1 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const grid = new Grid(view1);
const view1 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
const grid = store.add(new Grid(view1));
container.appendChild(grid.element);
grid.layout(800, 600);
assert.deepStrictEqual(view1.size, [800, 600]);
const view2 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view2 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view2, 200, view1, Direction.Up);
assert.deepStrictEqual(view1.size, [800, 400]);
assert.deepStrictEqual(view2.size, [800, 200]);
});
test('two views horizontally', function () {
const view1 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const grid = new Grid(view1);
const view1 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
const grid = store.add(new Grid(view1));
container.appendChild(grid.element);
grid.layout(800, 600);
assert.deepStrictEqual(view1.size, [800, 600]);
const view2 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view2 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view2, 300, view1, Direction.Right);
assert.deepStrictEqual(view1.size, [500, 600]);
assert.deepStrictEqual(view2.size, [300, 600]);
});
test('simple layout', function () {
const view1 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const grid = new Grid(view1);
const view1 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
const grid = store.add(new Grid(view1));
container.appendChild(grid.element);
grid.layout(800, 600);
assert.deepStrictEqual(view1.size, [800, 600]);
const view2 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view2 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view2, 200, view1, Direction.Up);
assert.deepStrictEqual(view1.size, [800, 400]);
assert.deepStrictEqual(view2.size, [800, 200]);
const view3 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view3 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view3, 200, view1, Direction.Right);
assert.deepStrictEqual(view1.size, [600, 400]);
assert.deepStrictEqual(view2.size, [800, 200]);
assert.deepStrictEqual(view3.size, [200, 400]);
const view4 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view4 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view4, 200, view2, Direction.Left);
assert.deepStrictEqual(view1.size, [600, 400]);
assert.deepStrictEqual(view2.size, [600, 200]);
assert.deepStrictEqual(view3.size, [200, 400]);
assert.deepStrictEqual(view4.size, [200, 200]);
const view5 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view5 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view5, 100, view1, Direction.Down);
assert.deepStrictEqual(view1.size, [600, 300]);
assert.deepStrictEqual(view2.size, [600, 200]);
@@ -143,32 +147,32 @@ suite('Grid', function () {
});
test('another simple layout with automatic size distribution', function () {
const view1 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const grid = new Grid(view1);
const view1 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
const grid = store.add(new Grid(view1));
container.appendChild(grid.element);
grid.layout(800, 600);
assert.deepStrictEqual(view1.size, [800, 600]);
const view2 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view2 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view2, Sizing.Distribute, view1, Direction.Left);
assert.deepStrictEqual(view1.size, [400, 600]);
assert.deepStrictEqual(view2.size, [400, 600]);
const view3 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view3 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view3, Sizing.Distribute, view1, Direction.Right);
assert.deepStrictEqual(view1.size, [266, 600]);
assert.deepStrictEqual(view2.size, [266, 600]);
assert.deepStrictEqual(view3.size, [268, 600]);
const view4 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view4 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view4, Sizing.Distribute, view2, Direction.Down);
assert.deepStrictEqual(view1.size, [266, 600]);
assert.deepStrictEqual(view2.size, [266, 300]);
assert.deepStrictEqual(view3.size, [268, 600]);
assert.deepStrictEqual(view4.size, [266, 300]);
const view5 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view5 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view5, Sizing.Distribute, view3, Direction.Up);
assert.deepStrictEqual(view1.size, [266, 600]);
assert.deepStrictEqual(view2.size, [266, 300]);
@@ -176,7 +180,7 @@ suite('Grid', function () {
assert.deepStrictEqual(view4.size, [266, 300]);
assert.deepStrictEqual(view5.size, [268, 300]);
const view6 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view6 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view6, Sizing.Distribute, view3, Direction.Down);
assert.deepStrictEqual(view1.size, [266, 600]);
assert.deepStrictEqual(view2.size, [266, 300]);
@@ -187,32 +191,32 @@ suite('Grid', function () {
});
test('another simple layout with split size distribution', function () {
const view1 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const grid = new Grid(view1);
const view1 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
const grid = store.add(new Grid(view1));
container.appendChild(grid.element);
grid.layout(800, 600);
assert.deepStrictEqual(view1.size, [800, 600]);
const view2 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view2 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view2, Sizing.Split, view1, Direction.Left);
assert.deepStrictEqual(view1.size, [400, 600]);
assert.deepStrictEqual(view2.size, [400, 600]);
const view3 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view3 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view3, Sizing.Split, view1, Direction.Right);
assert.deepStrictEqual(view1.size, [200, 600]);
assert.deepStrictEqual(view2.size, [400, 600]);
assert.deepStrictEqual(view3.size, [200, 600]);
const view4 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view4 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view4, Sizing.Split, view2, Direction.Down);
assert.deepStrictEqual(view1.size, [200, 600]);
assert.deepStrictEqual(view2.size, [400, 300]);
assert.deepStrictEqual(view3.size, [200, 600]);
assert.deepStrictEqual(view4.size, [400, 300]);
const view5 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view5 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view5, Sizing.Split, view3, Direction.Up);
assert.deepStrictEqual(view1.size, [200, 600]);
assert.deepStrictEqual(view2.size, [400, 300]);
@@ -220,7 +224,7 @@ suite('Grid', function () {
assert.deepStrictEqual(view4.size, [400, 300]);
assert.deepStrictEqual(view5.size, [200, 300]);
const view6 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view6 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view6, Sizing.Split, view3, Direction.Down);
assert.deepStrictEqual(view1.size, [200, 600]);
assert.deepStrictEqual(view2.size, [400, 300]);
@@ -231,32 +235,32 @@ suite('Grid', function () {
});
test('3/2 layout with split', function () {
const view1 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const grid = new Grid(view1);
const view1 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
const grid = store.add(new Grid(view1));
container.appendChild(grid.element);
grid.layout(800, 600);
assert.deepStrictEqual(view1.size, [800, 600]);
const view2 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view2 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view2, Sizing.Split, view1, Direction.Down);
assert.deepStrictEqual(view1.size, [800, 300]);
assert.deepStrictEqual(view2.size, [800, 300]);
const view3 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view3 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view3, Sizing.Split, view2, Direction.Right);
assert.deepStrictEqual(view1.size, [800, 300]);
assert.deepStrictEqual(view2.size, [400, 300]);
assert.deepStrictEqual(view3.size, [400, 300]);
const view4 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view4 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view4, Sizing.Split, view1, Direction.Right);
assert.deepStrictEqual(view1.size, [400, 300]);
assert.deepStrictEqual(view2.size, [400, 300]);
assert.deepStrictEqual(view3.size, [400, 300]);
assert.deepStrictEqual(view4.size, [400, 300]);
const view5 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view5 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view5, Sizing.Split, view1, Direction.Right);
assert.deepStrictEqual(view1.size, [200, 300]);
assert.deepStrictEqual(view2.size, [400, 300]);
@@ -266,19 +270,19 @@ suite('Grid', function () {
});
test('sizing should be correct after branch demotion #50564', function () {
const view1 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const grid = new Grid(view1);
const view1 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
const grid = store.add(new Grid(view1));
container.appendChild(grid.element);
grid.layout(800, 600);
const view2 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view2 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view2, Sizing.Split, view1, Direction.Right);
const view3 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view3 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view3, Sizing.Split, view2, Direction.Down);
const view4 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view4 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view4, Sizing.Split, view2, Direction.Right);
assert.deepStrictEqual(view1.size, [400, 600]);
assert.deepStrictEqual(view2.size, [200, 300]);
@@ -292,19 +296,19 @@ suite('Grid', function () {
});
test('sizing should be correct after branch demotion #50675', function () {
const view1 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const grid = new Grid(view1);
const view1 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
const grid = store.add(new Grid(view1));
container.appendChild(grid.element);
grid.layout(800, 600);
const view2 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view2 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view2, Sizing.Distribute, view1, Direction.Down);
const view3 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view3 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view3, Sizing.Distribute, view2, Direction.Down);
const view4 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view4 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view4, Sizing.Distribute, view3, Direction.Right);
assert.deepStrictEqual(view1.size, [800, 200]);
assert.deepStrictEqual(view2.size, [800, 200]);
@@ -318,8 +322,8 @@ suite('Grid', function () {
});
test('getNeighborViews should work on single view layout', function () {
const view1 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const grid = new Grid(view1);
const view1 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
const grid = store.add(new Grid(view1));
container.appendChild(grid.element);
grid.layout(800, 600);
@@ -336,16 +340,16 @@ suite('Grid', function () {
});
test('getNeighborViews should work on simple layout', function () {
const view1 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const grid = new Grid(view1);
const view1 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
const grid = store.add(new Grid(view1));
container.appendChild(grid.element);
grid.layout(800, 600);
const view2 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view2 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view2, Sizing.Distribute, view1, Direction.Down);
const view3 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view3 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view3, Sizing.Distribute, view2, Direction.Down);
assert.deepStrictEqual(grid.getNeighborViews(view1, Direction.Up), []);
@@ -380,22 +384,22 @@ suite('Grid', function () {
});
test('getNeighborViews should work on a complex layout', function () {
const view1 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const grid = new Grid(view1);
const view1 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
const grid = store.add(new Grid(view1));
container.appendChild(grid.element);
grid.layout(800, 600);
const view2 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view2 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view2, Sizing.Distribute, view1, Direction.Down);
const view3 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view3 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view3, Sizing.Distribute, view2, Direction.Down);
const view4 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view4 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view4, Sizing.Distribute, view2, Direction.Right);
const view5 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view5 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view5, Sizing.Distribute, view4, Direction.Down);
assert.deepStrictEqual(grid.getNeighborViews(view1, Direction.Up), []);
@@ -421,19 +425,19 @@ suite('Grid', function () {
});
test('getNeighborViews should work on another simple layout', function () {
const view1 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const grid = new Grid(view1);
const view1 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
const grid = store.add(new Grid(view1));
container.appendChild(grid.element);
grid.layout(800, 600);
const view2 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view2 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view2, Sizing.Distribute, view1, Direction.Right);
const view3 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view3 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view3, Sizing.Distribute, view2, Direction.Down);
const view4 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view4 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view4, Sizing.Distribute, view2, Direction.Right);
assert.deepStrictEqual(grid.getNeighborViews(view4, Direction.Up), []);
@@ -443,19 +447,19 @@ suite('Grid', function () {
});
test('getNeighborViews should only return immediate neighbors', function () {
const view1 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const grid = new Grid(view1);
const view1 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
const grid = store.add(new Grid(view1));
container.appendChild(grid.element);
grid.layout(800, 600);
const view2 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view2 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view2, Sizing.Distribute, view1, Direction.Right);
const view3 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view3 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view3, Sizing.Distribute, view2, Direction.Down);
const view4 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view4 = store.add(new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view4, Sizing.Distribute, view2, Direction.Right);
assert.deepStrictEqual(grid.getNeighborViews(view1, Direction.Right), [view2, view3]);
@@ -483,8 +487,10 @@ class TestViewDeserializer implements IViewDeserializer<TestSerializableView> {
private views = new Map<string, TestSerializableView>();
constructor(private readonly store: Pick<DisposableStore, 'add'>) { }
fromJSON(json: any): TestSerializableView {
const view = new TestSerializableView(json.name, 50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view = this.store.add(new TestSerializableView(json.name, 50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
this.views.set(json.name, view);
return view;
}
@@ -508,6 +514,7 @@ function nodesToNames(node: GridNode<TestSerializableView>): any {
suite('SerializableGrid', function () {
const store = ensureNoDisposablesAreLeakedInTestSuite();
let container: HTMLElement;
setup(function () {
@@ -518,8 +525,8 @@ suite('SerializableGrid', function () {
});
test('serialize empty', function () {
const view1 = new TestSerializableView('view1', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const grid = new SerializableGrid(view1);
const view1 = store.add(new TestSerializableView('view1', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
const grid = store.add(new SerializableGrid(view1));
container.appendChild(grid.element);
grid.layout(800, 600);
@@ -545,21 +552,21 @@ suite('SerializableGrid', function () {
});
test('serialize simple layout', function () {
const view1 = new TestSerializableView('view1', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const grid = new SerializableGrid(view1);
const view1 = store.add(new TestSerializableView('view1', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
const grid = store.add(new SerializableGrid(view1));
container.appendChild(grid.element);
grid.layout(800, 600);
const view2 = new TestSerializableView('view2', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view2 = store.add(new TestSerializableView('view2', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view2, 200, view1, Direction.Up);
const view3 = new TestSerializableView('view3', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view3 = store.add(new TestSerializableView('view3', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view3, 200, view1, Direction.Right);
const view4 = new TestSerializableView('view4', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view4 = store.add(new TestSerializableView('view4', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view4, 200, view2, Direction.Left);
const view5 = new TestSerializableView('view5', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view5 = store.add(new TestSerializableView('view5', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view5, 100, view1, Direction.Down);
assert.deepStrictEqual(grid.serialize(), {
@@ -599,45 +606,45 @@ suite('SerializableGrid', function () {
});
test('deserialize empty', function () {
const view1 = new TestSerializableView('view1', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const grid = new SerializableGrid(view1);
const view1 = store.add(new TestSerializableView('view1', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
const grid = store.add(new SerializableGrid(view1));
container.appendChild(grid.element);
grid.layout(800, 600);
const json = grid.serialize();
grid.dispose();
const deserializer = new TestViewDeserializer();
const grid2 = SerializableGrid.deserialize(json, deserializer);
const deserializer = new TestViewDeserializer(store);
const grid2 = store.add(SerializableGrid.deserialize(json, deserializer));
grid2.layout(800, 600);
assert.deepStrictEqual(nodesToNames(grid2.getViews()), ['view1']);
});
test('deserialize simple layout', function () {
const view1 = new TestSerializableView('view1', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const grid = new SerializableGrid(view1);
const view1 = store.add(new TestSerializableView('view1', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
const grid = store.add(new SerializableGrid(view1));
container.appendChild(grid.element);
grid.layout(800, 600);
const view2 = new TestSerializableView('view2', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view2 = store.add(new TestSerializableView('view2', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view2, 200, view1, Direction.Up);
const view3 = new TestSerializableView('view3', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view3 = store.add(new TestSerializableView('view3', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view3, 200, view1, Direction.Right);
const view4 = new TestSerializableView('view4', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view4 = store.add(new TestSerializableView('view4', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view4, 200, view2, Direction.Left);
const view5 = new TestSerializableView('view5', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view5 = store.add(new TestSerializableView('view5', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view5, 100, view1, Direction.Down);
const json = grid.serialize();
grid.dispose();
const deserializer = new TestViewDeserializer();
const grid2 = SerializableGrid.deserialize(json, deserializer);
const deserializer = new TestViewDeserializer(store);
const grid2 = store.add(SerializableGrid.deserialize(json, deserializer));
const view1Copy = deserializer.getView('view1');
const view2Copy = deserializer.getView('view2');
@@ -657,29 +664,29 @@ suite('SerializableGrid', function () {
});
test('deserialize simple layout with scaling', function () {
const view1 = new TestSerializableView('view1', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const grid = new SerializableGrid(view1);
const view1 = store.add(new TestSerializableView('view1', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
const grid = store.add(new SerializableGrid(view1));
container.appendChild(grid.element);
grid.layout(800, 600);
const view2 = new TestSerializableView('view2', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view2 = store.add(new TestSerializableView('view2', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view2, 200, view1, Direction.Up);
const view3 = new TestSerializableView('view3', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view3 = store.add(new TestSerializableView('view3', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view3, 200, view1, Direction.Right);
const view4 = new TestSerializableView('view4', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view4 = store.add(new TestSerializableView('view4', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view4, 200, view2, Direction.Left);
const view5 = new TestSerializableView('view5', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view5 = store.add(new TestSerializableView('view5', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view5, 100, view1, Direction.Down);
const json = grid.serialize();
grid.dispose();
const deserializer = new TestViewDeserializer();
const grid2 = SerializableGrid.deserialize(json, deserializer);
const deserializer = new TestViewDeserializer(store);
const grid2 = store.add(SerializableGrid.deserialize(json, deserializer));
const view1Copy = deserializer.getView('view1');
const view2Copy = deserializer.getView('view2');
@@ -696,25 +703,25 @@ suite('SerializableGrid', function () {
});
test('deserialize 4 view layout (ben issue #2)', function () {
const view1 = new TestSerializableView('view1', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const grid = new SerializableGrid(view1);
const view1 = store.add(new TestSerializableView('view1', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
const grid = store.add(new SerializableGrid(view1));
container.appendChild(grid.element);
grid.layout(800, 600);
const view2 = new TestSerializableView('view2', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view2 = store.add(new TestSerializableView('view2', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view2, Sizing.Split, view1, Direction.Down);
const view3 = new TestSerializableView('view3', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view3 = store.add(new TestSerializableView('view3', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view3, Sizing.Split, view2, Direction.Down);
const view4 = new TestSerializableView('view4', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view4 = store.add(new TestSerializableView('view4', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view4, Sizing.Split, view3, Direction.Right);
const json = grid.serialize();
grid.dispose();
const deserializer = new TestViewDeserializer();
const grid2 = SerializableGrid.deserialize(json, deserializer);
const deserializer = new TestViewDeserializer(store);
const grid2 = store.add(SerializableGrid.deserialize(json, deserializer));
const view1Copy = deserializer.getView('view1');
const view2Copy = deserializer.getView('view2');
@@ -730,20 +737,20 @@ suite('SerializableGrid', function () {
});
test('deserialize 2 view layout (ben issue #3)', function () {
const view1 = new TestSerializableView('view1', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const grid = new SerializableGrid(view1);
const view1 = store.add(new TestSerializableView('view1', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
const grid = store.add(new SerializableGrid(view1));
container.appendChild(grid.element);
grid.layout(800, 600);
const view2 = new TestSerializableView('view2', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view2 = store.add(new TestSerializableView('view2', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view2, Sizing.Split, view1, Direction.Right);
const json = grid.serialize();
grid.dispose();
const deserializer = new TestViewDeserializer();
const grid2 = SerializableGrid.deserialize(json, deserializer);
const deserializer = new TestViewDeserializer(store);
const grid2 = store.add(SerializableGrid.deserialize(json, deserializer));
const view1Copy = deserializer.getView('view1');
const view2Copy = deserializer.getView('view2');
@@ -755,16 +762,16 @@ suite('SerializableGrid', function () {
});
test('deserialize simple view layout #50609', function () {
const view1 = new TestSerializableView('view1', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const grid = new SerializableGrid(view1);
const view1 = store.add(new TestSerializableView('view1', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
const grid = store.add(new SerializableGrid(view1));
container.appendChild(grid.element);
grid.layout(800, 600);
const view2 = new TestSerializableView('view2', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view2 = store.add(new TestSerializableView('view2', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view2, Sizing.Split, view1, Direction.Right);
const view3 = new TestSerializableView('view3', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view3 = store.add(new TestSerializableView('view3', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view3, Sizing.Split, view2, Direction.Down);
grid.removeView(view1, Sizing.Split);
@@ -772,8 +779,8 @@ suite('SerializableGrid', function () {
const json = grid.serialize();
grid.dispose();
const deserializer = new TestViewDeserializer();
const grid2 = SerializableGrid.deserialize(json, deserializer);
const deserializer = new TestViewDeserializer(store);
const grid2 = store.add(SerializableGrid.deserialize(json, deserializer));
const view2Copy = deserializer.getView('view2');
const view3Copy = deserializer.getView('view3');
@@ -835,7 +842,7 @@ suite('SerializableGrid', function () {
}
};
const grid = SerializableGrid.deserialize(serializedGrid, deserializer);
const grid = store.add(SerializableGrid.deserialize(serializedGrid, deserializer));
assert.strictEqual(views.length, 3);
// should not throw
@@ -867,21 +874,21 @@ suite('SerializableGrid', function () {
});
test('serialize should store visibility and previous size', function () {
const view1 = new TestSerializableView('view1', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const grid = new SerializableGrid(view1);
const view1 = store.add(new TestSerializableView('view1', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
const grid = store.add(new SerializableGrid(view1));
container.appendChild(grid.element);
grid.layout(800, 600);
const view2 = new TestSerializableView('view2', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view2 = store.add(new TestSerializableView('view2', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view2, 200, view1, Direction.Up);
const view3 = new TestSerializableView('view3', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view3 = store.add(new TestSerializableView('view3', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view3, 200, view1, Direction.Right);
const view4 = new TestSerializableView('view4', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view4 = store.add(new TestSerializableView('view4', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view4, 200, view2, Direction.Left);
const view5 = new TestSerializableView('view5', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view5 = store.add(new TestSerializableView('view5', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view5, 100, view1, Direction.Down);
assert.deepStrictEqual(view1.size, [600, 300]);
@@ -954,8 +961,8 @@ suite('SerializableGrid', function () {
grid.dispose();
const deserializer = new TestViewDeserializer();
const grid2 = SerializableGrid.deserialize(json, deserializer);
const deserializer = new TestViewDeserializer(store);
const grid2 = store.add(SerializableGrid.deserialize(json, deserializer));
const view1Copy = deserializer.getView('view1');
const view2Copy = deserializer.getView('view2');
@@ -994,21 +1001,21 @@ suite('SerializableGrid', function () {
});
test('serialize should store visibility and previous size even for first leaf', function () {
const view1 = new TestSerializableView('view1', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const grid = new SerializableGrid(view1);
const view1 = store.add(new TestSerializableView('view1', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
const grid = store.add(new SerializableGrid(view1));
container.appendChild(grid.element);
grid.layout(800, 600);
const view2 = new TestSerializableView('view2', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view2 = store.add(new TestSerializableView('view2', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view2, 200, view1, Direction.Up);
const view3 = new TestSerializableView('view3', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view3 = store.add(new TestSerializableView('view3', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view3, 200, view1, Direction.Right);
const view4 = new TestSerializableView('view4', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view4 = store.add(new TestSerializableView('view4', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view4, 200, view2, Direction.Left);
const view5 = new TestSerializableView('view5', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
const view5 = store.add(new TestSerializableView('view5', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE));
grid.addView(view5, 100, view1, Direction.Down);
assert.deepStrictEqual(view1.size, [600, 300]);
@@ -1063,8 +1070,8 @@ suite('SerializableGrid', function () {
grid.dispose();
const deserializer = new TestViewDeserializer();
const grid2 = SerializableGrid.deserialize(json, deserializer);
const deserializer = new TestViewDeserializer(store);
const grid2 = store.add(SerializableGrid.deserialize(json, deserializer));
const view1Copy = deserializer.getView('view1');
const view2Copy = deserializer.getView('view2');
@@ -7,36 +7,41 @@ import * as assert from 'assert';
import { $ } from 'vs/base/browser/dom';
import { GridView, IView, Orientation, Sizing } from 'vs/base/browser/ui/grid/gridview';
import { nodesToArrays, TestView } from './util';
import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils';
suite('Gridview', function () {
let gridview: GridView;
setup(function () {
gridview = new GridView();
const store = ensureNoDisposablesAreLeakedInTestSuite();
function createGridView(): GridView {
const gridview = store.add(new GridView());
const container = $('.container');
container.style.position = 'absolute';
container.style.width = `${200}px`;
container.style.height = `${200}px`;
container.appendChild(gridview.element);
});
return gridview;
}
test('empty gridview is empty', function () {
const gridview = createGridView();
assert.deepStrictEqual(nodesToArrays(gridview.getView()), []);
gridview.dispose();
});
test('gridview addView', function () {
const gridview = createGridView();
const view = new TestView(20, 20, 20, 20);
const view = store.add(new TestView(20, 20, 20, 20));
assert.throws(() => gridview.addView(view, 200, []), 'empty location');
assert.throws(() => gridview.addView(view, 200, [1]), 'index overflow');
assert.throws(() => gridview.addView(view, 200, [0, 0]), 'hierarchy overflow');
const views = [
new TestView(20, 20, 20, 20),
new TestView(20, 20, 20, 20),
new TestView(20, 20, 20, 20)
store.add(new TestView(20, 20, 20, 20)),
store.add(new TestView(20, 20, 20, 20)),
store.add(new TestView(20, 20, 20, 20))
];
gridview.addView(views[0], 200, [0]);
@@ -44,17 +49,16 @@ suite('Gridview', function () {
gridview.addView(views[2], 200, [2]);
assert.deepStrictEqual(nodesToArrays(gridview.getView()), views);
gridview.dispose();
});
test('gridview addView nested', function () {
const gridview = createGridView();
const views = [
new TestView(20, 20, 20, 20),
store.add(new TestView(20, 20, 20, 20)),
[
new TestView(20, 20, 20, 20),
new TestView(20, 20, 20, 20)
store.add(new TestView(20, 20, 20, 20)),
store.add(new TestView(20, 20, 20, 20))
]
];
@@ -63,63 +67,61 @@ suite('Gridview', function () {
gridview.addView((views[1] as TestView[])[1] as IView, 200, [1, 1]);
assert.deepStrictEqual(nodesToArrays(gridview.getView()), views);
gridview.dispose();
});
test('gridview addView deep nested', function () {
const gridview = createGridView();
const view1 = new TestView(20, 20, 20, 20);
const view1 = store.add(new TestView(20, 20, 20, 20));
gridview.addView(view1 as IView, 200, [0]);
assert.deepStrictEqual(nodesToArrays(gridview.getView()), [view1]);
const view2 = new TestView(20, 20, 20, 20);
const view2 = store.add(new TestView(20, 20, 20, 20));
gridview.addView(view2 as IView, 200, [1]);
assert.deepStrictEqual(nodesToArrays(gridview.getView()), [view1, view2]);
const view3 = new TestView(20, 20, 20, 20);
const view3 = store.add(new TestView(20, 20, 20, 20));
gridview.addView(view3 as IView, 200, [1, 0]);
assert.deepStrictEqual(nodesToArrays(gridview.getView()), [view1, [view3, view2]]);
const view4 = new TestView(20, 20, 20, 20);
const view4 = store.add(new TestView(20, 20, 20, 20));
gridview.addView(view4 as IView, 200, [1, 0, 0]);
assert.deepStrictEqual(nodesToArrays(gridview.getView()), [view1, [[view4, view3], view2]]);
const view5 = new TestView(20, 20, 20, 20);
const view5 = store.add(new TestView(20, 20, 20, 20));
gridview.addView(view5 as IView, 200, [1, 0]);
assert.deepStrictEqual(nodesToArrays(gridview.getView()), [view1, [view5, [view4, view3], view2]]);
const view6 = new TestView(20, 20, 20, 20);
const view6 = store.add(new TestView(20, 20, 20, 20));
gridview.addView(view6 as IView, 200, [2]);
assert.deepStrictEqual(nodesToArrays(gridview.getView()), [view1, [view5, [view4, view3], view2], view6]);
const view7 = new TestView(20, 20, 20, 20);
const view7 = store.add(new TestView(20, 20, 20, 20));
gridview.addView(view7 as IView, 200, [1, 1]);
assert.deepStrictEqual(nodesToArrays(gridview.getView()), [view1, [view5, view7, [view4, view3], view2], view6]);
const view8 = new TestView(20, 20, 20, 20);
const view8 = store.add(new TestView(20, 20, 20, 20));
gridview.addView(view8 as IView, 200, [1, 1, 0]);
assert.deepStrictEqual(nodesToArrays(gridview.getView()), [view1, [view5, [view8, view7], [view4, view3], view2], view6]);
gridview.dispose();
});
test('simple layout', function () {
const gridview = createGridView();
gridview.layout(800, 600);
const view1 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
const view1 = store.add(new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY));
gridview.addView(view1, 200, [0]);
assert.deepStrictEqual(view1.size, [800, 600]);
assert.deepStrictEqual(gridview.getViewSize([0]), { width: 800, height: 600 });
const view2 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
const view2 = store.add(new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY));
gridview.addView(view2, 200, [0]);
assert.deepStrictEqual(view1.size, [800, 400]);
assert.deepStrictEqual(gridview.getViewSize([1]), { width: 800, height: 400 });
assert.deepStrictEqual(view2.size, [800, 200]);
assert.deepStrictEqual(gridview.getViewSize([0]), { width: 800, height: 200 });
const view3 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
const view3 = store.add(new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY));
gridview.addView(view3, 200, [1, 1]);
assert.deepStrictEqual(view1.size, [600, 400]);
assert.deepStrictEqual(gridview.getViewSize([1, 0]), { width: 600, height: 400 });
@@ -128,7 +130,7 @@ suite('Gridview', function () {
assert.deepStrictEqual(view3.size, [200, 400]);
assert.deepStrictEqual(gridview.getViewSize([1, 1]), { width: 200, height: 400 });
const view4 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
const view4 = store.add(new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY));
gridview.addView(view4, 200, [0, 0]);
assert.deepStrictEqual(view1.size, [600, 400]);
assert.deepStrictEqual(gridview.getViewSize([1, 0]), { width: 600, height: 400 });
@@ -139,7 +141,7 @@ suite('Gridview', function () {
assert.deepStrictEqual(view4.size, [200, 200]);
assert.deepStrictEqual(gridview.getViewSize([0, 0]), { width: 200, height: 200 });
const view5 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
const view5 = store.add(new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY));
gridview.addView(view5, 100, [1, 0, 1]);
assert.deepStrictEqual(view1.size, [600, 300]);
assert.deepStrictEqual(gridview.getViewSize([1, 0, 0]), { width: 600, height: 300 });
@@ -154,32 +156,33 @@ suite('Gridview', function () {
});
test('simple layout with automatic size distribution', function () {
const gridview = createGridView();
gridview.layout(800, 600);
const view1 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
const view1 = store.add(new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY));
gridview.addView(view1, Sizing.Distribute, [0]);
assert.deepStrictEqual(view1.size, [800, 600]);
assert.deepStrictEqual(gridview.getViewSize([0]), { width: 800, height: 600 });
const view2 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
const view2 = store.add(new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY));
gridview.addView(view2, Sizing.Distribute, [0]);
assert.deepStrictEqual(view1.size, [800, 300]);
assert.deepStrictEqual(view2.size, [800, 300]);
const view3 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
const view3 = store.add(new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY));
gridview.addView(view3, Sizing.Distribute, [1, 1]);
assert.deepStrictEqual(view1.size, [400, 300]);
assert.deepStrictEqual(view2.size, [800, 300]);
assert.deepStrictEqual(view3.size, [400, 300]);
const view4 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
const view4 = store.add(new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY));
gridview.addView(view4, Sizing.Distribute, [0, 0]);
assert.deepStrictEqual(view1.size, [400, 300]);
assert.deepStrictEqual(view2.size, [400, 300]);
assert.deepStrictEqual(view3.size, [400, 300]);
assert.deepStrictEqual(view4.size, [400, 300]);
const view5 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
const view5 = store.add(new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY));
gridview.addView(view5, Sizing.Distribute, [1, 0, 1]);
assert.deepStrictEqual(view1.size, [400, 150]);
assert.deepStrictEqual(view2.size, [400, 300]);
@@ -189,14 +192,15 @@ suite('Gridview', function () {
});
test('addviews before layout call 1', function () {
const gridview = createGridView();
const view1 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
const view1 = store.add(new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY));
gridview.addView(view1, 200, [0]);
const view2 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
const view2 = store.add(new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY));
gridview.addView(view2, 200, [0]);
const view3 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
const view3 = store.add(new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY));
gridview.addView(view3, 200, [1, 1]);
gridview.layout(800, 600);
@@ -207,13 +211,14 @@ suite('Gridview', function () {
});
test('addviews before layout call 2', function () {
const view1 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
const gridview = createGridView();
const view1 = store.add(new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY));
gridview.addView(view1, 200, [0]);
const view2 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
const view2 = store.add(new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY));
gridview.addView(view2, 200, [0]);
const view3 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
const view3 = store.add(new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY));
gridview.addView(view3, 200, [0, 0]);
gridview.layout(800, 600);
@@ -224,10 +229,11 @@ suite('Gridview', function () {
});
test('flipping orientation should preserve absolute offsets', function () {
const view1 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
const gridview = createGridView();
const view1 = store.add(new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY));
gridview.addView(view1, 200, [0]);
const view2 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
const view2 = store.add(new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY));
gridview.addView(view2, 200, [1]);
gridview.layout(800, 600, 100, 200);

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