Merge branch 'main' into joh/vscode-dts

This commit is contained in:
Johannes Rieken 2021-11-11 09:30:36 +01:00
commit edb91ace89
No known key found for this signature in database
GPG key ID: 96634B5AF12F8798
34 changed files with 364 additions and 135 deletions

View file

@ -49,7 +49,7 @@ export async function wrapWithAbbreviation(args: any): Promise<boolean> {
const helper = getEmmetHelper();
const operationRanges = editor.selections.sort((a, b) => a.start.compareTo(b.start)).map(selection => {
const operationRanges = Array.from(editor.selections).sort((a, b) => a.start.compareTo(b.start)).map(selection => {
let rangeToReplace: vscode.Range = selection;
// wrap around the node if the selection falls inside its open or close tag
{

View file

@ -8,8 +8,8 @@ import { getHtmlFlatNode, offsetRangeToSelection, validate } from './util';
import { getRootNode } from './parseDocument';
import { HtmlNode as HtmlFlatNode } from 'EmmetFlatNode';
let balanceOutStack: Array<vscode.Selection[]> = [];
let lastBalancedSelections: vscode.Selection[] = [];
let balanceOutStack: Array<readonly vscode.Selection[]> = [];
let lastBalancedSelections: readonly vscode.Selection[] = [];
export function balanceOut() {
balance(true);
@ -31,10 +31,8 @@ function balance(out: boolean) {
}
const rangeFn = out ? getRangeToBalanceOut : getRangeToBalanceIn;
let newSelections: vscode.Selection[] = [];
editor.selections.forEach(selection => {
const range = rangeFn(document, rootNode, selection);
newSelections.push(range);
let newSelections: readonly vscode.Selection[] = editor.selections.map(selection => {
return rangeFn(document, rootNode, selection);
});
// check whether we are starting a balance elsewhere
@ -122,7 +120,7 @@ function getRangeToBalanceIn(document: vscode.TextDocument, rootNode: HtmlFlatNo
return offsetRangeToSelection(document, firstChild.start, firstChild.end);
}
function areSameSelections(a: vscode.Selection[], b: vscode.Selection[]): boolean {
function areSameSelections(a: readonly vscode.Selection[], b: readonly vscode.Selection[]): boolean {
if (a.length !== b.length) {
return false;
}

View file

@ -21,7 +21,7 @@ export function mergeLines() {
}
return editor.edit(editBuilder => {
editor.selections.reverse().forEach(selection => {
Array.from(editor.selections).reverse().forEach(selection => {
const textEdit = getRangesToReplace(editor.document, selection, rootNode);
if (textEdit) {
editBuilder.replace(textEdit.range, textEdit.newText);

View file

@ -19,7 +19,7 @@ export function removeTag() {
return;
}
let finalRangesToRemove = editor.selections.reverse()
let finalRangesToRemove = Array.from(editor.selections).reverse()
.reduce<vscode.Range[]>((prev, selection) =>
prev.concat(getRangesToRemove(editor.document, rootNode, selection)), []);

View file

@ -21,7 +21,7 @@ export function splitJoinTag() {
}
return editor.edit(editBuilder => {
editor.selections.reverse().forEach(selection => {
Array.from(editor.selections).reverse().forEach(selection => {
const documentText = document.getText();
const offset = document.offsetAt(selection.start);
const nodeToUpdate = getHtmlFlatNode(documentText, rootNode, offset, true);

View file

@ -28,7 +28,7 @@ export function toggleComment(): Thenable<boolean> | undefined {
return editor.edit(editBuilder => {
let allEdits: vscode.TextEdit[][] = [];
editor.selections.reverse().forEach(selection => {
Array.from(editor.selections).reverse().forEach(selection => {
const edits = isStyleSheet(editor.document.languageId) ? toggleCommentStylesheet(editor.document, selection, <Stylesheet>rootNode) : toggleCommentHTML(editor.document, selection, rootNode!);
if (edits.length > 0) {
allEdits.push(edits);

View file

@ -23,7 +23,7 @@ export function updateImageSize(): Promise<boolean> | undefined {
}
const editor = window.activeTextEditor;
const allUpdatesPromise = editor.selections.reverse().map(selection => {
const allUpdatesPromise = Array.from(editor.selections).reverse().map(selection => {
const position = selection.isReversed ? selection.active : selection.anchor;
if (!isStyleSheet(editor.document.languageId)) {
return updateImageSizeHTML(editor, position);

View file

@ -25,7 +25,7 @@ export async function updateTag(tagName: string | undefined): Promise<boolean |
return;
}
const rangesToUpdate = editor.selections.reverse()
const rangesToUpdate = Array.from(editor.selections).reverse()
.reduce<TagRange[]>((prev, selection) =>
prev.concat(getRangesToUpdate(document, selection, rootNode)), []);
if (!rangesToUpdate.length) {

View file

@ -49,7 +49,7 @@ export function applyLineChanges(original: TextDocument, modified: TextDocument,
return result.join('');
}
export function toLineRanges(selections: Selection[], textDocument: TextDocument): Range[] {
export function toLineRanges(selections: readonly Selection[], textDocument: TextDocument): Range[] {
const lineRanges = selections.map(s => {
const startLine = textDocument.lineAt(s.start.line);
const endLine = textDocument.lineAt(s.end.line);

View file

@ -56,7 +56,9 @@ suite('git smoke test', function () {
git = ext!.exports.getAPI(1);
if (git.repositories.length === 0) {
await eventToPromise(git.onDidOpenRepository);
const onDidOpenRepository = eventToPromise(git.onDidOpenRepository);
await commands.executeCommand('git.openRepository', cwd);
await onDidOpenRepository;
}
assert.strictEqual(git.repositories.length, 1);

View file

@ -134,6 +134,7 @@ window.addEventListener('message', async event => {
root.replaceWith(newContent.querySelector('.markdown-body')!);
documentResource = event.data.source;
} else {
// Compare two elements but skip `data-line`
const areEqual = (a: Element, b: Element): boolean => {
if (a.isEqualNode(b)) {
return true;
@ -143,6 +144,23 @@ window.addEventListener('message', async event => {
return false;
}
const aAttrs = a.attributes;
const bAttrs = b.attributes;
if (aAttrs.length !== bAttrs.length) {
return false;
}
for (let i = 0; i < aAttrs.length; ++i) {
const aAttr = aAttrs[i];
const bAttr = bAttrs[i];
if (aAttr.name !== bAttr.name) {
return false;
}
if (aAttr.value !== bAttr.value && aAttr.name !== 'data-line') {
return false;
}
}
const aChildren = Array.from(a.children);
const bChildren = Array.from(b.children);

View file

@ -15,10 +15,13 @@ function workspaceFile(...segments: string[]) {
}
async function getLinksForFile(file: vscode.Uri): Promise<vscode.DocumentLink[]> {
return (await vscode.commands.executeCommand<vscode.DocumentLink[]>('vscode.executeLinkProvider', file))!;
console.log('getting links', file.toString(), Date.now());
const r = (await vscode.commands.executeCommand<vscode.DocumentLink[]>('vscode.executeLinkProvider', file))!;
console.log('got links', file.toString(), Date.now());
return r;
}
suite('Markdown Document links', () => {
suite.skip('Markdown Document links', () => {
setup(async () => {
// the tests make the assumption that link providers are already registered
@ -94,7 +97,6 @@ suite('Markdown Document links', () => {
assert.strictEqual(vscode.window.activeTextEditor!.selection.start.line, 1);
});
test('Should navigate to line number within non-md file', async () => {
await withFileContents(testFileA, '[b](sub/foo.txt#L3)');
@ -147,15 +149,21 @@ function assertActiveDocumentUri(expectedUri: vscode.Uri) {
}
async function withFileContents(file: vscode.Uri, contents: string): Promise<void> {
console.log('openTextDocument', file.toString(), Date.now());
const document = await vscode.workspace.openTextDocument(file);
console.log('showTextDocument', file.toString(), Date.now());
const editor = await vscode.window.showTextDocument(document);
console.log('editTextDocument', file.toString(), Date.now());
await editor.edit(edit => {
edit.replace(new vscode.Range(0, 0, 1000, 0), contents);
});
console.log('opened done', vscode.window.activeTextEditor?.document.toString(), Date.now());
}
async function executeLink(link: vscode.DocumentLink) {
console.log('executeingLink', link.target?.toString(), Date.now());
const args = JSON.parse(decodeURIComponent(link.target!.query));
await vscode.commands.executeCommand(link.target!.path, args);
console.log('executedLink', vscode.window.activeTextEditor?.document.toString(), Date.now());
}

View file

@ -45,11 +45,13 @@
async function load(modulePaths, resultCallback, options) {
const isDev = !!safeProcess.env['VSCODE_DEV'];
// Error handler (TODO@sandbox non-sandboxed only)
// Error handler (node.js enabled renderers only)
let showDevtoolsOnError = isDev;
safeProcess.on('uncaughtException', function (/** @type {string | Error} */ error) {
onUnexpectedError(error, showDevtoolsOnError);
});
if (!safeProcess.sandboxed) {
safeProcess.on('uncaughtException', function (/** @type {string | Error} */ error) {
onUnexpectedError(error, showDevtoolsOnError);
});
}
// Await window configuration from preload
const timeout = setTimeout(() => { console.error(`[resolve window config] Could not resolve window configuration within 10 seconds, but will continue to wait...`); }, 10000);
@ -83,7 +85,7 @@
developerDeveloperKeybindingsDisposable = registerDeveloperKeybindings(disallowReloadKeybinding);
}
// Enable ASAR support (TODO@sandbox non-sandboxed only)
// Enable ASAR support (node.js enabled renderers only)
if (!safeProcess.sandboxed) {
globalThis.MonacoBootstrap.enableASARSupport(configuration.appRoot);
}
@ -100,9 +102,12 @@
window.document.documentElement.setAttribute('lang', locale);
// Replace the patched electron fs with the original node fs for all AMD code (TODO@sandbox non-sandboxed only)
// Define `fs` as `original-fs` to disable ASAR support
// in fs-operations (node.js enabled renderers only)
if (!safeProcess.sandboxed) {
require.define('fs', [], function () { return require.__$__nodeRequire('original-fs'); });
require.define('fs', [], function () {
return require.__$__nodeRequire('original-fs');
});
}
window['MonacoEnvironment'] = {};
@ -140,8 +145,9 @@
'tas-client-umd': `${baseNodeModulesPath}/tas-client-umd/lib/tas-client-umd.js`
};
// For priviledged renderers, allow to load built-in and other node.js
// modules via AMD which has a fallback to using node.js `require`
// Allow to load built-in and other node.js modules via AMD
// which has a fallback to using node.js `require`
// (node.js enabled renderers only)
if (!safeProcess.sandboxed) {
loaderConfig.amdModulesPattern = /(^vs\/)|(^vscode-textmate$)|(^vscode-oniguruma$)|(^xterm$)|(^xterm-addon-search$)|(^xterm-addon-unicode11$)|(^xterm-addon-webgl$)|(^iconv-lite-umd$)|(^jschardet$)|(^@vscode\/vscode-languagedetection$)|(^tas-client-umd$)/;
}

3
src/bootstrap.js vendored
View file

@ -42,9 +42,6 @@
//#region Add support for using node_modules.asar
/**
* TODO@sandbox remove the support for passing in `appRoot` once
* sandbox is fully enabled
*
* @param {string=} appRoot
*/
function enableASARSupport(appRoot) {

View file

@ -34,6 +34,7 @@ export interface IMenuBarOptions {
getKeybinding?: (action: IAction) => ResolvedKeybinding | undefined;
alwaysOnMnemonics?: boolean;
compactMode?: Direction;
actionRunner?: IActionRunner;
getCompactMenuActions?: () => IAction[]
}
@ -109,7 +110,7 @@ export class MenuBar extends Disposable {
this.menuUpdater = this._register(new RunOnceScheduler(() => this.update(), 200));
this.actionRunner = this._register(new ActionRunner());
this.actionRunner = this.options.actionRunner ?? this._register(new ActionRunner());
this._register(this.actionRunner.onBeforeRun(() => {
this.setUnfocusedState();
}));

View file

@ -101,6 +101,7 @@ export class MenuId {
static readonly ExplorerContext = new MenuId('ExplorerContext');
static readonly ExtensionContext = new MenuId('ExtensionContext');
static readonly GlobalActivity = new MenuId('GlobalActivity');
static readonly LayoutControlMenu = new MenuId('LayoutControlMenu');
static readonly MenubarMainMenu = new MenuId('MenubarMainMenu');
static readonly MenubarAppearanceMenu = new MenuId('MenubarAppearanceMenu');
static readonly MenubarDebugMenu = new MenuId('MenubarDebugMenu');

View file

@ -59,11 +59,15 @@ export class ToggleActivityBarVisibilityAction extends Action2 {
category: CATEGORIES.View,
f1: true,
toggled: ContextKeyExpr.equals('config.workbench.activityBar.visible', true),
menu: {
menu: [{
id: MenuId.MenubarAppearanceMenu,
group: '2_workbench_layout',
order: 4
}
}, {
id: MenuId.LayoutControlMenu,
group: '0_workbench_layout',
order: 3
}]
});
}
@ -226,11 +230,15 @@ registerAction2(class extends Action2 {
category: CATEGORIES.View,
f1: true,
toggled: EditorAreaVisibleContext,
menu: {
menu: [{
id: MenuId.MenubarAppearanceMenu,
group: '2_workbench_layout',
order: 5
}
}, {
id: MenuId.LayoutControlMenu,
group: '0_workbench_layout',
order: 5
}]
});
}
@ -274,40 +282,53 @@ class ToggleSidebarVisibilityAction extends Action2 {
registerAction2(ToggleSidebarVisibilityAction);
MenuRegistry.appendMenuItems([{
id: MenuId.ViewContainerTitleContext,
item: {
group: '3_workbench_layout_move',
command: {
id: ToggleSidebarVisibilityAction.ID,
title: localize('compositePart.hideSideBarLabel', "Hide Side Bar"),
},
when: ContextKeyExpr.and(SideBarVisibleContext, ContextKeyExpr.equals('viewContainerLocation', ViewContainerLocationToString(ViewContainerLocation.Sidebar))),
order: 2
MenuRegistry.appendMenuItems([
{
id: MenuId.ViewContainerTitleContext,
item: {
group: '3_workbench_layout_move',
command: {
id: ToggleSidebarVisibilityAction.ID,
title: localize('compositePart.hideSideBarLabel', "Hide Side Bar"),
},
when: ContextKeyExpr.and(SideBarVisibleContext, ContextKeyExpr.equals('viewContainerLocation', ViewContainerLocationToString(ViewContainerLocation.Sidebar))),
order: 2
}
}, {
id: MenuId.ViewTitleContext,
item: {
group: '3_workbench_layout_move',
command: {
id: ToggleSidebarVisibilityAction.ID,
title: localize('compositePart.hideSideBarLabel', "Hide Side Bar"),
},
when: ContextKeyExpr.and(SideBarVisibleContext, ContextKeyExpr.equals('viewLocation', ViewContainerLocationToString(ViewContainerLocation.Sidebar))),
order: 2
}
}, {
id: MenuId.MenubarAppearanceMenu,
item: {
group: '2_workbench_layout',
command: {
id: ToggleSidebarVisibilityAction.ID,
title: localize({ key: 'miShowSidebar', comment: ['&& denotes a mnemonic'] }, "Show &&Side Bar"),
toggled: SideBarVisibleContext
},
order: 1
}
}, {
id: MenuId.LayoutControlMenu,
item: {
group: '0_workbench_layout',
command: {
id: ToggleSidebarVisibilityAction.ID,
title: localize('miShowSidebarNoMnnemonic', "Show Side Bar"),
toggled: SideBarVisibleContext
},
order: 0
}
}
}, {
id: MenuId.ViewTitleContext,
item: {
group: '3_workbench_layout_move',
command: {
id: ToggleSidebarVisibilityAction.ID,
title: localize('compositePart.hideSideBarLabel', "Hide Side Bar"),
},
when: ContextKeyExpr.and(SideBarVisibleContext, ContextKeyExpr.equals('viewLocation', ViewContainerLocationToString(ViewContainerLocation.Sidebar))),
order: 2
}
}, {
id: MenuId.MenubarAppearanceMenu,
item: {
group: '2_workbench_layout',
command: {
id: ToggleSidebarVisibilityAction.ID,
title: localize({ key: 'miShowSidebar', comment: ['&& denotes a mnemonic'] }, "Show &&Side Bar"),
toggled: SideBarVisibleContext
},
order: 1
}
}]);
]);
// --- Toggle Statusbar Visibility
@ -328,11 +349,15 @@ export class ToggleStatusbarVisibilityAction extends Action2 {
category: CATEGORIES.View,
f1: true,
toggled: ContextKeyExpr.equals('config.workbench.statusBar.visible', true),
menu: {
menu: [{
id: MenuId.MenubarAppearanceMenu,
group: '2_workbench_layout',
order: 3
}
}, {
id: MenuId.LayoutControlMenu,
group: '0_workbench_layout',
order: 1
}]
});
}

View file

@ -9,7 +9,7 @@ import { MenuId, MenuRegistry, SyncActionDescriptor } from 'vs/platform/actions/
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { Registry } from 'vs/platform/registry/common/platform';
import { CATEGORIES, Extensions as WorkbenchExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions';
import { ActiveAuxiliaryContext, AuxiliaryBarVisibleContext } from 'vs/workbench/common/auxiliarybar';
import { AuxiliaryBarVisibleContext } from 'vs/workbench/common/auxiliarybar';
import { ViewContainerLocation, ViewContainerLocationToString } from 'vs/workbench/common/views';
import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite';
@ -62,6 +62,19 @@ class FocusAuxiliaryBarAction extends Action {
}
MenuRegistry.appendMenuItems([
{
id: MenuId.LayoutControlMenu,
item: {
group: '0_workbench_layout',
command: {
id: ToggleAuxiliaryBarAction.ID,
title: localize({ key: 'miShowAuxiliaryBar', comment: ['&& denotes a mnemonic'] }, "Show Si&&de Panel"),
toggled: AuxiliaryBarVisibleContext
},
when: ContextKeyExpr.equals('config.workbench.experimental.sidePanel.enabled', true),
order: 4
}
},
{
id: MenuId.MenubarAppearanceMenu,
item: {
@ -69,7 +82,7 @@ MenuRegistry.appendMenuItems([
command: {
id: ToggleAuxiliaryBarAction.ID,
title: localize({ key: 'miShowAuxiliaryBar', comment: ['&& denotes a mnemonic'] }, "Show Si&&de Panel"),
toggled: ActiveAuxiliaryContext
toggled: AuxiliaryBarVisibleContext
},
when: ContextKeyExpr.equals('config.workbench.experimental.sidePanel.enabled', true),
order: 5

View file

@ -298,6 +298,17 @@ MenuRegistry.appendMenuItems([
},
order: 5
}
}, {
id: MenuId.LayoutControlMenu,
item: {
group: '0_workbench_layout',
command: {
id: TogglePanelAction.ID,
title: localize({ key: 'miShowPanel', comment: ['&& denotes a mnemonic'] }, "Show &&Panel"),
toggled: ActivePanelContext
},
order: 4
}
}, {
id: MenuId.ViewTitleContext,
item: {

View file

@ -132,11 +132,34 @@
margin-left: auto;
}
.monaco-workbench.mac:not(web) .part.titlebar > .window-controls-container {
position: absolute;
right: 0px;
width: 28px;
display: none;
}
.monaco-workbench.mac:not(web) .part.titlebar > .window-controls-container.show-layout-control {
display: flex;
}
.monaco-workbench.fullscreen .part.titlebar > .window-controls-container {
display: none;
background-color: transparent;
}
.monaco-workbench .part.titlebar > .window-controls-container.show-layout-control {
width: 160px;
}
.monaco-workbench .part.titlebar > .window-controls-container > .layout-dropdown-container {
display: none;
}
.monaco-workbench .part.titlebar > .window-controls-container.show-layout-control > .layout-dropdown-container {
display: inline-block;
}
.monaco-workbench .part.titlebar > .window-controls-container > .window-icon {
display: inline-block;
line-height: 30px;

View file

@ -8,7 +8,7 @@ import { IMenuService, MenuId, IMenu, SubmenuItemAction, registerAction2, Action
import { registerThemingParticipant, IThemeService } from 'vs/platform/theme/common/themeService';
import { MenuBarVisibility, getTitleBarStyle, IWindowOpenable, getMenuBarVisibility } from 'vs/platform/windows/common/windows';
import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IAction, Action, SubmenuAction, Separator } from 'vs/base/common/actions';
import { IAction, Action, SubmenuAction, Separator, IActionRunner, ActionRunner, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions';
import { addDisposableListener, Dimension, EventType } from 'vs/base/browser/dom';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { isMacintosh, isWeb, isIOS, isNative } from 'vs/base/common/platform';
@ -38,6 +38,7 @@ import { KeyCode } from 'vs/base/common/keyCodes';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { IsMacNativeContext, IsWebContext } from 'vs/platform/contextkey/common/contextkeys';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
export type IOpenRecentAction = IAction & { uri: URI, remoteAuthority?: string };
@ -374,6 +375,7 @@ export class CustomMenubarControl extends MenubarControl {
private alwaysOnMnemonics: boolean = false;
private focusInsideMenubar: boolean = false;
private visible: boolean = true;
private actionRunner: IActionRunner;
private readonly webNavigationMenu = this._register(this.menuService.createMenu(MenuId.MenubarHomeMenu, this.contextKeyService));
private readonly _onVisibilityChange: Emitter<boolean>;
@ -394,6 +396,7 @@ export class CustomMenubarControl extends MenubarControl {
@IAccessibilityService accessibilityService: IAccessibilityService,
@IThemeService private readonly themeService: IThemeService,
@IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService,
@ITelemetryService private readonly telemetryService: ITelemetryService,
@IHostService hostService: IHostService,
@ICommandService commandService: ICommandService
) {
@ -402,6 +405,11 @@ export class CustomMenubarControl extends MenubarControl {
this._onVisibilityChange = this._register(new Emitter<boolean>());
this._onFocusStateChange = this._register(new Emitter<boolean>());
this.actionRunner = this._register(new ActionRunner());
this.actionRunner.onDidRun(e => {
this.telemetryService.publicLog2<WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification>('workbenchActionExecuted', { id: e.action.id, from: 'menu' });
});
this.workspacesService.getRecentlyOpened().then((recentlyOpened) => {
this.recentlyOpened = recentlyOpened;
});
@ -811,6 +819,7 @@ export class CustomMenubarControl extends MenubarControl {
enableMnemonics: this.currentEnableMenuBarMnemonics,
disableAltFocus: this.currentDisableMenuBarAltFocus,
visibility: this.currentMenubarVisibility,
actionRunner: this.actionRunner,
getKeybinding: (action) => this.keybindingService.lookupKeybinding(action.id),
alwaysOnMnemonics: this.alwaysOnMnemonics,
compactMode: this.currentCompactMenuMode,

View file

@ -12,7 +12,7 @@ import { getZoomFactor } from 'vs/base/browser/browser';
import { MenuBarVisibility, getTitleBarStyle, getMenuBarVisibility } from 'vs/platform/windows/common/windows';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
import { IAction } from 'vs/base/common/actions';
import { IAction, SubmenuAction } from 'vs/base/common/actions';
import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { DisposableStore, dispose } from 'vs/base/common/lifecycle';
@ -28,14 +28,14 @@ import { trim } from 'vs/base/common/strings';
import { EventType, EventHelper, Dimension, isAncestor, append, $, addDisposableListener, runAtThisOrScheduleAtNextAnimationFrame, prepend } from 'vs/base/browser/dom';
import { CustomMenubarControl } from 'vs/workbench/browser/parts/titlebar/menubarControl';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { template } from 'vs/base/common/labels';
import { mnemonicButtonLabel, template } from 'vs/base/common/labels';
import { ILabelService } from 'vs/platform/label/common/label';
import { Emitter } from 'vs/base/common/event';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { Parts, IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { RunOnceScheduler } from 'vs/base/common/async';
import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IMenuService, IMenu, MenuId } from 'vs/platform/actions/common/actions';
import { IMenuService, IMenu, MenuId, MenuItemAction } from 'vs/platform/actions/common/actions';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IHostService } from 'vs/workbench/services/host/browser/host';
import { IProductService } from 'vs/platform/product/common/productService';
@ -43,6 +43,10 @@ import { Schemas } from 'vs/base/common/network';
import { withNullAsUndefined } from 'vs/base/common/types';
import { Codicon, iconRegistry } from 'vs/base/common/codicons';
import { getVirtualWorkspaceLocation } from 'vs/platform/remote/common/remoteHosts';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { DropdownMenuActionViewItem } from 'vs/base/browser/ui/dropdown/dropdownActionViewItem';
import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
export class TitlebarPart extends Part implements ITitleService {
@ -66,10 +70,13 @@ export class TitlebarPart extends Part implements ITitleService {
declare readonly _serviceBrand: undefined;
protected title!: HTMLElement;
protected customMenubar: CustomMenubarControl | undefined;
protected appIcon: HTMLElement | undefined;
private appIconBadge: HTMLElement | undefined;
protected menubar?: HTMLElement;
protected windowControls: HTMLElement | undefined;
private layoutToolbar: ActionBar | undefined;
protected lastLayoutDimensions: Dimension | undefined;
private titleBarStyle: 'native' | 'custom';
@ -91,12 +98,13 @@ export class TitlebarPart extends Part implements ITitleService {
@IWorkbenchEnvironmentService protected readonly environmentService: IWorkbenchEnvironmentService,
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
@IInstantiationService protected readonly instantiationService: IInstantiationService,
@IKeybindingService private readonly keybindingService: IKeybindingService,
@IThemeService themeService: IThemeService,
@ILabelService private readonly labelService: ILabelService,
@IStorageService storageService: IStorageService,
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
@IMenuService menuService: IMenuService,
@IContextKeyService contextKeyService: IContextKeyService,
@IMenuService private readonly menuService: IMenuService,
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@IHostService private readonly hostService: IHostService,
@IProductService private readonly productService: IProductService,
) {
@ -143,6 +151,10 @@ export class TitlebarPart extends Part implements ITitleService {
}
}
}
if (this.titleBarStyle !== 'native' && this.windowControls && event.affectsConfiguration('workbench.experimental.layoutControl.enabled')) {
this.windowControls.classList.toggle('show-layout-control', this.layoutControlEnabled);
}
}
protected onMenubarVisibilityChanged(visible: boolean): void {
@ -395,6 +407,53 @@ export class TitlebarPart extends Part implements ITitleService {
this.titleUpdater.schedule();
}
if (this.titleBarStyle !== 'native') {
this.windowControls = append(this.element, $('div.window-controls-container'));
this.windowControls.classList.toggle('show-layout-control', this.layoutControlEnabled);
const layoutDropdownContainer = append(this.windowControls, $('div.layout-dropdown-container'));
this.layoutToolbar = new ActionBar(layoutDropdownContainer,
{
ariaLabel: localize('layoutMenu', "Configure Layout"),
actionViewItemProvider: action => {
if (action instanceof SubmenuAction) {
return new DropdownMenuActionViewItem(action, action.actions, this.contextMenuService, {
classNames: Codicon.editorLayout.classNamesArray,
anchorAlignmentProvider: () => AnchorAlignment.RIGHT,
keybindingProvider: action => this.keybindingService.lookupKeybinding(action.id)
});
}
return undefined;
}
});
const menu = this._register(this.menuService.createMenu(MenuId.LayoutControlMenu, this.contextKeyService));
const updateLayoutMenu = () => {
if (!this.layoutToolbar) {
return;
}
const actions: IAction[] = [];
const toDispose = createAndFillInContextMenuActions(menu, undefined, { primary: [], secondary: actions });
this.layoutToolbar.clear();
this.layoutToolbar.push(new SubmenuAction('stenir', localize('layoutMenu', "Configure Layout"), actions.map(action => {
if (action instanceof MenuItemAction) {
(action as IAction).label = mnemonicButtonLabel(typeof action.item.title === 'string'
? action.item.title
: action.item.title.mnemonicTitle ?? action.item.title.value, true);
}
return action;
})));
toDispose.dispose();
};
menu.onDidChange(updateLayoutMenu);
updateLayoutMenu();
}
// Context menu on title
[EventType.CONTEXT_MENU, EventType.MOUSE_DOWN].forEach(event => {
this._register(addDisposableListener(this.title, event, e => {
@ -413,6 +472,10 @@ export class TitlebarPart extends Part implements ITitleService {
return;
}
if (e.target && this.layoutToolbar && isAncestor(e.target as HTMLElement, this.layoutToolbar.getContainer())) {
return;
}
const active = document.activeElement;
setTimeout(() => {
if (active instanceof HTMLElement) {
@ -507,6 +570,10 @@ export class TitlebarPart extends Part implements ITitleService {
return getMenuBarVisibility(this.configurationService);
}
private get layoutControlEnabled(): boolean {
return this.configurationService.getValue<boolean>('workbench.experimental.layoutControl.enabled');
}
updateLayout(dimension: Dimension): void {
this.lastLayoutDimensions = dimension;

View file

@ -356,6 +356,11 @@ const registry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Con
// On Mac, the delay is 1500.
'default': isMacintosh ? 1500 : 500
},
'workbench.experimental.layoutControl.enabled': {
'type': 'boolean',
'default': product.quality !== 'stable',
'description': localize('layoutControlEnabled', "Controls whether the layout control button in the custom title bar is enabled."),
},
'workbench.experimental.sidePanel.enabled': {
'type': 'boolean',
'default': false,

View file

@ -227,12 +227,13 @@ export class ExperimentService extends Disposable implements IExperimentService
}
protected async getExperiments(): Promise<IRawExperiment[] | null> {
if (!this.productService.experimentsUrl || this.configurationService.getValue('workbench.enableExperiments') === false) {
const experimentsUrl = this.configurationService.getValue<string>('_workbench.experimentsUrl') || this.productService.experimentsUrl;
if (!experimentsUrl || this.configurationService.getValue('workbench.enableExperiments') === false) {
return [];
}
try {
const context = await this.requestService.request({ type: 'GET', url: this.productService.experimentsUrl }, CancellationToken.None);
const context = await this.requestService.request({ type: 'GET', url: experimentsUrl }, CancellationToken.None);
if (context.res.statusCode !== 200) {
return null;
}

View file

@ -258,7 +258,12 @@ export class InteractiveEditor extends EditorPane {
cellExecuteToolbar: MenuId.InteractiveCellExecute,
cellExecutePrimary: undefined
},
cellEditorContributions: [],
cellEditorContributions: EditorExtensionsRegistry.getSomeEditorContributions([
SelectionClipboardContributionID,
ContextMenuController.ID,
ModesHoverController.ID,
MarkerController.ID
]),
options: this.#notebookOptions
});
@ -270,6 +275,9 @@ export class InteractiveEditor extends EditorPane {
top: INPUT_EDITOR_PADDING,
bottom: INPUT_EDITOR_PADDING
},
hover: {
enabled: true
}
}
}, {
...{

View file

@ -446,7 +446,7 @@ registerAction2(class ExecuteCellInsertBelow extends NotebookCellAction {
constructor() {
super({
id: EXECUTE_CELL_INSERT_BELOW,
precondition: executeThisCellCondition,
precondition: ContextKeyExpr.or(executeThisCellCondition, NOTEBOOK_CELL_TYPE.isEqualTo('markup')),
title: localize('notebookActions.executeAndInsertBelow', "Execute Notebook Cell and Insert Below"),
keybinding: {
when: NOTEBOOK_CELL_LIST_FOCUSED,
@ -460,14 +460,17 @@ registerAction2(class ExecuteCellInsertBelow extends NotebookCellAction {
const idx = context.notebookEditor.getCellIndex(context.cell);
const modeService = accessor.get(IModeService);
const newFocusMode = context.cell.focusMode === CellFocusMode.Editor ? 'editor' : 'container';
const executionP = runCell(accessor, context);
const newCell = insertCell(modeService, context.notebookEditor, idx, CellKind.Code, 'below');
const newCell = insertCell(modeService, context.notebookEditor, idx, context.cell.cellKind, 'below');
if (newCell) {
context.notebookEditor.focusNotebookCell(newCell, newFocusMode);
}
return executionP;
if (context.cell.cellKind === CellKind.Markup) {
context.cell.updateEditState(CellEditState.Preview, EXECUTE_CELL_INSERT_BELOW);
} else {
runCell(accessor, context);
}
}
});

View file

@ -637,7 +637,7 @@ async function webviewPreloads(ctx: PreloadContext) {
{
let outputContainer = document.getElementById(event.data.cellId);
if (!outputContainer) {
viewModel.ensureOutputCell(event.data.cellId, -100000);
viewModel.ensureOutputCell(event.data.cellId, -100000, true);
outputContainer = document.getElementById(event.data.cellId);
}
outputContainer?.classList.add(...event.data.addedClassNames);
@ -1032,7 +1032,7 @@ async function webviewPreloads(ctx: PreloadContext) {
return;
}
const cellOutput = this.ensureOutputCell(data.cellId, data.cellTop);
const cellOutput = this.ensureOutputCell(data.cellId, data.cellTop, false);
const outputNode = cellOutput.createOutputElement(data.outputId, data.outputOffset, data.left);
outputNode.render(data.content, preloadsAndErrors);
@ -1040,13 +1040,18 @@ async function webviewPreloads(ctx: PreloadContext) {
cellOutput.element.style.visibility = data.initiallyHidden ? 'hidden' : 'visible';
}
public ensureOutputCell(cellId: string, cellTop: number): OutputCell {
public ensureOutputCell(cellId: string, cellTop: number, skipCellTopUpdateIfExist: boolean): OutputCell {
let cell = this._outputCells.get(cellId);
let existed = !!cell;
if (!cell) {
cell = new OutputCell(cellId);
this._outputCells.set(cellId, cell);
}
if (existed && skipCellTopUpdateIfExist) {
return cell;
}
cell.element.style.top = cellTop + 'px';
return cell;
}

View file

@ -302,6 +302,46 @@ function createObjectValueSuggester(element: SettingsTreeSettingElement): IObjec
};
}
function isNonNullableNumericType(type: unknown): type is 'number' | 'integer' {
return type === 'number' || type === 'integer';
}
function parseNumericObjectValues(dataElement: SettingsTreeSettingElement, v: Record<string, unknown>): Record<string, unknown> {
const newRecord: Record<string, unknown> = {};
for (const key in v) {
// Set to true/false once we're sure of the answer
let keyMatchesNumericProperty: boolean | undefined;
const patternProperties = dataElement.setting.objectPatternProperties;
const properties = dataElement.setting.objectProperties;
const additionalProperties = dataElement.setting.objectAdditionalProperties;
// Match the current record key against the properties of the object
if (properties) {
for (const propKey in properties) {
if (propKey === key) {
keyMatchesNumericProperty = isNonNullableNumericType(properties[propKey].type);
break;
}
}
}
if (keyMatchesNumericProperty === undefined && patternProperties) {
for (const patternKey in patternProperties) {
if (key.match(patternKey)) {
keyMatchesNumericProperty = isNonNullableNumericType(patternProperties[patternKey].type);
break;
}
}
}
if (keyMatchesNumericProperty === undefined && additionalProperties && typeof additionalProperties !== 'boolean') {
if (isNonNullableNumericType(additionalProperties.type)) {
keyMatchesNumericProperty = true;
}
}
newRecord[key] = keyMatchesNumericProperty ? Number(v[key]) : v[key];
}
return newRecord;
}
function getListDisplayValue(element: SettingsTreeSettingElement): IListDataItem[] {
if (!element.value || !isArray(element.value)) {
return [];
@ -1110,18 +1150,6 @@ export class SettingArrayRenderer extends AbstractSettingRenderer implements ITr
return template;
}
private onDidChangeList(template: ISettingListItemTemplate, newList: unknown[] | undefined): void {
if (!template.context || !newList) {
return;
}
this._onDidChangeSetting.fire({
key: template.context.setting.key,
value: newList,
type: template.context.valueType
});
}
private computeNewList(template: ISettingListItemTemplate, e: ISettingListChangeEvent<IListDataItem>): string[] | undefined {
if (template.context) {
let newValue: string[] = [];
@ -1191,17 +1219,15 @@ export class SettingArrayRenderer extends AbstractSettingRenderer implements ITr
template.listWidget.cancelEdit();
}));
template.onChange = (v) => {
if (!renderArrayValidations(dataElement, template, v, false)) {
let arrToSave;
template.onChange = (v: string[] | undefined) => {
if (v && !renderArrayValidations(dataElement, template, v, false)) {
const itemType = dataElement.setting.arrayItemType;
if (v && (itemType === 'number' || itemType === 'integer')) {
arrToSave = v.map(a => +a);
} else {
arrToSave = v;
}
this.onDidChangeList(template, arrToSave);
const arrToSave = isNonNullableNumericType(itemType) ? v.map(a => +a) : v;
onChange(arrToSave);
} else {
// Save the setting unparsed and containing the errors.
// renderArrayValidations will render relevant error messages.
onChange(v);
}
};
@ -1343,8 +1369,14 @@ export class SettingObjectRenderer extends AbstractSettingObjectRenderer impleme
}));
template.onChange = (v: Record<string, unknown> | undefined) => {
onChange(v);
renderArrayValidations(dataElement, template, v, false);
if (v && !renderArrayValidations(dataElement, template, v, false)) {
const parsedRecord = parseNumericObjectValues(dataElement, v);
onChange(parsedRecord);
} else {
// Save the setting unparsed and containing the errors.
// renderArrayValidations will render relevant error messages.
onChange(v);
}
};
renderArrayValidations(dataElement, template, dataElement.value, true);
}

View file

@ -576,7 +576,7 @@ export function isExcludeSetting(setting: ISetting): boolean {
}
function isObjectRenderableSchema({ type }: IJSONSchema): boolean {
return type === 'string' || type === 'boolean';
return type === 'string' || type === 'boolean' || type === 'integer' || type === 'number';
}
function isObjectSetting({

View file

@ -25,9 +25,9 @@ import { getTitleBarStyle } from 'vs/platform/windows/common/windows';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { Codicon } from 'vs/base/common/codicons';
import { NativeMenubarControl } from 'vs/workbench/electron-sandbox/parts/titlebar/menubarControl';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
export class TitlebarPart extends BrowserTitleBarPart {
private windowControls: HTMLElement | undefined;
private maxRestoreControl: HTMLElement | undefined;
private dragRegion: HTMLElement | undefined;
private resizer: HTMLElement | undefined;
@ -53,6 +53,7 @@ export class TitlebarPart extends BrowserTitleBarPart {
@INativeWorkbenchEnvironmentService environmentService: INativeWorkbenchEnvironmentService,
@IWorkspaceContextService contextService: IWorkspaceContextService,
@IInstantiationService instantiationService: IInstantiationService,
@IKeybindingService keybindingService: IKeybindingService,
@IThemeService themeService: IThemeService,
@ILabelService labelService: ILabelService,
@IStorageService storageService: IStorageService,
@ -63,7 +64,7 @@ export class TitlebarPart extends BrowserTitleBarPart {
@IProductService productService: IProductService,
@INativeHostService private readonly nativeHostService: INativeHostService
) {
super(contextMenuService, configurationService, editorService, environmentService, contextService, instantiationService, themeService, labelService, storageService, layoutService, menuService, contextKeyService, hostService, productService);
super(contextMenuService, configurationService, editorService, environmentService, contextService, instantiationService, keybindingService, themeService, labelService, storageService, layoutService, menuService, contextKeyService, hostService, productService);
this.environmentService = environmentService;
}
@ -187,9 +188,7 @@ export class TitlebarPart extends BrowserTitleBarPart {
this.dragRegion = prepend(this.element, $('div.titlebar-drag-region'));
// Window Controls (Native Windows/Linux)
if (!isMacintosh) {
this.windowControls = append(this.element, $('div.window-controls-container'));
if (!isMacintosh && this.windowControls) {
// Minimize
const minimizeIcon = append(this.windowControls, $('div.window-icon.window-minimize' + Codicon.chromeMinimize.cssSelector));
this._register(addDisposableListener(minimizeIcon, EventType.CLICK, e => {

View file

@ -15,7 +15,7 @@ import { PreferredGroup, SIDE_GROUP } from 'vs/workbench/services/editor/common/
/**
* Finds the target `IEditorGroup` given the instructions provided
* that is best for the editor and matches the preferred group if
* posisble.
* possible.
*/
export function findGroup(accessor: ServicesAccessor, editor: IUntypedEditorInput, preferredGroup: PreferredGroup | undefined): [IEditorGroup, EditorActivation | undefined];
export function findGroup(accessor: ServicesAccessor, editor: EditorInputWithOptions, preferredGroup: PreferredGroup | undefined): [IEditorGroup, EditorActivation | undefined];

View file

@ -38,8 +38,6 @@ export class SharedProcessService extends Disposable implements ISharedProcessSe
// as a result. As such, make sure we await the `Restored`
// phase before making a connection attempt, but also add a
// timeout to be safe against possible deadlocks.
// TODO@sandbox revisit this when the shared process connection
// is more cruicial.
await Promise.race([this.restoredBarrier.wait(), timeout(2000)]);
// Acquire a message port connected to the shared process

View file

@ -1107,13 +1107,13 @@ declare module 'vscode' {
/**
* The selections in this text editor. The primary selection is always at index 0.
*/
selections: Selection[];
selections: readonly Selection[];
/**
* The current visible ranges in the editor (vertically).
* This accounts only for vertical scrolling, and not for horizontal scrolling.
*/
readonly visibleRanges: Range[];
readonly visibleRanges: readonly Range[];
/**
* Text editor options.
@ -8656,7 +8656,7 @@ declare module 'vscode' {
/**
* The currently visible editors or an empty array.
*/
export let visibleTextEditors: TextEditor[];
export let visibleTextEditors: readonly TextEditor[];
/**
* An {@link Event} which fires when the {@link window.activeTextEditor active editor}
@ -8669,7 +8669,7 @@ declare module 'vscode' {
* An {@link Event} which fires when the array of {@link window.visibleTextEditors visible editors}
* has changed.
*/
export const onDidChangeVisibleTextEditors: Event<TextEditor[]>;
export const onDidChangeVisibleTextEditors: Event<readonly TextEditor[]>;
/**
* An {@link Event} which fires when the selection in an editor has changed.
@ -9354,7 +9354,7 @@ declare module 'vscode' {
/**
* Selected elements.
*/
readonly selection: T[];
readonly selection: readonly T[];
}
@ -9388,7 +9388,7 @@ declare module 'vscode' {
/**
* Currently selected elements.
*/
readonly selection: T[];
readonly selection: readonly T[];
/**
* Event that is fired when the {@link TreeView.selection selection} has changed
@ -13387,7 +13387,7 @@ declare module 'vscode' {
/**
* List of breakpoints.
*/
export let breakpoints: Breakpoint[];
export let breakpoints: readonly Breakpoint[];
/**
* An {@link Event} which fires when the {@link debug.activeDebugSession active debug session}
@ -14322,7 +14322,7 @@ declare module 'vscode' {
* The process of running tests should resolve the children of any test
* items who have not yet been resolved.
*/
readonly include: TestItem[] | undefined;
readonly include: readonly TestItem[] | undefined;
/**
* An array of tests the user has marked as excluded from the test included
@ -14331,7 +14331,7 @@ declare module 'vscode' {
* May be omitted if no exclusions were requested. Test controllers should
* not run excluded tests or any children of excluded tests.
*/
readonly exclude: TestItem[] | undefined;
readonly exclude: readonly TestItem[] | undefined;
/**
* The profile used for this request. This will always be defined

View file

@ -752,7 +752,7 @@ declare module 'vscode' {
//#endregion
// eslint-disable-next-line vscode-dts-region-comments
//#region @roblourens: new debug session option for simple UI 'managedByParent' (see https://github.com/microsoft/vscode/issues/128588)
//#region notebookDebugOptions: @roblourens: new debug session option for simple UI 'managedByParent' (see https://github.com/microsoft/vscode/issues/128588)
/**
* Options for {@link debug.startDebugging starting a debug session}.
@ -774,8 +774,7 @@ declare module 'vscode' {
//#endregion
// eslint-disable-next-line vscode-dts-region-comments
// #region scmValidation: @joaomoreno:
// #region scmValidation: @joaomoreno
/**
* Represents the validation type of the Source Control input.
@ -830,7 +829,7 @@ declare module 'vscode' {
//#endregion
//#region scmSelectedProvider: @joaomoreno:
//#region scmSelectedProvider: @joaomoreno
export interface SourceControl {