Merge branch 'main' into lramos15/modelEvent
This commit is contained in:
commit
6ce7f83df2
10
.github/workflows/ci.yml
vendored
10
.github/workflows/ci.yml
vendored
|
@ -72,6 +72,9 @@ jobs:
|
||||||
- name: Run Unit Tests (Electron)
|
- name: Run Unit Tests (Electron)
|
||||||
run: .\scripts\test.bat
|
run: .\scripts\test.bat
|
||||||
|
|
||||||
|
- name: Run Unit Tests (node.js)
|
||||||
|
run: yarn test-node
|
||||||
|
|
||||||
- name: Run Unit Tests (Browser)
|
- name: Run Unit Tests (Browser)
|
||||||
run: yarn test-browser --browser chromium
|
run: yarn test-browser --browser chromium
|
||||||
|
|
||||||
|
@ -147,6 +150,10 @@ jobs:
|
||||||
id: electron-unit-tests
|
id: electron-unit-tests
|
||||||
run: DISPLAY=:10 ./scripts/test.sh
|
run: DISPLAY=:10 ./scripts/test.sh
|
||||||
|
|
||||||
|
- name: Run Unit Tests (node.js)
|
||||||
|
id: nodejs-unit-tests
|
||||||
|
run: yarn test-node
|
||||||
|
|
||||||
- name: Run Unit Tests (Browser)
|
- name: Run Unit Tests (Browser)
|
||||||
id: browser-unit-tests
|
id: browser-unit-tests
|
||||||
run: DISPLAY=:10 yarn test-browser --browser chromium
|
run: DISPLAY=:10 yarn test-browser --browser chromium
|
||||||
|
@ -222,6 +229,9 @@ jobs:
|
||||||
- name: Run Unit Tests (Electron)
|
- name: Run Unit Tests (Electron)
|
||||||
run: DISPLAY=:10 ./scripts/test.sh
|
run: DISPLAY=:10 ./scripts/test.sh
|
||||||
|
|
||||||
|
- name: Run Unit Tests (node.js)
|
||||||
|
run: yarn test-node
|
||||||
|
|
||||||
- name: Run Unit Tests (Browser)
|
- name: Run Unit Tests (Browser)
|
||||||
run: DISPLAY=:10 yarn test-browser --browser chromium
|
run: DISPLAY=:10 yarn test-browser --browser chromium
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2021-11-19T08:23:35Z
|
2021-11-24T12:04:58.681Z
|
||||||
|
|
|
@ -48,23 +48,23 @@ steps:
|
||||||
git pull --no-rebase https://github.com/$(VSCODE_MIXIN_REPO).git $(node -p "require('./package.json').distro")
|
git pull --no-rebase https://github.com/$(VSCODE_MIXIN_REPO).git $(node -p "require('./package.json').distro")
|
||||||
displayName: Merge distro
|
displayName: Merge distro
|
||||||
|
|
||||||
# - script: |
|
- script: |
|
||||||
# mkdir -p .build
|
mkdir -p .build
|
||||||
# node build/azure-pipelines/common/computeNodeModulesCacheKey.js $VSCODE_ARCH $ENABLE_TERRAPIN > .build/yarnlockhash
|
node build/azure-pipelines/common/computeNodeModulesCacheKey.js $VSCODE_ARCH $ENABLE_TERRAPIN > .build/yarnlockhash
|
||||||
# displayName: Prepare yarn cache flags
|
displayName: Prepare yarn cache flags
|
||||||
|
|
||||||
# - task: Cache@2
|
- task: Cache@2
|
||||||
# inputs:
|
inputs:
|
||||||
# key: "nodeModules | $(Agent.OS) | .build/yarnlockhash"
|
key: "nodeModules | $(Agent.OS) | .build/yarnlockhash"
|
||||||
# path: .build/node_modules_cache
|
path: .build/node_modules_cache
|
||||||
# cacheHitVar: NODE_MODULES_RESTORED
|
cacheHitVar: NODE_MODULES_RESTORED
|
||||||
# displayName: Restore node_modules cache
|
displayName: Restore node_modules cache
|
||||||
|
|
||||||
# - script: |
|
- script: |
|
||||||
# set -e
|
set -e
|
||||||
# tar -xzf .build/node_modules_cache/cache.tgz
|
tar -xzf .build/node_modules_cache/cache.tgz
|
||||||
# condition: and(succeeded(), eq(variables.NODE_MODULES_RESTORED, 'true'))
|
condition: and(succeeded(), eq(variables.NODE_MODULES_RESTORED, 'true'))
|
||||||
# displayName: Extract node_modules cache
|
displayName: Extract node_modules cache
|
||||||
|
|
||||||
- script: |
|
- script: |
|
||||||
set -e
|
set -e
|
||||||
|
@ -101,13 +101,13 @@ steps:
|
||||||
displayName: Install dependencies
|
displayName: Install dependencies
|
||||||
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
||||||
|
|
||||||
# - script: |
|
- script: |
|
||||||
# set -e
|
set -e
|
||||||
# node build/azure-pipelines/common/listNodeModules.js .build/node_modules_list.txt
|
node build/azure-pipelines/common/listNodeModules.js .build/node_modules_list.txt
|
||||||
# mkdir -p .build/node_modules_cache
|
mkdir -p .build/node_modules_cache
|
||||||
# tar -czf .build/node_modules_cache/cache.tgz --files-from .build/node_modules_list.txt
|
tar -czf .build/node_modules_cache/cache.tgz --files-from .build/node_modules_list.txt
|
||||||
# condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
||||||
# displayName: Create node_modules archive
|
displayName: Create node_modules archive
|
||||||
|
|
||||||
# This script brings in the right resources (images, icons, etc) based on the quality (insiders, stable, exploration)
|
# This script brings in the right resources (images, icons, etc) based on the quality (insiders, stable, exploration)
|
||||||
- script: |
|
- script: |
|
||||||
|
@ -179,6 +179,13 @@ steps:
|
||||||
timeoutInMinutes: 7
|
timeoutInMinutes: 7
|
||||||
condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||||
|
|
||||||
|
- script: |
|
||||||
|
set -e
|
||||||
|
yarn test-node --build
|
||||||
|
displayName: Run unit tests (node.js)
|
||||||
|
timeoutInMinutes: 7
|
||||||
|
condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||||
|
|
||||||
- script: |
|
- script: |
|
||||||
set -e
|
set -e
|
||||||
yarn test-browser --build --browser chromium --browser webkit --browser firefox --tfs "Browser Unit Tests"
|
yarn test-browser --build --browser chromium --browser webkit --browser firefox --tfs "Browser Unit Tests"
|
||||||
|
|
|
@ -47,23 +47,23 @@ steps:
|
||||||
git pull --no-rebase https://github.com/$(VSCODE_MIXIN_REPO).git $(node -p "require('./package.json').distro")
|
git pull --no-rebase https://github.com/$(VSCODE_MIXIN_REPO).git $(node -p "require('./package.json').distro")
|
||||||
displayName: Merge distro
|
displayName: Merge distro
|
||||||
|
|
||||||
# - script: |
|
- script: |
|
||||||
# mkdir -p .build
|
mkdir -p .build
|
||||||
# node build/azure-pipelines/common/computeNodeModulesCacheKey.js "alpine" $ENABLE_TERRAPIN > .build/yarnlockhash
|
node build/azure-pipelines/common/computeNodeModulesCacheKey.js "alpine" $ENABLE_TERRAPIN > .build/yarnlockhash
|
||||||
# displayName: Prepare yarn cache flags
|
displayName: Prepare yarn cache flags
|
||||||
|
|
||||||
# - task: Cache@2
|
- task: Cache@2
|
||||||
# inputs:
|
inputs:
|
||||||
# key: "nodeModules | $(Agent.OS) | .build/yarnlockhash"
|
key: "nodeModules | $(Agent.OS) | .build/yarnlockhash"
|
||||||
# path: .build/node_modules_cache
|
path: .build/node_modules_cache
|
||||||
# cacheHitVar: NODE_MODULES_RESTORED
|
cacheHitVar: NODE_MODULES_RESTORED
|
||||||
# displayName: Restore node_modules cache
|
displayName: Restore node_modules cache
|
||||||
|
|
||||||
# - script: |
|
- script: |
|
||||||
# set -e
|
set -e
|
||||||
# tar -xzf .build/node_modules_cache/cache.tgz
|
tar -xzf .build/node_modules_cache/cache.tgz
|
||||||
# condition: and(succeeded(), eq(variables.NODE_MODULES_RESTORED, 'true'))
|
condition: and(succeeded(), eq(variables.NODE_MODULES_RESTORED, 'true'))
|
||||||
# displayName: Extract node_modules cache
|
displayName: Extract node_modules cache
|
||||||
|
|
||||||
- script: |
|
- script: |
|
||||||
set -e
|
set -e
|
||||||
|
@ -89,13 +89,13 @@ steps:
|
||||||
displayName: Install dependencies
|
displayName: Install dependencies
|
||||||
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
||||||
|
|
||||||
# - script: |
|
- script: |
|
||||||
# set -e
|
set -e
|
||||||
# node build/azure-pipelines/common/listNodeModules.js .build/node_modules_list.txt
|
node build/azure-pipelines/common/listNodeModules.js .build/node_modules_list.txt
|
||||||
# mkdir -p .build/node_modules_cache
|
mkdir -p .build/node_modules_cache
|
||||||
# tar -czf .build/node_modules_cache/cache.tgz --files-from .build/node_modules_list.txt
|
tar -czf .build/node_modules_cache/cache.tgz --files-from .build/node_modules_list.txt
|
||||||
# condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
||||||
# displayName: Create node_modules archive
|
displayName: Create node_modules archive
|
||||||
|
|
||||||
- script: |
|
- script: |
|
||||||
set -e
|
set -e
|
||||||
|
|
|
@ -38,23 +38,23 @@ steps:
|
||||||
git pull --no-rebase https://github.com/$(VSCODE_MIXIN_REPO).git $(node -p "require('./package.json').distro")
|
git pull --no-rebase https://github.com/$(VSCODE_MIXIN_REPO).git $(node -p "require('./package.json').distro")
|
||||||
displayName: Merge distro
|
displayName: Merge distro
|
||||||
|
|
||||||
# - script: |
|
- script: |
|
||||||
# mkdir -p .build
|
mkdir -p .build
|
||||||
# node build/azure-pipelines/common/computeNodeModulesCacheKey.js $VSCODE_ARCH $ENABLE_TERRAPIN > .build/yarnlockhash
|
node build/azure-pipelines/common/computeNodeModulesCacheKey.js $VSCODE_ARCH $ENABLE_TERRAPIN > .build/yarnlockhash
|
||||||
# displayName: Prepare yarn cache flags
|
displayName: Prepare yarn cache flags
|
||||||
|
|
||||||
# - task: Cache@2
|
- task: Cache@2
|
||||||
# inputs:
|
inputs:
|
||||||
# key: "nodeModules | $(Agent.OS) | .build/yarnlockhash"
|
key: "nodeModules | $(Agent.OS) | .build/yarnlockhash"
|
||||||
# path: .build/node_modules_cache
|
path: .build/node_modules_cache
|
||||||
# cacheHitVar: NODE_MODULES_RESTORED
|
cacheHitVar: NODE_MODULES_RESTORED
|
||||||
# displayName: Restore node_modules cache
|
displayName: Restore node_modules cache
|
||||||
|
|
||||||
# - script: |
|
- script: |
|
||||||
# set -e
|
set -e
|
||||||
# tar -xzf .build/node_modules_cache/cache.tgz
|
tar -xzf .build/node_modules_cache/cache.tgz
|
||||||
# condition: and(succeeded(), eq(variables.NODE_MODULES_RESTORED, 'true'))
|
condition: and(succeeded(), eq(variables.NODE_MODULES_RESTORED, 'true'))
|
||||||
# displayName: Extract node_modules cache
|
displayName: Extract node_modules cache
|
||||||
|
|
||||||
- script: |
|
- script: |
|
||||||
set -e
|
set -e
|
||||||
|
@ -110,13 +110,13 @@ steps:
|
||||||
displayName: Install dependencies
|
displayName: Install dependencies
|
||||||
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
||||||
|
|
||||||
# - script: |
|
- script: |
|
||||||
# set -e
|
set -e
|
||||||
# node build/azure-pipelines/common/listNodeModules.js .build/node_modules_list.txt
|
node build/azure-pipelines/common/listNodeModules.js .build/node_modules_list.txt
|
||||||
# mkdir -p .build/node_modules_cache
|
mkdir -p .build/node_modules_cache
|
||||||
# tar -czf .build/node_modules_cache/cache.tgz --files-from .build/node_modules_list.txt
|
tar -czf .build/node_modules_cache/cache.tgz --files-from .build/node_modules_list.txt
|
||||||
# condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
||||||
# displayName: Create node_modules archive
|
displayName: Create node_modules archive
|
||||||
|
|
||||||
- script: |
|
- script: |
|
||||||
set -e
|
set -e
|
||||||
|
@ -162,6 +162,13 @@ steps:
|
||||||
timeoutInMinutes: 7
|
timeoutInMinutes: 7
|
||||||
condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||||
|
|
||||||
|
- script: |
|
||||||
|
set -e
|
||||||
|
yarn test-node --build
|
||||||
|
displayName: Run unit tests (node.js)
|
||||||
|
timeoutInMinutes: 7
|
||||||
|
condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||||
|
|
||||||
- script: |
|
- script: |
|
||||||
set -e
|
set -e
|
||||||
yarn test-browser --build --browser chromium --tfs "Browser Unit Tests"
|
yarn test-browser --build --browser chromium --tfs "Browser Unit Tests"
|
||||||
|
|
|
@ -27,24 +27,24 @@ steps:
|
||||||
git pull --no-rebase https://github.com/$(VSCODE_MIXIN_REPO).git $(node -p "require('./package.json').distro")
|
git pull --no-rebase https://github.com/$(VSCODE_MIXIN_REPO).git $(node -p "require('./package.json').distro")
|
||||||
displayName: Merge distro
|
displayName: Merge distro
|
||||||
|
|
||||||
# - script: |
|
- script: |
|
||||||
# mkdir -p .build
|
mkdir -p .build
|
||||||
# node build/azure-pipelines/common/computeNodeModulesCacheKey.js $VSCODE_ARCH $ENABLE_TERRAPIN > .build/yarnlockhash
|
node build/azure-pipelines/common/computeNodeModulesCacheKey.js $VSCODE_ARCH $ENABLE_TERRAPIN > .build/yarnlockhash
|
||||||
# displayName: Prepare yarn cache flags
|
displayName: Prepare yarn cache flags
|
||||||
|
|
||||||
# # using `genericNodeModules` instead of `nodeModules` here to avoid sharing the cache with builds running inside containers
|
# using `genericNodeModules` instead of `nodeModules` here to avoid sharing the cache with builds running inside containers
|
||||||
# - task: Cache@2
|
- task: Cache@2
|
||||||
# inputs:
|
inputs:
|
||||||
# key: "genericNodeModules | $(Agent.OS) | .build/yarnlockhash"
|
key: "genericNodeModules | $(Agent.OS) | .build/yarnlockhash"
|
||||||
# path: .build/node_modules_cache
|
path: .build/node_modules_cache
|
||||||
# cacheHitVar: NODE_MODULES_RESTORED
|
cacheHitVar: NODE_MODULES_RESTORED
|
||||||
# displayName: Restore node_modules cache
|
displayName: Restore node_modules cache
|
||||||
|
|
||||||
# - script: |
|
- script: |
|
||||||
# set -e
|
set -e
|
||||||
# tar -xzf .build/node_modules_cache/cache.tgz
|
tar -xzf .build/node_modules_cache/cache.tgz
|
||||||
# condition: and(succeeded(), eq(variables.NODE_MODULES_RESTORED, 'true'))
|
condition: and(succeeded(), eq(variables.NODE_MODULES_RESTORED, 'true'))
|
||||||
# displayName: Extract node_modules cache
|
displayName: Extract node_modules cache
|
||||||
|
|
||||||
- script: |
|
- script: |
|
||||||
set -e
|
set -e
|
||||||
|
@ -77,13 +77,13 @@ steps:
|
||||||
displayName: Install dependencies
|
displayName: Install dependencies
|
||||||
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
||||||
|
|
||||||
# - script: |
|
- script: |
|
||||||
# set -e
|
set -e
|
||||||
# node build/azure-pipelines/common/listNodeModules.js .build/node_modules_list.txt
|
node build/azure-pipelines/common/listNodeModules.js .build/node_modules_list.txt
|
||||||
# mkdir -p .build/node_modules_cache
|
mkdir -p .build/node_modules_cache
|
||||||
# tar -czf .build/node_modules_cache/cache.tgz --files-from .build/node_modules_list.txt
|
tar -czf .build/node_modules_cache/cache.tgz --files-from .build/node_modules_list.txt
|
||||||
# condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
||||||
# displayName: Create node_modules archive
|
displayName: Create node_modules archive
|
||||||
|
|
||||||
# Mixin must run before optimize, because the CSS loader will inline small SVGs
|
# Mixin must run before optimize, because the CSS loader will inline small SVGs
|
||||||
- script: |
|
- script: |
|
||||||
|
|
|
@ -38,23 +38,23 @@ steps:
|
||||||
git pull --no-rebase https://github.com/$(VSCODE_MIXIN_REPO).git $(node -p "require('./package.json').distro")
|
git pull --no-rebase https://github.com/$(VSCODE_MIXIN_REPO).git $(node -p "require('./package.json').distro")
|
||||||
displayName: Merge distro
|
displayName: Merge distro
|
||||||
|
|
||||||
# - script: |
|
- script: |
|
||||||
# mkdir -p .build
|
mkdir -p .build
|
||||||
# node build/azure-pipelines/common/computeNodeModulesCacheKey.js "web" $ENABLE_TERRAPIN > .build/yarnlockhash
|
node build/azure-pipelines/common/computeNodeModulesCacheKey.js "web" $ENABLE_TERRAPIN > .build/yarnlockhash
|
||||||
# displayName: Prepare yarn cache flags
|
displayName: Prepare yarn cache flags
|
||||||
|
|
||||||
# - task: Cache@2
|
- task: Cache@2
|
||||||
# inputs:
|
inputs:
|
||||||
# key: "nodeModules | $(Agent.OS) | .build/yarnlockhash"
|
key: "nodeModules | $(Agent.OS) | .build/yarnlockhash"
|
||||||
# path: .build/node_modules_cache
|
path: .build/node_modules_cache
|
||||||
# cacheHitVar: NODE_MODULES_RESTORED
|
cacheHitVar: NODE_MODULES_RESTORED
|
||||||
# displayName: Restore node_modules cache
|
displayName: Restore node_modules cache
|
||||||
|
|
||||||
# - script: |
|
- script: |
|
||||||
# set -e
|
set -e
|
||||||
# tar -xzf .build/node_modules_cache/cache.tgz
|
tar -xzf .build/node_modules_cache/cache.tgz
|
||||||
# condition: and(succeeded(), eq(variables.NODE_MODULES_RESTORED, 'true'))
|
condition: and(succeeded(), eq(variables.NODE_MODULES_RESTORED, 'true'))
|
||||||
# displayName: Extract node_modules cache
|
displayName: Extract node_modules cache
|
||||||
|
|
||||||
- script: |
|
- script: |
|
||||||
set -e
|
set -e
|
||||||
|
@ -80,13 +80,13 @@ steps:
|
||||||
displayName: Install dependencies
|
displayName: Install dependencies
|
||||||
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
||||||
|
|
||||||
# - script: |
|
- script: |
|
||||||
# set -e
|
set -e
|
||||||
# node build/azure-pipelines/common/listNodeModules.js .build/node_modules_list.txt
|
node build/azure-pipelines/common/listNodeModules.js .build/node_modules_list.txt
|
||||||
# mkdir -p .build/node_modules_cache
|
mkdir -p .build/node_modules_cache
|
||||||
# tar -czf .build/node_modules_cache/cache.tgz --files-from .build/node_modules_list.txt
|
tar -czf .build/node_modules_cache/cache.tgz --files-from .build/node_modules_list.txt
|
||||||
# condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
||||||
# displayName: Create node_modules archive
|
displayName: Create node_modules archive
|
||||||
|
|
||||||
- script: |
|
- script: |
|
||||||
set -e
|
set -e
|
||||||
|
|
|
@ -42,25 +42,25 @@ steps:
|
||||||
exec { git pull --no-rebase https://github.com/$(VSCODE_MIXIN_REPO).git $(node -p "require('./package.json').distro") }
|
exec { git pull --no-rebase https://github.com/$(VSCODE_MIXIN_REPO).git $(node -p "require('./package.json').distro") }
|
||||||
displayName: Merge distro
|
displayName: Merge distro
|
||||||
|
|
||||||
# - powershell: |
|
- powershell: |
|
||||||
# "$(VSCODE_ARCH)" | Out-File -Encoding ascii -NoNewLine .build\arch
|
"$(VSCODE_ARCH)" | Out-File -Encoding ascii -NoNewLine .build\arch
|
||||||
# "$env:ENABLE_TERRAPIN" | Out-File -Encoding ascii -NoNewLine .build\terrapin
|
"$env:ENABLE_TERRAPIN" | Out-File -Encoding ascii -NoNewLine .build\terrapin
|
||||||
# node build/azure-pipelines/common/computeNodeModulesCacheKey.js > .build/yarnlockhash
|
node build/azure-pipelines/common/computeNodeModulesCacheKey.js > .build/yarnlockhash
|
||||||
# displayName: Prepare yarn cache flags
|
displayName: Prepare yarn cache flags
|
||||||
|
|
||||||
# - task: Cache@2
|
- task: Cache@2
|
||||||
# inputs:
|
inputs:
|
||||||
# key: "nodeModules | $(Agent.OS) | .build/arch, .build/terrapin, .build/yarnlockhash"
|
key: "nodeModules | $(Agent.OS) | .build/arch, .build/terrapin, .build/yarnlockhash"
|
||||||
# path: .build/node_modules_cache
|
path: .build/node_modules_cache
|
||||||
# cacheHitVar: NODE_MODULES_RESTORED
|
cacheHitVar: NODE_MODULES_RESTORED
|
||||||
# displayName: Restore node_modules cache
|
displayName: Restore node_modules cache
|
||||||
|
|
||||||
# - powershell: |
|
- powershell: |
|
||||||
# . build/azure-pipelines/win32/exec.ps1
|
. build/azure-pipelines/win32/exec.ps1
|
||||||
# $ErrorActionPreference = "Stop"
|
$ErrorActionPreference = "Stop"
|
||||||
# exec { 7z.exe x .build/node_modules_cache/cache.7z -aos }
|
exec { 7z.exe x .build/node_modules_cache/cache.7z -aos }
|
||||||
# condition: and(succeeded(), eq(variables.NODE_MODULES_RESTORED, 'true'))
|
condition: and(succeeded(), eq(variables.NODE_MODULES_RESTORED, 'true'))
|
||||||
# displayName: Extract node_modules cache
|
displayName: Extract node_modules cache
|
||||||
|
|
||||||
- powershell: |
|
- powershell: |
|
||||||
. build/azure-pipelines/win32/exec.ps1
|
. build/azure-pipelines/win32/exec.ps1
|
||||||
|
@ -84,14 +84,14 @@ steps:
|
||||||
displayName: Install dependencies
|
displayName: Install dependencies
|
||||||
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
||||||
|
|
||||||
# - powershell: |
|
- powershell: |
|
||||||
# . build/azure-pipelines/win32/exec.ps1
|
. build/azure-pipelines/win32/exec.ps1
|
||||||
# $ErrorActionPreference = "Stop"
|
$ErrorActionPreference = "Stop"
|
||||||
# exec { node build/azure-pipelines/common/listNodeModules.js .build/node_modules_list.txt }
|
exec { node build/azure-pipelines/common/listNodeModules.js .build/node_modules_list.txt }
|
||||||
# exec { mkdir -Force .build/node_modules_cache }
|
exec { mkdir -Force .build/node_modules_cache }
|
||||||
# exec { 7z.exe a .build/node_modules_cache/cache.7z -mx3 `@.build/node_modules_list.txt }
|
exec { 7z.exe a .build/node_modules_cache/cache.7z -mx3 `@.build/node_modules_list.txt }
|
||||||
# condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
||||||
# displayName: Create node_modules archive
|
displayName: Create node_modules archive
|
||||||
|
|
||||||
- powershell: |
|
- powershell: |
|
||||||
. build/azure-pipelines/win32/exec.ps1
|
. build/azure-pipelines/win32/exec.ps1
|
||||||
|
@ -150,6 +150,14 @@ steps:
|
||||||
timeoutInMinutes: 7
|
timeoutInMinutes: 7
|
||||||
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'), ne(variables['VSCODE_ARCH'], 'arm64'))
|
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'), ne(variables['VSCODE_ARCH'], 'arm64'))
|
||||||
|
|
||||||
|
- powershell: |
|
||||||
|
. build/azure-pipelines/win32/exec.ps1
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
exec { yarn test-node --build }
|
||||||
|
displayName: Run unit tests (node.js)
|
||||||
|
timeoutInMinutes: 7
|
||||||
|
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'), ne(variables['VSCODE_ARCH'], 'arm64'))
|
||||||
|
|
||||||
- powershell: |
|
- powershell: |
|
||||||
. build/azure-pipelines/win32/exec.ps1
|
. build/azure-pipelines/win32/exec.ps1
|
||||||
$ErrorActionPreference = "Stop"
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
|
@ -209,6 +209,7 @@ exports.watchExtensionMedia = watchExtensionMedia;
|
||||||
|
|
||||||
const compileExtensionMediaBuildTask = task.define('compile-extension-media-build', () => ext.buildExtensionMedia(false, '.build/extensions'));
|
const compileExtensionMediaBuildTask = task.define('compile-extension-media-build', () => ext.buildExtensionMedia(false, '.build/extensions'));
|
||||||
gulp.task(compileExtensionMediaBuildTask);
|
gulp.task(compileExtensionMediaBuildTask);
|
||||||
|
exports.compileExtensionMediaBuildTask = compileExtensionMediaBuildTask;
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ const File = require('vinyl');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const glob = require('glob');
|
const glob = require('glob');
|
||||||
const { compileBuildTask } = require('./gulpfile.compile');
|
const { compileBuildTask } = require('./gulpfile.compile');
|
||||||
const { compileExtensionsBuildTask } = require('./gulpfile.extensions');
|
const { compileExtensionsBuildTask, compileExtensionMediaBuildTask } = require('./gulpfile.extensions');
|
||||||
const { vscodeWebEntryPoints, vscodeWebResourceIncludes, createVSCodeWebFileContentMapper } = require('./gulpfile.vscode.web');
|
const { vscodeWebEntryPoints, vscodeWebResourceIncludes, createVSCodeWebFileContentMapper } = require('./gulpfile.vscode.web');
|
||||||
const cp = require('child_process');
|
const cp = require('child_process');
|
||||||
|
|
||||||
|
@ -381,6 +381,7 @@ function packageTask(type, platform, arch, sourceFolderName, destinationFolderNa
|
||||||
const serverTask = task.define(`vscode-${type}${dashed(platform)}${dashed(arch)}${dashed(minified)}`, task.series(
|
const serverTask = task.define(`vscode-${type}${dashed(platform)}${dashed(arch)}${dashed(minified)}`, task.series(
|
||||||
compileBuildTask,
|
compileBuildTask,
|
||||||
compileExtensionsBuildTask,
|
compileExtensionsBuildTask,
|
||||||
|
compileExtensionMediaBuildTask,
|
||||||
minified ? minifyTask : optimizeTask,
|
minified ? minifyTask : optimizeTask,
|
||||||
serverTaskCI
|
serverTaskCI
|
||||||
));
|
));
|
||||||
|
|
|
@ -31,7 +31,7 @@ const { config } = require('./lib/electron');
|
||||||
const createAsar = require('./lib/asar').createAsar;
|
const createAsar = require('./lib/asar').createAsar;
|
||||||
const minimist = require('minimist');
|
const minimist = require('minimist');
|
||||||
const { compileBuildTask } = require('./gulpfile.compile');
|
const { compileBuildTask } = require('./gulpfile.compile');
|
||||||
const { compileExtensionsBuildTask } = require('./gulpfile.extensions');
|
const { compileExtensionsBuildTask, compileExtensionMediaBuildTask } = require('./gulpfile.extensions');
|
||||||
const { getSettingsSearchBuildId, shouldSetupSettingsSearch } = require('./azure-pipelines/upload-configuration');
|
const { getSettingsSearchBuildId, shouldSetupSettingsSearch } = require('./azure-pipelines/upload-configuration');
|
||||||
|
|
||||||
// Build
|
// Build
|
||||||
|
@ -379,6 +379,7 @@ BUILD_TARGETS.forEach(buildTarget => {
|
||||||
const vscodeTask = task.define(`vscode${dashed(platform)}${dashed(arch)}${dashed(minified)}`, task.series(
|
const vscodeTask = task.define(`vscode${dashed(platform)}${dashed(arch)}${dashed(minified)}`, task.series(
|
||||||
compileBuildTask,
|
compileBuildTask,
|
||||||
compileExtensionsBuildTask,
|
compileExtensionsBuildTask,
|
||||||
|
compileExtensionMediaBuildTask,
|
||||||
minified ? minifyVSCodeTask : optimizeVSCodeTask,
|
minified ? minifyVSCodeTask : optimizeVSCodeTask,
|
||||||
vscodeTaskCI
|
vscodeTaskCI
|
||||||
));
|
));
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "code-oss-dev",
|
"name": "code-oss-dev",
|
||||||
"version": "1.63.0",
|
"version": "1.63.0",
|
||||||
"distro": "f5a2c7f01629f6d3c0dc65e3fbb3818033206bf2",
|
"distro": "1aa3ab55b3cceca22ca6d647dc0095d562d23c8d",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Microsoft Corporation"
|
"name": "Microsoft Corporation"
|
||||||
},
|
},
|
||||||
|
@ -11,6 +11,7 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "mocha",
|
"test": "mocha",
|
||||||
"test-browser": "node test/unit/browser/index.js",
|
"test-browser": "node test/unit/browser/index.js",
|
||||||
|
"test-node": "mocha test/unit/node/index.js --delay --ui=tdd --exit",
|
||||||
"preinstall": "node build/npm/preinstall.js",
|
"preinstall": "node build/npm/preinstall.js",
|
||||||
"postinstall": "node build/npm/postinstall.js",
|
"postinstall": "node build/npm/postinstall.js",
|
||||||
"compile": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js compile",
|
"compile": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js compile",
|
||||||
|
@ -27,7 +28,6 @@
|
||||||
"watch-extensions": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js watch-extensions watch-extension-media",
|
"watch-extensions": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js watch-extensions watch-extension-media",
|
||||||
"watch-extensionsd": "deemon yarn watch-extensions",
|
"watch-extensionsd": "deemon yarn watch-extensions",
|
||||||
"kill-watch-extensionsd": "deemon --kill yarn watch-extensions",
|
"kill-watch-extensionsd": "deemon --kill yarn watch-extensions",
|
||||||
"mocha": "mocha test/unit/node/all.js --delay --ui=tdd",
|
|
||||||
"precommit": "node build/hygiene.js",
|
"precommit": "node build/hygiene.js",
|
||||||
"gulp": "node --max_old_space_size=8192 ./node_modules/gulp/bin/gulp.js",
|
"gulp": "node --max_old_space_size=8192 ./node_modules/gulp/bin/gulp.js",
|
||||||
"electron": "node build/lib/electron",
|
"electron": "node build/lib/electron",
|
||||||
|
@ -169,7 +169,6 @@
|
||||||
"istanbul-lib-report": "^3.0.0",
|
"istanbul-lib-report": "^3.0.0",
|
||||||
"istanbul-lib-source-maps": "^4.0.0",
|
"istanbul-lib-source-maps": "^4.0.0",
|
||||||
"istanbul-reports": "^3.0.0",
|
"istanbul-reports": "^3.0.0",
|
||||||
"jsdom-no-contextify": "^3.1.0",
|
|
||||||
"lazy.js": "^0.4.2",
|
"lazy.js": "^0.4.2",
|
||||||
"merge-options": "^1.0.1",
|
"merge-options": "^1.0.1",
|
||||||
"mime": "^1.4.1",
|
"mime": "^1.4.1",
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
"licenseName": "MIT",
|
"licenseName": "MIT",
|
||||||
"licenseUrl": "https://github.com/microsoft/vscode/blob/main/LICENSE.txt",
|
"licenseUrl": "https://github.com/microsoft/vscode/blob/main/LICENSE.txt",
|
||||||
"serverGreeting": [],
|
"serverGreeting": [],
|
||||||
|
"serverLicense": [],
|
||||||
|
"serverLicensePrompt": "",
|
||||||
"win32DirName": "Microsoft Code OSS",
|
"win32DirName": "Microsoft Code OSS",
|
||||||
"win32NameVersion": "Microsoft Code OSS",
|
"win32NameVersion": "Microsoft Code OSS",
|
||||||
"win32RegValueName": "CodeOSS",
|
"win32RegValueName": "CodeOSS",
|
||||||
|
|
|
@ -939,9 +939,15 @@ class FocusTracker extends Disposable implements IFocusTracker {
|
||||||
|
|
||||||
private _refreshStateHandler: () => void;
|
private _refreshStateHandler: () => void;
|
||||||
|
|
||||||
|
private static hasFocusWithin(element: HTMLElement): boolean {
|
||||||
|
const shadowRoot = getShadowRoot(element);
|
||||||
|
const activeElement = (shadowRoot ? shadowRoot.activeElement : document.activeElement);
|
||||||
|
return isAncestor(activeElement, element);
|
||||||
|
}
|
||||||
|
|
||||||
constructor(element: HTMLElement | Window) {
|
constructor(element: HTMLElement | Window) {
|
||||||
super();
|
super();
|
||||||
let hasFocus = isAncestor(document.activeElement, <HTMLElement>element);
|
let hasFocus = FocusTracker.hasFocusWithin(<HTMLElement>element);
|
||||||
let loosingFocus = false;
|
let loosingFocus = false;
|
||||||
|
|
||||||
const onFocus = () => {
|
const onFocus = () => {
|
||||||
|
@ -966,7 +972,7 @@ class FocusTracker extends Disposable implements IFocusTracker {
|
||||||
};
|
};
|
||||||
|
|
||||||
this._refreshStateHandler = () => {
|
this._refreshStateHandler = () => {
|
||||||
let currentNodeHasFocus = isAncestor(document.activeElement, <HTMLElement>element);
|
let currentNodeHasFocus = FocusTracker.hasFocusWithin(<HTMLElement>element);
|
||||||
if (currentNodeHasFocus !== hasFocus) {
|
if (currentNodeHasFocus !== hasFocus) {
|
||||||
if (hasFocus) {
|
if (hasFocus) {
|
||||||
onBlur();
|
onBlur();
|
||||||
|
|
|
@ -178,10 +178,7 @@ export class ActionWithDropdownActionViewItem extends ActionViewItem {
|
||||||
const menuActionsProvider = {
|
const menuActionsProvider = {
|
||||||
getActions: () => {
|
getActions: () => {
|
||||||
const actionsProvider = (<IActionWithDropdownActionViewItemOptions>this.options).menuActionsOrProvider;
|
const actionsProvider = (<IActionWithDropdownActionViewItemOptions>this.options).menuActionsOrProvider;
|
||||||
return [this._action, ...(Array.isArray(actionsProvider)
|
return Array.isArray(actionsProvider) ? actionsProvider : (actionsProvider as IActionProvider).getActions(); // TODO: microsoft/TypeScript#42768
|
||||||
? actionsProvider
|
|
||||||
: (actionsProvider as IActionProvider).getActions()) // TODO: microsoft/TypeScript#42768
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
this.dropdownMenuActionViewItem = new DropdownMenuActionViewItem(this._register(new Action('dropdownAction', undefined)), menuActionsProvider, this.contextMenuProvider, { classNames: ['dropdown', ...Codicon.dropDownButton.classNamesArray, ...(<IActionWithDropdownActionViewItemOptions>this.options).menuActionClassNames || []] });
|
this.dropdownMenuActionViewItem = new DropdownMenuActionViewItem(this._register(new Action('dropdownAction', undefined)), menuActionsProvider, this.contextMenuProvider, { classNames: ['dropdown', ...Codicon.dropDownButton.classNamesArray, ...(<IActionWithDropdownActionViewItemOptions>this.options).menuActionClassNames || []] });
|
||||||
|
|
|
@ -1337,3 +1337,281 @@ export namespace Promises {
|
||||||
}
|
}
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
|
//#region
|
||||||
|
|
||||||
|
const enum AsyncIterableSourceState {
|
||||||
|
Initial,
|
||||||
|
DoneOK,
|
||||||
|
DoneError,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object that allows to emit async values asynchronously or bring the iterable to an error state using `reject()`.
|
||||||
|
* This emitter is valid only for the duration of the executor (until the promise returned by the executor settles).
|
||||||
|
*/
|
||||||
|
export interface AsyncIterableEmitter<T> {
|
||||||
|
/**
|
||||||
|
* The value will be appended at the end.
|
||||||
|
*
|
||||||
|
* **NOTE** If `reject()` has already been called, this method has no effect.
|
||||||
|
*/
|
||||||
|
emitOne(value: T): void;
|
||||||
|
/**
|
||||||
|
* The values will be appended at the end.
|
||||||
|
*
|
||||||
|
* **NOTE** If `reject()` has already been called, this method has no effect.
|
||||||
|
*/
|
||||||
|
emitMany(values: T[]): void;
|
||||||
|
/**
|
||||||
|
* Writing an error will permanently invalidate this iterable.
|
||||||
|
* The current users will receive an error thrown, as will all future users.
|
||||||
|
*
|
||||||
|
* **NOTE** If `reject()` have already been called, this method has no effect.
|
||||||
|
*/
|
||||||
|
reject(error: Error): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An executor for the `AsyncIterableObject` that has access to an emitter.
|
||||||
|
*/
|
||||||
|
export interface AyncIterableExecutor<T> {
|
||||||
|
/**
|
||||||
|
* @param emitter An object that allows to emit async values valid only for the duration of the executor.
|
||||||
|
*/
|
||||||
|
(emitter: AsyncIterableEmitter<T>): void | Promise<void>
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A rich implementation for an `AsyncIterable<T>`.
|
||||||
|
*/
|
||||||
|
export class AsyncIterableObject<T> implements AsyncIterable<T> {
|
||||||
|
|
||||||
|
public static fromArray<T>(items: T[]): AsyncIterableObject<T> {
|
||||||
|
return new AsyncIterableObject<T>((writer) => {
|
||||||
|
writer.emitMany(items);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static fromPromise<T>(promise: Promise<T[]>): AsyncIterableObject<T> {
|
||||||
|
return new AsyncIterableObject<T>(async (emitter) => {
|
||||||
|
emitter.emitMany(await promise);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static fromPromises<T>(promises: Promise<T>[]): AsyncIterableObject<T> {
|
||||||
|
return new AsyncIterableObject<T>(async (emitter) => {
|
||||||
|
await Promise.all(promises.map(async (p) => emitter.emitOne(await p)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static merge<T>(iterables: AsyncIterable<T>[]): AsyncIterableObject<T> {
|
||||||
|
return new AsyncIterableObject(async (emitter) => {
|
||||||
|
await Promise.all(iterables.map(async (iterable) => {
|
||||||
|
for await(const item of iterable) {
|
||||||
|
emitter.emitOne(item);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static EMPTY = AsyncIterableObject.fromArray<any>([]);
|
||||||
|
|
||||||
|
private _state: AsyncIterableSourceState;
|
||||||
|
private _results: T[];
|
||||||
|
private _error: Error | null;
|
||||||
|
private readonly _onStateChanged: Emitter<void>;
|
||||||
|
|
||||||
|
constructor(executor: AyncIterableExecutor<T>) {
|
||||||
|
this._state = AsyncIterableSourceState.Initial;
|
||||||
|
this._results = [];
|
||||||
|
this._error = null;
|
||||||
|
this._onStateChanged = new Emitter<void>();
|
||||||
|
|
||||||
|
queueMicrotask(async () => {
|
||||||
|
const writer: AsyncIterableEmitter<T> = {
|
||||||
|
emitOne: (item) => this.emitOne(item),
|
||||||
|
emitMany: (items) => this.emitMany(items),
|
||||||
|
reject: (error) => this.reject(error)
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
await Promise.resolve(executor(writer));
|
||||||
|
this.resolve();
|
||||||
|
} catch (err) {
|
||||||
|
this.reject(err);
|
||||||
|
} finally {
|
||||||
|
writer.emitOne = undefined!;
|
||||||
|
writer.emitMany = undefined!;
|
||||||
|
writer.reject = undefined!;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Symbol.asyncIterator](): AsyncIterator<T, undefined, undefined> {
|
||||||
|
let i = 0;
|
||||||
|
return {
|
||||||
|
next: async () => {
|
||||||
|
do {
|
||||||
|
if (this._state === AsyncIterableSourceState.DoneError) {
|
||||||
|
throw this._error;
|
||||||
|
}
|
||||||
|
if (i < this._results.length) {
|
||||||
|
return { done: false, value: this._results[i++] };
|
||||||
|
}
|
||||||
|
if (this._state === AsyncIterableSourceState.DoneOK) {
|
||||||
|
return { done: true, value: undefined };
|
||||||
|
}
|
||||||
|
await Event.toPromise(this._onStateChanged.event);
|
||||||
|
} while (true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static map<T, R>(iterable: AsyncIterable<T>, mapFn: (item: T) => R): AsyncIterableObject<R> {
|
||||||
|
return new AsyncIterableObject<R>(async (emitter) => {
|
||||||
|
for await(const item of iterable) {
|
||||||
|
emitter.emitOne(mapFn(item));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public map<R>(mapFn: (item: T) => R): AsyncIterableObject<R> {
|
||||||
|
return AsyncIterableObject.map(this, mapFn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static filter<T>(iterable: AsyncIterable<T>, filterFn: (item: T) => boolean): AsyncIterableObject<T> {
|
||||||
|
return new AsyncIterableObject<T>(async (emitter) => {
|
||||||
|
for await(const item of iterable) {
|
||||||
|
if (filterFn(item)) {
|
||||||
|
emitter.emitOne(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public filter(filterFn: (item: T) => boolean): AsyncIterableObject<T> {
|
||||||
|
return AsyncIterableObject.filter(this, filterFn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static coalesce<T>(iterable: AsyncIterable<T | undefined | null>): AsyncIterableObject<T> {
|
||||||
|
return <AsyncIterableObject<T>>AsyncIterableObject.filter(iterable, item => !!item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public coalesce(): AsyncIterableObject<NonNullable<T>> {
|
||||||
|
return AsyncIterableObject.coalesce(this) as AsyncIterableObject<NonNullable<T>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async toPromise<T>(iterable: AsyncIterable<T>): Promise<T[]> {
|
||||||
|
const result: T[] = [];
|
||||||
|
for await (const item of iterable) {
|
||||||
|
result.push(item);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public toPromise(): Promise<T[]> {
|
||||||
|
return AsyncIterableObject.toPromise(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The value will be appended at the end.
|
||||||
|
*
|
||||||
|
* **NOTE** If `resolve()` or `reject()` have already been called, this method has no effect.
|
||||||
|
*/
|
||||||
|
private emitOne(value: T): void {
|
||||||
|
if (this._state !== AsyncIterableSourceState.Initial) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// it is important to add new values at the end,
|
||||||
|
// as we may have iterators already running on the array
|
||||||
|
this._results.push(value);
|
||||||
|
this._onStateChanged.fire();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The values will be appended at the end.
|
||||||
|
*
|
||||||
|
* **NOTE** If `resolve()` or `reject()` have already been called, this method has no effect.
|
||||||
|
*/
|
||||||
|
private emitMany(values: T[]): void {
|
||||||
|
if (this._state !== AsyncIterableSourceState.Initial) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// it is important to add new values at the end,
|
||||||
|
// as we may have iterators already running on the array
|
||||||
|
this._results = this._results.concat(values);
|
||||||
|
this._onStateChanged.fire();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calling `resolve()` will mark the result array as complete.
|
||||||
|
*
|
||||||
|
* **NOTE** `resolve()` must be called, otherwise all consumers of this iterable will hang indefinitely, similar to a non-resolved promise.
|
||||||
|
* **NOTE** If `resolve()` or `reject()` have already been called, this method has no effect.
|
||||||
|
*/
|
||||||
|
private resolve(): void {
|
||||||
|
if (this._state !== AsyncIterableSourceState.Initial) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._state = AsyncIterableSourceState.DoneOK;
|
||||||
|
this._onStateChanged.fire();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writing an error will permanently invalidate this iterable.
|
||||||
|
* The current users will receive an error thrown, as will all future users.
|
||||||
|
*
|
||||||
|
* **NOTE** If `resolve()` or `reject()` have already been called, this method has no effect.
|
||||||
|
*/
|
||||||
|
private reject(error: Error) {
|
||||||
|
if (this._state !== AsyncIterableSourceState.Initial) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._state = AsyncIterableSourceState.DoneError;
|
||||||
|
this._error = error;
|
||||||
|
this._onStateChanged.fire();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CancelableAsyncIterableObject<T> extends AsyncIterableObject<T> {
|
||||||
|
constructor(
|
||||||
|
private readonly _source: CancellationTokenSource,
|
||||||
|
executor: AyncIterableExecutor<T>
|
||||||
|
) {
|
||||||
|
super(executor);
|
||||||
|
}
|
||||||
|
|
||||||
|
cancel(): void {
|
||||||
|
this._source.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createCancelableAsyncIterable<T>(callback: (token: CancellationToken) => AsyncIterable<T>): CancelableAsyncIterableObject<T> {
|
||||||
|
const source = new CancellationTokenSource();
|
||||||
|
const innerIterable = callback(source.token);
|
||||||
|
|
||||||
|
return new CancelableAsyncIterableObject<T>(source, async (emitter) => {
|
||||||
|
const subscription = source.token.onCancellationRequested(() => {
|
||||||
|
subscription.dispose();
|
||||||
|
source.dispose();
|
||||||
|
emitter.reject(canceled());
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
for await (const item of innerIterable) {
|
||||||
|
if (source.token.isCancellationRequested) {
|
||||||
|
// canceled in the meantime
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
emitter.emitOne(item);
|
||||||
|
}
|
||||||
|
subscription.dispose();
|
||||||
|
source.dispose();
|
||||||
|
} catch (err) {
|
||||||
|
subscription.dispose();
|
||||||
|
source.dispose();
|
||||||
|
emitter.reject(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
|
@ -120,6 +120,8 @@ export interface IProductConfiguration {
|
||||||
readonly showTelemetryOptOut?: boolean;
|
readonly showTelemetryOptOut?: boolean;
|
||||||
|
|
||||||
readonly serverGreeting: string[];
|
readonly serverGreeting: string[];
|
||||||
|
readonly serverLicense?: string[];
|
||||||
|
readonly serverLicensePrompt?: string;
|
||||||
|
|
||||||
readonly npsSurveyUrl?: string;
|
readonly npsSurveyUrl?: string;
|
||||||
readonly cesSurveyUrl?: string;
|
readonly cesSurveyUrl?: string;
|
||||||
|
|
|
@ -48,7 +48,6 @@ suite('Event', function () {
|
||||||
|
|
||||||
let doc = new Samples.Document3();
|
let doc = new Samples.Document3();
|
||||||
|
|
||||||
document.createElement('div').onclick = function () { };
|
|
||||||
let subscription = doc.onDidChange(counter.onEvent, counter);
|
let subscription = doc.onDidChange(counter.onEvent, counter);
|
||||||
|
|
||||||
doc.setText('far');
|
doc.setText('far');
|
||||||
|
|
|
@ -2516,7 +2516,7 @@ export class TextModel extends Disposable implements model.ITextModel, IDecorati
|
||||||
renderHorizontalEndLineAtTheBottom = true;
|
renderHorizontalEndLineAtTheBottom = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: Consider indentation when computing guideVisibleColumn
|
|
||||||
const start = pair.openingBracketRange.getStartPosition();
|
const start = pair.openingBracketRange.getStartPosition();
|
||||||
const end = (pair.closingBracketRange?.getStartPosition() ?? pair.range.getEndPosition());
|
const end = (pair.closingBracketRange?.getStartPosition() ?? pair.range.getEndPosition());
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { AsyncIterableObject } from 'vs/base/common/async';
|
||||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||||
import { Color, RGBA } from 'vs/base/common/color';
|
import { Color, RGBA } from 'vs/base/common/color';
|
||||||
import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
|
import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
|
||||||
|
@ -54,7 +55,11 @@ export class ColorHoverParticipant implements IEditorHoverParticipant<ColorHover
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public async computeAsync(anchor: HoverAnchor, lineDecorations: IModelDecoration[], token: CancellationToken): Promise<ColorHover[]> {
|
public computeAsync(anchor: HoverAnchor, lineDecorations: IModelDecoration[], token: CancellationToken): AsyncIterableObject<ColorHover> {
|
||||||
|
return AsyncIterableObject.fromPromise(this._computeAsync(anchor, lineDecorations, token));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _computeAsync(anchor: HoverAnchor, lineDecorations: IModelDecoration[], token: CancellationToken): Promise<ColorHover[]> {
|
||||||
if (!this._editor.hasModel()) {
|
if (!this._editor.hasModel()) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,31 +3,45 @@
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { coalesce } from 'vs/base/common/arrays';
|
import { AsyncIterableObject } from 'vs/base/common/async';
|
||||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||||
import { onUnexpectedExternalError } from 'vs/base/common/errors';
|
import { onUnexpectedExternalError } from 'vs/base/common/errors';
|
||||||
import { registerModelAndPositionCommand } from 'vs/editor/browser/editorExtensions';
|
import { registerModelAndPositionCommand } from 'vs/editor/browser/editorExtensions';
|
||||||
import { Position } from 'vs/editor/common/core/position';
|
import { Position } from 'vs/editor/common/core/position';
|
||||||
import { ITextModel } from 'vs/editor/common/model';
|
import { ITextModel } from 'vs/editor/common/model';
|
||||||
import { Hover, HoverProviderRegistry } from 'vs/editor/common/modes';
|
import { Hover, HoverProvider, HoverProviderRegistry } from 'vs/editor/common/modes';
|
||||||
|
|
||||||
export function getHover(model: ITextModel, position: Position, token: CancellationToken): Promise<Hover[]> {
|
export class HoverProviderResult {
|
||||||
|
constructor(
|
||||||
const supports = HoverProviderRegistry.ordered(model);
|
public readonly provider: HoverProvider,
|
||||||
|
public readonly hover: Hover,
|
||||||
const promises = supports.map(support => {
|
public readonly ordinal: number
|
||||||
return Promise.resolve(support.provideHover(model, position, token)).then(hover => {
|
) {}
|
||||||
return hover && isValid(hover) ? hover : undefined;
|
|
||||||
}, err => {
|
|
||||||
onUnexpectedExternalError(err);
|
|
||||||
return undefined;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return Promise.all(promises).then(coalesce);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
registerModelAndPositionCommand('_executeHoverProvider', (model, position) => getHover(model, position, CancellationToken.None));
|
async function executeProvider(provider: HoverProvider, ordinal: number, model: ITextModel, position: Position, token: CancellationToken): Promise<HoverProviderResult | undefined> {
|
||||||
|
try {
|
||||||
|
const result = await Promise.resolve(provider.provideHover(model, position, token));
|
||||||
|
if (result && isValid(result)) {
|
||||||
|
return new HoverProviderResult(provider, result, ordinal);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
onUnexpectedExternalError(err);
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getHover(model: ITextModel, position: Position, token: CancellationToken): AsyncIterableObject<HoverProviderResult> {
|
||||||
|
const providers = HoverProviderRegistry.ordered(model);
|
||||||
|
const promises = providers.map((provider, index) => executeProvider(provider, index, model, position, token));
|
||||||
|
return AsyncIterableObject.fromPromises(promises).coalesce();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getHoverPromise(model: ITextModel, position: Position, token: CancellationToken): Promise<Hover[]> {
|
||||||
|
return getHover(model, position, token).map(item => item.hover).toPromise();
|
||||||
|
}
|
||||||
|
|
||||||
|
registerModelAndPositionCommand('_executeHoverProvider', (model, position) => getHoverPromise(model, position, CancellationToken.None));
|
||||||
|
|
||||||
function isValid(result: Hover) {
|
function isValid(result: Hover) {
|
||||||
const hasRange = (typeof result.range !== 'undefined');
|
const hasRange = (typeof result.range !== 'undefined');
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { CancelablePromise, createCancelablePromise, RunOnceScheduler } from 'vs/base/common/async';
|
import { AsyncIterableObject, CancelableAsyncIterableObject, createCancelableAsyncIterable, RunOnceScheduler } from 'vs/base/common/async';
|
||||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||||
|
|
||||||
|
@ -12,24 +12,24 @@ export interface IHoverComputer<Result> {
|
||||||
/**
|
/**
|
||||||
* This is called after half the hover time
|
* This is called after half the hover time
|
||||||
*/
|
*/
|
||||||
computeAsync?: (token: CancellationToken) => Promise<Result>;
|
computeAsync?: (token: CancellationToken) => AsyncIterableObject<Result>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is called after all the hover time
|
* This is called after all the hover time
|
||||||
*/
|
*/
|
||||||
computeSync?: () => Result;
|
computeSync?: () => Result[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is called whenever one of the compute* methods returns a truey value
|
* This is called whenever one of the compute* methods returns a truey value
|
||||||
*/
|
*/
|
||||||
onResult: (result: Result, isFromSynchronousComputation: boolean) => void;
|
onResult: (result: Result[], isFromSynchronousComputation: boolean) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is what will be sent as progress/complete to the computation promise
|
* This is what will be sent as progress/complete to the computation promise
|
||||||
*/
|
*/
|
||||||
getResult: () => Result;
|
getResult: () => Result[];
|
||||||
|
|
||||||
getResultWithLoadingMessage: () => Result;
|
getResultWithLoadingMessage: () => Result[];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +37,8 @@ const enum ComputeHoverOperationState {
|
||||||
IDLE = 0,
|
IDLE = 0,
|
||||||
FIRST_WAIT = 1,
|
FIRST_WAIT = 1,
|
||||||
SECOND_WAIT = 2,
|
SECOND_WAIT = 2,
|
||||||
WAITING_FOR_ASYNC_COMPUTATION = 3
|
WAITING_FOR_ASYNC_COMPUTATION = 3,
|
||||||
|
WAITING_FOR_ASYNC_COMPUTATION_SHOWING_LOADING = 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enum HoverStartMode {
|
export const enum HoverStartMode {
|
||||||
|
@ -54,14 +55,14 @@ export class HoverOperation<Result> {
|
||||||
private readonly _firstWaitScheduler: RunOnceScheduler;
|
private readonly _firstWaitScheduler: RunOnceScheduler;
|
||||||
private readonly _secondWaitScheduler: RunOnceScheduler;
|
private readonly _secondWaitScheduler: RunOnceScheduler;
|
||||||
private readonly _loadingMessageScheduler: RunOnceScheduler;
|
private readonly _loadingMessageScheduler: RunOnceScheduler;
|
||||||
private _asyncComputationPromise: CancelablePromise<Result> | null;
|
private _asyncIterable: CancelableAsyncIterableObject<Result> | null;
|
||||||
private _asyncComputationPromiseDone: boolean;
|
private _asyncIterableDone: boolean;
|
||||||
|
|
||||||
private readonly _completeCallback: (r: Result) => void;
|
private readonly _completeCallback: (r: Result[]) => void;
|
||||||
private readonly _errorCallback: ((err: any) => void) | null | undefined;
|
private readonly _errorCallback: ((err: any) => void) | null | undefined;
|
||||||
private readonly _progressCallback: (progress: any) => void;
|
private readonly _progressCallback: (progress: any) => void;
|
||||||
|
|
||||||
constructor(computer: IHoverComputer<Result>, success: (r: Result) => void, error: ((err: any) => void) | null | undefined, progress: (progress: any) => void, hoverTime: number) {
|
constructor(computer: IHoverComputer<Result>, success: (r: Result[]) => void, error: ((err: any) => void) | null | undefined, progress: (progress: any) => void, hoverTime: number) {
|
||||||
this._computer = computer;
|
this._computer = computer;
|
||||||
this._state = ComputeHoverOperationState.IDLE;
|
this._state = ComputeHoverOperationState.IDLE;
|
||||||
this._hoverTime = hoverTime;
|
this._hoverTime = hoverTime;
|
||||||
|
@ -70,8 +71,8 @@ export class HoverOperation<Result> {
|
||||||
this._secondWaitScheduler = new RunOnceScheduler(() => this._triggerSyncComputation(), 0);
|
this._secondWaitScheduler = new RunOnceScheduler(() => this._triggerSyncComputation(), 0);
|
||||||
this._loadingMessageScheduler = new RunOnceScheduler(() => this._showLoadingMessage(), 0);
|
this._loadingMessageScheduler = new RunOnceScheduler(() => this._showLoadingMessage(), 0);
|
||||||
|
|
||||||
this._asyncComputationPromise = null;
|
this._asyncIterable = null;
|
||||||
this._asyncComputationPromiseDone = false;
|
this._asyncIterableDone = false;
|
||||||
|
|
||||||
this._completeCallback = success;
|
this._completeCallback = success;
|
||||||
this._errorCallback = error;
|
this._errorCallback = error;
|
||||||
|
@ -99,15 +100,26 @@ export class HoverOperation<Result> {
|
||||||
this._secondWaitScheduler.schedule(this._secondWaitTime());
|
this._secondWaitScheduler.schedule(this._secondWaitTime());
|
||||||
|
|
||||||
if (this._computer.computeAsync) {
|
if (this._computer.computeAsync) {
|
||||||
this._asyncComputationPromiseDone = false;
|
this._asyncIterableDone = false;
|
||||||
this._asyncComputationPromise = createCancelablePromise(token => this._computer.computeAsync!(token));
|
this._asyncIterable = createCancelableAsyncIterable(token => this._computer.computeAsync!(token));
|
||||||
this._asyncComputationPromise.then((asyncResult: Result) => {
|
|
||||||
this._asyncComputationPromiseDone = true;
|
(async () => {
|
||||||
this._withAsyncResult(asyncResult);
|
try {
|
||||||
}, (e) => this._onError(e));
|
for await (const item of this._asyncIterable!) {
|
||||||
|
if (item) {
|
||||||
|
this._computer.onResult([item], false);
|
||||||
|
this._onProgress();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._asyncIterableDone = true;
|
||||||
|
this._withAsyncResult();
|
||||||
|
} catch (e) {
|
||||||
|
this._onError(e);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
this._asyncComputationPromiseDone = true;
|
this._asyncIterableDone = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,34 +128,31 @@ export class HoverOperation<Result> {
|
||||||
this._computer.onResult(this._computer.computeSync(), true);
|
this._computer.onResult(this._computer.computeSync(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._asyncComputationPromiseDone) {
|
if (this._asyncIterableDone) {
|
||||||
this._state = ComputeHoverOperationState.IDLE;
|
this._state = ComputeHoverOperationState.IDLE;
|
||||||
this._onComplete(this._computer.getResult());
|
this._onComplete();
|
||||||
} else {
|
} else {
|
||||||
this._state = ComputeHoverOperationState.WAITING_FOR_ASYNC_COMPUTATION;
|
this._state = ComputeHoverOperationState.WAITING_FOR_ASYNC_COMPUTATION;
|
||||||
this._onProgress(this._computer.getResult());
|
this._onProgress();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _showLoadingMessage(): void {
|
private _showLoadingMessage(): void {
|
||||||
if (this._state === ComputeHoverOperationState.WAITING_FOR_ASYNC_COMPUTATION) {
|
if (this._state === ComputeHoverOperationState.WAITING_FOR_ASYNC_COMPUTATION) {
|
||||||
this._onProgress(this._computer.getResultWithLoadingMessage());
|
this._state = ComputeHoverOperationState.WAITING_FOR_ASYNC_COMPUTATION_SHOWING_LOADING;
|
||||||
|
this._onProgress();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _withAsyncResult(asyncResult: Result): void {
|
private _withAsyncResult(): void {
|
||||||
if (asyncResult) {
|
if (this._state === ComputeHoverOperationState.WAITING_FOR_ASYNC_COMPUTATION || this._state === ComputeHoverOperationState.WAITING_FOR_ASYNC_COMPUTATION_SHOWING_LOADING) {
|
||||||
this._computer.onResult(asyncResult, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._state === ComputeHoverOperationState.WAITING_FOR_ASYNC_COMPUTATION) {
|
|
||||||
this._state = ComputeHoverOperationState.IDLE;
|
this._state = ComputeHoverOperationState.IDLE;
|
||||||
this._onComplete(this._computer.getResult());
|
this._onComplete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _onComplete(value: Result): void {
|
private _onComplete(): void {
|
||||||
this._completeCallback(value);
|
this._completeCallback(this._computer.getResult());
|
||||||
}
|
}
|
||||||
|
|
||||||
private _onError(error: any): void {
|
private _onError(error: any): void {
|
||||||
|
@ -154,8 +163,12 @@ export class HoverOperation<Result> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _onProgress(value: Result): void {
|
private _onProgress(): void {
|
||||||
this._progressCallback(value);
|
if (this._state === ComputeHoverOperationState.WAITING_FOR_ASYNC_COMPUTATION_SHOWING_LOADING) {
|
||||||
|
this._progressCallback(this._computer.getResultWithLoadingMessage());
|
||||||
|
} else {
|
||||||
|
this._progressCallback(this._computer.getResult());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public start(mode: HoverStartMode): void {
|
public start(mode: HoverStartMode): void {
|
||||||
|
@ -181,22 +194,12 @@ export class HoverOperation<Result> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public cancel(): void {
|
public cancel(): void {
|
||||||
|
this._firstWaitScheduler.cancel();
|
||||||
|
this._secondWaitScheduler.cancel();
|
||||||
this._loadingMessageScheduler.cancel();
|
this._loadingMessageScheduler.cancel();
|
||||||
if (this._state === ComputeHoverOperationState.FIRST_WAIT) {
|
if (this._asyncIterable) {
|
||||||
this._firstWaitScheduler.cancel();
|
this._asyncIterable.cancel();
|
||||||
}
|
this._asyncIterable = null;
|
||||||
if (this._state === ComputeHoverOperationState.SECOND_WAIT) {
|
|
||||||
this._secondWaitScheduler.cancel();
|
|
||||||
if (this._asyncComputationPromise) {
|
|
||||||
this._asyncComputationPromise.cancel();
|
|
||||||
this._asyncComputationPromise = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (this._state === ComputeHoverOperationState.WAITING_FOR_ASYNC_COMPUTATION) {
|
|
||||||
if (this._asyncComputationPromise) {
|
|
||||||
this._asyncComputationPromise.cancel();
|
|
||||||
this._asyncComputationPromise = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
this._state = ComputeHoverOperationState.IDLE;
|
this._state = ComputeHoverOperationState.IDLE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { AsyncIterableObject } from 'vs/base/common/async';
|
||||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||||
import { IEditorMouseEvent } from 'vs/editor/browser/editorBrowser';
|
import { IEditorMouseEvent } from 'vs/editor/browser/editorBrowser';
|
||||||
|
@ -85,7 +86,7 @@ export interface IEditorHoverAction {
|
||||||
export interface IEditorHoverParticipant<T extends IHoverPart = IHoverPart> {
|
export interface IEditorHoverParticipant<T extends IHoverPart = IHoverPart> {
|
||||||
suggestHoverAnchor?(mouseEvent: IEditorMouseEvent): HoverAnchor | null;
|
suggestHoverAnchor?(mouseEvent: IEditorMouseEvent): HoverAnchor | null;
|
||||||
computeSync(anchor: HoverAnchor, lineDecorations: IModelDecoration[]): T[];
|
computeSync(anchor: HoverAnchor, lineDecorations: IModelDecoration[]): T[];
|
||||||
computeAsync?(anchor: HoverAnchor, lineDecorations: IModelDecoration[], token: CancellationToken): Promise<T[]>;
|
computeAsync?(anchor: HoverAnchor, lineDecorations: IModelDecoration[], token: CancellationToken): AsyncIterableObject<T>;
|
||||||
createLoadingMessage?(anchor: HoverAnchor): T | null;
|
createLoadingMessage?(anchor: HoverAnchor): T | null;
|
||||||
renderHoverParts(hoverParts: T[], fragment: DocumentFragment, statusBar: IEditorHoverStatusBar): IDisposable;
|
renderHoverParts(hoverParts: T[], fragment: DocumentFragment, statusBar: IEditorHoverStatusBar): IDisposable;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
import * as dom from 'vs/base/browser/dom';
|
import * as dom from 'vs/base/browser/dom';
|
||||||
import { asArray } from 'vs/base/common/arrays';
|
import { asArray } from 'vs/base/common/arrays';
|
||||||
|
import { AsyncIterableObject } from 'vs/base/common/async';
|
||||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||||
import { IMarkdownString, isEmptyMarkdownString, MarkdownString } from 'vs/base/common/htmlContent';
|
import { IMarkdownString, isEmptyMarkdownString, MarkdownString } from 'vs/base/common/htmlContent';
|
||||||
import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
|
import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
|
||||||
|
@ -28,7 +29,8 @@ export class MarkdownHover implements IHoverPart {
|
||||||
constructor(
|
constructor(
|
||||||
public readonly owner: IEditorHoverParticipant<MarkdownHover>,
|
public readonly owner: IEditorHoverParticipant<MarkdownHover>,
|
||||||
public readonly range: Range,
|
public readonly range: Range,
|
||||||
public readonly contents: IMarkdownString[]
|
public readonly contents: IMarkdownString[],
|
||||||
|
public readonly ordinal: number
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
public isValidForHoverAnchor(anchor: HoverAnchor): boolean {
|
public isValidForHoverAnchor(anchor: HoverAnchor): boolean {
|
||||||
|
@ -51,7 +53,7 @@ export class MarkdownHoverParticipant implements IEditorHoverParticipant<Markdow
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
public createLoadingMessage(anchor: HoverAnchor): MarkdownHover | null {
|
public createLoadingMessage(anchor: HoverAnchor): MarkdownHover | null {
|
||||||
return new MarkdownHover(this, anchor.range, [new MarkdownString().appendText(nls.localize('modesContentHover.loading', "Loading..."))]);
|
return new MarkdownHover(this, anchor.range, [new MarkdownString().appendText(nls.localize('modesContentHover.loading', "Loading..."))], 2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
public computeSync(anchor: HoverAnchor, lineDecorations: IModelDecoration[]): MarkdownHover[] {
|
public computeSync(anchor: HoverAnchor, lineDecorations: IModelDecoration[]): MarkdownHover[] {
|
||||||
|
@ -63,6 +65,20 @@ export class MarkdownHoverParticipant implements IEditorHoverParticipant<Markdow
|
||||||
const lineNumber = anchor.range.startLineNumber;
|
const lineNumber = anchor.range.startLineNumber;
|
||||||
const maxColumn = model.getLineMaxColumn(lineNumber);
|
const maxColumn = model.getLineMaxColumn(lineNumber);
|
||||||
const result: MarkdownHover[] = [];
|
const result: MarkdownHover[] = [];
|
||||||
|
|
||||||
|
let index = 1000;
|
||||||
|
|
||||||
|
const lineLength = model.getLineLength(lineNumber);
|
||||||
|
const languageId = model.getLanguageIdAtPosition(anchor.range.startLineNumber, anchor.range.startColumn);
|
||||||
|
const maxTokenizationLineLength = this._configurationService.getValue<number>('editor.maxTokenizationLineLength', {
|
||||||
|
overrideIdentifier: languageId
|
||||||
|
});
|
||||||
|
if (typeof maxTokenizationLineLength === 'number' && lineLength >= maxTokenizationLineLength) {
|
||||||
|
result.push(new MarkdownHover(this, anchor.range, [{
|
||||||
|
value: nls.localize('too many characters', "Tokenization is skipped for long lines for performance reasons. This can be configured via `editor.maxTokenizationLineLength`.")
|
||||||
|
}], index++));
|
||||||
|
}
|
||||||
|
|
||||||
for (const d of lineDecorations) {
|
for (const d of lineDecorations) {
|
||||||
const startColumn = (d.range.startLineNumber === lineNumber) ? d.range.startColumn : 1;
|
const startColumn = (d.range.startLineNumber === lineNumber) ? d.range.startColumn : 1;
|
||||||
const endColumn = (d.range.endLineNumber === lineNumber) ? d.range.endColumn : maxColumn;
|
const endColumn = (d.range.endLineNumber === lineNumber) ? d.range.endColumn : maxColumn;
|
||||||
|
@ -73,48 +89,30 @@ export class MarkdownHoverParticipant implements IEditorHoverParticipant<Markdow
|
||||||
}
|
}
|
||||||
|
|
||||||
const range = new Range(anchor.range.startLineNumber, startColumn, anchor.range.startLineNumber, endColumn);
|
const range = new Range(anchor.range.startLineNumber, startColumn, anchor.range.startLineNumber, endColumn);
|
||||||
result.push(new MarkdownHover(this, range, asArray(hoverMessage)));
|
result.push(new MarkdownHover(this, range, asArray(hoverMessage), index++));
|
||||||
}
|
|
||||||
|
|
||||||
const lineLength = model.getLineLength(lineNumber);
|
|
||||||
const languageId = model.getLanguageIdAtPosition(anchor.range.startLineNumber, anchor.range.startColumn);
|
|
||||||
const maxTokenizationLineLength = this._configurationService.getValue<number>('editor.maxTokenizationLineLength', {
|
|
||||||
overrideIdentifier: languageId
|
|
||||||
});
|
|
||||||
if (typeof maxTokenizationLineLength === 'number' && lineLength >= maxTokenizationLineLength) {
|
|
||||||
result.push(new MarkdownHover(this, anchor.range, [{
|
|
||||||
value: nls.localize('too many characters', "Tokenization is skipped for long lines for performance reasons. This can be configured via `editor.maxTokenizationLineLength`.")
|
|
||||||
}]));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async computeAsync(anchor: HoverAnchor, lineDecorations: IModelDecoration[], token: CancellationToken): Promise<MarkdownHover[]> {
|
public computeAsync(anchor: HoverAnchor, lineDecorations: IModelDecoration[], token: CancellationToken): AsyncIterableObject<MarkdownHover> {
|
||||||
if (!this._editor.hasModel() || anchor.type !== HoverAnchorType.Range) {
|
if (!this._editor.hasModel() || anchor.type !== HoverAnchorType.Range) {
|
||||||
return Promise.resolve([]);
|
return AsyncIterableObject.EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
const model = this._editor.getModel();
|
const model = this._editor.getModel();
|
||||||
|
|
||||||
if (!HoverProviderRegistry.has(model)) {
|
if (!HoverProviderRegistry.has(model)) {
|
||||||
return Promise.resolve([]);
|
return AsyncIterableObject.EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
const hovers = await getHover(model, new Position(
|
const position = new Position(anchor.range.startLineNumber, anchor.range.startColumn);
|
||||||
anchor.range.startLineNumber,
|
return getHover(model, position, token)
|
||||||
anchor.range.startColumn
|
.filter(item => !isEmptyMarkdownString(item.hover.contents))
|
||||||
), token);
|
.map(item => {
|
||||||
|
const rng = item.hover.range ? Range.lift(item.hover.range) : anchor.range;
|
||||||
const result: MarkdownHover[] = [];
|
return new MarkdownHover(this, rng, item.hover.contents, item.ordinal);
|
||||||
for (const hover of hovers) {
|
});
|
||||||
if (isEmptyMarkdownString(hover.contents)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const rng = hover.range ? Range.lift(hover.range) : anchor.range;
|
|
||||||
result.push(new MarkdownHover(this, rng, hover.contents));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public renderHoverParts(hoverParts: MarkdownHover[], fragment: DocumentFragment, statusBar: IEditorHoverStatusBar): IDisposable {
|
public renderHoverParts(hoverParts: MarkdownHover[], fragment: DocumentFragment, statusBar: IEditorHoverStatusBar): IDisposable {
|
||||||
|
@ -130,6 +128,10 @@ export function renderMarkdownHovers(
|
||||||
modeService: IModeService,
|
modeService: IModeService,
|
||||||
openerService: IOpenerService,
|
openerService: IOpenerService,
|
||||||
): IDisposable {
|
): IDisposable {
|
||||||
|
|
||||||
|
// Sort hover parts to keep them stable since they might come in async, out-of-order
|
||||||
|
hoverParts.sort((a, b) => a.ordinal - b.ordinal);
|
||||||
|
|
||||||
const disposables = new DisposableStore();
|
const disposables = new DisposableStore();
|
||||||
for (const hoverPart of hoverParts) {
|
for (const hoverPart of hoverParts) {
|
||||||
for (const contents of hoverPart.contents) {
|
for (const contents of hoverPart.contents) {
|
||||||
|
|
|
@ -7,7 +7,7 @@ import * as dom from 'vs/base/browser/dom';
|
||||||
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||||
import { HoverAction, HoverWidget } from 'vs/base/browser/ui/hover/hoverWidget';
|
import { HoverAction, HoverWidget } from 'vs/base/browser/ui/hover/hoverWidget';
|
||||||
import { Widget } from 'vs/base/browser/ui/widget';
|
import { Widget } from 'vs/base/browser/ui/widget';
|
||||||
import { coalesce, flatten } from 'vs/base/common/arrays';
|
import { coalesce } from 'vs/base/common/arrays';
|
||||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||||
import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
|
import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
|
||||||
|
@ -32,6 +32,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
||||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||||
import { Context as SuggestContext } from 'vs/editor/contrib/suggest/suggest';
|
import { Context as SuggestContext } from 'vs/editor/contrib/suggest/suggest';
|
||||||
import { UnicodeHighlighterHoverParticipant } from 'vs/editor/contrib/unicodeHighlighter/unicodeHighlighter';
|
import { UnicodeHighlighterHoverParticipant } from 'vs/editor/contrib/unicodeHighlighter/unicodeHighlighter';
|
||||||
|
import { AsyncIterableObject } from 'vs/base/common/async';
|
||||||
|
|
||||||
const $ = dom.$;
|
const $ = dom.$;
|
||||||
|
|
||||||
|
@ -67,7 +68,7 @@ class EditorHoverStatusBar extends Disposable implements IEditorHoverStatusBar {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ModesContentComputer implements IHoverComputer<IHoverPart[]> {
|
class ModesContentComputer implements IHoverComputer<IHoverPart> {
|
||||||
|
|
||||||
private readonly _editor: ICodeEditor;
|
private readonly _editor: ICodeEditor;
|
||||||
private _result: IHoverPart[];
|
private _result: IHoverPart[];
|
||||||
|
@ -121,22 +122,22 @@ class ModesContentComputer implements IHoverComputer<IHoverPart[]> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public async computeAsync(token: CancellationToken): Promise<IHoverPart[]> {
|
public computeAsync(token: CancellationToken): AsyncIterableObject<IHoverPart> {
|
||||||
const anchor = this._anchor;
|
const anchor = this._anchor;
|
||||||
|
|
||||||
if (!this._editor.hasModel() || !anchor) {
|
if (!this._editor.hasModel() || !anchor) {
|
||||||
return Promise.resolve([]);
|
return AsyncIterableObject.EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
const lineDecorations = ModesContentComputer._getLineDecorations(this._editor, anchor);
|
const lineDecorations = ModesContentComputer._getLineDecorations(this._editor, anchor);
|
||||||
|
return AsyncIterableObject.merge(
|
||||||
const allResults = await Promise.all(this._participants.map(p => this._computeAsync(p, lineDecorations, anchor, token)));
|
this._participants.map(participant => this._computeAsync(participant, lineDecorations, anchor, token))
|
||||||
return flatten(allResults);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _computeAsync(participant: IEditorHoverParticipant, lineDecorations: IModelDecoration[], anchor: HoverAnchor, token: CancellationToken): Promise<IHoverPart[]> {
|
private _computeAsync(participant: IEditorHoverParticipant, lineDecorations: IModelDecoration[], anchor: HoverAnchor, token: CancellationToken): AsyncIterableObject<IHoverPart> {
|
||||||
if (!participant.computeAsync) {
|
if (!participant.computeAsync) {
|
||||||
return [];
|
return AsyncIterableObject.EMPTY;
|
||||||
}
|
}
|
||||||
return participant.computeAsync(anchor, lineDecorations, token);
|
return participant.computeAsync(anchor, lineDecorations, token);
|
||||||
}
|
}
|
||||||
|
@ -201,9 +202,10 @@ export class ModesContentHoverWidget extends Widget implements IContentWidget, I
|
||||||
public readonly allowEditorOverflow = true;
|
public readonly allowEditorOverflow = true;
|
||||||
|
|
||||||
private _messages: IHoverPart[];
|
private _messages: IHoverPart[];
|
||||||
|
private _messagesAreComplete: boolean;
|
||||||
private _lastAnchor: HoverAnchor | null;
|
private _lastAnchor: HoverAnchor | null;
|
||||||
private readonly _computer: ModesContentComputer;
|
private readonly _computer: ModesContentComputer;
|
||||||
private readonly _hoverOperation: HoverOperation<IHoverPart[]>;
|
private readonly _hoverOperation: HoverOperation<IHoverPart>;
|
||||||
private _highlightDecorations: string[];
|
private _highlightDecorations: string[];
|
||||||
private _isChangingDecorations: boolean;
|
private _isChangingDecorations: boolean;
|
||||||
private _shouldFocus: boolean;
|
private _shouldFocus: boolean;
|
||||||
|
@ -257,6 +259,7 @@ export class ModesContentHoverWidget extends Widget implements IContentWidget, I
|
||||||
this._stoleFocus = false;
|
this._stoleFocus = false;
|
||||||
|
|
||||||
this._messages = [];
|
this._messages = [];
|
||||||
|
this._messagesAreComplete = false;
|
||||||
this._lastAnchor = null;
|
this._lastAnchor = null;
|
||||||
this._computer = new ModesContentComputer(this._editor, this._participants);
|
this._computer = new ModesContentComputer(this._editor, this._participants);
|
||||||
this._highlightDecorations = [];
|
this._highlightDecorations = [];
|
||||||
|
@ -462,7 +465,7 @@ export class ModesContentHoverWidget extends Widget implements IContentWidget, I
|
||||||
const filteredMessages = this._messages.filter((m) => m.isValidForHoverAnchor(anchor));
|
const filteredMessages = this._messages.filter((m) => m.isValidForHoverAnchor(anchor));
|
||||||
if (filteredMessages.length === 0) {
|
if (filteredMessages.length === 0) {
|
||||||
this.hide();
|
this.hide();
|
||||||
} else if (filteredMessages.length === this._messages.length) {
|
} else if (filteredMessages.length === this._messages.length && this._messagesAreComplete) {
|
||||||
// no change
|
// no change
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
|
@ -521,6 +524,7 @@ export class ModesContentHoverWidget extends Widget implements IContentWidget, I
|
||||||
|
|
||||||
private _withResult(result: IHoverPart[], complete: boolean): void {
|
private _withResult(result: IHoverPart[], complete: boolean): void {
|
||||||
this._messages = result;
|
this._messages = result;
|
||||||
|
this._messagesAreComplete = complete;
|
||||||
|
|
||||||
if (this._lastAnchor && this._messages.length > 0) {
|
if (this._lastAnchor && this._messages.length > 0) {
|
||||||
this._renderMessages(this._lastAnchor, this._messages);
|
this._renderMessages(this._lastAnchor, this._messages);
|
||||||
|
@ -561,8 +565,11 @@ export class ModesContentHoverWidget extends Widget implements IContentWidget, I
|
||||||
|
|
||||||
const statusBar = disposables.add(new EditorHoverStatusBar(this._keybindingService));
|
const statusBar = disposables.add(new EditorHoverStatusBar(this._keybindingService));
|
||||||
|
|
||||||
for (const [participant, participantHoverParts] of hoverParts) {
|
for (const participant of this._participants) {
|
||||||
disposables.add(participant.renderHoverParts(participantHoverParts, fragment, statusBar));
|
if (hoverParts.has(participant)) {
|
||||||
|
const participantHoverParts = hoverParts.get(participant)!;
|
||||||
|
disposables.add(participant.renderHoverParts(participantHoverParts, fragment, statusBar));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (statusBar.hasContent) {
|
if (statusBar.hasContent) {
|
||||||
|
|
|
@ -22,7 +22,7 @@ export interface IHoverMessage {
|
||||||
value: IMarkdownString;
|
value: IMarkdownString;
|
||||||
}
|
}
|
||||||
|
|
||||||
class MarginComputer implements IHoverComputer<IHoverMessage[]> {
|
class MarginComputer implements IHoverComputer<IHoverMessage> {
|
||||||
|
|
||||||
private readonly _editor: ICodeEditor;
|
private readonly _editor: ICodeEditor;
|
||||||
private _lineNumber: number;
|
private _lineNumber: number;
|
||||||
|
@ -100,7 +100,7 @@ export class ModesGlyphHoverWidget extends Widget implements IOverlayWidget {
|
||||||
|
|
||||||
private readonly _markdownRenderer: MarkdownRenderer;
|
private readonly _markdownRenderer: MarkdownRenderer;
|
||||||
private readonly _computer: MarginComputer;
|
private readonly _computer: MarginComputer;
|
||||||
private readonly _hoverOperation: HoverOperation<IHoverMessage[]>;
|
private readonly _hoverOperation: HoverOperation<IHoverMessage>;
|
||||||
private readonly _renderDisposeables = this._register(new DisposableStore());
|
private readonly _renderDisposeables = this._register(new DisposableStore());
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
|
|
@ -119,26 +119,31 @@ export interface UnicodeHighlighterDecorationInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
type RemoveDeriveFromWorkspaceTrust<T> = T extends DeriveFromWorkspaceTrust ? never : T;
|
type RemoveDeriveFromWorkspaceTrust<T> = T extends DeriveFromWorkspaceTrust ? never : T;
|
||||||
|
type ResolvedOptions = { [TKey in keyof InternalUnicodeHighlightOptions]: RemoveDeriveFromWorkspaceTrust<InternalUnicodeHighlightOptions[TKey]> };
|
||||||
|
|
||||||
function resolveOptions(_trusted: boolean, options: InternalUnicodeHighlightOptions): { [TKey in keyof InternalUnicodeHighlightOptions]: RemoveDeriveFromWorkspaceTrust<InternalUnicodeHighlightOptions[TKey]> } {
|
function resolveOptions(trusted: boolean, options: InternalUnicodeHighlightOptions): ResolvedOptions {
|
||||||
/*
|
let defaults;
|
||||||
// TODO@hediet enable some settings by default (depending on trust).
|
if (trusted) {
|
||||||
// For now, make it opt in, so there is some time to test it without breaking anyone.
|
defaults = {
|
||||||
|
nonBasicASCII: false,
|
||||||
|
ambiguousCharacters: true,
|
||||||
|
invisibleCharacters: true,
|
||||||
|
includeComments: true,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
defaults = {
|
||||||
|
nonBasicASCII: true,
|
||||||
|
ambiguousCharacters: true,
|
||||||
|
invisibleCharacters: true,
|
||||||
|
includeComments: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
nonBasicASCII: options.nonBasicASCII !== deriveFromWorkspaceTrust ? options.nonBasicASCII : (trusted ? false : true),
|
nonBasicASCII: options.nonBasicASCII !== deriveFromWorkspaceTrust ? options.nonBasicASCII : defaults.nonBasicASCII,
|
||||||
ambiguousCharacters: options.ambiguousCharacters !== deriveFromWorkspaceTrust ? options.ambiguousCharacters : (trusted ? false : true),
|
ambiguousCharacters: options.ambiguousCharacters !== deriveFromWorkspaceTrust ? options.ambiguousCharacters : defaults.ambiguousCharacters,
|
||||||
invisibleCharacters: options.invisibleCharacters !== deriveFromWorkspaceTrust ? options.invisibleCharacters : (trusted ? true : true),
|
invisibleCharacters: options.invisibleCharacters !== deriveFromWorkspaceTrust ? options.invisibleCharacters : defaults.invisibleCharacters,
|
||||||
includeComments: options.includeComments !== deriveFromWorkspaceTrust ? options.includeComments : (trusted ? true : false),
|
includeComments: options.includeComments !== deriveFromWorkspaceTrust ? options.includeComments : defaults.includeComments,
|
||||||
allowedCharacters: options.allowedCharacters ?? [],
|
|
||||||
};
|
|
||||||
*/
|
|
||||||
|
|
||||||
return {
|
|
||||||
nonBasicASCII: options.nonBasicASCII !== deriveFromWorkspaceTrust ? options.nonBasicASCII : false,
|
|
||||||
ambiguousCharacters: options.ambiguousCharacters !== deriveFromWorkspaceTrust ? options.ambiguousCharacters : false,
|
|
||||||
invisibleCharacters: options.invisibleCharacters !== deriveFromWorkspaceTrust ? options.invisibleCharacters : false,
|
|
||||||
includeComments: options.includeComments !== deriveFromWorkspaceTrust ? options.includeComments : true,
|
|
||||||
allowedCharacters: options.allowedCharacters ?? [],
|
allowedCharacters: options.allowedCharacters ?? [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -306,6 +311,7 @@ export class UnicodeHighlighterHoverParticipant implements IEditorHoverParticipa
|
||||||
|
|
||||||
|
|
||||||
const result: MarkdownHover[] = [];
|
const result: MarkdownHover[] = [];
|
||||||
|
let index = 300;
|
||||||
for (const d of lineDecorations) {
|
for (const d of lineDecorations) {
|
||||||
|
|
||||||
const highlightInfo = unicodeHighlighter.getDecorationInfo(d.id);
|
const highlightInfo = unicodeHighlighter.getDecorationInfo(d.id);
|
||||||
|
@ -366,7 +372,7 @@ export class UnicodeHighlighterHoverParticipant implements IEditorHoverParticipa
|
||||||
isTrusted: true,
|
isTrusted: true,
|
||||||
}];
|
}];
|
||||||
|
|
||||||
result.push(new MarkdownHover(this, d.range, contents));
|
result.push(new MarkdownHover(this, d.range, contents, index++));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,7 @@
|
||||||
import { Event } from 'vs/base/common/event';
|
import { Event } from 'vs/base/common/event';
|
||||||
import * as types from 'vs/base/common/types';
|
import * as types from 'vs/base/common/types';
|
||||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||||
import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
|
|
||||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { Registry } from 'vs/platform/registry/common/platform';
|
|
||||||
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||||
|
|
||||||
export const IConfigurationService = createDecorator<IConfigurationService>('configurationService');
|
export const IConfigurationService = createDecorator<IConfigurationService>('configurationService');
|
||||||
|
@ -262,23 +260,6 @@ export function merge(base: any, add: any, overwrite: boolean): void {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getConfigurationKeys(): string[] {
|
|
||||||
const properties = Registry.as<IConfigurationRegistry>(Extensions.Configuration).getConfigurationProperties();
|
|
||||||
return Object.keys(properties);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getDefaultValues(): any {
|
|
||||||
const valueTreeRoot: any = Object.create(null);
|
|
||||||
const properties = Registry.as<IConfigurationRegistry>(Extensions.Configuration).getConfigurationProperties();
|
|
||||||
|
|
||||||
for (let key in properties) {
|
|
||||||
let value = properties[key].default;
|
|
||||||
addToValueTree(valueTreeRoot, key, value, message => console.error(`Conflict in default settings: ${message}`));
|
|
||||||
}
|
|
||||||
|
|
||||||
return valueTreeRoot;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getMigratedSettingValue<T>(configurationService: IConfigurationService, currentSettingName: string, legacySettingName: string): T {
|
export function getMigratedSettingValue<T>(configurationService: IConfigurationService, currentSettingName: string, legacySettingName: string): T {
|
||||||
const setting = configurationService.inspect<T>(currentSettingName);
|
const setting = configurationService.inspect<T>(currentSettingName);
|
||||||
const legacySetting = configurationService.inspect<T>(legacySettingName);
|
const legacySetting = configurationService.inspect<T>(legacySettingName);
|
||||||
|
|
|
@ -13,7 +13,7 @@ import * as objects from 'vs/base/common/objects';
|
||||||
import { IExtUri } from 'vs/base/common/resources';
|
import { IExtUri } from 'vs/base/common/resources';
|
||||||
import * as types from 'vs/base/common/types';
|
import * as types from 'vs/base/common/types';
|
||||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||||
import { addToValueTree, ConfigurationTarget, getConfigurationKeys, getConfigurationValue, getDefaultValues, IConfigurationChange, IConfigurationChangeEvent, IConfigurationCompareResult, IConfigurationData, IConfigurationModel, IConfigurationOverrides, IConfigurationUpdateOverrides, IConfigurationValue, IOverrides, removeFromValueTree, toValuesTree } from 'vs/platform/configuration/common/configuration';
|
import { addToValueTree, ConfigurationTarget, getConfigurationValue, IConfigurationChange, IConfigurationChangeEvent, IConfigurationCompareResult, IConfigurationData, IConfigurationModel, IConfigurationOverrides, IConfigurationUpdateOverrides, IConfigurationValue, IOverrides, removeFromValueTree, toValuesTree } from 'vs/platform/configuration/common/configuration';
|
||||||
import { ConfigurationScope, Extensions, IConfigurationPropertySchema, IConfigurationRegistry, overrideIdentifiersFromKey, OVERRIDE_PROPERTY_REGEX } from 'vs/platform/configuration/common/configurationRegistry';
|
import { ConfigurationScope, Extensions, IConfigurationPropertySchema, IConfigurationRegistry, overrideIdentifiersFromKey, OVERRIDE_PROPERTY_REGEX } from 'vs/platform/configuration/common/configurationRegistry';
|
||||||
import { IFileService } from 'vs/platform/files/common/files';
|
import { IFileService } from 'vs/platform/files/common/files';
|
||||||
import { Registry } from 'vs/platform/registry/common/platform';
|
import { Registry } from 'vs/platform/registry/common/platform';
|
||||||
|
@ -234,10 +234,17 @@ export class ConfigurationModel implements IConfigurationModel {
|
||||||
|
|
||||||
export class DefaultConfigurationModel extends ConfigurationModel {
|
export class DefaultConfigurationModel extends ConfigurationModel {
|
||||||
|
|
||||||
constructor() {
|
constructor(configurationDefaultsOverrides: IStringDictionary<any> = {}) {
|
||||||
const contents = getDefaultValues();
|
const properties = Registry.as<IConfigurationRegistry>(Extensions.Configuration).getConfigurationProperties();
|
||||||
const keys = getConfigurationKeys();
|
const keys = Object.keys(properties);
|
||||||
|
const contents: any = Object.create(null);
|
||||||
const overrides: IOverrides[] = [];
|
const overrides: IOverrides[] = [];
|
||||||
|
|
||||||
|
for (const key in properties) {
|
||||||
|
const defaultOverrideValue = configurationDefaultsOverrides[key];
|
||||||
|
const value = defaultOverrideValue !== undefined ? defaultOverrideValue : properties[key].default;
|
||||||
|
addToValueTree(contents, key, value, message => console.error(`Conflict in default settings: ${message}`));
|
||||||
|
}
|
||||||
for (const key of Object.keys(contents)) {
|
for (const key of Object.keys(contents)) {
|
||||||
if (OVERRIDE_PROPERTY_REGEX.test(key)) {
|
if (OVERRIDE_PROPERTY_REGEX.test(key)) {
|
||||||
overrides.push({
|
overrides.push({
|
||||||
|
@ -247,6 +254,7 @@ export class DefaultConfigurationModel extends ConfigurationModel {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
super(contents, keys, overrides);
|
super(contents, keys, overrides);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -587,21 +595,12 @@ export class Configuration {
|
||||||
this._foldersConsolidatedConfigurations.delete(resource);
|
this._foldersConsolidatedConfigurations.delete(resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
compareAndUpdateDefaultConfiguration(defaults: ConfigurationModel, keys: string[]): IConfigurationChange {
|
compareAndUpdateDefaultConfiguration(defaults: ConfigurationModel): IConfigurationChange {
|
||||||
const overrides: [string, string[]][] = [];
|
const { added, updated, removed, overrides } = compare(this._defaultConfiguration, defaults);
|
||||||
for (const key of keys) {
|
const keys = [...added, ...updated, ...removed];
|
||||||
for (const overrideIdentifier of overrideIdentifiersFromKey(key)) {
|
if (keys.length) {
|
||||||
const fromKeys = this._defaultConfiguration.getKeysForOverrideIdentifier(overrideIdentifier);
|
this.updateDefaultConfiguration(defaults);
|
||||||
const toKeys = defaults.getKeysForOverrideIdentifier(overrideIdentifier);
|
|
||||||
const keys = [
|
|
||||||
...toKeys.filter(key => fromKeys.indexOf(key) === -1),
|
|
||||||
...fromKeys.filter(key => toKeys.indexOf(key) === -1),
|
|
||||||
...fromKeys.filter(key => !objects.equals(this._defaultConfiguration.override(overrideIdentifier).getValue(key), defaults.override(overrideIdentifier).getValue(key)))
|
|
||||||
];
|
|
||||||
overrides.push([overrideIdentifier, keys]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
this.updateDefaultConfiguration(defaults);
|
|
||||||
return { keys, overrides };
|
return { keys, overrides };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,11 @@ export interface IConfigurationRegistry {
|
||||||
*/
|
*/
|
||||||
deregisterDefaultConfigurations(defaultConfigurations: IStringDictionary<any>[]): void;
|
deregisterDefaultConfigurations(defaultConfigurations: IStringDictionary<any>[]): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the registered configuration defaults overrides
|
||||||
|
*/
|
||||||
|
getConfigurationDefaultsOverrides(): IStringDictionary<any>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signal that the schema of a configuration setting has changes. It is currently only supported to change enumeration values.
|
* Signal that the schema of a configuration setting has changes. It is currently only supported to change enumeration values.
|
||||||
* Property or default value changes are not allowed.
|
* Property or default value changes are not allowed.
|
||||||
|
@ -65,13 +70,13 @@ export interface IConfigurationRegistry {
|
||||||
* Event that fires whenver a configuration has been
|
* Event that fires whenver a configuration has been
|
||||||
* registered.
|
* registered.
|
||||||
*/
|
*/
|
||||||
onDidSchemaChange: Event<void>;
|
readonly onDidSchemaChange: Event<void>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Event that fires whenver a configuration has been
|
* Event that fires whenver a configuration has been
|
||||||
* registered.
|
* registered.
|
||||||
*/
|
*/
|
||||||
onDidUpdateConfiguration: Event<string[]>;
|
readonly onDidUpdateConfiguration: Event<{ properties: string[], defaultsOverrides?: boolean }>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all configuration nodes contributed to this registry.
|
* Returns all configuration nodes contributed to this registry.
|
||||||
|
@ -190,7 +195,7 @@ const contributionRegistry = Registry.as<IJSONContributionRegistry>(JSONExtensio
|
||||||
|
|
||||||
class ConfigurationRegistry implements IConfigurationRegistry {
|
class ConfigurationRegistry implements IConfigurationRegistry {
|
||||||
|
|
||||||
private readonly defaultValues: IStringDictionary<any>;
|
private readonly configurationDefaultsOverrides: IStringDictionary<any>;
|
||||||
private readonly defaultLanguageConfigurationOverridesNode: IConfigurationNode;
|
private readonly defaultLanguageConfigurationOverridesNode: IConfigurationNode;
|
||||||
private readonly configurationContributors: IConfigurationNode[];
|
private readonly configurationContributors: IConfigurationNode[];
|
||||||
private readonly configurationProperties: { [qualifiedKey: string]: IJSONSchema };
|
private readonly configurationProperties: { [qualifiedKey: string]: IJSONSchema };
|
||||||
|
@ -201,11 +206,11 @@ class ConfigurationRegistry implements IConfigurationRegistry {
|
||||||
private readonly _onDidSchemaChange = new Emitter<void>();
|
private readonly _onDidSchemaChange = new Emitter<void>();
|
||||||
readonly onDidSchemaChange: Event<void> = this._onDidSchemaChange.event;
|
readonly onDidSchemaChange: Event<void> = this._onDidSchemaChange.event;
|
||||||
|
|
||||||
private readonly _onDidUpdateConfiguration: Emitter<string[]> = new Emitter<string[]>();
|
private readonly _onDidUpdateConfiguration = new Emitter<{ properties: string[], defaultsOverrides?: boolean }>();
|
||||||
readonly onDidUpdateConfiguration: Event<string[]> = this._onDidUpdateConfiguration.event;
|
readonly onDidUpdateConfiguration = this._onDidUpdateConfiguration.event;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.defaultValues = {};
|
this.configurationDefaultsOverrides = {};
|
||||||
this.defaultLanguageConfigurationOverridesNode = {
|
this.defaultLanguageConfigurationOverridesNode = {
|
||||||
id: 'defaultOverrides',
|
id: 'defaultOverrides',
|
||||||
title: nls.localize('defaultLanguageConfigurationOverrides.title', "Default Language Configuration Overrides"),
|
title: nls.localize('defaultLanguageConfigurationOverrides.title', "Default Language Configuration Overrides"),
|
||||||
|
@ -229,7 +234,7 @@ class ConfigurationRegistry implements IConfigurationRegistry {
|
||||||
|
|
||||||
contributionRegistry.registerSchema(resourceLanguageSettingsSchemaId, this.resourceLanguageSettingsSchema);
|
contributionRegistry.registerSchema(resourceLanguageSettingsSchemaId, this.resourceLanguageSettingsSchema);
|
||||||
this._onDidSchemaChange.fire();
|
this._onDidSchemaChange.fire();
|
||||||
this._onDidUpdateConfiguration.fire(properties);
|
this._onDidUpdateConfiguration.fire({ properties });
|
||||||
}
|
}
|
||||||
|
|
||||||
public deregisterConfigurations(configurations: IConfigurationNode[]): void {
|
public deregisterConfigurations(configurations: IConfigurationNode[]): void {
|
||||||
|
@ -237,7 +242,7 @@ class ConfigurationRegistry implements IConfigurationRegistry {
|
||||||
|
|
||||||
contributionRegistry.registerSchema(resourceLanguageSettingsSchemaId, this.resourceLanguageSettingsSchema);
|
contributionRegistry.registerSchema(resourceLanguageSettingsSchemaId, this.resourceLanguageSettingsSchema);
|
||||||
this._onDidSchemaChange.fire();
|
this._onDidSchemaChange.fire();
|
||||||
this._onDidUpdateConfiguration.fire(properties);
|
this._onDidUpdateConfiguration.fire({ properties });
|
||||||
}
|
}
|
||||||
|
|
||||||
public updateConfigurations({ add, remove }: { add: IConfigurationNode[], remove: IConfigurationNode[] }): void {
|
public updateConfigurations({ add, remove }: { add: IConfigurationNode[], remove: IConfigurationNode[] }): void {
|
||||||
|
@ -247,7 +252,7 @@ class ConfigurationRegistry implements IConfigurationRegistry {
|
||||||
|
|
||||||
contributionRegistry.registerSchema(resourceLanguageSettingsSchemaId, this.resourceLanguageSettingsSchema);
|
contributionRegistry.registerSchema(resourceLanguageSettingsSchemaId, this.resourceLanguageSettingsSchema);
|
||||||
this._onDidSchemaChange.fire();
|
this._onDidSchemaChange.fire();
|
||||||
this._onDidUpdateConfiguration.fire(distinct(properties));
|
this._onDidUpdateConfiguration.fire({ properties: distinct(properties) });
|
||||||
}
|
}
|
||||||
|
|
||||||
public registerDefaultConfigurations(defaultConfigurations: IStringDictionary<any>[]): void {
|
public registerDefaultConfigurations(defaultConfigurations: IStringDictionary<any>[]): void {
|
||||||
|
@ -259,10 +264,10 @@ class ConfigurationRegistry implements IConfigurationRegistry {
|
||||||
properties.push(key);
|
properties.push(key);
|
||||||
|
|
||||||
if (OVERRIDE_PROPERTY_REGEX.test(key)) {
|
if (OVERRIDE_PROPERTY_REGEX.test(key)) {
|
||||||
this.defaultValues[key] = { ...(this.defaultValues[key] || {}), ...defaultConfiguration[key] };
|
this.configurationDefaultsOverrides[key] = { ...(this.configurationDefaultsOverrides[key] || {}), ...defaultConfiguration[key] };
|
||||||
const property: IConfigurationPropertySchema = {
|
const property: IConfigurationPropertySchema = {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
default: this.defaultValues[key],
|
default: this.configurationDefaultsOverrides[key],
|
||||||
description: nls.localize('defaultLanguageConfiguration.description', "Configure settings to be overridden for {0} language.", key),
|
description: nls.localize('defaultLanguageConfiguration.description', "Configure settings to be overridden for {0} language.", key),
|
||||||
$ref: resourceLanguageSettingsSchemaId
|
$ref: resourceLanguageSettingsSchemaId
|
||||||
};
|
};
|
||||||
|
@ -270,7 +275,7 @@ class ConfigurationRegistry implements IConfigurationRegistry {
|
||||||
this.configurationProperties[key] = property;
|
this.configurationProperties[key] = property;
|
||||||
this.defaultLanguageConfigurationOverridesNode.properties![key] = property;
|
this.defaultLanguageConfigurationOverridesNode.properties![key] = property;
|
||||||
} else {
|
} else {
|
||||||
this.defaultValues[key] = defaultConfiguration[key];
|
this.configurationDefaultsOverrides[key] = defaultConfiguration[key];
|
||||||
const property = this.configurationProperties[key];
|
const property = this.configurationProperties[key];
|
||||||
if (property) {
|
if (property) {
|
||||||
this.updatePropertyDefaultValue(key, property);
|
this.updatePropertyDefaultValue(key, property);
|
||||||
|
@ -282,7 +287,7 @@ class ConfigurationRegistry implements IConfigurationRegistry {
|
||||||
|
|
||||||
this.registerOverrideIdentifiers(overrideIdentifiers);
|
this.registerOverrideIdentifiers(overrideIdentifiers);
|
||||||
this._onDidSchemaChange.fire();
|
this._onDidSchemaChange.fire();
|
||||||
this._onDidUpdateConfiguration.fire(properties);
|
this._onDidUpdateConfiguration.fire({ properties, defaultsOverrides: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
public deregisterDefaultConfigurations(defaultConfigurations: IStringDictionary<any>[]): void {
|
public deregisterDefaultConfigurations(defaultConfigurations: IStringDictionary<any>[]): void {
|
||||||
|
@ -290,7 +295,7 @@ class ConfigurationRegistry implements IConfigurationRegistry {
|
||||||
for (const defaultConfiguration of defaultConfigurations) {
|
for (const defaultConfiguration of defaultConfigurations) {
|
||||||
for (const key in defaultConfiguration) {
|
for (const key in defaultConfiguration) {
|
||||||
properties.push(key);
|
properties.push(key);
|
||||||
delete this.defaultValues[key];
|
delete this.configurationDefaultsOverrides[key];
|
||||||
if (OVERRIDE_PROPERTY_REGEX.test(key)) {
|
if (OVERRIDE_PROPERTY_REGEX.test(key)) {
|
||||||
delete this.configurationProperties[key];
|
delete this.configurationProperties[key];
|
||||||
delete this.defaultLanguageConfigurationOverridesNode.properties![key];
|
delete this.defaultLanguageConfigurationOverridesNode.properties![key];
|
||||||
|
@ -306,7 +311,7 @@ class ConfigurationRegistry implements IConfigurationRegistry {
|
||||||
|
|
||||||
this.updateOverridePropertyPatternKey();
|
this.updateOverridePropertyPatternKey();
|
||||||
this._onDidSchemaChange.fire();
|
this._onDidSchemaChange.fire();
|
||||||
this._onDidUpdateConfiguration.fire(properties);
|
this._onDidUpdateConfiguration.fire({ properties, defaultsOverrides: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
public notifyConfigurationSchemaUpdated(...configurations: IConfigurationNode[]) {
|
public notifyConfigurationSchemaUpdated(...configurations: IConfigurationNode[]) {
|
||||||
|
@ -417,6 +422,10 @@ class ConfigurationRegistry implements IConfigurationRegistry {
|
||||||
return this.excludedConfigurationProperties;
|
return this.excludedConfigurationProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getConfigurationDefaultsOverrides(): IStringDictionary<any> {
|
||||||
|
return this.configurationDefaultsOverrides;
|
||||||
|
}
|
||||||
|
|
||||||
private registerJSONConfiguration(configuration: IConfigurationNode) {
|
private registerJSONConfiguration(configuration: IConfigurationNode) {
|
||||||
const register = (configuration: IConfigurationNode) => {
|
const register = (configuration: IConfigurationNode) => {
|
||||||
let properties = configuration.properties;
|
let properties = configuration.properties;
|
||||||
|
@ -476,6 +485,7 @@ class ConfigurationRegistry implements IConfigurationRegistry {
|
||||||
case ConfigurationScope.RESOURCE:
|
case ConfigurationScope.RESOURCE:
|
||||||
case ConfigurationScope.LANGUAGE_OVERRIDABLE:
|
case ConfigurationScope.LANGUAGE_OVERRIDABLE:
|
||||||
delete resourceSettings.properties[key];
|
delete resourceSettings.properties[key];
|
||||||
|
delete this.resourceLanguageSettingsSchema.properties![key];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -517,7 +527,7 @@ class ConfigurationRegistry implements IConfigurationRegistry {
|
||||||
}
|
}
|
||||||
|
|
||||||
private updatePropertyDefaultValue(key: string, property: IConfigurationPropertySchema): void {
|
private updatePropertyDefaultValue(key: string, property: IConfigurationPropertySchema): void {
|
||||||
let defaultValue = this.defaultValues[key];
|
let defaultValue = this.configurationDefaultsOverrides[key];
|
||||||
if (types.isUndefined(defaultValue)) {
|
if (types.isUndefined(defaultValue)) {
|
||||||
defaultValue = property.default;
|
defaultValue = property.default;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ export class ConfigurationService extends Disposable implements IConfigurationSe
|
||||||
this.configuration = new Configuration(new DefaultConfigurationModel(), new ConfigurationModel());
|
this.configuration = new Configuration(new DefaultConfigurationModel(), new ConfigurationModel());
|
||||||
|
|
||||||
this.reloadConfigurationScheduler = this._register(new RunOnceScheduler(() => this.reloadConfiguration(), 50));
|
this.reloadConfigurationScheduler = this._register(new RunOnceScheduler(() => this.reloadConfiguration(), 50));
|
||||||
this._register(Registry.as<IConfigurationRegistry>(Extensions.Configuration).onDidUpdateConfiguration(configurationProperties => this.onDidDefaultConfigurationChange(configurationProperties)));
|
this._register(Registry.as<IConfigurationRegistry>(Extensions.Configuration).onDidUpdateConfiguration(() => this.onDidDefaultConfigurationChange()));
|
||||||
this._register(this.userConfiguration.onDidChange(() => this.reloadConfigurationScheduler.schedule()));
|
this._register(this.userConfiguration.onDidChange(() => this.reloadConfigurationScheduler.schedule()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,9 +89,9 @@ export class ConfigurationService extends Disposable implements IConfigurationSe
|
||||||
this.trigger(change, previous, ConfigurationTarget.USER);
|
this.trigger(change, previous, ConfigurationTarget.USER);
|
||||||
}
|
}
|
||||||
|
|
||||||
private onDidDefaultConfigurationChange(keys: string[]): void {
|
private onDidDefaultConfigurationChange(): void {
|
||||||
const previous = this.configuration.toData();
|
const previous = this.configuration.toData();
|
||||||
const change = this.configuration.compareAndUpdateDefaultConfiguration(new DefaultConfigurationModel(), keys);
|
const change = this.configuration.compareAndUpdateDefaultConfiguration(new DefaultConfigurationModel());
|
||||||
this.trigger(change, previous, ConfigurationTarget.DEFAULT);
|
this.trigger(change, previous, ConfigurationTarget.DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -443,6 +443,43 @@ suite('CustomConfigurationModel', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
suite('CustomConfigurationModel', () => {
|
||||||
|
|
||||||
|
test('Default configuration model uses overrides', () => {
|
||||||
|
Registry.as<IConfigurationRegistry>(Extensions.Configuration).registerConfiguration({
|
||||||
|
'id': 'a',
|
||||||
|
'order': 1,
|
||||||
|
'title': 'a',
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'a': {
|
||||||
|
'description': 'a',
|
||||||
|
'type': 'boolean',
|
||||||
|
'default': false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
assert.strictEqual(true, new DefaultConfigurationModel().getValue('a'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Default configuration model uses overrides', () => {
|
||||||
|
Registry.as<IConfigurationRegistry>(Extensions.Configuration).registerConfiguration({
|
||||||
|
'id': 'a',
|
||||||
|
'order': 1,
|
||||||
|
'title': 'a',
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'a': {
|
||||||
|
'description': 'a',
|
||||||
|
'type': 'boolean',
|
||||||
|
'default': false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
assert.strictEqual(false, new DefaultConfigurationModel({ a: false }).getValue('a'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
suite('Configuration', () => {
|
suite('Configuration', () => {
|
||||||
|
|
||||||
test('Test inspect for overrideIdentifiers', () => {
|
test('Test inspect for overrideIdentifiers', () => {
|
||||||
|
@ -488,9 +525,9 @@ suite('Configuration', () => {
|
||||||
'[markdown]': {
|
'[markdown]': {
|
||||||
'editor.wordWrap': 'off'
|
'editor.wordWrap': 'off'
|
||||||
}
|
}
|
||||||
}), ['editor.lineNumbers', '[markdown]']);
|
}));
|
||||||
|
|
||||||
assert.deepStrictEqual(actual, { keys: ['editor.lineNumbers', '[markdown]'], overrides: [['markdown', ['editor.wordWrap']]] });
|
assert.deepStrictEqual(actual, { keys: ['[markdown]', 'editor.lineNumbers'], overrides: [['markdown', ['editor.wordWrap']]] });
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -853,7 +890,7 @@ suite('ConfigurationChangeEvent', () => {
|
||||||
'[markdown]': {
|
'[markdown]': {
|
||||||
'editor.wordWrap': 'off'
|
'editor.wordWrap': 'off'
|
||||||
}
|
}
|
||||||
}), ['editor.lineNumbers', '[markdown]']),
|
})),
|
||||||
configuration.compareAndUpdateLocalUserConfiguration(toConfigurationModel({
|
configuration.compareAndUpdateLocalUserConfiguration(toConfigurationModel({
|
||||||
'[json]': {
|
'[json]': {
|
||||||
'editor.lineNumbers': 'relative'
|
'editor.lineNumbers': 'relative'
|
||||||
|
|
|
@ -6,7 +6,9 @@
|
||||||
import { Emitter } from 'vs/base/common/event';
|
import { Emitter } from 'vs/base/common/event';
|
||||||
import { TernarySearchTree } from 'vs/base/common/map';
|
import { TernarySearchTree } from 'vs/base/common/map';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { getConfigurationKeys, getConfigurationValue, IConfigurationChangeEvent, IConfigurationOverrides, IConfigurationService, IConfigurationValue, isConfigurationOverrides } from 'vs/platform/configuration/common/configuration';
|
import { getConfigurationValue, IConfigurationChangeEvent, IConfigurationOverrides, IConfigurationService, IConfigurationValue, isConfigurationOverrides } from 'vs/platform/configuration/common/configuration';
|
||||||
|
import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
|
||||||
|
import { Registry } from 'vs/platform/registry/common/platform';
|
||||||
|
|
||||||
export class TestConfigurationService implements IConfigurationService {
|
export class TestConfigurationService implements IConfigurationService {
|
||||||
public _serviceBrand: undefined;
|
public _serviceBrand: undefined;
|
||||||
|
@ -68,7 +70,7 @@ export class TestConfigurationService implements IConfigurationService {
|
||||||
|
|
||||||
public keys() {
|
public keys() {
|
||||||
return {
|
return {
|
||||||
default: getConfigurationKeys(),
|
default: Object.keys(Registry.as<IConfigurationRegistry>(Extensions.Configuration).getConfigurationProperties()),
|
||||||
user: Object.keys(this.configuration),
|
user: Object.keys(this.configuration),
|
||||||
workspace: [],
|
workspace: [],
|
||||||
workspaceFolder: []
|
workspaceFolder: []
|
||||||
|
|
|
@ -158,7 +158,7 @@ export abstract class BaseWindowDriver implements IWindowDriver {
|
||||||
throw new Error(`Xterm not found: ${selector}`);
|
throw new Error(`Xterm not found: ${selector}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
xterm._core._coreService.triggerDataEvent(text);
|
xterm._core.coreService.triggerDataEvent(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
getLocaleInfo(): Promise<ILocaleInfo> {
|
getLocaleInfo(): Promise<ILocaleInfo> {
|
||||||
|
|
|
@ -53,6 +53,7 @@ export interface IEnvironmentService {
|
||||||
untitledWorkspacesHome: URI;
|
untitledWorkspacesHome: URI;
|
||||||
globalStorageHome: URI;
|
globalStorageHome: URI;
|
||||||
workspaceStorageHome: URI;
|
workspaceStorageHome: URI;
|
||||||
|
cacheHome: URI;
|
||||||
|
|
||||||
// --- settings sync
|
// --- settings sync
|
||||||
userDataSyncHome: URI;
|
userDataSyncHome: URI;
|
||||||
|
|
|
@ -57,6 +57,9 @@ export abstract class AbstractNativeEnvironmentService implements INativeEnviron
|
||||||
@memoize
|
@memoize
|
||||||
get tmpDir(): URI { return URI.file(this.paths.tmpDir); }
|
get tmpDir(): URI { return URI.file(this.paths.tmpDir); }
|
||||||
|
|
||||||
|
@memoize
|
||||||
|
get cacheHome(): URI { return URI.file(this.userDataPath); }
|
||||||
|
|
||||||
@memoize
|
@memoize
|
||||||
get userRoamingDataHome(): URI { return this.appSettingsHome; }
|
get userRoamingDataHome(): URI { return this.appSettingsHome; }
|
||||||
|
|
||||||
|
|
|
@ -264,8 +264,6 @@ export interface IExtensionManifest {
|
||||||
readonly repository?: { url: string; };
|
readonly repository?: { url: string; };
|
||||||
readonly bugs?: { url: string; };
|
readonly bugs?: { url: string; };
|
||||||
readonly enabledApiProposals?: readonly string[];
|
readonly enabledApiProposals?: readonly string[];
|
||||||
/** @deprecated */
|
|
||||||
readonly enableProposedApi?: boolean;
|
|
||||||
readonly api?: string;
|
readonly api?: string;
|
||||||
readonly scripts?: { [key: string]: string; };
|
readonly scripts?: { [key: string]: string; };
|
||||||
readonly capabilities?: IExtensionCapabilities;
|
readonly capabilities?: IExtensionCapabilities;
|
||||||
|
@ -348,9 +346,6 @@ export interface IExtensionDescription extends IExtensionManifest {
|
||||||
readonly isUserBuiltin: boolean;
|
readonly isUserBuiltin: boolean;
|
||||||
readonly isUnderDevelopment: boolean;
|
readonly isUnderDevelopment: boolean;
|
||||||
readonly extensionLocation: URI;
|
readonly extensionLocation: URI;
|
||||||
|
|
||||||
/** @deprecated */
|
|
||||||
enableProposedApi?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isLanguagePackExtension(manifest: IExtensionManifest): boolean {
|
export function isLanguagePackExtension(manifest: IExtensionManifest): boolean {
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { realpathSync } from 'fs';
|
||||||
import { tmpdir } from 'os';
|
import { tmpdir } from 'os';
|
||||||
import { timeout } from 'vs/base/common/async';
|
import { timeout } from 'vs/base/common/async';
|
||||||
import { dirname, join, sep } from 'vs/base/common/path';
|
import { dirname, join, sep } from 'vs/base/common/path';
|
||||||
import { isLinux, isWindows } from 'vs/base/common/platform';
|
import { isLinux, isMacintosh, isWindows } from 'vs/base/common/platform';
|
||||||
import { Promises, RimRafMode } from 'vs/base/node/pfs';
|
import { Promises, RimRafMode } from 'vs/base/node/pfs';
|
||||||
import { flakySuite, getPathFromAmdModule, getRandomTestPath } from 'vs/base/test/node/testUtils';
|
import { flakySuite, getPathFromAmdModule, getRandomTestPath } from 'vs/base/test/node/testUtils';
|
||||||
import { FileChangeType } from 'vs/platform/files/common/files';
|
import { FileChangeType } from 'vs/platform/files/common/files';
|
||||||
|
@ -240,22 +240,26 @@ flakySuite('Recursive Watcher (parcel)', () => {
|
||||||
await Promises.writeFile(anotherNewFilePath, 'Hello Another World');
|
await Promises.writeFile(anotherNewFilePath, 'Hello Another World');
|
||||||
await changeFuture;
|
await changeFuture;
|
||||||
|
|
||||||
await timeout(1500); // ensure the previous added event is flushed by now (can happen on macOS with fsevents)
|
// Skip following asserts on macOS where the fs-events service
|
||||||
|
// does not really give a full guarantee about the correlation
|
||||||
|
// of an event to a change.
|
||||||
|
if (!isMacintosh) {
|
||||||
|
|
||||||
// Read file does not emit event
|
// Read file does not emit event
|
||||||
changeFuture = awaitEvent(service, anotherNewFilePath, FileChangeType.UPDATED, 'unexpected-event-from-read-file');
|
changeFuture = awaitEvent(service, anotherNewFilePath, FileChangeType.UPDATED, 'unexpected-event-from-read-file');
|
||||||
await Promises.readFile(anotherNewFilePath);
|
await Promises.readFile(anotherNewFilePath);
|
||||||
await Promise.race([timeout(100), changeFuture]);
|
await Promise.race([timeout(100), changeFuture]);
|
||||||
|
|
||||||
// Stat file does not emit event
|
// Stat file does not emit event
|
||||||
changeFuture = awaitEvent(service, anotherNewFilePath, FileChangeType.UPDATED, 'unexpected-event-from-stat');
|
changeFuture = awaitEvent(service, anotherNewFilePath, FileChangeType.UPDATED, 'unexpected-event-from-stat');
|
||||||
await Promises.stat(anotherNewFilePath);
|
await Promises.stat(anotherNewFilePath);
|
||||||
await Promise.race([timeout(100), changeFuture]);
|
await Promise.race([timeout(100), changeFuture]);
|
||||||
|
|
||||||
// Stat folder does not emit event
|
// Stat folder does not emit event
|
||||||
changeFuture = awaitEvent(service, copiedFolderpath, FileChangeType.UPDATED, 'unexpected-event-from-stat');
|
changeFuture = awaitEvent(service, copiedFolderpath, FileChangeType.UPDATED, 'unexpected-event-from-stat');
|
||||||
await Promises.stat(copiedFolderpath);
|
await Promises.stat(copiedFolderpath);
|
||||||
await Promise.race([timeout(100), changeFuture]);
|
await Promise.race([timeout(100), changeFuture]);
|
||||||
|
}
|
||||||
|
|
||||||
// Delete file
|
// Delete file
|
||||||
changeFuture = awaitEvent(service, copiedFilepath, FileChangeType.DELETED);
|
changeFuture = awaitEvent(service, copiedFilepath, FileChangeType.DELETED);
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
const perf = require('../base/common/performance');
|
const perf = require('../base/common/performance');
|
||||||
const performance = require('perf_hooks').performance;
|
const performance = require('perf_hooks').performance;
|
||||||
const product = require('../../../product.json');
|
const product = require('../../../product.json');
|
||||||
|
const readline = require('readline');
|
||||||
|
|
||||||
perf.mark('code/server/start');
|
perf.mark('code/server/start');
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
@ -24,7 +25,7 @@ async function start() {
|
||||||
|
|
||||||
// Do a quick parse to determine if a server or the cli needs to be started
|
// Do a quick parse to determine if a server or the cli needs to be started
|
||||||
const parsedArgs = minimist(process.argv.slice(2), {
|
const parsedArgs = minimist(process.argv.slice(2), {
|
||||||
boolean: ['start-server', 'list-extensions', 'print-ip-address', 'help', 'version'],
|
boolean: ['start-server', 'list-extensions', 'print-ip-address', 'help', 'version', 'accept-server-license-terms'],
|
||||||
string: ['install-extension', 'install-builtin-extension', 'uninstall-extension', 'locate-extension', 'socket-path', 'host', 'port', 'pick-port']
|
string: ['install-extension', 'install-builtin-extension', 'uninstall-extension', 'locate-extension', 'socket-path', 'host', 'port', 'pick-port']
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -57,6 +58,21 @@ async function start() {
|
||||||
const http = require('http');
|
const http = require('http');
|
||||||
const os = require('os');
|
const os = require('os');
|
||||||
|
|
||||||
|
if (Array.isArray(product.serverLicense) && product.serverLicense.length) {
|
||||||
|
console.log(product.serverLicense.join('\n'));
|
||||||
|
if (product.serverLicensePrompt && parsedArgs['accept-server-license-terms'] !== true) {
|
||||||
|
try {
|
||||||
|
const accept = await prompt(product.serverLicensePrompt);
|
||||||
|
if (!accept) {
|
||||||
|
process.exit();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
process.exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let firstRequest = true;
|
let firstRequest = true;
|
||||||
let firstWebSocket = true;
|
let firstWebSocket = true;
|
||||||
|
|
||||||
|
@ -218,4 +234,30 @@ function loadCode() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} question
|
||||||
|
* @returns { Promise<boolean> }
|
||||||
|
*/
|
||||||
|
function prompt(question) {
|
||||||
|
const rl = readline.createInterface({
|
||||||
|
input: process.stdin,
|
||||||
|
output: process.stdout
|
||||||
|
});
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
rl.question(question + ' ', async function (data) {
|
||||||
|
rl.close();
|
||||||
|
const str = data.toString().trim().toLowerCase();
|
||||||
|
if (str === '' || str === 'y' || str === 'yes') {
|
||||||
|
resolve(true);
|
||||||
|
} else if (str === 'n' || str === 'no') {
|
||||||
|
resolve(false);
|
||||||
|
} else {
|
||||||
|
process.stdout.write('\nInvalid Response. Answer either yes (y, yes) or no (n, no)\n');
|
||||||
|
resolve(await prompt(question));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
start();
|
start();
|
||||||
|
|
|
@ -57,6 +57,7 @@ export const serverOptions: OptionDescriptions<ServerParsedArgs> = {
|
||||||
|
|
||||||
'help': OPTIONS['help'],
|
'help': OPTIONS['help'],
|
||||||
'version': OPTIONS['version'],
|
'version': OPTIONS['version'],
|
||||||
|
'accept-server-license-terms': { type: 'boolean' },
|
||||||
|
|
||||||
_: OPTIONS['_']
|
_: OPTIONS['_']
|
||||||
};
|
};
|
||||||
|
@ -136,6 +137,8 @@ export interface ServerParsedArgs {
|
||||||
help: boolean;
|
help: boolean;
|
||||||
version: boolean;
|
version: boolean;
|
||||||
|
|
||||||
|
'accept-server-license-terms': boolean;
|
||||||
|
|
||||||
_: string[];
|
_: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,13 +8,14 @@ import * as objects from 'vs/base/common/objects';
|
||||||
import { Registry } from 'vs/platform/registry/common/platform';
|
import { Registry } from 'vs/platform/registry/common/platform';
|
||||||
import { IJSONSchema } from 'vs/base/common/jsonSchema';
|
import { IJSONSchema } from 'vs/base/common/jsonSchema';
|
||||||
import { ExtensionsRegistry, IExtensionPointUser } from 'vs/workbench/services/extensions/common/extensionsRegistry';
|
import { ExtensionsRegistry, IExtensionPointUser } from 'vs/workbench/services/extensions/common/extensionsRegistry';
|
||||||
import { IConfigurationNode, IConfigurationRegistry, Extensions, resourceLanguageSettingsSchemaId, validateProperty, ConfigurationScope, OVERRIDE_PROPERTY_PATTERN, OVERRIDE_PROPERTY_REGEX } from 'vs/platform/configuration/common/configurationRegistry';
|
import { IConfigurationNode, IConfigurationRegistry, Extensions, resourceLanguageSettingsSchemaId, validateProperty, ConfigurationScope, OVERRIDE_PROPERTY_PATTERN, OVERRIDE_PROPERTY_REGEX, windowSettings, resourceSettings, machineOverridableSettings } from 'vs/platform/configuration/common/configurationRegistry';
|
||||||
import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry';
|
import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry';
|
||||||
import { workspaceSettingsSchemaId, launchSchemaId, tasksSchemaId } from 'vs/workbench/services/configuration/common/configuration';
|
import { workspaceSettingsSchemaId, launchSchemaId, tasksSchemaId } from 'vs/workbench/services/configuration/common/configuration';
|
||||||
import { isObject } from 'vs/base/common/types';
|
import { isObject } from 'vs/base/common/types';
|
||||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||||
import { IStringDictionary } from 'vs/base/common/collections';
|
import { IStringDictionary } from 'vs/base/common/collections';
|
||||||
|
|
||||||
|
const jsonRegistry = Registry.as<IJSONContributionRegistry>(JSONExtensions.JSONContribution);
|
||||||
const configurationRegistry = Registry.as<IConfigurationRegistry>(Extensions.Configuration);
|
const configurationRegistry = Registry.as<IConfigurationRegistry>(Extensions.Configuration);
|
||||||
|
|
||||||
const configurationEntrySchema: IJSONSchema = {
|
const configurationEntrySchema: IJSONSchema = {
|
||||||
|
@ -111,21 +112,34 @@ const configurationEntrySchema: IJSONSchema = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const configurationDefaultsSchemaId = 'vscode://schemas/settings/configurationDefaults';
|
||||||
|
const configurationDefaultsSchema: IJSONSchema = {
|
||||||
|
type: 'object',
|
||||||
|
description: nls.localize('configurationDefaults.description', 'Contribute defaults for configurations'),
|
||||||
|
properties: {},
|
||||||
|
patternProperties: {
|
||||||
|
[OVERRIDE_PROPERTY_PATTERN]: {
|
||||||
|
type: 'object',
|
||||||
|
default: {},
|
||||||
|
$ref: resourceLanguageSettingsSchemaId,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
additionalProperties: false
|
||||||
|
};
|
||||||
|
jsonRegistry.registerSchema(configurationDefaultsSchemaId, configurationDefaultsSchema);
|
||||||
|
configurationRegistry.onDidSchemaChange(() => {
|
||||||
|
configurationDefaultsSchema.properties = {
|
||||||
|
...machineOverridableSettings.properties,
|
||||||
|
...windowSettings.properties,
|
||||||
|
...resourceSettings.properties
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
// BEGIN VSCode extension point `configurationDefaults`
|
// BEGIN VSCode extension point `configurationDefaults`
|
||||||
const defaultConfigurationExtPoint = ExtensionsRegistry.registerExtensionPoint<IConfigurationNode>({
|
const defaultConfigurationExtPoint = ExtensionsRegistry.registerExtensionPoint<IConfigurationNode>({
|
||||||
extensionPoint: 'configurationDefaults',
|
extensionPoint: 'configurationDefaults',
|
||||||
jsonSchema: {
|
jsonSchema: {
|
||||||
description: nls.localize('vscode.extension.contributes.defaultConfiguration', 'Contributes default editor configuration settings by language.'),
|
$ref: configurationDefaultsSchemaId,
|
||||||
type: 'object',
|
|
||||||
patternProperties: {
|
|
||||||
[OVERRIDE_PROPERTY_PATTERN]: {
|
|
||||||
type: 'object',
|
|
||||||
default: {},
|
|
||||||
$ref: resourceLanguageSettingsSchemaId,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
errorMessage: nls.localize('config.property.defaultConfiguration.languageExpected', "Language selector expected (e.g. [\"java\"])"),
|
|
||||||
additionalProperties: false
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
defaultConfigurationExtPoint.setHandler((extensions, { added, removed }) => {
|
defaultConfigurationExtPoint.setHandler((extensions, { added, removed }) => {
|
||||||
|
@ -134,12 +148,17 @@ defaultConfigurationExtPoint.setHandler((extensions, { added, removed }) => {
|
||||||
configurationRegistry.deregisterDefaultConfigurations(removedDefaultConfigurations);
|
configurationRegistry.deregisterDefaultConfigurations(removedDefaultConfigurations);
|
||||||
}
|
}
|
||||||
if (added.length) {
|
if (added.length) {
|
||||||
|
const registeredProperties = configurationRegistry.getConfigurationProperties();
|
||||||
|
const allowedScopes = [ConfigurationScope.MACHINE_OVERRIDABLE, ConfigurationScope.WINDOW, ConfigurationScope.RESOURCE, ConfigurationScope.LANGUAGE_OVERRIDABLE];
|
||||||
const addedDefaultConfigurations = added.map<IStringDictionary<any>>(extension => {
|
const addedDefaultConfigurations = added.map<IStringDictionary<any>>(extension => {
|
||||||
const defaults: IStringDictionary<any> = objects.deepClone(extension.value);
|
const defaults: IStringDictionary<any> = objects.deepClone(extension.value);
|
||||||
for (const key of Object.keys(defaults)) {
|
for (const key of Object.keys(defaults)) {
|
||||||
if (!OVERRIDE_PROPERTY_REGEX.test(key) || typeof defaults[key] !== 'object') {
|
if (!OVERRIDE_PROPERTY_REGEX.test(key)) {
|
||||||
extension.collector.warn(nls.localize('config.property.defaultConfiguration.warning', "Cannot register configuration defaults for '{0}'. Only defaults for language specific settings are supported.", key));
|
const registeredPropertyScheme = registeredProperties[key];
|
||||||
delete defaults[key];
|
if (registeredPropertyScheme.scope && !allowedScopes.includes(registeredPropertyScheme.scope)) {
|
||||||
|
extension.collector.warn(nls.localize('config.property.defaultConfiguration.warning', "Cannot register configuration defaults for '{0}'. Only defaults for machine-overridable, window, resource and language overridable scoped settings are supported.", key));
|
||||||
|
delete defaults[key];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return defaults;
|
return defaults;
|
||||||
|
@ -273,7 +292,6 @@ configurationExtPoint.setHandler((extensions, { added, removed }) => {
|
||||||
});
|
});
|
||||||
// END VSCode extension point `configuration`
|
// END VSCode extension point `configuration`
|
||||||
|
|
||||||
const jsonRegistry = Registry.as<IJSONContributionRegistry>(JSONExtensions.JSONContribution);
|
|
||||||
jsonRegistry.registerSchema('vscode://schemas/workspaceConfig', {
|
jsonRegistry.registerSchema('vscode://schemas/workspaceConfig', {
|
||||||
allowComments: true,
|
allowComments: true,
|
||||||
allowTrailingCommas: true,
|
allowTrailingCommas: true,
|
||||||
|
|
|
@ -29,7 +29,7 @@ import { setFullscreen } from 'vs/base/browser/browser';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { IWorkspaceInitializationPayload } from 'vs/platform/workspaces/common/workspaces';
|
import { IWorkspaceInitializationPayload } from 'vs/platform/workspaces/common/workspaces';
|
||||||
import { WorkspaceService } from 'vs/workbench/services/configuration/browser/configurationService';
|
import { WorkspaceService } from 'vs/workbench/services/configuration/browser/configurationService';
|
||||||
import { ConfigurationCache } from 'vs/workbench/services/configuration/browser/configurationCache';
|
import { ConfigurationCache } from 'vs/workbench/services/configuration/common/configurationCache';
|
||||||
import { ISignService } from 'vs/platform/sign/common/sign';
|
import { ISignService } from 'vs/platform/sign/common/sign';
|
||||||
import { SignService } from 'vs/platform/sign/browser/signService';
|
import { SignService } from 'vs/platform/sign/browser/signService';
|
||||||
import type { IWorkbenchConstructionOptions, IWorkspace, IWorkbench } from 'vs/workbench/workbench.web.api';
|
import type { IWorkbenchConstructionOptions, IWorkspace, IWorkbench } from 'vs/workbench/workbench.web.api';
|
||||||
|
@ -356,7 +356,8 @@ class BrowserMain extends Disposable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async createWorkspaceService(payload: IWorkspaceInitializationPayload, environmentService: IWorkbenchEnvironmentService, fileService: FileService, remoteAgentService: IRemoteAgentService, uriIdentityService: IUriIdentityService, logService: ILogService): Promise<WorkspaceService> {
|
private async createWorkspaceService(payload: IWorkspaceInitializationPayload, environmentService: IWorkbenchEnvironmentService, fileService: FileService, remoteAgentService: IRemoteAgentService, uriIdentityService: IUriIdentityService, logService: ILogService): Promise<WorkspaceService> {
|
||||||
const workspaceService = new WorkspaceService({ remoteAuthority: this.configuration.remoteAuthority, configurationCache: new ConfigurationCache() }, environmentService, fileService, remoteAgentService, uriIdentityService, logService);
|
const configurationCache = new ConfigurationCache([Schemas.file, Schemas.userData, Schemas.tmp] /* Cache all non native resources */, environmentService, fileService);
|
||||||
|
const workspaceService = new WorkspaceService({ remoteAuthority: this.configuration.remoteAuthority, configurationCache }, environmentService, fileService, remoteAgentService, uriIdentityService, logService);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await workspaceService.initialize(payload);
|
await workspaceService.initialize(payload);
|
||||||
|
|
|
@ -212,10 +212,16 @@ declare module DebugProtocol {
|
||||||
export interface OutputEvent extends Event {
|
export interface OutputEvent extends Event {
|
||||||
// event: 'output';
|
// event: 'output';
|
||||||
body: {
|
body: {
|
||||||
/** The output category. If not specified, 'console' is assumed.
|
/** The output category. If not specified or if the category is not understand by the client, 'console' is assumed.
|
||||||
Values: 'console', 'stdout', 'stderr', 'telemetry', etc.
|
Values:
|
||||||
|
'console': Show the output in the client's default message UI, e.g. a 'debug console'. This category should only be used for informational output from the debugger (as opposed to the debuggee).
|
||||||
|
'important': A hint for the client to show the ouput in the client's UI for important and highly visible information, e.g. as a popup notification. This category should only be used for important messages from the debugger (as opposed to the debuggee). Since this category value is a hint, clients might ignore the hint and assume the 'console' category.
|
||||||
|
'stdout': Show the output as normal program output from the debuggee.
|
||||||
|
'stderr': Show the output as error program output from the debuggee.
|
||||||
|
'telemetry': Send the output to telemetry instead of showing it to the user.
|
||||||
|
etc.
|
||||||
*/
|
*/
|
||||||
category?: 'console' | 'stdout' | 'stderr' | 'telemetry' | string;
|
category?: 'console' | 'important' | 'stdout' | 'stderr' | 'telemetry' | string;
|
||||||
/** The output to report. */
|
/** The output to report. */
|
||||||
output: string;
|
output: string;
|
||||||
/** Support for keeping an output log organized by grouping related messages.
|
/** Support for keeping an output log organized by grouping related messages.
|
||||||
|
@ -854,7 +860,7 @@ declare module DebugProtocol {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Continue request; value of command field is 'continue'.
|
/** Continue request; value of command field is 'continue'.
|
||||||
The request starts the debuggee to run again.
|
The request resumes execution of all threads. If the debug adapter supports single thread execution (see capability 'supportsSingleThreadExecutionRequests') setting the 'singleThread' argument to true resumes only the specified thread. If not all threads were resumed, the 'allThreadsContinued' attribute of the response must be set to false.
|
||||||
*/
|
*/
|
||||||
export interface ContinueRequest extends Request {
|
export interface ContinueRequest extends Request {
|
||||||
// command: 'continue';
|
// command: 'continue';
|
||||||
|
@ -863,24 +869,23 @@ declare module DebugProtocol {
|
||||||
|
|
||||||
/** Arguments for 'continue' request. */
|
/** Arguments for 'continue' request. */
|
||||||
export interface ContinueArguments {
|
export interface ContinueArguments {
|
||||||
/** Continue execution for the specified thread (if possible).
|
/** Specifies the active thread. If the debug adapter supports single thread execution (see 'supportsSingleThreadExecutionRequests') and the optional argument 'singleThread' is true, only the thread with this ID is resumed. */
|
||||||
If the backend cannot continue on a single thread but will continue on all threads, it should set the 'allThreadsContinued' attribute in the response to true.
|
|
||||||
*/
|
|
||||||
threadId: number;
|
threadId: number;
|
||||||
|
/** If this optional flag is true, execution is resumed only for the thread with given 'threadId'. */
|
||||||
|
singleThread?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Response to 'continue' request. */
|
/** Response to 'continue' request. */
|
||||||
export interface ContinueResponse extends Response {
|
export interface ContinueResponse extends Response {
|
||||||
body: {
|
body: {
|
||||||
/** If true, the 'continue' request has ignored the specified thread and continued all threads instead.
|
/** The value true (or a missing property) signals to the client that all threads have been resumed. The value false must be returned if not all threads were resumed. */
|
||||||
If this attribute is missing a value of 'true' is assumed for backward compatibility.
|
|
||||||
*/
|
|
||||||
allThreadsContinued?: boolean;
|
allThreadsContinued?: boolean;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Next request; value of command field is 'next'.
|
/** Next request; value of command field is 'next'.
|
||||||
The request starts the debuggee to run again for one step.
|
The request executes one step (in the given granularity) for the specified thread and allows all other threads to run freely by resuming them.
|
||||||
|
If the debug adapter supports single thread execution (see capability 'supportsSingleThreadExecutionRequests') setting the 'singleThread' argument to true prevents other suspended threads from resuming.
|
||||||
The debug adapter first sends the response and then a 'stopped' event (with reason 'step') after the step has completed.
|
The debug adapter first sends the response and then a 'stopped' event (with reason 'step') after the step has completed.
|
||||||
*/
|
*/
|
||||||
export interface NextRequest extends Request {
|
export interface NextRequest extends Request {
|
||||||
|
@ -890,8 +895,10 @@ declare module DebugProtocol {
|
||||||
|
|
||||||
/** Arguments for 'next' request. */
|
/** Arguments for 'next' request. */
|
||||||
export interface NextArguments {
|
export interface NextArguments {
|
||||||
/** Execute 'next' for this thread. */
|
/** Specifies the thread for which to resume execution for one step (of the given granularity). */
|
||||||
threadId: number;
|
threadId: number;
|
||||||
|
/** If this optional flag is true, all other suspended threads are not resumed. */
|
||||||
|
singleThread?: boolean;
|
||||||
/** Optional granularity to step. If no granularity is specified, a granularity of 'statement' is assumed. */
|
/** Optional granularity to step. If no granularity is specified, a granularity of 'statement' is assumed. */
|
||||||
granularity?: SteppingGranularity;
|
granularity?: SteppingGranularity;
|
||||||
}
|
}
|
||||||
|
@ -901,8 +908,9 @@ declare module DebugProtocol {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** StepIn request; value of command field is 'stepIn'.
|
/** StepIn request; value of command field is 'stepIn'.
|
||||||
The request starts the debuggee to step into a function/method if possible.
|
The request resumes the given thread to step into a function/method and allows all other threads to run freely by resuming them.
|
||||||
If it cannot step into a target, 'stepIn' behaves like 'next'.
|
If the debug adapter supports single thread execution (see capability 'supportsSingleThreadExecutionRequests') setting the 'singleThread' argument to true prevents other suspended threads from resuming.
|
||||||
|
If the request cannot step into a target, 'stepIn' behaves like the 'next' request.
|
||||||
The debug adapter first sends the response and then a 'stopped' event (with reason 'step') after the step has completed.
|
The debug adapter first sends the response and then a 'stopped' event (with reason 'step') after the step has completed.
|
||||||
If there are multiple function/method calls (or other targets) on the source line,
|
If there are multiple function/method calls (or other targets) on the source line,
|
||||||
the optional argument 'targetId' can be used to control into which target the 'stepIn' should occur.
|
the optional argument 'targetId' can be used to control into which target the 'stepIn' should occur.
|
||||||
|
@ -915,8 +923,10 @@ declare module DebugProtocol {
|
||||||
|
|
||||||
/** Arguments for 'stepIn' request. */
|
/** Arguments for 'stepIn' request. */
|
||||||
export interface StepInArguments {
|
export interface StepInArguments {
|
||||||
/** Execute 'stepIn' for this thread. */
|
/** Specifies the thread for which to resume execution for one step-into (of the given granularity). */
|
||||||
threadId: number;
|
threadId: number;
|
||||||
|
/** If this optional flag is true, all other suspended threads are not resumed. */
|
||||||
|
singleThread?: boolean;
|
||||||
/** Optional id of the target to step into. */
|
/** Optional id of the target to step into. */
|
||||||
targetId?: number;
|
targetId?: number;
|
||||||
/** Optional granularity to step. If no granularity is specified, a granularity of 'statement' is assumed. */
|
/** Optional granularity to step. If no granularity is specified, a granularity of 'statement' is assumed. */
|
||||||
|
@ -928,7 +938,8 @@ declare module DebugProtocol {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** StepOut request; value of command field is 'stepOut'.
|
/** StepOut request; value of command field is 'stepOut'.
|
||||||
The request starts the debuggee to run again for one step.
|
The request resumes the given thread to step out (return) from a function/method and allows all other threads to run freely by resuming them.
|
||||||
|
If the debug adapter supports single thread execution (see capability 'supportsSingleThreadExecutionRequests') setting the 'singleThread' argument to true prevents other suspended threads from resuming.
|
||||||
The debug adapter first sends the response and then a 'stopped' event (with reason 'step') after the step has completed.
|
The debug adapter first sends the response and then a 'stopped' event (with reason 'step') after the step has completed.
|
||||||
*/
|
*/
|
||||||
export interface StepOutRequest extends Request {
|
export interface StepOutRequest extends Request {
|
||||||
|
@ -938,8 +949,10 @@ declare module DebugProtocol {
|
||||||
|
|
||||||
/** Arguments for 'stepOut' request. */
|
/** Arguments for 'stepOut' request. */
|
||||||
export interface StepOutArguments {
|
export interface StepOutArguments {
|
||||||
/** Execute 'stepOut' for this thread. */
|
/** Specifies the thread for which to resume execution for one step-out (of the given granularity). */
|
||||||
threadId: number;
|
threadId: number;
|
||||||
|
/** If this optional flag is true, all other suspended threads are not resumed. */
|
||||||
|
singleThread?: boolean;
|
||||||
/** Optional granularity to step. If no granularity is specified, a granularity of 'statement' is assumed. */
|
/** Optional granularity to step. If no granularity is specified, a granularity of 'statement' is assumed. */
|
||||||
granularity?: SteppingGranularity;
|
granularity?: SteppingGranularity;
|
||||||
}
|
}
|
||||||
|
@ -949,7 +962,8 @@ declare module DebugProtocol {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** StepBack request; value of command field is 'stepBack'.
|
/** StepBack request; value of command field is 'stepBack'.
|
||||||
The request starts the debuggee to run one step backwards.
|
The request executes one backward step (in the given granularity) for the specified thread and allows all other threads to run backward freely by resuming them.
|
||||||
|
If the debug adapter supports single thread execution (see capability 'supportsSingleThreadExecutionRequests') setting the 'singleThread' argument to true prevents other suspended threads from resuming.
|
||||||
The debug adapter first sends the response and then a 'stopped' event (with reason 'step') after the step has completed.
|
The debug adapter first sends the response and then a 'stopped' event (with reason 'step') after the step has completed.
|
||||||
Clients should only call this request if the capability 'supportsStepBack' is true.
|
Clients should only call this request if the capability 'supportsStepBack' is true.
|
||||||
*/
|
*/
|
||||||
|
@ -960,8 +974,10 @@ declare module DebugProtocol {
|
||||||
|
|
||||||
/** Arguments for 'stepBack' request. */
|
/** Arguments for 'stepBack' request. */
|
||||||
export interface StepBackArguments {
|
export interface StepBackArguments {
|
||||||
/** Execute 'stepBack' for this thread. */
|
/** Specifies the thread for which to resume execution for one step backwards (of the given granularity). */
|
||||||
threadId: number;
|
threadId: number;
|
||||||
|
/** If this optional flag is true, all other suspended threads are not resumed. */
|
||||||
|
singleThread?: boolean;
|
||||||
/** Optional granularity to step. If no granularity is specified, a granularity of 'statement' is assumed. */
|
/** Optional granularity to step. If no granularity is specified, a granularity of 'statement' is assumed. */
|
||||||
granularity?: SteppingGranularity;
|
granularity?: SteppingGranularity;
|
||||||
}
|
}
|
||||||
|
@ -971,7 +987,7 @@ declare module DebugProtocol {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** ReverseContinue request; value of command field is 'reverseContinue'.
|
/** ReverseContinue request; value of command field is 'reverseContinue'.
|
||||||
The request starts the debuggee to run backward.
|
The request resumes backward execution of all threads. If the debug adapter supports single thread execution (see capability 'supportsSingleThreadExecutionRequests') setting the 'singleThread' argument to true resumes only the specified thread. If not all threads were resumed, the 'allThreadsContinued' attribute of the response must be set to false.
|
||||||
Clients should only call this request if the capability 'supportsStepBack' is true.
|
Clients should only call this request if the capability 'supportsStepBack' is true.
|
||||||
*/
|
*/
|
||||||
export interface ReverseContinueRequest extends Request {
|
export interface ReverseContinueRequest extends Request {
|
||||||
|
@ -981,8 +997,10 @@ declare module DebugProtocol {
|
||||||
|
|
||||||
/** Arguments for 'reverseContinue' request. */
|
/** Arguments for 'reverseContinue' request. */
|
||||||
export interface ReverseContinueArguments {
|
export interface ReverseContinueArguments {
|
||||||
/** Execute 'reverseContinue' for this thread. */
|
/** Specifies the active thread. If the debug adapter supports single thread execution (see 'supportsSingleThreadExecutionRequests') and the optional argument 'singleThread' is true, only the thread with this ID is resumed. */
|
||||||
threadId: number;
|
threadId: number;
|
||||||
|
/** If this optional flag is true, backward execution is resumed only for the thread with given 'threadId'. */
|
||||||
|
singleThread?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Response to 'reverseContinue' request. This is just an acknowledgement, so no body field is required. */
|
/** Response to 'reverseContinue' request. This is just an acknowledgement, so no body field is required. */
|
||||||
|
@ -1702,6 +1720,8 @@ declare module DebugProtocol {
|
||||||
supportsInstructionBreakpoints?: boolean;
|
supportsInstructionBreakpoints?: boolean;
|
||||||
/** The debug adapter supports 'filterOptions' as an argument on the 'setExceptionBreakpoints' request. */
|
/** The debug adapter supports 'filterOptions' as an argument on the 'setExceptionBreakpoints' request. */
|
||||||
supportsExceptionFilterOptions?: boolean;
|
supportsExceptionFilterOptions?: boolean;
|
||||||
|
/** The debug adapter supports the 'singleThread' property on the execution requests ('continue', 'next', 'stepIn', 'stepOut', 'reverseContinue', 'stepBack'). */
|
||||||
|
supportsSingleThreadExecutionRequests?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** An ExceptionBreakpointsFilter is shown in the UI as an filter option for configuring how exceptions are dealt with. */
|
/** An ExceptionBreakpointsFilter is shown in the UI as an filter option for configuring how exceptions are dealt with. */
|
||||||
|
|
|
@ -149,7 +149,10 @@ suite('Debug - Debugger', () => {
|
||||||
assert.deepStrictEqual(ae!.args, debuggerContribution.args);
|
assert.deepStrictEqual(ae!.args, debuggerContribution.args);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('merge platform specific attributes', () => {
|
test('merge platform specific attributes', function () {
|
||||||
|
if (!process.versions.electron) {
|
||||||
|
this.skip(); //TODO@debug this test fails when run in node.js environments
|
||||||
|
}
|
||||||
const ae = ExecutableDebugAdapter.platformAdapterExecutable([extensionDescriptor1, extensionDescriptor2], 'mock')!;
|
const ae = ExecutableDebugAdapter.platformAdapterExecutable([extensionDescriptor1, extensionDescriptor2], 'mock')!;
|
||||||
assert.strictEqual(ae.command, platform.isLinux ? 'linuxRuntime' : (platform.isMacintosh ? 'osxRuntime' : 'winRuntime'));
|
assert.strictEqual(ae.command, platform.isLinux ? 'linuxRuntime' : (platform.isMacintosh ? 'osxRuntime' : 'winRuntime'));
|
||||||
const xprogram = platform.isLinux ? 'linuxProgram' : (platform.isMacintosh ? 'osxProgram' : 'winProgram');
|
const xprogram = platform.isLinux ? 'linuxProgram' : (platform.isMacintosh ? 'osxProgram' : 'winProgram');
|
||||||
|
|
|
@ -302,7 +302,7 @@ export class ExperimentService extends Disposable implements IExperimentService
|
||||||
type ExperimentsClassification = {
|
type ExperimentsClassification = {
|
||||||
experiments: { classification: 'SystemMetaData', purpose: 'FeatureInsight'; };
|
experiments: { classification: 'SystemMetaData', purpose: 'FeatureInsight'; };
|
||||||
};
|
};
|
||||||
this.telemetryService.publicLog2<{ experiments: IExperiment[]; }, ExperimentsClassification>('experiments', { experiments: this._experiments });
|
this.telemetryService.publicLog2<{ experiments: string[]; }, ExperimentsClassification>('experiments', { experiments: this._experiments.map(e => e.id) });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ import {
|
||||||
UpdateAction, ReloadAction, EnableDropDownAction, DisableDropDownAction, ExtensionStatusLabelAction, SetFileIconThemeAction, SetColorThemeAction,
|
UpdateAction, ReloadAction, EnableDropDownAction, DisableDropDownAction, ExtensionStatusLabelAction, SetFileIconThemeAction, SetColorThemeAction,
|
||||||
RemoteInstallAction, ExtensionStatusAction, LocalInstallAction, ToggleSyncExtensionAction, SetProductIconThemeAction,
|
RemoteInstallAction, ExtensionStatusAction, LocalInstallAction, ToggleSyncExtensionAction, SetProductIconThemeAction,
|
||||||
ActionWithDropDownAction, InstallDropdownAction, InstallingLabelAction, UninstallAction, ExtensionActionWithDropdownActionViewItem, ExtensionDropDownAction,
|
ActionWithDropDownAction, InstallDropdownAction, InstallingLabelAction, UninstallAction, ExtensionActionWithDropdownActionViewItem, ExtensionDropDownAction,
|
||||||
InstallAnotherVersionAction, ExtensionEditorManageExtensionAction, WebInstallAction, UsePreReleaseVersionAction, StopUsingPreReleaseVersionAction
|
InstallAnotherVersionAction, ExtensionEditorManageExtensionAction, WebInstallAction, SwitchToPreReleaseVersionAction, SwitchToReleasedVersionAction
|
||||||
} from 'vs/workbench/contrib/extensions/browser/extensionsActions';
|
} from 'vs/workbench/contrib/extensions/browser/extensionsActions';
|
||||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||||
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
|
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
|
||||||
|
@ -426,7 +426,7 @@ export class ExtensionEditor extends EditorPane {
|
||||||
}
|
}
|
||||||
|
|
||||||
const widgets = [
|
const widgets = [
|
||||||
this.instantiationService.createInstance(PreReleaseIndicatorWidget, template.preRelease),
|
this.instantiationService.createInstance(PreReleaseIndicatorWidget, template.preRelease, { label: true, icon: false }),
|
||||||
remoteBadge,
|
remoteBadge,
|
||||||
this.instantiationService.createInstance(InstallCountWidget, template.installCount, false),
|
this.instantiationService.createInstance(InstallCountWidget, template.installCount, false),
|
||||||
this.instantiationService.createInstance(RatingsWidget, template.rating, false)
|
this.instantiationService.createInstance(RatingsWidget, template.rating, false)
|
||||||
|
@ -454,8 +454,8 @@ export class ExtensionEditor extends EditorPane {
|
||||||
this.instantiationService.createInstance(InstallAnotherVersionAction),
|
this.instantiationService.createInstance(InstallAnotherVersionAction),
|
||||||
]
|
]
|
||||||
]),
|
]),
|
||||||
this.instantiationService.createInstance(UsePreReleaseVersionAction),
|
this.instantiationService.createInstance(SwitchToPreReleaseVersionAction),
|
||||||
this.instantiationService.createInstance(StopUsingPreReleaseVersionAction),
|
this.instantiationService.createInstance(SwitchToReleasedVersionAction),
|
||||||
this.instantiationService.createInstance(ToggleSyncExtensionAction),
|
this.instantiationService.createInstance(ToggleSyncExtensionAction),
|
||||||
new ExtensionEditorManageExtensionAction(this.scopedContextKeyService || this.contextKeyService, this.instantiationService),
|
new ExtensionEditorManageExtensionAction(this.scopedContextKeyService || this.contextKeyService, this.instantiationService),
|
||||||
];
|
];
|
||||||
|
|
|
@ -15,7 +15,7 @@ import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWo
|
||||||
import { IOutputChannelRegistry, Extensions as OutputExtensions } from 'vs/workbench/services/output/common/output';
|
import { IOutputChannelRegistry, Extensions as OutputExtensions } from 'vs/workbench/services/output/common/output';
|
||||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||||
import { VIEWLET_ID, IExtensionsWorkbenchService, IExtensionsViewPaneContainer, TOGGLE_IGNORE_EXTENSION_ACTION_ID, INSTALL_EXTENSION_FROM_VSIX_COMMAND_ID, DefaultViewsContext, ExtensionsSortByContext, WORKSPACE_RECOMMENDATIONS_VIEW_ID, IWorkspaceRecommendedExtensionsView, AutoUpdateConfigurationKey, HasOutdatedExtensionsContext, SELECT_INSTALL_VSIX_EXTENSION_COMMAND_ID, LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID, ExtensionEditorTab } from 'vs/workbench/contrib/extensions/common/extensions';
|
import { VIEWLET_ID, IExtensionsWorkbenchService, IExtensionsViewPaneContainer, TOGGLE_IGNORE_EXTENSION_ACTION_ID, INSTALL_EXTENSION_FROM_VSIX_COMMAND_ID, DefaultViewsContext, ExtensionsSortByContext, WORKSPACE_RECOMMENDATIONS_VIEW_ID, IWorkspaceRecommendedExtensionsView, AutoUpdateConfigurationKey, HasOutdatedExtensionsContext, SELECT_INSTALL_VSIX_EXTENSION_COMMAND_ID, LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID, ExtensionEditorTab } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||||
import { ReinstallAction, InstallSpecificVersionOfExtensionAction, ConfigureWorkspaceRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction, PromptExtensionInstallFailureAction, SearchExtensionsAction, UsePreReleaseVersionAction, StopUsingPreReleaseVersionAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
|
import { ReinstallAction, InstallSpecificVersionOfExtensionAction, ConfigureWorkspaceRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction, PromptExtensionInstallFailureAction, SearchExtensionsAction, SwitchToPreReleaseVersionAction, SwitchToReleasedVersionAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
|
||||||
import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput';
|
import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput';
|
||||||
import { ExtensionEditor } from 'vs/workbench/contrib/extensions/browser/extensionEditor';
|
import { ExtensionEditor } from 'vs/workbench/contrib/extensions/browser/extensionEditor';
|
||||||
import { StatusUpdater, MaliciousExtensionChecker, ExtensionsViewletViewsContribution, ExtensionsViewPaneContainer } from 'vs/workbench/contrib/extensions/browser/extensionsViewlet';
|
import { StatusUpdater, MaliciousExtensionChecker, ExtensionsViewletViewsContribution, ExtensionsViewPaneContainer } from 'vs/workbench/contrib/extensions/browser/extensionsViewlet';
|
||||||
|
@ -1163,9 +1163,7 @@ class ExtensionsContributions extends Disposable implements IWorkbenchContributi
|
||||||
id: MenuId.ExtensionContext,
|
id: MenuId.ExtensionContext,
|
||||||
group: '0_install',
|
group: '0_install',
|
||||||
order: 0,
|
order: 0,
|
||||||
when: ContextKeyExpr.or(
|
when: ContextKeyExpr.and(ContextKeyExpr.has('inExtensionEditor'), ContextKeyExpr.has('extensionHasPreReleaseVersion'), ContextKeyExpr.not('showPreReleaseVersion'))
|
||||||
ContextKeyExpr.and(ContextKeyExpr.not('inExtensionEditor'), ContextKeyExpr.has('extensionHasPreReleaseVersion'), ContextKeyExpr.not('galleryExtensionIsPreReleaseVersion')),
|
|
||||||
ContextKeyExpr.and(ContextKeyExpr.has('inExtensionEditor'), ContextKeyExpr.has('extensionHasPreReleaseVersion'), ContextKeyExpr.not('showPreReleaseVersion')))
|
|
||||||
},
|
},
|
||||||
run: async (accessor: ServicesAccessor, extensionId: string) => {
|
run: async (accessor: ServicesAccessor, extensionId: string) => {
|
||||||
const extensionWorkbenchService = accessor.get(IExtensionsWorkbenchService);
|
const extensionWorkbenchService = accessor.get(IExtensionsWorkbenchService);
|
||||||
|
@ -1180,9 +1178,7 @@ class ExtensionsContributions extends Disposable implements IWorkbenchContributi
|
||||||
id: MenuId.ExtensionContext,
|
id: MenuId.ExtensionContext,
|
||||||
group: '0_install',
|
group: '0_install',
|
||||||
order: 1,
|
order: 1,
|
||||||
when: ContextKeyExpr.or(
|
when: ContextKeyExpr.and(ContextKeyExpr.has('inExtensionEditor'), ContextKeyExpr.has('extensionHasPreReleaseVersion'), ContextKeyExpr.has('showPreReleaseVersion'))
|
||||||
ContextKeyExpr.and(ContextKeyExpr.not('inExtensionEditor'), ContextKeyExpr.has('extensionHasPreReleaseVersion'), ContextKeyExpr.has('galleryExtensionIsPreReleaseVersion'), ContextKeyExpr.equals('extensionStatus', 'installed')),
|
|
||||||
ContextKeyExpr.and(ContextKeyExpr.has('inExtensionEditor'), ContextKeyExpr.has('extensionHasPreReleaseVersion'), ContextKeyExpr.has('showPreReleaseVersion')))
|
|
||||||
},
|
},
|
||||||
run: async (accessor: ServicesAccessor, extensionId: string) => {
|
run: async (accessor: ServicesAccessor, extensionId: string) => {
|
||||||
const extensionWorkbenchService = accessor.get(IExtensionsWorkbenchService);
|
const extensionWorkbenchService = accessor.get(IExtensionsWorkbenchService);
|
||||||
|
@ -1191,8 +1187,8 @@ class ExtensionsContributions extends Disposable implements IWorkbenchContributi
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.registerExtensionAction({
|
this.registerExtensionAction({
|
||||||
id: UsePreReleaseVersionAction.ID,
|
id: SwitchToPreReleaseVersionAction.ID,
|
||||||
title: UsePreReleaseVersionAction.TITLE,
|
title: SwitchToPreReleaseVersionAction.TITLE,
|
||||||
menu: {
|
menu: {
|
||||||
id: MenuId.ExtensionContext,
|
id: MenuId.ExtensionContext,
|
||||||
group: '0_install',
|
group: '0_install',
|
||||||
|
@ -1208,8 +1204,8 @@ class ExtensionsContributions extends Disposable implements IWorkbenchContributi
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.registerExtensionAction({
|
this.registerExtensionAction({
|
||||||
id: StopUsingPreReleaseVersionAction.ID,
|
id: SwitchToReleasedVersionAction.ID,
|
||||||
title: StopUsingPreReleaseVersionAction.TITLE,
|
title: SwitchToReleasedVersionAction.TITLE,
|
||||||
menu: {
|
menu: {
|
||||||
id: MenuId.ExtensionContext,
|
id: MenuId.ExtensionContext,
|
||||||
group: '0_install',
|
group: '0_install',
|
||||||
|
|
|
@ -237,11 +237,11 @@ export class ActionWithDropDownAction extends ExtensionAction {
|
||||||
actions = actions.length ? actions.slice(0, actions.length - 1) : actions;
|
actions = actions.length ? actions.slice(0, actions.length - 1) : actions;
|
||||||
|
|
||||||
this.action = actions[0];
|
this.action = actions[0];
|
||||||
this._menuActions = actions.slice(1);
|
this._menuActions = actions.length > 1 ? actions : [];
|
||||||
|
|
||||||
this.enabled = !!this.action;
|
this.enabled = !!this.action;
|
||||||
if (this.action) {
|
if (this.action) {
|
||||||
this.label = this.action.label;
|
this.label = this.getLabel(this.action as ExtensionAction);
|
||||||
this.tooltip = this.action.tooltip;
|
this.tooltip = this.action.tooltip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,6 +257,10 @@ export class ActionWithDropDownAction extends ExtensionAction {
|
||||||
const enabledActions = this.extensionActions.filter(a => a.enabled);
|
const enabledActions = this.extensionActions.filter(a => a.enabled);
|
||||||
return enabledActions[0].run();
|
return enabledActions[0].run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected getLabel(action: ExtensionAction): string {
|
||||||
|
return action.label;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class AbstractInstallAction extends ExtensionAction {
|
export abstract class AbstractInstallAction extends ExtensionAction {
|
||||||
|
@ -360,8 +364,16 @@ export abstract class AbstractInstallAction extends ExtensionAction {
|
||||||
this.label = this.getLabel();
|
this.label = this.getLabel();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected getLabel(): string {
|
getLabel(primary?: boolean): string {
|
||||||
return this.installPreReleaseVersion && this.extension?.hasPreReleaseVersion ? localize('install pre-release', "Install Pre-release Version") : localize('install', "Install");
|
/* install pre-release version */
|
||||||
|
if (this.installPreReleaseVersion && this.extension?.hasPreReleaseVersion) {
|
||||||
|
return primary ? localize('install pre-release', "Install Pre-release") : localize('install pre-release version', "Install Pre-release Version");
|
||||||
|
}
|
||||||
|
/* install released version that has a pre release version */
|
||||||
|
if (this.extension?.hasPreReleaseVersion) {
|
||||||
|
return primary ? localize('install', "Install") : localize('install released version', "Install Released Version");
|
||||||
|
}
|
||||||
|
return localize('install', "Install");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected getInstallOptions(): InstallOptions {
|
protected getInstallOptions(): InstallOptions {
|
||||||
|
@ -391,8 +403,8 @@ export class InstallAction extends AbstractInstallAction {
|
||||||
Event.filter(userDataSyncResourceEnablementService.onDidChangeResourceEnablement, e => e[0] === SyncResource.Extensions))(() => this.update()));
|
Event.filter(userDataSyncResourceEnablementService.onDidChangeResourceEnablement, e => e[0] === SyncResource.Extensions))(() => this.update()));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override getLabel(): string {
|
override getLabel(primary?: boolean): string {
|
||||||
const baseLabel = super.getLabel();
|
const baseLabel = super.getLabel(primary);
|
||||||
|
|
||||||
const donotSyncLabel = localize('do no sync', "Do not sync");
|
const donotSyncLabel = localize('do no sync', "Do not sync");
|
||||||
const isMachineScoped = this.getInstallOptions().isMachineScoped;
|
const isMachineScoped = this.getInstallOptions().isMachineScoped;
|
||||||
|
@ -477,19 +489,24 @@ export class InstallDropdownAction extends ActionWithDropDownAction {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@IInstantiationService instantiationService: IInstantiationService,
|
@IInstantiationService instantiationService: IInstantiationService,
|
||||||
|
@IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService,
|
||||||
) {
|
) {
|
||||||
super(`extensions.installActions`, '', [
|
super(`extensions.installActions`, '', [
|
||||||
[
|
[
|
||||||
instantiationService.createInstance(InstallAndSyncAction, false),
|
instantiationService.createInstance(InstallAndSyncAction, extensionsWorkbenchService.preferPreReleases),
|
||||||
instantiationService.createInstance(InstallAndSyncAction, true),
|
instantiationService.createInstance(InstallAndSyncAction, !extensionsWorkbenchService.preferPreReleases),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
instantiationService.createInstance(InstallAction, false),
|
instantiationService.createInstance(InstallAction, extensionsWorkbenchService.preferPreReleases),
|
||||||
instantiationService.createInstance(InstallAction, true),
|
instantiationService.createInstance(InstallAction, !extensionsWorkbenchService.preferPreReleases),
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override getLabel(action: AbstractInstallAction): string {
|
||||||
|
return action.getLabel(true);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class InstallingLabelAction extends ExtensionAction {
|
export class InstallingLabelAction extends ExtensionAction {
|
||||||
|
@ -1056,17 +1073,17 @@ export class MenuItemExtensionAction extends ExtensionAction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class UsePreReleaseVersionAction extends ExtensionAction {
|
export class SwitchToPreReleaseVersionAction extends ExtensionAction {
|
||||||
|
|
||||||
static readonly ID = 'workbench.extensions.action.usePreReleaseVersion';
|
static readonly ID = 'workbench.extensions.action.switchToPreReleaseVersion';
|
||||||
static readonly TITLE = { value: localize('use pre-release version', "Use Pre-release Version"), original: 'Use Pre-release Version' };
|
static readonly TITLE = { value: localize('switch to pre-release version', "Switch to Pre-release Version"), original: 'Switch to Pre-release Version' };
|
||||||
|
|
||||||
private static readonly Class = `${ExtensionAction.LABEL_ACTION_CLASS} hide-when-disabled`;
|
private static readonly Class = `${ExtensionAction.LABEL_ACTION_CLASS} hide-when-disabled`;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@ICommandService private readonly commandService: ICommandService,
|
@ICommandService private readonly commandService: ICommandService,
|
||||||
) {
|
) {
|
||||||
super(UsePreReleaseVersionAction.ID, UsePreReleaseVersionAction.TITLE.value, UsePreReleaseVersionAction.Class);
|
super(SwitchToPreReleaseVersionAction.ID, SwitchToPreReleaseVersionAction.TITLE.value, SwitchToPreReleaseVersionAction.Class);
|
||||||
this.update();
|
this.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1078,21 +1095,21 @@ export class UsePreReleaseVersionAction extends ExtensionAction {
|
||||||
if (!this.enabled) {
|
if (!this.enabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return this.commandService.executeCommand(UsePreReleaseVersionAction.ID, this.extension?.identifier.id);
|
return this.commandService.executeCommand(SwitchToPreReleaseVersionAction.ID, this.extension?.identifier.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class StopUsingPreReleaseVersionAction extends ExtensionAction {
|
export class SwitchToReleasedVersionAction extends ExtensionAction {
|
||||||
|
|
||||||
static readonly ID = 'workbench.extensions.action.stopUsingPreReleaseVersion';
|
static readonly ID = 'workbench.extensions.action.switchToReleasedVersion';
|
||||||
static readonly TITLE = { value: localize('stop using pre-release version', "Stop Using Pre-release Version"), original: 'Stop Using Pre-release Version' };
|
static readonly TITLE = { value: localize('switch to released version', "Switch to Released Version"), original: 'Switch to Released Version' };
|
||||||
|
|
||||||
private static readonly Class = `${ExtensionAction.LABEL_ACTION_CLASS} hide-when-disabled`;
|
private static readonly Class = `${ExtensionAction.LABEL_ACTION_CLASS} hide-when-disabled`;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@ICommandService private readonly commandService: ICommandService,
|
@ICommandService private readonly commandService: ICommandService,
|
||||||
) {
|
) {
|
||||||
super(StopUsingPreReleaseVersionAction.ID, StopUsingPreReleaseVersionAction.TITLE.value, StopUsingPreReleaseVersionAction.Class);
|
super(SwitchToReleasedVersionAction.ID, SwitchToReleasedVersionAction.TITLE.value, SwitchToReleasedVersionAction.Class);
|
||||||
this.update();
|
this.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1104,7 +1121,7 @@ export class StopUsingPreReleaseVersionAction extends ExtensionAction {
|
||||||
if (!this.enabled) {
|
if (!this.enabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return this.commandService.executeCommand(StopUsingPreReleaseVersionAction.ID, this.extension?.identifier.id);
|
return this.commandService.executeCommand(SwitchToReleasedVersionAction.ID, this.extension?.identifier.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -138,7 +138,7 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
|
||||||
extensionPackBadgeWidget,
|
extensionPackBadgeWidget,
|
||||||
headerRemoteBadgeWidget,
|
headerRemoteBadgeWidget,
|
||||||
extensionHoverWidget,
|
extensionHoverWidget,
|
||||||
this.instantiationService.createInstance(PreReleaseIndicatorWidget, preRelease),
|
this.instantiationService.createInstance(PreReleaseIndicatorWidget, preRelease, { icon: true, label: false }),
|
||||||
this.instantiationService.createInstance(SyncIgnoredWidget, syncIgnore),
|
this.instantiationService.createInstance(SyncIgnoredWidget, syncIgnore),
|
||||||
this.instantiationService.createInstance(ExtensionActivationStatusWidget, activationStatus, true),
|
this.instantiationService.createInstance(ExtensionActivationStatusWidget, activationStatus, true),
|
||||||
this.instantiationService.createInstance(InstallCountWidget, installCount, true),
|
this.instantiationService.createInstance(InstallCountWidget, installCount, true),
|
||||||
|
|
|
@ -160,7 +160,10 @@ export class RatingsWidget extends ExtensionWidget {
|
||||||
|
|
||||||
export class PreReleaseIndicatorWidget extends ExtensionWidget {
|
export class PreReleaseIndicatorWidget extends ExtensionWidget {
|
||||||
|
|
||||||
constructor(private container: HTMLElement) {
|
constructor(
|
||||||
|
private readonly container: HTMLElement,
|
||||||
|
private readonly options: { label: boolean, icon: boolean },
|
||||||
|
) {
|
||||||
super();
|
super();
|
||||||
container.classList.add('extension-pre-release');
|
container.classList.add('extension-pre-release');
|
||||||
this.render();
|
this.render();
|
||||||
|
@ -177,7 +180,12 @@ export class PreReleaseIndicatorWidget extends ExtensionWidget {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
append(this.container, $('span' + ThemeIcon.asCSSSelector(preReleaseIcon)));
|
if (this.options?.icon) {
|
||||||
|
append(this.container, $('span' + ThemeIcon.asCSSSelector(preReleaseIcon)));
|
||||||
|
}
|
||||||
|
if (this.options?.label) {
|
||||||
|
append(this.container, $('span.pre-releaselabel', undefined, localize('pre-release-label', "Pre-release")));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -576,8 +584,8 @@ export class ExtensionHoverWidget extends ExtensionWidget {
|
||||||
}
|
}
|
||||||
const extensionPreReleaseIcon = this.themeService.getColorTheme().getColor(extensionPreReleaseIconColor);
|
const extensionPreReleaseIcon = this.themeService.getColorTheme().getColor(extensionPreReleaseIconColor);
|
||||||
const preReleaseVersionLink = `[${localize('Show prerelease version', "Pre-release version")}](${URI.parse(`command:workbench.extensions.action.showPreReleaseVersion?${encodeURIComponent(JSON.stringify([extension.identifier.id]))}`)})`;
|
const preReleaseVersionLink = `[${localize('Show prerelease version', "Pre-release version")}](${URI.parse(`command:workbench.extensions.action.showPreReleaseVersion?${encodeURIComponent(JSON.stringify([extension.identifier.id]))}`)})`;
|
||||||
const message = localize('has prerelease', "There is a new {0} of this extension available in the Marketplace.", preReleaseVersionLink);
|
const message = localize('has prerelease', "This extension has a {0} available", preReleaseVersionLink);
|
||||||
return `<span style="color:${extensionPreReleaseIcon ? Color.Format.CSS.formatHex(extensionPreReleaseIcon) : '#ffffff'};">$(${preReleaseIcon.id})</span> ${message}.`;
|
return `<span style="color:${extensionPreReleaseIcon ? Color.Format.CSS.formatHex(extensionPreReleaseIcon) : '#ffffff'};">$(${preReleaseIcon.id})</span> ${message}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -609,10 +617,4 @@ registerThemingParticipant((theme, collector) => {
|
||||||
collector.addRule(`${ThemeIcon.asCSSSelector(verifiedPublisherIcon)} { color: ${extensionVerifiedPublisherIcon}; }`);
|
collector.addRule(`${ThemeIcon.asCSSSelector(verifiedPublisherIcon)} { color: ${extensionVerifiedPublisherIcon}; }`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const extensionPreReleaseIcon = theme.getColor(extensionPreReleaseIconColor);
|
|
||||||
if (extensionPreReleaseIcon) {
|
|
||||||
collector.addRule(`.extension-bookmark .pre-release { border-top-color: ${extensionPreReleaseIcon}; }`);
|
|
||||||
collector.addRule(`.extension-bookmark .pre-release ${ThemeIcon.asCSSSelector(preReleaseIcon)} { color: #ffffff; }`);
|
|
||||||
collector.addRule(`${ThemeIcon.asCSSSelector(preReleaseIcon)} { color: ${extensionPreReleaseIcon}; }`);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -40,7 +40,7 @@ import { FileAccess } from 'vs/base/common/network';
|
||||||
import { IIgnoredExtensionsManagementService } from 'vs/platform/userDataSync/common/ignoredExtensions';
|
import { IIgnoredExtensionsManagementService } from 'vs/platform/userDataSync/common/ignoredExtensions';
|
||||||
import { IUserDataAutoSyncService } from 'vs/platform/userDataSync/common/userDataSync';
|
import { IUserDataAutoSyncService } from 'vs/platform/userDataSync/common/userDataSync';
|
||||||
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||||
import { isBoolean } from 'vs/base/common/types';
|
import { isBoolean, isUndefined } from 'vs/base/common/types';
|
||||||
import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService';
|
import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService';
|
||||||
import { IExtensionService, IExtensionsStatus } from 'vs/workbench/services/extensions/common/extensions';
|
import { IExtensionService, IExtensionsStatus } from 'vs/workbench/services/extensions/common/extensions';
|
||||||
import { ExtensionEditor } from 'vs/workbench/contrib/extensions/browser/extensionEditor';
|
import { ExtensionEditor } from 'vs/workbench/contrib/extensions/browser/extensionEditor';
|
||||||
|
@ -587,6 +587,8 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
|
||||||
private readonly _onChange: Emitter<IExtension | undefined> = new Emitter<IExtension | undefined>();
|
private readonly _onChange: Emitter<IExtension | undefined> = new Emitter<IExtension | undefined>();
|
||||||
get onChange(): Event<IExtension | undefined> { return this._onChange.event; }
|
get onChange(): Event<IExtension | undefined> { return this._onChange.event; }
|
||||||
|
|
||||||
|
readonly preferPreReleases = this.productService.quality !== 'stable';
|
||||||
|
|
||||||
private installing: IExtension[] = [];
|
private installing: IExtension[] = [];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -613,6 +615,10 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
|
||||||
@IExtensionService private readonly extensionService: IExtensionService,
|
@IExtensionService private readonly extensionService: IExtensionService,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
const preferPreReleasesValue = configurationService.getValue('_extensions.preferPreReleases');
|
||||||
|
if (!isUndefined(preferPreReleasesValue)) {
|
||||||
|
this.preferPreReleases = !!preferPreReleasesValue;
|
||||||
|
}
|
||||||
this.hasOutdatedExtensionsContextKey = HasOutdatedExtensionsContext.bindTo(contextKeyService);
|
this.hasOutdatedExtensionsContextKey = HasOutdatedExtensionsContext.bindTo(contextKeyService);
|
||||||
if (extensionManagementServerService.localExtensionManagementServer) {
|
if (extensionManagementServerService.localExtensionManagementServer) {
|
||||||
this.localExtensions = this._register(instantiationService.createInstance(Extensions, extensionManagementServerService.localExtensionManagementServer, ext => this.getExtensionState(ext)));
|
this.localExtensions = this._register(instantiationService.createInstance(Extensions, extensionManagementServerService.localExtensionManagementServer, ext => this.getExtensionState(ext)));
|
||||||
|
@ -741,6 +747,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
|
||||||
const options: IQueryOptions = CancellationToken.isCancellationToken(arg1) ? {} : arg1;
|
const options: IQueryOptions = CancellationToken.isCancellationToken(arg1) ? {} : arg1;
|
||||||
const token: CancellationToken = CancellationToken.isCancellationToken(arg1) ? arg1 : arg2;
|
const token: CancellationToken = CancellationToken.isCancellationToken(arg1) ? arg1 : arg2;
|
||||||
options.text = options.text ? this.resolveQueryText(options.text) : options.text;
|
options.text = options.text ? this.resolveQueryText(options.text) : options.text;
|
||||||
|
options.includePreRelease = isUndefined(options.includePreRelease) ? this.preferPreReleases : options.includePreRelease;
|
||||||
|
|
||||||
const report = await this.extensionManagementService.getExtensionsReport();
|
const report = await this.extensionManagementService.getExtensionsReport();
|
||||||
const maliciousSet = getMaliciousExtensionsSet(report);
|
const maliciousSet = getMaliciousExtensionsSet(report);
|
||||||
|
|
|
@ -82,6 +82,10 @@
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.extension-list-item > .details > .header-container > .header > .extension-pre-release .codicon {
|
||||||
|
color: var(--vscode-extensionIcon-preReleaseForeground) !important;
|
||||||
|
}
|
||||||
|
|
||||||
.extension-list-item > .details > .header-container > .header > .activation-status,
|
.extension-list-item > .details > .header-container > .header > .activation-status,
|
||||||
.extension-list-item > .details > .header-container > .header > .install-count,
|
.extension-list-item > .details > .header-container > .header > .install-count,
|
||||||
.extension-list-item > .details > .header-container > .header > .ratings {
|
.extension-list-item > .details > .header-container > .header > .ratings {
|
||||||
|
|
|
@ -82,17 +82,24 @@
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.extension-editor > .header > .details > .title > .pre-release {
|
|
||||||
display: flex;
|
|
||||||
margin-left: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.extension-editor > .header > .details > .title > .builtin {
|
.extension-editor > .header > .details > .title > .builtin {
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.extension-editor > .header > .details > .title > .pre-release {
|
||||||
|
display: flex;
|
||||||
|
font-size: 10px;
|
||||||
|
margin-left: 10px;
|
||||||
|
padding: 0px 4px;
|
||||||
|
border-radius: 4px;
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
background-color: var(--vscode-extensionIcon-preReleaseForeground);
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
.monaco-workbench.vs .extension-editor > .header > .details > .title > .preview {
|
.monaco-workbench.vs .extension-editor > .header > .details > .title > .preview {
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,11 @@
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.extension-bookmark > .pre-release {
|
||||||
|
border-top-color: var(--vscode-extensionIcon-preReleaseForeground);
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
.extension-bookmark > .recommendation > .codicon,
|
.extension-bookmark > .recommendation > .codicon,
|
||||||
.extension-bookmark > .pre-release > .codicon {
|
.extension-bookmark > .pre-release > .codicon {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -53,3 +58,8 @@
|
||||||
color: inherit;
|
color: inherit;
|
||||||
font-size: 80%;
|
font-size: 80%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* codicon colors */
|
||||||
|
.codicon .codicon-extensions-pre-release {
|
||||||
|
color: var(--vscode-extensionIcon-preReleaseForeground);
|
||||||
|
}
|
||||||
|
|
|
@ -84,10 +84,11 @@ export const IExtensionsWorkbenchService = createDecorator<IExtensionsWorkbenchS
|
||||||
|
|
||||||
export interface IExtensionsWorkbenchService {
|
export interface IExtensionsWorkbenchService {
|
||||||
readonly _serviceBrand: undefined;
|
readonly _serviceBrand: undefined;
|
||||||
onChange: Event<IExtension | undefined>;
|
readonly onChange: Event<IExtension | undefined>;
|
||||||
local: IExtension[];
|
readonly preferPreReleases: boolean;
|
||||||
installed: IExtension[];
|
readonly local: IExtension[];
|
||||||
outdated: IExtension[];
|
readonly installed: IExtension[];
|
||||||
|
readonly outdated: IExtension[];
|
||||||
queryLocal(server?: IExtensionManagementServer): Promise<IExtension[]>;
|
queryLocal(server?: IExtensionManagementServer): Promise<IExtension[]>;
|
||||||
queryGallery(token: CancellationToken): Promise<IPager<IExtension>>;
|
queryGallery(token: CancellationToken): Promise<IPager<IExtension>>;
|
||||||
queryGallery(options: IQueryOptions, token: CancellationToken): Promise<IPager<IExtension>>;
|
queryGallery(options: IQueryOptions, token: CancellationToken): Promise<IPager<IExtension>>;
|
||||||
|
|
|
@ -46,6 +46,7 @@ import { IViewDescriptorService, ViewContainerLocation } from 'vs/workbench/comm
|
||||||
import { Schemas } from 'vs/base/common/network';
|
import { Schemas } from 'vs/base/common/network';
|
||||||
import { platform } from 'vs/base/common/platform';
|
import { platform } from 'vs/base/common/platform';
|
||||||
import { arch } from 'vs/base/common/process';
|
import { arch } from 'vs/base/common/process';
|
||||||
|
import { IProductService } from 'vs/platform/product/common/productService';
|
||||||
|
|
||||||
suite('ExtensionsListView Tests', () => {
|
suite('ExtensionsListView Tests', () => {
|
||||||
|
|
||||||
|
@ -81,6 +82,7 @@ suite('ExtensionsListView Tests', () => {
|
||||||
instantiationService = new TestInstantiationService();
|
instantiationService = new TestInstantiationService();
|
||||||
instantiationService.stub(ITelemetryService, NullTelemetryService);
|
instantiationService.stub(ITelemetryService, NullTelemetryService);
|
||||||
instantiationService.stub(ILogService, NullLogService);
|
instantiationService.stub(ILogService, NullLogService);
|
||||||
|
instantiationService.stub(IProductService, {});
|
||||||
|
|
||||||
instantiationService.stub(IWorkspaceContextService, new TestContextService());
|
instantiationService.stub(IWorkspaceContextService, new TestContextService());
|
||||||
instantiationService.stub(IConfigurationService, new TestConfigurationService());
|
instantiationService.stub(IConfigurationService, new TestConfigurationService());
|
||||||
|
|
|
@ -323,7 +323,8 @@ MenuRegistry.appendMenuItem(MenuId.NotebookToolbar, {
|
||||||
NOTEBOOK_EDITOR_EDITABLE.isEqualTo(true),
|
NOTEBOOK_EDITOR_EDITABLE.isEqualTo(true),
|
||||||
ContextKeyExpr.notEquals('config.notebook.insertToolbarLocation', 'betweenCells'),
|
ContextKeyExpr.notEquals('config.notebook.insertToolbarLocation', 'betweenCells'),
|
||||||
ContextKeyExpr.notEquals('config.notebook.insertToolbarLocation', 'hidden'),
|
ContextKeyExpr.notEquals('config.notebook.insertToolbarLocation', 'hidden'),
|
||||||
ContextKeyExpr.notEquals(`config.${NotebookSetting.globalToolbarShowLabel}`, false)
|
ContextKeyExpr.notEquals(`config.${NotebookSetting.globalToolbarShowLabel}`, false),
|
||||||
|
ContextKeyExpr.notEquals(`config.${NotebookSetting.globalToolbarShowLabel}`, 'never')
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -870,7 +870,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.output-show-more {
|
.output-show-more {
|
||||||
padding: 8px 0;
|
padding: 8px 0 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cell-contributed-items.cell-contributed-items-left {
|
.cell-contributed-items.cell-contributed-items-left {
|
||||||
|
|
|
@ -13,7 +13,7 @@ import { format } from 'vs/base/common/jsonFormatter';
|
||||||
import { applyEdits } from 'vs/base/common/jsonEdit';
|
import { applyEdits } from 'vs/base/common/jsonEdit';
|
||||||
import { ITextModel, ITextBufferFactory, DefaultEndOfLine, ITextBuffer } from 'vs/editor/common/model';
|
import { ITextModel, ITextBufferFactory, DefaultEndOfLine, ITextBuffer } from 'vs/editor/common/model';
|
||||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
import { ILanguageSelection, IModeService } from 'vs/editor/common/services/modeService';
|
||||||
import { ITextModelContentProvider, ITextModelService } from 'vs/editor/common/services/resolverService';
|
import { ITextModelContentProvider, ITextModelService } from 'vs/editor/common/services/resolverService';
|
||||||
import * as nls from 'vs/nls';
|
import * as nls from 'vs/nls';
|
||||||
import { Extensions, IConfigurationPropertySchema, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
|
import { Extensions, IConfigurationPropertySchema, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
|
||||||
|
@ -100,6 +100,7 @@ import { NotebookExecutionService } from 'vs/workbench/contrib/notebook/browser/
|
||||||
import { INotebookExecutionService } from 'vs/workbench/contrib/notebook/common/notebookExecutionService';
|
import { INotebookExecutionService } from 'vs/workbench/contrib/notebook/common/notebookExecutionService';
|
||||||
import { INotebookKeymapService } from 'vs/workbench/contrib/notebook/common/notebookKeymapService';
|
import { INotebookKeymapService } from 'vs/workbench/contrib/notebook/common/notebookKeymapService';
|
||||||
import { NotebookKeymapService } from 'vs/workbench/contrib/notebook/browser/notebookKeymapServiceImpl';
|
import { NotebookKeymapService } from 'vs/workbench/contrib/notebook/browser/notebookKeymapServiceImpl';
|
||||||
|
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------------------------- */
|
/*--------------------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
@ -372,25 +373,55 @@ class CellInfoContentProvider {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private parseStreamOutput(resource: URI, op?: ICellOutput) {
|
private parseStreamOutput(op?: ICellOutput): { content: string, mode: ILanguageSelection } | undefined {
|
||||||
if (!op) {
|
if (!op) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const streamOutputData = getStreamOutputData(op.outputs);
|
const streamOutputData = getStreamOutputData(op.outputs);
|
||||||
if (streamOutputData) {
|
if (streamOutputData) {
|
||||||
const result = this._modelService.createModel(
|
return {
|
||||||
streamOutputData,
|
content: streamOutputData,
|
||||||
this._modeService.create('plaintext'),
|
mode: this._modeService.create('plaintext')
|
||||||
resource
|
};
|
||||||
);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _getResult(data: {
|
||||||
|
notebook: URI;
|
||||||
|
handle: number;
|
||||||
|
outputId?: string | undefined;
|
||||||
|
}, cell: NotebookCellTextModel) {
|
||||||
|
let result: { content: string, mode: ILanguageSelection } | undefined = undefined;
|
||||||
|
|
||||||
|
const mode = this._modeService.create('json');
|
||||||
|
const op = cell.outputs.find(op => op.outputId === data.outputId);
|
||||||
|
const streamOutputData = this.parseStreamOutput(op);
|
||||||
|
if (streamOutputData) {
|
||||||
|
result = streamOutputData;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const content = JSON.stringify(cell.outputs.map(output => ({
|
||||||
|
metadata: output.metadata,
|
||||||
|
outputItems: output.outputs.map(opit => ({
|
||||||
|
mimeType: opit.mime,
|
||||||
|
data: opit.data.toString()
|
||||||
|
}))
|
||||||
|
})));
|
||||||
|
|
||||||
|
const edits = format(content, undefined, {});
|
||||||
|
const outputSource = applyEdits(content, edits);
|
||||||
|
result = {
|
||||||
|
content: outputSource,
|
||||||
|
mode
|
||||||
|
};
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
async provideOutputTextContent(resource: URI): Promise<ITextModel | null> {
|
async provideOutputTextContent(resource: URI): Promise<ITextModel | null> {
|
||||||
const existing = this._modelService.getModel(resource);
|
const existing = this._modelService.getModel(resource);
|
||||||
if (existing) {
|
if (existing) {
|
||||||
|
@ -403,48 +434,37 @@ class CellInfoContentProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
const ref = await this._notebookModelResolverService.resolve(data.notebook);
|
const ref = await this._notebookModelResolverService.resolve(data.notebook);
|
||||||
let result: ITextModel | null = null;
|
const cell = ref.object.notebook.cells.find(cell => cell.handle === data.handle);
|
||||||
|
|
||||||
const mode = this._modeService.create('json');
|
if (!cell) {
|
||||||
|
return null;
|
||||||
for (const cell of ref.object.notebook.cells) {
|
|
||||||
if (cell.handle !== data.handle) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const op = cell.outputs.find(op => op.outputId === data.outputId);
|
|
||||||
const streamOutputData = this.parseStreamOutput(resource, op);
|
|
||||||
if (streamOutputData) {
|
|
||||||
result = streamOutputData;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
const content = JSON.stringify(cell.outputs.map(output => ({
|
|
||||||
metadata: output.metadata,
|
|
||||||
outputItems: output.outputs.map(opit => ({
|
|
||||||
mimeType: opit.mime,
|
|
||||||
data: opit.data.toString()
|
|
||||||
}))
|
|
||||||
})));
|
|
||||||
|
|
||||||
const edits = format(content, undefined, {});
|
|
||||||
const outputSource = applyEdits(content, edits);
|
|
||||||
result = this._modelService.createModel(
|
|
||||||
outputSource,
|
|
||||||
mode,
|
|
||||||
resource
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const result = this._getResult(data, cell);
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
const once = result.onWillDispose(() => {
|
const model = this._modelService.createModel(result.content, result.mode, resource);
|
||||||
|
const cellModelListener = Event.any(cell.onDidChangeOutputs, cell.onDidChangeOutputItems)(() => {
|
||||||
|
const newResult = this._getResult(data, cell);
|
||||||
|
|
||||||
|
if (!newResult) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
model.setValue(newResult.content);
|
||||||
|
model.setMode(newResult.mode.languageId);
|
||||||
|
});
|
||||||
|
|
||||||
|
const once = model.onWillDispose(() => {
|
||||||
once.dispose();
|
once.dispose();
|
||||||
|
cellModelListener.dispose();
|
||||||
ref.dispose();
|
ref.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
import * as DOM from 'vs/base/browser/dom';
|
import * as DOM from 'vs/base/browser/dom';
|
||||||
import { renderMarkdown } from 'vs/base/browser/markdownRenderer';
|
import { renderMarkdown } from 'vs/base/browser/markdownRenderer';
|
||||||
|
import { Codicon } from 'vs/base/common/codicons';
|
||||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
|
@ -22,7 +23,7 @@ const SIZE_LIMIT = 65535;
|
||||||
|
|
||||||
function generateViewMoreElement(notebookUri: URI, cellViewModel: IGenericCellViewModel, outputId: string, disposables: DisposableStore, openerService: IOpenerService): HTMLElement {
|
function generateViewMoreElement(notebookUri: URI, cellViewModel: IGenericCellViewModel, outputId: string, disposables: DisposableStore, openerService: IOpenerService): HTMLElement {
|
||||||
const md: IMarkdownString = {
|
const md: IMarkdownString = {
|
||||||
value: `[show more (open the raw output data in a text editor) ...](command:workbench.action.openLargeOutput?${outputId})`,
|
value: `Output exceeds [size limit](command:workbench.action.openSettings?["notebook.output.textLineLimit"]), open the full output data[ in a text editor](command:workbench.action.openLargeOutput?${outputId})`,
|
||||||
isTrusted: true,
|
isTrusted: true,
|
||||||
supportThemeIcons: true
|
supportThemeIcons: true
|
||||||
};
|
};
|
||||||
|
@ -36,6 +37,10 @@ function generateViewMoreElement(notebookUri: URI, cellViewModel: IGenericCellVi
|
||||||
openerService.open(CellUri.generateCellOutputUri(notebookUri, cellViewModel.handle, outputId));
|
openerService.open(CellUri.generateCellOutputUri(notebookUri, cellViewModel.handle, outputId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (content.startsWith('command:workbench.action.openSettings')) {
|
||||||
|
openerService.open(content, { allowCommands: true });
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
disposables: disposables
|
disposables: disposables
|
||||||
|
@ -83,12 +88,14 @@ export function truncatedArrayOfString(notebookUri: URI, cellViewModel: IGeneric
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
container.appendChild(generateViewMoreElement(notebookUri, cellViewModel, outputId, disposables, openerService));
|
||||||
|
|
||||||
const pre = DOM.$('pre');
|
const pre = DOM.$('pre');
|
||||||
container.appendChild(pre);
|
container.appendChild(pre);
|
||||||
pre.appendChild(handleANSIOutput(buffer.getValueInRange(new Range(1, 1, linesLimit - 5, buffer.getLineLastNonWhitespaceColumn(linesLimit - 5)), EndOfLinePreference.TextDefined), linkDetector, themeService, undefined));
|
pre.appendChild(handleANSIOutput(buffer.getValueInRange(new Range(1, 1, linesLimit - 5, buffer.getLineLastNonWhitespaceColumn(linesLimit - 5)), EndOfLinePreference.TextDefined), linkDetector, themeService, undefined));
|
||||||
|
|
||||||
// view more ...
|
// view more ...
|
||||||
container.appendChild(generateViewMoreElement(notebookUri, cellViewModel, outputId, disposables, openerService));
|
DOM.append(container, DOM.$('span' + Codicon.toolBarMore.cssSelector));
|
||||||
|
|
||||||
const lineCount = buffer.getLineCount();
|
const lineCount = buffer.getLineCount();
|
||||||
const pre2 = DOM.$('div');
|
const pre2 = DOM.$('div');
|
||||||
|
|
|
@ -15,12 +15,15 @@ import { PieceTreeTextBufferBuilder } from 'vs/editor/common/model/pieceTreeText
|
||||||
import { TextModel } from 'vs/editor/common/model/textModel';
|
import { TextModel } from 'vs/editor/common/model/textModel';
|
||||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||||
import { NotebookCellOutputTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellOutputTextModel';
|
import { NotebookCellOutputTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellOutputTextModel';
|
||||||
import { CellInternalMetadataChangedEvent, CellKind, ICell, ICellOutput, IOutputDto, NotebookCellInternalMetadata, NotebookCellMetadata, NotebookCellOutputsSplice, TransientOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
import { CellInternalMetadataChangedEvent, CellKind, ICell, ICellOutput, IOutputDto, IOutputItemDto, NotebookCellInternalMetadata, NotebookCellMetadata, NotebookCellOutputsSplice, TransientOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||||
|
|
||||||
export class NotebookCellTextModel extends Disposable implements ICell {
|
export class NotebookCellTextModel extends Disposable implements ICell {
|
||||||
private readonly _onDidChangeOutputs = this._register(new Emitter<NotebookCellOutputsSplice>());
|
private readonly _onDidChangeOutputs = this._register(new Emitter<NotebookCellOutputsSplice>());
|
||||||
onDidChangeOutputs: Event<NotebookCellOutputsSplice> = this._onDidChangeOutputs.event;
|
onDidChangeOutputs: Event<NotebookCellOutputsSplice> = this._onDidChangeOutputs.event;
|
||||||
|
|
||||||
|
private readonly _onDidChangeOutputItems = this._register(new Emitter<void>());
|
||||||
|
onDidChangeOutputItems: Event<void> = this._onDidChangeOutputItems.event;
|
||||||
|
|
||||||
private readonly _onDidChangeContent = this._register(new Emitter<'content' | 'language' | 'mime'>());
|
private readonly _onDidChangeContent = this._register(new Emitter<'content' | 'language' | 'mime'>());
|
||||||
onDidChangeContent: Event<'content' | 'language' | 'mime'> = this._onDidChangeContent.event;
|
onDidChangeContent: Event<'content' | 'language' | 'mime'> = this._onDidChangeContent.event;
|
||||||
|
|
||||||
|
@ -264,6 +267,24 @@ export class NotebookCellTextModel extends Disposable implements ICell {
|
||||||
this._onDidChangeOutputs.fire(splice);
|
this._onDidChangeOutputs.fire(splice);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
changeOutputItems(outputId: string, append: boolean, items: IOutputItemDto[]): boolean {
|
||||||
|
const outputIndex = this.outputs.findIndex(output => output.outputId === outputId);
|
||||||
|
|
||||||
|
if (outputIndex < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const output = this.outputs[outputIndex];
|
||||||
|
if (append) {
|
||||||
|
output.appendData(items);
|
||||||
|
} else {
|
||||||
|
output.replaceData(items);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._onDidChangeOutputItems.fire();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private _outputNotEqualFastCheck(left: ICellOutput[], right: ICellOutput[]) {
|
private _outputNotEqualFastCheck(left: ICellOutput[], right: ICellOutput[]) {
|
||||||
if (left.length !== right.length) {
|
if (left.length !== right.length) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -955,53 +955,41 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
||||||
}
|
}
|
||||||
|
|
||||||
private _appendNotebookCellOutputItems(cell: NotebookCellTextModel, outputId: string, items: IOutputItemDto[]) {
|
private _appendNotebookCellOutputItems(cell: NotebookCellTextModel, outputId: string, items: IOutputItemDto[]) {
|
||||||
const outputIndex = cell.outputs.findIndex(output => output.outputId === outputId);
|
if (cell.changeOutputItems(outputId, true, items)) {
|
||||||
|
this._pauseableEmitter.fire({
|
||||||
|
rawEvents: [{
|
||||||
|
kind: NotebookCellsChangeType.OutputItem,
|
||||||
|
index: this._cells.indexOf(cell),
|
||||||
|
outputId: outputId,
|
||||||
|
outputItems: items,
|
||||||
|
append: true,
|
||||||
|
transient: this.transientOptions.transientOutputs
|
||||||
|
|
||||||
if (outputIndex < 0) {
|
}],
|
||||||
return;
|
versionId: this.versionId,
|
||||||
|
synchronous: true,
|
||||||
|
endSelectionState: undefined
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const output = cell.outputs[outputIndex];
|
|
||||||
output.appendData(items);
|
|
||||||
this._pauseableEmitter.fire({
|
|
||||||
rawEvents: [{
|
|
||||||
kind: NotebookCellsChangeType.OutputItem,
|
|
||||||
index: this._cells.indexOf(cell),
|
|
||||||
outputId: output.outputId,
|
|
||||||
outputItems: items,
|
|
||||||
append: true,
|
|
||||||
transient: this.transientOptions.transientOutputs
|
|
||||||
|
|
||||||
}],
|
|
||||||
versionId: this.versionId,
|
|
||||||
synchronous: true,
|
|
||||||
endSelectionState: undefined
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _replaceNotebookCellOutputItems(cell: NotebookCellTextModel, outputId: string, items: IOutputItemDto[]) {
|
private _replaceNotebookCellOutputItems(cell: NotebookCellTextModel, outputId: string, items: IOutputItemDto[]) {
|
||||||
const outputIndex = cell.outputs.findIndex(output => output.outputId === outputId);
|
if (cell.changeOutputItems(outputId, false, items)) {
|
||||||
|
this._pauseableEmitter.fire({
|
||||||
|
rawEvents: [{
|
||||||
|
kind: NotebookCellsChangeType.OutputItem,
|
||||||
|
index: this._cells.indexOf(cell),
|
||||||
|
outputId: outputId,
|
||||||
|
outputItems: items,
|
||||||
|
append: false,
|
||||||
|
transient: this.transientOptions.transientOutputs
|
||||||
|
|
||||||
if (outputIndex < 0) {
|
}],
|
||||||
return;
|
versionId: this.versionId,
|
||||||
|
synchronous: true,
|
||||||
|
endSelectionState: undefined
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const output = cell.outputs[outputIndex];
|
|
||||||
output.replaceData(items);
|
|
||||||
this._pauseableEmitter.fire({
|
|
||||||
rawEvents: [{
|
|
||||||
kind: NotebookCellsChangeType.OutputItem,
|
|
||||||
index: this._cells.indexOf(cell),
|
|
||||||
outputId: output.outputId,
|
|
||||||
outputItems: items,
|
|
||||||
append: false,
|
|
||||||
transient: this.transientOptions.transientOutputs
|
|
||||||
|
|
||||||
}],
|
|
||||||
versionId: this.versionId,
|
|
||||||
synchronous: true,
|
|
||||||
endSelectionState: undefined
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _moveCellToIdx(index: number, length: number, newIdx: number, synchronous: boolean, pushedToUndoStack: boolean, beforeSelections: ISelectionState | undefined, endSelections: ISelectionState | undefined): boolean {
|
private _moveCellToIdx(index: number, length: number, newIdx: number, synchronous: boolean, pushedToUndoStack: boolean, beforeSelections: ISelectionState | undefined, endSelections: ISelectionState | undefined): boolean {
|
||||||
|
|
|
@ -133,6 +133,10 @@ export class UserSettingsRenderer extends Disposable implements IPreferencesRend
|
||||||
const editableSetting = this.getSetting(setting);
|
const editableSetting = this.getSetting(setting);
|
||||||
return !!(editableSetting && this.editSettingActionRenderer.activateOnSetting(editableSetting));
|
return !!(editableSetting && this.editSettingActionRenderer.activateOnSetting(editableSetting));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override dispose(): void {
|
||||||
|
this.preferencesModel.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class WorkspaceSettingsRenderer extends UserSettingsRenderer implements IPreferencesRenderer {
|
export class WorkspaceSettingsRenderer extends UserSettingsRenderer implements IPreferencesRenderer {
|
||||||
|
|
|
@ -194,12 +194,14 @@ export interface ITerminalService extends ITerminalInstanceHost {
|
||||||
|
|
||||||
resolveLocation(location?: ITerminalLocationOptions): TerminalLocation | undefined
|
resolveLocation(location?: ITerminalLocationOptions): TerminalLocation | undefined
|
||||||
setNativeDelegate(nativeCalls: ITerminalServiceNativeDelegate): void;
|
setNativeDelegate(nativeCalls: ITerminalServiceNativeDelegate): void;
|
||||||
|
toggleDevTools(open?: boolean): Promise<void>;
|
||||||
handleNewRegisteredBackend(backend: ITerminalBackend): void;
|
handleNewRegisteredBackend(backend: ITerminalBackend): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ITerminalServiceNativeDelegate {
|
export interface ITerminalServiceNativeDelegate {
|
||||||
getWindowCount(): Promise<number>;
|
getWindowCount(): Promise<number>;
|
||||||
|
openDevTools(): Promise<void>;
|
||||||
|
toggleDevTools(): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -754,7 +756,7 @@ export interface ITerminalInstance {
|
||||||
|
|
||||||
addDisposable(disposable: IDisposable): void;
|
addDisposable(disposable: IDisposable): void;
|
||||||
|
|
||||||
toggleEscapeSequenceLogging(): void;
|
toggleEscapeSequenceLogging(): Promise<boolean>;
|
||||||
|
|
||||||
getInitialCwd(): Promise<string>;
|
getInitialCwd(): Promise<string>;
|
||||||
getCwd(): Promise<string>;
|
getCwd(): Promise<string>;
|
||||||
|
|
|
@ -1156,8 +1156,10 @@ export function registerTerminalActions() {
|
||||||
precondition: TerminalContextKeys.processSupported
|
precondition: TerminalContextKeys.processSupported
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
run(accessor: ServicesAccessor) {
|
async run(accessor: ServicesAccessor) {
|
||||||
accessor.get(ITerminalService).activeInstance?.toggleEscapeSequenceLogging();
|
const terminalService = accessor.get(ITerminalService);
|
||||||
|
const toggledOn = await terminalService.activeInstance?.toggleEscapeSequenceLogging();
|
||||||
|
terminalService.toggleDevTools(toggledOn);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
registerAction2(class extends Action2 {
|
registerAction2(class extends Action2 {
|
||||||
|
|
|
@ -1751,9 +1751,10 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async toggleEscapeSequenceLogging(): Promise<void> {
|
async toggleEscapeSequenceLogging(): Promise<boolean> {
|
||||||
const xterm = await this._xtermReadyPromise;
|
const xterm = await this._xtermReadyPromise;
|
||||||
xterm.raw.options.logLevel = xterm.raw.options.logLevel === 'debug' ? 'info' : 'debug';
|
xterm.raw.options.logLevel = xterm.raw.options.logLevel === 'debug' ? 'info' : 'debug';
|
||||||
|
return xterm.raw.options.logLevel === 'debug';
|
||||||
}
|
}
|
||||||
|
|
||||||
async getInitialCwd(): Promise<string> {
|
async getInitialCwd(): Promise<string> {
|
||||||
|
|
|
@ -540,6 +540,13 @@ export class TerminalService implements ITerminalService {
|
||||||
this._nativeDelegate = nativeDelegate;
|
this._nativeDelegate = nativeDelegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async toggleDevTools(open?: boolean): Promise<void> {
|
||||||
|
if (open) {
|
||||||
|
this._nativeDelegate?.openDevTools();
|
||||||
|
} else {
|
||||||
|
this._nativeDelegate?.toggleDevTools();
|
||||||
|
}
|
||||||
|
}
|
||||||
private _shouldReviveProcesses(reason: ShutdownReason): boolean {
|
private _shouldReviveProcesses(reason: ShutdownReason): boolean {
|
||||||
if (!this._configHelper.config.enablePersistentSessions) {
|
if (!this._configHelper.config.enablePersistentSessions) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -20,7 +20,7 @@ export interface IXtermCore {
|
||||||
height: number;
|
height: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
_coreService: {
|
coreService: {
|
||||||
triggerDataEvent(data: string, wasUserInput?: boolean): void;
|
triggerDataEvent(data: string, wasUserInput?: boolean): void;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,9 @@ export class TerminalNativeContribution extends Disposable implements IWorkbench
|
||||||
this._register(nativeHostService.onDidResumeOS(() => this._onOsResume()));
|
this._register(nativeHostService.onDidResumeOS(() => this._onOsResume()));
|
||||||
|
|
||||||
this._terminalService.setNativeDelegate({
|
this._terminalService.setNativeDelegate({
|
||||||
getWindowCount: () => nativeHostService.getWindowCount()
|
getWindowCount: () => nativeHostService.getWindowCount(),
|
||||||
|
openDevTools: () => nativeHostService.openDevTools(),
|
||||||
|
toggleDevTools: () => nativeHostService.toggleDevTools()
|
||||||
});
|
});
|
||||||
|
|
||||||
const connection = remoteAgentService.getConnection();
|
const connection = remoteAgentService.getConnection();
|
||||||
|
|
|
@ -19,6 +19,7 @@ import * as extpath from 'vs/base/common/extpath';
|
||||||
import { FuzzyScore } from 'vs/base/common/filters';
|
import { FuzzyScore } from 'vs/base/common/filters';
|
||||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||||
import { Disposable, dispose, IDisposable, MutableDisposable } from 'vs/base/common/lifecycle';
|
import { Disposable, dispose, IDisposable, MutableDisposable } from 'vs/base/common/lifecycle';
|
||||||
|
import { fuzzyContains } from 'vs/base/common/strings';
|
||||||
import { isDefined } from 'vs/base/common/types';
|
import { isDefined } from 'vs/base/common/types';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import 'vs/css!./media/testing';
|
import 'vs/css!./media/testing';
|
||||||
|
@ -907,7 +908,7 @@ class TestsFilter implements ITreeFilter<TestExplorerTreeElement> {
|
||||||
const data = e.label.toLowerCase();
|
const data = e.label.toLowerCase();
|
||||||
|
|
||||||
for (const { include, text } of this.state.globList) {
|
for (const { include, text } of this.state.globList) {
|
||||||
if (data.includes(text)) {
|
if (fuzzyContains(data, text)) {
|
||||||
included = include ? FilterResult.Include : FilterResult.Exclude;
|
included = include ? FilterResult.Include : FilterResult.Exclude;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteA
|
||||||
import { FileService } from 'vs/platform/files/common/fileService';
|
import { FileService } from 'vs/platform/files/common/fileService';
|
||||||
import { IFileService } from 'vs/platform/files/common/files';
|
import { IFileService } from 'vs/platform/files/common/files';
|
||||||
import { RemoteFileSystemProvider } from 'vs/workbench/services/remote/common/remoteAgentFileSystemChannel';
|
import { RemoteFileSystemProvider } from 'vs/workbench/services/remote/common/remoteAgentFileSystemChannel';
|
||||||
import { ConfigurationCache } from 'vs/workbench/services/configuration/electron-sandbox/configurationCache';
|
import { ConfigurationCache } from 'vs/workbench/services/configuration/common/configurationCache';
|
||||||
import { ISignService } from 'vs/platform/sign/common/sign';
|
import { ISignService } from 'vs/platform/sign/common/sign';
|
||||||
import { basename } from 'vs/base/common/path';
|
import { basename } from 'vs/base/common/path';
|
||||||
import { IProductService } from 'vs/platform/product/common/productService';
|
import { IProductService } from 'vs/platform/product/common/productService';
|
||||||
|
@ -50,6 +50,7 @@ import { registerWindowDriver } from 'vs/platform/driver/electron-sandbox/driver
|
||||||
import { safeStringify } from 'vs/base/common/objects';
|
import { safeStringify } from 'vs/base/common/objects';
|
||||||
import { ISharedProcessWorkerWorkbenchService, SharedProcessWorkerWorkbenchService } from 'vs/workbench/services/sharedProcess/electron-sandbox/sharedProcessWorkerWorkbenchService';
|
import { ISharedProcessWorkerWorkbenchService, SharedProcessWorkerWorkbenchService } from 'vs/workbench/services/sharedProcess/electron-sandbox/sharedProcessWorkerWorkbenchService';
|
||||||
import { isMacintosh } from 'vs/base/common/platform';
|
import { isMacintosh } from 'vs/base/common/platform';
|
||||||
|
import { Schemas } from 'vs/base/common/network';
|
||||||
|
|
||||||
export abstract class SharedDesktopMain extends Disposable {
|
export abstract class SharedDesktopMain extends Disposable {
|
||||||
|
|
||||||
|
@ -333,7 +334,8 @@ export abstract class SharedDesktopMain extends Disposable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async createWorkspaceService(payload: IWorkspaceInitializationPayload, environmentService: INativeWorkbenchEnvironmentService, fileService: FileService, remoteAgentService: IRemoteAgentService, uriIdentityService: IUriIdentityService, logService: ILogService): Promise<WorkspaceService> {
|
private async createWorkspaceService(payload: IWorkspaceInitializationPayload, environmentService: INativeWorkbenchEnvironmentService, fileService: FileService, remoteAgentService: IRemoteAgentService, uriIdentityService: IUriIdentityService, logService: ILogService): Promise<WorkspaceService> {
|
||||||
const workspaceService = new WorkspaceService({ remoteAuthority: environmentService.remoteAuthority, configurationCache: new ConfigurationCache(URI.file(environmentService.userDataPath), fileService) }, environmentService, fileService, remoteAgentService, uriIdentityService, logService);
|
const configurationCache = new ConfigurationCache([Schemas.file, Schemas.userData] /* Cache all non native resources */, environmentService, fileService);
|
||||||
|
const workspaceService = new WorkspaceService({ remoteAuthority: environmentService.remoteAuthority, configurationCache }, environmentService, fileService, remoteAgentService, uriIdentityService, logService);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await workspaceService.initialize(payload);
|
await workspaceService.initialize(payload);
|
||||||
|
|
|
@ -9,13 +9,13 @@ import * as errors from 'vs/base/common/errors';
|
||||||
import { Disposable, IDisposable, dispose, toDisposable, MutableDisposable, combinedDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
import { Disposable, IDisposable, dispose, toDisposable, MutableDisposable, combinedDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||||
import { RunOnceScheduler, timeout } from 'vs/base/common/async';
|
import { RunOnceScheduler, timeout } from 'vs/base/common/async';
|
||||||
import { FileChangeType, FileChangesEvent, IFileService, whenProviderRegistered, FileOperationError, FileOperationResult } from 'vs/platform/files/common/files';
|
import { FileChangeType, FileChangesEvent, IFileService, whenProviderRegistered, FileOperationError, FileOperationResult } from 'vs/platform/files/common/files';
|
||||||
import { ConfigurationModel, ConfigurationModelParser, ConfigurationParseOptions, UserSettings } from 'vs/platform/configuration/common/configurationModels';
|
import { ConfigurationModel, ConfigurationModelParser, ConfigurationParseOptions, DefaultConfigurationModel, UserSettings } from 'vs/platform/configuration/common/configurationModels';
|
||||||
import { WorkspaceConfigurationModelParser, StandaloneConfigurationModelParser } from 'vs/workbench/services/configuration/common/configurationModels';
|
import { WorkspaceConfigurationModelParser, StandaloneConfigurationModelParser } from 'vs/workbench/services/configuration/common/configurationModels';
|
||||||
import { TASKS_CONFIGURATION_KEY, FOLDER_SETTINGS_NAME, LAUNCH_CONFIGURATION_KEY, IConfigurationCache, ConfigurationKey, REMOTE_MACHINE_SCOPES, FOLDER_SCOPES, WORKSPACE_SCOPES } from 'vs/workbench/services/configuration/common/configuration';
|
import { TASKS_CONFIGURATION_KEY, FOLDER_SETTINGS_NAME, LAUNCH_CONFIGURATION_KEY, IConfigurationCache, ConfigurationKey, REMOTE_MACHINE_SCOPES, FOLDER_SCOPES, WORKSPACE_SCOPES } from 'vs/workbench/services/configuration/common/configuration';
|
||||||
import { IStoredWorkspaceFolder, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
|
import { IStoredWorkspaceFolder, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
|
||||||
import { JSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditingService';
|
import { JSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditingService';
|
||||||
import { WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
import { WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||||
import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
|
import { ConfigurationScope, Extensions, IConfigurationRegistry, OVERRIDE_PROPERTY_REGEX } from 'vs/platform/configuration/common/configurationRegistry';
|
||||||
import { equals } from 'vs/base/common/objects';
|
import { equals } from 'vs/base/common/objects';
|
||||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||||
import { hash } from 'vs/base/common/hash';
|
import { hash } from 'vs/base/common/hash';
|
||||||
|
@ -24,6 +24,92 @@ import { ILogService } from 'vs/platform/log/common/log';
|
||||||
import { IStringDictionary } from 'vs/base/common/collections';
|
import { IStringDictionary } from 'vs/base/common/collections';
|
||||||
import { ResourceMap } from 'vs/base/common/map';
|
import { ResourceMap } from 'vs/base/common/map';
|
||||||
import { joinPath } from 'vs/base/common/resources';
|
import { joinPath } from 'vs/base/common/resources';
|
||||||
|
import { Registry } from 'vs/platform/registry/common/platform';
|
||||||
|
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||||
|
import { isObject } from 'vs/base/common/types';
|
||||||
|
|
||||||
|
export class DefaultConfiguration extends Disposable {
|
||||||
|
|
||||||
|
private readonly configurationRegistry = Registry.as<IConfigurationRegistry>(Extensions.Configuration);
|
||||||
|
private cachedConfigurationDefaultsOverrides: IStringDictionary<any> = {};
|
||||||
|
private readonly cacheKey: ConfigurationKey = { type: 'defaults', key: 'configurationDefaultsOverrides' };
|
||||||
|
|
||||||
|
private readonly _onDidChangeConfiguration: Emitter<ConfigurationModel> = this._register(new Emitter<ConfigurationModel>());
|
||||||
|
readonly onDidChangeConfiguration: Event<ConfigurationModel> = this._onDidChangeConfiguration.event;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly configurationCache: IConfigurationCache,
|
||||||
|
environmentService: IWorkbenchEnvironmentService,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
if (environmentService.options?.configurationDefaults) {
|
||||||
|
this.configurationRegistry.registerDefaultConfigurations([environmentService.options.configurationDefaults]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _configurationModel: ConfigurationModel | undefined;
|
||||||
|
get configurationModel(): ConfigurationModel {
|
||||||
|
if (!this._configurationModel) {
|
||||||
|
this._configurationModel = new DefaultConfigurationModel(this.cachedConfigurationDefaultsOverrides);
|
||||||
|
}
|
||||||
|
return this._configurationModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
async initialize(): Promise<ConfigurationModel> {
|
||||||
|
await this.initializeCachedConfigurationDefaultsOverrides();
|
||||||
|
this._register(this.configurationRegistry.onDidUpdateConfiguration(({ defaultsOverrides }) => this.onDidUpdateConfiguration(defaultsOverrides)));
|
||||||
|
return this.configurationModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
reload(): ConfigurationModel {
|
||||||
|
this.cachedConfigurationDefaultsOverrides = {};
|
||||||
|
this._configurationModel = undefined;
|
||||||
|
this.updateCachedConfigurationDefaultsOverrides();
|
||||||
|
return this.configurationModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private initiaizeCachedConfigurationDefaultsOverridesPromise: Promise<void> | undefined;
|
||||||
|
private initializeCachedConfigurationDefaultsOverrides(): Promise<void> {
|
||||||
|
if (!this.initiaizeCachedConfigurationDefaultsOverridesPromise) {
|
||||||
|
this.initiaizeCachedConfigurationDefaultsOverridesPromise = (async () => {
|
||||||
|
try {
|
||||||
|
const content = await this.configurationCache.read(this.cacheKey);
|
||||||
|
if (content) {
|
||||||
|
this.cachedConfigurationDefaultsOverrides = JSON.parse(content);
|
||||||
|
}
|
||||||
|
} catch (error) { /* ignore */ }
|
||||||
|
this.cachedConfigurationDefaultsOverrides = isObject(this.cachedConfigurationDefaultsOverrides) ? this.cachedConfigurationDefaultsOverrides : {};
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
return this.initiaizeCachedConfigurationDefaultsOverridesPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
private onDidUpdateConfiguration(defaultsOverrides?: boolean): void {
|
||||||
|
this._configurationModel = undefined;
|
||||||
|
this._onDidChangeConfiguration.fire(this.configurationModel);
|
||||||
|
if (defaultsOverrides) {
|
||||||
|
this.updateCachedConfigurationDefaultsOverrides();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async updateCachedConfigurationDefaultsOverrides(): Promise<void> {
|
||||||
|
const cachedConfigurationDefaultsOverrides: IStringDictionary<any> = {};
|
||||||
|
const configurationDefaultsOverrides = this.configurationRegistry.getConfigurationDefaultsOverrides();
|
||||||
|
for (const key of Object.keys(configurationDefaultsOverrides)) {
|
||||||
|
if (!OVERRIDE_PROPERTY_REGEX.test(key) && configurationDefaultsOverrides[key] !== undefined) {
|
||||||
|
cachedConfigurationDefaultsOverrides[key] = configurationDefaultsOverrides[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (Object.keys(cachedConfigurationDefaultsOverrides).length) {
|
||||||
|
await this.configurationCache.write(this.cacheKey, JSON.stringify(cachedConfigurationDefaultsOverrides));
|
||||||
|
} else {
|
||||||
|
await this.configurationCache.remove(this.cacheKey);
|
||||||
|
}
|
||||||
|
} catch (error) {/* Ignore error */ }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
export class UserConfiguration extends Disposable {
|
export class UserConfiguration extends Disposable {
|
||||||
|
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------------------------
|
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
||||||
*--------------------------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
import { IConfigurationCache, ConfigurationKey } from 'vs/workbench/services/configuration/common/configuration';
|
|
||||||
import { Schemas } from 'vs/base/common/network';
|
|
||||||
import { URI } from 'vs/base/common/uri';
|
|
||||||
|
|
||||||
export class ConfigurationCache implements IConfigurationCache {
|
|
||||||
|
|
||||||
needsCaching(resource: URI): boolean {
|
|
||||||
// Cache all non user data resources
|
|
||||||
return ![Schemas.file, Schemas.userData, Schemas.tmp].includes(resource.scheme);
|
|
||||||
}
|
|
||||||
|
|
||||||
async read(key: ConfigurationKey): Promise<string> {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
async write(key: ConfigurationKey, content: string): Promise<void> {
|
|
||||||
}
|
|
||||||
|
|
||||||
async remove(key: ConfigurationKey): Promise<void> {
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -11,8 +11,8 @@ import { Disposable } from 'vs/base/common/lifecycle';
|
||||||
import { Queue, Barrier, runWhenIdle, Promises } from 'vs/base/common/async';
|
import { Queue, Barrier, runWhenIdle, Promises } from 'vs/base/common/async';
|
||||||
import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry';
|
import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry';
|
||||||
import { IWorkspaceContextService, Workspace as BaseWorkspace, WorkbenchState, IWorkspaceFolder, IWorkspaceFoldersChangeEvent, WorkspaceFolder, toWorkspaceFolder, isWorkspaceFolder, IWorkspaceFoldersWillChangeEvent } from 'vs/platform/workspace/common/workspace';
|
import { IWorkspaceContextService, Workspace as BaseWorkspace, WorkbenchState, IWorkspaceFolder, IWorkspaceFoldersChangeEvent, WorkspaceFolder, toWorkspaceFolder, isWorkspaceFolder, IWorkspaceFoldersWillChangeEvent } from 'vs/platform/workspace/common/workspace';
|
||||||
import { ConfigurationModel, DefaultConfigurationModel, ConfigurationChangeEvent, AllKeysConfigurationChangeEvent, mergeChanges } from 'vs/platform/configuration/common/configurationModels';
|
import { ConfigurationModel, ConfigurationChangeEvent, AllKeysConfigurationChangeEvent, mergeChanges } from 'vs/platform/configuration/common/configurationModels';
|
||||||
import { IConfigurationChangeEvent, ConfigurationTarget, IConfigurationOverrides, isConfigurationOverrides, IConfigurationData, IConfigurationValue, IConfigurationChange, ConfigurationTargetToString, IConfigurationUpdateOverrides, isConfigurationUpdateOverrides } from 'vs/platform/configuration/common/configuration';
|
import { IConfigurationChangeEvent, ConfigurationTarget, IConfigurationOverrides, isConfigurationOverrides, IConfigurationData, IConfigurationValue, IConfigurationChange, ConfigurationTargetToString, IConfigurationUpdateOverrides, isConfigurationUpdateOverrides, IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
import { Configuration } from 'vs/workbench/services/configuration/common/configurationModels';
|
import { Configuration } from 'vs/workbench/services/configuration/common/configurationModels';
|
||||||
import { FOLDER_CONFIG_FOLDER_NAME, defaultSettingsSchemaId, userSettingsSchemaId, workspaceSettingsSchemaId, folderSettingsSchemaId, IConfigurationCache, machineSettingsSchemaId, LOCAL_MACHINE_SCOPES, IWorkbenchConfigurationService, RestrictedSettings } from 'vs/workbench/services/configuration/common/configuration';
|
import { FOLDER_CONFIG_FOLDER_NAME, defaultSettingsSchemaId, userSettingsSchemaId, workspaceSettingsSchemaId, folderSettingsSchemaId, IConfigurationCache, machineSettingsSchemaId, LOCAL_MACHINE_SCOPES, IWorkbenchConfigurationService, RestrictedSettings } from 'vs/workbench/services/configuration/common/configuration';
|
||||||
import { Registry } from 'vs/platform/registry/common/platform';
|
import { Registry } from 'vs/platform/registry/common/platform';
|
||||||
|
@ -20,7 +20,7 @@ import { IConfigurationRegistry, Extensions, allSettings, windowSettings, resour
|
||||||
import { IWorkspaceIdentifier, isWorkspaceIdentifier, IStoredWorkspaceFolder, isStoredWorkspaceFolder, IWorkspaceFolderCreationData, IWorkspaceInitializationPayload, IEmptyWorkspaceIdentifier, useSlashForPath, getStoredWorkspaceFolder, isSingleFolderWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, toWorkspaceFolders } from 'vs/platform/workspaces/common/workspaces';
|
import { IWorkspaceIdentifier, isWorkspaceIdentifier, IStoredWorkspaceFolder, isStoredWorkspaceFolder, IWorkspaceFolderCreationData, IWorkspaceInitializationPayload, IEmptyWorkspaceIdentifier, useSlashForPath, getStoredWorkspaceFolder, isSingleFolderWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, toWorkspaceFolders } from 'vs/platform/workspaces/common/workspaces';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { ConfigurationEditingService, EditableConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditingService';
|
import { ConfigurationEditingService, EditableConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditingService';
|
||||||
import { WorkspaceConfiguration, FolderConfiguration, RemoteUserConfiguration, UserConfiguration } from 'vs/workbench/services/configuration/browser/configuration';
|
import { WorkspaceConfiguration, FolderConfiguration, RemoteUserConfiguration, UserConfiguration, DefaultConfiguration } from 'vs/workbench/services/configuration/browser/configuration';
|
||||||
import { JSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditingService';
|
import { JSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditingService';
|
||||||
import { IJSONSchema, IJSONSchemaMap } from 'vs/base/common/jsonSchema';
|
import { IJSONSchema, IJSONSchemaMap } from 'vs/base/common/jsonSchema';
|
||||||
import { mark } from 'vs/base/common/performance';
|
import { mark } from 'vs/base/common/performance';
|
||||||
|
@ -35,6 +35,7 @@ import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'
|
||||||
import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust';
|
import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust';
|
||||||
import { delta, distinct } from 'vs/base/common/arrays';
|
import { delta, distinct } from 'vs/base/common/arrays';
|
||||||
import { forEach, IStringDictionary } from 'vs/base/common/collections';
|
import { forEach, IStringDictionary } from 'vs/base/common/collections';
|
||||||
|
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||||
|
|
||||||
class Workspace extends BaseWorkspace {
|
class Workspace extends BaseWorkspace {
|
||||||
initialized: boolean = false;
|
initialized: boolean = false;
|
||||||
|
@ -50,7 +51,7 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
|
||||||
private readonly configurationCache: IConfigurationCache;
|
private readonly configurationCache: IConfigurationCache;
|
||||||
private _configuration: Configuration;
|
private _configuration: Configuration;
|
||||||
private initialized: boolean = false;
|
private initialized: boolean = false;
|
||||||
private defaultConfiguration: DefaultConfigurationModel;
|
private defaultConfiguration: DefaultConfiguration;
|
||||||
private localUserConfiguration: UserConfiguration;
|
private localUserConfiguration: UserConfiguration;
|
||||||
private remoteUserConfiguration: RemoteUserConfiguration | null = null;
|
private remoteUserConfiguration: RemoteUserConfiguration | null = null;
|
||||||
private workspaceConfiguration: WorkspaceConfiguration;
|
private workspaceConfiguration: WorkspaceConfiguration;
|
||||||
|
@ -102,20 +103,15 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.configurationRegistry = Registry.as<IConfigurationRegistry>(Extensions.Configuration);
|
this.configurationRegistry = Registry.as<IConfigurationRegistry>(Extensions.Configuration);
|
||||||
// register defaults before creating default configuration model
|
|
||||||
// so that the model is not required to be updated after registering
|
|
||||||
if (environmentService.options?.configurationDefaults) {
|
|
||||||
this.configurationRegistry.registerDefaultConfigurations([environmentService.options.configurationDefaults]);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.initRemoteUserConfigurationBarrier = new Barrier();
|
this.initRemoteUserConfigurationBarrier = new Barrier();
|
||||||
this.completeWorkspaceBarrier = new Barrier();
|
this.completeWorkspaceBarrier = new Barrier();
|
||||||
this.defaultConfiguration = new DefaultConfigurationModel();
|
this.defaultConfiguration = new DefaultConfiguration(configurationCache, environmentService);
|
||||||
this.configurationCache = configurationCache;
|
this.configurationCache = configurationCache;
|
||||||
this.fileService = fileService;
|
this.fileService = fileService;
|
||||||
this.uriIdentityService = uriIdentityService;
|
this.uriIdentityService = uriIdentityService;
|
||||||
this.logService = logService;
|
this.logService = logService;
|
||||||
this._configuration = new Configuration(this.defaultConfiguration, new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ResourceMap(), new ConfigurationModel(), new ResourceMap<ConfigurationModel>(), this.workspace);
|
this._configuration = new Configuration(this.defaultConfiguration.configurationModel, new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ResourceMap(), new ConfigurationModel(), new ResourceMap<ConfigurationModel>(), this.workspace);
|
||||||
this.cachedFolderConfigs = new ResourceMap<FolderConfiguration>();
|
this.cachedFolderConfigs = new ResourceMap<FolderConfiguration>();
|
||||||
this.localUserConfiguration = this._register(new UserConfiguration(environmentService.settingsResource, remoteAuthority ? LOCAL_MACHINE_SCOPES : undefined, fileService, uriIdentityService, logService));
|
this.localUserConfiguration = this._register(new UserConfiguration(environmentService.settingsResource, remoteAuthority ? LOCAL_MACHINE_SCOPES : undefined, fileService, uriIdentityService, logService));
|
||||||
this._register(this.localUserConfiguration.onDidChangeConfiguration(userConfiguration => this.onLocalUserConfigurationChanged(userConfiguration)));
|
this._register(this.localUserConfiguration.onDidChangeConfiguration(userConfiguration => this.onLocalUserConfigurationChanged(userConfiguration)));
|
||||||
|
@ -138,7 +134,7 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this._register(this.configurationRegistry.onDidUpdateConfiguration(configurationProperties => this.onDefaultConfigurationChanged(configurationProperties)));
|
this._register(this.defaultConfiguration.onDidChangeConfiguration(configurationModel => this.onDefaultConfigurationChanged(configurationModel)));
|
||||||
|
|
||||||
this.workspaceEditingQueue = new Queue<void>();
|
this.workspaceEditingQueue = new Queue<void>();
|
||||||
}
|
}
|
||||||
|
@ -350,6 +346,10 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (target) {
|
switch (target) {
|
||||||
|
case ConfigurationTarget.DEFAULT:
|
||||||
|
await this.reloadDefaultConfiguration();
|
||||||
|
return;
|
||||||
|
|
||||||
case ConfigurationTarget.USER:
|
case ConfigurationTarget.USER:
|
||||||
const { local, remote } = await this.reloadUserConfiguration();
|
const { local, remote } = await this.reloadUserConfiguration();
|
||||||
await this.loadConfiguration(local, remote);
|
await this.loadConfiguration(local, remote);
|
||||||
|
@ -566,6 +566,8 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
|
||||||
}
|
}
|
||||||
|
|
||||||
private async initializeConfiguration(): Promise<void> {
|
private async initializeConfiguration(): Promise<void> {
|
||||||
|
await this.defaultConfiguration.initialize();
|
||||||
|
|
||||||
mark('code/willInitUserConfiguration');
|
mark('code/willInitUserConfiguration');
|
||||||
const { local, remote } = await this.initializeUserConfiguration();
|
const { local, remote } = await this.initializeUserConfiguration();
|
||||||
mark('code/didInitUserConfiguration');
|
mark('code/didInitUserConfiguration');
|
||||||
|
@ -580,6 +582,10 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
|
||||||
return { local, remote };
|
return { local, remote };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async reloadDefaultConfiguration(): Promise<void> {
|
||||||
|
this.onDefaultConfigurationChanged(this.defaultConfiguration.reload());
|
||||||
|
}
|
||||||
|
|
||||||
private async reloadUserConfiguration(): Promise<{ local: ConfigurationModel, remote: ConfigurationModel }> {
|
private async reloadUserConfiguration(): Promise<{ local: ConfigurationModel, remote: ConfigurationModel }> {
|
||||||
const [local, remote] = await Promise.all([this.reloadLocalUserConfiguration(true), this.reloadRemoteUserConfiguration(true)]);
|
const [local, remote] = await Promise.all([this.reloadLocalUserConfiguration(true), this.reloadRemoteUserConfiguration(true)]);
|
||||||
return { local, remote };
|
return { local, remote };
|
||||||
|
@ -630,7 +636,7 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
|
||||||
folderConfigurations.forEach((folderConfiguration, index) => folderConfigurationModels.set(folders[index].uri, folderConfiguration));
|
folderConfigurations.forEach((folderConfiguration, index) => folderConfigurationModels.set(folders[index].uri, folderConfiguration));
|
||||||
|
|
||||||
const currentConfiguration = this._configuration;
|
const currentConfiguration = this._configuration;
|
||||||
this._configuration = new Configuration(this.defaultConfiguration, userConfigurationModel, remoteUserConfigurationModel, workspaceConfiguration, folderConfigurationModels, new ConfigurationModel(), new ResourceMap<ConfigurationModel>(), this.workspace);
|
this._configuration = new Configuration(this.defaultConfiguration.configurationModel, userConfigurationModel, remoteUserConfigurationModel, workspaceConfiguration, folderConfigurationModels, new ConfigurationModel(), new ResourceMap<ConfigurationModel>(), this.workspace);
|
||||||
|
|
||||||
if (this.initialized) {
|
if (this.initialized) {
|
||||||
const change = this._configuration.compare(currentConfiguration);
|
const change = this._configuration.compare(currentConfiguration);
|
||||||
|
@ -654,11 +660,10 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private onDefaultConfigurationChanged(keys: string[]): void {
|
private onDefaultConfigurationChanged(configurationModel: ConfigurationModel): void {
|
||||||
this.defaultConfiguration = new DefaultConfigurationModel();
|
|
||||||
if (this.workspace) {
|
if (this.workspace) {
|
||||||
const previousData = this._configuration.toData();
|
const previousData = this._configuration.toData();
|
||||||
const change = this._configuration.compareAndUpdateDefaultConfiguration(this.defaultConfiguration, keys);
|
const change = this._configuration.compareAndUpdateDefaultConfiguration(configurationModel);
|
||||||
if (this.remoteUserConfiguration) {
|
if (this.remoteUserConfiguration) {
|
||||||
this._configuration.updateLocalUserConfiguration(this.localUserConfiguration.reparse());
|
this._configuration.updateLocalUserConfiguration(this.localUserConfiguration.reparse());
|
||||||
this._configuration.updateRemoteUserConfiguration(this.remoteUserConfiguration.reparse());
|
this._configuration.updateRemoteUserConfiguration(this.remoteUserConfiguration.reparse());
|
||||||
|
@ -1101,5 +1106,16 @@ class RegisterConfigurationSchemasContribution extends Disposable implements IWo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ResetConfigurationDefaultsOverridesCache extends Disposable implements IWorkbenchContribution {
|
||||||
|
constructor(
|
||||||
|
@IConfigurationService configurationService: IConfigurationService,
|
||||||
|
@IExtensionService extensionService: IExtensionService,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
extensionService.whenInstalledExtensionsRegistered().then(() => configurationService.reloadConfiguration(ConfigurationTarget.DEFAULT));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const workbenchContributionsRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
|
const workbenchContributionsRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
|
||||||
workbenchContributionsRegistry.registerWorkbenchContribution(RegisterConfigurationSchemasContribution, LifecyclePhase.Restored);
|
workbenchContributionsRegistry.registerWorkbenchContribution(RegisterConfigurationSchemasContribution, LifecyclePhase.Restored);
|
||||||
|
workbenchContributionsRegistry.registerWorkbenchContribution(ResetConfigurationDefaultsOverridesCache, LifecyclePhase.Ready);
|
||||||
|
|
|
@ -36,7 +36,7 @@ WORKSPACE_STANDALONE_CONFIGURATIONS[LAUNCH_CONFIGURATION_KEY] = `${FOLDER_CONFIG
|
||||||
export const USER_STANDALONE_CONFIGURATIONS = Object.create(null);
|
export const USER_STANDALONE_CONFIGURATIONS = Object.create(null);
|
||||||
USER_STANDALONE_CONFIGURATIONS[TASKS_CONFIGURATION_KEY] = `${TASKS_CONFIGURATION_KEY}.json`;
|
USER_STANDALONE_CONFIGURATIONS[TASKS_CONFIGURATION_KEY] = `${TASKS_CONFIGURATION_KEY}.json`;
|
||||||
|
|
||||||
export type ConfigurationKey = { type: 'user' | 'workspaces' | 'folder', key: string };
|
export type ConfigurationKey = { type: 'defaults' | 'user' | 'workspaces' | 'folder', key: string };
|
||||||
|
|
||||||
export interface IConfigurationCache {
|
export interface IConfigurationCache {
|
||||||
|
|
||||||
|
|
|
@ -5,22 +5,28 @@
|
||||||
|
|
||||||
import { IConfigurationCache, ConfigurationKey } from 'vs/workbench/services/configuration/common/configuration';
|
import { IConfigurationCache, ConfigurationKey } from 'vs/workbench/services/configuration/common/configuration';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { Schemas } from 'vs/base/common/network';
|
|
||||||
import { FileOperationError, FileOperationResult, IFileService } from 'vs/platform/files/common/files';
|
import { FileOperationError, FileOperationResult, IFileService } from 'vs/platform/files/common/files';
|
||||||
import { joinPath } from 'vs/base/common/resources';
|
import { joinPath } from 'vs/base/common/resources';
|
||||||
import { VSBuffer } from 'vs/base/common/buffer';
|
import { VSBuffer } from 'vs/base/common/buffer';
|
||||||
import { Queue } from 'vs/base/common/async';
|
import { Queue } from 'vs/base/common/async';
|
||||||
|
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||||
|
|
||||||
export class ConfigurationCache implements IConfigurationCache {
|
export class ConfigurationCache implements IConfigurationCache {
|
||||||
|
|
||||||
|
private readonly cacheHome: URI;
|
||||||
private readonly cachedConfigurations: Map<string, CachedConfiguration> = new Map<string, CachedConfiguration>();
|
private readonly cachedConfigurations: Map<string, CachedConfiguration> = new Map<string, CachedConfiguration>();
|
||||||
|
|
||||||
constructor(private readonly cacheHome: URI, private readonly fileService: IFileService) {
|
constructor(
|
||||||
|
private readonly donotCacheResourcesWithSchemes: string[],
|
||||||
|
environmentService: IEnvironmentService,
|
||||||
|
private readonly fileService: IFileService
|
||||||
|
) {
|
||||||
|
this.cacheHome = environmentService.cacheHome;
|
||||||
}
|
}
|
||||||
|
|
||||||
needsCaching(resource: URI): boolean {
|
needsCaching(resource: URI): boolean {
|
||||||
// Cache all non native resources
|
// Cache all non native resources
|
||||||
return ![Schemas.file, Schemas.userData].includes(resource.scheme);
|
return !this.donotCacheResourcesWithSchemes.includes(resource.scheme);
|
||||||
}
|
}
|
||||||
|
|
||||||
read(key: ConfigurationKey): Promise<string> {
|
read(key: ConfigurationKey): Promise<string> {
|
|
@ -0,0 +1,146 @@
|
||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import * as assert from 'assert';
|
||||||
|
import { Event } from 'vs/base/common/event';
|
||||||
|
import { joinPath } from 'vs/base/common/resources';
|
||||||
|
import { URI } from 'vs/base/common/uri';
|
||||||
|
import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
|
||||||
|
import { Registry } from 'vs/platform/registry/common/platform';
|
||||||
|
import { DefaultConfiguration } from 'vs/workbench/services/configuration/browser/configuration';
|
||||||
|
import { ConfigurationKey, IConfigurationCache } from 'vs/workbench/services/configuration/common/configuration';
|
||||||
|
import { BrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService';
|
||||||
|
import { TestEnvironmentService, TestProductService } from 'vs/workbench/test/browser/workbenchTestServices';
|
||||||
|
|
||||||
|
export class ConfigurationCache implements IConfigurationCache {
|
||||||
|
private readonly cache = new Map<string, string>();
|
||||||
|
needsCaching(resource: URI): boolean { return false; }
|
||||||
|
async read({ type, key }: ConfigurationKey): Promise<string> { return this.cache.get(`${type}:${key}`) || ''; }
|
||||||
|
async write({ type, key }: ConfigurationKey, content: string): Promise<void> { this.cache.set(`${type}:${key}`, content); }
|
||||||
|
async remove({ type, key }: ConfigurationKey): Promise<void> { this.cache.delete(`${type}:${key}`); }
|
||||||
|
}
|
||||||
|
|
||||||
|
suite('DefaultConfiguration', () => {
|
||||||
|
|
||||||
|
const configurationRegistry = Registry.as<IConfigurationRegistry>(Extensions.Configuration);
|
||||||
|
const cacheKey: ConfigurationKey = { type: 'defaults', key: 'configurationDefaultsOverrides' };
|
||||||
|
let configurationCache: ConfigurationCache;
|
||||||
|
|
||||||
|
setup(() => {
|
||||||
|
configurationCache = new ConfigurationCache();
|
||||||
|
configurationRegistry.registerConfiguration({
|
||||||
|
'id': 'test.configurationDefaultsOverride',
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'test.configurationDefaultsOverride': {
|
||||||
|
'type': 'string',
|
||||||
|
'default': 'defaultValue',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
teardown(() => {
|
||||||
|
configurationRegistry.deregisterConfigurations(configurationRegistry.getConfigurations());
|
||||||
|
configurationRegistry.deregisterDefaultConfigurations([configurationRegistry.getConfigurationDefaultsOverrides()]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('configuration default overrides are read from environment', async () => {
|
||||||
|
const environmentService = new BrowserWorkbenchEnvironmentService({ logsPath: joinPath(URI.file('tests').with({ scheme: 'vscode-tests' }), 'logs'), workspaceId: '', configurationDefaults: { 'test.configurationDefaultsOverride': 'envOverrideValue' } }, TestProductService);
|
||||||
|
const testObject = new DefaultConfiguration(configurationCache, environmentService);
|
||||||
|
assert.deepStrictEqual(testObject.configurationModel.getValue('test.configurationDefaultsOverride'), 'envOverrideValue');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('configuration default overrides are read from cache', async () => {
|
||||||
|
await configurationCache.write(cacheKey, JSON.stringify({ 'test.configurationDefaultsOverride': 'overrideValue' }));
|
||||||
|
const testObject = new DefaultConfiguration(configurationCache, TestEnvironmentService);
|
||||||
|
|
||||||
|
const actual = await testObject.initialize();
|
||||||
|
|
||||||
|
assert.deepStrictEqual(actual.getValue('test.configurationDefaultsOverride'), 'overrideValue');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('configuration default overrides read from cache override environment', async () => {
|
||||||
|
const environmentService = new BrowserWorkbenchEnvironmentService({ logsPath: joinPath(URI.file('tests').with({ scheme: 'vscode-tests' }), 'logs'), workspaceId: '', configurationDefaults: { 'test.configurationDefaultsOverride': 'envOverrideValue' } }, TestProductService);
|
||||||
|
await configurationCache.write(cacheKey, JSON.stringify({ 'test.configurationDefaultsOverride': 'overrideValue' }));
|
||||||
|
const testObject = new DefaultConfiguration(configurationCache, environmentService);
|
||||||
|
|
||||||
|
const actual = await testObject.initialize();
|
||||||
|
|
||||||
|
assert.deepStrictEqual(actual.getValue('test.configurationDefaultsOverride'), 'overrideValue');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('configuration default overrides are read from cache when default configuration changed', async () => {
|
||||||
|
await configurationCache.write(cacheKey, JSON.stringify({ 'test.configurationDefaultsOverride': 'overrideValue' }));
|
||||||
|
const testObject = new DefaultConfiguration(configurationCache, TestEnvironmentService);
|
||||||
|
await testObject.initialize();
|
||||||
|
|
||||||
|
const promise = Event.toPromise(testObject.onDidChangeConfiguration);
|
||||||
|
configurationRegistry.registerConfiguration({
|
||||||
|
'id': 'test.configurationDefaultsOverride',
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'test.configurationDefaultsOverride1': {
|
||||||
|
'type': 'string',
|
||||||
|
'default': 'defaultValue',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const actual = await promise;
|
||||||
|
assert.deepStrictEqual(actual.getValue('test.configurationDefaultsOverride'), 'overrideValue');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('configuration default overrides are not read from cache after reload', async () => {
|
||||||
|
await configurationCache.write(cacheKey, JSON.stringify({ 'test.configurationDefaultsOverride': 'overrideValue' }));
|
||||||
|
const testObject = new DefaultConfiguration(configurationCache, TestEnvironmentService);
|
||||||
|
|
||||||
|
await testObject.initialize();
|
||||||
|
const actual = testObject.reload();
|
||||||
|
|
||||||
|
assert.deepStrictEqual(actual.getValue('test.configurationDefaultsOverride'), 'defaultValue');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('cache is reset after reload', async () => {
|
||||||
|
await configurationCache.write(cacheKey, JSON.stringify({ 'test.configurationDefaultsOverride': 'overrideValue' }));
|
||||||
|
const testObject = new DefaultConfiguration(configurationCache, TestEnvironmentService);
|
||||||
|
|
||||||
|
await testObject.initialize();
|
||||||
|
testObject.reload();
|
||||||
|
|
||||||
|
assert.deepStrictEqual(await configurationCache.read(cacheKey), '');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('configuration default overrides are written in cache', async () => {
|
||||||
|
const testObject = new DefaultConfiguration(configurationCache, TestEnvironmentService);
|
||||||
|
await testObject.initialize();
|
||||||
|
const promise = Event.toPromise(testObject.onDidChangeConfiguration);
|
||||||
|
configurationRegistry.registerDefaultConfigurations([{ 'test.configurationDefaultsOverride': 'newoverrideValue' }]);
|
||||||
|
await promise;
|
||||||
|
|
||||||
|
const actual = JSON.parse(await configurationCache.read(cacheKey));
|
||||||
|
assert.deepStrictEqual(actual, { 'test.configurationDefaultsOverride': 'newoverrideValue' });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('configuration default overrides are removed from cache if there are no overrides', async () => {
|
||||||
|
const testObject = new DefaultConfiguration(configurationCache, TestEnvironmentService);
|
||||||
|
await testObject.initialize();
|
||||||
|
const promise = Event.toPromise(testObject.onDidChangeConfiguration);
|
||||||
|
configurationRegistry.registerConfiguration({
|
||||||
|
'id': 'test.configurationDefaultsOverride',
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'test.configurationDefaultsOverride1': {
|
||||||
|
'type': 'string',
|
||||||
|
'default': 'defaultValue',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await promise;
|
||||||
|
|
||||||
|
assert.deepStrictEqual(await configurationCache.read(cacheKey), '');
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -14,7 +14,7 @@ import * as uuid from 'vs/base/common/uuid';
|
||||||
import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry';
|
import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry';
|
||||||
import { WorkspaceService } from 'vs/workbench/services/configuration/browser/configurationService';
|
import { WorkspaceService } from 'vs/workbench/services/configuration/browser/configurationService';
|
||||||
import { ConfigurationEditingService, ConfigurationEditingErrorCode, EditableConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditingService';
|
import { ConfigurationEditingService, ConfigurationEditingErrorCode, EditableConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditingService';
|
||||||
import { WORKSPACE_STANDALONE_CONFIGURATIONS, FOLDER_SETTINGS_PATH, USER_STANDALONE_CONFIGURATIONS } from 'vs/workbench/services/configuration/common/configuration';
|
import { WORKSPACE_STANDALONE_CONFIGURATIONS, FOLDER_SETTINGS_PATH, USER_STANDALONE_CONFIGURATIONS, IConfigurationCache } from 'vs/workbench/services/configuration/common/configuration';
|
||||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||||
|
@ -36,7 +36,6 @@ import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||||
import { InMemoryFileSystemProvider } from 'vs/platform/files/common/inMemoryFilesystemProvider';
|
import { InMemoryFileSystemProvider } from 'vs/platform/files/common/inMemoryFilesystemProvider';
|
||||||
import { joinPath } from 'vs/base/common/resources';
|
import { joinPath } from 'vs/base/common/resources';
|
||||||
import { VSBuffer } from 'vs/base/common/buffer';
|
import { VSBuffer } from 'vs/base/common/buffer';
|
||||||
import { ConfigurationCache } from 'vs/workbench/services/configuration/browser/configurationCache';
|
|
||||||
import { RemoteAgentService } from 'vs/workbench/services/remote/browser/remoteAgentServiceImpl';
|
import { RemoteAgentService } from 'vs/workbench/services/remote/browser/remoteAgentServiceImpl';
|
||||||
import { BrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService';
|
import { BrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService';
|
||||||
import { getSingleFolderWorkspaceIdentifier } from 'vs/workbench/services/workspaces/browser/workspaces';
|
import { getSingleFolderWorkspaceIdentifier } from 'vs/workbench/services/workspaces/browser/workspaces';
|
||||||
|
@ -44,6 +43,13 @@ import { IUserConfigurationFileService, UserConfigurationFileService } from 'vs/
|
||||||
|
|
||||||
const ROOT = URI.file('tests').with({ scheme: 'vscode-tests' });
|
const ROOT = URI.file('tests').with({ scheme: 'vscode-tests' });
|
||||||
|
|
||||||
|
export class ConfigurationCache implements IConfigurationCache {
|
||||||
|
needsCaching(resource: URI): boolean { return false; }
|
||||||
|
async read(): Promise<string> { return ''; }
|
||||||
|
async write(): Promise<void> { }
|
||||||
|
async remove(): Promise<void> { }
|
||||||
|
}
|
||||||
|
|
||||||
suite('ConfigurationEditingService', () => {
|
suite('ConfigurationEditingService', () => {
|
||||||
|
|
||||||
let instantiationService: TestInstantiationService;
|
let instantiationService: TestInstantiationService;
|
||||||
|
|
|
@ -40,7 +40,6 @@ import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||||
import { Event } from 'vs/base/common/event';
|
import { Event } from 'vs/base/common/event';
|
||||||
import { UriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentityService';
|
import { UriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentityService';
|
||||||
import { InMemoryFileSystemProvider } from 'vs/platform/files/common/inMemoryFilesystemProvider';
|
import { InMemoryFileSystemProvider } from 'vs/platform/files/common/inMemoryFilesystemProvider';
|
||||||
import { ConfigurationCache as BrowserConfigurationCache } from 'vs/workbench/services/configuration/browser/configurationCache';
|
|
||||||
import { BrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService';
|
import { BrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService';
|
||||||
import { RemoteAgentService } from 'vs/workbench/services/remote/browser/remoteAgentServiceImpl';
|
import { RemoteAgentService } from 'vs/workbench/services/remote/browser/remoteAgentServiceImpl';
|
||||||
import { RemoteAuthorityResolverService } from 'vs/platform/remote/browser/remoteAuthorityResolverService';
|
import { RemoteAuthorityResolverService } from 'vs/platform/remote/browser/remoteAuthorityResolverService';
|
||||||
|
@ -54,8 +53,11 @@ function convertToWorkspacePayload(folder: URI): ISingleFolderWorkspaceIdentifie
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class ConfigurationCache extends BrowserConfigurationCache {
|
export class ConfigurationCache implements IConfigurationCache {
|
||||||
override needsCaching() { return false; }
|
needsCaching(resource: URI): boolean { return false; }
|
||||||
|
async read(): Promise<string> { return ''; }
|
||||||
|
async write(): Promise<void> { }
|
||||||
|
async remove(): Promise<void> { }
|
||||||
}
|
}
|
||||||
|
|
||||||
const ROOT = URI.file('tests').with({ scheme: 'vscode-tests' });
|
const ROOT = URI.file('tests').with({ scheme: 'vscode-tests' });
|
||||||
|
@ -2191,44 +2193,6 @@ suite('WorkspaceConfigurationService - Remote Folder', () => {
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
suite('ConfigurationService - Configuration Defaults', () => {
|
|
||||||
|
|
||||||
const disposableStore: DisposableStore = new DisposableStore();
|
|
||||||
|
|
||||||
suiteSetup(() => {
|
|
||||||
Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration).registerConfiguration({
|
|
||||||
'id': '_test',
|
|
||||||
'type': 'object',
|
|
||||||
'properties': {
|
|
||||||
'configurationService.defaultOverridesSetting': {
|
|
||||||
'type': 'string',
|
|
||||||
'default': 'isSet',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
teardown(() => disposableStore.clear());
|
|
||||||
|
|
||||||
test('when default value is not overriden', () => {
|
|
||||||
const testObject = createConfigurationService({});
|
|
||||||
assert.deepStrictEqual(testObject.getValue('configurationService.defaultOverridesSetting'), 'isSet');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('when default value is overriden', () => {
|
|
||||||
const testObject = createConfigurationService({ 'configurationService.defaultOverridesSetting': 'overriddenValue' });
|
|
||||||
assert.deepStrictEqual(testObject.getValue('configurationService.defaultOverridesSetting'), 'overriddenValue');
|
|
||||||
});
|
|
||||||
|
|
||||||
function createConfigurationService(configurationDefaults: Record<string, any>): IConfigurationService {
|
|
||||||
const remoteAgentService = (<TestInstantiationService>workbenchInstantiationService(undefined, disposableStore)).createInstance(RemoteAgentService, null);
|
|
||||||
const environmentService = new BrowserWorkbenchEnvironmentService({ logsPath: joinPath(ROOT, 'logs'), workspaceId: '', configurationDefaults }, TestProductService);
|
|
||||||
const fileService = new FileService(new NullLogService());
|
|
||||||
return disposableStore.add(new WorkspaceService({ configurationCache: new ConfigurationCache() }, environmentService, fileService, remoteAgentService, new UriIdentityService(fileService), new NullLogService()));
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
function getWorkspaceId(configPath: URI): string {
|
function getWorkspaceId(configPath: URI): string {
|
||||||
let workspaceConfigPath = configPath.toString();
|
let workspaceConfigPath = configPath.toString();
|
||||||
if (!isLinux) {
|
if (!isLinux) {
|
||||||
|
|
|
@ -128,6 +128,9 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment
|
||||||
@memoize
|
@memoize
|
||||||
get snippetsHome(): URI { return joinPath(this.userRoamingDataHome, 'snippets'); }
|
get snippetsHome(): URI { return joinPath(this.userRoamingDataHome, 'snippets'); }
|
||||||
|
|
||||||
|
@memoize
|
||||||
|
get cacheHome(): URI { return joinPath(this.userRoamingDataHome, 'caches'); }
|
||||||
|
|
||||||
@memoize
|
@memoize
|
||||||
get globalStorageHome(): URI { return URI.joinPath(this.userRoamingDataHome, 'globalStorage'); }
|
get globalStorageHome(): URI { return URI.joinPath(this.userRoamingDataHome, 'globalStorage'); }
|
||||||
|
|
||||||
|
|
|
@ -1197,9 +1197,6 @@ class ProposedApiController {
|
||||||
}
|
}
|
||||||
|
|
||||||
extension.enabledApiProposals = productEnabledProposals;
|
extension.enabledApiProposals = productEnabledProposals;
|
||||||
|
|
||||||
// todo@jrieken REMOVE, legacy flag is turned on
|
|
||||||
extension.enableProposedApi = true;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1209,11 +1206,10 @@ class ProposedApiController {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!extension.isBuiltin && (extension.enableProposedApi || isNonEmptyArray(extension.enabledApiProposals))) {
|
if (!extension.isBuiltin && isNonEmptyArray(extension.enabledApiProposals)) {
|
||||||
// restrictive: extension cannot use proposed API in this context and its declaration is nulled
|
// restrictive: extension cannot use proposed API in this context and its declaration is nulled
|
||||||
this._logService.critical(`Extension '${extension.identifier.value} CANNOT USE these API proposals '${extension.enabledApiProposals?.join(', ') ?? '*'}'. You MUST start in extension development mode or use the --enable-proposed-api command line flag`);
|
this._logService.critical(`Extension '${extension.identifier.value} CANNOT USE these API proposals '${extension.enabledApiProposals?.join(', ') ?? '*'}'. You MUST start in extension development mode or use the --enable-proposed-api command line flag`);
|
||||||
extension.enabledApiProposals = [];
|
extension.enabledApiProposals = [];
|
||||||
extension.enableProposedApi = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,6 @@ export const nullExtensionDescription = Object.freeze(<IExtensionDescription>{
|
||||||
name: 'Null Extension Description',
|
name: 'Null Extension Description',
|
||||||
version: '0.0.0',
|
version: '0.0.0',
|
||||||
publisher: 'vscode',
|
publisher: 'vscode',
|
||||||
enableProposedApi: false,
|
|
||||||
engines: { vscode: '' },
|
engines: { vscode: '' },
|
||||||
extensionLocation: URI.parse('void:location'),
|
extensionLocation: URI.parse('void:location'),
|
||||||
isBuiltin: false,
|
isBuiltin: false,
|
||||||
|
@ -135,10 +134,10 @@ export interface IExtensionHost {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isProposedApiEnabled(extension: IExtensionDescription, proposal: ApiProposalName): boolean {
|
export function isProposedApiEnabled(extension: IExtensionDescription, proposal: ApiProposalName): boolean {
|
||||||
if (extension.enabledApiProposals?.includes(proposal)) {
|
if (!extension.enabledApiProposals) {
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
return Boolean(extension.enableProposedApi);
|
return extension.enabledApiProposals.includes(proposal);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function checkProposedApiEnabled(extension: IExtensionDescription, proposal: ApiProposalName): void {
|
export function checkProposedApiEnabled(extension: IExtensionDescription, proposal: ApiProposalName): void {
|
||||||
|
|
|
@ -309,7 +309,6 @@ export interface IRelaxedExtensionDescription {
|
||||||
vscode: string;
|
vscode: string;
|
||||||
};
|
};
|
||||||
main?: string;
|
main?: string;
|
||||||
enableProposedApi?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ExtensionManifestValidator extends ExtensionManifestHandler {
|
class ExtensionManifestValidator extends ExtensionManifestHandler {
|
||||||
|
|
|
@ -322,6 +322,9 @@ suite('Encoding', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('toDecodeStream - decodes buffer entirely', async function () {
|
test('toDecodeStream - decodes buffer entirely', async function () {
|
||||||
|
if (!process.versions.electron) {
|
||||||
|
this.skip(); // TODO@bpasero enable once we ship Electron 16
|
||||||
|
}
|
||||||
const emojis = Buffer.from('🖥️💻💾');
|
const emojis = Buffer.from('🖥️💻💾');
|
||||||
const incompleteEmojis = emojis.slice(0, emojis.length - 1);
|
const incompleteEmojis = emojis.slice(0, emojis.length - 1);
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ import { getDocumentSymbols } from 'vs/editor/contrib/documentSymbols/documentSy
|
||||||
import * as modes from 'vs/editor/common/modes';
|
import * as modes from 'vs/editor/common/modes';
|
||||||
import { getCodeLensModel } from 'vs/editor/contrib/codelens/codelens';
|
import { getCodeLensModel } from 'vs/editor/contrib/codelens/codelens';
|
||||||
import { getDefinitionsAtPosition, getImplementationsAtPosition, getTypeDefinitionsAtPosition, getDeclarationsAtPosition, getReferencesAtPosition } from 'vs/editor/contrib/gotoSymbol/goToSymbol';
|
import { getDefinitionsAtPosition, getImplementationsAtPosition, getTypeDefinitionsAtPosition, getDeclarationsAtPosition, getReferencesAtPosition } from 'vs/editor/contrib/gotoSymbol/goToSymbol';
|
||||||
import { getHover } from 'vs/editor/contrib/hover/getHover';
|
import { getHoverPromise } from 'vs/editor/contrib/hover/getHover';
|
||||||
import { getOccurrencesAtPosition } from 'vs/editor/contrib/wordHighlighter/wordHighlighter';
|
import { getOccurrencesAtPosition } from 'vs/editor/contrib/wordHighlighter/wordHighlighter';
|
||||||
import { getCodeActions } from 'vs/editor/contrib/codeAction/codeAction';
|
import { getCodeActions } from 'vs/editor/contrib/codeAction/codeAction';
|
||||||
import { getWorkspaceSymbols } from 'vs/workbench/contrib/search/common/search';
|
import { getWorkspaceSymbols } from 'vs/workbench/contrib/search/common/search';
|
||||||
|
@ -374,7 +374,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
await rpcProtocol.sync();
|
await rpcProtocol.sync();
|
||||||
getHover(model, new EditorPosition(1, 1), CancellationToken.None).then(value => {
|
getHoverPromise(model, new EditorPosition(1, 1), CancellationToken.None).then(value => {
|
||||||
assert.strictEqual(value.length, 1);
|
assert.strictEqual(value.length, 1);
|
||||||
let [entry] = value;
|
let [entry] = value;
|
||||||
assert.deepStrictEqual(entry.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 5 });
|
assert.deepStrictEqual(entry.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 5 });
|
||||||
|
@ -391,7 +391,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
await rpcProtocol.sync();
|
await rpcProtocol.sync();
|
||||||
getHover(model, new EditorPosition(1, 1), CancellationToken.None).then(value => {
|
getHoverPromise(model, new EditorPosition(1, 1), CancellationToken.None).then(value => {
|
||||||
assert.strictEqual(value.length, 1);
|
assert.strictEqual(value.length, 1);
|
||||||
let [entry] = value;
|
let [entry] = value;
|
||||||
assert.deepStrictEqual(entry.range, { startLineNumber: 4, startColumn: 1, endLineNumber: 9, endColumn: 8 });
|
assert.deepStrictEqual(entry.range, { startLineNumber: 4, startColumn: 1, endLineNumber: 9, endColumn: 8 });
|
||||||
|
@ -414,7 +414,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
await rpcProtocol.sync();
|
await rpcProtocol.sync();
|
||||||
const value = await getHover(model, new EditorPosition(1, 1), CancellationToken.None);
|
const value = await getHoverPromise(model, new EditorPosition(1, 1), CancellationToken.None);
|
||||||
assert.strictEqual(value.length, 2);
|
assert.strictEqual(value.length, 2);
|
||||||
let [first, second] = (value as modes.Hover[]);
|
let [first, second] = (value as modes.Hover[]);
|
||||||
assert.strictEqual(first.contents[0].value, 'registered second');
|
assert.strictEqual(first.contents[0].value, 'registered second');
|
||||||
|
@ -436,7 +436,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
await rpcProtocol.sync();
|
await rpcProtocol.sync();
|
||||||
getHover(model, new EditorPosition(1, 1), CancellationToken.None).then(value => {
|
getHoverPromise(model, new EditorPosition(1, 1), CancellationToken.None).then(value => {
|
||||||
assert.strictEqual(value.length, 1);
|
assert.strictEqual(value.length, 1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -145,6 +145,7 @@ import { FindReplaceState } from 'vs/editor/contrib/find/findState';
|
||||||
import { TerminalEditorInput } from 'vs/workbench/contrib/terminal/browser/terminalEditorInput';
|
import { TerminalEditorInput } from 'vs/workbench/contrib/terminal/browser/terminalEditorInput';
|
||||||
import { DeserializedTerminalEditorInput } from 'vs/workbench/contrib/terminal/browser/terminalEditorSerializer';
|
import { DeserializedTerminalEditorInput } from 'vs/workbench/contrib/terminal/browser/terminalEditorSerializer';
|
||||||
import { IGroupChangeEvent } from 'vs/workbench/common/editor/editorGroupModel';
|
import { IGroupChangeEvent } from 'vs/workbench/common/editor/editorGroupModel';
|
||||||
|
import { env } from 'vs/base/common/process';
|
||||||
|
|
||||||
export function createFileEditorInput(instantiationService: IInstantiationService, resource: URI): FileEditorInput {
|
export function createFileEditorInput(instantiationService: IInstantiationService, resource: URI): FileEditorInput {
|
||||||
return instantiationService.createInstance(FileEditorInput, resource, undefined, undefined, undefined, undefined, undefined, undefined);
|
return instantiationService.createInstance(FileEditorInput, resource, undefined, undefined, undefined, undefined, undefined, undefined);
|
||||||
|
@ -1824,7 +1825,7 @@ export class TestTerminalProfileResolverService implements ITerminalProfileResol
|
||||||
async getDefaultProfile(options: IShellLaunchConfigResolveOptions): Promise<ITerminalProfile> { return { path: '/default', profileName: 'Default', isDefault: true }; }
|
async getDefaultProfile(options: IShellLaunchConfigResolveOptions): Promise<ITerminalProfile> { return { path: '/default', profileName: 'Default', isDefault: true }; }
|
||||||
async getDefaultShell(options: IShellLaunchConfigResolveOptions): Promise<string> { return '/default'; }
|
async getDefaultShell(options: IShellLaunchConfigResolveOptions): Promise<string> { return '/default'; }
|
||||||
async getDefaultShellArgs(options: IShellLaunchConfigResolveOptions): Promise<string | string[]> { return []; }
|
async getDefaultShellArgs(options: IShellLaunchConfigResolveOptions): Promise<string | string[]> { return []; }
|
||||||
async getEnvironment(): Promise<IProcessEnvironment> { return process.env; }
|
async getEnvironment(): Promise<IProcessEnvironment> { return env; }
|
||||||
getSafeConfigValue(key: string, os: OperatingSystem): unknown | undefined { return undefined; }
|
getSafeConfigValue(key: string, os: OperatingSystem): unknown | undefined { return undefined; }
|
||||||
getSafeConfigValueFullKey(key: string): unknown | undefined { return undefined; }
|
getSafeConfigValueFullKey(key: string): unknown | undefined { return undefined; }
|
||||||
createProfileFromShellAndShellArgs(shell?: unknown, shellArgs?: unknown): Promise<string | ITerminalProfile> { throw new Error('Method not implemented.'); }
|
createProfileFromShellAndShellArgs(shell?: unknown, shellArgs?: unknown): Promise<string | ITerminalProfile> { throw new Error('Method not implemented.'); }
|
||||||
|
|
|
@ -39,7 +39,7 @@ export class QuickAccess {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async openFile(fileName: string): Promise<void> {
|
async openQuickAccessAndWait(fileName: string, exactMatch?: boolean): Promise<void> {
|
||||||
let retries = 0;
|
let retries = 0;
|
||||||
let fileFound = false;
|
let fileFound = false;
|
||||||
while (++retries < 10) {
|
while (++retries < 10) {
|
||||||
|
@ -49,7 +49,7 @@ export class QuickAccess {
|
||||||
|
|
||||||
await this.quickInput.waitForQuickInputElements(names => {
|
await this.quickInput.waitForQuickInputElements(names => {
|
||||||
const name = names[0];
|
const name = names[0];
|
||||||
if (name === fileName) {
|
if (exactMatch && name === fileName) {
|
||||||
fileFound = true;
|
fileFound = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,12 @@ export class QuickAccess {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
if (!exactMatch) {
|
||||||
|
fileFound = true;
|
||||||
|
return !!name;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!retry) {
|
if (!retry) {
|
||||||
|
@ -73,6 +78,10 @@ export class QuickAccess {
|
||||||
if (!fileFound) {
|
if (!fileFound) {
|
||||||
throw new Error(`Quick open file search was unable to find '${fileName}' after 10 attempts, giving up.`);
|
throw new Error(`Quick open file search was unable to find '${fileName}' after 10 attempts, giving up.`);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async openFile(fileName: string): Promise<void> {
|
||||||
|
await this.openQuickAccessAndWait(fileName, true);
|
||||||
|
|
||||||
await this.code.dispatchKeybinding('enter');
|
await this.code.dispatchKeybinding('enter');
|
||||||
await this.editors.waitForActiveTab(fileName);
|
await this.editors.waitForActiveTab(fileName);
|
||||||
|
|
|
@ -26,7 +26,8 @@ export enum TerminalCommandIdWithValue {
|
||||||
ChangeColor = 'workbench.action.terminal.changeColor',
|
ChangeColor = 'workbench.action.terminal.changeColor',
|
||||||
ChangeIcon = 'workbench.action.terminal.changeIcon',
|
ChangeIcon = 'workbench.action.terminal.changeIcon',
|
||||||
NewWithProfile = 'workbench.action.terminal.newWithProfile',
|
NewWithProfile = 'workbench.action.terminal.newWithProfile',
|
||||||
SelectDefaultProfile = 'workbench.action.terminal.selectDefaultShell'
|
SelectDefaultProfile = 'workbench.action.terminal.selectDefaultShell',
|
||||||
|
AttachToSession = 'workbench.action.terminal.attachToSession',
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum TerminalCommandId {
|
export enum TerminalCommandId {
|
||||||
|
@ -41,7 +42,8 @@ export enum TerminalCommandId {
|
||||||
MoveToPanel = 'workbench.action.terminal.moveToTerminalPanel',
|
MoveToPanel = 'workbench.action.terminal.moveToTerminalPanel',
|
||||||
MoveToEditor = 'workbench.action.terminal.moveToEditor',
|
MoveToEditor = 'workbench.action.terminal.moveToEditor',
|
||||||
NewWithProfile = 'workbench.action.terminal.newWithProfile',
|
NewWithProfile = 'workbench.action.terminal.newWithProfile',
|
||||||
SelectDefaultProfile = 'workbench.action.terminal.selectDefaultShell'
|
SelectDefaultProfile = 'workbench.action.terminal.selectDefaultShell',
|
||||||
|
DetachSession = 'workbench.action.terminal.detachSession',
|
||||||
}
|
}
|
||||||
interface TerminalLabel {
|
interface TerminalLabel {
|
||||||
name?: string,
|
name?: string,
|
||||||
|
@ -111,6 +113,27 @@ export class Terminal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getTerminalGroups(): Promise<TerminalGroup[]> {
|
||||||
|
const tabCount = (await this.code.waitForElements(Selector.Tabs, true)).length;
|
||||||
|
console.log('tabCount', tabCount);
|
||||||
|
const groups: TerminalGroup[] = [];
|
||||||
|
for (let i = 0; i < tabCount; i++) {
|
||||||
|
const instance = await this.code.waitForElement(`${Selector.Tabs}[data-index="${i}"] ${Selector.TabsEntry}`);
|
||||||
|
console.log('instance', instance);
|
||||||
|
const label: TerminalLabel = {
|
||||||
|
name: instance.textContent.replace(/^[├┌└]\s*/, '')
|
||||||
|
};
|
||||||
|
// It's a new group if the the tab does not start with ├ or └
|
||||||
|
if (instance.textContent.match(/^[├└]/)) {
|
||||||
|
groups[groups.length - 1].push(label);
|
||||||
|
} else {
|
||||||
|
groups.push([label]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log('groups', groups);
|
||||||
|
return groups;
|
||||||
|
}
|
||||||
|
|
||||||
async getSingleTabName(): Promise<string> {
|
async getSingleTabName(): Promise<string> {
|
||||||
return await (await this.code.waitForElement(Selector.SingleTab, singleTab => !!singleTab && singleTab?.textContent.length > 1)).textContent;
|
return await (await this.code.waitForElement(Selector.SingleTab, singleTab => !!singleTab && singleTab?.textContent.length > 1)).textContent;
|
||||||
}
|
}
|
||||||
|
@ -139,6 +162,10 @@ export class Terminal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async assertTerminalViewHidden(): Promise<void> {
|
||||||
|
await this.code.waitForElement(Selector.TerminalView, result => result === undefined);
|
||||||
|
}
|
||||||
|
|
||||||
async clickPlusButton(): Promise<void> {
|
async clickPlusButton(): Promise<void> {
|
||||||
await this.code.waitAndClick(Selector.PlusButton);
|
await this.code.waitAndClick(Selector.PlusButton);
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,7 +88,7 @@ export function setup(opts: minimist.ParsedArgs) {
|
||||||
'jsconfig.json'
|
'jsconfig.json'
|
||||||
];
|
];
|
||||||
|
|
||||||
await app.workbench.quickaccess.openQuickAccess('.js');
|
await app.workbench.quickaccess.openQuickAccessAndWait('.js');
|
||||||
await app.workbench.quickinput.waitForQuickInputElements(names => expectedNames.every(n => names.some(m => n === m)));
|
await app.workbench.quickinput.waitForQuickInputElements(names => expectedNames.every(n => names.some(m => n === m)));
|
||||||
await app.code.dispatchKeybinding('escape');
|
await app.code.dispatchKeybinding('escape');
|
||||||
});
|
});
|
||||||
|
@ -101,7 +101,7 @@ export function setup(opts: minimist.ParsedArgs) {
|
||||||
'package.json'
|
'package.json'
|
||||||
];
|
];
|
||||||
|
|
||||||
await app.workbench.quickaccess.openQuickAccess('a.s');
|
await app.workbench.quickaccess.openQuickAccessAndWait('a.s');
|
||||||
await app.workbench.quickinput.waitForQuickInputElements(names => expectedNames.every(n => names.some(m => n === m)));
|
await app.workbench.quickinput.waitForQuickInputElements(names => expectedNames.every(n => names.some(m => n === m)));
|
||||||
await app.code.dispatchKeybinding('escape');
|
await app.code.dispatchKeybinding('escape');
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,22 +4,16 @@
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { ParsedArgs } from 'minimist';
|
import { ParsedArgs } from 'minimist';
|
||||||
import { Terminal, TerminalCommandId, TerminalCommandIdWithValue } from '../../../../automation/out';
|
import { Application, Terminal, TerminalCommandId, TerminalCommandIdWithValue } from '../../../../automation/out';
|
||||||
import { afterSuite, beforeSuite } from '../../utils';
|
|
||||||
|
|
||||||
export function setup(opts: ParsedArgs) {
|
export function setup(opts: ParsedArgs) {
|
||||||
describe('Terminal Editors', () => {
|
describe('Terminal Editors', () => {
|
||||||
let terminal: Terminal;
|
let terminal: Terminal;
|
||||||
|
|
||||||
beforeSuite(opts);
|
// Acquire automation API
|
||||||
afterSuite(opts);
|
before(async function () {
|
||||||
|
const app = this.app as Application;
|
||||||
before(function () {
|
terminal = app.workbench.terminal;
|
||||||
terminal = this.app.workbench.terminal;
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
await terminal.runCommand(TerminalCommandId.KillAll);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: This was flaky in CI
|
// TODO: This was flaky in CI
|
||||||
|
@ -30,7 +24,8 @@ export function setup(opts: ParsedArgs) {
|
||||||
await terminal.assertSingleTab({ color }, true);
|
await terminal.assertSingleTab({ color }, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update icon of the tab', async () => {
|
// TODO: Flaky https://github.com/microsoft/vscode/issues/137808
|
||||||
|
it.skip('should update icon of the tab', async () => {
|
||||||
await terminal.runCommand(TerminalCommandId.CreateNewEditor);
|
await terminal.runCommand(TerminalCommandId.CreateNewEditor);
|
||||||
const icon = 'symbol-method';
|
const icon = 'symbol-method';
|
||||||
await terminal.runCommandWithValue(TerminalCommandIdWithValue.ChangeIcon, icon);
|
await terminal.runCommandWithValue(TerminalCommandIdWithValue.ChangeIcon, icon);
|
||||||
|
|
102
test/smoke/src/areas/terminal/terminal-persistence.test.ts
Normal file
102
test/smoke/src/areas/terminal/terminal-persistence.test.ts
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { ParsedArgs } from 'minimist';
|
||||||
|
import { Application, Terminal, TerminalCommandId, TerminalCommandIdWithValue } from '../../../../automation/out';
|
||||||
|
|
||||||
|
export function setup(opts: ParsedArgs) {
|
||||||
|
describe('Terminal Persistence', () => {
|
||||||
|
// Acquire automation API
|
||||||
|
let terminal: Terminal;
|
||||||
|
before(function () {
|
||||||
|
const app = this.app as Application;
|
||||||
|
terminal = app.workbench.terminal;
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('detach/attach', () => {
|
||||||
|
// https://github.com/microsoft/vscode/issues/137799
|
||||||
|
it.skip('should support basic reconnection', async () => {
|
||||||
|
await terminal.runCommand(TerminalCommandId.CreateNew);
|
||||||
|
// TODO: Handle passing in an actual regex, not string
|
||||||
|
await terminal.assertTerminalGroups([
|
||||||
|
[{ name: '.*' }]
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Get the terminal name
|
||||||
|
await terminal.assertTerminalGroups([
|
||||||
|
[{ name: '.*' }]
|
||||||
|
]);
|
||||||
|
const name = (await terminal.getTerminalGroups())[0][0].name!;
|
||||||
|
|
||||||
|
// Detach
|
||||||
|
await terminal.runCommand(TerminalCommandId.DetachSession);
|
||||||
|
await terminal.assertTerminalViewHidden();
|
||||||
|
|
||||||
|
// Attach
|
||||||
|
await terminal.runCommandWithValue(TerminalCommandIdWithValue.AttachToSession, name);
|
||||||
|
await terminal.assertTerminalGroups([
|
||||||
|
[{ name }]
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should persist buffer content', async () => {
|
||||||
|
await terminal.runCommand(TerminalCommandId.CreateNew);
|
||||||
|
// TODO: Handle passing in an actual regex, not string
|
||||||
|
await terminal.assertTerminalGroups([
|
||||||
|
[{ name: '.*' }]
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Get the terminal name
|
||||||
|
await terminal.assertTerminalGroups([
|
||||||
|
[{ name: '.*' }]
|
||||||
|
]);
|
||||||
|
const name = (await terminal.getTerminalGroups())[0][0].name!;
|
||||||
|
|
||||||
|
// Write in terminal
|
||||||
|
await terminal.runCommandInTerminal('echo terminal_test_content');
|
||||||
|
await terminal.waitForTerminalText(buffer => buffer.some(e => e.includes('terminal_test_content')));
|
||||||
|
|
||||||
|
// Detach
|
||||||
|
await terminal.runCommand(TerminalCommandId.DetachSession);
|
||||||
|
await terminal.assertTerminalViewHidden();
|
||||||
|
|
||||||
|
// Attach
|
||||||
|
await terminal.runCommandWithValue(TerminalCommandIdWithValue.AttachToSession, name);
|
||||||
|
await terminal.assertTerminalGroups([
|
||||||
|
[{ name }]
|
||||||
|
]);
|
||||||
|
await terminal.waitForTerminalText(buffer => buffer.some(e => e.includes('terminal_test_content')));
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: This is currently flaky because it takes time to send over the new icon to the backend
|
||||||
|
it.skip('should persist terminal icon', async () => {
|
||||||
|
await terminal.runCommand(TerminalCommandId.CreateNew);
|
||||||
|
// TODO: Handle passing in an actual regex, not string
|
||||||
|
await terminal.assertTerminalGroups([
|
||||||
|
[{ name: '.*' }]
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Get the terminal name
|
||||||
|
const name = (await terminal.getTerminalGroups())[0][0].name!;
|
||||||
|
|
||||||
|
// Set the icon
|
||||||
|
await terminal.runCommandWithValue(TerminalCommandIdWithValue.ChangeIcon, 'symbol-method');
|
||||||
|
await terminal.assertSingleTab({ icon: 'symbol-method' });
|
||||||
|
|
||||||
|
// Detach
|
||||||
|
await terminal.runCommand(TerminalCommandId.DetachSession);
|
||||||
|
await terminal.assertTerminalViewHidden();
|
||||||
|
|
||||||
|
// Attach
|
||||||
|
await terminal.runCommandWithValue(TerminalCommandIdWithValue.AttachToSession, name);
|
||||||
|
await terminal.assertTerminalGroups([
|
||||||
|
[{ name }]
|
||||||
|
]);
|
||||||
|
// TODO: This fails due to a bug
|
||||||
|
await terminal.assertSingleTab({ icon: 'symbol-method' });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
|
@ -4,25 +4,18 @@
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { ParsedArgs } from 'minimist';
|
import { ParsedArgs } from 'minimist';
|
||||||
import { Terminal, TerminalCommandId, TerminalCommandIdWithValue } from '../../../../automation';
|
import { Application, Terminal, TerminalCommandId, TerminalCommandIdWithValue } from '../../../../automation';
|
||||||
import { afterSuite, beforeSuite } from '../../utils';
|
|
||||||
|
|
||||||
const CONTRIBUTED_PROFILE_NAME = `JavaScript Debug Terminal`;
|
const CONTRIBUTED_PROFILE_NAME = `JavaScript Debug Terminal`;
|
||||||
const ANY_PROFILE_NAME = '^((?!JavaScript Debug Terminal).)*$';
|
const ANY_PROFILE_NAME = '^((?!JavaScript Debug Terminal).)*$';
|
||||||
|
|
||||||
export function setup(opts: ParsedArgs) {
|
export function setup(opts: ParsedArgs) {
|
||||||
describe('Terminal Profiles', () => {
|
describe('Terminal Profiles', () => {
|
||||||
|
// Acquire automation API
|
||||||
let terminal: Terminal;
|
let terminal: Terminal;
|
||||||
|
|
||||||
beforeSuite(opts);
|
|
||||||
afterSuite(opts);
|
|
||||||
|
|
||||||
before(function () {
|
before(function () {
|
||||||
terminal = this.app.workbench.terminal;
|
const app = this.app as Application;
|
||||||
});
|
terminal = app.workbench.terminal;
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
await terminal.runCommand(TerminalCommandId.KillAll);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should launch the default profile', async () => {
|
it('should launch the default profile', async () => {
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------------------------
|
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
||||||
*--------------------------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
import { ParsedArgs } from 'minimist';
|
|
||||||
import { Application } from '../../../../automation';
|
|
||||||
import { afterSuite, beforeSuite } from '../../utils';
|
|
||||||
|
|
||||||
export function setup(opts: ParsedArgs) {
|
|
||||||
describe('Terminal Reconnection', () => {
|
|
||||||
beforeSuite(opts);
|
|
||||||
afterSuite(opts);
|
|
||||||
|
|
||||||
it.skip('should reconnect to a single terminal on reload', async () => {
|
|
||||||
const app = this.app as Application;
|
|
||||||
console.log(app);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -5,22 +5,15 @@
|
||||||
|
|
||||||
|
|
||||||
import { ParsedArgs } from 'minimist';
|
import { ParsedArgs } from 'minimist';
|
||||||
import { Terminal, TerminalCommandId, TerminalCommandIdWithValue } from '../../../../automation/out';
|
import { Application, Terminal, TerminalCommandId, TerminalCommandIdWithValue } from '../../../../automation/out';
|
||||||
import { afterSuite, beforeSuite } from '../../utils';
|
|
||||||
|
|
||||||
export function setup(opts: ParsedArgs) {
|
export function setup(opts: ParsedArgs) {
|
||||||
describe('Terminal Tabs', () => {
|
describe('Terminal Tabs', () => {
|
||||||
|
// Acquire automation API
|
||||||
let terminal: Terminal;
|
let terminal: Terminal;
|
||||||
|
|
||||||
beforeSuite(opts);
|
|
||||||
afterSuite(opts);
|
|
||||||
|
|
||||||
before(function () {
|
before(function () {
|
||||||
terminal = this.app.workbench.terminal;
|
const app = this.app as Application;
|
||||||
});
|
terminal = app.workbench.terminal;
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
await terminal.runCommand(TerminalCommandId.KillAll);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('clicking the plus button should create a terminal and display the tabs view showing no split decorations', async () => {
|
it('clicking the plus button should create a terminal and display the tabs view showing no split decorations', async () => {
|
||||||
|
@ -67,7 +60,8 @@ export function setup(opts: ParsedArgs) {
|
||||||
await terminal.assertSingleTab({ name });
|
await terminal.assertSingleTab({ name });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should reset the tab name to the default value when no name is provided', async () => {
|
// Flaky: https://github.com/microsoft/vscode/issues/137795
|
||||||
|
it.skip('should reset the tab name to the default value when no name is provided', async () => {
|
||||||
await terminal.runCommand(TerminalCommandId.Show);
|
await terminal.runCommand(TerminalCommandId.Show);
|
||||||
const defaultName = await terminal.getSingleTabName();
|
const defaultName = await terminal.getSingleTabName();
|
||||||
const name = 'my terminal name';
|
const name = 'my terminal name';
|
||||||
|
|
47
test/smoke/src/areas/terminal/terminal.test.ts
Normal file
47
test/smoke/src/areas/terminal/terminal.test.ts
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import minimist = require('minimist');
|
||||||
|
import { Application, Terminal, TerminalCommandId } from '../../../../automation/out';
|
||||||
|
import { afterSuite, beforeSuite } from '../../utils';
|
||||||
|
import { setup as setupTerminalEditorsTests } from './terminal-editors.test';
|
||||||
|
import { setup as setupTerminalPersistenceTests } from './terminal-persistence.test';
|
||||||
|
import { setup as setupTerminalProfileTests } from './terminal-profiles.test';
|
||||||
|
import { setup as setupTerminalTabsTests } from './terminal-tabs.test';
|
||||||
|
|
||||||
|
export function setup(opts: minimist.ParsedArgs) {
|
||||||
|
describe('Terminal', () => {
|
||||||
|
// TODO: Enable terminal tests for non-web when the desktop driver is moved to playwright
|
||||||
|
if (!opts.web) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeSuite(opts);
|
||||||
|
afterSuite(opts);
|
||||||
|
|
||||||
|
let terminal: Terminal;
|
||||||
|
before(async function () {
|
||||||
|
// Fetch terminal automation API
|
||||||
|
const app = this.app as Application;
|
||||||
|
terminal = app.workbench.terminal;
|
||||||
|
|
||||||
|
// Always show tabs to make getting terminal groups easier
|
||||||
|
await app.workbench.settingsEditor.addUserSetting('terminal.integrated.tabs.hideCondition', '"never"');
|
||||||
|
|
||||||
|
// Close the settings editor
|
||||||
|
await app.workbench.quickaccess.runCommand('workbench.action.closeAllEditors');
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
// Kill all terminals between every test for a consistent testing environment
|
||||||
|
await terminal.runCommand(TerminalCommandId.KillAll);
|
||||||
|
});
|
||||||
|
|
||||||
|
setupTerminalEditorsTests(opts);
|
||||||
|
setupTerminalPersistenceTests(opts);
|
||||||
|
setupTerminalProfileTests(opts);
|
||||||
|
setupTerminalTabsTests(opts);
|
||||||
|
});
|
||||||
|
}
|
|
@ -28,9 +28,7 @@ import { setup as setupExtensionTests } from './areas/extensions/extensions.test
|
||||||
import { setup as setupMultirootTests } from './areas/multiroot/multiroot.test';
|
import { setup as setupMultirootTests } from './areas/multiroot/multiroot.test';
|
||||||
import { setup as setupLocalizationTests } from './areas/workbench/localization.test';
|
import { setup as setupLocalizationTests } from './areas/workbench/localization.test';
|
||||||
import { setup as setupLaunchTests } from './areas/workbench/launch.test';
|
import { setup as setupLaunchTests } from './areas/workbench/launch.test';
|
||||||
import { setup as setupTerminalProfileTests } from './areas/terminal/terminal-profiles.test';
|
import { setup as setupTerminalTests } from './areas/terminal/terminal.test';
|
||||||
import { setup as setupTerminalTabsTests } from './areas/terminal/terminal-tabs.test';
|
|
||||||
import { setup as setupTerminalEditorsTests } from './areas/terminal/terminal-editors.test';
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
gracefulify(fs);
|
gracefulify(fs);
|
||||||
|
@ -361,14 +359,10 @@ describe(`VSCode Smoke Tests (${opts.web ? 'Web' : 'Electron'})`, () => {
|
||||||
setupNotebookTests(opts);
|
setupNotebookTests(opts);
|
||||||
setupLanguagesTests(opts);
|
setupLanguagesTests(opts);
|
||||||
setupEditorTests(opts);
|
setupEditorTests(opts);
|
||||||
|
setupTerminalTests(opts);
|
||||||
setupStatusbarTests(opts);
|
setupStatusbarTests(opts);
|
||||||
setupExtensionTests(opts);
|
setupExtensionTests(opts);
|
||||||
if (!opts.web) { setupMultirootTests(opts); }
|
if (!opts.web) { setupMultirootTests(opts); }
|
||||||
if (!opts.web) { setupLocalizationTests(opts); }
|
if (!opts.web) { setupLocalizationTests(opts); }
|
||||||
if (!opts.web) { setupLaunchTests(opts); }
|
if (!opts.web) { setupLaunchTests(opts); }
|
||||||
|
|
||||||
// TODO: Enable terminal tests for non-web
|
|
||||||
if (opts.web) { setupTerminalProfileTests(opts); }
|
|
||||||
if (opts.web) { setupTerminalTabsTests(opts); }
|
|
||||||
if (opts.web) { setupTerminalEditorsTests(opts); }
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------------------------
|
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
||||||
*--------------------------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
const yaserver = require('yaserver');
|
|
||||||
const http = require('http');
|
|
||||||
const glob = require('glob');
|
|
||||||
const path = require('path');
|
|
||||||
const fs = require('fs');
|
|
||||||
|
|
||||||
const REPO_ROOT = path.join(__dirname, '../../../');
|
|
||||||
const PORT = 8887;
|
|
||||||
|
|
||||||
function template(str, env) {
|
|
||||||
return str.replace(/{{\s*([\w_\-]+)\s*}}/g, function (all, part) {
|
|
||||||
return env[part];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
yaserver.createServer({ rootDir: REPO_ROOT }).then((staticServer) => {
|
|
||||||
const server = http.createServer((req, res) => {
|
|
||||||
if (req.url === '' || req.url === '/') {
|
|
||||||
glob('**/vs/{base,platform,editor}/**/test/{common,browser}/**/*.test.js', {
|
|
||||||
cwd: path.join(REPO_ROOT, 'out'),
|
|
||||||
// ignore: ['**/test/{node,electron*}/**/*.js']
|
|
||||||
}, function (err, files) {
|
|
||||||
if (err) { console.log(err); process.exit(0); }
|
|
||||||
|
|
||||||
var modules = files
|
|
||||||
.map(function (file) { return file.replace(/\.js$/, ''); });
|
|
||||||
|
|
||||||
fs.readFile(path.join(__dirname, 'index.html'), 'utf8', function (err, templateString) {
|
|
||||||
if (err) { console.log(err); process.exit(0); }
|
|
||||||
|
|
||||||
res.end(template(templateString, {
|
|
||||||
modules: JSON.stringify(modules)
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return staticServer.handle(req, res);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
server.listen(PORT, () => {
|
|
||||||
console.log(`http://localhost:${PORT}/`);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,12 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------------------------
|
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
||||||
*--------------------------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
define([], function() {
|
|
||||||
return {
|
|
||||||
load: function(name, req, load) {
|
|
||||||
load({});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
|
@ -1,30 +0,0 @@
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<title>VSCode Tests</title>
|
|
||||||
<link href="https://cdn.rawgit.com/mochajs/mocha/2.2.5/mocha.css" rel="stylesheet" />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mocha"></div>
|
|
||||||
|
|
||||||
<script src="/out/vs/loader.js"></script>
|
|
||||||
<script src="https://cdn.rawgit.com/mochajs/mocha/2.2.5/mocha.js"></script>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
mocha.setup('tdd');
|
|
||||||
|
|
||||||
require.config({
|
|
||||||
baseUrl: '/out',
|
|
||||||
paths: {
|
|
||||||
assert: '/test/unit/assert.js',
|
|
||||||
sinon: '/node_modules/sinon/pkg/sinon.js',
|
|
||||||
'sinon-test': '/node_modules/sinon-test/dist/sinon-test.js'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
require({{ modules }}, function () {
|
|
||||||
mocha.run();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue