diff --git a/README.md b/README.md index 5d39d7e40c6..0de5f2f71da 100644 --- a/README.md +++ b/README.md @@ -22,8 +22,6 @@ This repository ("`Code - OSS`") is where we (Microsoft) develop the [Visual Stu Visual Studio Code is updated monthly with new features and bug fixes. You can download it for Windows, macOS, and Linux on [Visual Studio Code's website](https://code.visualstudio.com/Download). To get the latest releases every day, install the [Insiders build](https://code.visualstudio.com/insiders). - - ## Contributing There are many ways in which you can participate in the project, for example: @@ -52,11 +50,11 @@ please see the document [How to Contribute](https://github.com/Microsoft/vscode/ ## Related Projects -Many of the core components and extensions to Code live in their own repositories on GitHub. For example, the [node debug adapter](https://github.com/microsoft/vscode-node-debug) and the [mono debug adapter](https://github.com/microsoft/vscode-mono-debug) have their own repositories. For a complete list, please visit the [Related Projects](https://github.com/Microsoft/vscode/wiki/Related-Projects) page on our [wiki](https://github.com/Microsoft/vscode/wiki). +Many of the core components and extensions to VS Code live in their own repositories on GitHub. For example, the [node debug adapter](https://github.com/microsoft/vscode-node-debug) and the [mono debug adapter](https://github.com/microsoft/vscode-mono-debug) have their own repositories. For a complete list, please visit the [Related Projects](https://github.com/Microsoft/vscode/wiki/Related-Projects) page on our [wiki](https://github.com/Microsoft/vscode/wiki). ## Bundled Extensions -Code includes a set of built-in extensions located in the [extensions](extensions) folder, including grammars and snippets for many languages. Extensions that provide rich language support (code completion, Go to Definition) for a language have the suffix `language-features`. For example, the `json` extension provides coloring for `JSON` and the `json-language-features` provides rich language support for `JSON`. +VS Code includes a set of built-in extensions located in the [extensions](extensions) folder, including grammars and snippets for many languages. Extensions that provide rich language support (code completion, Go to Definition) for a language have the suffix `language-features`. For example, the `json` extension provides coloring for `JSON` and the `json-language-features` provides rich language support for `JSON`. ## Code of Conduct diff --git a/extensions/git/extension.webpack.config.js b/extensions/git/extension.webpack.config.js index 5efa2052e88..bf6953d3183 100644 --- a/extensions/git/extension.webpack.config.js +++ b/extensions/git/extension.webpack.config.js @@ -13,6 +13,6 @@ module.exports = withDefaults({ context: __dirname, entry: { main: './src/main.ts', - ['askpass-main']: './src/askpass-main.ts' + ['askpass-main']: './src/askpass/askpass-main.ts' } }); diff --git a/extensions/git/package.json b/extensions/git/package.json index 9d7086dbaad..d801ec64f97 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -1608,12 +1608,6 @@ "default": "mixed", "description": "%config.untrackedChanges%", "scope": "resource" - }, - "git.restoreCommitTemplateComments": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "%config.restoreCommitTemplateComments%" } } }, diff --git a/extensions/git/package.nls.json b/extensions/git/package.nls.json index c4821f5decd..5c357b40eb0 100644 --- a/extensions/git/package.nls.json +++ b/extensions/git/package.nls.json @@ -139,7 +139,6 @@ "config.untrackedChanges.mixed": "All changes, tracked and untracked, appear together and behave equally.", "config.untrackedChanges.separate": "Untracked changes appear separately in the Source Control view. They are also excluded from several actions.", "config.untrackedChanges.hidden": "Untracked changes are hidden and excluded from several actions.", - "config.restoreCommitTemplateComments": "Controls whether to restore commit template comments in the commit input box.", "colors.added": "Color for added resources.", "colors.modified": "Color for modified resources.", "colors.deleted": "Color for deleted resources.", diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index 432e16b8231..5dd981bbd9c 100644 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -1406,6 +1406,7 @@ export class CommandCenter { const message = repository.inputBox.value; const getCommitMessage = async () => { let _message: string | undefined = message; + if (!_message) { let value: string | undefined = undefined; @@ -1430,7 +1431,7 @@ export class CommandCenter { }); } - return _message ? repository.cleanUpCommitEditMessage(_message) : _message; + return _message; }; const didCommit = await this.smartCommit(repository, getCommitMessage, opts); diff --git a/extensions/git/src/git.ts b/extensions/git/src/git.ts index a710a539c29..193907a15bd 100644 --- a/extensions/git/src/git.ts +++ b/extensions/git/src/git.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as fs from 'fs'; +import { promises as fs, exists } from 'fs'; import * as path from 'path'; import * as os from 'os'; import * as cp from 'child_process'; @@ -11,7 +11,7 @@ import * as which from 'which'; import { EventEmitter } from 'events'; import iconv = require('iconv-lite'); import * as filetype from 'file-type'; -import { assign, groupBy, denodeify, IDisposable, toDisposable, dispose, mkdirp, readBytes, detectUnicodeEncoding, Encoding, onceEvent, splitInChunks, Limiter } from './util'; +import { assign, groupBy, IDisposable, toDisposable, dispose, mkdirp, readBytes, detectUnicodeEncoding, Encoding, onceEvent, splitInChunks, Limiter } from './util'; import { CancellationToken, Progress } from 'vscode'; import { URI } from 'vscode-uri'; import { detectEncoding } from './encoding'; @@ -22,8 +22,6 @@ import { StringDecoder } from 'string_decoder'; // https://github.com/microsoft/vscode/issues/65693 const MAX_CLI_LENGTH = 30000; -const readfile = denodeify(fs.readFile); - export interface IGit { path: string; version: string; @@ -350,7 +348,7 @@ export class Git { let folderPath = path.join(parentPath, folderName); let count = 1; - while (count < 20 && await new Promise(c => fs.exists(folderPath, c))) { + while (count < 20 && await new Promise(c => exists(folderPath, c))) { folderName = `${baseFolderName}-${count++}`; folderPath = path.join(parentPath, folderName); } @@ -1812,26 +1810,17 @@ export class Repository { } } - cleanupCommitEditMessage(message: string): string { - // If the message is a single line starting with whitespace followed by `#`, just allow it. - if (/^\s*#[^\n]*$/.test(message)) { - return message; - } - - // Else, remove all lines starting with whitespace followed by `#`. - // TODO: Support core.commentChar - return message.replace(/^(\s*#)(.*)$(\n?)/gm, (_, prefix, content, suffix) => { - // https://github.com/microsoft/vscode/issues/84201#issuecomment-552834814 - return /^\d/.test(content) ? `${prefix}${content}${suffix}` : ''; - }).trim(); + // TODO: Support core.commentChar + stripCommitMessageComments(message: string): string { + return message.replace(/^\s*#.*$\n?/gm, '').trim(); } async getMergeMessage(): Promise { const mergeMsgPath = path.join(this.repositoryRoot, '.git', 'MERGE_MSG'); try { - const raw = await readfile(mergeMsgPath, 'utf8'); - return raw.trim(); + const raw = await fs.readFile(mergeMsgPath, 'utf8'); + return this.stripCommitMessageComments(raw); } catch { return undefined; } @@ -1854,9 +1843,8 @@ export class Repository { templatePath = path.join(this.repositoryRoot, templatePath); } - const raw = await readfile(templatePath, 'utf8'); - return raw.trim(); - + const raw = await fs.readFile(templatePath, 'utf8'); + return this.stripCommitMessageComments(raw); } catch (err) { return ''; } @@ -1879,7 +1867,7 @@ export class Repository { const gitmodulesPath = path.join(this.root, '.gitmodules'); try { - const gitmodulesRaw = await readfile(gitmodulesPath, 'utf8'); + const gitmodulesRaw = await fs.readFile(gitmodulesPath, 'utf8'); return parseGitmodules(gitmodulesRaw); } catch (err) { if (/ENOENT/.test(err.message)) { diff --git a/extensions/git/src/ipc/ipcServer.ts b/extensions/git/src/ipc/ipcServer.ts index 39d2b59e6f8..332490896cc 100644 --- a/extensions/git/src/ipc/ipcServer.ts +++ b/extensions/git/src/ipc/ipcServer.ts @@ -4,15 +4,13 @@ *--------------------------------------------------------------------------------------------*/ import { Disposable } from 'vscode'; -import { denodeify, toDisposable } from '../util'; +import { toDisposable } from '../util'; import * as path from 'path'; import * as http from 'http'; import * as os from 'os'; import * as fs from 'fs'; import * as crypto from 'crypto'; -const randomBytes = denodeify(crypto.randomBytes); - function getIPCHandlePath(nonce: string): string { if (process.platform === 'win32') { return `\\\\.\\pipe\\vscode-git-ipc-${nonce}-sock`; @@ -31,7 +29,7 @@ export interface IIPCHandler { export async function createIPCServer(): Promise { const server = http.createServer(); - const buffer = await randomBytes(20); + const buffer = await new Promise((c, e) => crypto.randomBytes(20, (err, buf) => err ? e(err) : c(buf))); const nonce = buffer.toString('hex'); const ipcHandlePath = getIPCHandlePath(nonce); diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index 5f3c9bee464..4edc79262d2 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -844,15 +844,7 @@ export class Repository implements Disposable { return mergeMessage; } - let template = await this.repository.getCommitTemplate(); - - const config = workspace.getConfiguration('git', Uri.file(this.root)); - - if (!config.get('restoreCommitTemplateComments')) { - template = this.cleanUpCommitEditMessage(template); - } - - return template; + return await this.repository.getCommitTemplate(); } getConfigs(): Promise<{ key: string; value: string; }[]> { @@ -1286,10 +1278,6 @@ export class Repository implements Disposable { return await this.run(Operation.GetCommitTemplate, async () => this.repository.getCommitTemplate()); } - cleanUpCommitEditMessage(editMessage: string): string { - return this.repository.cleanupCommitEditMessage(editMessage); - } - async ignore(files: Uri[]): Promise { return await this.run(Operation.Ignore, async () => { const ignoreFile = `${this.repository.root}${path.sep}.gitignore`; diff --git a/extensions/git/src/util.ts b/extensions/git/src/util.ts index 0722cb16fbd..3110168343b 100644 --- a/extensions/git/src/util.ts +++ b/extensions/git/src/util.ts @@ -6,7 +6,7 @@ import { Event } from 'vscode'; import { dirname, sep } from 'path'; import { Readable } from 'stream'; -import * as fs from 'fs'; +import { promises as fs, createReadStream } from 'fs'; import * as byline from 'byline'; export function log(...args: any[]): void { @@ -140,25 +140,14 @@ export function groupBy(arr: T[], fn: (el: T) => string): { [key: string]: T[ }, Object.create(null)); } -export function denodeify(fn: Function): (a: A, b: B, c: C) => Promise; -export function denodeify(fn: Function): (a: A, b: B) => Promise; -export function denodeify(fn: Function): (a: A) => Promise; -export function denodeify(fn: Function): (...args: any[]) => Promise; -export function denodeify(fn: Function): (...args: any[]) => Promise { - return (...args) => new Promise((c, e) => fn(...args, (err: any, r: any) => err ? e(err) : c(r))); -} - -export function nfcall(fn: Function, ...args: any[]): Promise { - return new Promise((c, e) => fn(...args, (err: any, r: any) => err ? e(err) : c(r))); -} export async function mkdirp(path: string, mode?: number): Promise { const mkdir = async () => { try { - await nfcall(fs.mkdir, path, mode); + await fs.mkdir(path, mode); } catch (err) { if (err.code === 'EEXIST') { - const stat = await nfcall(fs.stat, path); + const stat = await fs.stat(path); if (stat.isDirectory()) { return; @@ -232,7 +221,7 @@ export function find(array: T[], fn: (t: T) => boolean): T | undefined { export async function grep(filename: string, pattern: RegExp): Promise { return new Promise((c, e) => { - const fileStream = fs.createReadStream(filename, { encoding: 'utf8' }); + const fileStream = createReadStream(filename, { encoding: 'utf8' }); const stream = byline(fileStream); stream.on('data', (line: string) => { if (pattern.test(line)) { diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts index ba6ea61595a..e8a190d2a7d 100644 --- a/src/vs/base/browser/dom.ts +++ b/src/vs/base/browser/dom.ts @@ -267,6 +267,12 @@ export let addStandardDisposableListener: IAddStandardDisposableListenerSignatur return addDisposableListener(node, type, wrapHandler, useCapture); }; +export let addStandardDisposableGenericMouseDownListner = function addStandardDisposableListener(node: HTMLElement, handler: (event: any) => void, useCapture?: boolean): IDisposable { + let wrapHandler = _wrapAsStandardMouseEvent(handler); + + return addDisposableGenericMouseDownListner(node, wrapHandler, useCapture); +}; + export function addDisposableGenericMouseDownListner(node: EventTarget, handler: (event: any) => void, useCapture?: boolean): IDisposable { return addDisposableListener(node, platform.isIOS && BrowserFeatures.pointerEvents ? EventType.POINTER_DOWN : EventType.MOUSE_DOWN, handler, useCapture); } @@ -506,7 +512,16 @@ export function getClientArea(element: HTMLElement): Dimension { // If visual view port exits and it's on mobile, it should be used instead of window innerWidth / innerHeight, or document.body.clientWidth / document.body.clientHeight if (platform.isIOS && (window).visualViewport) { - return new Dimension((window).visualViewport.width, (window).visualViewport.height); + const width = (window).visualViewport.width; + const height = (window).visualViewport.height - ( + browser.isStandalone + // in PWA mode, the visual viewport always includes the safe-area-inset-bottom (which is for the home indicator) + // even when you are using the onscreen monitor, the visual viewport will include the area between system statusbar and the onscreen keyboard + // plus the area between onscreen keyboard and the bottom bezel, which is 20px on iOS. + ? (20 + 4) // + 4px for body margin + : 0 + ); + return new Dimension(width, height); } // Try innerWidth / innerHeight diff --git a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css index 4dfc8f69330..2e259eda4f2 100644 --- a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css +++ b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css @@ -5,7 +5,7 @@ @font-face { font-family: "codicon"; - src: url("./codicon.ttf?6e26276ebddb23b7baa20bf099ba8332") format("truetype"); + src: url("./codicon.ttf?c4e66586cd3ad4acc55fc456c0760dec") format("truetype"); } .codicon[class*='codicon-'] { @@ -401,5 +401,8 @@ .codicon-debug-breakpoint-stackframe-focused:before { content: "\eb8b" } .codicon-debug-breakpoint-unsupported:before { content: "\eb8c" } .codicon-symbol-string:before { content: "\eb8d" } -.codicon-debug-reverse-continue:before { content: "\f101" } -.codicon-debug-step-back:before { content: "\f102" } +.codicon-debug-reverse-continue:before { content: "\eb8e" } +.codicon-debug-step-back:before { content: "\eb8f" } +.codicon-debug-restart-frame:before { content: "\eb90" } +.codicon-debug-alternate:before { content: "\eb91" } +.codicon-debug-alt:before { content: "\f101" } diff --git a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.ttf b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.ttf index a8ad5305b94..a51c284681e 100644 Binary files a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.ttf and b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.ttf differ diff --git a/src/vs/editor/browser/controller/pointerHandler.ts b/src/vs/editor/browser/controller/pointerHandler.ts index f1a997e1a4d..46894f1be15 100644 --- a/src/vs/editor/browser/controller/pointerHandler.ts +++ b/src/vs/editor/browser/controller/pointerHandler.ts @@ -226,6 +226,10 @@ export class PointerEventHandler extends MouseHandler { } private onTap(event: GestureEvent): void { + if (!event.initialTarget || !this.viewHelper.linesContentDomNode.contains(event.initialTarget)) { + return; + } + event.preventDefault(); this.viewHelper.focusTextArea(); const target = this._createMouseTarget(new EditorMouseEvent(event, this.viewHelper.viewDomNode), false); diff --git a/src/vs/editor/contrib/codeAction/codeActionCommands.ts b/src/vs/editor/contrib/codeAction/codeActionCommands.ts index c51443c95c3..8185eca6b17 100644 --- a/src/vs/editor/contrib/codeAction/codeActionCommands.ts +++ b/src/vs/editor/contrib/codeAction/codeActionCommands.ts @@ -106,7 +106,7 @@ export class QuickFixController extends Disposable implements IEditorContributio } } } - }, contextMenuService, keybindingService)) + }, this._instantiationService)) ); } diff --git a/src/vs/editor/contrib/codeAction/codeActionWidget.ts b/src/vs/editor/contrib/codeAction/codeActionMenu.ts similarity index 97% rename from src/vs/editor/contrib/codeAction/codeActionWidget.ts rename to src/vs/editor/contrib/codeAction/codeActionMenu.ts index 4e85aa712d2..c2cdc9c4f0f 100644 --- a/src/vs/editor/contrib/codeAction/codeActionWidget.ts +++ b/src/vs/editor/contrib/codeAction/codeActionMenu.ts @@ -43,7 +43,7 @@ export interface CodeActionShowOptions { readonly includeDisabledActions: boolean; } -export class CodeActionWidget extends Disposable { +export class CodeActionMenu extends Disposable { private _visible: boolean = false; private readonly _showingActions = this._register(new MutableDisposable()); @@ -52,9 +52,9 @@ export class CodeActionWidget extends Disposable { constructor( private readonly _editor: ICodeEditor, - private readonly _contextMenuService: IContextMenuService, - keybindingService: IKeybindingService, private readonly _delegate: CodeActionWidgetDelegate, + @IContextMenuService private readonly _contextMenuService: IContextMenuService, + @IKeybindingService keybindingService: IKeybindingService, ) { super(); diff --git a/src/vs/editor/contrib/codeAction/codeActionUi.ts b/src/vs/editor/contrib/codeAction/codeActionUi.ts index 61f1a9b29dd..5c34b32fe7f 100644 --- a/src/vs/editor/contrib/codeAction/codeActionUi.ts +++ b/src/vs/editor/contrib/codeAction/codeActionUi.ts @@ -13,16 +13,15 @@ import { IPosition } from 'vs/editor/common/core/position'; import { CodeAction } from 'vs/editor/common/modes'; import { CodeActionSet } from 'vs/editor/contrib/codeAction/codeAction'; import { MessageController } from 'vs/editor/contrib/message/messageController'; -import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { CodeActionsState } from './codeActionModel'; -import { CodeActionWidget, CodeActionShowOptions } from './codeActionWidget'; +import { CodeActionMenu, CodeActionShowOptions } from './codeActionMenu'; import { LightBulbWidget } from './lightBulbWidget'; import { CodeActionAutoApply, CodeActionTrigger } from './types'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; export class CodeActionUi extends Disposable { - private readonly _codeActionWidget: Lazy; + private readonly _codeActionWidget: Lazy; private readonly _lightBulbWidget: Lazy; private readonly _activeCodeActions = this._register(new MutableDisposable()); @@ -33,13 +32,12 @@ export class CodeActionUi extends Disposable { private readonly delegate: { applyCodeAction: (action: CodeAction, regtriggerAfterApply: boolean) => Promise }, - @IContextMenuService contextMenuService: IContextMenuService, - @IKeybindingService keybindingService: IKeybindingService, + @IInstantiationService instantiationService: IInstantiationService, ) { super(); this._codeActionWidget = new Lazy(() => { - return this._register(new CodeActionWidget(this._editor, contextMenuService, keybindingService, { + return this._register(instantiationService.createInstance(CodeActionMenu, this._editor, { onSelectCodeAction: async (action) => { this.delegate.applyCodeAction(action, /* retrigger */ true); } @@ -47,7 +45,7 @@ export class CodeActionUi extends Disposable { }); this._lightBulbWidget = new Lazy(() => { - const widget = this._register(new LightBulbWidget(this._editor, quickFixActionId, preferredFixActionId, keybindingService)); + const widget = this._register(instantiationService.createInstance(LightBulbWidget, this._editor, quickFixActionId, preferredFixActionId)); this._register(widget.onClick(e => this.showCodeActionList(e.actions, e, { includeDisabledActions: false }))); return widget; }); diff --git a/src/vs/editor/contrib/codeAction/lightBulbWidget.ts b/src/vs/editor/contrib/codeAction/lightBulbWidget.ts index 5512a63a60f..e01343ff2b5 100644 --- a/src/vs/editor/contrib/codeAction/lightBulbWidget.ts +++ b/src/vs/editor/contrib/codeAction/lightBulbWidget.ts @@ -17,6 +17,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; import { registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; import { editorLightBulbForeground, editorLightBulbAutoFixForeground } from 'vs/platform/theme/common/colorRegistry'; +import { Gesture } from 'vs/base/browser/touch'; namespace LightBulbState { @@ -71,7 +72,9 @@ export class LightBulbWidget extends Disposable implements IContentWidget { this.hide(); } })); - this._register(dom.addStandardDisposableListener(this._domNode, 'mousedown', e => { + + Gesture.ignoreTarget(this._domNode); + this._register(dom.addStandardDisposableGenericMouseDownListner(this._domNode, e => { if (this.state.type !== LightBulbState.Type.Showing) { return; } diff --git a/src/vs/editor/contrib/codeAction/test/codeActionKeybindingResolver.test.ts b/src/vs/editor/contrib/codeAction/test/codeActionKeybindingResolver.test.ts index 44314a90860..9a939303ece 100644 --- a/src/vs/editor/contrib/codeAction/test/codeActionKeybindingResolver.test.ts +++ b/src/vs/editor/contrib/codeAction/test/codeActionKeybindingResolver.test.ts @@ -8,7 +8,7 @@ import { ChordKeybinding, KeyCode, SimpleKeybinding } from 'vs/base/common/keyCo import { OperatingSystem } from 'vs/base/common/platform'; import { refactorCommandId, organizeImportsCommandId } from 'vs/editor/contrib/codeAction/codeAction'; import { CodeActionKind } from 'vs/editor/contrib/codeAction/types'; -import { CodeActionKeybindingResolver } from 'vs/editor/contrib/codeAction/codeActionWidget'; +import { CodeActionKeybindingResolver } from 'vs/editor/contrib/codeAction/codeActionMenu'; import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem'; import { USLayoutResolvedKeybinding } from 'vs/platform/keybinding/common/usLayoutResolvedKeybinding'; diff --git a/src/vs/editor/contrib/gotoSymbol/goToCommands.ts b/src/vs/editor/contrib/gotoSymbol/goToCommands.ts index 2c7b9cccefb..a0f70710925 100644 --- a/src/vs/editor/contrib/gotoSymbol/goToCommands.ts +++ b/src/vs/editor/contrib/gotoSymbol/goToCommands.ts @@ -49,15 +49,16 @@ export interface SymbolNavigationActionConfig { openToSide: boolean; openInPeek: boolean; muteMessage: boolean; + alternativeCommand?: string; } abstract class SymbolNavigationAction extends EditorAction { - private readonly _configuration: SymbolNavigationActionConfig; + private readonly _config: SymbolNavigationActionConfig; constructor(configuration: SymbolNavigationActionConfig, opts: IActionOptions) { super(opts); - this._configuration = configuration; + this._config = configuration; } run(accessor: ServicesAccessor, editor: ICodeEditor): Promise { @@ -83,11 +84,11 @@ abstract class SymbolNavigationAction extends EditorAction { alert(references.ariaMessage); const referenceCount = references.references.length; - const altAction = references.referenceAt(model.uri, pos) && editor.getAction(this._getAlternativeCommand()); + const altAction = references.referenceAt(model.uri, pos) && editor.getAction(this._config.alternativeCommand || ''); if (referenceCount === 0) { // no result -> show message - if (!this._configuration.muteMessage) { + if (!this._config.muteMessage) { const info = model.getWordAtPosition(pos); MessageController.get(editor).showMessage(this._getNoResultFoundMessage(info), pos); } @@ -115,20 +116,18 @@ abstract class SymbolNavigationAction extends EditorAction { protected abstract _getNoResultFoundMessage(info: IWordAtPosition | null): string; - protected abstract _getAlternativeCommand(): string; - protected abstract _getGoToPreference(editor: IActiveCodeEditor): GoToLocationValues; private async _onResult(editorService: ICodeEditorService, symbolNavService: ISymbolNavigationService, editor: IActiveCodeEditor, model: ReferencesModel): Promise { const gotoLocation = this._getGoToPreference(editor); - if (this._configuration.openInPeek || (gotoLocation === 'peek' && model.references.length > 1)) { + if (this._config.openInPeek || (gotoLocation === 'peek' && model.references.length > 1)) { this._openInPeek(editor, model); } else { const next = model.firstReference()!; const peek = model.references.length > 1 && gotoLocation === 'gotoAndPeek'; - const targetEditor = await this._openReference(editor, editorService, next, this._configuration.openToSide, !peek); + const targetEditor = await this._openReference(editor, editorService, next, this._config.openToSide, !peek); if (peek && targetEditor) { this._openInPeek(targetEditor, model); } else { @@ -182,7 +181,7 @@ abstract class SymbolNavigationAction extends EditorAction { private _openInPeek(target: ICodeEditor, model: ReferencesModel) { let controller = ReferencesController.get(target); if (controller && target.hasModel()) { - controller.toggleWidget(target.getSelection(), createCancelablePromise(_ => Promise.resolve(model)), this._configuration.openInPeek); + controller.toggleWidget(target.getSelection(), createCancelablePromise(_ => Promise.resolve(model)), this._config.openInPeek); } else { model.dispose(); } @@ -203,10 +202,6 @@ export class DefinitionAction extends SymbolNavigationAction { : nls.localize('generic.noResults', "No definition found"); } - protected _getAlternativeCommand(): string { - return 'editor.action.goToReferences'; - } - protected _getGoToPreference(editor: IActiveCodeEditor): GoToLocationValues { return editor.getOption(EditorOption.gotoLocation).multipleDefinitions; } @@ -224,7 +219,8 @@ registerEditorAction(class GoToDefinitionAction extends DefinitionAction { super({ openToSide: false, openInPeek: false, - muteMessage: false + muteMessage: false, + alternativeCommand: 'editor.action.goToReferences' }, { id: GoToDefinitionAction.id, label: nls.localize('actions.goToDecl.label', "Go to Definition"), @@ -327,10 +323,6 @@ class DeclarationAction extends SymbolNavigationAction { : nls.localize('decl.generic.noResults', "No declaration found"); } - protected _getAlternativeCommand(): string { - return 'editor.action.goToReferences'; - } - protected _getGoToPreference(editor: IActiveCodeEditor): GoToLocationValues { return editor.getOption(EditorOption.gotoLocation).multipleDeclarations; } @@ -344,7 +336,8 @@ registerEditorAction(class GoToDeclarationAction extends DeclarationAction { super({ openToSide: false, openInPeek: false, - muteMessage: false + muteMessage: false, + alternativeCommand: 'editor.action.goToReferences' }, { id: GoToDeclarationAction.id, label: nls.localize('actions.goToDeclaration.label', "Go to Declaration"), @@ -412,10 +405,6 @@ class TypeDefinitionAction extends SymbolNavigationAction { : nls.localize('goToTypeDefinition.generic.noResults', "No type definition found"); } - protected _getAlternativeCommand(): string { - return 'editor.action.goToReferences'; - } - protected _getGoToPreference(editor: IActiveCodeEditor): GoToLocationValues { return editor.getOption(EditorOption.gotoLocation).multipleTypeDefinitions; } @@ -429,7 +418,8 @@ registerEditorAction(class GoToTypeDefinitionAction extends TypeDefinitionAction super({ openToSide: false, openInPeek: false, - muteMessage: false + muteMessage: false, + alternativeCommand: 'editor.action.goToReferences' }, { id: GoToTypeDefinitionAction.ID, label: nls.localize('actions.goToTypeDefinition.label', "Go to Type Definition"), @@ -498,10 +488,6 @@ class ImplementationAction extends SymbolNavigationAction { : nls.localize('goToImplementation.generic.noResults', "No implementation found"); } - protected _getAlternativeCommand(): string { - return ''; - } - protected _getGoToPreference(editor: IActiveCodeEditor): GoToLocationValues { return editor.getOption(EditorOption.gotoLocation).multipleImplementations; } @@ -589,10 +575,6 @@ class ReferencesAction extends SymbolNavigationAction { : nls.localize('references.noGeneric', "No references found"); } - protected _getAlternativeCommand(): string { - return ''; - } - protected _getGoToPreference(editor: IActiveCodeEditor): GoToLocationValues { return editor.getOption(EditorOption.gotoLocation).multipleReferences; } @@ -694,8 +676,6 @@ class GenericGoToLocationAction extends SymbolNavigationAction { protected _getGoToPreference(editor: IActiveCodeEditor): GoToLocationValues { return this._gotoMultipleBehaviour ?? editor.getOption(EditorOption.gotoLocation).multipleReferences; } - - protected _getAlternativeCommand() { return ''; } } CommandsRegistry.registerCommand({ diff --git a/src/vs/platform/actions/browser/menuEntryActionViewItem.ts b/src/vs/platform/actions/browser/menuEntryActionViewItem.ts index 05efd4bd424..77d930aa7fd 100644 --- a/src/vs/platform/actions/browser/menuEntryActionViewItem.ts +++ b/src/vs/platform/actions/browser/menuEntryActionViewItem.ts @@ -147,7 +147,7 @@ export class MenuEntryActionViewItem extends ActionViewItem { @INotificationService protected _notificationService: INotificationService, @IContextMenuService _contextMenuService: IContextMenuService ) { - super(undefined, _action, { icon: !!(_action.class || _action.item.iconLocation), label: !_action.class && !_action.item.iconLocation }); + super(undefined, _action, { icon: !!(_action.class || _action.item.iconLocation || _action.item.iconClassName), label: !_action.class && !_action.item.iconLocation && !_action.item.iconClassName }); this._altKey = AlternativeKeyEmitter.getInstance(_contextMenuService); } diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 7f26e5267b9..ce948daac9b 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -1209,7 +1209,7 @@ declare module 'vscode' { //#region Custom editors, mjbvz /** - * + * Defines how a webview editor interacts with VS Code. */ interface WebviewEditorCapabilities { /** @@ -1224,26 +1224,36 @@ declare module 'vscode' { * * @return Thenable that signals the save is complete. */ - rename?(newResource: Uri): Thenable; + // rename?(newResource: Uri): Thenable; + /** + * Controls the editing functionality of a webview editor. This allows the webview editor to hook into standard + * editor events such as `undo` or `save`. + * + * WebviewEditors that do not have `editingCapability` are considered to be readonly. Users can still interact + * with readonly editors, but these editors will not integrate with VS Code's standard editor functionality. + */ readonly editingCapability?: WebviewEditorEditingCapability; } + /** + * Defines the editing functionality of a webview editor. This allows the webview editor to hook into standard + * editor events such as `undo` or `save`. + */ interface WebviewEditorEditingCapability { /** * Persist the resource. + * + * Extensions should persist the resource + * + * @return Thenable signaling that the save has completed. */ save(): Thenable; /** - * Called when the editor exits. - */ - hotExit(hotExitPath: Uri): Thenable; - - /** - * Signal to VS Code that an edit has occurred. + * Event triggered by extensions to signal to VS Code that an edit has occurred. * - * Edits must be a json serilizable object. + * The edit must be a json serializable object. */ readonly onEdit: Event; @@ -1269,14 +1279,16 @@ declare module 'vscode' { export interface WebviewEditorProvider { /** - * Fills out a `WebviewEditor` for a given resource. + * Resolve a webview editor for a given resource. + * + * To resolve a webview editor, a provider must fill in its initial html content and hook up all + * the event listeners it is interested it. The provider should also take ownership of the passed in `WebviewPanel`. * * @param input Information about the resource being resolved. * @param webview Webview being resolved. The provider should take ownership of this webview. * * @return Thenable to a `WebviewEditorCapabilities` indicating that the webview editor has been resolved. * The `WebviewEditorCapabilities` defines how the custom editor interacts with VS Code. - * **❗️Note**: `WebviewEditorCapabilities` is not actually implemented... yet! */ resolveWebviewEditor( input: { @@ -1287,6 +1299,15 @@ declare module 'vscode' { } namespace window { + /** + * Register a new provider for webview editors of a given type. + * + * @param viewType Type of the webview editor provider. + * @param provider Resolves webview editors. + * @param options Content settings for a webview panels the provider is given. + * + * @return Disposable that unregisters the `WebviewEditorProvider`. + */ export function registerWebviewEditorProvider( viewType: string, provider: WebviewEditorProvider, diff --git a/src/vs/workbench/api/common/extHostWebview.ts b/src/vs/workbench/api/common/extHostWebview.ts index 2f48b4e01ea..3cf879271d3 100644 --- a/src/vs/workbench/api/common/extHostWebview.ts +++ b/src/vs/workbench/api/common/extHostWebview.ts @@ -243,7 +243,7 @@ export class ExtHostWebviewEditor extends Disposable implements vscode.WebviewPa this._capabilities = capabilities; if (capabilities.editingCapability) { this._register(capabilities.editingCapability.onEdit(edit => { - this._proxy.$onEdit(this._handle, JSON.stringify(edit)); + this._proxy.$onEdit(this._handle, edit); })); } } @@ -449,18 +449,12 @@ export class ExtHostWebviews implements ExtHostWebviewsShape { $undoEdits(handle: WebviewPanelHandle, edits: string[]): void { const panel = this.getWebviewPanel(handle); - if (!panel) { - return; - } - panel._undoEdits(edits); + panel?._undoEdits(edits); } $redoEdits(handle: WebviewPanelHandle, edits: string[]): void { const panel = this.getWebviewPanel(handle); - if (!panel) { - return; - } - panel._redoEdits(edits); + panel?._redoEdits(edits); } async $onSave(handle: WebviewPanelHandle): Promise { diff --git a/src/vs/workbench/browser/parts/views/media/views.css b/src/vs/workbench/browser/parts/views/media/views.css index fb062a7a3af..43fa0eb55da 100644 --- a/src/vs/workbench/browser/parts/views/media/views.css +++ b/src/vs/workbench/browser/parts/views/media/views.css @@ -32,7 +32,7 @@ .file-icon-themable-tree.hide-arrows .monaco-tl-twistie:not(.force-twistie) { background-image: none !important; width: 0 !important; - margin-right: 0 !important; + padding-right: 0 !important; visibility: hidden; } diff --git a/src/vs/workbench/browser/style.ts b/src/vs/workbench/browser/style.ts index d38931efc44..ea118c2511a 100644 --- a/src/vs/workbench/browser/style.ts +++ b/src/vs/workbench/browser/style.ts @@ -8,9 +8,9 @@ import 'vs/css!./media/style'; import { registerThemingParticipant, ITheme, ICssStyleCollector, HIGH_CONTRAST } from 'vs/platform/theme/common/themeService'; import { iconForeground, foreground, selectionBackground, focusBorder, scrollbarShadow, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground, listHighlightForeground, inputPlaceholderForeground } from 'vs/platform/theme/common/colorRegistry'; import { WORKBENCH_BACKGROUND, TITLE_BAR_ACTIVE_BACKGROUND } from 'vs/workbench/common/theme'; -import { isWeb } from 'vs/base/common/platform'; +import { isWeb, isIOS } from 'vs/base/common/platform'; import { createMetaElement } from 'vs/base/browser/dom'; -import { isSafari } from 'vs/base/browser/browser'; +import { isSafari, isStandalone } from 'vs/base/browser/browser'; registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { @@ -184,4 +184,9 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { } `); } + + // Update body background color to ensure the home indicator area looks similar to the workbench + if (isIOS && isStandalone) { + collector.addRule(`body { background-color: ${workbenchBackground}; }`); + } }); diff --git a/src/vs/workbench/contrib/customEditor/browser/extensionPoint.ts b/src/vs/workbench/contrib/customEditor/browser/extensionPoint.ts index 5e169d1b2c4..2a126dabefe 100644 --- a/src/vs/workbench/contrib/customEditor/browser/extensionPoint.ts +++ b/src/vs/workbench/contrib/customEditor/browser/extensionPoint.ts @@ -53,10 +53,6 @@ const webviewEditorsContribution: IJSONSchema = { type: 'string', description: nls.localize('contributes.selector.filenamePattern', 'Glob that the custom editor is enabled for.'), }, - mime: { - type: 'string', - description: nls.localize('contributes.selector.mime', 'Glob that matches the mime type of a data uri resource.'), - } } } }, diff --git a/src/vs/workbench/contrib/debug/browser/callStackView.ts b/src/vs/workbench/contrib/debug/browser/callStackView.ts index ef83c73203a..20029b0ec3b 100644 --- a/src/vs/workbench/contrib/debug/browser/callStackView.ts +++ b/src/vs/workbench/contrib/debug/browser/callStackView.ts @@ -385,6 +385,7 @@ interface IStackFrameTemplateData { fileName: HTMLElement; lineNumber: HTMLElement; label: HighlightedLabel; + actionBar: ActionBar; } class SessionsRenderer implements ITreeRenderer { @@ -481,8 +482,9 @@ class StackFramesRenderer implements ITreeRenderer, index: number, data: IStackFrameTemplateData): void { @@ -490,6 +492,8 @@ class StackFramesRenderer implements ITreeRenderer { + return stackFrame.restart(); + }); + data.actionBar.push(action, { icon: true, label: false }); + } } disposeTemplate(templateData: IStackFrameTemplateData): void { - // noop + templateData.actionBar.dispose(); } } diff --git a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts index 7b74dcb4912..67ba00c4cd6 100644 --- a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts @@ -83,7 +83,7 @@ Registry.as(ViewletExtensions.Viewlets).registerViewlet(Viewlet DebugViewlet, VIEWLET_ID, nls.localize('debug', "Debug"), - 'codicon-debug', + 'codicon-debug-alt', 3 )); diff --git a/src/vs/workbench/contrib/debug/browser/debugToolBar.ts b/src/vs/workbench/contrib/debug/browser/debugToolBar.ts index cf629a37d01..4d8c423dbce 100644 --- a/src/vs/workbench/contrib/debug/browser/debugToolBar.ts +++ b/src/vs/workbench/contrib/debug/browser/debugToolBar.ts @@ -377,7 +377,7 @@ registerThemingParticipant((theme, collector) => { const debugIconRestartColor = theme.getColor(debugIconRestartForeground); if (debugIconRestartColor) { - collector.addRule(`.monaco-workbench .codicon-debug-restart { color: ${debugIconRestartColor} !important; }`); + collector.addRule(`.monaco-workbench .codicon-debug-restart, .monaco-workbench .codicon-debug-restart-frame { color: ${debugIconRestartColor} !important; }`); } const debugIconStepOverColor = theme.getColor(debugIconStepOverForeground); diff --git a/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css b/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css index 185b8187d41..d4e91e65cd1 100644 --- a/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css +++ b/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css @@ -148,6 +148,11 @@ display: none; } +.debug-viewlet .debug-call-stack .monaco-list-row:hover .stack-frame.has-actions .file, +.debug-viewlet .debug-call-stack .monaco-list-row.focused .stack-frame.has-actions .file { + display: none; +} + .debug-viewlet .debug-call-stack .monaco-list-row .monaco-action-bar { display: none; } diff --git a/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts b/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts index cd52141866d..6d38111b94b 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts @@ -39,7 +39,6 @@ import { ExplorerRootContext, ExplorerFolderContext } from 'vs/workbench/contrib import { ILabelService } from 'vs/platform/label/common/label'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; -import { registerAndGetAmdImageURL } from 'vs/base/common/amd'; Registry.as(EditorExtensions.Editors).registerEditor( EditorDescriptor.create( @@ -368,8 +367,6 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ } }); -const PREFERENCES_EDITOR_LIGHT_ICON_URI = URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/preferences/browser/media/preferences-editor-light.svg`)); -const PREFERENCES_EDITOR_DARK_ICON_URI = URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/preferences/browser/media/preferences-editor-dark.svg`)); class PreferencesActionsContribution extends Disposable implements IWorkbenchContribution { constructor( @@ -384,10 +381,7 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon command: { id: OpenGlobalKeybindingsAction.ID, title: OpenGlobalKeybindingsAction.LABEL, - iconLocation: { - light: PREFERENCES_EDITOR_LIGHT_ICON_URI, - dark: PREFERENCES_EDITOR_DARK_ICON_URI - } + iconClassName: 'codicon-go-to-file' }, when: ResourceContextKey.Resource.isEqualTo(environmentService.keybindingsResource.toString()), group: 'navigation', @@ -400,10 +394,7 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon command: { id: commandId, title: OpenSettings2Action.LABEL, - iconLocation: { - light: PREFERENCES_EDITOR_LIGHT_ICON_URI, - dark: PREFERENCES_EDITOR_DARK_ICON_URI - } + iconClassName: 'codicon-go-to-file' }, when: ResourceContextKey.Resource.isEqualTo(environmentService.settingsResource.toString()), group: 'navigation', @@ -441,10 +432,7 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon command: { id: commandId, title: OpenSettings2Action.LABEL, - iconLocation: { - light: PREFERENCES_EDITOR_LIGHT_ICON_URI, - dark: PREFERENCES_EDITOR_DARK_ICON_URI - } + iconClassName: 'codicon-go-to-file' }, when: ContextKeyExpr.and(ResourceContextKey.Resource.isEqualTo(this.preferencesService.workspaceSettingsResource!.toString()), WorkbenchStateContext.isEqualTo('workspace')), group: 'navigation', @@ -469,10 +457,7 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon command: { id: commandId, title: OpenSettings2Action.LABEL, - iconLocation: { - light: PREFERENCES_EDITOR_LIGHT_ICON_URI, - dark: PREFERENCES_EDITOR_DARK_ICON_URI - } + iconClassName: 'codicon-go-to-file' }, when: ContextKeyExpr.and(ResourceContextKey.Resource.isEqualTo(this.preferencesService.getFolderSettingsResource(folder.uri)!.toString())), group: 'navigation', @@ -536,10 +521,7 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: OpenGlobalKeybindingsFileAction.ID, title: OpenGlobalKeybindingsFileAction.LABEL, - iconLocation: { - light: PREFERENCES_EDITOR_LIGHT_ICON_URI, - dark: PREFERENCES_EDITOR_DARK_ICON_URI - } + iconClassName: 'codicon-go-to-file' }, when: ContextKeyExpr.and(CONTEXT_KEYBINDINGS_EDITOR), group: 'navigation', @@ -820,10 +802,7 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: SETTINGS_EDITOR_COMMAND_SWITCH_TO_JSON, title: nls.localize('openSettingsJson', "Open Settings (JSON)"), - iconLocation: { - dark: PREFERENCES_EDITOR_DARK_ICON_URI, - light: PREFERENCES_EDITOR_LIGHT_ICON_URI - } + iconClassName: 'codicon-go-to-file' }, group: 'navigation', order: 1, diff --git a/src/vs/workbench/contrib/scm/browser/repositoryPane.ts b/src/vs/workbench/contrib/scm/browser/repositoryPane.ts index ab1d61454b2..e4fa1369aed 100644 --- a/src/vs/workbench/contrib/scm/browser/repositoryPane.ts +++ b/src/vs/workbench/contrib/scm/browser/repositoryPane.ts @@ -53,6 +53,7 @@ import { IWorkbenchThemeService, IFileIconTheme } from 'vs/workbench/services/th import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { toResource, SideBySideEditor } from 'vs/workbench/common/editor'; import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme'; +import { Hasher } from 'vs/base/common/hash'; type TreeElement = ISCMResourceGroup | IResourceNode | ISCMResource; @@ -963,7 +964,10 @@ export class RepositoryViewDescriptor implements IViewDescriptor { constructor(readonly repository: ISCMRepository, readonly hideByDefault: boolean) { const repoId = repository.provider.rootUri ? repository.provider.rootUri.toString() : `#${RepositoryViewDescriptor.counter++}`; - this.id = `scm:repository:${repository.provider.label}:${repoId}`; + const hasher = new Hasher(); + hasher.hash(repository.provider.label); + hasher.hash(repoId); + this.id = `scm:repository:${hasher.value}`; this.name = repository.provider.rootUri ? basename(repository.provider.rootUri) : repository.provider.label; this.ctorDescriptor = { ctor: RepositoryPane, arguments: [repository] }; diff --git a/src/vs/workbench/contrib/search/browser/searchPanel.ts b/src/vs/workbench/contrib/search/browser/searchPanel.ts index 54cf8e628d1..559f023dee7 100644 --- a/src/vs/workbench/contrib/search/browser/searchPanel.ts +++ b/src/vs/workbench/contrib/search/browser/searchPanel.ts @@ -31,7 +31,7 @@ export class SearchPanel extends Panel { } create(parent: HTMLElement): void { - dom.addClasses(parent, 'monaco-panel-view', 'search-panel'); + dom.addClasses(parent, 'monaco-pane-view', 'search-panel'); this.searchView.render(); dom.append(parent, this.searchView.element); this.searchView.setExpanded(true);