Merge from vscode 6e530127a1bb8ffbd1bfb77dc680c321dc0d71f5 (#6844)

This commit is contained in:
Anthony Dresser
2019-08-20 21:07:47 -07:00
committed by GitHub
parent 1f00249646
commit ecb80f14f0
221 changed files with 3140 additions and 1552 deletions

View File

@@ -113,7 +113,7 @@ export function extractResources(e: DragEvent, externalOnly?: boolean): Array<ID
if (e.dataTransfer && e.dataTransfer.files) {
for (let i = 0; i < e.dataTransfer.files.length; i++) {
const file = e.dataTransfer.files[i];
if (file && file.path && !resources.some(r => r.resource.fsPath === file.path) /* prevent duplicates */) {
if (file && file.path /* Electron only */ && !resources.some(r => r.resource.fsPath === file.path) /* prevent duplicates */) {
try {
resources.push({ resource: URI.file(file.path), isExternal: true });
} catch (error) {

View File

@@ -317,40 +317,34 @@ class ResourceLabelWidget extends IconLabel {
}
notifyFormattersChange(): void {
if (this.label && this.label.resource) {
this.setFile(this.label.resource, this.options);
}
this.render(false);
}
setResource(label: IResourceLabelProps, options?: IResourceLabelOptions): void {
const hasResourceChanged = this.hasResourceChanged(label, options);
const hasPathLabelChanged = this.hasPathLabelChanged(label, options);
const clearIconCache = this.clearIconCache(label, options);
this.label = label;
this.options = options;
if (hasResourceChanged) {
if (hasPathLabelChanged) {
this.computedPathLabel = undefined; // reset path label due to resource change
}
this.render(hasResourceChanged);
this.render(clearIconCache);
}
private hasResourceChanged(label: IResourceLabelProps, options?: IResourceLabelOptions): boolean {
const newResource = label ? label.resource : undefined;
private clearIconCache(newLabel: IResourceLabelProps, newOptions?: IResourceLabelOptions): boolean {
const newResource = newLabel ? newLabel.resource : undefined;
const oldResource = this.label ? this.label.resource : undefined;
const newFileKind = options ? options.fileKind : undefined;
const newFileKind = newOptions ? newOptions.fileKind : undefined;
const oldFileKind = this.options ? this.options.fileKind : undefined;
if (newFileKind !== oldFileKind) {
return true; // same resource but different kind (file, folder)
}
if (newResource && this.computedPathLabel !== this.labelService.getUriLabel(newResource)) {
return true;
}
if (newResource && oldResource) {
return newResource.toString() !== oldResource.toString();
}
@@ -362,6 +356,12 @@ class ResourceLabelWidget extends IconLabel {
return true;
}
private hasPathLabelChanged(newLabel: IResourceLabelProps, newOptions?: IResourceLabelOptions): boolean {
const newResource = newLabel ? newLabel.resource : undefined;
return !!newResource && this.computedPathLabel !== this.labelService.getUriLabel(newResource);
}
setEditor(editor: IEditorInput, options?: IResourceLabelOptions): void {
this.setResource({
resource: toResource(editor, { supportSideBySide: SideBySideEditor.MASTER }),
@@ -460,6 +460,7 @@ class ResourceLabelWidget extends IconLabel {
}
iconLabelOptions.extraClasses = this.computedIconClasses.slice(0);
}
if (this.options && this.options.extraClasses) {
iconLabelOptions.extraClasses!.push(...this.options.extraClasses);
}

View File

@@ -9,7 +9,7 @@ import { CancellationTokenSource } from 'vs/base/common/cancellation';
import { size } from 'vs/base/common/collections';
import { onUnexpectedError } from 'vs/base/common/errors';
import { Emitter, Event } from 'vs/base/common/event';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { isEqual, dirname } from 'vs/base/common/resources';
import { URI } from 'vs/base/common/uri';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
@@ -36,14 +36,14 @@ type FileInfo = { path: FileElement[], folder?: IWorkspaceFolder };
export class EditorBreadcrumbsModel {
private readonly _disposables: IDisposable[] = [];
private readonly _disposables = new DisposableStore();
private readonly _fileInfo: FileInfo;
private readonly _cfgFilePath: BreadcrumbsConfig<'on' | 'off' | 'last'>;
private readonly _cfgSymbolPath: BreadcrumbsConfig<'on' | 'off' | 'last'>;
private _outlineElements: Array<OutlineModel | OutlineGroup | OutlineElement> = [];
private _outlineDisposables: IDisposable[] = [];
private _outlineDisposables = new DisposableStore();
private _onDidUpdate = new Emitter<this>();
readonly onDidUpdate: Event<this> = this._onDidUpdate.event;
@@ -58,8 +58,8 @@ export class EditorBreadcrumbsModel {
this._cfgFilePath = BreadcrumbsConfig.FilePath.bindTo(configurationService);
this._cfgSymbolPath = BreadcrumbsConfig.SymbolPath.bindTo(configurationService);
this._disposables.push(this._cfgFilePath.onDidChange(_ => this._onDidUpdate.fire(this)));
this._disposables.push(this._cfgSymbolPath.onDidChange(_ => this._onDidUpdate.fire(this)));
this._disposables.add(this._cfgFilePath.onDidChange(_ => this._onDidUpdate.fire(this)));
this._disposables.add(this._cfgSymbolPath.onDidChange(_ => this._onDidUpdate.fire(this)));
this._fileInfo = EditorBreadcrumbsModel._initFilePathInfo(this._uri, workspaceService);
this._bindToEditor();
@@ -69,7 +69,7 @@ export class EditorBreadcrumbsModel {
dispose(): void {
this._cfgFilePath.dispose();
this._cfgSymbolPath.dispose();
dispose(this._disposables);
this._disposables.dispose();
}
isRelative(): boolean {
@@ -133,20 +133,27 @@ export class EditorBreadcrumbsModel {
if (!this._editor) {
return;
}
// update as model changes
this._disposables.push(DocumentSymbolProviderRegistry.onDidChange(_ => this._updateOutline()));
this._disposables.push(this._editor.onDidChangeModel(_ => this._updateOutline()));
this._disposables.push(this._editor.onDidChangeModelLanguage(_ => this._updateOutline()));
this._disposables.push(Event.debounce(this._editor.onDidChangeModelContent, _ => _, 350)(_ => this._updateOutline(true)));
// update as language, model, providers changes
this._disposables.add(DocumentSymbolProviderRegistry.onDidChange(_ => this._updateOutline()));
this._disposables.add(this._editor.onDidChangeModel(_ => this._updateOutline()));
this._disposables.add(this._editor.onDidChangeModelLanguage(_ => this._updateOutline()));
// update soon'ish as model content change
const updateSoon = new TimeoutTimer();
this._disposables.add(updateSoon);
this._disposables.add(this._editor.onDidChangeModelContent(_ => {
const timeout = OutlineModel.getRequestDelay(this._editor!.getModel());
updateSoon.cancelAndSet(() => this._updateOutline(true), timeout);
}));
this._updateOutline();
// stop when editor dies
this._disposables.push(this._editor.onDidDispose(() => this._outlineDisposables = dispose(this._outlineDisposables)));
this._disposables.add(this._editor.onDidDispose(() => this._outlineDisposables.clear()));
}
private _updateOutline(didChangeContent?: boolean): void {
this._outlineDisposables = dispose(this._outlineDisposables);
this._outlineDisposables.clear();
if (!didChangeContent) {
this._updateOutlineElements([]);
}
@@ -162,7 +169,7 @@ export class EditorBreadcrumbsModel {
const versionIdThen = buffer.getVersionId();
const timeout = new TimeoutTimer();
this._outlineDisposables.push({
this._outlineDisposables.add({
dispose: () => {
source.cancel();
source.dispose();
@@ -180,7 +187,7 @@ export class EditorBreadcrumbsModel {
model = model.adopt();
this._updateOutlineElements(this._getOutlineElements(model, editor.getPosition()));
this._outlineDisposables.push(editor.onDidChangeCursorPosition(_ => {
this._outlineDisposables.add(editor.onDidChangeCursorPosition(_ => {
timeout.cancelAndSet(() => {
if (!buffer.isDisposed() && versionIdThen === buffer.getVersionId() && editor.getModel()) {
this._updateOutlineElements(this._getOutlineElements(model, editor.getPosition()));

View File

@@ -17,6 +17,10 @@
text-decoration-line: underline;
}
.monaco-workbench .monaco-breadcrumb-item.shows-symbol-icon .symbol-icon.block {
padding-right: 6px;
}
/* todo@joh move somewhere else */
.monaco-workbench .monaco-breadcrumbs-picker .arrow {

View File

@@ -66,4 +66,4 @@
.vs .monaco-workbench > .notifications-center > .notifications-center-header .hide-all-notifications-action {
background-image: url('tree-expanded-light.svg');
}
}

View File

@@ -91,6 +91,7 @@
.monaco-workbench .notifications-list-container .notification-list-item .notification-list-item-toolbar-container {
display: none;
height: 22px;
}
.monaco-workbench .notifications-list-container .notification-list-item:hover .notification-list-item-toolbar-container,
@@ -142,4 +143,4 @@
.monaco-workbench .notifications-list-container .progress-bit {
height: 2px;
bottom: 0;
}
}

View File

@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { IMenubarMenu, IMenubarMenuItemAction, IMenubarMenuItemSubmenu, IMenubarKeybinding, IMenubarService, IMenubarData, MenubarMenuItem } from 'vs/platform/menubar/common/menubar';
import { IMenuService, MenuId, IMenu, SubmenuItemAction } from 'vs/platform/actions/common/actions';
import { registerThemingParticipant, ITheme, ICssStyleCollector, IThemeService } from 'vs/platform/theme/common/themeService';
import { IWindowService, MenuBarVisibility, IWindowsService, getTitleBarStyle, IURIToOpen } from 'vs/platform/windows/common/windows';
@@ -33,7 +32,6 @@ import { attachMenuStyler } from 'vs/platform/theme/common/styler';
import { assign } from 'vs/base/common/objects';
import { mnemonicMenuLabel, unmnemonicLabel } from 'vs/base/common/labels';
import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
import { withNullAsUndefined } from 'vs/base/common/types';
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { isFullscreen } from 'vs/base/browser/browser';
@@ -134,7 +132,7 @@ export abstract class MenubarControl extends Disposable {
this.menuUpdater.schedule();
}
protected calculateActionLabel(action: IAction | IMenubarMenuItemAction): string {
protected calculateActionLabel(action: { id: string; label: string; }): string {
let label = action.label;
switch (action.id) {
default:
@@ -252,195 +250,6 @@ export abstract class MenubarControl extends Disposable {
}
}
export class NativeMenubarControl extends MenubarControl {
constructor(
@IMenuService menuService: IMenuService,
@IWindowService windowService: IWindowService,
@IWindowsService windowsService: IWindowsService,
@IContextKeyService contextKeyService: IContextKeyService,
@IKeybindingService keybindingService: IKeybindingService,
@IConfigurationService configurationService: IConfigurationService,
@ILabelService labelService: ILabelService,
@IUpdateService updateService: IUpdateService,
@IStorageService storageService: IStorageService,
@INotificationService notificationService: INotificationService,
@IPreferencesService preferencesService: IPreferencesService,
@IEnvironmentService environmentService: IEnvironmentService,
@IAccessibilityService accessibilityService: IAccessibilityService,
@IMenubarService private readonly menubarService: IMenubarService
) {
super(
menuService,
windowService,
windowsService,
contextKeyService,
keybindingService,
configurationService,
labelService,
updateService,
storageService,
notificationService,
preferencesService,
environmentService,
accessibilityService);
if (isMacintosh && !isWeb) {
this.menus['Preferences'] = this._register(this.menuService.createMenu(MenuId.MenubarPreferencesMenu, this.contextKeyService));
this.topLevelTitles['Preferences'] = nls.localize('mPreferences', "Preferences");
}
for (const topLevelMenuName of Object.keys(this.topLevelTitles)) {
const menu = this.menus[topLevelMenuName];
if (menu) {
this._register(menu.onDidChange(() => this.updateMenubar()));
}
}
this.windowService.getRecentlyOpened().then((recentlyOpened) => {
this.recentlyOpened = recentlyOpened;
this.doUpdateMenubar(true);
});
this.registerListeners();
}
protected doUpdateMenubar(firstTime: boolean): void {
// Send menus to main process to be rendered by Electron
const menubarData = { menus: {}, keybindings: {} };
if (this.getMenubarMenus(menubarData)) {
this.menubarService.updateMenubar(this.windowService.windowId, menubarData);
}
}
private getMenubarMenus(menubarData: IMenubarData): boolean {
if (!menubarData) {
return false;
}
menubarData.keybindings = this.getAdditionalKeybindings();
for (const topLevelMenuName of Object.keys(this.topLevelTitles)) {
const menu = this.menus[topLevelMenuName];
if (menu) {
const menubarMenu: IMenubarMenu = { items: [] };
this.populateMenuItems(menu, menubarMenu, menubarData.keybindings);
if (menubarMenu.items.length === 0) {
// Menus are incomplete
return false;
}
menubarData.menus[topLevelMenuName] = menubarMenu;
}
}
return true;
}
private populateMenuItems(menu: IMenu, menuToPopulate: IMenubarMenu, keybindings: { [id: string]: IMenubarKeybinding | undefined }) {
let groups = menu.getActions();
for (let group of groups) {
const [, actions] = group;
actions.forEach(menuItem => {
if (menuItem instanceof SubmenuItemAction) {
const submenu = { items: [] };
if (!this.menus[menuItem.item.submenu]) {
this.menus[menuItem.item.submenu] = this.menuService.createMenu(menuItem.item.submenu, this.contextKeyService);
this._register(this.menus[menuItem.item.submenu]!.onDidChange(() => this.updateMenubar()));
}
const menuToDispose = this.menuService.createMenu(menuItem.item.submenu, this.contextKeyService);
this.populateMenuItems(menuToDispose, submenu, keybindings);
let menubarSubmenuItem: IMenubarMenuItemSubmenu = {
id: menuItem.id,
label: menuItem.label,
submenu: submenu
};
menuToPopulate.items.push(menubarSubmenuItem);
menuToDispose.dispose();
} else {
if (menuItem.id === 'workbench.action.openRecent') {
const actions = this.getOpenRecentActions().map(this.transformOpenRecentAction);
menuToPopulate.items.push(...actions);
}
let menubarMenuItem: IMenubarMenuItemAction = {
id: menuItem.id,
label: menuItem.label
};
if (menuItem.checked) {
menubarMenuItem.checked = true;
}
if (!menuItem.enabled) {
menubarMenuItem.enabled = false;
}
menubarMenuItem.label = this.calculateActionLabel(menubarMenuItem);
keybindings[menuItem.id] = this.getMenubarKeybinding(menuItem.id);
menuToPopulate.items.push(menubarMenuItem);
}
});
menuToPopulate.items.push({ id: 'vscode.menubar.separator' });
}
if (menuToPopulate.items.length > 0) {
menuToPopulate.items.pop();
}
}
private transformOpenRecentAction(action: Separator | (IAction & { uri: URI })): MenubarMenuItem {
if (action instanceof Separator) {
return { id: 'vscode.menubar.separator' };
}
return {
id: action.id,
uri: action.uri,
enabled: action.enabled,
label: action.label
};
}
private getAdditionalKeybindings(): { [id: string]: IMenubarKeybinding } {
const keybindings: { [id: string]: IMenubarKeybinding } = {};
if (isMacintosh) {
const keybinding = this.getMenubarKeybinding('workbench.action.quit');
if (keybinding) {
keybindings['workbench.action.quit'] = keybinding;
}
}
return keybindings;
}
private getMenubarKeybinding(id: string): IMenubarKeybinding | undefined {
const binding = this.keybindingService.lookupKeybinding(id);
if (!binding) {
return undefined;
}
// first try to resolve a native accelerator
const electronAccelerator = binding.getElectronAccelerator();
if (electronAccelerator) {
return { label: electronAccelerator, userSettingsLabel: withNullAsUndefined(binding.getUserSettingsLabel()) };
}
// we need this fallback to support keybindings that cannot show in electron menus (e.g. chords)
const acceleratorLabel = binding.getLabel();
if (acceleratorLabel) {
return { label: acceleratorLabel, isNative: false, userSettingsLabel: withNullAsUndefined(binding.getUserSettingsLabel()) };
}
return undefined;
}
}
export class CustomMenubarControl extends MenubarControl {
private menubar: MenuBar;
private container: HTMLElement;

View File

@@ -27,7 +27,7 @@ import { URI } from 'vs/base/common/uri';
import { Color } from 'vs/base/common/color';
import { trim } from 'vs/base/common/strings';
import { EventType, EventHelper, Dimension, isAncestor, hide, show, removeClass, addClass, append, $, addDisposableListener, runAtThisOrScheduleAtNextAnimationFrame } from 'vs/base/browser/dom';
import { MenubarControl, NativeMenubarControl, CustomMenubarControl } from 'vs/workbench/browser/parts/titlebar/menubarControl';
import { CustomMenubarControl } from 'vs/workbench/browser/parts/titlebar/menubarControl';
import { IInstantiationService, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
import { template, getBaseLabel } from 'vs/base/common/labels';
import { ILabelService } from 'vs/platform/label/common/label';
@@ -65,7 +65,7 @@ export class TitlebarPart extends Part implements ITitleService {
private windowControls: HTMLElement;
private maxRestoreControl: HTMLElement;
private appIcon: HTMLElement;
private menubarPart: MenubarControl;
private customMenubar: CustomMenubarControl | undefined;
private menubar: HTMLElement;
private resizer: HTMLElement;
private lastLayoutDimensions: Dimension;
@@ -332,19 +332,16 @@ export class TitlebarPart extends Part implements ITitleService {
})));
}
// Menubar: the menubar part which is responsible for populating both the custom and native menubars
if ((isMacintosh && !isWeb) || getTitleBarStyle(this.configurationService, this.environmentService) === 'native') {
this.menubarPart = this.instantiationService.createInstance(NativeMenubarControl);
} else {
const customMenubarControl = this.instantiationService.createInstance(CustomMenubarControl);
this.menubarPart = customMenubarControl;
// Menubar: install a custom menu bar depending on configuration
if (getTitleBarStyle(this.configurationService, this.environmentService) !== 'native' && (!isMacintosh || isWeb)) {
this.customMenubar = this._register(this.instantiationService.createInstance(CustomMenubarControl));
this.menubar = append(this.element, $('div.menubar'));
this.menubar.setAttribute('role', 'menubar');
customMenubarControl.create(this.menubar);
this.customMenubar.create(this.menubar);
this._register(customMenubarControl.onVisibilityChange(e => this.onMenubarVisibilityChanged(e)));
this._register(customMenubarControl.onFocusStateChange(e => this.onMenubarFocusChanged(e)));
this._register(this.customMenubar.onVisibilityChange(e => this.onMenubarVisibilityChanged(e)));
this._register(this.customMenubar.onFocusStateChange(e => this.onMenubarFocusChanged(e)));
}
// Title
@@ -547,7 +544,7 @@ export class TitlebarPart extends Part implements ITitleService {
}
private adjustTitleMarginToCenter(): void {
if (this.menubarPart instanceof CustomMenubarControl) {
if (this.customMenubar) {
const leftMarker = (this.appIcon ? this.appIcon.clientWidth : 0) + this.menubar.clientWidth + 10;
const rightMarker = this.element.clientWidth - (this.windowControls ? this.windowControls.clientWidth : 0) - 10;
@@ -588,9 +585,9 @@ export class TitlebarPart extends Part implements ITitleService {
runAtThisOrScheduleAtNextAnimationFrame(() => this.adjustTitleMarginToCenter());
if (this.menubarPart instanceof CustomMenubarControl) {
if (this.customMenubar) {
const menubarDimension = new Dimension(0, dimension.height);
this.menubarPart.layout(menubarDimension);
this.customMenubar.layout(menubarDimension);
}
}
}

View File

@@ -69,7 +69,9 @@ export class CustomTreeViewPanel extends ViewletPanel {
}
renderBody(container: HTMLElement): void {
this.treeView.show(container);
if (this.treeView instanceof CustomTreeView) {
this.treeView.show(container);
}
}
layoutBody(height: number, width: number): void {

View File

@@ -204,7 +204,7 @@ class CodeRendererMain extends Disposable {
version: '1.38.0-unknown',
nameLong: 'Unknown',
extensionAllowedProposedApi: [],
}, ...{ urlProtocol: '', enableTelemetry: false }
}, ...{ urlProtocol: '' }
};
return { _serviceBrand: undefined, ...productConfiguration };
}

View File

@@ -50,12 +50,12 @@ export class Workbench extends Layout {
private readonly _onBeforeShutdown = this._register(new Emitter<BeforeShutdownEvent>());
readonly onBeforeShutdown: Event<BeforeShutdownEvent> = this._onBeforeShutdown.event;
private readonly _onShutdown = this._register(new Emitter<void>());
readonly onShutdown: Event<void> = this._onShutdown.event;
private readonly _onWillShutdown = this._register(new Emitter<WillShutdownEvent>());
readonly onWillShutdown: Event<WillShutdownEvent> = this._onWillShutdown.event;
private readonly _onShutdown = this._register(new Emitter<void>());
readonly onShutdown: Event<void> = this._onShutdown.event;
constructor(
parent: HTMLElement,
private readonly serviceCollection: ServiceCollection,
@@ -429,7 +429,7 @@ export class Workbench extends Layout {
// Restore Editor Center Mode
if (this.state.editor.restoreCentered) {
this.centerEditorLayout(true);
this.centerEditorLayout(true, true);
}
// Emit a warning after 10s if restore does not complete