diff --git a/.eslintrc.json b/.eslintrc.json index 63fb6b80ac5..df8c35d28ed 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -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", { diff --git a/.github/workflows/english-please.yml b/.github/workflows/english-please.yml index a11a9a357c6..48e675a1804 100644 --- a/.github/workflows/english-please.yml +++ b/.github/workflows/english-please.yml @@ -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}} diff --git a/build/lib/eslint/vscode-dts-vscode-in-comments.js b/build/lib/eslint/vscode-dts-vscode-in-comments.js new file mode 100644 index 00000000000..8f9a13fb01f --- /dev/null +++ b/build/lib/eslint/vscode-dts-vscode-in-comments.js @@ -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 } + }); + } + } + } + }; + } +}; diff --git a/build/lib/eslint/vscode-dts-vscode-in-comments.ts b/build/lib/eslint/vscode-dts-vscode-in-comments.ts new file mode 100644 index 00000000000..8ced8eb25fd --- /dev/null +++ b/build/lib/eslint/vscode-dts-vscode-in-comments.ts @@ -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 } + }); + } + } + } + }; + } +}; diff --git a/build/npm/update-localization-extension.js b/build/npm/update-localization-extension.js index 7c6a73aa9d8..976776c6901 100644 --- a/build/npm/update-localization-extension.js +++ b/build/npm/update-localization-extension.js @@ -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'); } }); }); diff --git a/extensions/markdown-language-features/notebook/index.ts b/extensions/markdown-language-features/notebook/index.ts index 371091691b7..4dc45856e45 100644 --- a/extensions/markdown-language-features/notebook/index.ts +++ b/extensions/markdown-language-features/notebook/index.ts @@ -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) => { diff --git a/extensions/typescript-language-features/src/typescriptServiceClient.ts b/extensions/typescript-language-features/src/typescriptServiceClient.ts index 4990b4ce1c7..279d0e2d4d8 100644 --- a/extensions/typescript-language-features/src/typescriptServiceClient.ts +++ b/extensions/typescript-language-features/src/typescriptServiceClient.ts @@ -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)); } } diff --git a/src/vs/base/common/actions.ts b/src/vs/base/common/actions.ts index 9125a2c5837..8c1b0858674 100644 --- a/src/vs/base/common/actions.ts +++ b/src/vs/base/common/actions.ts @@ -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) { diff --git a/src/vs/base/common/iterator.ts b/src/vs/base/common/iterator.ts index f7d81bf5bbc..4e325694222 100644 --- a/src/vs/base/common/iterator.ts +++ b/src/vs/base/common/iterator.ts @@ -30,7 +30,7 @@ export namespace Iterable { return iterable[Symbol.iterator]().next().value; } - export function some(iterable: Iterable, predicate: (t: T) => boolean): boolean { + export function some(iterable: Iterable, predicate: (t: T) => unknown): boolean { for (const element of iterable) { if (predicate(element)) { return true; diff --git a/src/vs/editor/contrib/hover/hover.ts b/src/vs/editor/contrib/hover/hover.ts index 9d8a6c8ee37..4a50358b6b4 100644 --- a/src/vs/editor/contrib/hover/hover.ts +++ b/src/vs/editor/contrib/hover/hover.ts @@ -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}; }`); diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 77b7c5465dc..327f4f98c18 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -1989,7 +1989,7 @@ declare module 'vscode' { * { language: 'typescript', scheme: 'file' } * * @example A language filter that applies to all package.json paths - * { 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; @@ -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; /** - * 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 *