Add support for markdown notebook renderers (#115191)
* Use shared webpack version instead of installing locally for simple-browser * Use npm for building markdown preview * render markdown in webview. * update markdown preview height and offset * Add basic custom notebook renderer point * update css * style update. * update markdown header padding left * Add example of loading katex to extend the markdown-it renderer * Rename global to make clear it only applies to markdown-in * hide/remove markdown preview * Add wait for initial markdown preview rendering before showing notebook * Add double click to switch to editing mode * Fix markdown cells not getting updated after editing * style polish * notebook.experimental.useMarkdownRenderer * switch render strategy. * Adding very intial drag drop support for notebook markdown cells * Implement drag/drop stubs for test classes * Revert unrelated file changes * Move markdown notebook math to own extension * Add missing imports Co-authored-by: rebornix <penn.lv@gmail.com>
This commit is contained in:
parent
c36a09929c
commit
35f855796b
|
@ -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/**
|
||||
|
|
|
@ -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',
|
||||
];
|
||||
|
||||
|
|
|
@ -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',
|
||||
|
|
964
extensions/markdown-language-features/notebook-out/index.js
Normal file
964
extensions/markdown-language-features/notebook-out/index.js
Normal file
File diff suppressed because one or more lines are too long
29
extensions/markdown-language-features/notebook/index.ts
Normal file
29
extensions/markdown-language-features/notebook/index.ts
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* 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) => {
|
||||
console.log('did create markdown cell');
|
||||
const rendered = markdownIt.render(content);
|
||||
element.innerHTML = rendered;
|
||||
});
|
||||
|
||||
console.log('markdown-it');
|
||||
}());
|
|
@ -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",
|
||||
|
|
27
extensions/markdown-language-features/webpack.notebook.js
Normal file
27
extensions/markdown-language-features/webpack.notebook.js
Normal 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')
|
||||
}
|
||||
};
|
12
extensions/markdown-notebook-math/.vscodeignore
Normal file
12
extensions/markdown-notebook-math/.vscodeignore
Normal 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
|
3
extensions/markdown-notebook-math/README.md
Normal file
3
extensions/markdown-notebook-math/README.md
Normal 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.
|
BIN
extensions/markdown-notebook-math/icon.png
Normal file
BIN
extensions/markdown-notebook-math/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 903 B |
File diff suppressed because one or more lines are too long
22
extensions/markdown-notebook-math/notebook/extension.ts
Normal file
22
extensions/markdown-notebook-math/notebook/extension.ts
Normal 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);
|
||||
});
|
||||
}
|
||||
}());
|
||||
|
12
extensions/markdown-notebook-math/notebook/tsconfig.json
Normal file
12
extensions/markdown-notebook-math/notebook/tsconfig.json
Normal file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"extends": "../../shared.tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist/",
|
||||
"jsx": "react",
|
||||
"lib": [
|
||||
"es2018",
|
||||
"DOM",
|
||||
"DOM.Iterable"
|
||||
]
|
||||
}
|
||||
}
|
45
extensions/markdown-notebook-math/package.json
Normal file
45
extensions/markdown-notebook-math/package.json
Normal 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"
|
||||
}
|
||||
}
|
4
extensions/markdown-notebook-math/package.nls.json
Normal file
4
extensions/markdown-notebook-math/package.nls.json
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"displayName": "Markdown Notebook math",
|
||||
"description": "Provides rich language support for Markdown."
|
||||
}
|
35
extensions/markdown-notebook-math/webpack.notebook.js
Normal file
35
extensions/markdown-notebook-math/webpack.notebook.js
Normal 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')
|
||||
}
|
||||
};
|
315
extensions/markdown-notebook-math/yarn.lock
Normal file
315
extensions/markdown-notebook-math/yarn.lock
Normal 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==
|
|
@ -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 { IDisplayOutputLayoutUpdateRequest, IDisplayOutputViewModel, IGenericCellViewModel, IInsetRenderOutput, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||
import { CellEditState, IDisplayOutputLayoutUpdateRequest, IDisplayOutputViewModel, 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);
|
||||
}
|
||||
|
|
|
@ -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 //
|
||||
});
|
||||
|
|
|
@ -167,6 +167,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 }): void;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
@ -462,6 +467,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
|
||||
*/
|
||||
|
@ -684,6 +693,7 @@ export interface BaseCellRenderTemplate {
|
|||
export interface MarkdownCellRenderTemplate extends BaseCellRenderTemplate {
|
||||
editorContainer: HTMLElement;
|
||||
foldingIndicator: HTMLElement;
|
||||
focusIndicatorBottom: HTMLElement;
|
||||
currentEditor?: ICodeEditor;
|
||||
}
|
||||
|
||||
|
|
|
@ -64,6 +64,7 @@ import { configureKernelIcon, errorStateIcon, successStateIcon } from 'vs/workbe
|
|||
import { debugIconStartForeground } from 'vs/workbench/contrib/debug/browser/debugColors';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { extname } from 'vs/base/common/resources';
|
||||
import { MarkdownCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/markdownCellViewModel';
|
||||
|
||||
const $ = DOM.$;
|
||||
|
||||
|
@ -1016,6 +1017,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
|
||||
|
||||
{
|
||||
|
@ -1105,6 +1119,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);
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
|
@ -1957,6 +1983,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) {
|
||||
|
@ -2048,6 +2109,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, position: { clientY: number }): void {
|
||||
const cell = this.viewModel?.viewCells.find(vc => vc.id === cellId);
|
||||
|
||||
if (cell && cell instanceof MarkdownCellViewModel) {
|
||||
this._dndController?.startExplicitDrag(cell, position);
|
||||
}
|
||||
}
|
||||
|
||||
markdownCellDrag(cellId: string, position: { clientY: number }): void {
|
||||
const cell = this.viewModel?.viewCells.find(vc => vc.id === cellId);
|
||||
|
||||
if (cell && cell instanceof MarkdownCellViewModel) {
|
||||
this._dndController?.explicitDrag(cell, position);
|
||||
}
|
||||
}
|
||||
|
||||
markdownCellDragEnd(cellId: string, position: { clientY: number }): void {
|
||||
const cell = this.viewModel?.viewCells.find(vc => vc.id === cellId);
|
||||
|
||||
if (cell && cell instanceof MarkdownCellViewModel) {
|
||||
this._dndController?.endExplicitDrag(cell, position);
|
||||
}
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
|
@ -2303,8 +2403,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;
|
||||
}`);
|
||||
|
||||
|
@ -2321,8 +2420,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;
|
||||
}`);
|
||||
|
||||
|
|
|
@ -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, CellOutputKind, DisplayOrderKey, ICellEditOperation, IDisplayOutput, INotebookDecorationRenderOptions, INotebookKernelInfo2, INotebookKernelProvider, INotebookRendererInfo, INotebookTextModel, IOrderedMimeType, ITransformedDisplayOutputDto, 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, CellOutputKind, DisplayOrderKey, ICellEditOperation, IDisplayOutput, INotebookDecorationRenderOptions, INotebookKernelInfo2, INotebookKernelProvider, INotebookMarkdownRendererInfo, INotebookRendererInfo, INotebookTextModel, IOrderedMimeType, ITransformedDisplayOutputDto, 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 = () => {
|
||||
|
@ -747,6 +776,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)) {
|
||||
|
|
|
@ -17,9 +17,9 @@ 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 { 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 { CellEditState, ICommonCellInfo, ICommonNotebookEditor, IDisplayOutputLayoutUpdateRequest, IDisplayOutputViewModel, IGenericCellViewModel, IInsetRenderOutput, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||
import { CellOutputKind, IDisplayOutput, INotebookRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
|
||||
import { IWebviewService, WebviewContentPurpose, WebviewElement } from 'vs/workbench/contrib/webview/browser/webview';
|
||||
|
@ -37,6 +37,7 @@ export interface IDimensionMessage {
|
|||
id: string;
|
||||
init: boolean;
|
||||
data: DOM.Dimension;
|
||||
isOutput: boolean;
|
||||
}
|
||||
|
||||
export interface IMouseEnterMessage {
|
||||
|
@ -79,6 +80,33 @@ 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 {
|
||||
__vscode_notebook_message: boolean;
|
||||
type: 'cell-drag-end';
|
||||
cellId: string;
|
||||
position: { clientX: number, clientY: number };
|
||||
}
|
||||
|
||||
export interface IClearMessage {
|
||||
type: 'clear';
|
||||
}
|
||||
|
@ -111,6 +139,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;
|
||||
|
@ -170,6 +203,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
|
||||
|
@ -179,8 +241,12 @@ export type FromWebviewMessage =
|
|||
| IScrollAckMessage
|
||||
| IBlurOutputMessage
|
||||
| ICustomRendererMessage
|
||||
| IClickedDataUrlMessage;
|
||||
|
||||
| IClickedDataUrlMessage
|
||||
| IToggleMarkdownPreviewMessage
|
||||
| ICellDragStartMessage
|
||||
| ICellDragMessage
|
||||
| ICellDragEndMessage
|
||||
;
|
||||
export type ToWebviewMessage =
|
||||
| IClearMessage
|
||||
| IFocusOutputMessage
|
||||
|
@ -192,7 +258,13 @@ export type ToWebviewMessage =
|
|||
| IShowOutputMessage
|
||||
| IUpdatePreloadResourceMessage
|
||||
| IUpdateDecorationsMessage
|
||||
| ICustomRendererMessage;
|
||||
| ICustomRendererMessage
|
||||
| ICreateMarkdownMessage
|
||||
| IRemoveMarkdownMessage
|
||||
| IShowMarkdownMessage
|
||||
| IHideMarkdownMessage
|
||||
| IInitializeMarkdownMessage
|
||||
| IViewScrollMarkdownRequestMessage;
|
||||
|
||||
export type AnyMessage = FromWebviewMessage | ToWebviewMessage;
|
||||
|
||||
|
@ -221,6 +293,7 @@ export class BackLayerWebView<T extends ICommonCellInfo> extends Disposable {
|
|||
element: HTMLElement;
|
||||
webview: WebviewElement | undefined = undefined;
|
||||
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;
|
||||
|
@ -256,20 +329,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);
|
||||
}
|
||||
|
@ -333,10 +559,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,
|
||||
|
@ -459,13 +704,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);
|
||||
|
@ -511,6 +761,14 @@ 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, data.position);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -559,7 +817,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,
|
||||
|
@ -611,6 +874,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;
|
||||
|
@ -639,6 +909,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;
|
||||
|
|
|
@ -64,14 +64,17 @@ export class CellDragAndDropController extends Disposable {
|
|||
};
|
||||
|
||||
addCellDragListener(DOM.EventType.DRAG_OVER, event => {
|
||||
console.log('dragOver');
|
||||
event.browserEvent.preventDefault();
|
||||
this.onCellDragover(event);
|
||||
});
|
||||
addCellDragListener(DOM.EventType.DROP, event => {
|
||||
console.log('drop');
|
||||
event.browserEvent.preventDefault();
|
||||
this.onCellDrop(event);
|
||||
});
|
||||
addCellDragListener(DOM.EventType.DRAG_LEAVE, event => {
|
||||
console.log('drag leave');
|
||||
event.browserEvent.preventDefault();
|
||||
this.onCellDragLeave(event);
|
||||
});
|
||||
|
@ -149,7 +152,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 +163,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 +192,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 +278,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, position: { clientY: number }) {
|
||||
this.currentDraggedCell = undefined;
|
||||
this.setInsertIndicatorVisibility(false);
|
||||
|
||||
const target = this.list.elementAt(position.clientY);
|
||||
if (!target || target === cell) {
|
||||
return;
|
||||
}
|
||||
|
||||
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 isCopy = false; // TODO
|
||||
if (isCopy) {
|
||||
// this.copyCells(draggedCells, event.draggedOverCell, 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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,106 @@ function webviewPreloads() {
|
|||
__vscode_notebook_message: true,
|
||||
type: 'initialized'
|
||||
});
|
||||
|
||||
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 => {
|
||||
(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 => {
|
||||
console.log('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');
|
||||
|
||||
const msg: ICellDragEndMessage = {
|
||||
__vscode_notebook_message: true,
|
||||
type: 'cell-drag-end',
|
||||
cellId: cellId,
|
||||
position: { clientX: e.clientX, clientY: e.clientY },
|
||||
};
|
||||
vscode.postMessage(msg);
|
||||
});
|
||||
|
||||
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}`);
|
||||
|
|
|
@ -140,6 +140,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 IStreamOutput {
|
||||
outputKind: CellOutputKind.Text;
|
||||
text: string;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -10,7 +10,7 @@ import { NotebookExtensionDescription } from 'vs/workbench/api/common/extHost.pr
|
|||
import { Event } from 'vs/base/common/event';
|
||||
import {
|
||||
INotebookTextModel, INotebookRendererInfo,
|
||||
IEditor, INotebookKernelProvider, INotebookKernelInfo2, TransientMetadata, NotebookDataDto, TransientOptions, INotebookDecorationRenderOptions, INotebookExclusiveDocumentFilter, IOrderedMimeType, ITransformedDisplayOutputDto
|
||||
IEditor, INotebookKernelProvider, INotebookKernelInfo2, TransientMetadata, NotebookDataDto, TransientOptions, INotebookDecorationRenderOptions, INotebookExclusiveDocumentFilter, IOrderedMimeType, ITransformedDisplayOutputDto, 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';
|
||||
|
@ -56,6 +56,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;
|
||||
|
|
|
@ -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, IDisplayOutputViewModel, ICommonCellInfo, IGenericCellViewModel, INotebookCellOutputLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||
import { ICellViewModel, INotebookEditor, INotebookEditorContribution, INotebookEditorMouseEvent, NotebookLayoutInfo, INotebookDeltaDecoration, INotebookEditorCreationOptions, NotebookEditorOptions, ICellOutputViewModel, IInsetRenderOutput, IDisplayOutputViewModel, 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';
|
||||
|
@ -87,6 +87,18 @@ export class TestNotebookEditor implements INotebookEditor {
|
|||
updateOutputHeight(cellInfo: ICommonCellInfo, output: IDisplayOutputViewModel, 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<INotebookKernelInfo2[]> {
|
||||
return [];
|
||||
}
|
||||
|
@ -303,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.');
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue