Merge branch 'main' into notebook/dev
This commit is contained in:
commit
1669dcee38
33 changed files with 1461 additions and 1062 deletions
|
@ -989,6 +989,7 @@
|
|||
"vscode-dts-cancellation": "warn",
|
||||
"vscode-dts-use-thenable": "warn",
|
||||
"vscode-dts-region-comments": "warn",
|
||||
"vscode-dts-vscode-in-comments": "warn",
|
||||
"vscode-dts-provider-naming": [
|
||||
"warn",
|
||||
{
|
||||
|
|
4
.github/workflows/english-please.yml
vendored
4
.github/workflows/english-please.yml
vendored
|
@ -7,19 +7,17 @@ on:
|
|||
jobs:
|
||||
main:
|
||||
runs-on: ubuntu-latest
|
||||
if: contains(github.event.issue.labels.*.name, '*english-please')
|
||||
steps:
|
||||
- name: Checkout Actions
|
||||
if: contains(github.event.issue.labels.*.name, '*english-please')
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: "microsoft/vscode-github-triage-actions"
|
||||
ref: stable
|
||||
path: ./actions
|
||||
- name: Install Actions
|
||||
if: contains(github.event.issue.labels.*.name, '*english-please')
|
||||
run: npm install --production --prefix ./actions
|
||||
- name: Run English Please
|
||||
if: contains(github.event.issue.labels.*.name, '*english-please')
|
||||
uses: ./actions/english-please
|
||||
with:
|
||||
appInsightsKey: ${{secrets.TRIAGE_ACTIONS_APP_INSIGHTS}}
|
||||
|
|
45
build/lib/eslint/vscode-dts-vscode-in-comments.js
Normal file
45
build/lib/eslint/vscode-dts-vscode-in-comments.js
Normal file
|
@ -0,0 +1,45 @@
|
|||
"use strict";
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
module.exports = new class ApiVsCodeInComments {
|
||||
constructor() {
|
||||
this.meta = {
|
||||
messages: {
|
||||
comment: `Don't use the term 'vs code' in comments`
|
||||
}
|
||||
};
|
||||
}
|
||||
create(context) {
|
||||
const sourceCode = context.getSourceCode();
|
||||
return {
|
||||
['Program']: (_node) => {
|
||||
for (const comment of sourceCode.getAllComments()) {
|
||||
if (comment.type !== 'Block') {
|
||||
continue;
|
||||
}
|
||||
if (!comment.range) {
|
||||
continue;
|
||||
}
|
||||
const startIndex = comment.range[0] + '/*'.length;
|
||||
const re = /vs code/ig;
|
||||
let match;
|
||||
while ((match = re.exec(comment.value))) {
|
||||
// Allow using 'VS Code' in quotes
|
||||
if (comment.value[match.index - 1] === `'` && comment.value[match.index + match[0].length] === `'`) {
|
||||
continue;
|
||||
}
|
||||
// Types for eslint seem incorrect
|
||||
const start = sourceCode.getLocFromIndex(startIndex + match.index);
|
||||
const end = sourceCode.getLocFromIndex(startIndex + match.index + match[0].length);
|
||||
context.report({
|
||||
messageId: 'comment',
|
||||
loc: { start, end }
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
53
build/lib/eslint/vscode-dts-vscode-in-comments.ts
Normal file
53
build/lib/eslint/vscode-dts-vscode-in-comments.ts
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as eslint from 'eslint';
|
||||
import type * as estree from 'estree';
|
||||
|
||||
export = new class ApiVsCodeInComments implements eslint.Rule.RuleModule {
|
||||
|
||||
readonly meta: eslint.Rule.RuleMetaData = {
|
||||
messages: {
|
||||
comment: `Don't use the term 'vs code' in comments`
|
||||
}
|
||||
};
|
||||
|
||||
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
|
||||
|
||||
const sourceCode = context.getSourceCode();
|
||||
|
||||
return {
|
||||
['Program']: (_node: any) => {
|
||||
|
||||
for (const comment of sourceCode.getAllComments()) {
|
||||
if (comment.type !== 'Block') {
|
||||
continue;
|
||||
}
|
||||
if (!comment.range) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const startIndex = comment.range[0] + '/*'.length;
|
||||
const re = /vs code/ig;
|
||||
let match: RegExpExecArray | null;
|
||||
while ((match = re.exec(comment.value))) {
|
||||
// Allow using 'VS Code' in quotes
|
||||
if (comment.value[match.index - 1] === `'` && comment.value[match.index + match[0].length] === `'`) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Types for eslint seem incorrect
|
||||
const start = sourceCode.getLocFromIndex(startIndex + match.index) as any as estree.Position;
|
||||
const end = sourceCode.getLocFromIndex(startIndex + match.index + match[0].length) as any as estree.Position;
|
||||
context.report({
|
||||
messageId: 'comment',
|
||||
loc: { start, end }
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
|
@ -88,7 +88,7 @@ function update(options) {
|
|||
for (let tp of translationPaths) {
|
||||
localization.translations.push({ id: tp.id, path: `./translations/${tp.resourceName}` });
|
||||
}
|
||||
fs.writeFileSync(path.join(locExtFolder, 'package.json'), JSON.stringify(packageJSON, null, '\t'));
|
||||
fs.writeFileSync(path.join(locExtFolder, 'package.json'), JSON.stringify(packageJSON, null, '\t') + '\n');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -10,14 +10,164 @@ export function activate() {
|
|||
html: true
|
||||
});
|
||||
|
||||
const style = document.createElement('style');
|
||||
style.classList.add('markdown-style');
|
||||
style.textContent = `
|
||||
.emptyMarkdownCell::before {
|
||||
content: "${document.documentElement.style.getPropertyValue('--notebook-cell-markup-empty-content')}";
|
||||
font-style: italic;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a:focus,
|
||||
input:focus,
|
||||
select:focus,
|
||||
textarea:focus {
|
||||
outline: 1px solid -webkit-focus-ring-color;
|
||||
outline-offset: -1px;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 0;
|
||||
height: 2px;
|
||||
border-bottom: 2px solid;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 26px;
|
||||
line-height: 31px;
|
||||
margin: 0;
|
||||
margin-bottom: 13px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 19px;
|
||||
margin: 0;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3 {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
div {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Adjust margin of first item in markdown cell */
|
||||
*:first-child {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
/* h1 tags don't need top margin */
|
||||
h1:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
/* Removes bottom margin when only one item exists in markdown cell */
|
||||
*:only-child,
|
||||
*:last-child {
|
||||
margin-bottom: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
/* makes all markdown cells consistent */
|
||||
div {
|
||||
min-height: var(--notebook-markdown-min-height);
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
table th,
|
||||
table td {
|
||||
border: 1px solid;
|
||||
}
|
||||
|
||||
table > thead > tr > th {
|
||||
text-align: left;
|
||||
border-bottom: 1px solid;
|
||||
}
|
||||
|
||||
table > thead > tr > th,
|
||||
table > thead > tr > td,
|
||||
table > tbody > tr > th,
|
||||
table > tbody > tr > td {
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
table > tbody > tr + tr > td {
|
||||
border-top: 1px solid;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 0 7px 0 5px;
|
||||
padding: 0 16px 0 10px;
|
||||
border-left-width: 5px;
|
||||
border-left-style: solid;
|
||||
}
|
||||
|
||||
code,
|
||||
.code {
|
||||
font-size: 1em;
|
||||
line-height: 1.357em;
|
||||
}
|
||||
|
||||
.code {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
`;
|
||||
document.head.append(style);
|
||||
|
||||
return {
|
||||
renderOutputItem: (outputInfo: { text(): string }, element: HTMLElement) => {
|
||||
const rendered = markdownIt.render(outputInfo.text());
|
||||
element.innerHTML = rendered;
|
||||
let previewNode: HTMLElement;
|
||||
if (!element.shadowRoot) {
|
||||
const previewRoot = element.attachShadow({ mode: 'open' });
|
||||
|
||||
// Insert styles into markdown preview shadow dom so that they are applied
|
||||
for (const markdownStyleNode of document.getElementsByClassName('markdown-style')) {
|
||||
element.insertAdjacentElement('beforebegin', markdownStyleNode.cloneNode(true) as Element);
|
||||
// Insert styles into markdown preview shadow dom so that they are applied.
|
||||
// First add default webview style
|
||||
const defaultStyles = document.getElementById('_defaultStyles') as HTMLStyleElement;
|
||||
previewRoot.appendChild(defaultStyles.cloneNode(true));
|
||||
|
||||
// And then contributed styles
|
||||
for (const markdownStyleNode of document.getElementsByClassName('markdown-style')) {
|
||||
previewRoot.appendChild(markdownStyleNode.cloneNode(true));
|
||||
}
|
||||
|
||||
previewNode = document.createElement('div');
|
||||
previewNode.id = 'preview';
|
||||
previewRoot.appendChild(previewNode);
|
||||
} else {
|
||||
previewNode = element.shadowRoot.getElementById('preview')!;
|
||||
}
|
||||
|
||||
const text = outputInfo.text();
|
||||
if (text.trim().length === 0) {
|
||||
previewNode.innerText = '';
|
||||
previewNode.classList.add('emptyMarkdownCell');
|
||||
} else {
|
||||
previewNode.classList.remove('emptyMarkdownCell');
|
||||
|
||||
const rendered = markdownIt.render(text);
|
||||
previewNode.innerHTML = rendered;
|
||||
}
|
||||
},
|
||||
extendMarkdownIt: (f: (md: typeof markdownIt) => void) => {
|
||||
|
|
|
@ -703,7 +703,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType
|
|||
if (isWeb()) {
|
||||
// On web, treat absolute paths as pointing to standard lib files
|
||||
if (filepath.startsWith('/')) {
|
||||
return vscode.Uri.joinPath(this.context.extensionUri, 'node_modules', 'typescript', 'lib', filepath.slice(1));
|
||||
return vscode.Uri.joinPath(this.context.extensionUri, 'dist', 'browser', 'typescript', filepath.slice(1));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -193,6 +193,24 @@ export class ActionRunner extends Disposable implements IActionRunner {
|
|||
|
||||
export class Separator extends Action {
|
||||
|
||||
/**
|
||||
* Joins all non-empty lists of actions with separators.
|
||||
*/
|
||||
public static join(...actionLists: readonly IAction[][]) {
|
||||
let out: IAction[] = [];
|
||||
for (const list of actionLists) {
|
||||
if (!list.length) {
|
||||
// skip
|
||||
} else if (out.length) {
|
||||
out = [...out, new Separator(), ...list];
|
||||
} else {
|
||||
out = list;
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static readonly ID = 'vs.actions.separator';
|
||||
|
||||
constructor(label?: string) {
|
||||
|
|
|
@ -30,7 +30,7 @@ export namespace Iterable {
|
|||
return iterable[Symbol.iterator]().next().value;
|
||||
}
|
||||
|
||||
export function some<T>(iterable: Iterable<T>, predicate: (t: T) => boolean): boolean {
|
||||
export function some<T>(iterable: Iterable<T>, predicate: (t: T) => unknown): boolean {
|
||||
for (const element of iterable) {
|
||||
if (predicate(element)) {
|
||||
return true;
|
||||
|
|
|
@ -19,7 +19,7 @@ import { ModesContentHoverWidget } from 'vs/editor/contrib/hover/modesContentHov
|
|||
import { ModesGlyphHoverWidget } from 'vs/editor/contrib/hover/modesGlyphHover';
|
||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { editorHoverBackground, editorHoverBorder, editorHoverHighlight, textCodeBlockBackground, textLinkForeground, editorHoverStatusBarBackground, editorHoverForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { editorHoverBackground, editorHoverBorder, editorHoverHighlight, textCodeBlockBackground, textLinkForeground, editorHoverStatusBarBackground, editorHoverForeground, textLinkActiveForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
|
||||
import { GotoDefinitionAtPositionEditorContribution } from 'vs/editor/contrib/gotoSymbol/link/goToDefinitionAtPosition';
|
||||
|
@ -327,6 +327,10 @@ registerThemingParticipant((theme, collector) => {
|
|||
if (link) {
|
||||
collector.addRule(`.monaco-editor .monaco-hover a { color: ${link}; }`);
|
||||
}
|
||||
const linkHover = theme.getColor(textLinkActiveForeground);
|
||||
if (linkHover) {
|
||||
collector.addRule(`.monaco-editor .monaco-hover a:hover { color: ${linkHover}; }`);
|
||||
}
|
||||
const hoverForeground = theme.getColor(editorHoverForeground);
|
||||
if (hoverForeground) {
|
||||
collector.addRule(`.monaco-editor .monaco-hover { color: ${hoverForeground}; }`);
|
||||
|
|
136
src/vs/vscode.d.ts
vendored
136
src/vs/vscode.d.ts
vendored
|
@ -1989,7 +1989,7 @@ declare module 'vscode' {
|
|||
* { language: 'typescript', scheme: 'file' }
|
||||
*
|
||||
* @example <caption>A language filter that applies to all package.json paths</caption>
|
||||
* { language: 'json', scheme: 'untitled', pattern: '**/package.json' }
|
||||
* { language: 'json', pattern: '**/package.json' }
|
||||
*/
|
||||
export interface DocumentFilter {
|
||||
|
||||
|
@ -2815,9 +2815,9 @@ declare module 'vscode' {
|
|||
}
|
||||
|
||||
/**
|
||||
* The inline values provider interface defines the contract between extensions and the VS Code debugger inline values feature.
|
||||
* The inline values provider interface defines the contract between extensions and the editor's debugger inline values feature.
|
||||
* In this contract the provider returns inline value information for a given document range
|
||||
* and VS Code shows this information in the editor at the end of lines.
|
||||
* and the editor shows this information in the editor at the end of lines.
|
||||
*/
|
||||
export interface InlineValuesProvider {
|
||||
|
||||
|
@ -2829,7 +2829,7 @@ declare module 'vscode' {
|
|||
|
||||
/**
|
||||
* Provide "inline value" information for a given document and range.
|
||||
* VS Code calls this method whenever debugging stops in the given document.
|
||||
* The editor calls this method whenever debugging stops in the given document.
|
||||
* The returned inline values information is rendered in the editor at the end of lines.
|
||||
*
|
||||
* @param document The document for which the inline values information is needed.
|
||||
|
@ -3646,7 +3646,7 @@ declare module 'vscode' {
|
|||
* ```
|
||||
*
|
||||
* @see {@link SemanticTokensBuilder} for a helper to encode tokens as integers.
|
||||
* *NOTE*: When doing edits, it is possible that multiple edits occur until VS Code decides to invoke the semantic tokens provider.
|
||||
* *NOTE*: When doing edits, it is possible that multiple edits occur until the editor decides to invoke the semantic tokens provider.
|
||||
* *NOTE*: If the provider cannot temporarily compute semantic tokens, it can indicate this by throwing an error with the message 'Busy'.
|
||||
*/
|
||||
provideDocumentSemanticTokens(document: TextDocument, token: CancellationToken): ProviderResult<SemanticTokens>;
|
||||
|
@ -5556,7 +5556,7 @@ declare module 'vscode' {
|
|||
/**
|
||||
* Role of the widget which defines how a screen reader interacts with it.
|
||||
* The role should be set in special cases when for example a tree-like element behaves like a checkbox.
|
||||
* If role is not specified VS Code will pick the appropriate role automatically.
|
||||
* If role is not specified the editor will pick the appropriate role automatically.
|
||||
* More about aria roles can be found here https://w3c.github.io/aria/#widget_roles
|
||||
*/
|
||||
role?: string;
|
||||
|
@ -5648,7 +5648,7 @@ declare module 'vscode' {
|
|||
* The command must be {@link commands.getCommands known}.
|
||||
*
|
||||
* Note that if this is a {@link Command `Command`} object, only the {@link Command.command `command`} and {@link Command.arguments `arguments`}
|
||||
* are used by VS Code.
|
||||
* are used by the editor.
|
||||
*/
|
||||
command: string | Command | undefined;
|
||||
|
||||
|
@ -5959,13 +5959,13 @@ declare module 'vscode' {
|
|||
export enum ExtensionMode {
|
||||
/**
|
||||
* The extension is installed normally (for example, from the marketplace
|
||||
* or VSIX) in VS Code.
|
||||
* or VSIX) in the editor.
|
||||
*/
|
||||
Production = 1,
|
||||
|
||||
/**
|
||||
* The extension is running from an `--extensionDevelopmentPath` provided
|
||||
* when launching VS Code.
|
||||
* when launching the editor.
|
||||
*/
|
||||
Development = 2,
|
||||
|
||||
|
@ -6549,7 +6549,7 @@ declare module 'vscode' {
|
|||
constructor(commandLine: string, options?: ShellExecutionOptions);
|
||||
|
||||
/**
|
||||
* Creates a shell execution with a command and arguments. For the real execution VS Code will
|
||||
* Creates a shell execution with a command and arguments. For the real execution the editor will
|
||||
* construct a command line from the command and the arguments. This is subject to interpretation
|
||||
* especially when it comes to quoting. If full control over the command line is needed please
|
||||
* use the constructor that creates a `ShellExecution` with the full command line.
|
||||
|
@ -6865,7 +6865,7 @@ declare module 'vscode' {
|
|||
export function fetchTasks(filter?: TaskFilter): Thenable<Task[]>;
|
||||
|
||||
/**
|
||||
* Executes a task that is managed by VS Code. The returned
|
||||
* Executes a task that is managed by the editor. The returned
|
||||
* task execution can be used to terminate the task.
|
||||
*
|
||||
* @throws When running a ShellExecution or a ProcessExecution
|
||||
|
@ -7281,7 +7281,7 @@ declare module 'vscode' {
|
|||
* @param scheme The scheme of the filesystem, for example `file` or `git`.
|
||||
*
|
||||
* @return `true` if the file system supports writing, `false` if it does not
|
||||
* support writing (i.e. it is readonly), and `undefined` if VS Code does not
|
||||
* support writing (i.e. it is readonly), and `undefined` if the editor does not
|
||||
* know about the filesystem.
|
||||
*/
|
||||
isWritableFileSystem(scheme: string): boolean | undefined;
|
||||
|
@ -7362,7 +7362,7 @@ declare module 'vscode' {
|
|||
* Webviews are sandboxed from normal extension process, so all communication with the webview must use
|
||||
* message passing. To send a message from the extension to the webview, use {@link Webview.postMessage `postMessage`}.
|
||||
* To send message from the webview back to an extension, use the `acquireVsCodeApi` function inside the webview
|
||||
* to get a handle to VS Code's api and then call `.postMessage()`:
|
||||
* to get a handle to the editor's api and then call `.postMessage()`:
|
||||
*
|
||||
* ```html
|
||||
* <script>
|
||||
|
@ -7384,7 +7384,7 @@ declare module 'vscode' {
|
|||
/**
|
||||
* Fired when the webview content posts a message.
|
||||
*
|
||||
* Webview content can post strings or json serializable objects back to a VS Code extension. They cannot
|
||||
* Webview content can post strings or json serializable objects back to an extension. They cannot
|
||||
* post `Blob`, `File`, `ImageData` and other DOM specific objects since the extension that receives the
|
||||
* message does not run in a browser environment.
|
||||
*/
|
||||
|
@ -7452,7 +7452,7 @@ declare module 'vscode' {
|
|||
*
|
||||
* Normally the webview panel's html context is created when the panel becomes visible
|
||||
* and destroyed when it is hidden. Extensions that have complex state
|
||||
* or UI can set the `retainContextWhenHidden` to make VS Code keep the webview
|
||||
* or UI can set the `retainContextWhenHidden` to make the editor keep the webview
|
||||
* context around, even when the webview moves to a background tab. When a webview using
|
||||
* `retainContextWhenHidden` becomes hidden, its scripts and other dynamic content are suspended.
|
||||
* When the panel becomes visible again, the context is automatically restored
|
||||
|
@ -7562,7 +7562,7 @@ declare module 'vscode' {
|
|||
* There are two types of webview persistence:
|
||||
*
|
||||
* - Persistence within a session.
|
||||
* - Persistence across sessions (across restarts of VS Code).
|
||||
* - Persistence across sessions (across restarts of the editor).
|
||||
*
|
||||
* A `WebviewPanelSerializer` is only required for the second case: persisting a webview across sessions.
|
||||
*
|
||||
|
@ -7582,8 +7582,8 @@ declare module 'vscode' {
|
|||
* setState({ value: oldState.value + 1 })
|
||||
* ```
|
||||
*
|
||||
* A `WebviewPanelSerializer` extends this persistence across restarts of VS Code. When the editor is shutdown,
|
||||
* VS Code will save off the state from `setState` of all webviews that have a serializer. When the
|
||||
* A `WebviewPanelSerializer` extends this persistence across restarts of the editor. When the editor is shutdown,
|
||||
* it will save off the state from `setState` of all webviews that have a serializer. When the
|
||||
* webview first becomes visible after the restart, this state is passed to `deserializeWebviewPanel`.
|
||||
* The extension can then restore the old `WebviewPanel` from this state.
|
||||
*
|
||||
|
@ -7678,7 +7678,7 @@ declare module 'vscode' {
|
|||
/**
|
||||
* Persisted state from the webview content.
|
||||
*
|
||||
* To save resources, VS Code normally deallocates webview documents (the iframe content) that are not visible.
|
||||
* To save resources, the editor normally deallocates webview documents (the iframe content) that are not visible.
|
||||
* For example, when the user collapse a view or switches to another top level activity in the sidebar, the
|
||||
* `WebviewView` itself is kept alive but the webview's underlying document is deallocated. It is recreated when
|
||||
* the view becomes visible again.
|
||||
|
@ -7701,7 +7701,7 @@ declare module 'vscode' {
|
|||
* setState({ value: oldState.value + 1 })
|
||||
* ```
|
||||
*
|
||||
* VS Code ensures that the persisted state is saved correctly when a webview is hidden and across
|
||||
* The editor ensures that the persisted state is saved correctly when a webview is hidden and across
|
||||
* editor restarts.
|
||||
*/
|
||||
readonly state: T | undefined;
|
||||
|
@ -7731,7 +7731,7 @@ declare module 'vscode' {
|
|||
* Provider for text based custom editors.
|
||||
*
|
||||
* Text based custom editors use a {@link TextDocument `TextDocument`} as their data model. This considerably simplifies
|
||||
* implementing a custom editor as it allows VS Code to handle many common operations such as
|
||||
* implementing a custom editor as it allows the editor to handle many common operations such as
|
||||
* undo and backup. The provider is responsible for synchronizing text changes between the webview and the `TextDocument`.
|
||||
*/
|
||||
export interface CustomTextEditorProvider {
|
||||
|
@ -7762,7 +7762,7 @@ declare module 'vscode' {
|
|||
* Represents a custom document used by a {@link CustomEditorProvider `CustomEditorProvider`}.
|
||||
*
|
||||
* Custom documents are only used within a given `CustomEditorProvider`. The lifecycle of a `CustomDocument` is
|
||||
* managed by VS Code. When no more references remain to a `CustomDocument`, it is disposed of.
|
||||
* managed by the editor. When no more references remain to a `CustomDocument`, it is disposed of.
|
||||
*/
|
||||
interface CustomDocument {
|
||||
/**
|
||||
|
@ -7773,14 +7773,14 @@ declare module 'vscode' {
|
|||
/**
|
||||
* Dispose of the custom document.
|
||||
*
|
||||
* This is invoked by VS Code when there are no more references to a given `CustomDocument` (for example when
|
||||
* This is invoked by the editor when there are no more references to a given `CustomDocument` (for example when
|
||||
* all editors associated with the document have been closed.)
|
||||
*/
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event triggered by extensions to signal to VS Code that an edit has occurred on an {@link CustomDocument `CustomDocument`}.
|
||||
* Event triggered by extensions to signal to the editor that an edit has occurred on an {@link CustomDocument `CustomDocument`}.
|
||||
*
|
||||
* @see {@link CustomEditorProvider.onDidChangeCustomDocument `CustomEditorProvider.onDidChangeCustomDocument`}.
|
||||
*/
|
||||
|
@ -7794,18 +7794,18 @@ declare module 'vscode' {
|
|||
/**
|
||||
* Undo the edit operation.
|
||||
*
|
||||
* This is invoked by VS Code when the user undoes this edit. To implement `undo`, your
|
||||
* This is invoked by the editor when the user undoes this edit. To implement `undo`, your
|
||||
* extension should restore the document and editor to the state they were in just before this
|
||||
* edit was added to VS Code's internal edit stack by `onDidChangeCustomDocument`.
|
||||
* edit was added to the editor's internal edit stack by `onDidChangeCustomDocument`.
|
||||
*/
|
||||
undo(): Thenable<void> | void;
|
||||
|
||||
/**
|
||||
* Redo the edit operation.
|
||||
*
|
||||
* This is invoked by VS Code when the user redoes this edit. To implement `redo`, your
|
||||
* This is invoked by the editor when the user redoes this edit. To implement `redo`, your
|
||||
* extension should restore the document and editor to the state they were in just after this
|
||||
* edit was added to VS Code's internal edit stack by `onDidChangeCustomDocument`.
|
||||
* edit was added to the editor's internal edit stack by `onDidChangeCustomDocument`.
|
||||
*/
|
||||
redo(): Thenable<void> | void;
|
||||
|
||||
|
@ -7818,7 +7818,7 @@ declare module 'vscode' {
|
|||
}
|
||||
|
||||
/**
|
||||
* Event triggered by extensions to signal to VS Code that the content of a {@link CustomDocument `CustomDocument`}
|
||||
* Event triggered by extensions to signal to the editor that the content of a {@link CustomDocument `CustomDocument`}
|
||||
* has changed.
|
||||
*
|
||||
* @see {@link CustomEditorProvider.onDidChangeCustomDocument `CustomEditorProvider.onDidChangeCustomDocument`}.
|
||||
|
@ -7844,7 +7844,7 @@ declare module 'vscode' {
|
|||
/**
|
||||
* Delete the current backup.
|
||||
*
|
||||
* This is called by VS Code when it is clear the current backup is no longer needed, such as when a new backup
|
||||
* This is called by the editor when it is clear the current backup is no longer needed, such as when a new backup
|
||||
* is made or when the file is saved.
|
||||
*/
|
||||
delete(): void;
|
||||
|
@ -7955,14 +7955,14 @@ declare module 'vscode' {
|
|||
* anything from changing some text, to cropping an image, to reordering a list. Your extension is free to
|
||||
* define what an edit is and what data is stored on each edit.
|
||||
*
|
||||
* Firing `onDidChange` causes VS Code to mark the editors as being dirty. This is cleared when the user either
|
||||
* Firing `onDidChange` causes the editors to be marked as being dirty. This is cleared when the user either
|
||||
* saves or reverts the file.
|
||||
*
|
||||
* Editors that support undo/redo must fire a `CustomDocumentEditEvent` whenever an edit happens. This allows
|
||||
* users to undo and redo the edit using VS Code's standard VS Code keyboard shortcuts. VS Code will also mark
|
||||
* users to undo and redo the edit using the editor's standard keyboard shortcuts. The editor will also mark
|
||||
* the editor as no longer being dirty if the user undoes all edits to the last saved state.
|
||||
*
|
||||
* Editors that support editing but cannot use VS Code's standard undo/redo mechanism must fire a `CustomDocumentContentChangeEvent`.
|
||||
* Editors that support editing but cannot use the editor's standard undo/redo mechanism must fire a `CustomDocumentContentChangeEvent`.
|
||||
* The only way for a user to clear the dirty state of an editor that does not support undo/redo is to either
|
||||
* `save` or `revert` the file.
|
||||
*
|
||||
|
@ -7973,7 +7973,7 @@ declare module 'vscode' {
|
|||
/**
|
||||
* Save a custom document.
|
||||
*
|
||||
* This method is invoked by VS Code when the user saves a custom editor. This can happen when the user
|
||||
* This method is invoked by the editor when the user saves a custom editor. This can happen when the user
|
||||
* triggers save while the custom editor is active, by commands such as `save all`, or by auto save if enabled.
|
||||
*
|
||||
* To implement `save`, the implementer must persist the custom editor. This usually means writing the
|
||||
|
@ -7990,7 +7990,7 @@ declare module 'vscode' {
|
|||
/**
|
||||
* Save a custom document to a different location.
|
||||
*
|
||||
* This method is invoked by VS Code when the user triggers 'save as' on a custom editor. The implementer must
|
||||
* This method is invoked by the editor when the user triggers 'save as' on a custom editor. The implementer must
|
||||
* persist the custom editor to `destination`.
|
||||
*
|
||||
* When the user accepts save as, the current editor is be replaced by an non-dirty editor for the newly saved file.
|
||||
|
@ -8006,8 +8006,8 @@ declare module 'vscode' {
|
|||
/**
|
||||
* Revert a custom document to its last saved state.
|
||||
*
|
||||
* This method is invoked by VS Code when the user triggers `File: Revert File` in a custom editor. (Note that
|
||||
* this is only used using VS Code's `File: Revert File` command and not on a `git revert` of the file).
|
||||
* This method is invoked by the editor when the user triggers `File: Revert File` in a custom editor. (Note that
|
||||
* this is only used using the editor's `File: Revert File` command and not on a `git revert` of the file).
|
||||
*
|
||||
* To implement `revert`, the implementer must make sure all editor instances (webviews) for `document`
|
||||
* are displaying the document in the same state is saved in. This usually means reloading the file from the
|
||||
|
@ -8025,7 +8025,7 @@ declare module 'vscode' {
|
|||
*
|
||||
* Backups are used for hot exit and to prevent data loss. Your `backup` method should persist the resource in
|
||||
* its current state, i.e. with the edits applied. Most commonly this means saving the resource to disk in
|
||||
* the `ExtensionContext.storagePath`. When VS Code reloads and your custom editor is opened for a resource,
|
||||
* the `ExtensionContext.storagePath`. When the editor reloads and your custom editor is opened for a resource,
|
||||
* your extension should first check to see if any backups exist for the resource. If there is a backup, your
|
||||
* extension should load the file contents from there instead of from the resource in the workspace.
|
||||
*
|
||||
|
@ -8039,7 +8039,7 @@ declare module 'vscode' {
|
|||
* @param cancellation Token that signals the current backup since a new backup is coming in. It is up to your
|
||||
* extension to decided how to respond to cancellation. If for example your extension is backing up a large file
|
||||
* in an operation that takes time to complete, your extension may decide to finish the ongoing backup rather
|
||||
* than cancelling it to ensure that VS Code has some valid backup.
|
||||
* than cancelling it to ensure that the editor has some valid backup.
|
||||
*/
|
||||
backupCustomDocument(document: T, context: CustomDocumentBackupContext, cancellation: CancellationToken): Thenable<CustomDocumentBackup>;
|
||||
}
|
||||
|
@ -8193,7 +8193,7 @@ declare module 'vscode' {
|
|||
*
|
||||
* If the extension is running remotely, this function automatically establishes a port forwarding tunnel
|
||||
* from the local machine to `target` on the remote and returns a local uri to the tunnel. The lifetime of
|
||||
* the port forwarding tunnel is managed by VS Code and the tunnel can be closed by the user.
|
||||
* the port forwarding tunnel is managed by the editor and the tunnel can be closed by the user.
|
||||
*
|
||||
* *Note* that uris passed through `openExternal` are automatically resolved and you should not call `asExternalUri` on them.
|
||||
*
|
||||
|
@ -9357,7 +9357,7 @@ declare module 'vscode' {
|
|||
cwd?: string | Uri;
|
||||
|
||||
/**
|
||||
* Object with environment variables that will be added to the VS Code process.
|
||||
* Object with environment variables that will be added to the editor process.
|
||||
*/
|
||||
env?: { [key: string]: string | null | undefined };
|
||||
|
||||
|
@ -10306,15 +10306,15 @@ declare module 'vscode' {
|
|||
|
||||
/**
|
||||
* Namespace for dealing with the current workspace. A workspace is the collection of one
|
||||
* or more folders that are opened in a VS Code window (instance).
|
||||
* or more folders that are opened in an editor window (instance).
|
||||
*
|
||||
* It is also possible to open VS Code without a workspace. For example, when you open a
|
||||
* new VS Code window by selecting a file from your platform's File menu, you will not be
|
||||
* inside a workspace. In this mode, some of VS Code's capabilities are reduced but you can
|
||||
* It is also possible to open an editor without a workspace. For example, when you open a
|
||||
* new editor window by selecting a file from your platform's File menu, you will not be
|
||||
* inside a workspace. In this mode, some of the editor's capabilities are reduced but you can
|
||||
* still open text files and edit them.
|
||||
*
|
||||
* Refer to https://code.visualstudio.com/docs/editor/workspaces for more information on
|
||||
* the concept of workspaces in VS Code.
|
||||
* the concept of workspaces.
|
||||
*
|
||||
* The workspace offers support for {@link workspace.createFileSystemWatcher listening} to fs
|
||||
* events and for {@link workspace.findFiles finding} files. Both perform well and run _outside_
|
||||
|
@ -10331,22 +10331,22 @@ declare module 'vscode' {
|
|||
export const fs: FileSystem;
|
||||
|
||||
/**
|
||||
* The workspace folder that is open in VS Code. `undefined` when no workspace
|
||||
* The workspace folder that is open in the editor. `undefined` when no workspace
|
||||
* has been opened.
|
||||
*
|
||||
* Refer to https://code.visualstudio.com/docs/editor/workspaces for more information
|
||||
* on workspaces in VS Code.
|
||||
* on workspaces.
|
||||
*
|
||||
* @deprecated Use {@link workspace.workspaceFolders `workspaceFolders`} instead.
|
||||
*/
|
||||
export const rootPath: string | undefined;
|
||||
|
||||
/**
|
||||
* List of workspace folders that are open in VS Code. `undefined` when no workspace
|
||||
* List of workspace folders that are open in the editor. `undefined` when no workspace
|
||||
* has been opened.
|
||||
*
|
||||
* Refer to https://code.visualstudio.com/docs/editor/workspaces for more information
|
||||
* on workspaces in VS Code.
|
||||
* on workspaces.
|
||||
*
|
||||
* *Note* that the first entry corresponds to the value of `rootPath`.
|
||||
*/
|
||||
|
@ -10357,7 +10357,7 @@ declare module 'vscode' {
|
|||
* has been opened.
|
||||
*
|
||||
* Refer to https://code.visualstudio.com/docs/editor/workspaces for more information on
|
||||
* the concept of workspaces in VS Code.
|
||||
* the concept of workspaces.
|
||||
*/
|
||||
export const name: string | undefined;
|
||||
|
||||
|
@ -10386,7 +10386,7 @@ declare module 'vscode' {
|
|||
* ```
|
||||
*
|
||||
* Refer to https://code.visualstudio.com/docs/editor/workspaces for more information on
|
||||
* the concept of workspaces in VS Code.
|
||||
* the concept of workspaces.
|
||||
*
|
||||
* **Note:** it is not advised to use `workspace.workspaceFile` to write
|
||||
* configuration data into the file. You can use `workspace.getConfiguration().update()`
|
||||
|
@ -11079,7 +11079,7 @@ declare module 'vscode' {
|
|||
|
||||
/**
|
||||
* Register a provider that locates evaluatable expressions in text documents.
|
||||
* VS Code will evaluate the expression in the active debug session and will show the result in the debug hover.
|
||||
* The editor will evaluate the expression in the active debug session and will show the result in the debug hover.
|
||||
*
|
||||
* If multiple providers are registered for a language an arbitrary provider will be used.
|
||||
*
|
||||
|
@ -11091,7 +11091,7 @@ declare module 'vscode' {
|
|||
|
||||
/**
|
||||
* Register a provider that returns data for the debugger's 'inline value' feature.
|
||||
* Whenever the generic VS Code debugger has stopped in a source file, providers registered for the language of the file
|
||||
* Whenever the generic debugger has stopped in a source file, providers registered for the language of the file
|
||||
* are called to return textual data that will be shown in the editor at the end of lines.
|
||||
*
|
||||
* Multiple providers can be registered for a language. In that case providers are asked in
|
||||
|
@ -12074,7 +12074,7 @@ declare module 'vscode' {
|
|||
* The command must be {@link commands.getCommands known}.
|
||||
*
|
||||
* Note that if this is a {@link Command `Command`} object, only the {@link Command.command `command`} and {@link Command.arguments `arguments`}
|
||||
* are used by VS Code.
|
||||
* are used by the editor.
|
||||
*/
|
||||
command?: string | Command;
|
||||
|
||||
|
@ -12496,10 +12496,10 @@ declare module 'vscode' {
|
|||
customRequest(command: string, args?: any): Thenable<any>;
|
||||
|
||||
/**
|
||||
* Maps a VS Code breakpoint to the corresponding Debug Adapter Protocol (DAP) breakpoint that is managed by the debug adapter of the debug session.
|
||||
* If no DAP breakpoint exists (either because the VS Code breakpoint was not yet registered or because the debug adapter is not interested in the breakpoint), the value `undefined` is returned.
|
||||
* Maps a breakpoint in the editor to the corresponding Debug Adapter Protocol (DAP) breakpoint that is managed by the debug adapter of the debug session.
|
||||
* If no DAP breakpoint exists (either because the editor breakpoint was not yet registered or because the debug adapter is not interested in the breakpoint), the value `undefined` is returned.
|
||||
*
|
||||
* @param breakpoint A VS Code {@link Breakpoint}.
|
||||
* @param breakpoint A {@link Breakpoint} in the editor.
|
||||
* @return A promise that resolves to the Debug Adapter Protocol breakpoint or `undefined`.
|
||||
*/
|
||||
getDebugProtocolBreakpoint(breakpoint: Breakpoint): Thenable<DebugProtocolBreakpoint | undefined>;
|
||||
|
@ -12588,7 +12588,7 @@ declare module 'vscode' {
|
|||
/**
|
||||
* The command or path of the debug adapter executable.
|
||||
* A command must be either an absolute path of an executable or the name of an command to be looked up via the PATH environment variable.
|
||||
* The special value 'node' will be mapped to VS Code's built-in Node.js runtime.
|
||||
* The special value 'node' will be mapped to the editor's built-in Node.js runtime.
|
||||
*/
|
||||
readonly command: string;
|
||||
|
||||
|
@ -12659,12 +12659,12 @@ declare module 'vscode' {
|
|||
}
|
||||
|
||||
/**
|
||||
* A debug adapter that implements the Debug Adapter Protocol can be registered with VS Code if it implements the DebugAdapter interface.
|
||||
* A debug adapter that implements the Debug Adapter Protocol can be registered with the editor if it implements the DebugAdapter interface.
|
||||
*/
|
||||
export interface DebugAdapter extends Disposable {
|
||||
|
||||
/**
|
||||
* An event which fires after the debug adapter has sent a Debug Adapter Protocol message to VS Code.
|
||||
* An event which fires after the debug adapter has sent a Debug Adapter Protocol message to the editor.
|
||||
* Messages can be requests, responses, or events.
|
||||
*/
|
||||
readonly onDidSendMessage: Event<DebugProtocolMessage>;
|
||||
|
@ -12713,7 +12713,7 @@ declare module 'vscode' {
|
|||
}
|
||||
|
||||
/**
|
||||
* A Debug Adapter Tracker is a means to track the communication between VS Code and a Debug Adapter.
|
||||
* A Debug Adapter Tracker is a means to track the communication between the editor and a Debug Adapter.
|
||||
*/
|
||||
export interface DebugAdapterTracker {
|
||||
/**
|
||||
|
@ -12721,11 +12721,11 @@ declare module 'vscode' {
|
|||
*/
|
||||
onWillStartSession?(): void;
|
||||
/**
|
||||
* The debug adapter is about to receive a Debug Adapter Protocol message from VS Code.
|
||||
* The debug adapter is about to receive a Debug Adapter Protocol message from the editor.
|
||||
*/
|
||||
onWillReceiveMessage?(message: any): void;
|
||||
/**
|
||||
* The debug adapter has sent a Debug Adapter Protocol message to VS Code.
|
||||
* The debug adapter has sent a Debug Adapter Protocol message to the editor.
|
||||
*/
|
||||
onDidSendMessage?(message: any): void;
|
||||
/**
|
||||
|
@ -12745,7 +12745,7 @@ declare module 'vscode' {
|
|||
export interface DebugAdapterTrackerFactory {
|
||||
/**
|
||||
* The method 'createDebugAdapterTracker' is called at the start of a debug session in order
|
||||
* to return a "tracker" object that provides read-access to the communication between VS Code and a debug adapter.
|
||||
* to return a "tracker" object that provides read-access to the communication between the editor and a debug adapter.
|
||||
*
|
||||
* @param session The {@link DebugSession debug session} for which the debug adapter tracker will be used.
|
||||
* @return A {@link DebugAdapterTracker debug adapter tracker} or undefined.
|
||||
|
@ -13036,7 +13036,7 @@ declare module 'vscode' {
|
|||
/**
|
||||
* Converts a "Source" descriptor object received via the Debug Adapter Protocol into a Uri that can be used to load its contents.
|
||||
* If the source descriptor is based on a path, a file Uri is returned.
|
||||
* If the source descriptor uses a reference number, a specific debug Uri (scheme 'debug') is constructed that requires a corresponding VS Code ContentProvider and a running debug session
|
||||
* If the source descriptor uses a reference number, a specific debug Uri (scheme 'debug') is constructed that requires a corresponding ContentProvider and a running debug session
|
||||
*
|
||||
* If the "Source" descriptor has insufficient information for creating the Uri, an error is thrown.
|
||||
*
|
||||
|
@ -13585,7 +13585,7 @@ declare module 'vscode' {
|
|||
* quickpick to select which account they would like to use.
|
||||
*
|
||||
* Currently, there are only two authentication providers that are contributed from built in extensions
|
||||
* to VS Code that implement GitHub and Microsoft authentication: their providerId's are 'github' and 'microsoft'.
|
||||
* to the editor that implement GitHub and Microsoft authentication: their providerId's are 'github' and 'microsoft'.
|
||||
* @param providerId The id of the provider to use
|
||||
* @param scopes A list of scopes representing the permissions requested. These are dependent on the authentication provider
|
||||
* @param options The {@link GetSessionOptions} to use
|
||||
|
@ -13600,7 +13600,7 @@ declare module 'vscode' {
|
|||
* quickpick to select which account they would like to use.
|
||||
*
|
||||
* Currently, there are only two authentication providers that are contributed from built in extensions
|
||||
* to VS Code that implement GitHub and Microsoft authentication: their providerId's are 'github' and 'microsoft'.
|
||||
* to the editor that implement GitHub and Microsoft authentication: their providerId's are 'github' and 'microsoft'.
|
||||
* @param providerId The id of the provider to use
|
||||
* @param scopes A list of scopes representing the permissions requested. These are dependent on the authentication provider
|
||||
* @param options The {@link GetSessionOptions} to use
|
||||
|
|
46
src/vs/vscode.proposed.d.ts
vendored
46
src/vs/vscode.proposed.d.ts
vendored
|
@ -9,7 +9,7 @@
|
|||
* distribution and CANNOT be used in published extensions.
|
||||
*
|
||||
* To test these API in local environment:
|
||||
* - Use Insiders release of VS Code.
|
||||
* - Use Insiders release of 'VS Code'.
|
||||
* - Add `"enableProposedApi": true` to your package.json.
|
||||
* - Copy this file to your project.
|
||||
*/
|
||||
|
@ -147,8 +147,8 @@ declare module 'vscode' {
|
|||
/**
|
||||
* Resolve the authority part of the current opened `vscode-remote://` URI.
|
||||
*
|
||||
* This method will be invoked once during the startup of VS Code and again each time
|
||||
* VS Code detects a disconnection.
|
||||
* This method will be invoked once during the startup of the editor and again each time
|
||||
* the editor detects a disconnection.
|
||||
*
|
||||
* @param authority The authority part of the current opened `vscode-remote://` URI.
|
||||
* @param context A context indicating if this is the first call or a subsequent call.
|
||||
|
@ -438,11 +438,11 @@ declare module 'vscode' {
|
|||
/**
|
||||
* Additional information regarding the state of the completed search.
|
||||
*
|
||||
* Messages with "Information" tyle support links in markdown syntax:
|
||||
* Messages with "Information" style support links in markdown syntax:
|
||||
* - Click to [run a command](command:workbench.action.OpenQuickPick)
|
||||
* - Click to [open a website](https://aka.ms)
|
||||
*
|
||||
* Commands may optionally return { triggerSearch: true } to signal to VS Code that the original search should run be agian.
|
||||
* Commands may optionally return { triggerSearch: true } to signal to the editor that the original search should run be again.
|
||||
*/
|
||||
message?: TextSearchCompleteMessage | TextSearchCompleteMessage[];
|
||||
}
|
||||
|
@ -553,7 +553,7 @@ declare module 'vscode' {
|
|||
/**
|
||||
* A FileSearchProvider provides search results for files in the given folder that match a query string. It can be invoked by quickopen or other extensions.
|
||||
*
|
||||
* A FileSearchProvider is the more powerful of two ways to implement file search in VS Code. Use a FileSearchProvider if you wish to search within a folder for
|
||||
* A FileSearchProvider is the more powerful of two ways to implement file search in the editor. Use a FileSearchProvider if you wish to search within a folder for
|
||||
* all files that match the user's query.
|
||||
*
|
||||
* The FileSearchProvider will be invoked on every keypress in quickopen. When `workspace.findFiles` is called, it will be invoked with an empty query string,
|
||||
|
@ -987,7 +987,7 @@ declare module 'vscode' {
|
|||
* Handle when the underlying resource for a custom editor is renamed.
|
||||
*
|
||||
* This allows the webview for the editor be preserved throughout the rename. If this method is not implemented,
|
||||
* VS Code will destory the previous custom editor and create a replacement one.
|
||||
* the editor will destroy the previous custom editor and create a replacement one.
|
||||
*
|
||||
* @param newDocument New text document to use for the custom editor.
|
||||
* @param existingWebviewPanel Webview panel for the custom editor.
|
||||
|
@ -1352,7 +1352,7 @@ declare module 'vscode' {
|
|||
/**
|
||||
* Delete the current backup.
|
||||
*
|
||||
* This is called by VS Code when it is clear the current backup is no longer needed, such as when a new backup
|
||||
* This is called by the editor when it is clear the current backup is no longer needed, such as when a new backup
|
||||
* is made or when the file is saved.
|
||||
*/
|
||||
delete(): void;
|
||||
|
@ -1884,7 +1884,7 @@ declare module 'vscode' {
|
|||
* disambiguate multiple sets of results in a test run. It is useful if
|
||||
* tests are run across multiple platforms, for example.
|
||||
* @param persist Whether the results created by the run should be
|
||||
* persisted in VS Code. This may be false if the results are coming from
|
||||
* persisted in the editor. This may be false if the results are coming from
|
||||
* a file already saved externally, such as a coverage information file.
|
||||
*/
|
||||
export function createTestRun<T>(request: TestRunRequest<T>, name?: string, persist?: boolean): TestRun<T>;
|
||||
|
@ -1903,7 +1903,7 @@ declare module 'vscode' {
|
|||
export function createTestItem<T = void, TChildren = any>(options: TestItemOptions): TestItem<T, TChildren>;
|
||||
|
||||
/**
|
||||
* List of test results stored by VS Code, sorted in descnding
|
||||
* List of test results stored by the editor, sorted in descending
|
||||
* order by their `completedAt` time.
|
||||
* @stability experimental
|
||||
*/
|
||||
|
@ -1943,7 +1943,7 @@ declare module 'vscode' {
|
|||
readonly onDidDiscoverInitialTests: Event<void>;
|
||||
|
||||
/**
|
||||
* Dispose of the observer, allowing VS Code to eventually tell test
|
||||
* Dispose of the observer, allowing the editor to eventually tell test
|
||||
* providers that they no longer need to update tests.
|
||||
*/
|
||||
dispose(): void;
|
||||
|
@ -2030,7 +2030,7 @@ declare module 'vscode' {
|
|||
tests: TestItem<T>[];
|
||||
|
||||
/**
|
||||
* An array of tests the user has marked as excluded in VS Code. May be
|
||||
* An array of tests the user has marked as excluded in the editor. May be
|
||||
* omitted if no exclusions were requested. Test controllers should not run
|
||||
* excluded tests or any children of excluded tests.
|
||||
*/
|
||||
|
@ -2334,7 +2334,7 @@ declare module 'vscode' {
|
|||
}
|
||||
|
||||
/**
|
||||
* TestResults can be provided to VS Code in {@link test.publishTestResult},
|
||||
* TestResults can be provided to the editor in {@link test.publishTestResult},
|
||||
* or read from it in {@link test.testResults}.
|
||||
*
|
||||
* The results contain a 'snapshot' of the tests at the point when the test
|
||||
|
@ -2437,7 +2437,7 @@ declare module 'vscode' {
|
|||
* if an opener should be selected automatically or if the user should be prompted to
|
||||
* select an opener.
|
||||
*
|
||||
* VS Code will try to use the best available opener, as sorted by `ExternalUriOpenerPriority`.
|
||||
* The editor will try to use the best available opener, as sorted by `ExternalUriOpenerPriority`.
|
||||
* If there are multiple potential "best" openers for a URI, then the user will be prompted
|
||||
* to select an opener.
|
||||
*/
|
||||
|
@ -2452,21 +2452,21 @@ declare module 'vscode' {
|
|||
|
||||
/**
|
||||
* The opener can open the uri but will not cause a prompt on its own
|
||||
* since VS Code always contributes a built-in `Default` opener.
|
||||
* since the editor always contributes a built-in `Default` opener.
|
||||
*/
|
||||
Option = 1,
|
||||
|
||||
/**
|
||||
* The opener can open the uri.
|
||||
*
|
||||
* VS Code's built-in opener has `Default` priority. This means that any additional `Default`
|
||||
* The editor's built-in opener has `Default` priority. This means that any additional `Default`
|
||||
* openers will cause the user to be prompted to select from a list of all potential openers.
|
||||
*/
|
||||
Default = 2,
|
||||
|
||||
/**
|
||||
* The opener can open the uri and should be automatically selected over any
|
||||
* default openers, include the built-in one from VS Code.
|
||||
* default openers, include the built-in one from the editor.
|
||||
*
|
||||
* A preferred opener will be automatically selected if no other preferred openers
|
||||
* are available. If multiple preferred openers are available, then the user
|
||||
|
@ -2479,7 +2479,7 @@ declare module 'vscode' {
|
|||
* Handles opening uris to external resources, such as http(s) links.
|
||||
*
|
||||
* Extensions can implement an `ExternalUriOpener` to open `http` links to a webserver
|
||||
* inside of VS Code instead of having the link be opened by the web browser.
|
||||
* inside of the editor instead of having the link be opened by the web browser.
|
||||
*
|
||||
* Currently openers may only be registered for `http` and `https` uris.
|
||||
*/
|
||||
|
@ -2570,11 +2570,11 @@ declare module 'vscode' {
|
|||
* Allows using openers contributed by extensions through `registerExternalUriOpener`
|
||||
* when opening the resource.
|
||||
*
|
||||
* If `true`, VS Code will check if any contributed openers can handle the
|
||||
* If `true`, the editor will check if any contributed openers can handle the
|
||||
* uri, and fallback to the default opener behavior.
|
||||
*
|
||||
* If it is string, this specifies the id of the `ExternalUriOpener`
|
||||
* that should be used if it is available. Use `'default'` to force VS Code's
|
||||
* that should be used if it is available. Use `'default'` to force the editor's
|
||||
* standard external opener to be used.
|
||||
*/
|
||||
readonly allowContributedOpeners?: boolean | string;
|
||||
|
@ -2603,7 +2603,7 @@ declare module 'vscode' {
|
|||
*
|
||||
* If the extension is running remotely, this function automatically establishes a port forwarding tunnel
|
||||
* from the local machine to `target` on the remote and returns a local uri to the tunnel. The lifetime of
|
||||
* the port forwarding tunnel is managed by VS Code and the tunnel can be closed by the user.
|
||||
* the port forwarding tunnel is managed by the editor and the tunnel can be closed by the user.
|
||||
*
|
||||
* *Note* that uris passed through `openExternal` are automatically resolved and you should not call `asExternalUri` on them.
|
||||
*
|
||||
|
@ -2640,7 +2640,7 @@ declare module 'vscode' {
|
|||
* #### Any other scheme
|
||||
*
|
||||
* Any other scheme will be handled as if the provided URI is a workspace URI. In that case, the method will return
|
||||
* a URI which, when handled, will make VS Code open the workspace.
|
||||
* a URI which, when handled, will make the editor open the workspace.
|
||||
*
|
||||
* @return A uri that can be used on the client machine.
|
||||
*/
|
||||
|
@ -2732,7 +2732,7 @@ declare module 'vscode' {
|
|||
/**
|
||||
* If your extension listens on ports, consider registering a PortAttributesProvider to provide information
|
||||
* about the ports. For example, a debug extension may know about debug ports in it's debuggee. By providing
|
||||
* this information with a PortAttributesProvider the extension can tell VS Code that these ports should be
|
||||
* this information with a PortAttributesProvider the extension can tell the editor that these ports should be
|
||||
* ignored, since they don't need to be user facing.
|
||||
*
|
||||
* @param portSelector If registerPortAttributesProvider is called after you start your process then you may already
|
||||
|
|
|
@ -1385,7 +1385,8 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
|||
}
|
||||
}
|
||||
|
||||
await this._webview!.initializeMarkdown(requests.map(request => ({
|
||||
await this._webview!.initializeMarkup(requests.map(request => ({
|
||||
mime: 'text/markdown',
|
||||
cellId: request[0].id,
|
||||
cellHandle: request[0].handle,
|
||||
content: request[0].getText(),
|
||||
|
@ -1393,8 +1394,10 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
|||
visible: false,
|
||||
})));
|
||||
} else {
|
||||
const initRequests = viewModel.viewCells.filter(cell => cell.cellKind === CellKind.Markup).slice(0, 5).map(cell => ({ cellId: cell.id, cellHandle: cell.handle, content: cell.getText(), offset: -10000, visible: false }));
|
||||
await this._webview!.initializeMarkdown(initRequests);
|
||||
const initRequests = viewModel.viewCells.filter(cell => cell.cellKind === CellKind.Markup).slice(0, 5).map(cell => ({
|
||||
cellId: cell.id, cellHandle: cell.handle, content: cell.getText(), offset: -10000, visible: false, mime: 'text/markdown',
|
||||
}));
|
||||
await this._webview!.initializeMarkup(initRequests);
|
||||
|
||||
// no cached view state so we are rendering the first viewport
|
||||
// after above async call, we already get init height for markdown cells, we can update their offset
|
||||
|
@ -2261,6 +2264,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
|||
|
||||
const cellTop = this._list.getAbsoluteTopOfElement(cell);
|
||||
await this._webview.showMarkdownPreview({
|
||||
mime: 'text/markdown',
|
||||
cellHandle: cell.handle,
|
||||
cellId: cell.id,
|
||||
content: cell.getText(),
|
||||
|
|
|
@ -26,7 +26,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
|||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { asWebviewUri } from 'vs/workbench/api/common/shared/webview';
|
||||
import { CellEditState, ICellOutputViewModel, ICommonCellInfo, ICommonNotebookEditor, IDisplayOutputLayoutUpdateRequest, IDisplayOutputViewModel, IGenericCellViewModel, IInsetRenderOutput, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||
import { PreloadOptions, preloadsScriptStr, RendererMetadata } from 'vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads';
|
||||
import { preloadsScriptStr, RendererMetadata } from 'vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads';
|
||||
import { transformWebviewThemeVars } from 'vs/workbench/contrib/notebook/browser/view/renderers/webviewThemeMapping';
|
||||
import { MarkdownCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/markdownCellViewModel';
|
||||
import { INotebookKernel, INotebookRendererInfo, RendererMessagingSpec } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
|
@ -34,368 +34,7 @@ import { IScopedRendererMessaging } from 'vs/workbench/contrib/notebook/common/n
|
|||
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
|
||||
import { IWebviewService, WebviewContentPurpose, WebviewElement } from 'vs/workbench/contrib/webview/browser/webview';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
|
||||
interface BaseToWebviewMessage {
|
||||
readonly __vscode_notebook_message: true;
|
||||
}
|
||||
|
||||
export interface WebviewIntialized extends BaseToWebviewMessage {
|
||||
type: 'initialized';
|
||||
}
|
||||
|
||||
export interface DimensionUpdate {
|
||||
id: string;
|
||||
init?: boolean;
|
||||
height: number;
|
||||
isOutput?: boolean;
|
||||
}
|
||||
|
||||
export interface IDimensionMessage extends BaseToWebviewMessage {
|
||||
type: 'dimension';
|
||||
updates: readonly DimensionUpdate[];
|
||||
}
|
||||
|
||||
export interface IMouseEnterMessage extends BaseToWebviewMessage {
|
||||
type: 'mouseenter';
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface IMouseLeaveMessage extends BaseToWebviewMessage {
|
||||
type: 'mouseleave';
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface IOutputFocusMessage extends BaseToWebviewMessage {
|
||||
type: 'outputFocus';
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface IOutputBlurMessage extends BaseToWebviewMessage {
|
||||
type: 'outputBlur';
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface IWheelMessage extends BaseToWebviewMessage {
|
||||
type: 'did-scroll-wheel';
|
||||
payload: any;
|
||||
}
|
||||
|
||||
export interface IScrollAckMessage extends BaseToWebviewMessage {
|
||||
type: 'scroll-ack';
|
||||
data: { top: number };
|
||||
version: number;
|
||||
}
|
||||
|
||||
export interface IBlurOutputMessage extends BaseToWebviewMessage {
|
||||
type: 'focus-editor';
|
||||
id: string;
|
||||
focusNext?: boolean;
|
||||
}
|
||||
|
||||
export interface IClickedDataUrlMessage extends BaseToWebviewMessage {
|
||||
type: 'clicked-data-url';
|
||||
data: string | ArrayBuffer | null;
|
||||
downloadName?: string;
|
||||
}
|
||||
|
||||
export interface IClickMarkdownPreviewMessage extends BaseToWebviewMessage {
|
||||
readonly type: 'clickMarkdownPreview';
|
||||
readonly cellId: string;
|
||||
readonly ctrlKey: boolean
|
||||
readonly altKey: boolean;
|
||||
readonly metaKey: boolean;
|
||||
readonly shiftKey: boolean;
|
||||
}
|
||||
|
||||
export interface IContextMenuMarkdownPreviewMessage extends BaseToWebviewMessage {
|
||||
readonly type: 'contextMenuMarkdownPreview';
|
||||
readonly cellId: string;
|
||||
readonly clientX: number;
|
||||
readonly clientY: number;
|
||||
}
|
||||
|
||||
export interface IMouseEnterMarkdownPreviewMessage extends BaseToWebviewMessage {
|
||||
type: 'mouseEnterMarkdownPreview';
|
||||
cellId: string;
|
||||
}
|
||||
|
||||
export interface IMouseLeaveMarkdownPreviewMessage extends BaseToWebviewMessage {
|
||||
type: 'mouseLeaveMarkdownPreview';
|
||||
cellId: string;
|
||||
}
|
||||
|
||||
export interface IToggleMarkdownPreviewMessage extends BaseToWebviewMessage {
|
||||
type: 'toggleMarkdownPreview';
|
||||
cellId: string;
|
||||
}
|
||||
|
||||
export interface ICellDragStartMessage extends BaseToWebviewMessage {
|
||||
type: 'cell-drag-start';
|
||||
readonly cellId: string;
|
||||
readonly dragOffsetY: number;
|
||||
}
|
||||
|
||||
export interface ICellDragMessage extends BaseToWebviewMessage {
|
||||
type: 'cell-drag';
|
||||
readonly cellId: string;
|
||||
readonly dragOffsetY: number;
|
||||
}
|
||||
|
||||
export interface ICellDropMessage extends BaseToWebviewMessage {
|
||||
readonly type: 'cell-drop';
|
||||
readonly cellId: string;
|
||||
readonly ctrlKey: boolean
|
||||
readonly altKey: boolean;
|
||||
readonly dragOffsetY: number;
|
||||
}
|
||||
|
||||
export interface ICellDragEndMessage extends BaseToWebviewMessage {
|
||||
readonly type: 'cell-drag-end';
|
||||
readonly cellId: string;
|
||||
}
|
||||
|
||||
export interface IInitializedMarkdownPreviewMessage extends BaseToWebviewMessage {
|
||||
readonly type: 'initializedMarkdownPreview';
|
||||
}
|
||||
|
||||
export interface ITelemetryFoundRenderedMarkdownMath extends BaseToWebviewMessage {
|
||||
readonly type: 'telemetryFoundRenderedMarkdownMath';
|
||||
}
|
||||
|
||||
export interface ITelemetryFoundUnrenderedMarkdownMath extends BaseToWebviewMessage {
|
||||
readonly type: 'telemetryFoundUnrenderedMarkdownMath';
|
||||
readonly latexDirective: string;
|
||||
}
|
||||
|
||||
export interface IClearMessage {
|
||||
type: 'clear';
|
||||
}
|
||||
|
||||
export interface IOutputRequestMetadata {
|
||||
/**
|
||||
* Additional attributes of a cell metadata.
|
||||
*/
|
||||
custom?: { [key: string]: unknown };
|
||||
}
|
||||
|
||||
export interface IOutputRequestDto {
|
||||
/**
|
||||
* { mime_type: value }
|
||||
*/
|
||||
data: { [key: string]: unknown; }
|
||||
|
||||
metadata?: IOutputRequestMetadata;
|
||||
outputId: string;
|
||||
}
|
||||
|
||||
export interface ICreationRequestMessage {
|
||||
type: 'html';
|
||||
content:
|
||||
| { type: RenderOutputType.Html; htmlContent: string }
|
||||
| { type: RenderOutputType.Extension; outputId: string; valueBytes: Uint8Array, metadata: unknown; metadata2: unknown, mimeType: string };
|
||||
cellId: string;
|
||||
outputId: string;
|
||||
cellTop: number;
|
||||
outputOffset: number;
|
||||
left: number;
|
||||
requiredPreloads: ReadonlyArray<IControllerPreload>;
|
||||
readonly initiallyHidden?: boolean;
|
||||
rendererId?: string | undefined;
|
||||
}
|
||||
|
||||
export interface IContentWidgetTopRequest {
|
||||
outputId: string;
|
||||
cellTop: number;
|
||||
outputOffset: number;
|
||||
forceDisplay: boolean;
|
||||
}
|
||||
|
||||
export interface IViewScrollTopRequestMessage {
|
||||
type: 'view-scroll';
|
||||
widgets: IContentWidgetTopRequest[];
|
||||
markdownPreviews: { id: string; top: number }[];
|
||||
}
|
||||
|
||||
export interface IScrollRequestMessage {
|
||||
type: 'scroll';
|
||||
id: string;
|
||||
top: number;
|
||||
widgetTop?: number;
|
||||
version: number;
|
||||
}
|
||||
|
||||
export interface IClearOutputRequestMessage {
|
||||
type: 'clearOutput';
|
||||
cellId: string;
|
||||
outputId: string;
|
||||
cellUri: string;
|
||||
rendererId: string | undefined;
|
||||
}
|
||||
|
||||
export interface IHideOutputMessage {
|
||||
type: 'hideOutput';
|
||||
outputId: string;
|
||||
cellId: string;
|
||||
}
|
||||
|
||||
export interface IShowOutputMessage {
|
||||
type: 'showOutput';
|
||||
cellId: string;
|
||||
outputId: string;
|
||||
cellTop: number;
|
||||
outputOffset: number;
|
||||
}
|
||||
|
||||
export interface IFocusOutputMessage {
|
||||
type: 'focus-output';
|
||||
cellId: string;
|
||||
}
|
||||
|
||||
export interface IAckOutputHeightMessage {
|
||||
type: 'ack-dimension',
|
||||
cellId: string;
|
||||
outputId: string;
|
||||
height: number;
|
||||
}
|
||||
|
||||
|
||||
export interface IControllerPreload {
|
||||
originalUri: string;
|
||||
uri: string;
|
||||
}
|
||||
|
||||
export interface IUpdateControllerPreloadsMessage {
|
||||
type: 'preload';
|
||||
resources: IControllerPreload[];
|
||||
}
|
||||
|
||||
export interface IUpdateDecorationsMessage {
|
||||
type: 'decorations';
|
||||
cellId: string;
|
||||
addedClassNames: string[];
|
||||
removedClassNames: string[];
|
||||
}
|
||||
|
||||
export interface ICustomKernelMessage extends BaseToWebviewMessage {
|
||||
type: 'customKernelMessage';
|
||||
message: unknown;
|
||||
}
|
||||
|
||||
export interface ICustomRendererMessage extends BaseToWebviewMessage {
|
||||
type: 'customRendererMessage';
|
||||
rendererId: string;
|
||||
message: unknown;
|
||||
}
|
||||
|
||||
export interface ICreateMarkdownMessage {
|
||||
type: 'createMarkdownPreview',
|
||||
cell: IMarkdownCellInitialization;
|
||||
}
|
||||
export interface IDeleteMarkdownMessage {
|
||||
type: 'deleteMarkdownPreview',
|
||||
ids: readonly string[];
|
||||
}
|
||||
|
||||
export interface IHideMarkdownMessage {
|
||||
type: 'hideMarkdownPreviews';
|
||||
ids: readonly string[];
|
||||
}
|
||||
|
||||
export interface IUnhideMarkdownMessage {
|
||||
type: 'unhideMarkdownPreviews';
|
||||
ids: readonly string[];
|
||||
}
|
||||
|
||||
export interface IShowMarkdownMessage {
|
||||
type: 'showMarkdownPreview',
|
||||
id: string;
|
||||
handle: number;
|
||||
content: string | undefined;
|
||||
top: number;
|
||||
}
|
||||
|
||||
export interface IUpdateSelectedMarkdownPreviews {
|
||||
readonly type: 'updateSelectedMarkdownPreviews',
|
||||
readonly selectedCellIds: readonly string[]
|
||||
}
|
||||
|
||||
export interface IMarkdownCellInitialization {
|
||||
cellId: string;
|
||||
cellHandle: number;
|
||||
content: string;
|
||||
offset: number;
|
||||
visible: boolean;
|
||||
}
|
||||
|
||||
export interface IInitializeMarkdownMessage {
|
||||
type: 'initializeMarkdownPreview';
|
||||
cells: ReadonlyArray<IMarkdownCellInitialization>;
|
||||
}
|
||||
|
||||
export interface INotebookStylesMessage {
|
||||
type: 'notebookStyles';
|
||||
styles: {
|
||||
[key: string]: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface INotebookOptionsMessage {
|
||||
type: 'notebookOptions';
|
||||
options: PreloadOptions;
|
||||
}
|
||||
|
||||
export type FromWebviewMessage =
|
||||
| WebviewIntialized
|
||||
| IDimensionMessage
|
||||
| IMouseEnterMessage
|
||||
| IMouseLeaveMessage
|
||||
| IOutputFocusMessage
|
||||
| IOutputBlurMessage
|
||||
| IWheelMessage
|
||||
| IScrollAckMessage
|
||||
| IBlurOutputMessage
|
||||
| ICustomKernelMessage
|
||||
| ICustomRendererMessage
|
||||
| IClickedDataUrlMessage
|
||||
| IClickMarkdownPreviewMessage
|
||||
| IContextMenuMarkdownPreviewMessage
|
||||
| IMouseEnterMarkdownPreviewMessage
|
||||
| IMouseLeaveMarkdownPreviewMessage
|
||||
| IToggleMarkdownPreviewMessage
|
||||
| ICellDragStartMessage
|
||||
| ICellDragMessage
|
||||
| ICellDropMessage
|
||||
| ICellDragEndMessage
|
||||
| IInitializedMarkdownPreviewMessage
|
||||
| ITelemetryFoundRenderedMarkdownMath
|
||||
| ITelemetryFoundUnrenderedMarkdownMath
|
||||
;
|
||||
|
||||
export type ToWebviewMessage =
|
||||
| IClearMessage
|
||||
| IFocusOutputMessage
|
||||
| IAckOutputHeightMessage
|
||||
| ICreationRequestMessage
|
||||
| IViewScrollTopRequestMessage
|
||||
| IScrollRequestMessage
|
||||
| IClearOutputRequestMessage
|
||||
| IHideOutputMessage
|
||||
| IShowOutputMessage
|
||||
| IUpdateControllerPreloadsMessage
|
||||
| IUpdateDecorationsMessage
|
||||
| ICustomKernelMessage
|
||||
| ICustomRendererMessage
|
||||
| ICreateMarkdownMessage
|
||||
| IDeleteMarkdownMessage
|
||||
| IShowMarkdownMessage
|
||||
| IHideMarkdownMessage
|
||||
| IUnhideMarkdownMessage
|
||||
| IUpdateSelectedMarkdownPreviews
|
||||
| IInitializeMarkdownMessage
|
||||
| INotebookStylesMessage
|
||||
| INotebookOptionsMessage;
|
||||
|
||||
export type AnyMessage = FromWebviewMessage | ToWebviewMessage;
|
||||
import { ICreationRequestMessage, IMarkupCellInitialization, FromWebviewMessage, IClickedDataUrlMessage, IContentWidgetTopRequest, IControllerPreload, ToWebviewMessage } from './webviewMessages';
|
||||
|
||||
export interface ICachedInset<K extends ICommonCellInfo> {
|
||||
outputId: string;
|
||||
|
@ -424,7 +63,7 @@ export class BackLayerWebView<T extends ICommonCellInfo> extends Disposable {
|
|||
element: HTMLElement;
|
||||
webview: WebviewElement | undefined = undefined;
|
||||
insetMapping: Map<IDisplayOutputViewModel, ICachedInset<T>> = new Map();
|
||||
readonly markdownPreviewMapping = new Map<string, IMarkdownCellInitialization>();
|
||||
readonly markdownPreviewMapping = new Map<string, IMarkupCellInitialization>();
|
||||
hiddenInsetMapping: Set<IDisplayOutputViewModel> = new Set();
|
||||
reversedInsetMapping: Map<string, IDisplayOutputViewModel> = new Map();
|
||||
localResourceRootsCache: URI[] | undefined = undefined;
|
||||
|
@ -525,7 +164,8 @@ export class BackLayerWebView<T extends ICommonCellInfo> extends Disposable {
|
|||
'notebook-markdown-left-margin': `${this.options.markdownLeftMargin}px`,
|
||||
'notebook-output-node-left-padding': `${this.options.outputNodeLeftPadding}px`,
|
||||
'notebook-markdown-min-height': `${this.options.previewNodePadding * 2}px`,
|
||||
'notebook-cell-output-font-size': `${this.options.fontSize}px`
|
||||
'notebook-cell-output-font-size': `${this.options.fontSize}px`,
|
||||
'notebook-cell-markup-empty-content': nls.localize('notebook.emptyMarkdownPlaceholder', "Empty markdown cell, double click or press enter to edit."),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -536,133 +176,6 @@ export class BackLayerWebView<T extends ICommonCellInfo> extends Disposable {
|
|||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<base href="${baseUrl}/"/>
|
||||
|
||||
<!--
|
||||
Markdown previews are rendered using a shadow dom and are not effected by normal css.
|
||||
Insert this style node into all preview shadow doms for styling.
|
||||
-->
|
||||
<template id="preview-styles">
|
||||
<style>
|
||||
img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a:focus,
|
||||
input:focus,
|
||||
select:focus,
|
||||
textarea:focus {
|
||||
outline: 1px solid -webkit-focus-ring-color;
|
||||
outline-offset: -1px;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 0;
|
||||
height: 2px;
|
||||
border-bottom: 2px solid;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 26px;
|
||||
line-height: 31px;
|
||||
margin: 0;
|
||||
margin-bottom: 13px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 19px;
|
||||
margin: 0;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3 {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
div {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Adjust margin of first item in markdown cell */
|
||||
*:first-child {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
/* h1 tags don't need top margin */
|
||||
h1:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
/* Removes bottom margin when only one item exists in markdown cell */
|
||||
*:only-child,
|
||||
*:last-child {
|
||||
margin-bottom: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
/* makes all markdown cells consistent */
|
||||
div {
|
||||
min-height: var(--notebook-markdown-min-height);
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
table th,
|
||||
table td {
|
||||
border: 1px solid;
|
||||
}
|
||||
|
||||
table > thead > tr > th {
|
||||
text-align: left;
|
||||
border-bottom: 1px solid;
|
||||
}
|
||||
|
||||
table > thead > tr > th,
|
||||
table > thead > tr > td,
|
||||
table > tbody > tr > th,
|
||||
table > tbody > tr > td {
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
table > tbody > tr + tr > td {
|
||||
border-top: 1px solid;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 0 7px 0 5px;
|
||||
padding: 0 16px 0 10px;
|
||||
border-left-width: 5px;
|
||||
border-left-style: solid;
|
||||
}
|
||||
|
||||
code,
|
||||
.code {
|
||||
font-size: 1em;
|
||||
line-height: 1.357em;
|
||||
}
|
||||
|
||||
.code {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
dragging {
|
||||
background-color: var(--theme-background);
|
||||
}
|
||||
</style>
|
||||
</template>
|
||||
<style>
|
||||
#container .cell_container {
|
||||
width: 100%;
|
||||
|
@ -706,12 +219,6 @@ export class BackLayerWebView<T extends ICommonCellInfo> extends Disposable {
|
|||
cursor: grab;
|
||||
}
|
||||
|
||||
#container > div.preview.emptyMarkdownCell::before {
|
||||
content: "${nls.localize('notebook.emptyMarkdownPlaceholder', "Empty markdown cell, double click or press enter to edit.")}";
|
||||
font-style: italic;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
#container > div.preview.selected {
|
||||
background: var(--theme-notebook-cell-selected-background);
|
||||
}
|
||||
|
@ -1048,7 +555,7 @@ var requirejs = (function() {
|
|||
this.rendererMessaging?.postMessage(data.rendererId, data.message);
|
||||
break;
|
||||
}
|
||||
case 'clickMarkdownPreview':
|
||||
case 'clickMarkupCell':
|
||||
{
|
||||
const cell = this.notebookEditor.getCellById(data.cellId);
|
||||
if (cell) {
|
||||
|
@ -1062,7 +569,7 @@ var requirejs = (function() {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case 'contextMenuMarkdownPreview':
|
||||
case 'contextMenuMarkupCell':
|
||||
{
|
||||
const cell = this.notebookEditor.getCellById(data.cellId);
|
||||
if (cell) {
|
||||
|
@ -1087,7 +594,7 @@ var requirejs = (function() {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case 'toggleMarkdownPreview':
|
||||
case 'toggleMarkupPreview':
|
||||
{
|
||||
const cell = this.notebookEditor.getCellById(data.cellId);
|
||||
if (cell) {
|
||||
|
@ -1096,7 +603,7 @@ var requirejs = (function() {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case 'mouseEnterMarkdownPreview':
|
||||
case 'mouseEnterMarkupCell':
|
||||
{
|
||||
const cell = this.notebookEditor.getCellById(data.cellId);
|
||||
if (cell instanceof MarkdownCellViewModel) {
|
||||
|
@ -1104,7 +611,7 @@ var requirejs = (function() {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case 'mouseLeaveMarkdownPreview':
|
||||
case 'mouseLeaveMarkupCell':
|
||||
{
|
||||
const cell = this.notebookEditor.getCellById(data.cellId);
|
||||
if (cell instanceof MarkdownCellViewModel) {
|
||||
|
@ -1245,7 +752,7 @@ var requirejs = (function() {
|
|||
|
||||
const mdCells = [...this.markdownPreviewMapping.values()];
|
||||
this.markdownPreviewMapping.clear();
|
||||
this.initializeMarkdown(mdCells);
|
||||
this.initializeMarkup(mdCells);
|
||||
this._updateStyles();
|
||||
this._updateOptions();
|
||||
}
|
||||
|
@ -1323,7 +830,7 @@ var requirejs = (function() {
|
|||
});
|
||||
}
|
||||
|
||||
private async createMarkdownPreview(initialization: IMarkdownCellInitialization) {
|
||||
private async createMarkdownPreview(initialization: IMarkupCellInitialization) {
|
||||
if (this._disposed) {
|
||||
return;
|
||||
}
|
||||
|
@ -1335,12 +842,12 @@ var requirejs = (function() {
|
|||
|
||||
this.markdownPreviewMapping.set(initialization.cellId, initialization);
|
||||
this._sendMessageToWebview({
|
||||
type: 'createMarkdownPreview',
|
||||
type: 'createMarkupCell',
|
||||
cell: initialization
|
||||
});
|
||||
}
|
||||
|
||||
async showMarkdownPreview(initialization: IMarkdownCellInitialization) {
|
||||
async showMarkdownPreview(initialization: IMarkupCellInitialization) {
|
||||
if (this._disposed) {
|
||||
return;
|
||||
}
|
||||
|
@ -1353,7 +860,7 @@ var requirejs = (function() {
|
|||
const sameContent = initialization.content === entry.content;
|
||||
if (!sameContent || !entry.visible) {
|
||||
this._sendMessageToWebview({
|
||||
type: 'showMarkdownPreview',
|
||||
type: 'showMarkupCell',
|
||||
id: initialization.cellId,
|
||||
handle: initialization.cellHandle,
|
||||
// If the content has not changed, we still want to make sure the
|
||||
|
@ -1386,7 +893,7 @@ var requirejs = (function() {
|
|||
|
||||
if (cellsToHide.length) {
|
||||
this._sendMessageToWebview({
|
||||
type: 'hideMarkdownPreviews',
|
||||
type: 'hideMarkupCells',
|
||||
ids: cellsToHide
|
||||
});
|
||||
}
|
||||
|
@ -1411,7 +918,7 @@ var requirejs = (function() {
|
|||
}
|
||||
|
||||
this._sendMessageToWebview({
|
||||
type: 'unhideMarkdownPreviews',
|
||||
type: 'unhideMarkupCells',
|
||||
ids: toUnhide,
|
||||
});
|
||||
}
|
||||
|
@ -1430,7 +937,7 @@ var requirejs = (function() {
|
|||
|
||||
if (cellIds.length) {
|
||||
this._sendMessageToWebview({
|
||||
type: 'deleteMarkdownPreview',
|
||||
type: 'deleteMarkupCell',
|
||||
ids: cellIds
|
||||
});
|
||||
}
|
||||
|
@ -1442,12 +949,12 @@ var requirejs = (function() {
|
|||
}
|
||||
|
||||
this._sendMessageToWebview({
|
||||
type: 'updateSelectedMarkdownPreviews',
|
||||
type: 'updateSelectedMarkupCells',
|
||||
selectedCellIds: selectedCellsIds.filter(id => this.markdownPreviewMapping.has(id)),
|
||||
});
|
||||
}
|
||||
|
||||
async initializeMarkdown(cells: ReadonlyArray<IMarkdownCellInitialization>) {
|
||||
async initializeMarkup(cells: readonly IMarkupCellInitialization[]) {
|
||||
if (this._disposed) {
|
||||
return;
|
||||
}
|
||||
|
@ -1455,7 +962,7 @@ var requirejs = (function() {
|
|||
// TODO: use proper handler
|
||||
const p = new Promise<void>(resolve => {
|
||||
this.webview?.onMessage(e => {
|
||||
if (e.message.type === 'initializedMarkdownPreview') {
|
||||
if (e.message.type === 'initializedMarkup') {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
|
@ -1466,7 +973,7 @@ var requirejs = (function() {
|
|||
}
|
||||
|
||||
this._sendMessageToWebview({
|
||||
type: 'initializeMarkdownPreview',
|
||||
type: 'initializeMarkup',
|
||||
cells,
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,366 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import type { RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||
import type { PreloadOptions } from 'vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads';
|
||||
|
||||
interface BaseToWebviewMessage {
|
||||
readonly __vscode_notebook_message: true;
|
||||
}
|
||||
|
||||
export interface WebviewIntialized extends BaseToWebviewMessage {
|
||||
readonly type: 'initialized';
|
||||
}
|
||||
|
||||
export interface DimensionUpdate {
|
||||
readonly id: string;
|
||||
readonly init?: boolean;
|
||||
readonly height: number;
|
||||
readonly isOutput?: boolean;
|
||||
}
|
||||
|
||||
export interface IDimensionMessage extends BaseToWebviewMessage {
|
||||
readonly type: 'dimension';
|
||||
readonly updates: readonly DimensionUpdate[];
|
||||
}
|
||||
|
||||
export interface IMouseEnterMessage extends BaseToWebviewMessage {
|
||||
readonly type: 'mouseenter';
|
||||
readonly id: string;
|
||||
}
|
||||
|
||||
export interface IMouseLeaveMessage extends BaseToWebviewMessage {
|
||||
readonly type: 'mouseleave';
|
||||
readonly id: string;
|
||||
}
|
||||
|
||||
export interface IOutputFocusMessage extends BaseToWebviewMessage {
|
||||
readonly type: 'outputFocus';
|
||||
readonly id: string;
|
||||
}
|
||||
|
||||
export interface IOutputBlurMessage extends BaseToWebviewMessage {
|
||||
readonly type: 'outputBlur';
|
||||
readonly id: string;
|
||||
}
|
||||
|
||||
export interface IWheelMessage extends BaseToWebviewMessage {
|
||||
readonly type: 'did-scroll-wheel';
|
||||
readonly payload: any;
|
||||
}
|
||||
|
||||
export interface IScrollAckMessage extends BaseToWebviewMessage {
|
||||
readonly type: 'scroll-ack';
|
||||
readonly data: { top: number; };
|
||||
readonly version: number;
|
||||
}
|
||||
|
||||
export interface IBlurOutputMessage extends BaseToWebviewMessage {
|
||||
readonly type: 'focus-editor';
|
||||
readonly id: string;
|
||||
readonly focusNext?: boolean;
|
||||
}
|
||||
|
||||
export interface IClickedDataUrlMessage extends BaseToWebviewMessage {
|
||||
readonly type: 'clicked-data-url';
|
||||
readonly data: string | ArrayBuffer | null;
|
||||
readonly downloadName?: string;
|
||||
}
|
||||
|
||||
export interface IClickMarkupCellMessage extends BaseToWebviewMessage {
|
||||
readonly type: 'clickMarkupCell';
|
||||
readonly cellId: string;
|
||||
readonly ctrlKey: boolean;
|
||||
readonly altKey: boolean;
|
||||
readonly metaKey: boolean;
|
||||
readonly shiftKey: boolean;
|
||||
}
|
||||
|
||||
export interface IContextMenuMarkupCellMessage extends BaseToWebviewMessage {
|
||||
readonly type: 'contextMenuMarkupCell';
|
||||
readonly cellId: string;
|
||||
readonly clientX: number;
|
||||
readonly clientY: number;
|
||||
}
|
||||
|
||||
export interface IMouseEnterMarkupCellMessage extends BaseToWebviewMessage {
|
||||
readonly type: 'mouseEnterMarkupCell';
|
||||
readonly cellId: string;
|
||||
}
|
||||
|
||||
export interface IMouseLeaveMarkupCellMessage extends BaseToWebviewMessage {
|
||||
readonly type: 'mouseLeaveMarkupCell';
|
||||
readonly cellId: string;
|
||||
}
|
||||
|
||||
export interface IToggleMarkupPreviewMessage extends BaseToWebviewMessage {
|
||||
readonly type: 'toggleMarkupPreview';
|
||||
readonly cellId: string;
|
||||
}
|
||||
|
||||
export interface ICellDragStartMessage extends BaseToWebviewMessage {
|
||||
readonly type: 'cell-drag-start';
|
||||
readonly cellId: string;
|
||||
readonly dragOffsetY: number;
|
||||
}
|
||||
|
||||
export interface ICellDragMessage extends BaseToWebviewMessage {
|
||||
readonly type: 'cell-drag';
|
||||
readonly cellId: string;
|
||||
readonly dragOffsetY: number;
|
||||
}
|
||||
|
||||
export interface ICellDropMessage extends BaseToWebviewMessage {
|
||||
readonly type: 'cell-drop';
|
||||
readonly cellId: string;
|
||||
readonly ctrlKey: boolean;
|
||||
readonly altKey: boolean;
|
||||
readonly dragOffsetY: number;
|
||||
}
|
||||
|
||||
export interface ICellDragEndMessage extends BaseToWebviewMessage {
|
||||
readonly type: 'cell-drag-end';
|
||||
readonly cellId: string;
|
||||
}
|
||||
|
||||
export interface IInitializedMarkupMessage extends BaseToWebviewMessage {
|
||||
readonly type: 'initializedMarkup';
|
||||
}
|
||||
|
||||
export interface ITelemetryFoundRenderedMarkdownMath extends BaseToWebviewMessage {
|
||||
readonly type: 'telemetryFoundRenderedMarkdownMath';
|
||||
}
|
||||
|
||||
export interface ITelemetryFoundUnrenderedMarkdownMath extends BaseToWebviewMessage {
|
||||
readonly type: 'telemetryFoundUnrenderedMarkdownMath';
|
||||
readonly latexDirective: string;
|
||||
}
|
||||
|
||||
export interface IClearMessage {
|
||||
readonly type: 'clear';
|
||||
}
|
||||
|
||||
export interface IOutputRequestMetadata {
|
||||
/**
|
||||
* Additional attributes of a cell metadata.
|
||||
*/
|
||||
readonly custom?: { [key: string]: unknown; };
|
||||
}
|
||||
|
||||
export interface IOutputRequestDto {
|
||||
/**
|
||||
* { mime_type: value }
|
||||
*/
|
||||
readonly data: { [key: string]: unknown; };
|
||||
|
||||
readonly metadata?: IOutputRequestMetadata;
|
||||
readonly outputId: string;
|
||||
}
|
||||
|
||||
export interface ICreationRequestMessage {
|
||||
readonly type: 'html';
|
||||
readonly content: { type: RenderOutputType.Html; htmlContent: string; } |
|
||||
{ type: RenderOutputType.Extension; outputId: string; valueBytes: Uint8Array; metadata: unknown; metadata2: unknown; mimeType: string; };
|
||||
readonly cellId: string;
|
||||
readonly outputId: string;
|
||||
cellTop: number;
|
||||
outputOffset: number;
|
||||
readonly left: number;
|
||||
readonly requiredPreloads: ReadonlyArray<IControllerPreload>;
|
||||
readonly initiallyHidden?: boolean;
|
||||
readonly rendererId?: string | undefined;
|
||||
}
|
||||
|
||||
export interface IContentWidgetTopRequest {
|
||||
readonly outputId: string;
|
||||
readonly cellTop: number;
|
||||
readonly outputOffset: number;
|
||||
readonly forceDisplay: boolean;
|
||||
}
|
||||
|
||||
export interface IViewScrollTopRequestMessage {
|
||||
readonly type: 'view-scroll';
|
||||
readonly widgets: IContentWidgetTopRequest[];
|
||||
readonly markdownPreviews: { id: string; top: number; }[];
|
||||
}
|
||||
|
||||
export interface IScrollRequestMessage {
|
||||
readonly type: 'scroll';
|
||||
readonly id: string;
|
||||
readonly top: number;
|
||||
readonly widgetTop?: number;
|
||||
readonly version: number;
|
||||
}
|
||||
|
||||
export interface IClearOutputRequestMessage {
|
||||
readonly type: 'clearOutput';
|
||||
readonly cellId: string;
|
||||
readonly outputId: string;
|
||||
readonly cellUri: string;
|
||||
readonly rendererId: string | undefined;
|
||||
}
|
||||
|
||||
export interface IHideOutputMessage {
|
||||
readonly type: 'hideOutput';
|
||||
readonly outputId: string;
|
||||
readonly cellId: string;
|
||||
}
|
||||
|
||||
export interface IShowOutputMessage {
|
||||
readonly type: 'showOutput';
|
||||
readonly cellId: string;
|
||||
readonly outputId: string;
|
||||
readonly cellTop: number;
|
||||
readonly outputOffset: number;
|
||||
}
|
||||
|
||||
export interface IFocusOutputMessage {
|
||||
readonly type: 'focus-output';
|
||||
readonly cellId: string;
|
||||
}
|
||||
|
||||
export interface IAckOutputHeightMessage {
|
||||
readonly type: 'ack-dimension';
|
||||
readonly cellId: string;
|
||||
readonly outputId: string;
|
||||
readonly height: number;
|
||||
}
|
||||
|
||||
export interface IControllerPreload {
|
||||
readonly originalUri: string;
|
||||
readonly uri: string;
|
||||
}
|
||||
|
||||
export interface IUpdateControllerPreloadsMessage {
|
||||
readonly type: 'preload';
|
||||
readonly resources: IControllerPreload[];
|
||||
}
|
||||
|
||||
export interface IUpdateDecorationsMessage {
|
||||
readonly type: 'decorations';
|
||||
readonly cellId: string;
|
||||
readonly addedClassNames: string[];
|
||||
readonly removedClassNames: string[];
|
||||
}
|
||||
|
||||
export interface ICustomKernelMessage extends BaseToWebviewMessage {
|
||||
readonly type: 'customKernelMessage';
|
||||
readonly message: unknown;
|
||||
}
|
||||
|
||||
export interface ICustomRendererMessage extends BaseToWebviewMessage {
|
||||
readonly type: 'customRendererMessage';
|
||||
readonly rendererId: string;
|
||||
readonly message: unknown;
|
||||
}
|
||||
|
||||
export interface ICreateMarkupCellMessage {
|
||||
readonly type: 'createMarkupCell';
|
||||
readonly cell: IMarkupCellInitialization;
|
||||
}
|
||||
|
||||
export interface IDeleteMarkupCellMessage {
|
||||
readonly type: 'deleteMarkupCell';
|
||||
readonly ids: readonly string[];
|
||||
}
|
||||
|
||||
export interface IHideMarkupCellMessage {
|
||||
readonly type: 'hideMarkupCells';
|
||||
readonly ids: readonly string[];
|
||||
}
|
||||
|
||||
export interface IUnhideMarkupCellMessage {
|
||||
readonly type: 'unhideMarkupCells';
|
||||
readonly ids: readonly string[];
|
||||
}
|
||||
|
||||
export interface IShowMarkupCellMessage {
|
||||
readonly type: 'showMarkupCell';
|
||||
readonly id: string;
|
||||
readonly handle: number;
|
||||
readonly content: string | undefined;
|
||||
readonly top: number;
|
||||
}
|
||||
|
||||
export interface IUpdateSelectedMarkupCellsMessage {
|
||||
readonly type: 'updateSelectedMarkupCells';
|
||||
readonly selectedCellIds: readonly string[];
|
||||
}
|
||||
|
||||
export interface IMarkupCellInitialization {
|
||||
mime: string;
|
||||
cellId: string;
|
||||
cellHandle: number;
|
||||
content: string;
|
||||
offset: number;
|
||||
visible: boolean;
|
||||
}
|
||||
|
||||
export interface IInitializeMarkupCells {
|
||||
readonly type: 'initializeMarkup';
|
||||
readonly cells: ReadonlyArray<IMarkupCellInitialization>;
|
||||
}
|
||||
|
||||
export interface INotebookStylesMessage {
|
||||
readonly type: 'notebookStyles';
|
||||
readonly styles: {
|
||||
[key: string]: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface INotebookOptionsMessage {
|
||||
readonly type: 'notebookOptions';
|
||||
readonly options: PreloadOptions;
|
||||
}
|
||||
|
||||
export type FromWebviewMessage = WebviewIntialized |
|
||||
IDimensionMessage |
|
||||
IMouseEnterMessage |
|
||||
IMouseLeaveMessage |
|
||||
IOutputFocusMessage |
|
||||
IOutputBlurMessage |
|
||||
IWheelMessage |
|
||||
IScrollAckMessage |
|
||||
IBlurOutputMessage |
|
||||
ICustomKernelMessage |
|
||||
ICustomRendererMessage |
|
||||
IClickedDataUrlMessage |
|
||||
IClickMarkupCellMessage |
|
||||
IContextMenuMarkupCellMessage |
|
||||
IMouseEnterMarkupCellMessage |
|
||||
IMouseLeaveMarkupCellMessage |
|
||||
IToggleMarkupPreviewMessage |
|
||||
ICellDragStartMessage |
|
||||
ICellDragMessage |
|
||||
ICellDropMessage |
|
||||
ICellDragEndMessage |
|
||||
IInitializedMarkupMessage |
|
||||
ITelemetryFoundRenderedMarkdownMath |
|
||||
ITelemetryFoundUnrenderedMarkdownMath;
|
||||
|
||||
export type ToWebviewMessage = IClearMessage |
|
||||
IFocusOutputMessage |
|
||||
IAckOutputHeightMessage |
|
||||
ICreationRequestMessage |
|
||||
IViewScrollTopRequestMessage |
|
||||
IScrollRequestMessage |
|
||||
IClearOutputRequestMessage |
|
||||
IHideOutputMessage |
|
||||
IShowOutputMessage |
|
||||
IUpdateControllerPreloadsMessage |
|
||||
IUpdateDecorationsMessage |
|
||||
ICustomKernelMessage |
|
||||
ICustomRendererMessage |
|
||||
ICreateMarkupCellMessage |
|
||||
IDeleteMarkupCellMessage |
|
||||
IShowMarkupCellMessage |
|
||||
IHideMarkupCellMessage |
|
||||
IUnhideMarkupCellMessage |
|
||||
IUpdateSelectedMarkupCellsMessage |
|
||||
IInitializeMarkupCells |
|
||||
INotebookStylesMessage |
|
||||
INotebookOptionsMessage;
|
||||
|
||||
export type AnyMessage = FromWebviewMessage | ToWebviewMessage;
|
|
@ -6,7 +6,7 @@
|
|||
import type { Event } from 'vs/base/common/event';
|
||||
import type { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||
import type { FromWebviewMessage, IBlurOutputMessage, ICellDropMessage, ICellDragMessage, ICellDragStartMessage, IClickedDataUrlMessage, IDimensionMessage, IClickMarkdownPreviewMessage, IMouseEnterMarkdownPreviewMessage, IMouseEnterMessage, IMouseLeaveMarkdownPreviewMessage, IMouseLeaveMessage, IToggleMarkdownPreviewMessage, IWheelMessage, ToWebviewMessage, ICellDragEndMessage, IOutputFocusMessage, IOutputBlurMessage, DimensionUpdate, IContextMenuMarkdownPreviewMessage, ITelemetryFoundRenderedMarkdownMath, ITelemetryFoundUnrenderedMarkdownMath, IMarkdownCellInitialization } from 'vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView';
|
||||
import type * as webviewMessages from 'vs/workbench/contrib/notebook/browser/view/renderers/webviewMessages';
|
||||
|
||||
// !! IMPORTANT !! everything must be in-line within the webviewPreloads
|
||||
// function. Imports are not allowed. This is stringified and injected into
|
||||
|
@ -71,7 +71,7 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
|
|||
};
|
||||
|
||||
const handleDataUrl = async (data: string | ArrayBuffer | null, downloadName: string) => {
|
||||
postNotebookMessage<IClickedDataUrlMessage>('clicked-data-url', {
|
||||
postNotebookMessage<webviewMessages.IClickedDataUrlMessage>('clicked-data-url', {
|
||||
data,
|
||||
downloadName
|
||||
});
|
||||
|
@ -201,7 +201,7 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
|
|||
});
|
||||
|
||||
const dimensionUpdater = new class {
|
||||
private readonly pending = new Map<string, DimensionUpdate>();
|
||||
private readonly pending = new Map<string, webviewMessages.DimensionUpdate>();
|
||||
|
||||
update(id: string, height: number, options: { init?: boolean; isOutput?: boolean }) {
|
||||
if (!this.pending.size) {
|
||||
|
@ -221,7 +221,7 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
|
|||
return;
|
||||
}
|
||||
|
||||
postNotebookMessage<IDimensionMessage>('dimension', {
|
||||
postNotebookMessage<webviewMessages.IDimensionMessage>('dimension', {
|
||||
updates: Array.from(this.pending.values())
|
||||
});
|
||||
this.pending.clear();
|
||||
|
@ -300,7 +300,7 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
|
|||
if (event.defaultPrevented || scrollWillGoToParent(event)) {
|
||||
return;
|
||||
}
|
||||
postNotebookMessage<IWheelMessage>('did-scroll-wheel', {
|
||||
postNotebookMessage<webviewMessages.IWheelMessage>('did-scroll-wheel', {
|
||||
payload: {
|
||||
deltaMode: event.deltaMode,
|
||||
deltaX: event.deltaX,
|
||||
|
@ -324,7 +324,7 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
|
|||
const element = document.createElement('div');
|
||||
element.tabIndex = 0;
|
||||
element.addEventListener('focus', () => {
|
||||
postNotebookMessage<IBlurOutputMessage>('focus-editor', {
|
||||
postNotebookMessage<webviewMessages.IBlurOutputMessage>('focus-editor', {
|
||||
id: outputId,
|
||||
focusNext
|
||||
});
|
||||
|
@ -335,12 +335,12 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
|
|||
|
||||
function addMouseoverListeners(element: HTMLElement, outputId: string): void {
|
||||
element.addEventListener('mouseenter', () => {
|
||||
postNotebookMessage<IMouseEnterMessage>('mouseenter', {
|
||||
postNotebookMessage<webviewMessages.IMouseEnterMessage>('mouseenter', {
|
||||
id: outputId,
|
||||
});
|
||||
});
|
||||
element.addEventListener('mouseleave', () => {
|
||||
postNotebookMessage<IMouseLeaveMessage>('mouseleave', {
|
||||
postNotebookMessage<webviewMessages.IMouseLeaveMessage>('mouseleave', {
|
||||
id: outputId,
|
||||
});
|
||||
});
|
||||
|
@ -376,7 +376,7 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
|
|||
this._loosingFocus = false;
|
||||
if (!this._hasFocus) {
|
||||
this._hasFocus = true;
|
||||
postNotebookMessage<IOutputFocusMessage>('outputFocus', {
|
||||
postNotebookMessage<webviewMessages.IOutputFocusMessage>('outputFocus', {
|
||||
id: this._outputId,
|
||||
});
|
||||
}
|
||||
|
@ -389,7 +389,7 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
|
|||
if (this._loosingFocus) {
|
||||
this._loosingFocus = false;
|
||||
this._hasFocus = false;
|
||||
postNotebookMessage<IOutputBlurMessage>('outputBlur', {
|
||||
postNotebookMessage<webviewMessages.IOutputBlurMessage>('outputBlur', {
|
||||
id: this._outputId,
|
||||
});
|
||||
}
|
||||
|
@ -507,79 +507,45 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
|
|||
window.addEventListener('wheel', handleWheel);
|
||||
|
||||
window.addEventListener('message', async rawEvent => {
|
||||
const event = rawEvent as ({ data: ToWebviewMessage; });
|
||||
const event = rawEvent as ({ data: webviewMessages.ToWebviewMessage; });
|
||||
|
||||
switch (event.data.type) {
|
||||
case 'initializeMarkdownPreview':
|
||||
{
|
||||
await ensureMarkdownPreviewCells(event.data.cells);
|
||||
dimensionUpdater.updateImmediately();
|
||||
postNotebookMessage('initializedMarkdownPreview', {});
|
||||
}
|
||||
case 'initializeMarkup':
|
||||
await notebookDocument.ensureMarkupCells(event.data.cells);
|
||||
dimensionUpdater.updateImmediately();
|
||||
postNotebookMessage('initializedMarkup', {});
|
||||
break;
|
||||
case 'createMarkdownPreview':
|
||||
ensureMarkdownPreviewCells([event.data.cell]);
|
||||
break;
|
||||
case 'showMarkdownPreview':
|
||||
{
|
||||
const data = event.data;
|
||||
|
||||
const cellContainer = document.getElementById(data.id);
|
||||
if (cellContainer) {
|
||||
cellContainer.style.visibility = 'visible';
|
||||
cellContainer.style.top = `${data.top}px`;
|
||||
updateMarkdownPreview(cellContainer, data.id, data.content);
|
||||
}
|
||||
}
|
||||
case 'createMarkupCell':
|
||||
notebookDocument.ensureMarkupCells([event.data.cell]);
|
||||
break;
|
||||
case 'hideMarkdownPreviews':
|
||||
{
|
||||
for (const id of event.data.ids) {
|
||||
const cellContainer = document.getElementById(id);
|
||||
if (cellContainer) {
|
||||
cellContainer.style.visibility = 'hidden';
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'unhideMarkdownPreviews':
|
||||
{
|
||||
for (const id of event.data.ids) {
|
||||
const cellContainer = document.getElementById(id);
|
||||
if (cellContainer) {
|
||||
cellContainer.style.visibility = 'visible';
|
||||
updateMarkdownPreview(cellContainer, id, undefined);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'deleteMarkdownPreview':
|
||||
{
|
||||
for (const id of event.data.ids) {
|
||||
const cellContainer = document.getElementById(id);
|
||||
cellContainer?.remove();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'updateSelectedMarkdownPreviews':
|
||||
{
|
||||
const selectedCellIds = new Set<string>(event.data.selectedCellIds);
|
||||
|
||||
for (const oldSelected of document.querySelectorAll('.preview.selected')) {
|
||||
const id = oldSelected.id;
|
||||
if (!selectedCellIds.has(id)) {
|
||||
oldSelected.classList.remove('selected');
|
||||
}
|
||||
}
|
||||
case 'showMarkupCell':
|
||||
notebookDocument.showMarkupCell(event.data.id, event.data.top, event.data.content);
|
||||
break;
|
||||
|
||||
for (const newSelected of selectedCellIds) {
|
||||
const previewContainer = document.getElementById(newSelected);
|
||||
if (previewContainer) {
|
||||
previewContainer.classList.add('selected');
|
||||
}
|
||||
}
|
||||
case 'hideMarkupCells':
|
||||
for (const id of event.data.ids) {
|
||||
notebookDocument.hideMarkupCell(id);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'unhideMarkupCells':
|
||||
for (const id of event.data.ids) {
|
||||
notebookDocument.unhideMarkupCell(id);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'deleteMarkupCell':
|
||||
for (const id of event.data.ids) {
|
||||
notebookDocument.deleteMarkupCell(id);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'updateSelectedMarkupCells':
|
||||
notebookDocument.updateSelectedCells(event.data.selectedCellIds);
|
||||
break;
|
||||
|
||||
case 'html': {
|
||||
const data = event.data;
|
||||
outputs.enqueue(event.data.outputId, async (state) => {
|
||||
|
@ -829,10 +795,9 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
|
|||
|
||||
// Update markdown previews
|
||||
for (const markdownContainer of document.querySelectorAll('.preview')) {
|
||||
setMarkdownContainerDraggable(markdownContainer, currentOptions.dragAndDropEnabled);
|
||||
setMarkupContainerDraggable(markdownContainer, currentOptions.dragAndDropEnabled);
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
@ -1021,47 +986,254 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
|
|||
this._renderers.get(rendererId)?.api?.disposeOutputItem?.(outputId);
|
||||
}
|
||||
|
||||
public async renderCustom(rendererId: string, info: IOutputItem, element: HTMLElement) {
|
||||
const api = await this.load(rendererId);
|
||||
if (!api) {
|
||||
throw new Error(`renderer ${rendererId} did not return an API`);
|
||||
}
|
||||
public async render(info: IOutputItem, element: HTMLElement) {
|
||||
const renderers = Array.from(this._renderers.values())
|
||||
.filter(renderer => renderer.data.mimeTypes.includes(info.mime) && !renderer.data.extends);
|
||||
|
||||
api.renderOutputItem(info, element);
|
||||
}
|
||||
|
||||
public async renderMarkdown(id: string, element: HTMLElement, content: string): Promise<void> {
|
||||
const markdownRenderers = Array.from(this._renderers.values())
|
||||
.filter(renderer => renderer.data.mimeTypes.includes('text/markdown') && !renderer.data.extends);
|
||||
|
||||
if (!markdownRenderers.length) {
|
||||
if (!renderers.length) {
|
||||
throw new Error('Could not find renderer');
|
||||
}
|
||||
|
||||
await Promise.all(markdownRenderers.map(x => x.load()));
|
||||
await Promise.all(renderers.map(x => x.load()));
|
||||
|
||||
markdownRenderers[0].api?.renderOutputItem({
|
||||
id,
|
||||
element,
|
||||
mime: 'text/markdown',
|
||||
metadata: undefined,
|
||||
metadata2: undefined,
|
||||
outputId: undefined,
|
||||
text() { return content; },
|
||||
json() { return undefined; },
|
||||
bytes() { return this.data(); },
|
||||
data() { return new TextEncoder().encode(content); },
|
||||
blob() { return new Blob([this.data()], { type: this.mime }); },
|
||||
}, element);
|
||||
renderers[0].api?.renderOutputItem(info, element);
|
||||
}
|
||||
}();
|
||||
|
||||
let hasPostedRenderedMathTelemetry = false;
|
||||
const unsupportedKatexTermsRegex = /(\\(?:abovewithdelims|array|Arrowvert|arrowvert|atopwithdelims|bbox|bracevert|buildrel|cancelto|cases|class|cssId|ddddot|dddot|DeclareMathOperator|definecolor|displaylines|enclose|eqalign|eqalignno|eqref|hfil|hfill|idotsint|iiiint|label|leftarrowtail|leftroot|leqalignno|lower|mathtip|matrix|mbox|mit|mmlToken|moveleft|moveright|mspace|newenvironment|Newextarrow|notag|oldstyle|overparen|overwithdelims|pmatrix|raise|ref|renewenvironment|require|root|Rule|scr|shoveleft|shoveright|sideset|skew|Space|strut|style|texttip|Tiny|toggle|underparen|unicode|uproot)\b)/gi;
|
||||
|
||||
const notebookDocument = new class {
|
||||
|
||||
private readonly _markupCells = new Map<string, MarkupCell>();
|
||||
|
||||
private async createMarkupCell(init: webviewMessages.IMarkupCellInitialization, top: number): Promise<MarkupCell> {
|
||||
const existing = this._markupCells.get(init.cellId);
|
||||
if (existing) {
|
||||
console.error(`Trying to create markup that already exists: ${init.cellId}`);
|
||||
return existing;
|
||||
}
|
||||
|
||||
const markdownCell = new MarkupCell(init.cellId, init.mime, init.content, top);
|
||||
this._markupCells.set(init.cellId, markdownCell);
|
||||
|
||||
await markdownCell.ready;
|
||||
return markdownCell;
|
||||
}
|
||||
|
||||
public async ensureMarkupCells(update: readonly webviewMessages.IMarkupCellInitialization[]): Promise<void> {
|
||||
await Promise.all(update.map(async info => {
|
||||
let cell = this._markupCells.get(info.cellId);
|
||||
if (cell) {
|
||||
await cell.updateContentAndRender(info.content);
|
||||
} else {
|
||||
cell = await this.createMarkupCell(info, info.offset);
|
||||
}
|
||||
cell.element.style.visibility = info.visible ? 'visible' : 'hidden';
|
||||
}));
|
||||
}
|
||||
|
||||
public deleteMarkupCell(id: string) {
|
||||
const cell = this.getExpectedMarkupCell(id);
|
||||
if (cell) {
|
||||
cell.element.remove();
|
||||
this._markupCells.delete(id);
|
||||
}
|
||||
}
|
||||
|
||||
public async updateMarkupContent(id: string, newContent: string): Promise<void> {
|
||||
const cell = this.getExpectedMarkupCell(id);
|
||||
await cell?.updateContentAndRender(newContent);
|
||||
}
|
||||
|
||||
public showMarkupCell(id: string, top: number, newContent: string | undefined): void {
|
||||
const cell = this.getExpectedMarkupCell(id);
|
||||
cell?.show(id, top, newContent);
|
||||
}
|
||||
|
||||
public hideMarkupCell(id: string): void {
|
||||
const cell = this.getExpectedMarkupCell(id);
|
||||
cell?.hide();
|
||||
}
|
||||
|
||||
public unhideMarkupCell(id: string): void {
|
||||
const cell = this.getExpectedMarkupCell(id);
|
||||
cell?.unhide();
|
||||
}
|
||||
|
||||
private getExpectedMarkupCell(id: string): MarkupCell | undefined {
|
||||
const cell = this._markupCells.get(id);
|
||||
if (!cell) {
|
||||
console.log(`Could not find markup cell '${id}'`);
|
||||
return undefined;
|
||||
}
|
||||
return cell;
|
||||
}
|
||||
|
||||
public updateSelectedCells(selectedCellIds: readonly string[]) {
|
||||
const selectedCellSet = new Set<string>(selectedCellIds);
|
||||
for (const cell of this._markupCells.values()) {
|
||||
cell.setSelected(selectedCellSet.has(cell.id));
|
||||
}
|
||||
}
|
||||
}();
|
||||
|
||||
class MarkupCell implements IOutputItem {
|
||||
|
||||
public readonly ready: Promise<void>;
|
||||
|
||||
/// Internal field that holds markdown text
|
||||
private _content: string;
|
||||
|
||||
constructor(id: string, mime: string, content: string, top: number) {
|
||||
this.id = id;
|
||||
this.mime = mime;
|
||||
this._content = content;
|
||||
|
||||
let resolveReady: () => void;
|
||||
this.ready = new Promise<void>(r => resolveReady = r);
|
||||
|
||||
const root = document.getElementById('container')!;
|
||||
|
||||
this.element = document.createElement('div');
|
||||
this.element.id = this.id;
|
||||
this.element.classList.add('preview');
|
||||
this.element.style.position = 'absolute';
|
||||
this.element.style.top = top + 'px';
|
||||
root.appendChild(this.element);
|
||||
|
||||
this.addEventListeners();
|
||||
|
||||
this.updateContentAndRender(this._content).then(() => {
|
||||
resizeObserver.observe(this.element, this.id, false);
|
||||
resolveReady();
|
||||
});
|
||||
}
|
||||
|
||||
//#region IOutputItem
|
||||
public readonly id: string;
|
||||
public readonly mime;
|
||||
public readonly element: HTMLElement;
|
||||
|
||||
// deprecated fields
|
||||
public readonly metadata = undefined;
|
||||
public readonly metadata2 = undefined;
|
||||
public readonly outputId?: string | undefined;
|
||||
|
||||
text() { return this._content; }
|
||||
json() { return undefined; }
|
||||
bytes() { return this.data(); }
|
||||
data() { return new TextEncoder().encode(this._content); }
|
||||
blob() { return new Blob([this.data()], { type: this.mime }); }
|
||||
//#endregion
|
||||
|
||||
private addEventListeners() {
|
||||
this.element.addEventListener('dblclick', () => {
|
||||
postNotebookMessage<webviewMessages.IToggleMarkupPreviewMessage>('toggleMarkupPreview', { cellId: this.id });
|
||||
});
|
||||
|
||||
this.element.addEventListener('click', e => {
|
||||
postNotebookMessage<webviewMessages.IClickMarkupCellMessage>('clickMarkupCell', {
|
||||
cellId: this.id,
|
||||
altKey: e.altKey,
|
||||
ctrlKey: e.ctrlKey,
|
||||
metaKey: e.metaKey,
|
||||
shiftKey: e.shiftKey,
|
||||
});
|
||||
});
|
||||
|
||||
this.element.addEventListener('contextmenu', e => {
|
||||
postNotebookMessage<webviewMessages.IContextMenuMarkupCellMessage>('contextMenuMarkupCell', {
|
||||
cellId: this.id,
|
||||
clientX: e.clientX,
|
||||
clientY: e.clientY,
|
||||
});
|
||||
});
|
||||
|
||||
this.element.addEventListener('mouseenter', () => {
|
||||
postNotebookMessage<webviewMessages.IMouseEnterMarkupCellMessage>('mouseEnterMarkupCell', { cellId: this.id });
|
||||
});
|
||||
|
||||
this.element.addEventListener('mouseleave', () => {
|
||||
postNotebookMessage<webviewMessages.IMouseLeaveMarkupCellMessage>('mouseLeaveMarkupCell', { cellId: this.id });
|
||||
});
|
||||
|
||||
setMarkupContainerDraggable(this.element, currentOptions.dragAndDropEnabled);
|
||||
|
||||
this.element.addEventListener('dragstart', e => {
|
||||
markdownPreviewDragManager.startDrag(e, this.id);
|
||||
});
|
||||
|
||||
this.element.addEventListener('drag', e => {
|
||||
markdownPreviewDragManager.updateDrag(e, this.id);
|
||||
});
|
||||
|
||||
this.element.addEventListener('dragend', e => {
|
||||
markdownPreviewDragManager.endDrag(e, this.id);
|
||||
});
|
||||
}
|
||||
|
||||
public async updateContentAndRender(newContent: string): Promise<void> {
|
||||
this._content = newContent;
|
||||
|
||||
await renderers.render(this, this.element);
|
||||
|
||||
if (!hasPostedRenderedMathTelemetry) {
|
||||
const hasRenderedMath = this.element.querySelector('.katex');
|
||||
if (hasRenderedMath) {
|
||||
hasPostedRenderedMathTelemetry = true;
|
||||
postNotebookMessage<webviewMessages.ITelemetryFoundRenderedMarkdownMath>('telemetryFoundRenderedMarkdownMath', {});
|
||||
}
|
||||
}
|
||||
|
||||
const matches = this.element.innerText.match(unsupportedKatexTermsRegex);
|
||||
if (matches) {
|
||||
postNotebookMessage<webviewMessages.ITelemetryFoundUnrenderedMarkdownMath>('telemetryFoundUnrenderedMarkdownMath', {
|
||||
latexDirective: matches[0],
|
||||
});
|
||||
}
|
||||
|
||||
dimensionUpdater.update(this.id, this.element.clientHeight, {
|
||||
isOutput: false
|
||||
});
|
||||
}
|
||||
|
||||
public show(id: string, top: number, newContent: string | undefined): void {
|
||||
this.element.style.visibility = 'visible';
|
||||
this.element.style.top = `${top}px`;
|
||||
if (typeof newContent === 'string') {
|
||||
this.updateContentAndRender(newContent);
|
||||
} else {
|
||||
this.updateMarkupDimensions();
|
||||
}
|
||||
}
|
||||
|
||||
public hide() {
|
||||
this.element.style.visibility = 'hidden';
|
||||
}
|
||||
|
||||
public unhide() {
|
||||
this.element.style.visibility = 'visible';
|
||||
this.updateMarkupDimensions();
|
||||
}
|
||||
|
||||
private async updateMarkupDimensions() {
|
||||
dimensionUpdater.update(this.id, this.element.clientHeight, {
|
||||
isOutput: false
|
||||
});
|
||||
}
|
||||
|
||||
public setSelected(selected: boolean) {
|
||||
this.element.classList.toggle('selected', selected);
|
||||
}
|
||||
}
|
||||
|
||||
vscode.postMessage({
|
||||
__vscode_notebook_message: true,
|
||||
type: 'initialized'
|
||||
});
|
||||
|
||||
function setMarkdownContainerDraggable(element: Element, isDraggable: boolean) {
|
||||
function setMarkupContainerDraggable(element: Element, isDraggable: boolean) {
|
||||
if (isDraggable) {
|
||||
element.classList.add('draggable');
|
||||
element.setAttribute('draggable', 'true');
|
||||
|
@ -1071,102 +1243,7 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
|
|||
}
|
||||
}
|
||||
|
||||
async function createMarkdownPreview(cellId: string, content: string, top: number): Promise<HTMLElement> {
|
||||
const container = document.getElementById('container')!;
|
||||
const cellContainer = document.createElement('div');
|
||||
|
||||
const existing = document.getElementById(cellId);
|
||||
if (existing) {
|
||||
console.error(`Trying to create markdown preview that already exists: ${cellId}`);
|
||||
return existing;
|
||||
}
|
||||
|
||||
cellContainer.id = cellId;
|
||||
cellContainer.classList.add('preview');
|
||||
|
||||
cellContainer.style.position = 'absolute';
|
||||
cellContainer.style.top = top + 'px';
|
||||
container.appendChild(cellContainer);
|
||||
|
||||
cellContainer.addEventListener('dblclick', () => {
|
||||
postNotebookMessage<IToggleMarkdownPreviewMessage>('toggleMarkdownPreview', { cellId });
|
||||
});
|
||||
|
||||
cellContainer.addEventListener('click', e => {
|
||||
postNotebookMessage<IClickMarkdownPreviewMessage>('clickMarkdownPreview', {
|
||||
cellId,
|
||||
altKey: e.altKey,
|
||||
ctrlKey: e.ctrlKey,
|
||||
metaKey: e.metaKey,
|
||||
shiftKey: e.shiftKey,
|
||||
});
|
||||
});
|
||||
|
||||
cellContainer.addEventListener('contextmenu', e => {
|
||||
postNotebookMessage<IContextMenuMarkdownPreviewMessage>('contextMenuMarkdownPreview', {
|
||||
cellId,
|
||||
clientX: e.clientX,
|
||||
clientY: e.clientY,
|
||||
});
|
||||
});
|
||||
|
||||
cellContainer.addEventListener('mouseenter', () => {
|
||||
postNotebookMessage<IMouseEnterMarkdownPreviewMessage>('mouseEnterMarkdownPreview', { cellId });
|
||||
});
|
||||
|
||||
cellContainer.addEventListener('mouseleave', () => {
|
||||
postNotebookMessage<IMouseLeaveMarkdownPreviewMessage>('mouseLeaveMarkdownPreview', { cellId });
|
||||
});
|
||||
|
||||
setMarkdownContainerDraggable(cellContainer, currentOptions.dragAndDropEnabled);
|
||||
|
||||
cellContainer.addEventListener('dragstart', e => {
|
||||
markdownPreviewDragManager.startDrag(e, cellId);
|
||||
});
|
||||
|
||||
cellContainer.addEventListener('drag', e => {
|
||||
markdownPreviewDragManager.updateDrag(e, cellId);
|
||||
});
|
||||
|
||||
cellContainer.addEventListener('dragend', e => {
|
||||
markdownPreviewDragManager.endDrag(e, cellId);
|
||||
});
|
||||
|
||||
const previewRoot = cellContainer.attachShadow({ mode: 'open' });
|
||||
|
||||
// Add default webview style
|
||||
const defaultStyles = document.getElementById('_defaultStyles') as HTMLStyleElement;
|
||||
previewRoot.appendChild(defaultStyles.cloneNode(true));
|
||||
|
||||
// Add default preview style
|
||||
const previewStyles = document.getElementById('preview-styles') as HTMLTemplateElement;
|
||||
previewRoot.appendChild(previewStyles.content.cloneNode(true));
|
||||
|
||||
const previewNode = document.createElement('div');
|
||||
previewNode.id = 'preview';
|
||||
previewRoot.appendChild(previewNode);
|
||||
|
||||
await updateMarkdownPreview(cellContainer, cellId, content);
|
||||
|
||||
resizeObserver.observe(cellContainer, cellId, false);
|
||||
|
||||
return cellContainer;
|
||||
}
|
||||
|
||||
async function ensureMarkdownPreviewCells(update: readonly IMarkdownCellInitialization[]): Promise<void> {
|
||||
await Promise.all(update.map(async cell => {
|
||||
let container = document.getElementById(cell.cellId);
|
||||
if (container) {
|
||||
await updateMarkdownPreview(container, cell.cellId, cell.content);
|
||||
} else {
|
||||
container = await createMarkdownPreview(cell.cellId, cell.content, cell.offset);
|
||||
}
|
||||
|
||||
container.style.visibility = cell.visible ? 'visible' : 'hidden';
|
||||
}));
|
||||
}
|
||||
|
||||
function postNotebookMessage<T extends FromWebviewMessage>(
|
||||
function postNotebookMessage<T extends webviewMessages.FromWebviewMessage>(
|
||||
type: T['type'],
|
||||
properties: Omit<T, '__vscode_notebook_message' | 'type'>
|
||||
) {
|
||||
|
@ -1177,46 +1254,6 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
|
|||
});
|
||||
}
|
||||
|
||||
let hasPostedRenderedMathTelemetry = false;
|
||||
const unsupportedKatexTermsRegex = /(\\(?:abovewithdelims|array|Arrowvert|arrowvert|atopwithdelims|bbox|bracevert|buildrel|cancelto|cases|class|cssId|ddddot|dddot|DeclareMathOperator|definecolor|displaylines|enclose|eqalign|eqalignno|eqref|hfil|hfill|idotsint|iiiint|label|leftarrowtail|leftroot|leqalignno|lower|mathtip|matrix|mbox|mit|mmlToken|moveleft|moveright|mspace|newenvironment|Newextarrow|notag|oldstyle|overparen|overwithdelims|pmatrix|raise|ref|renewenvironment|require|root|Rule|scr|shoveleft|shoveright|sideset|skew|Space|strut|style|texttip|Tiny|toggle|underparen|unicode|uproot)\b)/gi;
|
||||
|
||||
async function updateMarkdownPreview(previewContainerNode: HTMLElement, cellId: string, content: string | undefined) {
|
||||
const previewRoot = previewContainerNode.shadowRoot;
|
||||
const previewNode = previewRoot?.getElementById('preview');
|
||||
if (!previewNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof content === 'string') {
|
||||
if (content.trim().length === 0) {
|
||||
previewContainerNode.classList.add('emptyMarkdownCell');
|
||||
previewNode.innerText = '';
|
||||
} else {
|
||||
previewContainerNode.classList.remove('emptyMarkdownCell');
|
||||
await renderers.renderMarkdown(cellId, previewNode, content);
|
||||
|
||||
if (!hasPostedRenderedMathTelemetry) {
|
||||
const hasRenderedMath = previewNode.querySelector('.katex');
|
||||
if (hasRenderedMath) {
|
||||
hasPostedRenderedMathTelemetry = true;
|
||||
postNotebookMessage<ITelemetryFoundRenderedMarkdownMath>('telemetryFoundRenderedMarkdownMath', {});
|
||||
}
|
||||
}
|
||||
|
||||
const matches = previewNode.innerText.match(unsupportedKatexTermsRegex);
|
||||
if (matches) {
|
||||
postNotebookMessage<ITelemetryFoundUnrenderedMarkdownMath>('telemetryFoundUnrenderedMarkdownMath', {
|
||||
latexDirective: matches[0],
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dimensionUpdater.update(cellId, previewContainerNode.clientHeight, {
|
||||
isOutput: false
|
||||
});
|
||||
}
|
||||
|
||||
const markdownPreviewDragManager = new class MarkdownPreviewDragManager {
|
||||
|
||||
private currentDrag: { cellId: string, clientY: number } | undefined;
|
||||
|
@ -1236,7 +1273,7 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
|
|||
}
|
||||
|
||||
this.currentDrag = undefined;
|
||||
postNotebookMessage<ICellDropMessage>('cell-drop', {
|
||||
postNotebookMessage<webviewMessages.ICellDropMessage>('cell-drop', {
|
||||
cellId: drag.cellId,
|
||||
ctrlKey: e.ctrlKey,
|
||||
altKey: e.altKey,
|
||||
|
@ -1258,7 +1295,7 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
|
|||
|
||||
(e.target as HTMLElement).classList.add('dragging');
|
||||
|
||||
postNotebookMessage<ICellDragStartMessage>('cell-drag-start', {
|
||||
postNotebookMessage<webviewMessages.ICellDragStartMessage>('cell-drag-start', {
|
||||
cellId: cellId,
|
||||
dragOffsetY: e.clientY,
|
||||
});
|
||||
|
@ -1270,7 +1307,7 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
|
|||
return;
|
||||
}
|
||||
|
||||
postNotebookMessage<ICellDragMessage>('cell-drag', {
|
||||
postNotebookMessage<webviewMessages.ICellDragMessage>('cell-drag', {
|
||||
cellId: cellId,
|
||||
dragOffsetY: this.currentDrag.clientY,
|
||||
});
|
||||
|
@ -1289,7 +1326,7 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
|
|||
endDrag(e: DragEvent, cellId: string) {
|
||||
this.currentDrag = undefined;
|
||||
(e.target as HTMLElement).classList.remove('dragging');
|
||||
postNotebookMessage<ICellDragEndMessage>('cell-drag-end', {
|
||||
postNotebookMessage<webviewMessages.ICellDragEndMessage>('cell-drag-end', {
|
||||
cellId: cellId
|
||||
});
|
||||
}
|
||||
|
|
|
@ -19,19 +19,24 @@ import { BaseCellViewModel } from './baseCellViewModel';
|
|||
|
||||
export class CodeCellViewModel extends BaseCellViewModel implements ICellViewModel {
|
||||
readonly cellKind = CellKind.Code;
|
||||
protected readonly _onDidChangeOutputs = new Emitter<NotebookCellOutputsSplice[]>();
|
||||
|
||||
protected readonly _onDidChangeOutputs = this._register(new Emitter<NotebookCellOutputsSplice[]>());
|
||||
readonly onDidChangeOutputs = this._onDidChangeOutputs.event;
|
||||
private readonly _onDidRemoveOutputs = new Emitter<readonly ICellOutputViewModel[]>();
|
||||
|
||||
private readonly _onDidRemoveOutputs = this._register(new Emitter<readonly ICellOutputViewModel[]>());
|
||||
readonly onDidRemoveOutputs = this._onDidRemoveOutputs.event;
|
||||
private readonly _onDidHideInput = new Emitter<void>();
|
||||
|
||||
private readonly _onDidHideInput = this._register(new Emitter<void>());
|
||||
readonly onDidHideInput = this._onDidHideInput.event;
|
||||
private readonly _onDidHideOutputs = new Emitter<readonly ICellOutputViewModel[]>();
|
||||
|
||||
private readonly _onDidHideOutputs = this._register(new Emitter<readonly ICellOutputViewModel[]>());
|
||||
readonly onDidHideOutputs = this._onDidHideOutputs.event;
|
||||
|
||||
private _outputCollection: number[] = [];
|
||||
|
||||
private _outputsTop: PrefixSumComputer | null = null;
|
||||
|
||||
protected readonly _onDidChangeLayout = new Emitter<CodeCellLayoutChangeEvent>();
|
||||
protected readonly _onDidChangeLayout = this._register(new Emitter<CodeCellLayoutChangeEvent>());
|
||||
readonly onDidChangeLayout = this._onDidChangeLayout.event;
|
||||
|
||||
private _editorHeight = 0;
|
||||
|
|
|
@ -17,6 +17,8 @@ import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/mode
|
|||
import { CellKind, INotebookSearchOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { ITextModelService } from 'vs/editor/common/services/resolverService';
|
||||
import { ViewContext } from 'vs/workbench/contrib/notebook/browser/viewModel/viewContext';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { dirname } from 'vs/base/common/resources';
|
||||
|
||||
export class MarkdownCellViewModel extends BaseCellViewModel implements ICellViewModel {
|
||||
readonly cellKind = CellKind.Markup;
|
||||
|
@ -97,17 +99,22 @@ export class MarkdownCellViewModel extends BaseCellViewModel implements ICellVie
|
|||
private readonly _onDidHideInput = new Emitter<void>();
|
||||
readonly onDidHideInput = this._onDidHideInput.event;
|
||||
|
||||
private readonly _mdRenderer: MarkdownRenderer;
|
||||
|
||||
constructor(
|
||||
viewType: string,
|
||||
model: NotebookCellTextModel,
|
||||
initialNotebookLayoutInfo: NotebookLayoutInfo | null,
|
||||
readonly foldingDelegate: EditorFoldingStateDelegate,
|
||||
readonly viewContext: ViewContext,
|
||||
private readonly _mdRenderer: MarkdownRenderer,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@ITextModelService textModelService: ITextModelService,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
) {
|
||||
super(viewType, model, UUID.generateUuid(), viewContext, configurationService, textModelService);
|
||||
|
||||
this._mdRenderer = this._register(instantiationService.createInstance(MarkdownRenderer, { baseUrl: dirname(model.uri) }));
|
||||
|
||||
const { bottomToolbarGap } = this.viewContext.notebookOptions.computeBottomToolbarDimensions(this.viewType);
|
||||
|
||||
this._layoutInfo = {
|
||||
|
|
|
@ -8,10 +8,8 @@ import { onUnexpectedError } from 'vs/base/common/errors';
|
|||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { clamp } from 'vs/base/common/numbers';
|
||||
import { dirname } from 'vs/base/common/resources';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { MarkdownRenderer } from 'vs/editor/browser/core/markdownRenderer';
|
||||
import { IBulkEditService, ResourceEdit, ResourceTextEdit } from 'vs/editor/browser/services/bulkEditService';
|
||||
import { IPosition, Position } from 'vs/editor/common/core/position';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
|
@ -1188,7 +1186,6 @@ export function createCellViewModel(instantiationService: IInstantiationService,
|
|||
if (cell.cellKind === CellKind.Code) {
|
||||
return instantiationService.createInstance(CodeCellViewModel, notebookViewModel.viewType, cell, notebookViewModel.layoutInfo, notebookViewModel.viewContext);
|
||||
} else {
|
||||
const mdRenderer = instantiationService.createInstance(MarkdownRenderer, { baseUrl: dirname(notebookViewModel.uri) });
|
||||
return instantiationService.createInstance(MarkdownCellViewModel, notebookViewModel.viewType, cell, notebookViewModel.layoutInfo, notebookViewModel, notebookViewModel.viewContext, mdRenderer);
|
||||
return instantiationService.createInstance(MarkdownCellViewModel, notebookViewModel.viewType, cell, notebookViewModel.layoutInfo, notebookViewModel, notebookViewModel.viewContext);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { renderStringAsPlaintext } from 'vs/base/browser/markdownRenderer';
|
||||
import { Action, IAction, Separator } from 'vs/base/common/actions';
|
||||
import { Action, IAction, Separator, SubmenuAction } from 'vs/base/common/actions';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { MarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { Disposable, dispose, IDisposable, IReference, MutableDisposable } from 'vs/base/common/lifecycle';
|
||||
|
@ -19,6 +19,7 @@ import { IModelDeltaDecoration, OverviewRulerLane, TrackedRangeStickiness } from
|
|||
import { overviewRulerError, overviewRulerInfo, overviewRulerWarning } from 'vs/editor/common/view/editorColorRegistry';
|
||||
import { localize } from 'vs/nls';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IThemeService, themeColorFromId, ThemeIcon } from 'vs/platform/theme/common/themeService';
|
||||
|
@ -28,7 +29,10 @@ import { BREAKPOINT_EDITOR_CONTRIBUTION_ID, IBreakpointEditorContribution } from
|
|||
import { testingRunAllIcon, testingRunIcon, testingStatesToIcons } from 'vs/workbench/contrib/testing/browser/icons';
|
||||
import { TestingOutputPeekController } from 'vs/workbench/contrib/testing/browser/testingOutputPeek';
|
||||
import { testMessageSeverityColors } from 'vs/workbench/contrib/testing/browser/theme';
|
||||
import { IncrementalTestCollectionItem, IRichLocation, ITestMessage, TestDiffOpType, TestResultItem } from 'vs/workbench/contrib/testing/common/testCollection';
|
||||
import { DefaultGutterClickAction, getTestingConfiguration, TestingConfigKeys } from 'vs/workbench/contrib/testing/common/configuration';
|
||||
import { labelForTestInState } from 'vs/workbench/contrib/testing/common/constants';
|
||||
import { IncrementalTestCollectionItem, InternalTestItem, IRichLocation, ITestMessage, TestDiffOpType, TestResultItem } from 'vs/workbench/contrib/testing/common/testCollection';
|
||||
import { maxPriority } from 'vs/workbench/contrib/testing/common/testingStates';
|
||||
import { buildTestUri, TestUriType } from 'vs/workbench/contrib/testing/common/testingUri';
|
||||
import { ITestResultService } from 'vs/workbench/contrib/testing/common/testResultService';
|
||||
import { IMainThreadTestCollection, ITestService } from 'vs/workbench/contrib/testing/common/testService';
|
||||
|
@ -173,8 +177,15 @@ export class TestingDecorations extends Disposable implements IEditorContributio
|
|||
for (const test of ref.object.all) {
|
||||
const stateLookup = this.results.getStateById(test.item.extId);
|
||||
if (test.item.range) {
|
||||
newDecorations.push(this.instantiationService.createInstance(
|
||||
RunTestDecoration, test, ref.object, test.item.range, this.editor, stateLookup?.[1]));
|
||||
const line = test.item.range.startLineNumber;
|
||||
const resultItem = stateLookup?.[1];
|
||||
const existing = newDecorations.findIndex(d => d instanceof RunTestDecoration && d.line === line);
|
||||
if (existing !== -1) {
|
||||
newDecorations[existing] = (newDecorations[existing] as RunTestDecoration).merge(test, ref.object, resultItem);
|
||||
} else {
|
||||
newDecorations.push(this.instantiationService.createInstance(
|
||||
RunSingleTestDecoration, test, ref.object, this.editor, stateLookup?.[1]));
|
||||
}
|
||||
}
|
||||
|
||||
if (!stateLookup) {
|
||||
|
@ -249,116 +260,179 @@ const firstLineRange = (originalRange: IRange) => ({
|
|||
endColumn: 1,
|
||||
});
|
||||
|
||||
class RunTestDecoration extends Disposable implements ITestDecoration {
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
id = '';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public readonly editorDecoration: IModelDeltaDecoration;
|
||||
|
||||
private line: number;
|
||||
|
||||
constructor(
|
||||
private readonly test: IncrementalTestCollectionItem,
|
||||
private readonly collection: IMainThreadTestCollection,
|
||||
range: IRange,
|
||||
private readonly editor: ICodeEditor,
|
||||
stateItem: TestResultItem | undefined,
|
||||
@ITestService private readonly testService: ITestService,
|
||||
@IContextMenuService private readonly contextMenuService: IContextMenuService,
|
||||
@ICommandService private readonly commandService: ICommandService,
|
||||
) {
|
||||
super();
|
||||
this.line = range.startLineNumber;
|
||||
|
||||
const icon = stateItem?.computedState !== undefined && stateItem.computedState !== TestResultState.Unset
|
||||
? testingStatesToIcons.get(stateItem.computedState)!
|
||||
: test.children.size > 0 ? testingRunAllIcon : testingRunIcon;
|
||||
|
||||
const hoverMessage = new MarkdownString('', true).appendText(localize('failedHoverMessage', '{0} has failed. ', test.item.label));
|
||||
if (stateItem?.tasks.some(s => s.messages.length > 0)) {
|
||||
const args = encodeURIComponent(JSON.stringify([test.item.extId]));
|
||||
hoverMessage.appendMarkdown(`[${localize('failedPeekAction', 'Peek Error')}](command:vscode.peekTestError?${args})`);
|
||||
}
|
||||
|
||||
let glyphMarginClassName = ThemeIcon.asClassName(icon) + ' testing-run-glyph';
|
||||
if (stateItem?.retired) {
|
||||
glyphMarginClassName += ' retired';
|
||||
}
|
||||
|
||||
this.editorDecoration = {
|
||||
range: firstLineRange(range),
|
||||
options: {
|
||||
description: 'run-test-decoration',
|
||||
isWholeLine: true,
|
||||
hoverMessage,
|
||||
glyphMarginClassName,
|
||||
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
|
||||
glyphMarginHoverMessage: new MarkdownString().appendText(localize('testing.clickToRun', 'Click to run tests, right click for more options')),
|
||||
}
|
||||
};
|
||||
const createRunTestDecoration = (tests: readonly IncrementalTestCollectionItem[], states: readonly (TestResultItem | undefined)[]): IModelDeltaDecoration => {
|
||||
const range = tests[0]?.item.range;
|
||||
if (!range) {
|
||||
throw new Error('Test decorations can only be created for tests with a range');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
let computedState = TestResultState.Unset;
|
||||
let hoverMessageParts: string[] = [];
|
||||
let testIdWithMessages: string | undefined;
|
||||
let retired = false;
|
||||
for (let i = 0; i < tests.length; i++) {
|
||||
const test = tests[i];
|
||||
const resultItem = states[i];
|
||||
const state = resultItem?.computedState ?? TestResultState.Unset;
|
||||
hoverMessageParts.push(labelForTestInState(test.item.label, state));
|
||||
computedState = maxPriority(computedState, state);
|
||||
retired = retired || !!resultItem?.retired;
|
||||
if (!testIdWithMessages && resultItem?.tasks.some(t => t.messages.length)) {
|
||||
testIdWithMessages = test.item.extId;
|
||||
}
|
||||
}
|
||||
|
||||
const hasMultipleTests = tests.length > 1 || tests[0].children.size > 0;
|
||||
const icon = computedState === TestResultState.Unset
|
||||
? (hasMultipleTests ? testingRunAllIcon : testingRunIcon)
|
||||
: testingStatesToIcons.get(computedState)!;
|
||||
|
||||
const hoverMessage = new MarkdownString('', true).appendText(hoverMessageParts.join(', ') + '.');
|
||||
if (testIdWithMessages) {
|
||||
const args = encodeURIComponent(JSON.stringify([testIdWithMessages]));
|
||||
hoverMessage.appendMarkdown(`[${localize('peekTestOutout', 'Peek Test Output')}](command:vscode.peekTestError?${args})`);
|
||||
}
|
||||
|
||||
let glyphMarginClassName = ThemeIcon.asClassName(icon) + ' testing-run-glyph';
|
||||
if (retired) {
|
||||
glyphMarginClassName += ' retired';
|
||||
}
|
||||
|
||||
return {
|
||||
range: firstLineRange(range),
|
||||
options: {
|
||||
description: 'run-test-decoration',
|
||||
isWholeLine: true,
|
||||
hoverMessage,
|
||||
glyphMarginClassName,
|
||||
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
abstract class RunTestDecoration extends Disposable {
|
||||
/** @inheritdoc */
|
||||
public id = '';
|
||||
|
||||
public get line() {
|
||||
return this.editorDecoration.range.startLineNumber;
|
||||
}
|
||||
|
||||
constructor(
|
||||
public editorDecoration: IModelDeltaDecoration,
|
||||
protected readonly editor: ICodeEditor,
|
||||
@ITestService protected readonly testService: ITestService,
|
||||
@IContextMenuService protected readonly contextMenuService: IContextMenuService,
|
||||
@ICommandService protected readonly commandService: ICommandService,
|
||||
@IConfigurationService protected readonly configurationService: IConfigurationService,
|
||||
) {
|
||||
super();
|
||||
editorDecoration.options.glyphMarginHoverMessage = new MarkdownString().appendText(this.getGutterLabel());
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public click(e: IEditorMouseEvent): boolean {
|
||||
if (e.target.position?.lineNumber !== this.line || e.target.type !== MouseTargetType.GUTTER_GLYPH_MARGIN) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (e.event.rightButton) {
|
||||
const actions = this.getContextMenu();
|
||||
this.contextMenuService.showContextMenu({
|
||||
getAnchor: () => ({ x: e.event.posx, y: e.event.posy }),
|
||||
getActions: () => actions,
|
||||
onHide: () => dispose(actions),
|
||||
});
|
||||
} else {
|
||||
// todo: customize click behavior
|
||||
this.testService.runTests({
|
||||
tests: [{ testId: this.test.item.extId, src: this.test.src }],
|
||||
debug: false,
|
||||
});
|
||||
this.showContextMenu(e);
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (getTestingConfiguration(this.configurationService, TestingConfigKeys.DefaultGutterClickAction)) {
|
||||
case DefaultGutterClickAction.ContextMenu:
|
||||
this.showContextMenu(e);
|
||||
break;
|
||||
case DefaultGutterClickAction.Debug:
|
||||
this.defaultDebug();
|
||||
break;
|
||||
case DefaultGutterClickAction.Run:
|
||||
default:
|
||||
this.defaultRun();
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override dispose() {
|
||||
// no-op
|
||||
/**
|
||||
* Adds the test to this decoration.
|
||||
*/
|
||||
public abstract merge(other: IncrementalTestCollectionItem, collection: IMainThreadTestCollection, resultItem: TestResultItem | undefined): RunTestDecoration;
|
||||
|
||||
/**
|
||||
* Called when the decoration is clicked on.
|
||||
*/
|
||||
protected abstract getContextMenuActions(e: IEditorMouseEvent): IAction[];
|
||||
|
||||
/**
|
||||
* Default run action.
|
||||
*/
|
||||
protected abstract defaultRun(): void;
|
||||
|
||||
/**
|
||||
* Default debug action.
|
||||
*/
|
||||
protected abstract defaultDebug(): void;
|
||||
|
||||
private showContextMenu(e: IEditorMouseEvent) {
|
||||
let actions = this.getContextMenuActions(e);
|
||||
|
||||
const model = this.editor.getModel();
|
||||
if (model) {
|
||||
actions = Separator.join(
|
||||
actions,
|
||||
this.editor
|
||||
.getContribution<IBreakpointEditorContribution>(BREAKPOINT_EDITOR_CONTRIBUTION_ID)
|
||||
.getContextMenuActionsAtPosition(this.line, model)
|
||||
);
|
||||
}
|
||||
|
||||
this.contextMenuService.showContextMenu({
|
||||
getAnchor: () => ({ x: e.event.posx, y: e.event.posy }),
|
||||
getActions: () => actions,
|
||||
onHide: () => dispose(actions),
|
||||
});
|
||||
}
|
||||
|
||||
private getContextMenu() {
|
||||
const model = this.editor.getModel();
|
||||
if (!model) {
|
||||
return [];
|
||||
private getGutterLabel() {
|
||||
switch (getTestingConfiguration(this.configurationService, TestingConfigKeys.DefaultGutterClickAction)) {
|
||||
case DefaultGutterClickAction.ContextMenu:
|
||||
return localize('testing.gutterMsg.contextMenu', 'Click for test options');
|
||||
case DefaultGutterClickAction.Debug:
|
||||
return localize('testing.gutterMsg.debug', 'Click to debug tests, right click for more options');
|
||||
case DefaultGutterClickAction.Run:
|
||||
default:
|
||||
return localize('testing.gutterMsg.run', 'Click to run tests, right click for more options');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets context menu actions relevant for a singel test.
|
||||
*/
|
||||
protected getTestContextMenuActions(collection: IMainThreadTestCollection, test: InternalTestItem) {
|
||||
const testActions: IAction[] = [];
|
||||
if (this.test.item.runnable) {
|
||||
testActions.push(new Action('testing.run', localize('run test', 'Run Test'), undefined, undefined, () => this.testService.runTests({
|
||||
if (test.item.runnable) {
|
||||
testActions.push(new Action('testing.gutter.run', localize('run test', 'Run Test'), undefined, undefined, () => this.testService.runTests({
|
||||
debug: false,
|
||||
tests: [{ src: this.test.src, testId: this.test.item.extId }],
|
||||
tests: [{ src: test.src, testId: test.item.extId }],
|
||||
})));
|
||||
}
|
||||
|
||||
if (this.test.item.debuggable) {
|
||||
testActions.push(new Action('testing.debug', localize('debug test', 'Debug Test'), undefined, undefined, () => this.testService.runTests({
|
||||
if (test.item.debuggable) {
|
||||
testActions.push(new Action('testing.gutter.debug', localize('debug test', 'Debug Test'), undefined, undefined, () => this.testService.runTests({
|
||||
debug: true,
|
||||
tests: [{ src: this.test.src, testId: this.test.item.extId }],
|
||||
tests: [{ src: test.src, testId: test.item.extId }],
|
||||
})));
|
||||
}
|
||||
|
||||
testActions.push(new Action('testing.reveal', localize('reveal test', 'Reveal in Test Explorer'), undefined, undefined, async () => {
|
||||
const path = [this.test];
|
||||
testActions.push(new Action('testing.gutter.reveal', localize('reveal test', 'Reveal in Test Explorer'), undefined, undefined, async () => {
|
||||
const path = [test];
|
||||
while (true) {
|
||||
const parentId = path[0].parent;
|
||||
const parent = parentId && this.collection.getNodeById(parentId);
|
||||
const parent = parentId && collection.getNodeById(parentId);
|
||||
if (!parent) {
|
||||
break;
|
||||
}
|
||||
|
@ -369,11 +443,112 @@ class RunTestDecoration extends Disposable implements ITestDecoration {
|
|||
await this.commandService.executeCommand('vscode.revealTestInExplorer', path.map(t => t.item.extId));
|
||||
}));
|
||||
|
||||
const breakpointActions = this.editor
|
||||
.getContribution<IBreakpointEditorContribution>(BREAKPOINT_EDITOR_CONTRIBUTION_ID)
|
||||
.getContextMenuActionsAtPosition(this.line, model);
|
||||
return testActions;
|
||||
}
|
||||
}
|
||||
|
||||
return breakpointActions.length ? [...testActions, new Separator(), ...breakpointActions] : testActions;
|
||||
class MultiRunTestDecoration extends RunTestDecoration implements ITestDecoration {
|
||||
constructor(
|
||||
private readonly tests: {
|
||||
test: IncrementalTestCollectionItem,
|
||||
collection: IMainThreadTestCollection,
|
||||
resultItem: TestResultItem | undefined,
|
||||
}[],
|
||||
editor: ICodeEditor,
|
||||
@ITestService testService: ITestService,
|
||||
@ICommandService commandService: ICommandService,
|
||||
@IContextMenuService contextMenuService: IContextMenuService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
) {
|
||||
super(createRunTestDecoration(tests.map(t => t.test), tests.map(t => t.resultItem)), editor, testService, contextMenuService, commandService, configurationService);
|
||||
}
|
||||
|
||||
public override merge(test: IncrementalTestCollectionItem, collection: IMainThreadTestCollection, resultItem: TestResultItem | undefined): RunTestDecoration {
|
||||
this.tests.push({ collection, test, resultItem });
|
||||
this.editorDecoration = createRunTestDecoration(this.tests.map(t => t.test), this.tests.map(t => t.resultItem));
|
||||
return this;
|
||||
}
|
||||
|
||||
protected override getContextMenuActions() {
|
||||
const allActions: IAction[] = [];
|
||||
if (this.tests.some(({ test }) => test.item.runnable)) {
|
||||
allActions.push(new Action('testing.gutter.runAll', localize('run all test', 'Run All Tests'), undefined, undefined, () => this.defaultRun()));
|
||||
}
|
||||
|
||||
if (this.tests.some(({ test }) => test.item.debuggable)) {
|
||||
allActions.push(new Action('testing.gutter.debugAll', localize('debug all test', 'Debug All Tests'), undefined, undefined, () => this.defaultDebug()));
|
||||
}
|
||||
|
||||
const testSubmenus = this.tests.map(({ collection, test }) =>
|
||||
new SubmenuAction(test.item.extId, test.item.label, this.getTestContextMenuActions(collection, test)));
|
||||
|
||||
return Separator.join(allActions, testSubmenus);
|
||||
}
|
||||
|
||||
protected override defaultRun() {
|
||||
return this.testService.runTests({
|
||||
tests: this.tests
|
||||
.filter(({ test }) => test.item.runnable)
|
||||
.map(({ test }) => ({ testId: test.item.extId, src: test.src })),
|
||||
debug: false,
|
||||
});
|
||||
}
|
||||
|
||||
protected override defaultDebug() {
|
||||
return this.testService.runTests({
|
||||
tests: this.tests
|
||||
.filter(({ test }) => test.item.debuggable)
|
||||
.map(({ test }) => ({ testId: test.item.extId, src: test.src })),
|
||||
debug: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class RunSingleTestDecoration extends RunTestDecoration implements ITestDecoration {
|
||||
constructor(
|
||||
private readonly test: IncrementalTestCollectionItem,
|
||||
private readonly collection: IMainThreadTestCollection,
|
||||
editor: ICodeEditor,
|
||||
private readonly resultItem: TestResultItem | undefined,
|
||||
@ITestService testService: ITestService,
|
||||
@ICommandService commandService: ICommandService,
|
||||
@IContextMenuService contextMenuService: IContextMenuService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
) {
|
||||
super(createRunTestDecoration([test], [resultItem]), editor, testService, contextMenuService, commandService, configurationService);
|
||||
}
|
||||
|
||||
public override merge(test: IncrementalTestCollectionItem, collection: IMainThreadTestCollection, resultItem: TestResultItem | undefined): RunTestDecoration {
|
||||
return new MultiRunTestDecoration([
|
||||
{ collection: this.collection, test: this.test, resultItem: this.resultItem },
|
||||
{ collection, test, resultItem },
|
||||
], this.editor, this.testService, this.commandService, this.contextMenuService, this.configurationService);
|
||||
}
|
||||
|
||||
protected override getContextMenuActions(e: IEditorMouseEvent) {
|
||||
return this.getTestContextMenuActions(this.collection, this.test);
|
||||
}
|
||||
|
||||
protected override defaultRun() {
|
||||
if (!this.test.item.runnable) {
|
||||
return;
|
||||
}
|
||||
|
||||
return this.testService.runTests({
|
||||
tests: [{ testId: this.test.item.extId, src: this.test.src }],
|
||||
debug: false,
|
||||
});
|
||||
}
|
||||
|
||||
protected override defaultDebug() {
|
||||
if (!this.test.item.debuggable) {
|
||||
return;
|
||||
}
|
||||
|
||||
return this.testService.runTests({
|
||||
tests: [{ testId: this.test.item.extId, src: this.test.src }],
|
||||
debug: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -51,12 +51,12 @@ import { HierarchicalByNameProjection } from 'vs/workbench/contrib/testing/brows
|
|||
import { IActionableTestTreeElement, isActionableTestTreeElement, ITestTreeProjection, TestExplorerTreeElement, TestItemTreeElement, TestTreeErrorMessage, TestTreeWorkspaceFolder } from 'vs/workbench/contrib/testing/browser/explorerProjections/index';
|
||||
import { testingHiddenIcon, testingStatesToIcons } from 'vs/workbench/contrib/testing/browser/icons';
|
||||
import { ITestExplorerFilterState, TestExplorerFilterState, TestingExplorerFilter } from 'vs/workbench/contrib/testing/browser/testingExplorerFilter';
|
||||
import { ITestingPeekOpener } from 'vs/workbench/contrib/testing/common/testingPeekOpener';
|
||||
import { ITestingProgressUiService } from 'vs/workbench/contrib/testing/browser/testingProgressUiService';
|
||||
import { getTestingConfiguration, TestingConfigKeys } from 'vs/workbench/contrib/testing/common/configuration';
|
||||
import { TestExplorerStateFilter, TestExplorerViewMode, TestExplorerViewSorting, Testing, testStateNames } from 'vs/workbench/contrib/testing/common/constants';
|
||||
import { labelForTestInState, TestExplorerStateFilter, TestExplorerViewMode, TestExplorerViewSorting, Testing, testStateNames } from 'vs/workbench/contrib/testing/common/constants';
|
||||
import { TestIdPath, TestItemExpandState } from 'vs/workbench/contrib/testing/common/testCollection';
|
||||
import { TestingContextKeys } from 'vs/workbench/contrib/testing/common/testingContextKeys';
|
||||
import { ITestingPeekOpener } from 'vs/workbench/contrib/testing/common/testingPeekOpener';
|
||||
import { cmpPriority, isFailedState, isStateWithResult } from 'vs/workbench/contrib/testing/common/testingStates';
|
||||
import { getPathForTestInResult, TestResultItemChangeReason } from 'vs/workbench/contrib/testing/common/testResult';
|
||||
import { ITestResultService } from 'vs/workbench/contrib/testing/common/testResultService';
|
||||
|
@ -830,10 +830,7 @@ class TestExplorerActionRunner extends ActionRunner {
|
|||
}
|
||||
|
||||
const getLabelForTestTreeElement = (element: IActionableTestTreeElement) => {
|
||||
let label = localize({
|
||||
key: 'testing.treeElementLabel',
|
||||
comment: ['label then the unit tests state, for example "Addition Tests (Running)"'],
|
||||
}, '{0} ({1})', element.label, testStateNames[element.state]);
|
||||
let label = labelForTestInState(element.label, element.state);
|
||||
|
||||
if (element instanceof TestItemTreeElement) {
|
||||
if (element.duration !== undefined) {
|
||||
|
|
|
@ -64,7 +64,7 @@ import { TestingContextKeys } from 'vs/workbench/contrib/testing/common/testingC
|
|||
import { ITestingPeekOpener } from 'vs/workbench/contrib/testing/common/testingPeekOpener';
|
||||
import { isFailedState } from 'vs/workbench/contrib/testing/common/testingStates';
|
||||
import { buildTestUri, ParsedTestUri, parseTestUri, TestUriType } from 'vs/workbench/contrib/testing/common/testingUri';
|
||||
import { getPathForTestInResult, ITestResult, maxCountPriority, TestResultItemChange, TestResultItemChangeReason } from 'vs/workbench/contrib/testing/common/testResult';
|
||||
import { getPathForTestInResult, ITestResult, maxCountPriority, resultItemParents, TestResultItemChange, TestResultItemChangeReason } from 'vs/workbench/contrib/testing/common/testResult';
|
||||
import { ITestResultService, ResultChangeEvent } from 'vs/workbench/contrib/testing/common/testResultService';
|
||||
import { getAllTestsInHierarchy, ITestService } from 'vs/workbench/contrib/testing/common/testService';
|
||||
import { ACTIVE_GROUP, IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService';
|
||||
|
@ -196,9 +196,11 @@ export class TestingPeekOpener extends Disposable implements ITestingPeekOpener
|
|||
|
||||
// don't show the peek if the user asked to only auto-open peeks for visible tests,
|
||||
// and this test is not in any of the editors' models.
|
||||
const testUri = evt.item.item.uri?.toString();
|
||||
if (cfg === AutoOpenPeekViewWhen.FailureVisible && (!testUri || !editors.some(e => e.getModel()?.uri.toString() === testUri))) {
|
||||
return;
|
||||
if (cfg === AutoOpenPeekViewWhen.FailureVisible) {
|
||||
const editorUris = new Set(editors.map(e => e.getModel()?.uri.toString()));
|
||||
if (!Iterable.some(resultItemParents(evt.result, evt.item), i => i.item.uri && editorUris.has(i.item.uri.toString()))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const controllers = editors.map(TestingOutputPeekController.get);
|
||||
|
@ -912,20 +914,12 @@ export class TestCaseElement implements ITreeElement {
|
|||
private readonly results: ITestResult,
|
||||
public readonly test: TestResultItem,
|
||||
) {
|
||||
for (const parent of this.parents()) {
|
||||
this.description = this.description
|
||||
? parent.item.label + flatTestItemDelimiter + this.description
|
||||
: parent.item.label;
|
||||
}
|
||||
}
|
||||
|
||||
private *parents() {
|
||||
for (
|
||||
let parent = this.test.parent && this.results.getStateById(this.test.parent);
|
||||
parent;
|
||||
parent = parent.parent && this.results.getStateById(parent.parent)
|
||||
) {
|
||||
yield parent;
|
||||
for (const parent of resultItemParents(results, test)) {
|
||||
if (parent !== test) {
|
||||
this.description = this.description
|
||||
? parent.item.label + flatTestItemDelimiter + this.description
|
||||
: parent.item.label;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ export const enum TestingConfigKeys {
|
|||
AutoOpenPeekView = 'testing.automaticallyOpenPeekView',
|
||||
AutoOpenPeekViewDuringAutoRun = 'testing.automaticallyOpenPeekViewDuringAutoRun',
|
||||
FollowRunningTest = 'testing.followRunningTest',
|
||||
DefaultGutterClickAction = 'testing.defaultGutterClickAction',
|
||||
}
|
||||
|
||||
export const enum AutoOpenPeekViewWhen {
|
||||
|
@ -25,6 +26,12 @@ export const enum AutoRunMode {
|
|||
OnlyPreviouslyRun = 'rerun',
|
||||
}
|
||||
|
||||
export const enum DefaultGutterClickAction {
|
||||
Run = 'run',
|
||||
Debug = 'debug',
|
||||
ContextMenu = 'contextMenu',
|
||||
}
|
||||
|
||||
export const testingConfiguation: IConfigurationNode = {
|
||||
id: 'testing',
|
||||
order: 21,
|
||||
|
@ -71,6 +78,20 @@ export const testingConfiguation: IConfigurationNode = {
|
|||
type: 'boolean',
|
||||
default: true,
|
||||
},
|
||||
[TestingConfigKeys.DefaultGutterClickAction]: {
|
||||
description: localize('testing.defaultGutterClickAction', 'Controls the action to take when left-clicking on a test decoration in the gutter.'),
|
||||
enum: [
|
||||
DefaultGutterClickAction.Run,
|
||||
DefaultGutterClickAction.Debug,
|
||||
DefaultGutterClickAction.ContextMenu,
|
||||
],
|
||||
enumDescriptions: [
|
||||
localize('testing.defaultGutterClickAction.run', 'Run the test.'),
|
||||
localize('testing.defaultGutterClickAction.debug', 'Debug the test.'),
|
||||
localize('testing.defaultGutterClickAction.contextMenu', 'Open the context menu for more options.'),
|
||||
],
|
||||
default: DefaultGutterClickAction.Run,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -80,6 +101,7 @@ export interface ITestingConfiguration {
|
|||
[TestingConfigKeys.AutoOpenPeekView]: AutoOpenPeekViewWhen;
|
||||
[TestingConfigKeys.AutoOpenPeekViewDuringAutoRun]: boolean;
|
||||
[TestingConfigKeys.FollowRunningTest]: boolean;
|
||||
[TestingConfigKeys.DefaultGutterClickAction]: DefaultGutterClickAction;
|
||||
}
|
||||
|
||||
export const getTestingConfiguration = <K extends TestingConfigKeys>(config: IConfigurationService, key: K) => config.getValue<ITestingConfiguration[K]>(key);
|
||||
|
|
|
@ -38,5 +38,10 @@ export const testStateNames: { [K in TestResultState]: string } = {
|
|||
[TestResultState.Queued]: localize('testState.queued', 'Queued'),
|
||||
[TestResultState.Running]: localize('testState.running', 'Running'),
|
||||
[TestResultState.Skipped]: localize('testState.skipped', 'Skipped'),
|
||||
[TestResultState.Unset]: localize('testState.unset', 'Unset'),
|
||||
[TestResultState.Unset]: localize('testState.unset', 'Not yet run'),
|
||||
};
|
||||
|
||||
export const labelForTestInState = (label: string, state: TestResultState) => localize({
|
||||
key: 'testing.treeElementLabel',
|
||||
comment: ['label then the unit tests state, for example "Addition Tests (Running)"'],
|
||||
}, '{0} ({1})', label, testStateNames[state]);
|
||||
|
|
|
@ -69,19 +69,21 @@ export interface ITestResult {
|
|||
toJSON(): ISerializedTestResults | undefined;
|
||||
}
|
||||
|
||||
export const getPathForTestInResult = (test: TestResultItem, results: ITestResult): TestIdPath => {
|
||||
const path = [test];
|
||||
while (true) {
|
||||
const parentId = path[0].parent;
|
||||
const parent = parentId && results.getStateById(parentId);
|
||||
if (!parent) {
|
||||
break;
|
||||
}
|
||||
export const resultItemParents = function* (results: ITestResult, item: TestResultItem) {
|
||||
let i: TestResultItem | undefined = item;
|
||||
while (i) {
|
||||
yield i;
|
||||
i = i.parent ? results.getStateById(i.parent) : undefined;
|
||||
}
|
||||
};
|
||||
|
||||
path.unshift(parent);
|
||||
export const getPathForTestInResult = (test: TestResultItem, results: ITestResult): TestIdPath => {
|
||||
const path: TestIdPath = [];
|
||||
for (const node of resultItemParents(results, test)) {
|
||||
path.unshift(node.item.extId);
|
||||
}
|
||||
|
||||
return path.map(t => t.item.extId);
|
||||
return path;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -69,10 +69,10 @@ export interface IMainThreadTestCollection extends AbstractIncrementalTestCollec
|
|||
* Iterates through the item and its parents to the root.
|
||||
*/
|
||||
export const getCollectionItemParents = function* (collection: IMainThreadTestCollection, item: InternalTestItem) {
|
||||
let p: InternalTestItem | undefined = item;
|
||||
while (p) {
|
||||
yield p;
|
||||
p = p.parent ? collection.getNodeById(p.parent) : undefined;
|
||||
let i: InternalTestItem | undefined = item;
|
||||
while (i) {
|
||||
yield i;
|
||||
i = i.parent ? collection.getNodeById(i.parent) : undefined;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import { Lazy } from 'vs/base/common/lazy';
|
|||
import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService';
|
||||
import { NullLogService } from 'vs/platform/log/common/log';
|
||||
import { ITestTaskState, TestResultItem } from 'vs/workbench/contrib/testing/common/testCollection';
|
||||
import { HydratedTestResult, LiveOutputController, LiveTestResult, makeEmptyCounts, TestResultItemChange, TestResultItemChangeReason } from 'vs/workbench/contrib/testing/common/testResult';
|
||||
import { getPathForTestInResult, HydratedTestResult, LiveOutputController, LiveTestResult, makeEmptyCounts, resultItemParents, TestResultItemChange, TestResultItemChangeReason } from 'vs/workbench/contrib/testing/common/testResult';
|
||||
import { TestResultService } from 'vs/workbench/contrib/testing/common/testResultService';
|
||||
import { InMemoryResultStorage, ITestResultStorage } from 'vs/workbench/contrib/testing/common/testResultStorage';
|
||||
import { Convert, ReExportedTestRunState as TestRunState, TestItemImpl, TestResultState, testStubs, testStubsChain } from 'vs/workbench/contrib/testing/common/testStubs';
|
||||
|
@ -291,4 +291,24 @@ suite('Workbench - Test Results Service', () => {
|
|||
assert.deepStrictEqual(results.results, [r, hydrated1, hydrated2]);
|
||||
});
|
||||
});
|
||||
|
||||
test('resultItemParents', () => {
|
||||
assert.deepStrictEqual([...resultItemParents(r, r.getStateById('id-aa')!)], [
|
||||
r.getStateById('id-aa'),
|
||||
r.getStateById('id-a'),
|
||||
r.getStateById('id-root'),
|
||||
]);
|
||||
|
||||
assert.deepStrictEqual([...resultItemParents(r, r.getStateById('id-root')!)], [
|
||||
r.getStateById('id-root'),
|
||||
]);
|
||||
});
|
||||
|
||||
test('getPathForTestInResult', () => {
|
||||
assert.deepStrictEqual([...getPathForTestInResult(r.getStateById('id-aa')!, r)], [
|
||||
'id-root',
|
||||
'id-a',
|
||||
'id-aa',
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
import 'vs/css!./gettingStarted';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IInstantiationService, optional } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IEditorInputSerializer, IEditorOpenContext } from 'vs/workbench/common/editor';
|
||||
import { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { assertIsDefined } from 'vs/base/common/types';
|
||||
|
@ -17,7 +17,7 @@ import { IThemeService, registerThemingParticipant, ThemeIcon } from 'vs/platfor
|
|||
import { welcomePageBackground, welcomePageProgressBackground, welcomePageProgressForeground, welcomePageTileBackground, welcomePageTileHoverBackground, welcomePageTileShadow } from 'vs/workbench/contrib/welcome/page/browser/welcomePageColors';
|
||||
import { activeContrastBorder, buttonBackground, buttonForeground, buttonHoverBackground, contrastBorder, descriptionForeground, focusBorder, foreground, textLinkActiveForeground, textLinkForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { ITelemetryService, lastSessionDateStorageKey } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { firstSessionDateStorageKey, ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
|
||||
import { gettingStartedCheckedCodicon, gettingStartedUncheckedCodicon } from 'vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedIcons';
|
||||
import { IOpenerService, matchesScheme } from 'vs/platform/opener/common/opener';
|
||||
|
@ -27,7 +27,6 @@ import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storag
|
|||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ContextKeyExpr, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ITASExperimentService } from 'vs/workbench/services/experiment/common/experimentService';
|
||||
import { IRecentFolder, IRecentlyOpened, IRecentWorkspace, isRecentFolder, isRecentWorkspace, IWorkspacesService } from 'vs/platform/workspaces/common/workspaces';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
|
@ -103,7 +102,6 @@ export class GettingStartedPage extends EditorPane {
|
|||
private container: HTMLElement;
|
||||
|
||||
private contextService: IContextKeyService;
|
||||
private tasExperimentService?: ITASExperimentService;
|
||||
private previousSelection?: string;
|
||||
private recentlyOpened: Promise<IRecentlyOpened>;
|
||||
private selectedStepElement?: HTMLDivElement;
|
||||
|
@ -144,7 +142,6 @@ export class GettingStartedPage extends EditorPane {
|
|||
@IHostService private readonly hostService: IHostService,
|
||||
@IWebviewService private readonly webviewService: IWebviewService,
|
||||
@IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService,
|
||||
@optional(ITASExperimentService) tasExperimentService: ITASExperimentService,
|
||||
) {
|
||||
|
||||
super(GettingStartedPage.ID, telemetryService, themeService, storageService);
|
||||
|
@ -158,9 +155,6 @@ export class GettingStartedPage extends EditorPane {
|
|||
this.stepMediaComponent = $('.getting-started-media');
|
||||
this.stepMediaComponent.id = generateUuid();
|
||||
|
||||
|
||||
this.tasExperimentService = tasExperimentService;
|
||||
|
||||
this.contextService = this._register(contextService.createScoped(this.container));
|
||||
inGettingStartedContext.bindTo(this.contextService).set(true);
|
||||
|
||||
|
@ -797,28 +791,19 @@ export class GettingStartedPage extends EditorPane {
|
|||
const someStepsComplete = this.gettingStartedCategories.some(categry => categry.content.type === 'steps' && categry.content.stepsComplete);
|
||||
if (!someStepsComplete && !this.hasScrolledToFirstCategory) {
|
||||
|
||||
const fistContentBehaviour =
|
||||
!this.storageService.get(lastSessionDateStorageKey, StorageScope.GLOBAL) // isNewUser ?
|
||||
? 'openToFirstCategory'
|
||||
: await Promise.race([
|
||||
this.tasExperimentService?.getTreatment<'index' | 'openToFirstCategory'>('GettingStartedFirstContent'),
|
||||
new Promise<'index'>(resolve => setTimeout(() => resolve('index'), 1000)),
|
||||
]);
|
||||
const firstSessionDateString = this.storageService.get(firstSessionDateStorageKey, StorageScope.GLOBAL) || new Date().toUTCString();
|
||||
const daysSinceFirstSession = ((+new Date()) - (+new Date(firstSessionDateString))) / 1000 / 60 / 60 / 24;
|
||||
const fistContentBehaviour = daysSinceFirstSession < 1 ? 'openToFirstCategory' : 'index';
|
||||
|
||||
if (this.gettingStartedCategories.some(category => category.content.type === 'steps' && category.content.stepsComplete)) {
|
||||
this.setSlide('categories');
|
||||
return;
|
||||
} else {
|
||||
if (fistContentBehaviour === 'openToFirstCategory') {
|
||||
const first = this.gettingStartedCategories.find(category => category.content.type === 'steps');
|
||||
this.hasScrolledToFirstCategory = true;
|
||||
if (first) {
|
||||
this.currentCategory = first;
|
||||
this.editorInput.selectedCategory = this.currentCategory?.id;
|
||||
this.buildCategorySlide(this.editorInput.selectedCategory);
|
||||
this.setSlide('details');
|
||||
return;
|
||||
}
|
||||
if (fistContentBehaviour === 'openToFirstCategory') {
|
||||
const first = this.gettingStartedCategories.find(category => category.content.type === 'steps');
|
||||
this.hasScrolledToFirstCategory = true;
|
||||
if (first) {
|
||||
this.currentCategory = first;
|
||||
this.editorInput.selectedCategory = this.currentCategory?.id;
|
||||
this.buildCategorySlide(this.editorInput.selectedCategory);
|
||||
this.setSlide('details');
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@ import { localize } from 'vs/nls';
|
|||
import { IStartEntry, IWalkthrough } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry';
|
||||
|
||||
const titleTranslated = localize('title', "Title");
|
||||
|
||||
export const walkthroughsExtensionPoint = ExtensionsRegistry.registerExtensionPoint<IWalkthrough[]>({
|
||||
extensionPoint: 'walkthroughs',
|
||||
jsonSchema: {
|
||||
|
@ -64,10 +66,10 @@ export const walkthroughsExtensionPoint = ExtensionsRegistry.registerExtensionPo
|
|||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
description: localize('walkthroughs.steps.description', "Description of step. Supports ``preformatted``, __italic__, and **bold** text. Use markdown-style links for commands or external links: [Title](command:myext.command), [Title](command:toSide:myext.command), or [Title](https://aka.ms). Links on their own line will be rendered as buttons.")
|
||||
description: localize('walkthroughs.steps.description.interpolated', "Description of step. Supports ``preformatted``, __italic__, and **bold** text. Use markdown-style links for commands or external links: {0}, {1}, or {2}. Links on their own line will be rendered as buttons.", `[${titleTranslated}](command:myext.command)`, `[${titleTranslated}](command:toSide:myext.command)`, `[${titleTranslated}](https://aka.ms)`)
|
||||
},
|
||||
button: {
|
||||
deprecationMessage: localize('walkthroughs.steps.button.deprecated', "Deprecated. Use markdown links in the description instead, i.e. [Title](command:myext.command), [Title](command:toSide:myext.command), or [Title](https://aka.ms), "),
|
||||
deprecationMessage: localize('walkthroughs.steps.button.deprecated.interpolated', "Deprecated. Use markdown links in the description instead, i.e. {0}, {1}, or {2}", `[${titleTranslated}](command:myext.command)`, `[${titleTranslated}](command:toSide:myext.command)`, `[${titleTranslated}](https://aka.ms)`),
|
||||
},
|
||||
media: {
|
||||
type: 'object',
|
||||
|
|
|
@ -118,6 +118,8 @@ export const startEntries: GettingStartedStartEntryContent = [
|
|||
},
|
||||
];
|
||||
|
||||
const Button = (title: string, href: string) => `[${title}](${href})`;
|
||||
|
||||
export const walkthroughs: GettingStartedWalkthroughContent = [
|
||||
{
|
||||
id: 'Setup',
|
||||
|
@ -131,14 +133,17 @@ export const walkthroughs: GettingStartedWalkthroughContent = [
|
|||
{
|
||||
id: 'pickColorTheme',
|
||||
title: localize('gettingStarted.pickColor.title', "Choose the look you want"),
|
||||
description: localize('gettingStarted.pickColor.description', "The right color palette helps you focus on your code, is easy on your eyes, and is simply more fun to use.\n[Browse Color Themes](command:workbench.action.selectTheme)"),
|
||||
completionEvents: ['onSettingChanged:workbench.colorTheme'],
|
||||
description: localize('gettingStarted.pickColor.description.interpolated', "The right color palette helps you focus on your code, is easy on your eyes, and is simply more fun to use.\n{0}", Button(localize('titleID', "Browse Color Themes"), 'command:workbench.action.selectTheme')),
|
||||
completionEvents: [
|
||||
'onSettingChanged:workbench.colorTheme',
|
||||
'onCommand:workbench.action.selectTheme'
|
||||
],
|
||||
media: { type: 'markdown', path: 'example_markdown_media', }
|
||||
},
|
||||
{
|
||||
id: 'findLanguageExtensions',
|
||||
title: localize('gettingStarted.findLanguageExts.title', "Rich support for all your languages"),
|
||||
description: localize('gettingStarted.findLanguageExts.description', "Code smarter with syntax highlighting, code completion, linting and debugging. While many languages are built-in, many more can be added as extensions.\n[Browse Language Extensions](command:workbench.extensions.action.showLanguageExtensions)"),
|
||||
description: localize('gettingStarted.findLanguageExts.description.interpolated', "Code smarter with syntax highlighting, code completion, linting and debugging. While many languages are built-in, many more can be added as extensions.\n{0}", Button(localize('browseLangExts', "Browse Language Extensions"), 'command:workbench.extensions.action.showLanguageExtensions')),
|
||||
media: {
|
||||
type: 'image', altText: 'Language extensions', path: {
|
||||
dark: 'dark/languageExtensions.png',
|
||||
|
@ -150,7 +155,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [
|
|||
{
|
||||
id: 'commandPaletteTask',
|
||||
title: localize('gettingStarted.commandPalette.title', "One shortcut to access everything"),
|
||||
description: localize('gettingStarted.commandPalette.description', "Commands Palette is the keyboard way to accomplish any task in VS Code. **Practice** by looking up your frequently used commands to save time and keep in the flow.\n[Open Command Palette](command:workbench.action.showCommands)\n__Try searching for 'view toggle'.__"),
|
||||
description: localize('gettingStarted.commandPalette.description.interpolated', "Commands Palette is the keyboard way to accomplish any task in VS Code. **Practice** by looking up your frequently used commands to save time and keep in the flow.\n{0}\n__Try searching for 'view toggle'.__", Button(localize('commandPalette', "Open Command Palette"), 'command:workbench.action.showCommands')),
|
||||
media: {
|
||||
type: 'image', altText: 'Command Palette overlay for searching and executing commands.', path: {
|
||||
dark: 'dark/commandPalette.png',
|
||||
|
@ -162,7 +167,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [
|
|||
{
|
||||
id: 'workspaceTrust',
|
||||
title: localize('gettingStarted.workspaceTrust.title', "Safely browse and edit code"),
|
||||
description: localize('gettingStarted.workspaceTrust.description', "[Workspace Trust](https://github.com/microsoft/vscode-docs/blob/workspaceTrust/docs/editor/workspace-trust.md) lets you decide whether your project folders should **allow or restrict** automatic code execution __(required for extensions, debugging, etc)__.\nOpening a file/folder will prompt to grant trust. You can always [enable trust](command:toSide:workbench.action.manageTrustedDomain) later."),
|
||||
description: localize('gettingStarted.workspaceTrust.description.interpolated', "{0} lets you decide whether your project folders should **allow or restrict** automatic code execution __(required for extensions, debugging, etc)__.\nOpening a file/folder will prompt to grant trust. You can always {1} later.", Button(localize('workspaceTrust', "Workspace Trust"), 'https://github.com/microsoft/vscode-docs/blob/workspaceTrust/docs/editor/workspace-trust.md'), Button(localize('enableTrust', "enable trust"), 'command:toSide:workbench.action.manageTrustedDomain')),
|
||||
when: '!isWorkspaceTrusted && workspaceFolderCount == 0',
|
||||
media: {
|
||||
type: 'image', altText: 'Workspace Trust editor in Restricted mode and a primary button for switching to Trusted mode.', path: {
|
||||
|
@ -175,7 +180,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [
|
|||
{
|
||||
id: 'pickAFolderTask-Mac',
|
||||
title: localize('gettingStarted.setup.OpenFolder.title', "Open up your code"),
|
||||
description: localize('gettingStarted.setup.OpenFolder.description', "You're all set to start coding. Open a project folder to get your files into VS Code.\n[Pick a Folder](command:workbench.action.files.openFileFolder)"),
|
||||
description: localize('gettingStarted.setup.OpenFolder.description.interpolated', "You're all set to start coding. Open a project folder to get your files into VS Code.\n{0}", Button(localize('pickFolder', "Pick a Folder"), 'command:workbench.action.files.openFileFolder')),
|
||||
when: 'isMac && workspaceFolderCount == 0',
|
||||
media: {
|
||||
type: 'image', altText: 'Explorer view showing buttons for opening folder and cloning repository.', path: {
|
||||
|
@ -188,7 +193,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [
|
|||
{
|
||||
id: 'pickAFolderTask-Other',
|
||||
title: localize('gettingStarted.setup.OpenFolder.title', "Open up your code"),
|
||||
description: localize('gettingStarted.setup.OpenFolder.description2', "You're all set to start coding. Open a project folder to get your files into VS Code.\n[Pick a Folder](command:workbench.action.files.openFolder)"),
|
||||
description: localize('gettingStarted.setup.OpenFolder.description.interpolated', "You're all set to start coding. Open a project folder to get your files into VS Code.\n{0}", Button(localize('pickFolder', "Pick a Folder"), 'command:workbench.action.files.openFolder')),
|
||||
when: '!isMac && workspaceFolderCount == 0',
|
||||
media: {
|
||||
type: 'image', altText: 'Explorer view showing buttons for opening folder and cloning repository.', path: {
|
||||
|
@ -201,7 +206,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [
|
|||
{
|
||||
id: 'quickOpen',
|
||||
title: localize('gettingStarted.quickOpen.title', "Quickly navigate between your files"),
|
||||
description: localize('gettingStarted.quickOpen.description', "Navigate between files in an instant with one keystroke. Tip: Open multiple files by pressing the right arrow key.\n[Quick Open a File](command:toSide:workbench.action.quickOpen)"),
|
||||
description: localize('gettingStarted.quickOpen.description.interpolated', "Navigate between files in an instant with one keystroke. Tip: Open multiple files by pressing the right arrow key.\n{0}", Button(localize('quickOpen', "Quick Open a File"), 'command:toSide:workbench.action.quickOpen')),
|
||||
when: 'workspaceFolderCount != 0',
|
||||
media: {
|
||||
type: 'image', altText: 'Go to file in quick search.', path: {
|
||||
|
@ -227,7 +232,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [
|
|||
{
|
||||
id: 'playground',
|
||||
title: localize('gettingStarted.playground.title', "Redefine your editing skills"),
|
||||
description: localize('gettingStarted.playground.description', "Want to code faster and smarter? Practice powerful code editing features in the interactive playground.\n[Open Interactive Playground](command:toSide:workbench.action.showInteractivePlayground)"),
|
||||
description: localize('gettingStarted.playground.description.interpolated', "Want to code faster and smarter? Practice powerful code editing features in the interactive playground.\n{0}", Button(localize('openInteractivePlayground', "Open Interactive Playground"), 'command:toSide:workbench.action.showInteractivePlayground')),
|
||||
media: {
|
||||
type: 'image', altText: 'Interactive Playground.', path: {
|
||||
dark: 'dark/playground.png',
|
||||
|
@ -239,7 +244,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [
|
|||
{
|
||||
id: 'terminal',
|
||||
title: localize('gettingStarted.terminal.title', "Convenient built-in terminal"),
|
||||
description: localize('gettingStarted.terminal.description', "Quickly run shell commands and monitor build output, right next to your code.\n[Show Terminal Panel](command:workbench.action.terminal.toggleTerminal)"),
|
||||
description: localize('gettingStarted.terminal.description.interpolated', "Quickly run shell commands and monitor build output, right next to your code.\n{0}", Button(localize('showTerminal', "Show Terminal Panel"), 'command:workbench.action.terminal.toggleTerminal')),
|
||||
when: 'remoteName != codespaces && !terminalIsOpen',
|
||||
media: {
|
||||
type: 'image', altText: 'Integrated terminal running a few npm commands', path: {
|
||||
|
@ -252,7 +257,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [
|
|||
{
|
||||
id: 'extensions',
|
||||
title: localize('gettingStarted.extensions.title', "Limitless extensibility"),
|
||||
description: localize('gettingStarted.extensions.description', "Extensions are VS Code's power-ups. They range from handy productivity hacks, expanding out-of-the-box features, to adding completely new capabilities.\n[Browse Recommended Extensions](command:workbench.extensions.action.showRecommendedExtensions)"),
|
||||
description: localize('gettingStarted.extensions.description.interpolated', "Extensions are VS Code's power-ups. They range from handy productivity hacks, expanding out-of-the-box features, to adding completely new capabilities.\n{0}", Button(localize('browseRecommended', "Browse Recommended Extensions"), 'command:workbench.extensions.action.showRecommendedExtensions')),
|
||||
media: {
|
||||
type: 'image', altText: 'VS Code extension marketplace with featured language extensions', path: {
|
||||
dark: 'dark/extensions.png',
|
||||
|
@ -264,7 +269,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [
|
|||
{
|
||||
id: 'settings',
|
||||
title: localize('gettingStarted.settings.title', "Tune your settings"),
|
||||
description: localize('gettingStarted.settings.description', "Tweak every aspect of VS Code and your extensions to your liking. Commonly used settings are listed first to get you started.\n[Tweak my Settings](command:toSide:workbench.action.openSettings)"),
|
||||
description: localize('gettingStarted.settings.description.interpolated', "Tweak every aspect of VS Code and your extensions to your liking. Commonly used settings are listed first to get you started.\n{0}", Button(localize('tweakSettings', "Tweak my Settings"), 'command:toSide:workbench.action.openSettings')),
|
||||
media: {
|
||||
type: 'image', altText: 'VS Code Settings', path: {
|
||||
dark: 'dark/settings.png',
|
||||
|
@ -276,7 +281,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [
|
|||
{
|
||||
id: 'settingsSync',
|
||||
title: localize('gettingStarted.settingsSync.title', "Sync your stuff across devices"),
|
||||
description: localize('gettingStarted.settingsSync.description', "Never lose the perfect VS Code setup! Settings Sync will back up and share settings, keybindings & extensions across several installations.\n[Enable Settings Sync](command:workbench.userDataSync.actions.turnOn)"),
|
||||
description: localize('gettingStarted.settingsSync.description.interpolated', "Never lose the perfect VS Code setup! Settings Sync will back up and share settings, keybindings & extensions across several installations.\n{0}", Button(localize('enableSync', "Enable Settings Sync"), 'command:workbench.userDataSync.actions.turnOn')),
|
||||
when: 'syncStatus != uninitialized',
|
||||
completionEvents: ['onEvent:sync-enabled'],
|
||||
media: {
|
||||
|
@ -290,7 +295,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [
|
|||
{
|
||||
id: 'videoTutorial',
|
||||
title: localize('gettingStarted.videoTutorial.title', "Lean back and learn"),
|
||||
description: localize('gettingStarted.videoTutorial.description', "Watch the first in a series of short & practical video tutorials for VS Code's key features.\n[Watch Tutorial](https://aka.ms/vscode-getting-started-video)"),
|
||||
description: localize('gettingStarted.videoTutorial.description.interpolated', "Watch the first in a series of short & practical video tutorials for VS Code's key features.\n{0}", Button(localize('watch', "Watch Tutorial"), 'https://aka.ms/vscode-getting-started-video')),
|
||||
media: { type: 'image', altText: 'VS Code Settings', path: 'tutorialVideo.png' },
|
||||
}
|
||||
]
|
||||
|
@ -308,7 +313,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [
|
|||
{
|
||||
id: 'splitview',
|
||||
title: localize('gettingStarted.splitview.title', "Side by side editing"),
|
||||
description: localize('gettingStarted.splitview.description', "Make the most of your screen estate by opening files side by side, vertically and horizontally.\n[Split Editor](command:workbench.action.splitEditor)"),
|
||||
description: localize('gettingStarted.splitview.description.interpolated', "Make the most of your screen estate by opening files side by side, vertically and horizontally.\n{0}", Button(localize('splitEditor', "Split Editor"), 'command:workbench.action.splitEditor')),
|
||||
media: {
|
||||
type: 'image', altText: 'Multiple editors in split view.', path: {
|
||||
dark: 'dark/splitview.png',
|
||||
|
@ -320,7 +325,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [
|
|||
{
|
||||
id: 'debugging',
|
||||
title: localize('gettingStarted.debug.title', "Watch your code in action"),
|
||||
description: localize('gettingStarted.debug.description', "Accelerate your edit, build, test, and debug loop by setting up a launch configuration.\n[Run your Project](command:workbench.action.debug.selectandstart)"),
|
||||
description: localize('gettingStarted.debug.description.interpolated', "Accelerate your edit, build, test, and debug loop by setting up a launch configuration.\n{0}", Button(localize('runProject', "Run your Project"), 'command:workbench.action.debug.selectandstart')),
|
||||
when: 'workspaceFolderCount != 0',
|
||||
media: {
|
||||
type: 'image', altText: 'Run and debug view.', path: {
|
||||
|
@ -333,7 +338,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [
|
|||
{
|
||||
id: 'scmClone',
|
||||
title: localize('gettingStarted.scm.title', "Track your code with Git"),
|
||||
description: localize('gettingStarted.scmClone.description', "Set up the built-in version control for your project to track your changes and collaborate with others.\n[Clone Repository](command:git.clone)"),
|
||||
description: localize('gettingStarted.scmClone.description.interpolated', "Set up the built-in version control for your project to track your changes and collaborate with others.\n{0}", Button(localize('cloneRepo', "Clone Repository"), 'command:git.clone')),
|
||||
when: 'config.git.enabled && !git.missing && workspaceFolderCount == 0',
|
||||
media: {
|
||||
type: 'image', altText: 'Source Control view.', path: {
|
||||
|
@ -346,7 +351,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [
|
|||
{
|
||||
id: 'scmSetup',
|
||||
title: localize('gettingStarted.scm.title', "Track your code with Git"),
|
||||
description: localize('gettingStarted.scmSetup.description', "Set up the built-in version control for your project to track your changes and collaborate with others.\n[Initialize Git Repository](command:git.init)"),
|
||||
description: localize('gettingStarted.scmSetup.description.interpolated', "Set up the built-in version control for your project to track your changes and collaborate with others.\n{0}", Button(localize('initRepo', "Initialize Git Repository"), 'command:git.init')),
|
||||
when: 'config.git.enabled && !git.missing && workspaceFolderCount != 0 && gitOpenRepositoryCount == 0',
|
||||
media: {
|
||||
type: 'image', altText: 'Source Control view.', path: {
|
||||
|
@ -359,7 +364,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [
|
|||
{
|
||||
id: 'scm',
|
||||
title: localize('gettingStarted.scm.title', "Track your code with Git"),
|
||||
description: localize('gettingStarted.scm.description', "No more looking up Git commands! Git and GitHub workflows are seamlessly integrated.\n[Open Source Control](command:workbench.view.scm)"),
|
||||
description: localize('gettingStarted.scm.description.interpolated', "No more looking up Git commands! Git and GitHub workflows are seamlessly integrated.\n{0}", Button(localize('openSCM', "Open Source Control"), 'command:workbench.view.scm')),
|
||||
when: 'config.git.enabled && !git.missing && workspaceFolderCount != 0 && gitOpenRepositoryCount != 0 && activeViewlet != \'workbench.view.scm\'',
|
||||
media: {
|
||||
type: 'image', altText: 'Source Control view.', path: {
|
||||
|
@ -373,7 +378,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [
|
|||
id: 'tasks',
|
||||
title: localize('gettingStarted.tasks.title', "Automate your project tasks"),
|
||||
when: 'workspaceFolderCount != 0',
|
||||
description: localize('gettingStarted.tasks.description', "Create tasks for your common workflows and enjoy the integrated experience of running scripts and automatically checking results.\n[Run Auto-detected Tasks](command:workbench.action.tasks.runTask)"),
|
||||
description: localize('gettingStarted.tasks.description.interpolated', "Create tasks for your common workflows and enjoy the integrated experience of running scripts and automatically checking results.\n{0}", Button(localize('runTasks', "Run Auto-detected Tasks"), 'command:workbench.action.tasks.runTask')),
|
||||
media: {
|
||||
type: 'image', altText: 'Task runner.', path: {
|
||||
dark: 'dark/tasks.png',
|
||||
|
@ -385,7 +390,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [
|
|||
{
|
||||
id: 'shortcuts',
|
||||
title: localize('gettingStarted.shortcuts.title', "Customize your shortcuts"),
|
||||
description: localize('gettingStarted.shortcuts.description', "Once you have discovered your favorite commands, create custom keyboard shortcuts for instant access.\n[Keyboard Shortcuts](command:toSide:workbench.action.openGlobalKeybindings)"),
|
||||
description: localize('gettingStarted.shortcuts.description.interpolated', "Once you have discovered your favorite commands, create custom keyboard shortcuts for instant access.\n{0}", Button(localize('keyboardShortcuts', "Keyboard Shortcuts"), 'command:toSide:workbench.action.openGlobalKeybindings')),
|
||||
media: {
|
||||
type: 'image', altText: 'Interactive shortcuts.', path: {
|
||||
dark: 'dark/shortcuts.png',
|
||||
|
|
|
@ -25,7 +25,7 @@ Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration)
|
|||
'enumDescriptions': [
|
||||
localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.none' }, "Start without an editor."),
|
||||
localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.welcomePage' }, "Open the legacy Welcome page."),
|
||||
localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.readme' }, "Open the README when opening a folder that contains one, fallback to 'welcomePage' otherwise."),
|
||||
localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.readme' }, "Open the README when opening a folder that contains one, fallback to 'welcomePage' otherwise. Note: This is only observed as a global ccnfiguration, it will be ignored if set in a workspace or folder configuration."),
|
||||
localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.newUntitledFile' }, "Open a new untitled file (only applies when opening an empty window)."),
|
||||
localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.welcomePageInEmptyWorkbench' }, "Open the legacy Welcome page when opening an empty workbench."),
|
||||
localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.gettingStarted' }, "Open the new Welcome Page with content to aid in getting started with VS Code and extensions."),
|
||||
|
|
|
@ -637,7 +637,7 @@ Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration)
|
|||
},
|
||||
[WORKSPACE_TRUST_EMPTY_WINDOW]: {
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
default: true,
|
||||
included: !isWeb,
|
||||
markdownDescription: localize('workspace.trust.emptyWindow.description', "Controls whether or not the empty window is trusted by default within VS Code. When used with `#{0}#`, you can enable the full functionality of VS Code without prompting in an empty window.", WORKSPACE_TRUST_UNTRUSTED_FILES),
|
||||
scope: ConfigurationScope.APPLICATION
|
||||
|
|
|
@ -823,13 +823,13 @@ export class WorkspaceTrustEditor extends EditorPane {
|
|||
[
|
||||
localize('untrustedTasks', "Tasks are disabled"),
|
||||
localize('untrustedDebugging', "Debugging is disabled"),
|
||||
localize('untrustedExtensions', "[{0} extensions](command:{1}) are disabled or have limited functionality", numExtensions, LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID)
|
||||
localize('untrustedExtensions', "[{0} extensions]({1}) are disabled or have limited functionality", numExtensions, `command:${LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID}`)
|
||||
] :
|
||||
[
|
||||
localize('untrustedTasks', "Tasks are disabled"),
|
||||
localize('untrustedDebugging', "Debugging is disabled"),
|
||||
numSettings ? localize('untrustedSettings', "[{0} workspace settings](command:{1}) are not applied", numSettings, 'settings.filterUntrusted') : localize('no untrustedSettings', "Workspace settings requiring trust are not applied"),
|
||||
localize('untrustedExtensions', "[{0} extensions](command:{1}) are disabled or have limited functionality", numExtensions, LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID)
|
||||
numSettings ? localize('untrustedSettings', "[{0} workspace settings]({1}) are not applied", numSettings, 'command:settings.filterUntrusted') : localize('no untrustedSettings', "Workspace settings requiring trust are not applied"),
|
||||
localize('untrustedExtensions', "[{0} extensions]({1}) are disabled or have limited functionality", numExtensions, `command:${LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID}`)
|
||||
];
|
||||
this.renderLimitationsListElement(untrustedContainer, untrustedContainerItems, xListIcon.classNamesArray);
|
||||
|
||||
|
|
Loading…
Reference in a new issue