mirror of
https://github.com/coder/code-server.git
synced 2026-05-14 00:07:27 +02:00
chore(vscode): update to 1.55.2
This commit is contained in:
@@ -7,9 +7,9 @@ import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { List } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { WorkbenchListFocusContextKey, IListService, WorkbenchListSupportsMultiSelectContextKey, ListWidget, WorkbenchListHasSelectionOrFocus, getSelectionKeyboardEvent, WorkbenchListWidget } from 'vs/platform/list/browser/listService';
|
||||
import { WorkbenchListFocusContextKey, IListService, WorkbenchListSupportsMultiSelectContextKey, ListWidget, WorkbenchListHasSelectionOrFocus, getSelectionKeyboardEvent, WorkbenchListWidget, WorkbenchListSelectionNavigation } from 'vs/platform/list/browser/listService';
|
||||
import { PagedList } from 'vs/base/browser/ui/list/listPaging';
|
||||
import { range } from 'vs/base/common/arrays';
|
||||
import { equals, range } from 'vs/base/common/arrays';
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ObjectTree } from 'vs/base/browser/ui/tree/objectTree';
|
||||
import { AsyncDataTree } from 'vs/base/browser/ui/tree/asyncDataTree';
|
||||
@@ -28,36 +28,40 @@ function ensureDOMFocus(widget: ListWidget | undefined): void {
|
||||
}
|
||||
}
|
||||
|
||||
function focusDown(accessor: ServicesAccessor, arg2?: number, loop: boolean = false): void {
|
||||
const focused = accessor.get(IListService).lastFocusedList;
|
||||
const count = typeof arg2 === 'number' ? arg2 : 1;
|
||||
|
||||
// List
|
||||
if (focused instanceof List || focused instanceof PagedList || focused instanceof Table) {
|
||||
const list = focused;
|
||||
|
||||
list.focusNext(count);
|
||||
const listFocus = list.getFocus();
|
||||
if (listFocus.length) {
|
||||
list.reveal(listFocus[0]);
|
||||
}
|
||||
async function updateFocus(widget: WorkbenchListWidget, updateFocusFn: (widget: WorkbenchListWidget) => void | Promise<void>): Promise<void> {
|
||||
if (!WorkbenchListSelectionNavigation.getValue(widget.contextKeyService)) {
|
||||
return updateFocusFn(widget);
|
||||
}
|
||||
|
||||
// Tree
|
||||
else if (focused instanceof ObjectTree || focused instanceof DataTree || focused instanceof AsyncDataTree) {
|
||||
const tree = focused;
|
||||
const focus = widget.getFocus();
|
||||
const selection = widget.getSelection();
|
||||
|
||||
const fakeKeyboardEvent = new KeyboardEvent('keydown');
|
||||
tree.focusNext(count, loop, fakeKeyboardEvent);
|
||||
await updateFocusFn(widget);
|
||||
|
||||
const listFocus = tree.getFocus();
|
||||
if (listFocus.length) {
|
||||
tree.reveal(listFocus[0]);
|
||||
}
|
||||
const newFocus = widget.getFocus();
|
||||
|
||||
if (selection.length > 1 || !equals(focus, selection) || equals(focus, newFocus)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure DOM Focus
|
||||
ensureDOMFocus(focused);
|
||||
const fakeKeyboardEvent = new KeyboardEvent('keydown');
|
||||
widget.setSelection(newFocus, fakeKeyboardEvent);
|
||||
}
|
||||
|
||||
async function navigate(widget: WorkbenchListWidget | undefined, updateFocusFn: (widget: WorkbenchListWidget) => void | Promise<void>): Promise<void> {
|
||||
if (!widget) {
|
||||
return;
|
||||
}
|
||||
|
||||
await updateFocus(widget, updateFocusFn);
|
||||
|
||||
const listFocus = widget.getFocus();
|
||||
|
||||
if (listFocus.length) {
|
||||
widget.reveal(listFocus[0]);
|
||||
}
|
||||
|
||||
ensureDOMFocus(widget);
|
||||
}
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
@@ -69,7 +73,81 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
primary: KeyCode.DownArrow,
|
||||
secondary: [KeyMod.WinCtrl | KeyCode.KEY_N]
|
||||
},
|
||||
handler: (accessor, arg2) => focusDown(accessor, arg2)
|
||||
handler: (accessor, arg2) => {
|
||||
navigate(accessor.get(IListService).lastFocusedList, async widget => {
|
||||
const fakeKeyboardEvent = new KeyboardEvent('keydown');
|
||||
await widget.focusNext(typeof arg2 === 'number' ? arg2 : 1, false, fakeKeyboardEvent);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: 'list.focusUp',
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
when: WorkbenchListFocusContextKey,
|
||||
primary: KeyCode.UpArrow,
|
||||
mac: {
|
||||
primary: KeyCode.UpArrow,
|
||||
secondary: [KeyMod.WinCtrl | KeyCode.KEY_P]
|
||||
},
|
||||
handler: (accessor, arg2) => {
|
||||
navigate(accessor.get(IListService).lastFocusedList, async widget => {
|
||||
const fakeKeyboardEvent = new KeyboardEvent('keydown');
|
||||
await widget.focusPrevious(typeof arg2 === 'number' ? arg2 : 1, false, fakeKeyboardEvent);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: 'list.focusPageDown',
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
when: WorkbenchListFocusContextKey,
|
||||
primary: KeyCode.PageDown,
|
||||
handler: (accessor) => {
|
||||
navigate(accessor.get(IListService).lastFocusedList, async widget => {
|
||||
const fakeKeyboardEvent = new KeyboardEvent('keydown');
|
||||
await widget.focusNextPage(fakeKeyboardEvent);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: 'list.focusPageUp',
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
when: WorkbenchListFocusContextKey,
|
||||
primary: KeyCode.PageUp,
|
||||
handler: (accessor) => {
|
||||
navigate(accessor.get(IListService).lastFocusedList, async widget => {
|
||||
const fakeKeyboardEvent = new KeyboardEvent('keydown');
|
||||
await widget.focusPreviousPage(fakeKeyboardEvent);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: 'list.focusFirst',
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
when: WorkbenchListFocusContextKey,
|
||||
primary: KeyCode.Home,
|
||||
handler: (accessor) => {
|
||||
navigate(accessor.get(IListService).lastFocusedList, async widget => {
|
||||
const fakeKeyboardEvent = new KeyboardEvent('keydown');
|
||||
await widget.focusFirst(fakeKeyboardEvent);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: 'list.focusLast',
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
when: WorkbenchListFocusContextKey,
|
||||
primary: KeyCode.End,
|
||||
handler: (accessor) => {
|
||||
navigate(accessor.get(IListService).lastFocusedList, async widget => {
|
||||
const fakeKeyboardEvent = new KeyboardEvent('keydown');
|
||||
await widget.focusLast(fakeKeyboardEvent);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function expandMultiSelection(focused: WorkbenchListWidget, previousFocus: unknown): void {
|
||||
@@ -116,64 +194,28 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
when: ContextKeyExpr.and(WorkbenchListFocusContextKey, WorkbenchListSupportsMultiSelectContextKey),
|
||||
primary: KeyMod.Shift | KeyCode.DownArrow,
|
||||
handler: (accessor, arg2) => {
|
||||
const focused = accessor.get(IListService).lastFocusedList;
|
||||
const widget = accessor.get(IListService).lastFocusedList;
|
||||
|
||||
// List / Tree
|
||||
if (focused instanceof List || focused instanceof PagedList || focused instanceof Table || focused instanceof ObjectTree || focused instanceof DataTree || focused instanceof AsyncDataTree) {
|
||||
const list = focused;
|
||||
|
||||
// Focus down first
|
||||
const previousFocus = list.getFocus() ? list.getFocus()[0] : undefined;
|
||||
focusDown(accessor, arg2, false);
|
||||
|
||||
// Then adjust selection
|
||||
expandMultiSelection(focused, previousFocus);
|
||||
if (!widget) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function focusUp(accessor: ServicesAccessor, arg2?: number, loop: boolean = false): void {
|
||||
const focused = accessor.get(IListService).lastFocusedList;
|
||||
const count = typeof arg2 === 'number' ? arg2 : 1;
|
||||
|
||||
// List
|
||||
if (focused instanceof List || focused instanceof PagedList || focused instanceof Table) {
|
||||
const list = focused;
|
||||
|
||||
list.focusPrevious(count);
|
||||
const listFocus = list.getFocus();
|
||||
if (listFocus.length) {
|
||||
list.reveal(listFocus[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// Tree
|
||||
else if (focused instanceof ObjectTree || focused instanceof DataTree || focused instanceof AsyncDataTree) {
|
||||
const tree = focused;
|
||||
|
||||
// Focus down first
|
||||
const previousFocus = widget.getFocus() ? widget.getFocus()[0] : undefined;
|
||||
const fakeKeyboardEvent = new KeyboardEvent('keydown');
|
||||
tree.focusPrevious(count, loop, fakeKeyboardEvent);
|
||||
widget.focusNext(typeof arg2 === 'number' ? arg2 : 1, false, fakeKeyboardEvent);
|
||||
|
||||
const listFocus = tree.getFocus();
|
||||
if (listFocus.length) {
|
||||
tree.reveal(listFocus[0]);
|
||||
// Then adjust selection
|
||||
expandMultiSelection(widget, previousFocus);
|
||||
|
||||
const focus = widget.getFocus();
|
||||
|
||||
if (focus.length) {
|
||||
widget.reveal(focus[0]);
|
||||
}
|
||||
|
||||
ensureDOMFocus(widget);
|
||||
}
|
||||
|
||||
// Ensure DOM Focus
|
||||
ensureDOMFocus(focused);
|
||||
}
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: 'list.focusUp',
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
when: WorkbenchListFocusContextKey,
|
||||
primary: KeyCode.UpArrow,
|
||||
mac: {
|
||||
primary: KeyCode.UpArrow,
|
||||
secondary: [KeyMod.WinCtrl | KeyCode.KEY_P]
|
||||
},
|
||||
handler: (accessor, arg2) => focusUp(accessor, arg2)
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
@@ -182,19 +224,27 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
when: ContextKeyExpr.and(WorkbenchListFocusContextKey, WorkbenchListSupportsMultiSelectContextKey),
|
||||
primary: KeyMod.Shift | KeyCode.UpArrow,
|
||||
handler: (accessor, arg2) => {
|
||||
const focused = accessor.get(IListService).lastFocusedList;
|
||||
const widget = accessor.get(IListService).lastFocusedList;
|
||||
|
||||
// List / Tree
|
||||
if (focused instanceof List || focused instanceof PagedList || focused instanceof Table || focused instanceof ObjectTree || focused instanceof DataTree || focused instanceof AsyncDataTree) {
|
||||
const list = focused;
|
||||
|
||||
// Focus up first
|
||||
const previousFocus = list.getFocus() ? list.getFocus()[0] : undefined;
|
||||
focusUp(accessor, arg2, false);
|
||||
|
||||
// Then adjust selection
|
||||
expandMultiSelection(focused, previousFocus);
|
||||
if (!widget) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Focus up first
|
||||
const previousFocus = widget.getFocus() ? widget.getFocus()[0] : undefined;
|
||||
const fakeKeyboardEvent = new KeyboardEvent('keydown');
|
||||
widget.focusPrevious(typeof arg2 === 'number' ? arg2 : 1, false, fakeKeyboardEvent);
|
||||
|
||||
// Then adjust selection
|
||||
expandMultiSelection(widget, previousFocus);
|
||||
|
||||
const focus = widget.getFocus();
|
||||
|
||||
if (focus.length) {
|
||||
widget.reveal(focus[0]);
|
||||
}
|
||||
|
||||
ensureDOMFocus(widget);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -208,29 +258,29 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
secondary: [KeyMod.CtrlCmd | KeyCode.UpArrow]
|
||||
},
|
||||
handler: (accessor) => {
|
||||
const focused = accessor.get(IListService).lastFocusedList;
|
||||
const widget = accessor.get(IListService).lastFocusedList;
|
||||
|
||||
// Tree only
|
||||
if (focused && !(focused instanceof List || focused instanceof PagedList || focused instanceof Table)) {
|
||||
if (focused instanceof ObjectTree || focused instanceof DataTree || focused instanceof AsyncDataTree) {
|
||||
const tree = focused;
|
||||
const focusedElements = tree.getFocus();
|
||||
if (!widget || !(widget instanceof ObjectTree || widget instanceof DataTree || widget instanceof AsyncDataTree)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (focusedElements.length === 0) {
|
||||
return;
|
||||
}
|
||||
const tree = widget;
|
||||
const focusedElements = tree.getFocus();
|
||||
|
||||
const focus = focusedElements[0];
|
||||
if (focusedElements.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!tree.collapse(focus)) {
|
||||
const parent = tree.getParentElement(focus);
|
||||
const focus = focusedElements[0];
|
||||
|
||||
if (parent) {
|
||||
const fakeKeyboardEvent = new KeyboardEvent('keydown');
|
||||
tree.setFocus([parent], fakeKeyboardEvent);
|
||||
tree.reveal(parent);
|
||||
}
|
||||
}
|
||||
if (!tree.collapse(focus)) {
|
||||
const parent = tree.getParentElement(focus);
|
||||
|
||||
if (parent) {
|
||||
navigate(widget, widget => {
|
||||
const fakeKeyboardEvent = new KeyboardEvent('keydown');
|
||||
widget.setFocus([parent], fakeKeyboardEvent);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -260,25 +310,24 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
when: WorkbenchListFocusContextKey,
|
||||
handler: (accessor) => {
|
||||
const focused = accessor.get(IListService).lastFocusedList;
|
||||
const widget = accessor.get(IListService).lastFocusedList;
|
||||
|
||||
if (!focused || focused instanceof List || focused instanceof PagedList || focused instanceof Table) {
|
||||
if (!widget || !(widget instanceof ObjectTree || widget instanceof DataTree || widget instanceof AsyncDataTree)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (focused instanceof ObjectTree || focused instanceof DataTree || focused instanceof AsyncDataTree) {
|
||||
const tree = focused;
|
||||
const focusedElements = tree.getFocus();
|
||||
if (focusedElements.length === 0) {
|
||||
return;
|
||||
}
|
||||
const focus = focusedElements[0];
|
||||
const parent = tree.getParentElement(focus);
|
||||
if (parent) {
|
||||
const tree = widget;
|
||||
const focusedElements = tree.getFocus();
|
||||
if (focusedElements.length === 0) {
|
||||
return;
|
||||
}
|
||||
const focus = focusedElements[0];
|
||||
const parent = tree.getParentElement(focus);
|
||||
if (parent) {
|
||||
navigate(widget, widget => {
|
||||
const fakeKeyboardEvent = new KeyboardEvent('keydown');
|
||||
tree.setFocus([parent], fakeKeyboardEvent);
|
||||
tree.reveal(parent);
|
||||
}
|
||||
widget.setFocus([parent], fakeKeyboardEvent);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -289,202 +338,66 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
when: WorkbenchListFocusContextKey,
|
||||
primary: KeyCode.RightArrow,
|
||||
handler: (accessor) => {
|
||||
const focused = accessor.get(IListService).lastFocusedList;
|
||||
const widget = accessor.get(IListService).lastFocusedList;
|
||||
|
||||
// Tree only
|
||||
if (focused && !(focused instanceof List || focused instanceof PagedList || focused instanceof Table)) {
|
||||
if (focused instanceof ObjectTree || focused instanceof DataTree) {
|
||||
// TODO@Joao: instead of doing this here, just delegate to a tree method
|
||||
const tree = focused;
|
||||
const focusedElements = tree.getFocus();
|
||||
if (!widget) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (focusedElements.length === 0) {
|
||||
return;
|
||||
if (widget instanceof ObjectTree || widget instanceof DataTree) {
|
||||
// TODO@Joao: instead of doing this here, just delegate to a tree method
|
||||
const focusedElements = widget.getFocus();
|
||||
|
||||
if (focusedElements.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const focus = focusedElements[0];
|
||||
|
||||
if (!widget.expand(focus)) {
|
||||
const child = widget.getFirstElementChild(focus);
|
||||
|
||||
if (child) {
|
||||
const node = widget.getNode(child);
|
||||
|
||||
if (node.visible) {
|
||||
navigate(widget, widget => {
|
||||
const fakeKeyboardEvent = new KeyboardEvent('keydown');
|
||||
widget.setFocus([child], fakeKeyboardEvent);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (widget instanceof AsyncDataTree) {
|
||||
// TODO@Joao: instead of doing this here, just delegate to a tree method
|
||||
const focusedElements = widget.getFocus();
|
||||
|
||||
const focus = focusedElements[0];
|
||||
if (focusedElements.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!tree.expand(focus)) {
|
||||
const child = tree.getFirstElementChild(focus);
|
||||
const focus = focusedElements[0];
|
||||
widget.expand(focus).then(didExpand => {
|
||||
if (focus && !didExpand) {
|
||||
const child = widget.getFirstElementChild(focus);
|
||||
|
||||
if (child) {
|
||||
const node = tree.getNode(child);
|
||||
const node = widget.getNode(child);
|
||||
|
||||
if (node.visible) {
|
||||
const fakeKeyboardEvent = new KeyboardEvent('keydown');
|
||||
tree.setFocus([child], fakeKeyboardEvent);
|
||||
tree.reveal(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (focused instanceof AsyncDataTree) {
|
||||
// TODO@Joao: instead of doing this here, just delegate to a tree method
|
||||
const tree = focused;
|
||||
const focusedElements = tree.getFocus();
|
||||
|
||||
if (focusedElements.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const focus = focusedElements[0];
|
||||
tree.expand(focus).then(didExpand => {
|
||||
if (focus && !didExpand) {
|
||||
const child = tree.getFirstElementChild(focus);
|
||||
|
||||
if (child) {
|
||||
const node = tree.getNode(child);
|
||||
|
||||
if (node.visible) {
|
||||
navigate(widget, widget => {
|
||||
const fakeKeyboardEvent = new KeyboardEvent('keydown');
|
||||
tree.setFocus([child], fakeKeyboardEvent);
|
||||
tree.reveal(child);
|
||||
}
|
||||
widget.setFocus([child], fakeKeyboardEvent);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: 'list.focusPageUp',
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
when: WorkbenchListFocusContextKey,
|
||||
primary: KeyCode.PageUp,
|
||||
handler: (accessor) => {
|
||||
const focused = accessor.get(IListService).lastFocusedList;
|
||||
|
||||
// List
|
||||
if (focused instanceof List || focused instanceof PagedList || focused instanceof Table) {
|
||||
focused.focusPreviousPage();
|
||||
}
|
||||
|
||||
// Tree
|
||||
else if (focused instanceof ObjectTree || focused instanceof DataTree || focused instanceof AsyncDataTree) {
|
||||
const fakeKeyboardEvent = new KeyboardEvent('keydown');
|
||||
focused.focusPreviousPage(fakeKeyboardEvent);
|
||||
}
|
||||
|
||||
// Ensure DOM Focus
|
||||
ensureDOMFocus(focused);
|
||||
}
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: 'list.focusPageDown',
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
when: WorkbenchListFocusContextKey,
|
||||
primary: KeyCode.PageDown,
|
||||
handler: (accessor) => {
|
||||
const focused = accessor.get(IListService).lastFocusedList;
|
||||
|
||||
// List
|
||||
if (focused instanceof List || focused instanceof PagedList || focused instanceof Table) {
|
||||
focused.focusNextPage();
|
||||
}
|
||||
|
||||
// Tree
|
||||
else if (focused instanceof ObjectTree || focused instanceof DataTree || focused instanceof AsyncDataTree) {
|
||||
const fakeKeyboardEvent = new KeyboardEvent('keydown');
|
||||
focused.focusNextPage(fakeKeyboardEvent);
|
||||
}
|
||||
|
||||
// Ensure DOM Focus
|
||||
ensureDOMFocus(focused);
|
||||
}
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: 'list.focusFirst',
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
when: WorkbenchListFocusContextKey,
|
||||
primary: KeyCode.Home,
|
||||
handler: accessor => listFocusFirst(accessor)
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: 'list.focusFirstChild',
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
when: WorkbenchListFocusContextKey,
|
||||
primary: 0,
|
||||
handler: accessor => listFocusFirst(accessor, { fromFocused: true })
|
||||
});
|
||||
|
||||
function listFocusFirst(accessor: ServicesAccessor, options?: { fromFocused: boolean }): void {
|
||||
const focused = accessor.get(IListService).lastFocusedList;
|
||||
|
||||
// List
|
||||
if (focused instanceof List || focused instanceof PagedList || focused instanceof Table) {
|
||||
const list = focused;
|
||||
|
||||
list.setFocus([0]);
|
||||
list.reveal(0);
|
||||
}
|
||||
|
||||
// Tree
|
||||
else if (focused instanceof ObjectTree || focused instanceof DataTree || focused instanceof AsyncDataTree) {
|
||||
const tree = focused;
|
||||
const fakeKeyboardEvent = new KeyboardEvent('keydown');
|
||||
tree.focusFirst(fakeKeyboardEvent);
|
||||
|
||||
const focus = tree.getFocus();
|
||||
|
||||
if (focus.length > 0) {
|
||||
tree.reveal(focus[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure DOM Focus
|
||||
ensureDOMFocus(focused);
|
||||
}
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: 'list.focusLast',
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
when: WorkbenchListFocusContextKey,
|
||||
primary: KeyCode.End,
|
||||
handler: accessor => listFocusLast(accessor)
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: 'list.focusLastChild',
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
when: WorkbenchListFocusContextKey,
|
||||
primary: 0,
|
||||
handler: accessor => listFocusLast(accessor, { fromFocused: true })
|
||||
});
|
||||
|
||||
function listFocusLast(accessor: ServicesAccessor, options?: { fromFocused: boolean }): void {
|
||||
const focused = accessor.get(IListService).lastFocusedList;
|
||||
|
||||
// List
|
||||
if (focused instanceof List || focused instanceof PagedList || focused instanceof Table) {
|
||||
const list = focused;
|
||||
|
||||
list.setFocus([list.length - 1]);
|
||||
list.reveal(list.length - 1);
|
||||
}
|
||||
|
||||
// Tree
|
||||
else if (focused instanceof ObjectTree || focused instanceof DataTree || focused instanceof AsyncDataTree) {
|
||||
const tree = focused;
|
||||
const fakeKeyboardEvent = new KeyboardEvent('keydown');
|
||||
tree.focusLast(fakeKeyboardEvent);
|
||||
|
||||
const focus = tree.getFocus();
|
||||
|
||||
if (focus.length > 0) {
|
||||
tree.reveal(focus[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure DOM Focus
|
||||
ensureDOMFocus(focused);
|
||||
}
|
||||
|
||||
|
||||
function focusElement(accessor: ServicesAccessor, retainCurrentFocus: boolean): void {
|
||||
function selectElement(accessor: ServicesAccessor, retainCurrentFocus: boolean): void {
|
||||
const focused = accessor.get(IListService).lastFocusedList;
|
||||
const fakeKeyboardEvent = getSelectionKeyboardEvent('keydown', retainCurrentFocus);
|
||||
// List
|
||||
@@ -525,7 +438,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
secondary: [KeyMod.CtrlCmd | KeyCode.DownArrow]
|
||||
},
|
||||
handler: (accessor) => {
|
||||
focusElement(accessor, false);
|
||||
selectElement(accessor, false);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -534,7 +447,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
when: WorkbenchListFocusContextKey,
|
||||
handler: accessor => {
|
||||
focusElement(accessor, true);
|
||||
selectElement(accessor, true);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -654,7 +567,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
}
|
||||
}
|
||||
|
||||
focusElement(accessor, true);
|
||||
selectElement(accessor, true);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -664,43 +577,24 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
when: ContextKeyExpr.and(WorkbenchListFocusContextKey, WorkbenchListHasSelectionOrFocus),
|
||||
primary: KeyCode.Escape,
|
||||
handler: (accessor) => {
|
||||
const focused = accessor.get(IListService).lastFocusedList;
|
||||
const widget = accessor.get(IListService).lastFocusedList;
|
||||
|
||||
// List
|
||||
if (focused instanceof List || focused instanceof PagedList || focused instanceof Table) {
|
||||
const list = focused;
|
||||
|
||||
list.setSelection([]);
|
||||
list.setFocus([]);
|
||||
if (!widget) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Tree
|
||||
else if (focused instanceof ObjectTree || focused instanceof DataTree || focused instanceof AsyncDataTree) {
|
||||
const list = focused;
|
||||
const fakeKeyboardEvent = new KeyboardEvent('keydown');
|
||||
|
||||
list.setSelection([], fakeKeyboardEvent);
|
||||
list.setFocus([], fakeKeyboardEvent);
|
||||
}
|
||||
const fakeKeyboardEvent = new KeyboardEvent('keydown');
|
||||
widget.setSelection([], fakeKeyboardEvent);
|
||||
widget.setFocus([], fakeKeyboardEvent);
|
||||
widget.setAnchor(undefined);
|
||||
}
|
||||
});
|
||||
|
||||
CommandsRegistry.registerCommand({
|
||||
id: 'list.toggleKeyboardNavigation',
|
||||
handler: (accessor) => {
|
||||
const focused = accessor.get(IListService).lastFocusedList;
|
||||
|
||||
// List
|
||||
if (focused instanceof List || focused instanceof PagedList || focused instanceof Table) {
|
||||
const list = focused;
|
||||
list.toggleKeyboardNavigation();
|
||||
}
|
||||
|
||||
// Tree
|
||||
else if (focused instanceof ObjectTree || focused instanceof DataTree || focused instanceof AsyncDataTree) {
|
||||
const tree = focused;
|
||||
tree.toggleKeyboardNavigation();
|
||||
}
|
||||
const widget = accessor.get(IListService).lastFocusedList;
|
||||
widget?.toggleKeyboardNavigation();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -343,7 +343,7 @@ export class NewWindowAction extends Action {
|
||||
}
|
||||
|
||||
run(): Promise<void> {
|
||||
return this.hostService.openWindow();
|
||||
return this.hostService.openWindow({ remoteAuthority: null });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ import { IRange } from 'vs/editor/common/core/range';
|
||||
import { CursorChangeReason, ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents';
|
||||
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
|
||||
import { TrackedRangeStickiness, IModelDecorationsChangeAccessor } from 'vs/editor/common/model';
|
||||
import { EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
|
||||
export interface IRangeHighlightDecoration {
|
||||
resource: URI;
|
||||
@@ -264,6 +265,11 @@ export class OpenWorkspaceButtonContribution extends Disposable implements IEdit
|
||||
}
|
||||
}
|
||||
|
||||
if (editor.getOption(EditorOption.inDiffEditor)) {
|
||||
// in diff editor
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -83,17 +83,21 @@ export abstract class Composite extends Component implements IComposite {
|
||||
|
||||
protected actionRunner: IActionRunner | undefined;
|
||||
|
||||
private _telemetryService: ITelemetryService;
|
||||
protected get telemetryService(): ITelemetryService { return this._telemetryService; }
|
||||
|
||||
private visible: boolean;
|
||||
private parent: HTMLElement | undefined;
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
private _telemetryService: ITelemetryService,
|
||||
telemetryService: ITelemetryService,
|
||||
themeService: IThemeService,
|
||||
storageService: IStorageService
|
||||
) {
|
||||
super(id, themeService, storageService);
|
||||
|
||||
this._telemetryService = telemetryService;
|
||||
this.visible = false;
|
||||
}
|
||||
|
||||
@@ -101,10 +105,6 @@ export abstract class Composite extends Component implements IComposite {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
protected get telemetryService(): ITelemetryService {
|
||||
return this._telemetryService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: Clients should not call this method, the workbench calls this
|
||||
* method. Calling it otherwise may result in unexpected behavior.
|
||||
@@ -203,7 +203,7 @@ export abstract class Composite extends Component implements IComposite {
|
||||
*/
|
||||
getActionRunner(): IActionRunner {
|
||||
if (!this.actionRunner) {
|
||||
this.actionRunner = new ActionRunner();
|
||||
this.actionRunner = this._register(new ActionRunner());
|
||||
}
|
||||
|
||||
return this.actionRunner;
|
||||
|
||||
@@ -958,10 +958,6 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
return new Dimension(availableWidth, availableHeight);
|
||||
}
|
||||
|
||||
getWorkbenchContainer(): HTMLElement {
|
||||
return this.parent;
|
||||
}
|
||||
|
||||
toggleZenMode(skipLayout?: boolean, restoring = false): void {
|
||||
this.state.zenMode.active = !this.state.zenMode.active;
|
||||
this.state.zenMode.transitionDisposables.clear();
|
||||
|
||||
@@ -453,7 +453,7 @@ registerThemingParticipant((theme, collector) => {
|
||||
outline: 1px dashed;
|
||||
}
|
||||
|
||||
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:focus:before {
|
||||
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:focus .active-item-indicator:before {
|
||||
border-left-color: ${outline};
|
||||
}
|
||||
|
||||
@@ -472,7 +472,7 @@ registerThemingParticipant((theme, collector) => {
|
||||
const focusBorderColor = theme.getColor(focusBorder);
|
||||
if (focusBorderColor) {
|
||||
collector.addRule(`
|
||||
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:focus:before {
|
||||
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:focus .active-item-indicator:before {
|
||||
border-left-color: ${focusBorderColor};
|
||||
}
|
||||
`);
|
||||
|
||||
@@ -76,10 +76,9 @@
|
||||
}
|
||||
|
||||
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked .active-item-indicator:before,
|
||||
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:focus:before {
|
||||
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:focus .active-item-indicator:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
@@ -92,12 +91,9 @@
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked:focus .active-item-indicator:before {
|
||||
visibility: hidden; /* don't show active border + focus at the same time, focus takes priority */
|
||||
}
|
||||
|
||||
/* Hides active elements in high contrast mode */
|
||||
.monaco-workbench.hc-black .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked .active-item-indicator {
|
||||
.monaco-workbench.hc-black .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked:not(:focus) .active-item-indicator {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -105,13 +101,11 @@
|
||||
border-left: none !important; /* no focus feedback when using mouse */
|
||||
}
|
||||
|
||||
.monaco-workbench .activitybar.left > .content :not(.monaco-menu) > .monaco-action-bar .action-item:focus:before,
|
||||
.monaco-workbench .activitybar.left > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked .active-item-indicator:before{
|
||||
.monaco-workbench .activitybar.left > .content :not(.monaco-menu) > .monaco-action-bar .action-item .active-item-indicator:before{
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.monaco-workbench .activitybar.right > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked .active-item-indicator:before,
|
||||
.monaco-workbench .activitybar.right > .content :not(.monaco-menu) > .monaco-action-bar .action-item:focus:before {
|
||||
.monaco-workbench .activitybar.right > .content :not(.monaco-menu) > .monaco-action-bar .action-item .active-item-indicator:before {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
import { localize } from 'vs/nls';
|
||||
import { IAction, toAction } from 'vs/base/common/actions';
|
||||
import { illegalArgument } from 'vs/base/common/errors';
|
||||
import { equals } from 'vs/base/common/arrays';
|
||||
import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IBadge } from 'vs/workbench/services/activity/common/activity';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
@@ -277,10 +276,8 @@ export class CompositeBar extends Widget implements ICompositeBar {
|
||||
|
||||
switch (this.options.orientation) {
|
||||
case ActionsOrientation.HORIZONTAL:
|
||||
case ActionsOrientation.HORIZONTAL_REVERSE:
|
||||
return posX < rect.left;
|
||||
case ActionsOrientation.VERTICAL:
|
||||
case ActionsOrientation.VERTICAL_REVERSE:
|
||||
return posY < rect.top;
|
||||
}
|
||||
}
|
||||
@@ -538,10 +535,8 @@ export class CompositeBar extends Widget implements ICompositeBar {
|
||||
compositesToShow.length ? compositesToShow.splice(compositesToShow.length - 2, 1) : compositesToShow.pop();
|
||||
}
|
||||
|
||||
const visibleCompositesChange = !equals(compositesToShow, this.visibleComposites);
|
||||
|
||||
// Pull out overflow action if there is a composite change so that we can add it to the end later
|
||||
if (this.compositeOverflowAction && visibleCompositesChange) {
|
||||
// Remove the overflow action if there are no overflows
|
||||
if (!overflows && this.compositeOverflowAction) {
|
||||
compositeSwitcherBar.pull(compositeSwitcherBar.length() - 1);
|
||||
|
||||
this.compositeOverflowAction.dispose();
|
||||
@@ -584,7 +579,7 @@ export class CompositeBar extends Widget implements ICompositeBar {
|
||||
});
|
||||
|
||||
// Add overflow action as needed
|
||||
if ((visibleCompositesChange && overflows)) {
|
||||
if ((overflows && !this.compositeOverflowAction)) {
|
||||
this.compositeOverflowAction = this.instantiationService.createInstance(CompositeOverflowActivityAction, () => {
|
||||
if (this.compositeOverflowActionViewItem) {
|
||||
this.compositeOverflowActionViewItem.showMenu();
|
||||
|
||||
@@ -305,8 +305,9 @@ export class ActivityActionViewItem extends BaseActionViewItem {
|
||||
}
|
||||
|
||||
if (clazz) {
|
||||
this.badge.classList.add(...clazz.split(' '));
|
||||
this.badgeDisposable.value = toDisposable(() => this.badge.classList.remove(...clazz.split(' ')));
|
||||
const classNames = clazz.split(' ');
|
||||
this.badge.classList.add(...classNames);
|
||||
this.badgeDisposable.value = toDisposable(() => this.badge.classList.remove(...classNames));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -162,9 +162,9 @@ export class BreadcrumbsControl {
|
||||
static readonly Payload_RevealAside = {};
|
||||
static readonly Payload_Pick = {};
|
||||
|
||||
static readonly CK_BreadcrumbsPossible = new RawContextKey('breadcrumbsPossible', false);
|
||||
static readonly CK_BreadcrumbsVisible = new RawContextKey('breadcrumbsVisible', false);
|
||||
static readonly CK_BreadcrumbsActive = new RawContextKey('breadcrumbsActive', false);
|
||||
static readonly CK_BreadcrumbsPossible = new RawContextKey('breadcrumbsPossible', false, localize('breadcrumbsPossible', "Whether the editor can show breadcrumbs"));
|
||||
static readonly CK_BreadcrumbsVisible = new RawContextKey('breadcrumbsVisible', false, localize('breadcrumbsVisible', "Whether breadcrumbs are currently visible"));
|
||||
static readonly CK_BreadcrumbsActive = new RawContextKey('breadcrumbsActive', false, localize('breadcrumbsActive', "Whether breadcrumbs have focus"));
|
||||
|
||||
private readonly _ckBreadcrumbsPossible: IContextKey<boolean>;
|
||||
private readonly _ckBreadcrumbsVisible: IContextKey<boolean>;
|
||||
|
||||
@@ -287,7 +287,7 @@ registerEditorContribution(UntitledHintContribution.ID, UntitledHintContribution
|
||||
|
||||
// Register Status Actions
|
||||
const registry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.from(ChangeModeAction, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_M) }), 'Change Language Mode');
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.from(ChangeModeAction, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_M) }), 'Change Language Mode', undefined, ContextKeyExpr.not('notebookEditorFocused'));
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.from(ChangeEOLAction), 'Change End of Line Sequence');
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.from(ChangeEncodingAction), 'Change File Encoding');
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/la
|
||||
import { IHistoryService } from 'vs/workbench/services/history/common/history';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { CLOSE_EDITOR_COMMAND_ID, MOVE_ACTIVE_EDITOR_COMMAND_ID, ActiveEditorMoveArguments, SPLIT_EDITOR_LEFT, SPLIT_EDITOR_RIGHT, SPLIT_EDITOR_UP, SPLIT_EDITOR_DOWN, splitEditor, LAYOUT_EDITOR_GROUPS_COMMAND_ID, mergeAllGroups, UNPIN_EDITOR_COMMAND_ID } from 'vs/workbench/browser/parts/editor/editorCommands';
|
||||
import { CLOSE_EDITOR_COMMAND_ID, MOVE_ACTIVE_EDITOR_COMMAND_ID, ActiveEditorMoveArguments, SPLIT_EDITOR_LEFT, SPLIT_EDITOR_RIGHT, SPLIT_EDITOR_UP, SPLIT_EDITOR_DOWN, splitEditor, LAYOUT_EDITOR_GROUPS_COMMAND_ID, UNPIN_EDITOR_COMMAND_ID } from 'vs/workbench/browser/parts/editor/editorCommands';
|
||||
import { IEditorGroupsService, IEditorGroup, GroupsArrangement, GroupLocation, GroupDirection, preferredSideBySideGroupDirection, IFindGroupScope, GroupOrientation, EditorGroupLayout, GroupsOrder, OpenEditorContext } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
@@ -216,7 +216,7 @@ export class JoinAllGroupsAction extends Action {
|
||||
}
|
||||
|
||||
async run(): Promise<void> {
|
||||
mergeAllGroups(this.editorGroupService);
|
||||
this.editorGroupService.mergeAllGroups();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -279,17 +279,6 @@ function registerEditorGroupsLayoutCommand(): void {
|
||||
});
|
||||
}
|
||||
|
||||
export function mergeAllGroups(editorGroupService: IEditorGroupsService): void {
|
||||
const target = editorGroupService.activeGroup;
|
||||
for (const group of editorGroupService.getGroups(GroupsOrder.MOST_RECENTLY_ACTIVE)) {
|
||||
if (group === target) {
|
||||
continue; // keep target
|
||||
}
|
||||
|
||||
editorGroupService.mergeGroup(group, target);
|
||||
}
|
||||
}
|
||||
|
||||
function registerDiffEditorCommands(): void {
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: GOTO_NEXT_CHANGE,
|
||||
|
||||
@@ -1287,7 +1287,18 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
||||
// Open next active if there are more to show
|
||||
const nextActiveEditor = this._group.activeEditor;
|
||||
if (nextActiveEditor) {
|
||||
const options = EditorOptions.create({ preserveFocus: !focusNext });
|
||||
const preserveFocus = !focusNext;
|
||||
|
||||
let activation: EditorActivation | undefined = undefined;
|
||||
if (preserveFocus && this.accessor.activeGroup !== this) {
|
||||
// If we are opening the next editor in an inactive group
|
||||
// without focussing it, ensure we preserve the editor
|
||||
// group sizes in case that group is minimized.
|
||||
// https://github.com/microsoft/vscode/issues/117686
|
||||
activation = EditorActivation.PRESERVE;
|
||||
}
|
||||
|
||||
const options = EditorOptions.create({ preserveFocus, activation });
|
||||
|
||||
// When closing an editor due to an error we can end up in a loop where we continue closing
|
||||
// editors that fail to open (e.g. when the file no longer exists). We do not want to show
|
||||
@@ -1610,7 +1621,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
||||
// Extract active vs. inactive replacements
|
||||
let activeReplacement: EditorReplacement | undefined;
|
||||
const inactiveReplacements: EditorReplacement[] = [];
|
||||
for (let { editor, replacement, options } of editors) {
|
||||
for (let { editor, replacement, forceReplaceDirty, options } of editors) {
|
||||
const index = this.getIndexOfEditor(editor);
|
||||
if (index >= 0) {
|
||||
const isActiveEditor = this.isActive(editor);
|
||||
@@ -1625,7 +1636,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
||||
options.inactive = !isActiveEditor;
|
||||
options.pinned = options.pinned ?? true; // unless specified, prefer to pin upon replace
|
||||
|
||||
const editorToReplace = { editor, replacement, options };
|
||||
const editorToReplace = { editor, replacement, forceReplaceDirty, options };
|
||||
if (isActiveEditor) {
|
||||
activeReplacement = editorToReplace;
|
||||
} else {
|
||||
@@ -1635,14 +1646,20 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
||||
}
|
||||
|
||||
// Handle inactive first
|
||||
for (const { editor, replacement, options } of inactiveReplacements) {
|
||||
for (const { editor, replacement, forceReplaceDirty, options } of inactiveReplacements) {
|
||||
|
||||
// Open inactive editor
|
||||
await this.doOpenEditor(replacement, options);
|
||||
|
||||
// Close replaced inactive editor unless they match
|
||||
if (!editor.matches(replacement)) {
|
||||
const closed = await this.doCloseEditorWithDirtyHandling(editor, { preserveFocus: true });
|
||||
let closed = false;
|
||||
if (forceReplaceDirty) {
|
||||
this.doCloseEditor(editor, false);
|
||||
closed = true;
|
||||
} else {
|
||||
closed = await this.doCloseEditorWithDirtyHandling(editor, { preserveFocus: true });
|
||||
}
|
||||
if (!closed) {
|
||||
return; // canceled
|
||||
}
|
||||
@@ -1657,7 +1674,11 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
||||
|
||||
// Close replaced active editor unless they match
|
||||
if (!activeReplacement.editor.matches(activeReplacement.replacement)) {
|
||||
await this.doCloseEditorWithDirtyHandling(activeReplacement.editor, { preserveFocus: true });
|
||||
if (activeReplacement.forceReplaceDirty) {
|
||||
this.doCloseEditor(activeReplacement.editor, false);
|
||||
} else {
|
||||
await this.doCloseEditorWithDirtyHandling(activeReplacement.editor, { preserveFocus: true });
|
||||
}
|
||||
}
|
||||
|
||||
await openEditorResult;
|
||||
@@ -1776,6 +1797,8 @@ class EditorOpeningEvent implements IEditorOpeningEvent {
|
||||
export interface EditorReplacement {
|
||||
readonly editor: EditorInput;
|
||||
readonly replacement: EditorInput;
|
||||
/** Skips asking the user for confirmation and doesn't save the document. Only use this if you really need to! */
|
||||
readonly forceReplaceDirty?: boolean;
|
||||
readonly options?: EditorOptions;
|
||||
}
|
||||
|
||||
|
||||
@@ -764,6 +764,18 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
|
||||
return targetView;
|
||||
}
|
||||
|
||||
mergeAllGroups(target = this.activeGroup): IEditorGroupView {
|
||||
for (const group of this.getGroups(GroupsOrder.MOST_RECENTLY_ACTIVE)) {
|
||||
if (group === target) {
|
||||
continue; // keep target
|
||||
}
|
||||
|
||||
this.mergeGroup(group, target);
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
private assertGroupView(group: IEditorGroupView | GroupIdentifier): IEditorGroupView {
|
||||
let groupView: IEditorGroupView | undefined;
|
||||
if (typeof group === 'number') {
|
||||
|
||||
@@ -1064,19 +1064,12 @@ export class ChangeModeAction extends Action {
|
||||
@IPreferencesService private readonly preferencesService: IPreferencesService,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@ITextFileService private readonly textFileService: ITextFileService,
|
||||
@ICommandService private readonly commandService: ICommandService,
|
||||
@ITelemetryService private readonly telemetryService: ITelemetryService
|
||||
) {
|
||||
super(actionId, actionLabel);
|
||||
}
|
||||
|
||||
async run(event: any, data: ITelemetryData): Promise<void> {
|
||||
const activeEditorPane = this.editorService.activeEditorPane as unknown as { isNotebookEditor?: boolean } | undefined;
|
||||
if (activeEditorPane?.isNotebookEditor) { // TODO@rebornix TODO@jrieken debt: https://github.com/microsoft/vscode/issues/114554
|
||||
// it's inside notebook editor
|
||||
return this.commandService.executeCommand('notebook.cell.changeLanguage');
|
||||
}
|
||||
|
||||
const activeTextEditorControl = getCodeEditor(this.editorService.activeTextEditorControl);
|
||||
if (!activeTextEditorControl) {
|
||||
await this.quickInputService.pick([{ label: localize('noEditor', "No text editor active at this time") }]);
|
||||
|
||||
@@ -101,6 +101,10 @@
|
||||
margin-right: var(--last-tab-margin-right); /* when tabs wrap, we need a margin away from the absolute positioned editor actions */
|
||||
}
|
||||
|
||||
.monaco-workbench .part.editor > .content .editor-group-container > .title > .tabs-and-actions-container.wrapping .tabs-container > .tab.last-in-row:not(:last-child) {
|
||||
border-right: 0 !important; /* ensure no border for every last tab in a row except last row (#115046) */
|
||||
}
|
||||
|
||||
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.has-icon.tab-actions-right,
|
||||
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.has-icon.tab-actions-off:not(.sticky-compact) {
|
||||
padding-left: 5px; /* reduce padding when we show icons and are in shrinking mode and tab actions is not left (unless sticky-compact) */
|
||||
@@ -113,8 +117,8 @@
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.monaco-workbench .part.editor > .content .editor-group-container > .title > .tabs-and-actions-container.wrapping .tabs-container > .tab.sizing-fit {
|
||||
flex-grow: 1; /* grow the tabs to fill each row for a more homogeneous look when tabs wrap */
|
||||
.monaco-workbench .part.editor > .content .editor-group-container > .title > .tabs-and-actions-container.wrapping .tabs-container > .tab.sizing-fit.last-in-row:not(:last-child) {
|
||||
flex-grow: 1; /* grow the last tab in a row for a more homogeneous look except for last row (#113801) */
|
||||
}
|
||||
|
||||
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink {
|
||||
|
||||
@@ -1482,6 +1482,48 @@ export class TabsTitleControl extends TitleControl {
|
||||
});
|
||||
}
|
||||
|
||||
// Update the `last-in-row` class on tabs when wrapping
|
||||
// is enabled (it doesn't do any harm otherwise). This
|
||||
// class controls additional properties of tab when it is
|
||||
// the last tab in a row
|
||||
if (tabsWrapMultiLine) {
|
||||
|
||||
// Using a map here to change classes after the for loop is
|
||||
// crucial for performance because changing the class on a
|
||||
// tab can result in layouts of the rendering engine.
|
||||
const tabs = new Map<HTMLElement, boolean /* last in row */>();
|
||||
|
||||
let currentTabsPosY: number | undefined = undefined;
|
||||
let lastTab: HTMLElement | undefined = undefined;
|
||||
for (const child of tabsContainer.children) {
|
||||
const tab = child as HTMLElement;
|
||||
const tabPosY = tab.offsetTop;
|
||||
|
||||
// Marks a new or the first row of tabs
|
||||
if (tabPosY !== currentTabsPosY) {
|
||||
currentTabsPosY = tabPosY;
|
||||
if (lastTab) {
|
||||
tabs.set(lastTab, true); // previous tab must be last in row then
|
||||
}
|
||||
}
|
||||
|
||||
// Always remember last tab and ensure the
|
||||
// last-in-row class is not present until
|
||||
// we know the tab is last
|
||||
lastTab = tab;
|
||||
tabs.set(tab, false);
|
||||
}
|
||||
|
||||
// Last tab overally is always last-in-row
|
||||
if (lastTab) {
|
||||
tabs.set(lastTab, true);
|
||||
}
|
||||
|
||||
for (const [tab, lastInRow] of tabs) {
|
||||
tab.classList.toggle('last-in-row', lastInRow);
|
||||
}
|
||||
}
|
||||
|
||||
return tabsWrapMultiLine;
|
||||
}
|
||||
|
||||
|
||||
@@ -224,12 +224,11 @@ export abstract class TitleControl extends Themable {
|
||||
this.updateEditorActionsToolbar(); // Update editor toolbar whenever contributed actions change
|
||||
}));
|
||||
|
||||
const isPrimaryGroup = (group: string) => group === 'navigation' || group === '1_run';
|
||||
const shouldInlineGroup = (action: SubmenuAction, group: string) => isPrimaryGroup(group) && action.actions.length <= 1;
|
||||
const shouldInlineGroup = (action: SubmenuAction, group: string) => group === 'navigation' && action.actions.length <= 1;
|
||||
|
||||
this.editorToolBarMenuDisposables.add(createAndFillInActionBarActions(
|
||||
titleBarMenu, { arg: this.resourceContext.get(), shouldForwardArgs: true }, { primary, secondary },
|
||||
isPrimaryGroup, 9, shouldInlineGroup
|
||||
'navigation', 9, shouldInlineGroup
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ import { Schemas } from 'vs/base/common/network';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { FloatingClickWidget } from 'vs/workbench/browser/codeeditor';
|
||||
import { ITASExperimentService } from 'vs/workbench/services/experiment/common/experimentService';
|
||||
const $ = dom.$;
|
||||
|
||||
const untitledHintSetting = 'workbench.editor.untitled.hint';
|
||||
@@ -28,13 +29,15 @@ export class UntitledHintContribution implements IEditorContribution {
|
||||
private toDispose: IDisposable[];
|
||||
private untitledHintContentWidget: UntitledHintContentWidget | undefined;
|
||||
private button: FloatingClickWidget | undefined;
|
||||
private experimentTreatment: 'text' | 'button' | 'hidden' | undefined;
|
||||
|
||||
constructor(
|
||||
private editor: ICodeEditor,
|
||||
@ICommandService private readonly commandService: ICommandService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@IKeybindingService private readonly keybindingService: IKeybindingService,
|
||||
@IThemeService private readonly themeService: IThemeService
|
||||
@IThemeService private readonly themeService: IThemeService,
|
||||
@ITASExperimentService private readonly experimentService: ITASExperimentService
|
||||
) {
|
||||
this.toDispose = [];
|
||||
this.toDispose.push(this.editor.onDidChangeModel(() => this.update()));
|
||||
@@ -44,13 +47,17 @@ export class UntitledHintContribution implements IEditorContribution {
|
||||
this.update();
|
||||
}
|
||||
}));
|
||||
this.update();
|
||||
this.experimentService.getTreatment<'text' | 'button'>('untitledhint').then(treatment => {
|
||||
this.experimentTreatment = treatment;
|
||||
this.update();
|
||||
});
|
||||
}
|
||||
|
||||
private update(): void {
|
||||
this.untitledHintContentWidget?.dispose();
|
||||
this.button?.dispose();
|
||||
const untitledHintMode = this.configurationService.getValue(untitledHintSetting);
|
||||
const configValue = this.configurationService.getValue<'text' | 'button' | 'hidden' | 'default'>(untitledHintSetting);
|
||||
const untitledHintMode = configValue === 'default' ? (this.experimentTreatment || 'hidden') : configValue;
|
||||
const model = this.editor.getModel();
|
||||
|
||||
if (model && model.uri.scheme === Schemas.untitled && model.getModeId() === PLAINTEXT_MODE_ID) {
|
||||
|
||||
@@ -15,6 +15,7 @@ import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
import { registerIcon } from 'vs/platform/theme/common/iconRegistry';
|
||||
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
|
||||
import { hash } from 'vs/base/common/hash';
|
||||
|
||||
const clearIcon = registerIcon('notifications-clear', Codicon.close, localize('clearIcon', 'Icon for the clear action in notifications.'));
|
||||
const clearAllIcon = registerIcon('notifications-clear-all', Codicon.clearAll, localize('clearAllIcon', 'Icon for the clear all action in notifications.'));
|
||||
@@ -145,6 +146,17 @@ export class CopyNotificationMessageAction extends Action {
|
||||
}
|
||||
}
|
||||
|
||||
interface NotificationActionMetrics {
|
||||
id: string;
|
||||
actionLabel: string;
|
||||
source: string | undefined;
|
||||
}
|
||||
type NotificationActionMetricsClassification = {
|
||||
id: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
|
||||
actionLabel: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
|
||||
source: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
|
||||
};
|
||||
|
||||
export class NotificationActionRunner extends ActionRunner {
|
||||
|
||||
constructor(
|
||||
@@ -154,8 +166,12 @@ export class NotificationActionRunner extends ActionRunner {
|
||||
super();
|
||||
}
|
||||
|
||||
protected async runAction(action: IAction, context: INotificationViewItem): Promise<void> {
|
||||
protected async runAction(action: IAction, context: INotificationViewItem | undefined): Promise<void> {
|
||||
this.telemetryService.publicLog2<WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification>('workbenchActionExecuted', { id: action.id, from: 'message' });
|
||||
if (context) {
|
||||
// If the context is not present it is a "global" notification action. Will be captured by other events
|
||||
this.telemetryService.publicLog2<NotificationActionMetrics, NotificationActionMetricsClassification>('notification:actionExecuted', { id: hash(context.message.original.toString()).toString(), actionLabel: action.label, source: context.sourceId });
|
||||
}
|
||||
|
||||
// Run and make sure to notify on any error again
|
||||
try {
|
||||
|
||||
@@ -7,10 +7,12 @@ import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
import { RawContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import { INotificationViewItem, isNotificationViewItem } from 'vs/workbench/common/notifications';
|
||||
import { INotificationViewItem, isNotificationViewItem, NotificationsModel } from 'vs/workbench/common/notifications';
|
||||
import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IListService, WorkbenchList } from 'vs/platform/list/browser/listService';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { NotificationMetrics, NotificationMetricsClassification, notificationToMetrics } from 'vs/workbench/browser/parts/notifications/notificationsTelemetry';
|
||||
|
||||
// Center
|
||||
export const SHOW_NOTIFICATIONS_CENTER = 'notifications.showList';
|
||||
@@ -55,7 +57,7 @@ export interface INotificationsToastController {
|
||||
hide(): void;
|
||||
}
|
||||
|
||||
export function registerNotificationCommands(center: INotificationsCenterController, toasts: INotificationsToastController): void {
|
||||
export function registerNotificationCommands(center: INotificationsCenterController, toasts: INotificationsToastController, model: NotificationsModel): void {
|
||||
|
||||
function getNotificationFromContext(listService: IListService, context?: unknown): INotificationViewItem | undefined {
|
||||
if (isNotificationViewItem(context)) {
|
||||
@@ -85,7 +87,16 @@ export function registerNotificationCommands(center: INotificationsCenterControl
|
||||
weight: KeybindingWeight.WorkbenchContrib + 50,
|
||||
when: NotificationsCenterVisibleContext,
|
||||
primary: KeyCode.Escape,
|
||||
handler: accessor => center.hide()
|
||||
handler: accessor => {
|
||||
const telemetryService = accessor.get(ITelemetryService);
|
||||
model.notifications.forEach(n => {
|
||||
if (n.visible) {
|
||||
telemetryService.publicLog2<NotificationMetrics, NotificationMetricsClassification>('notification:hide', notificationToMetrics(n.message.original, n.sourceId, n.silent));
|
||||
}
|
||||
});
|
||||
|
||||
center.hide();
|
||||
}
|
||||
});
|
||||
|
||||
// Toggle Notifications Center
|
||||
@@ -159,7 +170,15 @@ export function registerNotificationCommands(center: INotificationsCenterControl
|
||||
});
|
||||
|
||||
// Hide Toasts
|
||||
CommandsRegistry.registerCommand(HIDE_NOTIFICATION_TOAST, accessor => toasts.hide());
|
||||
CommandsRegistry.registerCommand(HIDE_NOTIFICATION_TOAST, accessor => {
|
||||
const telemetryService = accessor.get(ITelemetryService);
|
||||
model.notifications.forEach(n => {
|
||||
if (n.visible) {
|
||||
telemetryService.publicLog2<NotificationMetrics, NotificationMetricsClassification>('notification:hide', notificationToMetrics(n.message.original, n.sourceId, n.silent));
|
||||
}
|
||||
});
|
||||
toasts.hide();
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerKeybindingRule({
|
||||
id: HIDE_NOTIFICATION_TOAST,
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { INotificationService, NotificationMessage } from 'vs/platform/notification/common/notification';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { hash } from 'vs/base/common/hash';
|
||||
|
||||
export interface NotificationMetrics {
|
||||
id: string;
|
||||
silent: boolean;
|
||||
source?: string;
|
||||
}
|
||||
|
||||
export type NotificationMetricsClassification = {
|
||||
id: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
|
||||
silent: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
|
||||
source?: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
|
||||
};
|
||||
|
||||
export function notificationToMetrics(message: NotificationMessage, source: string | undefined, silent: boolean): NotificationMetrics {
|
||||
return {
|
||||
id: hash(message.toString()).toString(),
|
||||
silent,
|
||||
source: source || 'core'
|
||||
};
|
||||
}
|
||||
|
||||
export class NotificationsTelemetry extends Disposable implements IWorkbenchContribution {
|
||||
|
||||
constructor(
|
||||
@ITelemetryService private readonly telemetryService: ITelemetryService,
|
||||
@INotificationService private readonly notificationService: INotificationService
|
||||
) {
|
||||
super();
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
this._register(this.notificationService.onDidAddNotification(notification => {
|
||||
const source = notification.source && typeof notification.source !== 'string' ? notification.source.id : notification.source;
|
||||
this.telemetryService.publicLog2<NotificationMetrics, NotificationMetricsClassification>('notification:show', notificationToMetrics(notification.message, source, !!notification.silent));
|
||||
}));
|
||||
|
||||
this._register(this.notificationService.onDidRemoveNotification(notification => {
|
||||
const source = notification.source && typeof notification.source !== 'string' ? notification.source.id : notification.source;
|
||||
this.telemetryService.publicLog2<NotificationMetrics, NotificationMetricsClassification>('notification:close', notificationToMetrics(notification.message, source, !!notification.silent));
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -178,15 +178,17 @@
|
||||
}
|
||||
|
||||
/* Rotate icons when panel is on right */
|
||||
.monaco-workbench .part.panel.right .title-actions .codicon-split-horizontal,
|
||||
.monaco-workbench .part.panel.right .title-actions .codicon-panel-maximize,
|
||||
.monaco-workbench .part.panel.right .title-actions .codicon-panel-restore {
|
||||
.monaco-workbench .part.panel.right .title-actions .codicon-split-horizontal::before,
|
||||
.monaco-workbench .part.panel.right .title-actions .codicon-panel-maximize::before,
|
||||
.monaco-workbench .part.panel.right .title-actions .codicon-panel-restore::before {
|
||||
display: inline-block;
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
/* Rotate icons when panel is on left */
|
||||
.monaco-workbench .part.panel.left .title-actions .codicon-split-horizontal,
|
||||
.monaco-workbench .part.panel.left .title-actions .codicon-panel-maximize,
|
||||
.monaco-workbench .part.panel.left .title-actions .codicon-panel-restore {
|
||||
.monaco-workbench .part.panel.left .title-actions .codicon-split-horizontal::before,
|
||||
.monaco-workbench .part.panel.left .title-actions .codicon-panel-maximize::before,
|
||||
.monaco-workbench .part.panel.left .title-actions .codicon-panel-restore::before {
|
||||
display: inline-block;
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
@@ -41,6 +41,8 @@ import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { Cookie } from 'vs/server/common/cookie';
|
||||
|
||||
export type IOpenRecentAction = IAction & { uri: URI, remoteAuthority?: string };
|
||||
|
||||
export abstract class MenubarControl extends Disposable {
|
||||
|
||||
protected keys = [
|
||||
@@ -160,7 +162,7 @@ export abstract class MenubarControl extends Disposable {
|
||||
this.updateMenubar();
|
||||
}
|
||||
|
||||
protected getOpenRecentActions(): (Separator | IAction & { uri: URI })[] {
|
||||
protected getOpenRecentActions(): (Separator | IOpenRecentAction)[] {
|
||||
if (!this.recentlyOpened) {
|
||||
return [];
|
||||
}
|
||||
@@ -226,12 +228,13 @@ export abstract class MenubarControl extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
private createOpenRecentMenuAction(recent: IRecent): IAction & { uri: URI } {
|
||||
private createOpenRecentMenuAction(recent: IRecent): IOpenRecentAction {
|
||||
|
||||
let label: string;
|
||||
let uri: URI;
|
||||
let commandId: string;
|
||||
let openable: IWindowOpenable;
|
||||
const remoteAuthority = recent.remoteAuthority;
|
||||
|
||||
if (isRecentFolder(recent)) {
|
||||
uri = recent.folderUri;
|
||||
@@ -254,11 +257,12 @@ export abstract class MenubarControl extends Disposable {
|
||||
const openInNewWindow = event && ((!isMacintosh && (event.ctrlKey || event.shiftKey)) || (isMacintosh && (event.metaKey || event.altKey)));
|
||||
|
||||
return this.hostService.openWindow([openable], {
|
||||
forceNewWindow: openInNewWindow
|
||||
forceNewWindow: openInNewWindow,
|
||||
remoteAuthority
|
||||
});
|
||||
});
|
||||
|
||||
return Object.assign(ret, { uri });
|
||||
return Object.assign(ret, { uri, remoteAuthority });
|
||||
}
|
||||
|
||||
private notifyUserOfCustomMenubarAccessibility(): void {
|
||||
@@ -415,7 +419,6 @@ export class CustomMenubarControl extends MenubarControl {
|
||||
.monaco-workbench .menubar > .menubar-menu-button.open,
|
||||
.monaco-workbench .menubar > .menubar-menu-button:focus,
|
||||
.monaco-workbench .menubar > .menubar-menu-button:hover {
|
||||
outline-offset: -1px;
|
||||
outline-color: ${menubarSelectedBorderColor};
|
||||
}
|
||||
`);
|
||||
@@ -594,6 +597,7 @@ export class CustomMenubarControl extends MenubarControl {
|
||||
const updateActions = (menu: IMenu, target: IAction[], topLevelTitle: string) => {
|
||||
target.splice(0);
|
||||
let groups = menu.getActions();
|
||||
|
||||
for (let group of groups) {
|
||||
const [, actions] = group;
|
||||
|
||||
@@ -622,7 +626,10 @@ export class CustomMenubarControl extends MenubarControl {
|
||||
|
||||
const submenuActions: SubmenuAction[] = [];
|
||||
updateActions(submenu, submenuActions, topLevelTitle);
|
||||
target.push(new SubmenuAction(action.id, mnemonicMenuLabel(title), submenuActions));
|
||||
|
||||
if (submenuActions.length > 0) {
|
||||
target.push(new SubmenuAction(action.id, mnemonicMenuLabel(title), submenuActions));
|
||||
}
|
||||
} else {
|
||||
const newAction = new Action(action.id, mnemonicMenuLabel(title), action.class, action.enabled, () => this.commandService.executeCommand(action.id));
|
||||
newAction.tooltip = action.tooltip;
|
||||
|
||||
@@ -133,7 +133,7 @@ export class TitlebarPart extends Part implements ITitleService {
|
||||
this.titleUpdater.schedule();
|
||||
}
|
||||
|
||||
if (this.titleBarStyle !== 'native') {
|
||||
if (this.titleBarStyle !== 'native' && (!isMacintosh || isWeb)) {
|
||||
if (event.affectsConfiguration('window.menuBarVisibility')) {
|
||||
if (this.currentMenubarVisibility === 'compact') {
|
||||
this.uninstallMenubar();
|
||||
|
||||
@@ -205,11 +205,11 @@ export class TreeView extends Disposable implements ITreeView {
|
||||
) {
|
||||
super();
|
||||
this.root = new Root();
|
||||
this.collapseAllContextKey = new RawContextKey<boolean>(`treeView.${this.id}.enableCollapseAll`, false);
|
||||
this.collapseAllContextKey = new RawContextKey<boolean>(`treeView.${this.id}.enableCollapseAll`, false, localize('treeView.enableCollapseAll', "Whether the the tree view with id {0} enables collapse all.", this.id));
|
||||
this.collapseAllContext = this.collapseAllContextKey.bindTo(contextKeyService);
|
||||
this.collapseAllToggleContextKey = new RawContextKey<boolean>(`treeView.${this.id}.toggleCollapseAll`, false);
|
||||
this.collapseAllToggleContextKey = new RawContextKey<boolean>(`treeView.${this.id}.toggleCollapseAll`, false, localize('treeView.toggleCollapseAll', "Whether collapse all is toggled for the tree view with id {0}.", this.id));
|
||||
this.collapseAllToggleContext = this.collapseAllToggleContextKey.bindTo(contextKeyService);
|
||||
this.refreshContextKey = new RawContextKey<boolean>(`treeView.${this.id}.enableRefresh`, false);
|
||||
this.refreshContextKey = new RawContextKey<boolean>(`treeView.${this.id}.enableRefresh`, false, localize('treeView.enableRefresh', "Whether the tree view with id {0} enables refresh.", this.id));
|
||||
this.refreshContext = this.refreshContextKey.bindTo(contextKeyService);
|
||||
|
||||
this._register(this.themeService.onDidFileIconThemeChange(() => this.doRefresh([this.root]) /** soft refresh **/));
|
||||
@@ -853,7 +853,8 @@ class TreeRenderer extends Disposable implements ITreeRenderer<ITreeItem, FuzzyS
|
||||
this._hoverDelegate = {
|
||||
showHover: (options: IHoverDelegateOptions): IDisposable | undefined => {
|
||||
return this.hoverService.showHover(options);
|
||||
}
|
||||
},
|
||||
delay: <number>this.configurationService.getValue('workbench.hover.delay')
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1133,7 +1134,7 @@ class TreeMenus extends Disposable implements IDisposable {
|
||||
const primary: IAction[] = [];
|
||||
const secondary: IAction[] = [];
|
||||
const result = { primary, secondary };
|
||||
createAndFillInContextMenuActions(menu, { shouldForwardArgs: true }, result, g => /^inline/.test(g));
|
||||
createAndFillInContextMenuActions(menu, { shouldForwardArgs: true }, result, 'inline');
|
||||
menu.dispose();
|
||||
|
||||
return result;
|
||||
|
||||
@@ -52,13 +52,13 @@ export class BrowserWindow extends Disposable {
|
||||
this._register(addDisposableListener(viewport, EventType.RESIZE, () => this.onWindowResize()));
|
||||
|
||||
// Prevent the back/forward gestures in macOS
|
||||
this._register(addDisposableListener(this.layoutService.getWorkbenchContainer(), EventType.WHEEL, e => e.preventDefault(), { passive: false }));
|
||||
this._register(addDisposableListener(this.layoutService.container, EventType.WHEEL, e => e.preventDefault(), { passive: false }));
|
||||
|
||||
// Prevent native context menus in web
|
||||
this._register(addDisposableListener(this.layoutService.getWorkbenchContainer(), EventType.CONTEXT_MENU, e => EventHelper.stop(e, true)));
|
||||
this._register(addDisposableListener(this.layoutService.container, EventType.CONTEXT_MENU, e => EventHelper.stop(e, true)));
|
||||
|
||||
// Prevent default navigation on drop
|
||||
this._register(addDisposableListener(this.layoutService.getWorkbenchContainer(), EventType.DROP, e => EventHelper.stop(e, true)));
|
||||
this._register(addDisposableListener(this.layoutService.container, EventType.DROP, e => EventHelper.stop(e, true)));
|
||||
|
||||
// Fullscreen (Browser)
|
||||
[EventType.FULLSCREEN_CHANGE, EventType.WK_FULLSCREEN_CHANGE].forEach(event => {
|
||||
@@ -153,7 +153,7 @@ export class BrowserWindow extends Disposable {
|
||||
scheme: Schemas.userData,
|
||||
priority: true,
|
||||
formatting: {
|
||||
label: '${scheme}:${path}',
|
||||
label: '(Settings) ${path}',
|
||||
separator: '/',
|
||||
}
|
||||
});
|
||||
|
||||
@@ -23,7 +23,7 @@ import { isStandalone } from 'vs/base/browser/browser';
|
||||
enum: ['default', 'large'],
|
||||
enumDescriptions: [
|
||||
localize('workbench.editor.titleScrollbarSizing.default', "The default size."),
|
||||
localize('workbench.editor.titleScrollbarSizing.large', "Increases the size, so it can be grabbed more easily with the mouse")
|
||||
localize('workbench.editor.titleScrollbarSizing.large', "Increases the size, so it can be grabbed more easily with the mouse.")
|
||||
],
|
||||
description: localize('tabScrollbarHeight', "Controls the height of the scrollbars used for tabs and breadcrumbs in the editor title area."),
|
||||
default: 'default',
|
||||
@@ -40,7 +40,7 @@ import { isStandalone } from 'vs/base/browser/browser';
|
||||
},
|
||||
'workbench.editor.scrollToSwitchTabs': {
|
||||
'type': 'boolean',
|
||||
'markdownDescription': localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'scrollToSwitchTabs' }, "Controls whether scrolling over tabs will open them or not. By default tabs will only reveal upon scrolling, but not open. You can press and hold the Shift-key while scrolling to change this behaviour for that duration. This value is ignored when `#workbench.editor.showTabs#` is disabled."),
|
||||
'markdownDescription': localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'scrollToSwitchTabs' }, "Controls whether scrolling over tabs will open them or not. By default tabs will only reveal upon scrolling, but not open. You can press and hold the Shift-key while scrolling to change this behavior for that duration. This value is ignored when `#workbench.editor.showTabs#` is disabled."),
|
||||
'default': false
|
||||
},
|
||||
'workbench.editor.highlightModifiedTabs': {
|
||||
@@ -51,12 +51,12 @@ import { isStandalone } from 'vs/base/browser/browser';
|
||||
'workbench.editor.decorations.badges': {
|
||||
'type': 'boolean',
|
||||
'markdownDescription': localize('decorations.badges', "Controls whether editor file decorations should use badges."),
|
||||
'default': false
|
||||
'default': true
|
||||
},
|
||||
'workbench.editor.decorations.colors': {
|
||||
'type': 'boolean',
|
||||
'markdownDescription': localize('decorations.colors', "Controls whether editor file decorations should use colors."),
|
||||
'default': false
|
||||
'default': true
|
||||
},
|
||||
'workbench.editor.labelFormat': {
|
||||
'type': 'string',
|
||||
@@ -88,8 +88,8 @@ import { isStandalone } from 'vs/base/browser/browser';
|
||||
},
|
||||
'workbench.editor.untitled.hint': {
|
||||
'type': 'string',
|
||||
'enum': ['text', 'button', 'hidden'],
|
||||
'default': 'hidden',
|
||||
'enum': ['text', 'button', 'hidden', 'default'],
|
||||
'default': 'default',
|
||||
'markdownDescription': localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'untitledHint' }, "Controls if the untitled hint should be inline text in the editor or a floating button or hidden.")
|
||||
},
|
||||
'workbench.editor.tabCloseButton': {
|
||||
@@ -174,7 +174,7 @@ import { isStandalone } from 'vs/base/browser/browser';
|
||||
'type': 'string',
|
||||
'enum': ['right', 'down'],
|
||||
'default': 'right',
|
||||
'markdownDescription': localize('sideBySideDirection', "Controls the default direction of editors that are opened side by side (e.g. from the explorer). By default, editors will open on the right hand side of the currently active one. If changed to `down`, the editors will open below the currently active one.")
|
||||
'markdownDescription': localize('sideBySideDirection', "Controls the default direction of editors that are opened side by side (for example, from the Explorer). By default, editors will open on the right hand side of the currently active one. If changed to `down`, the editors will open below the currently active one.")
|
||||
},
|
||||
'workbench.editor.closeEmptyGroups': {
|
||||
'type': 'boolean',
|
||||
@@ -325,6 +325,13 @@ import { isStandalone } from 'vs/base/browser/browser';
|
||||
'description': localize('settings.editor.desc', "Determines which settings editor to use by default."),
|
||||
'default': 'ui',
|
||||
'scope': ConfigurationScope.WINDOW
|
||||
},
|
||||
'workbench.hover.delay': {
|
||||
'type': 'number',
|
||||
'description': localize('workbench.hover.delay', "Controls the delay in milliseconds after which the hover is shown for workbench items (ex. some extension provided tree view items). Already visible items may require a refresh before reflecting this setting change."),
|
||||
// Testing has indicated that on Windows and Linux 500 ms matches the native hovers most closely.
|
||||
// On Mac, the delay is 1500.
|
||||
'default': isMacintosh ? 1500 : 500
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -26,6 +26,7 @@ import { NotificationService } from 'vs/workbench/services/notification/common/n
|
||||
import { NotificationsCenter } from 'vs/workbench/browser/parts/notifications/notificationsCenter';
|
||||
import { NotificationsAlerts } from 'vs/workbench/browser/parts/notifications/notificationsAlerts';
|
||||
import { NotificationsStatus } from 'vs/workbench/browser/parts/notifications/notificationsStatus';
|
||||
import { NotificationsTelemetry } from 'vs/workbench/browser/parts/notifications/notificationsTelemetry';
|
||||
import { registerNotificationCommands } from 'vs/workbench/browser/parts/notifications/notificationsCommands';
|
||||
import { NotificationsToasts } from 'vs/workbench/browser/parts/notifications/notificationsToasts';
|
||||
import { setARIAContainer } from 'vs/base/browser/ui/aria/aria';
|
||||
@@ -378,6 +379,7 @@ export class Workbench extends Layout {
|
||||
const notificationsToasts = this._register(instantiationService.createInstance(NotificationsToasts, this.container, notificationService.model));
|
||||
this._register(instantiationService.createInstance(NotificationsAlerts, notificationService.model));
|
||||
const notificationsStatus = instantiationService.createInstance(NotificationsStatus, notificationService.model);
|
||||
this._register(instantiationService.createInstance(NotificationsTelemetry));
|
||||
|
||||
// Visibility
|
||||
this._register(notificationsCenter.onDidChangeVisibility(() => {
|
||||
@@ -390,7 +392,7 @@ export class Workbench extends Layout {
|
||||
}));
|
||||
|
||||
// Register Commands
|
||||
registerNotificationCommands(notificationsCenter, notificationsToasts);
|
||||
registerNotificationCommands(notificationsCenter, notificationsToasts, notificationService.model);
|
||||
|
||||
// Register with Layout
|
||||
this.registerNotifications({
|
||||
|
||||
Reference in New Issue
Block a user