Merge from vscode 8a997f7321ae6612fc0e6eb3eac4f358a6233bfb

This commit is contained in:
ADS Merger
2020-02-11 07:08:19 +00:00
parent 0f934081e1
commit 085752f111
217 changed files with 2561 additions and 2063 deletions

View File

@@ -11,46 +11,49 @@ on:
- release/* - release/*
jobs: jobs:
# linux: linux:
# runs-on: ubuntu-latest runs-on: ubuntu-latest
# env: env:
# CHILD_CONCURRENCY: "1" CHILD_CONCURRENCY: "1"
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# steps: steps:
# - uses: actions/checkout@v1 - uses: actions/checkout@v1
# # TODO: rename azure-pipelines/linux/xvfb.init to github-actions # TODO: rename azure-pipelines/linux/xvfb.init to github-actions
# - run: | - run: |
# sudo apt-get update sudo apt-get update
# sudo apt-get install -y libxkbfile-dev pkg-config libsecret-1-dev libxss1 dbus xvfb libgtk-3-0 libkrb5-dev # {{SQL CARBON EDIT}} add kerberos dep sudo apt-get install -y libxkbfile-dev pkg-config libsecret-1-dev libxss1 dbus xvfb libgtk-3-0 libkrb5-dev # {{SQL CARBON EDIT}} add kerberos dep
# sudo cp build/azure-pipelines/linux/xvfb.init /etc/init.d/xvfb sudo cp build/azure-pipelines/linux/xvfb.init /etc/init.d/xvfb
# sudo chmod +x /etc/init.d/xvfb sudo chmod +x /etc/init.d/xvfb
# sudo update-rc.d xvfb defaults sudo update-rc.d xvfb defaults
# sudo service xvfb start sudo service xvfb start
# name: Setup Build Environment name: Setup Build Environment
# - uses: actions/setup-node@v1 - uses: actions/setup-node@v1
# with: with:
# node-version: 10 node-version: 10
# # TODO: cache node modules # TODO: cache node modules
# - run: yarn --frozen-lockfile - run: yarn --frozen-lockfile
# name: Install Dependencies name: Install Dependencies
# - run: yarn electron x64 - run: yarn electron x64
# name: Download Electron name: Download Electron
# - run: yarn gulp hygiene - run: yarn gulp hygiene
# name: Run Hygiene Checks name: Run Hygiene Checks
# - run: yarn strict-vscode # {{SQL CARBON EDIT}} add step - run: yarn strict-vscode # {{SQL CARBON EDIT}} add step
# name: Run Strict Compile Options name: Run Strict Compile Options
# # - run: yarn monaco-compile-check {{SQL CARBON EDIT}} remove step # - run: yarn monaco-compile-check {{SQL CARBON EDIT}} remove step
# # name: Run Monaco Editor Checks # name: Run Monaco Editor Checks
# - run: yarn valid-layers-check - run: yarn valid-layers-check
# name: Run Valid Layers Checks name: Run Valid Layers Checks
# - run: yarn compile - run: yarn compile
# name: Compile Sources name: Compile Sources
# # - run: yarn download-builtin-extensions {{SQL CARBON EDIT}} remove step # - run: yarn download-builtin-extensions {{SQL CARBON EDIT}} remove step
# # name: Download Built-in Extensions # name: Download Built-in Extensions
# - run: DISPLAY=:10 ./scripts/test.sh --tfs "Unit Tests" - run: DISPLAY=:10 ./scripts/test.sh --tfs "Unit Tests"
# name: Run Unit Tests name: Run Unit Tests (Electron)
# # - run: DISPLAY=:10 ./scripts/test-integration.sh --tfs "Integration Tests" {{SQL CARBON EDIT}} remove step # Fails with cryptic error (e.g. https://github.com/microsoft/vscode/pull/90292/checks?check_run_id=433681926#step:13:9)
# # name: Run Integration Tests # - run: DISPLAY=:10 yarn test-browser --browser chromium
# name: Run Unit Tests (Browser)
# - run: DISPLAY=:10 ./scripts/test-integration.sh --tfs "Integration Tests" {{SQL CARBON EDIT}} remove step
# name: Run Integration Tests (Electron)
windows: windows:
runs-on: windows-2016 runs-on: windows-2016
@@ -82,9 +85,11 @@ jobs:
# - run: yarn download-builtin-extensions {{SQL CARBON EDIT}} remove step # - run: yarn download-builtin-extensions {{SQL CARBON EDIT}} remove step
# name: Download Built-in Extensions # name: Download Built-in Extensions
- run: .\scripts\test.bat --tfs "Unit Tests" - run: .\scripts\test.bat --tfs "Unit Tests"
name: Run Unit Tests name: Run Unit Tests (Electron)
- run: yarn test-browser --browser chromium
name: Run Unit Tests (Browser)
# - run: .\scripts\test-integration.bat --tfs "Integration Tests" {{SQL CARBON EDIT}} remove step # - run: .\scripts\test-integration.bat --tfs "Integration Tests" {{SQL CARBON EDIT}} remove step
# name: Run Integration Tests # name: Run Integration Tests (Electron)
darwin: darwin:
runs-on: macos-latest runs-on: macos-latest
@@ -113,6 +118,8 @@ jobs:
# - run: yarn download-builtin-extensions {{SQL CARBON EDIT}} remove step # - run: yarn download-builtin-extensions {{SQL CARBON EDIT}} remove step
# name: Download Built-in Extensions # name: Download Built-in Extensions
- run: ./scripts/test.sh --tfs "Unit Tests" - run: ./scripts/test.sh --tfs "Unit Tests"
name: Run Unit Tests name: Run Unit Tests (Electron)
- run: yarn test-browser --browser chromium --browser webkit
name: Run Unit Tests (Browser)
# - run: ./scripts/test-integration.sh --tfs "Integration Tests" {{SQL CARBON EDIT}} remove step # - run: ./scripts/test-integration.sh --tfs "Integration Tests" {{SQL CARBON EDIT}} remove step
# name: Run Integration Tests # name: Run Integration Tests (Electron)

View File

@@ -43,13 +43,13 @@ steps:
# displayName: Download Built-in Extensions # displayName: Download Built-in Extensions
- script: | - script: |
./scripts/test.sh --tfs "Unit Tests" ./scripts/test.sh --tfs "Unit Tests"
displayName: Run Unit Tests displayName: Run Unit Tests (Electron)
- script: | - script: |
yarn test-browser --browser chromium --browser webkit yarn test-browser --browser chromium --browser webkit
displayName: Run Unit Tests (Browsers) displayName: Run Unit Tests (Browser)
# - script: | {{SQL CARBON EDIT}} remove step # - script: | {{SQL CARBON EDIT}} remove step
# ./scripts/test-integration.sh --tfs "Integration Tests" # ./scripts/test-integration.sh --tfs "Integration Tests"
# displayName: Run Integration Tests # displayName: Run Integration Tests (Electron)
- task: PublishTestResults@2 - task: PublishTestResults@2
displayName: Publish Tests Results displayName: Publish Tests Results
inputs: inputs:

View File

@@ -44,13 +44,6 @@ steps:
git config user.email "vscode@microsoft.com" git config user.email "vscode@microsoft.com"
git config user.name "VSCode" git config user.name "VSCode"
security create-keychain -p pwd $(agent.tempdirectory)/buildagent.keychain
security default-keychain -s $(agent.tempdirectory)/buildagent.keychain
security unlock-keychain -p pwd $(agent.tempdirectory)/buildagent.keychain
echo "$(macos-developer-certificate)" | base64 -D > $(agent.tempdirectory)/cert.p12
security import $(agent.tempdirectory)/cert.p12 -k $(agent.tempdirectory)/buildagent.keychain -P "$(macos-developer-certificate-key)" -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k pwd $(agent.tempdirectory)/buildagent.keychain
displayName: Prepare tooling displayName: Prepare tooling
- script: | - script: |
@@ -103,9 +96,13 @@ steps:
- script: | - script: |
set -e set -e
./scripts/test.sh --build --tfs "Unit Tests" ./scripts/test.sh --build --tfs "Unit Tests"
# APP_NAME="`ls $(agent.builddirectory)/VSCode-darwin | head -n 1`" displayName: Run unit tests (Electron)
# yarn smoketest -- --build "$(agent.builddirectory)/VSCode-darwin/$APP_NAME" condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
displayName: Run unit tests
- script: |
set -e
yarn test-browser --build --browser chromium --browser webkit
displayName: Run unit tests (Browser)
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
- script: | - script: |
@@ -118,22 +115,32 @@ steps:
INTEGRATION_TEST_ELECTRON_PATH="$APP_ROOT/$APP_NAME/Contents/MacOS/Electron" \ INTEGRATION_TEST_ELECTRON_PATH="$APP_ROOT/$APP_NAME/Contents/MacOS/Electron" \
VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-darwin" \ VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-darwin" \
./scripts/test-integration.sh --build --tfs "Integration Tests" ./scripts/test-integration.sh --build --tfs "Integration Tests"
displayName: Run integration tests displayName: Run integration tests (Electron)
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
- script: | - script: |
set -e set -e
cd test/smoke
yarn compile
cd -
VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-darwin" \ VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-darwin" \
yarn smoketest --web --headless ./resources/server/test/test-web-integration.sh --browser webkit
continueOnError: true displayName: Run integration tests (Browser)
displayName: Run web smoke tests
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
- script: | - script: |
set -e set -e
VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-darwin" \
yarn smoketest --web --headless --browser webkit
continueOnError: true
displayName: Run smoke tests (Browser)
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
- script: |
set -e
security create-keychain -p pwd $(agent.tempdirectory)/buildagent.keychain
security default-keychain -s $(agent.tempdirectory)/buildagent.keychain
security unlock-keychain -p pwd $(agent.tempdirectory)/buildagent.keychain
echo "$(macos-developer-certificate)" | base64 -D > $(agent.tempdirectory)/cert.p12
security import $(agent.tempdirectory)/cert.p12 -k $(agent.tempdirectory)/buildagent.keychain -P "$(macos-developer-certificate-key)" -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k pwd $(agent.tempdirectory)/buildagent.keychain
codesign -s 99FM488X57 --deep --force --options runtime --entitlements build/azure-pipelines/darwin/entitlements.plist $(agent.builddirectory)/VSCode-darwin/*.app codesign -s 99FM488X57 --deep --force --options runtime --entitlements build/azure-pipelines/darwin/entitlements.plist $(agent.builddirectory)/VSCode-darwin/*.app
displayName: Set Hardened Entitlements displayName: Set Hardened Entitlements

View File

@@ -51,13 +51,13 @@ steps:
# displayName: Download Built-in Extensions # displayName: Download Built-in Extensions
- script: | - script: |
DISPLAY=:10 ./scripts/test.sh --tfs "Unit Tests" DISPLAY=:10 ./scripts/test.sh --tfs "Unit Tests"
displayName: Run Unit Tests displayName: Run Unit Tests (Electron)
- script: | - script: |
DISPLAY=:10 yarn test-browser --browser chromium DISPLAY=:10 yarn test-browser --browser chromium
displayName: Run Unit Tests (Browser) displayName: Run Unit Tests (Browser)
# - script: | {{SQL CARBON EDIT}} remove step # - script: | {{SQL CARBON EDIT}} remove step
# DISPLAY=:10 ./scripts/test-integration.sh --tfs "Integration Tests" # DISPLAY=:10 ./scripts/test-integration.sh --tfs "Integration Tests"
# displayName: Run Integration Tests # displayName: Run Integration Tests (Electron)
- task: PublishTestResults@2 - task: PublishTestResults@2
displayName: Publish Tests Results displayName: Publish Tests Results
inputs: inputs:

View File

@@ -101,7 +101,13 @@ steps:
- script: | - script: |
set -e set -e
DISPLAY=:10 ./scripts/test.sh --build --tfs "Unit Tests" DISPLAY=:10 ./scripts/test.sh --build --tfs "Unit Tests"
displayName: Run unit tests displayName: Run unit tests (Electron)
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
- script: |
set -e
DISPLAY=:10 yarn test-browser --build --browser chromium
displayName: Run unit tests (Browser)
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
- script: | - script: |
@@ -114,8 +120,23 @@ steps:
INTEGRATION_TEST_ELECTRON_PATH="$APP_ROOT/$APP_NAME" \ INTEGRATION_TEST_ELECTRON_PATH="$APP_ROOT/$APP_NAME" \
VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-linux-x64" \ VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-linux-x64" \
DISPLAY=:10 ./scripts/test-integration.sh --build --tfs "Integration Tests" DISPLAY=:10 ./scripts/test-integration.sh --build --tfs "Integration Tests"
# yarn smoketest -- --build "$(agent.builddirectory)/VSCode-linux-x64" displayName: Run integration tests (Electron)
displayName: Run integration tests condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
# Fails due to weird error: Protocol error (Target.getBrowserContexts): Target closed.
# - script: |
# set -e
# VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-linux-x64" \
# DISPLAY=:10 ./resources/server/test/test-web-integration.sh --browser chromium
# displayName: Run integration tests (Browser)
# condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
- script: |
set -e
VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-linux-x64" \
yarn smoketest --web --headless --browser firefox
continueOnError: true
displayName: Run smoke tests (Firefox)
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
- script: | - script: |

View File

@@ -48,13 +48,13 @@ steps:
# displayName: Download Built-in Extensions # displayName: Download Built-in Extensions
- powershell: | - powershell: |
.\scripts\test.bat --tfs "Unit Tests" .\scripts\test.bat --tfs "Unit Tests"
displayName: Run Unit Tests displayName: Run Unit Tests (Electron)
- powershell: | - powershell: |
yarn test-browser --browser chromium --browser webkit yarn test-browser --browser chromium
displayName: Run Unit Tests (Browser) displayName: Run Unit Tests (Browser)
# - powershell: | {{SQL CARBON EDIT}} remove step # - powershell: | {{SQL CARBON EDIT}} remove step
# .\scripts\test-integration.bat --tfs "Integration Tests" # .\scripts\test-integration.bat --tfs "Integration Tests"
# displayName: Run Integration Tests # displayName: Run Integration Tests (Electron)
- task: PublishTestResults@2 - task: PublishTestResults@2
displayName: Publish Tests Results displayName: Publish Tests Results
inputs: inputs:

View File

@@ -109,7 +109,14 @@ steps:
$ErrorActionPreference = "Stop" $ErrorActionPreference = "Stop"
exec { yarn electron $(VSCODE_ARCH) } exec { yarn electron $(VSCODE_ARCH) }
exec { .\scripts\test.bat --build --tfs "Unit Tests" } exec { .\scripts\test.bat --build --tfs "Unit Tests" }
displayName: Run unit tests displayName: Run unit tests (Electron)
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
- powershell: |
. build/azure-pipelines/win32/exec.ps1
$ErrorActionPreference = "Stop"
exec { yarn test-browser --build --browser chromium }
displayName: Run unit tests (Browser)
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
- powershell: | - powershell: |
@@ -122,7 +129,22 @@ steps:
$AppProductJson = Get-Content -Raw -Path "$AppRoot\resources\app\product.json" | ConvertFrom-Json $AppProductJson = Get-Content -Raw -Path "$AppRoot\resources\app\product.json" | ConvertFrom-Json
$AppNameShort = $AppProductJson.nameShort $AppNameShort = $AppProductJson.nameShort
exec { $env:INTEGRATION_TEST_ELECTRON_PATH = "$AppRoot\$AppNameShort.exe"; $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-reh-win32-$(VSCODE_ARCH)"; .\scripts\test-integration.bat --build --tfs "Integration Tests" } exec { $env:INTEGRATION_TEST_ELECTRON_PATH = "$AppRoot\$AppNameShort.exe"; $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-reh-win32-$(VSCODE_ARCH)"; .\scripts\test-integration.bat --build --tfs "Integration Tests" }
displayName: Run integration tests displayName: Run integration tests (Electron)
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
- powershell: |
. build/azure-pipelines/win32/exec.ps1
$ErrorActionPreference = "Stop"
exec { $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-reh-web-win32-$(VSCODE_ARCH)"; .\resources\server\test\test-web-integration.bat --browser chromium }
displayName: Run integration tests (Browser)
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
- powershell: |
. build/azure-pipelines/win32/exec.ps1
$ErrorActionPreference = "Stop"
exec { $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-reh-web-win32-$(VSCODE_ARCH)"; yarn smoketest --web --headless --browser chromium }
continueOnError: true
displayName: Run smoke tests (Browser)
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1 - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1

View File

@@ -333,7 +333,7 @@ function sanitizePath(path: string): string {
return path.replace(/^([a-z]):\\/i, (_, letter) => `${letter.toUpperCase()}:\\`); return path.replace(/^([a-z]):\\/i, (_, letter) => `${letter.toUpperCase()}:\\`);
} }
const COMMIT_FORMAT = '%H\n%aN\n%aE\n%at\n%P\n%B'; const COMMIT_FORMAT = '%H%n%aN%n%aE%n%at%n%P%n%B';
export class Git { export class Git {
@@ -801,8 +801,8 @@ export class Repository {
} }
async log(options?: LogOptions): Promise<Commit[]> { async log(options?: LogOptions): Promise<Commit[]> {
const maxEntries = options && typeof options.maxEntries === 'number' && options.maxEntries > 0 ? options.maxEntries : 32; const maxEntries = options?.maxEntries ?? 32;
const args = ['log', '-' + maxEntries, `--format:${COMMIT_FORMAT}`, '-z']; const args = ['log', `-n${maxEntries}`, `--format=${COMMIT_FORMAT}`, '-z', '--'];
const result = await this.run(args); const result = await this.run(args);
if (result.exitCode) { if (result.exitCode) {
@@ -815,7 +815,7 @@ export class Repository {
async logFile(uri: Uri, options?: LogFileOptions): Promise<Commit[]> { async logFile(uri: Uri, options?: LogFileOptions): Promise<Commit[]> {
const maxEntries = options?.maxEntries ?? 32; const maxEntries = options?.maxEntries ?? 32;
const args = ['log', `-${maxEntries}`, `--format=${COMMIT_FORMAT}`, '-z', '--', uri.fsPath]; const args = ['log', `-n${maxEntries}`, `--format=${COMMIT_FORMAT}`, '-z', '--', uri.fsPath];
const result = await this.run(args); const result = await this.run(args);
if (result.exitCode) { if (result.exitCode) {

View File

@@ -333,7 +333,7 @@
"dependencies": { "dependencies": {
"highlight.js": "9.15.10", "highlight.js": "9.15.10",
"markdown-it": "^10.0.0", "markdown-it": "^10.0.0",
"markdown-it-front-matter": "^0.1.2", "markdown-it-front-matter": "^0.2.1",
"vscode-extension-telemetry": "0.1.1", "vscode-extension-telemetry": "0.1.1",
"vscode-nls": "^4.0.0" "vscode-nls": "^4.0.0"
}, },

View File

@@ -0,0 +1 @@
DO NOT DELETE, USED BY INTEGRATION TESTS

View File

@@ -2821,10 +2821,10 @@ map-visit@^1.0.0:
dependencies: dependencies:
object-visit "^1.0.0" object-visit "^1.0.0"
markdown-it-front-matter@^0.1.2: markdown-it-front-matter@^0.2.1:
version "0.1.2" version "0.2.1"
resolved "https://registry.yarnpkg.com/markdown-it-front-matter/-/markdown-it-front-matter-0.1.2.tgz#e50bf56e77e6a4f5ac4ffa894d4d45ccd9896b20" resolved "https://registry.yarnpkg.com/markdown-it-front-matter/-/markdown-it-front-matter-0.2.1.tgz#dca49a827bb3cebb0528452c1d87dff276eb28dc"
integrity sha1-5Qv1bnfmpPWsT/qJTU1FzNmJayA= integrity sha512-ydUIqlKfDscRpRUTRcA3maeeUKn3Cl5EaKZSA+I/f0KOGCBurW7e+bbz59sxqkC3FA9Q2S2+t4mpkH9T0BCM6A==
markdown-it@^10.0.0: markdown-it@^10.0.0:
version "10.0.0" version "10.0.0"

View File

@@ -75,11 +75,11 @@
"vscode-minimist": "^1.2.2", "vscode-minimist": "^1.2.2",
"vscode-nsfw": "1.2.8", "vscode-nsfw": "1.2.8",
"vscode-proxy-agent": "^0.5.2", "vscode-proxy-agent": "^0.5.2",
"vscode-ripgrep": "^1.5.7", "vscode-ripgrep": "^1.5.8",
"vscode-sqlite3": "4.0.9", "vscode-sqlite3": "4.0.9",
"vscode-textmate": "4.4.0", "vscode-textmate": "4.4.0",
"xterm": "4.4.0", "xterm": "4.4.0",
"xterm-addon-search": "0.4.0", "xterm-addon-search": "0.5.0",
"xterm-addon-unicode11": "0.1.1", "xterm-addon-unicode11": "0.1.1",
"xterm-addon-web-links": "0.2.1", "xterm-addon-web-links": "0.2.1",
"xterm-addon-webgl": "0.5.0", "xterm-addon-webgl": "0.5.0",

View File

@@ -18,10 +18,10 @@
"vscode-minimist": "^1.2.2", "vscode-minimist": "^1.2.2",
"vscode-nsfw": "1.2.8", "vscode-nsfw": "1.2.8",
"vscode-proxy-agent": "^0.5.2", "vscode-proxy-agent": "^0.5.2",
"vscode-ripgrep": "^1.5.7", "vscode-ripgrep": "^1.5.8",
"vscode-textmate": "4.4.0", "vscode-textmate": "4.4.0",
"xterm": "4.4.0", "xterm": "4.4.0",
"xterm-addon-search": "0.4.0", "xterm-addon-search": "0.5.0",
"xterm-addon-unicode11": "0.1.1", "xterm-addon-unicode11": "0.1.1",
"xterm-addon-web-links": "0.2.1", "xterm-addon-web-links": "0.2.1",
"xterm-addon-webgl": "0.5.0", "xterm-addon-webgl": "0.5.0",

View File

@@ -6,7 +6,7 @@
"semver-umd": "^5.5.5", "semver-umd": "^5.5.5",
"vscode-textmate": "4.4.0", "vscode-textmate": "4.4.0",
"xterm": "4.4.0", "xterm": "4.4.0",
"xterm-addon-search": "0.4.0", "xterm-addon-search": "0.5.0",
"xterm-addon-unicode11": "0.1.1", "xterm-addon-unicode11": "0.1.1",
"xterm-addon-web-links": "0.2.1", "xterm-addon-web-links": "0.2.1",
"xterm-addon-webgl": "0.5.0" "xterm-addon-webgl": "0.5.0"

View File

@@ -31,10 +31,10 @@ vscode-textmate@4.4.0:
dependencies: dependencies:
oniguruma "^7.2.0" oniguruma "^7.2.0"
xterm-addon-search@0.4.0: xterm-addon-search@0.5.0:
version "0.4.0" version "0.5.0"
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.4.0.tgz#a7beadb3caa7330eb31fb1f17d92de25537684a1" resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.5.0.tgz#cd3a2f8056084c28e236d4e732da37682010bcc2"
integrity sha512-g07qb/Z4aSfrQ25e6Z6rz6KiExm2DvesQXkx+eA715VABBr5VM/9Jf0INoCiDSYy/nn7rpna+kXiGVJejIffKg== integrity sha512-zLVqVTrg5w2nk9fRj3UuVKCPo/dmFe/cLf3EM9Is5Dm6cgOoXmeo9eq2KgD8A0gquAflTFTf0ya2NaFmShHwyg==
xterm-addon-unicode11@0.1.1: xterm-addon-unicode11@0.1.1:
version "0.1.1" version "0.1.1"

View File

@@ -389,10 +389,10 @@ vscode-proxy-agent@^0.5.2:
https-proxy-agent "^2.2.3" https-proxy-agent "^2.2.3"
socks-proxy-agent "^4.0.1" socks-proxy-agent "^4.0.1"
vscode-ripgrep@^1.5.7: vscode-ripgrep@^1.5.8:
version "1.5.7" version "1.5.8"
resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.5.7.tgz#acb6b548af488a4bca5d0f1bb5faf761343289ce" resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.5.8.tgz#32cb33da6d1a9ca8f5de8c2813ed5114fd55fc11"
integrity sha512-/Vsz/+k8kTvui0q3O74pif9FK0nKopgFTiGNVvxicZANxtSA8J8gUE9GQ/4dpi7D/2yI/YVORszwVskFbz46hQ== integrity sha512-l6Pv/t1Jk63RU+kEkMO04XxnNRYdyzuesizj9AzFpcfrUxxpAjEJBK1qO9Mov30UUGZl7uDUBn+uCv9koaHPPA==
vscode-textmate@4.4.0: vscode-textmate@4.4.0:
version "4.4.0" version "4.4.0"
@@ -413,10 +413,10 @@ vscode-windows-registry@1.0.2:
resolved "https://registry.yarnpkg.com/vscode-windows-registry/-/vscode-windows-registry-1.0.2.tgz#b863e704a6a69c50b3098a55fbddbe595b0c124a" resolved "https://registry.yarnpkg.com/vscode-windows-registry/-/vscode-windows-registry-1.0.2.tgz#b863e704a6a69c50b3098a55fbddbe595b0c124a"
integrity sha512-/CLLvuOSM2Vme2z6aNyB+4Omd7hDxpf4Thrt8ImxnXeQtxzel2bClJpFQvQqK/s4oaXlkBKS7LqVLeZM+uSVIA== integrity sha512-/CLLvuOSM2Vme2z6aNyB+4Omd7hDxpf4Thrt8ImxnXeQtxzel2bClJpFQvQqK/s4oaXlkBKS7LqVLeZM+uSVIA==
xterm-addon-search@0.4.0: xterm-addon-search@0.5.0:
version "0.4.0" version "0.5.0"
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.4.0.tgz#a7beadb3caa7330eb31fb1f17d92de25537684a1" resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.5.0.tgz#cd3a2f8056084c28e236d4e732da37682010bcc2"
integrity sha512-g07qb/Z4aSfrQ25e6Z6rz6KiExm2DvesQXkx+eA715VABBr5VM/9Jf0INoCiDSYy/nn7rpna+kXiGVJejIffKg== integrity sha512-zLVqVTrg5w2nk9fRj3UuVKCPo/dmFe/cLf3EM9Is5Dm6cgOoXmeo9eq2KgD8A0gquAflTFTf0ya2NaFmShHwyg==
xterm-addon-unicode11@0.1.1: xterm-addon-unicode11@0.1.1:
version "0.1.1" version "0.1.1"

View File

@@ -39,17 +39,20 @@ if "%INTEGRATION_TEST_ELECTRON_PATH%"=="" (
:: Tests in the extension host :: Tests in the extension host
call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-api-tests\testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\singlefolder-tests --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% REM call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-api-tests\testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\singlefolder-tests --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR%
if %errorlevel% neq 0 exit /b %errorlevel% REM if %errorlevel% neq 0 exit /b %errorlevel%
call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-api-tests\testworkspace.code-workspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\workspace-tests --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% REM call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-api-tests\testworkspace.code-workspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\workspace-tests --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR%
if %errorlevel% neq 0 exit /b %errorlevel% REM if %errorlevel% neq 0 exit /b %errorlevel%
call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-colorize-tests\test --extensionDevelopmentPath=%~dp0\..\extensions\vscode-colorize-tests --extensionTestsPath=%~dp0\..\extensions\vscode-colorize-tests\out --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% REM call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-colorize-tests\test --extensionDevelopmentPath=%~dp0\..\extensions\vscode-colorize-tests --extensionTestsPath=%~dp0\..\extensions\vscode-colorize-tests\out --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR%
if %errorlevel% neq 0 exit /b %errorlevel% REM if %errorlevel% neq 0 exit /b %errorlevel%
:: call "%INTEGRATION_TEST_ELECTRON_PATH%" $%~dp0\..\extensions\emmet\test-fixtures --extensionDevelopmentPath=%~dp0\..\extensions\emmet --extensionTestsPath=%~dp0\..\extensions\emmet\out\test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% . REM call "%INTEGRATION_TEST_ELECTRON_PATH%" $%~dp0\..\extensions\markdown-language-features\out\test\test-fixtures --extensionDevelopmentPath=%~dp0\..\extensions\markdown-language-features --extensionTestsPath=%~dp0\..\extensions\markdown-language-features\out\test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% .
:: if %errorlevel% neq 0 exit /b %errorlevel% REM if %errorlevel% neq 0 exit /b %errorlevel%
REM call "%INTEGRATION_TEST_ELECTRON_PATH%" $%~dp0\..\extensions\emmet\out\test\test-fixtures --extensionDevelopmentPath=%~dp0\..\extensions\emmet --extensionTestsPath=%~dp0\..\extensions\emmet\out\test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% .
REM if %errorlevel% neq 0 exit /b %errorlevel%
call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\azurecore\test-fixtures --extensionDevelopmentPath=%~dp0\..\extensions\azurecore --extensionTestsPath=%~dp0\..\extensions\azurecore\out\test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\azurecore\test-fixtures --extensionDevelopmentPath=%~dp0\..\extensions\azurecore --extensionTestsPath=%~dp0\..\extensions\azurecore\out\test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR%
if %errorlevel% neq 0 exit /b %errorlevel% if %errorlevel% neq 0 exit /b %errorlevel%

View File

@@ -44,14 +44,12 @@ fi
# Tests in the extension host # Tests in the extension host
# "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-api-tests/testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/singlefolder-tests --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --user-data-dir=$VSCODEUSERDATADIR # "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-api-tests/testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/singlefolder-tests --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --user-data-dir=$VSCODEUSERDATADIR
# "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-api-tests/testworkspace.code-workspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/workspace-tests --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --user-data-dir=$VSCODEUSERDATADIR # "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-api-tests/testworkspace.code-workspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/workspace-tests --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --user-data-dir=$VSCODEUSERDATADIR
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-colorize-tests/test --extensionDevelopmentPath=$ROOT/extensions/vscode-colorize-tests --extensionTestsPath=$ROOT/extensions/vscode-colorize-tests/out --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --user-data-dir=$VSCODEUSERDATADIR # "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-colorize-tests/test --extensionDevelopmentPath=$ROOT/extensions/vscode-colorize-tests --extensionTestsPath=$ROOT/extensions/vscode-colorize-tests/out --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --user-data-dir=$VSCODEUSERDATADIR
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/markdown-language-features/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/markdown-language-features --extensionTestsPath=$ROOT/extensions/markdown-language-features/out/test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --user-data-dir=$VSCODEUSERDATADIR # "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/markdown-language-features/out/test/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/markdown-language-features --extensionTestsPath=$ROOT/extensions/markdown-language-features/out/test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --user-data-dir=$VSCODEUSERDATADIR
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/azurecore/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/azurecore --extensionTestsPath=$ROOT/extensions/azurecore/out/test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --user-data-dir=$VSCODEUSERDATADIR # "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/emmet/out/test/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/emmet --extensionTestsPath=$ROOT/extensions/emmet/out/test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --user-data-dir=$VSCODEUSERDATADIR
# "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $(mktemp -d 2>/dev/null) --extensionDevelopmentPath=$ROOT/extensions/git --extensionTestsPath=$ROOT/extensions/git/out/test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --user-data-dir=$VSCODEUSERDATADIR # "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $(mktemp -d 2>/dev/null) --extensionDevelopmentPath=$ROOT/extensions/git --extensionTestsPath=$ROOT/extensions/git/out/test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --user-data-dir=$VSCODEUSERDATADIR
mkdir -p $ROOT/extensions/emmet/test-fixtures "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/azurecore/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/azurecore --extensionTestsPath=$ROOT/extensions/azurecore/out/test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --user-data-dir=$VSCODEUSERDATADIR
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/emmet/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/emmet --extensionTestsPath=$ROOT/extensions/emmet/out/test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --user-data-dir=$VSCODEUSERDATADIR
rm -rf $ROOT/extensions/emmet/test-fixtures
# Remote Integration Tests # Remote Integration Tests
if [ -f ./resources/server/test/test-remote-integration.sh ]; then if [ -f ./resources/server/test/test-remote-integration.sh ]; then

View File

@@ -35,7 +35,7 @@ import { UntitledNotebookInput } from 'sql/workbench/contrib/notebook/common/mod
import { FileNotebookInput } from 'sql/workbench/contrib/notebook/common/models/fileNotebookInput'; import { FileNotebookInput } from 'sql/workbench/contrib/notebook/common/models/fileNotebookInput';
import { find } from 'vs/base/common/arrays'; import { find } from 'vs/base/common/arrays';
import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService'; import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService';
import { UntitledTextEditorInput } from 'vs/workbench/common/editor/untitledTextEditorInput'; import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput'; import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';

View File

@@ -19,7 +19,7 @@ import { IModelService } from 'vs/editor/common/services/modelService';
import { ComponentBase } from 'sql/workbench/browser/modelComponents/componentBase'; import { ComponentBase } from 'sql/workbench/browser/modelComponents/componentBase';
import { QueryTextEditor } from 'sql/workbench/browser/modelComponents/queryTextEditor'; import { QueryTextEditor } from 'sql/workbench/browser/modelComponents/queryTextEditor';
import { ILogService } from 'vs/platform/log/common/log'; import { ILogService } from 'vs/platform/log/common/log';
import { UntitledTextEditorInput } from 'vs/workbench/common/editor/untitledTextEditorInput'; import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { IEditorProgressService } from 'vs/platform/progress/common/progress'; import { IEditorProgressService } from 'vs/platform/progress/common/progress';
import { SimpleProgressIndicator } from 'sql/workbench/services/progress/browser/simpleProgressIndicator'; import { SimpleProgressIndicator } from 'sql/workbench/services/progress/browser/simpleProgressIndicator';

View File

@@ -21,7 +21,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { UntitledTextEditorInput } from 'vs/workbench/common/editor/untitledTextEditorInput'; import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
/** /**

View File

@@ -33,7 +33,7 @@ import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { INotificationService } from 'vs/platform/notification/common/notification'; import { INotificationService } from 'vs/platform/notification/common/notification';
import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService'; import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService';
import { isUndefinedOrNull } from 'vs/base/common/types'; import { isUndefinedOrNull } from 'vs/base/common/types';
import { UntitledTextEditorInput } from 'vs/workbench/common/editor/untitledTextEditorInput'; import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
import { LabelService } from 'vs/workbench/services/label/common/labelService'; import { LabelService } from 'vs/workbench/services/label/common/labelService';
class TestParsedArgs implements ParsedArgs { class TestParsedArgs implements ParsedArgs {

View File

@@ -29,7 +29,7 @@ import {
import { TextResourceEditor } from 'vs/workbench/browser/parts/editor/textResourceEditor'; import { TextResourceEditor } from 'vs/workbench/browser/parts/editor/textResourceEditor';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { UntitledTextEditorInput } from 'vs/workbench/common/editor/untitledTextEditorInput'; import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
import { IFlexibleSash, HorizontalFlexibleSash } from 'sql/workbench/contrib/query/browser/flexibleSash'; import { IFlexibleSash, HorizontalFlexibleSash } from 'sql/workbench/contrib/query/browser/flexibleSash';
import { EditDataResultsEditor } from 'sql/workbench/contrib/editData/browser/editDataResultsEditor'; import { EditDataResultsEditor } from 'sql/workbench/contrib/editData/browser/editDataResultsEditor';
import { EditDataResultsInput } from 'sql/workbench/contrib/editData/browser/editDataResultsInput'; import { EditDataResultsInput } from 'sql/workbench/contrib/editData/browser/editDataResultsInput';

View File

@@ -14,7 +14,7 @@ import { INotificationService } from 'vs/platform/notification/common/notificati
import Severity from 'vs/base/common/severity'; import Severity from 'vs/base/common/severity';
import { EditDataResultsInput } from 'sql/workbench/contrib/editData/browser/editDataResultsInput'; import { EditDataResultsInput } from 'sql/workbench/contrib/editData/browser/editDataResultsInput';
import { IEditorViewState } from 'vs/editor/common/editorCommon'; import { IEditorViewState } from 'vs/editor/common/editorCommon';
import { UntitledTextEditorInput } from 'vs/workbench/common/editor/untitledTextEditorInput'; import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
/** /**
* Input for the EditDataEditor. * Input for the EditDataEditor.

View File

@@ -15,7 +15,7 @@ import { Registry } from 'vs/platform/registry/common/platform';
import * as path from 'vs/base/common/path'; import * as path from 'vs/base/common/path';
import { ILanguageAssociationRegistry, Extensions as LanguageAssociationExtensions } from 'sql/workbench/services/languageAssociation/common/languageAssociation'; import { ILanguageAssociationRegistry, Extensions as LanguageAssociationExtensions } from 'sql/workbench/services/languageAssociation/common/languageAssociation';
import { UntitledTextEditorInput } from 'vs/workbench/common/editor/untitledTextEditorInput'; import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
const languageAssociationRegistry = Registry.as<ILanguageAssociationRegistry>(LanguageAssociationExtensions.LanguageAssociations); const languageAssociationRegistry = Registry.as<ILanguageAssociationRegistry>(LanguageAssociationExtensions.LanguageAssociations);

View File

@@ -24,7 +24,7 @@ import { QueryEditorLanguageAssociation } from 'sql/workbench/contrib/query/comm
import { workbenchInstantiationService } from 'sql/workbench/test/workbenchTestServices'; import { workbenchInstantiationService } from 'sql/workbench/test/workbenchTestServices';
import { NotebookEditorInputAssociation } from 'sql/workbench/contrib/notebook/common/models/nodebookInputFactory'; import { NotebookEditorInputAssociation } from 'sql/workbench/contrib/notebook/common/models/nodebookInputFactory';
import { NotebookInput } from 'sql/workbench/contrib/notebook/browser/models/notebookInput'; import { NotebookInput } from 'sql/workbench/contrib/notebook/browser/models/notebookInput';
import { UntitledTextEditorInput } from 'vs/workbench/common/editor/untitledTextEditorInput'; import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
import { UntitledQueryEditorInput } from 'sql/workbench/contrib/query/common/untitledQueryEditorInput'; import { UntitledQueryEditorInput } from 'sql/workbench/contrib/query/common/untitledQueryEditorInput';
import { INotebookService } from 'sql/workbench/services/notebook/browser/notebookService'; import { INotebookService } from 'sql/workbench/services/notebook/browser/notebookService';
import { NotebookServiceStub } from 'sql/workbench/contrib/notebook/test/stubs'; import { NotebookServiceStub } from 'sql/workbench/contrib/notebook/test/stubs';

View File

@@ -30,8 +30,8 @@ import { ILogService } from 'vs/platform/log/common/log';
import { CollapseComponent } from 'sql/workbench/contrib/notebook/browser/cellViews/collapse.component'; import { CollapseComponent } from 'sql/workbench/contrib/notebook/browser/cellViews/collapse.component';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { CellView } from 'sql/workbench/contrib/notebook/browser/cellViews/interfaces'; import { CellView } from 'sql/workbench/contrib/notebook/browser/cellViews/interfaces';
import { UntitledTextEditorInput } from 'vs/workbench/common/editor/untitledTextEditorInput'; import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
import { UntitledTextEditorModel } from 'vs/workbench/common/editor/untitledTextEditorModel'; import { UntitledTextEditorModel } from 'vs/workbench/services/untitled/common/untitledTextEditorModel';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { IEditorProgressService } from 'vs/platform/progress/common/progress'; import { IEditorProgressService } from 'vs/platform/progress/common/progress';
import { SimpleProgressIndicator } from 'sql/workbench/services/progress/browser/simpleProgressIndicator'; import { SimpleProgressIndicator } from 'sql/workbench/services/progress/browser/simpleProgressIndicator';

View File

@@ -26,8 +26,8 @@ import { Deferred } from 'sql/base/common/promise';
import { NotebookTextFileModel } from 'sql/workbench/contrib/notebook/browser/models/notebookTextFileModel'; import { NotebookTextFileModel } from 'sql/workbench/contrib/notebook/browser/models/notebookTextFileModel';
import { ITextResourcePropertiesService } from 'vs/editor/common/services/textResourceConfigurationService'; import { ITextResourcePropertiesService } from 'vs/editor/common/services/textResourceConfigurationService';
import { ResourceEditorModel } from 'vs/workbench/common/editor/resourceEditorModel'; import { ResourceEditorModel } from 'vs/workbench/common/editor/resourceEditorModel';
import { UntitledTextEditorModel } from 'vs/workbench/common/editor/untitledTextEditorModel'; import { UntitledTextEditorModel } from 'vs/workbench/services/untitled/common/untitledTextEditorModel';
import { UntitledTextEditorInput } from 'vs/workbench/common/editor/untitledTextEditorInput'; import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput'; import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput';
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput'; import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel'; import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel';

View File

@@ -10,7 +10,7 @@ import { FILE_EDITOR_INPUT_ID } from 'vs/workbench/contrib/files/common/files';
import { FileNotebookInput } from 'sql/workbench/contrib/notebook/common/models/fileNotebookInput'; import { FileNotebookInput } from 'sql/workbench/contrib/notebook/common/models/fileNotebookInput';
import { UntitledNotebookInput } from 'sql/workbench/contrib/notebook/common/models/untitledNotebookInput'; import { UntitledNotebookInput } from 'sql/workbench/contrib/notebook/common/models/untitledNotebookInput';
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput'; import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
import { UntitledTextEditorInput } from 'vs/workbench/common/editor/untitledTextEditorInput'; import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
import { ILanguageAssociation } from 'sql/workbench/services/languageAssociation/common/languageAssociation'; import { ILanguageAssociation } from 'sql/workbench/services/languageAssociation/common/languageAssociation';
import { NotebookInput } from 'sql/workbench/contrib/notebook/browser/models/notebookInput'; import { NotebookInput } from 'sql/workbench/contrib/notebook/browser/models/notebookInput';

View File

@@ -9,7 +9,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { NotebookInput } from 'sql/workbench/contrib/notebook/browser/models/notebookInput'; import { NotebookInput } from 'sql/workbench/contrib/notebook/browser/models/notebookInput';
import { INotebookService } from 'sql/workbench/services/notebook/browser/notebookService'; import { INotebookService } from 'sql/workbench/services/notebook/browser/notebookService';
import { UntitledTextEditorInput } from 'vs/workbench/common/editor/untitledTextEditorInput'; import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
export class UntitledNotebookInput extends NotebookInput { export class UntitledNotebookInput extends NotebookInput {
public static ID: string = 'workbench.editorinputs.untitledNotebookInput'; public static ID: string = 'workbench.editorinputs.untitledNotebookInput';

View File

@@ -12,10 +12,10 @@ import { URI } from 'vs/base/common/uri';
import { UntitledNotebookInput } from 'sql/workbench/contrib/notebook/common/models/untitledNotebookInput'; import { UntitledNotebookInput } from 'sql/workbench/contrib/notebook/common/models/untitledNotebookInput';
import { FileNotebookInput } from 'sql/workbench/contrib/notebook/common/models/fileNotebookInput'; import { FileNotebookInput } from 'sql/workbench/contrib/notebook/common/models/fileNotebookInput';
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces'; import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
import { UntitledTextEditorModel } from 'vs/workbench/common/editor/untitledTextEditorModel'; import { UntitledTextEditorModel } from 'vs/workbench/services/untitled/common/untitledTextEditorModel';
import { NodeStub, NotebookServiceStub } from 'sql/workbench/contrib/notebook/test/stubs'; import { NodeStub, NotebookServiceStub } from 'sql/workbench/contrib/notebook/test/stubs';
import { basenameOrAuthority } from 'vs/base/common/resources'; import { basenameOrAuthority } from 'vs/base/common/resources';
import { UntitledTextEditorInput } from 'vs/workbench/common/editor/untitledTextEditorInput'; import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
import { IExtensionService, NullExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { IExtensionService, NullExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { INotebookService, IProviderInfo } from 'sql/workbench/services/notebook/browser/notebookService'; import { INotebookService, IProviderInfo } from 'sql/workbench/services/notebook/browser/notebookService';
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';

View File

@@ -51,7 +51,7 @@ import { CellSelectionModel } from 'sql/base/browser/ui/table/plugins/cellSelect
import { handleCopyRequest } from 'sql/workbench/contrib/profiler/browser/profilerCopyHandler'; import { handleCopyRequest } from 'sql/workbench/contrib/profiler/browser/profilerCopyHandler';
import { ITextResourcePropertiesService } from 'vs/editor/common/services/textResourceConfigurationService'; import { ITextResourcePropertiesService } from 'vs/editor/common/services/textResourceConfigurationService';
import { find } from 'vs/base/common/arrays'; import { find } from 'vs/base/common/arrays';
import { UntitledTextEditorInput } from 'vs/workbench/common/editor/untitledTextEditorInput'; import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
import { attachTabbedPanelStyler } from 'sql/workbench/common/styler'; import { attachTabbedPanelStyler } from 'sql/workbench/common/styler';
class BasicView implements IView { class BasicView implements IView {

View File

@@ -19,7 +19,7 @@ import { EditorOptions } from 'vs/workbench/common/editor';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { CancellationToken } from 'vs/base/common/cancellation'; import { CancellationToken } from 'vs/base/common/cancellation';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { UntitledTextEditorInput } from 'vs/workbench/common/editor/untitledTextEditorInput'; import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
class ProfilerResourceCodeEditor extends CodeEditorWidget { class ProfilerResourceCodeEditor extends CodeEditorWidget {

View File

@@ -11,7 +11,7 @@ import { FILE_EDITOR_INPUT_ID } from 'vs/workbench/contrib/files/common/files';
import { UntitledQueryEditorInput } from 'sql/workbench/contrib/query/common/untitledQueryEditorInput'; import { UntitledQueryEditorInput } from 'sql/workbench/contrib/query/common/untitledQueryEditorInput';
import { FileQueryEditorInput } from 'sql/workbench/contrib/query/common/fileQueryEditorInput'; import { FileQueryEditorInput } from 'sql/workbench/contrib/query/common/fileQueryEditorInput';
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput'; import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
import { UntitledTextEditorInput } from 'vs/workbench/common/editor/untitledTextEditorInput'; import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
import { ILanguageAssociation } from 'sql/workbench/services/languageAssociation/common/languageAssociation'; import { ILanguageAssociation } from 'sql/workbench/services/languageAssociation/common/languageAssociation';
import { QueryEditorInput } from 'sql/workbench/contrib/query/common/queryEditorInput'; import { QueryEditorInput } from 'sql/workbench/contrib/query/common/queryEditorInput';
import { getCurrentGlobalConnection } from 'sql/workbench/browser/taskUtilities'; import { getCurrentGlobalConnection } from 'sql/workbench/browser/taskUtilities';

View File

@@ -11,12 +11,10 @@ import { IQueryModelService } from 'sql/workbench/services/query/common/queryMod
import { IEncodingSupport, EncodingMode } from 'vs/workbench/common/editor'; import { IEncodingSupport, EncodingMode } from 'vs/workbench/common/editor';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IResolvedTextEditorModel } from 'vs/editor/common/services/resolverService'; import { IResolvedTextEditorModel } from 'vs/editor/common/services/resolverService';
import { UntitledTextEditorInput } from 'vs/workbench/common/editor/untitledTextEditorInput'; import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
import { UntitledTextEditorModel } from 'vs/workbench/common/editor/untitledTextEditorModel'; import { UntitledTextEditorModel } from 'vs/workbench/services/untitled/common/untitledTextEditorModel';
type PublicPart<T> = { [K in keyof T]: T[K] }; export class UntitledQueryEditorInput extends QueryEditorInput implements IEncodingSupport {
export class UntitledQueryEditorInput extends QueryEditorInput implements IEncodingSupport, PublicPart<UntitledTextEditorInput> {
public static readonly ID = 'workbench.editorInput.untitledQueryInput'; public static readonly ID = 'workbench.editorInput.untitledQueryInput';

View File

@@ -32,7 +32,7 @@ import { URI } from 'vs/base/common/uri';
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
import { TestConnectionManagementService } from 'sql/platform/connection/test/common/testConnectionManagementService'; import { TestConnectionManagementService } from 'sql/platform/connection/test/common/testConnectionManagementService';
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
import { UntitledTextEditorInput } from 'vs/workbench/common/editor/untitledTextEditorInput'; import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
import { LabelService } from 'vs/workbench/services/label/common/labelService'; import { LabelService } from 'vs/workbench/services/label/common/labelService';
suite('SQL QueryAction Tests', () => { suite('SQL QueryAction Tests', () => {

View File

@@ -20,7 +20,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
import { TestStorageService, TestFileService } from 'vs/workbench/test/browser/workbenchTestServices'; import { TestStorageService, TestFileService } from 'vs/workbench/test/browser/workbenchTestServices';
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
import { UntitledTextEditorInput } from 'vs/workbench/common/editor/untitledTextEditorInput'; import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
import { UntitledQueryEditorInput } from 'sql/workbench/contrib/query/common/untitledQueryEditorInput'; import { UntitledQueryEditorInput } from 'sql/workbench/contrib/query/common/untitledQueryEditorInput';
import { TestQueryModelService } from 'sql/workbench/services/query/test/common/testQueryModelService'; import { TestQueryModelService } from 'sql/workbench/services/query/test/common/testQueryModelService';
import { Event } from 'vs/base/common/event'; import { Event } from 'vs/base/common/event';

View File

@@ -19,7 +19,7 @@ import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
import { IConnectionManagementService, IConnectionCompletionOptions, IConnectionCallbacks, IConnectionResult } from 'sql/platform/connection/common/connectionManagement'; import { IConnectionManagementService, IConnectionCompletionOptions, IConnectionCallbacks, IConnectionResult } from 'sql/platform/connection/common/connectionManagement';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { UntitledQueryEditorInput } from 'sql/workbench/contrib/query/common/untitledQueryEditorInput'; import { UntitledQueryEditorInput } from 'sql/workbench/contrib/query/common/untitledQueryEditorInput';
import { UntitledTextEditorInput } from 'vs/workbench/common/editor/untitledTextEditorInput'; import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
suite('Query Input Factory', () => { suite('Query Input Factory', () => {

View File

@@ -7,7 +7,7 @@ import { EditorInput, EditorModel, IEditorInput } from 'vs/workbench/common/edit
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces'; import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
import { IFileService } from 'vs/platform/files/common/files'; import { IFileService } from 'vs/platform/files/common/files';
import { URI } from 'vs/base/common/uri'; import { URI } from 'vs/base/common/uri';
import { UntitledTextEditorInput } from 'vs/workbench/common/editor/untitledTextEditorInput'; import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ILanguageAssociation } from 'sql/workbench/services/languageAssociation/common/languageAssociation'; import { ILanguageAssociation } from 'sql/workbench/services/languageAssociation/common/languageAssociation';

View File

@@ -4,10 +4,10 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { EditorInput } from 'vs/workbench/common/editor'; import { EditorInput } from 'vs/workbench/common/editor';
import { UntitledTextEditorInput } from 'vs/workbench/common/editor/untitledTextEditorInput';
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput'; import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
import { Extensions as ILanguageAssociationExtensions, ILanguageAssociationRegistry } from 'sql/workbench/services/languageAssociation/common/languageAssociation'; import { Extensions as ILanguageAssociationExtensions, ILanguageAssociationRegistry } from 'sql/workbench/services/languageAssociation/common/languageAssociation';
import { Registry } from 'vs/platform/registry/common/platform'; import { Registry } from 'vs/platform/registry/common/platform';
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
const languageRegistry = Registry.as<ILanguageAssociationRegistry>(ILanguageAssociationExtensions.LanguageAssociations); const languageRegistry = Registry.as<ILanguageAssociationRegistry>(ILanguageAssociationExtensions.LanguageAssociations);

View File

@@ -140,7 +140,7 @@ export class QueryEditorService implements IQueryEditorService {
let counter = 1; let counter = 1;
// Get document name and check if it exists // Get document name and check if it exists
let filePath = prefixFileName(counter); let filePath = prefixFileName(counter);
while (this._untitledEditorService.exists(URI.from({ scheme: Schemas.untitled, path: filePath }))) { while (this._untitledEditorService.get(URI.from({ scheme: Schemas.untitled, path: filePath }))) {
counter++; counter++;
filePath = prefixFileName(counter); filePath = prefixFileName(counter);
} }

View File

@@ -5,6 +5,7 @@
import * as dom from 'vs/base/browser/dom'; import * as dom from 'vs/base/browser/dom';
import * as platform from 'vs/base/common/platform'; import * as platform from 'vs/base/common/platform';
import * as browser from 'vs/base/browser/browser';
import { IframeUtils } from 'vs/base/browser/iframe'; import { IframeUtils } from 'vs/base/browser/iframe';
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
@@ -102,7 +103,7 @@ export class GlobalMouseMoveMonitor<R extends { buttons: number; }> implements I
for (const element of listenTo) { for (const element of listenTo) {
this._hooks.add(dom.addDisposableThrottledListener(element, mouseMove, this._hooks.add(dom.addDisposableThrottledListener(element, mouseMove,
(data: R) => { (data: R) => {
if (data.buttons !== initialButtons) { if (!browser.isIE && data.buttons !== initialButtons) {
// Buttons state has changed in the meantime // Buttons state has changed in the meantime
this.stopMonitoring(true); this.stopMonitoring(true);
return; return;

View File

@@ -9,7 +9,7 @@ import * as strings from 'vs/base/common/strings';
import { IActionRunner, IAction, Action, IActionViewItem } from 'vs/base/common/actions'; import { IActionRunner, IAction, Action, IActionViewItem } from 'vs/base/common/actions';
import { ActionBar, IActionViewItemProvider, ActionsOrientation, Separator, ActionViewItem, IActionViewItemOptions, BaseActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { ActionBar, IActionViewItemProvider, ActionsOrientation, Separator, ActionViewItem, IActionViewItemOptions, BaseActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { ResolvedKeybinding, KeyCode } from 'vs/base/common/keyCodes'; import { ResolvedKeybinding, KeyCode } from 'vs/base/common/keyCodes';
import { addClass, EventType, EventHelper, EventLike, removeTabIndexAndUpdateFocus, isAncestor, hasClass, addDisposableListener, removeClass, append, $, addClasses, removeClasses } from 'vs/base/browser/dom'; import { addClass, EventType, EventHelper, EventLike, removeTabIndexAndUpdateFocus, isAncestor, hasClass, addDisposableListener, removeClass, append, $, addClasses, removeClasses, clearNode } from 'vs/base/browser/dom';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { RunOnceScheduler } from 'vs/base/common/async'; import { RunOnceScheduler } from 'vs/base/common/async';
import { DisposableStore } from 'vs/base/common/lifecycle'; import { DisposableStore } from 'vs/base/common/lifecycle';
@@ -464,7 +464,13 @@ class BaseMenuActionViewItem extends BaseActionViewItem {
} }
updateLabel(): void { updateLabel(): void {
if (!this.label) {
return;
}
if (this.options.label) { if (this.options.label) {
clearNode(this.label);
let label = this.getAction().label; let label = this.getAction().label;
if (label) { if (label) {
const cleanLabel = cleanMnemonic(label); const cleanLabel = cleanMnemonic(label);
@@ -472,9 +478,7 @@ class BaseMenuActionViewItem extends BaseActionViewItem {
label = cleanLabel; label = cleanLabel;
} }
if (this.label) { this.label.setAttribute('aria-label', cleanLabel.replace(/&&/g, '&'));
this.label.setAttribute('aria-label', cleanLabel.replace(/&&/g, '&'));
}
const matches = MENU_MNEMONIC_REGEX.exec(label); const matches = MENU_MNEMONIC_REGEX.exec(label);
@@ -490,22 +494,25 @@ class BaseMenuActionViewItem extends BaseActionViewItem {
escMatch = MENU_ESCAPED_MNEMONIC_REGEX.exec(label); escMatch = MENU_ESCAPED_MNEMONIC_REGEX.exec(label);
} }
const replaceDoubleEscapes = (str: string) => str.replace(/&amp;&amp;/g, '&amp;');
if (escMatch) { if (escMatch) {
label = `${label.substr(0, escMatch.index)}<u aria-hidden="true">${escMatch[3]}</u>${label.substr(escMatch.index + escMatch[0].length)}`; this.label.append(
strings.ltrim(replaceDoubleEscapes(label.substr(0, escMatch.index)), ' '),
$('u', { 'aria-hidden': 'true' },
escMatch[3]),
strings.rtrim(replaceDoubleEscapes(label.substr(escMatch.index + escMatch[0].length)), ' '));
} else {
this.label.innerText = replaceDoubleEscapes(label).trim();
} }
label = label.replace(/&amp;&amp;/g, '&amp;');
if (this.item) { if (this.item) {
this.item.setAttribute('aria-keyshortcuts', (!!matches[1] ? matches[1] : matches[3]).toLocaleLowerCase()); this.item.setAttribute('aria-keyshortcuts', (!!matches[1] ? matches[1] : matches[3]).toLocaleLowerCase());
} }
} else { } else {
label = label.replace(/&&/g, '&'); this.label.innerText = label.replace(/&&/g, '&').trim();
} }
} }
if (this.label) {
this.label.innerHTML = label.trim();
}
} }
} }

View File

@@ -360,7 +360,7 @@ function doWriteFileAndFlush(path: string, data: string | Buffer | Uint8Array, o
} }
// Flush contents (not metadata) of the file to disk // Flush contents (not metadata) of the file to disk
fs.fdatasync(fd, (syncError: Error) => { fs.fdatasync(fd, (syncError: Error | null) => {
// In some exotic setups it is well possible that node fails to sync // In some exotic setups it is well possible that node fails to sync
// In that case we disable flushing and warn to the console // In that case we disable flushing and warn to the console

View File

@@ -409,7 +409,7 @@ export function createQueuedSender(childProcess: cp.ChildProcess): IQueuedSender
return; return;
} }
const result = childProcess.send(msg, (error: Error) => { const result = childProcess.send(msg, (error: Error | null) => {
if (error) { if (error) {
console.error(error); // unlikely to happen, best we can do is log this error console.error(error); // unlikely to happen, best we can do is log this error
} }

View File

@@ -440,7 +440,7 @@ export class IssueReporter extends Disposable {
sendWorkbenchCommand('workbench.action.reloadWindowWithExtensionsDisabled'); sendWorkbenchCommand('workbench.action.reloadWindowWithExtensionsDisabled');
}); });
this.addEventListener('extensionBugsLink', 'click', (e: MouseEvent) => { this.addEventListener('extensionBugsLink', 'click', (e: Event) => {
const url = (<HTMLElement>e.target).innerText; const url = (<HTMLElement>e.target).innerText;
shell.openExternal(url); shell.openExternal(url);
}); });

View File

@@ -12,7 +12,7 @@ import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService'; import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment'; import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment';
import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; import { EnvironmentService } from 'vs/platform/environment/node/environmentService';
import { ExtensionManagementChannel, GlobalExtensionEnablementServiceClient } from 'vs/platform/extensionManagement/common/extensionManagementIpc'; import { ExtensionManagementChannel } from 'vs/platform/extensionManagement/common/extensionManagementIpc';
import { IExtensionManagementService, IExtensionGalleryService, IGlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IExtensionManagementService, IExtensionGalleryService, IGlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService'; import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService';
@@ -49,7 +49,7 @@ import { IFileService } from 'vs/platform/files/common/files';
import { DiskFileSystemProvider } from 'vs/platform/files/electron-browser/diskFileSystemProvider'; import { DiskFileSystemProvider } from 'vs/platform/files/electron-browser/diskFileSystemProvider';
import { Schemas } from 'vs/base/common/network'; import { Schemas } from 'vs/base/common/network';
import { IProductService } from 'vs/platform/product/common/productService'; import { IProductService } from 'vs/platform/product/common/productService';
import { IUserDataSyncService, IUserDataSyncStoreService, registerConfiguration, IUserDataSyncLogService, IUserDataSyncUtilService, ISettingsSyncService, IUserDataAuthTokenService } from 'vs/platform/userDataSync/common/userDataSync'; import { IUserDataSyncService, IUserDataSyncStoreService, registerConfiguration, IUserDataSyncLogService, IUserDataSyncUtilService, ISettingsSyncService, IUserDataAuthTokenService, IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync';
import { UserDataSyncService } from 'vs/platform/userDataSync/common/userDataSyncService'; import { UserDataSyncService } from 'vs/platform/userDataSync/common/userDataSyncService';
import { UserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSyncStoreService'; import { UserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSyncStoreService';
import { UserDataSyncChannel, UserDataSyncUtilServiceClient, SettingsSyncChannel, UserDataAuthTokenServiceChannel, UserDataAutoSyncChannel } from 'vs/platform/userDataSync/common/userDataSyncIpc'; import { UserDataSyncChannel, UserDataSyncUtilServiceClient, SettingsSyncChannel, UserDataAuthTokenServiceChannel, UserDataAutoSyncChannel } from 'vs/platform/userDataSync/common/userDataSyncIpc';
@@ -61,6 +61,11 @@ import { KeytarCredentialsService } from 'vs/platform/credentials/node/credentia
import { UserDataAutoSyncService } from 'vs/platform/userDataSync/electron-browser/userDataAutoSyncService'; import { UserDataAutoSyncService } from 'vs/platform/userDataSync/electron-browser/userDataAutoSyncService';
import { SettingsSynchroniser } from 'vs/platform/userDataSync/common/settingsSync'; import { SettingsSynchroniser } from 'vs/platform/userDataSync/common/settingsSync';
import { UserDataAuthTokenService } from 'vs/platform/userDataSync/common/userDataAuthTokenService'; import { UserDataAuthTokenService } from 'vs/platform/userDataSync/common/userDataAuthTokenService';
import { NativeStorageService } from 'vs/platform/storage/node/storageService';
import { GlobalStorageDatabaseChannelClient } from 'vs/platform/storage/node/storageIpc';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { GlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionEnablementService';
import { UserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSyncEnablementService';
export interface ISharedProcessConfiguration { export interface ISharedProcessConfiguration {
readonly machineId: string; readonly machineId: string;
@@ -100,7 +105,7 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat
const onExit = () => disposables.dispose(); const onExit = () => disposables.dispose();
process.once('exit', onExit); process.once('exit', onExit);
ipcRenderer.once('handshake:goodbye', onExit); ipcRenderer.once('electron-main->shared-process: exit', onExit);
disposables.add(server); disposables.add(server);
@@ -119,6 +124,11 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat
disposables.add(configurationService); disposables.add(configurationService);
await configurationService.initialize(); await configurationService.initialize();
const storageService = new NativeStorageService(new GlobalStorageDatabaseChannelClient(mainProcessService.getChannel('storage')), logService, environmentService);
await storageService.initialize();
services.set(IStorageService, storageService);
disposables.add(toDisposable(() => storageService.flush()));
services.set(IEnvironmentService, environmentService); services.set(IEnvironmentService, environmentService);
services.set(IProductService, { _serviceBrand: undefined, ...product }); services.set(IProductService, { _serviceBrand: undefined, ...product });
services.set(ILogService, logService); services.set(ILogService, logService);
@@ -147,7 +157,7 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat
instantiationService.invokeFunction(accessor => { instantiationService.invokeFunction(accessor => {
const services = new ServiceCollection(); const services = new ServiceCollection();
const environmentService = accessor.get(IEnvironmentService); const environmentService = accessor.get(IEnvironmentService);
const { appRoot, extensionsPath, extensionDevelopmentLocationURI: extensionDevelopmentLocationURI, isBuilt, installSourcePath } = environmentService; const { appRoot, extensionsPath, extensionDevelopmentLocationURI, isBuilt, installSourcePath } = environmentService;
const telemetryLogService = new FollowerLogService(loggerClient, new SpdLogService('telemetry', environmentService.logsPath, initData.logLevel)); const telemetryLogService = new FollowerLogService(loggerClient, new SpdLogService('telemetry', environmentService.logsPath, initData.logLevel));
telemetryLogService.info('The below are logs for every telemetry event sent from VS Code once the log level is set to trace.'); telemetryLogService.info('The below are logs for every telemetry event sent from VS Code once the log level is set to trace.');
telemetryLogService.info('==========================================================='); telemetryLogService.info('===========================================================');
@@ -181,8 +191,9 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat
services.set(IUserDataAuthTokenService, new SyncDescriptor(UserDataAuthTokenService)); services.set(IUserDataAuthTokenService, new SyncDescriptor(UserDataAuthTokenService));
services.set(IUserDataSyncLogService, new SyncDescriptor(UserDataSyncLogService)); services.set(IUserDataSyncLogService, new SyncDescriptor(UserDataSyncLogService));
services.set(IUserDataSyncUtilService, new UserDataSyncUtilServiceClient(server.getChannel('userDataSyncUtil', client => client.ctx !== 'main'))); services.set(IUserDataSyncUtilService, new UserDataSyncUtilServiceClient(server.getChannel('userDataSyncUtil', client => client.ctx !== 'main')));
services.set(IGlobalExtensionEnablementService, new GlobalExtensionEnablementServiceClient(server.getChannel('globalExtensionEnablement', client => client.ctx !== 'main'))); services.set(IGlobalExtensionEnablementService, new SyncDescriptor(GlobalExtensionEnablementService));
services.set(IUserDataSyncStoreService, new SyncDescriptor(UserDataSyncStoreService)); services.set(IUserDataSyncStoreService, new SyncDescriptor(UserDataSyncStoreService));
services.set(IUserDataSyncEnablementService, new SyncDescriptor(UserDataSyncEnablementService));
services.set(ISettingsSyncService, new SyncDescriptor(SettingsSynchroniser)); services.set(ISettingsSyncService, new SyncDescriptor(SettingsSynchroniser));
services.set(IUserDataSyncService, new SyncDescriptor(UserDataSyncService)); services.set(IUserDataSyncService, new SyncDescriptor(UserDataSyncService));
registerConfiguration(); registerConfiguration();
@@ -271,13 +282,20 @@ function setupIPC(hook: string): Promise<Server> {
} }
async function handshake(configuration: ISharedProcessConfiguration): Promise<void> { async function handshake(configuration: ISharedProcessConfiguration): Promise<void> {
// receive payload from electron-main to start things
const data = await new Promise<ISharedProcessInitData>(c => { const data = await new Promise<ISharedProcessInitData>(c => {
ipcRenderer.once('handshake:hey there', (_: any, r: ISharedProcessInitData) => c(r)); ipcRenderer.once('electron-main->shared-process: payload', (_: any, r: ISharedProcessInitData) => c(r));
ipcRenderer.send('handshake:hello');
// tell electron-main we are ready to receive payload
ipcRenderer.send('shared-process->electron-main: ready-for-payload');
}); });
// await IPC connection and signal this back to electron-main
const server = await setupIPC(data.sharedIPCHandle); const server = await setupIPC(data.sharedIPCHandle);
ipcRenderer.send('shared-process->electron-main: ipc-ready');
// await initialization and signal this back to electron-main
await main(server, data, configuration); await main(server, data, configuration);
ipcRenderer.send('handshake:im ready'); ipcRenderer.send('shared-process->electron-main: init-done');
} }

View File

@@ -364,7 +364,14 @@ export class CodeApplication extends Disposable {
// Spawn shared process after the first window has opened and 3s have passed // Spawn shared process after the first window has opened and 3s have passed
const sharedProcess = this.instantiationService.createInstance(SharedProcess, machineId, this.userEnv); const sharedProcess = this.instantiationService.createInstance(SharedProcess, machineId, this.userEnv);
const sharedProcessClient = sharedProcess.whenReady().then(() => connect(this.environmentService.sharedIPCHandle, 'main')); const sharedProcessClient = sharedProcess.whenIpcReady().then(() => {
this.logService.trace('Shared process: IPC ready');
return connect(this.environmentService.sharedIPCHandle, 'main');
});
const sharedProcessReady = sharedProcess.whenReady().then(() => {
this.logService.trace('Shared process: init ready');
return sharedProcessClient;
});
this.lifecycleMainService.when(LifecycleMainPhase.AfterWindowOpen).then(() => { this.lifecycleMainService.when(LifecycleMainPhase.AfterWindowOpen).then(() => {
this._register(new RunOnceScheduler(async () => { this._register(new RunOnceScheduler(async () => {
const userEnv = await getShellEnvironment(this.logService, this.environmentService); const userEnv = await getShellEnvironment(this.logService, this.environmentService);
@@ -374,7 +381,7 @@ export class CodeApplication extends Disposable {
}); });
// Services // Services
const appInstantiationService = await this.createServices(machineId, trueMachineId, sharedProcess, sharedProcessClient); const appInstantiationService = await this.createServices(machineId, trueMachineId, sharedProcess, sharedProcessReady);
// Create driver // Create driver
if (this.environmentService.driverHandle) { if (this.environmentService.driverHandle) {
@@ -391,7 +398,7 @@ export class CodeApplication extends Disposable {
const windows = appInstantiationService.invokeFunction(accessor => this.openFirstWindow(accessor, electronIpcServer, sharedProcessClient)); const windows = appInstantiationService.invokeFunction(accessor => this.openFirstWindow(accessor, electronIpcServer, sharedProcessClient));
// Post Open Windows Tasks // Post Open Windows Tasks
this.afterWindowOpen(); appInstantiationService.invokeFunction(this.afterWindowOpen.bind(this));
// Tracing: Stop tracing after windows are ready if enabled // Tracing: Stop tracing after windows are ready if enabled
if (this.environmentService.args.trace) { if (this.environmentService.args.trace) {
@@ -424,7 +431,7 @@ export class CodeApplication extends Disposable {
return { machineId, trueMachineId }; return { machineId, trueMachineId };
} }
private async createServices(machineId: string, trueMachineId: string | undefined, sharedProcess: SharedProcess, sharedProcessClient: Promise<Client<string>>): Promise<IInstantiationService> { private async createServices(machineId: string, trueMachineId: string | undefined, sharedProcess: SharedProcess, sharedProcessReady: Promise<Client<string>>): Promise<IInstantiationService> {
const services = new ServiceCollection(); const services = new ServiceCollection();
const fileService = this._register(new FileService(this.logService)); const fileService = this._register(new FileService(this.logService));
@@ -456,7 +463,7 @@ export class CodeApplication extends Disposable {
services.set(ISharedProcessMainService, new SyncDescriptor(SharedProcessMainService, [sharedProcess])); services.set(ISharedProcessMainService, new SyncDescriptor(SharedProcessMainService, [sharedProcess]));
services.set(ILaunchMainService, new SyncDescriptor(LaunchMainService)); services.set(ILaunchMainService, new SyncDescriptor(LaunchMainService));
const diagnosticsChannel = getDelayedChannel(sharedProcessClient.then(client => client.getChannel('diagnostics'))); const diagnosticsChannel = getDelayedChannel(sharedProcessReady.then(client => client.getChannel('diagnostics')));
services.set(IDiagnosticsService, new SyncDescriptor(DiagnosticsService, [diagnosticsChannel])); services.set(IDiagnosticsService, new SyncDescriptor(DiagnosticsService, [diagnosticsChannel]));
services.set(IIssueService, new SyncDescriptor(IssueMainService, [machineId, this.userEnv])); services.set(IIssueService, new SyncDescriptor(IssueMainService, [machineId, this.userEnv]));
@@ -477,7 +484,7 @@ export class CodeApplication extends Disposable {
// Telemetry // Telemetry
if (!this.environmentService.isExtensionDevelopment && !this.environmentService.args['disable-telemetry'] && !!product.enableTelemetry) { if (!this.environmentService.isExtensionDevelopment && !this.environmentService.args['disable-telemetry'] && !!product.enableTelemetry) {
const channel = getDelayedChannel(sharedProcessClient.then(client => client.getChannel('telemetryAppender'))); const channel = getDelayedChannel(sharedProcessReady.then(client => client.getChannel('telemetryAppender')));
const appender = combinedAppender(new TelemetryAppenderClient(channel), new LogAppender(this.logService)); const appender = combinedAppender(new TelemetryAppenderClient(channel), new LogAppender(this.logService));
const commonProperties = resolveCommonProperties(product.commit, product.version, machineId, product.msftInternalDomains, this.environmentService.installSourcePath); const commonProperties = resolveCommonProperties(product.commit, product.version, machineId, product.msftInternalDomains, this.environmentService.installSourcePath);
const piiPaths = this.environmentService.extensionsPath ? [this.environmentService.appRoot, this.environmentService.extensionsPath] : [this.environmentService.appRoot]; const piiPaths = this.environmentService.extensionsPath ? [this.environmentService.appRoot, this.environmentService.extensionsPath] : [this.environmentService.appRoot];
@@ -571,6 +578,7 @@ export class CodeApplication extends Disposable {
const storageMainService = accessor.get(IStorageMainService); const storageMainService = accessor.get(IStorageMainService);
const storageChannel = this._register(new GlobalStorageDatabaseChannel(this.logService, storageMainService)); const storageChannel = this._register(new GlobalStorageDatabaseChannel(this.logService, storageMainService));
electronIpcServer.registerChannel('storage', storageChannel); electronIpcServer.registerChannel('storage', storageChannel);
sharedProcessClient.then(client => client.registerChannel('storage', storageChannel));
const loggerChannel = new LoggerChannel(accessor.get(ILogService)); const loggerChannel = new LoggerChannel(accessor.get(ILogService));
electronIpcServer.registerChannel('logger', loggerChannel); electronIpcServer.registerChannel('logger', loggerChannel);
@@ -706,13 +714,18 @@ export class CodeApplication extends Disposable {
return { fileUri: URI.file(path) }; return { fileUri: URI.file(path) };
} }
private afterWindowOpen(): void { private afterWindowOpen(accessor: ServicesAccessor): void {
// Signal phase: after window open // Signal phase: after window open
this.lifecycleMainService.phase = LifecycleMainPhase.AfterWindowOpen; this.lifecycleMainService.phase = LifecycleMainPhase.AfterWindowOpen;
// Remote Authorities // Remote Authorities
this.handleRemoteAuthorities(); this.handleRemoteAuthorities();
// Initialize update service
const updateService = accessor.get(IUpdateService);
if (updateService instanceof Win32UpdateService || updateService instanceof LinuxUpdateService || updateService instanceof DarwinUpdateService) {
updateService.initialize();
}
} }
private handleRemoteAuthorities(): void { private handleRemoteAuthorities(): void {

View File

@@ -21,6 +21,8 @@ export class SharedProcess implements ISharedProcess {
private window: BrowserWindow | null = null; private window: BrowserWindow | null = null;
private readonly _whenReady: Promise<void>;
constructor( constructor(
private readonly machineId: string, private readonly machineId: string,
private userEnv: NodeJS.ProcessEnv, private userEnv: NodeJS.ProcessEnv,
@@ -28,10 +30,13 @@ export class SharedProcess implements ISharedProcess {
@ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService, @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService,
@ILogService private readonly logService: ILogService, @ILogService private readonly logService: ILogService,
@IThemeMainService private readonly themeMainService: IThemeMainService @IThemeMainService private readonly themeMainService: IThemeMainService
) { } ) {
// overall ready promise when shared process signals initialization is done
this._whenReady = new Promise<void>(c => ipcMain.once('shared-process->electron-main: init-done', () => c(undefined)));
}
@memoize @memoize
private get _whenReady(): Promise<void> { private get _whenIpcReady(): Promise<void> {
this.window = new BrowserWindow({ this.window = new BrowserWindow({
show: false, show: false,
backgroundColor: this.themeMainService.getBackgroundColor(), backgroundColor: this.themeMainService.getBackgroundColor(),
@@ -98,16 +103,19 @@ export class SharedProcess implements ISharedProcess {
}); });
return new Promise<void>(c => { return new Promise<void>(c => {
const onHello = Event.once(Event.fromNodeEventEmitter(ipcMain, 'handshake:hello', ({ sender }: { sender: WebContents }) => sender)); // send payload once shared process is ready to receive it
disposables.add(onHello(sender => { disposables.add(Event.once(Event.fromNodeEventEmitter(ipcMain, 'shared-process->electron-main: ready-for-payload', ({ sender }: { sender: WebContents }) => sender))(sender => {
sender.send('handshake:hey there', { sender.send('electron-main->shared-process: payload', {
sharedIPCHandle: this.environmentService.sharedIPCHandle, sharedIPCHandle: this.environmentService.sharedIPCHandle,
args: this.environmentService.args, args: this.environmentService.args,
logLevel: this.logService.getLevel() logLevel: this.logService.getLevel()
}); });
disposables.add(toDisposable(() => sender.send('handshake:goodbye'))); // signal exit to shared process when we get disposed
ipcMain.once('handshake:im ready', () => c(undefined)); disposables.add(toDisposable(() => sender.send('electron-main->shared-process: exit')));
// complete IPC-ready promise when shared process signals this to us
ipcMain.once('shared-process->electron-main: ipc-ready', () => c(undefined));
})); }));
}); });
} }
@@ -122,6 +130,11 @@ export class SharedProcess implements ISharedProcess {
await this._whenReady; await this._whenReady;
} }
async whenIpcReady(): Promise<void> {
await this.barrier.wait();
await this._whenIpcReady;
}
toggle(): void { toggle(): void {
if (!this.window || this.window.isVisible()) { if (!this.window || this.window.isVisible()) {
this.hide(); this.hide();

View File

@@ -331,7 +331,7 @@ export async function main(argv: ParsedArgs): Promise<void> {
const envService = accessor.get(IEnvironmentService); const envService = accessor.get(IEnvironmentService);
const stateService = accessor.get(IStateService); const stateService = accessor.get(IStateService);
const { appRoot, extensionsPath, extensionDevelopmentLocationURI: extensionDevelopmentLocationURI, isBuilt, installSourcePath } = envService; const { appRoot, extensionsPath, extensionDevelopmentLocationURI, isBuilt, installSourcePath } = envService;
const services = new ServiceCollection(); const services = new ServiceCollection();

View File

@@ -88,6 +88,7 @@ export interface ISerializedFontInfo {
readonly canUseHalfwidthRightwardsArrow: boolean; readonly canUseHalfwidthRightwardsArrow: boolean;
readonly spaceWidth: number; readonly spaceWidth: number;
middotWidth: number; middotWidth: number;
wsmiddotWidth: number;
readonly maxDigitWidth: number; readonly maxDigitWidth: number;
} }
@@ -161,6 +162,7 @@ class CSSBasedConfiguration extends Disposable {
// compatibility with older versions of VS Code which did not store this... // compatibility with older versions of VS Code which did not store this...
savedFontInfo.fontFeatureSettings = savedFontInfo.fontFeatureSettings || EditorFontLigatures.OFF; savedFontInfo.fontFeatureSettings = savedFontInfo.fontFeatureSettings || EditorFontLigatures.OFF;
savedFontInfo.middotWidth = savedFontInfo.middotWidth || savedFontInfo.spaceWidth; savedFontInfo.middotWidth = savedFontInfo.middotWidth || savedFontInfo.spaceWidth;
savedFontInfo.wsmiddotWidth = savedFontInfo.wsmiddotWidth || savedFontInfo.spaceWidth;
const fontInfo = new FontInfo(savedFontInfo, false); const fontInfo = new FontInfo(savedFontInfo, false);
this._writeToCache(fontInfo, fontInfo); this._writeToCache(fontInfo, fontInfo);
} }
@@ -186,6 +188,7 @@ class CSSBasedConfiguration extends Disposable {
canUseHalfwidthRightwardsArrow: readConfig.canUseHalfwidthRightwardsArrow, canUseHalfwidthRightwardsArrow: readConfig.canUseHalfwidthRightwardsArrow,
spaceWidth: Math.max(readConfig.spaceWidth, 5), spaceWidth: Math.max(readConfig.spaceWidth, 5),
middotWidth: Math.max(readConfig.middotWidth, 5), middotWidth: Math.max(readConfig.middotWidth, 5),
wsmiddotWidth: Math.max(readConfig.wsmiddotWidth, 5),
maxDigitWidth: Math.max(readConfig.maxDigitWidth, 5), maxDigitWidth: Math.max(readConfig.maxDigitWidth, 5),
}, false); }, false);
} }
@@ -226,9 +229,12 @@ class CSSBasedConfiguration extends Disposable {
const rightwardsArrow = this.createRequest('→', CharWidthRequestType.Regular, all, monospace); const rightwardsArrow = this.createRequest('→', CharWidthRequestType.Regular, all, monospace);
const halfwidthRightwardsArrow = this.createRequest('→', CharWidthRequestType.Regular, all, null); const halfwidthRightwardsArrow = this.createRequest('→', CharWidthRequestType.Regular, all, null);
// middle dot character // U+00B7 - MIDDLE DOT
const middot = this.createRequest('·', CharWidthRequestType.Regular, all, monospace); const middot = this.createRequest('·', CharWidthRequestType.Regular, all, monospace);
// U+2E31 - WORD SEPARATOR MIDDLE DOT
const wsmiddotWidth = this.createRequest(String.fromCharCode(0x2E31), CharWidthRequestType.Regular, all, null);
// monospace test: some characters // monospace test: some characters
this.createRequest('|', CharWidthRequestType.Regular, all, monospace); this.createRequest('|', CharWidthRequestType.Regular, all, monospace);
this.createRequest('/', CharWidthRequestType.Regular, all, monospace); this.createRequest('/', CharWidthRequestType.Regular, all, monospace);
@@ -294,6 +300,7 @@ class CSSBasedConfiguration extends Disposable {
canUseHalfwidthRightwardsArrow: canUseHalfwidthRightwardsArrow, canUseHalfwidthRightwardsArrow: canUseHalfwidthRightwardsArrow,
spaceWidth: space.width, spaceWidth: space.width,
middotWidth: middot.width, middotWidth: middot.width,
wsmiddotWidth: wsmiddotWidth.width,
maxDigitWidth: maxDigitWidth maxDigitWidth: maxDigitWidth
}, canTrustBrowserZoomLevel); }, canTrustBrowserZoomLevel);
} }
@@ -379,7 +386,11 @@ export class Configuration extends CommonEditorConfiguration {
emptySelectionClipboard: browser.isWebKit || browser.isFirefox, emptySelectionClipboard: browser.isWebKit || browser.isFirefox,
pixelRatio: browser.getPixelRatio(), pixelRatio: browser.getPixelRatio(),
zoomLevel: browser.getZoomLevel(), zoomLevel: browser.getZoomLevel(),
accessibilitySupport: this.accessibilityService.isScreenReaderOptimized() ? AccessibilitySupport.Enabled : AccessibilitySupport.Disabled accessibilitySupport: (
this.accessibilityService.isScreenReaderOptimized()
? AccessibilitySupport.Enabled
: this.accessibilityService.getAccessibilitySupport()
)
}; };
} }

View File

@@ -57,19 +57,6 @@ export interface ITextAreaInputHost {
deduceModelPosition(viewAnchorPosition: Position, deltaOffset: number, lineFeedCnt: number): Position; deduceModelPosition(viewAnchorPosition: Position, deltaOffset: number, lineFeedCnt: number): Position;
} }
const enum TextAreaInputEventType {
none,
compositionstart,
compositionupdate,
compositionend,
input,
cut,
copy,
paste,
focus,
blur
}
interface CompositionEvent extends UIEvent { interface CompositionEvent extends UIEvent {
readonly data: string; readonly data: string;
readonly locale: string; readonly locale: string;
@@ -155,7 +142,6 @@ export class TextAreaInput extends Disposable {
private readonly _host: ITextAreaInputHost; private readonly _host: ITextAreaInputHost;
private readonly _textArea: TextAreaWrapper; private readonly _textArea: TextAreaWrapper;
private _lastTextAreaEvent: TextAreaInputEventType;
private readonly _asyncTriggerCut: RunOnceScheduler; private readonly _asyncTriggerCut: RunOnceScheduler;
private _textAreaState: TextAreaState; private _textAreaState: TextAreaState;
@@ -169,7 +155,6 @@ export class TextAreaInput extends Disposable {
super(); super();
this._host = host; this._host = host;
this._textArea = this._register(new TextAreaWrapper(textArea)); this._textArea = this._register(new TextAreaWrapper(textArea));
this._lastTextAreaEvent = TextAreaInputEventType.none;
this._asyncTriggerCut = this._register(new RunOnceScheduler(() => this._onCut.fire(), 0)); this._asyncTriggerCut = this._register(new RunOnceScheduler(() => this._onCut.fire(), 0));
this._textAreaState = TextAreaState.EMPTY; this._textAreaState = TextAreaState.EMPTY;
@@ -200,8 +185,6 @@ export class TextAreaInput extends Disposable {
})); }));
this._register(dom.addDisposableListener(textArea.domNode, 'compositionstart', (e: CompositionEvent) => { this._register(dom.addDisposableListener(textArea.domNode, 'compositionstart', (e: CompositionEvent) => {
this._lastTextAreaEvent = TextAreaInputEventType.compositionstart;
if (this._isDoingComposition) { if (this._isDoingComposition) {
return; return;
} }
@@ -218,10 +201,10 @@ export class TextAreaInput extends Disposable {
/** /**
* Deduce the typed input from a text area's value and the last observed state. * Deduce the typed input from a text area's value and the last observed state.
*/ */
const deduceInputFromTextAreaValue = (couldBeEmojiInput: boolean, couldBeTypingAtOffset0: boolean): [TextAreaState, ITypeData] => { const deduceInputFromTextAreaValue = (couldBeEmojiInput: boolean): [TextAreaState, ITypeData] => {
const oldState = this._textAreaState; const oldState = this._textAreaState;
const newState = TextAreaState.readFromTextArea(this._textArea); const newState = TextAreaState.readFromTextArea(this._textArea);
return [newState, TextAreaState.deduceInput(oldState, newState, couldBeEmojiInput, couldBeTypingAtOffset0)]; return [newState, TextAreaState.deduceInput(oldState, newState, couldBeEmojiInput)];
}; };
/** /**
@@ -258,10 +241,8 @@ export class TextAreaInput extends Disposable {
}; };
this._register(dom.addDisposableListener(textArea.domNode, 'compositionupdate', (e: CompositionEvent) => { this._register(dom.addDisposableListener(textArea.domNode, 'compositionupdate', (e: CompositionEvent) => {
this._lastTextAreaEvent = TextAreaInputEventType.compositionupdate;
if (compositionDataInValid(e.locale)) { if (compositionDataInValid(e.locale)) {
const [newState, typeInput] = deduceInputFromTextAreaValue(/*couldBeEmojiInput*/false, /*couldBeTypingAtOffset0*/false); const [newState, typeInput] = deduceInputFromTextAreaValue(/*couldBeEmojiInput*/false);
this._textAreaState = newState; this._textAreaState = newState;
this._onType.fire(typeInput); this._onType.fire(typeInput);
this._onCompositionUpdate.fire(e); this._onCompositionUpdate.fire(e);
@@ -275,7 +256,6 @@ export class TextAreaInput extends Disposable {
})); }));
this._register(dom.addDisposableListener(textArea.domNode, 'compositionend', (e: CompositionEvent) => { this._register(dom.addDisposableListener(textArea.domNode, 'compositionend', (e: CompositionEvent) => {
this._lastTextAreaEvent = TextAreaInputEventType.compositionend;
// https://github.com/microsoft/monaco-editor/issues/1663 // https://github.com/microsoft/monaco-editor/issues/1663
// On iOS 13.2, Chinese system IME randomly trigger an additional compositionend event with empty data // On iOS 13.2, Chinese system IME randomly trigger an additional compositionend event with empty data
if (!this._isDoingComposition) { if (!this._isDoingComposition) {
@@ -283,7 +263,7 @@ export class TextAreaInput extends Disposable {
} }
if (compositionDataInValid(e.locale)) { if (compositionDataInValid(e.locale)) {
// https://github.com/Microsoft/monaco-editor/issues/339 // https://github.com/Microsoft/monaco-editor/issues/339
const [newState, typeInput] = deduceInputFromTextAreaValue(/*couldBeEmojiInput*/false, /*couldBeTypingAtOffset0*/false); const [newState, typeInput] = deduceInputFromTextAreaValue(/*couldBeEmojiInput*/false);
this._textAreaState = newState; this._textAreaState = newState;
this._onType.fire(typeInput); this._onType.fire(typeInput);
} else { } else {
@@ -307,10 +287,6 @@ export class TextAreaInput extends Disposable {
})); }));
this._register(dom.addDisposableListener(textArea.domNode, 'input', () => { this._register(dom.addDisposableListener(textArea.domNode, 'input', () => {
// We want to find out if this is the first `input` after a `focus`.
const previousEventWasFocus = (this._lastTextAreaEvent === TextAreaInputEventType.focus);
this._lastTextAreaEvent = TextAreaInputEventType.input;
// Pretend here we touched the text area, as the `input` event will most likely // Pretend here we touched the text area, as the `input` event will most likely
// result in a `selectionchange` event which we want to ignore // result in a `selectionchange` event which we want to ignore
this._textArea.setIgnoreSelectionChangeTime('received input event'); this._textArea.setIgnoreSelectionChangeTime('received input event');
@@ -319,7 +295,7 @@ export class TextAreaInput extends Disposable {
return; return;
} }
const [newState, typeInput] = deduceInputFromTextAreaValue(/*couldBeEmojiInput*/platform.isMacintosh, /*couldBeTypingAtOffset0*/previousEventWasFocus && platform.isMacintosh); const [newState, typeInput] = deduceInputFromTextAreaValue(/*couldBeEmojiInput*/platform.isMacintosh);
if (typeInput.replaceCharCnt === 0 && typeInput.text.length === 1 && strings.isHighSurrogate(typeInput.text.charCodeAt(0))) { if (typeInput.replaceCharCnt === 0 && typeInput.text.length === 1 && strings.isHighSurrogate(typeInput.text.charCodeAt(0))) {
// Ignore invalid input but keep it around for next time // Ignore invalid input but keep it around for next time
return; return;
@@ -341,8 +317,6 @@ export class TextAreaInput extends Disposable {
// --- Clipboard operations // --- Clipboard operations
this._register(dom.addDisposableListener(textArea.domNode, 'cut', (e: ClipboardEvent) => { this._register(dom.addDisposableListener(textArea.domNode, 'cut', (e: ClipboardEvent) => {
this._lastTextAreaEvent = TextAreaInputEventType.cut;
// Pretend here we touched the text area, as the `cut` event will most likely // Pretend here we touched the text area, as the `cut` event will most likely
// result in a `selectionchange` event which we want to ignore // result in a `selectionchange` event which we want to ignore
this._textArea.setIgnoreSelectionChangeTime('received cut event'); this._textArea.setIgnoreSelectionChangeTime('received cut event');
@@ -352,14 +326,10 @@ export class TextAreaInput extends Disposable {
})); }));
this._register(dom.addDisposableListener(textArea.domNode, 'copy', (e: ClipboardEvent) => { this._register(dom.addDisposableListener(textArea.domNode, 'copy', (e: ClipboardEvent) => {
this._lastTextAreaEvent = TextAreaInputEventType.copy;
this._ensureClipboardGetsEditorSelection(e); this._ensureClipboardGetsEditorSelection(e);
})); }));
this._register(dom.addDisposableListener(textArea.domNode, 'paste', (e: ClipboardEvent) => { this._register(dom.addDisposableListener(textArea.domNode, 'paste', (e: ClipboardEvent) => {
this._lastTextAreaEvent = TextAreaInputEventType.paste;
// Pretend here we touched the text area, as the `paste` event will most likely // Pretend here we touched the text area, as the `paste` event will most likely
// result in a `selectionchange` event which we want to ignore // result in a `selectionchange` event which we want to ignore
this._textArea.setIgnoreSelectionChangeTime('received paste event'); this._textArea.setIgnoreSelectionChangeTime('received paste event');
@@ -379,11 +349,9 @@ export class TextAreaInput extends Disposable {
})); }));
this._register(dom.addDisposableListener(textArea.domNode, 'focus', () => { this._register(dom.addDisposableListener(textArea.domNode, 'focus', () => {
this._lastTextAreaEvent = TextAreaInputEventType.focus;
this._setHasFocus(true); this._setHasFocus(true);
})); }));
this._register(dom.addDisposableListener(textArea.domNode, 'blur', () => { this._register(dom.addDisposableListener(textArea.domNode, 'blur', () => {
this._lastTextAreaEvent = TextAreaInputEventType.blur;
this._setHasFocus(false); this._setHasFocus(false);
})); }));
} }
@@ -625,7 +593,8 @@ class ClipboardEventUtils {
if ((<any>window).clipboardData) { if ((<any>window).clipboardData) {
e.preventDefault(); e.preventDefault();
return (<any>window).clipboardData.getData('Text'); const text: string = (<any>window).clipboardData.getData('Text');
return [text, null];
} }
throw new Error('ClipboardEventUtils.getTextData: Cannot use text data!'); throw new Error('ClipboardEventUtils.getTextData: Cannot use text data!');

View File

@@ -96,7 +96,7 @@ export class TextAreaState {
return new TextAreaState(text, 0, text.length, null, null); return new TextAreaState(text, 0, text.length, null, null);
} }
public static deduceInput(previousState: TextAreaState, currentState: TextAreaState, couldBeEmojiInput: boolean, couldBeTypingAtOffset0: boolean): ITypeData { public static deduceInput(previousState: TextAreaState, currentState: TextAreaState, couldBeEmojiInput: boolean): ITypeData {
if (!previousState) { if (!previousState) {
// This is the EMPTY state // This is the EMPTY state
return { return {
@@ -116,18 +116,6 @@ export class TextAreaState {
let currentSelectionStart = currentState.selectionStart; let currentSelectionStart = currentState.selectionStart;
let currentSelectionEnd = currentState.selectionEnd; let currentSelectionEnd = currentState.selectionEnd;
if (couldBeTypingAtOffset0 && previousValue.length > 0 && previousSelectionStart === previousSelectionEnd && currentSelectionStart === currentSelectionEnd) {
// See https://github.com/Microsoft/vscode/issues/42251
// where typing always happens at offset 0 in the textarea
// when using a custom title area in OSX and moving the window
if (!strings.startsWith(currentValue, previousValue) && strings.endsWith(currentValue, previousValue)) {
// Looks like something was typed at offset 0
// ==> pretend we placed the cursor at offset 0 to begin with...
previousSelectionStart = 0;
previousSelectionEnd = 0;
}
}
// Strip the previous suffix from the value (without interfering with the current selection) // Strip the previous suffix from the value (without interfering with the current selection)
const previousSuffix = previousValue.substring(previousSelectionEnd); const previousSuffix = previousValue.substring(previousSelectionEnd);
const currentSuffix = currentValue.substring(currentSelectionEnd); const currentSuffix = currentValue.substring(currentSelectionEnd);

View File

@@ -74,6 +74,7 @@ export class ViewLineOptions {
public readonly renderControlCharacters: boolean; public readonly renderControlCharacters: boolean;
public readonly spaceWidth: number; public readonly spaceWidth: number;
public readonly middotWidth: number; public readonly middotWidth: number;
public readonly wsmiddotWidth: number;
public readonly useMonospaceOptimizations: boolean; public readonly useMonospaceOptimizations: boolean;
public readonly canUseHalfwidthRightwardsArrow: boolean; public readonly canUseHalfwidthRightwardsArrow: boolean;
public readonly lineHeight: number; public readonly lineHeight: number;
@@ -88,6 +89,7 @@ export class ViewLineOptions {
this.renderControlCharacters = options.get(EditorOption.renderControlCharacters); this.renderControlCharacters = options.get(EditorOption.renderControlCharacters);
this.spaceWidth = fontInfo.spaceWidth; this.spaceWidth = fontInfo.spaceWidth;
this.middotWidth = fontInfo.middotWidth; this.middotWidth = fontInfo.middotWidth;
this.wsmiddotWidth = fontInfo.wsmiddotWidth;
this.useMonospaceOptimizations = ( this.useMonospaceOptimizations = (
fontInfo.isMonospace fontInfo.isMonospace
&& !options.get(EditorOption.disableMonospaceOptimizations) && !options.get(EditorOption.disableMonospaceOptimizations)
@@ -105,6 +107,7 @@ export class ViewLineOptions {
&& this.renderControlCharacters === other.renderControlCharacters && this.renderControlCharacters === other.renderControlCharacters
&& this.spaceWidth === other.spaceWidth && this.spaceWidth === other.spaceWidth
&& this.middotWidth === other.middotWidth && this.middotWidth === other.middotWidth
&& this.wsmiddotWidth === other.wsmiddotWidth
&& this.useMonospaceOptimizations === other.useMonospaceOptimizations && this.useMonospaceOptimizations === other.useMonospaceOptimizations
&& this.canUseHalfwidthRightwardsArrow === other.canUseHalfwidthRightwardsArrow && this.canUseHalfwidthRightwardsArrow === other.canUseHalfwidthRightwardsArrow
&& this.lineHeight === other.lineHeight && this.lineHeight === other.lineHeight
@@ -219,6 +222,7 @@ export class ViewLine implements IVisibleLine {
lineData.startVisibleColumn, lineData.startVisibleColumn,
options.spaceWidth, options.spaceWidth,
options.middotWidth, options.middotWidth,
options.wsmiddotWidth,
options.stopRenderingLineAfter, options.stopRenderingLineAfter,
options.renderWhitespace, options.renderWhitespace,
options.renderControlCharacters, options.renderControlCharacters,

View File

@@ -8,7 +8,7 @@ import * as nls from 'vs/nls';
import * as dom from 'vs/base/browser/dom'; import * as dom from 'vs/base/browser/dom';
import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode'; import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';
import { ISashEvent, IVerticalSashLayoutProvider, Sash, SashState } from 'vs/base/browser/ui/sash/sash'; import { ISashEvent, IVerticalSashLayoutProvider, Sash, SashState } from 'vs/base/browser/ui/sash/sash';
import { RunOnceScheduler, IntervalTimer } from 'vs/base/common/async'; import { RunOnceScheduler } from 'vs/base/common/async';
import { Color } from 'vs/base/common/color'; import { Color } from 'vs/base/common/color';
import { Emitter, Event } from 'vs/base/common/event'; import { Emitter, Event } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle'; import { Disposable } from 'vs/base/common/lifecycle';
@@ -48,6 +48,7 @@ import { Constants } from 'vs/base/common/uint';
import { EditorExtensionsRegistry, IDiffEditorContributionDescription } from 'vs/editor/browser/editorExtensions'; import { EditorExtensionsRegistry, IDiffEditorContributionDescription } from 'vs/editor/browser/editorExtensions';
import { onUnexpectedError } from 'vs/base/common/errors'; import { onUnexpectedError } from 'vs/base/common/errors';
import { IEditorProgressService, IProgressRunner } from 'vs/platform/progress/common/progress'; import { IEditorProgressService, IProgressRunner } from 'vs/platform/progress/common/progress';
import { ElementSizeObserver } from 'vs/editor/browser/config/elementSizeObserver';
interface IEditorDiffDecorations { interface IEditorDiffDecorations {
decorations: IModelDeltaDecoration[]; decorations: IModelDeltaDecoration[];
@@ -179,10 +180,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
private readonly _overviewDomElement: HTMLElement; private readonly _overviewDomElement: HTMLElement;
private readonly _overviewViewportDomElement: FastDomNode<HTMLElement>; private readonly _overviewViewportDomElement: FastDomNode<HTMLElement>;
private _width: number; private readonly _elementSizeObserver: ElementSizeObserver;
private _height: number;
private _reviewHeight: number;
private readonly _measureDomElementToken: IntervalTimer | null;
private readonly originalEditor: CodeEditorWidget; private readonly originalEditor: CodeEditorWidget;
private readonly _originalDomNode: HTMLElement; private readonly _originalDomNode: HTMLElement;
@@ -329,9 +327,10 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
this._isVisible = true; this._isVisible = true;
this._isHandlingScrollEvent = false; this._isHandlingScrollEvent = false;
this._width = 0; this._elementSizeObserver = this._register(new ElementSizeObserver(this._containerDomElement, undefined, () => this._onDidContainerSizeChanged()));
this._height = 0; if (options.automaticLayout) {
this._reviewHeight = 0; this._elementSizeObserver.startObserving();
}
this._diffComputationResult = null; this._diffComputationResult = null;
@@ -360,12 +359,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
this._containerDomElement.appendChild(this._reviewPane.shadow.domNode); this._containerDomElement.appendChild(this._reviewPane.shadow.domNode);
this._containerDomElement.appendChild(this._reviewPane.actionBarContainer.domNode); this._containerDomElement.appendChild(this._reviewPane.actionBarContainer.domNode);
if (options.automaticLayout) {
this._measureDomElementToken = new IntervalTimer();
this._measureDomElementToken.cancelAndSet(() => this._measureDomElement(false), 100);
} else {
this._measureDomElementToken = null;
}
// enableSplitViewResizing // enableSplitViewResizing
this._enableSplitViewResizing = true; this._enableSplitViewResizing = true;
@@ -563,10 +557,6 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
this._beginUpdateDecorationsTimeout = -1; this._beginUpdateDecorationsTimeout = -1;
} }
if (this._measureDomElementToken) {
this._measureDomElementToken.dispose();
}
this._cleanViewZonesAndDecorations(); this._cleanViewZonesAndDecorations();
if (this._originalOverviewRuler) { if (this._originalOverviewRuler) {
@@ -866,7 +856,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
} }
public layout(dimension?: editorCommon.IDimension): void { public layout(dimension?: editorCommon.IDimension): void {
this._measureDomElement(false, dimension); this._elementSizeObserver.observe(dimension);
} }
public focus(): void { public focus(): void {
@@ -907,35 +897,21 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
//------------ begin layouting methods //------------ begin layouting methods
private _measureDomElement(forceDoLayoutCall: boolean, dimensions?: editorCommon.IDimension): void { private _onDidContainerSizeChanged(): void {
dimensions = dimensions || {
width: this._containerDomElement.clientWidth,
height: this._containerDomElement.clientHeight
};
if (dimensions.width <= 0) {
this._width = 0;
this._height = 0;
this._reviewHeight = 0;
return;
}
if (!forceDoLayoutCall && dimensions.width === this._width && dimensions.height === this._height) {
// Nothing has changed
return;
}
this._width = dimensions.width;
this._height = dimensions.height;
this._reviewHeight = this._reviewPane.isVisible() ? this._height : 0;
this._doLayout(); this._doLayout();
} }
private _getReviewHeight(): number {
return this._reviewPane.isVisible() ? this._elementSizeObserver.getHeight() : 0;
}
private _layoutOverviewRulers(): void { private _layoutOverviewRulers(): void {
if (!this._originalOverviewRuler || !this._modifiedOverviewRuler) { if (!this._originalOverviewRuler || !this._modifiedOverviewRuler) {
return; return;
} }
const height = this._elementSizeObserver.getHeight();
const reviewHeight = this._getReviewHeight();
let freeSpace = DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH - 2 * DiffEditorWidget.ONE_OVERVIEW_WIDTH; let freeSpace = DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH - 2 * DiffEditorWidget.ONE_OVERVIEW_WIDTH;
let layoutInfo = this.modifiedEditor.getLayoutInfo(); let layoutInfo = this.modifiedEditor.getLayoutInfo();
if (layoutInfo) { if (layoutInfo) {
@@ -943,13 +919,13 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
top: 0, top: 0,
width: DiffEditorWidget.ONE_OVERVIEW_WIDTH, width: DiffEditorWidget.ONE_OVERVIEW_WIDTH,
right: freeSpace + DiffEditorWidget.ONE_OVERVIEW_WIDTH, right: freeSpace + DiffEditorWidget.ONE_OVERVIEW_WIDTH,
height: (this._height - this._reviewHeight) height: (height - reviewHeight)
}); });
this._modifiedOverviewRuler.setLayout({ this._modifiedOverviewRuler.setLayout({
top: 0, top: 0,
right: 0, right: 0,
width: DiffEditorWidget.ONE_OVERVIEW_WIDTH, width: DiffEditorWidget.ONE_OVERVIEW_WIDTH,
height: (this._height - this._reviewHeight) height: (height - reviewHeight)
}); });
} }
} }
@@ -1095,33 +1071,38 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
} }
public doLayout(): void { public doLayout(): void {
this._measureDomElement(true); this._elementSizeObserver.observe();
this._doLayout();
} }
private _doLayout(): void { private _doLayout(): void {
const width = this._elementSizeObserver.getWidth();
const height = this._elementSizeObserver.getHeight();
const reviewHeight = this._getReviewHeight();
let splitPoint = this._strategy.layout(); let splitPoint = this._strategy.layout();
this._originalDomNode.style.width = splitPoint + 'px'; this._originalDomNode.style.width = splitPoint + 'px';
this._originalDomNode.style.left = '0px'; this._originalDomNode.style.left = '0px';
this._modifiedDomNode.style.width = (this._width - splitPoint) + 'px'; this._modifiedDomNode.style.width = (width - splitPoint) + 'px';
this._modifiedDomNode.style.left = splitPoint + 'px'; this._modifiedDomNode.style.left = splitPoint + 'px';
this._overviewDomElement.style.top = '0px'; this._overviewDomElement.style.top = '0px';
this._overviewDomElement.style.height = (this._height - this._reviewHeight) + 'px'; this._overviewDomElement.style.height = (height - reviewHeight) + 'px';
this._overviewDomElement.style.width = DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH + 'px'; this._overviewDomElement.style.width = DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH + 'px';
this._overviewDomElement.style.left = (this._width - DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH) + 'px'; this._overviewDomElement.style.left = (width - DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH) + 'px';
this._overviewViewportDomElement.setWidth(DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH); this._overviewViewportDomElement.setWidth(DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH);
this._overviewViewportDomElement.setHeight(30); this._overviewViewportDomElement.setHeight(30);
this.originalEditor.layout({ width: splitPoint, height: (this._height - this._reviewHeight) }); this.originalEditor.layout({ width: splitPoint, height: (height - reviewHeight) });
this.modifiedEditor.layout({ width: this._width - splitPoint - DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH, height: (this._height - this._reviewHeight) }); this.modifiedEditor.layout({ width: width - splitPoint - DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH, height: (height - reviewHeight) });
if (this._originalOverviewRuler || this._modifiedOverviewRuler) { if (this._originalOverviewRuler || this._modifiedOverviewRuler) {
this._layoutOverviewRulers(); this._layoutOverviewRulers();
} }
this._reviewPane.layout(this._height - this._reviewHeight, this._width, this._reviewHeight); this._reviewPane.layout(height - reviewHeight, width, reviewHeight);
this._layoutOverviewViewport(); this._layoutOverviewViewport();
} }
@@ -1162,11 +1143,11 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
private _createDataSource(): IDataSource { private _createDataSource(): IDataSource {
return { return {
getWidth: () => { getWidth: () => {
return this._width; return this._elementSizeObserver.getWidth();
}, },
getHeight: () => { getHeight: () => {
return (this._height - this._reviewHeight); return (this._elementSizeObserver.getHeight() - this._getReviewHeight());
}, },
getContainerDomNode: () => { getContainerDomNode: () => {
@@ -1200,7 +1181,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
} }
// Just do a layout, the strategy might need it // Just do a layout, the strategy might need it
this._measureDomElement(true); this._doLayout();
} }
private _getLineChangeAtOrBeforeLineNumber(lineNumber: number, startLineNumberExtractor: (lineChange: editorCommon.ILineChange) => number): editorCommon.ILineChange | null { private _getLineChangeAtOrBeforeLineNumber(lineNumber: number, startLineNumberExtractor: (lineChange: editorCommon.ILineChange) => number): editorCommon.ILineChange | null {
@@ -2181,6 +2162,7 @@ class InlineViewZonesComputer extends ViewZonesComputer {
0, 0,
fontInfo.spaceWidth, fontInfo.spaceWidth,
fontInfo.middotWidth, fontInfo.middotWidth,
fontInfo.wsmiddotWidth,
options.get(EditorOption.stopRenderingLineAfter), options.get(EditorOption.stopRenderingLineAfter),
options.get(EditorOption.renderWhitespace), options.get(EditorOption.renderWhitespace),
options.get(EditorOption.renderControlCharacters), options.get(EditorOption.renderControlCharacters),

View File

@@ -783,6 +783,7 @@ export class DiffReview extends Disposable {
0, 0,
fontInfo.spaceWidth, fontInfo.spaceWidth,
fontInfo.middotWidth, fontInfo.middotWidth,
fontInfo.wsmiddotWidth,
options.get(EditorOption.stopRenderingLineAfter), options.get(EditorOption.stopRenderingLineAfter),
options.get(EditorOption.renderWhitespace), options.get(EditorOption.renderWhitespace),
options.get(EditorOption.renderControlCharacters), options.get(EditorOption.renderControlCharacters),

View File

@@ -366,6 +366,10 @@ export interface IEditorOptions {
* Defaults to 10 (ms) * Defaults to 10 (ms)
*/ */
quickSuggestionsDelay?: number; quickSuggestionsDelay?: number;
/**
* Controls the spacing around the editor.
*/
padding?: IEditorPaddingOptions;
/** /**
* Parameter hint options. * Parameter hint options.
*/ */
@@ -2082,6 +2086,65 @@ function _multiCursorModifierFromString(multiCursorModifier: 'ctrlCmd' | 'alt'):
//#endregion //#endregion
//#region padding
/**
* Configuration options for editor padding
*/
export interface IEditorPaddingOptions {
/**
* Spacing between top edge of editor and first line.
*/
top?: number;
/**
* Spacing between bottom edge of editor and last line.
*/
bottom?: number;
}
export interface InternalEditorPaddingOptions {
readonly top: number;
readonly bottom: number;
}
class EditorPadding extends BaseEditorOption<EditorOption.padding, InternalEditorPaddingOptions> {
constructor() {
super(
EditorOption.padding, 'padding', { top: 0, bottom: 0 },
{
'editor.padding.top': {
type: 'number',
default: 0,
minimum: 0,
maximum: 1000,
description: nls.localize('padding.top', "Controls the amount of space between the top edge of the editor and the first line.")
},
'editor.padding.bottom': {
type: 'number',
default: 0,
minimum: 0,
maximum: 1000,
description: nls.localize('padding.bottom', "Controls the amount of space between the bottom edge of the editor and the last line.")
}
}
);
}
public validate(_input: any): InternalEditorPaddingOptions {
if (typeof _input !== 'object') {
return this.defaultValue;
}
const input = _input as IEditorPaddingOptions;
return {
top: EditorIntOption.clampedInt(input.top, 0, 0, 1000),
bottom: EditorIntOption.clampedInt(input.bottom, 0, 0, 1000)
};
}
}
//#endregion
//#region parameterHints //#region parameterHints
/** /**
@@ -3188,6 +3251,7 @@ export const enum EditorOption {
occurrencesHighlight, occurrencesHighlight,
overviewRulerBorder, overviewRulerBorder,
overviewRulerLanes, overviewRulerLanes,
padding,
parameterHints, parameterHints,
peekWidgetDefaultFocus, peekWidgetDefaultFocus,
definitionLinkOpensInPeek, definitionLinkOpensInPeek,
@@ -3575,6 +3639,7 @@ export const EditorOptions = {
EditorOption.overviewRulerLanes, 'overviewRulerLanes', EditorOption.overviewRulerLanes, 'overviewRulerLanes',
3, 0, 3 3, 0, 3
)), )),
padding: register(new EditorPadding()),
parameterHints: register(new EditorParameterHints()), parameterHints: register(new EditorParameterHints()),
peekWidgetDefaultFocus: register(new EditorStringEnumOption( peekWidgetDefaultFocus: register(new EditorStringEnumOption(
EditorOption.peekWidgetDefaultFocus, 'peekWidgetDefaultFocus', EditorOption.peekWidgetDefaultFocus, 'peekWidgetDefaultFocus',
@@ -3634,7 +3699,7 @@ export const EditorOptions = {
)), )),
renderWhitespace: register(new EditorStringEnumOption( renderWhitespace: register(new EditorStringEnumOption(
EditorOption.renderWhitespace, 'renderWhitespace', EditorOption.renderWhitespace, 'renderWhitespace',
'none' as 'none' | 'boundary' | 'selection' | 'all', 'selection' as 'selection' | 'none' | 'boundary' | 'all',
['none', 'boundary', 'selection', 'all'] as const, ['none', 'boundary', 'selection', 'all'] as const,
{ {
enumDescriptions: [ enumDescriptions: [

View File

@@ -135,6 +135,7 @@ export class FontInfo extends BareFontInfo {
readonly canUseHalfwidthRightwardsArrow: boolean; readonly canUseHalfwidthRightwardsArrow: boolean;
readonly spaceWidth: number; readonly spaceWidth: number;
readonly middotWidth: number; readonly middotWidth: number;
readonly wsmiddotWidth: number;
readonly maxDigitWidth: number; readonly maxDigitWidth: number;
/** /**
@@ -154,6 +155,7 @@ export class FontInfo extends BareFontInfo {
canUseHalfwidthRightwardsArrow: boolean; canUseHalfwidthRightwardsArrow: boolean;
spaceWidth: number; spaceWidth: number;
middotWidth: number; middotWidth: number;
wsmiddotWidth: number;
maxDigitWidth: number; maxDigitWidth: number;
}, isTrusted: boolean) { }, isTrusted: boolean) {
super(opts); super(opts);
@@ -164,6 +166,7 @@ export class FontInfo extends BareFontInfo {
this.canUseHalfwidthRightwardsArrow = opts.canUseHalfwidthRightwardsArrow; this.canUseHalfwidthRightwardsArrow = opts.canUseHalfwidthRightwardsArrow;
this.spaceWidth = opts.spaceWidth; this.spaceWidth = opts.spaceWidth;
this.middotWidth = opts.middotWidth; this.middotWidth = opts.middotWidth;
this.wsmiddotWidth = opts.wsmiddotWidth;
this.maxDigitWidth = opts.maxDigitWidth; this.maxDigitWidth = opts.maxDigitWidth;
} }
@@ -183,6 +186,7 @@ export class FontInfo extends BareFontInfo {
&& this.canUseHalfwidthRightwardsArrow === other.canUseHalfwidthRightwardsArrow && this.canUseHalfwidthRightwardsArrow === other.canUseHalfwidthRightwardsArrow
&& this.spaceWidth === other.spaceWidth && this.spaceWidth === other.spaceWidth
&& this.middotWidth === other.middotWidth && this.middotWidth === other.middotWidth
&& this.wsmiddotWidth === other.wsmiddotWidth
&& this.maxDigitWidth === other.maxDigitWidth && this.maxDigitWidth === other.maxDigitWidth
); );
} }

View File

@@ -61,6 +61,11 @@ export interface ITextEditorModel extends IEditorModel {
* Figure out if this model is resolved or not. * Figure out if this model is resolved or not.
*/ */
isResolved(): this is IResolvedTextEditorModel; isResolved(): this is IResolvedTextEditorModel;
/**
* The mode id of the text model if known.
*/
getMode(): string | undefined;
} }
export interface IResolvedTextEditorModel extends ITextEditorModel { export interface IResolvedTextEditorModel extends ITextEditorModel {

View File

@@ -229,53 +229,54 @@ export enum EditorOption {
occurrencesHighlight = 61, occurrencesHighlight = 61,
overviewRulerBorder = 62, overviewRulerBorder = 62,
overviewRulerLanes = 63, overviewRulerLanes = 63,
parameterHints = 64, padding = 64,
peekWidgetDefaultFocus = 65, parameterHints = 65,
definitionLinkOpensInPeek = 66, peekWidgetDefaultFocus = 66,
quickSuggestions = 67, definitionLinkOpensInPeek = 67,
quickSuggestionsDelay = 68, quickSuggestions = 68,
readOnly = 69, quickSuggestionsDelay = 69,
renderControlCharacters = 70, readOnly = 70,
renderIndentGuides = 71, renderControlCharacters = 71,
renderFinalNewline = 72, renderIndentGuides = 72,
renderLineHighlight = 73, renderFinalNewline = 73,
renderValidationDecorations = 74, renderLineHighlight = 74,
renderWhitespace = 75, renderValidationDecorations = 75,
revealHorizontalRightPadding = 76, renderWhitespace = 76,
roundedSelection = 77, revealHorizontalRightPadding = 77,
rulers = 78, roundedSelection = 78,
scrollbar = 79, rulers = 79,
scrollBeyondLastColumn = 80, scrollbar = 80,
scrollBeyondLastLine = 81, scrollBeyondLastColumn = 81,
scrollPredominantAxis = 82, scrollBeyondLastLine = 82,
selectionClipboard = 83, scrollPredominantAxis = 83,
selectionHighlight = 84, selectionClipboard = 84,
selectOnLineNumbers = 85, selectionHighlight = 85,
showFoldingControls = 86, selectOnLineNumbers = 86,
showUnused = 87, showFoldingControls = 87,
snippetSuggestions = 88, showUnused = 88,
smoothScrolling = 89, snippetSuggestions = 89,
stopRenderingLineAfter = 90, smoothScrolling = 90,
suggest = 91, stopRenderingLineAfter = 91,
suggestFontSize = 92, suggest = 92,
suggestLineHeight = 93, suggestFontSize = 93,
suggestOnTriggerCharacters = 94, suggestLineHeight = 94,
suggestSelection = 95, suggestOnTriggerCharacters = 95,
tabCompletion = 96, suggestSelection = 96,
useTabStops = 97, tabCompletion = 97,
wordSeparators = 98, useTabStops = 98,
wordWrap = 99, wordSeparators = 99,
wordWrapBreakAfterCharacters = 100, wordWrap = 100,
wordWrapBreakBeforeCharacters = 101, wordWrapBreakAfterCharacters = 101,
wordWrapColumn = 102, wordWrapBreakBeforeCharacters = 102,
wordWrapMinified = 103, wordWrapColumn = 103,
wrappingIndent = 104, wordWrapMinified = 104,
wrappingStrategy = 105, wrappingIndent = 105,
editorClassName = 106, wrappingStrategy = 106,
pixelRatio = 107, editorClassName = 107,
tabFocusMode = 108, pixelRatio = 108,
layoutInfo = 109, tabFocusMode = 109,
wrappingInfo = 110 layoutInfo = 110,
wrappingInfo = 111
} }
/** /**

View File

@@ -111,8 +111,10 @@ export class LinesLayout {
private _minWidth: number; private _minWidth: number;
private _lineCount: number; private _lineCount: number;
private _lineHeight: number; private _lineHeight: number;
private _paddingTop: number;
private _paddingBottom: number;
constructor(lineCount: number, lineHeight: number) { constructor(lineCount: number, lineHeight: number, paddingTop: number, paddingBottom: number) {
this._instanceId = strings.singleLetterHash(++LinesLayout.INSTANCE_COUNT); this._instanceId = strings.singleLetterHash(++LinesLayout.INSTANCE_COUNT);
this._pendingChanges = new PendingChanges(); this._pendingChanges = new PendingChanges();
this._lastWhitespaceId = 0; this._lastWhitespaceId = 0;
@@ -121,6 +123,8 @@ export class LinesLayout {
this._minWidth = -1; /* marker for not being computed */ this._minWidth = -1; /* marker for not being computed */
this._lineCount = lineCount; this._lineCount = lineCount;
this._lineHeight = lineHeight; this._lineHeight = lineHeight;
this._paddingTop = paddingTop;
this._paddingBottom = paddingBottom;
} }
/** /**
@@ -158,6 +162,14 @@ export class LinesLayout {
this._lineHeight = lineHeight; this._lineHeight = lineHeight;
} }
/**
* Changes the padding used to calculate vertical offsets.
*/
public setPadding(paddingTop: number, paddingBottom: number): void {
this._paddingTop = paddingTop;
this._paddingBottom = paddingBottom;
}
/** /**
* Set the number of lines. * Set the number of lines.
* *
@@ -404,7 +416,8 @@ export class LinesLayout {
this._checkPendingChanges(); this._checkPendingChanges();
const linesHeight = this._lineHeight * this._lineCount; const linesHeight = this._lineHeight * this._lineCount;
const whitespacesHeight = this.getWhitespacesTotalHeight(); const whitespacesHeight = this.getWhitespacesTotalHeight();
return linesHeight + whitespacesHeight;
return linesHeight + whitespacesHeight + this._paddingTop + this._paddingBottom;
} }
/** /**
@@ -495,7 +508,7 @@ export class LinesLayout {
const previousWhitespacesHeight = this.getWhitespaceAccumulatedHeightBeforeLineNumber(lineNumber); const previousWhitespacesHeight = this.getWhitespaceAccumulatedHeightBeforeLineNumber(lineNumber);
return previousLinesHeight + previousWhitespacesHeight; return previousLinesHeight + previousWhitespacesHeight + this._paddingTop;
} }
/** /**
@@ -719,7 +732,7 @@ export class LinesLayout {
} else { } else {
previousWhitespacesHeight = 0; previousWhitespacesHeight = 0;
} }
return previousLinesHeight + previousWhitespacesHeight; return previousLinesHeight + previousWhitespacesHeight + this._paddingTop;
} }
public getWhitespaceIndexAtOrAfterVerticallOffset(verticalOffset: number): number { public getWhitespaceIndexAtOrAfterVerticallOffset(verticalOffset: number): number {

View File

@@ -161,8 +161,9 @@ export class ViewLayout extends Disposable implements IViewLayout {
this._configuration = configuration; this._configuration = configuration;
const options = this._configuration.options; const options = this._configuration.options;
const layoutInfo = options.get(EditorOption.layoutInfo); const layoutInfo = options.get(EditorOption.layoutInfo);
const padding = options.get(EditorOption.padding);
this._linesLayout = new LinesLayout(lineCount, options.get(EditorOption.lineHeight)); this._linesLayout = new LinesLayout(lineCount, options.get(EditorOption.lineHeight), padding.top, padding.bottom);
this._scrollable = this._register(new EditorScrollable(0, scheduleAtNextAnimationFrame)); this._scrollable = this._register(new EditorScrollable(0, scheduleAtNextAnimationFrame));
this._configureSmoothScrollDuration(); this._configureSmoothScrollDuration();
@@ -202,6 +203,10 @@ export class ViewLayout extends Disposable implements IViewLayout {
if (e.hasChanged(EditorOption.lineHeight)) { if (e.hasChanged(EditorOption.lineHeight)) {
this._linesLayout.setLineHeight(options.get(EditorOption.lineHeight)); this._linesLayout.setLineHeight(options.get(EditorOption.lineHeight));
} }
if (e.hasChanged(EditorOption.padding)) {
const padding = options.get(EditorOption.padding);
this._linesLayout.setPadding(padding.top, padding.bottom);
}
if (e.hasChanged(EditorOption.layoutInfo)) { if (e.hasChanged(EditorOption.layoutInfo)) {
const layoutInfo = options.get(EditorOption.layoutInfo); const layoutInfo = options.get(EditorOption.layoutInfo);
const width = layoutInfo.contentWidth; const width = layoutInfo.contentWidth;

View File

@@ -68,7 +68,8 @@ export class RenderLineInput {
public readonly tabSize: number; public readonly tabSize: number;
public readonly startVisibleColumn: number; public readonly startVisibleColumn: number;
public readonly spaceWidth: number; public readonly spaceWidth: number;
public readonly middotWidth: number; public readonly renderSpaceWidth: number;
public readonly renderSpaceCharCode: number;
public readonly stopRenderingLineAfter: number; public readonly stopRenderingLineAfter: number;
public readonly renderWhitespace: RenderWhitespace; public readonly renderWhitespace: RenderWhitespace;
public readonly renderControlCharacters: boolean; public readonly renderControlCharacters: boolean;
@@ -94,6 +95,7 @@ export class RenderLineInput {
startVisibleColumn: number, startVisibleColumn: number,
spaceWidth: number, spaceWidth: number,
middotWidth: number, middotWidth: number,
wsmiddotWidth: number,
stopRenderingLineAfter: number, stopRenderingLineAfter: number,
renderWhitespace: 'none' | 'boundary' | 'selection' | 'all', renderWhitespace: 'none' | 'boundary' | 'selection' | 'all',
renderControlCharacters: boolean, renderControlCharacters: boolean,
@@ -112,7 +114,6 @@ export class RenderLineInput {
this.tabSize = tabSize; this.tabSize = tabSize;
this.startVisibleColumn = startVisibleColumn; this.startVisibleColumn = startVisibleColumn;
this.spaceWidth = spaceWidth; this.spaceWidth = spaceWidth;
this.middotWidth = middotWidth;
this.stopRenderingLineAfter = stopRenderingLineAfter; this.stopRenderingLineAfter = stopRenderingLineAfter;
this.renderWhitespace = ( this.renderWhitespace = (
renderWhitespace === 'all' renderWhitespace === 'all'
@@ -126,6 +127,16 @@ export class RenderLineInput {
this.renderControlCharacters = renderControlCharacters; this.renderControlCharacters = renderControlCharacters;
this.fontLigatures = fontLigatures; this.fontLigatures = fontLigatures;
this.selectionsOnLine = selectionsOnLine && selectionsOnLine.sort((a, b) => a.startOffset < b.startOffset ? -1 : 1); this.selectionsOnLine = selectionsOnLine && selectionsOnLine.sort((a, b) => a.startOffset < b.startOffset ? -1 : 1);
const wsmiddotDiff = Math.abs(wsmiddotWidth - spaceWidth);
const middotDiff = Math.abs(middotWidth - spaceWidth);
if (wsmiddotDiff < middotDiff) {
this.renderSpaceWidth = wsmiddotWidth;
this.renderSpaceCharCode = 0x2E31; // U+2E31 - WORD SEPARATOR MIDDLE DOT
} else {
this.renderSpaceWidth = middotWidth;
this.renderSpaceCharCode = 0xB7; // U+00B7 - MIDDLE DOT
}
} }
private sameSelection(otherSelections: LineRange[] | null): boolean { private sameSelection(otherSelections: LineRange[] | null): boolean {
@@ -162,6 +173,8 @@ export class RenderLineInput {
&& this.tabSize === other.tabSize && this.tabSize === other.tabSize
&& this.startVisibleColumn === other.startVisibleColumn && this.startVisibleColumn === other.startVisibleColumn
&& this.spaceWidth === other.spaceWidth && this.spaceWidth === other.spaceWidth
&& this.renderSpaceWidth === other.renderSpaceWidth
&& this.renderSpaceCharCode === other.renderSpaceCharCode
&& this.stopRenderingLineAfter === other.stopRenderingLineAfter && this.stopRenderingLineAfter === other.stopRenderingLineAfter
&& this.renderWhitespace === other.renderWhitespace && this.renderWhitespace === other.renderWhitespace
&& this.renderControlCharacters === other.renderControlCharacters && this.renderControlCharacters === other.renderControlCharacters
@@ -383,7 +396,7 @@ class ResolvedRenderLineInput {
public readonly startVisibleColumn: number, public readonly startVisibleColumn: number,
public readonly containsRTL: boolean, public readonly containsRTL: boolean,
public readonly spaceWidth: number, public readonly spaceWidth: number,
public readonly middotWidth: number, public readonly renderSpaceCharCode: number,
public readonly renderWhitespace: RenderWhitespace, public readonly renderWhitespace: RenderWhitespace,
public readonly renderControlCharacters: boolean, public readonly renderControlCharacters: boolean,
) { ) {
@@ -392,7 +405,6 @@ class ResolvedRenderLineInput {
} }
function resolveRenderLineInput(input: RenderLineInput): ResolvedRenderLineInput { function resolveRenderLineInput(input: RenderLineInput): ResolvedRenderLineInput {
const useMonospaceOptimizations = input.useMonospaceOptimizations;
const lineContent = input.lineContent; const lineContent = input.lineContent;
let isOverflowing: boolean; let isOverflowing: boolean;
@@ -408,7 +420,7 @@ function resolveRenderLineInput(input: RenderLineInput): ResolvedRenderLineInput
let tokens = transformAndRemoveOverflowing(input.lineTokens, input.fauxIndentLength, len); let tokens = transformAndRemoveOverflowing(input.lineTokens, input.fauxIndentLength, len);
if (input.renderWhitespace === RenderWhitespace.All || input.renderWhitespace === RenderWhitespace.Boundary || (input.renderWhitespace === RenderWhitespace.Selection && !!input.selectionsOnLine)) { if (input.renderWhitespace === RenderWhitespace.All || input.renderWhitespace === RenderWhitespace.Boundary || (input.renderWhitespace === RenderWhitespace.Selection && !!input.selectionsOnLine)) {
tokens = _applyRenderWhitespace(lineContent, len, input.continuesWithWrappedLine, tokens, input.fauxIndentLength, input.tabSize, input.startVisibleColumn, useMonospaceOptimizations, input.selectionsOnLine, input.renderWhitespace === RenderWhitespace.Boundary); tokens = _applyRenderWhitespace(input, lineContent, len, tokens);
} }
let containsForeignElements = ForeignElementType.None; let containsForeignElements = ForeignElementType.None;
if (input.lineDecorations.length > 0) { if (input.lineDecorations.length > 0) {
@@ -431,7 +443,7 @@ function resolveRenderLineInput(input: RenderLineInput): ResolvedRenderLineInput
} }
return new ResolvedRenderLineInput( return new ResolvedRenderLineInput(
useMonospaceOptimizations, input.useMonospaceOptimizations,
input.canUseHalfwidthRightwardsArrow, input.canUseHalfwidthRightwardsArrow,
lineContent, lineContent,
len, len,
@@ -443,7 +455,7 @@ function resolveRenderLineInput(input: RenderLineInput): ResolvedRenderLineInput
input.startVisibleColumn, input.startVisibleColumn,
input.containsRTL, input.containsRTL,
input.spaceWidth, input.spaceWidth,
input.middotWidth, input.renderSpaceCharCode,
input.renderWhitespace, input.renderWhitespace,
input.renderControlCharacters input.renderControlCharacters
); );
@@ -553,7 +565,16 @@ function splitLargeTokens(lineContent: string, tokens: LinePart[], onlyAtSpaces:
* Moreover, a token is created for every visual indent because on some fonts the glyphs used for rendering whitespace (&rarr; or &middot;) do not have the same width as &nbsp;. * Moreover, a token is created for every visual indent because on some fonts the glyphs used for rendering whitespace (&rarr; or &middot;) do not have the same width as &nbsp;.
* The rendering phase will generate `style="width:..."` for these tokens. * The rendering phase will generate `style="width:..."` for these tokens.
*/ */
function _applyRenderWhitespace(lineContent: string, len: number, continuesWithWrappedLine: boolean, tokens: LinePart[], fauxIndentLength: number, tabSize: number, startVisibleColumn: number, useMonospaceOptimizations: boolean, selections: LineRange[] | null, onlyBoundary: boolean): LinePart[] { function _applyRenderWhitespace(input: RenderLineInput, lineContent: string, len: number, tokens: LinePart[]): LinePart[] {
const continuesWithWrappedLine = input.continuesWithWrappedLine;
const fauxIndentLength = input.fauxIndentLength;
const tabSize = input.tabSize;
const startVisibleColumn = input.startVisibleColumn;
const useMonospaceOptimizations = input.useMonospaceOptimizations;
const selections = input.selectionsOnLine;
const onlyBoundary = (input.renderWhitespace === RenderWhitespace.Boundary);
const generateLinePartForEachWhitespace = (input.renderSpaceWidth !== input.spaceWidth);
let result: LinePart[] = [], resultLen = 0; let result: LinePart[] = [], resultLen = 0;
let tokenIndex = 0; let tokenIndex = 0;
@@ -616,7 +637,14 @@ function _applyRenderWhitespace(lineContent: string, len: number, continuesWithW
// was in whitespace token // was in whitespace token
if (!isInWhitespace || (!useMonospaceOptimizations && tmpIndent >= tabSize)) { if (!isInWhitespace || (!useMonospaceOptimizations && tmpIndent >= tabSize)) {
// leaving whitespace token or entering a new indent // leaving whitespace token or entering a new indent
result[resultLen++] = new LinePart(charIndex, 'mtkw'); if (generateLinePartForEachWhitespace) {
const lastEndIndex = (resultLen > 0 ? result[resultLen - 1].endIndex : fauxIndentLength);
for (let i = lastEndIndex + 1; i <= charIndex; i++) {
result[resultLen++] = new LinePart(i, 'mtkw');
}
} else {
result[resultLen++] = new LinePart(charIndex, 'mtkw');
}
tmpIndent = tmpIndent % tabSize; tmpIndent = tmpIndent % tabSize;
} }
} else { } else {
@@ -661,7 +689,18 @@ function _applyRenderWhitespace(lineContent: string, len: number, continuesWithW
} }
} }
result[resultLen++] = new LinePart(len, generateWhitespace ? 'mtkw' : tokenType); if (generateWhitespace) {
if (generateLinePartForEachWhitespace) {
const lastEndIndex = (resultLen > 0 ? result[resultLen - 1].endIndex : fauxIndentLength);
for (let i = lastEndIndex + 1; i <= len; i++) {
result[resultLen++] = new LinePart(i, 'mtkw');
}
} else {
result[resultLen++] = new LinePart(len, 'mtkw');
}
} else {
result[resultLen++] = new LinePart(len, tokenType);
}
return result; return result;
} }
@@ -739,13 +778,10 @@ function _renderLine(input: ResolvedRenderLineInput, sb: IStringBuilder): Render
const startVisibleColumn = input.startVisibleColumn; const startVisibleColumn = input.startVisibleColumn;
const containsRTL = input.containsRTL; const containsRTL = input.containsRTL;
const spaceWidth = input.spaceWidth; const spaceWidth = input.spaceWidth;
const middotWidth = input.middotWidth; const renderSpaceCharCode = input.renderSpaceCharCode;
const renderWhitespace = input.renderWhitespace; const renderWhitespace = input.renderWhitespace;
const renderControlCharacters = input.renderControlCharacters; const renderControlCharacters = input.renderControlCharacters;
// use U+2E31 - WORD SEPARATOR MIDDLE DOT or U+00B7 - MIDDLE DOT
const spaceRenderWhitespaceCharacter = (middotWidth > spaceWidth ? 0x2E31 : 0xB7);
const characterMapping = new CharacterMapping(len + 1, parts.length); const characterMapping = new CharacterMapping(len + 1, parts.length);
let charIndex = 0; let charIndex = 0;
@@ -815,7 +851,7 @@ function _renderLine(input: ResolvedRenderLineInput, sb: IStringBuilder): Render
} else { // must be CharCode.Space } else { // must be CharCode.Space
charWidth = 1; charWidth = 1;
sb.write1(spaceRenderWhitespaceCharacter); // &middot; or word separator middle dot sb.write1(renderSpaceCharCode); // &middot; or word separator middle dot
} }
charOffsetInPart += charWidth; charOffsetInPart += charWidth;

View File

@@ -611,7 +611,14 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
return; return;
} else { } else {
const scrollAdjustment = this._getHeight(); let scrollAdjustment = this._getHeight();
// if the editor has top padding, factor that into the zone height
scrollAdjustment -= this._codeEditor.getOption(EditorOption.padding).top;
if (scrollAdjustment <= 0) {
return;
}
viewZone.heightInPx = scrollAdjustment; viewZone.heightInPx = scrollAdjustment;
this._viewZoneId = accessor.addZone(viewZone); this._viewZoneId = accessor.addZone(viewZone);

View File

@@ -304,7 +304,7 @@ export class MarkerController implements IEditorContribution {
model.currentMarker = marker; model.currentMarker = marker;
} }
private _onMarkerChanged(changedResources: URI[]): void { private _onMarkerChanged(changedResources: readonly URI[]): void {
const editorModel = this._editor.getModel(); const editorModel = this._editor.getModel();
if (!editorModel) { if (!editorModel) {
return; return;

View File

@@ -134,10 +134,10 @@ class MessageWidget {
detailsElement.appendChild(codeElement); detailsElement.appendChild(codeElement);
} else { } else {
this._codeLink = dom.$('a.code-link'); this._codeLink = dom.$('a.code-link');
this._codeLink.setAttribute('href', `${code.link.toString()}`); this._codeLink.setAttribute('href', `${code.target.toString()}`);
this._codeLink.onclick = (e) => { this._codeLink.onclick = (e) => {
this._openerService.open(code.link); this._openerService.open(code.target);
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
}; };

View File

@@ -516,10 +516,10 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
sourceElement.innerText = source; sourceElement.innerText = source;
} }
this._codeLink = dom.append(sourceAndCodeElement, $('a.code-link')); this._codeLink = dom.append(sourceAndCodeElement, $('a.code-link'));
this._codeLink.setAttribute('href', code.link.toString()); this._codeLink.setAttribute('href', code.target.toString());
this._codeLink.onclick = (e) => { this._codeLink.onclick = (e) => {
this._openerService.open(code.link); this._openerService.open(code.target);
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
}; };

View File

@@ -468,6 +468,7 @@ export class SnippetSession {
// that ensures the primiary cursor stays primary despite not being // that ensures the primiary cursor stays primary despite not being
// the one with lowest start position // the one with lowest start position
edits[idx] = EditOperation.replace(snippetSelection, snippet.toString()); edits[idx] = EditOperation.replace(snippetSelection, snippet.toString());
edits[idx].identifier = { major: idx, minor: 0 }; // mark the edit so only our undo edits will be used to generate end cursors
snippets[idx] = new OneSnippet(editor, snippet, offset); snippets[idx] = new OneSnippet(editor, snippet, offset);
} }
@@ -507,7 +508,11 @@ export class SnippetSession {
if (this._snippets[0].hasPlaceholder) { if (this._snippets[0].hasPlaceholder) {
return this._move(true); return this._move(true);
} else { } else {
return undoEdits.map(edit => Selection.fromPositions(edit.range.getEndPosition())); return (
undoEdits
.filter(edit => !!edit.identifier) // only use our undo edits
.map(edit => Selection.fromPositions(edit.range.getEndPosition()))
);
} }
}); });
this._editor.revealRange(this._editor.getSelections()[0]); this._editor.revealRange(this._editor.getSelections()[0]);
@@ -529,7 +534,11 @@ export class SnippetSession {
if (this._snippets[0].hasPlaceholder) { if (this._snippets[0].hasPlaceholder) {
return this._move(undefined); return this._move(undefined);
} else { } else {
return undoEdits.map(edit => Selection.fromPositions(edit.range.getEndPosition())); return (
undoEdits
.filter(edit => !!edit.identifier) // only use our undo edits
.map(edit => Selection.fromPositions(edit.range.getEndPosition()))
);
} }
}); });
} }

View File

@@ -11,6 +11,7 @@ import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKe
import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { NullLogService } from 'vs/platform/log/common/log'; import { NullLogService } from 'vs/platform/log/common/log';
import { Handler } from 'vs/editor/common/editorCommon'; import { Handler } from 'vs/editor/common/editorCommon';
import { CoreEditingCommands } from 'vs/editor/browser/controller/coreCommands';
suite('SnippetController2', function () { suite('SnippetController2', function () {
@@ -428,4 +429,13 @@ suite('SnippetController2', function () {
assertSelections(editor, new Selection(2, 5, 2, 5)); assertSelections(editor, new Selection(2, 5, 2, 5));
assertContextKeys(contextKeys, false, false, false); assertContextKeys(contextKeys, false, false, false);
}); });
test('issue #90135: confusing trim whitespace edits', function () {
const ctrl = new SnippetController2(editor, logService, contextKeys);
model.setValue('');
CoreEditingCommands.Tab.runEditorCommand(null, editor, null);
ctrl.insert('\nfoo');
assertSelections(editor, new Selection(2, 8, 2, 8));
});
}); });

View File

@@ -127,6 +127,7 @@ export class Colorizer {
0, 0,
0, 0,
0, 0,
0,
-1, -1,
'none', 'none',
false, false,
@@ -197,6 +198,7 @@ function _fakeColorize(lines: string[], tabSize: number): string {
0, 0,
0, 0,
0, 0,
0,
-1, -1,
'none', 'none',
false, false,
@@ -236,6 +238,7 @@ function _actualColorize(lines: string[], tabSize: number, tokenizationSupport:
0, 0,
0, 0,
0, 0,
0,
-1, -1,
'none', 'none',
false, false,

View File

@@ -84,6 +84,10 @@ export class SimpleModel implements IResolvedTextEditorModel {
public isResolved(): boolean { public isResolved(): boolean {
return true; return true;
} }
public getMode(): string | undefined {
return this.model.getModeId();
}
} }
export interface IOpenEditorDelegate { export interface IOpenEditorDelegate {

View File

@@ -90,7 +90,7 @@ export interface IGlobalEditorOptions {
tabSize?: number; tabSize?: number;
/** /**
* Insert spaces when pressing `Tab`. * Insert spaces when pressing `Tab`.
* This setting is overridden based on the file contents when detectIndentation` is on. * This setting is overridden based on the file contents when `detectIndentation` is on.
* Defaults to true. * Defaults to true.
*/ */
insertSpaces?: boolean; insertSpaces?: boolean;

View File

@@ -501,7 +501,7 @@ export class MonarchTokenizer implements modes.ITokenizationSupport {
} }
let result = line.search(regex); let result = line.search(regex);
if (result === -1) { if (result === -1 || (result !== 0 && rule.matchOnlyAtLineStart)) {
continue; continue;
} }

View File

@@ -123,7 +123,7 @@ suite('TextAreaState', () => {
textArea.dispose(); textArea.dispose();
}); });
function testDeduceInput(prevState: TextAreaState | null, value: string, selectionStart: number, selectionEnd: number, couldBeEmojiInput: boolean, couldBeTypingAtOffset0: boolean, expected: string, expectedCharReplaceCnt: number): void { function testDeduceInput(prevState: TextAreaState | null, value: string, selectionStart: number, selectionEnd: number, couldBeEmojiInput: boolean, expected: string, expectedCharReplaceCnt: number): void {
prevState = prevState || TextAreaState.EMPTY; prevState = prevState || TextAreaState.EMPTY;
let textArea = new MockTextAreaWrapper(); let textArea = new MockTextAreaWrapper();
@@ -132,7 +132,7 @@ suite('TextAreaState', () => {
textArea._selectionEnd = selectionEnd; textArea._selectionEnd = selectionEnd;
let newState = TextAreaState.readFromTextArea(textArea); let newState = TextAreaState.readFromTextArea(textArea);
let actual = TextAreaState.deduceInput(prevState, newState, couldBeEmojiInput, couldBeTypingAtOffset0); let actual = TextAreaState.deduceInput(prevState, newState, couldBeEmojiInput);
assert.equal(actual.text, expected); assert.equal(actual.text, expected);
assert.equal(actual.replaceCharCnt, expectedCharReplaceCnt); assert.equal(actual.replaceCharCnt, expectedCharReplaceCnt);
@@ -153,7 +153,7 @@ suite('TextAreaState', () => {
testDeduceInput( testDeduceInput(
TextAreaState.EMPTY, TextAreaState.EMPTY,
'', '',
0, 1, true, false, 0, 1, true,
'', 0 '', 0
); );
@@ -163,7 +163,7 @@ suite('TextAreaState', () => {
testDeduceInput( testDeduceInput(
new TextAreaState('', 0, 1, null, null), new TextAreaState('', 0, 1, null, null),
'せ', 'せ',
0, 1, true, false, 0, 1, true,
'せ', 1 'せ', 1
); );
@@ -173,7 +173,7 @@ suite('TextAreaState', () => {
testDeduceInput( testDeduceInput(
new TextAreaState('せ', 0, 1, null, null), new TextAreaState('せ', 0, 1, null, null),
'せn', 'せn',
0, 2, true, false, 0, 2, true,
'せn', 1 'せn', 1
); );
@@ -183,7 +183,7 @@ suite('TextAreaState', () => {
testDeduceInput( testDeduceInput(
new TextAreaState('せn', 0, 2, null, null), new TextAreaState('せn', 0, 2, null, null),
'せん', 'せん',
0, 2, true, false, 0, 2, true,
'せん', 2 'せん', 2
); );
@@ -193,7 +193,7 @@ suite('TextAreaState', () => {
testDeduceInput( testDeduceInput(
new TextAreaState('せん', 0, 2, null, null), new TextAreaState('せん', 0, 2, null, null),
'せんs', 'せんs',
0, 3, true, false, 0, 3, true,
'せんs', 2 'せんs', 2
); );
@@ -203,7 +203,7 @@ suite('TextAreaState', () => {
testDeduceInput( testDeduceInput(
new TextAreaState('せんs', 0, 3, null, null), new TextAreaState('せんs', 0, 3, null, null),
'せんせ', 'せんせ',
0, 3, true, false, 0, 3, true,
'せんせ', 3 'せんせ', 3
); );
@@ -213,7 +213,7 @@ suite('TextAreaState', () => {
testDeduceInput( testDeduceInput(
new TextAreaState('せんせ', 0, 3, null, null), new TextAreaState('せんせ', 0, 3, null, null),
'せんせ', 'せんせ',
0, 3, true, false, 0, 3, true,
'せんせ', 3 'せんせ', 3
); );
@@ -223,7 +223,7 @@ suite('TextAreaState', () => {
testDeduceInput( testDeduceInput(
new TextAreaState('せんせ', 0, 3, null, null), new TextAreaState('せんせ', 0, 3, null, null),
'せんせい', 'せんせい',
0, 4, true, false, 0, 4, true,
'せんせい', 3 'せんせい', 3
); );
@@ -233,7 +233,7 @@ suite('TextAreaState', () => {
testDeduceInput( testDeduceInput(
new TextAreaState('せんせい', 0, 4, null, null), new TextAreaState('せんせい', 0, 4, null, null),
'せんせい', 'せんせい',
4, 4, true, false, 4, 4, true,
'', 0 '', 0
); );
}); });
@@ -252,7 +252,7 @@ suite('TextAreaState', () => {
testDeduceInput( testDeduceInput(
new TextAreaState('せんせい', 0, 4, null, null), new TextAreaState('せんせい', 0, 4, null, null),
'せんせい', 'せんせい',
0, 4, true, false, 0, 4, true,
'せんせい', 4 'せんせい', 4
); );
@@ -262,7 +262,7 @@ suite('TextAreaState', () => {
testDeduceInput( testDeduceInput(
new TextAreaState('せんせい', 0, 4, null, null), new TextAreaState('せんせい', 0, 4, null, null),
'先生', '先生',
0, 2, true, false, 0, 2, true,
'先生', 4 '先生', 4
); );
@@ -272,7 +272,7 @@ suite('TextAreaState', () => {
testDeduceInput( testDeduceInput(
new TextAreaState('先生', 0, 2, null, null), new TextAreaState('先生', 0, 2, null, null),
'先生', '先生',
2, 2, true, false, 2, 2, true,
'', 0 '', 0
); );
}); });
@@ -281,7 +281,7 @@ suite('TextAreaState', () => {
testDeduceInput( testDeduceInput(
null, null,
'a', 'a',
0, 1, true, false, 0, 1, true,
'a', 0 'a', 0
); );
}); });
@@ -290,7 +290,7 @@ suite('TextAreaState', () => {
testDeduceInput( testDeduceInput(
new TextAreaState(']\n', 1, 2, null, null), new TextAreaState(']\n', 1, 2, null, null),
']\n', ']\n',
2, 2, true, false, 2, 2, true,
'\n', 0 '\n', 0
); );
}); });
@@ -299,7 +299,7 @@ suite('TextAreaState', () => {
testDeduceInput( testDeduceInput(
null, null,
'a', 'a',
1, 1, true, false, 1, 1, true,
'a', 0 'a', 0
); );
}); });
@@ -308,7 +308,7 @@ suite('TextAreaState', () => {
testDeduceInput( testDeduceInput(
TextAreaState.EMPTY, TextAreaState.EMPTY,
'a', 'a',
0, 1, true, false, 0, 1, true,
'a', 0 'a', 0
); );
}); });
@@ -317,7 +317,7 @@ suite('TextAreaState', () => {
testDeduceInput( testDeduceInput(
TextAreaState.EMPTY, TextAreaState.EMPTY,
'a', 'a',
1, 1, true, false, 1, 1, true,
'a', 0 'a', 0
); );
}); });
@@ -326,7 +326,7 @@ suite('TextAreaState', () => {
testDeduceInput( testDeduceInput(
new TextAreaState('Hello world!', 0, 12, null, null), new TextAreaState('Hello world!', 0, 12, null, null),
'H', 'H',
1, 1, true, false, 1, 1, true,
'H', 0 'H', 0
); );
}); });
@@ -335,7 +335,7 @@ suite('TextAreaState', () => {
testDeduceInput( testDeduceInput(
new TextAreaState('Hello world!', 12, 12, null, null), new TextAreaState('Hello world!', 12, 12, null, null),
'Hello world!a', 'Hello world!a',
13, 13, true, false, 13, 13, true,
'a', 0 'a', 0
); );
}); });
@@ -344,7 +344,7 @@ suite('TextAreaState', () => {
testDeduceInput( testDeduceInput(
new TextAreaState('Hello world!', 0, 0, null, null), new TextAreaState('Hello world!', 0, 0, null, null),
'aHello world!', 'aHello world!',
1, 1, true, false, 1, 1, true,
'a', 0 'a', 0
); );
}); });
@@ -353,7 +353,7 @@ suite('TextAreaState', () => {
testDeduceInput( testDeduceInput(
new TextAreaState('Hello world!', 6, 11, null, null), new TextAreaState('Hello world!', 6, 11, null, null),
'Hello other!', 'Hello other!',
11, 11, true, false, 11, 11, true,
'other', 0 'other', 0
); );
}); });
@@ -362,7 +362,7 @@ suite('TextAreaState', () => {
testDeduceInput( testDeduceInput(
TextAreaState.EMPTY, TextAreaState.EMPTY,
'これは', 'これは',
3, 3, true, false, 3, 3, true,
'これは', 0 'これは', 0
); );
}); });
@@ -371,7 +371,7 @@ suite('TextAreaState', () => {
testDeduceInput( testDeduceInput(
new TextAreaState('Hello world!', 0, 0, null, null), new TextAreaState('Hello world!', 0, 0, null, null),
'Aello world!', 'Aello world!',
1, 1, true, false, 1, 1, true,
'A', 0 'A', 0
); );
}); });
@@ -380,7 +380,7 @@ suite('TextAreaState', () => {
testDeduceInput( testDeduceInput(
new TextAreaState('Hello world!', 5, 5, null, null), new TextAreaState('Hello world!', 5, 5, null, null),
'Hellö world!', 'Hellö world!',
4, 5, true, false, 4, 5, true,
'ö', 0 'ö', 0
); );
}); });
@@ -389,7 +389,7 @@ suite('TextAreaState', () => {
testDeduceInput( testDeduceInput(
new TextAreaState('Hello world!', 5, 5, null, null), new TextAreaState('Hello world!', 5, 5, null, null),
'Hellöö world!', 'Hellöö world!',
5, 5, true, false, 5, 5, true,
'öö', 1 'öö', 1
); );
}); });
@@ -398,7 +398,7 @@ suite('TextAreaState', () => {
testDeduceInput( testDeduceInput(
new TextAreaState('Hello world!', 5, 5, null, null), new TextAreaState('Hello world!', 5, 5, null, null),
'Helöö world!', 'Helöö world!',
5, 5, true, false, 5, 5, true,
'öö', 2 'öö', 2
); );
}); });
@@ -407,7 +407,7 @@ suite('TextAreaState', () => {
testDeduceInput( testDeduceInput(
new TextAreaState('Hello world!', 5, 5, null, null), new TextAreaState('Hello world!', 5, 5, null, null),
'Hellö world!', 'Hellö world!',
5, 5, true, false, 5, 5, true,
'ö', 1 'ö', 1
); );
}); });
@@ -416,7 +416,7 @@ suite('TextAreaState', () => {
testDeduceInput( testDeduceInput(
new TextAreaState('a', 0, 1, null, null), new TextAreaState('a', 0, 1, null, null),
'a', 'a',
1, 1, true, false, 1, 1, true,
'a', 0 'a', 0
); );
}); });
@@ -425,7 +425,7 @@ suite('TextAreaState', () => {
testDeduceInput( testDeduceInput(
new TextAreaState('x x', 0, 1, null, null), new TextAreaState('x x', 0, 1, null, null),
'x x', 'x x',
1, 1, true, false, 1, 1, true,
'x', 0 'x', 0
); );
}); });
@@ -455,7 +455,7 @@ suite('TextAreaState', () => {
'some6 text', 'some6 text',
'some7 text' 'some7 text'
].join('\n'), ].join('\n'),
4, 4, true, false, 4, 4, true,
'📅', 0 '📅', 0
); );
}); });
@@ -469,7 +469,7 @@ suite('TextAreaState', () => {
null, null null, null
), ),
'some💊1 text', 'some💊1 text',
6, 6, true, false, 6, 6, true,
'💊', 0 '💊', 0
); );
}); });
@@ -483,7 +483,7 @@ suite('TextAreaState', () => {
null, null null, null
), ),
'qwertyu\nasdfghj\nzxcvbnm🎈', 'qwertyu\nasdfghj\nzxcvbnm🎈',
25, 25, true, false, 25, 25, true,
'🎈', 0 '🎈', 0
); );
}); });
@@ -498,39 +498,11 @@ suite('TextAreaState', () => {
null, null null, null
), ),
'some⌨1 text', 'some⌨1 text',
6, 6, true, false, 6, 6, true,
'⌨️', 0 '⌨️', 0
); );
}); });
test('issue #42251: Minor issue, character swapped when typing', () => {
// Typing on OSX occurs at offset 0 after moving the window using the custom (non-native) titlebar.
testDeduceInput(
new TextAreaState(
'ab',
2, 2,
null, null
),
'cab',
1, 1, true, true,
'c', 0
);
});
test('issue #49480: Double curly braces inserted', () => {
// Characters get doubled
testDeduceInput(
new TextAreaState(
'aa',
2, 2,
null, null
),
'aaa',
3, 3, true, true,
'a', 0
);
});
suite('PagedScreenReaderStrategy', () => { suite('PagedScreenReaderStrategy', () => {
function testPagedScreenReaderStrategy(lines: string[], selection: Selection, expected: TextAreaState): void { function testPagedScreenReaderStrategy(lines: string[], selection: Selection, expected: TextAreaState): void {

View File

@@ -42,6 +42,7 @@ export class TestConfiguration extends CommonEditorConfiguration {
canUseHalfwidthRightwardsArrow: true, canUseHalfwidthRightwardsArrow: true,
spaceWidth: 10, spaceWidth: 10,
middotWidth: 10, middotWidth: 10,
wsmiddotWidth: 10,
maxDigitWidth: 10, maxDigitWidth: 10,
}, true); }, true);
} }

View File

@@ -28,7 +28,7 @@ suite('Editor ViewLayout - LinesLayout', () => {
test('LinesLayout 1', () => { test('LinesLayout 1', () => {
// Start off with 10 lines // Start off with 10 lines
let linesLayout = new LinesLayout(10, 10); let linesLayout = new LinesLayout(10, 10, 0, 0);
// lines: [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] // lines: [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
// whitespace: - // whitespace: -
@@ -137,7 +137,7 @@ suite('Editor ViewLayout - LinesLayout', () => {
test('LinesLayout 2', () => { test('LinesLayout 2', () => {
// Start off with 10 lines and one whitespace after line 2, of height 5 // Start off with 10 lines and one whitespace after line 2, of height 5
let linesLayout = new LinesLayout(10, 1); let linesLayout = new LinesLayout(10, 1, 0, 0);
let a = insertWhitespace(linesLayout, 2, 0, 5, 0); let a = insertWhitespace(linesLayout, 2, 0, 5, 0);
// 10 lines // 10 lines
@@ -232,8 +232,103 @@ suite('Editor ViewLayout - LinesLayout', () => {
assert.equal(linesLayout.getVerticalOffsetForLineNumber(10), 9); assert.equal(linesLayout.getVerticalOffsetForLineNumber(10), 9);
}); });
test('LinesLayout Padding', () => {
// Start off with 10 lines
let linesLayout = new LinesLayout(10, 10, 15, 20);
// lines: [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
// whitespace: -
assert.equal(linesLayout.getLinesTotalHeight(), 135);
assert.equal(linesLayout.getVerticalOffsetForLineNumber(1), 15);
assert.equal(linesLayout.getVerticalOffsetForLineNumber(2), 25);
assert.equal(linesLayout.getVerticalOffsetForLineNumber(3), 35);
assert.equal(linesLayout.getVerticalOffsetForLineNumber(4), 45);
assert.equal(linesLayout.getVerticalOffsetForLineNumber(5), 55);
assert.equal(linesLayout.getVerticalOffsetForLineNumber(6), 65);
assert.equal(linesLayout.getVerticalOffsetForLineNumber(7), 75);
assert.equal(linesLayout.getVerticalOffsetForLineNumber(8), 85);
assert.equal(linesLayout.getVerticalOffsetForLineNumber(9), 95);
assert.equal(linesLayout.getVerticalOffsetForLineNumber(10), 105);
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(0), 1);
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(10), 1);
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(15), 1);
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(24), 1);
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(25), 2);
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(34), 2);
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(35), 3);
// Add whitespace of height 5px after 2nd line
insertWhitespace(linesLayout, 2, 0, 5, 0);
// lines: [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
// whitespace: a(2,5)
assert.equal(linesLayout.getLinesTotalHeight(), 140);
assert.equal(linesLayout.getVerticalOffsetForLineNumber(1), 15);
assert.equal(linesLayout.getVerticalOffsetForLineNumber(2), 25);
assert.equal(linesLayout.getVerticalOffsetForLineNumber(3), 40);
assert.equal(linesLayout.getVerticalOffsetForLineNumber(4), 50);
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(0), 1);
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(10), 1);
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(25), 2);
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(34), 2);
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(35), 3);
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(39), 3);
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(40), 3);
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(41), 3);
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(49), 3);
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(50), 4);
// Add two more whitespaces of height 5px
insertWhitespace(linesLayout, 3, 0, 5, 0);
insertWhitespace(linesLayout, 4, 0, 5, 0);
// lines: [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
// whitespace: a(2,5), b(3, 5), c(4, 5)
assert.equal(linesLayout.getLinesTotalHeight(), 150);
assert.equal(linesLayout.getVerticalOffsetForLineNumber(1), 15);
assert.equal(linesLayout.getVerticalOffsetForLineNumber(2), 25);
assert.equal(linesLayout.getVerticalOffsetForLineNumber(3), 40);
assert.equal(linesLayout.getVerticalOffsetForLineNumber(4), 55);
assert.equal(linesLayout.getVerticalOffsetForLineNumber(5), 70);
assert.equal(linesLayout.getVerticalOffsetForLineNumber(6), 80);
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(0), 1);
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(15), 1);
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(24), 1);
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(30), 2);
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(35), 3);
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(39), 3);
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(40), 3);
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(49), 3);
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(50), 4);
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(54), 4);
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(55), 4);
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(64), 4);
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(65), 5);
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(69), 5);
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(70), 5);
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(80), 6);
assert.equal(linesLayout.getVerticalOffsetForWhitespaceIndex(0), 35); // 35 -> 40
assert.equal(linesLayout.getVerticalOffsetForWhitespaceIndex(1), 50); // 50 -> 55
assert.equal(linesLayout.getVerticalOffsetForWhitespaceIndex(2), 65);
assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(0), 0);
assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(34), 0);
assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(35), 0);
assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(39), 0);
assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(40), 1);
assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(49), 1);
assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(50), 1);
assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(54), 1);
assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(55), 2);
assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(64), 2);
assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(65), 2);
assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(70), -1);
});
test('LinesLayout getLineNumberAtOrAfterVerticalOffset', () => { test('LinesLayout getLineNumberAtOrAfterVerticalOffset', () => {
let linesLayout = new LinesLayout(10, 1); let linesLayout = new LinesLayout(10, 1, 0, 0);
insertWhitespace(linesLayout, 6, 0, 10, 0); insertWhitespace(linesLayout, 6, 0, 10, 0);
// 10 lines // 10 lines
@@ -282,7 +377,7 @@ suite('Editor ViewLayout - LinesLayout', () => {
}); });
test('LinesLayout getCenteredLineInViewport', () => { test('LinesLayout getCenteredLineInViewport', () => {
let linesLayout = new LinesLayout(10, 1); let linesLayout = new LinesLayout(10, 1, 0, 0);
insertWhitespace(linesLayout, 6, 0, 10, 0); insertWhitespace(linesLayout, 6, 0, 10, 0);
// 10 lines // 10 lines
@@ -365,7 +460,7 @@ suite('Editor ViewLayout - LinesLayout', () => {
}); });
test('LinesLayout getLinesViewportData 1', () => { test('LinesLayout getLinesViewportData 1', () => {
let linesLayout = new LinesLayout(10, 10); let linesLayout = new LinesLayout(10, 10, 0, 0);
insertWhitespace(linesLayout, 6, 0, 100, 0); insertWhitespace(linesLayout, 6, 0, 100, 0);
// 10 lines // 10 lines
@@ -498,7 +593,7 @@ suite('Editor ViewLayout - LinesLayout', () => {
}); });
test('LinesLayout getLinesViewportData 2 & getWhitespaceViewportData', () => { test('LinesLayout getLinesViewportData 2 & getWhitespaceViewportData', () => {
let linesLayout = new LinesLayout(10, 10); let linesLayout = new LinesLayout(10, 10, 0, 0);
let a = insertWhitespace(linesLayout, 6, 0, 100, 0); let a = insertWhitespace(linesLayout, 6, 0, 100, 0);
let b = insertWhitespace(linesLayout, 7, 0, 50, 0); let b = insertWhitespace(linesLayout, 7, 0, 50, 0);
@@ -569,7 +664,7 @@ suite('Editor ViewLayout - LinesLayout', () => {
}); });
test('LinesLayout getWhitespaceAtVerticalOffset', () => { test('LinesLayout getWhitespaceAtVerticalOffset', () => {
let linesLayout = new LinesLayout(10, 10); let linesLayout = new LinesLayout(10, 10, 0, 0);
let a = insertWhitespace(linesLayout, 6, 0, 100, 0); let a = insertWhitespace(linesLayout, 6, 0, 100, 0);
let b = insertWhitespace(linesLayout, 7, 0, 50, 0); let b = insertWhitespace(linesLayout, 7, 0, 50, 0);
@@ -612,7 +707,7 @@ suite('Editor ViewLayout - LinesLayout', () => {
test('LinesLayout', () => { test('LinesLayout', () => {
const linesLayout = new LinesLayout(100, 20); const linesLayout = new LinesLayout(100, 20, 0, 0);
// Insert a whitespace after line number 2, of height 10 // Insert a whitespace after line number 2, of height 10
const a = insertWhitespace(linesLayout, 2, 0, 10, 0); const a = insertWhitespace(linesLayout, 2, 0, 10, 0);
@@ -963,7 +1058,7 @@ suite('Editor ViewLayout - LinesLayout', () => {
}); });
test('LinesLayout changeWhitespaceAfterLineNumber & getFirstWhitespaceIndexAfterLineNumber', () => { test('LinesLayout changeWhitespaceAfterLineNumber & getFirstWhitespaceIndexAfterLineNumber', () => {
const linesLayout = new LinesLayout(100, 20); const linesLayout = new LinesLayout(100, 20, 0, 0);
const a = insertWhitespace(linesLayout, 0, 0, 1, 0); const a = insertWhitespace(linesLayout, 0, 0, 1, 0);
const b = insertWhitespace(linesLayout, 7, 0, 1, 0); const b = insertWhitespace(linesLayout, 7, 0, 1, 0);
@@ -1087,7 +1182,7 @@ suite('Editor ViewLayout - LinesLayout', () => {
}); });
test('LinesLayout Bug', () => { test('LinesLayout Bug', () => {
const linesLayout = new LinesLayout(100, 20); const linesLayout = new LinesLayout(100, 20, 0, 0);
const a = insertWhitespace(linesLayout, 0, 0, 1, 0); const a = insertWhitespace(linesLayout, 0, 0, 1, 0);
const b = insertWhitespace(linesLayout, 7, 0, 1, 0); const b = insertWhitespace(linesLayout, 7, 0, 1, 0);

View File

@@ -40,6 +40,7 @@ suite('viewLineRenderer.renderLine', () => {
0, 0,
0, 0,
0, 0,
0,
-1, -1,
'none', 'none',
false, false,
@@ -92,6 +93,7 @@ suite('viewLineRenderer.renderLine', () => {
0, 0,
0, 0,
0, 0,
0,
-1, -1,
'none', 'none',
false, false,
@@ -147,6 +149,7 @@ suite('viewLineRenderer.renderLine', () => {
0, 0,
10, 10,
10, 10,
10,
6, 6,
'boundary', 'boundary',
false, false,
@@ -241,6 +244,7 @@ suite('viewLineRenderer.renderLine', () => {
0, 0,
10, 10,
10, 10,
10,
-1, -1,
'boundary', 'boundary',
false, false,
@@ -306,6 +310,7 @@ suite('viewLineRenderer.renderLine', () => {
0, 0,
10, 10,
10, 10,
10,
-1, -1,
'none', 'none',
false, false,
@@ -371,6 +376,7 @@ suite('viewLineRenderer.renderLine', () => {
0, 0,
10, 10,
10, 10,
10,
-1, -1,
'none', 'none',
false, false,
@@ -413,6 +419,7 @@ suite('viewLineRenderer.renderLine', () => {
0, 0,
10, 10,
10, 10,
10,
-1, -1,
'none', 'none',
false, false,
@@ -446,6 +453,7 @@ suite('viewLineRenderer.renderLine', () => {
0, 0,
10, 10,
10, 10,
10,
-1, -1,
'none', 'none',
false, false,
@@ -549,6 +557,7 @@ suite('viewLineRenderer.renderLine', () => {
0, 0,
10, 10,
10, 10,
10,
-1, -1,
'none', 'none',
false, false,
@@ -590,6 +599,7 @@ suite('viewLineRenderer.renderLine', () => {
0, 0,
10, 10,
10, 10,
10,
-1, -1,
'none', 'none',
false, false,
@@ -622,6 +632,7 @@ suite('viewLineRenderer.renderLine', () => {
0, 0,
10, 10,
10, 10,
10,
-1, -1,
'none', 'none',
false, false,
@@ -671,6 +682,7 @@ suite('viewLineRenderer.renderLine', () => {
0, 0,
10, 10,
10, 10,
10,
-1, -1,
'none', 'none',
false, false,
@@ -755,6 +767,7 @@ suite('viewLineRenderer.renderLine 2', () => {
0, 0,
10, 10,
10, 10,
10,
-1, -1,
renderWhitespace, renderWhitespace,
false, false,
@@ -783,6 +796,7 @@ suite('viewLineRenderer.renderLine 2', () => {
0, 0,
10, 10,
10, 10,
10,
-1, -1,
'none', 'none',
false, false,
@@ -825,6 +839,7 @@ suite('viewLineRenderer.renderLine 2', () => {
0, 0,
10, 10,
10, 10,
10,
-1, -1,
'none', 'none',
false, false,
@@ -1242,6 +1257,7 @@ suite('viewLineRenderer.renderLine 2', () => {
0, 0,
10, 10,
10, 10,
10,
-1, -1,
'none', 'none',
false, false,
@@ -1285,6 +1301,7 @@ suite('viewLineRenderer.renderLine 2', () => {
0, 0,
10, 10,
10, 10,
10,
-1, -1,
'all', 'all',
false, false,
@@ -1320,6 +1337,7 @@ suite('viewLineRenderer.renderLine 2', () => {
0, 0,
10, 10,
10, 10,
10,
-1, -1,
'all', 'all',
false, false,
@@ -1356,6 +1374,7 @@ suite('viewLineRenderer.renderLine 2', () => {
0, 0,
10, 10,
10, 10,
10,
-1, -1,
'all', 'all',
false, false,
@@ -1388,6 +1407,7 @@ suite('viewLineRenderer.renderLine 2', () => {
0, 0,
10, 10,
10, 10,
10,
10000, 10000,
'none', 'none',
false, false,
@@ -1424,6 +1444,7 @@ suite('viewLineRenderer.renderLine 2', () => {
0, 0,
10, 10,
10, 10,
10,
10000, 10000,
'none', 'none',
false, false,
@@ -1460,6 +1481,7 @@ suite('viewLineRenderer.renderLine 2', () => {
0, 0,
10, 10,
10, 10,
10,
10000, 10000,
'none', 'none',
false, false,
@@ -1493,6 +1515,7 @@ suite('viewLineRenderer.renderLine 2', () => {
0, 0,
10, 10,
10, 10,
10,
10000, 10000,
'none', 'none',
false, false,
@@ -1525,6 +1548,7 @@ suite('viewLineRenderer.renderLine 2', () => {
0, 0,
10, 10,
10, 10,
10,
10000, 10000,
'all', 'all',
false, false,
@@ -1563,6 +1587,7 @@ suite('viewLineRenderer.renderLine 2', () => {
0, 0,
10, 10,
10, 10,
10,
10000, 10000,
'none', 'none',
false, false,
@@ -1595,6 +1620,7 @@ suite('viewLineRenderer.renderLine 2', () => {
0, 0,
10, 10,
10, 10,
10,
10000, 10000,
'none', 'none',
false, false,
@@ -1629,6 +1655,7 @@ suite('viewLineRenderer.renderLine 2', () => {
0, 0,
10, 10,
10, 10,
10,
10000, 10000,
'none', 'none',
false, false,
@@ -1662,6 +1689,7 @@ suite('viewLineRenderer.renderLine 2', () => {
0, 0,
10, 10,
10, 10,
10,
10000, 10000,
'boundary', 'boundary',
false, false,
@@ -1693,6 +1721,7 @@ suite('viewLineRenderer.renderLine 2', () => {
0, 0,
10, 10,
10, 10,
10,
10000, 10000,
'none', 'none',
false, false,
@@ -1728,6 +1757,7 @@ suite('viewLineRenderer.renderLine 2', () => {
0, 0,
10, 10,
10, 10,
10,
10000, 10000,
'none', 'none',
false, false,
@@ -1759,6 +1789,7 @@ suite('viewLineRenderer.renderLine 2', () => {
0, 0,
10, 10,
10, 10,
10,
-1, -1,
'none', 'none',
false, false,

View File

@@ -58,6 +58,7 @@ function getLineBreakData(factory: ILineBreaksComputerFactory, tabSize: number,
canUseHalfwidthRightwardsArrow: true, canUseHalfwidthRightwardsArrow: true,
spaceWidth: 7, spaceWidth: 7,
middotWidth: 7, middotWidth: 7,
wsmiddotWidth: 7,
maxDigitWidth: 7 maxDigitWidth: 7
}, false); }, false);
const lineBreaksComputer = factory.createLineBreaksComputer(fontInfo, tabSize, breakAfter, wrappingIndent); const lineBreaksComputer = factory.createLineBreaksComputer(fontInfo, tabSize, breakAfter, wrappingIndent);

126
src/vs/monaco.d.ts vendored
View File

@@ -1067,7 +1067,7 @@ declare namespace monaco.editor {
tabSize?: number; tabSize?: number;
/** /**
* Insert spaces when pressing `Tab`. * Insert spaces when pressing `Tab`.
* This setting is overridden based on the file contents when detectIndentation` is on. * This setting is overridden based on the file contents when `detectIndentation` is on.
* Defaults to true. * Defaults to true.
*/ */
insertSpaces?: boolean; insertSpaces?: boolean;
@@ -1184,7 +1184,7 @@ declare namespace monaco.editor {
severity: MarkerSeverity; severity: MarkerSeverity;
code?: string | { code?: string | {
value: string; value: string;
link: Uri; target: Uri;
}; };
message: string; message: string;
source?: string; source?: string;
@@ -1202,7 +1202,7 @@ declare namespace monaco.editor {
export interface IMarkerData { export interface IMarkerData {
code?: string | { code?: string | {
value: string; value: string;
link: Uri; target: Uri;
}; };
severity: MarkerSeverity; severity: MarkerSeverity;
message: string; message: string;
@@ -2841,6 +2841,10 @@ declare namespace monaco.editor {
* Defaults to 10 (ms) * Defaults to 10 (ms)
*/ */
quickSuggestionsDelay?: number; quickSuggestionsDelay?: number;
/**
* Controls the spacing around the editor.
*/
padding?: IEditorPaddingOptions;
/** /**
* Parameter hint options. * Parameter hint options.
*/ */
@@ -3395,6 +3399,25 @@ declare namespace monaco.editor {
export type EditorMinimapOptions = Readonly<Required<IEditorMinimapOptions>>; export type EditorMinimapOptions = Readonly<Required<IEditorMinimapOptions>>;
/**
* Configuration options for editor padding
*/
export interface IEditorPaddingOptions {
/**
* Spacing between top edge of editor and first line.
*/
top?: number;
/**
* Spacing between bottom edge of editor and last line.
*/
bottom?: number;
}
export interface InternalEditorPaddingOptions {
readonly top: number;
readonly bottom: number;
}
/** /**
* Configuration options for parameter hints * Configuration options for parameter hints
*/ */
@@ -3763,53 +3786,54 @@ declare namespace monaco.editor {
occurrencesHighlight = 61, occurrencesHighlight = 61,
overviewRulerBorder = 62, overviewRulerBorder = 62,
overviewRulerLanes = 63, overviewRulerLanes = 63,
parameterHints = 64, padding = 64,
peekWidgetDefaultFocus = 65, parameterHints = 65,
definitionLinkOpensInPeek = 66, peekWidgetDefaultFocus = 66,
quickSuggestions = 67, definitionLinkOpensInPeek = 67,
quickSuggestionsDelay = 68, quickSuggestions = 68,
readOnly = 69, quickSuggestionsDelay = 69,
renderControlCharacters = 70, readOnly = 70,
renderIndentGuides = 71, renderControlCharacters = 71,
renderFinalNewline = 72, renderIndentGuides = 72,
renderLineHighlight = 73, renderFinalNewline = 73,
renderValidationDecorations = 74, renderLineHighlight = 74,
renderWhitespace = 75, renderValidationDecorations = 75,
revealHorizontalRightPadding = 76, renderWhitespace = 76,
roundedSelection = 77, revealHorizontalRightPadding = 77,
rulers = 78, roundedSelection = 78,
scrollbar = 79, rulers = 79,
scrollBeyondLastColumn = 80, scrollbar = 80,
scrollBeyondLastLine = 81, scrollBeyondLastColumn = 81,
scrollPredominantAxis = 82, scrollBeyondLastLine = 82,
selectionClipboard = 83, scrollPredominantAxis = 83,
selectionHighlight = 84, selectionClipboard = 84,
selectOnLineNumbers = 85, selectionHighlight = 85,
showFoldingControls = 86, selectOnLineNumbers = 86,
showUnused = 87, showFoldingControls = 87,
snippetSuggestions = 88, showUnused = 88,
smoothScrolling = 89, snippetSuggestions = 89,
stopRenderingLineAfter = 90, smoothScrolling = 90,
suggest = 91, stopRenderingLineAfter = 91,
suggestFontSize = 92, suggest = 92,
suggestLineHeight = 93, suggestFontSize = 93,
suggestOnTriggerCharacters = 94, suggestLineHeight = 94,
suggestSelection = 95, suggestOnTriggerCharacters = 95,
tabCompletion = 96, suggestSelection = 96,
useTabStops = 97, tabCompletion = 97,
wordSeparators = 98, useTabStops = 98,
wordWrap = 99, wordSeparators = 99,
wordWrapBreakAfterCharacters = 100, wordWrap = 100,
wordWrapBreakBeforeCharacters = 101, wordWrapBreakAfterCharacters = 101,
wordWrapColumn = 102, wordWrapBreakBeforeCharacters = 102,
wordWrapMinified = 103, wordWrapColumn = 103,
wrappingIndent = 104, wordWrapMinified = 104,
wrappingStrategy = 105, wrappingIndent = 105,
editorClassName = 106, wrappingStrategy = 106,
pixelRatio = 107, editorClassName = 107,
tabFocusMode = 108, pixelRatio = 108,
layoutInfo = 109, tabFocusMode = 109,
wrappingInfo = 110 layoutInfo = 110,
wrappingInfo = 111
} }
export const EditorOptions: { export const EditorOptions: {
acceptSuggestionOnCommitCharacter: IEditorOption<EditorOption.acceptSuggestionOnCommitCharacter, boolean>; acceptSuggestionOnCommitCharacter: IEditorOption<EditorOption.acceptSuggestionOnCommitCharacter, boolean>;
@@ -3876,6 +3900,7 @@ declare namespace monaco.editor {
occurrencesHighlight: IEditorOption<EditorOption.occurrencesHighlight, boolean>; occurrencesHighlight: IEditorOption<EditorOption.occurrencesHighlight, boolean>;
overviewRulerBorder: IEditorOption<EditorOption.overviewRulerBorder, boolean>; overviewRulerBorder: IEditorOption<EditorOption.overviewRulerBorder, boolean>;
overviewRulerLanes: IEditorOption<EditorOption.overviewRulerLanes, number>; overviewRulerLanes: IEditorOption<EditorOption.overviewRulerLanes, number>;
padding: IEditorOption<EditorOption.padding, InternalEditorPaddingOptions>;
parameterHints: IEditorOption<EditorOption.parameterHints, InternalParameterHintOptions>; parameterHints: IEditorOption<EditorOption.parameterHints, InternalParameterHintOptions>;
peekWidgetDefaultFocus: IEditorOption<EditorOption.peekWidgetDefaultFocus, 'tree' | 'editor'>; peekWidgetDefaultFocus: IEditorOption<EditorOption.peekWidgetDefaultFocus, 'tree' | 'editor'>;
definitionLinkOpensInPeek: IEditorOption<EditorOption.definitionLinkOpensInPeek, boolean>; definitionLinkOpensInPeek: IEditorOption<EditorOption.definitionLinkOpensInPeek, boolean>;
@@ -4669,6 +4694,7 @@ declare namespace monaco.editor {
readonly canUseHalfwidthRightwardsArrow: boolean; readonly canUseHalfwidthRightwardsArrow: boolean;
readonly spaceWidth: number; readonly spaceWidth: number;
readonly middotWidth: number; readonly middotWidth: number;
readonly wsmiddotWidth: number;
readonly maxDigitWidth: number; readonly maxDigitWidth: number;
} }

View File

@@ -16,6 +16,7 @@ export interface IAccessibilityService {
alwaysUnderlineAccessKeys(): Promise<boolean>; alwaysUnderlineAccessKeys(): Promise<boolean>;
isScreenReaderOptimized(): boolean; isScreenReaderOptimized(): boolean;
getAccessibilitySupport(): AccessibilitySupport;
setAccessibilitySupport(accessibilitySupport: AccessibilitySupport): void; setAccessibilitySupport(accessibilitySupport: AccessibilitySupport): void;
} }

View File

@@ -42,6 +42,10 @@ export class AccessibilityService extends Disposable implements IAccessibilitySe
return config === 'on' || (config === 'auto' && this._accessibilitySupport === AccessibilitySupport.Enabled); return config === 'on' || (config === 'auto' && this._accessibilitySupport === AccessibilitySupport.Enabled);
} }
getAccessibilitySupport(): AccessibilitySupport {
return this._accessibilitySupport;
}
alwaysUnderlineAccessKeys(): Promise<boolean> { alwaysUnderlineAccessKeys(): Promise<boolean> {
return Promise.resolve(false); return Promise.resolve(false);
} }

View File

@@ -324,10 +324,10 @@ export class SyncActionDescriptor {
public static create<Services extends BrandedService[]>(ctor: { new(id: string, label: string, ...services: Services): Action }, public static create<Services extends BrandedService[]>(ctor: { new(id: string, label: string, ...services: Services): Action },
id: string, label: string | undefined, keybindings?: IKeybindings, keybindingContext?: ContextKeyExpr, keybindingWeight?: number id: string, label: string | undefined, keybindings?: IKeybindings, keybindingContext?: ContextKeyExpr, keybindingWeight?: number
): SyncActionDescriptor { ): SyncActionDescriptor {
return new SyncActionDescriptor(ctor as IConstructorSignature2<string, string, Action>, id, label, keybindings, keybindingContext, keybindingWeight); return new SyncActionDescriptor(ctor as IConstructorSignature2<string, string | undefined, Action>, id, label, keybindings, keybindingContext, keybindingWeight);
} }
private constructor(ctor: IConstructorSignature2<string, string, Action>, private constructor(ctor: IConstructorSignature2<string, string | undefined, Action>,
id: string, label: string | undefined, keybindings?: IKeybindings, keybindingContext?: ContextKeyExpr, keybindingWeight?: number id: string, label: string | undefined, keybindings?: IKeybindings, keybindingContext?: ContextKeyExpr, keybindingWeight?: number
) { ) {
this._id = id; this._id = id;

View File

@@ -223,8 +223,6 @@ export interface IGlobalExtensionEnablementService {
enableExtension(extension: IExtensionIdentifier, source?: string): Promise<boolean>; enableExtension(extension: IExtensionIdentifier, source?: string): Promise<boolean>;
disableExtension(extension: IExtensionIdentifier, source?: string): Promise<boolean>; disableExtension(extension: IExtensionIdentifier, source?: string): Promise<boolean>;
// Async method until storage service is available in shared process
getDisabledExtensionsAsync(): Promise<IExtensionIdentifier[]>;
} }
export const ExtensionsLabel = localize('extensions', "Extensions"); export const ExtensionsLabel = localize('extensions', "Extensions");

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc';
import { IExtensionManagementService, ILocalExtension, InstallExtensionEvent, DidInstallExtensionEvent, IGalleryExtension, DidUninstallExtensionEvent, IExtensionIdentifier, IGalleryMetadata, IReportedExtension, IGlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IExtensionManagementService, ILocalExtension, InstallExtensionEvent, DidInstallExtensionEvent, IGalleryExtension, DidUninstallExtensionEvent, IExtensionIdentifier, IGalleryMetadata, IReportedExtension } from 'vs/platform/extensionManagement/common/extensionManagement';
import { Event } from 'vs/base/common/event'; import { Event } from 'vs/base/common/event';
import { URI, UriComponents } from 'vs/base/common/uri'; import { URI, UriComponents } from 'vs/base/common/uri';
import { IURITransformer, DefaultURITransformer, transformAndReviveIncomingURIs } from 'vs/base/common/uriIpc'; import { IURITransformer, DefaultURITransformer, transformAndReviveIncomingURIs } from 'vs/base/common/uriIpc';
@@ -130,53 +130,3 @@ export class ExtensionManagementChannelClient implements IExtensionManagementSer
return Promise.resolve(this.channel.call('getExtensionsReport')); return Promise.resolve(this.channel.call('getExtensionsReport'));
} }
} }
export class GlobalExtensionEnablementServiceChannel implements IServerChannel {
constructor(private readonly service: IGlobalExtensionEnablementService) { }
listen(_: unknown, event: string): Event<any> {
switch (event) {
case 'onDidChangeEnablement': return this.service.onDidChangeEnablement;
}
throw new Error(`Event not found: ${event}`);
}
call(context: any, command: string, args?: any): Promise<any> {
switch (command) {
case 'getDisabledExtensionsAsync': return Promise.resolve(this.service.getDisabledExtensions());
case 'enableExtension': return this.service.enableExtension(args[0]);
case 'disableExtension': return this.service.disableExtension(args[0]);
}
throw new Error('Invalid call');
}
}
export class GlobalExtensionEnablementServiceClient implements IGlobalExtensionEnablementService {
_serviceBrand: undefined;
get onDidChangeEnablement(): Event<{ readonly extensions: IExtensionIdentifier[], readonly source?: string }> { return this.channel.listen('onDidChangeEnablement'); }
constructor(private readonly channel: IChannel) {
}
getDisabledExtensionsAsync(): Promise<IExtensionIdentifier[]> {
return this.channel.call('getDisabledExtensionsAsync');
}
enableExtension(extension: IExtensionIdentifier): Promise<boolean> {
return this.channel.call('enableExtension', [extension]);
}
disableExtension(extension: IExtensionIdentifier): Promise<boolean> {
return this.channel.call('disableExtension', [extension]);
}
getDisabledExtensions(): IExtensionIdentifier[] {
throw new Error('not supported');
}
}

View File

@@ -8,8 +8,8 @@ import { ServiceIdentifier, BrandedService } from './instantiation';
const _registry: [ServiceIdentifier<any>, SyncDescriptor<any>][] = []; const _registry: [ServiceIdentifier<any>, SyncDescriptor<any>][] = [];
export function registerSingleton<T, Services extends BrandedService[]>(id: ServiceIdentifier<T>, ctor: { new(...services: Services): T }, supportsDelayedInstantiation?: boolean): void { export function registerSingleton<T, Services extends BrandedService[]>(id: ServiceIdentifier<T>, ctor: new (...services: Services) => T, supportsDelayedInstantiation?: boolean): void {
_registry.push([id, new SyncDescriptor<T>(ctor, [], supportsDelayedInstantiation)]); _registry.push([id, new SyncDescriptor<T>(ctor as new (...args: any[]) => T, [], supportsDelayedInstantiation)]);
} }
export function getSingletonServiceDescriptors(): [ServiceIdentifier<any>, SyncDescriptor<any>][] { export function getSingletonServiceDescriptors(): [ServiceIdentifier<any>, SyncDescriptor<any>][] {

View File

@@ -64,7 +64,7 @@ export class InstantiationService implements IInstantiationService {
return result; return result;
} }
}; };
return fn.apply(undefined, [accessor, ...args]); return fn(accessor, ...args);
} finally { } finally {
_done = true; _done = true;
_trace.stop(); _trace.stop();

View File

@@ -87,7 +87,7 @@ export namespace MarkerSeverity {
* A structure defining a problem/warning/etc. * A structure defining a problem/warning/etc.
*/ */
export interface IMarkerData { export interface IMarkerData {
code?: string | { value: string; link: URI }; code?: string | { value: string; target: URI };
severity: MarkerSeverity; severity: MarkerSeverity;
message: string; message: string;
source?: string; source?: string;
@@ -108,7 +108,7 @@ export interface IMarker {
owner: string; owner: string;
resource: URI; resource: URI;
severity: MarkerSeverity; severity: MarkerSeverity;
code?: string | { value: string; link: URI }; code?: string | { value: string; target: URI };
message: string; message: string;
source?: string; source?: string;
startLineNumber: number; startLineNumber: number;

View File

@@ -284,14 +284,12 @@ export class Menubar {
this.setMenuById(editMenu, 'Edit'); this.setMenuById(editMenu, 'Edit');
menubar.append(editMenuItem); menubar.append(editMenuItem);
// {{SQL CARBON EDIT}} - Disable unused menus // Selection
// // Selection /*const selectionMenu = new Menu();
// const selectionMenu = new Menu(); const selectionMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mSelection', comment: ['&& denotes a mnemonic'] }, "&&Selection")), submenu: selectionMenu });
// const selectionMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mSelection', comment: ['&& denotes a mnemonic'] }, "&&Selection")), submenu: selectionMenu });
// this.setMenuById(selectionMenu, 'Selection'); this.setMenuById(selectionMenu, 'Selection');
// menubar.append(selectionMenuItem); menubar.append(selectionMenuItem); {{SQL CARBON EDIT}} - Disable unused menus */
// {{SQL CARBON EDIT}} - End
// View // View
const viewMenu = new Menu(); const viewMenu = new Menu();
@@ -300,32 +298,26 @@ export class Menubar {
this.setMenuById(viewMenu, 'View'); this.setMenuById(viewMenu, 'View');
menubar.append(viewMenuItem); menubar.append(viewMenuItem);
// {{SQL CARBON EDIT}} - Disable unused menus // Go
// // Go /* const gotoMenu = new Menu();
// const gotoMenu = new Menu(); const gotoMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mGoto', comment: ['&& denotes a mnemonic'] }, "&&Go")), submenu: gotoMenu });
// const gotoMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mGoto', comment: ['&& denotes a mnemonic'] }, "&&Go")), submenu: gotoMenu });
// this.setMenuById(gotoMenu, 'Go'); this.setMenuById(gotoMenu, 'Go');
// menubar.append(gotoMenuItem); menubar.append(gotoMenuItem); {{SQL CARBON EDIT}} - Disable unused menus */
// {{SQL CARBON EDIT}} - End
// {{SQL CARBON EDIT}} - Disable unused menus // Debug
// // Debug /*const debugMenu = new Menu();
// const debugMenu = new Menu(); const debugMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mRun', comment: ['&& denotes a mnemonic'] }, "&&Run")), submenu: debugMenu });
// const debugMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mDebug', comment: ['&& denotes a mnemonic'] }, "&&Debug")), submenu: debugMenu });
// this.setMenuById(debugMenu, 'Debug'); this.setMenuById(debugMenu, 'Run');
// menubar.append(debugMenuItem); menubar.append(debugMenuItem); {{SQL CARBON EDIT}} - Disable unused menus */
// {{SQL CARBON EDIT}} - End
// {{SQL CARBON EDIT}} - Disable unused menus // Terminal
// // Terminal /*const terminalMenu = new Menu();
// const terminalMenu = new Menu(); const terminalMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mTerminal', comment: ['&& denotes a mnemonic'] }, "&&Terminal")), submenu: terminalMenu });
// const terminalMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mTerminal', comment: ['&& denotes a mnemonic'] }, "&&Terminal")), submenu: terminalMenu });
// this.setMenuById(terminalMenu, 'Terminal'); this.setMenuById(terminalMenu, 'Terminal');
// menubar.append(terminalMenuItem); menubar.append(terminalMenuItem); {{SQL CARBON EDIT}} - Disable unused menus */
// {{SQL CARBON EDIT}} - End
// Mac: Window // Mac: Window
let macWindowMenuItem: MenuItem | undefined; let macWindowMenuItem: MenuItem | undefined;

View File

@@ -15,7 +15,7 @@ import { copy, exists, mkdirp, writeFile } from 'vs/base/node/pfs';
import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IWorkspaceInitializationPayload, isWorkspaceIdentifier, isSingleFolderWorkspaceInitializationPayload } from 'vs/platform/workspaces/common/workspaces'; import { IWorkspaceInitializationPayload, isWorkspaceIdentifier, isSingleFolderWorkspaceInitializationPayload } from 'vs/platform/workspaces/common/workspaces';
import { onUnexpectedError } from 'vs/base/common/errors'; import { onUnexpectedError } from 'vs/base/common/errors';
import { assertIsDefined, assertAllDefined } from 'vs/base/common/types'; import { assertIsDefined } from 'vs/base/common/types';
import { RunOnceScheduler, runWhenIdle } from 'vs/base/common/async'; import { RunOnceScheduler, runWhenIdle } from 'vs/base/common/async';
export class NativeStorageService extends Disposable implements IStorageService { export class NativeStorageService extends Disposable implements IStorageService {
@@ -238,14 +238,11 @@ export class NativeStorageService extends Disposable implements IStorageService
} }
async logStorage(): Promise<void> { async logStorage(): Promise<void> {
const [workspaceStorage, workspaceStoragePath] = assertAllDefined(this.workspaceStorage, this.workspaceStoragePath); return logStorage(
const result = await Promise.all([
this.globalStorage.items, this.globalStorage.items,
workspaceStorage.items this.workspaceStorage ? this.workspaceStorage.items : new Map<string, string>(), // Shared process storage does not has workspace storage
]); this.environmentService.globalStorageHome,
this.workspaceStoragePath || '');
logStorage(result[0], result[1], this.environmentService.globalStorageHome, workspaceStoragePath);
} }
async migrate(toWorkspace: IWorkspaceInitializationPayload): Promise<void> { async migrate(toWorkspace: IWorkspaceInitializationPayload): Promise<void> {

View File

@@ -401,22 +401,22 @@ function registerDefaultClassifications(): void {
registerTokenType('namespace', nls.localize('namespace', "Style for namespaces."), [['entity.name.namespace']]); registerTokenType('namespace', nls.localize('namespace', "Style for namespaces."), [['entity.name.namespace']]);
registerTokenType('type', nls.localize('type', "Style for types."), [['entity.name.type'], ['support.type'], ['support.class']]); registerTokenType('type', nls.localize('type', "Style for types."), [['entity.name.type'], ['support.type']]);
registerTokenType('struct', nls.localize('struct', "Style for structs."), [['storage.type.struct']], 'type'); registerTokenType('struct', nls.localize('struct', "Style for structs."), [['storage.type.struct']]);
registerTokenType('class', nls.localize('class', "Style for classes."), [['entity.name.type.class']], 'type'); registerTokenType('class', nls.localize('class', "Style for classes."), [['entity.name.type.class'], ['support.class']]);
registerTokenType('interface', nls.localize('interface', "Style for interfaces."), [['entity.name.type.interface']], 'type'); registerTokenType('interface', nls.localize('interface', "Style for interfaces."), [['entity.name.type.interface']]);
registerTokenType('enum', nls.localize('enum', "Style for enums."), [['entity.name.type.enum']], 'type'); registerTokenType('enum', nls.localize('enum', "Style for enums."), [['entity.name.type.enum']]);
registerTokenType('typeParameter', nls.localize('typeParameter', "Style for type parameters."), [['entity.name.type', 'meta.type.parameters']], 'type'); registerTokenType('typeParameter', nls.localize('typeParameter', "Style for type parameters."), [['entity.name.type.parameter']]);
registerTokenType('function', nls.localize('function', "Style for functions"), [['entity.name.function'], ['support.function']]); registerTokenType('function', nls.localize('function', "Style for functions"), [['entity.name.function'], ['support.function']]);
registerTokenType('member', nls.localize('member', "Style for member"), [['entity.name.function.member'], ['support.function']]); registerTokenType('member', nls.localize('member', "Style for member"), [['entity.name.function.member'], ['support.function']]);
registerTokenType('macro', nls.localize('macro', "Style for macros."), [['entity.name.other.preprocessor.macro']], 'function'); registerTokenType('macro', nls.localize('macro', "Style for macros."), [['entity.name.other.preprocessor.macro']]);
registerTokenType('variable', nls.localize('variable', "Style for variables."), [['variable.other.readwrite'], ['entity.name.variable']]); registerTokenType('variable', nls.localize('variable', "Style for variables."), [['variable.other.readwrite'], ['entity.name.variable']]);
registerTokenType('parameter', nls.localize('parameter', "Style for parameters."), [['variable.parameter']], 'variable'); registerTokenType('parameter', nls.localize('parameter', "Style for parameters."), [['variable.parameter']]);
registerTokenType('property', nls.localize('property', "Style for properties."), [['variable.other.property']], 'variable'); registerTokenType('property', nls.localize('property', "Style for properties."), [['variable.other.property']]);
registerTokenType('enumMember', nls.localize('enumMember', "Style for enum members."), [['variable.other.enummember']], 'variable'); registerTokenType('enumMember', nls.localize('enumMember', "Style for enum members."), [['variable.other.enummember']]);
registerTokenType('event', nls.localize('event', "Style for events."), [['variable.other.event']], 'variable'); registerTokenType('event', nls.localize('event', "Style for events."), [['variable.other.event']]);
registerTokenType('label', nls.localize('labels', "Style for labels. "), undefined); registerTokenType('label', nls.localize('labels', "Style for labels. "), undefined);

View File

@@ -26,7 +26,7 @@ export abstract class AbstractUpdateService implements IUpdateService {
_serviceBrand: undefined; _serviceBrand: undefined;
protected readonly url: string | undefined; protected url: string | undefined;
private _state: State = State.Uninitialized; private _state: State = State.Uninitialized;
@@ -49,7 +49,14 @@ export abstract class AbstractUpdateService implements IUpdateService {
@IEnvironmentService private readonly environmentService: IEnvironmentService, @IEnvironmentService private readonly environmentService: IEnvironmentService,
@IRequestService protected requestService: IRequestService, @IRequestService protected requestService: IRequestService,
@ILogService protected logService: ILogService, @ILogService protected logService: ILogService,
) { ) { }
/**
* This must be called before any other call. This is a performance
* optimization, to avoid using extra CPU cycles before first window open.
* https://github.com/microsoft/vscode/issues/89784
*/
initialize(): void {
if (!this.environmentService.isBuilt) { if (!this.environmentService.isBuilt) {
return; // updates are never enabled when running out of sources return; // updates are never enabled when running out of sources
} }
@@ -173,6 +180,7 @@ export abstract class AbstractUpdateService implements IUpdateService {
if (!this.url) { if (!this.url) {
return Promise.resolve(undefined); return Promise.resolve(undefined);
} }
return this.requestService.request({ url: this.url }, CancellationToken.None).then(context => { return this.requestService.request({ url: this.url }, CancellationToken.None).then(context => {
// The update server replies with 204 (No Content) when no // The update server replies with 204 (No Content) when no
// update is available - that's all we want to know. // update is available - that's all we want to know.

View File

@@ -36,6 +36,10 @@ export class DarwinUpdateService extends AbstractUpdateService {
@ILogService logService: ILogService @ILogService logService: ILogService
) { ) {
super(lifecycleMainService, configurationService, environmentService, requestService, logService); super(lifecycleMainService, configurationService, environmentService, requestService, logService);
}
initialize(): void {
super.initialize();
this.onRawError(this.onError, this, this.disposables); this.onRawError(this.onError, this, this.disposables);
this.onRawUpdateAvailable(this.onUpdateAvailable, this, this.disposables); this.onRawUpdateAvailable(this.onUpdateAvailable, this, this.disposables);
this.onRawUpdateDownloaded(this.onUpdateDownloaded, this, this.disposables); this.onRawUpdateDownloaded(this.onUpdateDownloaded, this, this.disposables);

View File

@@ -70,6 +70,10 @@ export class Win32UpdateService extends AbstractUpdateService {
@IFileService private readonly fileService: IFileService @IFileService private readonly fileService: IFileService
) { ) {
super(lifecycleMainService, configurationService, environmentService, requestService, logService); super(lifecycleMainService, configurationService, environmentService, requestService, logService);
}
initialize(): void {
super.initialize();
if (getUpdateType() === UpdateType.Setup) { if (getUpdateType() === UpdateType.Setup) {
/* __GDPR__ /* __GDPR__
@@ -82,7 +86,7 @@ export class Win32UpdateService extends AbstractUpdateService {
"target" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } "target" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
} }
*/ */
telemetryService.publicLog('update:win32SetupTarget', { target: product.target }); this.telemetryService.publicLog('update:win32SetupTarget', { target: product.target });
} }
} }

View File

@@ -58,7 +58,7 @@ export class ElectronURLListener {
return url; return url;
}); });
const onOpenUrl = Event.filter(Event.map(onOpenElectronUrl, uriFromRawUrl), uri => !!uri); const onOpenUrl = Event.filter<URI | null, URI>(Event.map(onOpenElectronUrl, uriFromRawUrl), (uri): uri is URI => !!uri);
onOpenUrl(this.urlService.open, this.urlService, this.disposables); onOpenUrl(this.urlService.open, this.urlService, this.disposables);
const isWindowReady = windowsMainService.getWindows() const isWindowReady = windowsMainService.getWindows()

View File

@@ -4,15 +4,22 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { Disposable } from 'vs/base/common/lifecycle'; import { Disposable } from 'vs/base/common/lifecycle';
import { IFileService, IFileContent } from 'vs/platform/files/common/files'; import { IFileService, IFileContent, FileChangesEvent, FileSystemProviderError, FileSystemProviderErrorCode, FileOperationResult, FileOperationError } from 'vs/platform/files/common/files';
import { VSBuffer } from 'vs/base/common/buffer'; import { VSBuffer } from 'vs/base/common/buffer';
import { URI } from 'vs/base/common/uri'; import { URI } from 'vs/base/common/uri';
import { SyncSource, SyncStatus, IUserData, IUserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSync'; import { SyncSource, SyncStatus, IUserData, IUserDataSyncStoreService, UserDataSyncErrorCode, UserDataSyncError, IUserDataSyncLogService, IUserDataSyncUtilService, ResourceKey, IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync';
import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { joinPath, dirname } from 'vs/base/common/resources'; import { joinPath, dirname } from 'vs/base/common/resources';
import { toLocalISOString } from 'vs/base/common/date'; import { toLocalISOString } from 'vs/base/common/date';
import { ThrottledDelayer } from 'vs/base/common/async'; import { ThrottledDelayer, CancelablePromise } from 'vs/base/common/async';
import { Emitter, Event } from 'vs/base/common/event'; import { Emitter, Event } from 'vs/base/common/event';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { ParseError, parse } from 'vs/base/common/json';
import { FormattingOptions } from 'vs/base/common/jsonFormatter';
type SyncConflictsClassification = {
source?: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true };
};
export abstract class AbstractSynchroniser extends Disposable { export abstract class AbstractSynchroniser extends Disposable {
@@ -34,6 +41,9 @@ export abstract class AbstractSynchroniser extends Disposable {
@IFileService protected readonly fileService: IFileService, @IFileService protected readonly fileService: IFileService,
@IEnvironmentService environmentService: IEnvironmentService, @IEnvironmentService environmentService: IEnvironmentService,
@IUserDataSyncStoreService protected readonly userDataSyncStoreService: IUserDataSyncStoreService, @IUserDataSyncStoreService protected readonly userDataSyncStoreService: IUserDataSyncStoreService,
@IUserDataSyncEnablementService protected readonly userDataSyncEnablementService: IUserDataSyncEnablementService,
@ITelemetryService private readonly telemetryService: ITelemetryService,
@IUserDataSyncLogService protected readonly logService: IUserDataSyncLogService,
) { ) {
super(); super();
this.syncFolder = joinPath(environmentService.userDataSyncHome, source); this.syncFolder = joinPath(environmentService.userDataSyncHome, source);
@@ -43,20 +53,53 @@ export abstract class AbstractSynchroniser extends Disposable {
protected setStatus(status: SyncStatus): void { protected setStatus(status: SyncStatus): void {
if (this._status !== status) { if (this._status !== status) {
const oldStatus = this._status;
this._status = status; this._status = status;
this._onDidChangStatus.fire(status); this._onDidChangStatus.fire(status);
if (status === SyncStatus.HasConflicts) {
// Log to telemetry when there is a sync conflict
this.telemetryService.publicLog2<{ source: string }, SyncConflictsClassification>('sync/conflictsDetected', { source: this.source });
}
if (oldStatus === SyncStatus.HasConflicts && status === SyncStatus.Idle) {
// Log to telemetry when conflicts are resolved
this.telemetryService.publicLog2<{ source: string }, SyncConflictsClassification>('sync/conflictsResolved', { source: this.source });
}
} }
} }
protected get enabled(): boolean { return this.userDataSyncEnablementService.isResourceEnabled(this.resourceKey); }
async sync(ref?: string): Promise<void> {
if (!this.enabled) {
this.logService.info(`${this.source}: Skipped synchronizing ${this.source.toLowerCase()} as it is disabled.`);
return;
}
if (this.status === SyncStatus.HasConflicts) {
this.logService.info(`${this.source}: Skipped synchronizing ${this.source.toLowerCase()} as there are conflicts.`);
return;
}
if (this.status === SyncStatus.Syncing) {
this.logService.info(`${this.source}: Skipped synchronizing ${this.source.toLowerCase()} as it is running already.`);
return;
}
this.logService.trace(`${this.source}: Started synchronizing ${this.source.toLowerCase()}...`);
this.setStatus(SyncStatus.Syncing);
const lastSyncUserData = await this.getLastSyncUserData();
const remoteUserData = ref && lastSyncUserData && lastSyncUserData.ref === ref ? lastSyncUserData : await this.getRemoteUserData(lastSyncUserData);
return this.doSync(remoteUserData, lastSyncUserData);
}
async hasPreviouslySynced(): Promise<boolean> { async hasPreviouslySynced(): Promise<boolean> {
const lastSyncData = await this.getLastSyncUserData(); const lastSyncData = await this.getLastSyncUserData();
return !!lastSyncData; return !!lastSyncData;
} }
async hasRemoteData(): Promise<boolean> { async getRemoteContent(): Promise<string | null> {
const lastSyncData = await this.getLastSyncUserData(); const lastSyncData = await this.getLastSyncUserData();
const remoteUserData = await this.getRemoteUserData(lastSyncData); const remoteUserData = await this.getRemoteUserData(lastSyncData);
return remoteUserData.content !== null; return remoteUserData.content;
} }
async resetLocal(): Promise<void> { async resetLocal(): Promise<void> {
@@ -79,11 +122,11 @@ export abstract class AbstractSynchroniser extends Disposable {
} }
protected async getRemoteUserData(lastSyncData: IUserData | null): Promise<IUserData> { protected async getRemoteUserData(lastSyncData: IUserData | null): Promise<IUserData> {
return this.userDataSyncStoreService.read(this.getRemoteDataResourceKey(), lastSyncData, this.source); return this.userDataSyncStoreService.read(this.resourceKey, lastSyncData, this.source);
} }
protected async updateRemoteUserData(content: string, ref: string | null): Promise<string> { protected async updateRemoteUserData(content: string, ref: string | null): Promise<string> {
return this.userDataSyncStoreService.write(this.getRemoteDataResourceKey(), content, ref, this.source); return this.userDataSyncStoreService.write(this.resourceKey, content, ref, this.source);
} }
protected async backupLocal(content: VSBuffer): Promise<void> { protected async backupLocal(content: VSBuffer): Promise<void> {
@@ -101,21 +144,56 @@ export abstract class AbstractSynchroniser extends Disposable {
} }
} }
protected abstract getRemoteDataResourceKey(): string; abstract readonly resourceKey: ResourceKey;
protected abstract doSync(remoteUserData: IUserData, lastSyncUserData: IUserData | null): Promise<void>;
}
export interface IFileSyncPreviewResult {
readonly fileContent: IFileContent | null;
readonly remoteUserData: IUserData;
readonly lastSyncUserData: IUserData | null;
readonly content: string | null;
readonly hasLocalChanged: boolean;
readonly hasRemoteChanged: boolean;
readonly hasConflicts: boolean;
} }
export abstract class AbstractFileSynchroniser extends AbstractSynchroniser { export abstract class AbstractFileSynchroniser extends AbstractSynchroniser {
protected syncPreviewResultPromise: CancelablePromise<IFileSyncPreviewResult> | null = null;
constructor( constructor(
protected readonly file: URI, protected readonly file: URI,
readonly source: SyncSource, source: SyncSource,
@IFileService fileService: IFileService, @IFileService fileService: IFileService,
@IEnvironmentService environmentService: IEnvironmentService, @IEnvironmentService environmentService: IEnvironmentService,
@IUserDataSyncStoreService userDataSyncStoreService: IUserDataSyncStoreService, @IUserDataSyncStoreService userDataSyncStoreService: IUserDataSyncStoreService,
@IUserDataSyncEnablementService userDataSyncEnablementService: IUserDataSyncEnablementService,
@ITelemetryService telemetryService: ITelemetryService,
@IUserDataSyncLogService logService: IUserDataSyncLogService,
) { ) {
super(source, fileService, environmentService, userDataSyncStoreService); super(source, fileService, environmentService, userDataSyncStoreService, userDataSyncEnablementService, telemetryService, logService);
this._register(this.fileService.watch(dirname(file))); this._register(this.fileService.watch(dirname(file)));
this._register(Event.filter(this.fileService.onFileChanges, e => e.contains(file))(() => this._onDidChangeLocal.fire())); this._register(this.fileService.onFileChanges(e => this.onFileChanges(e)));
}
async stop(): Promise<void> {
this.cancel();
this.logService.trace(`${this.source}: Stopped synchronizing ${this.source.toLowerCase()}.`);
try {
await this.fileService.del(this.conflictsPreviewResource);
} catch (e) { /* ignore */ }
this.setStatus(SyncStatus.Idle);
}
async getRemoteContent(preview?: boolean): Promise<string | null> {
if (preview) {
if (this.syncPreviewResultPromise) {
const result = await this.syncPreviewResultPromise;
return result.remoteUserData ? result.remoteUserData.content : null;
}
}
return super.getRemoteContent();
} }
protected async getLocalFileContent(): Promise<IFileContent | null> { protected async getLocalFileContent(): Promise<IFileContent | null> {
@@ -127,14 +205,87 @@ export abstract class AbstractFileSynchroniser extends AbstractSynchroniser {
} }
protected async updateLocalFileContent(newContent: string, oldContent: IFileContent | null): Promise<void> { protected async updateLocalFileContent(newContent: string, oldContent: IFileContent | null): Promise<void> {
if (oldContent) { try {
// file exists already if (oldContent) {
await this.backupLocal(oldContent.value); // file exists already
await this.fileService.writeFile(this.file, VSBuffer.fromString(newContent), oldContent); await this.backupLocal(oldContent.value);
} else { await this.fileService.writeFile(this.file, VSBuffer.fromString(newContent), oldContent);
// file does not exist } else {
await this.fileService.createFile(this.file, VSBuffer.fromString(newContent), { overwrite: false }); // file does not exist
await this.fileService.createFile(this.file, VSBuffer.fromString(newContent), { overwrite: false });
}
} catch (e) {
if ((e instanceof FileSystemProviderError && e.code === FileSystemProviderErrorCode.FileExists) ||
(e instanceof FileOperationError && e.fileOperationResult === FileOperationResult.FILE_MODIFIED_SINCE)) {
throw new UserDataSyncError(e.message, UserDataSyncErrorCode.LocalPreconditionFailed);
} else {
throw e;
}
} }
} }
private onFileChanges(e: FileChangesEvent): void {
if (!e.contains(this.file)) {
return;
}
if (!this.enabled) {
return;
}
// Sync again if local file has changed and current status is in conflicts
if (this.status === SyncStatus.HasConflicts) {
this.syncPreviewResultPromise?.then(result => {
this.cancel();
this.doSync(result.remoteUserData, result.lastSyncUserData);
});
}
// Otherwise fire change event
else {
this._onDidChangeLocal.fire();
}
}
protected cancel(): void {
if (this.syncPreviewResultPromise) {
this.syncPreviewResultPromise.cancel();
this.syncPreviewResultPromise = null;
}
}
protected abstract readonly conflictsPreviewResource: URI;
}
export abstract class AbstractJsonFileSynchroniser extends AbstractFileSynchroniser {
constructor(
file: URI,
source: SyncSource,
@IFileService fileService: IFileService,
@IEnvironmentService environmentService: IEnvironmentService,
@IUserDataSyncStoreService userDataSyncStoreService: IUserDataSyncStoreService,
@IUserDataSyncEnablementService userDataSyncEnablementService: IUserDataSyncEnablementService,
@ITelemetryService telemetryService: ITelemetryService,
@IUserDataSyncLogService logService: IUserDataSyncLogService,
@IUserDataSyncUtilService protected readonly userDataSyncUtilService: IUserDataSyncUtilService,
) {
super(file, source, fileService, environmentService, userDataSyncStoreService, userDataSyncEnablementService, telemetryService, logService);
}
protected hasErrors(content: string): boolean {
const parseErrors: ParseError[] = [];
parse(content, parseErrors, { allowEmptyContent: true, allowTrailingComma: true });
return parseErrors.length > 0;
}
private _formattingOptions: Promise<FormattingOptions> | undefined = undefined;
protected getFormattingOptions(): Promise<FormattingOptions> {
if (!this._formattingOptions) {
this._formattingOptions = this.userDataSyncUtilService.resolveFormattingOptions(this.file);
}
return this._formattingOptions;
}
} }

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { IUserData, UserDataSyncError, UserDataSyncErrorCode, SyncStatus, IUserDataSyncStoreService, ISyncExtension, IUserDataSyncLogService, IUserDataSynchroniser, SyncSource } from 'vs/platform/userDataSync/common/userDataSync'; import { IUserData, UserDataSyncError, UserDataSyncErrorCode, SyncStatus, IUserDataSyncStoreService, ISyncExtension, IUserDataSyncLogService, IUserDataSynchroniser, SyncSource, ResourceKey, IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync';
import { Event } from 'vs/base/common/event'; import { Event } from 'vs/base/common/event';
import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IExtensionManagementService, IExtensionGalleryService, IGlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IExtensionManagementService, IExtensionGalleryService, IGlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement';
@@ -15,6 +15,7 @@ import { localize } from 'vs/nls';
import { merge } from 'vs/platform/userDataSync/common/extensionsMerge'; import { merge } from 'vs/platform/userDataSync/common/extensionsMerge';
import { isNonEmptyArray } from 'vs/base/common/arrays'; import { isNonEmptyArray } from 'vs/base/common/arrays';
import { AbstractSynchroniser } from 'vs/platform/userDataSync/common/abstractSynchronizer'; import { AbstractSynchroniser } from 'vs/platform/userDataSync/common/abstractSynchronizer';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
interface ISyncPreviewResult { interface ISyncPreviewResult {
readonly added: ISyncExtension[]; readonly added: ISyncExtension[];
@@ -32,17 +33,21 @@ interface ILastSyncUserData extends IUserData {
export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUserDataSynchroniser { export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUserDataSynchroniser {
readonly resourceKey: ResourceKey = 'extensions';
constructor( constructor(
@IEnvironmentService environmentService: IEnvironmentService, @IEnvironmentService environmentService: IEnvironmentService,
@IFileService fileService: IFileService, @IFileService fileService: IFileService,
@IUserDataSyncStoreService userDataSyncStoreService: IUserDataSyncStoreService, @IUserDataSyncStoreService userDataSyncStoreService: IUserDataSyncStoreService,
@IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService, @IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService,
@IGlobalExtensionEnablementService private readonly extensionEnablementService: IGlobalExtensionEnablementService, @IGlobalExtensionEnablementService private readonly extensionEnablementService: IGlobalExtensionEnablementService,
@IUserDataSyncLogService private readonly logService: IUserDataSyncLogService, @IUserDataSyncLogService logService: IUserDataSyncLogService,
@IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService, @IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService,
@IConfigurationService private readonly configurationService: IConfigurationService, @IConfigurationService private readonly configurationService: IConfigurationService,
@IUserDataSyncEnablementService userDataSyncEnablementService: IUserDataSyncEnablementService,
@ITelemetryService telemetryService: ITelemetryService,
) { ) {
super(SyncSource.Extensions, fileService, environmentService, userDataSyncStoreService); super(SyncSource.Extensions, fileService, environmentService, userDataSyncStoreService, userDataSyncEnablementService, telemetryService, logService);
this._register( this._register(
Event.debounce( Event.debounce(
Event.any<any>( Event.any<any>(
@@ -52,10 +57,8 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
() => undefined, 500)(() => this._onDidChangeLocal.fire())); () => undefined, 500)(() => this._onDidChangeLocal.fire()));
} }
protected getRemoteDataResourceKey(): string { return 'extensions'; }
async pull(): Promise<void> { async pull(): Promise<void> {
if (!this.configurationService.getValue<boolean>('sync.enableExtensions')) { if (!this.enabled) {
this.logService.info('Extensions: Skipped pulling extensions as it is disabled.'); this.logService.info('Extensions: Skipped pulling extensions as it is disabled.');
return; return;
} }
@@ -88,7 +91,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
} }
async push(): Promise<void> { async push(): Promise<void> {
if (!this.configurationService.getValue<boolean>('sync.enableExtensions')) { if (!this.enabled) {
this.logService.info('Extensions: Skipped pushing extensions as it is disabled.'); this.logService.info('Extensions: Skipped pushing extensions as it is disabled.');
return; return;
} }
@@ -112,46 +115,16 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
} }
async sync(): Promise<void> { async sync(ref?: string): Promise<void> {
if (!this.configurationService.getValue<boolean>('sync.enableExtensions')) {
this.logService.trace('Extensions: Skipping synchronizing extensions as it is disabled.');
return;
}
if (!this.extensionGalleryService.isEnabled()) { if (!this.extensionGalleryService.isEnabled()) {
this.logService.trace('Extensions: Skipping synchronizing extensions as gallery is disabled.'); this.logService.info('Extensions: Skipping synchronizing extensions as gallery is disabled.');
return; return;
} }
if (this.status !== SyncStatus.Idle) { return super.sync(ref);
this.logService.trace('Extensions: Skipping synchronizing extensions as it is running already.');
return;
}
this.logService.trace('Extensions: Started synchronizing extensions...');
this.setStatus(SyncStatus.Syncing);
try {
const previewResult = await this.getPreview();
await this.apply(previewResult);
} catch (e) {
this.setStatus(SyncStatus.Idle);
if (e instanceof UserDataSyncError && e.code === UserDataSyncErrorCode.Rejected) {
// Rejected as there is a new remote version. Syncing again,
this.logService.info('Extensions: Failed to synchronize extensions as there is a new remote version available. Synchronizing again...');
return this.sync();
}
throw e;
}
this.logService.trace('Extensions: Finished synchronizing extensions.');
this.setStatus(SyncStatus.Idle);
} }
async stop(): Promise<void> { } async stop(): Promise<void> { }
async restart(): Promise<void> {
throw new Error('Extensions: Conflicts should not occur');
}
accept(content: string): Promise<void> { accept(content: string): Promise<void> {
throw new Error('Extensions: Conflicts should not occur'); throw new Error('Extensions: Conflicts should not occur');
} }
@@ -172,14 +145,29 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
return null; return null;
} }
private async getPreview(): Promise<ISyncPreviewResult> { protected async doSync(remoteUserData: IUserData, lastSyncUserData: ILastSyncUserData | null): Promise<void> {
const lastSyncUserData = await this.getLastSyncUserData<ILastSyncUserData>(); try {
const previewResult = await this.getPreview(remoteUserData, lastSyncUserData);
await this.apply(previewResult);
} catch (e) {
this.setStatus(SyncStatus.Idle);
if (e instanceof UserDataSyncError && e.code === UserDataSyncErrorCode.RemotePreconditionFailed) {
// Rejected as there is a new remote version. Syncing again,
this.logService.info('Extensions: Failed to synchronize extensions as there is a new remote version available. Synchronizing again...');
return this.sync();
}
throw e;
}
this.logService.trace('Extensions: Finished synchronizing extensions.');
this.setStatus(SyncStatus.Idle);
}
private async getPreview(remoteUserData: IUserData, lastSyncUserData: ILastSyncUserData | null): Promise<ISyncPreviewResult> {
const remoteExtensions: ISyncExtension[] = remoteUserData.content ? JSON.parse(remoteUserData.content) : null;
const lastSyncExtensions: ISyncExtension[] | null = lastSyncUserData ? JSON.parse(lastSyncUserData.content!) : null; const lastSyncExtensions: ISyncExtension[] | null = lastSyncUserData ? JSON.parse(lastSyncUserData.content!) : null;
const skippedExtensions: ISyncExtension[] = lastSyncUserData ? lastSyncUserData.skippedExtensions || [] : []; const skippedExtensions: ISyncExtension[] = lastSyncUserData ? lastSyncUserData.skippedExtensions || [] : [];
const remoteUserData = await this.getRemoteUserData(lastSyncUserData);
const remoteExtensions: ISyncExtension[] = remoteUserData.content ? JSON.parse(remoteUserData.content) : null;
const localExtensions = await this.getLocalExtensions(); const localExtensions = await this.getLocalExtensions();
if (remoteExtensions) { if (remoteExtensions) {
@@ -202,7 +190,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
const hasChanges = added.length || removed.length || updated.length || remote; const hasChanges = added.length || removed.length || updated.length || remote;
if (!hasChanges) { if (!hasChanges) {
this.logService.trace('Extensions: No changes found during synchronizing extensions.'); this.logService.info('Extensions: No changes found during synchronizing extensions.');
} }
if (added.length || removed.length || updated.length) { if (added.length || removed.length || updated.length) {
@@ -255,7 +243,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
} else { } else {
this.logService.trace('Extensions: Disabling extension...', e.identifier.id); this.logService.trace('Extensions: Disabling extension...', e.identifier.id);
await this.extensionEnablementService.disableExtension(e.identifier); await this.extensionEnablementService.disableExtension(e.identifier);
this.logService.info('Extensions: Disabled extension.', e.identifier.id); this.logService.info('Extensions: Disabled extension', e.identifier.id);
} }
removeFromSkipped.push(e.identifier); removeFromSkipped.push(e.identifier);
return; return;
@@ -307,7 +295,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
private async getLocalExtensions(): Promise<ISyncExtension[]> { private async getLocalExtensions(): Promise<ISyncExtension[]> {
const installedExtensions = await this.extensionManagementService.getInstalled(); const installedExtensions = await this.extensionManagementService.getInstalled();
const disabledExtensions = await this.extensionEnablementService.getDisabledExtensionsAsync(); const disabledExtensions = await this.extensionEnablementService.getDisabledExtensions();
return installedExtensions return installedExtensions
.map(({ identifier }) => ({ identifier, enabled: !disabledExtensions.some(disabledExtension => areSameExtensions(disabledExtension, identifier)) })); .map(({ identifier }) => ({ identifier, enabled: !disabledExtensions.some(disabledExtension => areSameExtensions(disabledExtension, identifier)) }));
} }

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { IUserData, UserDataSyncError, UserDataSyncErrorCode, SyncStatus, IUserDataSyncStoreService, IUserDataSyncLogService, IGlobalState, SyncSource, IUserDataSynchroniser } from 'vs/platform/userDataSync/common/userDataSync'; import { IUserData, UserDataSyncError, UserDataSyncErrorCode, SyncStatus, IUserDataSyncStoreService, IUserDataSyncLogService, IGlobalState, SyncSource, IUserDataSynchroniser, ResourceKey, IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync';
import { VSBuffer } from 'vs/base/common/buffer'; import { VSBuffer } from 'vs/base/common/buffer';
import { Event } from 'vs/base/common/event'; import { Event } from 'vs/base/common/event';
import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IEnvironmentService } from 'vs/platform/environment/common/environment';
@@ -12,9 +12,9 @@ import { IFileService } from 'vs/platform/files/common/files';
import { IStringDictionary } from 'vs/base/common/collections'; import { IStringDictionary } from 'vs/base/common/collections';
import { edit } from 'vs/platform/userDataSync/common/content'; import { edit } from 'vs/platform/userDataSync/common/content';
import { merge } from 'vs/platform/userDataSync/common/globalStateMerge'; import { merge } from 'vs/platform/userDataSync/common/globalStateMerge';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { parse } from 'vs/base/common/json'; import { parse } from 'vs/base/common/json';
import { AbstractSynchroniser } from 'vs/platform/userDataSync/common/abstractSynchronizer'; import { AbstractSynchroniser } from 'vs/platform/userDataSync/common/abstractSynchronizer';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
const argvProperties: string[] = ['locale']; const argvProperties: string[] = ['locale'];
@@ -27,22 +27,23 @@ interface ISyncPreviewResult {
export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUserDataSynchroniser { export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUserDataSynchroniser {
readonly resourceKey: ResourceKey = 'globalState';
constructor( constructor(
@IFileService fileService: IFileService, @IFileService fileService: IFileService,
@IUserDataSyncStoreService userDataSyncStoreService: IUserDataSyncStoreService, @IUserDataSyncStoreService userDataSyncStoreService: IUserDataSyncStoreService,
@IUserDataSyncLogService private readonly logService: IUserDataSyncLogService, @IUserDataSyncLogService logService: IUserDataSyncLogService,
@IEnvironmentService private readonly environmentService: IEnvironmentService, @IEnvironmentService private readonly environmentService: IEnvironmentService,
@IConfigurationService private readonly configurationService: IConfigurationService, @IUserDataSyncEnablementService userDataSyncEnablementService: IUserDataSyncEnablementService,
@ITelemetryService telemetryService: ITelemetryService,
) { ) {
super(SyncSource.GlobalState, fileService, environmentService, userDataSyncStoreService); super(SyncSource.GlobalState, fileService, environmentService, userDataSyncStoreService, userDataSyncEnablementService, telemetryService, logService);
this._register(this.fileService.watch(dirname(this.environmentService.argvResource))); this._register(this.fileService.watch(dirname(this.environmentService.argvResource)));
this._register(Event.filter(this.fileService.onFileChanges, e => e.contains(this.environmentService.argvResource))(() => this._onDidChangeLocal.fire())); this._register(Event.filter(this.fileService.onFileChanges, e => e.contains(this.environmentService.argvResource))(() => this._onDidChangeLocal.fire()));
} }
protected getRemoteDataResourceKey(): string { return 'globalState'; }
async pull(): Promise<void> { async pull(): Promise<void> {
if (!this.configurationService.getValue<boolean>('sync.enableUIState')) { if (!this.enabled) {
this.logService.info('UI State: Skipped pulling ui state as it is disabled.'); this.logService.info('UI State: Skipped pulling ui state as it is disabled.');
return; return;
} }
@@ -73,7 +74,7 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs
} }
async push(): Promise<void> { async push(): Promise<void> {
if (!this.configurationService.getValue<boolean>('sync.enableUIState')) { if (!this.enabled) {
this.logService.info('UI State: Skipped pushing UI State as it is disabled.'); this.logService.info('UI State: Skipped pushing UI State as it is disabled.');
return; return;
} }
@@ -96,43 +97,8 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs
} }
async sync(): Promise<void> {
if (!this.configurationService.getValue<boolean>('sync.enableUIState')) {
this.logService.trace('UI State: Skipping synchronizing UI state as it is disabled.');
return;
}
if (this.status !== SyncStatus.Idle) {
this.logService.trace('UI State: Skipping synchronizing ui state as it is running already.');
return;
}
this.logService.trace('UI State: Started synchronizing ui state...');
this.setStatus(SyncStatus.Syncing);
try {
const result = await this.getPreview();
await this.apply(result);
this.logService.trace('UI State: Finished synchronizing ui state.');
} catch (e) {
this.setStatus(SyncStatus.Idle);
if (e instanceof UserDataSyncError && e.code === UserDataSyncErrorCode.Rejected) {
// Rejected as there is a new remote version. Syncing again,
this.logService.info('UI State: Failed to synchronize ui state as there is a new remote version available. Synchronizing again...');
return this.sync();
}
throw e;
} finally {
this.setStatus(SyncStatus.Idle);
}
}
async stop(): Promise<void> { } async stop(): Promise<void> { }
async restart(): Promise<void> {
throw new Error('UI State: Conflicts should not occur');
}
accept(content: string): Promise<void> { accept(content: string): Promise<void> {
throw new Error('UI State: Conflicts should not occur'); throw new Error('UI State: Conflicts should not occur');
} }
@@ -153,12 +119,27 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs
return null; return null;
} }
private async getPreview(): Promise<ISyncPreviewResult> { protected async doSync(remoteUserData: IUserData, lastSyncUserData: IUserData | null): Promise<void> {
const lastSyncUserData = await this.getLastSyncUserData(); try {
const lastSyncGlobalState = lastSyncUserData && lastSyncUserData.content ? JSON.parse(lastSyncUserData.content) : null; const result = await this.getPreview(remoteUserData, lastSyncUserData);
await this.apply(result);
this.logService.trace('UI State: Finished synchronizing ui state.');
} catch (e) {
this.setStatus(SyncStatus.Idle);
if (e instanceof UserDataSyncError && e.code === UserDataSyncErrorCode.RemotePreconditionFailed) {
// Rejected as there is a new remote version. Syncing again,
this.logService.info('UI State: Failed to synchronize ui state as there is a new remote version available. Synchronizing again...');
return this.sync();
}
throw e;
} finally {
this.setStatus(SyncStatus.Idle);
}
}
const remoteUserData = await this.getRemoteUserData(lastSyncUserData); private async getPreview(remoteUserData: IUserData, lastSyncUserData: IUserData | null, ): Promise<ISyncPreviewResult> {
const remoteGlobalState: IGlobalState = remoteUserData.content ? JSON.parse(remoteUserData.content) : null; const remoteGlobalState: IGlobalState = remoteUserData.content ? JSON.parse(remoteUserData.content) : null;
const lastSyncGlobalState = lastSyncUserData && lastSyncUserData.content ? JSON.parse(lastSyncUserData.content) : null;
const localGloablState = await this.getLocalGlobalState(); const localGloablState = await this.getLocalGlobalState();
@@ -178,7 +159,7 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs
const hasChanges = local || remote; const hasChanges = local || remote;
if (!hasChanges) { if (!hasChanges) {
this.logService.trace('UI State: No changes found during synchronizing ui state.'); this.logService.info('UI State: No changes found during synchronizing ui state.');
} }
if (local) { if (local) {
@@ -208,26 +189,32 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs
private async getLocalGlobalState(): Promise<IGlobalState> { private async getLocalGlobalState(): Promise<IGlobalState> {
const argv: IStringDictionary<any> = {}; const argv: IStringDictionary<any> = {};
const storage: IStringDictionary<any> = {}; const storage: IStringDictionary<any> = {};
try { const argvContent: string = await this.getLocalArgvContent();
const content = await this.fileService.readFile(this.environmentService.argvResource); const argvValue: IStringDictionary<any> = parse(argvContent);
const argvValue: IStringDictionary<any> = parse(content.value.toString()); for (const argvProperty of argvProperties) {
for (const argvProperty of argvProperties) { if (argvValue[argvProperty] !== undefined) {
if (argvValue[argvProperty] !== undefined) { argv[argvProperty] = argvValue[argvProperty];
argv[argvProperty] = argvValue[argvProperty];
}
} }
} catch (error) { } }
return { argv, storage }; return { argv, storage };
} }
private async getLocalArgvContent(): Promise<string> {
try {
const content = await this.fileService.readFile(this.environmentService.argvResource);
return content.value.toString();
} catch (error) { }
return '{}';
}
private async writeLocalGlobalState(globalState: IGlobalState): Promise<void> { private async writeLocalGlobalState(globalState: IGlobalState): Promise<void> {
const content = await this.fileService.readFile(this.environmentService.argvResource); const argvContent = await this.getLocalArgvContent();
let argvContent = content.value.toString(); let content = argvContent;
for (const argvProperty of Object.keys(globalState.argv)) { for (const argvProperty of Object.keys(globalState.argv)) {
argvContent = edit(argvContent, [argvProperty], globalState.argv[argvProperty], {}); content = edit(content, [argvProperty], globalState.argv[argvProperty], {});
} }
if (argvContent !== content.value.toString()) { if (argvContent !== content) {
await this.fileService.writeFile(this.environmentService.argvResource, VSBuffer.fromString(argvContent)); await this.fileService.writeFile(this.environmentService.argvResource, VSBuffer.fromString(content));
} }
} }

View File

@@ -3,21 +3,22 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { IFileService, FileSystemProviderErrorCode, FileSystemProviderError, IFileContent, FileOperationError, FileOperationResult } from 'vs/platform/files/common/files'; import { IFileService, FileOperationError, FileOperationResult } from 'vs/platform/files/common/files';
import { IUserData, UserDataSyncError, UserDataSyncErrorCode, SyncStatus, IUserDataSyncStoreService, IUserDataSyncLogService, IUserDataSyncUtilService, SyncSource, IUserDataSynchroniser } from 'vs/platform/userDataSync/common/userDataSync'; import { UserDataSyncError, UserDataSyncErrorCode, SyncStatus, IUserDataSyncStoreService, IUserDataSyncLogService, IUserDataSyncUtilService, SyncSource, IUserDataSynchroniser, IUserData, ResourceKey, IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync';
import { merge } from 'vs/platform/userDataSync/common/keybindingsMerge'; import { merge } from 'vs/platform/userDataSync/common/keybindingsMerge';
import { VSBuffer } from 'vs/base/common/buffer'; import { VSBuffer } from 'vs/base/common/buffer';
import { parse, ParseError } from 'vs/base/common/json'; import { parse } from 'vs/base/common/json';
import { localize } from 'vs/nls'; import { localize } from 'vs/nls';
import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async'; import { createCancelablePromise } from 'vs/base/common/async';
import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { CancellationToken } from 'vs/base/common/cancellation'; import { CancellationToken } from 'vs/base/common/cancellation';
import { OS, OperatingSystem } from 'vs/base/common/platform'; import { OS, OperatingSystem } from 'vs/base/common/platform';
import { isUndefined } from 'vs/base/common/types'; import { isUndefined } from 'vs/base/common/types';
import { FormattingOptions } from 'vs/base/common/jsonFormatter';
import { isNonEmptyArray } from 'vs/base/common/arrays'; import { isNonEmptyArray } from 'vs/base/common/arrays';
import { AbstractFileSynchroniser } from 'vs/platform/userDataSync/common/abstractSynchronizer'; import { IFileSyncPreviewResult, AbstractJsonFileSynchroniser } from 'vs/platform/userDataSync/common/abstractSynchronizer';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { URI } from 'vs/base/common/uri';
interface ISyncContent { interface ISyncContent {
mac?: string; mac?: string;
@@ -26,34 +27,26 @@ interface ISyncContent {
all?: string; all?: string;
} }
interface ISyncPreviewResult { export class KeybindingsSynchroniser extends AbstractJsonFileSynchroniser implements IUserDataSynchroniser {
readonly fileContent: IFileContent | null;
readonly remoteUserData: IUserData;
readonly lastSyncUserData: IUserData | null;
readonly hasLocalChanged: boolean;
readonly hasRemoteChanged: boolean;
readonly hasConflicts: boolean;
}
export class KeybindingsSynchroniser extends AbstractFileSynchroniser implements IUserDataSynchroniser { readonly resourceKey: ResourceKey = 'keybindings';
protected get conflictsPreviewResource(): URI { return this.environmentService.keybindingsSyncPreviewResource; }
private syncPreviewResultPromise: CancelablePromise<ISyncPreviewResult> | null = null;
constructor( constructor(
@IUserDataSyncStoreService userDataSyncStoreService: IUserDataSyncStoreService, @IUserDataSyncStoreService userDataSyncStoreService: IUserDataSyncStoreService,
@IUserDataSyncLogService private readonly logService: IUserDataSyncLogService, @IUserDataSyncLogService logService: IUserDataSyncLogService,
@IConfigurationService private readonly configurationService: IConfigurationService, @IConfigurationService private readonly configurationService: IConfigurationService,
@IUserDataSyncEnablementService userDataSyncEnablementService: IUserDataSyncEnablementService,
@IFileService fileService: IFileService, @IFileService fileService: IFileService,
@IEnvironmentService private readonly environmentService: IEnvironmentService, @IEnvironmentService private readonly environmentService: IEnvironmentService,
@IUserDataSyncUtilService private readonly userDataSyncUtilService: IUserDataSyncUtilService, @IUserDataSyncUtilService userDataSyncUtilService: IUserDataSyncUtilService,
@ITelemetryService telemetryService: ITelemetryService,
) { ) {
super(environmentService.keybindingsResource, SyncSource.Keybindings, fileService, environmentService, userDataSyncStoreService); super(environmentService.keybindingsResource, SyncSource.Keybindings, fileService, environmentService, userDataSyncStoreService, userDataSyncEnablementService, telemetryService, logService, userDataSyncUtilService);
} }
protected getRemoteDataResourceKey(): string { return 'keybindings'; }
async pull(): Promise<void> { async pull(): Promise<void> {
if (!this.configurationService.getValue<boolean>('sync.enableKeybindings')) { if (!this.enabled) {
this.logService.info('Keybindings: Skipped pulling keybindings as it is disabled.'); this.logService.info('Keybindings: Skipped pulling keybindings as it is disabled.');
return; return;
} }
@@ -66,18 +59,18 @@ export class KeybindingsSynchroniser extends AbstractFileSynchroniser implements
const lastSyncUserData = await this.getLastSyncUserData(); const lastSyncUserData = await this.getLastSyncUserData();
const remoteUserData = await this.getRemoteUserData(lastSyncUserData); const remoteUserData = await this.getRemoteUserData(lastSyncUserData);
const remoteContent = remoteUserData.content !== null ? this.getKeybindingsContentFromSyncContent(remoteUserData.content) : null; const content = remoteUserData.content !== null ? this.getKeybindingsContentFromSyncContent(remoteUserData.content) : null;
if (remoteContent !== null) { if (content !== null) {
await this.fileService.writeFile(this.environmentService.keybindingsSyncPreviewResource, VSBuffer.fromString(remoteContent));
const fileContent = await this.getLocalFileContent(); const fileContent = await this.getLocalFileContent();
this.syncPreviewResultPromise = createCancelablePromise(() => Promise.resolve<ISyncPreviewResult>({ this.syncPreviewResultPromise = createCancelablePromise(() => Promise.resolve<IFileSyncPreviewResult>({
fileContent, fileContent,
remoteUserData,
lastSyncUserData,
content,
hasConflicts: false, hasConflicts: false,
hasLocalChanged: true, hasLocalChanged: true,
hasRemoteChanged: false, hasRemoteChanged: false,
remoteUserData,
lastSyncUserData
})); }));
await this.apply(); await this.apply();
} }
@@ -95,7 +88,7 @@ export class KeybindingsSynchroniser extends AbstractFileSynchroniser implements
} }
async push(): Promise<void> { async push(): Promise<void> {
if (!this.configurationService.getValue<boolean>('sync.enableKeybindings')) { if (!this.enabled) {
this.logService.info('Keybindings: Skipped pushing keybindings as it is disabled.'); this.logService.info('Keybindings: Skipped pushing keybindings as it is disabled.');
return; return;
} }
@@ -111,16 +104,16 @@ export class KeybindingsSynchroniser extends AbstractFileSynchroniser implements
if (fileContent !== null) { if (fileContent !== null) {
const lastSyncUserData = await this.getLastSyncUserData(); const lastSyncUserData = await this.getLastSyncUserData();
const remoteUserData = await this.getRemoteUserData(lastSyncUserData); const remoteUserData = await this.getRemoteUserData(lastSyncUserData);
await this.fileService.writeFile(this.environmentService.settingsSyncPreviewResource, fileContent.value); this.syncPreviewResultPromise = createCancelablePromise(() => Promise.resolve<IFileSyncPreviewResult>({
this.syncPreviewResultPromise = createCancelablePromise(() => Promise.resolve<ISyncPreviewResult>({
fileContent, fileContent,
hasConflicts: false, remoteUserData,
lastSyncUserData,
content: fileContent.value.toString(),
hasLocalChanged: false, hasLocalChanged: false,
hasRemoteChanged: true, hasRemoteChanged: true,
remoteUserData, hasConflicts: false,
lastSyncUserData
})); }));
await this.apply(undefined, true); await this.apply(true);
} }
// No local exists to push // No local exists to push
@@ -135,53 +128,13 @@ export class KeybindingsSynchroniser extends AbstractFileSynchroniser implements
} }
async sync(): Promise<void> {
if (!this.configurationService.getValue<boolean>('sync.enableKeybindings')) {
this.logService.trace('Keybindings: Skipping synchronizing keybindings as it is disabled.');
return;
}
if (this.status !== SyncStatus.Idle) {
this.logService.trace('Keybindings: Skipping synchronizing keybindings as it is running already.');
return;
}
this.logService.trace('Keybindings: Started synchronizing keybindings...');
this.setStatus(SyncStatus.Syncing);
return this.doSync();
}
async stop(): Promise<void> {
if (this.syncPreviewResultPromise) {
this.syncPreviewResultPromise.cancel();
this.syncPreviewResultPromise = null;
this.logService.trace('Keybindings: Stopped synchronizing keybindings.');
}
await this.fileService.del(this.environmentService.keybindingsSyncPreviewResource);
this.setStatus(SyncStatus.Idle);
}
async restart(): Promise<void> {
if (this.status === SyncStatus.HasConflicts) {
this.syncPreviewResultPromise!.cancel();
this.syncPreviewResultPromise = null;
await this.doSync();
}
}
async accept(content: string): Promise<void> { async accept(content: string): Promise<void> {
if (this.status === SyncStatus.HasConflicts) { if (this.status === SyncStatus.HasConflicts) {
try { const preview = await this.syncPreviewResultPromise!;
await this.apply(content, true); this.cancel();
this.setStatus(SyncStatus.Idle); this.syncPreviewResultPromise = createCancelablePromise(async () => ({ ...preview, content }));
} catch (e) { await this.apply(true);
if ((e instanceof FileSystemProviderError && e.code === FileSystemProviderErrorCode.FileExists) || this.setStatus(SyncStatus.Idle);
(e instanceof FileOperationError && e.fileOperationResult === FileOperationResult.FILE_MODIFIED_SINCE)) {
throw new UserDataSyncError('Failed to resolve conflicts as there is a new local version available.', UserDataSyncErrorCode.NewLocal);
}
throw e;
}
} }
} }
@@ -202,22 +155,14 @@ export class KeybindingsSynchroniser extends AbstractFileSynchroniser implements
return false; return false;
} }
async getRemoteContent(): Promise<string | null> { async getRemoteContent(preview?: boolean): Promise<string | null> {
let content: string | null | undefined = null; const content = await super.getRemoteContent(preview);
if (this.syncPreviewResultPromise) { return content !== null ? this.getKeybindingsContentFromSyncContent(content) : null;
const preview = await this.syncPreviewResultPromise;
content = preview.remoteUserData?.content;
} else {
const lastSyncData = await this.getLastSyncUserData();
const remoteUserData = await this.getRemoteUserData(lastSyncData);
content = remoteUserData.content;
}
return content ? this.getKeybindingsContentFromSyncContent(content) : null;
} }
private async doSync(): Promise<void> { protected async doSync(remoteUserData: IUserData, lastSyncUserData: IUserData | null): Promise<void> {
try { try {
const result = await this.getPreview(); const result = await this.getPreview(remoteUserData, lastSyncUserData);
if (result.hasConflicts) { if (result.hasConflicts) {
this.logService.info('Keybindings: Detected conflicts while synchronizing keybindings.'); this.logService.info('Keybindings: Detected conflicts while synchronizing keybindings.');
this.setStatus(SyncStatus.HasConflicts); this.setStatus(SyncStatus.HasConflicts);
@@ -232,44 +177,32 @@ export class KeybindingsSynchroniser extends AbstractFileSynchroniser implements
} catch (e) { } catch (e) {
this.syncPreviewResultPromise = null; this.syncPreviewResultPromise = null;
this.setStatus(SyncStatus.Idle); this.setStatus(SyncStatus.Idle);
if (e instanceof UserDataSyncError && e.code === UserDataSyncErrorCode.Rejected) { if (e instanceof UserDataSyncError) {
// Rejected as there is a new remote version. Syncing again, switch (e.code) {
this.logService.info('Keybindings: Failed to synchronize keybindings as there is a new remote version available. Synchronizing again...'); case UserDataSyncErrorCode.RemotePreconditionFailed:
return this.sync(); // Rejected as there is a new remote version. Syncing again,
} this.logService.info('Keybindings: Failed to synchronize keybindings as there is a new remote version available. Synchronizing again...');
if ((e instanceof FileSystemProviderError && e.code === FileSystemProviderErrorCode.FileExists) || return this.sync();
(e instanceof FileOperationError && e.fileOperationResult === FileOperationResult.FILE_MODIFIED_SINCE)) { case UserDataSyncErrorCode.LocalPreconditionFailed:
// Rejected as there is a new local version. Syncing again. // Rejected as there is a new local version. Syncing again.
this.logService.info('Keybindings: Failed to synchronize keybindings as there is a new local version available. Synchronizing again...'); this.logService.info('Keybindings: Failed to synchronize keybindings as there is a new local version available. Synchronizing again...');
return this.sync(); return this.sync(remoteUserData.ref);
}
} }
throw e; throw e;
} }
} }
private async apply(content?: string, forcePush?: boolean): Promise<void> { private async apply(forcePush?: boolean): Promise<void> {
if (!this.syncPreviewResultPromise) { if (!this.syncPreviewResultPromise) {
return; return;
} }
let { fileContent, remoteUserData, lastSyncUserData, hasLocalChanged, hasRemoteChanged } = await this.syncPreviewResultPromise; let { fileContent, remoteUserData, lastSyncUserData, content, hasLocalChanged, hasRemoteChanged } = await this.syncPreviewResultPromise;
if (content === undefined) { if (content !== null) {
if (await this.fileService.exists(this.environmentService.keybindingsSyncPreviewResource)) {
const keybindingsPreivew = await this.fileService.readFile(this.environmentService.keybindingsSyncPreviewResource);
content = keybindingsPreivew.value.toString();
}
}
if (content !== undefined) {
if (this.hasErrors(content)) { if (this.hasErrors(content)) {
const error = new Error(localize('errorInvalidKeybindings', "Unable to sync keybindings. Please resolve conflicts without any errors/warnings and try again.")); throw new UserDataSyncError(localize('errorInvalidSettings', "Unable to sync keybindings as there are errors/warning in keybindings file."), UserDataSyncErrorCode.LocalInvalidContent, this.source);
this.logService.error(error);
throw error;
}
if (!hasLocalChanged && !hasRemoteChanged) {
this.logService.trace('Keybindings: No changes found during synchronizing keybindings.');
} }
if (hasLocalChanged) { if (hasLocalChanged) {
@@ -287,14 +220,16 @@ export class KeybindingsSynchroniser extends AbstractFileSynchroniser implements
} }
// Delete the preview // Delete the preview
await this.fileService.del(this.environmentService.keybindingsSyncPreviewResource); try {
await this.fileService.del(this.conflictsPreviewResource);
} catch (e) { /* ignore */ }
} else { } else {
this.logService.trace('Keybindings: No changes found during synchronizing keybindings.'); this.logService.info('Keybindings: No changes found during synchronizing keybindings.');
} }
if (lastSyncUserData?.ref !== remoteUserData.ref && (content !== undefined || fileContent !== null)) { if (lastSyncUserData?.ref !== remoteUserData.ref && (content !== null || fileContent !== null)) {
this.logService.trace('Keybindings: Updating last synchronized keybindings...'); this.logService.trace('Keybindings: Updating last synchronized keybindings...');
const lastSyncContent = this.updateSyncContent(content !== undefined ? content : fileContent!.value.toString(), null); const lastSyncContent = this.updateSyncContent(content !== null ? content : fileContent!.value.toString(), null);
await this.updateLastSyncUserData({ ref: remoteUserData.ref, content: lastSyncContent }); await this.updateLastSyncUserData({ ref: remoteUserData.ref, content: lastSyncContent });
this.logService.info('Keybindings: Updated last synchronized keybindings'); this.logService.info('Keybindings: Updated last synchronized keybindings');
} }
@@ -302,36 +237,29 @@ export class KeybindingsSynchroniser extends AbstractFileSynchroniser implements
this.syncPreviewResultPromise = null; this.syncPreviewResultPromise = null;
} }
private hasErrors(content: string): boolean { private getPreview(remoteUserData: IUserData, lastSyncUserData: IUserData | null): Promise<IFileSyncPreviewResult> {
const parseErrors: ParseError[] = [];
parse(content, parseErrors, { allowEmptyContent: true, allowTrailingComma: true });
return parseErrors.length > 0;
}
private getPreview(): Promise<ISyncPreviewResult> {
if (!this.syncPreviewResultPromise) { if (!this.syncPreviewResultPromise) {
this.syncPreviewResultPromise = createCancelablePromise(token => this.generatePreview(token)); this.syncPreviewResultPromise = createCancelablePromise(token => this.generatePreview(remoteUserData, lastSyncUserData, token));
} }
return this.syncPreviewResultPromise; return this.syncPreviewResultPromise;
} }
private async generatePreview(token: CancellationToken): Promise<ISyncPreviewResult> { private async generatePreview(remoteUserData: IUserData, lastSyncUserData: IUserData | null, token: CancellationToken): Promise<IFileSyncPreviewResult> {
const lastSyncUserData = await this.getLastSyncUserData();
const lastSyncContent = lastSyncUserData && lastSyncUserData.content ? this.getKeybindingsContentFromSyncContent(lastSyncUserData.content) : null;
const remoteUserData = await this.getRemoteUserData(lastSyncUserData);
const remoteContent = remoteUserData.content ? this.getKeybindingsContentFromSyncContent(remoteUserData.content) : null; const remoteContent = remoteUserData.content ? this.getKeybindingsContentFromSyncContent(remoteUserData.content) : null;
const lastSyncContent = lastSyncUserData && lastSyncUserData.content ? this.getKeybindingsContentFromSyncContent(lastSyncUserData.content) : null;
// Get file content last to get the latest // Get file content last to get the latest
const fileContent = await this.getLocalFileContent(); const fileContent = await this.getLocalFileContent();
const formattingOptions = await this.getFormattingOptions();
let content: string | null = null;
let hasLocalChanged: boolean = false; let hasLocalChanged: boolean = false;
let hasRemoteChanged: boolean = false; let hasRemoteChanged: boolean = false;
let hasConflicts: boolean = false; let hasConflicts: boolean = false;
let previewContent = null;
if (remoteContent) { if (remoteContent) {
const localContent: string = fileContent ? fileContent.value.toString() : '[]'; const localContent: string = fileContent ? fileContent.value.toString() : '[]';
if (this.hasErrors(localContent)) { if (this.hasErrors(localContent)) {
this.logService.error('Keybindings: Unable to sync keybindings as there are errors/warning in keybindings file.'); throw new UserDataSyncError(localize('errorInvalidSettings', "Unable to sync keybindings as there are errors/warning in keybindings file."), UserDataSyncErrorCode.LocalInvalidContent, this.source);
return { fileContent, remoteUserData, lastSyncUserData, hasLocalChanged, hasRemoteChanged, hasConflicts };
} }
if (!lastSyncContent // First time sync if (!lastSyncContent // First time sync
@@ -339,14 +267,13 @@ export class KeybindingsSynchroniser extends AbstractFileSynchroniser implements
|| lastSyncContent !== remoteContent // Remote has forwarded || lastSyncContent !== remoteContent // Remote has forwarded
) { ) {
this.logService.trace('Keybindings: Merging remote keybindings with local keybindings...'); this.logService.trace('Keybindings: Merging remote keybindings with local keybindings...');
const formattingOptions = await this.getFormattingOptions();
const result = await merge(localContent, remoteContent, lastSyncContent, formattingOptions, this.userDataSyncUtilService); const result = await merge(localContent, remoteContent, lastSyncContent, formattingOptions, this.userDataSyncUtilService);
// Sync only if there are changes // Sync only if there are changes
if (result.hasChanges) { if (result.hasChanges) {
hasLocalChanged = result.mergeContent !== localContent; content = result.mergeContent;
hasRemoteChanged = result.mergeContent !== remoteContent;
hasConflicts = result.hasConflicts; hasConflicts = result.hasConflicts;
previewContent = result.mergeContent; hasLocalChanged = hasConflicts || result.mergeContent !== localContent;
hasRemoteChanged = hasConflicts || result.mergeContent !== remoteContent;
} }
} }
} }
@@ -354,23 +281,15 @@ export class KeybindingsSynchroniser extends AbstractFileSynchroniser implements
// First time syncing to remote // First time syncing to remote
else if (fileContent) { else if (fileContent) {
this.logService.trace('Keybindings: Remote keybindings does not exist. Synchronizing keybindings for the first time.'); this.logService.trace('Keybindings: Remote keybindings does not exist. Synchronizing keybindings for the first time.');
content = fileContent.value.toString();
hasRemoteChanged = true; hasRemoteChanged = true;
previewContent = fileContent.value.toString();
} }
if (previewContent && !token.isCancellationRequested) { if (content && !token.isCancellationRequested) {
await this.fileService.writeFile(this.environmentService.keybindingsSyncPreviewResource, VSBuffer.fromString(previewContent)); await this.fileService.writeFile(this.environmentService.keybindingsSyncPreviewResource, VSBuffer.fromString(content));
} }
return { fileContent, remoteUserData, lastSyncUserData, hasLocalChanged, hasRemoteChanged, hasConflicts }; return { fileContent, remoteUserData, lastSyncUserData, content, hasLocalChanged, hasRemoteChanged, hasConflicts };
}
private _formattingOptions: Promise<FormattingOptions> | undefined = undefined;
private getFormattingOptions(): Promise<FormattingOptions> {
if (!this._formattingOptions) {
this._formattingOptions = this.userDataSyncUtilService.resolveFormattingOptions(this.environmentService.keybindingsResource);
}
return this._formattingOptions;
} }
private getKeybindingsContentFromSyncContent(syncContent: string): string | null { private getKeybindingsContentFromSyncContent(syncContent: string): string | null {

View File

@@ -10,7 +10,7 @@ import { values } from 'vs/base/common/map';
import { IStringDictionary } from 'vs/base/common/collections'; import { IStringDictionary } from 'vs/base/common/collections';
import { FormattingOptions, Edit, getEOL } from 'vs/base/common/jsonFormatter'; import { FormattingOptions, Edit, getEOL } from 'vs/base/common/jsonFormatter';
import * as contentUtil from 'vs/platform/userDataSync/common/content'; import * as contentUtil from 'vs/platform/userDataSync/common/content';
import { IConflictSetting, DEFAULT_IGNORED_SETTINGS } from 'vs/platform/userDataSync/common/userDataSync'; import { IConflictSetting, CONFIGURATION_SYNC_STORE_KEY } from 'vs/platform/userDataSync/common/userDataSync';
import { firstIndex } from 'vs/base/common/arrays'; import { firstIndex } from 'vs/base/common/arrays';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { startsWith } from 'vs/base/common/strings'; import { startsWith } from 'vs/base/common/strings';
@@ -42,7 +42,7 @@ export function getIgnoredSettings(configurationService: IConfigurationService,
} }
} }
} }
return [...DEFAULT_IGNORED_SETTINGS, ...added].filter(setting => removed.indexOf(setting) === -1); return [CONFIGURATION_SYNC_STORE_KEY, ...added].filter(setting => removed.indexOf(setting) === -1);
} }

View File

@@ -3,40 +3,31 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { IFileService, FileSystemProviderErrorCode, FileSystemProviderError, IFileContent, FileOperationError, FileOperationResult } from 'vs/platform/files/common/files'; import { IFileService, FileOperationError, FileOperationResult } from 'vs/platform/files/common/files';
import { IUserData, UserDataSyncError, UserDataSyncErrorCode, SyncStatus, IUserDataSyncStoreService, IUserDataSyncLogService, IUserDataSyncUtilService, IConflictSetting, ISettingsSyncService, CONFIGURATION_SYNC_STORE_KEY, SyncSource } from 'vs/platform/userDataSync/common/userDataSync'; import { UserDataSyncError, UserDataSyncErrorCode, SyncStatus, IUserDataSyncStoreService, IUserDataSyncLogService, IUserDataSyncUtilService, IConflictSetting, ISettingsSyncService, CONFIGURATION_SYNC_STORE_KEY, SyncSource, IUserData, ResourceKey, IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync';
import { VSBuffer } from 'vs/base/common/buffer'; import { VSBuffer } from 'vs/base/common/buffer';
import { parse, ParseError } from 'vs/base/common/json'; import { parse } from 'vs/base/common/json';
import { localize } from 'vs/nls'; import { localize } from 'vs/nls';
import { Emitter, Event } from 'vs/base/common/event'; import { Emitter, Event } from 'vs/base/common/event';
import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async'; import { createCancelablePromise } from 'vs/base/common/async';
import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { CancellationToken } from 'vs/base/common/cancellation'; import { CancellationToken } from 'vs/base/common/cancellation';
import { updateIgnoredSettings, merge, getIgnoredSettings } from 'vs/platform/userDataSync/common/settingsMerge'; import { updateIgnoredSettings, merge, getIgnoredSettings } from 'vs/platform/userDataSync/common/settingsMerge';
import { FormattingOptions } from 'vs/base/common/jsonFormatter';
import * as arrays from 'vs/base/common/arrays'; import * as arrays from 'vs/base/common/arrays';
import * as objects from 'vs/base/common/objects'; import * as objects from 'vs/base/common/objects';
import { isEmptyObject, isUndefinedOrNull } from 'vs/base/common/types'; import { isEmptyObject } from 'vs/base/common/types';
import { edit } from 'vs/platform/userDataSync/common/content'; import { edit } from 'vs/platform/userDataSync/common/content';
import { AbstractFileSynchroniser } from 'vs/platform/userDataSync/common/abstractSynchronizer'; import { IFileSyncPreviewResult, AbstractJsonFileSynchroniser } from 'vs/platform/userDataSync/common/abstractSynchronizer';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { URI } from 'vs/base/common/uri';
interface ISyncPreviewResult { export class SettingsSynchroniser extends AbstractJsonFileSynchroniser implements ISettingsSyncService {
readonly fileContent: IFileContent | null;
readonly remoteUserData: IUserData;
readonly lastSyncUserData: IUserData | null;
readonly content: string | null;
readonly hasLocalChanged: boolean;
readonly hasRemoteChanged: boolean;
readonly hasConflicts: boolean;
readonly conflictSettings: IConflictSetting[];
}
export class SettingsSynchroniser extends AbstractFileSynchroniser implements ISettingsSyncService {
_serviceBrand: any; _serviceBrand: any;
private syncPreviewResultPromise: CancelablePromise<ISyncPreviewResult> | null = null; readonly resourceKey: ResourceKey = 'settings';
protected get conflictsPreviewResource(): URI { return this.environmentService.settingsSyncPreviewResource; }
private _conflicts: IConflictSetting[] = []; private _conflicts: IConflictSetting[] = [];
get conflicts(): IConflictSetting[] { return this._conflicts; } get conflicts(): IConflictSetting[] { return this._conflicts; }
@@ -47,15 +38,15 @@ export class SettingsSynchroniser extends AbstractFileSynchroniser implements IS
@IFileService fileService: IFileService, @IFileService fileService: IFileService,
@IEnvironmentService private readonly environmentService: IEnvironmentService, @IEnvironmentService private readonly environmentService: IEnvironmentService,
@IUserDataSyncStoreService userDataSyncStoreService: IUserDataSyncStoreService, @IUserDataSyncStoreService userDataSyncStoreService: IUserDataSyncStoreService,
@IUserDataSyncLogService private readonly logService: IUserDataSyncLogService, @IUserDataSyncLogService logService: IUserDataSyncLogService,
@IUserDataSyncUtilService private readonly userDataSyncUtilService: IUserDataSyncUtilService, @IUserDataSyncUtilService userDataSyncUtilService: IUserDataSyncUtilService,
@IConfigurationService private readonly configurationService: IConfigurationService, @IConfigurationService private readonly configurationService: IConfigurationService,
@IUserDataSyncEnablementService userDataSyncEnablementService: IUserDataSyncEnablementService,
@ITelemetryService telemetryService: ITelemetryService,
) { ) {
super(environmentService.settingsResource, SyncSource.Settings, fileService, environmentService, userDataSyncStoreService); super(environmentService.settingsResource, SyncSource.Settings, fileService, environmentService, userDataSyncStoreService, userDataSyncEnablementService, telemetryService, logService, userDataSyncUtilService);
} }
protected getRemoteDataResourceKey(): string { return 'settings'; }
protected setStatus(status: SyncStatus): void { protected setStatus(status: SyncStatus): void {
super.setStatus(status); super.setStatus(status);
if (this.status !== SyncStatus.HasConflicts) { if (this.status !== SyncStatus.HasConflicts) {
@@ -73,7 +64,7 @@ export class SettingsSynchroniser extends AbstractFileSynchroniser implements IS
} }
async pull(): Promise<void> { async pull(): Promise<void> {
if (!this.configurationService.getValue<boolean>('sync.enableSettings')) { if (!this.enabled) {
this.logService.info('Settings: Skipped pulling settings as it is disabled.'); this.logService.info('Settings: Skipped pulling settings as it is disabled.');
return; return;
} }
@@ -92,7 +83,7 @@ export class SettingsSynchroniser extends AbstractFileSynchroniser implements IS
const formatUtils = await this.getFormattingOptions(); const formatUtils = await this.getFormattingOptions();
// Update ignored settings from local file content // Update ignored settings from local file content
const content = updateIgnoredSettings(remoteUserData.content, fileContent ? fileContent.value.toString() : '{}', getIgnoredSettings(this.configurationService), formatUtils); const content = updateIgnoredSettings(remoteUserData.content, fileContent ? fileContent.value.toString() : '{}', getIgnoredSettings(this.configurationService), formatUtils);
this.syncPreviewResultPromise = createCancelablePromise(() => Promise.resolve<ISyncPreviewResult>({ this.syncPreviewResultPromise = createCancelablePromise(() => Promise.resolve<IFileSyncPreviewResult>({
fileContent, fileContent,
remoteUserData, remoteUserData,
lastSyncUserData, lastSyncUserData,
@@ -100,7 +91,6 @@ export class SettingsSynchroniser extends AbstractFileSynchroniser implements IS
hasLocalChanged: true, hasLocalChanged: true,
hasRemoteChanged: false, hasRemoteChanged: false,
hasConflicts: false, hasConflicts: false,
conflictSettings: [],
})); }));
await this.apply(); await this.apply();
@@ -118,7 +108,7 @@ export class SettingsSynchroniser extends AbstractFileSynchroniser implements IS
} }
async push(): Promise<void> { async push(): Promise<void> {
if (!this.configurationService.getValue<boolean>('sync.enableSettings')) { if (!this.enabled) {
this.logService.info('Settings: Skipped pushing settings as it is disabled.'); this.logService.info('Settings: Skipped pushing settings as it is disabled.');
return; return;
} }
@@ -138,7 +128,7 @@ export class SettingsSynchroniser extends AbstractFileSynchroniser implements IS
const lastSyncUserData = await this.getLastSyncUserData(); const lastSyncUserData = await this.getLastSyncUserData();
const remoteUserData = await this.getRemoteUserData(lastSyncUserData); const remoteUserData = await this.getRemoteUserData(lastSyncUserData);
this.syncPreviewResultPromise = createCancelablePromise(() => Promise.resolve<ISyncPreviewResult>({ this.syncPreviewResultPromise = createCancelablePromise(() => Promise.resolve<IFileSyncPreviewResult>({
fileContent, fileContent,
remoteUserData, remoteUserData,
lastSyncUserData, lastSyncUserData,
@@ -146,7 +136,6 @@ export class SettingsSynchroniser extends AbstractFileSynchroniser implements IS
hasRemoteChanged: true, hasRemoteChanged: true,
hasLocalChanged: false, hasLocalChanged: false,
hasConflicts: false, hasConflicts: false,
conflictSettings: [],
})); }));
await this.apply(true); await this.apply(true);
@@ -163,32 +152,6 @@ export class SettingsSynchroniser extends AbstractFileSynchroniser implements IS
} }
} }
async sync(): Promise<void> {
if (!this.configurationService.getValue<boolean>('sync.enableSettings')) {
this.logService.trace('Settings: Skipping synchronizing settings as it is disabled.');
return;
}
if (this.status !== SyncStatus.Idle) {
this.logService.trace('Settings: Skipping synchronizing settings as it is running already.');
return;
}
this.logService.trace('Settings: Started synchronizing settings...');
this.setStatus(SyncStatus.Syncing);
return this.doSync([]);
}
async stop(): Promise<void> {
if (this.syncPreviewResultPromise) {
this.syncPreviewResultPromise.cancel();
this.syncPreviewResultPromise = null;
this.logService.trace('Settings: Stopped synchronizing settings.');
}
await this.fileService.del(this.environmentService.settingsSyncPreviewResource);
this.setStatus(SyncStatus.Idle);
}
async hasLocalData(): Promise<boolean> { async hasLocalData(): Promise<boolean> {
try { try {
const localFileContent = await this.getLocalFileContent(); const localFileContent = await this.getLocalFileContent();
@@ -209,62 +172,39 @@ export class SettingsSynchroniser extends AbstractFileSynchroniser implements IS
} }
async getRemoteContent(preview?: boolean): Promise<string | null> { async getRemoteContent(preview?: boolean): Promise<string | null> {
let content: string | null | undefined = null; let content = await super.getRemoteContent(preview);
if (this.syncPreviewResultPromise) { if (preview && content !== null) {
const preview = await this.syncPreviewResultPromise;
content = preview.remoteUserData?.content;
} else {
const lastSyncData = await this.getLastSyncUserData();
const remoteUserData = await this.getRemoteUserData(lastSyncData);
content = remoteUserData.content;
}
if (preview && !isUndefinedOrNull(content)) {
const formatUtils = await this.getFormattingOptions(); const formatUtils = await this.getFormattingOptions();
// remove ignored settings from the remote content for preview // remove ignored settings from the remote content for preview
content = updateIgnoredSettings(content, '{}', getIgnoredSettings(this.configurationService), formatUtils); content = updateIgnoredSettings(content, '{}', getIgnoredSettings(this.configurationService), formatUtils);
} }
return content !== undefined ? content : null; return content;
}
async restart(): Promise<void> {
if (this.status === SyncStatus.HasConflicts) {
this.syncPreviewResultPromise!.cancel();
this.syncPreviewResultPromise = null;
await this.doSync([]);
}
} }
async accept(content: string): Promise<void> { async accept(content: string): Promise<void> {
if (this.status === SyncStatus.HasConflicts) { if (this.status === SyncStatus.HasConflicts) {
try { const preview = await this.syncPreviewResultPromise!;
const preview = await this.syncPreviewResultPromise!; this.cancel();
const formatUtils = await this.getFormattingOptions(); const formatUtils = await this.getFormattingOptions();
// Add ignored settings from local file content // Add ignored settings from local file content
content = updateIgnoredSettings(content, preview.fileContent ? preview.fileContent.value.toString() : '{}', getIgnoredSettings(this.configurationService), formatUtils); content = updateIgnoredSettings(content, preview.fileContent ? preview.fileContent.value.toString() : '{}', getIgnoredSettings(this.configurationService), formatUtils);
this.syncPreviewResultPromise = createCancelablePromise(async () => ({ ...preview, content })); this.syncPreviewResultPromise = createCancelablePromise(async () => ({ ...preview, content }));
await this.apply(true); await this.apply(true);
this.setStatus(SyncStatus.Idle); this.setStatus(SyncStatus.Idle);
} catch (e) {
if ((e instanceof FileSystemProviderError && e.code === FileSystemProviderErrorCode.FileExists) ||
(e instanceof FileOperationError && e.fileOperationResult === FileOperationResult.FILE_MODIFIED_SINCE)) {
throw new UserDataSyncError('Failed to resolve conflicts as there is a new local version available.', UserDataSyncErrorCode.NewLocal);
}
throw e;
}
} }
} }
async resolveSettingsConflicts(resolvedConflicts: { key: string, value: any | undefined }[]): Promise<void> { async resolveSettingsConflicts(resolvedConflicts: { key: string, value: any | undefined }[]): Promise<void> {
if (this.status === SyncStatus.HasConflicts) { if (this.status === SyncStatus.HasConflicts) {
this.syncPreviewResultPromise!.cancel(); const preview = await this.syncPreviewResultPromise!;
this.syncPreviewResultPromise = null; this.cancel();
await this.doSync(resolvedConflicts); await this.doSync(preview.remoteUserData, preview.lastSyncUserData, resolvedConflicts);
} }
} }
private async doSync(resolvedConflicts: { key: string, value: any | undefined }[]): Promise<void> { protected async doSync(remoteUserData: IUserData, lastSyncUserData: IUserData | null, resolvedConflicts: { key: string, value: any | undefined }[] = []): Promise<void> {
try { try {
const result = await this.getPreview(resolvedConflicts); const result = await this.getPreview(remoteUserData, lastSyncUserData, resolvedConflicts);
if (result.hasConflicts) { if (result.hasConflicts) {
this.logService.info('Settings: Detected conflicts while synchronizing settings.'); this.logService.info('Settings: Detected conflicts while synchronizing settings.');
this.setStatus(SyncStatus.HasConflicts); this.setStatus(SyncStatus.HasConflicts);
@@ -279,16 +219,17 @@ export class SettingsSynchroniser extends AbstractFileSynchroniser implements IS
} catch (e) { } catch (e) {
this.syncPreviewResultPromise = null; this.syncPreviewResultPromise = null;
this.setStatus(SyncStatus.Idle); this.setStatus(SyncStatus.Idle);
if (e instanceof UserDataSyncError && e.code === UserDataSyncErrorCode.Rejected) { if (e instanceof UserDataSyncError) {
// Rejected as there is a new remote version. Syncing again, switch (e.code) {
this.logService.info('Settings: Failed to synchronize settings as there is a new remote version available. Synchronizing again...'); case UserDataSyncErrorCode.RemotePreconditionFailed:
return this.sync(); // Rejected as there is a new remote version. Syncing again,
} this.logService.info('Settings: Failed to synchronize settings as there is a new remote version available. Synchronizing again...');
if ((e instanceof FileSystemProviderError && e.code === FileSystemProviderErrorCode.FileExists) || return this.sync();
(e instanceof FileOperationError && e.fileOperationResult === FileOperationResult.FILE_MODIFIED_SINCE)) { case UserDataSyncErrorCode.LocalPreconditionFailed:
// Rejected as there is a new local version. Syncing again. // Rejected as there is a new local version. Syncing again.
this.logService.info('Settings: Failed to synchronize settings as there is a new local version available. Synchronizing again...'); this.logService.info('Settings: Failed to synchronize settings as there is a new local version available. Synchronizing again...');
return this.sync(); return this.sync(remoteUserData.ref);
}
} }
throw e; throw e;
} }
@@ -304,9 +245,7 @@ export class SettingsSynchroniser extends AbstractFileSynchroniser implements IS
if (content !== null) { if (content !== null) {
if (this.hasErrors(content)) { if (this.hasErrors(content)) {
const error = new Error(localize('errorInvalidSettings', "Unable to sync settings. Please resolve conflicts without any errors/warnings and try again.")); throw new UserDataSyncError(localize('errorInvalidSettings', "Unable to sync settings as there are errors/warning in settings file."), UserDataSyncErrorCode.LocalInvalidContent, this.source);
this.logService.error(error);
throw error;
} }
if (hasLocalChanged) { if (hasLocalChanged) {
@@ -325,9 +264,11 @@ export class SettingsSynchroniser extends AbstractFileSynchroniser implements IS
} }
// Delete the preview // Delete the preview
await this.fileService.del(this.environmentService.settingsSyncPreviewResource); try {
await this.fileService.del(this.conflictsPreviewResource);
} catch (e) { /* ignore */ }
} else { } else {
this.logService.trace('Settings: No changes found during synchronizing settings.'); this.logService.info('Settings: No changes found during synchronizing settings.');
} }
if (lastSyncUserData?.ref !== remoteUserData.ref) { if (lastSyncUserData?.ref !== remoteUserData.ref) {
@@ -339,25 +280,16 @@ export class SettingsSynchroniser extends AbstractFileSynchroniser implements IS
this.syncPreviewResultPromise = null; this.syncPreviewResultPromise = null;
} }
private hasErrors(content: string): boolean { private getPreview(remoteUserData: IUserData, lastSyncUserData: IUserData | null, resolvedConflicts: { key: string, value: any }[]): Promise<IFileSyncPreviewResult> {
const parseErrors: ParseError[] = [];
parse(content, parseErrors, { allowEmptyContent: true, allowTrailingComma: true });
return parseErrors.length > 0;
}
private getPreview(resolvedConflicts: { key: string, value: any }[]): Promise<ISyncPreviewResult> {
if (!this.syncPreviewResultPromise) { if (!this.syncPreviewResultPromise) {
this.syncPreviewResultPromise = createCancelablePromise(token => this.generatePreview(resolvedConflicts, token)); this.syncPreviewResultPromise = createCancelablePromise(token => this.generatePreview(remoteUserData, lastSyncUserData, resolvedConflicts, token));
} }
return this.syncPreviewResultPromise; return this.syncPreviewResultPromise;
} }
private async generatePreview(resolvedConflicts: { key: string, value: any }[], token: CancellationToken): Promise<ISyncPreviewResult> { protected async generatePreview(remoteUserData: IUserData, lastSyncUserData: IUserData | null, resolvedConflicts: { key: string, value: any }[], token: CancellationToken): Promise<IFileSyncPreviewResult> {
const lastSyncUserData = await this.getLastSyncUserData();
const remoteUserData = await this.getRemoteUserData(lastSyncUserData);
// Get file content last to get the latest
const fileContent = await this.getLocalFileContent(); const fileContent = await this.getLocalFileContent();
const formatUtils = await this.getFormattingOptions(); const formattingOptions = await this.getFormattingOptions();
let content: string | null = null; let content: string | null = null;
let hasLocalChanged: boolean = false; let hasLocalChanged: boolean = false;
@@ -370,12 +302,12 @@ export class SettingsSynchroniser extends AbstractFileSynchroniser implements IS
// No action when there are errors // No action when there are errors
if (this.hasErrors(localContent)) { if (this.hasErrors(localContent)) {
this.logService.error('Settings: Unable to sync settings as there are errors/warning in settings file.'); throw new UserDataSyncError(localize('errorInvalidSettings', "Unable to sync settings as there are errors/warning in settings file."), UserDataSyncErrorCode.LocalInvalidContent, this.source);
} }
else { else {
this.logService.trace('Settings: Merging remote settings with local settings...'); this.logService.trace('Settings: Merging remote settings with local settings...');
const result = merge(localContent, remoteUserData.content, lastSyncUserData ? lastSyncUserData.content : null, getIgnoredSettings(this.configurationService), resolvedConflicts, formatUtils); const result = merge(localContent, remoteUserData.content, lastSyncUserData ? lastSyncUserData.content : null, getIgnoredSettings(this.configurationService), resolvedConflicts, formattingOptions);
content = result.localContent || result.remoteContent; content = result.localContent || result.remoteContent;
hasLocalChanged = result.localContent !== null; hasLocalChanged = result.localContent !== null;
hasRemoteChanged = result.remoteContent !== null; hasRemoteChanged = result.remoteContent !== null;
@@ -393,20 +325,12 @@ export class SettingsSynchroniser extends AbstractFileSynchroniser implements IS
if (content && !token.isCancellationRequested) { if (content && !token.isCancellationRequested) {
// Remove the ignored settings from the preview. // Remove the ignored settings from the preview.
const previewContent = updateIgnoredSettings(content, '{}', getIgnoredSettings(this.configurationService), formatUtils); const previewContent = updateIgnoredSettings(content, '{}', getIgnoredSettings(this.configurationService), formattingOptions);
await this.fileService.writeFile(this.environmentService.settingsSyncPreviewResource, VSBuffer.fromString(previewContent)); await this.fileService.writeFile(this.environmentService.settingsSyncPreviewResource, VSBuffer.fromString(previewContent));
} }
this.setConflicts(conflictSettings); this.setConflicts(conflictSettings);
return { fileContent, remoteUserData, lastSyncUserData, content, hasLocalChanged, hasRemoteChanged, conflictSettings, hasConflicts }; return { fileContent, remoteUserData, lastSyncUserData, content, hasLocalChanged, hasRemoteChanged, hasConflicts };
}
private _formattingOptions: Promise<FormattingOptions> | undefined = undefined;
private getFormattingOptions(): Promise<FormattingOptions> {
if (!this._formattingOptions) {
this._formattingOptions = this.userDataSyncUtilService.resolveFormattingOptions(this.environmentService.settingsResource);
}
return this._formattingOptions;
} }
} }

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