Merge branch 'main' into fix-156481

This commit is contained in:
John Murray
2022-08-06 21:55:58 +01:00
committed by GitHub
576 changed files with 7303 additions and 7419 deletions
+1
View File
@@ -259,6 +259,7 @@
"windows-process-tree",
"worker_threads",
"xterm",
"xterm-addon-canvas",
"xterm-addon-search",
"xterm-addon-serialize",
"xterm-addon-unicode11",
+2 -2
View File
@@ -197,10 +197,10 @@
},
{
"type": "label",
"name": "~needs version info",
"name": "~version-info-needed",
"action": "updateLabels",
"addLabel": "info-needed",
"removeLabel": "~needs version info",
"removeLabel": "~version-info-needed",
"comment": "Thanks for creating this issue! We figured it's missing some basic information, such as a version number, or in some other way doesn't follow our [issue reporting guidelines](https://aka.ms/vscodeissuereporting). Please take the time to review these and update the issue.\n\nHappy Coding!"
},
{
+3 -6
View File
@@ -39,8 +39,7 @@ jobs:
uses: actions/cache@v3
with:
path: "**/node_modules"
key: ${{ runner.os }}-cacheNodeModules22-${{ steps.nodeModulesCacheKey.outputs.value }}
restore-keys: ${{ runner.os }}-cacheNodeModules22-
key: ${{ runner.os }}-cacheNodeModulesLinux-${{ steps.nodeModulesCacheKey.outputs.value }}
- name: Get yarn cache directory path
id: yarnCacheDirPath
if: ${{ steps.cacheNodeModules.outputs.cache-hit != 'true' }}
@@ -92,8 +91,7 @@ jobs:
uses: actions/cache@v3
with:
path: "**/node_modules"
key: ${{ runner.os }}-cacheNodeModules22-${{ steps.nodeModulesCacheKey.outputs.value }}
restore-keys: ${{ runner.os }}-cacheNodeModules22-
key: ${{ runner.os }}-cacheNodeModulesLinux-${{ steps.nodeModulesCacheKey.outputs.value }}
- name: Get yarn cache directory path
id: yarnCacheDirPath
if: ${{ steps.cacheNodeModules.outputs.cache-hit != 'true' }}
@@ -155,8 +153,7 @@ jobs:
uses: actions/cache@v3
with:
path: "**/node_modules"
key: ${{ runner.os }}-cacheNodeModules22-${{ steps.nodeModulesCacheKey.outputs.value }}
restore-keys: ${{ runner.os }}-cacheNodeModules22-
key: ${{ runner.os }}-cacheNodeModulesLinux-${{ steps.nodeModulesCacheKey.outputs.value }}
- name: Get yarn cache directory path
id: yarnCacheDirPath
if: ${{ steps.cacheNodeModules.outputs.cache-hit != 'true' }}
+3 -6
View File
@@ -125,8 +125,7 @@ jobs:
uses: actions/cache@v2
with:
path: "**/node_modules"
key: ${{ runner.os }}-cacheNodeModules22-${{ steps.nodeModulesCacheKey.outputs.value }}
restore-keys: ${{ runner.os }}-cacheNodeModules22-
key: ${{ runner.os }}-cacheNodeModulesLinux-${{ steps.nodeModulesCacheKey.outputs.value }}
- name: Get yarn cache directory path
id: yarnCacheDirPath
if: ${{ steps.cacheNodeModules.outputs.cache-hit != 'true' }}
@@ -197,8 +196,7 @@ jobs:
uses: actions/cache@v2
with:
path: "**/node_modules"
key: ${{ runner.os }}-cacheNodeModules22-${{ steps.nodeModulesCacheKey.outputs.value }}
restore-keys: ${{ runner.os }}-cacheNodeModules22-
key: ${{ runner.os }}-cacheNodeModulesMacOS-${{ steps.nodeModulesCacheKey.outputs.value }}
- name: Get yarn cache directory path
id: yarnCacheDirPath
if: ${{ steps.cacheNodeModules.outputs.cache-hit != 'true' }}
@@ -271,8 +269,7 @@ jobs:
uses: actions/cache@v2
with:
path: "**/node_modules"
key: ${{ runner.os }}-cacheNodeModules22-${{ steps.nodeModulesCacheKey.outputs.value }}
restore-keys: ${{ runner.os }}-cacheNodeModules22-
key: ${{ runner.os }}-cacheNodeModulesLinux-${{ steps.nodeModulesCacheKey.outputs.value }}
- name: Get yarn cache directory path
id: yarnCacheDirPath
if: ${{ steps.cacheNodeModules.outputs.cache-hit != 'true' }}
+1 -1
View File
@@ -7,7 +7,7 @@
{
"kind": 2,
"language": "github-issues",
"value": "$repo=repo:microsoft/vscode\n$milestone=milestone:\"July 2022\""
"value": "$repo=repo:microsoft/vscode\n$milestone=milestone:\"August 2022\""
},
{
"kind": 1,
+1 -1
View File
@@ -1,4 +1,4 @@
disturl "https://electronjs.org/headers"
target "18.3.5"
target "19.0.11"
runtime "electron"
build_from_source "true"
+1 -1
View File
@@ -1 +1 @@
2022-07-12T09:44:15.185Z
2022-08-01T11:24:47.411Z
+3
View File
@@ -20,6 +20,9 @@ vscode-textmate/webpack.config.js
xterm/src/**
xterm-addon-canvas/src/**
xterm-addon-canvas/out/**
xterm-addon-search/src/**
xterm-addon-search/out/**
xterm-addon-search/fixtures/**
@@ -0,0 +1,15 @@
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
const fs = require("fs");
const path = require("path");
const crypto = require("crypto");
const productjson = JSON.parse(fs.readFileSync(path.join(__dirname, '../../../product.json'), 'utf8'));
const shasum = crypto.createHash('sha1');
for (const ext of productjson.builtInExtensions) {
shasum.update(`${ext.name}@${ext.version}`);
}
process.stdout.write(shasum.digest('hex'));
@@ -0,0 +1,17 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as fs from 'fs';
import * as path from 'path';
import * as crypto from 'crypto';
const productjson = JSON.parse(fs.readFileSync(path.join(__dirname, '../../../product.json'), 'utf8'));
const shasum = crypto.createHash('sha1');
for (const ext of productjson.builtInExtensions) {
shasum.update(`${ext.name}@${ext.version}`);
}
process.stdout.write(shasum.digest('hex'));
@@ -38,6 +38,7 @@ steps:
- script: |
mkdir -p .build
node build/azure-pipelines/common/computeNodeModulesCacheKey.js x64 $ENABLE_TERRAPIN > .build/yarnlockhash
node build/azure-pipelines/common/computeBuiltInDepsCacheKey.js > .build/builtindepshash
displayName: Prepare yarn cache flags
- task: Cache@2
@@ -47,6 +48,12 @@ steps:
cacheHitVar: NODE_MODULES_RESTORED
displayName: Restore node_modules cache
- task: Cache@2
inputs:
key: '"builtInDeps" | .build/builtindepshash'
path: .build/builtInExtensions
displayName: Restore built-in extensions
- script: |
set -e
tar -xzf .build/node_modules_cache/cache.tgz
@@ -88,6 +95,13 @@ steps:
displayName: Install dependencies
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
- script: |
set -e
node build/lib/builtInExtensions.js
env:
GITHUB_TOKEN: "$(github-distro-mixin-password)"
displayName: Download missing built-in extensions
- script: |
set -e
node build/azure-pipelines/common/listNodeModules.js .build/node_modules_list.txt
@@ -38,6 +38,7 @@ steps:
- script: |
mkdir -p .build
node build/azure-pipelines/common/computeNodeModulesCacheKey.js x64 $ENABLE_TERRAPIN > .build/yarnlockhash
node build/azure-pipelines/common/computeBuiltInDepsCacheKey.js > .build/builtindepshash
displayName: Prepare yarn cache flags
- task: Cache@2
@@ -47,6 +48,12 @@ steps:
cacheHitVar: NODE_MODULES_RESTORED
displayName: Restore node_modules cache
- task: Cache@2
inputs:
key: '"builtInDeps" | .build/builtindepshash'
path: .build/builtInExtensions
displayName: Restore built-in extensions
- script: |
set -e
tar -xzf .build/node_modules_cache/cache.tgz
@@ -88,6 +95,13 @@ steps:
displayName: Install dependencies
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
- script: |
set -e
node build/lib/builtInExtensions.js
env:
GITHUB_TOKEN: "$(github-distro-mixin-password)"
displayName: Download missing built-in extensions
- script: |
set -e
node build/azure-pipelines/common/listNodeModules.js .build/node_modules_list.txt
@@ -72,6 +72,7 @@ steps:
- script: |
mkdir -p .build
node build/azure-pipelines/common/computeNodeModulesCacheKey.js $VSCODE_ARCH $ENABLE_TERRAPIN > .build/yarnlockhash
node build/azure-pipelines/common/computeBuiltInDepsCacheKey.js > .build/builtindepshash
displayName: Prepare yarn cache flags
- task: Cache@2
@@ -81,6 +82,12 @@ steps:
cacheHitVar: NODE_MODULES_RESTORED
displayName: Restore node_modules cache
- task: Cache@2
inputs:
key: '"builtInDeps" | .build/builtindepshash'
path: .build/builtInExtensions
displayName: Restore built-in extensions
- script: |
set -e
tar -xzf .build/node_modules_cache/cache.tgz
@@ -115,6 +122,13 @@ steps:
displayName: Install dependencies
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
- script: |
set -e
node build/lib/builtInExtensions.js
env:
GITHUB_TOKEN: "$(github-distro-mixin-password)"
displayName: Download missing built-in extensions
- script: |
set -e
node build/azure-pipelines/common/listNodeModules.js .build/node_modules_list.txt
@@ -58,6 +58,7 @@ steps:
- script: |
mkdir -p .build
node build/azure-pipelines/common/computeNodeModulesCacheKey.js "alpine" $ENABLE_TERRAPIN > .build/yarnlockhash
node build/azure-pipelines/common/computeBuiltInDepsCacheKey.js > .build/builtindepshash
displayName: Prepare yarn cache flags
- task: Cache@2
@@ -67,6 +68,12 @@ steps:
cacheHitVar: NODE_MODULES_RESTORED
displayName: Restore node_modules cache
- task: Cache@2
inputs:
key: '"builtInDeps" | .build/builtindepshash'
path: .build/builtInExtensions
displayName: Restore built-in extensions
- script: |
set -e
tar -xzf .build/node_modules_cache/cache.tgz
@@ -98,6 +105,13 @@ steps:
displayName: Install dependencies
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
- script: |
set -e
node build/lib/builtInExtensions.js
env:
GITHUB_TOKEN: "$(github-distro-mixin-password)"
displayName: Download missing built-in extensions
- script: |
set -e
node build/azure-pipelines/common/listNodeModules.js .build/node_modules_list.txt
@@ -91,14 +91,30 @@ steps:
- script: |
mkdir -p .build
node build/azure-pipelines/common/computeNodeModulesCacheKey.js $VSCODE_ARCH $ENABLE_TERRAPIN > .build/yarnlockhash
node build/azure-pipelines/common/computeBuiltInDepsCacheKey.js > .build/builtindepshash
displayName: Prepare yarn cache flags
- ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}:
- task: Cache@2
inputs:
key: "genericNodeModules | $(Agent.OS) | .build/yarnlockhash"
path: .build/node_modules_cache
cacheHitVar: NODE_MODULES_RESTORED
displayName: Restore node_modules cache
- ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}:
- task: Cache@2
inputs:
key: "nodeModules | $(Agent.OS) | .build/yarnlockhash"
path: .build/node_modules_cache
cacheHitVar: NODE_MODULES_RESTORED
displayName: Restore node_modules cache
- task: Cache@2
inputs:
key: "nodeModules | $(Agent.OS) | .build/yarnlockhash"
path: .build/node_modules_cache
cacheHitVar: NODE_MODULES_RESTORED
displayName: Restore node_modules cache
key: '"builtInDeps" | .build/builtindepshash'
path: .build/builtInExtensions
displayName: Restore built-in extensions
- script: |
set -e
@@ -178,6 +194,13 @@ steps:
displayName: Install dependencies
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
- script: |
set -e
node build/lib/builtInExtensions.js
env:
GITHUB_TOKEN: "$(github-distro-mixin-password)"
displayName: Download missing built-in extensions
- ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}:
- script: |
set -e
@@ -10,6 +10,7 @@ steps:
- script: |
mkdir -p .build
node build/azure-pipelines/common/computeNodeModulesCacheKey.js $VSCODE_ARCH $ENABLE_TERRAPIN > .build/yarnlockhash
node build/azure-pipelines/common/computeBuiltInDepsCacheKey.js > .build/builtindepshash
displayName: Prepare yarn cache flags
- task: Cache@2
@@ -19,6 +20,12 @@ steps:
cacheHitVar: NODE_MODULES_RESTORED
displayName: Restore node_modules cache
- task: Cache@2
inputs:
key: '"builtInDeps" | .build/builtindepshash'
path: .build/builtInExtensions
displayName: Restore built-in extensions
- script: |
set -e
tar -xzf .build/node_modules_cache/cache.tgz
@@ -50,6 +57,13 @@ steps:
displayName: Install dependencies
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
- script: |
set -e
node build/lib/builtInExtensions.js
env:
GITHUB_TOKEN: "$(github-distro-mixin-password)"
displayName: Download missing built-in extensions
- script: |
set -e
node build/azure-pipelines/common/listNodeModules.js .build/node_modules_list.txt
+160 -166
View File
@@ -22,174 +22,168 @@ variables:
- name: VSCODE_STEP_ON_IT
value: false
stages:
- ${{ if eq(variables['VSCODE_CIBUILD'], true) }}:
- stage: MaintainNodeModulesCache
displayName: Maintain node_modules cache
jobs:
- job: MaintainNodeModulesCache
displayName: Maintain node_modules cache
pool: vscode-1es-vscode-linux-20.04
steps:
- template: product-build-pr-cache.yml
jobs:
- ${{ if ne(variables['VSCODE_CIBUILD'], true) }}:
- stage: Compile
- job: Compile
displayName: Compile & Hygiene
jobs:
- job: Compile
displayName: Compile & Hygiene
pool: vscode-1es-vscode-linux-20.04
variables:
VSCODE_ARCH: x64
steps:
- template: product-compile.yml
parameters:
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
pool: vscode-1es-vscode-linux-20.04
timeoutInMinutes: 30
variables:
VSCODE_ARCH: x64
steps:
- template: product-compile.yml
parameters:
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
- stage: Test
dependsOn: []
jobs:
- job: Linuxx64UnitTest
displayName: Linux (Unit Tests)
pool: vscode-1es-vscode-linux-20.04
# container: vscode-bionic-x64
timeoutInMinutes: 60
variables:
VSCODE_ARCH: x64
NPM_ARCH: x64
DISPLAY: ":10"
steps:
- template: linux/product-build-linux-client.yml
parameters:
VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }}
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
VSCODE_RUN_UNIT_TESTS: true
VSCODE_RUN_INTEGRATION_TESTS: false
VSCODE_RUN_SMOKE_TESTS: false
- job: Linuxx64IntegrationTest
displayName: Linux (Integration Tests)
pool: vscode-1es-vscode-linux-20.04
# container: vscode-bionic-x64
timeoutInMinutes: 60
variables:
VSCODE_ARCH: x64
NPM_ARCH: x64
DISPLAY: ":10"
steps:
- template: linux/product-build-linux-client.yml
parameters:
VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }}
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
VSCODE_RUN_UNIT_TESTS: false
VSCODE_RUN_INTEGRATION_TESTS: true
VSCODE_RUN_SMOKE_TESTS: false
- job: Linuxx64SmokeTest
displayName: Linux (Smoke Tests)
pool: vscode-1es-vscode-linux-20.04
# container: vscode-bionic-x64
timeoutInMinutes: 60
variables:
VSCODE_ARCH: x64
NPM_ARCH: x64
DISPLAY: ":10"
steps:
- template: linux/product-build-linux-client.yml
parameters:
VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }}
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
VSCODE_RUN_UNIT_TESTS: false
VSCODE_RUN_INTEGRATION_TESTS: false
VSCODE_RUN_SMOKE_TESTS: true
- job: Linuxx64UnitTest
displayName: Linux (Unit Tests)
pool: vscode-1es-vscode-linux-20.04
timeoutInMinutes: 30
variables:
VSCODE_ARCH: x64
NPM_ARCH: x64
DISPLAY: ":10"
steps:
- template: linux/product-build-linux-client.yml
parameters:
VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }}
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
VSCODE_RUN_UNIT_TESTS: true
VSCODE_RUN_INTEGRATION_TESTS: false
VSCODE_RUN_SMOKE_TESTS: false
# - job: macOSUnitTest
# displayName: macOS (Unit Tests)
# pool:
# vmImage: macOS-latest
# timeoutInMinutes: 60
# variables:
# BUILDSECMON_OPT_IN: true
# VSCODE_ARCH: x64
# steps:
# - template: darwin/product-build-darwin.yml
# parameters:
# VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }}
# VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
# VSCODE_RUN_UNIT_TESTS: true
# VSCODE_RUN_INTEGRATION_TESTS: false
# VSCODE_RUN_SMOKE_TESTS: false
# - job: macOSIntegrationTest
# displayName: macOS (Integration Tests)
# pool:
# vmImage: macOS-latest
# timeoutInMinutes: 60
# variables:
# BUILDSECMON_OPT_IN: true
# VSCODE_ARCH: x64
# steps:
# - template: darwin/product-build-darwin.yml
# parameters:
# VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }}
# VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
# VSCODE_RUN_UNIT_TESTS: false
# VSCODE_RUN_INTEGRATION_TESTS: true
# VSCODE_RUN_SMOKE_TESTS: false
# - job: macOSSmokeTest
# displayName: macOS (Smoke Tests)
# pool:
# vmImage: macOS-latest
# timeoutInMinutes: 60
# variables:
# BUILDSECMON_OPT_IN: true
# VSCODE_ARCH: x64
# steps:
# - template: darwin/product-build-darwin.yml
# parameters:
# VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }}
# VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
# VSCODE_RUN_UNIT_TESTS: false
# VSCODE_RUN_INTEGRATION_TESTS: false
# VSCODE_RUN_SMOKE_TESTS: true
- job: Linuxx64IntegrationTest
displayName: Linux (Integration Tests)
pool: vscode-1es-vscode-linux-20.04
timeoutInMinutes: 30
variables:
VSCODE_ARCH: x64
NPM_ARCH: x64
DISPLAY: ":10"
steps:
- template: linux/product-build-linux-client.yml
parameters:
VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }}
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
VSCODE_RUN_UNIT_TESTS: false
VSCODE_RUN_INTEGRATION_TESTS: true
VSCODE_RUN_SMOKE_TESTS: false
# - job: WindowsUnitTests
# displayName: Windows (Unit Tests)
# pool: vscode-1es-vscode-windows-2019
# timeoutInMinutes: 60
# variables:
# VSCODE_ARCH: x64
# steps:
# - template: win32/product-build-win32.yml
# parameters:
# VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }}
# VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
# VSCODE_RUN_UNIT_TESTS: true
# VSCODE_RUN_INTEGRATION_TESTS: false
# VSCODE_RUN_SMOKE_TESTS: false
# - job: WindowsIntegrationTests
# displayName: Windows (Integration Tests)
# pool: vscode-1es-vscode-windows-2019
# timeoutInMinutes: 60
# variables:
# VSCODE_ARCH: x64
# steps:
# - template: win32/product-build-win32.yml
# parameters:
# VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }}
# VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
# VSCODE_RUN_UNIT_TESTS: false
# VSCODE_RUN_INTEGRATION_TESTS: true
# VSCODE_RUN_SMOKE_TESTS: false
# - job: WindowsSmokeTests
# displayName: Windows (Smoke Tests)
# pool: vscode-1es-vscode-windows-2019
# timeoutInMinutes: 60
# variables:
# VSCODE_ARCH: x64
# steps:
# - template: win32/product-build-win32.yml
# parameters:
# VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }}
# VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
# VSCODE_RUN_UNIT_TESTS: false
# VSCODE_RUN_INTEGRATION_TESTS: false
# VSCODE_RUN_SMOKE_TESTS: true
- job: Linuxx64SmokeTest
displayName: Linux (Smoke Tests)
pool: vscode-1es-vscode-linux-20.04
timeoutInMinutes: 30
variables:
VSCODE_ARCH: x64
NPM_ARCH: x64
DISPLAY: ":10"
steps:
- template: linux/product-build-linux-client.yml
parameters:
VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }}
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
VSCODE_RUN_UNIT_TESTS: false
VSCODE_RUN_INTEGRATION_TESTS: false
VSCODE_RUN_SMOKE_TESTS: true
- ${{ if eq(variables['VSCODE_CIBUILD'], true) }}:
- job: Linuxx64MaintainNodeModulesCache
displayName: Linux (Maintain node_modules cache)
pool: vscode-1es-vscode-linux-20.04
timeoutInMinutes: 30
variables:
VSCODE_ARCH: x64
steps:
- template: product-build-pr-cache.yml
# - job: macOSUnitTest
# displayName: macOS (Unit Tests)
# pool:
# vmImage: macOS-latest
# timeoutInMinutes: 60
# variables:
# BUILDSECMON_OPT_IN: true
# VSCODE_ARCH: x64
# steps:
# - template: darwin/product-build-darwin.yml
# parameters:
# VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }}
# VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
# VSCODE_RUN_UNIT_TESTS: true
# VSCODE_RUN_INTEGRATION_TESTS: false
# VSCODE_RUN_SMOKE_TESTS: false
# - job: macOSIntegrationTest
# displayName: macOS (Integration Tests)
# pool:
# vmImage: macOS-latest
# timeoutInMinutes: 60
# variables:
# BUILDSECMON_OPT_IN: true
# VSCODE_ARCH: x64
# steps:
# - template: darwin/product-build-darwin.yml
# parameters:
# VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }}
# VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
# VSCODE_RUN_UNIT_TESTS: false
# VSCODE_RUN_INTEGRATION_TESTS: true
# VSCODE_RUN_SMOKE_TESTS: false
# - job: macOSSmokeTest
# displayName: macOS (Smoke Tests)
# pool:
# vmImage: macOS-latest
# timeoutInMinutes: 60
# variables:
# BUILDSECMON_OPT_IN: true
# VSCODE_ARCH: x64
# steps:
# - template: darwin/product-build-darwin.yml
# parameters:
# VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }}
# VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
# VSCODE_RUN_UNIT_TESTS: false
# VSCODE_RUN_INTEGRATION_TESTS: false
# VSCODE_RUN_SMOKE_TESTS: true
# - job: WindowsUnitTests
# displayName: Windows (Unit Tests)
# pool: vscode-1es-vscode-windows-2019
# timeoutInMinutes: 60
# variables:
# VSCODE_ARCH: x64
# steps:
# - template: win32/product-build-win32.yml
# parameters:
# VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }}
# VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
# VSCODE_RUN_UNIT_TESTS: true
# VSCODE_RUN_INTEGRATION_TESTS: false
# VSCODE_RUN_SMOKE_TESTS: false
# - job: WindowsIntegrationTests
# displayName: Windows (Integration Tests)
# pool: vscode-1es-vscode-windows-2019
# timeoutInMinutes: 60
# variables:
# VSCODE_ARCH: x64
# steps:
# - template: win32/product-build-win32.yml
# parameters:
# VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }}
# VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
# VSCODE_RUN_UNIT_TESTS: false
# VSCODE_RUN_INTEGRATION_TESTS: true
# VSCODE_RUN_SMOKE_TESTS: false
# - job: WindowsSmokeTests
# displayName: Windows (Smoke Tests)
# pool: vscode-1es-vscode-windows-2019
# timeoutInMinutes: 60
# variables:
# VSCODE_ARCH: x64
# steps:
# - template: win32/product-build-win32.yml
# parameters:
# VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }}
# VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
# VSCODE_RUN_UNIT_TESTS: false
# VSCODE_RUN_INTEGRATION_TESTS: false
# VSCODE_RUN_SMOKE_TESTS: true
+15
View File
@@ -46,6 +46,7 @@ steps:
- script: |
mkdir -p .build
node build/azure-pipelines/common/computeNodeModulesCacheKey.js $VSCODE_ARCH $ENABLE_TERRAPIN > .build/yarnlockhash
node build/azure-pipelines/common/computeBuiltInDepsCacheKey.js > .build/builtindepshash
displayName: Prepare yarn cache flags
# using `genericNodeModules` instead of `nodeModules` here to avoid sharing the cache with builds running inside containers
@@ -56,6 +57,13 @@ steps:
cacheHitVar: NODE_MODULES_RESTORED
displayName: Restore node_modules cache
# Cache built-in extensions to avoid GH rate limits.
- task: Cache@2
inputs:
key: '"builtInDeps" | .build/builtindepshash'
path: .build/builtInExtensions
displayName: Restore built-in extensions
- script: |
set -e
tar -xzf .build/node_modules_cache/cache.tgz
@@ -94,6 +102,13 @@ steps:
displayName: Install dependencies
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
- script: |
set -e
node build/lib/builtInExtensions.js
env:
GITHUB_TOKEN: "$(github-distro-mixin-password)"
displayName: Download missing built-in extensions
- script: |
set -e
node build/azure-pipelines/common/listNodeModules.js .build/node_modules_list.txt
@@ -49,6 +49,7 @@ steps:
- script: |
mkdir -p .build
node build/azure-pipelines/common/computeNodeModulesCacheKey.js "web" $ENABLE_TERRAPIN > .build/yarnlockhash
node build/azure-pipelines/common/computeBuiltInDepsCacheKey.js > .build/builtindepshash
displayName: Prepare yarn cache flags
- task: Cache@2
@@ -58,6 +59,12 @@ steps:
cacheHitVar: NODE_MODULES_RESTORED
displayName: Restore node_modules cache
- task: Cache@2
inputs:
key: '"builtInDeps" | .build/builtindepshash'
path: .build/builtInExtensions
displayName: Restore built-in extensions
- script: |
set -e
tar -xzf .build/node_modules_cache/cache.tgz
@@ -89,6 +96,13 @@ steps:
displayName: Install dependencies
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
- script: |
set -e
node build/lib/builtInExtensions.js
env:
GITHUB_TOKEN: "$(github-distro-mixin-password)"
displayName: Download missing built-in extensions
- script: |
set -e
node build/azure-pipelines/common/listNodeModules.js .build/node_modules_list.txt
@@ -36,8 +36,8 @@ steps:
- powershell: |
. build/azure-pipelines/win32/exec.ps1
$ErrorActionPreference = "Stop"
exec { node test/unit/browser/index.js --sequential --browser chromium --browser firefox --tfs "Browser Unit Tests" }
displayName: Run unit tests (Browser, Chromium & Firefox)
exec { node test/unit/browser/index.js --sequential --browser chromium --tfs "Browser Unit Tests" }
displayName: Run unit tests (Browser, Chromium)
timeoutInMinutes: 20
- ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}:
@@ -59,8 +59,8 @@ steps:
- powershell: |
. build/azure-pipelines/win32/exec.ps1
$ErrorActionPreference = "Stop"
exec { yarn test-browser-no-install --sequential --build --browser chromium --browser firefox --tfs "Browser Unit Tests" }
displayName: Run unit tests (Browser, Chromium & Firefox)
exec { yarn test-browser-no-install --sequential --build --browser chromium --tfs "Browser Unit Tests" }
displayName: Run unit tests (Browser, Chromium)
timeoutInMinutes: 20
- ${{ if eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true) }}:
@@ -80,6 +80,7 @@ steps:
"$(VSCODE_ARCH)" | Out-File -Encoding ascii -NoNewLine .build\arch
"$env:ENABLE_TERRAPIN" | Out-File -Encoding ascii -NoNewLine .build\terrapin
node build/azure-pipelines/common/computeNodeModulesCacheKey.js > .build/yarnlockhash
node build/azure-pipelines/common/computeBuiltInDepsCacheKey.js > .build/builtindepshash
displayName: Prepare yarn cache flags
- task: Cache@2
@@ -89,6 +90,12 @@ steps:
cacheHitVar: NODE_MODULES_RESTORED
displayName: Restore node_modules cache
- task: Cache@2
inputs:
key: '"builtInDeps" | .build/builtindepshash'
path: .build/builtInExtensions
displayName: Restore built-in extensions
- powershell: |
. build/azure-pipelines/win32/exec.ps1
$ErrorActionPreference = "Stop"
@@ -119,6 +126,14 @@ steps:
displayName: Install dependencies
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
- powershell: |
. build/azure-pipelines/win32/exec.ps1
$ErrorActionPreference = "Stop"
exec { node build/lib/builtInExtensions.js }
env:
GITHUB_TOKEN: "$(github-distro-mixin-password)"
displayName: Download missing built-in extensions
- powershell: |
. build/azure-pipelines/win32/exec.ps1
$ErrorActionPreference = "Stop"
+1 -1
View File
@@ -236,8 +236,8 @@ exports.compileExtensionMediaBuildTask = compileExtensionMediaBuildTask;
const cleanExtensionsBuildTask = task.define('clean-extensions-build', util.rimraf('.build/extensions'));
const compileExtensionsBuildTask = task.define('compile-extensions-build', task.series(
cleanExtensionsBuildTask,
task.define('bundle-marketplace-extensions-build', () => ext.packageMarketplaceExtensionsStream(false).pipe(gulp.dest('.build'))),
task.define('bundle-extensions-build', () => ext.packageLocalExtensionsStream(false).pipe(gulp.dest('.build'))),
task.define('bundle-marketplace-extensions-build', () => ext.packageMarketplaceExtensionsStream(false, product.extensionsGallery?.serviceUrl).pipe(gulp.dest('.build'))),
));
gulp.task(compileExtensionsBuildTask);
+1 -1
View File
@@ -229,7 +229,7 @@ function packageTask(sourceFolderName, destinationFolderName) {
const compileWebExtensionsBuildTask = task.define('compile-web-extensions-build', task.series(
task.define('clean-web-extensions-build', util.rimraf('.build/web/extensions')),
task.define('bundle-web-extensions-build', () => extensions.packageLocalExtensionsStream(true).pipe(gulp.dest('.build/web'))),
task.define('bundle-marketplace-web-extensions-build', () => extensions.packageMarketplaceExtensionsStream(true, product.extensionsGallery?.serviceUrl).pipe(gulp.dest('.build/web'))),
task.define('bundle-marketplace-web-extensions-build', () => extensions.packageMarketplaceExtensionsStream(true).pipe(gulp.dest('.build/web'))),
task.define('bundle-web-extension-media-build', () => extensions.buildExtensionMedia(false, '.build/web/extensions')),
));
gulp.task(compileWebExtensionsBuildTask);
+17 -3
View File
@@ -4,7 +4,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.getBuiltInExtensions = void 0;
exports.getBuiltInExtensions = exports.getExtensionStream = void 0;
const fs = require("fs");
const path = require("path");
const os = require("os");
@@ -44,6 +44,21 @@ function isUpToDate(extension) {
return false;
}
}
function getExtensionDownloadStream(extension) {
const galleryServiceUrl = productjson.extensionsGallery?.serviceUrl;
return (galleryServiceUrl ? ext.fromMarketplace(galleryServiceUrl, extension) : ext.fromGithub(extension))
.pipe(rename(p => p.dirname = `${extension.name}/${p.dirname}`));
}
function getExtensionStream(extension) {
// if the extension exists on disk, use those files instead of downloading anew
if (isUpToDate(extension)) {
log('[extensions]', `${extension.name}@${extension.version} up to date`, ansiColors.green('✔︎'));
return vfs.src(['**'], { cwd: getExtensionPath(extension), dot: true })
.pipe(rename(p => p.dirname = `${extension.name}/${p.dirname}`));
}
return getExtensionDownloadStream(extension);
}
exports.getExtensionStream = getExtensionStream;
function syncMarketplaceExtension(extension) {
const galleryServiceUrl = productjson.extensionsGallery?.serviceUrl;
const source = ansiColors.blue(galleryServiceUrl ? '[marketplace]' : '[github]');
@@ -52,8 +67,7 @@ function syncMarketplaceExtension(extension) {
return es.readArray([]);
}
rimraf.sync(getExtensionPath(extension));
return (galleryServiceUrl ? ext.fromMarketplace(galleryServiceUrl, extension) : ext.fromGithub(extension))
.pipe(rename(p => p.dirname = `${extension.name}/${p.dirname}`))
return getExtensionDownloadStream(extension)
.pipe(vfs.dest('.build/builtInExtensions'))
.on('end', () => log(source, extension.name, ansiColors.green('✔︎')));
}
+18 -3
View File
@@ -68,10 +68,26 @@ function isUpToDate(extension: IExtensionDefinition): boolean {
}
}
function getExtensionDownloadStream(extension: IExtensionDefinition) {
const galleryServiceUrl = productjson.extensionsGallery?.serviceUrl;
return (galleryServiceUrl ? ext.fromMarketplace(galleryServiceUrl, extension) : ext.fromGithub(extension))
.pipe(rename(p => p.dirname = `${extension.name}/${p.dirname}`));
}
export function getExtensionStream(extension: IExtensionDefinition) {
// if the extension exists on disk, use those files instead of downloading anew
if (isUpToDate(extension)) {
log('[extensions]', `${extension.name}@${extension.version} up to date`, ansiColors.green('✔︎'));
return vfs.src(['**'], { cwd: getExtensionPath(extension), dot: true })
.pipe(rename(p => p.dirname = `${extension.name}/${p.dirname}`));
}
return getExtensionDownloadStream(extension);
}
function syncMarketplaceExtension(extension: IExtensionDefinition): Stream {
const galleryServiceUrl = productjson.extensionsGallery?.serviceUrl;
const source = ansiColors.blue(galleryServiceUrl ? '[marketplace]' : '[github]');
if (isUpToDate(extension)) {
log(source, `${extension.name}@${extension.version}`, ansiColors.green('✔︎'));
return es.readArray([]);
@@ -79,8 +95,7 @@ function syncMarketplaceExtension(extension: IExtensionDefinition): Stream {
rimraf.sync(getExtensionPath(extension));
return (galleryServiceUrl ? ext.fromMarketplace(galleryServiceUrl, extension) : ext.fromGithub(extension))
.pipe(rename(p => p.dirname = `${extension.name}/${p.dirname}`))
return getExtensionDownloadStream(extension)
.pipe(vfs.dest('.build/builtInExtensions'))
.on('end', () => log(source, extension.name, ansiColors.green('✔︎')));
}
+5 -4
View File
@@ -25,6 +25,7 @@ const buffer = require('gulp-buffer');
const jsoncParser = require("jsonc-parser");
const dependencies_1 = require("./dependencies");
const _ = require("underscore");
const builtInExtensions_1 = require("./builtInExtensions");
const util = require('./util');
const root = path.dirname(path.dirname(__dirname));
const commit = util.getVersion(root);
@@ -312,16 +313,15 @@ function packageLocalExtensionsStream(forWeb) {
.pipe(util2.setExecutableBit(['**/*.sh'])));
}
exports.packageLocalExtensionsStream = packageLocalExtensionsStream;
function packageMarketplaceExtensionsStream(forWeb, galleryServiceUrl) {
function packageMarketplaceExtensionsStream(forWeb) {
const marketplaceExtensionsDescriptions = [
...builtInExtensions.filter(({ name }) => (forWeb ? !marketplaceWebExtensionsExclude.has(name) : true)),
...(forWeb ? webBuiltInExtensions : [])
];
const marketplaceExtensionsStream = minifyExtensionResources(es.merge(...marketplaceExtensionsDescriptions
.map(extension => {
const input = (galleryServiceUrl ? fromMarketplace(galleryServiceUrl, extension) : fromGithub(extension))
.pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`));
return updateExtensionPackageJSON(input, (data) => {
const src = (0, builtInExtensions_1.getExtensionStream)(extension).pipe(rename(p => p.dirname = `extensions/${p.dirname}`));
return updateExtensionPackageJSON(src, (data) => {
delete data.scripts;
delete data.dependencies;
delete data.devDependencies;
@@ -399,6 +399,7 @@ const esbuildMediaScripts = [
'markdown-language-features/esbuild-preview.js',
'markdown-math/esbuild.js',
'notebook-renderers/esbuild.js',
'ipynb/esbuild.js',
'simple-browser/esbuild-preview.js',
];
async function webpackExtensions(taskName, isWatch, webpackConfigLocations) {
+5 -4
View File
@@ -25,6 +25,7 @@ import * as jsoncParser from 'jsonc-parser';
import webpack = require('webpack');
import { getProductionDependencies } from './dependencies';
import _ = require('underscore');
import { getExtensionStream } from './builtInExtensions';
const util = require('./util');
const root = path.dirname(path.dirname(__dirname));
const commit = util.getVersion(root);
@@ -381,7 +382,7 @@ export function packageLocalExtensionsStream(forWeb: boolean): Stream {
);
}
export function packageMarketplaceExtensionsStream(forWeb: boolean, galleryServiceUrl?: string): Stream {
export function packageMarketplaceExtensionsStream(forWeb: boolean): Stream {
const marketplaceExtensionsDescriptions = [
...builtInExtensions.filter(({ name }) => (forWeb ? !marketplaceWebExtensionsExclude.has(name) : true)),
...(forWeb ? webBuiltInExtensions : [])
@@ -390,9 +391,8 @@ export function packageMarketplaceExtensionsStream(forWeb: boolean, galleryServi
es.merge(
...marketplaceExtensionsDescriptions
.map(extension => {
const input = (galleryServiceUrl ? fromMarketplace(galleryServiceUrl, extension) : fromGithub(extension))
.pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`));
return updateExtensionPackageJSON(input, (data: any) => {
const src = getExtensionStream(extension).pipe(rename(p => p.dirname = `extensions/${p.dirname}`));
return updateExtensionPackageJSON(src, (data: any) => {
delete data.scripts;
delete data.dependencies;
delete data.devDependencies;
@@ -486,6 +486,7 @@ const esbuildMediaScripts = [
'markdown-language-features/esbuild-preview.js',
'markdown-math/esbuild.js',
'notebook-renderers/esbuild.js',
'ipynb/esbuild.js',
'simple-browser/esbuild-preview.js',
];
+1
View File
@@ -51,6 +51,7 @@ const CORE_TYPES = [
'BigInt64Array',
'btoa',
'atob',
'AbortController',
'AbortSignal',
'MessageChannel',
'MessagePort',
+1
View File
@@ -52,6 +52,7 @@ const CORE_TYPES = [
'BigInt64Array',
'btoa',
'atob',
'AbortController',
'AbortSignal',
'MessageChannel',
'MessagePort',
+14 -2
View File
@@ -438,8 +438,20 @@ async function getNLS(resourceUrlTemplate, languageId, version) {
}
catch (err) {
if (/\[404\]/.test(err.message)) {
console.warn(`Language pack ${languageId}@${version} is missing. Downloading previous version...`);
return await getSpecificNLS(resourceUrlTemplate, languageId, previousVersion(version));
const thePreviousVersion = previousVersion(version);
console.warn(`Language pack ${languageId}@${version} is missing. Downloading previous version ${thePreviousVersion}...`);
try {
return await getSpecificNLS(resourceUrlTemplate, languageId, thePreviousVersion);
}
catch (err) {
if (/\[404\]/.test(err.message)) {
console.warn(`Language pack ${languageId}@${thePreviousVersion} is missing. Downloading previous version...`);
return await getSpecificNLS(resourceUrlTemplate, languageId, previousVersion(thePreviousVersion));
}
else {
throw err;
}
}
}
else {
throw err;
+12 -2
View File
@@ -622,8 +622,18 @@ async function getNLS(resourceUrlTemplate: string, languageId: string, version:
return await getSpecificNLS(resourceUrlTemplate, languageId, version);
} catch (err) {
if (/\[404\]/.test(err.message)) {
console.warn(`Language pack ${languageId}@${version} is missing. Downloading previous version...`);
return await getSpecificNLS(resourceUrlTemplate, languageId, previousVersion(version));
const thePreviousVersion = previousVersion(version);
console.warn(`Language pack ${languageId}@${version} is missing. Downloading previous version ${thePreviousVersion}...`);
try {
return await getSpecificNLS(resourceUrlTemplate, languageId, thePreviousVersion);
} catch (err) {
if (/\[404\]/.test(err.message)) {
console.warn(`Language pack ${languageId}@${thePreviousVersion} is missing. Downloading previous version...`);
return await getSpecificNLS(resourceUrlTemplate, languageId, previousVersion(thePreviousVersion));
} else {
throw err;
}
}
} else {
throw err;
}
+3 -3
View File
@@ -48,7 +48,7 @@ exports.referenceGeneratedDepsByArch = {
'libdrm2 (>= 2.4.38)',
'libexpat1 (>= 2.0.1)',
'libgbm1 (>= 8.1~0)',
'libgcc1 (>= 1:3.0)',
'libgcc-s1 (>= 3.0)',
'libglib2.0-0 (>= 2.16.0)',
'libglib2.0-0 (>= 2.39.4)',
'libgtk-3-0 (>= 3.9.10)',
@@ -85,8 +85,8 @@ exports.referenceGeneratedDepsByArch = {
'libdrm2 (>= 2.4.38)',
'libexpat1 (>= 2.0.1)',
'libgbm1 (>= 8.1~0)',
'libgcc1 (>= 1:3.0)',
'libgcc1 (>= 1:3.5)',
'libgcc-s1 (>= 3.0)',
'libgcc-s1 (>= 3.5)',
'libglib2.0-0 (>= 2.16.0)',
'libglib2.0-0 (>= 2.39.4)',
'libgtk-3-0 (>= 3.9.10)',
+3 -3
View File
@@ -49,7 +49,7 @@ export const referenceGeneratedDepsByArch = {
'libdrm2 (>= 2.4.38)',
'libexpat1 (>= 2.0.1)',
'libgbm1 (>= 8.1~0)',
'libgcc1 (>= 1:3.0)',
'libgcc-s1 (>= 3.0)',
'libglib2.0-0 (>= 2.16.0)',
'libglib2.0-0 (>= 2.39.4)',
'libgtk-3-0 (>= 3.9.10)',
@@ -86,8 +86,8 @@ export const referenceGeneratedDepsByArch = {
'libdrm2 (>= 2.4.38)',
'libexpat1 (>= 2.0.1)',
'libgbm1 (>= 8.1~0)',
'libgcc1 (>= 1:3.0)',
'libgcc1 (>= 1:3.5)',
'libgcc-s1 (>= 3.0)',
'libgcc-s1 (>= 3.5)',
'libglib2.0-0 (>= 2.16.0)',
'libglib2.0-0 (>= 2.39.4)',
'libgtk-3-0 (>= 3.9.10)',
+5 -1
View File
@@ -10,6 +10,7 @@ const fs_1 = require("fs");
const os_1 = require("os");
const path = require("path");
const dep_lists_1 = require("./dep-lists");
const manifests = require("../../../cgmanifest.json");
// A flag that can easily be toggled.
// Make sure to compile the build directory after toggling the value.
// If false, we warn about new dependencies if they show up
@@ -76,7 +77,10 @@ function calculatePackageDeps(binaryPath, arch, sysroot) {
console.error('Tried to stat ' + binaryPath + ' but failed.');
}
// Get the Chromium dpkg-shlibdeps file.
const dpkgShlibdepsUrl = 'https://raw.githubusercontent.com/chromium/chromium/100.0.4896.160/third_party/dpkg-shlibdeps/dpkg-shlibdeps.pl';
const chromiumManifest = manifests.registrations.filter(registration => {
return registration.component.type === 'git' && registration.component.git.name === 'chromium';
});
const dpkgShlibdepsUrl = `https://raw.githubusercontent.com/chromium/chromium/${chromiumManifest[0].version}/third_party/dpkg-shlibdeps/dpkg-shlibdeps.pl`;
const dpkgShlibdepsScriptLocation = `${(0, os_1.tmpdir)()}/dpkg-shlibdeps.pl`;
const result = (0, child_process_1.spawnSync)('curl', [dpkgShlibdepsUrl, '-o', dpkgShlibdepsScriptLocation]);
if (result.status !== 0) {
+5 -1
View File
@@ -11,6 +11,7 @@ import { tmpdir } from 'os';
import path = require('path');
import { additionalDeps, bundledDeps, referenceGeneratedDepsByArch } from './dep-lists';
import { ArchString } from './types';
import * as manifests from '../../../cgmanifest.json';
// A flag that can easily be toggled.
// Make sure to compile the build directory after toggling the value.
@@ -86,7 +87,10 @@ function calculatePackageDeps(binaryPath: string, arch: ArchString, sysroot: str
}
// Get the Chromium dpkg-shlibdeps file.
const dpkgShlibdepsUrl = 'https://raw.githubusercontent.com/chromium/chromium/100.0.4896.160/third_party/dpkg-shlibdeps/dpkg-shlibdeps.pl';
const chromiumManifest = manifests.registrations.filter(registration => {
return registration.component.type === 'git' && registration.component.git!.name === 'chromium';
});
const dpkgShlibdepsUrl = `https://raw.githubusercontent.com/chromium/chromium/${chromiumManifest[0].version}/third_party/dpkg-shlibdeps/dpkg-shlibdeps.pl`;
const dpkgShlibdepsScriptLocation = `${tmpdir()}/dpkg-shlibdeps.pl`;
const result = spawnSync('curl', [dpkgShlibdepsUrl, '-o', dpkgShlibdepsScriptLocation]);
if (result.status !== 0) {
+10 -2
View File
@@ -11,7 +11,7 @@ const os_1 = require("os");
const fs = require("fs");
const https = require("https");
const path = require("path");
const sysroots_1 = require("./sysroots");
const util = require("../../lib/util");
// Based on https://source.chromium.org/chromium/chromium/src/+/main:build/linux/sysroot_scripts/install-sysroot.py.
const URL_PREFIX = 'https://msftelectron.blob.core.windows.net';
const URL_PATH = 'sysroots/toolchain';
@@ -30,7 +30,15 @@ function getSha(filename) {
return hash.digest('hex');
}
async function getSysroot(arch) {
const sysrootDict = sysroots_1.sysrootInfo[arch];
const sysrootJSONUrl = `https://raw.githubusercontent.com/electron/electron/v${util.getElectronVersion()}/script/sysroots.json`;
const sysrootDictLocation = `${(0, os_1.tmpdir)()}/sysroots.json`;
const result = (0, child_process_1.spawnSync)('curl', [sysrootJSONUrl, '-o', sysrootDictLocation]);
if (result.status !== 0) {
throw new Error('Cannot retrieve sysroots.json. Stderr:\n' + result.stderr);
}
const sysrootInfo = require(sysrootDictLocation);
const sysrootArch = arch === 'armhf' ? 'bullseye_arm' : `bullseye_${arch}`;
const sysrootDict = sysrootInfo[sysrootArch];
const tarballFilename = sysrootDict['Tarball'];
const tarballSha = sysrootDict['Sha1Sum'];
const sysroot = path.join((0, os_1.tmpdir)(), sysrootDict['SysrootDir']);
+10 -2
View File
@@ -9,8 +9,8 @@ import { tmpdir } from 'os';
import * as fs from 'fs';
import * as https from 'https';
import * as path from 'path';
import { sysrootInfo } from './sysroots';
import { ArchString } from './types';
import * as util from '../../lib/util';
// Based on https://source.chromium.org/chromium/chromium/src/+/main:build/linux/sysroot_scripts/install-sysroot.py.
const URL_PREFIX = 'https://msftelectron.blob.core.windows.net';
@@ -38,7 +38,15 @@ type SysrootDictEntry = {
};
export async function getSysroot(arch: ArchString): Promise<string> {
const sysrootDict: SysrootDictEntry = sysrootInfo[arch];
const sysrootJSONUrl = `https://raw.githubusercontent.com/electron/electron/v${util.getElectronVersion()}/script/sysroots.json`;
const sysrootDictLocation = `${tmpdir()}/sysroots.json`;
const result = spawnSync('curl', [sysrootJSONUrl, '-o', sysrootDictLocation]);
if (result.status !== 0) {
throw new Error('Cannot retrieve sysroots.json. Stderr:\n' + result.stderr);
}
const sysrootInfo = require(sysrootDictLocation);
const sysrootArch = arch === 'armhf' ? 'bullseye_arm' : `bullseye_${arch}`;
const sysrootDict: SysrootDictEntry = sysrootInfo[sysrootArch];
const tarballFilename = sysrootDict['Tarball'];
const tarballSha = sysrootDict['Sha1Sum'];
const sysroot = path.join(tmpdir(), sysrootDict['SysrootDir']);
-26
View File
@@ -1,26 +0,0 @@
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.sysrootInfo = void 0;
// Based on https://github.com/electron/electron/blob/main/script/sysroots.json,
// which itself is based on https://source.chromium.org/chromium/chromium/src/+/main:build/linux/sysroot_scripts/sysroots.json.
exports.sysrootInfo = {
'amd64': {
'Sha1Sum': '7e008cea9eae822d80d55c67fbb5ef4204678e74',
'SysrootDir': 'debian_sid_amd64-sysroot',
'Tarball': 'debian_sid_amd64_sysroot.tar.xz'
},
'armhf': {
'Sha1Sum': 'b6f4bb07817bea91b06514a9c1e3832df5a90dbf',
'SysrootDir': 'debian_sid_arm-sysroot',
'Tarball': 'debian_sid_arm_sysroot.tar.xz'
},
'arm64': {
'Sha1Sum': '5a56c1ef714154ea5003bcafb16f21b0f8dde023',
'SysrootDir': 'debian_sid_arm64-sysroot',
'Tarball': 'debian_sid_arm64_sysroot.tar.xz'
}
};
-24
View File
@@ -1,24 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
// Based on https://github.com/electron/electron/blob/main/script/sysroots.json,
// which itself is based on https://source.chromium.org/chromium/chromium/src/+/main:build/linux/sysroot_scripts/sysroots.json.
export const sysrootInfo = {
'amd64': {
'Sha1Sum': '7e008cea9eae822d80d55c67fbb5ef4204678e74',
'SysrootDir': 'debian_sid_amd64-sysroot',
'Tarball': 'debian_sid_amd64_sysroot.tar.xz'
},
'armhf': {
'Sha1Sum': 'b6f4bb07817bea91b06514a9c1e3832df5a90dbf',
'SysrootDir': 'debian_sid_arm-sysroot',
'Tarball': 'debian_sid_arm_sysroot.tar.xz'
},
'arm64': {
'Sha1Sum': '5a56c1ef714154ea5003bcafb16f21b0f8dde023',
'SysrootDir': 'debian_sid_arm64-sysroot',
'Tarball': 'debian_sid_arm64_sysroot.tar.xz'
}
};
+6 -6
View File
@@ -6,7 +6,7 @@
"git": {
"name": "chromium",
"repositoryUrl": "https://chromium.googlesource.com/chromium/src",
"commitHash": "59f4a82f7cf9fd0397aa7bf0273bf5b62433c5da"
"commitHash": "16e28102fdf876ce6d136674ba66343ede07441f"
}
},
"licenseDetail": [
@@ -40,7 +40,7 @@
"SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
],
"isOnlyProductionDependency": true,
"version": "100.0.4896.160"
"version": "102.0.5005.167"
},
{
"component": {
@@ -48,11 +48,11 @@
"git": {
"name": "nodejs",
"repositoryUrl": "https://github.com/nodejs/node",
"commitHash": "acb71eab779fb56bf70e8a9e0cb2e82a089a87de"
"commitHash": "442e84a358d75152556b5d087e4dd6a51615330d"
}
},
"isOnlyProductionDependency": true,
"version": "16.13.2"
"version": "16.14.2"
},
{
"component": {
@@ -60,12 +60,12 @@
"git": {
"name": "electron",
"repositoryUrl": "https://github.com/electron/electron",
"commitHash": "6165f6afc9af6f9ab4e32f4a7a8b0818f11e766a"
"commitHash": "a5cafd174d2027529d0b251e5b8e58da2b364e5b"
}
},
"isOnlyProductionDependency": true,
"license": "MIT",
"version": "18.3.5"
"version": "19.0.11"
},
{
"component": {
@@ -177,6 +177,13 @@
}
}
}
},
"codespaces": {
"type": "object",
"additionalProperties": true,
"description": "Codespaces-specific configuration.",
"deprecated": true,
"deprecationMessage": "Use 'customizations/codespaces' instead"
}
}
}
@@ -28,6 +28,29 @@
}
}
}
},
"extensions": {
"type": "array",
"description": "An array of extensions that should be installed into the container.",
"items": {
"type": "string",
"pattern": "^([a-z0-9A-Z][a-z0-9A-Z-]*)\\.([a-z0-9A-Z][a-z0-9A-Z-]*)((@(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?)|@prerelease)?$",
"errorMessage": "Expected format: '${publisher}.${name}' or '${publisher}.${name}@${version}'. Example: 'ms-dotnettools.csharp'."
},
"deprecated": true,
"deprecationMessage": "Use 'customizations/vscode/extensions' instead"
},
"settings": {
"$ref": "vscode://schemas/settings/machine",
"description": "Machine specific settings that should be copied into the container. These are only copied when connecting to the container for the first time, rebuilding the container then triggers it again.",
"deprecated": true,
"deprecationMessage": "Use 'customizations/vscode/settings' instead"
},
"devPort": {
"type": "integer",
"description": "The port VS Code can use to connect to its backend.",
"deprecated": true,
"deprecationMessage": "Use 'customizations/vscode/devPort' instead"
}
}
}
+1 -1
View File
@@ -65,7 +65,7 @@
"emmet.showAbbreviationSuggestions": {
"type": "boolean",
"default": true,
"scope": "language-overridable",
"scope": "resource",
"markdownDescription": "%emmetShowAbbreviationSuggestions%"
},
"emmet.includeLanguages": {
+30 -30
View File
@@ -264,47 +264,47 @@ export async function wrapWithAbbreviation(args: any): Promise<boolean> {
}
export function expandEmmetAbbreviation(args: any): Thenable<boolean | undefined> {
if (!validate() || !vscode.window.activeTextEditor) {
return fallbackTab();
if (!validate()) {
return Promise.resolve(undefined);
}
const editor = vscode.window.activeTextEditor!;
args = args || {};
if (!args['language']) {
args['language'] = editor.document.languageId;
} else {
const excludedLanguages = vscode.workspace.getConfiguration('emmet')['excludeLanguages'] ?? [];
if (excludedLanguages.includes(args['language'])) {
return fallbackTab(args['language']);
}
}
const languageId: string = args['language'];
/**
* Short circuit the parsing. If previous character is space, do not expand.
*/
if (vscode.window.activeTextEditor.selections.length === 1 &&
vscode.window.activeTextEditor.selection.isEmpty
if (editor.selections.length === 1 && editor.selection.isEmpty
) {
const anchor = vscode.window.activeTextEditor.selection.anchor;
const anchor = editor.selection.anchor;
if (anchor.character === 0) {
return fallbackTab();
return fallbackTab(languageId);
}
const prevPositionAnchor = anchor.translate(0, -1);
const prevText = vscode.window.activeTextEditor.document.getText(new vscode.Range(prevPositionAnchor, anchor));
const prevText = editor.document.getText(new vscode.Range(prevPositionAnchor, anchor));
if (prevText === ' ' || prevText === '\t') {
return fallbackTab();
return fallbackTab(languageId);
}
}
args = args || {};
if (!args['language']) {
args['language'] = vscode.window.activeTextEditor.document.languageId;
} else {
const excludedLanguages = vscode.workspace.getConfiguration('emmet')['excludeLanguages'] ? vscode.workspace.getConfiguration('emmet')['excludeLanguages'] : [];
if (excludedLanguages.indexOf(vscode.window.activeTextEditor.document.languageId) > -1) {
return fallbackTab();
}
}
const syntax = getSyntaxFromArgs(args);
if (!syntax) {
return fallbackTab();
return fallbackTab(languageId);
}
const editor = vscode.window.activeTextEditor;
// When tabbed on a non empty selection, do not treat it as an emmet abbreviation, and fallback to tab instead
if (vscode.workspace.getConfiguration('emmet')['triggerExpansionOnTab'] === true && editor.selections.find(x => !x.isEmpty)) {
return fallbackTab();
if (vscode.workspace.getConfiguration('emmet', { languageId })['triggerExpansionOnTab'] === true && editor.selections.find(x => !x.isEmpty)) {
return fallbackTab(languageId);
}
const abbreviationList: ExpandAbbreviationInput[] = [];
@@ -325,7 +325,7 @@ export function expandEmmetAbbreviation(args: any): Thenable<boolean | undefined
}
const currentLine = editor.document.lineAt(position.line).text;
const textTillPosition = currentLine.substr(0, position.character);
const textTillPosition = currentLine.substring(0, position.character);
// Expand cases like <div to <div></div> explicitly
// else we will end up with <<div></div>
@@ -415,12 +415,12 @@ export function expandEmmetAbbreviation(args: any): Thenable<boolean | undefined
});
return expandAbbreviationInRange(editor, abbreviationList, allAbbreviationsSame).then(success => {
return success ? Promise.resolve(undefined) : fallbackTab();
return success ? Promise.resolve(undefined) : fallbackTab(languageId);
});
}
function fallbackTab(): Thenable<boolean | undefined> {
if (vscode.workspace.getConfiguration('emmet')['triggerExpansionOnTab'] === true) {
function fallbackTab(languageId: string): Thenable<boolean | undefined> {
if (vscode.workspace.getConfiguration('emmet', { languageId })['triggerExpansionOnTab'] === true) {
return vscode.commands.executeCommand('tab');
}
return Promise.resolve(true);
@@ -470,13 +470,13 @@ export function isValidLocationForEmmetAbbreviation(document: vscode.TextDocumen
&& propertyNode.separator
&& offset >= propertyNode.separatorToken.end
&& offset <= propertyNode.terminatorToken.start
&& abbreviation.indexOf(':') === -1) {
&& !abbreviation.includes(':')) {
return hexColorRegex.test(abbreviation) || abbreviation === '!';
}
if (!propertyNode.terminatorToken
&& propertyNode.separator
&& offset >= propertyNode.separatorToken.end
&& abbreviation.indexOf(':') === -1) {
&& !abbreviation.includes(':')) {
return hexColorRegex.test(abbreviation) || abbreviation === '!';
}
if (hexColorRegex.test(abbreviation) || abbreviation === '!') {
@@ -529,7 +529,7 @@ export function isValidLocationForEmmetAbbreviation(document: vscode.TextDocumen
const typeAttribute = (currentHtmlNode.attributes || []).filter(x => x.name.toString() === 'type')[0];
const typeValue = typeAttribute ? typeAttribute.value.toString() : '';
if (allowedMimeTypesInScriptTag.indexOf(typeValue) > -1) {
if (allowedMimeTypesInScriptTag.includes(typeValue)) {
return true;
}
@@ -31,7 +31,7 @@ export class DefaultCompletionItemProvider implements vscode.CompletionItemProvi
if (expandedText.startsWith('<')) {
this.lastCompletionType = 'html';
} else if (expandedText.indexOf(':') > 0 && expandedText.endsWith(';')) {
} else if (expandedText.includes(':') && expandedText.endsWith(';')) {
this.lastCompletionType = 'css';
} else {
this.lastCompletionType = undefined;
@@ -43,7 +43,7 @@ export class DefaultCompletionItemProvider implements vscode.CompletionItemProvi
private provideCompletionItemsInternal(document: vscode.TextDocument, position: vscode.Position, context: vscode.CompletionContext): Thenable<vscode.CompletionList | undefined> | undefined {
const emmetConfig = vscode.workspace.getConfiguration('emmet');
const excludedLanguages = emmetConfig['excludeLanguages'] ? emmetConfig['excludeLanguages'] : [];
if (excludedLanguages.indexOf(document.languageId) > -1) {
if (excludedLanguages.includes(document.languageId)) {
return;
}
+1 -1
View File
@@ -140,7 +140,7 @@ function getNextAttribute(document: vscode.TextDocument, selectionStart: number,
}
// Fetch the next word in the attr value
if (attr.value.toString().indexOf(' ') === -1) {
if (!attr.value.toString().includes(' ')) {
// attr value does not have space, so no next word to find
continue;
}
@@ -243,7 +243,7 @@ export class GitHubServer implements IGitHubServer {
try {
return await Promise.race([
codeExchangePromise.promise,
new Promise<string>((_, reject) => setTimeout(() => reject('Cancelled'), 60000)),
new Promise<string>((_, reject) => setTimeout(() => reject('Timed out'), 300_000)), // 5min timeout
promiseFromEvent<any, any>(token.onCancellationRequested, (_, __, reject) => { reject('User Cancelled'); }).promise
]);
} finally {
@@ -276,7 +276,7 @@ export class GitHubServer implements IGitHubServer {
vscode.env.openExternal(vscode.Uri.parse(`http://127.0.0.1:${port}/signin?nonce=${encodeURIComponent(server.nonce)}`));
const { code } = await Promise.race([
server.waitForOAuthResponse(),
new Promise<any>((_, reject) => setTimeout(() => reject('Cancelled'), 60000)),
new Promise<any>((_, reject) => setTimeout(() => reject('Timed out'), 300_000)), // 5min timeout
promiseFromEvent<any, any>(token.onCancellationRequested, (_, __, reject) => { reject('User Cancelled'); }).promise
]);
codeToExchange = code;
+6 -2
View File
@@ -9,9 +9,13 @@ import { publishRepository } from './publish';
import { DisposableStore } from './util';
import { getPermalink } from './links';
function getVscodeDevHost(): string {
return `https://${vscode.env.appName.toLowerCase().includes('insiders') ? 'insiders.' : ''}vscode.dev/github`;
}
async function copyVscodeDevLink(gitAPI: GitAPI, useSelection: boolean) {
try {
const permalink = getPermalink(gitAPI, useSelection, 'https://vscode.dev/github');
const permalink = getPermalink(gitAPI, useSelection, getVscodeDevHost());
if (permalink) {
return vscode.env.clipboard.writeText(permalink);
}
@@ -22,7 +26,7 @@ async function copyVscodeDevLink(gitAPI: GitAPI, useSelection: boolean) {
async function openVscodeDevLink(gitAPI: GitAPI): Promise<vscode.Uri | undefined> {
try {
const permalink = getPermalink(gitAPI, true, 'https://vscode.dev/github');
const permalink = getPermalink(gitAPI, true, getVscodeDevHost());
return permalink ? vscode.Uri.parse(permalink) : undefined;
} catch (err) {
vscode.window.showErrorMessage(err.message);
+2 -2
View File
@@ -125,11 +125,11 @@ export function getPermalink(gitAPI: GitAPI, useSelection: boolean, hostPrefix?:
return;
}
const commitHash = gitRepo.state.HEAD?.commit;
const commitHash = (gitRepo.state.HEAD?.ahead === 0) ? `/blob/${gitRepo.state.HEAD?.commit}` : '';
const fileSegments = fileAndPosition.type === LinkType.File
? (useSelection ? `${uri.path.substring(gitRepo.rootUri.path.length)}${rangeString(fileAndPosition.range)}` : '')
: (useSelection ? `${uri.path.substring(gitRepo.rootUri.path.length)}${notebookCellRangeString(fileAndPosition.cellIndex, fileAndPosition.range)}` : '');
return `${hostPrefix}/${repo.owner}/${repo.repo}/blob/${commitHash
return `${hostPrefix}/${repo.owner}/${repo.repo}${commitHash
}${fileSegments}`;
}
+1 -1
View File
@@ -6,4 +6,4 @@ extension.webpack.config.js
extension-browser.webpack.config.js
yarn.lock
.gitignore
esbuild.js
+12 -4
View File
@@ -22,11 +22,19 @@ export async function activate(ctx: RendererContext<void>) {
md.renderer.rules.image = (tokens: MarkdownItToken[], idx: number, options, env, self) => {
const token = tokens[idx];
const src = token.attrGet('src');
const attachments: Record<string, Record<string, string>> = env.outputItem.metadata?.custom?.attachments;
const attachments: Record<string, Record<string, string>> = env.outputItem.metadata().custom?.attachments;
if (attachments && src) {
const [attachmentKey, attachmentVal] = Object.entries(attachments[src.replace('attachment:', '')])[0];
const b64Markdown = 'data:' + attachmentKey + ';base64,' + attachmentVal;
token.attrSet('src', b64Markdown);
const imageAttachment = attachments[src.replace('attachment:', '')];
if (imageAttachment) {
// objEntries will always be length 1, with objEntries[0] holding [0]=mime,[1]=b64
// if length = 0, something is wrong with the attachment, mime/b64 weren't copied over
const objEntries = Object.entries(imageAttachment);
if (objEntries.length) {
const [attachmentKey, attachmentVal] = objEntries[0];
const b64Markdown = 'data:' + attachmentKey + ';base64,' + attachmentVal;
token.attrSet('src', b64Markdown);
}
}
}
if (original) {
+1 -1
View File
@@ -8,7 +8,7 @@ import { v4 as uuid } from 'uuid';
import { getCellMetadata } from './serializers';
import { CellMetadata } from './common';
import { getNotebookMetadata } from './notebookSerializer';
import * as nbformat from '@jupyterlab/nbformat';
import type * as nbformat from '@jupyterlab/nbformat';
/**
* Ensure all new cells in notebooks with nbformat >= 4.5 have an id.
+2 -2
View File
@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nbformat from '@jupyterlab/nbformat';
import type * as nbformat from '@jupyterlab/nbformat';
/**
* Metadata we store in VS Code cell output items.
@@ -44,7 +44,7 @@ export interface CellOutputMetadata {
/**
* Metadata we store in VS Code cells.
* This contains the original metadata from the Jupyuter cells.
* This contains the original metadata from the Jupyter cells.
*/
export interface CellMetadata {
/**
+1 -1
View File
@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nbformat from '@jupyterlab/nbformat';
import type * as nbformat from '@jupyterlab/nbformat';
import { extensions, NotebookCellData, NotebookCellExecutionSummary, NotebookCellKind, NotebookCellOutput, NotebookCellOutputItem, NotebookData } from 'vscode';
import { CellMetadata, CellOutputMetadata } from './common';
+1 -1
View File
@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nbformat from '@jupyterlab/nbformat';
import type * as nbformat from '@jupyterlab/nbformat';
import * as detectIndent from 'detect-indent';
import * as vscode from 'vscode';
import { defaultNotebookFormat } from './constants';
+1 -1
View File
@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nbformat from '@jupyterlab/nbformat';
import type * as nbformat from '@jupyterlab/nbformat';
import { NotebookCell, NotebookCellData, NotebookCellKind, NotebookCellOutput } from 'vscode';
import { CellMetadata, CellOutputMetadata } from './common';
import { textMimeTypes } from './deserializers';
@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nbformat from '@jupyterlab/nbformat';
import type * as nbformat from '@jupyterlab/nbformat';
import * as assert from 'assert';
import * as vscode from 'vscode';
import { jupyterCellOutputToCellOutput, jupyterNotebookModelToNotebookData } from '../deserializers';
+1 -1
View File
@@ -33,7 +33,7 @@
"git": {
"name": "microsoft/vscode-markdown-tm-grammar",
"repositoryUrl": "https://github.com/microsoft/vscode-markdown-tm-grammar",
"commitHash": "69d3321b4923ca2d5e8e900018887cc38b5fe04a"
"commitHash": "97f2f8d38f10d3febd77d85b745945dc60fe334e"
}
},
"license": "MIT",
@@ -4,7 +4,7 @@
"If you want to provide a fix or improvement, please create a pull request against the original repository.",
"Once accepted there, we are happy to receive an update request."
],
"version": "https://github.com/microsoft/vscode-markdown-tm-grammar/commit/69d3321b4923ca2d5e8e900018887cc38b5fe04a",
"version": "https://github.com/microsoft/vscode-markdown-tm-grammar/commit/97f2f8d38f10d3febd77d85b745945dc60fe334e",
"name": "Markdown",
"scopeName": "text.html.markdown",
"patterns": [
@@ -2766,7 +2766,24 @@
"name": "punctuation.definition.link.title.begin.markdown"
},
"2": {
"name": "string.other.link.title.markdown"
"name": "string.other.link.title.markdown",
"patterns": [
{
"include": "#raw"
},
{
"include": "#bold"
},
{
"include": "#italic"
},
{
"include": "#strikethrough"
},
{
"include": "#image-inline"
}
]
},
"4": {
"name": "punctuation.definition.link.title.end.markdown"
@@ -2826,7 +2843,24 @@
"name": "punctuation.definition.link.title.begin.markdown"
},
"2": {
"name": "string.other.link.title.markdown"
"name": "string.other.link.title.markdown",
"patterns": [
{
"include": "#raw"
},
{
"include": "#bold"
},
{
"include": "#italic"
},
{
"include": "#strikethrough"
},
{
"include": "#image-inline"
}
]
},
"4": {
"name": "punctuation.definition.link.title.end.markdown"
@@ -2957,7 +2991,7 @@
"name": "punctuation.definition.strikethrough.markdown"
}
},
"match": "(~{2,})((?:[^~]|(?!(?<!~)\\1(?!~))~)*+)(\\1)",
"match": "(?<!\\\\)(~{2,})((?:[^~]|(?!(?<![~\\\\])\\1(?!~))~)*+)(\\1)",
"name": "markup.strikethrough.markdown"
}
}
@@ -12,7 +12,8 @@ cgmanifest.json
yarn.lock
preview-src/**
webpack.config.js
esbuild.js
esbuild-notebook.js
esbuild-preview.js
.gitignore
server/src/**
server/extension.webpack.config.js
@@ -187,22 +187,22 @@
},
{
"command": "markdown.showSource",
"when": "markdownPreviewFocus",
"when": "activeWebviewPanelId == 'markdown.preview' || activeCustomEditorId == 'vscode.markdown.preview.editor'",
"group": "navigation"
},
{
"command": "markdown.preview.refresh",
"when": "markdownPreviewFocus",
"when": "activeWebviewPanelId == 'markdown.preview' || activeCustomEditorId == 'vscode.markdown.preview.editor'",
"group": "1_markdown"
},
{
"command": "markdown.preview.toggleLock",
"when": "markdownPreviewFocus",
"when": "activeWebviewPanelId == 'markdown.preview' || activeCustomEditorId == 'vscode.markdown.preview.editor'",
"group": "1_markdown"
},
{
"command": "markdown.showPreviewSecuritySelector",
"when": "markdownPreviewFocus",
"when": "activeWebviewPanelId == 'markdown.preview' || activeCustomEditorId == 'vscode.markdown.preview.editor'",
"group": "1_markdown"
}
],
@@ -247,7 +247,7 @@
},
{
"command": "markdown.showSource",
"when": "markdownPreviewFocus",
"when": "activeWebviewPanelId == 'markdown.preview' || activeCustomEditorId == 'vscode.markdown.preview.editor'",
"group": "navigation"
},
{
@@ -256,11 +256,11 @@
},
{
"command": "markdown.showPreviewSecuritySelector",
"when": "markdownPreviewFocus"
"when": "activeWebviewPanelId == 'markdown.preview' || activeCustomEditorId == 'vscode.markdown.preview.editor'"
},
{
"command": "markdown.preview.toggleLock",
"when": "markdownPreviewFocus"
"when": "activeWebviewPanelId == 'markdown.preview' || activeCustomEditorId == 'vscode.markdown.preview.editor'"
},
{
"command": "markdown.preview.refresh",
@@ -268,7 +268,7 @@
},
{
"command": "markdown.preview.refresh",
"when": "markdownPreviewFocus"
"when": "activeWebviewPanelId == 'markdown.preview' || activeCustomEditorId == 'vscode.markdown.preview.editor'"
},
{
"command": "markdown.findAllFileReferences",
@@ -515,7 +515,11 @@
"configurationDefaults": {
"[markdown]": {
"editor.wordWrap": "on",
"editor.quickSuggestions": false
"editor.quickSuggestions": {
"comments": "off",
"strings": "off",
"other": "off"
}
}
},
"jsonValidation": [
@@ -1,7 +1,7 @@
{
"name": "vscode-markdown-languageserver",
"description": "Markdown language server",
"version": "0.0.0-alpha-1",
"version": "0.0.0-alpha-2",
"author": "Microsoft Corporation",
"license": "MIT",
"engines": {
@@ -10,10 +10,10 @@
"main": "./out/node/main",
"browser": "./dist/browser/main",
"dependencies": {
"vscode-languageserver": "^8.0.2-next.5`",
"vscode-languageserver": "^8.0.2",
"vscode-languageserver-textdocument": "^1.0.5",
"vscode-languageserver-types": "^3.17.1",
"vscode-markdown-languageservice": "^0.0.0-alpha.12",
"vscode-markdown-languageservice": "^0.0.0-alpha.13",
"vscode-uri": "^3.0.3"
},
"devDependencies": {
@@ -48,13 +48,13 @@ export function registerValidateSupport(
workspace: VsCodeClientWorkspace,
ls: md.IMdLanguageService,
config: ConfigurationManager,
logger: md.ILogger,
): Disposable {
let diagnosticOptions: md.DiagnosticOptions = defaultDiagnosticOptions;
function updateDiagnosticsSetting(): void {
diagnosticOptions = getDiagnosticsOptions(config);
}
const subs: Disposable[] = [];
const manager = ls.createPullDiagnosticsManager();
subs.push(manager);
@@ -64,14 +64,23 @@ export function registerValidateSupport(
connection.languages.diagnostics.refresh();
}));
const emptyDiagnosticsResponse = Object.freeze({ kind: 'full', items: [] });
connection.languages.diagnostics.on(async (params, token): Promise<FullDocumentDiagnosticReport | UnchangedDocumentDiagnosticReport> => {
logger.log(md.LogLevel.Trace, 'Server: connection.languages.diagnostics.on', params.textDocument.uri);
if (!config.getSettings()?.markdown.experimental.validate.enabled) {
return { kind: 'full', items: [] };
return emptyDiagnosticsResponse;
}
const document = await workspace.openMarkdownDocument(URI.parse(params.textDocument.uri));
const uri = URI.parse(params.textDocument.uri);
if (!workspace.hasMarkdownDocument(uri)) {
return emptyDiagnosticsResponse;
}
const document = await workspace.openMarkdownDocument(uri);
if (!document) {
return { kind: 'full', items: [] };
return emptyDiagnosticsResponse;
}
const diagnostics = await manager.computeDiagnostics(document, diagnosticOptions, token);
@@ -48,7 +48,7 @@ export async function startServer(connection: Connection) {
});
registerCompletionsSupport(connection, documents, provider, configurationManager);
registerValidateSupport(connection, workspace, provider, configurationManager);
registerValidateSupport(connection, workspace, provider, configurationManager, logger);
workspace.workspaceFolders = (params.workspaceFolders ?? []).map(x => URI.parse(x.uri));
return {
@@ -63,7 +63,12 @@ export class VsCodeClientWorkspace implements md.IWorkspaceWithWatching {
});
documents.onDidClose(e => {
this._documentCache.delete(URI.parse(e.document.uri));
const uri = URI.parse(e.document.uri);
this._documentCache.delete(uri);
if (this.isRelevantMarkdownDocument(e.document)) {
this._onDidDeleteMarkdownDocument.fire(uri);
}
});
connection.onDidChangeWatchedFiles(async ({ changes }) => {
@@ -3,54 +3,49 @@
"@types/node@16.x":
version "16.11.43"
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.43.tgz#555e5a743f76b6b897d47f945305b618525ddbe6"
integrity sha512-GqWykok+3uocgfAJM8imbozrqLnPyTrpFlrryURQlw1EesPUCx5XxTiucWDSFF9/NUEXDuD4bnvHm8xfVGWTpQ==
version "16.11.47"
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.47.tgz#efa9e3e0f72e7aa6a138055dace7437a83d9f91c"
integrity sha512-fpP+jk2zJ4VW66+wAMFoBJlx1bxmBKx4DUFf68UHgdGCOuyUTDlLWqsaNPJh7xhNDykyJ9eIzAygilP/4WoN8g==
picomatch@^2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
vscode-jsonrpc@8.0.2-next.1:
version "8.0.2-next.1"
resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.0.2-next.1.tgz#6bdc39fd194782032e34047eeefce562941259c6"
integrity sha512-sbbvGSWja7NVBLHPGawtgezc8DHYJaP4qfr/AaJiyDapWcSFtHyPtm18+LnYMLTmB7bhOUW/lf5PeeuLpP6bKA==
vscode-jsonrpc@8.0.2:
version "8.0.2"
resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.0.2.tgz#f239ed2cd6004021b6550af9fd9d3e47eee3cac9"
integrity sha512-RY7HwI/ydoC1Wwg4gJ3y6LpU9FJRZAUnTYMXthqhFXXu77ErDd/xkREpGuk4MyYkk4a+XDWAMqe0S3KkelYQEQ==
vscode-languageserver-protocol@3.17.2-next.6:
version "3.17.2-next.6"
resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.2-next.6.tgz#8f1dc0fcb29366b85f623a3f9af726de433b5fcc"
integrity sha512-WtsebNOOkWyNn4oFYoAMPC8Q/ZDoJ/K7Ja53OzTixiitvrl/RpXZETrtzH79R8P5kqCyx6VFBPb6KQILJfkDkA==
vscode-languageserver-protocol@3.17.2:
version "3.17.2"
resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.2.tgz#beaa46aea06ed061576586c5e11368a9afc1d378"
integrity sha512-8kYisQ3z/SQ2kyjlNeQxbkkTNmVFoQCqkmGrzLH6A9ecPlgTbp3wDTnUNqaUxYr4vlAcloxx8zwy7G5WdguYNg==
dependencies:
vscode-jsonrpc "8.0.2-next.1"
vscode-languageserver-types "3.17.2-next.2"
vscode-jsonrpc "8.0.2"
vscode-languageserver-types "3.17.2"
vscode-languageserver-textdocument@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.5.tgz#838769940ece626176ec5d5a2aa2d0aa69f5095c"
integrity sha512-1ah7zyQjKBudnMiHbZmxz5bYNM9KKZYz+5VQLj+yr8l+9w3g+WAhCkUkWbhMEdC5u0ub4Ndiye/fDyS8ghIKQg==
vscode-languageserver-types@3.17.2-next.2:
version "3.17.2-next.2"
resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2-next.2.tgz#af5d6978eee7682aab87c1419323f5b141ac6596"
integrity sha512-TiAkLABgqkVWdAlC3XlOfdhdjIAdVU4YntPUm9kKGbXr+MGwpVnKz2KZMNBcvG0CFx8Hi8qliL0iq+ndPB720w==
vscode-languageserver-types@3.17.2, vscode-languageserver-types@^3.17.1:
version "3.17.2"
resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz#b2c2e7de405ad3d73a883e91989b850170ffc4f2"
integrity sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA==
vscode-languageserver-types@^3.17.1:
version "3.17.1"
resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.1.tgz#c2d87fa7784f8cac389deb3ff1e2d9a7bef07e16"
integrity sha512-K3HqVRPElLZVVPtMeKlsyL9aK0GxGQpvtAUTfX4k7+iJ4mc1M+JM+zQwkgGy2LzY0f0IAafe8MKqIkJrxfGGjQ==
vscode-languageserver@^8.0.2-next.5`:
version "8.0.2-next.5"
resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-8.0.2-next.5.tgz#39a2dd4c504fb88042375e7ac706a714bdaab4e5"
integrity sha512-2ZDb7O/4atS9mJKufPPz637z+51kCyZfgnobFW5eSrUdS3c0UB/nMS4Ng1EavYTX84GVaVMKCrmP0f2ceLmR0A==
vscode-languageserver@^8.0.2:
version "8.0.2"
resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-8.0.2.tgz#cfe2f0996d9dfd40d3854e786b2821604dfec06d"
integrity sha512-bpEt2ggPxKzsAOZlXmCJ50bV7VrxwCS5BI4+egUmure/oI/t4OlFzi/YNtVvY24A2UDOZAgwFGgnZPwqSJubkA==
dependencies:
vscode-languageserver-protocol "3.17.2-next.6"
vscode-languageserver-protocol "3.17.2"
vscode-markdown-languageservice@^0.0.0-alpha.12:
version "0.0.0-alpha.12"
resolved "https://registry.yarnpkg.com/vscode-markdown-languageservice/-/vscode-markdown-languageservice-0.0.0-alpha.12.tgz#5a3c7559969c3cb455d508d48129c8e221589630"
integrity sha512-9dJ/GL6A9UUOcB1TpvgsbcwqsYjnxHx4jxDaqeZZEMWFSUySfp0PAn1ge2S2Qj00zypvsu0eCTGUNd56G1/BNQ==
vscode-markdown-languageservice@^0.0.0-alpha.13:
version "0.0.0-alpha.13"
resolved "https://registry.yarnpkg.com/vscode-markdown-languageservice/-/vscode-markdown-languageservice-0.0.0-alpha.13.tgz#28cd8dd8eca451aaa3db1c92ec97ace53623dd5d"
integrity sha512-jgRVBQmdO0aC5Svap1RcAd3x2XOSNWla01GF/rzaVx9M5pEcel4SPz+2H9PYXul6jRKe1oKJF9OOciaiE7pSXQ==
dependencies:
picomatch "^2.3.1"
vscode-languageserver-textdocument "^1.0.5"
@@ -11,7 +11,6 @@ import { MarkdownContributionProvider } from './markdownExtensions';
import { Slugifier } from './slugify';
import { ITextDocument } from './types/textDocument';
import { Disposable } from './util/dispose';
import { stringHash } from './util/hash';
import { WebviewResourceProvider } from './util/resources';
import { isOfScheme, Schemes } from './util/schemes';
import { MdDocumentInfoCache } from './util/workspaceCache';
@@ -86,11 +85,11 @@ class TokenCache {
export interface RenderOutput {
html: string;
containingImages: { src: string }[];
containingImages: Set<string>;
}
interface RenderEnv {
containingImages: { src: string }[];
containingImages: Set<string>;
currentDocument: vscode.Uri | undefined;
resourceProvider: WebviewResourceProvider | undefined;
}
@@ -209,7 +208,7 @@ export class MarkdownItEngine implements IMdParser {
: this.tokenizeDocument(input, config, engine);
const env: RenderEnv = {
containingImages: [],
containingImages: new Set<string>(),
currentDocument: typeof input === 'string' ? undefined : input.uri,
resourceProvider,
};
@@ -248,13 +247,9 @@ export class MarkdownItEngine implements IMdParser {
const original = md.renderer.rules.image;
md.renderer.rules.image = (tokens: Token[], idx: number, options, env: RenderEnv, self) => {
const token = tokens[idx];
token.attrJoin('class', 'loading');
const src = token.attrGet('src');
if (src) {
env.containingImages?.push({ src });
const imgHash = stringHash(src);
token.attrSet('id', `image-hash-${imgHash}`);
env.containingImages?.add(src);
if (!token.attrGet('data-src')) {
token.attrSet('src', this.toResourceUri(src, env.currentDocument, env.resourceProvider));
@@ -38,7 +38,7 @@ const previewStrings = {
export interface MarkdownContentProviderOutput {
html: string;
containingImages: { src: string }[];
containingImages: Set<string>;
}
@@ -88,7 +88,7 @@ export class MdDocumentRenderer {
const body = await this.renderBody(markdownDocument, resourceProvider);
if (token.isCancellationRequested) {
return { html: '', containingImages: [] };
return { html: '', containingImages: new Set() };
}
const html = `<!DOCTYPE html>
@@ -396,9 +396,7 @@ class MarkdownPreview extends Disposable implements WebviewResourceProvider {
}
}
private updateImageWatchers(containingImages: { src: string }[]) {
const srcs = new Set(containingImages.map(img => img.src));
private updateImageWatchers(srcs: Set<string>) {
// Delete stale file watchers.
for (const [src, watcher] of this._fileWatchersBySrc) {
if (!srcs.has(src)) {
@@ -58,8 +58,6 @@ class PreviewStore<T extends IManagedMarkdownPreview> extends Disposable {
export class MarkdownPreviewManager extends Disposable implements vscode.WebviewPanelSerializer, vscode.CustomTextEditorProvider {
private static readonly markdownPreviewActiveContextKey = 'markdownPreviewFocus';
private readonly _topmostLineMonitor = new TopmostLineMonitor();
private readonly _previewConfigurations = new MarkdownPreviewConfigurationManager();
@@ -216,7 +214,6 @@ export class MarkdownPreviewManager extends Disposable implements vscode.Webview
this._contributions,
this._tocProvider);
this.setPreviewActiveContext(true);
this._activePreview = preview;
return this.registerDynamicPreview(preview);
}
@@ -250,19 +247,14 @@ export class MarkdownPreviewManager extends Disposable implements vscode.Webview
private trackActive(preview: IManagedMarkdownPreview): void {
preview.onDidChangeViewState(({ webviewPanel }) => {
this.setPreviewActiveContext(webviewPanel.active);
this._activePreview = webviewPanel.active ? preview : undefined;
});
preview.onDispose(() => {
if (this._activePreview === preview) {
this.setPreviewActiveContext(false);
this._activePreview = undefined;
}
});
}
private setPreviewActiveContext(value: boolean) {
vscode.commands.executeCommand('setContext', MarkdownPreviewManager.markdownPreviewActiveContextKey, value);
}
}
@@ -30,22 +30,23 @@ suite('markdown.engine', () => {
});
});
suite('image-caching', () => {
suite.only('image-caching', () => {
const input = '![](img.png) [](no-img.png) ![](http://example.org/img.png) ![](img.png) ![](./img2.png)';
test('Extracts all images', async () => {
const engine = createNewMarkdownEngine();
assert.deepStrictEqual((await engine.render(input)), {
html: '<p data-line="0" class="code-line" dir="auto">'
+ '<img src="img.png" alt="" class="loading" id="image-hash--754511435" data-src="img.png"> '
+ '<a href="no-img.png" data-href="no-img.png"></a> '
+ '<img src="http://example.org/img.png" alt="" class="loading" id="image-hash--1903814170" data-src="http://example.org/img.png"> '
+ '<img src="img.png" alt="" class="loading" id="image-hash--754511435" data-src="img.png"> '
+ '<img src="./img2.png" alt="" class="loading" id="image-hash-265238964" data-src="./img2.png">'
+ '</p>\n'
,
containingImages: [{ src: 'img.png' }, { src: 'http://example.org/img.png' }, { src: 'img.png' }, { src: './img2.png' }],
});
const result = await engine.render(input);
assert.deepStrictEqual(result.html,
'<p data-line="0" class="code-line" dir="auto">'
+ '<img src="img.png" alt="" data-src="img.png"> '
+ '<a href="no-img.png" data-href="no-img.png"></a> '
+ '<img src="http://example.org/img.png" alt="" data-src="http://example.org/img.png"> '
+ '<img src="img.png" alt="" data-src="img.png"> '
+ '<img src="./img2.png" alt="" data-src="./img2.png">'
+ '</p>\n'
);
assert.deepStrictEqual([...result.containingImages], ['img.png', 'http://example.org/img.png', './img2.png']);
});
});
});
@@ -1,16 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
function numberHash(val: number, initialHashVal: number): number {
return (((initialHashVal << 5) - initialHashVal) + val) | 0; // hashVal * 31 + ch, keep as int32
}
export function stringHash(s: string) {
let hashVal = numberHash(149417, 0);
for (let i = 0, length = s.length; i < length; i++) {
hashVal = numberHash(s.charCodeAt(i), hashVal);
}
return hashVal;
}
@@ -11,7 +11,7 @@ import * as nls from 'vscode-nls';
import { v4 as uuid } from 'uuid';
import fetch, { Response } from 'node-fetch';
import Logger from './logger';
import { toBase64UrlEncoding } from './utils';
import { isSupportedEnvironment, toBase64UrlEncoding } from './utils';
import { sha256 } from './env/node/sha256';
import { BetterTokenStorage, IDidChangeInOtherWindowEvent } from './betterSecretStorage';
import { LoopbackAuthServer } from './authServer';
@@ -319,13 +319,7 @@ export class AzureActiveDirectoryService {
}, 5000);
}
const token = await this.exchangeCodeForToken(codeToExchange, codeVerifier, scopeData);
if (token.expiresIn) {
this.setSessionTimeout(token.sessionId, token.refreshToken, scopeData, token.expiresIn * AzureActiveDirectoryService.REFRESH_TIMEOUT_MODIFIER);
}
await this.setToken(token, scopeData);
Logger.info(`Login successful for scopes: ${scopeData.scopeStr}`);
const session = await this.convertToSession(token);
const session = await this.exchangeCodeForSession(codeToExchange, codeVerifier, scopeData);
return session;
}
@@ -355,9 +349,11 @@ export class AzureActiveDirectoryService {
const uri = vscode.Uri.parse(`${signInUrl}?${oauthStartQuery.toString()}`);
vscode.env.openExternal(uri);
let inputBox: vscode.InputBox | undefined;
const timeoutPromise = new Promise((_: (value: vscode.AuthenticationSession) => void, reject) => {
const wait = setTimeout(() => {
clearTimeout(wait);
inputBox?.dispose();
reject('Login timed out.');
}, 1000 * 60 * 5);
});
@@ -369,7 +365,12 @@ export class AzureActiveDirectoryService {
// before completing it.
let existingPromise = this._codeExchangePromises.get(scopeData.scopeStr);
if (!existingPromise) {
existingPromise = this.handleCodeResponse(scopeData);
if (isSupportedEnvironment(callbackUri)) {
existingPromise = this.handleCodeResponse(scopeData);
} else {
inputBox = vscode.window.createInputBox();
existingPromise = this.handleCodeInputBox(inputBox, codeVerifier, scopeData);
}
this._codeExchangePromises.set(scopeData.scopeStr, existingPromise);
}
@@ -659,13 +660,7 @@ export class AzureActiveDirectoryService {
throw new Error('No available code verifier');
}
const token = await this.exchangeCodeForToken(code, verifier, scopeData);
if (token.expiresIn) {
this.setSessionTimeout(token.sessionId, token.refreshToken, scopeData, token.expiresIn * AzureActiveDirectoryService.REFRESH_TIMEOUT_MODIFIER);
}
await this.setToken(token, scopeData);
const session = await this.convertToSession(token);
const session = await this.exchangeCodeForSession(code, verifier, scopeData);
resolve(session);
} catch (err) {
reject(err);
@@ -680,8 +675,33 @@ export class AzureActiveDirectoryService {
});
}
private async exchangeCodeForToken(code: string, codeVerifier: string, scopeData: IScopeData): Promise<IToken> {
private async handleCodeInputBox(inputBox: vscode.InputBox, verifier: string, scopeData: IScopeData): Promise<vscode.AuthenticationSession> {
inputBox.ignoreFocusOut = true;
inputBox.title = localize('pasteCodeTitle', 'Microsoft Authentication');
inputBox.prompt = localize('pasteCodePrompt', 'Provide the authorization code to complete the sign in flow.');
inputBox.placeholder = localize('pasteCodePlaceholder', 'Paste authorization code here...');
return new Promise((resolve: (value: vscode.AuthenticationSession) => void, reject) => {
inputBox.show();
inputBox.onDidAccept(async () => {
const code = inputBox.value;
if (code) {
inputBox.dispose();
const session = await this.exchangeCodeForSession(code, verifier, scopeData);
resolve(session);
}
});
inputBox.onDidHide(() => {
if (!inputBox.value) {
inputBox.dispose();
reject('Cancelled');
}
});
});
}
private async exchangeCodeForSession(code: string, codeVerifier: string, scopeData: IScopeData): Promise<vscode.AuthenticationSession> {
Logger.info(`Exchanging login code for token for scopes: ${scopeData.scopeStr}`);
let token: IToken | undefined;
try {
const postData = querystring.stringify({
grant_type: 'authorization_code',
@@ -698,11 +718,18 @@ export class AzureActiveDirectoryService {
const json = await this.fetchTokenResponse(endpoint, postData, scopeData);
Logger.info(`Exchanging login code for token (for scopes: ${scopeData.scopeStr}) succeeded!`);
return this.convertToTokenSync(json, scopeData);
token = this.convertToTokenSync(json, scopeData);
} catch (e) {
Logger.error(`Error exchanging code for token (for scopes ${scopeData.scopeStr}): ${e}`);
throw e;
}
if (token.expiresIn) {
this.setSessionTimeout(token.sessionId, token.refreshToken, scopeData, token.expiresIn * AzureActiveDirectoryService.REFRESH_TIMEOUT_MODIFIER);
}
await this.setToken(token, scopeData);
Logger.info(`Login successful for scopes: ${scopeData.scopeStr}`);
return await this.convertToSession(token);
}
private async fetchTokenResponse(endpoint: string, postData: string, scopeData: IScopeData): Promise<ITokenResponse> {
@@ -2,7 +2,40 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { env, UIKind, Uri } from 'vscode';
export function toBase64UrlEncoding(base64string: string) {
return base64string.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_'); // Need to use base64url encoding
}
const LOCALHOST_ADDRESSES = ['localhost', '127.0.0.1', '0:0:0:0:0:0:0:1', '::1'];
function isLocalhost(uri: Uri): boolean {
if (!/^https?$/i.test(uri.scheme)) {
return false;
}
const host = uri.authority.split(':')[0];
return LOCALHOST_ADDRESSES.indexOf(host) >= 0;
}
export function isSupportedEnvironment(uri: Uri): boolean {
if (env.uiKind === UIKind.Desktop) {
return true;
}
// local development (localhost:* or 127.0.0.1:*)
if (isLocalhost(uri)) {
return true;
}
// At this point we should only ever see https
if (uri.scheme !== 'https') {
return false;
}
return (
// vscode.dev & insiders.vscode.dev
/(?:^|\.)vscode\.dev$/.test(uri.authority) ||
// github.dev & codespaces
/(?:^|\.)github\.dev$/.test(uri.authority) ||
// github.dev/codespaces local setup (github.localhost)
/(?:^|\.)github\.localhost$/.test(uri.authority)
);
}
+6
View File
@@ -298,6 +298,12 @@
"tags": [
"usesOnlineServices"
]
},
"npm.scriptHover": {
"type": "boolean",
"description": "%config.npm.scriptHover%",
"default": true,
"scope": "window"
}
}
},
+1
View File
@@ -15,6 +15,7 @@
"config.npm.scriptExplorerExclude": "An array of regular expressions that indicate which scripts should be excluded from the NPM Scripts view.",
"config.npm.enableRunFromFolder": "Enable running npm scripts contained in a folder from the Explorer context menu.",
"config.npm.fetchOnlinePackageInfo": "Fetch data from https://registry.npmjs.org and https://registry.bower.io to provide auto-completion and information on hover features on npm dependencies.",
"config.npm.scriptHover": "Display hover with 'Run' and 'Debug' commands for scripts.",
"npm.parseError": "Npm task detection: failed to parse the file {0}",
"taskdef.script": "The npm script to customize.",
"taskdef.path": "The path to the folder of the package.json file that provides the script. Can be omitted.",
+13
View File
@@ -33,6 +33,7 @@ export function invalidateHoverScriptsCache(document?: TextDocument) {
}
export class NpmScriptHoverProvider implements HoverProvider {
private enabled: boolean;
constructor(private context: ExtensionContext) {
context.subscriptions.push(commands.registerCommand('npm.runScriptFromHover', this.runScriptFromHover, this));
@@ -40,9 +41,21 @@ export class NpmScriptHoverProvider implements HoverProvider {
context.subscriptions.push(workspace.onDidChangeTextDocument((e) => {
invalidateHoverScriptsCache(e.document);
}));
const isEnabled = () => workspace.getConfiguration('npm').get<boolean>('scriptHover', true);
this.enabled = isEnabled();
context.subscriptions.push(workspace.onDidChangeConfiguration((e) => {
if (e.affectsConfiguration('npm.scriptHover')) {
this.enabled = isEnabled();
}
}));
}
public provideHover(document: TextDocument, position: Position, _token: CancellationToken): ProviderResult<Hover> {
if (!this.enabled) {
return;
}
let hover: Hover | undefined = undefined;
if (!cachedDocument || cachedDocument.fsPath !== document.uri.fsPath) {
+1 -1
View File
@@ -4,7 +4,7 @@
"license": "MIT",
"description": "Dependencies shared by all extensions",
"dependencies": {
"typescript": "4.7.3"
"typescript": "^4.8.0-dev.20220801"
},
"scripts": {
"postinstall": "node ./postinstall.mjs"
+1
View File
@@ -11,3 +11,4 @@ cgmanifest.json
yarn.lock
preview-src/**
webpack.config.js
esbuild-preview.js
@@ -7,7 +7,11 @@
}
},
{
"scope": ["meta.embedded", "source.groovy.embedded"],
"scope": [
"meta.embedded",
"source.groovy.embedded",
"string meta.image.inline.markdown"
],
"settings": {
"foreground": "#6688cc"
}
@@ -26,7 +26,8 @@
{
"scope": [
"meta.embedded",
"source.groovy.embedded"
"source.groovy.embedded",
"string meta.image.inline.markdown",
],
"settings": {
"foreground": "#D4D4D4"
@@ -17,7 +17,8 @@
{
"scope": [
"meta.embedded",
"source.groovy.embedded"
"source.groovy.embedded",
"string meta.image.inline.markdown"
],
"settings": {
"foreground": "#FFFFFF"
@@ -32,7 +32,8 @@
{
"scope": [
"meta.embedded",
"source.groovy.embedded"
"source.groovy.embedded",
"string meta.image.inline.markdown"
],
"settings": {
"foreground": "#000000ff"
@@ -60,7 +60,11 @@
}
},
{
"scope": ["meta.embedded", "source.groovy.embedded"],
"scope": [
"meta.embedded",
"source.groovy.embedded",
"string meta.image.inline.markdown"
],
"settings": {
"foreground": "#d3af86"
}
@@ -110,7 +110,8 @@
{
"scope": [
"meta.embedded",
"source.groovy.embedded"
"source.groovy.embedded",
"string meta.image.inline.markdown"
],
"settings": {
"foreground": "#F8F8F2"
@@ -9,7 +9,8 @@
{
"scope": [
"meta.embedded",
"source.groovy.embedded"
"source.groovy.embedded",
"string meta.image.inline.markdown"
],
"settings": {
"foreground": "#333333"
@@ -69,7 +69,8 @@
{
"scope": [
"meta.embedded",
"source.groovy.embedded"
"source.groovy.embedded",
"string meta.image.inline.markdown"
],
"settings": {
"foreground": "#F8F8F8"
@@ -9,7 +9,8 @@
{
"scope": [
"meta.embedded",
"source.groovy.embedded"
"source.groovy.embedded",
"string meta.image.inline.markdown"
],
"settings": {
"foreground": "#839496"
@@ -9,7 +9,8 @@
{
"scope": [
"meta.embedded",
"source.groovy.embedded"
"source.groovy.embedded",
"string meta.image.inline.markdown"
],
"settings": {
"foreground": "#657B83"
@@ -15,8 +15,8 @@
"editor.foreground": "#ffffff",
"editor.selectionBackground": "#003f8e",
"minimap.selectionHighlight": "#003f8e",
"editor.lineHighlightBackground": "#00346e",
"editorLineNumber.activeForeground": "#949494",
"editor.lineHighlightBackground": "#00346e",
"editorLineNumber.activeForeground": "#949494",
"editorCursor.foreground": "#ffffff",
"editorWhitespace.foreground": "#404f7d",
"editorWidget.background": "#001c40",
@@ -65,7 +65,12 @@
}
},
{
"scope": ["meta.embedded", "source.groovy.embedded", "meta.jsx.children"],
"scope": [
"meta.embedded",
"source.groovy.embedded",
"meta.jsx.children",
"string meta.image.inline.markdown"
],
"settings": {
//"background": "#002451",
"foreground": "#FFFFFF"
@@ -8,6 +8,8 @@
'use strict';
const CopyPlugin = require('copy-webpack-plugin');
const Terser = require('terser');
const fs = require('fs');
const path = require('path');
const defaultConfig = require('../shared.webpack.config');
const withBrowserDefaults = defaultConfig.browser;
@@ -64,9 +66,12 @@ module.exports = withBrowserDefaults({
{
from: '../node_modules/typescript/lib/tsserver.js',
to: 'typescript/tsserver.web.js',
transform: (content) => {
return Terser.minify(content.toString()).then(output => output.code);
transform: async (content) => {
const dynamicImportCompatPath = path.join(__dirname, '..', 'node_modules', 'typescript', 'lib', 'dynamicImportCompat.js');
const prefix = fs.existsSync(dynamicImportCompatPath) ? fs.readFileSync(dynamicImportCompatPath) : undefined;
const output = await Terser.minify(content.toString());
return prefix + '\n' + output.code;
},
transformPath: (targetPath) => {
return targetPath.replace('tsserver.js', 'tsserver.web.js');
@@ -190,7 +190,6 @@ export default class FileConfigurationManager extends Disposable {
includeCompletionsWithSnippetText: config.get<boolean>('suggest.includeCompletionsWithSnippetText', true),
includeCompletionsWithClassMemberSnippets: config.get<boolean>('suggest.classMemberSnippets.enabled', true),
includeCompletionsWithObjectLiteralMethodSnippets: config.get<boolean>('suggest.objectLiteralMethodSnippets.enabled', true),
// @ts-expect-error until TS 4.8
autoImportFileExcludePatterns: this.getAutoImportFileExcludePatternsPreference(preferencesConfig, vscode.workspace.getWorkspaceFolder(document.uri)?.uri),
useLabelDetailsInCompletionEntries: true,
allowIncompleteCompletions: true,
@@ -11,6 +11,7 @@ import { coalesce } from '../utils/arrays';
import { Delayer, setImmediate } from '../utils/async';
import { nulToken } from '../utils/cancellation';
import { Disposable } from '../utils/dispose';
import { vscodeNotebookCell } from '../utils/fileSchemes';
import * as languageModeIds from '../utils/languageIds';
import { ResourceMap } from '../utils/resourceMap';
import * as typeConverters from '../utils/typeConverters';
@@ -361,6 +362,98 @@ class GetErrRequest {
}
}
class TabResourceTracker extends Disposable {
private readonly _onDidChange = this._register(new vscode.EventEmitter<{
readonly closed: Iterable<vscode.Uri>;
readonly opened: Iterable<vscode.Uri>;
}>());
public readonly onDidChange = this._onDidChange.event;
private readonly _tabResources: ResourceMap<{ readonly tabs: Set<vscode.Tab> }>;
constructor(
normalizePath: (resource: vscode.Uri) => string | undefined,
config: {
readonly onCaseInsensitiveFileSystem: boolean;
},
) {
super();
this._tabResources = new ResourceMap<{ readonly tabs: Set<vscode.Tab> }>(normalizePath, config);
for (const tabGroup of vscode.window.tabGroups.all) {
for (const tab of tabGroup.tabs) {
this.add(tab);
}
}
this._register(vscode.window.tabGroups.onDidChangeTabs(e => {
const closed = e.closed.flatMap(tab => this.delete(tab));
const opened = e.opened.flatMap(tab => this.add(tab));
if (closed.length || opened.length) {
this._onDidChange.fire({ closed, opened });
}
}));
}
public has(resource: vscode.Uri): boolean {
if (resource.scheme === vscodeNotebookCell) {
const notebook = vscode.workspace.notebookDocuments.find(doc =>
doc.getCells().some(cell => cell.document.uri.toString() === resource.toString()));
return !!notebook && this.has(notebook.uri);
}
const entry = this._tabResources.get(resource);
return !!entry && entry.tabs.size > 0;
}
private add(tab: vscode.Tab): vscode.Uri[] {
const addedResources: vscode.Uri[] = [];
for (const uri of this.getResourcesForTab(tab)) {
const entry = this._tabResources.get(uri);
if (entry) {
entry.tabs.add(tab);
} else {
this._tabResources.set(uri, { tabs: new Set([tab]) });
addedResources.push(uri);
}
}
return addedResources;
}
private delete(tab: vscode.Tab): vscode.Uri[] {
const closedResources: vscode.Uri[] = [];
for (const uri of this.getResourcesForTab(tab)) {
const entry = this._tabResources.get(uri);
if (!entry) {
continue;
}
entry.tabs.delete(tab);
if (entry.tabs.size === 0) {
this._tabResources.delete(uri);
closedResources.push(uri);
}
}
return closedResources;
}
private getResourcesForTab(tab: vscode.Tab): vscode.Uri[] {
if (tab.input instanceof vscode.TabInputText) {
return [tab.input.uri];
} else if (tab.input instanceof vscode.TabInputTextDiff) {
return [tab.input.original, tab.input.modified];
} else if (tab.input instanceof vscode.TabInputNotebook) {
return [tab.input.uri];
} else {
return [];
}
}
}
export default class BufferSyncSupport extends Disposable {
private readonly client: ITypeScriptServiceClient;
@@ -375,6 +468,8 @@ export default class BufferSyncSupport extends Disposable {
private listening: boolean = false;
private readonly synchronizer: BufferSynchronizer;
private readonly _tabResources: TabResourceTracker;
constructor(
client: ITypeScriptServiceClient,
modeIds: readonly string[],
@@ -391,6 +486,28 @@ export default class BufferSyncSupport extends Disposable {
this.pendingDiagnostics = new PendingDiagnostics(pathNormalizer, { onCaseInsensitiveFileSystem });
this.synchronizer = new BufferSynchronizer(client, pathNormalizer, onCaseInsensitiveFileSystem);
this._tabResources = this._register(new TabResourceTracker(pathNormalizer, { onCaseInsensitiveFileSystem }));
this._register(this._tabResources.onDidChange(e => {
if (this.client.configuration.enableProjectDiagnostics) {
return;
}
for (const closed of e.closed) {
const syncedBuffer = this.syncedBuffers.get(closed);
if (syncedBuffer) {
this.pendingDiagnostics.delete(closed);
this.pendingGetErr?.files.delete(closed);
}
}
for (const opened of e.opened) {
const syncedBuffer = this.syncedBuffers.get(opened);
if (syncedBuffer) {
this.requestDiagnostic(syncedBuffer);
}
}
}));
this.updateConfiguration();
vscode.workspace.onDidChangeConfiguration(this.updateConfiguration, this, this._disposables);
}
@@ -494,6 +611,7 @@ export default class BufferSyncSupport extends Disposable {
if (!syncedBuffer) {
return;
}
this.pendingDiagnostics.delete(resource);
this.pendingGetErr?.files.delete(resource);
this.syncedBuffers.delete(resource);
@@ -506,7 +624,7 @@ export default class BufferSyncSupport extends Disposable {
public interruptGetErr<R>(f: () => R): R {
if (!this.pendingGetErr
|| this.client.configuration.enableProjectDiagnostics // `geterr` happens on seperate server so no need to cancel it.
|| this.client.configuration.enableProjectDiagnostics // `geterr` happens on separate server so no need to cancel it.
) {
return f();
}
@@ -628,7 +746,11 @@ export default class BufferSyncSupport extends Disposable {
this._validateTypeScript = tsConfig.get<boolean>('validate.enable', true);
}
private shouldValidate(buffer: SyncedBuffer) {
private shouldValidate(buffer: SyncedBuffer): boolean {
if (!this.client.configuration.enableProjectDiagnostics && !this._tabResources.has(buffer.resource)) { // Only validate resources that are showing to the user
return false;
}
switch (buffer.kind) {
case BufferKind.JavaScript:
return this._validateJavaScript;
@@ -25,7 +25,7 @@ import * as fileSchemes from './utils/fileSchemes';
import { Logger } from './utils/logger';
import { isWeb } from './utils/platform';
import { TypeScriptPluginPathsProvider } from './utils/pluginPathsProvider';
import { PluginManager } from './utils/plugins';
import { PluginManager, TypeScriptServerPlugin } from './utils/plugins';
import { TelemetryProperties, TelemetryReporter, VSCodeTelemetryReporter } from './utils/telemetry';
import Tracer from './utils/tracer';
import { inferredProjectCompilerOptions, ProjectType } from './utils/tsconfig';
@@ -430,32 +430,29 @@ export default class TypeScriptServiceClient extends Disposable implements IType
});
handle.onExit((data: TypeScriptServerExitEvent) => {
const { code, signal } = data;
this.error(`TSServer exited. Code: ${code}. Signal: ${signal}`);
// In practice, the exit code is an integer with no ties to any identity,
// so it can be classified as SystemMetaData, rather than CallstackOrException.
/* __GDPR__
"tsserver.exitWithCode" : {
"owner": "mjbvz",
"code" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" },
"signal" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" },
"${include}": [
"${TypeScriptCommonProperties}"
]
}
*/
this.logTelemetry('tsserver.exitWithCode', { code: code ?? undefined, signal: signal ?? undefined });
if (this.token !== mytoken) {
// this is coming from an old process
return;
}
const { code, signal } = data;
if (code === null || typeof code === 'undefined') {
this.info(`TSServer exited. Signal: ${signal}`);
} else {
// In practice, the exit code is an integer with no ties to any identity,
// so it can be classified as SystemMetaData, rather than CallstackOrException.
this.error(`TSServer exited with code: ${code}. Signal: ${signal}`);
/* __GDPR__
"tsserver.exitWithCode" : {
"owner": "mjbvz",
"code" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" },
"signal" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" },
"${include}": [
"${TypeScriptCommonProperties}"
]
}
*/
this.logTelemetry('tsserver.exitWithCode', { code, signal: signal ?? undefined });
}
if (handle.tsServerLogFile) {
this.info(`TSServer log file: ${handle.tsServerLogFile}`);
}
@@ -587,6 +584,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType
this.numberRestarts++;
let startService = true;
const pluginExtensionList = this.pluginManager.plugins.map(plugin => plugin.extension.id).join(', ');
const reportIssueItem: vscode.MessageItem = {
title: localize('serverDiedReportIssue', 'Report Issue'),
};
@@ -599,7 +597,9 @@ export default class TypeScriptServiceClient extends Disposable implements IType
startService = false;
this.hasServerFatallyCrashedTooManyTimes = true;
prompt = vscode.window.showErrorMessage(
localize('serverDiedAfterStart', 'The TypeScript language service died 5 times right after it got started. The service will not be restarted.'),
this.pluginManager.plugins.length
? localize('serverDiedImmediatelyWithPlugins', "The JS/TS language service immediately crashed 5 times. The service will not be restarted.\nThis may be caused by a plugin contributed by one of these extensions: {0}", pluginExtensionList)
: localize('serverDiedImmediately', "The JS/TS language service immediately crashed 5 times. The service will not be restarted."),
reportIssueItem);
/* __GDPR__
@@ -613,21 +613,30 @@ export default class TypeScriptServiceClient extends Disposable implements IType
this.logTelemetry('serviceExited');
} else if (diff < 60 * 1000 * 5 /* 5 Minutes */) {
this.lastStart = Date.now();
prompt = vscode.window.showWarningMessage(
localize('serverDied', 'The TypeScript language service died unexpectedly 5 times in the last 5 Minutes.'),
reportIssueItem);
if (!this._isPromptingAfterCrash) {
prompt = vscode.window.showWarningMessage(
this.pluginManager.plugins.length
? localize('serverDiedFiveTimesWithPlugins', "The JS/TS language service crashed 5 times in the last 5 Minutes.\nThis may be caused by a plugin contributed by one of these extensions: {0}", pluginExtensionList)
: localize('serverDiedFiveTimes', "The JS/TS language service crashed 5 times in the last 5 Minutes."),
reportIssueItem);
}
}
} else if (['vscode-insiders', 'code-oss'].includes(vscode.env.uriScheme)) {
// Prompt after a single restart
if (!this._isPromptingAfterCrash && previousState.type === ServerState.Type.Errored && previousState.error instanceof TypeScriptServerError) {
this.numberRestarts = 0;
this._isPromptingAfterCrash = true;
this.numberRestarts = 0;
if (!this._isPromptingAfterCrash) {
prompt = vscode.window.showWarningMessage(
localize('serverDiedOnce', 'The TypeScript language service died unexpectedly.'),
this.pluginManager.plugins.length
? localize('serverDiedOnceWithPlugins', "The JS/TS language service crashed.\nThis may be caused by a plugin contributed by one of these extensions: {0}", pluginExtensionList)
: localize('serverDiedOnce', "The JS/TS language service crashed."),
reportIssueItem);
}
}
if (prompt) {
this._isPromptingAfterCrash = true;
}
prompt?.then(item => {
this._isPromptingAfterCrash = false;
@@ -647,7 +656,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType
});
} else {
const args = previousState.type === ServerState.Type.Errored && previousState.error instanceof TypeScriptServerError
? getReportIssueArgsForError(previousState.error, previousState.tsServerLogFile)
? getReportIssueArgsForError(previousState.error, previousState.tsServerLogFile, this.pluginManager.plugins)
: undefined;
vscode.commands.executeCommand('workbench.action.openIssueReporter', args);
}
@@ -1005,6 +1014,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType
function getReportIssueArgsForError(
error: TypeScriptServerError,
logPath: string | undefined,
globalPlugins: readonly TypeScriptServerPlugin[],
): { extensionId: string; issueTitle: string; issueBody: string } | undefined {
if (!error.serverStack || !error.serverMessage) {
return undefined;
@@ -1023,6 +1033,10 @@ function getReportIssueArgsForError(
3.`,
];
if (globalPlugins.length) {
sections.push(`**Global TS Server Plugins**\n\n` + globalPlugins.map(plugin => `- \`${plugin.name}\``).join('\n'));
}
if (logPath) {
sections.push(`**TS Server Log**
@@ -1036,7 +1050,7 @@ The log file may contain personal data, including full paths and source code fro
sections.push(`**TS Server Log**
Server logging disabled. To help us fix crashes like this, please enable logging by setting:
Server logging disabled. To help us fix crashes like this, please enable logging by setting:
\`\`\`json
"typescript.tsserver.log": "verbose"
@@ -8,6 +8,7 @@ import * as arrays from './arrays';
import { Disposable } from './dispose';
export interface TypeScriptServerPlugin {
readonly extension: vscode.Extension<unknown>;
readonly uri: vscode.Uri;
readonly name: string;
readonly enableForWorkspaceTypeScriptVersions: boolean;
@@ -74,6 +75,7 @@ export class PluginManager extends Disposable {
const plugins: TypeScriptServerPlugin[] = [];
for (const plugin of pack.contributes.typescriptServerPlugins) {
plugins.push({
extension,
name: plugin.name,
enableForWorkspaceTypeScriptVersions: !!plugin.enableForWorkspaceTypeScriptVersions,
uri: extension.extensionUri,
@@ -7,7 +7,7 @@ import * as assert from 'assert';
import 'mocha';
import * as vscode from 'vscode';
import { disposeAll } from '../utils';
import { Kernel, saveAllFilesAndCloseAll } from './notebook.test';
import { Kernel, saveAllFilesAndCloseAll } from './notebook.api.test';
export type INativeInteractiveWindow = { notebookUri: vscode.Uri; inputUri: vscode.Uri; notebookEditor: vscode.NotebookEditor };
@@ -0,0 +1,358 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import 'mocha';
import { TextDecoder, TextEncoder } from 'util';
import * as vscode from 'vscode';
import { asPromise, assertNoRpc, closeAllEditors, createRandomFile, disposeAll, revertAllDirty, saveAllEditors } from '../utils';
async function createRandomNotebookFile() {
return createRandomFile('', undefined, '.vsctestnb');
}
async function openRandomNotebookDocument() {
const uri = await createRandomNotebookFile();
return vscode.workspace.openNotebookDocument(uri);
}
export async function saveAllFilesAndCloseAll() {
await saveAllEditors();
await closeAllEditors();
}
function sleep(ms: number): Promise<void> {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
}
export class Kernel {
readonly controller: vscode.NotebookController;
readonly associatedNotebooks = new Set<string>();
constructor(id: string, label: string, viewType: string = 'notebookCoreTest') {
this.controller = vscode.notebooks.createNotebookController(id, viewType, label);
this.controller.executeHandler = this._execute.bind(this);
this.controller.supportsExecutionOrder = true;
this.controller.supportedLanguages = ['typescript', 'javascript'];
this.controller.onDidChangeSelectedNotebooks(e => {
if (e.selected) {
this.associatedNotebooks.add(e.notebook.uri.toString());
} else {
this.associatedNotebooks.delete(e.notebook.uri.toString());
}
});
}
protected async _execute(cells: vscode.NotebookCell[]): Promise<void> {
for (const cell of cells) {
await this._runCell(cell);
}
}
protected async _runCell(cell: vscode.NotebookCell) {
// create a single output with exec order 1 and output is plain/text
// of either the cell itself or (iff empty) the cell's document's uri
const task = this.controller.createNotebookCellExecution(cell);
task.start(Date.now());
task.executionOrder = 1;
await sleep(10); // Force to be take some time
await task.replaceOutput([new vscode.NotebookCellOutput([
vscode.NotebookCellOutputItem.text(cell.document.getText() || cell.document.uri.toString(), 'text/plain')
])]);
task.end(true);
}
}
function getFocusedCell(editor?: vscode.NotebookEditor) {
return editor ? editor.notebook.cellAt(editor.selections[0].start) : undefined;
}
const apiTestContentProvider: vscode.NotebookContentProvider = {
openNotebook: async (resource: vscode.Uri): Promise<vscode.NotebookData> => {
if (/.*empty\-.*\.vsctestnb$/.test(resource.path)) {
return {
metadata: {},
cells: []
};
}
const dto: vscode.NotebookData = {
metadata: { custom: { testMetadata: false } },
cells: [
{
value: 'test',
languageId: 'typescript',
kind: vscode.NotebookCellKind.Code,
outputs: [],
metadata: { custom: { testCellMetadata: 123 } },
executionSummary: { timing: { startTime: 10, endTime: 20 } }
},
{
value: 'test2',
languageId: 'typescript',
kind: vscode.NotebookCellKind.Code,
outputs: [
new vscode.NotebookCellOutput([
vscode.NotebookCellOutputItem.text('Hello World', 'text/plain')
],
{
testOutputMetadata: true,
['text/plain']: { testOutputItemMetadata: true }
})
],
executionSummary: { executionOrder: 5, success: true },
metadata: { custom: { testCellMetadata: 456 } }
}
]
};
return dto;
},
saveNotebook: async (_document: vscode.NotebookDocument, _cancellation: vscode.CancellationToken) => {
return;
},
saveNotebookAs: async (_targetResource: vscode.Uri, _document: vscode.NotebookDocument, _cancellation: vscode.CancellationToken) => {
return;
},
backupNotebook: async (_document: vscode.NotebookDocument, _context: vscode.NotebookDocumentBackupContext, _cancellation: vscode.CancellationToken) => {
return {
id: '1',
delete: () => { }
};
}
};
(vscode.env.uiKind === vscode.UIKind.Web ? suite.skip : suite)('Notebook API tests', function () {
const testDisposables: vscode.Disposable[] = [];
const suiteDisposables: vscode.Disposable[] = [];
suiteTeardown(async function () {
assertNoRpc();
await revertAllDirty();
await closeAllEditors();
disposeAll(suiteDisposables);
suiteDisposables.length = 0;
});
suiteSetup(function () {
suiteDisposables.push(vscode.workspace.registerNotebookContentProvider('notebookCoreTest', apiTestContentProvider));
});
let defaultKernel: Kernel;
setup(async function () {
// there should be ONE default kernel in this suite
defaultKernel = new Kernel('mainKernel', 'Notebook Default Kernel');
testDisposables.push(defaultKernel.controller);
await saveAllFilesAndCloseAll();
});
teardown(async function () {
disposeAll(testDisposables);
testDisposables.length = 0;
await saveAllFilesAndCloseAll();
});
test('notebook open', async function () {
const notebook = await openRandomNotebookDocument();
const editor = await vscode.window.showNotebookDocument(notebook);
assert.strictEqual(getFocusedCell(editor)?.document.getText(), 'test');
assert.strictEqual(getFocusedCell(editor)?.document.languageId, 'typescript');
const secondCell = editor.notebook.cellAt(1);
assert.strictEqual(secondCell.outputs.length, 1);
assert.deepStrictEqual(secondCell.outputs[0].metadata, { testOutputMetadata: true, ['text/plain']: { testOutputItemMetadata: true } });
assert.strictEqual(secondCell.outputs[0].items.length, 1);
assert.strictEqual(secondCell.outputs[0].items[0].mime, 'text/plain');
assert.strictEqual(new TextDecoder().decode(secondCell.outputs[0].items[0].data), 'Hello World');
assert.strictEqual(secondCell.executionSummary?.executionOrder, 5);
assert.strictEqual(secondCell.executionSummary?.success, true);
});
test('multiple tabs: different editors with same document', async function () {
const notebook = await openRandomNotebookDocument();
const firstNotebookEditor = await vscode.window.showNotebookDocument(notebook, { viewColumn: vscode.ViewColumn.One });
const secondNotebookEditor = await vscode.window.showNotebookDocument(notebook, { viewColumn: vscode.ViewColumn.Beside });
assert.notStrictEqual(firstNotebookEditor, secondNotebookEditor);
assert.strictEqual(firstNotebookEditor?.notebook, secondNotebookEditor?.notebook, 'split notebook editors share the same document');
});
test.skip('#106657. Opening a notebook from markers view is broken ', async function () {
const document = await openRandomNotebookDocument();
const [cell] = document.getCells();
assert.strictEqual(vscode.window.activeNotebookEditor, undefined);
// opening a cell-uri opens a notebook editor
await vscode.window.showTextDocument(cell.document, { viewColumn: vscode.ViewColumn.Active });
// await vscode.commands.executeCommand('vscode.open', cell.document.uri, vscode.ViewColumn.Active);
assert.strictEqual(!!vscode.window.activeNotebookEditor, true);
assert.strictEqual(vscode.window.activeNotebookEditor!.notebook.uri.toString(), document.uri.toString());
});
test('Cannot open notebook from cell-uri with vscode.open-command', async function () {
const document = await openRandomNotebookDocument();
const [cell] = document.getCells();
await saveAllFilesAndCloseAll();
assert.strictEqual(vscode.window.activeNotebookEditor, undefined);
// BUG is that the editor opener (https://github.com/microsoft/vscode/blob/8e7877bdc442f1e83a7fec51920d82b696139129/src/vs/editor/browser/services/openerService.ts#L69)
// removes the fragment if it matches something numeric. For notebooks that's not wanted...
// opening a cell-uri opens a notebook editor
await vscode.commands.executeCommand('vscode.open', cell.document.uri);
assert.strictEqual(vscode.window.activeNotebookEditor!.notebook.uri.toString(), document.uri.toString());
});
test('#97830, #97764. Support switch to other editor types', async function () {
const notebook = await openRandomNotebookDocument();
const editor = await vscode.window.showNotebookDocument(notebook);
const edit = new vscode.WorkspaceEdit();
const focusedCell = getFocusedCell(editor);
assert.ok(focusedCell);
edit.replace(focusedCell.document.uri, focusedCell.document.lineAt(0).range, 'var abc = 0;');
await vscode.workspace.applyEdit(edit);
assert.strictEqual(getFocusedCell(editor)?.document.getText(), 'var abc = 0;');
// no kernel -> no default language
assert.strictEqual(getFocusedCell(editor)?.document.languageId, 'typescript');
await vscode.commands.executeCommand('vscode.openWith', notebook.uri, 'default');
assert.strictEqual(vscode.window.activeTextEditor?.document.uri.path, notebook.uri.path);
});
test('#102411 - untitled notebook creation failed', async function () {
await vscode.commands.executeCommand('workbench.action.files.newUntitledFile', { viewType: 'notebookCoreTest' });
assert.notStrictEqual(vscode.window.activeNotebookEditor, undefined, 'untitled notebook editor is not undefined');
await closeAllEditors();
});
test('#115855 onDidSaveNotebookDocument', async function () {
const resource = await createRandomNotebookFile();
const notebook = await vscode.workspace.openNotebookDocument(resource);
const notebookEdit = new vscode.NotebookEdit(new vscode.NotebookRange(1, 1), [new vscode.NotebookCellData(vscode.NotebookCellKind.Code, 'test 2', 'javascript')]);
const edit = new vscode.WorkspaceEdit();
edit.set(notebook.uri, [notebookEdit]);
await vscode.workspace.applyEdit(edit);
assert.strictEqual(notebook.isDirty, true);
const saveEvent = asPromise(vscode.workspace.onDidSaveNotebookDocument);
await notebook.save();
await saveEvent;
assert.strictEqual(notebook.isDirty, false);
});
});
(vscode.env.uiKind === vscode.UIKind.Web ? suite.skip : suite)('statusbar', () => {
const emitter = new vscode.EventEmitter<vscode.NotebookCell>();
const onDidCallProvide = emitter.event;
const suiteDisposables: vscode.Disposable[] = [];
suiteTeardown(async function () {
assertNoRpc();
await revertAllDirty();
await closeAllEditors();
disposeAll(suiteDisposables);
suiteDisposables.length = 0;
});
suiteSetup(() => {
suiteDisposables.push(vscode.notebooks.registerNotebookCellStatusBarItemProvider('notebookCoreTest', {
async provideCellStatusBarItems(cell: vscode.NotebookCell, _token: vscode.CancellationToken): Promise<vscode.NotebookCellStatusBarItem[]> {
emitter.fire(cell);
return [];
}
}));
suiteDisposables.push(vscode.workspace.registerNotebookContentProvider('notebookCoreTest', apiTestContentProvider));
});
test('provideCellStatusBarItems called on metadata change', async function () {
const provideCalled = asPromise(onDidCallProvide);
const notebook = await openRandomNotebookDocument();
await vscode.window.showNotebookDocument(notebook);
await provideCalled;
const edit = new vscode.WorkspaceEdit();
edit.replaceNotebookCellMetadata(notebook.uri, 0, { inputCollapsed: true });
await vscode.workspace.applyEdit(edit);
await provideCalled;
});
});
suite('Notebook & LiveShare', function () {
const suiteDisposables: vscode.Disposable[] = [];
const notebookType = 'vsls-testing';
suiteTeardown(() => {
vscode.Disposable.from(...suiteDisposables).dispose();
});
suiteSetup(function () {
suiteDisposables.push(vscode.workspace.registerNotebookSerializer(notebookType, new class implements vscode.NotebookSerializer {
deserializeNotebook(content: Uint8Array, _token: vscode.CancellationToken): vscode.NotebookData | Thenable<vscode.NotebookData> {
const value = new TextDecoder().decode(content);
const cell1 = new vscode.NotebookCellData(vscode.NotebookCellKind.Code, value, 'fooLang');
cell1.outputs = [new vscode.NotebookCellOutput([vscode.NotebookCellOutputItem.stderr(value)])];
return new vscode.NotebookData([cell1]);
}
serializeNotebook(data: vscode.NotebookData, _token: vscode.CancellationToken): Uint8Array | Thenable<Uint8Array> {
return new TextEncoder().encode(data.cells[0].value);
}
}, {}, {
displayName: 'LS',
filenamePattern: ['*'],
}));
});
test('command: vscode.resolveNotebookContentProviders', async function () {
type Info = { viewType: string; displayName: string; filenamePattern: string[] };
const info = await vscode.commands.executeCommand<Info[]>('vscode.resolveNotebookContentProviders');
assert.strictEqual(Array.isArray(info), true);
const item = info.find(item => item.viewType === notebookType);
assert.ok(item);
assert.strictEqual(item?.viewType, notebookType);
});
test('command: vscode.executeDataToNotebook', async function () {
const value = 'dataToNotebook';
const data = await vscode.commands.executeCommand<vscode.NotebookData>('vscode.executeDataToNotebook', notebookType, new TextEncoder().encode(value));
assert.ok(data instanceof vscode.NotebookData);
assert.strictEqual(data.cells.length, 1);
assert.strictEqual(data.cells[0].value, value);
assert.strictEqual(new TextDecoder().decode(data.cells[0].outputs![0].items[0].data), value);
});
test('command: vscode.executeNotebookToData', async function () {
const value = 'notebookToData';
const notebook = new vscode.NotebookData([new vscode.NotebookCellData(vscode.NotebookCellKind.Code, value, 'fooLang')]);
const data = await vscode.commands.executeCommand<Uint8Array>('vscode.executeNotebookToData', notebookType, notebook);
assert.ok(data instanceof Uint8Array);
assert.deepStrictEqual(new TextDecoder().decode(data), value);
});
});
@@ -7,7 +7,7 @@ import * as assert from 'assert';
import * as vscode from 'vscode';
import * as utils from '../utils';
suite.skip('Notebook Document', function () {
suite('Notebook Document', function () {
const simpleContentProvider = new class implements vscode.NotebookSerializer {
deserializeNotebook(_data: Uint8Array): vscode.NotebookData | Thenable<vscode.NotebookData> {
@@ -315,6 +315,18 @@ suite.skip('Notebook Document', function () {
assert.strictEqual(data.cellChanges[0].cell.index, 0);
});
test('workspace edit API (notebookMetadata)', async function () {
const uri = await utils.createRandomFile(undefined, undefined, '.nbdtest');
const document = await vscode.workspace.openNotebookDocument(uri);
const edit = new vscode.WorkspaceEdit();
const metdataEdit = vscode.NotebookEdit.updateNotebookMetadata({ ...document.metadata, custom: { ...(document.metadata.custom || {}), extraNotebookMetadata: true } });
edit.set(document.uri, [metdataEdit]);
const success = await vscode.workspace.applyEdit(edit);
assert.equal(success, true);
assert.ok(document.metadata.custom.extraNotebookMetadata, `Test metadata not found`);
});
test('document save API', async function () {
const uri = await utils.createRandomFile(undefined, undefined, '.nbdtest');
const notebook = await vscode.workspace.openNotebookDocument(uri);
@@ -411,7 +423,7 @@ suite.skip('Notebook Document', function () {
assert.strictEqual(document.isDirty, false);
});
test('onDidOpenNotebookDocument - emit event only once when opened in two editors', async function () {
test.skip('onDidOpenNotebookDocument - emit event only once when opened in two editors', async function () { // TODO@rebornix https://github.com/microsoft/vscode/issues/157222
const uri = await utils.createRandomFile(undefined, undefined, '.nbdtest');
let counter = 0;
testDisposables.push(vscode.workspace.onDidOpenNotebookDocument(nb => {
@@ -65,39 +65,6 @@ import * as utils from '../utils';
testDisposables.length = 0;
});
test.skip('showNotebookDocument', async function () { // TODO@rebornix https://github.com/microsoft/vscode/issues/139078
const notebookDocumentsFromOnDidOpen = new Set<vscode.NotebookDocument>();
const sub = vscode.workspace.onDidOpenNotebookDocument(e => {
notebookDocumentsFromOnDidOpen.add(e);
});
const uri = await utils.createRandomFile(undefined, undefined, '.nbdtest');
const editor = await vscode.window.showNotebookDocument(uri);
assert.strictEqual(uri.toString(), editor.notebook.uri.toString());
assert.strictEqual(notebookDocumentsFromOnDidOpen.has(editor.notebook), true);
const includes = vscode.workspace.notebookDocuments.includes(editor.notebook);
assert.strictEqual(true, includes);
sub.dispose();
});
// TODO@rebornix deal with getting started
test.skip('notebook editor has viewColumn', async function () {
const uri1 = await utils.createRandomFile(undefined, undefined, '.nbdtest');
const editor1 = await vscode.window.showNotebookDocument(uri1);
assert.strictEqual(editor1.viewColumn, vscode.ViewColumn.One);
const uri2 = await utils.createRandomFile(undefined, undefined, '.nbdtest');
const editor2 = await vscode.window.showNotebookDocument(uri2, { viewColumn: vscode.ViewColumn.Beside });
assert.strictEqual(editor2.viewColumn, vscode.ViewColumn.Two);
});
// #138683
test('Opening a notebook should fire activeNotebook event changed only once', async function () {
const openedEditor = onDidOpenNotebookEditor();
@@ -0,0 +1,494 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import 'mocha';
import { TextDecoder } from 'util';
import * as vscode from 'vscode';
import { asPromise, assertNoRpc, closeAllEditors, createRandomFile, DeferredPromise, disposeAll, revertAllDirty, saveAllEditors } from '../utils';
async function createRandomNotebookFile() {
return createRandomFile('', undefined, '.vsctestnb');
}
async function openRandomNotebookDocument() {
const uri = await createRandomNotebookFile();
return vscode.workspace.openNotebookDocument(uri);
}
export async function saveAllFilesAndCloseAll() {
await saveAllEditors();
await closeAllEditors();
}
async function withEvent<T>(event: vscode.Event<T>, callback: (e: Promise<T>) => Promise<void>) {
const e = asPromise<T>(event);
await callback(e);
}
function sleep(ms: number): Promise<void> {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
}
export class Kernel {
readonly controller: vscode.NotebookController;
readonly associatedNotebooks = new Set<string>();
constructor(id: string, label: string, viewType: string = 'notebookCoreTest') {
this.controller = vscode.notebooks.createNotebookController(id, viewType, label);
this.controller.executeHandler = this._execute.bind(this);
this.controller.supportsExecutionOrder = true;
this.controller.supportedLanguages = ['typescript', 'javascript'];
this.controller.onDidChangeSelectedNotebooks(e => {
if (e.selected) {
this.associatedNotebooks.add(e.notebook.uri.toString());
} else {
this.associatedNotebooks.delete(e.notebook.uri.toString());
}
});
}
protected async _execute(cells: vscode.NotebookCell[]): Promise<void> {
for (const cell of cells) {
await this._runCell(cell);
}
}
protected async _runCell(cell: vscode.NotebookCell) {
// create a single output with exec order 1 and output is plain/text
// of either the cell itself or (iff empty) the cell's document's uri
const task = this.controller.createNotebookCellExecution(cell);
task.start(Date.now());
task.executionOrder = 1;
await sleep(10); // Force to be take some time
await task.replaceOutput([new vscode.NotebookCellOutput([
vscode.NotebookCellOutputItem.text(cell.document.getText() || cell.document.uri.toString(), 'text/plain')
])]);
task.end(true);
}
}
async function assertKernel(kernel: Kernel, notebook: vscode.NotebookDocument): Promise<void> {
const success = await vscode.commands.executeCommand('notebook.selectKernel', {
extension: 'vscode.vscode-api-tests',
id: kernel.controller.id
});
assert.ok(success, `expected selected kernel to be ${kernel.controller.id}`);
assert.ok(kernel.associatedNotebooks.has(notebook.uri.toString()));
}
const apiTestContentProvider: vscode.NotebookContentProvider = {
openNotebook: async (resource: vscode.Uri): Promise<vscode.NotebookData> => {
if (/.*empty\-.*\.vsctestnb$/.test(resource.path)) {
return {
metadata: {},
cells: []
};
}
const dto: vscode.NotebookData = {
metadata: { custom: { testMetadata: false } },
cells: [
{
value: 'test',
languageId: 'typescript',
kind: vscode.NotebookCellKind.Code,
outputs: [],
metadata: { custom: { testCellMetadata: 123 } },
executionSummary: { timing: { startTime: 10, endTime: 20 } }
},
{
value: 'test2',
languageId: 'typescript',
kind: vscode.NotebookCellKind.Code,
outputs: [
new vscode.NotebookCellOutput([
vscode.NotebookCellOutputItem.text('Hello World', 'text/plain')
],
{
testOutputMetadata: true,
['text/plain']: { testOutputItemMetadata: true }
})
],
executionSummary: { executionOrder: 5, success: true },
metadata: { custom: { testCellMetadata: 456 } }
}
]
};
return dto;
},
saveNotebook: async (_document: vscode.NotebookDocument, _cancellation: vscode.CancellationToken) => {
return;
},
saveNotebookAs: async (_targetResource: vscode.Uri, _document: vscode.NotebookDocument, _cancellation: vscode.CancellationToken) => {
return;
},
backupNotebook: async (_document: vscode.NotebookDocument, _context: vscode.NotebookDocumentBackupContext, _cancellation: vscode.CancellationToken) => {
return {
id: '1',
delete: () => { }
};
}
};
(vscode.env.uiKind === vscode.UIKind.Web ? suite.skip : suite)('Notebook Kernel API tests', function () {
const testDisposables: vscode.Disposable[] = [];
const suiteDisposables: vscode.Disposable[] = [];
suiteTeardown(async function () {
assertNoRpc();
await revertAllDirty();
await closeAllEditors();
disposeAll(suiteDisposables);
suiteDisposables.length = 0;
});
suiteSetup(function () {
suiteDisposables.push(vscode.workspace.registerNotebookContentProvider('notebookCoreTest', apiTestContentProvider));
});
let defaultKernel: Kernel;
setup(async function () {
// there should be ONE default kernel in this suite
defaultKernel = new Kernel('mainKernel', 'Notebook Default Kernel');
testDisposables.push(defaultKernel.controller);
await saveAllFilesAndCloseAll();
});
teardown(async function () {
disposeAll(testDisposables);
testDisposables.length = 0;
await saveAllFilesAndCloseAll();
});
test('cell execute command takes arguments', async () => {
const notebook = await openRandomNotebookDocument();
await vscode.window.showNotebookDocument(notebook);
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
const editor = vscode.window.activeNotebookEditor!;
const cell = editor.notebook.cellAt(0);
await withEvent(vscode.workspace.onDidChangeNotebookDocument, async event => {
await vscode.commands.executeCommand('notebook.execute');
await event;
assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked
});
await withEvent(vscode.workspace.onDidChangeNotebookDocument, async event => {
await vscode.commands.executeCommand('notebook.cell.clearOutputs');
await event;
assert.strictEqual(cell.outputs.length, 0, 'should clear');
});
const secondResource = await createRandomNotebookFile();
await vscode.commands.executeCommand('vscode.openWith', secondResource, 'notebookCoreTest');
await withEvent<vscode.NotebookDocumentChangeEvent>(vscode.workspace.onDidChangeNotebookDocument, async event => {
await vscode.commands.executeCommand('notebook.cell.execute', { start: 0, end: 1 }, notebook.uri);
await event;
assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked
assert.strictEqual(vscode.window.activeNotebookEditor?.notebook.uri.fsPath, secondResource.fsPath);
});
});
test('cell execute command takes arguments 2', async () => {
const notebook = await openRandomNotebookDocument();
await vscode.window.showNotebookDocument(notebook);
let firstCellExecuted = false;
let secondCellExecuted = false;
const def = new DeferredPromise<void>();
testDisposables.push(vscode.workspace.onDidChangeNotebookDocument(e => {
e.cellChanges.forEach(change => {
if (change.cell.index === 0 && change.executionSummary) {
firstCellExecuted = true;
}
if (change.cell.index === 1 && change.executionSummary) {
secondCellExecuted = true;
}
});
if (firstCellExecuted && secondCellExecuted) {
def.complete();
}
}));
vscode.commands.executeCommand('notebook.cell.execute', { document: notebook.uri, ranges: [{ start: 0, end: 1 }, { start: 1, end: 2 }] });
await def.p;
await saveAllFilesAndCloseAll();
});
test('document execute command takes arguments', async () => {
const notebook = await openRandomNotebookDocument();
await vscode.window.showNotebookDocument(notebook);
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
const editor = vscode.window.activeNotebookEditor!;
const cell = editor.notebook.cellAt(0);
await withEvent<vscode.NotebookDocumentChangeEvent>(vscode.workspace.onDidChangeNotebookDocument, async (event) => {
await vscode.commands.executeCommand('notebook.execute', notebook.uri);
await event;
assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked
});
});
test('cell execute and select kernel', async function () {
const notebook = await openRandomNotebookDocument();
const editor = await vscode.window.showNotebookDocument(notebook);
assert.strictEqual(vscode.window.activeNotebookEditor === editor, true, 'notebook first');
const cell = editor.notebook.cellAt(0);
const alternativeKernel = new class extends Kernel {
constructor() {
super('secondaryKernel', 'Notebook Secondary Test Kernel');
this.controller.supportsExecutionOrder = false;
}
override async _runCell(cell: vscode.NotebookCell) {
const task = this.controller.createNotebookCellExecution(cell);
task.start();
await task.replaceOutput([new vscode.NotebookCellOutput([
vscode.NotebookCellOutputItem.text('my second output', 'text/plain')
])]);
task.end(true);
}
};
testDisposables.push(alternativeKernel.controller);
await withEvent<vscode.NotebookDocumentChangeEvent>(vscode.workspace.onDidChangeNotebookDocument, async (event) => {
await assertKernel(defaultKernel, notebook);
await vscode.commands.executeCommand('notebook.cell.execute');
await event;
assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked
assert.strictEqual(cell.outputs[0].items.length, 1);
assert.strictEqual(cell.outputs[0].items[0].mime, 'text/plain');
assert.deepStrictEqual(new TextDecoder().decode(cell.outputs[0].items[0].data), cell.document.getText());
});
await withEvent<vscode.NotebookDocumentChangeEvent>(vscode.workspace.onDidChangeNotebookDocument, async (event) => {
await assertKernel(alternativeKernel, notebook);
await vscode.commands.executeCommand('notebook.cell.execute');
await event;
assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked
assert.strictEqual(cell.outputs[0].items.length, 1);
assert.strictEqual(cell.outputs[0].items[0].mime, 'text/plain');
assert.deepStrictEqual(new TextDecoder().decode(cell.outputs[0].items[0].data), 'my second output');
});
});
test('onDidChangeCellExecutionState is fired', async () => {
const notebook = await openRandomNotebookDocument();
const editor = await vscode.window.showNotebookDocument(notebook);
const cell = editor.notebook.cellAt(0);
let eventCount = 0;
const def = new DeferredPromise<void>();
testDisposables.push(vscode.notebooks.onDidChangeNotebookCellExecutionState(e => {
try {
assert.strictEqual(e.cell.document.uri.toString(), cell.document.uri.toString(), 'event should be fired for the executing cell');
if (eventCount === 0) {
assert.strictEqual(e.state, vscode.NotebookCellExecutionState.Pending, 'should be set to Pending');
} else if (eventCount === 1) {
assert.strictEqual(e.state, vscode.NotebookCellExecutionState.Executing, 'should be set to Executing');
assert.strictEqual(cell.outputs.length, 0, 'no outputs yet: ' + JSON.stringify(cell.outputs[0]));
} else if (e.state === vscode.NotebookCellExecutionState.Idle) {
assert.strictEqual(cell.outputs.length, 1, 'should have an output');
def.complete();
}
eventCount++;
} catch (err) {
def.error(err);
}
}));
vscode.commands.executeCommand('notebook.cell.execute', { document: notebook.uri, ranges: [{ start: 0, end: 1 }] });
await def.p;
});
test('Output changes are applied once the promise resolves', async function () {
let called = false;
const verifyOutputSyncKernel = new class extends Kernel {
constructor() {
super('verifyOutputSyncKernel', '');
}
override async _execute(cells: vscode.NotebookCell[]) {
const [cell] = cells;
const task = this.controller.createNotebookCellExecution(cell);
task.start();
await task.replaceOutput([new vscode.NotebookCellOutput([
vscode.NotebookCellOutputItem.text('Some output', 'text/plain')
])]);
assert.strictEqual(cell.notebook.cellAt(0).outputs.length, 1);
assert.deepStrictEqual(new TextDecoder().decode(cell.notebook.cellAt(0).outputs[0].items[0].data), 'Some output');
task.end(undefined);
called = true;
}
};
const notebook = await openRandomNotebookDocument();
await vscode.window.showNotebookDocument(notebook);
await assertKernel(verifyOutputSyncKernel, notebook);
await vscode.commands.executeCommand('notebook.cell.execute');
assert.strictEqual(called, true);
verifyOutputSyncKernel.controller.dispose();
});
test('executionSummary', async () => {
const notebook = await openRandomNotebookDocument();
const editor = await vscode.window.showNotebookDocument(notebook);
const cell = editor.notebook.cellAt(0);
assert.strictEqual(cell.executionSummary?.success, undefined);
assert.strictEqual(cell.executionSummary?.executionOrder, undefined);
await vscode.commands.executeCommand('notebook.cell.execute');
assert.strictEqual(cell.outputs.length, 1, 'should execute');
assert.ok(cell.executionSummary);
assert.strictEqual(cell.executionSummary!.success, true);
assert.strictEqual(typeof cell.executionSummary!.executionOrder, 'number');
});
test('initialize executionSummary', async () => {
const document = await openRandomNotebookDocument();
const cell = document.cellAt(0);
assert.strictEqual(cell.executionSummary?.success, undefined);
assert.strictEqual(cell.executionSummary?.timing?.startTime, 10);
assert.strictEqual(cell.executionSummary?.timing?.endTime, 20);
});
test('execution cancelled when delete while executing', async () => {
const document = await openRandomNotebookDocument();
const cell = document.cellAt(0);
let executionWasCancelled = false;
const cancelledKernel = new class extends Kernel {
constructor() {
super('cancelledKernel', '');
}
override async _execute(cells: vscode.NotebookCell[]) {
const [cell] = cells;
const exe = this.controller.createNotebookCellExecution(cell);
exe.token.onCancellationRequested(() => executionWasCancelled = true);
}
};
testDisposables.push(cancelledKernel.controller);
await vscode.window.showNotebookDocument(document);
await assertKernel(cancelledKernel, document);
await vscode.commands.executeCommand('notebook.cell.execute');
// Delete executing cell
const edit = new vscode.WorkspaceEdit();
edit.replaceNotebookCells(cell!.notebook.uri, new vscode.NotebookRange(cell!.index, cell!.index + 1), []);
await vscode.workspace.applyEdit(edit);
assert.strictEqual(executionWasCancelled, true);
});
test('appendOutput to different cell', async function () {
const notebook = await openRandomNotebookDocument();
const editor = await vscode.window.showNotebookDocument(notebook);
const cell0 = editor.notebook.cellAt(0);
const notebookEdit = new vscode.NotebookEdit(new vscode.NotebookRange(1, 1), [new vscode.NotebookCellData(vscode.NotebookCellKind.Code, 'test 2', 'javascript')]);
const edit = new vscode.WorkspaceEdit();
edit.set(notebook.uri, [notebookEdit]);
await vscode.workspace.applyEdit(edit);
const cell1 = editor.notebook.cellAt(1);
const nextCellKernel = new class extends Kernel {
constructor() {
super('nextCellKernel', 'Append to cell kernel');
}
override async _runCell(cell: vscode.NotebookCell) {
const task = this.controller.createNotebookCellExecution(cell);
task.start();
await task.appendOutput([new vscode.NotebookCellOutput([
vscode.NotebookCellOutputItem.text('my output')
])], cell1);
await task.appendOutput([new vscode.NotebookCellOutput([
vscode.NotebookCellOutputItem.text('my output 2')
])], cell1);
task.end(true);
}
};
testDisposables.push(nextCellKernel.controller);
await withEvent<vscode.NotebookDocumentChangeEvent>(vscode.workspace.onDidChangeNotebookDocument, async (event) => {
await assertKernel(nextCellKernel, notebook);
await vscode.commands.executeCommand('notebook.cell.execute');
await event;
assert.strictEqual(cell0.outputs.length, 0, 'should not change cell 0');
assert.strictEqual(cell1.outputs.length, 2, 'should update cell 1');
assert.strictEqual(cell1.outputs[0].items.length, 1);
assert.deepStrictEqual(new TextDecoder().decode(cell1.outputs[0].items[0].data), 'my output');
});
});
test('replaceOutput to different cell', async function () {
const notebook = await openRandomNotebookDocument();
const editor = await vscode.window.showNotebookDocument(notebook);
const cell0 = editor.notebook.cellAt(0);
const notebookEdit = new vscode.NotebookEdit(new vscode.NotebookRange(1, 1), [new vscode.NotebookCellData(vscode.NotebookCellKind.Code, 'test 2', 'javascript')]);
const edit = new vscode.WorkspaceEdit();
edit.set(notebook.uri, [notebookEdit]);
await vscode.workspace.applyEdit(edit);
const cell1 = editor.notebook.cellAt(1);
const nextCellKernel = new class extends Kernel {
constructor() {
super('nextCellKernel', 'Replace to cell kernel');
}
override async _runCell(cell: vscode.NotebookCell) {
const task = this.controller.createNotebookCellExecution(cell);
task.start();
await task.replaceOutput([new vscode.NotebookCellOutput([
vscode.NotebookCellOutputItem.text('my output')
])], cell1);
await task.replaceOutput([new vscode.NotebookCellOutput([
vscode.NotebookCellOutputItem.text('my output 2')
])], cell1);
task.end(true);
}
};
testDisposables.push(nextCellKernel.controller);
await withEvent<vscode.NotebookDocumentChangeEvent>(vscode.workspace.onDidChangeNotebookDocument, async (event) => {
await assertKernel(nextCellKernel, notebook);
await vscode.commands.executeCommand('notebook.cell.execute');
await event;
assert.strictEqual(cell0.outputs.length, 0, 'should not change cell 0');
assert.strictEqual(cell1.outputs.length, 1, 'should update cell 1');
assert.strictEqual(cell1.outputs[0].items.length, 1);
assert.deepStrictEqual(new TextDecoder().decode(cell1.outputs[0].items[0].data), 'my output 2');
});
});
});

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