Merge branch 'main' into fix-200571

This commit is contained in:
John Murray
2023-12-13 09:48:33 +00:00
committed by GitHub
126 changed files with 1764 additions and 923 deletions
+14 -14
View File
@@ -7,7 +7,7 @@
{
"kind": 2,
"language": "github-issues",
"value": "// list of repos we work in\n$REPOS=repo:microsoft/lsprotocol repo:microsoft/monaco-editor repo:microsoft/vscode repo:microsoft/vscode-anycode repo:microsoft/vscode-autopep8 repo:microsoft/vscode-black-formatter repo:microsoft/vscode-copilot repo:microsoft/vscode-copilot-release repo:microsoft/vscode-dev repo:microsoft/vscode-dev-chrome-launcher repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-flake8 repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-hexeditor repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-isort repo:microsoft/vscode-js-debug repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-l10n repo:microsoft/vscode-livepreview repo:microsoft/vscode-markdown-languageservice repo:microsoft/vscode-markdown-tm-grammar repo:microsoft/vscode-mypy repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-pylint repo:microsoft/vscode-python repo:microsoft/vscode-python-debugger repo:microsoft/vscode-python-tools-extension-template repo:microsoft/vscode-references-view repo:microsoft/vscode-remote-release repo:microsoft/vscode-remote-repositories-github repo:microsoft/vscode-remote-tunnels repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-unpkg repo:microsoft/vscode-vsce\n\n// current milestone name\n$MILESTONE=milestone:\"November 2023\"\n"
"value": "// list of repos we work in\r\n$REPOS=repo:microsoft/lsprotocol repo:microsoft/monaco-editor repo:microsoft/vscode repo:microsoft/vscode-anycode repo:microsoft/vscode-autopep8 repo:microsoft/vscode-black-formatter repo:microsoft/vscode-copilot repo:microsoft/vscode-copilot-release repo:microsoft/vscode-dev repo:microsoft/vscode-dev-chrome-launcher repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-flake8 repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-hexeditor repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-isort repo:microsoft/vscode-js-debug repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-l10n repo:microsoft/vscode-livepreview repo:microsoft/vscode-markdown-languageservice repo:microsoft/vscode-markdown-tm-grammar repo:microsoft/vscode-mypy repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-pylint repo:microsoft/vscode-python repo:microsoft/vscode-python-debugger repo:microsoft/vscode-python-tools-extension-template repo:microsoft/vscode-references-view repo:microsoft/vscode-remote-release repo:microsoft/vscode-remote-repositories-github repo:microsoft/vscode-remote-tunnels repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-unpkg repo:microsoft/vscode-vsce\r\n\r\n// current milestone name\r\n$MILESTONE=milestone:\"December / January 2024\"\r\n"
},
{
"kind": 1,
@@ -17,7 +17,7 @@
{
"kind": 2,
"language": "github-issues",
"value": "$REPOS $MILESTONE assignee:@me is:open\n"
"value": "$REPOS $MILESTONE assignee:@me is:open\r\n"
},
{
"kind": 1,
@@ -32,7 +32,7 @@
{
"kind": 2,
"language": "github-issues",
"value": "$REPOS assignee:@me is:open label:bug\n"
"value": "$REPOS assignee:@me is:open label:bug\r\n"
},
{
"kind": 1,
@@ -42,7 +42,7 @@
{
"kind": 2,
"language": "github-issues",
"value": "$REPOS assignee:@me is:open label:debt,engineering\n"
"value": "$REPOS assignee:@me is:open label:debt,engineering\r\n"
},
{
"kind": 1,
@@ -52,7 +52,7 @@
{
"kind": 2,
"language": "github-issues",
"value": "$REPOS assignee:@me is:open label:perf,perf-startup,perf-bloat,freeze-slow-crash-leak\n"
"value": "$REPOS assignee:@me is:open label:perf,perf-startup,perf-bloat,freeze-slow-crash-leak\r\n"
},
{
"kind": 1,
@@ -62,12 +62,12 @@
{
"kind": 2,
"language": "github-issues",
"value": "$REPOS assignee:@me is:open label:feature-request milestone:Backlog sort:reactions-+1-desc\n"
"value": "$REPOS assignee:@me is:open label:feature-request milestone:Backlog sort:reactions-+1-desc\r\n"
},
{
"kind": 2,
"language": "github-issues",
"value": "$REPOS assignee:@me is:open milestone:\"Backlog Candidates\"\n"
"value": "$REPOS assignee:@me is:open milestone:\"Backlog Candidates\"\r\n"
},
{
"kind": 1,
@@ -82,7 +82,7 @@
{
"kind": 2,
"language": "github-issues",
"value": "repo:microsoft/vscode is:open assignee:@me label:triage-needed\n"
"value": "repo:microsoft/vscode is:open assignee:@me label:triage-needed\r\n"
},
{
"kind": 1,
@@ -92,7 +92,7 @@
{
"kind": 2,
"language": "github-issues",
"value": "$REPOS assignee:@me is:open type:issue -label:bug -label:\"info-needed\" -label:feature-request -label:under-discussion -label:debt -label:plan-item -label:upstream -label:polish -label:testplan-item -label:error-telemetry -label:engineering\n"
"value": "$REPOS assignee:@me is:open type:issue -label:bug -label:\"info-needed\" -label:feature-request -label:under-discussion -label:debt -label:plan-item -label:upstream -label:polish -label:testplan-item -label:error-telemetry -label:engineering\r\n"
},
{
"kind": 1,
@@ -112,7 +112,7 @@
{
"kind": 2,
"language": "github-issues",
"value": "$REPOS assignee:@me is:open type:issue no:milestone -label:info-needed -label:triage-needed\n"
"value": "$REPOS assignee:@me is:open type:issue no:milestone -label:info-needed -label:triage-needed\r\n"
},
{
"kind": 1,
@@ -122,7 +122,7 @@
{
"kind": 2,
"language": "github-issues",
"value": "$REPOS assignee:@me is:open label:\"info-needed\"\n"
"value": "$REPOS assignee:@me is:open label:\"info-needed\"\r\n"
},
{
"kind": 1,
@@ -137,7 +137,7 @@
{
"kind": 2,
"language": "github-issues",
"value": "$REPOS author:@me is:open is:pr review:approved\n"
"value": "$REPOS author:@me is:open is:pr review:approved\r\n"
},
{
"kind": 1,
@@ -147,7 +147,7 @@
{
"kind": 2,
"language": "github-issues",
"value": "$REPOS author:@me is:open is:pr review:required\n"
"value": "$REPOS author:@me is:open is:pr review:required\r\n"
},
{
"kind": 1,
@@ -157,6 +157,6 @@
{
"kind": 2,
"language": "github-issues",
"value": "$REPOS author:@me is:open is:pr review:changes_requested\n"
"value": "$REPOS author:@me is:open is:pr review:changes_requested\r\n"
}
]
+2 -1
View File
@@ -6,7 +6,8 @@ There are several ways in which you can contribute, beyond writing code. The goa
## Asking Questions
Have a question? Instead of opening an issue, please ask on [Stack Overflow](https://stackoverflow.com/questions/tagged/vscode) using the tag `vscode`.
Have a question? Instead of opening an issue, please ask on [Stack Overflow](https://stackoverflow.com/questions/tagged/visual-studio-code) using the tag `visual-studio-code`.
The active community will be eager to assist you. Your well-worded question will serve as a resource to others searching for help.
+1 -1
View File
@@ -1 +1 @@
2023-09-06T09:54:45.225Z
2023-12-07T16:21:36.646Z
@@ -38,14 +38,45 @@ steps:
${{ pair.key }}: ${{ pair.value }}
- ${{ else }}:
- script: cargo build --release --target ${{ parameters.VSCODE_CLI_TARGET }} --bin=code
displayName: Compile ${{ parameters.VSCODE_CLI_TARGET }}
workingDirectory: $(Build.SourcesDirectory)/cli
env:
CARGO_NET_GIT_FETCH_WITH_CLI: true
VSCODE_CLI_COMMIT: $(Build.SourceVersion)
${{ each pair in parameters.VSCODE_CLI_ENV }}:
${{ pair.key }}: ${{ pair.value }}
- ${{ if contains(parameters.VSCODE_CLI_TARGET, '-linux-') }}:
- script: |
set -e
if [ -n "$SYSROOT_ARCH" ]; then
export VSCODE_SYSROOT_DIR=$(Build.SourcesDirectory)/.build/sysroots
node -e '(async () => { const { getVSCodeSysroot } = require("../build/linux/debian/install-sysroot.js"); await getVSCodeSysroot(process.env["SYSROOT_ARCH"]); })()'
if [ "$SYSROOT_ARCH" == "arm64" ]; then
export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER="$VSCODE_SYSROOT_DIR/aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc"
export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUSTFLAGS="-C link-arg=--sysroot=$VSCODE_SYSROOT_DIR/aarch64-linux-gnu/aarch64-linux-gnu/sysroot"
export CC_aarch64_unknown_linux_gnu="$VSCODE_SYSROOT_DIR/aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc --sysroot=$VSCODE_SYSROOT_DIR/aarch64-linux-gnu/aarch64-linux-gnu/sysroot"
elif [ "$SYSROOT_ARCH" == "amd64" ]; then
export CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER="$VSCODE_SYSROOT_DIR/x86_64-linux-gnu/bin/x86_64-linux-gnu-gcc"
export CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUSTFLAGS="-C link-arg=--sysroot=$VSCODE_SYSROOT_DIR/x86_64-linux-gnu/x86_64-linux-gnu/sysroot -C link-arg=-L$VSCODE_SYSROOT_DIR/x86_64-linux-gnu/x86_64-linux-gnu/sysroot/usr/lib/x86_64-linux-gnu"
export CC_x86_64_unknown_linux_gnu="$VSCODE_SYSROOT_DIR/x86_64-linux-gnu/bin/x86_64-linux-gnu-gcc --sysroot=$VSCODE_SYSROOT_DIR/x86_64-linux-gnu/x86_64-linux-gnu/sysroot"
elif [ "$SYSROOT_ARCH" == "armhf" ]; then
export CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER="$VSCODE_SYSROOT_DIR/arm-rpi-linux-gnueabihf/bin/arm-rpi-linux-gnueabihf-gcc"
export CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_RUSTFLAGS="-C link-arg=--sysroot=$VSCODE_SYSROOT_DIR/arm-rpi-linux-gnueabihf/arm-rpi-linux-gnueabihf/sysroot"
export CC_armv7_unknown_linux_gnueabihf="$VSCODE_SYSROOT_DIR/arm-rpi-linux-gnueabihf/bin/arm-rpi-linux-gnueabihf-gcc --sysroot=$VSCODE_SYSROOT_DIR/arm-rpi-linux-gnueabihf/arm-rpi-linux-gnueabihf/sysroot"
fi
fi
cargo build --release --target ${{ parameters.VSCODE_CLI_TARGET }} --bin=code
displayName: Compile ${{ parameters.VSCODE_CLI_TARGET }}
workingDirectory: $(Build.SourcesDirectory)/cli
env:
CARGO_NET_GIT_FETCH_WITH_CLI: true
VSCODE_CLI_COMMIT: $(Build.SourceVersion)
GITHUB_TOKEN: "$(github-distro-mixin-password)"
${{ each pair in parameters.VSCODE_CLI_ENV }}:
${{ pair.key }}: ${{ pair.value }}
- ${{ else }}:
- script: cargo build --release --target ${{ parameters.VSCODE_CLI_TARGET }} --bin=code
displayName: Compile ${{ parameters.VSCODE_CLI_TARGET }}
workingDirectory: $(Build.SourcesDirectory)/cli
env:
CARGO_NET_GIT_FETCH_WITH_CLI: true
VSCODE_CLI_COMMIT: $(Build.SourceVersion)
${{ each pair in parameters.VSCODE_CLI_ENV }}:
${{ pair.key }}: ${{ pair.value }}
- ${{ if contains(parameters.VSCODE_CLI_TARGET, '-windows-') }}:
- powershell: |
@@ -39,13 +39,45 @@ steps:
tar -xvzf $(Build.ArtifactStagingDirectory)/vscode-internal-openssl-prebuilt-0.0.11.tgz --strip-components=1 --directory=$(Build.ArtifactStagingDirectory)/openssl
displayName: Extract openssl prebuilt
- ${{ if eq(parameters.VSCODE_BUILD_LINUX_ARMHF, true) }}:
- bash: sudo apt-get install -yq gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf binutils-arm-linux-gnueabihf
displayName: Install arm32 toolchains
- ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}:
- script: node build/setup-npm-registry.js $NPM_REGISTRY
condition: and(succeeded(), ne(variables['NPM_REGISTRY'], 'none'))
displayName: Setup NPM Registry
- ${{ if eq(parameters.VSCODE_BUILD_LINUX_ARM64, true) }}:
- bash: sudo apt-get install -yq gcc-aarch64-linux-gnu g++-aarch64-linux-gnu binutils-aarch64-linux-gnu
displayName: Install arm64 toolchains
- script: |
set -e
npm config set registry "$NPM_REGISTRY" --location=project
# npm >v7 deprecated the `always-auth` config option, refs npm/cli@72a7eeb
# following is a workaround for yarn to send authorization header
# for GET requests to the registry.
echo "always-auth=true" >> .npmrc
yarn config set registry "$NPM_REGISTRY"
condition: and(succeeded(), ne(variables['NPM_REGISTRY'], 'none'))
displayName: Setup NPM & Yarn
- task: npmAuthenticate@0
inputs:
workingFile: .npmrc
condition: and(succeeded(), ne(variables['NPM_REGISTRY'], 'none'))
displayName: Setup NPM Authentication
- script: |
set -e
for i in {1..5}; do # try 5 times
yarn --cwd build --frozen-lockfile --check-files && break
if [ $i -eq 3 ]; then
echo "Yarn failed too many times" >&2
exit 1
fi
echo "Yarn failed $i, trying again..."
done
displayName: Install build dependencies
- script: |
set -e
mkdir -p $(Build.SourcesDirectory)/.build
displayName: Create .build folder for misc dependencies
- template: ../cli/install-rust-posix.yml
parameters:
@@ -65,9 +97,9 @@ steps:
VSCODE_CLI_ARTIFACT: vscode_cli_linux_arm64_cli
VSCODE_CHECK_ONLY: ${{ parameters.VSCODE_CHECK_ONLY }}
VSCODE_CLI_ENV:
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
OPENSSL_LIB_DIR: $(Build.ArtifactStagingDirectory)/openssl/arm64-linux/lib
OPENSSL_INCLUDE_DIR: $(Build.ArtifactStagingDirectory)/openssl/arm64-linux/include
SYSROOT_ARCH: arm64
- ${{ if eq(parameters.VSCODE_BUILD_LINUX, true) }}:
- template: ../cli/cli-compile-and-publish.yml
@@ -79,6 +111,7 @@ steps:
VSCODE_CLI_ENV:
OPENSSL_LIB_DIR: $(Build.ArtifactStagingDirectory)/openssl/x64-linux/lib
OPENSSL_INCLUDE_DIR: $(Build.ArtifactStagingDirectory)/openssl/x64-linux/include
SYSROOT_ARCH: amd64
- ${{ if eq(parameters.VSCODE_BUILD_LINUX_ARMHF, true) }}:
- template: ../cli/cli-compile-and-publish.yml
@@ -88,6 +121,6 @@ steps:
VSCODE_CLI_ARTIFACT: vscode_cli_linux_armhf_cli
VSCODE_CHECK_ONLY: ${{ parameters.VSCODE_CHECK_ONLY }}
VSCODE_CLI_ENV:
CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER: arm-linux-gnueabihf-gcc
OPENSSL_LIB_DIR: $(Build.ArtifactStagingDirectory)/openssl/arm-linux/lib
OPENSSL_INCLUDE_DIR: $(Build.ArtifactStagingDirectory)/openssl/arm-linux/include
SYSROOT_ARCH: armhf
+30 -7
View File
@@ -5,7 +5,15 @@ set -e
# To workaround the issue of yarn not respecting the registry value from .npmrc
yarn config set registry "$NPM_REGISTRY"
if [ -z "$CC" ] || [ -z "$CXX" ]; then
SYSROOT_ARCH=$VSCODE_ARCH
if [ "$SYSROOT_ARCH" == "x64" ]; then
SYSROOT_ARCH="amd64"
fi
export VSCODE_SYSROOT_DIR=$PWD/.build/sysroots
SYSROOT_ARCH="$SYSROOT_ARCH" node -e '(async () => { const { getVSCodeSysroot } = require("./build/linux/debian/install-sysroot.js"); await getVSCodeSysroot(process.env["SYSROOT_ARCH"]); })()'
if [ "$npm_config_arch" == "x64" ]; then
# Download clang based on chromium revision used by vscode
curl -s https://raw.githubusercontent.com/chromium/chromium/118.0.5993.159/tools/clang/scripts/update.py | python - --output-dir=$PWD/.build/CR_Clang --host-os=linux
@@ -22,12 +30,27 @@ if [ -z "$CC" ] || [ -z "$CXX" ]; then
# https://source.chromium.org/chromium/chromium/src/+/refs/tags/118.0.5993.159:build/config/arm.gni
# https://source.chromium.org/chromium/chromium/src/+/refs/tags/118.0.5993.159:build/config/compiler/BUILD.gn
# https://source.chromium.org/chromium/chromium/src/+/refs/tags/118.0.5993.159:build/config/c++/BUILD.gn
export CC=$PWD/.build/CR_Clang/bin/clang
export CXX=$PWD/.build/CR_Clang/bin/clang++
export CXXFLAGS="-nostdinc++ -D__NO_INLINE__ -I$PWD/.build/libcxx_headers -isystem$PWD/.build/libcxx_headers/include -isystem$PWD/.build/libcxxabi_headers/include -fPIC -flto=thin -fsplit-lto-unit -D_LIBCPP_ABI_NAMESPACE=Cr"
export LDFLAGS="-stdlib=libc++ -fuse-ld=lld -flto=thin -L$PWD/.build/libcxx-objects -lc++abi -Wl,--lto-O0"
export VSCODE_REMOTE_CC=$(which gcc)
export VSCODE_REMOTE_CXX=$(which g++)
export CC="$PWD/.build/CR_Clang/bin/clang --gcc-toolchain=$VSCODE_SYSROOT_DIR/x86_64-linux-gnu"
export CXX="$PWD/.build/CR_Clang/bin/clang++ --gcc-toolchain=$VSCODE_SYSROOT_DIR/x86_64-linux-gnu"
export CXXFLAGS="-nostdinc++ -D__NO_INLINE__ -I$PWD/.build/libcxx_headers -isystem$PWD/.build/libcxx_headers/include -isystem$PWD/.build/libcxxabi_headers/include -fPIC -flto=thin -fsplit-lto-unit -D_LIBCPP_ABI_NAMESPACE=Cr --sysroot=$VSCODE_SYSROOT_DIR/x86_64-linux-gnu/x86_64-linux-gnu/sysroot"
export LDFLAGS="-stdlib=libc++ --sysroot=$VSCODE_SYSROOT_DIR/x86_64-linux-gnu/x86_64-linux-gnu/sysroot -fuse-ld=lld -flto=thin -L$PWD/.build/libcxx-objects -lc++abi -L$VSCODE_SYSROOT_DIR/x86_64-linux-gnu/x86_64-linux-gnu/sysroot/usr/lib/x86_64-linux-gnu -L$VSCODE_SYSROOT_DIR/x86_64-linux-gnu/x86_64-linux-gnu/sysroot/lib/x86_64-linux-gnu -Wl,--lto-O0"
# Set compiler toolchain for remote server
export VSCODE_REMOTE_CC=$VSCODE_SYSROOT_DIR/x86_64-linux-gnu/bin/x86_64-linux-gnu-gcc
export VSCODE_REMOTE_CXX=$VSCODE_SYSROOT_DIR/x86_64-linux-gnu/bin/x86_64-linux-gnu-g++
export VSCODE_REMOTE_CXXFLAGS="--sysroot=$VSCODE_SYSROOT_DIR/x86_64-linux-gnu/x86_64-linux-gnu/sysroot"
export VSCODE_REMOTE_LDFLAGS="--sysroot=$VSCODE_SYSROOT_DIR/x86_64-linux-gnu/x86_64-linux-gnu/sysroot -L$VSCODE_SYSROOT_DIR/x86_64-linux-gnu/x86_64-linux-gnu/sysroot/usr/lib/x86_64-linux-gnu -L$VSCODE_SYSROOT_DIR/x86_64-linux-gnu/x86_64-linux-gnu/sysroot/lib/x86_64-linux-gnu"
elif [ "$npm_config_arch" == "arm64" ]; then
# Set compiler toolchain for client native modules and remote server
export CC=$VSCODE_SYSROOT_DIR/aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc
export CXX=$VSCODE_SYSROOT_DIR/aarch64-linux-gnu/bin/aarch64-linux-gnu-g++
export CXXFLAGS="--sysroot=$VSCODE_SYSROOT_DIR/aarch64-linux-gnu/aarch64-linux-gnu/sysroot"
export LDFLAGS="--sysroot=$VSCODE_SYSROOT_DIR/aarch64-linux-gnu/aarch64-linux-gnu/sysroot -L$VSCODE_SYSROOT_DIR/aarch64-linux-gnu/aarch64-linux-gnu/sysroot/usr/lib/aarch64-linux-gnu -L$VSCODE_SYSROOT_DIR/aarch64-linux-gnu/aarch64-linux-gnu/sysroot/lib/aarch64-linux-gnu"
elif [ "$npm_config_arch" == "arm" ]; then
# Set compiler toolchain for client native modules and remote server
export CC=$VSCODE_SYSROOT_DIR/arm-rpi-linux-gnueabihf/bin/arm-rpi-linux-gnueabihf-gcc
export CXX=$VSCODE_SYSROOT_DIR/arm-rpi-linux-gnueabihf/bin/arm-rpi-linux-gnueabihf-g++
export CXXFLAGS="--sysroot=$VSCODE_SYSROOT_DIR/arm-rpi-linux-gnueabihf/arm-rpi-linux-gnueabihf/sysroot"
export LDFLAGS="--sysroot=$VSCODE_SYSROOT_DIR/arm-rpi-linux-gnueabihf/arm-rpi-linux-gnueabihf/sysroot -L$VSCODE_SYSROOT_DIR/arm-rpi-linux-gnueabihf/arm-rpi-linux-gnueabihf/sysroot/usr/lib/arm-linux-gnueabihf -L$VSCODE_SYSROOT_DIR/arm-rpi-linux-gnueabihf/arm-rpi-linux-gnueabihf/sysroot/lib/arm-linux-gnueabihf"
fi
for i in {1..5}; do # try 5 times
@@ -48,13 +48,13 @@ steps:
# Start X server
sudo apt-get update
sudo apt-get install -y pkg-config \
libxss1 \
dbus \
xvfb \
libgtk-3-0 \
libgbm1 \
libxkbfile-dev \
libkrb5-dev
libkrb5-dev \
libgbm1 \
rpm
sudo cp build/azure-pipelines/linux/xvfb.init /etc/init.d/xvfb
sudo chmod +x /etc/init.d/xvfb
sudo update-rc.d xvfb defaults
@@ -100,17 +100,6 @@ steps:
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none'))
displayName: Setup NPM Authentication
- ${{ if and(ne(parameters.VSCODE_QUALITY, 'oss'), or(eq(parameters.VSCODE_ARCH, 'x64'), eq(parameters.VSCODE_ARCH, 'arm64'))) }}:
- task: Docker@1
displayName: "Pull Docker image"
inputs:
azureSubscriptionEndpoint: "vscode-builds-subscription"
azureContainerRegistry: vscodehub.azurecr.io
command: "Run an image"
imageName: vscode-linux-build-agent:centos7-devtoolset8-$(VSCODE_ARCH)
containerCommand: uname
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
- ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}:
- script: |
set -e
@@ -124,30 +113,62 @@ steps:
echo "Yarn failed $i, trying again..."
done
docker run -e GITHUB_TOKEN -e npm_config_arch -e NPM_REGISTRY \
-e VSCODE_REMOTE_DEPENDENCIES_CONTAINER_NAME -e VSCODE_HOST_MOUNT \
-e ELECTRON_SKIP_BINARY_DOWNLOAD -e PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD \
-e VSCODE_SKIP_NODE_VERSION_CHECK \
-v /mnt/vss/_work/1/s:/home/builduser/vscode -v /mnt/vss/_work/1/s/.build/.netrc:/home/builduser/.netrc \
-v /var/run/docker.sock:/var/run/docker.sock \
-u 1000:1000 \
-w /home/builduser/vscode vscodehub.azurecr.io/vscode-linux-build-agent:bionic-$(VSCODE_ARCH) \
/bin/bash -c "./build/azure-pipelines/linux/install.sh"
sudo chown -R $USER:$USER /mnt/vss/_work/1/s
./build/azure-pipelines/linux/install.sh
env:
npm_config_arch: $(NPM_ARCH)
VSCODE_ARCH: $(VSCODE_ARCH)
NPM_REGISTRY: "$(NPM_REGISTRY)"
ELECTRON_SKIP_BINARY_DOWNLOAD: 1
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
VSCODE_SKIP_NODE_VERSION_CHECK: 1
GITHUB_TOKEN: "$(github-distro-mixin-password)"
VSCODE_HOST_MOUNT: "/mnt/vss/_work/1/s"
${{ if or(eq(parameters.VSCODE_ARCH, 'x64'), eq(parameters.VSCODE_ARCH, 'arm64')) }}:
VSCODE_REMOTE_DEPENDENCIES_CONTAINER_NAME: vscodehub.azurecr.io/vscode-linux-build-agent:centos7-devtoolset8-$(VSCODE_ARCH)
displayName: Install dependencies (non-OSS)
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
- script: |
set -e
TRIPLE="x86_64-linux-gnu"
if [ "$VSCODE_ARCH" == "arm64" ]; then
TRIPLE="aarch64-linux-gnu"
elif [ "$VSCODE_ARCH" == "armhf" ]; then
TRIPLE="arm-rpi-linux-gnueabihf"
fi
# Get all files with .node extension from remote/node_modules folder
files=$(find remote/node_modules -name "*.node")
# Check if any file has dependency of GLIBC > 2.28 or GLIBCXX > 3.4.25
for file in $files; do
glibc_version="2.28"
glibcxx_version="3.4.25"
while IFS= read -r line; do
if [[ $line == *"GLIBC_"* ]]; then
version=$(echo "$line" | awk '{print $5}' | tr -d '()')
version=${version#*_}
if [[ $(printf "%s\n%s" "$version" "$glibc_version" | sort -V | tail -n1) == "$version" ]]; then
glibc_version=$version
fi
elif [[ $line == *"GLIBCXX_"* ]]; then
version=$(echo "$line" | awk '{print $5}' | tr -d '()')
version=${version#*_}
if [[ $(printf "%s\n%s" "$version" "$glibcxx_version" | sort -V | tail -n1) == "$version" ]]; then
glibcxx_version=$version
fi
fi
done < <("$PWD/.build/sysroots/$TRIPLE/$TRIPLE/bin/objdump" -T "$file")
if [[ "$glibc_version" != "2.28" ]]; then
echo "Error: File $file has dependency on GLIBC > 2.28"
exit 1
fi
if [[ "$glibcxx_version" != "3.4.25" ]]; then
echo "Error: File $file has dependency on GLIBCXX > 3.4.25"
exit 1
fi
done
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
displayName: Check GLIBC and GLIBCXX dependencies in remote/node_modules
- script: node build/azure-pipelines/distro/mixin-npm
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
displayName: Mixin distro node modules
@@ -266,11 +287,6 @@ steps:
- ${{ if and(ne(parameters.VSCODE_CIBUILD, true), ne(parameters.VSCODE_QUALITY, 'oss')) }}:
- script: |
set -e
docker run -v /mnt/vss/_work/1/s:/home/builduser/vscode \
-v /mnt/vss/_work/1/s/.build/.netrc:/home/builduser/.netrc \
-v /mnt/vss/_work/1/VSCode-linux-$(VSCODE_ARCH):/home/builduser/VSCode-linux-$(VSCODE_ARCH) \
-u 1000:1000 \
-w /home/builduser/vscode vscodehub.azurecr.io/vscode-linux-build-agent:bionic-$(VSCODE_ARCH) \
yarn gulp "vscode-linux-$(VSCODE_ARCH)-prepare-deb"
displayName: Prepare deb package
@@ -282,11 +298,6 @@ steps:
- script: |
set -e
docker run -v /mnt/vss/_work/1/s:/home/builduser/vscode \
-v /mnt/vss/_work/1/s/.build/.netrc:/home/builduser/.netrc \
-v /mnt/vss/_work/1/VSCode-linux-$(VSCODE_ARCH):/home/builduser/VSCode-linux-$(VSCODE_ARCH) \
-u 1000:1000 \
-w /home/builduser/vscode vscodehub.azurecr.io/vscode-linux-build-agent:bionic-$(VSCODE_ARCH) \
yarn gulp "vscode-linux-$(VSCODE_ARCH)-prepare-rpm"
displayName: Prepare rpm package
+3
View File
@@ -0,0 +1,3 @@
a2d51dc505ed544c52757f90bcdab44920132295fc7a67166eff86b6e0e24aa8 aarch64-linux-gnu.tar.gz
032cf16bf8b965e1351305f10f3dedabf4f9868027ac6d0e8f52321ca0b70d4a arm-rpi-linux-gnueabihf.tar.gz
360475a764d0faf4d3743aa866347eff78072639d20660def83e1a03eadf534c x86_64-linux-gnu.tar.gz
+19 -16
View File
@@ -17,7 +17,6 @@ const task = require('./lib/task');
const packageJson = require('../package.json');
const product = require('../product.json');
const dependenciesGenerator = require('./linux/dependencies-generator');
const sysrootInstaller = require('./linux/debian/install-sysroot');
const debianRecommendedDependencies = require('./linux/debian/dep-lists').recommendedDeps;
const path = require('path');
const root = path.dirname(__dirname);
@@ -82,8 +81,7 @@ function prepareDebPackage(arch) {
function (f) { size += f.isDirectory() ? 4096 : f.contents.length; },
async function () {
const that = this;
const sysroot = await sysrootInstaller.getSysroot(debArch);
const dependencies = dependenciesGenerator.getDependencies('deb', binaryDir, product.applicationName, debArch, sysroot);
const dependencies = await dependenciesGenerator.getDependencies('deb', binaryDir, product.applicationName, debArch);
gulp.src('resources/linux/debian/control.template', { base: '.' })
.pipe(replace('@@NAME@@', product.applicationName))
.pipe(replace('@@VERSION@@', packageJson.version + '-' + linuxPackageRevision))
@@ -186,19 +184,24 @@ function prepareRpmPackage(arch) {
const code = gulp.src(binaryDir + '/**/*', { base: binaryDir })
.pipe(rename(function (p) { p.dirname = 'BUILD/usr/share/' + product.applicationName + '/' + p.dirname; }));
const dependencies = dependenciesGenerator.getDependencies('rpm', binaryDir, product.applicationName, rpmArch);
const spec = gulp.src('resources/linux/rpm/code.spec.template', { base: '.' })
.pipe(replace('@@NAME@@', product.applicationName))
.pipe(replace('@@NAME_LONG@@', product.nameLong))
.pipe(replace('@@ICON@@', product.linuxIconName))
.pipe(replace('@@VERSION@@', packageJson.version))
.pipe(replace('@@RELEASE@@', linuxPackageRevision))
.pipe(replace('@@ARCHITECTURE@@', rpmArch))
.pipe(replace('@@LICENSE@@', product.licenseName))
.pipe(replace('@@QUALITY@@', product.quality || '@@QUALITY@@'))
.pipe(replace('@@UPDATEURL@@', product.updateUrl || '@@UPDATEURL@@'))
.pipe(replace('@@DEPENDENCIES@@', dependencies.join(', ')))
.pipe(rename('SPECS/' + product.applicationName + '.spec'));
const spec = code.pipe(es.through(
async function () {
const that = this;
const dependencies = await dependenciesGenerator.getDependencies('rpm', binaryDir, product.applicationName, rpmArch);
gulp.src('resources/linux/rpm/code.spec.template', { base: '.' })
.pipe(replace('@@NAME@@', product.applicationName))
.pipe(replace('@@NAME_LONG@@', product.nameLong))
.pipe(replace('@@ICON@@', product.linuxIconName))
.pipe(replace('@@VERSION@@', packageJson.version))
.pipe(replace('@@RELEASE@@', linuxPackageRevision))
.pipe(replace('@@ARCHITECTURE@@', rpmArch))
.pipe(replace('@@LICENSE@@', product.licenseName))
.pipe(replace('@@QUALITY@@', product.quality || '@@QUALITY@@'))
.pipe(replace('@@UPDATEURL@@', product.updateUrl || '@@UPDATEURL@@'))
.pipe(replace('@@DEPENDENCIES@@', dependencies.join(', ')))
.pipe(rename('SPECS/' + product.applicationName + '.spec'))
.pipe(es.through(function (f) { that.emit('data', f); }, function () { that.emit('end'); }));
}));
const specIcon = gulp.src('resources/linux/rpm/code.xpm', { base: '.' })
.pipe(rename('SOURCES/' + product.applicationName + '.xpm'));
+10 -11
View File
@@ -11,15 +11,15 @@ const os_1 = require("os");
const path = require("path");
const manifests = require("../../../cgmanifest.json");
const dep_lists_1 = require("./dep-lists");
function generatePackageDeps(files, arch, sysroot) {
const dependencies = files.map(file => calculatePackageDeps(file, arch, sysroot));
function generatePackageDeps(files, arch, chromiumSysroot, vscodeSysroot) {
const dependencies = files.map(file => calculatePackageDeps(file, arch, chromiumSysroot, vscodeSysroot));
const additionalDepsSet = new Set(dep_lists_1.additionalDeps);
dependencies.push(additionalDepsSet);
return dependencies;
}
exports.generatePackageDeps = generatePackageDeps;
// Based on https://source.chromium.org/chromium/chromium/src/+/main:chrome/installer/linux/debian/calculate_package_deps.py.
function calculatePackageDeps(binaryPath, arch, sysroot) {
function calculatePackageDeps(binaryPath, arch, chromiumSysroot, vscodeSysroot) {
try {
if (!((0, fs_1.statSync)(binaryPath).mode & fs_1.constants.S_IXUSR)) {
throw new Error(`Binary ${binaryPath} needs to have an executable bit set.`);
@@ -42,18 +42,19 @@ function calculatePackageDeps(binaryPath, arch, sysroot) {
const cmd = [dpkgShlibdepsScriptLocation, '--ignore-weak-undefined'];
switch (arch) {
case 'amd64':
cmd.push(`-l${sysroot}/usr/lib/x86_64-linux-gnu`, `-l${sysroot}/lib/x86_64-linux-gnu`);
cmd.push(`-l${chromiumSysroot}/usr/lib/x86_64-linux-gnu`, `-l${chromiumSysroot}/lib/x86_64-linux-gnu`, `-l${vscodeSysroot}/usr/lib/x86_64-linux-gnu`, `-l${vscodeSysroot}/lib/x86_64-linux-gnu`);
break;
case 'armhf':
cmd.push(`-l${sysroot}/usr/lib/arm-linux-gnueabihf`, `-l${sysroot}/lib/arm-linux-gnueabihf`);
cmd.push(`-l${chromiumSysroot}/usr/lib/arm-linux-gnueabihf`, `-l${chromiumSysroot}/lib/arm-linux-gnueabihf`, `-l${vscodeSysroot}/usr/lib/arm-linux-gnueabihf`, `-l${vscodeSysroot}/lib/arm-linux-gnueabihf`);
break;
case 'arm64':
cmd.push(`-l${sysroot}/usr/lib/aarch64-linux-gnu`, `-l${sysroot}/lib/aarch64-linux-gnu`);
cmd.push(`-l${chromiumSysroot}/usr/lib/aarch64-linux-gnu`, `-l${chromiumSysroot}/lib/aarch64-linux-gnu`, `-l${vscodeSysroot}/usr/lib/aarch64-linux-gnu`, `-l${vscodeSysroot}/lib/aarch64-linux-gnu`);
break;
}
cmd.push(`-l${sysroot}/usr/lib`);
cmd.push(`-l${chromiumSysroot}/usr/lib`);
cmd.push(`-L${vscodeSysroot}/debian/libxkbfile1/DEBIAN/shlibs`);
cmd.push('-O', '-e', path.resolve(binaryPath));
const dpkgShlibdepsResult = (0, child_process_1.spawnSync)('perl', cmd, { cwd: sysroot });
const dpkgShlibdepsResult = (0, child_process_1.spawnSync)('perl', cmd, { cwd: chromiumSysroot });
if (dpkgShlibdepsResult.status !== 0) {
throw new Error(`dpkg-shlibdeps failed with exit code ${dpkgShlibdepsResult.status}. stderr:\n${dpkgShlibdepsResult.stderr} `);
}
@@ -78,9 +79,7 @@ function calculatePackageDeps(binaryPath, arch, sysroot) {
// TODO(deepak1556): remove this workaround in favor of computing the
// versions from build container for native modules.
const filteredDeps = depsStr.split(', ').filter(dependency => {
return !dependency.startsWith('libgcc-s1') &&
!dependency.startsWith('libgssapi-krb5-2') &&
!dependency.startsWith('libkrb5-3');
return !dependency.startsWith('libgcc-s1');
}).sort();
const requires = new Set(filteredDeps);
return requires;
+19 -14
View File
@@ -11,15 +11,15 @@ import * as manifests from '../../../cgmanifest.json';
import { additionalDeps } from './dep-lists';
import { DebianArchString } from './types';
export function generatePackageDeps(files: string[], arch: DebianArchString, sysroot: string): Set<string>[] {
const dependencies: Set<string>[] = files.map(file => calculatePackageDeps(file, arch, sysroot));
export function generatePackageDeps(files: string[], arch: DebianArchString, chromiumSysroot: string, vscodeSysroot: string): Set<string>[] {
const dependencies: Set<string>[] = files.map(file => calculatePackageDeps(file, arch, chromiumSysroot, vscodeSysroot));
const additionalDepsSet = new Set(additionalDeps);
dependencies.push(additionalDepsSet);
return dependencies;
}
// Based on https://source.chromium.org/chromium/chromium/src/+/main:chrome/installer/linux/debian/calculate_package_deps.py.
function calculatePackageDeps(binaryPath: string, arch: DebianArchString, sysroot: string): Set<string> {
function calculatePackageDeps(binaryPath: string, arch: DebianArchString, chromiumSysroot: string, vscodeSysroot: string): Set<string> {
try {
if (!(statSync(binaryPath).mode & constants.S_IXUSR)) {
throw new Error(`Binary ${binaryPath} needs to have an executable bit set.`);
@@ -42,22 +42,29 @@ function calculatePackageDeps(binaryPath: string, arch: DebianArchString, sysroo
const cmd = [dpkgShlibdepsScriptLocation, '--ignore-weak-undefined'];
switch (arch) {
case 'amd64':
cmd.push(`-l${sysroot}/usr/lib/x86_64-linux-gnu`,
`-l${sysroot}/lib/x86_64-linux-gnu`);
cmd.push(`-l${chromiumSysroot}/usr/lib/x86_64-linux-gnu`,
`-l${chromiumSysroot}/lib/x86_64-linux-gnu`,
`-l${vscodeSysroot}/usr/lib/x86_64-linux-gnu`,
`-l${vscodeSysroot}/lib/x86_64-linux-gnu`);
break;
case 'armhf':
cmd.push(`-l${sysroot}/usr/lib/arm-linux-gnueabihf`,
`-l${sysroot}/lib/arm-linux-gnueabihf`);
cmd.push(`-l${chromiumSysroot}/usr/lib/arm-linux-gnueabihf`,
`-l${chromiumSysroot}/lib/arm-linux-gnueabihf`,
`-l${vscodeSysroot}/usr/lib/arm-linux-gnueabihf`,
`-l${vscodeSysroot}/lib/arm-linux-gnueabihf`);
break;
case 'arm64':
cmd.push(`-l${sysroot}/usr/lib/aarch64-linux-gnu`,
`-l${sysroot}/lib/aarch64-linux-gnu`);
cmd.push(`-l${chromiumSysroot}/usr/lib/aarch64-linux-gnu`,
`-l${chromiumSysroot}/lib/aarch64-linux-gnu`,
`-l${vscodeSysroot}/usr/lib/aarch64-linux-gnu`,
`-l${vscodeSysroot}/lib/aarch64-linux-gnu`);
break;
}
cmd.push(`-l${sysroot}/usr/lib`);
cmd.push(`-l${chromiumSysroot}/usr/lib`);
cmd.push(`-L${vscodeSysroot}/debian/libxkbfile1/DEBIAN/shlibs`);
cmd.push('-O', '-e', path.resolve(binaryPath));
const dpkgShlibdepsResult = spawnSync('perl', cmd, { cwd: sysroot });
const dpkgShlibdepsResult = spawnSync('perl', cmd, { cwd: chromiumSysroot });
if (dpkgShlibdepsResult.status !== 0) {
throw new Error(`dpkg-shlibdeps failed with exit code ${dpkgShlibdepsResult.status}. stderr:\n${dpkgShlibdepsResult.stderr} `);
}
@@ -83,9 +90,7 @@ function calculatePackageDeps(binaryPath: string, arch: DebianArchString, sysroo
// TODO(deepak1556): remove this workaround in favor of computing the
// versions from build container for native modules.
const filteredDeps = depsStr.split(', ').filter(dependency => {
return !dependency.startsWith('libgcc-s1') &&
!dependency.startsWith('libgssapi-krb5-2') &&
!dependency.startsWith('libkrb5-3');
return !dependency.startsWith('libgcc-s1');
}).sort();
const requires = new Set(filteredDeps);
return requires;
+16 -14
View File
@@ -13,8 +13,6 @@ exports.additionalDeps = [
'libnss3 (>= 3.26)',
'libcurl3-gnutls | libcurl3-nss | libcurl4 | libcurl3', // For Breakpad crash reports.
'xdg-utils (>= 1.0.2)', // OS integration
'libgssapi-krb5-2',
'libkrb5-3',
];
// Based on https://source.chromium.org/chromium/chromium/src/+/main:chrome/installer/linux/debian/manual_recommends
// Dependencies that we can only recommend
@@ -33,6 +31,7 @@ exports.referenceGeneratedDepsByArch = {
'libc6 (>= 2.16)',
'libc6 (>= 2.17)',
'libc6 (>= 2.2.5)',
'libc6 (>= 2.28)',
'libcairo2 (>= 1.6.0)',
'libcurl3-gnutls | libcurl3-nss | libcurl4 | libcurl3',
'libdbus-1-3 (>= 1.9.14)',
@@ -40,10 +39,10 @@ exports.referenceGeneratedDepsByArch = {
'libexpat1 (>= 2.1~beta3)',
'libgbm1 (>= 17.1.0~rc2)',
'libglib2.0-0 (>= 2.37.3)',
'libgssapi-krb5-2',
'libgssapi-krb5-2 (>= 1.17)',
'libgtk-3-0 (>= 3.9.10)',
'libgtk-3-0 (>= 3.9.10) | libgtk-4-1',
'libkrb5-3',
'libkrb5-3 (>= 1.6.dfsg.2)',
'libnspr4 (>= 2:4.9-2~)',
'libnss3 (>= 2:3.30)',
'libnss3 (>= 3.26)',
@@ -56,9 +55,10 @@ exports.referenceGeneratedDepsByArch = {
'libxext6',
'libxfixes3',
'libxkbcommon0 (>= 0.5.0)',
'libxkbfile1',
'libxkbfile1 (>= 1:1.1.0)',
'libxrandr2',
'xdg-utils (>= 1.0.2)'
'xdg-utils (>= 1.0.2)',
'zlib1g (>= 1:1.2.3.4)'
],
'armhf': [
'ca-certificates',
@@ -66,11 +66,10 @@ exports.referenceGeneratedDepsByArch = {
'libatk-bridge2.0-0 (>= 2.5.3)',
'libatk1.0-0 (>= 2.2.0)',
'libatspi2.0-0 (>= 2.9.90)',
'libc6 (>= 2.15)',
'libc6 (>= 2.16)',
'libc6 (>= 2.17)',
'libc6 (>= 2.28)',
'libc6 (>= 2.4)',
'libc6 (>= 2.8)',
'libc6 (>= 2.9)',
'libcairo2 (>= 1.6.0)',
'libcurl3-gnutls | libcurl3-nss | libcurl4 | libcurl3',
@@ -79,14 +78,15 @@ exports.referenceGeneratedDepsByArch = {
'libexpat1 (>= 2.1~beta3)',
'libgbm1 (>= 17.1.0~rc2)',
'libglib2.0-0 (>= 2.37.3)',
'libgssapi-krb5-2',
'libgssapi-krb5-2 (>= 1.17)',
'libgtk-3-0 (>= 3.9.10)',
'libgtk-3-0 (>= 3.9.10) | libgtk-4-1',
'libkrb5-3',
'libkrb5-3 (>= 1.6.dfsg.2)',
'libnspr4 (>= 2:4.9-2~)',
'libnss3 (>= 2:3.30)',
'libnss3 (>= 3.26)',
'libpango-1.0-0 (>= 1.14.0)',
'libstdc++6 (>= 4.1.1)',
'libstdc++6 (>= 5)',
'libstdc++6 (>= 5.2)',
'libstdc++6 (>= 6)',
@@ -98,7 +98,7 @@ exports.referenceGeneratedDepsByArch = {
'libxext6',
'libxfixes3',
'libxkbcommon0 (>= 0.5.0)',
'libxkbfile1',
'libxkbfile1 (>= 1:1.1.0)',
'libxrandr2',
'xdg-utils (>= 1.0.2)'
],
@@ -109,6 +109,7 @@ exports.referenceGeneratedDepsByArch = {
'libatk1.0-0 (>= 2.2.0)',
'libatspi2.0-0 (>= 2.9.90)',
'libc6 (>= 2.17)',
'libc6 (>= 2.28)',
'libcairo2 (>= 1.6.0)',
'libcurl3-gnutls | libcurl3-nss | libcurl4 | libcurl3',
'libdbus-1-3 (>= 1.9.14)',
@@ -116,14 +117,15 @@ exports.referenceGeneratedDepsByArch = {
'libexpat1 (>= 2.1~beta3)',
'libgbm1 (>= 17.1.0~rc2)',
'libglib2.0-0 (>= 2.37.3)',
'libgssapi-krb5-2',
'libgssapi-krb5-2 (>= 1.17)',
'libgtk-3-0 (>= 3.9.10)',
'libgtk-3-0 (>= 3.9.10) | libgtk-4-1',
'libkrb5-3',
'libkrb5-3 (>= 1.6.dfsg.2)',
'libnspr4 (>= 2:4.9-2~)',
'libnss3 (>= 2:3.30)',
'libnss3 (>= 3.26)',
'libpango-1.0-0 (>= 1.14.0)',
'libstdc++6 (>= 4.1.1)',
'libstdc++6 (>= 5)',
'libstdc++6 (>= 5.2)',
'libstdc++6 (>= 6)',
@@ -135,7 +137,7 @@ exports.referenceGeneratedDepsByArch = {
'libxext6',
'libxfixes3',
'libxkbcommon0 (>= 0.5.0)',
'libxkbfile1',
'libxkbfile1 (>= 1:1.1.0)',
'libxrandr2',
'xdg-utils (>= 1.0.2)'
]
+16 -14
View File
@@ -11,8 +11,6 @@ export const additionalDeps = [
'libnss3 (>= 3.26)',
'libcurl3-gnutls | libcurl3-nss | libcurl4 | libcurl3', // For Breakpad crash reports.
'xdg-utils (>= 1.0.2)', // OS integration
'libgssapi-krb5-2',
'libkrb5-3',
];
// Based on https://source.chromium.org/chromium/chromium/src/+/main:chrome/installer/linux/debian/manual_recommends
@@ -33,6 +31,7 @@ export const referenceGeneratedDepsByArch = {
'libc6 (>= 2.16)',
'libc6 (>= 2.17)',
'libc6 (>= 2.2.5)',
'libc6 (>= 2.28)',
'libcairo2 (>= 1.6.0)',
'libcurl3-gnutls | libcurl3-nss | libcurl4 | libcurl3',
'libdbus-1-3 (>= 1.9.14)',
@@ -40,10 +39,10 @@ export const referenceGeneratedDepsByArch = {
'libexpat1 (>= 2.1~beta3)',
'libgbm1 (>= 17.1.0~rc2)',
'libglib2.0-0 (>= 2.37.3)',
'libgssapi-krb5-2',
'libgssapi-krb5-2 (>= 1.17)',
'libgtk-3-0 (>= 3.9.10)',
'libgtk-3-0 (>= 3.9.10) | libgtk-4-1',
'libkrb5-3',
'libkrb5-3 (>= 1.6.dfsg.2)',
'libnspr4 (>= 2:4.9-2~)',
'libnss3 (>= 2:3.30)',
'libnss3 (>= 3.26)',
@@ -56,9 +55,10 @@ export const referenceGeneratedDepsByArch = {
'libxext6',
'libxfixes3',
'libxkbcommon0 (>= 0.5.0)',
'libxkbfile1',
'libxkbfile1 (>= 1:1.1.0)',
'libxrandr2',
'xdg-utils (>= 1.0.2)'
'xdg-utils (>= 1.0.2)',
'zlib1g (>= 1:1.2.3.4)'
],
'armhf': [
'ca-certificates',
@@ -66,11 +66,10 @@ export const referenceGeneratedDepsByArch = {
'libatk-bridge2.0-0 (>= 2.5.3)',
'libatk1.0-0 (>= 2.2.0)',
'libatspi2.0-0 (>= 2.9.90)',
'libc6 (>= 2.15)',
'libc6 (>= 2.16)',
'libc6 (>= 2.17)',
'libc6 (>= 2.28)',
'libc6 (>= 2.4)',
'libc6 (>= 2.8)',
'libc6 (>= 2.9)',
'libcairo2 (>= 1.6.0)',
'libcurl3-gnutls | libcurl3-nss | libcurl4 | libcurl3',
@@ -79,14 +78,15 @@ export const referenceGeneratedDepsByArch = {
'libexpat1 (>= 2.1~beta3)',
'libgbm1 (>= 17.1.0~rc2)',
'libglib2.0-0 (>= 2.37.3)',
'libgssapi-krb5-2',
'libgssapi-krb5-2 (>= 1.17)',
'libgtk-3-0 (>= 3.9.10)',
'libgtk-3-0 (>= 3.9.10) | libgtk-4-1',
'libkrb5-3',
'libkrb5-3 (>= 1.6.dfsg.2)',
'libnspr4 (>= 2:4.9-2~)',
'libnss3 (>= 2:3.30)',
'libnss3 (>= 3.26)',
'libpango-1.0-0 (>= 1.14.0)',
'libstdc++6 (>= 4.1.1)',
'libstdc++6 (>= 5)',
'libstdc++6 (>= 5.2)',
'libstdc++6 (>= 6)',
@@ -98,7 +98,7 @@ export const referenceGeneratedDepsByArch = {
'libxext6',
'libxfixes3',
'libxkbcommon0 (>= 0.5.0)',
'libxkbfile1',
'libxkbfile1 (>= 1:1.1.0)',
'libxrandr2',
'xdg-utils (>= 1.0.2)'
],
@@ -109,6 +109,7 @@ export const referenceGeneratedDepsByArch = {
'libatk1.0-0 (>= 2.2.0)',
'libatspi2.0-0 (>= 2.9.90)',
'libc6 (>= 2.17)',
'libc6 (>= 2.28)',
'libcairo2 (>= 1.6.0)',
'libcurl3-gnutls | libcurl3-nss | libcurl4 | libcurl3',
'libdbus-1-3 (>= 1.9.14)',
@@ -116,14 +117,15 @@ export const referenceGeneratedDepsByArch = {
'libexpat1 (>= 2.1~beta3)',
'libgbm1 (>= 17.1.0~rc2)',
'libglib2.0-0 (>= 2.37.3)',
'libgssapi-krb5-2',
'libgssapi-krb5-2 (>= 1.17)',
'libgtk-3-0 (>= 3.9.10)',
'libgtk-3-0 (>= 3.9.10) | libgtk-4-1',
'libkrb5-3',
'libkrb5-3 (>= 1.6.dfsg.2)',
'libnspr4 (>= 2:4.9-2~)',
'libnss3 (>= 2:3.30)',
'libnss3 (>= 3.26)',
'libpango-1.0-0 (>= 1.14.0)',
'libstdc++6 (>= 4.1.1)',
'libstdc++6 (>= 5)',
'libstdc++6 (>= 5.2)',
'libstdc++6 (>= 6)',
@@ -135,7 +137,7 @@ export const referenceGeneratedDepsByArch = {
'libxext6',
'libxfixes3',
'libxkbcommon0 (>= 0.5.0)',
'libxkbfile1',
'libxkbfile1 (>= 1:1.1.0)',
'libxrandr2',
'xdg-utils (>= 1.0.2)'
]
+131 -6
View File
@@ -4,17 +4,35 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.getSysroot = void 0;
exports.getChromiumSysroot = exports.getVSCodeSysroot = void 0;
const child_process_1 = require("child_process");
const crypto_1 = require("crypto");
const os_1 = require("os");
const fs = require("fs");
const https = require("https");
const path = require("path");
const util = require("../../lib/util");
const crypto_1 = require("crypto");
const ansiColors = require("ansi-colors");
// Based on https://source.chromium.org/chromium/chromium/src/+/main:build/linux/sysroot_scripts/install-sysroot.py.
const URL_PREFIX = 'https://msftelectron.blob.core.windows.net';
const URL_PATH = 'sysroots/toolchain';
const REPO_ROOT = path.dirname(path.dirname(path.dirname(__dirname)));
const ghApiHeaders = {
Accept: 'application/vnd.github.v3+json',
'User-Agent': 'VSCode Build',
};
if (process.env.GITHUB_TOKEN) {
ghApiHeaders.Authorization = 'Basic ' + Buffer.from(process.env.GITHUB_TOKEN).toString('base64');
}
const ghDownloadHeaders = {
...ghApiHeaders,
Accept: 'application/octet-stream',
};
function getElectronVersion() {
const yarnrc = fs.readFileSync(path.join(REPO_ROOT, '.yarnrc'), 'utf8');
const electronVersion = /^target "(.*)"$/m.exec(yarnrc)[1];
const msBuildId = /^ms_build_id "(.*)"$/m.exec(yarnrc)[1];
return { electronVersion, msBuildId };
}
function getSha(filename) {
const hash = (0, crypto_1.createHash)('sha1');
// Read file 1 MB at a time
@@ -29,8 +47,115 @@ function getSha(filename) {
hash.update(buffer.slice(0, bytesRead));
return hash.digest('hex');
}
async function getSysroot(arch) {
const sysrootJSONUrl = `https://raw.githubusercontent.com/electron/electron/v${util.getElectronVersion().electronVersion}/script/sysroots.json`;
function getVSCodeSysrootChecksum(expectedName) {
const checksums = fs.readFileSync(path.join(REPO_ROOT, 'build', 'checksums', 'vscode-sysroot.txt'), 'utf8');
for (const line of checksums.split('\n')) {
const [checksum, name] = line.split(/\s+/);
if (name === expectedName) {
return checksum;
}
}
return undefined;
}
/*
* Do not use the fetch implementation from build/lib/fetch as it relies on vinyl streams
* and vinyl-fs breaks the symlinks in the compiler toolchain sysroot. We use the native
* tar implementation for that reason.
*/
async function fetchUrl(options, retries = 10, retryDelay = 1000) {
try {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 30 * 1000);
const version = '20231122-245579';
try {
const response = await fetch(`https://api.github.com/repos/Microsoft/vscode-linux-build-agent/releases/tags/v${version}`, {
headers: ghApiHeaders,
signal: controller.signal /* Typings issue with lib.dom.d.ts */
});
if (response.ok && (response.status >= 200 && response.status < 300)) {
console.log(`Fetch completed: Status ${response.status}.`);
const contents = Buffer.from(await response.arrayBuffer());
const asset = JSON.parse(contents.toString()).assets.find((a) => a.name === options.assetName);
if (!asset) {
throw new Error(`Could not find asset in release of Microsoft/vscode-linux-build-agent @ ${version}`);
}
console.log(`Found asset ${options.assetName} @ ${asset.url}.`);
const assetResponse = await fetch(asset.url, {
headers: ghDownloadHeaders
});
if (assetResponse.ok && (assetResponse.status >= 200 && assetResponse.status < 300)) {
const assetContents = Buffer.from(await assetResponse.arrayBuffer());
console.log(`Fetched response body buffer: ${ansiColors.magenta(`${assetContents.byteLength} bytes`)}`);
if (options.checksumSha256) {
const actualSHA256Checksum = (0, crypto_1.createHash)('sha256').update(assetContents).digest('hex');
if (actualSHA256Checksum !== options.checksumSha256) {
throw new Error(`Checksum mismatch for ${ansiColors.cyan(asset.url)} (expected ${options.checksumSha256}, actual ${actualSHA256Checksum}))`);
}
}
console.log(`Verified SHA256 checksums match for ${ansiColors.cyan(asset.url)}`);
const tarCommand = `tar -xz -C ${options.dest}`;
(0, child_process_1.execSync)(tarCommand, { input: assetContents });
console.log(`Fetch complete!`);
return;
}
throw new Error(`Request ${ansiColors.magenta(asset.url)} failed with status code: ${assetResponse.status}`);
}
throw new Error(`Request ${ansiColors.magenta('https://api.github.com')} failed with status code: ${response.status}`);
}
finally {
clearTimeout(timeout);
}
}
catch (e) {
if (retries > 0) {
console.log(`Fetching failed: ${e}`);
await new Promise(resolve => setTimeout(resolve, retryDelay));
return fetchUrl(options, retries - 1, retryDelay);
}
throw e;
}
}
async function getVSCodeSysroot(arch) {
let expectedName;
let triple;
switch (arch) {
case 'amd64':
expectedName = `x86_64-linux-gnu.tar.gz`;
triple = 'x86_64-linux-gnu';
break;
case 'arm64':
expectedName = `aarch64-linux-gnu.tar.gz`;
triple = 'aarch64-linux-gnu';
break;
case 'armhf':
expectedName = `arm-rpi-linux-gnueabihf.tar.gz`;
triple = 'arm-rpi-linux-gnueabihf';
break;
}
const checksumSha256 = getVSCodeSysrootChecksum(expectedName);
if (!checksumSha256) {
throw new Error(`Could not find checksum for ${expectedName}`);
}
const sysroot = process.env['VSCODE_SYSROOT_DIR'] ?? path.join((0, os_1.tmpdir)(), `vscode-${arch}-sysroot`);
const stamp = path.join(sysroot, '.stamp');
const result = `${sysroot}/${triple}/${triple}/sysroot`;
if (fs.existsSync(stamp) && fs.readFileSync(stamp).toString() === expectedName) {
return result;
}
console.log(`Installing ${arch} root image: ${sysroot}`);
fs.rmSync(sysroot, { recursive: true, force: true });
fs.mkdirSync(sysroot);
await fetchUrl({
checksumSha256,
assetName: expectedName,
dest: sysroot
});
fs.writeFileSync(stamp, expectedName);
return result;
}
exports.getVSCodeSysroot = getVSCodeSysroot;
async function getChromiumSysroot(arch) {
const sysrootJSONUrl = `https://raw.githubusercontent.com/electron/electron/v${getElectronVersion().electronVersion}/script/sysroots.json`;
const sysrootDictLocation = `${(0, os_1.tmpdir)()}/sysroots.json`;
const result = (0, child_process_1.spawnSync)('curl', [sysrootJSONUrl, '-o', sysrootDictLocation]);
if (result.status !== 0) {
@@ -86,5 +211,5 @@ async function getSysroot(arch) {
fs.writeFileSync(stamp, url);
return sysroot;
}
exports.getSysroot = getSysroot;
exports.getChromiumSysroot = getChromiumSysroot;
//# sourceMappingURL=install-sysroot.js.map
+140 -5
View File
@@ -3,18 +3,46 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { spawnSync } from 'child_process';
import { createHash } from 'crypto';
import { spawnSync, execSync } from 'child_process';
import { tmpdir } from 'os';
import * as fs from 'fs';
import * as https from 'https';
import * as path from 'path';
import { createHash } from 'crypto';
import { DebianArchString } from './types';
import * as util from '../../lib/util';
import * as ansiColors from 'ansi-colors';
// Based on https://source.chromium.org/chromium/chromium/src/+/main:build/linux/sysroot_scripts/install-sysroot.py.
const URL_PREFIX = 'https://msftelectron.blob.core.windows.net';
const URL_PATH = 'sysroots/toolchain';
const REPO_ROOT = path.dirname(path.dirname(path.dirname(__dirname)));
const ghApiHeaders: Record<string, string> = {
Accept: 'application/vnd.github.v3+json',
'User-Agent': 'VSCode Build',
};
if (process.env.GITHUB_TOKEN) {
ghApiHeaders.Authorization = 'Basic ' + Buffer.from(process.env.GITHUB_TOKEN).toString('base64');
}
const ghDownloadHeaders = {
...ghApiHeaders,
Accept: 'application/octet-stream',
};
interface IFetchOptions {
assetName: string;
checksumSha256?: string;
dest: string;
}
function getElectronVersion(): Record<string, string> {
const yarnrc = fs.readFileSync(path.join(REPO_ROOT, '.yarnrc'), 'utf8');
const electronVersion = /^target "(.*)"$/m.exec(yarnrc)![1];
const msBuildId = /^ms_build_id "(.*)"$/m.exec(yarnrc)![1];
return { electronVersion, msBuildId };
}
function getSha(filename: fs.PathLike): string {
const hash = createHash('sha1');
@@ -31,14 +59,121 @@ function getSha(filename: fs.PathLike): string {
return hash.digest('hex');
}
function getVSCodeSysrootChecksum(expectedName: string) {
const checksums = fs.readFileSync(path.join(REPO_ROOT, 'build', 'checksums', 'vscode-sysroot.txt'), 'utf8');
for (const line of checksums.split('\n')) {
const [checksum, name] = line.split(/\s+/);
if (name === expectedName) {
return checksum;
}
}
return undefined;
}
/*
* Do not use the fetch implementation from build/lib/fetch as it relies on vinyl streams
* and vinyl-fs breaks the symlinks in the compiler toolchain sysroot. We use the native
* tar implementation for that reason.
*/
async function fetchUrl(options: IFetchOptions, retries = 10, retryDelay = 1000): Promise<undefined> {
try {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 30 * 1000);
const version = '20231122-245579';
try {
const response = await fetch(`https://api.github.com/repos/Microsoft/vscode-linux-build-agent/releases/tags/v${version}`, {
headers: ghApiHeaders,
signal: controller.signal as any /* Typings issue with lib.dom.d.ts */
});
if (response.ok && (response.status >= 200 && response.status < 300)) {
console.log(`Fetch completed: Status ${response.status}.`);
const contents = Buffer.from(await response.arrayBuffer());
const asset = JSON.parse(contents.toString()).assets.find((a: { name: string }) => a.name === options.assetName);
if (!asset) {
throw new Error(`Could not find asset in release of Microsoft/vscode-linux-build-agent @ ${version}`);
}
console.log(`Found asset ${options.assetName} @ ${asset.url}.`);
const assetResponse = await fetch(asset.url, {
headers: ghDownloadHeaders
});
if (assetResponse.ok && (assetResponse.status >= 200 && assetResponse.status < 300)) {
const assetContents = Buffer.from(await assetResponse.arrayBuffer());
console.log(`Fetched response body buffer: ${ansiColors.magenta(`${(assetContents as Buffer).byteLength} bytes`)}`);
if (options.checksumSha256) {
const actualSHA256Checksum = createHash('sha256').update(assetContents).digest('hex');
if (actualSHA256Checksum !== options.checksumSha256) {
throw new Error(`Checksum mismatch for ${ansiColors.cyan(asset.url)} (expected ${options.checksumSha256}, actual ${actualSHA256Checksum}))`);
}
}
console.log(`Verified SHA256 checksums match for ${ansiColors.cyan(asset.url)}`);
const tarCommand = `tar -xz -C ${options.dest}`;
execSync(tarCommand, { input: assetContents });
console.log(`Fetch complete!`);
return;
}
throw new Error(`Request ${ansiColors.magenta(asset.url)} failed with status code: ${assetResponse.status}`);
}
throw new Error(`Request ${ansiColors.magenta('https://api.github.com')} failed with status code: ${response.status}`);
} finally {
clearTimeout(timeout);
}
} catch (e) {
if (retries > 0) {
console.log(`Fetching failed: ${e}`);
await new Promise(resolve => setTimeout(resolve, retryDelay));
return fetchUrl(options, retries - 1, retryDelay);
}
throw e;
}
}
type SysrootDictEntry = {
Sha1Sum: string;
SysrootDir: string;
Tarball: string;
};
export async function getSysroot(arch: DebianArchString): Promise<string> {
const sysrootJSONUrl = `https://raw.githubusercontent.com/electron/electron/v${util.getElectronVersion().electronVersion}/script/sysroots.json`;
export async function getVSCodeSysroot(arch: DebianArchString): Promise<string> {
let expectedName: string;
let triple: string;
switch (arch) {
case 'amd64':
expectedName = `x86_64-linux-gnu.tar.gz`;
triple = 'x86_64-linux-gnu';
break;
case 'arm64':
expectedName = `aarch64-linux-gnu.tar.gz`;
triple = 'aarch64-linux-gnu';
break;
case 'armhf':
expectedName = `arm-rpi-linux-gnueabihf.tar.gz`;
triple = 'arm-rpi-linux-gnueabihf';
break;
}
const checksumSha256 = getVSCodeSysrootChecksum(expectedName);
if (!checksumSha256) {
throw new Error(`Could not find checksum for ${expectedName}`);
}
const sysroot = process.env['VSCODE_SYSROOT_DIR'] ?? path.join(tmpdir(), `vscode-${arch}-sysroot`);
const stamp = path.join(sysroot, '.stamp');
const result = `${sysroot}/${triple}/${triple}/sysroot`;
if (fs.existsSync(stamp) && fs.readFileSync(stamp).toString() === expectedName) {
return result;
}
console.log(`Installing ${arch} root image: ${sysroot}`);
fs.rmSync(sysroot, { recursive: true, force: true });
fs.mkdirSync(sysroot);
await fetchUrl({
checksumSha256,
assetName: expectedName,
dest: sysroot
});
fs.writeFileSync(stamp, expectedName);
return result;
}
export async function getChromiumSysroot(arch: DebianArchString): Promise<string> {
const sysrootJSONUrl = `https://raw.githubusercontent.com/electron/electron/v${getElectronVersion().electronVersion}/script/sysroots.json`;
const sysrootDictLocation = `${tmpdir()}/sysroots.json`;
const result = spawnSync('curl', [sysrootJSONUrl, '-o', sysrootDictLocation]);
if (result.status !== 0) {
+17 -8
View File
@@ -7,12 +7,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
exports.getDependencies = void 0;
const child_process_1 = require("child_process");
const path = require("path");
const install_sysroot_1 = require("./debian/install-sysroot");
const calculate_deps_1 = require("./debian/calculate-deps");
const calculate_deps_2 = require("./rpm/calculate-deps");
const dep_lists_1 = require("./debian/dep-lists");
const dep_lists_2 = require("./rpm/dep-lists");
const types_1 = require("./debian/types");
const types_2 = require("./rpm/types");
const product = require("../../product.json");
// A flag that can easily be toggled.
// Make sure to compile the build directory after toggling the value.
// If false, we warn about new dependencies if they show up
@@ -31,14 +33,11 @@ const bundledDeps = [
'libvk_swiftshader.so',
'libffmpeg.so'
];
function getDependencies(packageType, buildDir, applicationName, arch, sysroot) {
async function getDependencies(packageType, buildDir, applicationName, arch) {
if (packageType === 'deb') {
if (!(0, types_1.isDebianArchString)(arch)) {
throw new Error('Invalid Debian arch string ' + arch);
}
if (!sysroot) {
throw new Error('Missing sysroot parameter');
}
}
if (packageType === 'rpm' && !(0, types_2.isRpmArchString)(arch)) {
throw new Error('Invalid RPM arch string ' + arch);
@@ -51,16 +50,26 @@ function getDependencies(packageType, buildDir, applicationName, arch, sysroot)
console.error(findResult.stderr.toString());
return [];
}
const files = findResult.stdout.toString().trimEnd().split('\n');
const appPath = path.join(buildDir, applicationName);
// Add the native modules
const files = findResult.stdout.toString().trimEnd().split('\n');
// Add the tunnel binary.
files.push(path.join(buildDir, 'bin', product.tunnelApplicationName));
// Add the main executable.
files.push(appPath);
// Add chrome sandbox and crashpad handler.
files.push(path.join(buildDir, 'chrome-sandbox'));
files.push(path.join(buildDir, 'chrome_crashpad_handler'));
// Generate the dependencies.
const dependencies = packageType === 'deb' ?
(0, calculate_deps_1.generatePackageDeps)(files, arch, sysroot) :
(0, calculate_deps_2.generatePackageDeps)(files);
let dependencies;
if (packageType === 'deb') {
const chromiumSysroot = await (0, install_sysroot_1.getChromiumSysroot)(arch);
const vscodeSysroot = await (0, install_sysroot_1.getVSCodeSysroot)(arch);
dependencies = (0, calculate_deps_1.generatePackageDeps)(files, arch, chromiumSysroot, vscodeSysroot);
}
else {
dependencies = (0, calculate_deps_2.generatePackageDeps)(files);
}
// Merge all the dependencies.
const mergedDependencies = mergePackageDeps(dependencies);
// Exclude bundled dependencies and sort
+16 -10
View File
@@ -7,12 +7,14 @@
import { spawnSync } from 'child_process';
import path = require('path');
import { getChromiumSysroot, getVSCodeSysroot } from './debian/install-sysroot';
import { generatePackageDeps as generatePackageDepsDebian } from './debian/calculate-deps';
import { generatePackageDeps as generatePackageDepsRpm } from './rpm/calculate-deps';
import { referenceGeneratedDepsByArch as debianGeneratedDeps } from './debian/dep-lists';
import { referenceGeneratedDepsByArch as rpmGeneratedDeps } from './rpm/dep-lists';
import { DebianArchString, isDebianArchString } from './debian/types';
import { isRpmArchString, RpmArchString } from './rpm/types';
import product = require('../../product.json');
// A flag that can easily be toggled.
// Make sure to compile the build directory after toggling the value.
@@ -34,14 +36,11 @@ const bundledDeps = [
'libffmpeg.so'
];
export function getDependencies(packageType: 'deb' | 'rpm', buildDir: string, applicationName: string, arch: string, sysroot?: string): string[] {
export async function getDependencies(packageType: 'deb' | 'rpm', buildDir: string, applicationName: string, arch: string): Promise<string[]> {
if (packageType === 'deb') {
if (!isDebianArchString(arch)) {
throw new Error('Invalid Debian arch string ' + arch);
}
if (!sysroot) {
throw new Error('Missing sysroot parameter');
}
}
if (packageType === 'rpm' && !isRpmArchString(arch)) {
throw new Error('Invalid RPM arch string ' + arch);
@@ -56,19 +55,26 @@ export function getDependencies(packageType: 'deb' | 'rpm', buildDir: string, ap
return [];
}
const files = findResult.stdout.toString().trimEnd().split('\n');
const appPath = path.join(buildDir, applicationName);
// Add the native modules
const files = findResult.stdout.toString().trimEnd().split('\n');
// Add the tunnel binary.
files.push(path.join(buildDir, 'bin', product.tunnelApplicationName));
// Add the main executable.
files.push(appPath);
// Add chrome sandbox and crashpad handler.
files.push(path.join(buildDir, 'chrome-sandbox'));
files.push(path.join(buildDir, 'chrome_crashpad_handler'));
// Generate the dependencies.
const dependencies = packageType === 'deb' ?
generatePackageDepsDebian(files, arch as DebianArchString, sysroot!) :
generatePackageDepsRpm(files);
let dependencies: Set<string>[];
if (packageType === 'deb') {
const chromiumSysroot = await getChromiumSysroot(arch as DebianArchString);
const vscodeSysroot = await getVSCodeSysroot(arch as DebianArchString);
dependencies = generatePackageDepsDebian(files, arch as DebianArchString, chromiumSysroot, vscodeSysroot);
} else {
dependencies = generatePackageDepsRpm(files);
}
// Merge all the dependencies.
const mergedDependencies = mergePackageDeps(dependencies);
+18
View File
@@ -42,7 +42,11 @@ exports.referenceGeneratedDepsByArch = {
'libc.so.6(GLIBC_2.15)(64bit)',
'libc.so.6(GLIBC_2.16)(64bit)',
'libc.so.6(GLIBC_2.17)(64bit)',
'libc.so.6(GLIBC_2.18)(64bit)',
'libc.so.6(GLIBC_2.2.5)(64bit)',
'libc.so.6(GLIBC_2.25)(64bit)',
'libc.so.6(GLIBC_2.27)(64bit)',
'libc.so.6(GLIBC_2.28)(64bit)',
'libc.so.6(GLIBC_2.3)(64bit)',
'libc.so.6(GLIBC_2.3.2)(64bit)',
'libc.so.6(GLIBC_2.3.3)(64bit)',
@@ -63,6 +67,8 @@ exports.referenceGeneratedDepsByArch = {
'libgbm.so.1()(64bit)',
'libgcc_s.so.1()(64bit)',
'libgcc_s.so.1(GCC_3.0)(64bit)',
'libgcc_s.so.1(GCC_3.3)(64bit)',
'libgcc_s.so.1(GCC_4.2.0)(64bit)',
'libgio-2.0.so.0()(64bit)',
'libglib-2.0.so.0()(64bit)',
'libgobject-2.0.so.0()(64bit)',
@@ -107,6 +113,8 @@ exports.referenceGeneratedDepsByArch = {
'libxkbcommon.so.0()(64bit)',
'libxkbcommon.so.0(V_0.5.0)(64bit)',
'libxkbfile.so.1()(64bit)',
'libz.so.1()(64bit)',
'libz.so.1(ZLIB_1.2.3.4)(64bit)',
'rpmlib(FileDigests) <= 4.6.0-1',
'rtld(GNU_HASH)',
'xdg-utils'
@@ -133,6 +141,10 @@ exports.referenceGeneratedDepsByArch = {
'libc.so.6(GLIBC_2.15)',
'libc.so.6(GLIBC_2.16)',
'libc.so.6(GLIBC_2.17)',
'libc.so.6(GLIBC_2.18)',
'libc.so.6(GLIBC_2.25)',
'libc.so.6(GLIBC_2.27)',
'libc.so.6(GLIBC_2.28)',
'libc.so.6(GLIBC_2.4)',
'libc.so.6(GLIBC_2.6)',
'libc.so.6(GLIBC_2.7)',
@@ -150,6 +162,7 @@ exports.referenceGeneratedDepsByArch = {
'libgcc_s.so.1',
'libgcc_s.so.1(GCC_3.0)',
'libgcc_s.so.1(GCC_3.5)',
'libgcc_s.so.1(GCC_4.3.0)',
'libgio-2.0.so.0',
'libglib-2.0.so.0',
'libgobject-2.0.so.0',
@@ -232,6 +245,10 @@ exports.referenceGeneratedDepsByArch = {
'libatspi.so.0()(64bit)',
'libc.so.6()(64bit)',
'libc.so.6(GLIBC_2.17)(64bit)',
'libc.so.6(GLIBC_2.18)(64bit)',
'libc.so.6(GLIBC_2.25)(64bit)',
'libc.so.6(GLIBC_2.27)(64bit)',
'libc.so.6(GLIBC_2.28)(64bit)',
'libcairo.so.2()(64bit)',
'libcurl.so.4()(64bit)',
'libdbus-1.so.3()(64bit)',
@@ -243,6 +260,7 @@ exports.referenceGeneratedDepsByArch = {
'libgbm.so.1()(64bit)',
'libgcc_s.so.1()(64bit)',
'libgcc_s.so.1(GCC_3.0)(64bit)',
'libgcc_s.so.1(GCC_3.3)(64bit)',
'libgcc_s.so.1(GCC_4.2.0)(64bit)',
'libgcc_s.so.1(GCC_4.5.0)(64bit)',
'libgio-2.0.so.0()(64bit)',
+18
View File
@@ -41,7 +41,11 @@ export const referenceGeneratedDepsByArch = {
'libc.so.6(GLIBC_2.15)(64bit)',
'libc.so.6(GLIBC_2.16)(64bit)',
'libc.so.6(GLIBC_2.17)(64bit)',
'libc.so.6(GLIBC_2.18)(64bit)',
'libc.so.6(GLIBC_2.2.5)(64bit)',
'libc.so.6(GLIBC_2.25)(64bit)',
'libc.so.6(GLIBC_2.27)(64bit)',
'libc.so.6(GLIBC_2.28)(64bit)',
'libc.so.6(GLIBC_2.3)(64bit)',
'libc.so.6(GLIBC_2.3.2)(64bit)',
'libc.so.6(GLIBC_2.3.3)(64bit)',
@@ -62,6 +66,8 @@ export const referenceGeneratedDepsByArch = {
'libgbm.so.1()(64bit)',
'libgcc_s.so.1()(64bit)',
'libgcc_s.so.1(GCC_3.0)(64bit)',
'libgcc_s.so.1(GCC_3.3)(64bit)',
'libgcc_s.so.1(GCC_4.2.0)(64bit)',
'libgio-2.0.so.0()(64bit)',
'libglib-2.0.so.0()(64bit)',
'libgobject-2.0.so.0()(64bit)',
@@ -106,6 +112,8 @@ export const referenceGeneratedDepsByArch = {
'libxkbcommon.so.0()(64bit)',
'libxkbcommon.so.0(V_0.5.0)(64bit)',
'libxkbfile.so.1()(64bit)',
'libz.so.1()(64bit)',
'libz.so.1(ZLIB_1.2.3.4)(64bit)',
'rpmlib(FileDigests) <= 4.6.0-1',
'rtld(GNU_HASH)',
'xdg-utils'
@@ -132,6 +140,10 @@ export const referenceGeneratedDepsByArch = {
'libc.so.6(GLIBC_2.15)',
'libc.so.6(GLIBC_2.16)',
'libc.so.6(GLIBC_2.17)',
'libc.so.6(GLIBC_2.18)',
'libc.so.6(GLIBC_2.25)',
'libc.so.6(GLIBC_2.27)',
'libc.so.6(GLIBC_2.28)',
'libc.so.6(GLIBC_2.4)',
'libc.so.6(GLIBC_2.6)',
'libc.so.6(GLIBC_2.7)',
@@ -149,6 +161,7 @@ export const referenceGeneratedDepsByArch = {
'libgcc_s.so.1',
'libgcc_s.so.1(GCC_3.0)',
'libgcc_s.so.1(GCC_3.5)',
'libgcc_s.so.1(GCC_4.3.0)',
'libgio-2.0.so.0',
'libglib-2.0.so.0',
'libgobject-2.0.so.0',
@@ -231,6 +244,10 @@ export const referenceGeneratedDepsByArch = {
'libatspi.so.0()(64bit)',
'libc.so.6()(64bit)',
'libc.so.6(GLIBC_2.17)(64bit)',
'libc.so.6(GLIBC_2.18)(64bit)',
'libc.so.6(GLIBC_2.25)(64bit)',
'libc.so.6(GLIBC_2.27)(64bit)',
'libc.so.6(GLIBC_2.28)(64bit)',
'libcairo.so.2()(64bit)',
'libcurl.so.4()(64bit)',
'libdbus-1.so.3()(64bit)',
@@ -242,6 +259,7 @@ export const referenceGeneratedDepsByArch = {
'libgbm.so.1()(64bit)',
'libgcc_s.so.1()(64bit)',
'libgcc_s.so.1(GCC_3.0)(64bit)',
'libgcc_s.so.1(GCC_3.3)(64bit)',
'libgcc_s.so.1(GCC_4.2.0)(64bit)',
'libgcc_s.so.1(GCC_4.5.0)(64bit)',
'libgio-2.0.so.0()(64bit)',
+11 -6
View File
@@ -85,22 +85,27 @@ for (let dir of dirs) {
continue;
}
let opts;
if (dir === 'build') {
const env = { ...process.env };
setupBuildYarnrc();
yarnInstall('build');
opts = { env };
if (process.env['CC']) { env['CC'] = 'gcc'; }
if (process.env['CXX']) { env['CXX'] = 'g++'; }
if (process.env['CXXFLAGS']) { env['CXXFLAGS'] = ''; }
if (process.env['LDFLAGS']) { env['LDFLAGS'] = ''; }
yarnInstall('build', opts);
continue;
}
let opts;
if (/^(.build\/distro\/npm\/)?remote$/.test(dir)) {
// node modules used by vscode server
const env = { ...process.env };
if (process.env['VSCODE_REMOTE_CC']) { env['CC'] = process.env['VSCODE_REMOTE_CC']; }
if (process.env['VSCODE_REMOTE_CXX']) { env['CXX'] = process.env['VSCODE_REMOTE_CXX']; }
if (process.env['CXXFLAGS']) { delete env['CXXFLAGS']; }
if (process.env['CFLAGS']) { delete env['CFLAGS']; }
if (process.env['LDFLAGS']) { delete env['LDFLAGS']; }
if (process.env['VSCODE_REMOTE_CXXFLAGS']) { env['CXXFLAGS'] = process.env['VSCODE_REMOTE_CXXFLAGS']; }
if (process.env['VSCODE_REMOTE_LDFLAGS']) { env['LDFLAGS'] = process.env['VSCODE_REMOTE_LDFLAGS']; }
if (process.env['VSCODE_REMOTE_NODE_GYP']) { env['npm_config_node_gyp'] = process.env['VSCODE_REMOTE_NODE_GYP']; }
opts = { env };
+3 -3
View File
@@ -1721,7 +1721,7 @@ is-extendable@^1.0.1:
is-extglob@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
is-glob@^4.0.1:
version "4.0.1"
@@ -2201,7 +2201,7 @@ picomatch@^2.2.1:
pify@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw=
integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==
pify@^3.0.0:
version "3.0.0"
@@ -2602,7 +2602,7 @@ through2@^4.0.2:
through@^2.3.8:
version "2.3.8"
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==
time-stamp@^1.0.0:
version "1.1.0"
@@ -189,11 +189,11 @@ export function appendToLinkSnippet(
title: string,
link: string,
placeholderValue: number,
isExternalLink: boolean,
_isExternalLink: boolean,
): void {
snippet.appendText('[');
snippet.appendPlaceholder(escapeBrackets(title) || 'Title', placeholderValue);
snippet.appendText(`](${escapeMarkdownLinkPath(link, isExternalLink)})`);
snippet.appendText(`](${escapeMarkdownLinkPath(link)})`);
}
export function createUriListSnippet(
@@ -238,17 +238,15 @@ export function createUriListSnippet(
snippet.appendPlaceholder(escapeBrackets(title) || 'Title', placeholderValue);
snippet.appendText('"></audio>');
} else if (insertAsMedia) {
if (insertAsMedia) {
insertedImageCount++;
if (pasteAsMarkdownLink) {
snippet.appendText('![');
const placeholderText = escapeBrackets(title) || options?.placeholderText || 'Alt text';
const placeholderIndex = typeof options?.placeholderStartIndex !== 'undefined' ? options?.placeholderStartIndex + i : (placeholderValue === 0 ? undefined : placeholderValue);
snippet.appendPlaceholder(placeholderText, placeholderIndex);
snippet.appendText(`](${escapeMarkdownLinkPath(mdPath, isExternalLink)})`);
} else {
snippet.appendText(escapeMarkdownLinkPath(mdPath, isExternalLink));
}
insertedImageCount++;
if (pasteAsMarkdownLink) {
snippet.appendText('![');
const placeholderText = escapeBrackets(title) || options?.placeholderText || 'Alt text';
const placeholderIndex = typeof options?.placeholderStartIndex !== 'undefined' ? options?.placeholderStartIndex + i : (placeholderValue === 0 ? undefined : placeholderValue);
snippet.appendPlaceholder(placeholderText, placeholderIndex);
snippet.appendText(`](${escapeMarkdownLinkPath(mdPath)})`);
} else {
snippet.appendText(escapeMarkdownLinkPath(mdPath));
}
} else {
insertedLinkCount++;
@@ -371,12 +369,12 @@ function escapeHtmlAttribute(attr: string): string {
return encodeURI(attr).replaceAll('"', '&quot;');
}
function escapeMarkdownLinkPath(mdPath: string, isExternalLink: boolean): string {
function escapeMarkdownLinkPath(mdPath: string): string {
if (needsBracketLink(mdPath)) {
return '<' + mdPath.replaceAll('<', '\\<').replaceAll('>', '\\>') + '>';
}
return isExternalLink ? mdPath : encodeURI(mdPath);
return mdPath;
}
function escapeBrackets(value: string): string {
@@ -384,7 +382,7 @@ function escapeBrackets(value: string): string {
return value;
}
function needsBracketLink(mdPath: string) {
function needsBracketLink(mdPath: string): boolean {
// Links with whitespace or control characters must be enclosed in brackets
if (mdPath.startsWith('<') || /\s|[\u007F\u0000-\u001f]/.test(mdPath)) {
return true;
+6 -8
View File
@@ -5,11 +5,10 @@
import { RGBA, Color } from './color';
import { ansiColorIdentifiers } from './colorMap';
import { linkify } from './linkify';
import { LinkOptions, linkify } from './linkify';
export function handleANSIOutput(text: string, trustHtml: boolean): HTMLSpanElement {
const workspaceFolder = undefined;
export function handleANSIOutput(text: string, linkOptions: LinkOptions): HTMLSpanElement {
const root: HTMLSpanElement = document.createElement('span');
const textLength: number = text.length;
@@ -52,7 +51,7 @@ export function handleANSIOutput(text: string, trustHtml: boolean): HTMLSpanElem
if (sequenceFound) {
// Flush buffer with previous styles.
appendStylizedStringToContainer(root, buffer, trustHtml, styleNames, workspaceFolder, customFgColor, customBgColor, customUnderlineColor);
appendStylizedStringToContainer(root, buffer, linkOptions, styleNames, customFgColor, customBgColor, customUnderlineColor);
buffer = '';
@@ -98,7 +97,7 @@ export function handleANSIOutput(text: string, trustHtml: boolean): HTMLSpanElem
// Flush remaining text buffer if not empty.
if (buffer) {
appendStylizedStringToContainer(root, buffer, trustHtml, styleNames, workspaceFolder, customFgColor, customBgColor, customUnderlineColor);
appendStylizedStringToContainer(root, buffer, linkOptions, styleNames, customFgColor, customBgColor, customUnderlineColor);
}
return root;
@@ -382,9 +381,8 @@ export function handleANSIOutput(text: string, trustHtml: boolean): HTMLSpanElem
function appendStylizedStringToContainer(
root: HTMLElement,
stringContent: string,
trustHtml: boolean,
linkOptions: LinkOptions,
cssClasses: string[],
workspaceFolder: string | undefined,
customTextColor?: RGBA | string,
customBackgroundColor?: RGBA | string,
customUnderlineColor?: RGBA | string
@@ -397,7 +395,7 @@ function appendStylizedStringToContainer(
if (container.childElementCount === 0) {
// plain text
container = linkify(stringContent, true, workspaceFolder, trustHtml);
container = linkify(stringContent, linkOptions, true);
}
container.className = cssClasses.join(' ');
+6 -3
View File
@@ -176,7 +176,9 @@ function renderError(
const stackTrace = formatStackTrace(err.stack);
const outputScrolling = scrollingEnabled(outputInfo, ctx.settings);
const content = createOutputContent(outputInfo.id, stackTrace ?? '', { linesLimit: ctx.settings.lineLimit, scrollable: outputScrolling, trustHtml });
const outputOptions = { linesLimit: ctx.settings.lineLimit, scrollable: outputScrolling, trustHtml, linkifyFilePaths: ctx.settings.linkifyFilePaths };
const content = createOutputContent(outputInfo.id, stackTrace ?? '', outputOptions);
const contentParent = document.createElement('div');
contentParent.classList.toggle('word-wrap', ctx.settings.outputWordWrap);
disposableStore.push(ctx.onDidChangeSettings(e => {
@@ -279,7 +281,7 @@ function scrollingEnabled(output: OutputItem, options: RenderOptions) {
function renderStream(outputInfo: OutputWithAppend, outputElement: HTMLElement, error: boolean, ctx: IRichRenderContext): IDisposable {
const disposableStore = createDisposableStore();
const outputScrolling = scrollingEnabled(outputInfo, ctx.settings);
const outputOptions = { linesLimit: ctx.settings.lineLimit, scrollable: outputScrolling, trustHtml: false, error };
const outputOptions = { linesLimit: ctx.settings.lineLimit, scrollable: outputScrolling, trustHtml: false, error, linkifyFilePaths: ctx.settings.linkifyFilePaths };
outputElement.classList.add('output-stream');
@@ -330,7 +332,8 @@ function renderText(outputInfo: OutputItem, outputElement: HTMLElement, ctx: IRi
const text = outputInfo.text();
const outputScrolling = scrollingEnabled(outputInfo, ctx.settings);
const content = createOutputContent(outputInfo.id, text, { linesLimit: ctx.settings.lineLimit, scrollable: outputScrolling, trustHtml: false });
const outputOptions = { linesLimit: ctx.settings.lineLimit, scrollable: outputScrolling, trustHtml: false, linkifyFilePaths: ctx.settings.linkifyFilePaths };
const content = createOutputContent(outputInfo.id, text, outputOptions);
content.classList.add('output-plaintext');
if (ctx.settings.outputWordWrap) {
content.classList.add('word-wrap');
+29 -15
View File
@@ -26,6 +26,11 @@ type LinkPart = {
captures: string[];
};
export type LinkOptions = {
trustHtml?: boolean;
linkifyFilePaths: boolean;
};
export class LinkDetector {
// used by unit tests
@@ -51,7 +56,7 @@ export class LinkDetector {
* When splitLines is true, each line of the text, even if it contains no links, is wrapped in a <span>
* and added as a child of the returned <span>.
*/
linkify(text: string, splitLines?: boolean, workspaceFolder?: string, trustHtml?: boolean): HTMLElement {
linkify(text: string, options: LinkOptions, splitLines?: boolean): HTMLElement {
if (splitLines) {
const lines = text.split('\n');
for (let i = 0; i < lines.length - 1; i++) {
@@ -61,7 +66,7 @@ export class LinkDetector {
// Remove the last element ('') that split added.
lines.pop();
}
const elements = lines.map(line => this.linkify(line, false, workspaceFolder, trustHtml));
const elements = lines.map(line => this.linkify(line, options, false));
if (elements.length === 1) {
// Do not wrap single line with extra span.
return elements[0];
@@ -72,8 +77,9 @@ export class LinkDetector {
}
const container = document.createElement('span');
for (const part of this.detectLinks(text)) {
for (const part of this.detectLinks(text, !!options.trustHtml, options.linkifyFilePaths)) {
try {
let span: HTMLSpanElement | null = null;
switch (part.kind) {
case 'text':
container.appendChild(document.createTextNode(part.value));
@@ -83,13 +89,9 @@ export class LinkDetector {
container.appendChild(this.createWebLink(part.value));
break;
case 'html':
if (this.shouldGenerateHtml(!!trustHtml)) {
const span = document.createElement('span');
span.innerHTML = this.createHtml(part.value)!;
container.appendChild(span);
} else {
container.appendChild(document.createTextNode(part.value));
}
span = document.createElement('span');
span.innerHTML = this.createHtml(part.value)!;
container.appendChild(span);
break;
}
} catch (e) {
@@ -149,15 +151,27 @@ export class LinkDetector {
return link;
}
private detectLinks(text: string): LinkPart[] {
private detectLinks(text: string, trustHtml: boolean, detectFilepaths: boolean): LinkPart[] {
if (text.length > MAX_LENGTH) {
return [{ kind: 'text', value: text, captures: [] }];
}
const regexes: RegExp[] = [HTML_LINK_REGEX, WEB_LINK_REGEX, PATH_LINK_REGEX];
const kinds: LinkKind[] = ['html', 'web', 'path'];
const regexes: RegExp[] = [];
const kinds: LinkKind[] = [];
const result: LinkPart[] = [];
if (this.shouldGenerateHtml(trustHtml)) {
regexes.push(HTML_LINK_REGEX);
kinds.push('html');
}
regexes.push(WEB_LINK_REGEX);
kinds.push('web');
if (detectFilepaths) {
regexes.push(PATH_LINK_REGEX);
kinds.push('path');
}
const splitOne = (text: string, regexIndex: number) => {
if (regexIndex >= regexes.length) {
result.push({ value: text, kind: 'text', captures: [] });
@@ -192,6 +206,6 @@ export class LinkDetector {
}
const linkDetector = new LinkDetector();
export function linkify(text: string, splitLines?: boolean, workspaceFolder?: string, trustHtml = false) {
return linkDetector.linkify(text, splitLines, workspaceFolder, trustHtml);
export function linkify(text: string, linkOptions: LinkOptions, splitLines?: boolean) {
return linkDetector.linkify(text, linkOptions, splitLines);
}
@@ -32,6 +32,7 @@ export interface RenderOptions {
readonly lineLimit: number;
readonly outputScrolling: boolean;
readonly outputWordWrap: boolean;
readonly linkifyFilePaths: boolean;
}
export type IRichRenderContext = RendererContext<void> & { readonly settings: RenderOptions; readonly onDidChangeSettings: Event<RenderOptions> };
@@ -41,6 +42,7 @@ export type OutputElementOptions = {
scrollable?: boolean;
error?: boolean;
trustHtml?: boolean;
linkifyFilePaths: boolean;
};
export interface OutputWithAppend extends OutputItem {
@@ -15,27 +15,32 @@ suite('Notebook builtin output link detection', () => {
LinkDetector.injectedHtmlCreator = (value: string) => value;
test('no links', () => {
const htmlWithLinks = linkify('hello', true, undefined, true);
const htmlWithLinks = linkify('hello', { linkifyFilePaths: true, trustHtml: true }, true);
assert.equal(htmlWithLinks.innerHTML, 'hello');
});
test('web link detection', () => {
const htmlWithLinks = linkify('something www.example.com something', true, undefined, true);
const htmlWithLinks = linkify('something www.example.com something', { linkifyFilePaths: true, trustHtml: true }, true);
const htmlWithLinks2 = linkify('something www.example.com something', { linkifyFilePaths: false, trustHtml: false }, true);
assert.equal(htmlWithLinks.innerHTML, 'something <a href="www.example.com">www.example.com</a> something');
assert.equal(htmlWithLinks.textContent, 'something www.example.com something');
assert.equal(htmlWithLinks2.innerHTML, 'something <a href="www.example.com">www.example.com</a> something');
assert.equal(htmlWithLinks2.textContent, 'something www.example.com something');
});
test('html link detection', () => {
const htmlWithLinks = linkify('something <a href="www.example.com">link</a> something', true, undefined, true);
const htmlWithLinks = linkify('something <a href="www.example.com">link</a> something', { linkifyFilePaths: true, trustHtml: true }, true);
const htmlWithLinks2 = linkify('something <a href="www.example.com">link</a> something', { linkifyFilePaths: false, trustHtml: true }, true);
assert.equal(htmlWithLinks.innerHTML, 'something <span><a href="www.example.com">link</a></span> something');
assert.equal(htmlWithLinks.textContent, 'something link something');
assert.equal(htmlWithLinks2.innerHTML, 'something <span><a href="www.example.com">link</a></span> something');
assert.equal(htmlWithLinks2.textContent, 'something link something');
});
test('html link without trust', () => {
const trustHtml = false;
const htmlWithLinks = linkify('something <a href="file.py">link</a> something', true, undefined, trustHtml);
const htmlWithLinks = linkify('something <a href="file.py">link</a> something', { linkifyFilePaths: true, trustHtml: false }, true);
assert.equal(htmlWithLinks.innerHTML, 'something &lt;a href="file.py"&gt;link&lt;/a&gt; something');
assert.equal(htmlWithLinks.textContent, 'something <a href="file.py">link</a> something');
@@ -273,6 +273,36 @@ suite('Notebook builtin output renderer', () => {
assert.ok(inserted.innerHTML.indexOf('shouldBeTruncated') === -1, `Beginning content should be truncated`);
});
test(`Render filepath links in text output when enabled`, async () => {
LinkDetector.injectedHtmlCreator = (value: string) => value;
const context = createContext({ outputWordWrap: true, outputScrolling: true, linkifyFilePaths: true });
const renderer = await activate(context);
assert.ok(renderer, 'Renderer not created');
const outputElement = new OutputHtml().getFirstOuputElement();
const outputItem = createOutputItem('./dir/file.txt', stdoutMimeType);
await renderer!.renderOutputItem(outputItem, outputElement);
const inserted = outputElement.firstChild as HTMLElement;
assert.ok(inserted, `nothing appended to output element: ${outputElement.innerHTML}`);
assert.ok(outputElement.innerHTML.indexOf('<a href="./dir/file.txt">') !== -1, `inner HTML:\n ${outputElement.innerHTML}`);
});
test(`No filepath links in text output when disabled`, async () => {
LinkDetector.injectedHtmlCreator = (value: string) => value;
const context = createContext({ outputWordWrap: true, outputScrolling: true, linkifyFilePaths: false });
const renderer = await activate(context);
assert.ok(renderer, 'Renderer not created');
const outputElement = new OutputHtml().getFirstOuputElement();
const outputItem = createOutputItem('./dir/file.txt', stdoutMimeType);
await renderer!.renderOutputItem(outputItem, outputElement);
const inserted = outputElement.firstChild as HTMLElement;
assert.ok(inserted, `nothing appended to output element: ${outputElement.innerHTML}`);
assert.ok(outputElement.innerHTML.indexOf('<a href="./dir/file.txt">') === -1, `inner HTML:\n ${outputElement.innerHTML}`);
});
test(`Render with wordwrap and scrolling for error output`, async () => {
LinkDetector.injectedHtmlCreator = (value: string) => value;
const context = createContext({ outputWordWrap: true, outputScrolling: true });
@@ -474,7 +504,6 @@ suite('Notebook builtin output renderer', () => {
const inserted = outputElement.firstChild as HTMLElement;
assert.ok(inserted, `nothing appended to output element: ${outputElement.innerHTML}`);
//assert.ok(false, `TextContent:\n ${outputElement.textContent}`);
assert.ok(outputElement.innerHTML.indexOf('class="code-background-colored"') === -1, `inner HTML:\n ${outputElement.innerHTML}`);
});
+15 -12
View File
@@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { handleANSIOutput } from './ansi';
import { LinkOptions } from './linkify';
import { OutputElementOptions, OutputWithAppend } from './rendererTypes';
export const scrollableClass = 'scrollable';
@@ -68,44 +69,44 @@ function generateNestedViewAllElement(outputId: string) {
return container;
}
function truncatedArrayOfString(id: string, buffer: string[], linesLimit: number, trustHtml: boolean) {
function truncatedArrayOfString(id: string, buffer: string[], linesLimit: number, linkOptions: LinkOptions) {
const container = document.createElement('div');
const lineCount = buffer.length;
if (lineCount <= linesLimit) {
const spanElement = handleANSIOutput(buffer.join('\n'), trustHtml);
const spanElement = handleANSIOutput(buffer.join('\n'), linkOptions);
container.appendChild(spanElement);
return container;
}
container.appendChild(handleANSIOutput(buffer.slice(0, linesLimit - 5).join('\n'), trustHtml));
container.appendChild(handleANSIOutput(buffer.slice(0, linesLimit - 5).join('\n'), linkOptions));
// truncated piece
const elipses = document.createElement('div');
elipses.innerText = '...';
container.appendChild(elipses);
container.appendChild(handleANSIOutput(buffer.slice(lineCount - 5).join('\n'), trustHtml));
container.appendChild(handleANSIOutput(buffer.slice(lineCount - 5).join('\n'), linkOptions));
container.appendChild(generateViewMoreElement(id));
return container;
}
function scrollableArrayOfString(id: string, buffer: string[], trustHtml: boolean) {
function scrollableArrayOfString(id: string, buffer: string[], linkOptions: LinkOptions) {
const element = document.createElement('div');
if (buffer.length > softScrollableLineLimit) {
element.appendChild(generateNestedViewAllElement(id));
}
element.appendChild(handleANSIOutput(buffer.slice(-1 * softScrollableLineLimit).join('\n'), trustHtml));
element.appendChild(handleANSIOutput(buffer.slice(-1 * softScrollableLineLimit).join('\n'), linkOptions));
return element;
}
const outputLengths: Record<string, number> = {};
function appendScrollableOutput(element: HTMLElement, id: string, appended: string, trustHtml: boolean) {
function appendScrollableOutput(element: HTMLElement, id: string, appended: string, linkOptions: LinkOptions) {
if (!outputLengths[id]) {
outputLengths[id] = 0;
}
@@ -117,22 +118,23 @@ function appendScrollableOutput(element: HTMLElement, id: string, appended: stri
return false;
}
else {
element.appendChild(handleANSIOutput(buffer.join('\n'), trustHtml));
element.appendChild(handleANSIOutput(buffer.join('\n'), linkOptions));
outputLengths[id] = appendedLength;
}
return true;
}
export function createOutputContent(id: string, outputText: string, options: OutputElementOptions): HTMLElement {
const { linesLimit, error, scrollable, trustHtml } = options;
const { linesLimit, error, scrollable, trustHtml, linkifyFilePaths } = options;
const linkOptions: LinkOptions = { linkifyFilePaths, trustHtml };
const buffer = outputText.split(/\r\n|\r|\n/g);
outputLengths[id] = outputLengths[id] = Math.min(buffer.length, softScrollableLineLimit);
let outputElement: HTMLElement;
if (scrollable) {
outputElement = scrollableArrayOfString(id, buffer, !!trustHtml);
outputElement = scrollableArrayOfString(id, buffer, linkOptions);
} else {
outputElement = truncatedArrayOfString(id, buffer, linesLimit, !!trustHtml);
outputElement = truncatedArrayOfString(id, buffer, linesLimit, linkOptions);
}
outputElement.setAttribute('output-item-id', id);
@@ -145,9 +147,10 @@ export function createOutputContent(id: string, outputText: string, options: Out
export function appendOutput(outputInfo: OutputWithAppend, existingContent: HTMLElement, options: OutputElementOptions) {
const appendedText = outputInfo.appendedText?.();
const linkOptions = { linkifyFilePaths: options.linkifyFilePaths, trustHtml: options.trustHtml };
// appending output only supported for scrollable ouputs currently
if (appendedText && options.scrollable) {
if (appendScrollableOutput(existingContent, outputInfo.id, appendedText, false)) {
if (appendScrollableOutput(existingContent, outputInfo.id, appendedText, linkOptions)) {
return;
}
}
@@ -85,7 +85,7 @@ class TypeScriptRenameProvider implements vscode.RenameProvider {
}
if (renameInfo.fileToRename) {
const edits = await this.renameFile(renameInfo.fileToRename, newName, token);
const edits = await this.renameFile(renameInfo.fileToRename, renameInfo.fullDisplayName, newName, token);
if (edits) {
return edits;
} else {
@@ -170,13 +170,17 @@ class TypeScriptRenameProvider implements vscode.RenameProvider {
private async renameFile(
fileToRename: string,
fullDisplayName: string,
newName: string,
token: vscode.CancellationToken,
): Promise<vscode.WorkspaceEdit | undefined> {
// Make sure we preserve file extension if none provided
// Make sure we preserve file extension if extension is unchanged or none provided
if (!path.extname(newName)) {
newName += path.extname(fileToRename);
}
else if (path.extname(newName) === path.extname(fullDisplayName)) {
newName = newName.slice(0, newName.length - path.extname(newName).length) + path.extname(fileToRename);
}
const dirname = path.dirname(fileToRename);
const newFilePath = path.join(dirname, newName);
+9 -9
View File
@@ -1,7 +1,7 @@
{
"name": "code-oss-dev",
"version": "1.86.0",
"distro": "1a07d32cc58bafa5dc4cf8cfa8f044b3789e285c",
"distro": "536a5224f3131ed95718b23b3f82d75485d89721",
"author": {
"name": "Microsoft Corporation"
},
@@ -80,14 +80,14 @@
"@vscode/windows-mutex": "^0.4.4",
"@vscode/windows-process-tree": "^0.5.0",
"@vscode/windows-registry": "^1.1.0",
"@xterm/addon-canvas": "0.6.0-beta.15",
"@xterm/addon-image": "0.7.0-beta.13",
"@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.15",
"@xterm/xterm": "5.4.0-beta.15",
"@xterm/addon-canvas": "0.6.0-beta.16",
"@xterm/addon-image": "0.7.0-beta.14",
"@xterm/addon-search": "0.14.0-beta.16",
"@xterm/addon-serialize": "0.12.0-beta.16",
"@xterm/addon-unicode11": "0.7.0-beta.16",
"@xterm/addon-webgl": "0.17.0-beta.16",
"@xterm/headless": "5.4.0-beta.16",
"@xterm/xterm": "5.4.0-beta.16",
"graceful-fs": "4.2.11",
"http-proxy-agent": "^7.0.0",
"https-proxy-agent": "^7.0.2",
+8 -8
View File
@@ -13,14 +13,14 @@
"@vscode/vscode-languagedetection": "1.0.21",
"@vscode/windows-process-tree": "^0.5.0",
"@vscode/windows-registry": "^1.1.0",
"@xterm/addon-canvas": "0.6.0-beta.15",
"@xterm/addon-image": "0.7.0-beta.13",
"@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.15",
"@xterm/xterm": "5.4.0-beta.15",
"@xterm/addon-canvas": "0.6.0-beta.16",
"@xterm/addon-image": "0.7.0-beta.14",
"@xterm/addon-search": "0.14.0-beta.16",
"@xterm/addon-serialize": "0.12.0-beta.16",
"@xterm/addon-unicode11": "0.7.0-beta.16",
"@xterm/addon-webgl": "0.17.0-beta.16",
"@xterm/headless": "5.4.0-beta.16",
"@xterm/xterm": "5.4.0-beta.16",
"cookie": "^0.4.0",
"graceful-fs": "4.2.11",
"http-proxy-agent": "^7.0.0",
+7 -7
View File
@@ -7,13 +7,13 @@
"@microsoft/1ds-post-js": "^3.2.13",
"@vscode/iconv-lite-umd": "0.7.0",
"@vscode/vscode-languagedetection": "1.0.21",
"@xterm/addon-canvas": "0.6.0-beta.15",
"@xterm/addon-image": "0.7.0-beta.13",
"@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/xterm": "5.4.0-beta.15",
"@xterm/addon-canvas": "0.6.0-beta.16",
"@xterm/addon-image": "0.7.0-beta.14",
"@xterm/addon-search": "0.14.0-beta.16",
"@xterm/addon-serialize": "0.12.0-beta.16",
"@xterm/addon-unicode11": "0.7.0-beta.16",
"@xterm/addon-webgl": "0.17.0-beta.16",
"@xterm/xterm": "5.4.0-beta.16",
"jschardet": "3.0.0",
"tas-client-umd": "0.1.8",
"vscode-oniguruma": "1.7.0",
+28 -28
View File
@@ -48,40 +48,40 @@
resolved "https://registry.yarnpkg.com/@vscode/vscode-languagedetection/-/vscode-languagedetection-1.0.21.tgz#89b48f293f6aa3341bb888c1118d16ff13b032d3"
integrity sha512-zSUH9HYCw5qsCtd7b31yqkpaCU6jhtkKLkvOOA8yTrIRfBSOFb8PPhgmMicD7B/m+t4PwOJXzU1XDtrM9Fd3/g==
"@xterm/addon-canvas@0.6.0-beta.15":
version "0.6.0-beta.15"
resolved "https://registry.yarnpkg.com/@xterm/addon-canvas/-/addon-canvas-0.6.0-beta.15.tgz#ac800c3e8a1a26eeb0f76e36dabc342a840a1e0b"
integrity sha512-P5E+ywLTGG+Ii48Q3TZyK6aOzkYnoghJnUiyCb67g7zva3nDjw8Q4kKMlOrvZl6RHsLkSBwwLjOvUvg1nNOusg==
"@xterm/addon-canvas@0.6.0-beta.16":
version "0.6.0-beta.16"
resolved "https://registry.yarnpkg.com/@xterm/addon-canvas/-/addon-canvas-0.6.0-beta.16.tgz#d22ba7f1b211882215c5206ca07ce177378a898f"
integrity sha512-o89xcm0Tqy1ksEYMq3EIqxJNDUWJBaS9QUggc7i5vKUL2unw9TMa5IiiNzc3CsBOlBQDlITwEXoHDEbOMxoZPQ==
"@xterm/addon-image@0.7.0-beta.13":
version "0.7.0-beta.13"
resolved "https://registry.yarnpkg.com/@xterm/addon-image/-/addon-image-0.7.0-beta.13.tgz#bb854ecc3c2c9363804ca5c2d386e4298ffff425"
integrity sha512-q57H1ONHJ5e14XEN0MsjnvB3MdlsyVVjwAJfjWjESJFZT2e2qxyc2kflvXcTiBkLC4RCfnYchvU6PjgHJll3jw==
"@xterm/addon-image@0.7.0-beta.14":
version "0.7.0-beta.14"
resolved "https://registry.yarnpkg.com/@xterm/addon-image/-/addon-image-0.7.0-beta.14.tgz#39b123dd0a0390766aff631cf43cb2e51b3b2174"
integrity sha512-oCOIupROzkb5p2vZarY6HrX74OqvtbmjnkC6uuGEJXQ75XL2CX+uTUl2DlgeSTvvR0S8ZVB3hQlp4hrtoNNelA==
"@xterm/addon-search@0.14.0-beta.15":
version "0.14.0-beta.15"
resolved "https://registry.yarnpkg.com/@xterm/addon-search/-/addon-search-0.14.0-beta.15.tgz#48ed3f0899cdfe3310058aa46dc03b7e40269742"
integrity sha512-HFiyJgHD8wnhYZLF3Dy5J4dWMhpCp6WR1IEoT3PchV3c6s52Sc8GCL/eJtequ8Rai5b7x/o0gNxBLzDL5dODnA==
"@xterm/addon-search@0.14.0-beta.16":
version "0.14.0-beta.16"
resolved "https://registry.yarnpkg.com/@xterm/addon-search/-/addon-search-0.14.0-beta.16.tgz#5fa21d2b993970e8ced1e0ada3dcca5f7581c314"
integrity sha512-e6l5jCJIULQ6nzRcc0gp9obZsqd76qubAr0HZF6Ebxf3KOGRz4UX6g+kgt6RB1liWgG94WD8vI1rGB1z5bMSEg==
"@xterm/addon-serialize@0.12.0-beta.15":
version "0.12.0-beta.15"
resolved "https://registry.yarnpkg.com/@xterm/addon-serialize/-/addon-serialize-0.12.0-beta.15.tgz#ca69f732490ae4512c312c4c0edf239d575390d0"
integrity sha512-SREdfJZ2eafeg846mYM8akjgezc+b+hN/a+UkvI/IOStE4kJXwNWQXSGPfmn+9UNzRxTYUEmjT+nbadE9M+9yg==
"@xterm/addon-serialize@0.12.0-beta.16":
version "0.12.0-beta.16"
resolved "https://registry.yarnpkg.com/@xterm/addon-serialize/-/addon-serialize-0.12.0-beta.16.tgz#68c4d68dba7ff17a231650cc0d07dcc77721877b"
integrity sha512-F6ngtvTC5VDLn585uJro7V1xjM43TbjPQjQ6Fn0Uic3+dsQrbPFxZmNZuQOjMZDoYj/febFsuspKjXdpoxo21w==
"@xterm/addon-unicode11@0.7.0-beta.15":
version "0.7.0-beta.15"
resolved "https://registry.yarnpkg.com/@xterm/addon-unicode11/-/addon-unicode11-0.7.0-beta.15.tgz#3127bd0e0ba611ac7f1a72417c449dd6e234f054"
integrity sha512-6ZpYy3OMokO0CSmHrhvqbLVZg2iMDGGVeaYqPhe3+Ga5t9y1mSRXjKkKpXiQQYbEpiGcLd6cKfyfSzejw8v4tg==
"@xterm/addon-unicode11@0.7.0-beta.16":
version "0.7.0-beta.16"
resolved "https://registry.yarnpkg.com/@xterm/addon-unicode11/-/addon-unicode11-0.7.0-beta.16.tgz#c4c640cb119290e1d0a6401ac018aba1d71287f9"
integrity sha512-sP81NX13madSeATjlBReZbaay17DgatR7dZP6OF8aMyJf6cBVaHMYjTipyw3NnsmjUtBfLc3Alu+JKv8NFteiw==
"@xterm/addon-webgl@0.17.0-beta.15":
version "0.17.0-beta.15"
resolved "https://registry.yarnpkg.com/@xterm/addon-webgl/-/addon-webgl-0.17.0-beta.15.tgz#19700e78bf86bec21e5d2049ea4f488a70db7960"
integrity sha512-w/sszGoGk4X1QniYP+T/NGYz83TXIIoSgWUVeThYgNM2QZjKxymBbMn2VAVAPS4WEEGMCKFNJaeskc0k9pgmzA==
"@xterm/addon-webgl@0.17.0-beta.16":
version "0.17.0-beta.16"
resolved "https://registry.yarnpkg.com/@xterm/addon-webgl/-/addon-webgl-0.17.0-beta.16.tgz#75466614bf8ea02a3fcb0900df48724c2344d081"
integrity sha512-+/eTLvSgYjvRX7oAKfpCDZdotrE8P/asCKXQtXjkbOtYRToI7kWEYfJzfgdFKFgDLKOpDdgY6Bgq384wEewlTA==
"@xterm/xterm@5.4.0-beta.15":
version "5.4.0-beta.15"
resolved "https://registry.yarnpkg.com/@xterm/xterm/-/xterm-5.4.0-beta.15.tgz#d76f3f92730f27dc960db415f36361a1ba751c54"
integrity sha512-jtOJLaEwjmgciM3VEmwvb1S5jLD14jRkg234qPq4H//JJ+D8fTwRblON5T2ccpcClpVGaW4Ro5g/XPuFuQ8dvw==
"@xterm/xterm@5.4.0-beta.16":
version "5.4.0-beta.16"
resolved "https://registry.yarnpkg.com/@xterm/xterm/-/xterm-5.4.0-beta.16.tgz#eb00506e56ba78c587fcacbada096c2af3693992"
integrity sha512-ARzWYQ8LfuZIn47TS8c+XKQhn/1ZVvbHdwlpolZIrT2pTarP+71U1b6cSpF7fV+OIV6tAPA8+q4g/1ZKHuOX8g==
jschardet@3.0.0:
version "3.0.0"
+32 -32
View File
@@ -114,45 +114,45 @@
resolved "https://registry.yarnpkg.com/@vscode/windows-registry/-/windows-registry-1.1.0.tgz#03dace7c29c46f658588b9885b9580e453ad21f9"
integrity sha512-5AZzuWJpGscyiMOed0IuyEwt6iKmV5Us7zuwCDCFYMIq7tsvooO9BUiciywsvuthGz6UG4LSpeDeCxvgMVhnIw==
"@xterm/addon-canvas@0.6.0-beta.15":
version "0.6.0-beta.15"
resolved "https://registry.yarnpkg.com/@xterm/addon-canvas/-/addon-canvas-0.6.0-beta.15.tgz#ac800c3e8a1a26eeb0f76e36dabc342a840a1e0b"
integrity sha512-P5E+ywLTGG+Ii48Q3TZyK6aOzkYnoghJnUiyCb67g7zva3nDjw8Q4kKMlOrvZl6RHsLkSBwwLjOvUvg1nNOusg==
"@xterm/addon-canvas@0.6.0-beta.16":
version "0.6.0-beta.16"
resolved "https://registry.yarnpkg.com/@xterm/addon-canvas/-/addon-canvas-0.6.0-beta.16.tgz#d22ba7f1b211882215c5206ca07ce177378a898f"
integrity sha512-o89xcm0Tqy1ksEYMq3EIqxJNDUWJBaS9QUggc7i5vKUL2unw9TMa5IiiNzc3CsBOlBQDlITwEXoHDEbOMxoZPQ==
"@xterm/addon-image@0.7.0-beta.13":
version "0.7.0-beta.13"
resolved "https://registry.yarnpkg.com/@xterm/addon-image/-/addon-image-0.7.0-beta.13.tgz#bb854ecc3c2c9363804ca5c2d386e4298ffff425"
integrity sha512-q57H1ONHJ5e14XEN0MsjnvB3MdlsyVVjwAJfjWjESJFZT2e2qxyc2kflvXcTiBkLC4RCfnYchvU6PjgHJll3jw==
"@xterm/addon-image@0.7.0-beta.14":
version "0.7.0-beta.14"
resolved "https://registry.yarnpkg.com/@xterm/addon-image/-/addon-image-0.7.0-beta.14.tgz#39b123dd0a0390766aff631cf43cb2e51b3b2174"
integrity sha512-oCOIupROzkb5p2vZarY6HrX74OqvtbmjnkC6uuGEJXQ75XL2CX+uTUl2DlgeSTvvR0S8ZVB3hQlp4hrtoNNelA==
"@xterm/addon-search@0.14.0-beta.15":
version "0.14.0-beta.15"
resolved "https://registry.yarnpkg.com/@xterm/addon-search/-/addon-search-0.14.0-beta.15.tgz#48ed3f0899cdfe3310058aa46dc03b7e40269742"
integrity sha512-HFiyJgHD8wnhYZLF3Dy5J4dWMhpCp6WR1IEoT3PchV3c6s52Sc8GCL/eJtequ8Rai5b7x/o0gNxBLzDL5dODnA==
"@xterm/addon-search@0.14.0-beta.16":
version "0.14.0-beta.16"
resolved "https://registry.yarnpkg.com/@xterm/addon-search/-/addon-search-0.14.0-beta.16.tgz#5fa21d2b993970e8ced1e0ada3dcca5f7581c314"
integrity sha512-e6l5jCJIULQ6nzRcc0gp9obZsqd76qubAr0HZF6Ebxf3KOGRz4UX6g+kgt6RB1liWgG94WD8vI1rGB1z5bMSEg==
"@xterm/addon-serialize@0.12.0-beta.15":
version "0.12.0-beta.15"
resolved "https://registry.yarnpkg.com/@xterm/addon-serialize/-/addon-serialize-0.12.0-beta.15.tgz#ca69f732490ae4512c312c4c0edf239d575390d0"
integrity sha512-SREdfJZ2eafeg846mYM8akjgezc+b+hN/a+UkvI/IOStE4kJXwNWQXSGPfmn+9UNzRxTYUEmjT+nbadE9M+9yg==
"@xterm/addon-serialize@0.12.0-beta.16":
version "0.12.0-beta.16"
resolved "https://registry.yarnpkg.com/@xterm/addon-serialize/-/addon-serialize-0.12.0-beta.16.tgz#68c4d68dba7ff17a231650cc0d07dcc77721877b"
integrity sha512-F6ngtvTC5VDLn585uJro7V1xjM43TbjPQjQ6Fn0Uic3+dsQrbPFxZmNZuQOjMZDoYj/febFsuspKjXdpoxo21w==
"@xterm/addon-unicode11@0.7.0-beta.15":
version "0.7.0-beta.15"
resolved "https://registry.yarnpkg.com/@xterm/addon-unicode11/-/addon-unicode11-0.7.0-beta.15.tgz#3127bd0e0ba611ac7f1a72417c449dd6e234f054"
integrity sha512-6ZpYy3OMokO0CSmHrhvqbLVZg2iMDGGVeaYqPhe3+Ga5t9y1mSRXjKkKpXiQQYbEpiGcLd6cKfyfSzejw8v4tg==
"@xterm/addon-unicode11@0.7.0-beta.16":
version "0.7.0-beta.16"
resolved "https://registry.yarnpkg.com/@xterm/addon-unicode11/-/addon-unicode11-0.7.0-beta.16.tgz#c4c640cb119290e1d0a6401ac018aba1d71287f9"
integrity sha512-sP81NX13madSeATjlBReZbaay17DgatR7dZP6OF8aMyJf6cBVaHMYjTipyw3NnsmjUtBfLc3Alu+JKv8NFteiw==
"@xterm/addon-webgl@0.17.0-beta.15":
version "0.17.0-beta.15"
resolved "https://registry.yarnpkg.com/@xterm/addon-webgl/-/addon-webgl-0.17.0-beta.15.tgz#19700e78bf86bec21e5d2049ea4f488a70db7960"
integrity sha512-w/sszGoGk4X1QniYP+T/NGYz83TXIIoSgWUVeThYgNM2QZjKxymBbMn2VAVAPS4WEEGMCKFNJaeskc0k9pgmzA==
"@xterm/addon-webgl@0.17.0-beta.16":
version "0.17.0-beta.16"
resolved "https://registry.yarnpkg.com/@xterm/addon-webgl/-/addon-webgl-0.17.0-beta.16.tgz#75466614bf8ea02a3fcb0900df48724c2344d081"
integrity sha512-+/eTLvSgYjvRX7oAKfpCDZdotrE8P/asCKXQtXjkbOtYRToI7kWEYfJzfgdFKFgDLKOpDdgY6Bgq384wEewlTA==
"@xterm/headless@5.4.0-beta.15":
version "5.4.0-beta.15"
resolved "https://registry.yarnpkg.com/@xterm/headless/-/headless-5.4.0-beta.15.tgz#04826e48635fdf2b5f89727534d577fc35699194"
integrity sha512-mtN4yEV2e/Nx9KBDLeQIdC5Dux5g3lEeX1nWafLEG1MRNBXts9Y5yp/x0oUZUN73zqr4LxlC+4h5JHrdXxaIZA==
"@xterm/headless@5.4.0-beta.16":
version "5.4.0-beta.16"
resolved "https://registry.yarnpkg.com/@xterm/headless/-/headless-5.4.0-beta.16.tgz#d12097c6c2082f14f5650169471eb120ed7600e7"
integrity sha512-5GTEzrZzpjfoQrFexULq20Mqc5jbTmhkTBYk0XaE4jeZVdCvsw1yiZNDVj7/66cKOmhQMCxV809p2jQZ/BJ0ww==
"@xterm/xterm@5.4.0-beta.15":
version "5.4.0-beta.15"
resolved "https://registry.yarnpkg.com/@xterm/xterm/-/xterm-5.4.0-beta.15.tgz#d76f3f92730f27dc960db415f36361a1ba751c54"
integrity sha512-jtOJLaEwjmgciM3VEmwvb1S5jLD14jRkg234qPq4H//JJ+D8fTwRblON5T2ccpcClpVGaW4Ro5g/XPuFuQ8dvw==
"@xterm/xterm@5.4.0-beta.16":
version "5.4.0-beta.16"
resolved "https://registry.yarnpkg.com/@xterm/xterm/-/xterm-5.4.0-beta.16.tgz#eb00506e56ba78c587fcacbada096c2af3693992"
integrity sha512-ARzWYQ8LfuZIn47TS8c+XKQhn/1ZVvbHdwlpolZIrT2pTarP+71U1b6cSpF7fV+OIV6tAPA8+q4g/1ZKHuOX8g==
agent-base@^7.0.1, agent-base@^7.0.2, agent-base@^7.1.0:
version "7.1.0"
@@ -159,8 +159,8 @@ export class ContextView extends Disposable {
const usedShadowDOM = this.useShadowDOM;
this.useShadowDOM = domPosition === ContextViewDOMPosition.FIXED_SHADOW;
if (container === this.container && usedShadowDOM !== this.useShadowDOM) {
return; // container is the same and now shadow DOM usage has changed
if (container === this.container && usedShadowDOM === this.useShadowDOM) {
return; // container is the same and no shadow DOM usage has changed
}
if (this.container) {
+18
View File
@@ -301,6 +301,24 @@ export class CodeApplication extends Disposable {
//#endregion
//#region Allow CORS for the PRSS CDN
// https://github.com/microsoft/vscode-remote-release/issues/9246
session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
if (details.url.startsWith('https://vscode.download.prss.microsoft.com/')) {
const responseHeaders = details.responseHeaders ?? Object.create(null);
if (responseHeaders['Access-Control-Allow-Origin'] === undefined) {
responseHeaders['Access-Control-Allow-Origin'] = ['*'];
return callback({ cancel: false, responseHeaders });
}
}
return callback({ cancel: false });
});
//#endregion
//#region Code Cache
type SessionWithCodeCachePathSupport = Session & {
@@ -3,6 +3,9 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { addDisposableListener, h, EventType } from 'vs/base/browser/dom';
import { renderIcon } from 'vs/base/browser/ui/iconLabel/iconLabels';
import { Codicon } from 'vs/base/common/codicons';
import { Disposable, toDisposable } from 'vs/base/common/lifecycle';
import { IObservable, autorunWithStore, derived } from 'vs/base/common/observable';
import { IGlyphMarginWidget, IGlyphMarginWidgetPosition } from 'vs/editor/browser/editorBrowser';
@@ -12,12 +15,9 @@ import { DiffEditorViewModel } from 'vs/editor/browser/widget/diffEditor/diffEdi
import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditor/diffEditorWidget';
import { LineRange, LineRangeSet } from 'vs/editor/common/core/lineRange';
import { Range } from 'vs/editor/common/core/range';
import { RangeMapping } from 'vs/editor/common/diff/rangeMapping';
import { GlyphMarginLane } from 'vs/editor/common/model';
import { localize } from 'vs/nls';
import { RangeMapping } from 'vs/editor/common/diff/rangeMapping';
import { renderIcon } from 'vs/base/browser/ui/iconLabel/iconLabels';
import { Codicon } from 'vs/base/common/codicons';
import { h } from 'vs/base/browser/dom';
export class RevertButtonsFeature extends Disposable {
constructor(
@@ -69,7 +69,7 @@ export class RevertButtonsFeature extends Disposable {
if (selectedDiffs_.length > 0) {
const selections = this._editors.modifiedSelections.read(reader);
const btn = new RevertButton(selections[selections.length - 1].positionLineNumber, this._widget, selectedDiffs_.flatMap(d => d.rangeMappings), true);
const btn = store.add(new RevertButton(selections[selections.length - 1].positionLineNumber, this._widget, selectedDiffs_.flatMap(d => d.rangeMappings), true));
this._editors.modified.addGlyphMarginWidget(btn);
glyphWidgetsModified.push(btn);
}
@@ -79,7 +79,7 @@ export class RevertButtonsFeature extends Disposable {
continue;
}
if (!m.lineRangeMapping.modified.isEmpty && m.lineRangeMapping.innerChanges) {
const btn = new RevertButton(m.lineRangeMapping.modified.startLineNumber, this._widget, m.lineRangeMapping.innerChanges, false);
const btn = store.add(new RevertButton(m.lineRangeMapping.modified.startLineNumber, this._widget, m.lineRangeMapping.innerChanges, false));
this._editors.modified.addGlyphMarginWidget(btn);
glyphWidgetsModified.push(btn);
}
@@ -94,7 +94,7 @@ export class RevertButtonsFeature extends Disposable {
}
}
export class RevertButton implements IGlyphMarginWidget {
export class RevertButton extends Disposable implements IGlyphMarginWidget {
public static counter = 0;
private readonly _id: string = `revertButton${RevertButton.counter++}`;
@@ -115,22 +115,27 @@ export class RevertButton implements IGlyphMarginWidget {
private readonly _diffs: RangeMapping[],
private readonly _selection: boolean,
) {
this._domNode.onmousedown = e => {
super();
this._register(addDisposableListener(this._domNode, EventType.MOUSE_DOWN, e => {
// don't prevent context menu from showing up
if (e.button !== 2) {
e.stopPropagation();
e.preventDefault();
}
};
this._domNode.onmouseup = e => {
}));
this._register(addDisposableListener(this._domNode, EventType.MOUSE_UP, e => {
e.stopPropagation();
e.preventDefault();
};
this._domNode.onclick = (e) => {
}));
this._register(addDisposableListener(this._domNode, EventType.CLICK, (e) => {
this._widget.revertRangeMappings(this._diffs);
e.stopPropagation();
e.preventDefault();
};
}));
}
/**
+5 -1
View File
@@ -5600,7 +5600,11 @@ export const EditorOptions = {
)),
mouseWheelZoom: register(new EditorBooleanOption(
EditorOption.mouseWheelZoom, 'mouseWheelZoom', false,
{ markdownDescription: nls.localize('mouseWheelZoom', "Zoom the font of the editor when using mouse wheel and holding `Ctrl`.") }
{
markdownDescription: platform.isMacintosh
? nls.localize('mouseWheelZoom.mac', "Zoom the font of the editor when using mouse wheel and holding `Cmd`.")
: nls.localize('mouseWheelZoom', "Zoom the font of the editor when using mouse wheel and holding `Ctrl`.")
}
)),
multiCursorMergeOverlapping: register(new EditorBooleanOption(
EditorOption.multiCursorMergeOverlapping, 'multiCursorMergeOverlapping', true,
@@ -10,10 +10,14 @@ import { PLAINTEXT_LANGUAGE_ID } from 'vs/editor/common/languages/modesRegistry'
import { ILanguageService } from 'vs/editor/common/languages/language';
import { IModelService } from 'vs/editor/common/services/model';
import { FileKind } from 'vs/platform/files/common/files';
import { ThemeIcon } from 'vs/base/common/themables';
const fileIconDirectoryRegex = /(?:\/|^)(?:([^\/]+)\/)?([^\/]+)$/;
export function getIconClasses(modelService: IModelService, languageService: ILanguageService, resource: uri | undefined, fileKind?: FileKind): string[] {
export function getIconClasses(modelService: IModelService, languageService: ILanguageService, resource: uri | undefined, fileKind?: FileKind, icon?: ThemeIcon): string[] {
if (icon) {
return [`codicon-${icon.id}`, 'product-icon'];
}
// we always set these base classes even if we do not have a path
const classes = fileKind === FileKind.ROOT_FOLDER ? ['rootfolder-icon'] : fileKind === FileKind.FOLDER ? ['folder-icon'] : ['file-icon'];
@@ -229,7 +229,7 @@ if (PasteAction) {
if (focusedEditor && focusedEditor.hasTextFocus()) {
const result = focusedEditor.getContainerDomNode().ownerDocument.execCommand('paste');
if (result) {
return CopyPasteController.get(focusedEditor).finishedPaste();
return CopyPasteController.get(focusedEditor)?.finishedPaste() ?? Promise.resolve();
} else if (platform.isWeb) {
// Use the clipboard service if document.execCommand('paste') was not successful
return (async () => {
@@ -93,8 +93,13 @@ export class LightBulbWidget extends Disposable implements IContentWidget {
&& this.state.actions.validActions.length === 1
) {
const action = this.state.actions.validActions[0].action;
if (action.command?.id) {
commandService.executeCommand(action.command.id, ...(action.command.arguments || []));
const id = action.command?.id;
if (id) {
let args = action.command?.arguments;
if (id === 'inlineChat.start' && args && args.length === 1) {
args = [{ ...args[0], autoSend: false }];
}
commandService.executeCommand(id, ...(args || []));
e.preventDefault();
return;
}
@@ -198,20 +203,22 @@ export class LightBulbWidget extends Disposable implements IContentWidget {
};
let effectiveLineNumber = lineNumber;
let effectiveColumnNumber = 1;
if (!lineHasSpace) {
if (lineNumber > 1 && !isFolded(lineNumber - 1)) {
effectiveLineNumber -= 1;
} else if (!isFolded(lineNumber + 1)) {
} else if ((lineNumber < model.getLineCount()) && !isFolded(lineNumber + 1)) {
effectiveLineNumber += 1;
} else if (column * fontInfo.spaceWidth < 22) {
// cannot show lightbulb above/below and showing
// it inline would overlay the cursor...
return this.hide();
}
effectiveColumnNumber = !!model.getLineContent(effectiveLineNumber).match(/^\S\s*$/) ? 2 : 1;
}
this.state = new LightBulbState.Showing(actions, trigger, atPosition, {
position: { lineNumber: effectiveLineNumber, column: !!model.getLineContent(effectiveLineNumber).match(/^\S\s*$/) ? 2 : 1 },
position: { lineNumber: effectiveLineNumber, column: effectiveColumnNumber },
preference: LightBulbWidget._posPref
});
this._editor.layoutContentWidget(this);
@@ -239,32 +246,14 @@ export class LightBulbWidget extends Disposable implements IContentWidget {
if (this.state.type !== LightBulbState.Type.Showing) {
return;
}
const updateAutoFixLightbulbTitle = () => {
if (this._preferredKbLabel) {
this.title = nls.localize('preferredcodeActionWithKb', "Show Code Actions. Preferred Quick Fix Available ({0})", this._preferredKbLabel);
}
};
const updateLightbulbTitle = () => {
if (this._quickFixKbLabel) {
this.title = nls.localize('codeActionWithKb', "Show Code Actions ({0})", this._quickFixKbLabel);
} else {
this.title = nls.localize('codeAction', "Show Code Actions");
}
};
let icon: ThemeIcon;
let autoRun = false;
const option = this._editor.getOption(EditorOption.lightbulb).experimental.showAiIcon;
if (option === ShowAiIconMode.On || option === ShowAiIconMode.OnCode) {
if (option === ShowAiIconMode.On && this.state.actions.allAIFixes) {
icon = Codicon.sparkleFilled;
if (this.state.actions.validActions.length === 1) {
if (this.state.actions.validActions[0].action.command?.id === `inlineChat.start`) {
const keybinding = this._keybindingService.lookupKeybinding('inlineChat.start')?.getLabel() ?? undefined;
this.title = keybinding ? nls.localize('codeActionStartInlineChatWithKb', 'Start Inline Chat ({0})', keybinding) : nls.localize('codeActionStartInlineChat', 'Start Inline Chat',);
} else {
this.title = nls.localize('codeActionTriggerAiAction', "Trigger AI Action");
}
} else {
updateLightbulbTitle();
autoRun = true;
}
} else if (this.state.actions.hasAutoFix) {
if (this.state.actions.hasAIFix) {
@@ -272,27 +261,38 @@ export class LightBulbWidget extends Disposable implements IContentWidget {
} else {
icon = Codicon.lightbulbAutofix;
}
updateAutoFixLightbulbTitle();
} else if (this.state.actions.hasAIFix) {
icon = Codicon.lightbulbSparkle;
updateLightbulbTitle();
} else {
icon = Codicon.lightBulb;
updateLightbulbTitle();
}
} else {
if (this.state.actions.hasAutoFix) {
icon = Codicon.lightbulbAutofix;
updateAutoFixLightbulbTitle();
} else {
icon = Codicon.lightBulb;
updateLightbulbTitle();
}
}
this._updateLightbulbTitle(this.state.actions.hasAutoFix, autoRun);
this._iconClasses = ThemeIcon.asClassNameArray(icon);
this._domNode.classList.add(...this._iconClasses);
}
private _updateLightbulbTitle(autoFix: boolean, autoRun: boolean): void {
if (this.state.type !== LightBulbState.Type.Showing) {
return;
}
if (autoRun) {
this.title = nls.localize('codeActionAutoRun', "Run: {0}", this.state.actions.validActions[0].action.title);
} else if (autoFix && this._preferredKbLabel) {
this.title = nls.localize('preferredcodeActionWithKb', "Show Code Actions. Preferred Quick Fix Available ({0})", this._preferredKbLabel);
} else if (!autoFix && this._quickFixKbLabel) {
this.title = nls.localize('codeActionWithKb', "Show Code Actions ({0})", this._quickFixKbLabel);
} else if (!autoFix) {
this.title = nls.localize('codeAction', "Show Code Actions");
}
}
private set title(value: string) {
this._domNode.title = value;
}
@@ -7,7 +7,7 @@ import { AsyncIterableObject } from 'vs/base/common/async';
import { CancellationToken } from 'vs/base/common/cancellation';
import { Color, RGBA } from 'vs/base/common/color';
import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { IActiveCodeEditor, ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { EditorOption } from 'vs/editor/common/config/editorOptions';
import { Range } from 'vs/editor/common/core/range';
import { IModelDecoration, ITextModel, TrackedRangeStickiness } from 'vs/editor/common/model';
@@ -207,7 +207,7 @@ function renderHoverParts(participant: ColorHoverParticipant | StandaloneColorPi
disposables.add(model.onColorFlushed(async (color: Color) => {
await _updateColorPresentations(editorModel, model, color, range, colorHover);
editorUpdatedByColorPicker = true;
range = _updateEditorModel(editor, range, model, context);
range = _updateEditorModel(editor, range, model);
}));
}
disposables.add(model.onDidChangeColor((color: Color) => {
@@ -224,30 +224,19 @@ function renderHoverParts(participant: ColorHoverParticipant | StandaloneColorPi
return disposables;
}
function _updateEditorModel(editor: ICodeEditor, range: Range, model: ColorPickerModel, context?: IEditorHoverRenderContext) {
let newRange: Range;
function _updateEditorModel(editor: IActiveCodeEditor, range: Range, model: ColorPickerModel): Range {
const textEdits: ISingleEditOperation[] = [];
if (model.presentation.textEdit) {
textEdits.push(model.presentation.textEdit);
newRange = new Range(
model.presentation.textEdit.range.startLineNumber,
model.presentation.textEdit.range.startColumn,
model.presentation.textEdit.range.endLineNumber,
model.presentation.textEdit.range.endColumn
);
const trackedRange = editor.getModel()!._setTrackedRange(null, newRange, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter);
newRange = editor.getModel()!._getTrackedRange(trackedRange) || newRange;
} else {
textEdits.push({ range, text: model.presentation.label, forceMoveMarkers: false });
newRange = range.setEndPosition(range.endLineNumber, range.startColumn + model.presentation.label.length);
}
const edit = model.presentation.textEdit ?? { range, text: model.presentation.label, forceMoveMarkers: false };
textEdits.push(edit);
if (model.presentation.additionalTextEdits) {
textEdits.push(...model.presentation.additionalTextEdits);
}
const replaceRange = Range.lift(edit.range);
const trackedRange = editor.getModel()._setTrackedRange(null, replaceRange, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter);
editor.executeEdits('colorpicker', textEdits);
editor.pushUndoStop();
return newRange;
return editor.getModel()._getTrackedRange(trackedRange) ?? replaceRange;
}
async function _updateColorPresentations(editorModel: ITextModel, colorPickerModel: ColorPickerModel, color: Color, range: Range, colorHover: ColorHover | StandaloneColorPickerHover) {
@@ -51,8 +51,8 @@ export class CopyPasteController extends Disposable implements IEditorContributi
public static readonly ID = 'editor.contrib.copyPasteActionController';
public static get(editor: ICodeEditor): CopyPasteController {
return editor.getContribution<CopyPasteController>(CopyPasteController.ID)!;
public static get(editor: ICodeEditor): CopyPasteController | null {
return editor.getContribution<CopyPasteController>(CopyPasteController.ID);
}
private readonly _editor: ICodeEditor;
@@ -31,23 +31,13 @@ const $ = dom.$;
export class ContentHoverController extends Disposable {
private readonly _participants: IEditorHoverParticipant[];
private readonly _widget: ContentHoverWidget;
getWidgetContent(): string | undefined {
const node = this._widget.getDomNode();
if (!node.textContent) {
return undefined;
}
return node.textContent;
}
private _currentResult: HoverResult | null = null;
private readonly _computer: ContentHoverComputer;
private readonly _widget: ContentHoverWidget;
private readonly _participants: IEditorHoverParticipant[];
private readonly _hoverOperation: HoverOperation<IHoverPart>;
private _currentResult: HoverResult | null = null;
constructor(
private readonly _editor: ICodeEditor,
@IInstantiationService private readonly _instantiationService: IInstantiationService,
@@ -87,58 +77,17 @@ export class ContentHoverController extends Disposable {
}));
}
get widget() {
return this._widget;
}
/**
* Returns true if the hover shows now or will show.
*/
public showsOrWillShow(mouseEvent: IEditorMouseEvent): boolean {
if (this._widget.isResizing) {
return true;
}
const anchorCandidates: HoverAnchor[] = [];
private _startShowingOrUpdateHover(
anchor: HoverAnchor | null,
mode: HoverStartMode,
source: HoverStartSource,
focus: boolean,
mouseEvent: IEditorMouseEvent | null
): boolean {
for (const participant of this._participants) {
if (participant.suggestHoverAnchor) {
const anchor = participant.suggestHoverAnchor(mouseEvent);
if (anchor) {
anchorCandidates.push(anchor);
}
}
}
const target = mouseEvent.target;
if (target.type === MouseTargetType.CONTENT_TEXT) {
anchorCandidates.push(new HoverRangeAnchor(0, target.range, mouseEvent.event.posx, mouseEvent.event.posy));
}
if (target.type === MouseTargetType.CONTENT_EMPTY) {
const epsilon = this._editor.getOption(EditorOption.fontInfo).typicalHalfwidthCharacterWidth / 2;
if (!target.detail.isAfterLines && typeof target.detail.horizontalDistanceToText === 'number' && target.detail.horizontalDistanceToText < epsilon) {
// Let hover kick in even when the mouse is technically in the empty area after a line, given the distance is small enough
anchorCandidates.push(new HoverRangeAnchor(0, target.range, mouseEvent.event.posx, mouseEvent.event.posy));
}
}
if (anchorCandidates.length === 0) {
return this._startShowingOrUpdateHover(null, HoverStartMode.Delayed, HoverStartSource.Mouse, false, mouseEvent);
}
anchorCandidates.sort((a, b) => b.priority - a.priority);
return this._startShowingOrUpdateHover(anchorCandidates[0], HoverStartMode.Delayed, HoverStartSource.Mouse, false, mouseEvent);
}
public startShowingAtRange(range: Range, mode: HoverStartMode, source: HoverStartSource, focus: boolean): void {
this._startShowingOrUpdateHover(new HoverRangeAnchor(0, range, undefined, undefined), mode, source, focus, null);
}
/**
* Returns true if the hover shows now or will show.
*/
private _startShowingOrUpdateHover(anchor: HoverAnchor | null, mode: HoverStartMode, source: HoverStartSource, focus: boolean, mouseEvent: IEditorMouseEvent | null): boolean {
if (!this._widget.position || !this._currentResult) {
// The hover is not visible
if (anchor) {
@@ -149,8 +98,13 @@ export class ContentHoverController extends Disposable {
}
// The hover is currently visible
const hoverIsSticky = this._editor.getOption(EditorOption.hover).sticky;
const isGettingCloser = (hoverIsSticky && mouseEvent && this._widget.isMouseGettingCloser(mouseEvent.event.posx, mouseEvent.event.posy));
const isHoverSticky = this._editor.getOption(EditorOption.hover).sticky;
const isGettingCloser = (
isHoverSticky
&& mouseEvent
&& this._widget.isMouseGettingCloser(mouseEvent.event.posx, mouseEvent.event.posy)
);
if (isGettingCloser) {
// The mouse is getting closer to the hover, so we will keep the hover untouched
// But we will kick off a hover update at the new anchor, insisting on keeping the hover visible.
@@ -185,11 +139,11 @@ export class ContentHoverController extends Disposable {
}
private _startHoverOperationIfNecessary(anchor: HoverAnchor, mode: HoverStartMode, source: HoverStartSource, focus: boolean, insistOnKeepingHoverVisible: boolean): void {
if (this._computer.anchor && this._computer.anchor.equals(anchor)) {
// We have to start a hover operation at the exact same anchor as before, so no work is needed
return;
}
this._hoverOperation.cancel();
this._computer.anchor = anchor;
this._computer.shouldFocus = focus;
@@ -199,6 +153,7 @@ export class ContentHoverController extends Disposable {
}
private _setCurrentResult(hoverResult: HoverResult | null): void {
if (this._currentResult === hoverResult) {
// avoid updating the DOM to avoid resetting the user selection
return;
@@ -214,36 +169,6 @@ export class ContentHoverController extends Disposable {
}
}
public hide(): void {
this._computer.anchor = null;
this._hoverOperation.cancel();
this._setCurrentResult(null);
}
public get isColorPickerVisible(): boolean {
return this._widget.isColorPickerVisible;
}
public get isVisibleFromKeyboard(): boolean {
return this._widget.isVisibleFromKeyboard;
}
public get isVisible(): boolean {
return this._widget.isVisible;
}
public get isFocused(): boolean {
return this._widget.isFocused;
}
public get isResizing(): boolean {
return this._widget.isResizing;
}
public containsNode(node: Node | null | undefined): boolean {
return (node ? this._widget.getDomNode().contains(node) : false);
}
private _addLoadingMessage(result: IHoverPart[]): IHoverPart[] {
if (this._computer.anchor) {
for (const participant of this._participants) {
@@ -319,6 +244,8 @@ export class ContentHoverController extends Disposable {
}
this._widget.showAt(fragment, new ContentHoverVisibleData(
anchor.initialMousePosX,
anchor.initialMousePosY,
colorPicker,
showAtPosition,
showAtSecondaryPosition,
@@ -326,8 +253,6 @@ export class ContentHoverController extends Disposable {
this._computer.shouldFocus,
this._computer.source,
isBeforeContent,
anchor.initialMousePosX,
anchor.initialMousePosY,
disposables
));
} else {
@@ -341,6 +266,7 @@ export class ContentHoverController extends Disposable {
});
public static computeHoverRanges(editor: ICodeEditor, anchorRange: Range, messages: IHoverPart[]) {
let startColumnBoundary = 1;
if (editor.hasModel()) {
// Ensure the range is on the current view line
@@ -350,11 +276,12 @@ export class ContentHoverController extends Disposable {
const anchorViewRangeStart = new Position(anchorViewRange.startLineNumber, viewModel.getLineMinColumn(anchorViewRange.startLineNumber));
startColumnBoundary = coordinatesConverter.convertViewPositionToModelPosition(anchorViewRangeStart).column;
}
// The anchor range is always on a single line
const anchorLineNumber = anchorRange.startLineNumber;
let renderStartColumn = anchorRange.startColumn;
let highlightRange: Range = messages[0].range;
let forceShowAtRange: Range | null = null;
let highlightRange = messages[0].range;
let forceShowAtRange = null;
for (const msg of messages) {
highlightRange = Range.plusRange(highlightRange, msg.range);
@@ -367,13 +294,77 @@ export class ContentHoverController extends Disposable {
}
}
const showAtPosition = forceShowAtRange ? forceShowAtRange.getStartPosition() : new Position(anchorLineNumber, anchorRange.startColumn);
const showAtSecondaryPosition = forceShowAtRange ? forceShowAtRange.getStartPosition() : new Position(anchorLineNumber, renderStartColumn);
return {
showAtPosition: forceShowAtRange ? forceShowAtRange.getStartPosition() : new Position(anchorLineNumber, anchorRange.startColumn),
showAtSecondaryPosition: forceShowAtRange ? forceShowAtRange.getStartPosition() : new Position(anchorLineNumber, renderStartColumn),
showAtPosition,
showAtSecondaryPosition,
highlightRange
};
}
/**
* Returns true if the hover shows now or will show.
*/
public showsOrWillShow(mouseEvent: IEditorMouseEvent): boolean {
if (this._widget.isResizing) {
return true;
}
const anchorCandidates: HoverAnchor[] = [];
for (const participant of this._participants) {
if (participant.suggestHoverAnchor) {
const anchor = participant.suggestHoverAnchor(mouseEvent);
if (anchor) {
anchorCandidates.push(anchor);
}
}
}
const target = mouseEvent.target;
if (target.type === MouseTargetType.CONTENT_TEXT) {
anchorCandidates.push(new HoverRangeAnchor(0, target.range, mouseEvent.event.posx, mouseEvent.event.posy));
}
if (target.type === MouseTargetType.CONTENT_EMPTY) {
const epsilon = this._editor.getOption(EditorOption.fontInfo).typicalHalfwidthCharacterWidth / 2;
if (
!target.detail.isAfterLines
&& typeof target.detail.horizontalDistanceToText === 'number'
&& target.detail.horizontalDistanceToText < epsilon
) {
// Let hover kick in even when the mouse is technically in the empty area after a line, given the distance is small enough
anchorCandidates.push(new HoverRangeAnchor(0, target.range, mouseEvent.event.posx, mouseEvent.event.posy));
}
}
if (anchorCandidates.length === 0) {
return this._startShowingOrUpdateHover(null, HoverStartMode.Delayed, HoverStartSource.Mouse, false, mouseEvent);
}
anchorCandidates.sort((a, b) => b.priority - a.priority);
return this._startShowingOrUpdateHover(anchorCandidates[0], HoverStartMode.Delayed, HoverStartSource.Mouse, false, mouseEvent);
}
public startShowingAtRange(range: Range, mode: HoverStartMode, source: HoverStartSource, focus: boolean): void {
this._startShowingOrUpdateHover(new HoverRangeAnchor(0, range, undefined, undefined), mode, source, focus, null);
}
public getWidgetContent(): string | undefined {
const node = this._widget.getDomNode();
if (!node.textContent) {
return undefined;
}
return node.textContent;
}
public containsNode(node: Node | null | undefined): boolean {
return (node ? this._widget.getDomNode().contains(node) : false);
}
public focus(): void {
this._widget.focus();
}
@@ -409,6 +400,36 @@ export class ContentHoverController extends Disposable {
public goToBottom(): void {
this._widget.goToBottom();
}
public hide(): void {
this._computer.anchor = null;
this._hoverOperation.cancel();
this._setCurrentResult(null);
}
public get isColorPickerVisible(): boolean {
return this._widget.isColorPickerVisible;
}
public get isVisibleFromKeyboard(): boolean {
return this._widget.isVisibleFromKeyboard;
}
public get isVisible(): boolean {
return this._widget.isVisible;
}
public get isFocused(): boolean {
return this._widget.isFocused;
}
public get isResizing(): boolean {
return this._widget.isResizing;
}
public get widget() {
return this._widget;
}
}
class HoverResult {
@@ -449,6 +470,8 @@ class ContentHoverVisibleData {
public closestMouseDistance: number | undefined = undefined;
constructor(
public initialMousePosX: number | undefined,
public initialMousePosY: number | undefined,
public readonly colorPicker: IEditorHoverColorPickerWidget | null,
public readonly showAtPosition: Position,
public readonly showAtSecondaryPosition: Position,
@@ -456,8 +479,6 @@ class ContentHoverVisibleData {
public readonly stoleFocus: boolean,
public readonly source: HoverStartSource,
public readonly isBeforeContent: boolean,
public initialMousePosX: number | undefined,
public initialMousePosY: number | undefined,
public readonly disposables: DisposableStore
) { }
}
@@ -507,6 +528,7 @@ export class ContentHoverWidget extends ResizableContentWidget {
const minimumWidth = 150;
const minimumSize = new dom.Dimension(minimumWidth, minimumHeight);
super(editor, minimumSize);
this._minimumSize = minimumSize;
this._hoverVisibleKey = EditorContextKeys.hoverVisible.bindTo(contextKeyService);
this._hoverFocusedKey = EditorContextKeys.hoverFocused.bindTo(contextKeyService);
@@ -630,7 +652,9 @@ export class ContentHoverWidget extends ResizableContentWidget {
if (!position) {
return;
}
return this._positionPreference === ContentWidgetPositionPreference.ABOVE ? this._availableVerticalSpaceAbove(position) : this._availableVerticalSpaceBelow(position);
return this._positionPreference === ContentWidgetPositionPreference.ABOVE ?
this._availableVerticalSpaceAbove(position)
: this._availableVerticalSpaceBelow(position);
}
private _findMaximumRenderingHeight(): number | undefined {
@@ -643,6 +667,7 @@ export class ContentHoverWidget extends ResizableContentWidget {
Array.from(this._hover.contentsDomNode.children).forEach((hoverPart) => {
maximumHeight += hoverPart.clientHeight;
});
if (this._hasHorizontalScrollbar()) {
maximumHeight += SCROLLBAR_WIDTH;
}
@@ -670,7 +695,6 @@ export class ContentHoverWidget extends ResizableContentWidget {
}
const overflowing = this._isHoverTextOverflowing();
const initialWidth = (
typeof this._contentWidth === 'undefined'
? 0
@@ -687,10 +711,14 @@ export class ContentHoverWidget extends ResizableContentWidget {
}
public isMouseGettingCloser(posx: number, posy: number): boolean {
if (!this._visibleData) {
return false;
}
if (typeof this._visibleData.initialMousePosX === 'undefined' || typeof this._visibleData.initialMousePosY === 'undefined') {
if (
typeof this._visibleData.initialMousePosX === 'undefined'
|| typeof this._visibleData.initialMousePosY === 'undefined'
) {
this._visibleData.initialMousePosX = posx;
this._visibleData.initialMousePosY = posy;
return false;
@@ -698,13 +726,29 @@ export class ContentHoverWidget extends ResizableContentWidget {
const widgetRect = dom.getDomNodePagePosition(this.getDomNode());
if (typeof this._visibleData.closestMouseDistance === 'undefined') {
this._visibleData.closestMouseDistance = computeDistanceFromPointToRectangle(this._visibleData.initialMousePosX, this._visibleData.initialMousePosY, widgetRect.left, widgetRect.top, widgetRect.width, widgetRect.height);
this._visibleData.closestMouseDistance = computeDistanceFromPointToRectangle(
this._visibleData.initialMousePosX,
this._visibleData.initialMousePosY,
widgetRect.left,
widgetRect.top,
widgetRect.width,
widgetRect.height
);
}
const distance = computeDistanceFromPointToRectangle(posx, posy, widgetRect.left, widgetRect.top, widgetRect.width, widgetRect.height);
const distance = computeDistanceFromPointToRectangle(
posx,
posy,
widgetRect.left,
widgetRect.top,
widgetRect.width,
widgetRect.height
);
if (distance > this._visibleData.closestMouseDistance + 4 /* tolerance of 4 pixels */) {
// The mouse is getting farther away
return false;
}
this._visibleData.closestMouseDistance = Math.min(this._visibleData.closestMouseDistance, distance);
return true;
}
@@ -784,7 +828,11 @@ export class ContentHoverWidget extends ResizableContentWidget {
hoverData.colorPicker?.layout();
// The aria label overrides the label, so if we add to it, add the contents of the hover
const hoverFocused = this._hover.containerDomNode.ownerDocument.activeElement === this._hover.containerDomNode;
const accessibleViewHint = hoverFocused && getHoverAccessibleViewHint(this._configurationService.getValue('accessibility.verbosity.hover') === true && this._accessibilityService.isScreenReaderOptimized(), this._keybindingService.lookupKeybinding('editor.action.accessibleView')?.getAriaLabel() ?? '');
const accessibleViewHint = hoverFocused && getHoverAccessibleViewHint(
this._configurationService.getValue('accessibility.verbosity.hover') === true && this._accessibilityService.isScreenReaderOptimized(),
this._keybindingService.lookupKeybinding('editor.action.accessibleView')?.getAriaLabel() ?? ''
);
if (accessibleViewHint) {
this._hover.contentsDomNode.ariaLabel = this._hover.contentsDomNode.textContent + ', ' + accessibleViewHint;
}
@@ -931,7 +979,13 @@ export class EditorHoverStatusBar extends Disposable implements IEditorHoverStat
this.actionsElement = dom.append(this.hoverElement, $('div.actions'));
}
public addAction(actionOptions: { label: string; iconClass?: string; run: (target: HTMLElement) => void; commandId: string }): IEditorHoverAction {
public addAction(
actionOptions: {
label: string;
iconClass?: string; run: (target: HTMLElement) => void;
commandId: string;
}): IEditorHoverAction {
const keybinding = this._keybindingService.lookupKeybinding(actionOptions.commandId);
const keybindingLabel = keybinding ? keybinding.getLabel() : null;
this._hasContent = true;
@@ -983,6 +1037,7 @@ class ContentHoverComputer implements IHoverComputer<IHoverPart> {
}
const maxColumn = model.getLineMaxColumn(lineNumber);
return editor.getLineDecorations(lineNumber).filter((d) => {
if (d.options.isWholeLine) {
return true;
@@ -990,6 +1045,7 @@ class ContentHoverComputer implements IHoverComputer<IHoverPart> {
const startColumn = (d.range.startLineNumber === lineNumber) ? d.range.startColumn : 1;
const endColumn = (d.range.endLineNumber === lineNumber) ? d.range.endColumn : maxColumn;
if (d.options.showIfCollapsed) {
// Relax check around `showIfCollapsed` decorations to also include +/- 1 character
if (startColumn > anchor.range.startColumn + 1 || anchor.range.endColumn - 1 > endColumn) {
@@ -1013,6 +1069,7 @@ class ContentHoverComputer implements IHoverComputer<IHoverPart> {
}
const lineDecorations = ContentHoverComputer._getLineDecorations(this._editor, anchor);
return AsyncIterableObject.merge(
this._participants.map((participant) => {
if (!participant.computeAsync) {
+4 -6
View File
@@ -39,9 +39,9 @@ const _sticky = false
;
interface IHoverSettings {
enabled: boolean;
sticky: boolean;
hidingDelay: number;
readonly enabled: boolean;
readonly sticky: boolean;
readonly hidingDelay: number;
}
interface IHoverState {
@@ -279,9 +279,7 @@ export class HoverController extends Disposable implements IEditorContribution {
(decoratorActivatedOn === 'click' && !activatedByDecoratorClick) ||
(decoratorActivatedOn === 'hover' && !enabled && !_sticky) ||
(decoratorActivatedOn === 'clickAndHover' && !enabled && !activatedByDecoratorClick))
)
||
(
) || (
!mouseOnDecorator && !enabled && !activatedByDecoratorClick
)
) {
@@ -45,6 +45,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { basename, extname } from 'vs/base/common/resources';
import { hash } from 'vs/base/common/hash';
import { WindowIdleValue, getWindow } from 'vs/base/browser/dom';
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
// sticky suggest widget which doesn't disappear on focus out and such
const _sticky = false
@@ -53,7 +54,12 @@ const _sticky = false
class LineSuffix {
private readonly _marker: string[] | undefined;
private readonly _decorationOptions = ModelDecorationOptions.register({
description: 'suggest-line-suffix',
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges
});
private _marker: string | undefined;
constructor(private readonly _model: ITextModel, private readonly _position: IPosition) {
// spy on what's happening right of the cursor. two cases:
@@ -63,16 +69,21 @@ class LineSuffix {
if (maxColumn !== _position.column) {
const offset = _model.getOffsetAt(_position);
const end = _model.getPositionAt(offset + 1);
this._marker = _model.deltaDecorations([], [{
range: Range.fromPositions(_position, end),
options: { description: 'suggest-line-suffix', stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges }
}]);
_model.changeDecorations(accessor => {
if (this._marker) {
accessor.removeDecoration(this._marker);
}
this._marker = accessor.addDecoration(Range.fromPositions(_position, end), this._decorationOptions);
});
}
}
dispose(): void {
if (this._marker && !this._model.isDisposed()) {
this._model.deltaDecorations(this._marker, []);
this._model.changeDecorations(accessor => {
accessor.removeDecoration(this._marker!);
this._marker = undefined;
});
}
}
@@ -84,7 +95,7 @@ class LineSuffix {
// read the marker (in case suggest was triggered at line end) or compare
// the cursor to the line end.
if (this._marker) {
const range = this._model.getDecorationRange(this._marker[0]);
const range = this._model.getDecorationRange(this._marker);
const end = this._model.getOffsetAt(range!.getStartPosition());
return end - this._model.getOffsetAt(position);
} else {
@@ -282,6 +282,9 @@ export class SuggestWidget implements IDisposable {
applyStatusBarStyle();
applyIconStyle();
}
if (this._completionModel && (e.hasChanged(EditorOption.fontInfo) || e.hasChanged(EditorOption.suggestFontSize) || e.hasChanged(EditorOption.suggestLineHeight))) {
this._list.splice(0, this._list.length, this._completionModel.items);
}
}));
this._ctxSuggestWidgetVisible = SuggestContext.Visible.bindTo(_contextKeyService);
@@ -85,6 +85,8 @@ export interface ISuggestionTemplateData {
readonly detailsLabel: HTMLElement;
readonly readMore: HTMLElement;
readonly disposables: DisposableStore;
readonly configureFont: () => void;
}
export class ItemRenderer implements IListRenderer<CompletionItem, ISuggestionTemplateData> {
@@ -156,18 +158,14 @@ export class ItemRenderer implements IListRenderer<CompletionItem, ISuggestionTe
readMore.style.width = lineHeightPx;
};
configureFont();
disposables.add(this._editor.onDidChangeConfiguration(e => {
if (e.hasChanged(EditorOption.fontInfo) || e.hasChanged(EditorOption.suggestFontSize) || e.hasChanged(EditorOption.suggestLineHeight)) {
configureFont();
}
}));
return { root, left, right, icon, colorspan, iconLabel, iconContainer, parametersLabel, qualifierLabel, detailsLabel, readMore, disposables };
return { root, left, right, icon, colorspan, iconLabel, iconContainer, parametersLabel, qualifierLabel, detailsLabel, readMore, disposables, configureFont };
}
renderElement(element: CompletionItem, index: number, data: ISuggestionTemplateData): void {
data.configureFont();
const { completion } = element;
data.root.id = getAriaId(index);
data.colorspan.style.backgroundColor = '';
@@ -405,6 +405,8 @@ export class UnicodeHighlighterHover implements IHoverPart {
}
}
const configureUnicodeHighlightOptionsStr = nls.localize('unicodeHighlight.configureUnicodeHighlightOptions', 'Configure Unicode Highlight Options');
export class UnicodeHighlighterHoverParticipant implements IEditorHoverParticipant<MarkdownHover> {
public readonly hoverOrdinal: number = 5;
@@ -498,7 +500,7 @@ export class UnicodeHighlighterHoverParticipant implements IEditorHoverParticipa
const markdown = new MarkdownString('', true)
.appendMarkdown(reason)
.appendText(' ')
.appendLink(uri, adjustSettings);
.appendLink(uri, adjustSettings, configureUnicodeHighlightOptionsStr);
result.push(new MarkdownHover(this, d.range, [markdown], false, index++));
}
return result;
@@ -767,7 +769,7 @@ export class ShowExcludeOptions extends EditorAction {
const result = await quickPickService.pick(
options,
{ title: nls.localize('unicodeHighlight.configureUnicodeHighlightOptions', 'Configure Unicode Highlight Options') }
{ title: configureUnicodeHighlightOptionsStr }
);
if (result) {
@@ -110,6 +110,17 @@
text-overflow: ellipsis;
}
.action-widget .monaco-list-row.action .monaco-keybinding > .monaco-keybinding-key {
background-color: var(--vscode-keybindingLabel-background);
color: var(--vscode-keybindingLabel-foreground);
border-style: solid;
border-width: 1px;
border-radius: 3px;
border-color: var(--vscode-keybindingLabel-border);
border-bottom-color: var(--vscode-keybindingLabel-bottomBorder);
box-shadow: inset 0 -1px 0 var(--vscode-widget-shadow);
}
/* Action bar */
.action-widget .action-widget-action-bar {
@@ -381,11 +381,11 @@ export class DropdownWithDefaultActionViewItem extends BaseActionViewItem {
};
this._dropdown = new DropdownMenuActionViewItem(submenuAction, submenuAction.actions, this._contextMenuService, dropdownOptions);
this._dropdown.actionRunner.onDidRun((e: IRunEvent) => {
this._register(this._dropdown.actionRunner.onDidRun((e: IRunEvent) => {
if (e.action instanceof MenuItemAction) {
this.update(e.action);
}
});
}));
}
private update(lastAction: MenuItemAction): void {
@@ -120,6 +120,7 @@ export const enum TerminalSettingId {
AccessibleViewFocusOnCommandExecution = 'terminal.integrated.accessibleViewFocusOnCommandExecution',
StickyScrollEnabled = 'terminal.integrated.stickyScroll.enabled',
StickyScrollMaxLineCount = 'terminal.integrated.stickyScroll.maxLineCount',
MouseWheelZoom = 'terminal.integrated.mouseWheelZoom',
// Debug settings that are hidden from user
@@ -407,7 +407,7 @@ export const editorInlayHintParameterBackground = registerColor('editorInlayHint
*/
export const editorLightBulbForeground = registerColor('editorLightBulb.foreground', { dark: '#FFCC00', light: '#DDB100', hcDark: '#FFCC00', hcLight: '#007ACC' }, nls.localize('editorLightBulbForeground', "The color used for the lightbulb actions icon."));
export const editorLightBulbAutoFixForeground = registerColor('editorLightBulbAutoFix.foreground', { dark: '#75BEFF', light: '#007ACC', hcDark: '#75BEFF', hcLight: '#007ACC' }, nls.localize('editorLightBulbAutoFixForeground', "The color used for the lightbulb auto fix actions icon."));
export const editorLightBulbAiForeground = registerColor('editorLightBulbAi.foreground', { dark: darken(iconForeground, 0.4), light: lighten(iconForeground, 1), hcDark: iconForeground, hcLight: iconForeground }, nls.localize('editorLightBulbAiForeground', "The color used for the lightbulb AI icon."));
export const editorLightBulbAiForeground = registerColor('editorLightBulbAi.foreground', { dark: editorLightBulbForeground, light: editorLightBulbForeground, hcDark: editorLightBulbForeground, hcLight: editorLightBulbForeground }, nls.localize('editorLightBulbAiForeground', "The color used for the lightbulb AI icon."));
/**
* Diff Editor Colors
@@ -136,7 +136,7 @@ export class MainThreadTesting extends Disposable implements MainThreadTestingSh
const fn = available ? ((token: CancellationToken) => TestCoverage.load(taskId, {
provideFileCoverage: async token => await this.proxy.$provideFileCoverage(runId, taskId, token)
.then(c => c.map(IFileCoverage.deserialize)),
.then(c => c.map(u => IFileCoverage.deserialize(this.uriIdentityService, u))),
resolveFileCoverage: (i, token) => this.proxy.$resolveFileCoverage(runId, taskId, i, token)
.then(d => d.map(CoverageDetails.deserialize)),
}, token)) : undefined;
+84 -65
View File
@@ -232,6 +232,25 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
return function (extension: IExtensionDescription, extensionInfo: IExtensionRegistries, configProvider: ExtHostConfigProvider): typeof vscode {
// Wraps an event with error handling and telemetry so that we know what extension fails
// handling events. This will prevent us from reporting this as "our" error-telemetry and
// allows for better blaming
function _asExtensionEvent<T>(actual: vscode.Event<T>): vscode.Event<T> {
return (listener, thisArgs, disposables) => {
const handle = actual(e => {
try {
listener.call(thisArgs, e);
} catch (err) {
errors.onUnexpectedExternalError(new Error(`[ExtensionListenerError] Extension '${extension.identifier.value}' FAILED to handle event`, { cause: err }));
extHostTelemetry.onExtensionError(extension.identifier, err);
}
});
disposables?.push(handle);
return handle;
};
}
// Check document selectors for being overly generic. Technically this isn't a problem but
// in practice many extensions say they support `fooLang` but need fs-access to do so. Those
// extension should specify then the `file`-scheme, e.g. `{ scheme: 'fooLang', language: 'fooLang' }`
@@ -276,8 +295,8 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
checkProposedApiEnabled(extension, 'authSession');
return !!(await extHostAuthentication.getSession(extension, providerId, scopes, { silent: true } as any));
},
get onDidChangeSessions(): Event<vscode.AuthenticationSessionsChangeEvent> {
return extHostAuthentication.onDidChangeSessions;
get onDidChangeSessions(): vscode.Event<vscode.AuthenticationSessionsChangeEvent> {
return _asExtensionEvent(extHostAuthentication.onDidChangeSessions);
},
registerAuthenticationProvider(id: string, label: string, provider: vscode.AuthenticationProvider, options?: vscode.AuthenticationProviderOptions): vscode.Disposable {
return extHostAuthentication.registerAuthenticationProvider(id, label, provider, options);
@@ -344,21 +363,21 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
return extHostTerminalService.getDefaultShell(false);
},
get onDidChangeShell() {
return extHostTerminalService.onDidChangeShell;
return _asExtensionEvent(extHostTerminalService.onDidChangeShell);
},
get isTelemetryEnabled() {
return extHostTelemetry.getTelemetryConfiguration();
},
get onDidChangeTelemetryEnabled(): Event<boolean> {
return extHostTelemetry.onDidChangeTelemetryEnabled;
get onDidChangeTelemetryEnabled(): vscode.Event<boolean> {
return _asExtensionEvent(extHostTelemetry.onDidChangeTelemetryEnabled);
},
get telemetryConfiguration(): vscode.TelemetryConfiguration {
checkProposedApiEnabled(extension, 'telemetry');
return extHostTelemetry.getTelemetryDetails();
},
get onDidChangeTelemetryConfiguration(): Event<vscode.TelemetryConfiguration> {
get onDidChangeTelemetryConfiguration(): vscode.Event<vscode.TelemetryConfiguration> {
checkProposedApiEnabled(extension, 'telemetry');
return extHostTelemetry.onDidChangeTelemetryConfiguration;
return _asExtensionEvent(extHostTelemetry.onDidChangeTelemetryConfiguration);
},
get isNewAppInstall() {
return isNewAppInstall(initData.telemetryInfo.firstSessionDate);
@@ -402,7 +421,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
return extHostLogService.getLevel();
},
get onDidChangeLogLevel() {
return extHostLogService.onDidChangeLogLevel;
return _asExtensionEvent(extHostLogService.onDidChangeLogLevel);
},
registerIssueUriRequestHandler(handler: vscode.IssueUriRequestHandler) {
checkProposedApiEnabled(extension, 'handleIssueUri');
@@ -441,7 +460,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
},
get onDidChangeTestResults() {
checkProposedApiEnabled(extension, 'testObserver');
return extHostTesting.onResultsChanged;
return _asExtensionEvent(extHostTesting.onResultsChanged);
},
get testResults() {
checkProposedApiEnabled(extension, 'testObserver');
@@ -490,9 +509,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
},
get onDidChange() {
if (isProposedApiEnabled(extension, 'extensionsAny')) {
return Event.any(extensionInfo.mine.onDidChange, extensionInfo.all.onDidChange);
return _asExtensionEvent(Event.any(extensionInfo.mine.onDidChange, extensionInfo.all.onDidChange));
}
return extensionInfo.mine.onDidChange;
return _asExtensionEvent(extensionInfo.mine.onDidChange);
}
};
@@ -502,7 +521,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
return extHostDiagnostics.createDiagnosticCollection(extension.identifier, name);
},
get onDidChangeDiagnostics() {
return extHostDiagnostics.onDidChangeDiagnostics;
return _asExtensionEvent(extHostDiagnostics.onDidChangeDiagnostics);
},
getDiagnostics: (resource?: vscode.Uri) => {
return <any>extHostDiagnostics.getDiagnostics(resource);
@@ -666,52 +685,52 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
return extHostEditors.createTextEditorDecorationType(extension, options);
},
onDidChangeActiveTextEditor(listener, thisArg?, disposables?) {
return extHostEditors.onDidChangeActiveTextEditor(listener, thisArg, disposables);
return _asExtensionEvent(extHostEditors.onDidChangeActiveTextEditor)(listener, thisArg, disposables);
},
onDidChangeVisibleTextEditors(listener, thisArg, disposables) {
return extHostEditors.onDidChangeVisibleTextEditors(listener, thisArg, disposables);
return _asExtensionEvent(extHostEditors.onDidChangeVisibleTextEditors)(listener, thisArg, disposables);
},
onDidChangeTextEditorSelection(listener: (e: vscode.TextEditorSelectionChangeEvent) => any, thisArgs?: any, disposables?: extHostTypes.Disposable[]) {
return extHostEditors.onDidChangeTextEditorSelection(listener, thisArgs, disposables);
return _asExtensionEvent(extHostEditors.onDidChangeTextEditorSelection)(listener, thisArgs, disposables);
},
onDidChangeTextEditorOptions(listener: (e: vscode.TextEditorOptionsChangeEvent) => any, thisArgs?: any, disposables?: extHostTypes.Disposable[]) {
return extHostEditors.onDidChangeTextEditorOptions(listener, thisArgs, disposables);
return _asExtensionEvent(extHostEditors.onDidChangeTextEditorOptions)(listener, thisArgs, disposables);
},
onDidChangeTextEditorVisibleRanges(listener: (e: vscode.TextEditorVisibleRangesChangeEvent) => any, thisArgs?: any, disposables?: extHostTypes.Disposable[]) {
return extHostEditors.onDidChangeTextEditorVisibleRanges(listener, thisArgs, disposables);
return _asExtensionEvent(extHostEditors.onDidChangeTextEditorVisibleRanges)(listener, thisArgs, disposables);
},
onDidChangeTextEditorViewColumn(listener, thisArg?, disposables?) {
return extHostEditors.onDidChangeTextEditorViewColumn(listener, thisArg, disposables);
return _asExtensionEvent(extHostEditors.onDidChangeTextEditorViewColumn)(listener, thisArg, disposables);
},
onDidCloseTerminal(listener, thisArg?, disposables?) {
return extHostTerminalService.onDidCloseTerminal(listener, thisArg, disposables);
return _asExtensionEvent(extHostTerminalService.onDidCloseTerminal)(listener, thisArg, disposables);
},
onDidOpenTerminal(listener, thisArg?, disposables?) {
return extHostTerminalService.onDidOpenTerminal(listener, thisArg, disposables);
return _asExtensionEvent(extHostTerminalService.onDidOpenTerminal)(listener, thisArg, disposables);
},
onDidChangeActiveTerminal(listener, thisArg?, disposables?) {
return extHostTerminalService.onDidChangeActiveTerminal(listener, thisArg, disposables);
return _asExtensionEvent(extHostTerminalService.onDidChangeActiveTerminal)(listener, thisArg, disposables);
},
onDidChangeTerminalDimensions(listener, thisArg?, disposables?) {
checkProposedApiEnabled(extension, 'terminalDimensions');
return extHostTerminalService.onDidChangeTerminalDimensions(listener, thisArg, disposables);
return _asExtensionEvent(extHostTerminalService.onDidChangeTerminalDimensions)(listener, thisArg, disposables);
},
onDidChangeTerminalState(listener, thisArg?, disposables?) {
return extHostTerminalService.onDidChangeTerminalState(listener, thisArg, disposables);
return _asExtensionEvent(extHostTerminalService.onDidChangeTerminalState)(listener, thisArg, disposables);
},
onDidWriteTerminalData(listener, thisArg?, disposables?) {
checkProposedApiEnabled(extension, 'terminalDataWriteEvent');
return extHostTerminalService.onDidWriteTerminalData(listener, thisArg, disposables);
return _asExtensionEvent(extHostTerminalService.onDidWriteTerminalData)(listener, thisArg, disposables);
},
onDidExecuteTerminalCommand(listener, thisArg?, disposables?) {
checkProposedApiEnabled(extension, 'terminalExecuteCommandEvent');
return extHostTerminalService.onDidExecuteTerminalCommand(listener, thisArg, disposables);
return _asExtensionEvent(extHostTerminalService.onDidExecuteTerminalCommand)(listener, thisArg, disposables);
},
get state() {
return extHostWindow.getState(extension);
},
onDidChangeWindowState(listener, thisArg?, disposables?) {
return extHostWindow.onDidChangeWindowState(listener, thisArg, disposables);
return _asExtensionEvent(extHostWindow.onDidChangeWindowState)(listener, thisArg, disposables);
},
showInformationMessage(message: string, ...rest: Array<vscode.MessageOptions | string | vscode.MessageItem>) {
return <Thenable<any>>extHostMessageService.showMessage(extension, Severity.Info, message, rest[0], <Array<string | vscode.MessageItem>>rest.slice(1));
@@ -822,7 +841,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
return extHostTheming.activeColorTheme;
},
onDidChangeActiveColorTheme(listener, thisArg?, disposables?) {
return extHostTheming.onDidChangeActiveColorTheme(listener, thisArg, disposables);
return _asExtensionEvent(extHostTheming.onDidChangeActiveColorTheme)(listener, thisArg, disposables);
},
registerWebviewViewProvider(viewId: string, provider: vscode.WebviewViewProvider, options?: {
webviewOptions?: {
@@ -835,19 +854,19 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
return extHostNotebook.activeNotebookEditor;
},
onDidChangeActiveNotebookEditor(listener, thisArgs?, disposables?) {
return extHostNotebook.onDidChangeActiveNotebookEditor(listener, thisArgs, disposables);
return _asExtensionEvent(extHostNotebook.onDidChangeActiveNotebookEditor)(listener, thisArgs, disposables);
},
get visibleNotebookEditors() {
return extHostNotebook.visibleNotebookEditors;
},
get onDidChangeVisibleNotebookEditors() {
return extHostNotebook.onDidChangeVisibleNotebookEditors;
return _asExtensionEvent(extHostNotebook.onDidChangeVisibleNotebookEditors);
},
onDidChangeNotebookEditorSelection(listener, thisArgs?, disposables?) {
return extHostNotebookEditors.onDidChangeNotebookEditorSelection(listener, thisArgs, disposables);
return _asExtensionEvent(extHostNotebookEditors.onDidChangeNotebookEditorSelection)(listener, thisArgs, disposables);
},
onDidChangeNotebookEditorVisibleRanges(listener, thisArgs?, disposables?) {
return extHostNotebookEditors.onDidChangeNotebookEditorVisibleRanges(listener, thisArgs, disposables);
return _asExtensionEvent(extHostNotebookEditors.onDidChangeNotebookEditorVisibleRanges)(listener, thisArgs, disposables);
},
showNotebookDocument(document, options?) {
return extHostNotebook.showNotebookDocument(document, options);
@@ -907,7 +926,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
return extHostWorkspace.updateWorkspaceFolders(extension, index, deleteCount || 0, ...workspaceFoldersToAdd);
},
onDidChangeWorkspaceFolders: function (listener, thisArgs?, disposables?) {
return extHostWorkspace.onDidChangeWorkspace(listener, thisArgs, disposables);
return _asExtensionEvent(extHostWorkspace.onDidChangeWorkspace)(listener, thisArgs, disposables);
},
asRelativePath: (pathOrUri, includeWorkspace?) => {
return extHostWorkspace.getRelativePath(pathOrUri, includeWorkspace);
@@ -991,19 +1010,19 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
});
},
onDidOpenTextDocument: (listener, thisArgs?, disposables?) => {
return extHostDocuments.onDidAddDocument(listener, thisArgs, disposables);
return _asExtensionEvent(extHostDocuments.onDidAddDocument)(listener, thisArgs, disposables);
},
onDidCloseTextDocument: (listener, thisArgs?, disposables?) => {
return extHostDocuments.onDidRemoveDocument(listener, thisArgs, disposables);
return _asExtensionEvent(extHostDocuments.onDidRemoveDocument)(listener, thisArgs, disposables);
},
onDidChangeTextDocument: (listener, thisArgs?, disposables?) => {
return extHostDocuments.onDidChangeDocument(listener, thisArgs, disposables);
return _asExtensionEvent(extHostDocuments.onDidChangeDocument)(listener, thisArgs, disposables);
},
onDidSaveTextDocument: (listener, thisArgs?, disposables?) => {
return extHostDocuments.onDidSaveDocument(listener, thisArgs, disposables);
return _asExtensionEvent(extHostDocuments.onDidSaveDocument)(listener, thisArgs, disposables);
},
onWillSaveTextDocument: (listener, thisArgs?, disposables?) => {
return extHostDocumentSaveParticipant.getOnWillSaveTextDocumentEvent(extension)(listener, thisArgs, disposables);
return _asExtensionEvent(extHostDocumentSaveParticipant.getOnWillSaveTextDocumentEvent(extension))(listener, thisArgs, disposables);
},
get notebookDocuments(): vscode.NotebookDocument[] {
return extHostNotebook.notebookDocuments.map(d => d.apiNotebook);
@@ -1021,25 +1040,25 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
return extHostNotebook.getNotebookDocument(uri).apiNotebook;
},
onDidSaveNotebookDocument(listener, thisArg, disposables) {
return extHostNotebookDocuments.onDidSaveNotebookDocument(listener, thisArg, disposables);
return _asExtensionEvent(extHostNotebookDocuments.onDidSaveNotebookDocument)(listener, thisArg, disposables);
},
onDidChangeNotebookDocument(listener, thisArg, disposables) {
return extHostNotebookDocuments.onDidChangeNotebookDocument(listener, thisArg, disposables);
return _asExtensionEvent(extHostNotebookDocuments.onDidChangeNotebookDocument)(listener, thisArg, disposables);
},
onWillSaveNotebookDocument(listener, thisArg, disposables) {
return extHostNotebookDocumentSaveParticipant.getOnWillSaveNotebookDocumentEvent(extension)(listener, thisArg, disposables);
return _asExtensionEvent(extHostNotebookDocumentSaveParticipant.getOnWillSaveNotebookDocumentEvent(extension))(listener, thisArg, disposables);
},
get onDidOpenNotebookDocument(): Event<vscode.NotebookDocument> {
return extHostNotebook.onDidOpenNotebookDocument;
get onDidOpenNotebookDocument() {
return _asExtensionEvent(extHostNotebook.onDidOpenNotebookDocument);
},
get onDidCloseNotebookDocument(): Event<vscode.NotebookDocument> {
return extHostNotebook.onDidCloseNotebookDocument;
get onDidCloseNotebookDocument() {
return _asExtensionEvent(extHostNotebook.onDidCloseNotebookDocument);
},
registerNotebookSerializer(viewType: string, serializer: vscode.NotebookSerializer, options?: vscode.NotebookDocumentContentOptions, registration?: vscode.NotebookRegistrationData) {
return extHostNotebook.registerNotebookSerializer(extension, viewType, serializer, options, isProposedApiEnabled(extension, 'notebookLiveShare') ? registration : undefined);
},
onDidChangeConfiguration: (listener: (_: any) => any, thisArgs?: any, disposables?: extHostTypes.Disposable[]) => {
return configProvider.onDidChangeConfiguration(listener, thisArgs, disposables);
return _asExtensionEvent(configProvider.onDidChangeConfiguration)(listener, thisArgs, disposables);
},
getConfiguration(section?: string, scope?: vscode.ConfigurationScope | null): vscode.WorkspaceConfiguration {
scope = arguments.length === 1 ? undefined : scope;
@@ -1084,22 +1103,22 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
return extensionService.getRemoteExecServer(authority);
},
onDidCreateFiles: (listener, thisArg, disposables) => {
return extHostFileSystemEvent.onDidCreateFile(listener, thisArg, disposables);
return _asExtensionEvent(extHostFileSystemEvent.onDidCreateFile)(listener, thisArg, disposables);
},
onDidDeleteFiles: (listener, thisArg, disposables) => {
return extHostFileSystemEvent.onDidDeleteFile(listener, thisArg, disposables);
return _asExtensionEvent(extHostFileSystemEvent.onDidDeleteFile)(listener, thisArg, disposables);
},
onDidRenameFiles: (listener, thisArg, disposables) => {
return extHostFileSystemEvent.onDidRenameFile(listener, thisArg, disposables);
return _asExtensionEvent(extHostFileSystemEvent.onDidRenameFile)(listener, thisArg, disposables);
},
onWillCreateFiles: (listener: (e: vscode.FileWillCreateEvent) => any, thisArg?: any, disposables?: vscode.Disposable[]) => {
return extHostFileSystemEvent.getOnWillCreateFileEvent(extension)(listener, thisArg, disposables);
return _asExtensionEvent(extHostFileSystemEvent.getOnWillCreateFileEvent(extension))(listener, thisArg, disposables);
},
onWillDeleteFiles: (listener: (e: vscode.FileWillDeleteEvent) => any, thisArg?: any, disposables?: vscode.Disposable[]) => {
return extHostFileSystemEvent.getOnWillDeleteFileEvent(extension)(listener, thisArg, disposables);
return _asExtensionEvent(extHostFileSystemEvent.getOnWillDeleteFileEvent(extension))(listener, thisArg, disposables);
},
onWillRenameFiles: (listener: (e: vscode.FileWillRenameEvent) => any, thisArg?: any, disposables?: vscode.Disposable[]) => {
return extHostFileSystemEvent.getOnWillRenameFileEvent(extension)(listener, thisArg, disposables);
return _asExtensionEvent(extHostFileSystemEvent.getOnWillRenameFileEvent(extension))(listener, thisArg, disposables);
},
openTunnel: (forward: vscode.TunnelOptions) => {
checkProposedApiEnabled(extension, 'tunnels');
@@ -1116,7 +1135,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
},
onDidChangeTunnels: (listener, thisArg?, disposables?) => {
checkProposedApiEnabled(extension, 'tunnels');
return extHostTunnelService.onDidChangeTunnels(listener, thisArg, disposables);
return _asExtensionEvent(extHostTunnelService.onDidChangeTunnels)(listener, thisArg, disposables);
},
registerPortAttributesProvider: (portSelector: vscode.PortAttributesSelector, provider: vscode.PortAttributesProvider) => {
checkProposedApiEnabled(extension, 'portsAttributes');
@@ -1138,7 +1157,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
return extHostWorkspace.requestWorkspaceTrust(options);
},
onDidGrantWorkspaceTrust: (listener, thisArgs?, disposables?) => {
return extHostWorkspace.onDidGrantWorkspaceTrust(listener, thisArgs, disposables);
return _asExtensionEvent(extHostWorkspace.onDidGrantWorkspaceTrust)(listener, thisArgs, disposables);
},
registerEditSessionIdentityProvider: (scheme: string, provider: vscode.EditSessionIdentityProvider) => {
checkProposedApiEnabled(extension, 'editSessionIdentityProvider');
@@ -1146,7 +1165,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
},
onWillCreateEditSessionIdentity: (listener, thisArgs?, disposables?) => {
checkProposedApiEnabled(extension, 'editSessionIdentityProvider');
return extHostWorkspace.getOnWillCreateEditSessionIdentityEvent(extension)(listener, thisArgs, disposables);
return _asExtensionEvent(extHostWorkspace.getOnWillCreateEditSessionIdentityEvent(extension))(listener, thisArgs, disposables);
},
registerCanonicalUriProvider: (scheme: string, provider: vscode.CanonicalUriProvider) => {
checkProposedApiEnabled(extension, 'canonicalUriProvider');
@@ -1193,23 +1212,23 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
return extHostDebugService.stackFrameFocus;
},
onDidStartDebugSession(listener, thisArg?, disposables?) {
return extHostDebugService.onDidStartDebugSession(listener, thisArg, disposables);
return _asExtensionEvent(extHostDebugService.onDidStartDebugSession)(listener, thisArg, disposables);
},
onDidTerminateDebugSession(listener, thisArg?, disposables?) {
return extHostDebugService.onDidTerminateDebugSession(listener, thisArg, disposables);
return _asExtensionEvent(extHostDebugService.onDidTerminateDebugSession)(listener, thisArg, disposables);
},
onDidChangeActiveDebugSession(listener, thisArg?, disposables?) {
return extHostDebugService.onDidChangeActiveDebugSession(listener, thisArg, disposables);
return _asExtensionEvent(extHostDebugService.onDidChangeActiveDebugSession)(listener, thisArg, disposables);
},
onDidReceiveDebugSessionCustomEvent(listener, thisArg?, disposables?) {
return extHostDebugService.onDidReceiveDebugSessionCustomEvent(listener, thisArg, disposables);
return _asExtensionEvent(extHostDebugService.onDidReceiveDebugSessionCustomEvent)(listener, thisArg, disposables);
},
onDidChangeBreakpoints(listener, thisArgs?, disposables?) {
return extHostDebugService.onDidChangeBreakpoints(listener, thisArgs, disposables);
return _asExtensionEvent(extHostDebugService.onDidChangeBreakpoints)(listener, thisArgs, disposables);
},
onDidChangeStackFrameFocus(listener, thisArg?, disposables?) {
checkProposedApiEnabled(extension, 'debugFocus');
return extHostDebugService.onDidChangeStackFrameFocus(listener, thisArg, disposables);
return _asExtensionEvent(extHostDebugService.onDidChangeStackFrameFocus)(listener, thisArg, disposables);
},
registerDebugConfigurationProvider(debugType: string, provider: vscode.DebugConfigurationProvider, triggerKind?: vscode.DebugConfigurationProviderTriggerKind) {
return extHostDebugService.registerDebugConfigurationProvider(debugType, provider, triggerKind || DebugConfigurationProviderTriggerKind.Initial);
@@ -1254,16 +1273,16 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
return extHostTask.taskExecutions;
},
onDidStartTask: (listeners, thisArgs?, disposables?) => {
return extHostTask.onDidStartTask(listeners, thisArgs, disposables);
return _asExtensionEvent(extHostTask.onDidStartTask)(listeners, thisArgs, disposables);
},
onDidEndTask: (listeners, thisArgs?, disposables?) => {
return extHostTask.onDidEndTask(listeners, thisArgs, disposables);
return _asExtensionEvent(extHostTask.onDidEndTask)(listeners, thisArgs, disposables);
},
onDidStartTaskProcess: (listeners, thisArgs?, disposables?) => {
return extHostTask.onDidStartTaskProcess(listeners, thisArgs, disposables);
return _asExtensionEvent(extHostTask.onDidStartTaskProcess)(listeners, thisArgs, disposables);
},
onDidEndTaskProcess: (listeners, thisArgs?, disposables?) => {
return extHostTask.onDidEndTaskProcess(listeners, thisArgs, disposables);
return _asExtensionEvent(extHostTask.onDidEndTaskProcess)(listeners, thisArgs, disposables);
}
};
@@ -1288,7 +1307,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
},
onDidChangeNotebookCellExecutionState(listener, thisArgs?, disposables?) {
checkProposedApiEnabled(extension, 'notebookCellExecutionState');
return extHostNotebookKernels.onDidChangeNotebookCellExecutionState(listener, thisArgs, disposables);
return _asExtensionEvent(extHostNotebookKernels.onDidChangeNotebookCellExecutionState)(listener, thisArgs, disposables);
}
};
@@ -15,14 +15,13 @@ import type * as vscode from 'vscode';
import { assertIsDefined } from 'vs/base/common/types';
import { deepFreeze } from 'vs/base/common/objects';
import { TextDocumentChangeReason } from 'vs/workbench/api/common/extHostTypes';
import { onUnexpectedExternalError } from 'vs/base/common/errors';
export class ExtHostDocuments implements ExtHostDocumentsShape {
private readonly _onDidAddDocument = new Emitter<vscode.TextDocument>({ onListenerError: onUnexpectedExternalError });
private readonly _onDidRemoveDocument = new Emitter<vscode.TextDocument>({ onListenerError: onUnexpectedExternalError });
private readonly _onDidChangeDocument = new Emitter<vscode.TextDocumentChangeEvent>({ onListenerError: onUnexpectedExternalError });
private readonly _onDidSaveDocument = new Emitter<vscode.TextDocument>({ onListenerError: onUnexpectedExternalError });
private readonly _onDidAddDocument = new Emitter<vscode.TextDocument>();
private readonly _onDidRemoveDocument = new Emitter<vscode.TextDocument>();
private readonly _onDidChangeDocument = new Emitter<vscode.TextDocumentChangeEvent>();
private readonly _onDidSaveDocument = new Emitter<vscode.TextDocument>();
readonly onDidAddDocument: Event<vscode.TextDocument> = this._onDidAddDocument.event;
readonly onDidRemoveDocument: Event<vscode.TextDocument> = this._onDidRemoveDocument.event;
@@ -28,7 +28,6 @@ import { SerializableObjectWithBuffers } from 'vs/workbench/services/extensions/
import type * as vscode from 'vscode';
import { ExtHostCell, ExtHostNotebookDocument } from './extHostNotebookDocument';
import { ExtHostNotebookEditor } from './extHostNotebookEditor';
import { onUnexpectedExternalError } from 'vs/base/common/errors';
import { IExtHostConsumerFileSystem } from 'vs/workbench/api/common/extHostFileSystemConsumer';
import { filter } from 'vs/base/common/objects';
import { Schemas } from 'vs/base/common/network';
@@ -51,7 +50,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
private readonly _editors = new Map<string, ExtHostNotebookEditor>();
private readonly _commandsConverter: CommandsConverter;
private readonly _onDidChangeActiveNotebookEditor = new Emitter<vscode.NotebookEditor | undefined>({ onListenerError: onUnexpectedExternalError });
private readonly _onDidChangeActiveNotebookEditor = new Emitter<vscode.NotebookEditor | undefined>();
readonly onDidChangeActiveNotebookEditor = this._onDidChangeActiveNotebookEditor.event;
private _activeNotebookEditor: ExtHostNotebookEditor | undefined;
@@ -63,12 +62,12 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
return this._visibleNotebookEditors.map(editor => editor.apiEditor);
}
private _onDidOpenNotebookDocument = new Emitter<vscode.NotebookDocument>({ onListenerError: onUnexpectedExternalError });
private _onDidOpenNotebookDocument = new Emitter<vscode.NotebookDocument>();
onDidOpenNotebookDocument: Event<vscode.NotebookDocument> = this._onDidOpenNotebookDocument.event;
private _onDidCloseNotebookDocument = new Emitter<vscode.NotebookDocument>({ onListenerError: onUnexpectedExternalError });
private _onDidCloseNotebookDocument = new Emitter<vscode.NotebookDocument>();
onDidCloseNotebookDocument: Event<vscode.NotebookDocument> = this._onDidCloseNotebookDocument.event;
private _onDidChangeVisibleNotebookEditors = new Emitter<vscode.NotebookEditor[]>({ onListenerError: onUnexpectedExternalError });
private _onDidChangeVisibleNotebookEditors = new Emitter<vscode.NotebookEditor[]>();
onDidChangeVisibleNotebookEditors = this._onDidChangeVisibleNotebookEditors.event;
private _statusBarCache = new Cache<IDisposable>('NotebookCellStatusBarCache');
@@ -3,7 +3,6 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { onUnexpectedExternalError } from 'vs/base/common/errors';
import { Emitter } from 'vs/base/common/event';
import { ILogService } from 'vs/platform/log/common/log';
import { ExtHostNotebookEditorsShape, INotebookEditorPropertiesChangeData, INotebookEditorViewColumnInfo } from 'vs/workbench/api/common/extHost.protocol';
@@ -14,8 +13,8 @@ import type * as vscode from 'vscode';
export class ExtHostNotebookEditors implements ExtHostNotebookEditorsShape {
private readonly _onDidChangeNotebookEditorSelection = new Emitter<vscode.NotebookEditorSelectionChangeEvent>({ onListenerError: onUnexpectedExternalError });
private readonly _onDidChangeNotebookEditorVisibleRanges = new Emitter<vscode.NotebookEditorVisibleRangesChangeEvent>({ onListenerError: onUnexpectedExternalError });
private readonly _onDidChangeNotebookEditorSelection = new Emitter<vscode.NotebookEditorSelectionChangeEvent>();
private readonly _onDidChangeNotebookEditorVisibleRanges = new Emitter<vscode.NotebookEditorVisibleRangesChangeEvent>();
readonly onDidChangeNotebookEditorSelection = this._onDidChangeNotebookEditorSelection.event;
readonly onDidChangeNotebookEditorVisibleRanges = this._onDidChangeNotebookEditorVisibleRanges.event;
@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
import * as arrays from 'vs/base/common/arrays';
import { onUnexpectedExternalError } from 'vs/base/common/errors';
import { Emitter, Event } from 'vs/base/common/event';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { ExtHostEditorsShape, IEditorPropertiesChangeData, IMainContext, ITextDocumentShowOptions, ITextEditorPositionData, MainContext, MainThreadTextEditorsShape } from 'vs/workbench/api/common/extHost.protocol';
@@ -16,12 +15,12 @@ import * as vscode from 'vscode';
export class ExtHostEditors implements ExtHostEditorsShape {
private readonly _onDidChangeTextEditorSelection = new Emitter<vscode.TextEditorSelectionChangeEvent>({ onListenerError: onUnexpectedExternalError });
private readonly _onDidChangeTextEditorOptions = new Emitter<vscode.TextEditorOptionsChangeEvent>({ onListenerError: onUnexpectedExternalError });
private readonly _onDidChangeTextEditorVisibleRanges = new Emitter<vscode.TextEditorVisibleRangesChangeEvent>({ onListenerError: onUnexpectedExternalError });
private readonly _onDidChangeTextEditorViewColumn = new Emitter<vscode.TextEditorViewColumnChangeEvent>({ onListenerError: onUnexpectedExternalError });
private readonly _onDidChangeActiveTextEditor = new Emitter<vscode.TextEditor | undefined>({ onListenerError: onUnexpectedExternalError });
private readonly _onDidChangeVisibleTextEditors = new Emitter<readonly vscode.TextEditor[]>({ onListenerError: onUnexpectedExternalError });
private readonly _onDidChangeTextEditorSelection = new Emitter<vscode.TextEditorSelectionChangeEvent>();
private readonly _onDidChangeTextEditorOptions = new Emitter<vscode.TextEditorOptionsChangeEvent>();
private readonly _onDidChangeTextEditorVisibleRanges = new Emitter<vscode.TextEditorVisibleRangesChangeEvent>();
private readonly _onDidChangeTextEditorViewColumn = new Emitter<vscode.TextEditorViewColumnChangeEvent>();
private readonly _onDidChangeActiveTextEditor = new Emitter<vscode.TextEditor | undefined>();
private readonly _onDidChangeVisibleTextEditors = new Emitter<readonly vscode.TextEditor[]>();
readonly onDidChangeTextEditorSelection: Event<vscode.TextEditorSelectionChangeEvent> = this._onDidChangeTextEditorSelection.event;
readonly onDidChangeTextEditorOptions: Event<vscode.TextEditorOptionsChangeEvent> = this._onDidChangeTextEditorOptions.event;
@@ -1217,7 +1217,8 @@ class IncreaseViewSizeAction extends BaseResizeViewAction {
super({
id: 'workbench.action.increaseViewSize',
title: { value: localize('increaseViewSize', "Increase Current View Size"), original: 'Increase Current View Size' },
f1: true
f1: true,
precondition: IsAuxiliaryWindowFocusedContext.toNegated()
});
}
@@ -1232,7 +1233,8 @@ class IncreaseViewWidthAction extends BaseResizeViewAction {
super({
id: 'workbench.action.increaseViewWidth',
title: { value: localize('increaseEditorWidth', "Increase Editor Width"), original: 'Increase Editor Width' },
f1: true
f1: true,
precondition: IsAuxiliaryWindowFocusedContext.toNegated()
});
}
@@ -1247,7 +1249,8 @@ class IncreaseViewHeightAction extends BaseResizeViewAction {
super({
id: 'workbench.action.increaseViewHeight',
title: { value: localize('increaseEditorHeight', "Increase Editor Height"), original: 'Increase Editor Height' },
f1: true
f1: true,
precondition: IsAuxiliaryWindowFocusedContext.toNegated()
});
}
@@ -1262,7 +1265,8 @@ class DecreaseViewSizeAction extends BaseResizeViewAction {
super({
id: 'workbench.action.decreaseViewSize',
title: { value: localize('decreaseViewSize', "Decrease Current View Size"), original: 'Decrease Current View Size' },
f1: true
f1: true,
precondition: IsAuxiliaryWindowFocusedContext.toNegated()
});
}
@@ -1276,7 +1280,8 @@ class DecreaseViewWidthAction extends BaseResizeViewAction {
super({
id: 'workbench.action.decreaseViewWidth',
title: { value: localize('decreaseEditorWidth', "Decrease Editor Width"), original: 'Decrease Editor Width' },
f1: true
f1: true,
precondition: IsAuxiliaryWindowFocusedContext.toNegated()
});
}
@@ -1291,7 +1296,8 @@ class DecreaseViewHeightAction extends BaseResizeViewAction {
super({
id: 'workbench.action.decreaseViewHeight',
title: { value: localize('decreaseEditorHeight', "Decrease Editor Height"), original: 'Decrease Editor Height' },
f1: true
f1: true,
precondition: IsAuxiliaryWindowFocusedContext.toNegated()
});
}
+13 -2
View File
@@ -23,6 +23,7 @@ import { Disposable, dispose, IDisposable, MutableDisposable } from 'vs/base/com
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { normalizeDriveLetter } from 'vs/base/common/labels';
import { IRange } from 'vs/editor/common/core/range';
import { ThemeIcon } from 'vs/base/common/themables';
export interface IResourceLabelProps {
resource?: URI | { primary?: URI; secondary?: URI };
@@ -59,6 +60,11 @@ export interface IResourceLabelOptions extends IIconLabelValueOptions {
* Will take the provided label as is and e.g. not override it for untitled files.
*/
readonly forceLabel?: boolean;
/**
* Uses the provided icon instead of deriving a resource icon.
*/
readonly icon?: ThemeIcon;
}
export interface IFileLabelOptions extends IResourceLabelOptions {
@@ -462,6 +468,7 @@ class ResourceLabelWidget extends IconLabel {
const hasResourceChanged = this.hasResourceChanged(label);
const hasPathLabelChanged = hasResourceChanged || this.hasPathLabelChanged(label);
const hasFileKindChanged = this.hasFileKindChanged(options);
const hasIconChanged = this.hasIconChanged(options);
this.label = label;
this.options = options;
@@ -475,7 +482,7 @@ class ResourceLabelWidget extends IconLabel {
}
this.render({
updateIcon: hasResourceChanged || hasFileKindChanged,
updateIcon: hasResourceChanged || hasFileKindChanged || hasIconChanged,
updateDecoration: hasResourceChanged || hasFileKindChanged
});
}
@@ -508,6 +515,10 @@ class ResourceLabelWidget extends IconLabel {
return !!newResource && this.computedPathLabel !== this.labelService.getUriLabel(newResource);
}
private hasIconChanged(newOptions?: IResourceLabelOptions): boolean {
return this.options?.icon !== newOptions?.icon;
}
clear(): void {
this.label = undefined;
this.options = undefined;
@@ -573,7 +584,7 @@ class ResourceLabelWidget extends IconLabel {
if (this.options && !this.options.hideIcon) {
if (!this.computedIconClasses) {
this.computedIconClasses = getIconClasses(this.modelService, this.languageService, resource, this.options.fileKind);
this.computedIconClasses = getIconClasses(this.modelService, this.languageService, resource, this.options.fileKind, this.options.icon);
}
iconLabelOptions.extraClasses = this.computedIconClasses.slice(0);
+7
View File
@@ -150,6 +150,13 @@ body.web {
font-size: 16px; /* sets font-size for codicons in workbench (https://github.com/microsoft/vscode/issues/98495) */
}
.monaco-workbench .product-icon[class*='codicon-']::before {
font-family: 'codicon';
width: 16px;
padding-left: 3px; /* width (16px) - font-size (13px) = padding-left (3px) */
padding-right: 3px;
}
.monaco-workbench.modal-dialog-visible .monaco-progress-container.infinite .progress-bit {
display: none; /* stop progress animations when dialogs are visible (https://github.com/microsoft/vscode/issues/138396) */
}
@@ -353,7 +353,7 @@ MenuRegistry.appendMenuItem(MenuId.EmptyEditorGroupContext, { command: { id: SPL
MenuRegistry.appendMenuItem(MenuId.EmptyEditorGroupContext, { command: { id: SPLIT_EDITOR_LEFT, title: localize('splitLeft', "Split Left") }, group: '2_split', order: 30 });
MenuRegistry.appendMenuItem(MenuId.EmptyEditorGroupContext, { command: { id: SPLIT_EDITOR_RIGHT, title: localize('splitRight', "Split Right") }, group: '2_split', order: 40 });
MenuRegistry.appendMenuItem(MenuId.EmptyEditorGroupContext, { command: { id: NEW_EMPTY_EDITOR_WINDOW_COMMAND_ID, title: localize('newWindow', "New Window") }, group: '3_window', order: 10 });
MenuRegistry.appendMenuItem(MenuId.EmptyEditorGroupContext, { command: { id: TOGGLE_LOCK_GROUP_COMMAND_ID, title: localize('toggleLockGroup', "Lock Group"), toggled: ActiveEditorGroupLockedContext }, group: '4_lock', order: 10, when: ContextKeyExpr.and(MultipleEditorGroupsContext, IsAuxiliaryEditorPartContext.toNegated()) });
MenuRegistry.appendMenuItem(MenuId.EmptyEditorGroupContext, { command: { id: TOGGLE_LOCK_GROUP_COMMAND_ID, title: localize('toggleLockGroup', "Lock Group"), toggled: ActiveEditorGroupLockedContext }, group: '4_lock', order: 10, when: IsAuxiliaryEditorPartContext.toNegated() /* already a primary action for aux windows */ });
MenuRegistry.appendMenuItem(MenuId.EmptyEditorGroupContext, { command: { id: CLOSE_EDITOR_GROUP_COMMAND_ID, title: localize('close', "Close") }, group: '5_close', order: 10, when: MultipleEditorGroupsContext });
// Editor Tab Container Context Menu
@@ -407,7 +407,7 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: CLOSE_SAVED_EDI
MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: TOGGLE_KEEP_EDITORS_COMMAND_ID, title: localize('togglePreviewMode', "Enable Preview Editors"), toggled: ContextKeyExpr.has('config.workbench.editor.enablePreview') }, group: '7_settings', order: 10 });
MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: TOGGLE_MAXIMIZE_EDITOR_GROUP, title: localize('maximizeGroup', "Maximize Group") }, group: '8_group_operations', order: 5, when: ContextKeyExpr.and(EditorPartMaximizedEditorGroupContext.negate(), EditorPartMultipleEditorGroupsContext) });
MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: TOGGLE_MAXIMIZE_EDITOR_GROUP, title: localize('unmaximizeGroup', "Unmaximize Group") }, group: '8_group_operations', order: 5, when: EditorPartMaximizedEditorGroupContext });
MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: TOGGLE_LOCK_GROUP_COMMAND_ID, title: localize('lockGroup', "Lock Group"), toggled: ActiveEditorGroupLockedContext }, group: '8_group_operations', order: 10, when: ContextKeyExpr.and(MultipleEditorGroupsContext, IsAuxiliaryEditorPartContext.toNegated()) });
MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: TOGGLE_LOCK_GROUP_COMMAND_ID, title: localize('lockGroup', "Lock Group"), toggled: ActiveEditorGroupLockedContext }, group: '8_group_operations', order: 10, when: IsAuxiliaryEditorPartContext.toNegated() /* already a primary action for aux windows */ });
function appendEditorToolItem(primary: ICommandAction, when: ContextKeyExpression | undefined, order: number, alternative?: ICommandAction, precondition?: ContextKeyExpression | undefined): void {
const item: IMenuItem = {
@@ -605,14 +605,14 @@ abstract class AbstractCloseAllAction extends Action2 {
// Editor will be saved on focus change when a
// dialog appears, so just track that separate
else if (filesConfigurationService.getAutoSaveMode(editor) === AutoSaveMode.ON_FOCUS_CHANGE && !editor.hasCapability(EditorInputCapabilities.Untitled)) {
else if (!editor.hasCapability(EditorInputCapabilities.Untitled) && filesConfigurationService.getAutoSaveMode(editor) === AutoSaveMode.ON_FOCUS_CHANGE) {
dirtyAutoSaveOnFocusChangeEditors.add({ editor, groupId });
}
// Windows, Linux: editor will be saved on window change
// when a native dialog appears, so just track that separate
// (see https://github.com/microsoft/vscode/issues/134250)
else if ((isNative && (isWindows || isLinux)) && filesConfigurationService.getAutoSaveMode(editor) === AutoSaveMode.ON_WINDOW_CHANGE && !editor.hasCapability(EditorInputCapabilities.Untitled)) {
else if ((isNative && (isWindows || isLinux)) && !editor.hasCapability(EditorInputCapabilities.Untitled) && filesConfigurationService.getAutoSaveMode(editor) === AutoSaveMode.ON_WINDOW_CHANGE) {
dirtyAutoSaveOnWindowChangeEditors.add({ editor, groupId });
}
@@ -90,7 +90,7 @@ export class EditorAutoSave extends Disposable implements IWorkbenchContribution
}
}
private maybeTriggerAutoSave(reason: SaveReason, editorIdentifier?: IEditorIdentifier): void {
private maybeTriggerAutoSave(reason: SaveReason.WINDOW_CHANGE | SaveReason.FOCUS_CHANGE, editorIdentifier?: IEditorIdentifier): void {
if (editorIdentifier) {
if (
!editorIdentifier.editor.isDirty() ||
@@ -1435,7 +1435,6 @@ function registerOtherEditorCommands(): void {
id: TOGGLE_LOCK_GROUP_COMMAND_ID,
title: { value: localize('toggleEditorGroupLock', "Toggle Editor Group Lock"), original: 'Toggle Editor Group Lock' },
category: Categories.View,
precondition: MultipleEditorGroupsContext,
f1: true
});
}
@@ -1450,7 +1449,7 @@ function registerOtherEditorCommands(): void {
id: LOCK_GROUP_COMMAND_ID,
title: { value: localize('lockEditorGroup', "Lock Editor Group"), original: 'Lock Editor Group' },
category: Categories.View,
precondition: ContextKeyExpr.and(MultipleEditorGroupsContext, ActiveEditorGroupLockedContext.toNegated()),
precondition: ActiveEditorGroupLockedContext.toNegated(),
f1: true
});
}
@@ -1464,7 +1463,7 @@ function registerOtherEditorCommands(): void {
super({
id: UNLOCK_GROUP_COMMAND_ID,
title: { value: localize('unlockEditorGroup', "Unlock Editor Group"), original: 'Unlock Editor Group' },
precondition: ContextKeyExpr.and(MultipleEditorGroupsContext, ActiveEditorGroupLockedContext),
precondition: ActiveEditorGroupLockedContext,
category: Categories.View,
f1: true
});
@@ -19,7 +19,11 @@ import { ByteSize, getLargeFileConfirmationLimit } from 'vs/platform/files/commo
export class DynamicEditorConfigurations extends Disposable implements IWorkbenchContribution {
private static readonly AUTO_LOCK_DEFAULT_ENABLED = new Set<string>(['terminalEditor']);
private static readonly AUTO_LOCK_DEFAULT_ENABLED = new Set<string>([
'terminalEditor',
'mainThreadWebview-simpleBrowser.view',
'mainThreadWebview-browserPreview'
]);
private static readonly AUTO_LOCK_EXTRA_EDITORS: RegisteredEditorInfo[] = [
@@ -35,6 +39,16 @@ export class DynamicEditorConfigurations extends Disposable implements IWorkbenc
id: 'mainThreadWebview-markdown.preview',
label: localize('markdownPreview', "Markdown Preview"),
priority: RegisteredEditorPriority.builtin
},
{
id: 'mainThreadWebview-simpleBrowser.view',
label: localize('simpleBrowser', "Simple Browser"),
priority: RegisteredEditorPriority.builtin
},
{
id: 'mainThreadWebview-browserPreview',
label: localize('livePreview', "Live Preview"),
priority: RegisteredEditorPriority.builtin
}
];
@@ -6,7 +6,7 @@
import 'vs/css!./media/editorgroupview';
import { EditorGroupModel, IEditorOpenOptions, IGroupModelChangeEvent, ISerializedEditorGroupModel, isGroupEditorCloseEvent, isGroupEditorOpenEvent, isSerializedEditorGroupModel } from 'vs/workbench/common/editor/editorGroupModel';
import { GroupIdentifier, CloseDirection, IEditorCloseEvent, IEditorPane, SaveReason, IEditorPartOptionsChangeEvent, EditorsOrder, IVisibleEditorPane, EditorResourceAccessor, EditorInputCapabilities, IUntypedEditorInput, DEFAULT_EDITOR_ASSOCIATION, SideBySideEditor, EditorCloseContext, IEditorWillMoveEvent, IEditorWillOpenEvent, IMatchEditorOptions, GroupModelChangeKind, IActiveEditorChangeEvent, IFindEditorOptions, IToolbarActions } from 'vs/workbench/common/editor';
import { ActiveEditorGroupLockedContext, ActiveEditorDirtyContext, EditorGroupEditorsCountContext, ActiveEditorStickyContext, ActiveEditorPinnedContext, ActiveEditorLastInGroupContext, ActiveEditorFirstInGroupContext, EditorPinnedAndUnpinnedTabsContext, ResourceContextKey, applyAvailableEditorIds, ActiveEditorAvailableEditorIdsContext, ActiveEditorCanSplitInGroupContext, SideBySideEditorActiveContext } from 'vs/workbench/common/contextkeys';
import { ActiveEditorGroupLockedContext, ActiveEditorDirtyContext, EditorGroupEditorsCountContext, ActiveEditorStickyContext, ActiveEditorPinnedContext, ActiveEditorLastInGroupContext, ActiveEditorFirstInGroupContext, ResourceContextKey, applyAvailableEditorIds, ActiveEditorAvailableEditorIdsContext, ActiveEditorCanSplitInGroupContext, SideBySideEditorActiveContext } from 'vs/workbench/common/contextkeys';
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
import { SideBySideEditorInput } from 'vs/workbench/common/editor/sideBySideEditorInput';
import { Emitter, Relay } from 'vs/base/common/event';
@@ -249,7 +249,6 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
const groupActiveEditorStickyContext = ActiveEditorStickyContext.bindTo(this.scopedContextKeyService);
const groupEditorsCountContext = EditorGroupEditorsCountContext.bindTo(this.scopedContextKeyService);
const groupLockedContext = ActiveEditorGroupLockedContext.bindTo(this.scopedContextKeyService);
const groupHasPinnedAndUnpinnedContext = EditorPinnedAndUnpinnedTabsContext.bindTo(this.scopedContextKeyService);
const groupActiveEditorAvailableEditorIds = ActiveEditorAvailableEditorIdsContext.bindTo(this.scopedContextKeyService);
const groupActiveEditorCanSplitInGroupContext = ActiveEditorCanSplitInGroupContext.bindTo(this.scopedContextKeyService);
@@ -287,10 +286,14 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
case GroupModelChangeKind.GROUP_LOCKED:
groupLockedContext.set(this.isLocked);
break;
case GroupModelChangeKind.EDITOR_ACTIVE:
groupActiveEditorFirstContext.set(this.model.isFirst(this.model.activeEditor));
groupActiveEditorLastContext.set(this.model.isLast(this.model.activeEditor));
groupActiveEditorPinnedContext.set(this.model.activeEditor ? this.model.isPinned(this.model.activeEditor) : false);
groupActiveEditorStickyContext.set(this.model.activeEditor ? this.model.isSticky(this.model.activeEditor) : false);
break;
case GroupModelChangeKind.EDITOR_CLOSE:
case GroupModelChangeKind.EDITOR_OPEN:
groupHasPinnedAndUnpinnedContext.set(this.hasPinnedAndUnpinnedEditors());
case GroupModelChangeKind.EDITOR_ACTIVE:
case GroupModelChangeKind.EDITOR_MOVE:
groupActiveEditorFirstContext.set(this.model.isFirst(this.model.activeEditor));
groupActiveEditorLastContext.set(this.model.isLast(this.model.activeEditor));
@@ -304,7 +307,6 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
if (e.editor && e.editor === this.model.activeEditor) {
groupActiveEditorStickyContext.set(this.model.isSticky(this.model.activeEditor));
}
groupHasPinnedAndUnpinnedContext.set(this.hasPinnedAndUnpinnedEditors());
break;
}
@@ -320,11 +322,6 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
// Update context keys on startup
observeActiveEditor();
groupHasPinnedAndUnpinnedContext.set(this.hasPinnedAndUnpinnedEditors());
}
private hasPinnedAndUnpinnedEditors(): boolean {
return this.model.stickyCount > 0 && this.model.stickyCount < this.model.count;
}
private registerContainerListeners(): void {
@@ -1083,9 +1080,9 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
// Conditionally lock the group
if (
isNew && // only if this editor was new for the group
this.count === 1 && // only when this editor was the first editor in the group
this.canLock() // only when we met the requirements to lock
isNew && // only if this editor was new for the group
this.count === 1 && // only when this editor was the first editor in the group
this.editorPartsView.groups.length > 1 // only allow auto locking if more than 1 group is opened
) {
// only when the editor identifier is configured as such
if (openedEditor.editorId && this.groupsView.partOptions.autoLockGroups?.has(openedEditor.editorId)) {
@@ -1884,29 +1881,13 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
//#region Locking
get isLocked(): boolean {
if (!this.canLock()) {
// Special case: if only 1 group is opened, never report it as locked
// to ensure editors can always open in the "default" editor group
return false;
}
return this.model.isLocked;
}
lock(locked: boolean): void {
if (!this.canLock()) {
// Special case: if only 1 group is opened, never allow to lock
// to ensure editors can always open in the "default" editor group
locked = false;
}
this.model.lock(locked);
}
private canLock(): boolean {
return this.editorPartsView.groups.length > 1; // only allow locking if more than 1 group is opened
}
//#endregion
//#region Editor Actions
@@ -13,7 +13,7 @@ import { IEditorGroupView, IEditorPartsView } from 'vs/workbench/browser/parts/e
import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IAuxiliaryWindowOpenOptions } from 'vs/workbench/services/auxiliaryWindow/browser/auxiliaryWindowService';
import { distinct, firstOrDefault } from 'vs/base/common/arrays';
import { distinct } from 'vs/base/common/arrays';
import { AuxiliaryEditorPart } from 'vs/workbench/browser/parts/editor/auxiliaryEditorPart';
import { MultiWindowParts } from 'vs/workbench/browser/part';
@@ -94,7 +94,7 @@ export class EditorParts extends MultiWindowParts<EditorPart> implements IEditor
disposables.add(part.onDidChangeActiveGroup(group => this._onDidActiveGroupChange.fire(group)));
disposables.add(part.onDidAddGroup(group => this._onDidAddGroup.fire(group)));
disposables.add(part.onDidRemoveGroup(group => this.handleOnDidRemoveGroup(group)));
disposables.add(part.onDidRemoveGroup(group => this._onDidRemoveGroup.fire(group)));
disposables.add(part.onDidMoveGroup(group => this._onDidMoveGroup.fire(group)));
disposables.add(part.onDidActivateGroup(group => this._onDidActivateGroup.fire(group)));
disposables.add(part.onDidChangeGroupMaximized(maximized => this._onDidChangeGroupMaximized.fire(maximized)));
@@ -103,17 +103,6 @@ export class EditorParts extends MultiWindowParts<EditorPart> implements IEditor
disposables.add(part.onDidChangeGroupLocked(group => this._onDidChangeGroupLocked.fire(group)));
}
private handleOnDidRemoveGroup(group: IEditorGroupView): void {
// Reset locked state when only one group is remaining
if (this.count === 1) {
firstOrDefault(this.mainPart.groups)?.lock(false);
}
// Events
this._onDidRemoveGroup.fire(group);
}
private doUpdateMostRecentActive(part: EditorPart, makeMostRecentlyActive?: boolean): void {
const index = this.mostRecentActiveParts.indexOf(part);
@@ -157,7 +157,7 @@ export abstract class BaseEditorQuickAccessProvider extends PickerQuickAccessPro
return isDirty ? localize('entryAriaLabelDirty', "{0}, unsaved changes", nameAndDescription) : nameAndDescription;
})(),
description,
iconClasses: getIconClasses(this.modelService, this.languageService, resource).concat(editor.getLabelExtraClasses()),
iconClasses: getIconClasses(this.modelService, this.languageService, resource, undefined, editor.getIcon()).concat(editor.getLabelExtraClasses()),
italic: !this.editorGroupService.getGroup(groupId)?.isPinned(editor),
buttons: (() => {
return [
@@ -1462,7 +1462,9 @@ export class MultiEditorTabsControl extends EditorTabsControl {
fileDecorations: {
colors: fileDecorationColors,
badges: fileDecorationBadges
}
},
icon: editor.getIcon(),
hideIcon: options.showIcons === false,
}
);
@@ -323,6 +323,8 @@ export class SingleEditorTabsControl extends EditorTabsControl {
colors: Boolean(options.decorations?.colors),
badges: Boolean(options.decorations?.badges)
},
icon: editor.getIcon(),
hideIcon: options.showIcons === false,
}
);
@@ -306,7 +306,6 @@ export abstract class AbstractPaneCompositePart extends CompositePart<PaneCompos
orientation: ActionsOrientation.HORIZONTAL,
getKeyBinding: action => this.keybindingService.lookupKeybinding(action.id),
anchorAlignmentProvider: () => this.getTitleAreaDropDownAnchorAlignment(),
highlightToggledItems: true,
toggleMenuTitle: localize('moreActions', "More Actions...")
}));
@@ -480,7 +479,7 @@ export abstract class AbstractPaneCompositePart extends CompositePart<PaneCompos
if (!activePane || !this.toolBar) {
return 0;
}
return this.toolBar.getItemsWidth() + (this.globalToolBar?.getItemsWidth() ?? 0);
return this.toolBar.getItemsWidth() + 5 + (this.globalToolBar?.getItemsWidth() ?? 0); // 5px toolBar padding-left
}
private onTitleAreaContextMenu(event: StandardMouseEvent): void {
-1
View File
@@ -86,7 +86,6 @@ export const IsCenteredLayoutContext = new RawContextKey<boolean>('isCenteredLay
export const SplitEditorsVertically = new RawContextKey<boolean>('splitEditorsVertically', false, localize('splitEditorsVertically', "Whether editors split vertically"));
export const MainEditorAreaVisibleContext = new RawContextKey<boolean>('mainEditorAreaVisible', true, localize('mainEditorAreaVisible', "Whether the editor area in the main window is visible"));
export const EditorTabsVisibleContext = new RawContextKey<boolean>('editorTabsVisible', true, localize('editorTabsVisible', "Whether editor tabs are visible"));
export const EditorPinnedAndUnpinnedTabsContext = new RawContextKey<boolean>('editorPinnedAndUnpinnedTabsVisible', false, true);
//#endregion
@@ -12,6 +12,7 @@ import { isEqual } from 'vs/base/common/resources';
import { ConfirmResult } from 'vs/platform/dialogs/common/dialogs';
import { IMarkdownString } from 'vs/base/common/htmlContent';
import { IDisposable } from 'vs/base/common/lifecycle';
import { ThemeIcon } from 'vs/base/common/themables';
export interface IEditorCloseHandler {
@@ -163,6 +164,14 @@ export abstract class EditorInput extends AbstractEditorInput {
return this.getTitle(Verbosity.SHORT);
}
/**
* Returns the icon which represents this editor input.
* If undefined, the default icon will be used.
*/
getIcon(): ThemeIcon | undefined {
return undefined;
}
/**
* Returns a descriptor suitable for telemetry events.
*
@@ -3,7 +3,6 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/chatEditor';
import * as dom from 'vs/base/browser/dom';
import { CancellationToken } from 'vs/base/common/cancellation';
import { IContextKeyService, IScopedContextKeyService } from 'vs/platform/contextkey/common/contextkey';
@@ -4,9 +4,11 @@
*--------------------------------------------------------------------------------------------*/
import { CancellationToken } from 'vs/base/common/cancellation';
import { Codicon } from 'vs/base/common/codicons';
import { Emitter } from 'vs/base/common/event';
import { Disposable, toDisposable } from 'vs/base/common/lifecycle';
import { Schemas } from 'vs/base/common/network';
import { ThemeIcon } from 'vs/base/common/themables';
import { URI } from 'vs/base/common/uri';
import * as nls from 'vs/nls';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
@@ -81,8 +83,8 @@ export class ChatEditorInput extends EditorInput {
return this.model?.title || nls.localize('chatEditorName', "Chat") + (this.inputCount > 0 ? ` ${this.inputCount + 1}` : '');
}
override getLabelExtraClasses(): string[] {
return ['chat-editor-label'];
override getIcon(): ThemeIcon {
return Codicon.commentDiscussion;
}
override async resolve(): Promise<ChatEditorModel | null> {
@@ -246,7 +246,12 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
options.cursorWidth = 1;
options.wrappingStrategy = 'advanced';
options.bracketPairColorization = { enabled: false };
options.suggest = { showIcons: false };
options.suggest = {
showIcons: false,
showSnippets: false,
showWords: true,
showStatusBar: false,
};
options.scrollbar = { ...(options.scrollbar ?? {}), vertical: 'hidden' };
this._inputEditorElement = dom.append(inputContainer, $('.interactive-input-editor'));
@@ -520,6 +520,11 @@
.interactive-item-container .value .interactive-response-placeholder-content {
color: var(--vscode-editorGhostText-foreground);
font-size: 12px;
margin-bottom: 16px;
}
.interactive-item-container .value .interactive-response-placeholder-content p {
margin: 0;
}
.interactive-response .interactive-response-codicon-details {
@@ -1,11 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.vs .show-file-icons .chat-editor-label.file-icon::before,
.show-file-icons .chat-editor-label.file-icon::before {
content: '\EAC7';
font-family: 'codicon';
font-size: 16px;
}
@@ -26,5 +26,5 @@
.suggest-input-container .monaco-editor,
.suggest-input-container .monaco-editor .lines-content {
background: none;
background: none !important;
}
@@ -5,6 +5,8 @@
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
import { localize } from 'vs/nls';
import { ThemeIcon } from 'vs/base/common/themables';
import { Codicon } from 'vs/base/common/codicons';
export class DisassemblyViewInput extends EditorInput {
@@ -29,6 +31,10 @@ export class DisassemblyViewInput extends EditorInput {
return localize('disassemblyInputName', "Disassembly");
}
override getIcon(): ThemeIcon {
return Codicon.debug;
}
override matches(other: unknown): boolean {
return other instanceof DisassemblyViewInput;
}
@@ -12,6 +12,8 @@ import { ExtensionEditorTab, IExtension } from 'vs/workbench/contrib/extensions/
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { join } from 'vs/base/common/path';
import { IEditorOptions } from 'vs/platform/editor/common/editor';
import { ThemeIcon } from 'vs/base/common/themables';
import { Codicon } from 'vs/base/common/codicons';
export interface IExtensionEditorOptions extends IEditorOptions {
showPreReleaseVersion?: boolean;
@@ -48,6 +50,10 @@ export class ExtensionsInput extends EditorInput {
return localize('extensionsInputName', "Extension: {0}", this._extension.displayName);
}
override getIcon(): ThemeIcon | undefined {
return Codicon.extensions;
}
override matches(other: EditorInput | IUntypedEditorInput): boolean {
if (super.matches(other)) {
return true;
@@ -7,6 +7,8 @@ import * as nls from 'vs/nls';
import { URI } from 'vs/base/common/uri';
import { EditorInputCapabilities, IUntypedEditorInput } from 'vs/workbench/common/editor';
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
import { ThemeIcon } from 'vs/base/common/themables';
import { Codicon } from 'vs/base/common/codicons';
export class RuntimeExtensionsInput extends EditorInput {
@@ -38,6 +40,10 @@ export class RuntimeExtensionsInput extends EditorInput {
return nls.localize('extensionsInputName', "Running Extensions");
}
override getIcon(): ThemeIcon {
return Codicon.extensions;
}
override matches(other: EditorInput | IUntypedEditorInput): boolean {
if (super.matches(other)) {
return true;
@@ -16,7 +16,7 @@ import { IReference, dispose, DisposableStore } from 'vs/base/common/lifecycle';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { FILE_EDITOR_INPUT_ID, TEXT_FILE_EDITOR_ID, BINARY_FILE_EDITOR_ID } from 'vs/workbench/contrib/files/common/files';
import { ILabelService } from 'vs/platform/label/common/label';
import { AutoSaveMode, IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService';
import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { isEqual } from 'vs/base/common/resources';
import { Event } from 'vs/base/common/event';
@@ -318,7 +318,7 @@ export class FileEditorInput extends AbstractTextResourceEditorInput implements
// and it could result in bad UX where an editor can be closed even though
// it shows up as dirty and has not finished saving yet.
if (this.filesConfigurationService.getAutoSaveMode(this) === AutoSaveMode.AFTER_SHORT_DELAY) {
if (this.filesConfigurationService.isShortAutoSaveDelayConfigured(this)) {
return true; // a short auto save is configured, treat this as being saved
}
@@ -13,7 +13,7 @@ import { IHostService } from 'vs/workbench/services/host/browser/host';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { RunOnceWorker } from 'vs/base/common/async';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { IFilesConfigurationService, AutoSaveMode } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService';
import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService';
import { FILE_EDITOR_INPUT_ID } from 'vs/workbench/contrib/files/common/files';
import { Schemas } from 'vs/base/common/network';
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
@@ -69,7 +69,7 @@ export class TextFileEditorTracker extends Disposable implements IWorkbenchContr
return false; // resource must not be pending to save
}
if (resource.scheme !== Schemas.untitled && this.filesConfigurationService.getAutoSaveMode(resource) === AutoSaveMode.AFTER_SHORT_DELAY && !fileModel?.hasState(TextFileEditorModelState.ERROR)) {
if (resource.scheme !== Schemas.untitled && !fileModel?.hasState(TextFileEditorModelState.ERROR) && this.filesConfigurationService.isShortAutoSaveDelayConfigured(resource)) {
// leave models auto saved after short delay unless
// the save resulted in an error and not for untitled
// that are not auto-saved anyway
@@ -286,9 +286,6 @@ export class ExplorerService implements IExplorerService {
const previouslyCutItems = this.cutItems;
this.cutItems = cut ? items : undefined;
await this.clipboardService.writeResources(items.map(s => s.resource));
if (items.length === 1) {
await this.clipboardService.writeText(items[0].name);
}
this.view?.itemsCopied(items, cut, previouslyCutItems);
}
@@ -329,8 +329,9 @@ export class ExplorerView extends ViewPane implements IExplorerView {
if (!this.hasFocus() || this.readonlyContext.get()) {
return;
}
await this.commandService.executeCommand('filesExplorer.paste', event.clipboardData?.files);
if (event.clipboardData?.files?.length) {
await this.commandService.executeCommand('filesExplorer.paste', event.clipboardData?.files);
}
}));
}
@@ -39,7 +39,7 @@ import { memoize } from 'vs/base/common/decorators';
import { ElementsDragAndDropData, NativeDragAndDropData } from 'vs/base/browser/ui/list/listView';
import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService';
import { IWorkingCopy, WorkingCopyCapabilities } from 'vs/workbench/services/workingCopy/common/workingCopy';
import { AutoSaveMode, IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService';
import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService';
import { IViewDescriptorService } from 'vs/workbench/common/views';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { Orientation } from 'vs/base/browser/ui/splitview/splitview';
@@ -460,7 +460,7 @@ export class OpenEditorsView extends ViewPane {
private updateDirtyIndicator(workingCopy?: IWorkingCopy): void {
if (workingCopy) {
const gotDirty = workingCopy.isDirty();
if (gotDirty && !(workingCopy.capabilities & WorkingCopyCapabilities.Untitled) && this.filesConfigurationService.getAutoSaveMode(workingCopy.resource) === AutoSaveMode.AFTER_SHORT_DELAY) {
if (gotDirty && !(workingCopy.capabilities & WorkingCopyCapabilities.Untitled) && this.filesConfigurationService.isShortAutoSaveDelayConfigured(workingCopy.resource)) {
return; // do not indicate dirty of working copies that are auto saved after short delay
}
}
@@ -650,7 +650,8 @@ class OpenEditorRenderer implements IListRenderer<OpenEditor, IOpenEditorTemplat
italic: openedEditor.isPreview(),
extraClasses: ['open-editor'].concat(openedEditor.editor.getLabelExtraClasses()),
fileDecorations: this.configurationService.getValue<IFilesConfiguration>().explorer.decorations,
title: editor.getTitle(Verbosity.LONG)
title: editor.getTitle(Verbosity.LONG),
icon: editor.getIcon()
});
const editorAction = openedEditor.isSticky() ? this.unpinEditorAction : this.closeEditorAction;
if (!templateData.actionBar.hasAction(editorAction)) {
@@ -11,7 +11,7 @@ import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle';
import { IActivityService, NumberBadge } from 'vs/workbench/services/activity/common/activity';
import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService';
import { IWorkingCopy, WorkingCopyCapabilities } from 'vs/workbench/services/workingCopy/common/workingCopy';
import { IFilesConfigurationService, AutoSaveMode } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService';
import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService';
export class DirtyFilesIndicator extends Disposable implements IWorkbenchContribution {
private readonly badgeHandle = this._register(new MutableDisposable());
@@ -42,7 +42,7 @@ export class DirtyFilesIndicator extends Disposable implements IWorkbenchContrib
private onWorkingCopyDidChangeDirty(workingCopy: IWorkingCopy): void {
const gotDirty = workingCopy.isDirty();
if (gotDirty && !(workingCopy.capabilities & WorkingCopyCapabilities.Untitled) && this.filesConfigurationService.getAutoSaveMode(workingCopy.resource) === AutoSaveMode.AFTER_SHORT_DELAY) {
if (gotDirty && !(workingCopy.capabilities & WorkingCopyCapabilities.Untitled) && this.filesConfigurationService.isShortAutoSaveDelayConfigured(workingCopy.resource)) {
return; // do not indicate dirty of working copies that are auto saved after short delay
}
@@ -109,6 +109,7 @@ export const _inputEditorOptions: IEditorConstructionOptions = {
suggest: {
showIcons: false,
showSnippets: false,
showWords: true,
showStatusBar: false,
},
wordWrap: 'on',
@@ -4,10 +4,12 @@
*--------------------------------------------------------------------------------------------*/
import { LazyStatefulPromise, raceTimeout } from 'vs/base/common/async';
import { Codicon } from 'vs/base/common/codicons';
import { onUnexpectedError } from 'vs/base/common/errors';
import { IMarkdownString } from 'vs/base/common/htmlContent';
import { IDisposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle';
import { deepClone } from 'vs/base/common/objects';
import { ThemeIcon } from 'vs/base/common/themables';
import { isDefined, isObject } from 'vs/base/common/types';
import { URI } from 'vs/base/common/uri';
import { ConstLazyPromise, IDocumentDiffItem, IMultiDiffEditorModel } from 'vs/editor/browser/widget/multiDiffEditorWidget/model';
@@ -49,6 +51,10 @@ export class MultiDiffEditorInput extends EditorInput implements ILanguageSuppor
return DEFAULT_EDITOR_ASSOCIATION.id;
}
override getIcon(): ThemeIcon {
return Codicon.diffMultiple;
}
constructor(
readonly label: string | undefined,
readonly resources: readonly MultiDiffEditorInputData[],
@@ -424,7 +424,7 @@ Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration).regis
},
[NotebookSetting.gotoSymbolsAllSymbols]: {
type: 'boolean',
default: false,
default: true,
markdownDescription: localize('notebook.gotoSymbols.showAllSymbols', "When enabled the Go to Symbol Quick Pick will display full code symbols from the notebook, as well as Markdown headers.")
},
}
@@ -922,6 +922,12 @@ configurationRegistry.registerConfiguration({
tags: ['notebookLayout', 'notebookOutputLayout'],
minimum: 1,
},
[NotebookSetting.LinkifyOutputFilePaths]: {
description: nls.localize('notebook.disableOutputFilePathLinks', "Control whether to disable filepath links in the output of notebook cells."),
type: 'boolean',
default: true,
tags: ['notebookOutputLayout']
},
[NotebookSetting.markupFontSize]: {
markdownDescription: nls.localize('notebook.markup.fontSize', "Controls the font size in pixels of rendered markup in notebooks. When set to {0}, 120% of {1} is used.", '`0`', '`#editor.fontSize#`'),
type: 'number',
@@ -372,6 +372,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD
|| e.outputFontFamily
|| e.outputWordWrap
|| e.outputScrolling
|| e.outputLinkifyFilePaths
) {
this._styleElement?.remove();
this._createLayoutStyles();
@@ -50,6 +50,7 @@ export interface NotebookDisplayOptions {
outputScrolling: boolean;
outputWordWrap: boolean;
outputLineLimit: number;
outputLinkifyFilePaths: boolean;
fontSize: number;
outputFontSize: number;
outputFontFamily: string;
@@ -106,6 +107,7 @@ export interface NotebookOptionsChangeEvent {
readonly outputLineHeight?: boolean;
readonly outputWordWrap?: boolean;
readonly outputScrolling?: boolean;
readonly outputLinkifyFilePaths?: boolean;
}
const defaultConfigConstants = Object.freeze({
@@ -199,6 +201,7 @@ export class NotebookOptions extends Disposable {
const outputLineHeight = this._computeOutputLineHeight(outputLineHeightSettingValue, outputFontSize);
const outputWordWrap = this.configurationService.getValue<boolean>(NotebookSetting.outputWordWrap);
const outputLineLimit = this.configurationService.getValue<number>(NotebookSetting.textOutputLineLimit) ?? 30;
const linkifyFilePaths = this.configurationService.getValue<boolean>(NotebookSetting.LinkifyOutputFilePaths) ?? true;
this._layoutConfiguration = {
...(compactView ? compactConfigConstants : defaultConfigConstants),
@@ -239,7 +242,8 @@ export class NotebookOptions extends Disposable {
markdownFoldHintHeight: 22,
outputScrolling: outputScrolling,
outputWordWrap: outputWordWrap,
outputLineLimit: outputLineLimit
outputLineLimit: outputLineLimit,
outputLinkifyFilePaths: linkifyFilePaths
};
this._register(this.configurationService.onDidChangeConfiguration(e => {
@@ -355,6 +359,7 @@ export class NotebookOptions extends Disposable {
const outputLineHeight = e.affectsConfiguration(NotebookSetting.outputLineHeight);
const outputScrolling = e.affectsConfiguration(NotebookSetting.outputScrolling);
const outputWordWrap = e.affectsConfiguration(NotebookSetting.outputWordWrap);
const outputLinkifyFilePaths = e.affectsConfiguration(NotebookSetting.LinkifyOutputFilePaths);
if (
!cellStatusBarVisibility
@@ -379,7 +384,8 @@ export class NotebookOptions extends Disposable {
&& !interactiveWindowCollapseCodeCells
&& !outputLineHeight
&& !outputScrolling
&& !outputWordWrap) {
&& !outputWordWrap
&& !outputLinkifyFilePaths) {
return;
}
@@ -478,6 +484,10 @@ export class NotebookOptions extends Disposable {
configuration.outputScrolling = this.configurationService.getValue<boolean>(NotebookSetting.outputScrolling);
}
if (outputLinkifyFilePaths) {
configuration.outputLinkifyFilePaths = this.configurationService.getValue<boolean>(NotebookSetting.LinkifyOutputFilePaths);
}
this._layoutConfiguration = Object.freeze(configuration);
// trigger event
@@ -504,7 +514,8 @@ export class NotebookOptions extends Disposable {
interactiveWindowCollapseCodeCells,
outputLineHeight,
outputScrolling,
outputWordWrap
outputWordWrap,
outputLinkifyFilePaths: outputLinkifyFilePaths
});
}
@@ -713,6 +724,7 @@ export class NotebookOptions extends Disposable {
outputScrolling: this._layoutConfiguration.outputScrolling,
outputWordWrap: this._layoutConfiguration.outputWordWrap,
outputLineLimit: this._layoutConfiguration.outputLineLimit,
outputLinkifyFilePaths: this._layoutConfiguration.outputLinkifyFilePaths,
};
}
@@ -734,6 +746,7 @@ export class NotebookOptions extends Disposable {
outputScrolling: this._layoutConfiguration.outputScrolling,
outputWordWrap: this._layoutConfiguration.outputWordWrap,
outputLineLimit: this._layoutConfiguration.outputLineLimit,
outputLinkifyFilePaths: false
};
}
@@ -117,6 +117,7 @@ interface BacklayerWebviewOptions {
readonly outputScrolling: boolean;
readonly outputWordWrap: boolean;
readonly outputLineLimit: number;
readonly outputLinkifyFilePaths: boolean;
}
@@ -245,7 +246,8 @@ export class BackLayerWebView<T extends ICommonCellInfo> extends Themable {
renderOptions: {
lineLimit: this.options.outputLineLimit,
outputScrolling: this.options.outputScrolling,
outputWordWrap: this.options.outputWordWrap
outputWordWrap: this.options.outputWordWrap,
linkifyFilePaths: this.options.outputLinkifyFilePaths,
}
});
}
@@ -283,7 +285,8 @@ export class BackLayerWebView<T extends ICommonCellInfo> extends Themable {
const renderOptions = {
lineLimit: this.options.outputLineLimit,
outputScrolling: this.options.outputScrolling,
outputWordWrap: this.options.outputWordWrap
outputWordWrap: this.options.outputWordWrap,
linkifyFilePaths: this.options.outputLinkifyFilePaths
};
const preloadScript = preloadsScriptStr(
{
@@ -70,6 +70,7 @@ export interface RenderOptions {
readonly lineLimit: number;
readonly outputScrolling: boolean;
readonly outputWordWrap: boolean;
readonly linkifyFilePaths: boolean;
}
interface PreloadContext {
@@ -1696,6 +1697,7 @@ async function webviewPreloads(ctx: PreloadContext) {
get lineLimit() { return currentRenderOptions.lineLimit; },
get outputScrolling() { return currentRenderOptions.outputScrolling; },
get outputWordWrap() { return currentRenderOptions.outputWordWrap; },
get linkifyFilePaths() { return currentRenderOptions.linkifyFilePaths; },
},
get onDidChangeSettings() { return settingChange.event; }
};
@@ -956,6 +956,7 @@ export const NotebookSetting = {
outputScrollingDeprecated: 'notebook.experimental.outputScrolling',
outputScrolling: 'notebook.output.scrolling',
textOutputLineLimit: 'notebook.output.textLineLimit',
LinkifyOutputFilePaths: 'notebook.output.linkifyFilePaths',
formatOnSave: 'notebook.formatOnSave.enabled',
insertFinalNewline: 'notebook.insertFinalNewline',
formatOnCellExecution: 'notebook.formatOnCellExecution',

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