Merge branch 'master' into joh/kernelLanguages

This commit is contained in:
Johannes Rieken 2021-02-11 16:45:39 +01:00
commit e498c28de1
161 changed files with 4164 additions and 1217 deletions

View file

@ -13,5 +13,6 @@
**/extensions/**/out/**
**/extensions/**/build/**
**/extensions/markdown-language-features/media/**
**/extensions/markdown-language-features/notebook-out/**
**/extensions/typescript-basics/test/colorize-fixtures/**
**/extensions/**/dist/**

View file

@ -86,6 +86,8 @@ module.exports.indentationFilter = [
'!**/*.Dockerfile',
'!**/*.dockerfile',
'!extensions/markdown-language-features/media/*.js',
'!extensions/markdown-language-features/notebook-out/*.js',
'!extensions/markdown-notebook-math/notebook-out/*.js',
'!extensions/simple-browser/media/*.js',
];

View file

@ -29,6 +29,7 @@ exports.dirs = [
'extensions/json-language-features',
'extensions/json-language-features/server',
'extensions/markdown-language-features',
'extensions/markdown-notebook-math',
'extensions/merge-conflict',
'extensions/microsoft-authentication',
'extensions/npm',

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,26 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as MarkdownIt from 'markdown-it';
declare const acquireNotebookRendererApi: any;
type extendMarkdownItFnType = (
(f: (md: MarkdownIt.MarkdownIt) => void) => void
);
(function () {
const markdownIt = new MarkdownIt();
(globalThis as any).extendMarkdownIt = ((f: (md: MarkdownIt.MarkdownIt) => void) => {
f(markdownIt);
}) as extendMarkdownItFnType;
const notebook = acquireNotebookRendererApi('notebookCoreTestRenderer');
notebook.onDidCreateMarkdown(({ element, content }: any) => {
const rendered = markdownIt.render(content);
element.innerHTML = rendered;
});
}());

View file

@ -30,6 +30,13 @@
"onCustomEditor:vscode.markdown.preview.editor"
],
"contributes": {
"notebookMarkdownRenderer": [
{
"id": "markdownItRenderer",
"displayName": "Markdown it renderer",
"entrypoint": "./notebook-out/index.js"
}
],
"commands": [
{
"command": "markdown.showPreview",

View file

@ -0,0 +1,27 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
const path = require('path');
module.exports = {
entry: {
index: './notebook/index.ts'
},
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
}
]
},
resolve: {
extensions: ['.tsx', '.ts', '.js']
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'notebook-out')
}
};

View file

@ -0,0 +1,12 @@
test/**
test-workspace/**
src/**
tsconfig.json
out/test/**
out/**
extension.webpack.config.js
extension-browser.webpack.config.js
cgmanifest.json
yarn.lock
preview-src/**
webpack.config.js

View file

@ -0,0 +1,3 @@
# Markdown Notebook Math support
**Notice:** This extension is bundled with Visual Studio Code. It can be disabled but not uninstalled.

Binary file not shown.

After

Width:  |  Height:  |  Size: 903 B

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,22 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import type * as markdownIt from 'markdown-it';
import 'katex/dist/katex.min.css';
declare const extendMarkdownIt: undefined | (
(f: (md: markdownIt.MarkdownIt) => void) => void
);
(function () {
const katex = require('@iktakahiro/markdown-it-katex');
if (typeof extendMarkdownIt !== 'undefined') {
extendMarkdownIt((md: markdownIt.MarkdownIt) => {
md.use(katex);
});
}
}());

View file

@ -0,0 +1,12 @@
{
"extends": "../../shared.tsconfig.json",
"compilerOptions": {
"outDir": "./dist/",
"jsx": "react",
"lib": [
"es2018",
"DOM",
"DOM.Iterable"
]
}
}

View file

@ -0,0 +1,45 @@
{
"name": "markdown-notebook-math",
"displayName": "%displayName%",
"description": "%description%",
"version": "1.0.0",
"icon": "icon.png",
"publisher": "vscode",
"enableProposedApi": true,
"license": "MIT",
"aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217",
"engines": {
"vscode": "^1.54.0"
},
"categories": [
"Other"
],
"contributes": {
"notebookMarkdownRenderer": [
{
"id": "markdownItRenderer-katex",
"displayName": "Markdown it renderer",
"entrypoint": "./notebook-out/extension.js"
}
]
},
"scripts": {
"compile": "npm run build-notebook",
"watch": "npm run build-notebook",
"build-notebook": "npx webpack-cli --config webpack.notebook.js --mode production"
},
"dependencies": {
"@iktakahiro/markdown-it-katex": "^4.0.1"
},
"devDependencies": {
"@types/markdown-it": "^0.0.0",
"css-loader": "^5.0.2",
"markdown-it": "^12.0.4",
"style-loader": "^2.0.0",
"url-loader": "^4.1.1"
},
"repository": {
"type": "git",
"url": "https://github.com/microsoft/vscode.git"
}
}

View file

@ -0,0 +1,4 @@
{
"displayName": "Markdown Notebook math",
"description": "Provides rich language support for Markdown."
}

View file

@ -0,0 +1,35 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
const path = require('path');
module.exports = {
entry: {
extension: './notebook/extension.ts',
},
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
},
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
use: ['url-loader?limit=100000']
},
],
},
resolve: {
extensions: ['.tsx', '.ts', '.js']
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'notebook-out')
}
};

View file

@ -0,0 +1,315 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@iktakahiro/markdown-it-katex@^4.0.1":
version "4.0.1"
resolved "https://registry.yarnpkg.com/@iktakahiro/markdown-it-katex/-/markdown-it-katex-4.0.1.tgz#65ff9d12afd4c0b7684dd247abe7ce42fc1edac3"
integrity sha512-kGFooO7fIOgY34PSG8ZNVsUlKhhNoqhzW2kq94TNGa8COzh73PO4KsEoPOsQVG1mEAe8tg7GqG0FoVao0aMHaw==
dependencies:
katex "^0.12.0"
"@types/json-schema@^7.0.6":
version "7.0.7"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad"
integrity sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==
"@types/markdown-it@^0.0.0":
version "0.0.0"
resolved "https://registry.yarnpkg.com/@types/markdown-it/-/markdown-it-0.0.0.tgz#8f6acaa5e3245e275f684e95deb3e518d1c6ab16"
integrity sha1-j2rKpeMkXidfaE6V3rPlGNHGqxY=
ajv-keywords@^3.5.2:
version "3.5.2"
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d"
integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==
ajv@^6.12.5:
version "6.12.6"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
dependencies:
fast-deep-equal "^3.1.1"
fast-json-stable-stringify "^2.0.0"
json-schema-traverse "^0.4.1"
uri-js "^4.2.2"
argparse@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
big.js@^5.2.2:
version "5.2.2"
resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==
camelcase@^6.2.0:
version "6.2.0"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809"
integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==
colorette@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.1.tgz#4d0b921325c14faf92633086a536db6e89564b1b"
integrity sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==
commander@^2.19.0:
version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
css-loader@^5.0.2:
version "5.0.2"
resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-5.0.2.tgz#24f758dae349bad0a440c50d7e2067742e0899cb"
integrity sha512-gbkBigdcHbmNvZ1Cg6aV6qh6k9N6XOr8YWzISLQGrwk2mgOH8LLrizhkxbDhQtaLtktyKHD4970S0xwz5btfTA==
dependencies:
camelcase "^6.2.0"
cssesc "^3.0.0"
icss-utils "^5.1.0"
loader-utils "^2.0.0"
postcss "^8.2.4"
postcss-modules-extract-imports "^3.0.0"
postcss-modules-local-by-default "^4.0.0"
postcss-modules-scope "^3.0.0"
postcss-modules-values "^4.0.0"
postcss-value-parser "^4.1.0"
schema-utils "^3.0.0"
semver "^7.3.4"
cssesc@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
emojis-list@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78"
integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==
entities@~2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/entities/-/entities-2.1.0.tgz#992d3129cf7df6870b96c57858c249a120f8b8b5"
integrity sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==
fast-deep-equal@^3.1.1:
version "3.1.3"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
fast-json-stable-stringify@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
icss-utils@^5.0.0, icss-utils@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae"
integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==
indexes-of@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607"
integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc=
json-schema-traverse@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
json5@^2.1.2:
version "2.2.0"
resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3"
integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==
dependencies:
minimist "^1.2.5"
katex@^0.12.0:
version "0.12.0"
resolved "https://registry.yarnpkg.com/katex/-/katex-0.12.0.tgz#2fb1c665dbd2b043edcf8a1f5c555f46beaa0cb9"
integrity sha512-y+8btoc/CK70XqcHqjxiGWBOeIL8upbS0peTPXTvgrh21n1RiWWcIpSWM+4uXq+IAgNh9YYQWdc7LVDPDAEEAg==
dependencies:
commander "^2.19.0"
linkify-it@^3.0.1:
version "3.0.2"
resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-3.0.2.tgz#f55eeb8bc1d3ae754049e124ab3bb56d97797fb8"
integrity sha512-gDBO4aHNZS6coiZCKVhSNh43F9ioIL4JwRjLZPkoLIY4yZFwg264Y5lu2x6rb1Js42Gh6Yqm2f6L2AJcnkzinQ==
dependencies:
uc.micro "^1.0.1"
loader-utils@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.0.tgz#e4cace5b816d425a166b5f097e10cd12b36064b0"
integrity sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==
dependencies:
big.js "^5.2.2"
emojis-list "^3.0.0"
json5 "^2.1.2"
lru-cache@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
dependencies:
yallist "^4.0.0"
markdown-it@^12.0.4:
version "12.0.4"
resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-12.0.4.tgz#eec8247d296327eac3ba9746bdeec9cfcc751e33"
integrity sha512-34RwOXZT8kyuOJy25oJNJoulO8L0bTHYWXcdZBYZqFnjIy3NgjeoM3FmPXIOFQ26/lSHYMr8oc62B6adxXcb3Q==
dependencies:
argparse "^2.0.1"
entities "~2.1.0"
linkify-it "^3.0.1"
mdurl "^1.0.1"
uc.micro "^1.0.5"
mdurl@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e"
integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=
mime-db@1.45.0:
version "1.45.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.45.0.tgz#cceeda21ccd7c3a745eba2decd55d4b73e7879ea"
integrity sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w==
mime-types@^2.1.27:
version "2.1.28"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.28.tgz#1160c4757eab2c5363888e005273ecf79d2a0ecd"
integrity sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ==
dependencies:
mime-db "1.45.0"
minimist@^1.2.5:
version "1.2.5"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
nanoid@^3.1.20:
version "3.1.20"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.20.tgz#badc263c6b1dcf14b71efaa85f6ab4c1d6cfc788"
integrity sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==
postcss-modules-extract-imports@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d"
integrity sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==
postcss-modules-local-by-default@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz#ebbb54fae1598eecfdf691a02b3ff3b390a5a51c"
integrity sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==
dependencies:
icss-utils "^5.0.0"
postcss-selector-parser "^6.0.2"
postcss-value-parser "^4.1.0"
postcss-modules-scope@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz#9ef3151456d3bbfa120ca44898dfca6f2fa01f06"
integrity sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==
dependencies:
postcss-selector-parser "^6.0.4"
postcss-modules-values@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz#d7c5e7e68c3bb3c9b27cbf48ca0bb3ffb4602c9c"
integrity sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==
dependencies:
icss-utils "^5.0.0"
postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4:
version "6.0.4"
resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.4.tgz#56075a1380a04604c38b063ea7767a129af5c2b3"
integrity sha512-gjMeXBempyInaBqpp8gODmwZ52WaYsVOsfr4L4lDQ7n3ncD6mEyySiDtgzCT+NYC0mmeOLvtsF8iaEf0YT6dBw==
dependencies:
cssesc "^3.0.0"
indexes-of "^1.0.1"
uniq "^1.0.1"
util-deprecate "^1.0.2"
postcss-value-parser@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb"
integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==
postcss@^8.2.4:
version "8.2.6"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.2.6.tgz#5d69a974543b45f87e464bc4c3e392a97d6be9fe"
integrity sha512-xpB8qYxgPuly166AGlpRjUdEYtmOWx2iCwGmrv4vqZL9YPVviDVPZPRXxnXr6xPZOdxQ9lp3ZBFCRgWJ7LE3Sg==
dependencies:
colorette "^1.2.1"
nanoid "^3.1.20"
source-map "^0.6.1"
punycode@^2.1.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
schema-utils@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.0.0.tgz#67502f6aa2b66a2d4032b4279a2944978a0913ef"
integrity sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==
dependencies:
"@types/json-schema" "^7.0.6"
ajv "^6.12.5"
ajv-keywords "^3.5.2"
semver@^7.3.4:
version "7.3.4"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97"
integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==
dependencies:
lru-cache "^6.0.0"
source-map@^0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
style-loader@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-2.0.0.tgz#9669602fd4690740eaaec137799a03addbbc393c"
integrity sha512-Z0gYUJmzZ6ZdRUqpg1r8GsaFKypE+3xAzuFeMuoHgjc9KZv3wMyCRjQIWEbhoFSq7+7yoHXySDJyyWQaPajeiQ==
dependencies:
loader-utils "^2.0.0"
schema-utils "^3.0.0"
uc.micro@^1.0.1, uc.micro@^1.0.5:
version "1.0.6"
resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac"
integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==
uniq@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff"
integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=
uri-js@^4.2.2:
version "4.4.1"
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
dependencies:
punycode "^2.1.0"
url-loader@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-4.1.1.tgz#28505e905cae158cf07c92ca622d7f237e70a4e2"
integrity sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==
dependencies:
loader-utils "^2.0.0"
mime-types "^2.1.27"
schema-utils "^3.0.0"
util-deprecate@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
yallist@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==

View file

@ -602,6 +602,18 @@
"description": "%configuration.suggest.completeJSDocs%",
"scope": "resource"
},
"javascript.suggest.jsdoc.generateReturns": {
"type": "boolean",
"default": true,
"markdownDescription": "%configuration.suggest.jsdoc.generateReturns%",
"scope": "resource"
},
"typescript.suggest.jsdoc.generateReturns": {
"type": "boolean",
"default": true,
"markdownDescription": "%configuration.suggest.jsdoc.generateReturns%",
"scope": "resource"
},
"typescript.locale": {
"type": [
"string",

View file

@ -68,6 +68,7 @@
"configuration.javascript.checkJs.experimentalDecorators.deprecation": "This setting has been deprecated in favor of `js/ts.implicitProjectConfig.experimentalDecorators`.",
"configuration.implicitProjectConfig.strictNullChecks": "Enable/disable [strict null checks](https://www.typescriptlang.org/tsconfig#strictNullChecks) in JavaScript and TypeScript files that are not part of a project. Existing `jsconfig.json` or `tsconfig.json` files override this setting.",
"configuration.implicitProjectConfig.strictFunctionTypes": "Enable/disable [strict function types](https://www.typescriptlang.org/tsconfig#strictFunctionTypes) in JavaScript and TypeScript files that are not part of a project. Existing `jsconfig.json` or `tsconfig.json` files override this setting.",
"configuration.suggest.jsdoc.generateReturns": "Enable/disable generating `@return` annotations for JSDoc templates. Requires using TypeScript 4.2+ in the workspace.",
"configuration.suggest.autoImports": "Enable/disable auto import suggestions.",
"taskDefinition.tsconfig.description": "The tsconfig file that defines the TS build.",
"javascript.suggestionActions.enabled": "Enable/disable suggestion diagnostics for JavaScript files in the editor.",

View file

@ -182,6 +182,7 @@ export default class FileConfigurationManager extends Disposable {
allowRenameOfImportPath: true,
includeAutomaticOptionalChainCompletions: config.get<boolean>('suggest.includeAutomaticOptionalChainCompletions', true),
provideRefactorNotApplicableReason: true,
generateReturnInDocTemplate: config.get<boolean>('suggest.jsdoc.generateReturns', true),
};
return preferences;

View file

@ -9,6 +9,7 @@ import { ITypeScriptServiceClient } from '../typescriptService';
import { conditionalRegistration, requireConfiguration } from '../utils/dependentRegistration';
import { DocumentSelector } from '../utils/documentSelector';
import * as typeConverters from '../utils/typeConverters';
import FileConfigurationManager from './fileConfigurationManager';
const localize = nls.loadMessageBundle();
@ -37,6 +38,7 @@ class JsDocCompletionProvider implements vscode.CompletionItemProvider {
constructor(
private readonly client: ITypeScriptServiceClient,
private readonly fileConfigurationManager: FileConfigurationManager,
) { }
public async provideCompletionItems(
@ -53,8 +55,12 @@ class JsDocCompletionProvider implements vscode.CompletionItemProvider {
return undefined;
}
const args = typeConverters.Position.toFileLocationRequestArgs(file, position);
const response = await this.client.execute('docCommentTemplate', args, token);
const response = await this.client.interruptGetErr(async () => {
await this.fileConfigurationManager.ensureConfigurationForDocument(document, token);
const args = typeConverters.Position.toFileLocationRequestArgs(file, position);
return this.client.execute('docCommentTemplate', args, token);
});
if (response.type !== 'response' || !response.body) {
return undefined;
}
@ -107,6 +113,9 @@ export function templateToSnippet(template: string): vscode.SnippetString {
out += post + ` \${${snippetIndex++}}`;
return out;
});
template = template.replace(/\* @returns[ \t]*$/gm, `* @returns \${${snippetIndex++}}`);
return new vscode.SnippetString(template);
}
@ -114,12 +123,14 @@ export function register(
selector: DocumentSelector,
modeId: string,
client: ITypeScriptServiceClient,
fileConfigurationManager: FileConfigurationManager,
): vscode.Disposable {
return conditionalRegistration([
requireConfiguration(modeId, 'suggest.completeJSDocs')
], () => {
return vscode.languages.registerCompletionItemProvider(selector.syntax,
new JsDocCompletionProvider(client),
new JsDocCompletionProvider(client, fileConfigurationManager),
'*');
});
}

View file

@ -72,7 +72,7 @@ export default class LanguageProvider extends Disposable {
import('./languageFeatures/formatting').then(provider => this._register(provider.register(selector, this.description.id, this.client, this.fileConfigurationManager))),
import('./languageFeatures/hover').then(provider => this._register(provider.register(selector, this.client))),
import('./languageFeatures/implementations').then(provider => this._register(provider.register(selector, this.client))),
import('./languageFeatures/jsDocCompletions').then(provider => this._register(provider.register(selector, this.description.id, this.client))),
import('./languageFeatures/jsDocCompletions').then(provider => this._register(provider.register(selector, this.description.id, this.client, this.fileConfigurationManager))),
import('./languageFeatures/organizeImports').then(provider => this._register(provider.register(selector, this.client, this.commandManager, this.fileConfigurationManager, this.telemetryReporter))),
import('./languageFeatures/quickFix').then(provider => this._register(provider.register(selector, this.client, this.fileConfigurationManager, this.commandManager, this.client.diagnosticsManager, this.telemetryReporter))),
import('./languageFeatures/refactor').then(provider => this._register(provider.register(selector, this.client, this.fileConfigurationManager, this.commandManager, this.telemetryReporter))),

View file

@ -1,7 +1,7 @@
{
"name": "code-oss-dev",
"version": "1.54.0",
"distro": "f542aeaaf397d5c71e480442fe772dbe362726db",
"distro": "4e0b11c36e1bc4032ef3c28c82fdf336f7f48cf3",
"author": {
"name": "Microsoft Corporation"
},

View file

@ -163,8 +163,11 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem {
this.actionRunner.run(this._action, context);
}
// Only set the tabIndex on the element once it is about to get focused
// That way this element wont be a tab stop when it is not needed #106441
focus(): void {
if (this.element) {
this.element.tabIndex = 0;
this.element.focus();
this.element.classList.add('focused');
}
@ -173,10 +176,21 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem {
blur(): void {
if (this.element) {
this.element.blur();
this.element.tabIndex = -1;
this.element.classList.remove('focused');
}
}
setFocusable(): void {
if (this.element) {
this.element.tabIndex = 0;
}
}
get trapsArrowNavigation(): boolean {
return false;
}
protected updateEnabled(): void {
// implement in subclass
}
@ -259,14 +273,27 @@ export class ActionViewItem extends BaseActionViewItem {
this.updateChecked();
}
// Only set the tabIndex on the element once it is about to get focused
// That way this element wont be a tab stop when it is not needed #106441
focus(): void {
super.focus();
if (this.label) {
this.label.tabIndex = 0;
this.label.focus();
}
}
blur(): void {
if (this.label) {
this.label.tabIndex = -1;
}
}
setFocusable(): void {
if (this.label) {
this.label.tabIndex = 0;
}
}
updateLabel(): void {
if (this.options.label && this.label) {
this.label.textContent = this.getAction().label;
@ -320,7 +347,6 @@ export class ActionViewItem extends BaseActionViewItem {
if (this.label) {
this.label.removeAttribute('aria-disabled');
this.label.classList.remove('disabled');
this.label.tabIndex = 0;
}
if (this.element) {

View file

@ -140,6 +140,7 @@ export class ActionBar extends Disposable implements IActionRunner {
this._register(DOM.addDisposableListener(this.domNode, DOM.EventType.KEY_DOWN, e => {
const event = new StandardKeyboardEvent(e);
let eventHandled = true;
const focusedItem = typeof this.focusedItem === 'number' ? this.viewItems[this.focusedItem] : undefined;
if (previousKeys && (event.equals(previousKeys[0]) || event.equals(previousKeys[1]))) {
eventHandled = this.focusPrevious();
@ -147,6 +148,12 @@ export class ActionBar extends Disposable implements IActionRunner {
eventHandled = this.focusNext();
} else if (event.equals(KeyCode.Escape) && this.cancelHasListener) {
this._onDidCancel.fire();
} else if ((event.equals(KeyCode.Tab) || event.equals(KeyMod.Shift | KeyCode.Tab)) && focusedItem instanceof BaseActionViewItem && focusedItem.trapsArrowNavigation) {
if (event.equals(KeyCode.Tab)) {
this.focusNext();
} else {
this.focusPrevious();
}
} else if (this.isTriggerKeyEvent(event)) {
// Staying out of the else branch even if not triggered
if (this._triggerKeys.keyDown) {
@ -294,6 +301,11 @@ export class ActionBar extends Disposable implements IActionRunner {
item.setActionContext(this.context);
item.render(actionViewItemElement);
if (this.viewItems.every(i => !i.isEnabled()) && item instanceof BaseActionViewItem && item.isEnabled()) {
// We need to allow for the first enabled item to be focused on using tab navigation #106441
item.setFocusable();
}
if (index === null || index < 0 || index >= this.actionsList.children.length) {
this.actionsList.appendChild(actionViewItemElement);
this.viewItems.push(item);

View file

@ -19,6 +19,7 @@ export interface ICheckboxOpts extends ICheckboxStyles {
readonly icon?: CSSIcon;
readonly title: string;
readonly isChecked: boolean;
readonly notFocusable?: boolean;
}
export interface ICheckboxStyles {
@ -51,7 +52,8 @@ export class CheckboxActionViewItem extends BaseActionViewItem {
this.checkbox = new Checkbox({
actionClassName: this._action.class,
isChecked: this._action.checked,
title: this._action.label
title: this._action.label,
notFocusable: true
});
this.disposables.add(this.checkbox);
this.disposables.add(this.checkbox.onChange(() => this._action.checked = !!this.checkbox && this.checkbox.checked, this));
@ -113,7 +115,9 @@ export class Checkbox extends Widget {
this.domNode = document.createElement('div');
this.domNode.title = this._opts.title;
this.domNode.classList.add(...classes);
this.domNode.tabIndex = 0;
if (!this._opts.notFocusable) {
this.domNode.tabIndex = 0;
}
this.domNode.setAttribute('role', 'checkbox');
this.domNode.setAttribute('aria-checked', String(this._checked));
this.domNode.setAttribute('aria-label', this._opts.title);

View file

@ -78,7 +78,6 @@ export class DropdownMenuActionViewItem extends BaseActionViewItem {
this.element.classList.add(...classNames);
this.element.tabIndex = 0;
this.element.setAttribute('role', 'button');
this.element.setAttribute('aria-haspopup', 'true');
this.element.setAttribute('aria-expanded', 'false');

View file

@ -54,6 +54,7 @@
/* TODO: actions should be part of the pane, but they aren't yet */
.monaco-pane-view .pane:hover > .pane-header.expanded > .actions,
.monaco-pane-view .pane:focus-within > .pane-header.expanded > .actions,
.monaco-pane-view .pane > .pane-header.actions-always-visible.expanded > .actions,
.monaco-pane-view .pane > .pane-header.focused.expanded > .actions {
display: initial;

View file

@ -10,8 +10,8 @@ import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { LinkedList } from 'vs/base/common/linkedList';
import { URI } from 'vs/base/common/uri';
export function isThenable<T>(obj: any): obj is Promise<T> {
return obj && typeof (<Promise<any>>obj).then === 'function';
export function isThenable<T>(obj: unknown): obj is Promise<T> {
return !!obj && typeof (obj as unknown as Promise<T>).then === 'function';
}
export interface CancelablePromise<T> extends Promise<T> {
@ -166,10 +166,10 @@ export class Throttler {
this.activePromise = promiseFactory();
return new Promise((resolve, reject) => {
this.activePromise!.then((result: any) => {
this.activePromise!.then((result: T) => {
this.activePromise = null;
resolve(result);
}, (err: any) => {
}, (err: unknown) => {
this.activePromise = null;
reject(err);
});
@ -179,7 +179,7 @@ export class Throttler {
export class Sequencer {
private current: Promise<any> = Promise.resolve(null);
private current: Promise<unknown> = Promise.resolve(null);
queue<T>(promiseTask: ITask<Promise<T>>): Promise<T> {
return this.current = this.current.then(() => promiseTask(), () => promiseTask());
@ -188,7 +188,7 @@ export class Sequencer {
export class SequencerByKey<TKey> {
private promiseMap = new Map<TKey, Promise<any>>();
private promiseMap = new Map<TKey, Promise<unknown>>();
queue<T>(key: TKey, promiseTask: ITask<Promise<T>>): Promise<T> {
const runningPromise = this.promiseMap.get(key) ?? Promise.resolve();
@ -321,7 +321,7 @@ export class ThrottledDelayer<T> {
}
trigger(promiseFactory: ITask<Promise<T>>, delay?: number): Promise<T> {
return this.delayer.trigger(() => this.throttler.queue(promiseFactory), delay) as any as Promise<T>;
return this.delayer.trigger(() => this.throttler.queue(promiseFactory), delay) as unknown as Promise<T>;
}
isTriggered(): boolean {
@ -488,7 +488,7 @@ export function firstParallel<T>(promiseList: Promise<T>[], shouldStop: (t: T) =
interface ILimitedTaskFactory<T> {
factory: ITask<Promise<T>>;
c: (value: T | Promise<T>) => void;
e: (error?: any) => void;
e: (error?: unknown) => void;
}
/**
@ -667,7 +667,7 @@ export class IntervalTimer implements IDisposable {
export class RunOnceScheduler {
protected runner: ((...args: any[]) => void) | null;
protected runner: ((...args: unknown[]) => void) | null;
private timeoutToken: any;
private timeout: number;
@ -827,7 +827,7 @@ export class IdleValue<T> {
private _didRun: boolean = false;
private _value?: T;
private _error: any;
private _error: unknown;
constructor(executor: () => T) {
this._executor = () => {
@ -1017,7 +1017,7 @@ export class IntervalCounter {
//#region
export type ValueCallback<T = any> = (value: T | Promise<T>) => void;
export type ValueCallback<T = unknown> = (value: T | Promise<T>) => void;
/**
* Creates a promise whose resolution or rejection can be controlled imperatively.
@ -1025,7 +1025,7 @@ export type ValueCallback<T = any> = (value: T | Promise<T>) => void;
export class DeferredPromise<T> {
private completeCallback!: ValueCallback<T>;
private errorCallback!: (err: any) => void;
private errorCallback!: (err: unknown) => void;
private rejected = false;
private resolved = false;
@ -1058,7 +1058,7 @@ export class DeferredPromise<T> {
});
}
public error(err: any) {
public error(err: unknown) {
return new Promise<void>(resolve => {
this.errorCallback(err);
this.rejected = true;
@ -1080,14 +1080,14 @@ export class DeferredPromise<T> {
//#region
export interface IWaitUntil {
waitUntil(thenable: Promise<any>): void;
waitUntil(thenable: Promise<unknown>): void;
}
export class AsyncEmitter<T extends IWaitUntil> extends Emitter<T> {
private _asyncDeliveryQueue?: LinkedList<[Listener<T>, Omit<T, 'waitUntil'>]>;
async fireAsync(data: Omit<T, 'waitUntil'>, token: CancellationToken, promiseJoin?: (p: Promise<any>, listener: Function) => Promise<any>): Promise<void> {
async fireAsync(data: Omit<T, 'waitUntil'>, token: CancellationToken, promiseJoin?: (p: Promise<unknown>, listener: Function) => Promise<unknown>): Promise<void> {
if (!this._listeners) {
return;
}
@ -1103,11 +1103,11 @@ export class AsyncEmitter<T extends IWaitUntil> extends Emitter<T> {
while (this._asyncDeliveryQueue.size > 0 && !token.isCancellationRequested) {
const [listener, data] = this._asyncDeliveryQueue.shift()!;
const thenables: Promise<any>[] = [];
const thenables: Promise<unknown>[] = [];
const event = <T>{
...data,
waitUntil: (p: Promise<any>): void => {
waitUntil: (p: Promise<unknown>): void => {
if (Object.isFrozen(thenables)) {
throw new Error('waitUntil can NOT be called asynchronous');
}
@ -1208,7 +1208,7 @@ export namespace Promises {
return undefined; // do not rethrow so that other promises can settle
})));
if (firstError) {
if (typeof firstError !== 'undefined') {
throw firstError;
}

View file

@ -28,7 +28,6 @@ export function toSlashes(osPath: string) {
* or `getRoot('\\server\shares\path') === \\server\shares\`
*/
export function getRoot(path: string, sep: string = posix.sep): string {
if (!path) {
return '';
}

View file

@ -15,15 +15,15 @@ export function isArray<T>(array: T | {}): array is T extends readonly any[] ? (
/**
* @returns whether the provided parameter is a JavaScript String or not.
*/
export function isString(str: any): str is string {
export function isString(str: unknown): str is string {
return (typeof str === 'string');
}
/**
* @returns whether the provided parameter is a JavaScript Array and each element in the array is a string.
*/
export function isStringArray(value: any): value is string[] {
return Array.isArray(value) && (<any[]>value).every(elem => isString(elem));
export function isStringArray(value: unknown): value is string[] {
return Array.isArray(value) && (<unknown[]>value).every(elem => isString(elem));
}
/**
@ -31,7 +31,7 @@ export function isStringArray(value: any): value is string[] {
* @returns whether the provided parameter is of type `object` but **not**
* `null`, an `array`, a `regexp`, nor a `date`.
*/
export function isObject(obj: any): obj is Object {
export function isObject(obj: unknown): obj is Object {
// The method can't do a type cast since there are type (like strings) which
// are subclasses of any put not positvely matched by the function. Hence type
// narrowing results in wrong results.
@ -46,21 +46,21 @@ export function isObject(obj: any): obj is Object {
* In **contrast** to just checking `typeof` this will return `false` for `NaN`.
* @returns whether the provided parameter is a JavaScript Number or not.
*/
export function isNumber(obj: any): obj is number {
export function isNumber(obj: unknown): obj is number {
return (typeof obj === 'number' && !isNaN(obj));
}
/**
* @returns whether the provided parameter is a JavaScript Boolean or not.
*/
export function isBoolean(obj: any): obj is boolean {
export function isBoolean(obj: unknown): obj is boolean {
return (obj === true || obj === false);
}
/**
* @returns whether the provided parameter is undefined.
*/
export function isUndefined(obj: any): obj is undefined {
export function isUndefined(obj: unknown): obj is undefined {
return (typeof obj === 'undefined');
}
@ -74,12 +74,12 @@ export function isDefined<T>(arg: T | null | undefined): arg is T {
/**
* @returns whether the provided parameter is undefined or null.
*/
export function isUndefinedOrNull(obj: any): obj is undefined | null {
export function isUndefinedOrNull(obj: unknown): obj is undefined | null {
return (isUndefined(obj) || obj === null);
}
export function assertType(condition: any, type?: string): asserts condition {
export function assertType(condition: unknown, type?: string): asserts condition {
if (!condition) {
throw new Error(type ? `Unexpected type, expected '${type}'` : 'Unexpected type');
}
@ -123,7 +123,7 @@ const hasOwnProperty = Object.prototype.hasOwnProperty;
/**
* @returns whether the provided parameter is an empty JavaScript Object or not.
*/
export function isEmptyObject(obj: any): obj is any {
export function isEmptyObject(obj: unknown): obj is object {
if (!isObject(obj)) {
return false;
}
@ -140,27 +140,27 @@ export function isEmptyObject(obj: any): obj is any {
/**
* @returns whether the provided parameter is a JavaScript Function or not.
*/
export function isFunction(obj: any): obj is Function {
export function isFunction(obj: unknown): obj is Function {
return (typeof obj === 'function');
}
/**
* @returns whether the provided parameters is are JavaScript Function or not.
*/
export function areFunctions(...objects: any[]): boolean {
export function areFunctions(...objects: unknown[]): boolean {
return objects.length > 0 && objects.every(isFunction);
}
export type TypeConstraint = string | Function;
export function validateConstraints(args: any[], constraints: Array<TypeConstraint | undefined>): void {
export function validateConstraints(args: unknown[], constraints: Array<TypeConstraint | undefined>): void {
const len = Math.min(args.length, constraints.length);
for (let i = 0; i < len; i++) {
validateConstraint(args[i], constraints[i]);
}
}
export function validateConstraint(arg: any, constraint: TypeConstraint | undefined): void {
export function validateConstraint(arg: unknown, constraint: TypeConstraint | undefined): void {
if (isString(constraint)) {
if (typeof arg !== constraint) {
@ -174,7 +174,7 @@ export function validateConstraint(arg: any, constraint: TypeConstraint | undefi
} catch {
// ignore
}
if (!isUndefinedOrNull(arg) && arg.constructor === constraint) {
if (!isUndefinedOrNull(arg) && (arg as any).constructor === constraint) {
return;
}
if (constraint.length === 1 && constraint.call(undefined, arg) === true) {
@ -204,8 +204,8 @@ export function getAllMethodNames(obj: object): string[] {
return methods;
}
export function createProxyObject<T extends object>(methodNames: string[], invoke: (method: string, args: any[]) => any): T {
const createProxyMethod = (method: string): () => any => {
export function createProxyObject<T extends object>(methodNames: string[], invoke: (method: string, args: unknown[]) => unknown): T {
const createProxyMethod = (method: string): () => unknown => {
return function () {
const args = Array.prototype.slice.call(arguments, 0);
return invoke(method, args);
@ -242,7 +242,7 @@ export type AddFirstParameterToFunctions<Target, TargetFunctionsReturnType, Firs
[K in keyof Target]:
// Function: add param to function
Target[K] extends (...args: any) => TargetFunctionsReturnType ? (firstArg: FirstParameter, ...args: Parameters<Target[K]>) => ReturnType<Target[K]> :
Target[K] extends (...args: any[]) => TargetFunctionsReturnType ? (firstArg: FirstParameter, ...args: Parameters<Target[K]>) => ReturnType<Target[K]> :
// Else: just leave as is
Target[K]

View file

@ -71,10 +71,8 @@ export interface IIPCOptions {
debugBrk?: number;
/**
* See https://github.com/microsoft/vscode/issues/27665
* Allows to pass in fresh execArgv to the forked process such that it doesn't inherit them from `process.execArgv`.
* e.g. Launching the extension host process with `--inspect-brk=xxx` and then forking a process from the extension host
* results in the forked process inheriting `--inspect-brk=xxx`.
* If set, starts the fork with empty execArgv. If not set, execArgv from the parent proces are inherited,
* except --inspect= and --inspect-brk= which are filtered as they would result in a port conflict.
*/
freshExecArgv?: boolean;
@ -198,6 +196,12 @@ export class Client implements IChannelClient, IDisposable {
forkOpts.execArgv = ['--nolazy', '--inspect-brk=' + this.options.debugBrk];
}
if (forkOpts.execArgv === undefined) {
// if not set, the forked process inherits the execArgv of the parent process
// --inspect and --inspect-brk can not be inherited as the port would conflict
forkOpts.execArgv = process.execArgv.filter(a => !/^--inspect(-brk)?=/.test(a)); // remove
}
if (isMacintosh && forkOpts.env) {
// Unset `DYLD_LIBRARY_PATH`, as it leads to process crashes
// See https://github.com/microsoft/vscode/issues/105848

View file

@ -275,7 +275,7 @@ class WorkspaceProvider implements IWorkspaceProvider {
static QUERY_PARAM_PAYLOAD = 'payload';
readonly trusted = undefined;
readonly trusted = true;
constructor(
public readonly workspace: IWorkspace,

View file

@ -40,7 +40,7 @@ import { NodeCachedDataCleaner } from 'vs/code/electron-browser/sharedProcess/co
import { LanguagePackCachedDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/languagePackCachedDataCleaner';
import { StorageDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/storageDataCleaner';
import { LogsDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/logsDataCleaner';
import { IMainProcessService } from 'vs/platform/ipc/electron-sandbox/mainProcessService';
import { IMainProcessService } from 'vs/platform/ipc/electron-sandbox/services';
import { MessagePortMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService';
import { SpdLogLogger } from 'vs/platform/log/node/spdlogLog';
import { DiagnosticsService } from 'vs/platform/diagnostics/node/diagnosticsService';

View file

@ -12,7 +12,7 @@ import { IWindowOpenable } from 'vs/platform/windows/common/windows';
import { ILifecycleMainService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMainService';
import { resolveShellEnv } from 'vs/platform/environment/node/shellEnv';
import { IUpdateService } from 'vs/platform/update/common/update';
import { UpdateChannel } from 'vs/platform/update/electron-main/updateIpc';
import { UpdateChannel } from 'vs/platform/update/common/updateIpc';
import { getDelayedChannel, StaticRouter, ProxyChannel } from 'vs/base/parts/ipc/common/ipc';
import { Server as ElectronIPCServer } from 'vs/base/parts/ipc/electron-main/ipc.electron';
import { Server as NodeIPCServer } from 'vs/base/parts/ipc/node/ipc.net';

View file

@ -22,11 +22,12 @@ import BaseHtml from 'vs/code/electron-sandbox/issue/issueReporterPage';
import { localize } from 'vs/nls';
import { isRemoteDiagnosticError, SystemInfo } from 'vs/platform/diagnostics/common/diagnostics';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { IMainProcessService, ElectronIPCMainProcessService } from 'vs/platform/ipc/electron-sandbox/mainProcessService';
import { IMainProcessService } from 'vs/platform/ipc/electron-sandbox/services';
import { IssueReporterData, IssueReporterExtensionData, IssueReporterFeatures, IssueReporterStyles, IssueType } from 'vs/platform/issue/common/issue';
import { IWindowConfiguration } from 'vs/platform/windows/common/windows';
import { Codicon } from 'vs/base/common/codicons';
import { renderIcon } from 'vs/base/browser/ui/iconLabel/iconLabels';
import { ElectronIPCMainProcessService } from 'vs/platform/ipc/electron-sandbox/mainProcessService';
const MAX_URL_LENGTH = 2045;

View file

@ -15,7 +15,6 @@ import { URI } from 'vs/base/common/uri';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { EditorOpenContext } from 'vs/platform/editor/common/editor';
import { ILogService } from 'vs/platform/log/common/log';
import { IExternalOpener, IExternalUriResolver, IOpener, IOpenerService, IResolvedExternalUri, IValidator, matchesScheme, OpenOptions, ResolveExternalUriOptions } from 'vs/platform/opener/common/opener';
class CommandOpener implements IOpener {
@ -106,8 +105,7 @@ export class OpenerService implements IOpenerService {
constructor(
@ICodeEditorService editorService: ICodeEditorService,
@ICommandService commandService: ICommandService,
@ILogService private logService: ILogService
@ICommandService commandService: ICommandService
) {
// Default external opener is going through window.open()
this._defaultExternalOpener = {
@ -169,7 +167,6 @@ export class OpenerService implements IOpenerService {
const targetURI = typeof target === 'string' ? URI.parse(target) : target;
// validate against the original URI that this URI resolves to, if one exists
const validationTarget = this._resolvedUriTargets.get(targetURI) ?? targetURI;
this.logService.trace(`OpenerService#open: ${targetURI.authority} validating via ${validationTarget.authority}`);
for (const validator of this._validators) {
if (!(await validator.shouldOpen(validationTarget))) {
return false;
@ -192,7 +189,6 @@ export class OpenerService implements IOpenerService {
const result = await resolver.resolveExternalUri(resource, options);
if (result) {
if (!this._resolvedUriTargets.has(result.resolved)) {
this.logService.trace(`OpenerService#resolveExternalUri: ${resource.authority} resolved to ${result.resolved.authority}`);
this._resolvedUriTargets.set(result.resolved, resource);
}
return result;

View file

@ -1140,15 +1140,15 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
const clonedOptions = { ...options };
clonedOptions.inDiffEditor = true;
clonedOptions.automaticLayout = false;
clonedOptions.scrollbar = clonedOptions.scrollbar || {};
// Clone scrollbar options before changing them
clonedOptions.scrollbar = { ...(clonedOptions.scrollbar || {}) };
clonedOptions.scrollbar.vertical = 'visible';
clonedOptions.folding = false;
clonedOptions.codeLens = this._diffCodeLens;
clonedOptions.fixedOverflowWidgets = true;
// clonedOptions.lineDecorationsWidth = '2ch';
if (!clonedOptions.minimap) {
clonedOptions.minimap = {};
}
// Clone minimap options before changing them
clonedOptions.minimap = { ...(clonedOptions.minimap || {}) };
clonedOptions.minimap.enabled = false;
return clonedOptions;
}

View file

@ -43,7 +43,6 @@ import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService
import { StandaloneThemeServiceImpl } from 'vs/editor/standalone/browser/standaloneThemeServiceImpl';
import { splitLines } from 'vs/base/common/strings';
import { IModelService } from 'vs/editor/common/services/modelService';
import { ILogService } from 'vs/platform/log/common/log';
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
@ -57,7 +56,7 @@ function withAllStandaloneServices<T extends IEditor>(domElement: HTMLElement, o
}
if (!services.has(IOpenerService)) {
services.set(IOpenerService, new OpenerService(services.get(ICodeEditorService), services.get(ICommandService), services.get(ILogService)));
services.set(IOpenerService, new OpenerService(services.get(ICodeEditorService), services.get(ICommandService)));
}
let result = callback(services);

View file

@ -8,7 +8,6 @@ import { URI } from 'vs/base/common/uri';
import { OpenerService } from 'vs/editor/browser/services/openerService';
import { TestCodeEditorService } from 'vs/editor/test/browser/editorTestServices';
import { CommandsRegistry, ICommandService, NullCommandService } from 'vs/platform/commands/common/commands';
import { NullLogService } from 'vs/platform/log/common/log';
import { matchesScheme } from 'vs/platform/opener/common/opener';
suite('OpenerService', function () {
@ -31,13 +30,13 @@ suite('OpenerService', function () {
});
test('delegate to editorService, scheme:///fff', async function () {
const openerService = new OpenerService(editorService, NullCommandService, new NullLogService());
const openerService = new OpenerService(editorService, NullCommandService);
await openerService.open(URI.parse('another:///somepath'));
assert.equal(editorService.lastInput!.options!.selection, undefined);
});
test('delegate to editorService, scheme:///fff#L123', async function () {
const openerService = new OpenerService(editorService, NullCommandService, new NullLogService());
const openerService = new OpenerService(editorService, NullCommandService);
await openerService.open(URI.parse('file:///somepath#L23'));
assert.equal(editorService.lastInput!.options!.selection!.startLineNumber, 23);
@ -59,7 +58,7 @@ suite('OpenerService', function () {
});
test('delegate to editorService, scheme:///fff#123,123', async function () {
const openerService = new OpenerService(editorService, NullCommandService, new NullLogService());
const openerService = new OpenerService(editorService, NullCommandService);
await openerService.open(URI.parse('file:///somepath#23'));
assert.equal(editorService.lastInput!.options!.selection!.startLineNumber, 23);
@ -77,7 +76,7 @@ suite('OpenerService', function () {
});
test('delegate to commandsService, command:someid', async function () {
const openerService = new OpenerService(editorService, commandService, new NullLogService());
const openerService = new OpenerService(editorService, commandService);
const id = `aCommand${Math.random()}`;
CommandsRegistry.registerCommand(id, function () { });
@ -99,7 +98,7 @@ suite('OpenerService', function () {
});
test('links are protected by validators', async function () {
const openerService = new OpenerService(editorService, commandService, new NullLogService());
const openerService = new OpenerService(editorService, commandService);
openerService.registerValidator({ shouldOpen: () => Promise.resolve(false) });
@ -110,7 +109,7 @@ suite('OpenerService', function () {
});
test('links validated by validators go to openers', async function () {
const openerService = new OpenerService(editorService, commandService, new NullLogService());
const openerService = new OpenerService(editorService, commandService);
openerService.registerValidator({ shouldOpen: () => Promise.resolve(true) });
@ -129,7 +128,7 @@ suite('OpenerService', function () {
});
test('links validated by multiple validators', async function () {
const openerService = new OpenerService(editorService, commandService, new NullLogService());
const openerService = new OpenerService(editorService, commandService);
let v1 = 0;
openerService.registerValidator({
@ -166,7 +165,7 @@ suite('OpenerService', function () {
});
test('links invalidated by first validator do not continue validating', async function () {
const openerService = new OpenerService(editorService, commandService, new NullLogService());
const openerService = new OpenerService(editorService, commandService);
let v1 = 0;
openerService.registerValidator({

View file

@ -10,7 +10,7 @@ import { TernarySearchTree } from 'vs/base/common/map';
import { distinct } from 'vs/base/common/objects';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IContext, IContextKey, IContextKeyChangeEvent, IContextKeyService, IContextKeyServiceTarget, IReadableSet, SET_CONTEXT_COMMAND_ID, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey';
import { IContext, IContextKey, IContextKeyChangeEvent, IContextKeyService, IContextKeyServiceTarget, IReadableSet, SET_CONTEXT_COMMAND_ID, ContextKeyExpression, RawContextKey, ContextKeyInfo } from 'vs/platform/contextkey/common/contextkey';
import { KeybindingResolver } from 'vs/platform/keybinding/common/keybindingResolver';
const KEYBINDING_CONTEXT_ATTR = 'data-keybinding-context';
@ -501,3 +501,16 @@ function findContextAttr(domNode: IContextKeyServiceTarget | null): number {
CommandsRegistry.registerCommand(SET_CONTEXT_COMMAND_ID, function (accessor, contextKey: any, contextValue: any) {
accessor.get(IContextKeyService).createKey(String(contextKey), contextValue);
});
CommandsRegistry.registerCommand('_generateContextKeyInfo', function () {
const result: ContextKeyInfo[] = [];
const seen = new Set<string>();
for (let info of RawContextKey.all()) {
if (!seen.has(info.key)) {
seen.add(info.key);
result.push(info);
}
}
result.sort((a, b) => a.key.localeCompare(b.key));
console.log(JSON.stringify(result, undefined, 2));
});

View file

@ -1257,13 +1257,28 @@ export class ContextKeyOrExpr implements IContextKeyExpression {
}
}
export interface ContextKeyInfo {
readonly key: string;
readonly type: string;
readonly description?: string;
}
export class RawContextKey<T> extends ContextKeyDefinedExpr {
private static _info: ContextKeyInfo[] = [];
static all(): IterableIterator<ContextKeyInfo> {
return RawContextKey._info.values();
}
private readonly _defaultValue: T | undefined;
constructor(key: string, defaultValue: T | undefined) {
constructor(key: string, defaultValue: T | undefined, description?: string) {
super(key);
this._defaultValue = defaultValue;
// collect all context keys into a central place
RawContextKey._info.push({ key, description, type: typeof defaultValue });
}
public bindTo(target: IContextKeyService): IContextKey<T> {

View file

@ -6,7 +6,7 @@
import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { WindowDriverChannel, WindowDriverRegistryChannelClient } from 'vs/platform/driver/node/driver';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IMainProcessService } from 'vs/platform/ipc/electron-sandbox/mainProcessService';
import { IMainProcessService } from 'vs/platform/ipc/electron-sandbox/services';
import { timeout } from 'vs/base/common/async';
import { BaseWindowDriver } from 'vs/platform/driver/browser/baseDriver';
import { INativeHostService } from 'vs/platform/native/electron-sandbox/native';

View file

@ -61,9 +61,7 @@ export class NsfwWatcherService extends Disposable implements IWatcherService {
});
// Logging
if (this.verboseLogging) {
this.log(`Start watching: [${rootsToStartWatching.map(r => r.path).join(',')}]\nStop watching: [${rootsToStopWatching.join(',')}]`);
}
this.debug(`Start watching: [${rootsToStartWatching.map(r => r.path).join(',')}]\nStop watching: [${rootsToStopWatching.join(',')}]`);
// Stop watching some roots
rootsToStopWatching.forEach(root => {
@ -133,9 +131,7 @@ export class NsfwWatcherService extends Disposable implements IWatcherService {
}
}
if (this.verboseLogging) {
this.log(`Start watching with nsfw: ${request.path}`);
}
this.debug(`Start watching with nsfw: ${request.path}`);
nsfw(request.path, events => {
for (const e of events) {
@ -249,4 +245,8 @@ export class NsfwWatcherService extends Disposable implements IWatcherService {
private error(message: string) {
this._onDidLogMessage.fire({ type: 'error', message: `[File Watcher (nsfw)] ` + message });
}
private debug(message: string) {
this._onDidLogMessage.fire({ type: 'debug', message: `[File Watcher (chokidar)] ` + message });
}
}

View file

@ -146,9 +146,7 @@ export class ChokidarWatcherService extends Disposable implements IWatcherServic
this.warn(`Watcher basePath does not match version on disk and was corrected (original: ${basePath}, real: ${realBasePath})`);
}
if (this.verboseLogging) {
this.log(`Start watching with chokidar: ${realBasePath}, excludes: ${excludes.join(',')}, usePolling: ${usePolling ? 'true, interval ' + pollingInterval : 'false'}`);
}
this.debug(`Start watching with chokidar: ${realBasePath}, excludes: ${excludes.join(',')}, usePolling: ${usePolling ? 'true, interval ' + pollingInterval : 'false'}`);
let chokidarWatcher: chokidar.FSWatcher | null = chokidar.watch(realBasePath, watcherOpts);
this._watcherCount++;
@ -301,6 +299,10 @@ export class ChokidarWatcherService extends Disposable implements IWatcherServic
this._onDidLogMessage.fire({ type: 'trace', message: `[File Watcher (chokidar)] ` + message });
}
private debug(message: string) {
this._onDidLogMessage.fire({ type: 'debug', message: `[File Watcher (chokidar)] ` + message });
}
private warn(message: string) {
this._onDidLogMessage.fire({ type: 'warn', message: `[File Watcher (chokidar)] ` + message });
}

View file

@ -13,7 +13,7 @@ export interface IDiskFileChange {
}
export interface ILogMessage {
type: 'trace' | 'warn' | 'error';
type: 'trace' | 'warn' | 'error' | 'info' | 'debug';
message: string;
}

View file

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

View file

@ -5,7 +5,7 @@
import { IChannel, IServerChannel, StaticRouter } from 'vs/base/parts/ipc/common/ipc';
import { Server as MessagePortServer } from 'vs/base/parts/ipc/electron-browser/ipc.mp';
import { IMainProcessService } from 'vs/platform/ipc/electron-sandbox/mainProcessService';
import { IMainProcessService } from 'vs/platform/ipc/electron-sandbox/services';
/**
* An implementation of `IMainProcessService` that leverages MessagePorts.

View file

@ -6,18 +6,7 @@
import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc';
import { Client as IPCElectronClient } from 'vs/base/parts/ipc/electron-sandbox/ipc.electron';
import { Disposable } from 'vs/base/common/lifecycle';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
export const IMainProcessService = createDecorator<IMainProcessService>('mainProcessService');
export interface IMainProcessService {
readonly _serviceBrand: undefined;
getChannel(channelName: string): IChannel;
registerChannel(channelName: string, channel: IServerChannel<string>): void;
}
import { IMainProcessService } from 'vs/platform/ipc/electron-sandbox/services';
/**
* An implementation of `IMainProcessService` that leverages Electron's IPC.

View file

@ -0,0 +1,77 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IChannel, IServerChannel, ProxyChannel } from 'vs/base/parts/ipc/common/ipc';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
type ChannelClientCtor<T> = { new(channel: IChannel): T };
type Remote = { getChannel(channelName: string): IChannel; };
abstract class RemoteServiceStub<T> {
constructor(
channelName: string,
channelClientCtor: ChannelClientCtor<T> | undefined,
remote: Remote
) {
const channel = remote.getChannel(channelName);
if (channelClientCtor) {
return new channelClientCtor(channel);
} else {
return ProxyChannel.toService(channel);
}
}
}
export interface IRemoteServiceOptions<T> {
readonly channelClientCtor?: ChannelClientCtor<T>;
readonly supportsDelayedInstantiation?: boolean;
}
//#region Main Process
export const IMainProcessService = createDecorator<IMainProcessService>('mainProcessService');
export interface IMainProcessService {
readonly _serviceBrand: undefined;
getChannel(channelName: string): IChannel;
registerChannel(channelName: string, channel: IServerChannel<string>): void;
}
class MainProcessRemoteServiceStub<T> extends RemoteServiceStub<T> {
constructor(channelName: string, channelClientCtor: ChannelClientCtor<T> | undefined, @IMainProcessService ipcService: IMainProcessService) {
super(channelName, channelClientCtor, ipcService);
}
}
export function registerMainProcessRemoteService<T>(id: ServiceIdentifier<T>, channelName: string, options: IRemoteServiceOptions<T> = {}): void {
registerSingleton(id, new SyncDescriptor(MainProcessRemoteServiceStub, [channelName, options.channelClientCtor], options.supportsDelayedInstantiation));
}
//#endregion
//#region Shared Process
export const ISharedProcessService = createDecorator<ISharedProcessService>('sharedProcessService');
export interface ISharedProcessService {
readonly _serviceBrand: undefined;
getChannel(channelName: string): IChannel;
registerChannel(channelName: string, channel: IServerChannel<string>): void;
}
class SharedProcessRemoteServiceStub<T> extends RemoteServiceStub<T> {
constructor(channelName: string, channelClientCtor: ChannelClientCtor<T> | undefined, @ISharedProcessService ipcService: ISharedProcessService) {
super(channelName, channelClientCtor, ipcService);
}
}
export function registerSharedProcessRemoteService<T>(id: ServiceIdentifier<T>, channelName: string, options: IRemoteServiceOptions<T> = {}): void {
registerSingleton(id, new SyncDescriptor(SharedProcessRemoteServiceStub, [channelName, options.channelClientCtor], options.supportsDelayedInstantiation));
}
//#endregion

View file

@ -3,7 +3,6 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { Event } from 'vs/base/common/event';
import { ipcMessagePort } from 'vs/base/parts/sandbox/electron-sandbox/globals';
import { Client as MessagePortClient } from 'vs/base/parts/ipc/common/ipc.mp';
@ -12,16 +11,7 @@ import { INativeHostService } from 'vs/platform/native/electron-sandbox/native';
import { generateUuid } from 'vs/base/common/uuid';
import { ILogService } from 'vs/platform/log/common/log';
import { Disposable } from 'vs/base/common/lifecycle';
export const ISharedProcessService = createDecorator<ISharedProcessService>('sharedProcessService');
export interface ISharedProcessService {
readonly _serviceBrand: undefined;
getChannel(channelName: string): IChannel;
registerChannel(channelName: string, channel: IServerChannel<string>): void;
}
import { ISharedProcessService } from 'vs/platform/ipc/electron-sandbox/services';
export class SharedProcessService extends Disposable implements ISharedProcessService {

View file

@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { INativeHostService } from 'vs/platform/native/electron-sandbox/native';
import { IMainProcessService } from 'vs/platform/ipc/electron-sandbox/mainProcessService';
import { IMainProcessService } from 'vs/platform/ipc/electron-sandbox/services';
import { ProxyChannel } from 'vs/base/parts/ipc/common/ipc';
// @ts-ignore: interface is implemented via proxy

View file

@ -0,0 +1,74 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc';
import { Emitter, Event } from 'vs/base/common/event';
import { IUpdateService, State } from 'vs/platform/update/common/update';
export class UpdateChannel implements IServerChannel {
constructor(private service: IUpdateService) { }
listen(_: unknown, event: string): Event<any> {
switch (event) {
case 'onStateChange': return this.service.onStateChange;
}
throw new Error(`Event not found: ${event}`);
}
call(_: unknown, command: string, arg?: any): Promise<any> {
switch (command) {
case 'checkForUpdates': return this.service.checkForUpdates(arg);
case 'downloadUpdate': return this.service.downloadUpdate();
case 'applyUpdate': return this.service.applyUpdate();
case 'quitAndInstall': return this.service.quitAndInstall();
case '_getInitialState': return Promise.resolve(this.service.state);
case 'isLatestVersion': return this.service.isLatestVersion();
}
throw new Error(`Call not found: ${command}`);
}
}
export class UpdateChannelClient implements IUpdateService {
declare readonly _serviceBrand: undefined;
private readonly _onStateChange = new Emitter<State>();
readonly onStateChange: Event<State> = this._onStateChange.event;
private _state: State = State.Uninitialized;
get state(): State { return this._state; }
set state(state: State) {
this._state = state;
this._onStateChange.fire(state);
}
constructor(private readonly channel: IChannel) {
this.channel.listen<State>('onStateChange')(state => this.state = state);
this.channel.call<State>('_getInitialState').then(state => this.state = state);
}
checkForUpdates(context: any): Promise<void> {
return this.channel.call('checkForUpdates', context);
}
downloadUpdate(): Promise<void> {
return this.channel.call('downloadUpdate');
}
applyUpdate(): Promise<void> {
return this.channel.call('applyUpdate');
}
quitAndInstall(): Promise<void> {
return this.channel.call('quitAndInstall');
}
isLatestVersion(): Promise<boolean> {
return this.channel.call('isLatestVersion');
}
}

View file

@ -1,34 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IServerChannel } from 'vs/base/parts/ipc/common/ipc';
import { Event } from 'vs/base/common/event';
import { IUpdateService } from 'vs/platform/update/common/update';
export class UpdateChannel implements IServerChannel {
constructor(private service: IUpdateService) { }
listen(_: unknown, event: string): Event<any> {
switch (event) {
case 'onStateChange': return this.service.onStateChange;
}
throw new Error(`Event not found: ${event}`);
}
call(_: unknown, command: string, arg?: any): Promise<any> {
switch (command) {
case 'checkForUpdates': return this.service.checkForUpdates(arg);
case 'downloadUpdate': return this.service.downloadUpdate();
case 'applyUpdate': return this.service.applyUpdate();
case 'quitAndInstall': return this.service.quitAndInstall();
case '_getInitialState': return Promise.resolve(this.service.state);
case 'isLatestVersion': return this.service.isLatestVersion();
}
throw new Error(`Call not found: ${command}`);
}
}

View file

@ -195,8 +195,29 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
try {
await synchroniser.sync(manifest, syncHeaders);
} catch (e) {
this.handleSynchronizerError(e, synchroniser.resource);
this._syncErrors.push([synchroniser.resource, UserDataSyncError.toUserDataSyncError(e)]);
if (e instanceof UserDataSyncError) {
// Bail out for following errors
switch (e.code) {
case UserDataSyncErrorCode.TooLarge:
throw new UserDataSyncError(e.message, e.code, synchroniser.resource);
case UserDataSyncErrorCode.TooManyRequests:
case UserDataSyncErrorCode.TooManyRequestsAndRetryAfter:
case UserDataSyncErrorCode.LocalTooManyRequests:
case UserDataSyncErrorCode.Gone:
case UserDataSyncErrorCode.UpgradeRequired:
case UserDataSyncErrorCode.IncompatibleRemoteContent:
case UserDataSyncErrorCode.IncompatibleLocalContent:
throw e;
}
}
// Log and report other errors and continue
const userDataSyncError = UserDataSyncError.toUserDataSyncError(e);
this.reportUserDataSyncError(userDataSyncError, executionId);
this.logService.error(e);
this.logService.error(`${synchroniser.resource}: ${toErrorMessage(e)}`);
this._syncErrors.push([synchroniser.resource, userDataSyncError]);
}
}
@ -371,26 +392,6 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
}
}
private handleSynchronizerError(e: Error, source: SyncResource): void {
if (e instanceof UserDataSyncError) {
switch (e.code) {
case UserDataSyncErrorCode.TooLarge:
throw new UserDataSyncError(e.message, e.code, source);
case UserDataSyncErrorCode.TooManyRequests:
case UserDataSyncErrorCode.TooManyRequestsAndRetryAfter:
case UserDataSyncErrorCode.LocalTooManyRequests:
case UserDataSyncErrorCode.Gone:
case UserDataSyncErrorCode.UpgradeRequired:
case UserDataSyncErrorCode.IncompatibleRemoteContent:
case UserDataSyncErrorCode.IncompatibleLocalContent:
throw e;
}
}
this.logService.error(e);
this.logService.error(`${source}: ${toErrorMessage(e)}`);
}
private reportUserDataSyncError(userDataSyncError: UserDataSyncError, executionId: string) {
this.telemetryService.publicLog2<{ code: string, service: string, url?: string, resource?: string, executionId?: string }, SyncErrorClassification>('sync/error',
{ code: userDataSyncError.code, url: userDataSyncError instanceof UserDataSyncStoreError ? userDataSyncError.url : undefined, resource: userDataSyncError.resource, executionId, service: this.userDataSyncStoreManagementService.userDataSyncStore!.url.toString() });

View file

@ -3,19 +3,10 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Emitter, Event } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
import { Event } from 'vs/base/common/event';
import { URI } from 'vs/base/common/uri';
import { localize } from 'vs/nls';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { IWorkspace, IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
export const WORKSPACE_TRUST_ENABLED = 'workspace.trustEnabled';
export const WORKSPACE_TRUST_URI = URI.parse('workspaceTrust:/Trusted Workspaces');
export enum WorkspaceTrustScope {
Local = 0,
@ -40,11 +31,6 @@ export function workspaceTrustStateToString(trustState: WorkspaceTrustState) {
}
}
export const WorkspaceTrustContext = {
PendingRequest: new RawContextKey<boolean>('workspaceTrustPendingRequest', false),
TrustState: new RawContextKey<WorkspaceTrustState>('workspaceTrustState', WorkspaceTrustState.Unknown)
};
export interface IWorkspaceTrustModel {
readonly onDidChangeTrustState: Event<void>;
@ -86,290 +72,11 @@ export interface IWorkspaceTrustService {
getWorkspaceTrustState(): WorkspaceTrustState;
isWorkspaceTrustEnabled(): boolean;
requireWorkspaceTrust(request: IWorkspaceTrustRequest): Promise<WorkspaceTrustState>;
resetWorkspaceTrust(): Promise<WorkspaceTrustState>;
}
interface IWorkspaceTrustStateInfo {
export interface IWorkspaceTrustStateInfo {
localFolders: { uri: string, trustState: WorkspaceTrustState }[]
// Removing complexity of remote items
//trustedRemoteItems: { uri: string }[]
}
export const WORKSPACE_TRUST_STORAGE_KEY = 'content.trust.model.key';
export class WorkspaceTrustModel extends Disposable implements IWorkspaceTrustModel {
private storageKey = WORKSPACE_TRUST_STORAGE_KEY;
private trustStateInfo: IWorkspaceTrustStateInfo;
private readonly _onDidChangeTrustState = this._register(new Emitter<void>());
readonly onDidChangeTrustState = this._onDidChangeTrustState.event;
constructor(
private readonly storageService: IStorageService
) {
super();
this.trustStateInfo = this.loadTrustInfo();
this._register(this.storageService.onDidChangeValue(changeEvent => {
if (changeEvent.key === this.storageKey) {
this.onDidStorageChange();
}
}));
}
private loadTrustInfo(): IWorkspaceTrustStateInfo {
const infoAsString = this.storageService.get(this.storageKey, StorageScope.GLOBAL);
let result: IWorkspaceTrustStateInfo | undefined;
try {
if (infoAsString) {
result = JSON.parse(infoAsString);
}
} catch { }
if (!result) {
result = {
localFolders: [],
//trustedRemoteItems: []
};
}
if (!result.localFolders) {
result.localFolders = [];
}
// if (!result.trustedRemoteItems) {
// result.trustedRemoteItems = [];
// }
return result;
}
private saveTrustInfo(): void {
this.storageService.store(this.storageKey, JSON.stringify(this.trustStateInfo), StorageScope.GLOBAL, StorageTarget.MACHINE);
}
private onDidStorageChange(): void {
this.trustStateInfo = this.loadTrustInfo();
this._onDidChangeTrustState.fire();
}
setFolderTrustState(folder: URI, trustState: WorkspaceTrustState): void {
let changed = false;
if (trustState === WorkspaceTrustState.Unknown) {
const before = this.trustStateInfo.localFolders.length;
this.trustStateInfo.localFolders = this.trustStateInfo.localFolders.filter(info => info.uri !== folder.toString());
if (this.trustStateInfo.localFolders.length !== before) {
changed = true;
}
} else {
let found = false;
for (const trustInfo of this.trustStateInfo.localFolders) {
if (trustInfo.uri === folder.toString()) {
found = true;
if (trustInfo.trustState !== trustState) {
trustInfo.trustState = trustState;
changed = true;
}
}
}
if (!found) {
this.trustStateInfo.localFolders.push({ uri: folder.toString(), trustState });
changed = true;
}
}
if (changed) {
this.saveTrustInfo();
}
}
getFolderTrustState(folder: URI): WorkspaceTrustState {
for (const trustInfo of this.trustStateInfo.localFolders) {
if (trustInfo.uri === folder.toString()) {
return trustInfo.trustState;
}
}
return WorkspaceTrustState.Unknown;
}
}
export class WorkspaceTrustRequestModel extends Disposable implements IWorkspaceTrustRequestModel {
trustRequest: IWorkspaceTrustRequest | undefined;
_onDidInitiateRequest = this._register(new Emitter<void>());
onDidInitiateRequest: Event<void> = this._onDidInitiateRequest.event;
_onDidCompleteRequest = this._register(new Emitter<WorkspaceTrustState | undefined>());
onDidCompleteRequest = this._onDidCompleteRequest.event;
initiateRequest(request: IWorkspaceTrustRequest): void {
if (this.trustRequest && (!request.immediate || this.trustRequest.immediate)) {
return;
}
this.trustRequest = request;
this._onDidInitiateRequest.fire();
}
completeRequest(trustState?: WorkspaceTrustState): void {
this.trustRequest = undefined;
this._onDidCompleteRequest.fire(trustState);
}
}
export class WorkspaceTrustService extends Disposable implements IWorkspaceTrustService {
_serviceBrand: undefined;
private readonly dataModel: IWorkspaceTrustModel;
readonly requestModel: IWorkspaceTrustRequestModel;
private readonly _onDidChangeTrustState = this._register(new Emitter<WorkspaceTrustStateChangeEvent>());
readonly onDidChangeTrustState = this._onDidChangeTrustState.event;
private _currentTrustState: WorkspaceTrustState = WorkspaceTrustState.Unknown;
private _inFlightResolver?: (trustState: WorkspaceTrustState) => void;
private _trustRequestPromise?: Promise<WorkspaceTrustState>;
private _workspace: IWorkspace;
private readonly _ctxWorkspaceTrustState: IContextKey<WorkspaceTrustState>;
private readonly _ctxWorkspaceTrustPendingRequest: IContextKey<boolean>;
constructor(
@IStorageService private readonly storageService: IStorageService,
@IWorkspaceContextService private readonly workspaceService: IWorkspaceContextService,
@IConfigurationService readonly configurationService: IConfigurationService,
@IContextKeyService readonly contextKeyService: IContextKeyService
) {
super();
this.dataModel = this._register(new WorkspaceTrustModel(this.storageService));
this.requestModel = this._register(new WorkspaceTrustRequestModel());
this._workspace = this.workspaceService.getWorkspace();
this._currentTrustState = this.calculateWorkspaceTrustState();
this._register(this.dataModel.onDidChangeTrustState(() => this.currentTrustState = this.calculateWorkspaceTrustState()));
this._register(this.requestModel.onDidCompleteRequest((trustState) => this.onTrustRequestCompleted(trustState)));
this._ctxWorkspaceTrustState = WorkspaceTrustContext.TrustState.bindTo(contextKeyService);
this._ctxWorkspaceTrustPendingRequest = WorkspaceTrustContext.PendingRequest.bindTo(contextKeyService);
this._ctxWorkspaceTrustState.set(this.currentTrustState);
}
private get currentTrustState(): WorkspaceTrustState {
return this._currentTrustState;
}
private set currentTrustState(trustState: WorkspaceTrustState) {
if (this._currentTrustState === trustState) { return; }
const previousState = this._currentTrustState;
this._currentTrustState = trustState;
this._onDidChangeTrustState.fire({ previousTrustState: previousState, currentTrustState: this._currentTrustState });
}
private calculateWorkspaceTrustState(): WorkspaceTrustState {
if (!this.isWorkspaceTrustEnabled()) {
return WorkspaceTrustState.Trusted;
}
if (this.workspaceService.getWorkbenchState() === WorkbenchState.EMPTY) {
return WorkspaceTrustState.Trusted;
}
let state = undefined;
for (const folder of this._workspace.folders) {
const folderTrust = this.dataModel.getFolderTrustState(folder.uri);
switch (folderTrust) {
case WorkspaceTrustState.Untrusted:
return WorkspaceTrustState.Untrusted;
case WorkspaceTrustState.Unknown:
state = folderTrust;
break;
case WorkspaceTrustState.Trusted:
if (state === undefined) {
state = folderTrust;
}
break;
}
}
return state ?? WorkspaceTrustState.Unknown;
}
private onTrustRequestCompleted(trustState?: WorkspaceTrustState): void {
if (this._inFlightResolver) {
this._inFlightResolver(trustState === undefined ? this.currentTrustState : trustState);
}
this._inFlightResolver = undefined;
this._trustRequestPromise = undefined;
if (trustState === undefined) {
return;
}
this._workspace.folders.forEach(folder => {
this.dataModel.setFolderTrustState(folder.uri, trustState);
});
this._ctxWorkspaceTrustPendingRequest.set(false);
this._ctxWorkspaceTrustState.set(trustState);
}
getWorkspaceTrustState(): WorkspaceTrustState {
return this.currentTrustState;
}
isWorkspaceTrustEnabled(): boolean {
return this.configurationService.getValue<boolean>(WORKSPACE_TRUST_ENABLED) ?? false;
}
async requireWorkspaceTrust(request?: IWorkspaceTrustRequest): Promise<WorkspaceTrustState> {
if (this.currentTrustState === WorkspaceTrustState.Trusted) {
return this.currentTrustState;
}
if (this.currentTrustState === WorkspaceTrustState.Untrusted && !request?.immediate) {
return this.currentTrustState;
}
if (this._trustRequestPromise) {
if (request?.immediate &&
this.requestModel.trustRequest &&
!this.requestModel.trustRequest.immediate) {
this.requestModel.initiateRequest(request);
}
return this._trustRequestPromise;
}
this._trustRequestPromise = new Promise(resolve => {
this._inFlightResolver = resolve;
});
this.requestModel.initiateRequest(request);
this._ctxWorkspaceTrustPendingRequest.set(true);
return this._trustRequestPromise;
}
async resetWorkspaceTrust(): Promise<WorkspaceTrustState> {
if (this.currentTrustState !== WorkspaceTrustState.Unknown) {
this._workspace.folders.forEach(folder => {
this.dataModel.setFolderTrustState(folder.uri, WorkspaceTrustState.Unknown);
});
}
return Promise.resolve(WorkspaceTrustState.Unknown);
}
}
registerSingleton(IWorkspaceTrustService, WorkspaceTrustService);

View file

@ -21,6 +21,8 @@ export class MainThreadAuthenticationProvider extends Disposable {
private _accounts = new Map<string, string[]>(); // Map account name to session ids
private _sessions = new Map<string, string>(); // Map account id to name
private _hasInitializedSessions = false;
constructor(
private readonly _proxy: ExtHostAuthenticationShape,
public readonly id: string,
@ -33,11 +35,6 @@ export class MainThreadAuthenticationProvider extends Disposable {
) {
super();
}
public async initialize(): Promise<void> {
return this.registerCommandsAndContextMenuItems();
}
public hasSessions(): boolean {
return !!this._sessions.size;
}
@ -83,15 +80,6 @@ export class MainThreadAuthenticationProvider extends Disposable {
quickPick.show();
}
private async registerCommandsAndContextMenuItems(): Promise<void> {
try {
const sessions = await this._proxy.$getSessions(this.id);
sessions.forEach(session => this.registerSession(session));
} catch (_) {
// Ignore
}
}
private registerSession(session: modes.AuthenticationSession) {
this._sessions.set(session.id, session.account.label);
@ -123,7 +111,13 @@ export class MainThreadAuthenticationProvider extends Disposable {
}
async getSessions(): Promise<ReadonlyArray<modes.AuthenticationSession>> {
return this._proxy.$getSessions(this.id);
const sessions = await this._proxy.$getSessions(this.id);
if (!this._hasInitializedSessions) {
sessions.forEach(session => this.registerSession(session));
this._hasInitializedSessions = true;
}
return sessions;
}
async updateSessionItems(event: modes.AuthenticationSessionsChangeEvent): Promise<void> {
@ -195,7 +189,6 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
async $registerAuthenticationProvider(id: string, label: string, supportsMultipleAccounts: boolean): Promise<void> {
const provider = new MainThreadAuthenticationProvider(this._proxy, id, label, supportsMultipleAccounts, this.notificationService, this.storageService, this.quickInputService, this.dialogService);
await provider.initialize();
this.authenticationService.registerAuthenticationProvider(id, provider);
}

View file

@ -51,6 +51,17 @@ export class MainThreadTesting extends Disposable implements MainThreadTestingSh
}
}
/**
* @inheritdoc
*/
$retireTest(extId: string): void {
for (const result of this.resultService.results) {
if (result instanceof LiveTestResult) {
result.retire(extId);
}
}
}
/**
* @inheritdoc
*/

View file

@ -1855,6 +1855,7 @@ export interface MainThreadTestingShape {
$publishDiff(resource: ExtHostTestingResource, uri: UriComponents, diff: TestsDiff): void;
$updateTestStateInRun(runId: string, testId: string, state: ITestState): void;
$runTests(req: RunTestsRequest, token: CancellationToken): Promise<string>;
$retireTest(extId: string): void;
}
// --- proxy identifiers

View file

@ -170,6 +170,14 @@ export class ExtHostTesting implements ExtHostTestingShape {
collection.addRoot(hierarchy.root, id);
Promise.resolve(hierarchy.discoveredInitialTests).then(() => collection.pushDiff([TestDiffOpType.DeltaDiscoverComplete, -1]));
hierarchy.onDidChangeTest(e => collection.onItemChange(e, id));
hierarchy.onDidInvalidateTest?.(e => {
const internal = collection.getTestByReference(e);
if (!internal) {
console.warn(`Received a TestProvider.onDidInvalidateTest for a test that does not currently exist.`);
} else {
this.proxy.$retireTest(internal.item.extId);
}
});
} catch (e) {
console.error(e);
}

View file

@ -13,7 +13,7 @@ import { URI } from 'vs/base/common/uri';
import { generateUuid } from 'vs/base/common/uuid';
import { FileSystemProviderErrorCode, markAsFileSystemProviderError } from 'vs/platform/files/common/files';
import { RemoteAuthorityResolverErrorCode } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { CellEditType, ICellEditOperation, notebookDocumentMetadataDefaults } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CellEditType, ICellEditOperation, notebookDocumentMetadataDefaults, NOTEBOOK_DISPLAY_ORDER } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import type * as vscode from 'vscode';
function es5ClassCompat(target: Function): any {
@ -2851,30 +2851,69 @@ export enum ColorThemeKind {
export class NotebookCellMetadata {
readonly readonly: boolean;
readonly inputCollapsed: boolean;
readonly outputCollapsed: boolean;
constructor(
readonly editable?: boolean,
readonly breakpointMargin?: boolean,
readonly runnable?: boolean,
readonly hasExecutionOrder?: boolean,
readonly executionOrder?: number,
readonly runState?: NotebookCellRunState,
readonly runStartTime?: number,
readonly statusMessage?: string,
readonly lastRunDuration?: number,
readonly inputCollapsed?: boolean,
readonly outputCollapsed?: boolean,
readonly custom?: Record<string, any>,
) { }
[key: string]: unknown;
constructor(readonly: boolean, inputCollapsed: boolean, outputCollapsed: boolean) {
this.readonly = readonly;
this.inputCollapsed = inputCollapsed;
this.outputCollapsed = outputCollapsed;
}
with(change: Partial<{ readonly: boolean, inputCollapsed: boolean, outputCollapsed: boolean, [key: string]: unknown }>): NotebookCellMetadata {
const thisAndChange = { ...this, ...change };
const res = new NotebookCellMetadata(thisAndChange.readonly, thisAndChange.inputCollapsed, thisAndChange.outputCollapsed);
for (const key in change) {
if (Object.prototype.hasOwnProperty.call(change, key)) {
res[key] = change[key];
}
}
return res;
with(change: Partial<Omit<NotebookCellMetadata, 'with'>>): NotebookCellMetadata {
return new NotebookCellMetadata(
change.editable ?? this.editable,
change.breakpointMargin ?? this.breakpointMargin,
change.runnable ?? this.runnable,
change.hasExecutionOrder ?? this.hasExecutionOrder,
change.executionOrder ?? this.executionOrder,
change.runState ?? this.runState,
change.runStartTime ?? this.runStartTime,
change.statusMessage ?? this.statusMessage,
change.lastRunDuration ?? this.lastRunDuration,
change.inputCollapsed ?? this.inputCollapsed,
change.outputCollapsed ?? this.outputCollapsed,
change.custom ?? this.custom
);
}
}
export class NotebookDocumentMetadata {
constructor(
readonly editable: boolean = true,
readonly runnable: boolean = true,
readonly cellEditable: boolean = true,
readonly cellRunnable: boolean = true,
readonly cellHasExecutionOrder: boolean = true,
readonly displayOrder: vscode.GlobPattern[] = NOTEBOOK_DISPLAY_ORDER,
readonly custom: { [key: string]: any; } = {},
readonly runState: NotebookRunState = NotebookRunState.Idle,
readonly trusted: boolean = true,
readonly languages: string[] = [],
) { }
with(change: Partial<Omit<NotebookDocumentMetadata, 'with'>>) {
return new NotebookDocumentMetadata(
change.editable ?? this.editable,
change.runnable ?? this.runnable,
change.cellEditable ?? this.cellEditable,
change.cellRunnable ?? this.cellRunnable,
change.cellHasExecutionOrder ?? this.cellHasExecutionOrder,
change.displayOrder ?? this.displayOrder,
change.custom ?? this.custom,
change.runState ?? this.runState,
change.trusted ?? this.trusted,
change.languages ?? this.languages,
);
}
}
export class NotebookCellOutputItem {

View file

@ -23,7 +23,7 @@ import { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { IWorkspacesService, hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces';
import { WORKSPACE_TRUST_ENABLED, WORKSPACE_TRUST_URI } from 'vs/platform/workspace/common/workspaceTrust';
import { WORKSPACE_TRUST_ENABLED, WORKSPACE_TRUST_URI } from 'vs/workbench/services/workspaces/common/workspaceTrust';
export class OpenFileAction extends Action {
@ -255,8 +255,9 @@ class WorkspaceTrustManageAction extends Action2 {
constructor() {
super({
id: 'workbench.action.manageTrust',
title: { value: nls.localize('resetTrustAction', "Manage Trusted Workspaces"), original: 'Manage Trusted Workspaces' },
title: { value: nls.localize('manageTrustAction', "Manage Workspace Trust"), original: 'Manage Workspace Trust' },
precondition: ContextKeyExpr.equals(`config.${WORKSPACE_TRUST_ENABLED}`, true),
category: nls.localize('workspacesCategory', "Workspaces"),
f1: true,
});
}

View file

@ -259,6 +259,11 @@ export class AccountsActivityActionViewItem extends MenuActivityActionViewItem {
}
});
if (providers.length && !menus.length) {
const noAccountsAvailableAction = disposables.add(new Action('noAccountsAvailable', localize('noAccounts', "You are not signed in to any accounts"), undefined, false));
menus.push(noAccountsAvailableAction);
}
if (menus.length && otherCommands.length) {
menus.push(disposables.add(new Separator()));
}

View file

@ -199,8 +199,6 @@ export class ActivityActionViewItem extends BaseActionViewItem {
this.container = container;
// Make the container tab-able for keyboard navigation
this.container.tabIndex = 0;
this.container.setAttribute('role', 'tab');
// Try hard to prevent keyboard only focus feedback when using mouse
@ -647,10 +645,6 @@ export class CompositeActionViewItem extends ActivityActionViewItem {
});
}
focus(): void {
this.container.focus();
}
protected updateChecked(): void {
if (this.getAction().checked) {
this.container.classList.add('checked');

View file

@ -427,15 +427,9 @@ export class BreadcrumbsFilePicker extends BreadcrumbsPicker {
}
async _revealElement(element: IFileStat | IWorkspaceFolder, options: IEditorOptions, sideBySide: boolean): Promise<boolean> {
let resource: URI | undefined;
if (isWorkspaceFolder(element)) {
resource = element.uri;
} else if (!element.isDirectory) {
resource = element.resource;
}
if (resource) {
if (!isWorkspaceFolder(element) && element.isFile) {
this._onWillPickElement.fire();
await this._editorService.openEditor({ resource, options }, sideBySide ? SIDE_GROUP : undefined);
await this._editorService.openEditor({ resource: element.resource, options }, sideBySide ? SIDE_GROUP : undefined);
return true;
}
return false;

View file

@ -192,7 +192,8 @@ export abstract class ViewPane extends Pane implements IView {
return this._titleDescription;
}
private readonly menuActions: ViewMenuActions;
readonly menuActions: ViewMenuActions;
private progressBar!: ProgressBar;
private progressIndicator!: IProgressIndicator;
@ -478,7 +479,7 @@ export abstract class ViewPane extends Pane implements IView {
private setActions(): void {
if (this.toolbar) {
this.toolbar.setActions(prepareActions(this.getActions()), prepareActions(this.getSecondaryActions()));
this.toolbar.setActions(prepareActions(this.menuActions.getPrimaryActions()), prepareActions(this.menuActions.getSecondaryActions()));
this.toolbar.context = this.getActionsContext();
}
}
@ -496,18 +497,6 @@ export abstract class ViewPane extends Pane implements IView {
this._onDidChangeTitleArea.fire();
}
getActions(): IAction[] {
return this.menuActions.getPrimaryActions();
}
getSecondaryActions(): IAction[] {
return this.menuActions.getSecondaryActions();
}
getContextMenuActions(): IAction[] {
return this.menuActions.getContextMenuActions();
}
getActionViewItem(action: IAction): IActionViewItem | undefined {
return createActionViewItem(this.instantiationService, action);
}

View file

@ -583,13 +583,13 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
const result = [];
result.push(...this.menuActions.getPrimaryActions());
if (this.isViewMergedWithContainer()) {
result.push(...this.paneItems[0].pane.getActions());
result.push(...this.paneItems[0].pane.menuActions.getPrimaryActions());
}
return result;
}
getSecondaryActions(): IAction[] {
const viewPaneActions = this.isViewMergedWithContainer() ? this.paneItems[0].pane.getSecondaryActions() : [];
const viewPaneActions = this.isViewMergedWithContainer() ? this.paneItems[0].pane.menuActions.getSecondaryActions() : [];
let menuActions = this.menuActions.getSecondaryActions();
const viewsSubmenuActionIndex = menuActions.findIndex(action => action instanceof SubmenuItemAction && action.item.submenu === ViewsSubMenu);
@ -768,7 +768,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
event.stopPropagation();
event.preventDefault();
const actions: IAction[] = viewPane.getContextMenuActions();
const actions: IAction[] = viewPane.menuActions.getContextMenuActions();
let anchor: { x: number, y: number } = { x: event.posx, y: event.posy };
this.contextMenuService.showContextMenu({

View file

@ -7,7 +7,7 @@ import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle
import { Registry } from 'vs/platform/registry/common/platform';
import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions';
import { Disposable } from 'vs/base/common/lifecycle';
import { IMainProcessService } from 'vs/platform/ipc/electron-sandbox/mainProcessService';
import { IMainProcessService } from 'vs/platform/ipc/electron-sandbox/services';
import { IDisplayMainService } from 'vs/platform/display/common/displayMainService';
import { ProxyChannel } from 'vs/base/parts/ipc/common/ipc';
import { clearAllFontInfos } from 'vs/editor/browser/config/configuration';

View file

@ -20,7 +20,7 @@ import {
} from 'vs/workbench/contrib/debug/common/debug';
import { DebugToolBar } from 'vs/workbench/contrib/debug/browser/debugToolBar';
import { DebugService } from 'vs/workbench/contrib/debug/browser/debugService';
import { registerCommands, ADD_CONFIGURATION_ID, TOGGLE_INLINE_BREAKPOINT_ID, COPY_STACK_TRACE_ID, RESTART_SESSION_ID, TERMINATE_THREAD_ID, STEP_OVER_ID, STEP_INTO_ID, STEP_OUT_ID, PAUSE_ID, DISCONNECT_ID, STOP_ID, RESTART_FRAME_ID, CONTINUE_ID, FOCUS_REPL_ID, JUMP_TO_CURSOR_ID, RESTART_LABEL, STEP_INTO_LABEL, STEP_OVER_LABEL, STEP_OUT_LABEL, PAUSE_LABEL, DISCONNECT_LABEL, STOP_LABEL, CONTINUE_LABEL, DEBUG_START_LABEL, DEBUG_START_COMMAND_ID, DEBUG_RUN_LABEL, DEBUG_RUN_COMMAND_ID, EDIT_EXPRESSION_COMMAND_ID, REMOVE_EXPRESSION_COMMAND_ID } from 'vs/workbench/contrib/debug/browser/debugCommands';
import { registerCommands, ADD_CONFIGURATION_ID, TOGGLE_INLINE_BREAKPOINT_ID, COPY_STACK_TRACE_ID, RESTART_SESSION_ID, TERMINATE_THREAD_ID, STEP_OVER_ID, STEP_INTO_ID, STEP_OUT_ID, PAUSE_ID, DISCONNECT_ID, STOP_ID, RESTART_FRAME_ID, CONTINUE_ID, FOCUS_REPL_ID, JUMP_TO_CURSOR_ID, RESTART_LABEL, STEP_INTO_LABEL, STEP_OVER_LABEL, STEP_OUT_LABEL, PAUSE_LABEL, DISCONNECT_LABEL, STOP_LABEL, CONTINUE_LABEL, DEBUG_START_LABEL, DEBUG_START_COMMAND_ID, DEBUG_RUN_LABEL, DEBUG_RUN_COMMAND_ID, EDIT_EXPRESSION_COMMAND_ID, REMOVE_EXPRESSION_COMMAND_ID, SELECT_AND_START_ID, SELECT_AND_START_LABEL } from 'vs/workbench/contrib/debug/browser/debugCommands';
import { StatusBarColorProvider } from 'vs/workbench/contrib/debug/browser/statusbarColorProvider';
import { IViewsRegistry, Extensions as ViewExtensions, IViewContainersRegistry, ViewContainerLocation, ViewContainer } from 'vs/workbench/common/views';
import { isMacintosh, isWeb } from 'vs/base/common/platform';
@ -123,6 +123,8 @@ function registerCommandsAndActions(): void {
registerDebugCommandPaletteItem(TOGGLE_INLINE_BREAKPOINT_ID, nls.localize('inlineBreakpoint', "Inline Breakpoint"));
registerDebugCommandPaletteItem(DEBUG_START_COMMAND_ID, DEBUG_START_LABEL, ContextKeyExpr.and(CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_DEBUG_STATE.notEqualsTo(getStateLabel(State.Initializing))));
registerDebugCommandPaletteItem(DEBUG_RUN_COMMAND_ID, DEBUG_RUN_LABEL, ContextKeyExpr.and(CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_DEBUG_STATE.notEqualsTo(getStateLabel(State.Initializing))));
registerDebugCommandPaletteItem(SELECT_AND_START_ID, SELECT_AND_START_LABEL, ContextKeyExpr.and(CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_DEBUG_STATE.notEqualsTo(getStateLabel(State.Initializing))));
// Debug callstack context menu
const registerDebugViewMenuItem = (menuId: MenuId, id: string, title: string, order: number, when?: ContextKeyExpression, precondition?: ContextKeyExpression, group = 'navigation') => {

View file

@ -165,6 +165,10 @@ export class ReplFilterActionViewItem extends BaseActionViewItem {
return this.filterInputBox.getHistory();
}
get trapsArrowNavigation(): boolean {
return true;
}
private clearFilterText(): void {
this.filterInputBox.value = '';
}

View file

@ -5,7 +5,7 @@
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug';
import { IMainProcessService } from 'vs/platform/ipc/electron-sandbox/mainProcessService';
import { IMainProcessService } from 'vs/platform/ipc/electron-sandbox/services';
import { ExtensionHostDebugChannelClient, ExtensionHostDebugBroadcastChannel } from 'vs/platform/debug/common/extensionHostDebugIpc';
export class ExtensionHostDebugService extends ExtensionHostDebugChannelClient {

View file

@ -32,7 +32,7 @@ import { timeout } from 'vs/base/common/async';
import { TestExtensionService } from 'vs/workbench/test/common/workbenchTestServices';
import { OS } from 'vs/base/common/platform';
import { IWorkspaceTrustService } from 'vs/platform/workspace/common/workspaceTrust';
import { TestWorkspaceTrustService } from 'vs/platform/workspace/test/common/testWorkspaceTrust';
import { TestWorkspaceTrustService } from 'vs/workbench/services/workspaces/test/common/testWorkspaceTrustService';
interface ExperimentSettings {
enabled?: boolean;

View file

@ -13,7 +13,7 @@ import { IExtensionManagementServerService } from 'vs/workbench/services/extensi
import { IExtensionRecommendationsService } from 'vs/workbench/services/extensionRecommendations/common/extensionRecommendations';
import { ILabelService } from 'vs/platform/label/common/label';
import { extensionButtonProminentBackground, extensionButtonProminentForeground, ExtensionToolTipAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
import { IThemeService, IColorTheme, ThemeIcon } from 'vs/platform/theme/common/themeService';
import { IThemeService, IColorTheme, ThemeIcon, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { EXTENSION_BADGE_REMOTE_BACKGROUND, EXTENSION_BADGE_REMOTE_FOREGROUND } from 'vs/workbench/common/theme';
import { Emitter, Event } from 'vs/base/common/event';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
@ -21,6 +21,7 @@ import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IUserDataAutoSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync';
import { installCountIcon, ratingIcon, remoteIcon, starEmptyIcon, starFullIcon, starHalfIcon, syncIgnoredIcon } from 'vs/workbench/contrib/extensions/browser/extensionsIcons';
import { registerColor } from 'vs/platform/theme/common/colorRegistry';
export abstract class ExtensionWidget extends Disposable implements IExtensionContainer {
private _extension: IExtension | null = null;
@ -368,3 +369,13 @@ export class SyncIgnoredWidget extends ExtensionWidget {
this.element.classList.toggle('hide', !(this.extension && this.extension.state === ExtensionState.Installed && this.userDataAutoSyncEnablementService.isEnabled() && this.extensionsWorkbenchService.isExtensionIgnoredToSync(this.extension)));
}
}
// Rating icon
export const extensionRatingIconColor = registerColor('extensionIcon.starForeground', { light: '#DF6100', dark: '#FF8E00', hc: '#FF8E00' }, localize('extensionIconStarForeground', "The icon color for extension ratings."), true);
registerThemingParticipant((theme, collector) => {
const extensionRatingIcon = theme.getColor(extensionRatingIconColor);
if (extensionRatingIcon) {
collector.addRule(`.extension-ratings .codicon-extensions-star-full, .extension-ratings .codicon-extensions-star-half { color: ${extensionRatingIcon}; }`);
}
});

View file

@ -27,12 +27,6 @@
margin-left: 0;
}
/* TODO @misolori make this a color token */
.extension-ratings .codicon-extensions-star-full,
.extension-ratings .codicon-extensions-star-half {
color: #FF8E00 !important;
}
.extension-install-count .codicon,
.extension-action.codicon-extensions-info-message,
.extension-action.codicon-extensions-warning-message,

View file

@ -24,7 +24,7 @@ import { ExtensionsAutoProfiler } from 'vs/workbench/contrib/extensions/electron
import { OpenExtensionsFolderAction } from 'vs/workbench/contrib/extensions/electron-sandbox/extensionsActions';
import { ExtensionsLabel } from 'vs/platform/extensionManagement/common/extensionManagement';
import { IExtensionRecommendationNotificationService } from 'vs/platform/extensionRecommendations/common/extensionRecommendations';
import { ISharedProcessService } from 'vs/platform/ipc/electron-sandbox/sharedProcessService';
import { ISharedProcessService } from 'vs/platform/ipc/electron-sandbox/services';
import { ExtensionRecommendationNotificationServiceChannel } from 'vs/platform/extensionRecommendations/electron-sandbox/extensionRecommendationsIpc';
import { Codicon } from 'vs/base/common/codicons';

View file

@ -40,7 +40,7 @@ import { IExperimentService } from 'vs/workbench/contrib/experiments/common/expe
import { TestExperimentService } from 'vs/workbench/contrib/experiments/test/electron-browser/experimentService.test';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
import { ISharedProcessService } from 'vs/platform/ipc/electron-sandbox/sharedProcessService';
import { ISharedProcessService } from 'vs/platform/ipc/electron-sandbox/services';
import { FileService } from 'vs/platform/files/common/fileService';
import { NullLogService, ILogService } from 'vs/platform/log/common/log';
import { IFileService } from 'vs/platform/files/common/files';

View file

@ -35,7 +35,7 @@ import { TestConfigurationService } from 'vs/platform/configuration/test/common/
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { RemoteAgentService } from 'vs/workbench/services/remote/electron-sandbox/remoteAgentServiceImpl';
import { ExtensionIdentifier, IExtensionContributions, ExtensionType, IExtensionDescription, IExtension } from 'vs/platform/extensions/common/extensions';
import { ISharedProcessService } from 'vs/platform/ipc/electron-sandbox/sharedProcessService';
import { ISharedProcessService } from 'vs/platform/ipc/electron-sandbox/services';
import { CancellationToken } from 'vs/base/common/cancellation';
import { ILabelService, IFormatterChangeEvent } from 'vs/platform/label/common/label';
import { IProductService } from 'vs/platform/product/common/productService';
@ -56,7 +56,7 @@ import { UserDataSyncResourceEnablementService } from 'vs/platform/userDataSync/
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService';
import { IWorkspaceTrustService } from 'vs/platform/workspace/common/workspaceTrust';
import { TestWorkspaceTrustService } from 'vs/platform/workspace/test/common/testWorkspaceTrust';
import { TestWorkspaceTrustService } from 'vs/workbench/services/workspaces/test/common/testWorkspaceTrustService';
let instantiationService: TestInstantiationService;
let installEvent: Emitter<InstallExtensionEvent>,

View file

@ -37,7 +37,7 @@ import { IExperimentService, ExperimentState, ExperimentActionType, ExperimentSe
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { RemoteAgentService } from 'vs/workbench/services/remote/electron-sandbox/remoteAgentServiceImpl';
import { ExtensionType, IExtension, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { ISharedProcessService } from 'vs/platform/ipc/electron-sandbox/sharedProcessService';
import { ISharedProcessService } from 'vs/platform/ipc/electron-sandbox/services';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService';
import { IMenuService } from 'vs/platform/actions/common/actions';

View file

@ -37,7 +37,7 @@ import { CancellationToken } from 'vs/base/common/cancellation';
import { ExtensionType, IExtension, ExtensionKind } from 'vs/platform/extensions/common/extensions';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { RemoteAgentService } from 'vs/workbench/services/remote/electron-sandbox/remoteAgentServiceImpl';
import { ISharedProcessService } from 'vs/platform/ipc/electron-sandbox/sharedProcessService';
import { ISharedProcessService } from 'vs/platform/ipc/electron-sandbox/services';
import { TestContextService } from 'vs/workbench/test/common/workbenchTestServices';
import { IProductService } from 'vs/platform/product/common/productService';
import { ILifecycleService } from 'vs/workbench/services/lifecycle/common/lifecycle';

View file

@ -283,6 +283,10 @@ export class MarkersFilterActionViewItem extends BaseActionViewItem {
}
}
get trapsArrowNavigation(): boolean {
return true;
}
private clearFilterText(): void {
if (this.filterInputBox) {
this.filterInputBox.value = '';

View file

@ -23,7 +23,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
import { BareFontInfo } from 'vs/editor/common/config/fontInfo';
import { getPixelRatio, getZoomLevel } from 'vs/base/browser/browser';
import { ICellOutputViewModel, IDisplayOutputLayoutUpdateRequest, IGenericCellViewModel, IInsetRenderOutput, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { CellEditState, ICellOutputViewModel, IDisplayOutputLayoutUpdateRequest, IGenericCellViewModel, IInsetRenderOutput, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { DiffSide, DIFF_CELL_MARGIN, IDiffCellInfo, INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser';
import { Emitter } from 'vs/base/common/event';
import { DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
@ -134,6 +134,19 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD
}
}
setMarkdownCellEditState(cellId: string, editState: CellEditState): void {
// throw new Error('Method not implemented.');
}
markdownCellDragStart(cellId: string, position: { clientY: number }): void {
// throw new Error('Method not implemented.');
}
markdownCellDrag(cellId: string, position: { clientY: number }): void {
// throw new Error('Method not implemented.');
}
markdownCellDragEnd(cellId: string, position: { clientY: number }): void {
// throw new Error('Method not implemented.');
}
protected createEditor(parent: HTMLElement): void {
this._rootElement = DOM.append(parent, DOM.$('.notebook-text-diff-editor'));
this._overflowContainer = document.createElement('div');
@ -589,6 +602,10 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD
});
}
updateMarkdownCellHeight() {
// TODO
}
getCellByInfo(cellInfo: IDiffCellInfo): IGenericCellViewModel {
return cellInfo.diffElement.getCellByUri(cellInfo.cellUri);
}

View file

@ -38,6 +38,12 @@ export interface INotebookRendererContribution {
readonly [NotebookRendererContribution.entrypoint]: string;
}
export interface INotebookMarkdownRendererContribution {
readonly [NotebookRendererContribution.id]?: string;
readonly [NotebookRendererContribution.viewType]?: string;
readonly [NotebookRendererContribution.entrypoint]: string;
}
const notebookProviderContribution: IJSONSchema = {
description: nls.localize('contributes.notebook.provider', 'Contributes notebook document provider.'),
type: 'array',
@ -144,3 +150,9 @@ export const notebookRendererExtensionPoint = ExtensionsRegistry.registerExtensi
extensionPoint: 'notebookOutputRenderer',
jsonSchema: notebookRendererContribution
});
export const notebookMarkdownRendererExtensionPoint = ExtensionsRegistry.registerExtensionPoint<INotebookMarkdownRendererContribution[]>(
{
extensionPoint: 'notebookMarkdownRenderer',
jsonSchema: notebookRendererContribution //
});

View file

@ -164,6 +164,11 @@ export interface ICommonNotebookEditor {
focusNotebookCell(cell: IGenericCellViewModel, focus: 'editor' | 'container' | 'output'): void;
focusNextNotebookCell(cell: IGenericCellViewModel, focus: 'editor' | 'container' | 'output'): void;
updateOutputHeight(cellInfo: ICommonCellInfo, output: IDisplayOutputViewModel, height: number, isInit: boolean): void;
updateMarkdownCellHeight(cellId: string, height: number, isInit: boolean): void;
setMarkdownCellEditState(cellId: string, editState: CellEditState): void;
markdownCellDragStart(cellId: string, position: { clientY: number }): void;
markdownCellDrag(cellId: string, position: { clientY: number }): void;
markdownCellDragEnd(cellId: string, position: { clientY: number, ctrlKey: boolean, altKey: boolean }): void;
}
//#endregion
@ -459,6 +464,10 @@ export interface INotebookEditor extends IEditor, ICommonNotebookEditor {
*/
layoutNotebookCell(cell: ICellViewModel, height: number): Promise<void>;
createMarkdownPreview(cell: ICellViewModel): Promise<void>;
hideMarkdownPreview(cell: ICellViewModel): Promise<void>;
removeMarkdownPreview(cell: ICellViewModel): Promise<void>;
/**
* Render the output in webview layer
*/
@ -681,6 +690,7 @@ export interface BaseCellRenderTemplate {
export interface MarkdownCellRenderTemplate extends BaseCellRenderTemplate {
editorContainer: HTMLElement;
foldingIndicator: HTMLElement;
focusIndicatorBottom: HTMLElement;
currentEditor?: ICodeEditor;
}

View file

@ -65,6 +65,7 @@ import { debugIconStartForeground } from 'vs/workbench/contrib/debug/browser/deb
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { extname } from 'vs/base/common/resources';
import { IModeService } from 'vs/editor/common/services/modeService';
import { MarkdownCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/markdownCellViewModel';
const $ = DOM.$;
@ -1018,6 +1019,19 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
this._updateForMetadata();
}));
const useRenderer = this.configurationService.getValue<string>('notebook.experimental.useMarkdownRenderer');
if (useRenderer) {
await this._resolveWebview();
await this._webview!.initializeMarkdown(this.viewModel.viewCells
.filter(cell => cell.cellKind === CellKind.Markdown)
.map(cell => ({ cellId: cell.id, content: cell.getText() }))
// TODO: look at cell position cache instead of just getting first five cells
.slice(0, 5));
}
// restore view states, including contributions
{
@ -1107,6 +1121,18 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
this._webview?.updateViewScrollTop(-scrollTop, false, updateItems);
}
}
if (this._webview?.markdownPreviewMapping) {
const updateItems: { id: string, top: number }[] = [];
this._webview!.markdownPreviewMapping.forEach(cellId => {
const cell = this.viewModel?.viewCells.find(cell => cell.id === cellId);
if (cell) {
const cellTop = this._list.getAbsoluteTopOfElement(cell);
updateItems.push({ id: cellId, top: cellTop });
}
});
this._webview?.updateMarkdownScrollTop(updateItems);
}
});
}));
@ -1959,6 +1985,41 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
this._list.triggerScrollFromMouseWheelEvent(event);
}
async createMarkdownPreview(cell: MarkdownCellViewModel) {
if (!this._webview) {
return;
}
await this._resolveWebview();
const cellTop = this._list.getAbsoluteTopOfElement(cell);
if (this._webview.markdownPreviewMapping.has(cell.id)) {
await this._webview!.showMarkdownPreview(cell.id, cell.getText(), cellTop);
} else {
await this._webview!.createMarkdownPreview(cell.id, cell.getText(), cellTop);
}
}
async hideMarkdownPreview(cell: MarkdownCellViewModel) {
if (!this._webview) {
return;
}
await this._resolveWebview();
await this._webview!.hideMarkdownPreview(cell.id);
}
async removeMarkdownPreview(cell: MarkdownCellViewModel) {
if (!this._webview) {
return;
}
await this._resolveWebview();
await this._webview!.removeMarkdownPreview(cell.id);
}
async createInset(cell: CodeCellViewModel, output: IInsetRenderOutput, offset: number): Promise<void> {
this._insetModifyQueueByOutputId.queue(output.source.model.outputId, async () => {
if (!this._webview) {
@ -2042,6 +2103,45 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
}
}
updateMarkdownCellHeight(cellId: string, height: number, isInit: boolean) {
const cell = this.viewModel?.viewCells.find(vc => vc.id === cellId);
if (cell && cell instanceof MarkdownCellViewModel) {
cell.renderedMarkdownHeight = height;
}
}
setMarkdownCellEditState(cellId: string, editState: CellEditState): void {
const cell = this.viewModel?.viewCells.find(vc => vc.id === cellId);
if (cell && cell instanceof MarkdownCellViewModel) {
cell.editState = editState;
}
}
markdownCellDragStart(cellId: string, ctx: { clientY: number }): void {
const cell = this.viewModel?.viewCells.find(vc => vc.id === cellId);
if (cell && cell instanceof MarkdownCellViewModel) {
this._dndController?.startExplicitDrag(cell, ctx);
}
}
markdownCellDrag(cellId: string, ctx: { clientY: number }): void {
const cell = this.viewModel?.viewCells.find(vc => vc.id === cellId);
if (cell && cell instanceof MarkdownCellViewModel) {
this._dndController?.explicitDrag(cell, ctx);
}
}
markdownCellDragEnd(cellId: string, ctx: { clientY: number, ctrlKey: boolean, altKey: boolean }): void {
const cell = this.viewModel?.viewCells.find(vc => vc.id === cellId);
if (cell && cell instanceof MarkdownCellViewModel) {
this._dndController?.endExplicitDrag(cell, ctx);
}
}
//#endregion
@ -2297,8 +2397,7 @@ registerThemingParticipant((theme, collector) => {
collector.addRule(`
.monaco-workbench .notebookOverlay .monaco-list:focus-within .monaco-list-row.focused .cell-focus-indicator-top:before,
.monaco-workbench .notebookOverlay .monaco-list:focus-within .monaco-list-row.focused .cell-focus-indicator-bottom:before,
.monaco-workbench .notebookOverlay .monaco-list:focus-within .markdown-cell-row.focused .cell-inner-container:not(.cell-editor-focus):before,
.monaco-workbench .notebookOverlay .monaco-list:focus-within .markdown-cell-row.focused .cell-inner-container:not(.cell-editor-focus):after {
.monaco-workbench .notebookOverlay .monaco-list:focus-within .markdown-cell-row.focused .cell-inner-container:not(.cell-editor-focus):before {
border-color: ${focusedCellBorderColor} !important;
}`);
@ -2315,8 +2414,7 @@ registerThemingParticipant((theme, collector) => {
collector.addRule(`
.monaco-workbench .notebookOverlay .monaco-list:focus-within .monaco-list-row.focused .cell-editor-focus .cell-focus-indicator-top:before,
.monaco-workbench .notebookOverlay .monaco-list:focus-within .monaco-list-row.focused .cell-editor-focus .cell-focus-indicator-bottom:before,
.monaco-workbench .notebookOverlay .monaco-list:focus-within .monaco-list-row.focused .cell-inner-container.cell-editor-focus:before,
.monaco-workbench .notebookOverlay .monaco-list:focus-within .monaco-list-row.focused .cell-inner-container.cell-editor-focus:after {
.monaco-workbench .notebookOverlay .monaco-list:focus-within .monaco-list-row.focused .cell-inner-container.cell-editor-focus:before {
border-color: ${selectedCellBorderColor} !important;
}`);

View file

@ -26,13 +26,14 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { NotebookExtensionDescription } from 'vs/workbench/api/common/extHost.protocol';
import { Memento } from 'vs/workbench/common/memento';
import { INotebookEditorContribution, notebookProviderExtensionPoint, notebookRendererExtensionPoint } from 'vs/workbench/contrib/notebook/browser/extensionPoint';
import { INotebookEditorContribution, notebookMarkdownRendererExtensionPoint, notebookProviderExtensionPoint, notebookRendererExtensionPoint } from 'vs/workbench/contrib/notebook/browser/extensionPoint';
import { CellEditState, getActiveNotebookEditor, ICellViewModel, INotebookEditor, NotebookEditorOptions, updateEditorTopPadding } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { NotebookKernelProviderAssociationRegistry, NotebookViewTypesExtensionRegistry, updateNotebookKernelProvideAssociationSchema } from 'vs/workbench/contrib/notebook/browser/notebookKernelAssociation';
import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
import { ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, BUILTIN_RENDERER_ID, CellEditType, CellKind, DisplayOrderKey, ICellEditOperation, INotebookDecorationRenderOptions, INotebookKernel, INotebookKernelProvider, INotebookRendererInfo, INotebookTextModel, IOrderedMimeType, IOutputDto, mimeTypeIsAlwaysSecure, mimeTypeSupportedByCore, notebookDocumentFilterMatch, NotebookEditorPriority, NOTEBOOK_DISPLAY_ORDER, RENDERER_NOT_AVAILABLE, sortMimeTypes } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, BUILTIN_RENDERER_ID, CellEditType, CellKind, DisplayOrderKey, ICellEditOperation, INotebookDecorationRenderOptions, INotebookKernel, INotebookKernelProvider, INotebookMarkdownRendererInfo, INotebookRendererInfo, INotebookTextModel, IOrderedMimeType, IOutputDto, mimeTypeIsAlwaysSecure, mimeTypeSupportedByCore, notebookDocumentFilterMatch, NotebookEditorPriority, NOTEBOOK_DISPLAY_ORDER, RENDERER_NOT_AVAILABLE, sortMimeTypes } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { NotebookMarkdownRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookMarkdownRenderer';
import { NotebookOutputRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookOutputRenderer';
import { NotebookEditorDescriptor, NotebookProviderInfo } from 'vs/workbench/contrib/notebook/common/notebookProvider';
import { IMainNotebookController, INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
@ -235,11 +236,13 @@ class ModelData implements IDisposable {
this._modelEventListeners.dispose();
}
}
export class NotebookService extends Disposable implements INotebookService, ICustomEditorViewTypesHandler {
declare readonly _serviceBrand: undefined;
private readonly _notebookProviders = new Map<string, { controller: IMainNotebookController, extensionData: NotebookExtensionDescription; }>();
notebookProviderInfoStore: NotebookProviderInfoStore;
notebookRenderersInfoStore: NotebookOutputRendererInfoStore = new NotebookOutputRendererInfoStore();
private readonly markdownRenderersInfos = new Set<INotebookMarkdownRendererInfo>();
notebookKernelProviderInfoStore: NotebookKernelProviderInfoStore = new NotebookKernelProviderInfoStore();
private readonly _models = new ResourceMap<ModelData>();
private _onDidChangeActiveEditor = new Emitter<string | null>();
@ -320,6 +323,32 @@ export class NotebookService extends Disposable implements INotebookService, ICu
}
});
notebookMarkdownRendererExtensionPoint.setHandler((renderers) => {
this.markdownRenderersInfos.clear();
for (const extension of renderers) {
for (const notebookContribution of extension.value) {
if (!notebookContribution.entrypoint) { // avoid crashing
console.error(`Cannot register renderer for ${extension.description.identifier.value} since it did not have an entrypoint. This is now required: https://github.com/microsoft/vscode/issues/102644`);
continue;
}
const id = notebookContribution.id ?? notebookContribution.viewType;
if (!id) {
console.error(`Notebook renderer from ${extension.description.identifier.value} is missing an 'id'`);
continue;
}
this.markdownRenderersInfos.add(new NotebookMarkdownRendererInfo({
id,
extension: extension.description,
entrypoint: notebookContribution.entrypoint,
displayName: 'todo',
}));
}
}
});
this._editorService.registerCustomEditorViewTypesHandler('Notebook', this);
const updateOrder = () => {
@ -715,6 +744,10 @@ export class NotebookService extends Disposable implements INotebookService, ICu
return this.notebookRenderersInfoStore.get(id);
}
getMarkdownRendererInfo(): INotebookMarkdownRendererInfo[] {
return Array.from(this.markdownRenderersInfos);
}
async resolveNotebook(viewType: string, uri: URI, forceReload: boolean, backupId?: string): Promise<NotebookTextModel> {
if (!await this.canResolve(viewType)) {

View file

@ -17,7 +17,7 @@ import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs';
import { IFileService } from 'vs/platform/files/common/files';
import { IOpenerService, matchesScheme } from 'vs/platform/opener/common/opener';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { ICellOutputViewModel, ICommonCellInfo, ICommonNotebookEditor, IDisplayOutputLayoutUpdateRequest, IGenericCellViewModel, IInsetRenderOutput, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { CellEditState, ICellOutputViewModel, ICommonCellInfo, ICommonNotebookEditor, IDisplayOutputLayoutUpdateRequest, IDisplayOutputViewModel, IGenericCellViewModel, IInsetRenderOutput, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { preloadsScriptStr } from 'vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads';
import { transformWebviewThemeVars } from 'vs/workbench/contrib/notebook/browser/view/renderers/webviewThemeMapping';
import { INotebookRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookCommon';
@ -37,6 +37,7 @@ export interface IDimensionMessage {
id: string;
init: boolean;
data: DOM.Dimension;
isOutput: boolean;
}
export interface IMouseEnterMessage {
@ -79,6 +80,38 @@ export interface IClickedDataUrlMessage {
downloadName?: string;
}
export interface IToggleMarkdownPreviewMessage {
__vscode_notebook_message: boolean;
type: 'toggleMarkdownPreview';
cellId: string;
}
export interface ICellDragStartMessage {
__vscode_notebook_message: boolean;
type: 'cell-drag-start';
cellId: string;
position: { clientX: number, clientY: number };
}
export interface ICellDragMessage {
__vscode_notebook_message: boolean;
type: 'cell-drag';
cellId: string;
position: { clientX: number, clientY: number };
}
export interface ICellDragEndMessage {
readonly __vscode_notebook_message: boolean;
readonly type: 'cell-drag-end';
readonly cellId: string;
readonly ctrlKey: boolean
readonly altKey: boolean;
readonly position: {
readonly clientX: number;
readonly clientY: number;
};
}
export interface IClearMessage {
type: 'clear';
}
@ -128,6 +161,11 @@ export interface IViewScrollTopRequestMessage {
version: number;
}
export interface IViewScrollMarkdownRequestMessage {
type: 'view-scroll-markdown';
cells: { id: string; top: number }[];
}
export interface IScrollRequestMessage {
type: 'scroll';
id: string;
@ -187,6 +225,35 @@ export interface ICustomRendererMessage {
message: unknown;
}
export interface ICreateMarkdownMessage {
type: 'createMarkdownPreview',
id: string;
content: string;
top: number;
}
export interface IRemoveMarkdownMessage {
type: 'removeMarkdownPreview',
id: string;
}
export interface IHideMarkdownMessage {
type: 'hideMarkdownPreview',
id: string;
}
export interface IShowMarkdownMessage {
type: 'showMarkdownPreview',
id: string;
content: string;
top: number;
}
export interface IInitializeMarkdownMessage {
type: 'initializeMarkdownPreview';
cells: Array<{ cellId: string, content: string }>;
}
export type FromWebviewMessage =
| WebviewIntialized
| IDimensionMessage
@ -196,8 +263,12 @@ export type FromWebviewMessage =
| IScrollAckMessage
| IBlurOutputMessage
| ICustomRendererMessage
| IClickedDataUrlMessage;
| IClickedDataUrlMessage
| IToggleMarkdownPreviewMessage
| ICellDragStartMessage
| ICellDragMessage
| ICellDragEndMessage
;
export type ToWebviewMessage =
| IClearMessage
| IFocusOutputMessage
@ -209,7 +280,13 @@ export type ToWebviewMessage =
| IShowOutputMessage
| IUpdatePreloadResourceMessage
| IUpdateDecorationsMessage
| ICustomRendererMessage;
| ICustomRendererMessage
| ICreateMarkdownMessage
| IRemoveMarkdownMessage
| IShowMarkdownMessage
| IHideMarkdownMessage
| IInitializeMarkdownMessage
| IViewScrollMarkdownRequestMessage;
export type AnyMessage = FromWebviewMessage | ToWebviewMessage;
@ -237,9 +314,10 @@ let version = 0;
export class BackLayerWebView<T extends ICommonCellInfo> extends Disposable {
element: HTMLElement;
webview: WebviewElement | undefined = undefined;
insetMapping: Map<ICellOutputViewModel, ICachedInset<T>> = new Map();
hiddenInsetMapping: Set<ICellOutputViewModel> = new Set();
reversedInsetMapping: Map<string, ICellOutputViewModel> = new Map();
insetMapping: Map<IDisplayOutputViewModel, ICachedInset<T>> = new Map();
markdownPreviewMapping: Set<string> = new Set();
hiddenInsetMapping: Set<IDisplayOutputViewModel> = new Set();
reversedInsetMapping: Map<string, IDisplayOutputViewModel> = new Map();
localResourceRootsCache: URI[] | undefined = undefined;
rendererRootsCache: URI[] = [];
kernelRootsCache: URI[] = [];
@ -273,20 +351,173 @@ export class BackLayerWebView<T extends ICommonCellInfo> extends Disposable {
this.element.style.height = '1400px';
this.element.style.position = 'absolute';
}
generateContent(coreDependencies: string, baseUrl: string) {
private generateContent(coreDependencies: string, baseUrl: string) {
const markdownRenderersSrc = this.getMarkdownRendererScripts();
return html`
<html lang="en">
<head>
<meta charset="UTF-8">
<base href="${baseUrl}/"/>
<style>
#container > div > div {
#container > div > div.output {
width: 100%;
padding: ${this.options.outputNodePadding}px ${this.options.outputNodePadding}px ${this.options.outputNodePadding}px ${this.options.outputNodeLeftPadding}px;
box-sizing: border-box;
background-color: var(--vscode-notebook-outputContainerBackgroundColor);
}
#container > div > div.preview {
width: 100%;
box-sizing: border-box;
white-space: nowrap;
overflow: hidden;
user-select: text;
-webkit-user-select: text;
-ms-user-select: text;
white-space: initial;
padding-left: 0px !important;
}
/* markdown */
#container > div > div.preview img {
max-width: 100%;
max-height: 100%;
}
#container > div > div.preview a {
text-decoration: none;
}
#container > div > div.preview a:hover {
text-decoration: underline;
}
#container > div > div.preview a:focus,
#container > div > div.preview input:focus,
#container > div > div.preview select:focus,
#container > div > div.preview textarea:focus {
outline: 1px solid -webkit-focus-ring-color;
outline-offset: -1px;
}
#container > div > div.preview hr {
border: 0;
height: 2px;
border-bottom: 2px solid;
}
#container > div > div.preview h1 {
padding-bottom: 0.3em;
line-height: 1.2;
border-bottom-width: 1px;
border-bottom-style: solid;
border-color: rgba(255, 255, 255, 0.18);
}
#container > div > div.preview h1 {
border-color: rgba(0, 0, 0, 0.18);
}
#container > div > div.preview h1,
#container > div > div.preview h2,
#container > div > div.preview h3 {
font-weight: normal;
}
#container > div > div.preview div {
width: 100%;
}
/* Adjust margin of first item in markdown cell */
#container > div > div.preview *:first-child {
margin-top: 0px;
}
/* h1 tags don't need top margin */
#container > div > div.preview h1:first-child {
margin-top: 0;
}
/* Removes bottom margin when only one item exists in markdown cell */
#container > div > div.preview *:only-child,
#container > div > div.preview *:last-child {
margin-bottom: 0;
padding-bottom: 0;
}
/* makes all markdown cells consistent */
#container > div > div.preview div {
min-height: 24px;
}
#container > div > div.preview table {
border-collapse: collapse;
border-spacing: 0;
}
#container > div > div.preview table th,
#container > div > div.preview table td {
border: 1px solid;
}
#container > div > div.preview table > thead > tr > th {
text-align: left;
border-bottom: 1px solid;
}
#container > div > div.preview table > thead > tr > th,
#container > div > div.preview table > thead > tr > td,
#container > div > div.preview table > tbody > tr > th,
#container > div > div.preview table > tbody > tr > td {
padding: 5px 10px;
}
#container > div > div.preview table > tbody > tr + tr > td {
border-top: 1px solid;
}
#container > div > div.preview blockquote {
margin: 0 7px 0 5px;
padding: 0 16px 0 10px;
border-left-width: 5px;
border-left-style: solid;
}
#container > div > div.preview code,
#container > div > div.preview .code {
font-family: var(--monaco-monospace-font);
font-size: 1em;
line-height: 1.357em;
}
#container > div > div.preview .code {
white-space: pre-wrap;
}
#container > div > div.preview .latex-block {
display: block;
}
#container > div > div.preview .latex {
vertical-align: middle;
display: inline-block;
}
#container > div > div.preview .latex img,
#container > div > div.preview .latex-block img {
filter: brightness(0) invert(0)
}
#container > div > div.preview.dragging {
background-color: var(--vscode-editor-background);
}
.monaco-workbench.vs-dark .notebookOverlay .cell.markdown .latex img,
.monaco-workbench.vs-dark .notebookOverlay .cell.markdown .latex-block img {
filter: brightness(0) invert(1)
}
#container > div.nb-symbolHighlight > div {
background-color: var(--vscode-notebook-symbolHighlightBackground);
}
@ -350,10 +581,29 @@ export class BackLayerWebView<T extends ICommonCellInfo> extends Disposable {
${coreDependencies}
<div id='container' class="widgetarea" style="position: absolute;width:100%;top: 0px"></div>
<script>${preloadsScriptStr(this.options.outputNodePadding, this.options.outputNodeLeftPadding)}</script>
${markdownRenderersSrc}
</body>
</html>`;
}
private getMarkdownRendererScripts() {
const markdownRenderers = this.notebookService.getMarkdownRendererInfo();
return markdownRenderers
.sort((a, b) => {
// prefer built-in extension
if (a.extensionIsBuiltin) {
return b.extensionIsBuiltin ? 0 : -1;
}
return b.extensionIsBuiltin ? 1 : -1;
})
.map(renderer => {
return asWebviewUri(this.environmentService, this.id, renderer.entrypoint);
})
.map(src => `<script src="${src}"></script>`)
.join('\n');
}
postRendererMessage(rendererId: string, message: any) {
this._sendMessageToWebview({
__vscode_notebook_message: true,
@ -476,13 +726,18 @@ var requirejs = (function() {
if (data.__vscode_notebook_message) {
if (data.type === 'dimension') {
const height = data.data.height;
const outputHeight = height;
if (data.isOutput) {
const height = data.data.height;
const outputHeight = height;
const resolvedResult = this.resolveOutputId(data.id);
if (resolvedResult) {
const { cellInfo, output } = resolvedResult;
this.notebookEditor.updateOutputHeight(cellInfo, output, outputHeight, !!data.init);
const resolvedResult = this.resolveOutputId(data.id);
if (resolvedResult) {
const { cellInfo, output } = resolvedResult;
this.notebookEditor.updateOutputHeight(cellInfo, output, outputHeight, !!data.init);
}
} else {
const cellId = data.id.substr(0, data.id.length - '_preview'.length);
this.notebookEditor.updateMarkdownCellHeight(cellId, data.data.height, !!data.init);
}
} else if (data.type === 'mouseenter') {
const resolvedResult = this.resolveOutputId(data.id);
@ -528,6 +783,18 @@ var requirejs = (function() {
this._onDidClickDataLink(data);
} else if (data.type === 'customRendererMessage') {
this._onMessage.fire({ message: data.message, forRenderer: data.rendererId });
} else if (data.type === 'toggleMarkdownPreview') {
this.notebookEditor.setMarkdownCellEditState(data.cellId, CellEditState.Editing);
} else if (data.type === 'cell-drag-start') {
this.notebookEditor.markdownCellDragStart(data.cellId, data.position);
} else if (data.type === 'cell-drag') {
this.notebookEditor.markdownCellDrag(data.cellId, data.position);
} else if (data.type === 'cell-drag-end') {
this.notebookEditor.markdownCellDragEnd(data.cellId, {
clientY: data.position.clientY,
ctrlKey: data.ctrlKey,
altKey: data.altKey,
});
}
return;
}
@ -576,7 +843,12 @@ var requirejs = (function() {
const workspaceFolders = this.contextService.getWorkspace().folders.map(x => x.uri);
this.localResourceRootsCache = [...this.notebookService.getNotebookProviderResourceRoots(), ...workspaceFolders, rootPath];
this.localResourceRootsCache = [
...this.notebookService.getNotebookProviderResourceRoots(),
...this.notebookService.getMarkdownRendererInfo().map(x => dirname(x.entrypoint)),
...workspaceFolders,
rootPath,
];
const webview = webviewService.createWebviewElement(this.id, {
purpose: WebviewContentPurpose.NotebookRenderer,
@ -628,6 +900,13 @@ var requirejs = (function() {
return true;
}
updateMarkdownScrollTop(items: { id: string, top: number }[]) {
this._sendMessageToWebview({
type: 'view-scroll-markdown',
cells: items
});
}
updateViewScrollTop(top: number, forceDisplay: boolean, items: IDisplayOutputLayoutUpdateRequest[]) {
if (this._disposed) {
return;
@ -656,6 +935,83 @@ var requirejs = (function() {
});
}
async createMarkdownPreview(cellId: string, content: string, cellTop: number) {
if (this._disposed) {
return;
}
const initialTop = cellTop;
this.markdownPreviewMapping.add(cellId);
this._sendMessageToWebview({
type: 'createMarkdownPreview',
id: cellId,
content: content,
top: initialTop,
});
}
async showMarkdownPreview(cellId: string, content: string, cellTop: number) {
if (this._disposed) {
return;
}
this._sendMessageToWebview({
type: 'showMarkdownPreview',
id: cellId,
content: content,
top: cellTop
});
}
async hideMarkdownPreview(cellId: string,) {
if (this._disposed) {
return;
}
this._sendMessageToWebview({
type: 'hideMarkdownPreview',
id: cellId
});
}
async removeMarkdownPreview(cellId: string,) {
if (this._disposed) {
return;
}
this.markdownPreviewMapping.delete(cellId);
this._sendMessageToWebview({
type: 'removeMarkdownPreview',
id: cellId
});
}
async initializeMarkdown(cells: Array<{ cellId: string, content: string }>) {
await this._loaded;
// TODO: use proper handler
const p = new Promise<void>(resolve => {
this.webview?.onMessage(e => {
if (e.type === 'initializedMarkdownPreview') {
resolve();
}
});
});
for (const cell of cells) {
this.markdownPreviewMapping.add(cell.cellId);
}
this._sendMessageToWebview({
type: 'initializeMarkdownPreview',
cells: cells,
});
await p;
}
async createInset(cellInfo: T, content: IInsetRenderOutput, cellTop: number, offset: number) {
if (this._disposed) {
return;

View file

@ -149,7 +149,7 @@ export class CellDragAndDropController extends Disposable {
return;
}
const dropDirection = this.getDropInsertDirection(event);
const dropDirection = this.getDropInsertDirection(event.dragPosRatio);
const insertionIndicatorAbsolutePos = dropDirection === 'above' ? event.cellTop : event.cellTop + event.cellHeight;
const insertionIndicatorTop = insertionIndicatorAbsolutePos - this.list.scrollTop + BOTTOM_CELL_TOOLBAR_GAP / 2;
if (insertionIndicatorTop >= 0) {
@ -160,8 +160,8 @@ export class CellDragAndDropController extends Disposable {
}
}
private getDropInsertDirection(event: CellDragEvent): 'above' | 'below' {
return event.dragPosRatio < 0.5 ? 'above' : 'below';
private getDropInsertDirection(dragPosRatio: number): 'above' | 'below' {
return dragPosRatio < 0.5 ? 'above' : 'below';
}
private onCellDrop(event: CellDragEvent): void {
@ -189,7 +189,7 @@ export class CellDragAndDropController extends Disposable {
const isCopy = (event.browserEvent.ctrlKey && !platform.isMacintosh) || (event.browserEvent.altKey && platform.isMacintosh);
const dropDirection = this.getDropInsertDirection(event);
const dropDirection = this.getDropInsertDirection(event.dragPosRatio);
const insertionIndicatorAbsolutePos = dropDirection === 'above' ? event.cellTop : event.cellTop + event.cellHeight;
const insertionIndicatorTop = insertionIndicatorAbsolutePos - this.list.scrollTop + BOTTOM_CELL_TOOLBAR_GAP / 2;
const editorHeight = this.notebookEditor.getDomNode().getBoundingClientRect().height;
@ -275,4 +275,65 @@ export class CellDragAndDropController extends Disposable {
this.notebookEditor.textModel!.pushStackElement('Copy Cells', undefined, undefined);
}
public startExplicitDrag(cell: ICellViewModel, position: { clientY: number }) {
this.currentDraggedCell = cell;
this.setInsertIndicatorVisibility(true);
}
public explicitDrag(cell: ICellViewModel, position: { clientY: number }) {
const target = this.list.elementAt(position.clientY);
if (target && target !== cell) {
const cellTop = this.list.getAbsoluteTopOfElement(target);
const cellHeight = this.list.elementHeight(target);
const dragOffset = this.list.scrollTop + position.clientY - cellTop;
const dragPosInElement = dragOffset - cellTop;
const dragPosRatio = dragPosInElement / cellHeight;
const dropDirection = this.getDropInsertDirection(dragPosRatio);
const insertionIndicatorAbsolutePos = dropDirection === 'above' ? cellTop : cellTop + cellHeight;
const insertionIndicatorTop = insertionIndicatorAbsolutePos - this.list.scrollTop + BOTTOM_CELL_TOOLBAR_GAP / 2;
if (insertionIndicatorTop >= 0) {
this.listInsertionIndicator.style.top = `${insertionIndicatorTop}px`;
}
}
}
public endExplicitDrag(cell: ICellViewModel, ctx: { clientY: number, ctrlKey: boolean, altKey: boolean }) {
this.currentDraggedCell = undefined;
this.setInsertIndicatorVisibility(false);
const target = this.list.elementAt(ctx.clientY);
if (!target || target === cell) {
return;
}
const cellTop = this.list.getAbsoluteTopOfElement(target);
const cellHeight = this.list.elementHeight(target);
const dragOffset = this.list.scrollTop + ctx.clientY - cellTop;
const dragPosInElement = dragOffset - cellTop;
const dragPosRatio = dragPosInElement / cellHeight;
const dropDirection = this.getDropInsertDirection(dragPosRatio);
const isCopy = (ctx.ctrlKey && !platform.isMacintosh) || (ctx.altKey && platform.isMacintosh);
if (isCopy) {
this.copyCells([cell], target, dropDirection);
} else {
const viewModel = this.notebookEditor.viewModel!;
let originalToIdx = viewModel.getCellIndex(target);
if (dropDirection === 'below') {
const relativeToIndex = viewModel.getCellIndex(target);
const newIdx = viewModel.getNextVisibleCellIndex(relativeToIndex);
originalToIdx = newIdx;
}
const draggedCellRange = [this.notebookEditor.viewModel!.getCellIndex(cell), 1];
this.notebookEditor.moveCellsToIdx(draggedCellRange[0], draggedCellRange[1], originalToIdx);
}
}
}

View file

@ -414,6 +414,7 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR
const bottomCellContainer = DOM.append(container, $('.cell-bottom-toolbar-container'));
const betweenCellToolbar = disposables.add(this.createBetweenCellToolbar(bottomCellContainer, disposables, contextKeyService));
const focusIndicatorBottom = DOM.append(container, $('.cell-focus-indicator.cell-focus-indicator-bottom'));
const statusBar = disposables.add(this.instantiationService.createInstance(CellEditorStatusBar, editorPart));
DOM.hide(statusBar.durationContainer);
@ -432,6 +433,7 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR
editorPart,
editorContainer,
focusIndicatorLeft,
focusIndicatorBottom,
foldingIndicator,
disposables,
elementDisposables: new DisposableStore(),
@ -524,6 +526,11 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR
elementDisposables.add(new CellContextKeyManager(templateData.contextKeyService, this.notebookEditor, this.notebookEditor.viewModel.notebookDocument!, element));
this.updateForLayout(element, templateData);
elementDisposables.add(element.onDidChangeLayout(() => {
this.updateForLayout(element, templateData);
}));
// render toolbar first
this.setupCellToolbarActions(templateData, elementDisposables);
@ -545,6 +552,11 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR
templateData.statusBar.update(toolbarContext);
}
private updateForLayout(element: MarkdownCellViewModel, templateData: MarkdownCellRenderTemplate): void {
// templateData.focusIndicatorLeft.style.height = `${element.layoutInfo.indicatorHeight}px`;
templateData.focusIndicatorBottom.style.top = `${element.layoutInfo.totalHeight - BOTTOM_CELL_TOOLBAR_GAP - CELL_BOTTOM_MARGIN}px`;
}
disposeTemplate(templateData: MarkdownCellRenderTemplate): void {
templateData.disposables.clear();
}

View file

@ -23,16 +23,97 @@ import { INotebookCellStatusBarService } from 'vs/workbench/contrib/notebook/com
import { NotebookCellsChangeType } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { collapsedIcon, expandedIcon } from 'vs/workbench/contrib/notebook/browser/notebookIcons';
import { renderIcon } from 'vs/base/browser/ui/iconLabel/iconLabels';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
interface IMarkdownRenderStrategy extends IDisposable {
update(): void;
}
class WebviewMarkdownRenderer extends Disposable implements IMarkdownRenderStrategy {
constructor(
readonly notebookEditor: IActiveNotebookEditor,
readonly viewCell: MarkdownCellViewModel
) {
super();
}
update(): void {
this.notebookEditor.createMarkdownPreview(this.viewCell);
}
}
class BuiltinMarkdownRenderer extends Disposable implements IMarkdownRenderStrategy {
private localDisposables = new DisposableStore();
constructor(
readonly notebookEditor: IActiveNotebookEditor,
readonly viewCell: MarkdownCellViewModel,
readonly container: HTMLElement,
readonly markdownContainer: HTMLElement,
readonly dataSource: { codeEditor: CodeEditorWidget | null; }
) {
super();
this._register(getResizesObserver(this.markdownContainer, undefined, () => {
if (viewCell.editState === CellEditState.Preview) {
this.viewCell.renderedMarkdownHeight = container.clientHeight;
}
})).startObserving();
}
update(): void {
const markdownRenderer = this.viewCell.getMarkdownRenderer();
const renderedHTML = this.viewCell.getHTML();
if (renderedHTML) {
this.markdownContainer.appendChild(renderedHTML);
}
if (this.dataSource.codeEditor) {
// switch from editing mode
this.viewCell.renderedMarkdownHeight = this.container.clientHeight;
this.relayoutCell();
} else {
// first time, readonly mode
this.localDisposables.add(markdownRenderer.onDidRenderAsync(() => {
this.viewCell.renderedMarkdownHeight = this.container.clientHeight;
this.relayoutCell();
}));
this.localDisposables.add(this.viewCell.textBuffer.onDidChangeContent(() => {
this.markdownContainer.innerText = '';
this.viewCell.clearHTML();
const renderedHTML = this.viewCell.getHTML();
if (renderedHTML) {
this.markdownContainer.appendChild(renderedHTML);
}
}));
this.viewCell.renderedMarkdownHeight = this.container.clientHeight;
this.relayoutCell();
}
}
relayoutCell() {
this.notebookEditor.layoutNotebookCell(this.viewCell, this.viewCell.layoutInfo.totalHeight);
}
}
export class StatefulMarkdownCell extends Disposable {
private editor: CodeEditorWidget | null = null;
get codeEditor() {
return this.editor;
}
private markdownContainer: HTMLElement;
private editorPart: HTMLElement;
private localDisposables = new DisposableStore();
private foldingState: CellFoldingState;
private _activeCellRunPlaceholder: IDisposable | null = null;
private _useRenderer: boolean = false;
private _renderStrategy: IMarkdownRenderStrategy;
constructor(
private readonly notebookEditor: IActiveNotebookEditor,
@ -43,11 +124,21 @@ export class StatefulMarkdownCell extends Disposable {
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@INotebookCellStatusBarService readonly notebookCellStatusBarService: INotebookCellStatusBarService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IConfigurationService private readonly configurationSerivce: IConfigurationService
) {
super();
this.markdownContainer = templateData.cellContainer;
this.editorPart = templateData.editorPart;
this._useRenderer = !!(this.configurationSerivce.getValue<string>('notebook.experimental.useMarkdownRenderer'));
if (this._useRenderer) {
this._renderStrategy = new WebviewMarkdownRenderer(this.notebookEditor, this.viewCell);
} else {
this._renderStrategy = new BuiltinMarkdownRenderer(this.notebookEditor, this.viewCell, this.templateData.container, this.markdownContainer, this);
}
this._register(this._renderStrategy);
this._register(this.localDisposables);
this._register(toDisposable(() => renderedEditors.delete(this.viewCell)));
@ -64,12 +155,6 @@ export class StatefulMarkdownCell extends Disposable {
this.viewUpdate();
}));
this._register(getResizesObserver(this.markdownContainer, undefined, () => {
if (viewCell.editState === CellEditState.Preview) {
this.viewCell.renderedMarkdownHeight = templateData.container.clientHeight;
}
})).startObserving();
const updateForFocusMode = () => {
if (viewCell.focusMode === CellFocusMode.Editor) {
this.focusEditorIfNeeded();
@ -286,35 +371,8 @@ export class StatefulMarkdownCell extends Disposable {
this.markdownContainer.innerText = '';
this.viewCell.clearHTML();
const markdownRenderer = this.viewCell.getMarkdownRenderer();
const renderedHTML = this.viewCell.getHTML();
if (renderedHTML) {
this.markdownContainer.appendChild(renderedHTML);
}
if (this.editor) {
// switch from editing mode
this.viewCell.renderedMarkdownHeight = this.templateData.container.clientHeight;
this.relayoutCell();
} else {
// first time, readonly mode
this.localDisposables.add(markdownRenderer.onDidRenderAsync(() => {
this.viewCell.renderedMarkdownHeight = this.templateData.container.clientHeight;
this.relayoutCell();
}));
this.localDisposables.add(this.viewCell.textBuffer.onDidChangeContent(() => {
this.markdownContainer.innerText = '';
this.viewCell.clearHTML();
const renderedHTML = this.viewCell.getHTML();
if (renderedHTML) {
this.markdownContainer.appendChild(renderedHTML);
}
}));
this.viewCell.renderedMarkdownHeight = this.templateData.container.clientHeight;
this.relayoutCell();
}
this._renderStrategy.update();
}
private focusEditorIfNeeded() {
@ -342,7 +400,7 @@ export class StatefulMarkdownCell extends Disposable {
// this.relayoutCell();
}
private relayoutCell(): void {
relayoutCell(): void {
this.notebookEditor.layoutNotebookCell(this.viewCell, this.viewCell.layoutInfo.totalHeight);
}
@ -420,6 +478,7 @@ export class StatefulMarkdownCell extends Disposable {
}
dispose() {
this.notebookEditor.removeMarkdownPreview(this.viewCell);
this.viewCell.detachTextEditor();
super.dispose();
}

View file

@ -5,7 +5,7 @@
import type { Event } from 'vs/base/common/event';
import type { IDisposable } from 'vs/base/common/lifecycle';
import { ToWebviewMessage } from 'vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView';
import { ICellDragEndMessage, ICellDragMessage, ICellDragStartMessage, ToWebviewMessage } from 'vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView';
import { RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
// !! IMPORTANT !! everything must be in-line within the webviewPreloads
@ -136,7 +136,7 @@ function webviewPreloads() {
const outputObservers = new Map<string, ResizeObserver>();
const resizeObserve = (container: Element, id: string) => {
const resizeObserve = (container: Element, id: string, output: boolean) => {
const resizeObserver = new ResizeObserver(entries => {
for (const entry of entries) {
if (!document.body.contains(entry.target)) {
@ -152,7 +152,8 @@ function webviewPreloads() {
id: id,
data: {
height: entry.contentRect.height + __outputNodePadding__ * 2
}
},
isOutput: output
});
} else {
entry.target.style.padding = `0px`;
@ -162,7 +163,8 @@ function webviewPreloads() {
id: id,
data: {
height: entry.contentRect.height
}
},
isOutput: output
});
}
}
@ -320,6 +322,10 @@ function webviewPreloads() {
mimeType?: string;
element: HTMLElement;
}
interface ICreateMarkdownInfo {
readonly content: string;
readonly element: HTMLElement;
}
interface IDestroyCellInfo {
outputId: string;
@ -327,6 +333,7 @@ function webviewPreloads() {
const onWillDestroyOutput = createEmitter<[string | undefined /* namespace */, IDestroyCellInfo | undefined /* cell uri */]>();
const onDidCreateOutput = createEmitter<[string | undefined /* namespace */, ICreateCellInfo]>();
const onDidCreateMarkdown = createEmitter<[string | undefined /* namespace */, ICreateMarkdownInfo]>();
const onDidReceiveMessage = createEmitter<[string, unknown]>();
const matchesNs = (namespace: string, query: string | undefined) => namespace === '*' || query === namespace || query === 'undefined';
@ -355,6 +362,7 @@ function webviewPreloads() {
onDidReceiveMessage: mapEmitter(onDidReceiveMessage, ([ns, data]) => ns === namespace ? data : dontEmit),
onWillDestroyOutput: mapEmitter(onWillDestroyOutput, ([ns, data]) => matchesNs(namespace, ns) ? data : dontEmit),
onDidCreateOutput: mapEmitter(onDidCreateOutput, ([ns, data]) => matchesNs(namespace, ns) ? data : dontEmit),
onDidCreateMarkdown: mapEmitter(onDidCreateMarkdown, ([ns, data]) => data),
};
};
@ -405,6 +413,51 @@ function webviewPreloads() {
const event = rawEvent as ({ data: ToWebviewMessage; });
switch (event.data.type) {
case 'initializeMarkdownPreview':
for (const cell of event.data.cells) {
createMarkdownPreview(cell.cellId, cell.content, -10000);
}
vscode.postMessage({
__vscode_notebook_message: true,
type: 'initializedMarkdownPreview',
});
break;
case 'createMarkdownPreview':
createMarkdownPreview(event.data.id, event.data.content, event.data.top);
break;
case 'showMarkdownPreview':
{
const data = event.data;
let cellContainer = document.getElementById(data.id);
if (cellContainer) {
cellContainer.style.display = 'block';
}
const previewNode = document.getElementById(`${data.id}_container`);
if (previewNode) {
previewNode.style.top = `${data.top}px`;
}
updateMarkdownPreview(data.id, data.content);
}
break;
case 'hideMarkdownPreview':
{
const data = event.data;
let cellContainer = document.getElementById(data.id);
if (cellContainer) {
cellContainer.style.display = 'none';
}
}
break;
case 'removeMarkdownPreview':
{
const data = event.data;
let cellContainer = document.getElementById(data.id);
if (cellContainer) {
cellContainer?.parentElement?.removeChild(cellContainer);
}
}
break;
case 'html':
enqueueOutputAction(event.data, async data => {
const preloadResults = await Promise.all(data.requiredPreloads.map(p => preloadPromises.get(p.uri)));
@ -431,6 +484,7 @@ function webviewPreloads() {
}
const outputNode = document.createElement('div');
outputNode.classList.add('output');
outputNode.style.position = 'absolute';
outputNode.style.top = data.top + 'px';
outputNode.style.left = data.left + 'px';
@ -468,7 +522,7 @@ function webviewPreloads() {
cellOutputContainer.appendChild(outputNode);
}
resizeObserve(outputNode, outputId);
resizeObserve(outputNode, outputId, true);
vscode.postMessage({
__vscode_notebook_message: true,
@ -498,6 +552,21 @@ function webviewPreloads() {
}
}
}
break;
}
case 'view-scroll-markdown':
{
// const date = new Date();
// console.log('----- will scroll ---- ', date.getMinutes() + ':' + date.getSeconds() + ':' + date.getMilliseconds());
event.data.cells.map(cell => {
const widget = document.getElementById(`${cell.id}_preview`)!;
if (widget) {
widget.style.top = `${cell.top}px`;
}
});
break;
}
case 'clear':
@ -589,6 +658,127 @@ function webviewPreloads() {
__vscode_notebook_message: true,
type: 'initialized'
});
document.addEventListener('dragover', e => {
// Allow dropping dragged markdown cells
e.preventDefault();
});
const markdownCellDragDataType = 'x-vscode-markdown-cell-drag';
document.addEventListener('drop', e => {
const data = e.dataTransfer?.getData(markdownCellDragDataType);
if (!data) {
return;
}
e.preventDefault();
const { cellId } = JSON.parse(data);
const msg: ICellDragEndMessage = {
__vscode_notebook_message: true,
type: 'cell-drag-end',
cellId: cellId,
ctrlKey: e.ctrlKey,
altKey: e.altKey,
position: { clientX: e.clientX, clientY: e.clientY },
};
vscode.postMessage(msg);
});
function createMarkdownPreview(cellId: string, content: string, top: number) {
let cellContainer = document.getElementById(cellId);
if (!cellContainer) {
const container = document.getElementById('container')!;
const newElement = document.createElement('div');
newElement.id = `${cellId}`;
container.appendChild(newElement);
cellContainer = newElement;
const previewContainerNode = document.createElement('div');
previewContainerNode.style.position = 'absolute';
previewContainerNode.style.top = top + 'px';
previewContainerNode.id = `${cellId}_preview`;
previewContainerNode.classList.add('preview');
previewContainerNode.addEventListener('dblclick', () => {
vscode.postMessage({
__vscode_notebook_message: true,
type: 'toggleMarkdownPreview',
cellId,
});
});
previewContainerNode.setAttribute('draggable', 'true');
previewContainerNode.addEventListener('dragstart', e => {
if (!e.dataTransfer) {
return;
}
e.dataTransfer.setData(markdownCellDragDataType, JSON.stringify({ cellId }));
(e.target as HTMLElement).classList.add('dragging');
const msg: ICellDragStartMessage = {
__vscode_notebook_message: true,
type: 'cell-drag-start',
cellId: cellId,
position: { clientX: e.clientX, clientY: e.clientY },
};
vscode.postMessage(msg);
});
previewContainerNode.addEventListener('drag', e => {
const msg: ICellDragMessage = {
__vscode_notebook_message: true,
type: 'cell-drag',
cellId: cellId,
position: { clientX: e.clientX, clientY: e.clientY },
};
vscode.postMessage(msg);
});
previewContainerNode.addEventListener('dragend', e => {
(e.target as HTMLElement).classList.remove('dragging');
});
cellContainer.appendChild(previewContainerNode);
const previewNode = document.createElement('div');
previewContainerNode.appendChild(previewNode);
// TODO: handle namespace
onDidCreateMarkdown.fire([undefined /* data.apiNamespace */, {
element: previewNode,
content: content
}]);
resizeObserve(previewContainerNode, `${cellId}_preview`, false);
vscode.postMessage({
__vscode_notebook_message: true,
type: 'dimension',
id: `${cellId}_preview`,
init: true,
data: {
height: previewContainerNode.clientHeight
},
isOutput: false
});
} else {
updateMarkdownPreview(cellId, content);
}
}
function updateMarkdownPreview(cellId: string, content: string) {
const previewNode = document.getElementById(`${cellId}_preview`);
if (previewNode) {
// TODO: handle namespace
onDidCreateMarkdown.fire([undefined /* data.apiNamespace */, {
element: previewNode,
content: content
}]);
}
}
}
export const preloadsScriptStr = (outputNodePadding: number, outputNodeLeftPadding: number) => `(${webviewPreloads})()`.replace(/__outputNodePadding__/g, `${outputNodePadding}`).replace(/__outputNodeLeftPadding__/g, `${outputNodeLeftPadding}`);

View file

@ -131,6 +131,13 @@ export interface INotebookRendererInfo {
matches(mimeType: string): boolean;
}
export interface INotebookMarkdownRendererInfo {
readonly entrypoint: URI;
readonly extensionLocation: URI;
readonly extensionId: ExtensionIdentifier;
readonly extensionIsBuiltin: boolean;
}
export interface NotebookCellOutputMetadata {
/**
* Additional attributes of a cell metadata.

View file

@ -0,0 +1,33 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { joinPath } from 'vs/base/common/resources';
import { URI } from 'vs/base/common/uri';
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { INotebookMarkdownRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookCommon';
export class NotebookMarkdownRendererInfo implements INotebookMarkdownRendererInfo {
readonly id: string;
readonly entrypoint: URI;
readonly displayName: string;
readonly extensionLocation: URI;
readonly extensionId: ExtensionIdentifier;
readonly extensionIsBuiltin: boolean;
constructor(descriptor: {
readonly id: string;
readonly displayName: string;
readonly entrypoint: string;
readonly extension: IExtensionDescription;
}) {
this.id = descriptor.id;
this.extensionId = descriptor.extension.identifier;
this.extensionLocation = descriptor.extension.extensionLocation;
this.entrypoint = joinPath(this.extensionLocation, descriptor.entrypoint);
this.displayName = descriptor.displayName;
this.extensionIsBuiltin = descriptor.extension.isBuiltin;
}
}

View file

@ -8,7 +8,7 @@ import { URI } from 'vs/base/common/uri';
import { NotebookProviderInfo } from 'vs/workbench/contrib/notebook/common/notebookProvider';
import { NotebookExtensionDescription } from 'vs/workbench/api/common/extHost.protocol';
import { Event } from 'vs/base/common/event';
import { INotebookTextModel, INotebookRendererInfo, IEditor, INotebookKernelProvider, INotebookKernel, TransientMetadata, NotebookDataDto, TransientOptions, INotebookDecorationRenderOptions, INotebookExclusiveDocumentFilter, IOrderedMimeType, IOutputDto } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotebookTextModel, INotebookRendererInfo, IEditor, INotebookKernelProvider, INotebookKernel, TransientMetadata, NotebookDataDto, TransientOptions, INotebookDecorationRenderOptions, INotebookExclusiveDocumentFilter, IOrderedMimeType, IOutputDto, INotebookMarkdownRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
import { CancellationToken } from 'vs/base/common/cancellation';
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
@ -53,6 +53,7 @@ export interface INotebookService {
getContributedNotebookKernelProviders(): Promise<INotebookKernelProvider[]>;
getContributedNotebookOutputRenderers(id: string): NotebookOutputRendererInfo | undefined;
getRendererInfo(id: string): INotebookRendererInfo | undefined;
getMarkdownRendererInfo(): INotebookMarkdownRendererInfo[];
resolveNotebook(viewType: string, uri: URI, forceReload: boolean, backupId?: string): Promise<NotebookTextModel>;
getNotebookTextModel(uri: URI): NotebookTextModel | undefined;

View file

@ -12,7 +12,7 @@ import { BareFontInfo } from 'vs/editor/common/config/fontInfo';
import { Range } from 'vs/editor/common/core/range';
import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
import { EditorModel } from 'vs/workbench/common/editor';
import { ICellViewModel, INotebookEditor, INotebookEditorContribution, INotebookEditorMouseEvent, NotebookLayoutInfo, INotebookDeltaDecoration, INotebookEditorCreationOptions, NotebookEditorOptions, ICellOutputViewModel, IInsetRenderOutput, ICommonCellInfo, IGenericCellViewModel, INotebookCellOutputLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { ICellViewModel, INotebookEditor, INotebookEditorContribution, INotebookEditorMouseEvent, NotebookLayoutInfo, INotebookDeltaDecoration, INotebookEditorCreationOptions, NotebookEditorOptions, ICellOutputViewModel, IInsetRenderOutput, ICommonCellInfo, IGenericCellViewModel, INotebookCellOutputLayoutInfo, CellEditState } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer';
import { NotebookEventDispatcher } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher';
import { CellViewModel, IModelDecorationsChangeAccessor, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
@ -86,6 +86,19 @@ export class TestNotebookEditor implements INotebookEditor {
updateOutputHeight(cellInfo: ICommonCellInfo, output: ICellOutputViewModel, height: number, isInit: boolean): void {
throw new Error('Method not implemented.');
}
setMarkdownCellEditState(cellId: string, editState: CellEditState): void {
throw new Error('Method not implemented.');
}
markdownCellDragStart(cellId: string, position: { clientY: number }): void {
throw new Error('Method not implemented.');
}
markdownCellDrag(cellId: string, position: { clientY: number }): void {
throw new Error('Method not implemented.');
}
markdownCellDragEnd(cellId: string, position: { clientY: number }): void {
throw new Error('Method not implemented.');
}
async beginComputeContributedKernels(): Promise<INotebookKernel[]> {
return [];
}
@ -302,6 +315,18 @@ export class TestNotebookEditor implements INotebookEditor {
createInset(cell: CellViewModel, output: IInsetRenderOutput, offset: number): Promise<void> {
return Promise.resolve();
}
createMarkdownPreview(cell: ICellViewModel): Promise<void> {
return Promise.resolve();
}
hideMarkdownPreview(cell: ICellViewModel): Promise<void> {
return Promise.resolve();
}
removeMarkdownPreview(cell: ICellViewModel): Promise<void> {
return Promise.resolve();
}
updateMarkdownCellHeight(cellId: string, height: number, isInit: boolean): void {
// noop
}
removeInset(output: ICellOutputViewModel): void {
// throw new Error('Method not implemented.');
}

View file

@ -254,11 +254,11 @@ export class PreferencesEditor extends EditorPane {
const promise = this.input && this.input.isDirty() ? this.editorService.save({ editor: this.input, groupId: this.group!.id }) : Promise.resolve(true);
promise.then(() => {
if (target === ConfigurationTarget.USER_LOCAL) {
this.preferencesService.switchSettings(ConfigurationTarget.USER_LOCAL, this.preferencesService.userSettingsResource, true);
this.preferencesService.switchSettings(ConfigurationTarget.USER_LOCAL, this.preferencesService.userSettingsResource);
} else if (target === ConfigurationTarget.WORKSPACE) {
this.preferencesService.switchSettings(ConfigurationTarget.WORKSPACE, this.preferencesService.workspaceSettingsResource!, true);
this.preferencesService.switchSettings(ConfigurationTarget.WORKSPACE, this.preferencesService.workspaceSettingsResource!);
} else if (target instanceof URI) {
this.preferencesService.switchSettings(ConfigurationTarget.WORKSPACE_FOLDER, target, true);
this.preferencesService.switchSettings(ConfigurationTarget.WORKSPACE_FOLDER, target);
}
});
}

View file

@ -303,6 +303,10 @@ export class SettingsEditor2 extends EditorPane {
}
private _setOptions(options: SettingsEditorOptions): void {
if (options.focusSearch) {
this.focusSearch();
}
if (options.query) {
this.searchWidget.setValue(options.query);
}

View file

@ -87,6 +87,7 @@ export class TunnelViewModel extends Disposable implements ITunnelViewModel {
this._register(this.model.onCandidatesChanged(() => this._onForwardedPortsChanged.fire()));
this._input = {
label: nls.localize('remote.tunnelsView.add', "Forward a Port..."),
wideLabel: nls.localize('remote.tunnelsView.add', "Forward a Port..."),
tunnelType: TunnelType.Add,
remoteHost: 'localhost',
remotePort: 0,
@ -265,8 +266,9 @@ class TunnelTreeRenderer extends Disposable implements ITreeRenderer<ITunnelGrou
private renderTunnel(node: ITunnelItem, templateData: ITunnelTemplateData) {
const isWide = templateData.container.parentElement?.parentElement?.parentElement?.parentElement?.parentElement?.parentElement?.parentElement?.parentElement?.classList.contains('wide');
const description = isWide ? node.wideDescription : node.description;
const label = node.label + (description ? (' - ' + description) : '');
templateData.iconLabel.setLabel(node.label, description, { title: node instanceof TunnelItem ? node.tooltip : label, extraClasses: ['tunnel-view-label'] });
const label = isWide ? node.wideLabel : node.label;
const tooltip = label + (description ? (' - ' + description) : '');
templateData.iconLabel.setLabel(label, description, { title: node instanceof TunnelItem ? node.tooltip : tooltip, extraClasses: ['tunnel-view-label'] });
templateData.actionBar.context = node;
const contextKeyService = this._register(this.contextKeyService.createScoped());
@ -434,16 +436,25 @@ class TunnelItem implements ITunnelItem {
public privacy?: TunnelPrivacy,
private remoteExplorerService?: IRemoteExplorerService
) { }
get label(): string {
if (this.name) {
return nls.localize('remote.tunnelsView.forwardedPortLabel0', "{0}", this.name);
} else if (this.localAddress) {
return nls.localize('remote.tunnelsView.forwardedPortLabel1', "{0} \u2192 {1}", this.remotePort, TunnelItem.compactLongAddress(this.localAddress));
private static getLabel(name: string | undefined, localAddress: string | undefined, remotePort: number, isWide: boolean = false): string {
if (name) {
return nls.localize('remote.tunnelsView.forwardedPortLabel0', "{0}", name);
} else if (localAddress) {
return nls.localize('remote.tunnelsView.forwardedPortLabel1', "{0} \u2192 {1}", remotePort, isWide ? localAddress : TunnelItem.compactLongAddress(localAddress));
} else {
return nls.localize('remote.tunnelsView.forwardedPortLabel2', "{0}", this.remotePort);
return nls.localize('remote.tunnelsView.forwardedPortLabel2', "{0}", remotePort);
}
}
get label(): string {
return TunnelItem.getLabel(this.name, this.localAddress, this.remotePort);
}
get wideLabel(): string {
return TunnelItem.getLabel(this.name, this.localAddress, this.remotePort, true);
}
private static compactLongAddress(address: string): string {
if (address.length < 16) {
return address;
@ -475,7 +486,7 @@ class TunnelItem implements ITunnelItem {
const description: string[] = [];
if (item.name && item.localAddress) {
description.push(nls.localize('remote.tunnelsView.forwardedPortDescription0', "{0} \u2192 {1}", item.remotePort, TunnelItem.compactLongAddress(item.localAddress)));
description.push(nls.localize('remote.tunnelsView.forwardedPortDescription0', "{0} \u2192 {1}", item.remotePort, isWide ? item.localAddress : TunnelItem.compactLongAddress(item.localAddress)));
}
if (item.runningProcess) {

View file

@ -8,6 +8,7 @@ import { assertIsDefined, withNullAsUndefined } from 'vs/base/common/types';
import { URI } from 'vs/base/common/uri';
import 'vs/css!./media/searchEditor';
import { ICodeEditor, isDiffEditor } from 'vs/editor/browser/editorBrowser';
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { ILabelService } from 'vs/platform/label/common/label';
@ -109,6 +110,7 @@ export const openNewSearchEditor =
const activeWorkspaceRootUri = historyService.getLastActiveWorkspaceRoot(Schemas.file);
const lastActiveWorkspaceRoot = activeWorkspaceRootUri ? withNullAsUndefined(workspaceContextService.getWorkspaceFolder(activeWorkspaceRootUri)) : undefined;
const activeEditorControl = editorService.activeTextEditorControl;
let activeModel: ICodeEditor | undefined;
let selected = '';
@ -133,7 +135,8 @@ export const openNewSearchEditor =
telemetryService.publicLog2('searchEditor/openNewSearchEditor');
const args: OpenSearchEditorArgs = { query: selected || undefined };
const seedSearchStringFromSelection = _args.location === 'new' || configurationService.getValue<IEditorOptions>('editor').find!.seedSearchStringFromSelection;
const args: OpenSearchEditorArgs = { query: seedSearchStringFromSelection ? selected : undefined };
Object.entries(_args).forEach(([name, value]) => {
if (value !== undefined) {
(args as any)[name as any] = (typeof value === 'string') ? configurationResolverService.resolve(lastActiveWorkspaceRoot, value) : value;

View file

@ -913,7 +913,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
}).then((value) => {
if (runSource === TaskRunSource.User) {
this.getWorkspaceTasks().then(workspaceTasks => {
RunAutomaticTasks.promptForPermission(this, this.storageService, this.notificationService, this.workspaceTrustService, workspaceTasks);
RunAutomaticTasks.promptForPermission(this, this.storageService, this.notificationService, this.workspaceTrustService, this.openerService, workspaceTasks);
});
}
return value;

View file

@ -4,17 +4,21 @@
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import * as resources from 'vs/base/common/resources';
import { Disposable } from 'vs/base/common/lifecycle';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { ITaskService, WorkspaceFolderTaskResult } from 'vs/workbench/contrib/tasks/common/taskService';
import { forEach } from 'vs/base/common/collections';
import { RunOnOptions, Task, TaskRunSource, TASKS_CATEGORY } from 'vs/workbench/contrib/tasks/common/tasks';
import { RunOnOptions, Task, TaskRunSource, TaskSource, TaskSourceKind, TASKS_CATEGORY, WorkspaceFileTaskSource, WorkspaceTaskSource } from 'vs/workbench/contrib/tasks/common/tasks';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
import { IQuickPickItem, IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
import { Action2 } from 'vs/platform/actions/common/actions';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IWorkspaceTrustService, WorkspaceTrustState } from 'vs/platform/workspace/common/workspaceTrust';
import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { URI } from 'vs/base/common/uri';
const ARE_AUTOMATIC_TASKS_ALLOWED_IN_WORKSPACE = 'tasks.run.allowAutomatic';
@ -55,9 +59,24 @@ export class RunAutomaticTasks extends Disposable implements IWorkbenchContribut
});
}
private static findAutoTasks(taskService: ITaskService, workspaceTaskResult: Map<string, WorkspaceFolderTaskResult>): { tasks: Array<Task | Promise<Task | undefined>>, taskNames: Array<string> } {
private static getTaskSource(source: TaskSource): URI | undefined {
const taskKind = TaskSourceKind.toConfigurationTarget(source.kind);
switch (taskKind) {
case ConfigurationTarget.WORKSPACE_FOLDER: {
return resources.joinPath((<WorkspaceTaskSource>source).config.workspaceFolder!.uri, (<WorkspaceTaskSource>source).config.file);
}
case ConfigurationTarget.WORKSPACE: {
return (<WorkspaceFileTaskSource>source).config.workspace?.configuration ?? undefined;
}
}
return undefined;
}
private static findAutoTasks(taskService: ITaskService, workspaceTaskResult: Map<string, WorkspaceFolderTaskResult>): { tasks: Array<Task | Promise<Task | undefined>>, taskNames: Array<string>, locations: Map<string, URI> } {
const tasks = new Array<Task | Promise<Task | undefined>>();
const taskNames = new Array<string>();
const locations = new Map<string, URI>();
if (workspaceTaskResult) {
workspaceTaskResult.forEach(resultElement => {
if (resultElement.set) {
@ -65,6 +84,10 @@ export class RunAutomaticTasks extends Disposable implements IWorkbenchContribut
if (task.runOptions.runOn === RunOnOptions.folderOpen) {
tasks.push(task);
taskNames.push(task._label);
const location = RunAutomaticTasks.getTaskSource(task._source);
if (location) {
locations.set(location.fsPath, location);
}
}
});
}
@ -79,16 +102,20 @@ export class RunAutomaticTasks extends Disposable implements IWorkbenchContribut
} else {
taskNames.push(configedTask.value.configures.task);
}
const location = RunAutomaticTasks.getTaskSource(configedTask.value._source);
if (location) {
locations.set(location.fsPath, location);
}
}
});
}
});
}
return { tasks, taskNames };
return { tasks, taskNames, locations };
}
public static async promptForPermission(taskService: ITaskService, storageService: IStorageService, notificationService: INotificationService, workspaceTrustService: IWorkspaceTrustService,
workspaceTaskResult: Map<string, WorkspaceFolderTaskResult>) {
openerService: IOpenerService, workspaceTaskResult: Map<string, WorkspaceFolderTaskResult>) {
const isWorkspaceTrusted = await workspaceTrustService.requireWorkspaceTrust({ immediate: false }) === WorkspaceTrustState.Trusted;
if (!isWorkspaceTrusted) {
return;
@ -99,10 +126,10 @@ export class RunAutomaticTasks extends Disposable implements IWorkbenchContribut
return;
}
let { tasks, taskNames } = RunAutomaticTasks.findAutoTasks(taskService, workspaceTaskResult);
let { tasks, taskNames, locations } = RunAutomaticTasks.findAutoTasks(taskService, workspaceTaskResult);
if (taskNames.length > 0) {
// We have automatic tasks, prompt to allow.
this.showPrompt(notificationService, storageService, taskService, taskNames).then(allow => {
this.showPrompt(notificationService, storageService, taskService, openerService, taskNames, locations).then(allow => {
if (allow) {
RunAutomaticTasks.runTasks(taskService, tasks);
}
@ -111,9 +138,13 @@ export class RunAutomaticTasks extends Disposable implements IWorkbenchContribut
}
private static showPrompt(notificationService: INotificationService, storageService: IStorageService, taskService: ITaskService,
taskNames: Array<string>): Promise<boolean> {
openerService: IOpenerService, taskNames: Array<string>, locations: Map<string, URI>): Promise<boolean> {
return new Promise<boolean>(resolve => {
notificationService.prompt(Severity.Info, nls.localize('tasks.run.allowAutomatic', "This folder has tasks ({0}) defined in \'tasks.json\' that run automatically when you open this folder. Do you allow automatic tasks to run when you open this folder?", taskNames.join(', ')),
notificationService.prompt(Severity.Info, nls.localize('tasks.run.allowAutomatic',
"This workspace has tasks ({0}) defined ({1}) that run automatically when you open this workspace. Do you allow automatic tasks to run when you open this workspace?",
taskNames.join(', '),
Array.from(locations.keys()).join(', ')
),
[{
label: nls.localize('allow', "Allow and run"),
run: () => {
@ -129,9 +160,11 @@ export class RunAutomaticTasks extends Disposable implements IWorkbenchContribut
}
},
{
label: nls.localize('openTasks', "Open tasks.json"),
run: () => {
taskService.openConfig(undefined);
label: locations.size === 1 ? nls.localize('openTask', "Open file") : nls.localize('openTasks', "Open files"),
run: async () => {
for (const location of locations) {
await openerService.open(location[1]);
}
resolve(false);
}
}]

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