Merge from vscode e0762af258c0b20320ed03f3871a41967acc4421 (#7404)

* Merge from vscode e0762af258c0b20320ed03f3871a41967acc4421

* readd svgs
This commit is contained in:
Anthony Dresser
2019-09-27 11:13:19 -07:00
committed by GitHub
parent 6385443a4c
commit 07109617b5
348 changed files with 4219 additions and 4307 deletions

5
.vscode/launch.json vendored
View File

@@ -165,7 +165,10 @@
"cwd": "${workspaceFolder}",
"outFiles": [
"${workspaceFolder}/out/**/*.js"
]
],
"env": {
"MOCHA_COLORS": "true"
}
},
{
"type": "chrome",

6
.vscode/tasks.json vendored
View File

@@ -5,7 +5,10 @@
"type": "npm",
"script": "watch",
"label": "Build VS Code",
"group": "build",
"group": {
"kind": "build",
"isDefault": true
},
"isBackground": true,
"presentation": {
"reveal": "never"
@@ -96,6 +99,5 @@
"task": "hygiene",
"problemMatcher": []
},
]
}

View File

@@ -242,6 +242,10 @@
"name": "vs/workbench/services/keybinding",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/services/lifecycle",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/services/mode",
"project": "vscode-workbench"

View File

@@ -190,7 +190,7 @@ export class Model {
openRepositoriesToDispose.forEach(r => r.dispose());
}
private async onDidChangeVisibleTextEditors(editors: TextEditor[]): Promise<void> {
private async onDidChangeVisibleTextEditors(editors: readonly TextEditor[]): Promise<void> {
const config = workspace.getConfiguration('git');
const autoRepositoryDetection = config.get<boolean | 'subFolders' | 'openEditors'>('autoRepositoryDetection');

View File

@@ -8,7 +8,6 @@ html, body {
max-height: 100%;
}
body img {
max-width: none;
max-height: none;
@@ -34,6 +33,7 @@ body img {
padding: 0;
background-position: 0 0, 8px 8px;
background-size: 16px 16px;
border: 1px solid var(--vscode-imagePreview-border);
}
.container.image img {

View File

@@ -2,6 +2,7 @@
"name": "image-preview",
"displayName": "%displayName%",
"description": "%description%",
"extensionKind": "ui",
"version": "1.0.0",
"publisher": "vscode",
"icon": "icon.png",

View File

@@ -77,7 +77,7 @@
"vscode-ripgrep": "^1.5.7",
"vscode-sqlite3": "4.0.8",
"vscode-textmate": "^4.2.2",
"xterm": "4.0.0",
"xterm": "4.1.0-beta8",
"xterm-addon-search": "0.2.0",
"xterm-addon-web-links": "0.2.0",
"yauzl": "^2.9.2",

View File

@@ -21,7 +21,7 @@
"vscode-proxy-agent": "0.4.0",
"vscode-ripgrep": "^1.5.7",
"vscode-textmate": "^4.2.2",
"xterm": "4.0.0",
"xterm": "4.1.0-beta8",
"xterm-addon-search": "0.2.0",
"xterm-addon-web-links": "0.2.0",
"yauzl": "^2.9.2",

View File

@@ -6,7 +6,7 @@
"onigasm-umd": "^2.2.2",
"semver-umd": "^5.5.3",
"vscode-textmate": "^4.2.2",
"xterm": "4.0.0",
"xterm": "4.1.0-beta8",
"xterm-addon-search": "0.2.0",
"xterm-addon-web-links": "0.2.0"
}

View File

@@ -109,7 +109,7 @@ xterm-addon-web-links@0.2.0:
resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.2.0.tgz#b408a0be46211d8d4a0bb5e701d8f3c2bd07d473"
integrity sha512-dq81c4Pzli2PgKVBgY2REte9sCVibR3df8AP3SEvCTM9uYFnUFxtxzMTplPnc7+rXabVhFdbU6x+rstIk8HNQg==
xterm@4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.0.0.tgz#eac93e08cbe69cf238cbace9185ed9e38873df1a"
integrity sha512-Xbx3vvf9FnrUcI1qU31Jww7/fc/NqpXGqgByTvjj7+g3/yPvt/RvLkP/LLMcof2kLAC3evzZGMiovs7NkjdWDw==
xterm@4.1.0-beta8:
version "4.1.0-beta8"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.1.0-beta8.tgz#c1ef323ba336d92f5b52302b66f672dfff75b3ef"
integrity sha512-6lf+XVv0qT285w49P92tSYoUB406jdbgdhnPKNzxCIGtGX8kcwK+pHZ8HncDwcEhmTmI4LZ/WXPGtOQJg+onwg==

View File

@@ -489,10 +489,10 @@ xterm-addon-web-links@0.2.0:
resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.2.0.tgz#b408a0be46211d8d4a0bb5e701d8f3c2bd07d473"
integrity sha512-dq81c4Pzli2PgKVBgY2REte9sCVibR3df8AP3SEvCTM9uYFnUFxtxzMTplPnc7+rXabVhFdbU6x+rstIk8HNQg==
xterm@4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.0.0.tgz#eac93e08cbe69cf238cbace9185ed9e38873df1a"
integrity sha512-Xbx3vvf9FnrUcI1qU31Jww7/fc/NqpXGqgByTvjj7+g3/yPvt/RvLkP/LLMcof2kLAC3evzZGMiovs7NkjdWDw==
xterm@4.1.0-beta8:
version "4.1.0-beta8"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.1.0-beta8.tgz#c1ef323ba336d92f5b52302b66f672dfff75b3ef"
integrity sha512-6lf+XVv0qT285w49P92tSYoUB406jdbgdhnPKNzxCIGtGX8kcwK+pHZ8HncDwcEhmTmI4LZ/WXPGtOQJg+onwg==
yauzl@^2.9.2:
version "2.10.0"

View File

@@ -22,10 +22,9 @@ import { StandaloneCodeEditor } from 'vs/editor/standalone/browser/standaloneCod
import { CancellationToken } from 'vs/base/common/cancellation';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { IWindowService } from 'vs/platform/windows/common/windows';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IHostService } from 'vs/workbench/services/host/browser/host';
/**
* Extension of TextResourceEditor that is always readonly rather than only with non UntitledInputs
@@ -51,14 +50,13 @@ export class QueryTextEditor extends BaseTextEditor {
@ITextFileService textFileService: ITextFileService,
@IEditorGroupsService editorGroupService: IEditorGroupsService,
@IEditorService protected editorService: IEditorService,
@IWindowService windowService: IWindowService,
@IHostService hostService: IHostService,
@IConfigurationService private workspaceConfigurationService: IConfigurationService,
@IAccessibilityService private accessibilityService: IAccessibilityService
) {
super(
QueryTextEditor.ID, telemetryService, instantiationService, storageService,
configurationService, themeService, textFileService, editorService, editorGroupService, windowService);
configurationService, themeService, textFileService, editorService, editorGroupService, hostService);
}
public createEditorControl(parent: HTMLElement, configuration: IEditorOptions): editorCommon.IEditor {

View File

@@ -8,7 +8,6 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
import { localize } from 'vs/nls';
import { onUnexpectedError } from 'vs/base/common/errors';
import { IWindowService } from 'vs/platform/windows/common/windows';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IHostService } from 'vs/workbench/services/host/browser/host';
@@ -19,7 +18,6 @@ export class EnablePreviewFeatures implements IWorkbenchContribution {
constructor(
@IStorageService storageService: IStorageService,
@INotificationService notificationService: INotificationService,
@IWindowService windowService: IWindowService,
@IHostService hostService: IHostService,
@IConfigurationService configurationService: IConfigurationService
) {
@@ -28,7 +26,7 @@ export class EnablePreviewFeatures implements IWorkbenchContribution {
return;
}
Promise.all([
windowService.isFocused(),
hostService.hasFocus,
hostService.windowCount
]).then(([focused, count]) => {
if (!focused && count > 1) {

View File

@@ -6,7 +6,7 @@
import { Registry } from 'vs/platform/registry/common/platform';
import { Disposable } from 'vs/base/common/lifecycle';
import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
import { IStatusbarService, StatusbarAlignment } from 'vs/platform/statusbar/common/statusbar';
import { IStatusbarService, StatusbarAlignment } from 'vs/workbench/services/statusbar/common/statusbar';
import { localize } from 'vs/nls';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';

View File

@@ -9,7 +9,6 @@ import { IClipboardService } from 'sql/platform/clipboard/common/clipboardServic
import { localize } from 'vs/nls';
import { Action } from 'vs/base/common/actions';
import { IWindowsService, FileFilter } from 'vs/platform/windows/common/windows';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
import { URI } from 'vs/base/common/uri';
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
@@ -18,7 +17,7 @@ import { QueryInput } from 'sql/workbench/parts/query/common/queryInput';
import { IInsightsConfig } from 'sql/platform/dashboard/browser/insightRegistry';
import { IInsightOptions } from 'sql/workbench/parts/charts/common/interfaces';
import { IFileService } from 'vs/platform/files/common/files';
import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs';
import { IFileDialogService, FileFilter } from 'vs/platform/dialogs/common/dialogs';
import { VSBuffer } from 'vs/base/common/buffer';
import { IOpenerService } from 'vs/platform/opener/common/opener';

View File

@@ -9,7 +9,7 @@ import { IConnectionManagementService } from 'sql/platform/connection/common/con
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
import { IObjectExplorerService } from 'sql/workbench/services/objectExplorer/browser/objectExplorerService';
import * as TaskUtilities from 'sql/workbench/browser/taskUtilities';
import { IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment } from 'vs/platform/statusbar/common/statusbar';
import { IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment } from 'vs/workbench/services/statusbar/common/statusbar';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { localize } from 'vs/nls';

View File

@@ -22,7 +22,6 @@ import { MimeRendererComponent } from 'sql/workbench/parts/notebook/browser/outp
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { URI } from 'vs/base/common/uri';
import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing';
import { IWindowService } from 'vs/platform/windows/common/windows';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { NodeContextKey } from 'sql/workbench/parts/dataExplorer/browser/nodeContext';
import { MssqlNodeContext } from 'sql/workbench/parts/dataExplorer/browser/mssqlNodeContext';
@@ -130,7 +129,6 @@ registerAction({
handler: async (accessor, options: { forceNewWindow: boolean, folderPath: URI }) => {
const viewletService = accessor.get(IViewletService);
const workspaceEditingService = accessor.get(IWorkspaceEditingService);
const windowService = accessor.get(IWindowService);
const hostService = accessor.get(IHostService);
let folders = [];
if (!options.folderPath) {
@@ -140,7 +138,7 @@ registerAction({
await workspaceEditingService.addFolders(folders.map(folder => ({ uri: folder })));
await viewletService.openViewlet(viewletService.getDefaultViewletId(), true);
if (options.forceNewWindow) {
return windowService.openWindow([{ folderUri: folders[0] }], { forceNewWindow: options.forceNewWindow });
return hostService.openInWindow([{ folderUri: folders[0] }], { forceNewWindow: options.forceNewWindow });
}
else {
return hostService.reload();

View File

@@ -21,8 +21,8 @@ import { EditorOptions } from 'vs/workbench/common/editor';
import { StandaloneCodeEditor } from 'vs/editor/standalone/browser/standaloneCodeEditor';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { CancellationToken } from 'vs/base/common/cancellation';
import { IWindowService } from 'vs/platform/windows/common/windows';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IHostService } from 'vs/workbench/services/host/browser/host';
class ProfilerResourceCodeEditor extends StandaloneCodeEditor {
@@ -50,10 +50,10 @@ export class ProfilerResourceEditor extends BaseTextEditor {
@ITextFileService textFileService: ITextFileService,
@IEditorService protected editorService: IEditorService,
@IEditorGroupsService editorGroupService: IEditorGroupsService,
@IWindowService windowService: IWindowService
@IHostService hostService: IHostService
) {
super(ProfilerResourceEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, windowService);
super(ProfilerResourceEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, hostService);
}
public createEditorControl(parent: HTMLElement, configuration: IEditorOptions): editorCommon.IEditor {

View File

@@ -27,7 +27,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import { Dimension } from 'vs/base/browser/dom';
import { textFormatter, slickGridDataItemColumnValueExtractor } from 'sql/base/browser/ui/table/formatters';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { IStatusbarService, StatusbarAlignment } from 'vs/platform/statusbar/common/statusbar';
import { IStatusbarService, StatusbarAlignment } from 'vs/workbench/services/statusbar/common/statusbar';
import { localize } from 'vs/nls';
import { CopyKeybind } from 'sql/base/browser/ui/table/plugins/copyKeybind.plugin';
import { IClipboardService } from 'sql/platform/clipboard/common/clipboardService';

View File

@@ -21,7 +21,7 @@ import { EditorServiceImpl } from 'vs/workbench/browser/parts/editor/editor';
import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
import { mssqlProviderName } from 'sql/platform/connection/common/constants';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { IStatusbarService, StatusbarAlignment, IStatusbarEntryAccessor } from 'vs/platform/statusbar/common/statusbar';
import { IStatusbarService, StatusbarAlignment, IStatusbarEntryAccessor } from 'vs/workbench/services/statusbar/common/statusbar';
export interface ISqlProviderEntry extends IQuickPickItem {
providerId: string;

View File

@@ -6,7 +6,6 @@
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IQueryModelService } from 'sql/platform/query/common/queryModel';
import { IntervalTimer } from 'vs/base/common/async';
import { IStatusbarService, StatusbarAlignment, IStatusbarEntryAccessor } from 'vs/platform/statusbar/common/statusbar';
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { localize } from 'vs/nls';
@@ -14,6 +13,7 @@ import { QueryInput } from 'sql/workbench/parts/query/common/queryInput';
import QueryRunner from 'sql/platform/query/common/queryRunner';
import { parseNumAsTimeString } from 'sql/platform/connection/common/utils';
import { Event } from 'vs/base/common/event';
import { IStatusbarService, IStatusbarEntryAccessor, StatusbarAlignment } from 'vs/workbench/services/statusbar/common/statusbar';
export class TimeElapsedStatusBarContributions extends Disposable implements IWorkbenchContribution {

View File

@@ -10,7 +10,6 @@ import { IQueryManagementService } from 'sql/platform/query/common/queryManageme
import { ISaveRequest, SaveFormat } from 'sql/workbench/parts/grid/common/interfaces';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { FileFilter } from 'vs/platform/windows/common/windows';
import { Registry } from 'vs/platform/registry/common/platform';
import { URI } from 'vs/base/common/uri';
import * as path from 'vs/base/common/path';
@@ -24,7 +23,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
import { getRootPath, resolveCurrentDirectory, resolveFilePath } from 'sql/platform/common/pathUtilities';
import { IOutputService, IOutputChannelRegistry, IOutputChannel, Extensions as OutputExtensions } from 'vs/workbench/contrib/output/common/output';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs';
import { IFileDialogService, FileFilter } from 'vs/platform/dialogs/common/dialogs';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
let prevSavePath: string;

View File

@@ -25,6 +25,7 @@ import { getRandomTestPath } from 'vs/base/test/node/testUtils';
import { IWorkbenchConstructionOptions } from 'vs/workbench/workbench.web.api';
class TestEnvironmentService implements IWorkbenchEnvironmentService {
userDataSyncLogResource: URI;
settingsSyncPreviewResource: URI;
webviewExternalEndpoint: string;
logFile: URI;

View File

@@ -650,24 +650,32 @@ declare module 'xterm' {
clear(): void;
/**
* Writes text to the terminal.
* @param data The text to write to the terminal.
* Write data to the terminal.
* @param data The data to write to the terminal. This can either be raw
* bytes given as Uint8Array from the pty or a string. Raw bytes will always
* be treated as UTF-8 encoded, string data as UTF-16.
* @param callback Optional callback that fires when the data was processed
* by the parser.
*/
write(data: string): void;
write(data: string | Uint8Array, callback?: () => void): void;
/**
* Writes text to the terminal, followed by a break line character (\n).
* @param data The text to write to the terminal.
* Writes data to the terminal, followed by a break line character (\n).
* @param data The data to write to the terminal. This can either be raw
* bytes given as Uint8Array from the pty or a string. Raw bytes will always
* be treated as UTF-8 encoded, string data as UTF-16.
* @param callback Optional callback that fires when the data was processed
* by the parser.
*/
writeln(data: string): void;
writeln(data: string | Uint8Array, callback?: () => void): void;
/**
* Writes UTF8 data to the terminal. This has a slight performance advantage
* over the string based write method due to lesser data conversions needed
* on the way from the pty to xterm.js.
* Write UTF8 data to the terminal.
* @param data The data to write to the terminal.
* @param callback Optional callback when data was processed.
* @deprecated use `write` instead
*/
writeUtf8(data: Uint8Array): void;
writeUtf8(data: Uint8Array, callback?: () => void): void;
/**
* Writes text to the terminal, performing the necessary transformations for pasted text.
@@ -804,7 +812,7 @@ declare module 'xterm' {
*/
export interface ITerminalAddon extends IDisposable {
/**
* (EXPERIMENTAL) This is called when the addon is activated.
* This is called when the addon is activated.
*/
activate(terminal: Terminal): void;
}

View File

@@ -173,6 +173,11 @@
outline: 0;
}
.menubar.compact > .menubar-menu-button {
width: 100%;
height: 100%;
}
.menubar .menubar-menu-items-holder {
position: absolute;
left: 0px;
@@ -197,9 +202,23 @@
height: 100%;
}
.menubar.compact .toolbar-toggle-more {
background-position: center;
background-repeat: no-repeat;
background-size: 16px;
cursor: pointer;
width: 100%;
height: 100%;
}
.menubar .toolbar-toggle-more {
display: inline-block;
padding: 0;
-webkit-mask: url('ellipsis.svg') no-repeat 50% 55%/14px 14px;
mask: url('ellipsis.svg') no-repeat 50% 55%/14px 14px;
}
}
.menubar.compact .toolbar-toggle-more {
-webkit-mask: url('menu.svg') no-repeat 50% 55%/16px 16px;
mask: url('menu.svg') no-repeat 50% 55%/16px 16px;
}

View File

@@ -0,0 +1,3 @@
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M18 5.625H0V4.5H18V5.625ZM18 14.625H0V13.5H18V14.625ZM18 10.1162H0V9H18V10.1162Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 209 B

View File

@@ -23,6 +23,11 @@ import { isLinux, isMacintosh } from 'vs/base/common/platform';
export const MENU_MNEMONIC_REGEX = /\(&([^\s&])\)|(^|[^&])&([^\s&])/;
export const MENU_ESCAPED_MNEMONIC_REGEX = /(&amp;)?(&amp;)([^\s&])/g;
export enum Direction {
Right,
Left
}
export interface IMenuOptions {
context?: any;
actionViewItemProvider?: IActionViewItemProvider;
@@ -31,6 +36,7 @@ export interface IMenuOptions {
ariaLabel?: string;
enableMnemonics?: boolean;
anchorAlignment?: AnchorAlignment;
expandDirection?: Direction;
}
export interface IMenuStyles {
@@ -591,6 +597,7 @@ class SubmenuMenuActionViewItem extends BaseMenuActionViewItem {
private mouseOver: boolean;
private showScheduler: RunOnceScheduler;
private hideScheduler: RunOnceScheduler;
private expandDirection: Direction;
constructor(
action: IAction,
@@ -600,6 +607,8 @@ class SubmenuMenuActionViewItem extends BaseMenuActionViewItem {
) {
super(action, action, submenuOptions);
this.expandDirection = submenuOptions && submenuOptions.expandDirection !== undefined ? submenuOptions.expandDirection : Direction.Right;
this.showScheduler = new RunOnceScheduler(() => {
if (this.mouseOver) {
this.cleanupExistingSubmenu(false);
@@ -715,11 +724,17 @@ class SubmenuMenuActionViewItem extends BaseMenuActionViewItem {
const computedStyles = getComputedStyle(this.parentData.parent.domNode);
const paddingTop = parseFloat(computedStyles.paddingTop || '0') || 0;
if (window.innerWidth <= boundingRect.right + childBoundingRect.width) {
this.submenuContainer.style.left = '10px';
this.submenuContainer.style.top = `${this.element.offsetTop - this.parentData.parent.scrollOffset + boundingRect.height}px`;
} else {
this.submenuContainer.style.left = `${this.element.offsetWidth}px`;
if (this.expandDirection === Direction.Right) {
if (window.innerWidth <= boundingRect.right + childBoundingRect.width) {
this.submenuContainer.style.left = '10px';
this.submenuContainer.style.top = `${this.element.offsetTop - this.parentData.parent.scrollOffset + boundingRect.height}px`;
} else {
this.submenuContainer.style.left = `${this.element.offsetWidth}px`;
this.submenuContainer.style.top = `${this.element.offsetTop - this.parentData.parent.scrollOffset - paddingTop}px`;
}
} else if (this.expandDirection === Direction.Left) {
this.submenuContainer.style.right = `${this.element.offsetWidth}px`;
this.submenuContainer.style.left = 'auto';
this.submenuContainer.style.top = `${this.element.offsetTop - this.parentData.parent.scrollOffset - paddingTop}px`;
}

View File

@@ -10,7 +10,7 @@ import * as nls from 'vs/nls';
import { domEvent } from 'vs/base/browser/event';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { EventType, Gesture, GestureEvent } from 'vs/base/browser/touch';
import { cleanMnemonic, IMenuOptions, Menu, MENU_ESCAPED_MNEMONIC_REGEX, MENU_MNEMONIC_REGEX, SubmenuAction, IMenuStyles } from 'vs/base/browser/ui/menu/menu';
import { cleanMnemonic, IMenuOptions, Menu, MENU_ESCAPED_MNEMONIC_REGEX, MENU_MNEMONIC_REGEX, SubmenuAction, IMenuStyles, Direction } from 'vs/base/browser/ui/menu/menu';
import { ActionRunner, IAction, IActionRunner } from 'vs/base/common/actions';
import { RunOnceScheduler } from 'vs/base/common/async';
import { Event, Emitter } from 'vs/base/common/event';
@@ -29,6 +29,7 @@ export interface IMenuBarOptions {
visibility?: string;
getKeybinding?: (action: IAction) => ResolvedKeybinding | undefined;
alwaysOnMnemonics?: boolean;
compactMode?: Direction;
}
export interface MenuBarMenu {
@@ -92,6 +93,9 @@ export class MenuBar extends Disposable {
super();
this.container.setAttribute('role', 'menubar');
if (this.options.compactMode !== undefined) {
DOM.addClass(this.container, 'compact');
}
this.menuCache = [];
this.mnemonics = new Map<string, number>();
@@ -292,7 +296,7 @@ export class MenuBar extends Disposable {
}
createOverflowMenu(): void {
const label = nls.localize('mMore', "...");
const label = this.options.compactMode !== undefined ? nls.localize('mAppMenu', 'Application Menu') : nls.localize('mMore', "...");
const buttonElement = $('div.menubar-menu-button', { 'role': 'menuitem', 'tabindex': -1, 'aria-label': label, 'aria-haspopup': true });
const titleElement = $('div.menubar-menu-title.toolbar-toggle-more', { 'role': 'none', 'aria-hidden': true });
@@ -421,7 +425,7 @@ export class MenuBar extends Disposable {
const sizeAvailable = this.container.offsetWidth;
let currentSize = 0;
let full = false;
let full = this.options.compactMode !== undefined;
const prevNumMenusShown = this.numMenusShown;
this.numMenusShown = 0;
for (let menuBarMenu of this.menuCache) {
@@ -884,8 +888,19 @@ export class MenuBar extends Disposable {
const menuHolder = $('div.menubar-menu-items-holder');
DOM.addClass(customMenu.buttonElement, 'open');
menuHolder.style.top = `${this.container.clientHeight}px`;
menuHolder.style.left = `${customMenu.buttonElement.getBoundingClientRect().left}px`;
if (this.options.compactMode === Direction.Right) {
menuHolder.style.top = `0px`;
menuHolder.style.left = `${customMenu.buttonElement.getBoundingClientRect().left + this.container.clientWidth}px`;
} else if (this.options.compactMode === Direction.Left) {
menuHolder.style.top = `0px`;
menuHolder.style.right = `${this.container.clientWidth}px`;
menuHolder.style.left = 'auto';
console.log(customMenu.buttonElement.getBoundingClientRect().right - this.container.clientWidth);
} else {
menuHolder.style.top = `${this.container.clientHeight}px`;
menuHolder.style.left = `${customMenu.buttonElement.getBoundingClientRect().left}px`;
}
customMenu.buttonElement.appendChild(menuHolder);
@@ -893,7 +908,8 @@ export class MenuBar extends Disposable {
getKeyBinding: this.options.getKeybinding,
actionRunner: this.actionRunner,
enableMnemonics: this.options.alwaysOnMnemonics || (this.mnemonicsInUse && this.options.enableMnemonics),
ariaLabel: withNullAsUndefined(customMenu.buttonElement.getAttribute('aria-label'))
ariaLabel: withNullAsUndefined(customMenu.buttonElement.getAttribute('aria-label')),
expandDirection: this.options.compactMode !== undefined ? this.options.compactMode : Direction.Right
};
let menuWidget = this._register(new Menu(menuHolder, customMenu.actions, menuOptions));

View File

@@ -4,8 +4,6 @@
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./octicons/octicons';
import 'vs/css!./octicons/octicons2';
import 'vs/css!./octicons/octicons-main';
import 'vs/css!./octicons/octicons-animations';
import { escape } from 'vs/base/common/strings';

View File

@@ -1,17 +0,0 @@
body[data-octicons-update="enabled"] {
--version: octicons2;
}
body {
--version: octicons;
}
.octicon, .mega-octicon {
font-family: var(--version) !important;
}
body[data-octicons-update="enabled"] .monaco-workbench .part.statusbar > .items-container > .statusbar-item > a {
display: flex;
align-items: center;
justify-content: center;
}

View File

@@ -1,7 +1,6 @@
@font-face {
font-family: "octicons";
src: url("./octicons.ttf?1b0f2a9535896866c74dd24eedeb4374") format("truetype"),
url("./octicons.svg?1b0f2a9535896866c74dd24eedeb4374#octicons") format("svg");
src: url("./octicons.ttf?628f71ee09945d25ba5fceb0c17f7b0f") format("truetype");
}
.octicon, .mega-octicon {
@@ -137,11 +136,11 @@ url("./octicons.svg?1b0f2a9535896866c74dd24eedeb4374#octicons") format("svg");
.octicon-lock:before { content: "\f06a" }
.octicon-log-in:before { content: "\f036" }
.octicon-log-out:before { content: "\f032" }
.octicon-logo-gist:before { content: "\f288" }
.octicon-logo-github:before { content: "\f092" }
.octicon-mail-read:before { content: "\f03c" }
.octicon-mail-reply:before { content: "\f28c" }
.octicon-mail:before { content: "\f03b" }
.octicon-logo-gist:before { content: "\f00a" }
.octicon-logo-github:before { content: "\f00a" }
.octicon-mark-github:before { content: "\f00a" }
.octicon-markdown:before { content: "\f0c9" }
.octicon-megaphone:before { content: "\f077" }
@@ -157,7 +156,7 @@ url("./octicons.svg?1b0f2a9535896866c74dd24eedeb4374#octicons") format("svg");
.octicon-note:before { content: "\f289" }
.octicon-octoface:before { content: "\f008" }
.octicon-organization:before { content: "\f037" }
.octicon-organization-filled:before { content: "\26a2" }
.octicon-organization-filled:before { content: "\f037" }
.octicon-organization-outline:before { content: "\f037" }
.octicon-package:before { content: "\f0c4" }
.octicon-paintcan:before { content: "\f0d1" }
@@ -165,7 +164,7 @@ url("./octicons.svg?1b0f2a9535896866c74dd24eedeb4374#octicons") format("svg");
.octicon-person-add:before { content: "\f018" }
.octicon-person-follow:before { content: "\f018" }
.octicon-person:before { content: "\f018" }
.octicon-person-filled:before { content: "\26a3" }
.octicon-person-filled:before { content: "\f018" }
.octicon-person-outline:before { content: "\f018" }
.octicon-pin:before { content: "\f041" }
.octicon-plug:before { content: "\f0d4" }
@@ -202,7 +201,7 @@ url("./octicons.svg?1b0f2a9535896866c74dd24eedeb4374#octicons") format("svg");
.octicon-shield:before { content: "\f0e1" }
.octicon-sign-in:before { content: "\f036" }
.octicon-sign-out:before { content: "\f032" }
.octicon-smiley:before { content: "\f27d" }
.octicon-smiley:before { content: "\26b2" }
.octicon-squirrel:before { content: "\f0b2" }
.octicon-star-add:before { content: "\f02a" }
.octicon-star-delete:before { content: "\f02a" }
@@ -233,16 +232,20 @@ url("./octicons.svg?1b0f2a9535896866c74dd24eedeb4374#octicons") format("svg");
.octicon-watch:before { content: "\f0e0" }
.octicon-x:before { content: "\f081" }
.octicon-zap:before { content: "\26a1" }
.octicon-archive:before { content: "\f101" }
.octicon-arrow-both:before { content: "\f102" }
.octicon-error:before { content: "\f103" }
.octicon-eye-closed:before { content: "\f104" }
.octicon-fold-down:before { content: "\f105" }
.octicon-fold-up:before { content: "\f106" }
.octicon-github-action:before { content: "\f107" }
.octicon-info-outline:before { content: "\f108" }
.octicon-play:before { content: "\f109" }
.octicon-remote:before { content: "\f10a" }
.octicon-request-changes:before { content: "\f10b" }
.octicon-smiley-outline:before { content: "\f10c" }
.octicon-warning:before { content: "\f10d" }
.octicon-error:before { content: "\26b1" }
.octicon-eye-closed:before { content: "\26a3" }
.octicon-fold-down:before { content: "\26a4" }
.octicon-fold-up:before { content: "\26a5" }
.octicon-github-action:before { content: "\26a6" }
.octicon-info-outline:before { content: "\26a7" }
.octicon-play:before { content: "\26a8" }
.octicon-remote:before { content: "\26a9" }
.octicon-request-changes:before { content: "\26aa" }
.octicon-smiley-outline:before { content: "\26b2" }
.octicon-warning:before { content: "\f02d" }
.octicon-controls:before { content: "\26ad" }
.octicon-event:before { content: "\26ae" }
.octicon-record-keys:before { content: "\26af" }
.octicon-Vector:before { content: "\f101" }
.octicon-archive:before { content: "\f102" }
.octicon-arrow-both:before { content: "\f103" }

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 130 KiB

View File

@@ -1,251 +0,0 @@
@font-face {
font-family: "octicons2";
src: url("./octicons2.ttf?aa78025ff36faa0aebb5b864685c6dc4") format("truetype");
}
.octicon, .mega-octicon {
font: normal normal normal 16px/1 octicons2;
display: inline-block;
text-decoration: none;
text-rendering: auto;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.mega-octicon { font-size: 32px; }
body[data-octicons-update="enabled"] .octicon-alert:before { content: "\f02d" }
body[data-octicons-update="enabled"] .octicon-arrow-down:before { content: "\f03f" }
body[data-octicons-update="enabled"] .octicon-arrow-left:before { content: "\f040" }
body[data-octicons-update="enabled"] .octicon-arrow-right:before { content: "\f03e" }
body[data-octicons-update="enabled"] .octicon-arrow-small-down:before { content: "\f0a0" }
body[data-octicons-update="enabled"] .octicon-arrow-small-left:before { content: "\f0a1" }
body[data-octicons-update="enabled"] .octicon-arrow-small-right:before { content: "\f071" }
body[data-octicons-update="enabled"] .octicon-arrow-small-up:before { content: "\f09f" }
body[data-octicons-update="enabled"] .octicon-arrow-up:before { content: "\f03d" }
body[data-octicons-update="enabled"] .octicon-beaker:before { content: "\f0dd" }
body[data-octicons-update="enabled"] .octicon-bell:before { content: "\f0de" }
body[data-octicons-update="enabled"] .octicon-bold:before { content: "\f282" }
body[data-octicons-update="enabled"] .octicon-book:before { content: "\f007" }
body[data-octicons-update="enabled"] .octicon-bookmark:before { content: "\f07b" }
body[data-octicons-update="enabled"] .octicon-briefcase:before { content: "\f0d3" }
body[data-octicons-update="enabled"] .octicon-broadcast:before { content: "\f048" }
body[data-octicons-update="enabled"] .octicon-browser:before { content: "\f0c5" }
body[data-octicons-update="enabled"] .octicon-bug:before { content: "\f091" }
body[data-octicons-update="enabled"] .octicon-calendar:before { content: "\f068" }
body[data-octicons-update="enabled"] .octicon-check:before { content: "\f03a" }
body[data-octicons-update="enabled"] .octicon-checklist:before { content: "\f076" }
body[data-octicons-update="enabled"] .octicon-chevron-down:before { content: "\f0a3" }
body[data-octicons-update="enabled"] .octicon-chevron-left:before { content: "\f0a4" }
body[data-octicons-update="enabled"] .octicon-chevron-right:before { content: "\f078" }
body[data-octicons-update="enabled"] .octicon-chevron-up:before { content: "\f0a2" }
body[data-octicons-update="enabled"] .octicon-circle-slash:before { content: "\f084" }
body[data-octicons-update="enabled"] .octicon-circuit-board:before { content: "\f0d6" }
body[data-octicons-update="enabled"] .octicon-clippy:before { content: "\f035" }
body[data-octicons-update="enabled"] .octicon-clock:before { content: "\f046" }
body[data-octicons-update="enabled"] .octicon-clone:before { content: "\f0dc" }
body[data-octicons-update="enabled"] .octicon-cloud-download:before { content: "\f00b" }
body[data-octicons-update="enabled"] .octicon-cloud-upload:before { content: "\f00c" }
body[data-octicons-update="enabled"] .octicon-code:before { content: "\f05f" }
body[data-octicons-update="enabled"] .octicon-color-mode:before { content: "\f065" }
body[data-octicons-update="enabled"] .octicon-comment-add:before { content: "\f02b" }
body[data-octicons-update="enabled"] .octicon-comment-discussion:before { content: "\f04f" }
body[data-octicons-update="enabled"] .octicon-comment:before { content: "\f02b" }
body[data-octicons-update="enabled"] .octicon-credit-card:before { content: "\f045" }
body[data-octicons-update="enabled"] .octicon-dash:before { content: "\f0ca" }
body[data-octicons-update="enabled"] .octicon-dashboard:before { content: "\f07d" }
body[data-octicons-update="enabled"] .octicon-database:before { content: "\f096" }
body[data-octicons-update="enabled"] .octicon-desktop-download:before { content: "\f0dc" }
body[data-octicons-update="enabled"] .octicon-device-camera-video:before { content: "\f057" }
body[data-octicons-update="enabled"] .octicon-device-camera:before { content: "\f056" }
body[data-octicons-update="enabled"] .octicon-device-desktop:before { content: "\f27c" }
body[data-octicons-update="enabled"] .octicon-device-mobile:before { content: "\f038" }
body[data-octicons-update="enabled"] .octicon-diff-added:before { content: "\f06b" }
body[data-octicons-update="enabled"] .octicon-diff-ignored:before { content: "\f099" }
body[data-octicons-update="enabled"] .octicon-diff-modified:before { content: "\f06d" }
body[data-octicons-update="enabled"] .octicon-diff-removed:before { content: "\f06c" }
body[data-octicons-update="enabled"] .octicon-diff-renamed:before { content: "\f06e" }
body[data-octicons-update="enabled"] .octicon-diff:before { content: "\f04d" }
body[data-octicons-update="enabled"] .octicon-ellipsis:before { content: "\f09a" }
body[data-octicons-update="enabled"] .octicon-eye-unwatch:before { content: "\f04e" }
body[data-octicons-update="enabled"] .octicon-eye-watch:before { content: "\f04e" }
body[data-octicons-update="enabled"] .octicon-eye:before { content: "\f04e" }
body[data-octicons-update="enabled"] .octicon-file-add:before { content: "\f05d" }
body[data-octicons-update="enabled"] .octicon-file-binary:before { content: "\f094" }
body[data-octicons-update="enabled"] .octicon-file-code:before { content: "\f010" }
body[data-octicons-update="enabled"] .octicon-file-directory-create:before { content: "\f05d" }
body[data-octicons-update="enabled"] .octicon-file-directory:before { content: "\f016" }
body[data-octicons-update="enabled"] .octicon-file-media:before { content: "\f012" }
body[data-octicons-update="enabled"] .octicon-file-pdf:before { content: "\f014" }
body[data-octicons-update="enabled"] .octicon-file-submodule:before { content: "\f017" }
body[data-octicons-update="enabled"] .octicon-file-symlink-directory:before { content: "\f0b1" }
body[data-octicons-update="enabled"] .octicon-file-symlink-file:before { content: "\f0b0" }
body[data-octicons-update="enabled"] .octicon-file-text:before { content: "\f283" }
body[data-octicons-update="enabled"] .octicon-file-zip:before { content: "\f013" }
body[data-octicons-update="enabled"] .octicon-file:before { content: "\f283" }
body[data-octicons-update="enabled"] .octicon-flame:before { content: "\f0d2" }
body[data-octicons-update="enabled"] .octicon-fold:before { content: "\f0cc" }
body[data-octicons-update="enabled"] .octicon-gear:before { content: "\f02f" }
body[data-octicons-update="enabled"] .octicon-gift:before { content: "\f042" }
body[data-octicons-update="enabled"] .octicon-gist-fork:before { content: "\f002" }
body[data-octicons-update="enabled"] .octicon-gist-new:before { content: "\f05d" }
body[data-octicons-update="enabled"] .octicon-gist-private:before { content: "\f06a" }
body[data-octicons-update="enabled"] .octicon-gist-secret:before { content: "\f08c" }
body[data-octicons-update="enabled"] .octicon-gist:before { content: "\f00e" }
body[data-octicons-update="enabled"] .octicon-git-branch-create:before { content: "\f020" }
body[data-octicons-update="enabled"] .octicon-git-branch-delete:before { content: "\f020" }
body[data-octicons-update="enabled"] .octicon-git-branch:before { content: "\f020" }
body[data-octicons-update="enabled"] .octicon-git-commit:before { content: "\f01f" }
body[data-octicons-update="enabled"] .octicon-git-compare:before { content: "\f0ac" }
body[data-octicons-update="enabled"] .octicon-git-fork-private:before { content: "\f06a" }
body[data-octicons-update="enabled"] .octicon-git-merge:before { content: "\f023" }
body[data-octicons-update="enabled"] .octicon-git-pull-request-abandoned:before { content: "\f009" }
body[data-octicons-update="enabled"] .octicon-git-pull-request:before { content: "\f009" }
body[data-octicons-update="enabled"] .octicon-globe:before { content: "\f0b6" }
body[data-octicons-update="enabled"] .octicon-grabber:before { content: "\f284" }
body[data-octicons-update="enabled"] .octicon-graph:before { content: "\f043" }
body[data-octicons-update="enabled"] .octicon-heart:before { content: "\2665" }
body[data-octicons-update="enabled"] .octicon-history:before { content: "\f07e" }
body[data-octicons-update="enabled"] .octicon-home:before { content: "\f08d" }
body[data-octicons-update="enabled"] .octicon-horizontal-rule:before { content: "\f070" }
body[data-octicons-update="enabled"] .octicon-hubot:before { content: "\f09d" }
body[data-octicons-update="enabled"] .octicon-inbox:before { content: "\f0cf" }
body[data-octicons-update="enabled"] .octicon-info:before { content: "\f059" }
body[data-octicons-update="enabled"] .octicon-issue-closed:before { content: "\f028" }
body[data-octicons-update="enabled"] .octicon-issue-opened:before { content: "\f026" }
body[data-octicons-update="enabled"] .octicon-issue-reopened:before { content: "\f027" }
body[data-octicons-update="enabled"] .octicon-italic:before { content: "\f285" }
body[data-octicons-update="enabled"] .octicon-jersey:before { content: "\f019" }
body[data-octicons-update="enabled"] .octicon-kebab-horizontal:before { content: "\f286" }
body[data-octicons-update="enabled"] .octicon-kebab-vertical:before { content: "\f287" }
body[data-octicons-update="enabled"] .octicon-key:before { content: "\f049" }
body[data-octicons-update="enabled"] .octicon-keyboard:before { content: "\f00d" }
body[data-octicons-update="enabled"] .octicon-law:before { content: "\f0d8" }
body[data-octicons-update="enabled"] .octicon-light-bulb:before { content: "\f000" }
body[data-octicons-update="enabled"] .octicon-link-external:before { content: "\f07f" }
body[data-octicons-update="enabled"] .octicon-link:before { content: "\f05c" }
body[data-octicons-update="enabled"] .octicon-list-ordered:before { content: "\f062" }
body[data-octicons-update="enabled"] .octicon-list-unordered:before { content: "\f061" }
body[data-octicons-update="enabled"] .octicon-location:before { content: "\f060" }
body[data-octicons-update="enabled"] .octicon-lock:before { content: "\f06a" }
body[data-octicons-update="enabled"] .octicon-log-in:before { content: "\f036" }
body[data-octicons-update="enabled"] .octicon-log-out:before { content: "\f032" }
body[data-octicons-update="enabled"] .octicon-logo-gist:before { content: "\f288" }
body[data-octicons-update="enabled"] .octicon-logo-github:before { content: "\f092" }
body[data-octicons-update="enabled"] .octicon-mail-read:before { content: "\f03c" }
body[data-octicons-update="enabled"] .octicon-mail-reply:before { content: "\f28c" }
body[data-octicons-update="enabled"] .octicon-mail:before { content: "\f03b" }
body[data-octicons-update="enabled"] .octicon-mark-github:before { content: "\f00a" }
body[data-octicons-update="enabled"] .octicon-markdown:before { content: "\f0c9" }
body[data-octicons-update="enabled"] .octicon-megaphone:before { content: "\f077" }
body[data-octicons-update="enabled"] .octicon-mention:before { content: "\f0be" }
body[data-octicons-update="enabled"] .octicon-microscope:before { content: "\f0dd" }
body[data-octicons-update="enabled"] .octicon-milestone:before { content: "\f075" }
body[data-octicons-update="enabled"] .octicon-mirror-private:before { content: "\f06a" }
body[data-octicons-update="enabled"] .octicon-mirror-public:before { content: "\f024" }
body[data-octicons-update="enabled"] .octicon-mirror:before { content: "\f024" }
body[data-octicons-update="enabled"] .octicon-mortar-board:before { content: "\f0d7" }
body[data-octicons-update="enabled"] .octicon-mute:before { content: "\f080" }
body[data-octicons-update="enabled"] .octicon-no-newline:before { content: "\f09c" }
body[data-octicons-update="enabled"] .octicon-note:before { content: "\f289" }
body[data-octicons-update="enabled"] .octicon-octoface:before { content: "\f008" }
body[data-octicons-update="enabled"] .octicon-organization:before { content: "\f037" }
body[data-octicons-update="enabled"] .octicon-organization-filled:before { content: "\f037" }
body[data-octicons-update="enabled"] .octicon-organization-outline:before { content: "\f037" }
body[data-octicons-update="enabled"] .octicon-package:before { content: "\f0c4" }
body[data-octicons-update="enabled"] .octicon-paintcan:before { content: "\f0d1" }
body[data-octicons-update="enabled"] .octicon-pencil:before { content: "\f058" }
body[data-octicons-update="enabled"] .octicon-person-add:before { content: "\f018" }
body[data-octicons-update="enabled"] .octicon-person-follow:before { content: "\f018" }
body[data-octicons-update="enabled"] .octicon-person:before { content: "\f018" }
body[data-octicons-update="enabled"] .octicon-person-filled:before { content: "\f018" }
body[data-octicons-update="enabled"] .octicon-person-outline:before { content: "\f018" }
body[data-octicons-update="enabled"] .octicon-pin:before { content: "\f041" }
body[data-octicons-update="enabled"] .octicon-plug:before { content: "\f0d4" }
body[data-octicons-update="enabled"] .octicon-plus-small:before { content: "\f28a" }
body[data-octicons-update="enabled"] .octicon-plus:before { content: "\f05d" }
body[data-octicons-update="enabled"] .octicon-primitive-dot:before { content: "\f052" }
body[data-octicons-update="enabled"] .octicon-primitive-square:before { content: "\f053" }
body[data-octicons-update="enabled"] .octicon-project:before { content: "\f28b" }
body[data-octicons-update="enabled"] .octicon-pulse:before { content: "\f085" }
body[data-octicons-update="enabled"] .octicon-question:before { content: "\f02c" }
body[data-octicons-update="enabled"] .octicon-quote:before { content: "\f063" }
body[data-octicons-update="enabled"] .octicon-radio-tower:before { content: "\f030" }
body[data-octicons-update="enabled"] .octicon-remove-close:before { content: "\f081" }
body[data-octicons-update="enabled"] .octicon-reply:before { content: "\f28c" }
body[data-octicons-update="enabled"] .octicon-repo-clone:before { content: "\f04c" }
body[data-octicons-update="enabled"] .octicon-repo-create:before { content: "\f05d" }
body[data-octicons-update="enabled"] .octicon-repo-delete:before { content: "\f001" }
body[data-octicons-update="enabled"] .octicon-repo-force-push:before { content: "\f04a" }
body[data-octicons-update="enabled"] .octicon-repo-forked:before { content: "\f002" }
body[data-octicons-update="enabled"] .octicon-repo-pull:before { content: "\f006" }
body[data-octicons-update="enabled"] .octicon-repo-push:before { content: "\f005" }
body[data-octicons-update="enabled"] .octicon-repo-sync:before { content: "\f087" }
body[data-octicons-update="enabled"] .octicon-repo:before { content: "\f001" }
body[data-octicons-update="enabled"] .octicon-report:before { content: "\f28d" }
body[data-octicons-update="enabled"] .octicon-rocket:before { content: "\f033" }
body[data-octicons-update="enabled"] .octicon-rss:before { content: "\f034" }
body[data-octicons-update="enabled"] .octicon-ruby:before { content: "\f047" }
body[data-octicons-update="enabled"] .octicon-screen-full:before { content: "\f066" }
body[data-octicons-update="enabled"] .octicon-screen-normal:before { content: "\f067" }
body[data-octicons-update="enabled"] .octicon-search-save:before { content: "\f02e" }
body[data-octicons-update="enabled"] .octicon-search:before { content: "\f02e" }
body[data-octicons-update="enabled"] .octicon-server:before { content: "\f097" }
body[data-octicons-update="enabled"] .octicon-settings:before { content: "\f07c" }
body[data-octicons-update="enabled"] .octicon-shield:before { content: "\f0e1" }
body[data-octicons-update="enabled"] .octicon-sign-in:before { content: "\f036" }
body[data-octicons-update="enabled"] .octicon-sign-out:before { content: "\f032" }
body[data-octicons-update="enabled"] .octicon-smiley:before { content: "\26b2" }
body[data-octicons-update="enabled"] .octicon-squirrel:before { content: "\f0b2" }
body[data-octicons-update="enabled"] .octicon-star-add:before { content: "\f02a" }
body[data-octicons-update="enabled"] .octicon-star-delete:before { content: "\f02a" }
body[data-octicons-update="enabled"] .octicon-star:before { content: "\f02a" }
body[data-octicons-update="enabled"] .octicon-stop:before { content: "\f08f" }
body[data-octicons-update="enabled"] .octicon-sync:before { content: "\f087" }
body[data-octicons-update="enabled"] .octicon-tag-add:before { content: "\f015" }
body[data-octicons-update="enabled"] .octicon-tag-remove:before { content: "\f015" }
body[data-octicons-update="enabled"] .octicon-tag:before { content: "\f015" }
body[data-octicons-update="enabled"] .octicon-tasklist:before { content: "\f27e" }
body[data-octicons-update="enabled"] .octicon-telescope:before { content: "\f088" }
body[data-octicons-update="enabled"] .octicon-terminal:before { content: "\f0c8" }
body[data-octicons-update="enabled"] .octicon-text-size:before { content: "\f27f" }
body[data-octicons-update="enabled"] .octicon-three-bars:before { content: "\f05e" }
body[data-octicons-update="enabled"] .octicon-thumbsdown:before { content: "\f0db" }
body[data-octicons-update="enabled"] .octicon-thumbsup:before { content: "\f0da" }
body[data-octicons-update="enabled"] .octicon-tools:before { content: "\f031" }
body[data-octicons-update="enabled"] .octicon-trashcan:before { content: "\f0d0" }
body[data-octicons-update="enabled"] .octicon-triangle-down:before { content: "\f05b" }
body[data-octicons-update="enabled"] .octicon-triangle-left:before { content: "\f044" }
body[data-octicons-update="enabled"] .octicon-triangle-right:before { content: "\f05a" }
body[data-octicons-update="enabled"] .octicon-triangle-up:before { content: "\f0aa" }
body[data-octicons-update="enabled"] .octicon-unfold:before { content: "\f039" }
body[data-octicons-update="enabled"] .octicon-unmute:before { content: "\f0ba" }
body[data-octicons-update="enabled"] .octicon-unverified:before { content: "\f280" }
body[data-octicons-update="enabled"] .octicon-verified:before { content: "\f281" }
body[data-octicons-update="enabled"] .octicon-versions:before { content: "\f064" }
body[data-octicons-update="enabled"] .octicon-watch:before { content: "\f0e0" }
body[data-octicons-update="enabled"] .octicon-x:before { content: "\f081" }
body[data-octicons-update="enabled"] .octicon-zap:before { content: "\26a1" }
body[data-octicons-update="enabled"] .octicon-error:before { content: "\26b1" }
body[data-octicons-update="enabled"] .octicon-eye-closed:before { content: "\26a3" }
body[data-octicons-update="enabled"] .octicon-fold-down:before { content: "\26a4" }
body[data-octicons-update="enabled"] .octicon-fold-up:before { content: "\26a5" }
body[data-octicons-update="enabled"] .octicon-github-action:before { content: "\26a6" }
body[data-octicons-update="enabled"] .octicon-info-outline:before { content: "\26a7" }
body[data-octicons-update="enabled"] .octicon-play:before { content: "\26a8" }
body[data-octicons-update="enabled"] .octicon-remote:before { content: "\26a9" }
body[data-octicons-update="enabled"] .octicon-request-changes:before { content: "\26aa" }
body[data-octicons-update="enabled"] .octicon-smiley-outline:before { content: "\26b2" }
body[data-octicons-update="enabled"] .octicon-warning:before { content: "\f02d" }
body[data-octicons-update="enabled"] .octicon-controls:before { content: "\26ad" }
body[data-octicons-update="enabled"] .octicon-event:before { content: "\26ae" }
body[data-octicons-update="enabled"] .octicon-record-keys:before { content: "\26af" }
body[data-octicons-update="enabled"] .octicon-Vector:before { content: "\f101" }
body[data-octicons-update="enabled"] .octicon-archive:before { content: "\f102" }
body[data-octicons-update="enabled"] .octicon-arrow-both:before { content: "\f103" }

View File

@@ -20,38 +20,22 @@
font-size: 11px;
font-weight: bold;
text-transform: uppercase;
padding-left: 20px;
overflow: hidden;
display: flex;
cursor: pointer;
}
.monaco-panel-view .panel > .panel-header {
background-image: url('tree-collapsed-light.svg');
background-position: 2px center;
background-repeat: no-repeat;
.monaco-panel-view .panel > .panel-header > .twisties {
width: 20px;
display: flex;
align-items: center;
justify-content: center;
transform-origin: center;
color: inherit;
}
.monaco-panel-view .panel > .panel-header.expanded {
background-image: url('tree-expanded-light.svg');
background-position: 2px center;
background-repeat: no-repeat;
}
.vs-dark .monaco-panel-view .panel > .panel-header {
background-image: url('tree-collapsed-dark.svg');
}
.vs-dark .monaco-panel-view .panel > .panel-header.expanded {
background-image: url('tree-expanded-dark.svg');
}
.hc-black .monaco-panel-view .panel > .panel-header {
background-image: url('tree-collapsed-hc.svg');
}
.hc-black .monaco-panel-view .panel > .panel-header.expanded {
background-image: url('tree-expanded-hc.svg');
.monaco-panel-view .panel > .panel-header.expanded > .twisties::before {
transform: rotate(90deg);
}
/* TODO: actions should be part of the panel, but they aren't yet */
@@ -79,6 +63,7 @@
display: flex;
align-items: center;
justify-content: center;
color: inherit;
}
/* Bold font style does not go well with CJK fonts */

View File

@@ -54,10 +54,10 @@ export interface IView {
}
interface ISashEvent {
sash: Sash;
start: number;
current: number;
alt: boolean;
readonly sash: Sash;
readonly start: number;
readonly current: number;
readonly alt: boolean;
}
type ViewItemSize = number | { cachedVisibleSize: number };

View File

@@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.0719 7.99999L5.71461 12.3573L6.33333 12.976L11 8.30935V7.69064L6.33333 3.02397L5.71461 3.64269L10.0719 7.99999Z" fill="#C5C5C5"/>
</svg>

Before

Width:  |  Height:  |  Size: 286 B

View File

@@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.0719 7.99999L5.71461 12.3573L6.33333 12.976L11 8.30935V7.69063L6.33333 3.02396L5.71461 3.64268L10.0719 7.99999Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 284 B

View File

@@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.0719 7.99999L5.71461 12.3573L6.33333 12.976L11 8.30935V7.69063L6.33333 3.02396L5.71461 3.64268L10.0719 7.99999Z" fill="#424242"/>
</svg>

Before

Width:  |  Height:  |  Size: 286 B

View File

@@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.97603 10.0719L12.3333 5.71461L12.9521 6.33333L8.28539 11L7.66667 11L3 6.33333L3.61872 5.71461L7.97603 10.0719Z" fill="#C5C5C5"/>
</svg>

Before

Width:  |  Height:  |  Size: 284 B

View File

@@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.97603 10.0719L12.3333 5.71461L12.9521 6.33333L8.28539 11L7.66667 11L3 6.33333L3.61872 5.71461L7.97603 10.0719Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 282 B

View File

@@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.97603 10.0719L12.3333 5.71461L12.9521 6.33333L8.28539 11L7.66667 11L3 6.33333L3.61872 5.71461L7.97603 10.0719Z" fill="#424242"/>
</svg>

Before

Width:  |  Height:  |  Size: 284 B

View File

@@ -225,18 +225,14 @@ interface Collection<T> {
class EventCollection<T> implements Collection<T> {
private disposables = new DisposableStore();
readonly onDidChange: Event<T[]>;
get elements(): T[] {
return this._elements;
}
constructor(readonly onDidChange: Event<T[]>, private _elements: T[] = []) {
onDidChange(e => this._elements = e, null, this.disposables);
}
dispose() {
this.disposables.dispose();
constructor(onDidChange: Event<T[]>, private _elements: T[] = []) {
this.onDidChange = Event.forEach(onDidChange, elements => this._elements = elements);
}
}
@@ -249,7 +245,7 @@ class TreeRenderer<T, TFilterData, TRef, TTemplateData> implements IListRenderer
private renderedNodes = new Map<ITreeNode<T, TFilterData>, IRenderData<TTemplateData>>();
private indent: number = TreeRenderer.DefaultIndent;
private _renderIndentGuides: RenderIndentGuides = RenderIndentGuides.None;
private shouldRenderIndentGuides: boolean = false;
private renderedIndentGuides = new SetMap<ITreeNode<T, TFilterData>, HTMLDivElement>();
private activeIndentNodes = new Set<ITreeNode<T, TFilterData>>();
private indentGuidesDisposable: IDisposable = Disposable.None;
@@ -279,19 +275,18 @@ class TreeRenderer<T, TFilterData, TRef, TTemplateData> implements IListRenderer
}
if (typeof options.renderIndentGuides !== 'undefined') {
const renderIndentGuides = options.renderIndentGuides;
const shouldRenderIndentGuides = options.renderIndentGuides !== RenderIndentGuides.None;
if (renderIndentGuides !== this._renderIndentGuides) {
this._renderIndentGuides = renderIndentGuides;
if (shouldRenderIndentGuides !== this.shouldRenderIndentGuides) {
this.shouldRenderIndentGuides = shouldRenderIndentGuides;
this.indentGuidesDisposable.dispose();
if (renderIndentGuides) {
if (shouldRenderIndentGuides) {
const disposables = new DisposableStore();
this.activeNodes.onDidChange(this._onDidChangeActiveNodes, this, disposables);
this.indentGuidesDisposable = disposables;
this._onDidChangeActiveNodes(this.activeNodes.elements);
} else {
this.indentGuidesDisposable.dispose();
}
}
}
@@ -370,6 +365,8 @@ class TreeRenderer<T, TFilterData, TRef, TTemplateData> implements IListRenderer
this.renderer.renderTwistie(node.element, templateData.twistie);
}
toggleClass(templateData.twistie, 'codicon', node.collapsible);
toggleClass(templateData.twistie, 'codicon-chevron-down', node.collapsible);
toggleClass(templateData.twistie, 'collapsible', node.collapsible);
toggleClass(templateData.twistie, 'collapsed', node.collapsible && node.collapsed);
@@ -384,7 +381,7 @@ class TreeRenderer<T, TFilterData, TRef, TTemplateData> implements IListRenderer
clearNode(templateData.indent);
templateData.indentGuidesDisposable.dispose();
if (this._renderIndentGuides === RenderIndentGuides.None) {
if (!this.shouldRenderIndentGuides) {
return;
}
@@ -424,7 +421,7 @@ class TreeRenderer<T, TFilterData, TRef, TTemplateData> implements IListRenderer
}
private _onDidChangeActiveNodes(nodes: ITreeNode<T, TFilterData>[]): void {
if (this._renderIndentGuides === RenderIndentGuides.None) {
if (!this.shouldRenderIndentGuides) {
return;
}
@@ -1001,7 +998,6 @@ class Trait<T> {
insertedNodes.forEach(node => dfs(node, insertedNodesVisitor));
const nodes: ITreeNode<T, any>[] = [];
let silent = true;
for (const node of this.nodes) {
const id = this.identityProvider.getId(node.element).toString();
@@ -1014,13 +1010,11 @@ class Trait<T> {
if (insertedNode) {
nodes.push(insertedNode);
} else {
silent = false;
}
}
}
this._set(nodes, silent);
this._set(nodes, true);
}
private createNodeSet(): Set<ITreeNode<T, any>> {
@@ -1228,9 +1222,8 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
const treeDelegate = new ComposedTreeDelegate<T, ITreeNode<T, TFilterData>>(delegate);
const onDidChangeCollapseStateRelay = new Relay<ICollapseStateChangeEvent<T, TFilterData>>();
const onDidChangeActiveNodes = new Emitter<ITreeNode<T, TFilterData>[]>();
const onDidChangeActiveNodes = new Relay<ITreeNode<T, TFilterData>[]>();
const activeNodes = new EventCollection(onDidChangeActiveNodes.event);
this.disposables.push(activeNodes);
this.renderers = renderers.map(r => new TreeRenderer<T, TFilterData, TRef, any>(r, () => this.model, onDidChangeCollapseStateRelay.event, activeNodes, _options));
this.disposables.push(...this.renderers);
@@ -1250,24 +1243,35 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
this.model = this.createModel(user, this.view, _options);
onDidChangeCollapseStateRelay.input = this.model.onDidChangeCollapseState;
this.model.onDidSplice(e => {
const onDidModelSplice = Event.forEach(this.model.onDidSplice, e => {
this.eventBufferer.bufferEvents(() => {
this.focus.onDidModelSplice(e);
this.selection.onDidModelSplice(e);
});
});
const set = new Set<ITreeNode<T, TFilterData>>();
// Make sure the `forEach` always runs
onDidModelSplice(() => null, null, this.disposables);
for (const node of this.focus.getNodes()) {
set.add(node);
}
// Active nodes can change when the model changes or when focus or selection change.
// We debouce it with 0 delay since these events may fire in the same stack and we only
// want to run this once. It also doesn't matter if it runs on the next tick since it's only
// a nice to have UI feature.
onDidChangeActiveNodes.input = Event.chain(Event.any<any>(onDidModelSplice, this.focus.onDidChange, this.selection.onDidChange))
.debounce(() => null, 0)
.map(() => {
const set = new Set<ITreeNode<T, TFilterData>>();
for (const node of this.selection.getNodes()) {
set.add(node);
}
for (const node of this.focus.getNodes()) {
set.add(node);
}
onDidChangeActiveNodes.fire(fromSet(set));
}, null, this.disposables);
for (const node of this.selection.getNodes()) {
set.add(node);
}
return fromSet(set);
}).event;
if (_options.keyboardSupport !== false) {
const onKeyDown = Event.chain(this.view.onKeyDown)

View File

@@ -108,7 +108,7 @@ class AsyncDataTreeRenderer<TInput, T, TFilterData, TTemplateData> implements IT
}
renderTwistie(element: IAsyncDataTreeNode<TInput, T>, twistieElement: HTMLElement): boolean {
toggleClass(twistieElement, 'loading', element.slow);
toggleClass(twistieElement, 'codicon-loading', element.slow);
return false;
}
@@ -986,7 +986,7 @@ class CompressibleAsyncDataTreeRenderer<TInput, T, TFilterData, TTemplateData> i
}
renderTwistie(element: IAsyncDataTreeNode<TInput, T>, twistieElement: HTMLElement): boolean {
toggleClass(twistieElement, 'loading', element.slow);
toggleClass(twistieElement, 'codicon-loading', element.slow);
return false;
}

View File

@@ -27,7 +27,9 @@ function noCompress<T>(element: ICompressedTreeElement<T>): ITreeElement<ICompre
return {
element: { elements, incompressible },
children: Iterator.map(Iterator.from(element.children), noCompress)
children: Iterator.map(Iterator.from(element.children), noCompress),
collapsible: element.collapsible,
collapsed: element.collapsed
};
}
@@ -58,7 +60,9 @@ export function compress<T>(element: ICompressedTreeElement<T>): ITreeElement<IC
return {
element: { elements, incompressible },
children: Iterator.map(Iterator.concat(Iterator.fromArray(children), childrenIterator), compress)
children: Iterator.map(Iterator.concat(Iterator.fromArray(children), childrenIterator), compress),
collapsible: element.collapsible,
collapsed: element.collapsed
};
}
@@ -72,10 +76,21 @@ function _decompress<T>(element: ITreeElement<ICompressedTreeNode<T>>, index = 0
}
if (index === 0 && element.element.incompressible) {
return { element: element.element.elements[index], children, incompressible: true };
return {
element: element.element.elements[index],
children,
incompressible: true,
collapsible: element.collapsible,
collapsed: element.collapsed
};
}
return { element: element.element.elements[index], children };
return {
element: element.element.elements[index],
children,
collapsible: element.collapsible,
collapsed: element.collapsed
};
}
// Exported only for test reasons, do not use directly

View File

@@ -44,6 +44,11 @@
margin-right: 6px;
flex-shrink: 0;
width: 16px;
display: flex !important;
align-items: center;
justify-content: center;
color: inherit !important;
transform: translateX(3px);
}
.monaco-tl-contents {
@@ -51,43 +56,10 @@
overflow: hidden;
}
.monaco-tl-twistie.collapsible {
background-size: 16px;
background-position: 3px 50%;
background-repeat: no-repeat;
background-image: url("tree-expanded-light.svg");
.monaco-tl-twistie.collapsed::before {
transform: rotate(-90deg);
}
.monaco-tl-twistie.collapsible.collapsed:not(.loading) {
display: inline-block;
background-image: url("tree-collapsed-light.svg");
}
.vs-dark .monaco-tl-twistie.collapsible:not(.loading) {
background-image: url("tree-expanded-dark.svg");
}
.vs-dark .monaco-tl-twistie.collapsible.collapsed:not(.loading) {
background-image: url("tree-collapsed-dark.svg");
}
.hc-black .monaco-tl-twistie.collapsible:not(.loading) {
background-image: url("tree-expanded-hc.svg");
}
.hc-black .monaco-tl-twistie.collapsible.collapsed:not(.loading) {
background-image: url("tree-collapsed-hc.svg");
}
.monaco-tl-twistie.loading {
background-image: url("loading.svg");
background-position: 0 center;
}
.vs-dark .monaco-tl-twistie.loading {
background-image: url("loading-dark.svg");
}
.hc-black .monaco-tl-twistie.loading {
background-image: url("loading-hc.svg");
.monaco-tl-twistie.codicon-loading::before {
animation: codicon-spin 1.25s linear infinite;
}

View File

@@ -271,6 +271,8 @@ export namespace Event {
filter(fn: (e: T) => boolean): IChainableEvent<T>;
reduce<R>(merge: (last: R | undefined, event: T) => R, initial?: R): IChainableEvent<R>;
latch(): IChainableEvent<T>;
debounce(merge: (last: T | undefined, event: T) => T, delay?: number, leading?: boolean, leakWarningThreshold?: number): IChainableEvent<T>;
debounce<R>(merge: (last: R | undefined, event: T) => R, delay?: number, leading?: boolean, leakWarningThreshold?: number): IChainableEvent<R>;
on(listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[] | DisposableStore): IDisposable;
once(listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[]): IDisposable;
}
@@ -299,6 +301,12 @@ export namespace Event {
return new ChainableEvent(latch(this.event));
}
debounce(merge: (last: T | undefined, event: T) => T, delay?: number, leading?: boolean, leakWarningThreshold?: number): IChainableEvent<T>;
debounce<R>(merge: (last: R | undefined, event: T) => R, delay?: number, leading?: boolean, leakWarningThreshold?: number): IChainableEvent<R>;
debounce<R>(merge: (last: R | undefined, event: T) => R, delay: number = 100, leading = false, leakWarningThreshold?: number): IChainableEvent<R> {
return new ChainableEvent(debounce(this.event, merge, delay, leading, leakWarningThreshold));
}
on(listener: (e: T) => any, thisArgs: any, disposables: IDisposable[] | DisposableStore) {
return this.event(listener, thisArgs, disposables);
}

View File

@@ -12,7 +12,7 @@ export function stringify(obj: any): string {
export function parse(text: string): any {
let data = JSON.parse(text);
data = revive(data, 0);
data = revive(data);
return data;
}
@@ -32,8 +32,7 @@ function replacer(key: string, value: any): any {
return value;
}
export function revive(obj: any, depth: number): any {
export function revive(obj: any, depth = 0): any {
if (!obj || depth > 200) {
return obj;
}

View File

@@ -207,3 +207,18 @@ export function withNullAsUndefined<T>(x: T | null): T | undefined {
export function withUndefinedAsNull<T>(x: T | undefined): T | null {
return typeof x === 'undefined' ? null : x;
}
/**
* Allows to add a first parameter to functions of a type.
*/
export type AddFirstParameterToFunctions<Target, TargetFunctionsReturnType, FirstParameter> = {
// For every property
[K in keyof Target]:
// Function: add param to function
Target[K] extends (...args: any) => TargetFunctionsReturnType ? (firstArg: FirstParameter, ...args: Parameters<Target[K]>) => ReturnType<Target[K]> :
// Else: just leave as is
Target[K]
};

View File

@@ -0,0 +1,124 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Event } from 'vs/base/common/event';
import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc';
import { revive } from 'vs/base/common/marshalling';
import { isUndefinedOrNull } from 'vs/base/common/types';
import { isUpperAsciiLetter } from 'vs/base/common/strings';
//
// Use both `createChannelReceiver` and `createChannelSender`
// for automated process <=> process communication over methods
// and events.
//
export interface IBaseChannelOptions {
/**
* Disables automatic marshalling of `URI`.
* If marshalling is disabled, `UriComponents`
* must be used instead.
*/
disableMarshalling?: boolean;
}
export interface IChannelReceiverOptions extends IBaseChannelOptions { }
export function createChannelReceiver(service: unknown, options?: IChannelReceiverOptions): IServerChannel {
const handler = service as { [key: string]: unknown };
const disableMarshalling = options && options.disableMarshalling;
// Buffer any event that should be supported by
// iterating over all property keys and finding them
const mapEventNameToEvent = new Map<string, Event<unknown>>();
for (const key in handler) {
if (propertyIsEvent(key)) {
mapEventNameToEvent.set(key, Event.buffer(handler[key] as Event<unknown>, true));
}
}
return new class implements IServerChannel {
listen<T>(_: unknown, event: string): Event<T> {
const eventImpl = mapEventNameToEvent.get(event);
if (eventImpl) {
return eventImpl as Event<T>;
}
throw new Error(`Event not found: ${event}`);
}
call(_: unknown, command: string, args?: any[]): Promise<any> {
const target = handler[command];
if (typeof target === 'function') {
// Revive unless marshalling disabled
if (!disableMarshalling && Array.isArray(args)) {
for (let i = 0; i < args.length; i++) {
args[i] = revive(args[i]);
}
}
return target.apply(handler, args);
}
throw new Error(`Method not found: ${command}`);
}
};
}
export interface IChannelSenderOptions extends IBaseChannelOptions {
/**
* If provided, will add the value of `context`
* to each method call to the target.
*/
context?: unknown;
}
export function createChannelSender<T>(channel: IChannel, options?: IChannelSenderOptions): T {
const disableMarshalling = options && options.disableMarshalling;
return new Proxy({}, {
get(_target, propKey, _receiver) {
if (typeof propKey === 'string') {
// Event
if (propertyIsEvent(propKey)) {
return channel.listen(propKey);
}
// Function
return async function (...args: any[]) {
// Add context if any
let methodArgs: any[];
if (options && !isUndefinedOrNull(options.context)) {
methodArgs = [options.context, ...args];
} else {
methodArgs = args;
}
const result = await channel.call(propKey, methodArgs);
// Revive unless marshalling disabled
if (!disableMarshalling) {
return revive(result);
}
return result;
};
}
throw new Error(`Property not found: ${String(propKey)}`);
}
}) as T;
}
function propertyIsEvent(name: string): boolean {
// Assume a property is an event if it has a form of "onSomething"
return name[0] === 'o' && name[1] === 'n' && isUpperAsciiLetter(name.charCodeAt(2));
}

View File

@@ -60,8 +60,14 @@
display: none;
}
/* Expansion */
/* Highlighted */
.monaco-tree.highlighted .monaco-tree-rows > .monaco-tree-row:not(.highlighted) {
opacity: 0.3;
}
/* {{SQL CARBON EDIT}} lower css settings
/* Expansion */
.monaco-tree .monaco-tree-rows.show-twisties > .monaco-tree-row.has-children > .content:before {
content: ' ';
position: absolute;
@@ -90,13 +96,6 @@
.monaco-tree .monaco-tree-rows > .monaco-tree-row.has-children.loading > .content:before {
background-image: url('loading.svg');
}
/* Highlighted */
.monaco-tree.highlighted .monaco-tree-rows > .monaco-tree-row:not(.highlighted) {
opacity: 0.3;
}
.vs-dark .monaco-tree .monaco-tree-rows.show-twisties > .monaco-tree-row.has-children > .content:before {
background-image: url('tree-collapsed-dark.svg');
}

View File

@@ -154,7 +154,7 @@ export class ViewItem implements IViewItem {
}
set loading(value: boolean) {
value ? this.addClass('loading') : this.removeClass('loading');
value ? this.addClass('codicon-loading') : this.removeClass('codicon-loading');
}
set draggable(value: boolean) {

View File

@@ -18,7 +18,7 @@ import { Disposable } from 'vs/base/common/lifecycle';
import { getDelayedChannel } from 'vs/base/parts/ipc/common/ipc';
import { connect as connectNet } from 'vs/base/parts/ipc/node/ipc.net';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { IWindowConfiguration, IWindowsService } from 'vs/platform/windows/common/windows';
import { IWindowConfiguration } from 'vs/platform/windows/common/windows';
import { NullTelemetryService, combinedAppender, LogAppender } from 'vs/platform/telemetry/common/telemetryUtils';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { ITelemetryServiceConfig, TelemetryService } from 'vs/platform/telemetry/common/telemetryService';
@@ -26,7 +26,6 @@ import { TelemetryAppenderClient } from 'vs/platform/telemetry/node/telemetryIpc
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProperties';
import { WindowsService } from 'vs/platform/windows/electron-browser/windowsService';
import { MainProcessService, IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService';
import { EnvironmentService } from 'vs/platform/environment/node/environmentService';
import { IssueReporterModel, IssueReporterData as IssueReporterModelData } from 'vs/code/electron-browser/issue/issueReporterModel';
@@ -40,6 +39,8 @@ import { Button } from 'vs/base/browser/ui/button/button';
import { withUndefinedAsNull } from 'vs/base/common/types';
import { SystemInfo, isRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnostics';
import { SpdLogService } from 'vs/platform/log/node/spdlogService';
import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService';
import { createChannelSender } from 'vs/base/parts/ipc/node/ipcChannelCreator';
const MAX_URL_LENGTH = 2045;
@@ -296,14 +297,15 @@ export class IssueReporter extends Disposable {
const mainProcessService = new MainProcessService(configuration.windowId);
serviceCollection.set(IMainProcessService, mainProcessService);
serviceCollection.set(IWindowsService, new WindowsService(mainProcessService));
this.environmentService = new EnvironmentService(configuration, configuration.execPath);
const logService = new SpdLogService(`issuereporter${configuration.windowId}`, this.environmentService.logsPath, getLogLevel(this.environmentService));
const loggerClient = new LoggerChannelClient(mainProcessService.getChannel('logger'));
this.logService = new FollowerLogService(loggerClient, logService);
const sharedProcess = mainProcessService.getChannel('sharedProcess').call('whenSharedProcessReady')
const sharedProcessService = createChannelSender<ISharedProcessService>(mainProcessService.getChannel('sharedProcess'));
const sharedProcess = sharedProcessService.whenSharedProcessReady()
.then(() => connectNet(this.environmentService.sharedIPCHandle, `window:${configuration.windowId}`));
const instantiationService = new InstantiationService(serviceCollection, true);

View File

@@ -14,6 +14,7 @@ bootstrap.avoidMonkeyPatchFromAppInsights();
bootstrapWindow.load(['vs/code/electron-browser/sharedProcess/sharedProcessMain'], function (sharedProcess, configuration) {
sharedProcess.startup({
machineId: configuration.machineId
machineId: configuration.machineId,
windowId: configuration.windowId
});
});
});

View File

@@ -26,10 +26,9 @@ import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProper
import { TelemetryAppenderChannel } from 'vs/platform/telemetry/node/telemetryIpc';
import { TelemetryService, ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService';
import { AppInsightsAppender } from 'vs/platform/telemetry/node/appInsightsAppender';
import { IWindowsService, ActiveWindowManager } from 'vs/platform/windows/common/windows';
import { WindowsService } from 'vs/platform/windows/electron-browser/windowsService';
import { ActiveWindowManager } from 'vs/code/node/activeWindowTracker';
import { ipcRenderer } from 'electron';
import { ILogService, LogLevel } from 'vs/platform/log/common/log';
import { ILogService, LogLevel, ILoggerService } from 'vs/platform/log/common/log';
import { LoggerChannelClient, FollowerLogService } from 'vs/platform/log/common/logIpc';
import { LocalizationsService } from 'vs/platform/localizations/node/localizations';
import { ILocalizationsService } from 'vs/platform/localizations/common/localizations';
@@ -51,14 +50,19 @@ import { IFileService } from 'vs/platform/files/common/files';
import { DiskFileSystemProvider } from 'vs/platform/files/electron-browser/diskFileSystemProvider';
import { Schemas } from 'vs/base/common/network';
import { IProductService } from 'vs/platform/product/common/productService';
import { IUserDataSyncService, IUserDataSyncStoreService, ISettingsMergeService, registerConfiguration } from 'vs/platform/userDataSync/common/userDataSync';
import { IUserDataSyncService, IUserDataSyncStoreService, ISettingsMergeService, registerConfiguration, IUserDataSyncLogService } from 'vs/platform/userDataSync/common/userDataSync';
import { UserDataSyncService, UserDataAutoSync } from 'vs/platform/userDataSync/common/userDataSyncService';
import { UserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSyncStoreService';
import { UserDataSyncChannel } from 'vs/platform/userDataSync/common/userDataSyncIpc';
import { SettingsMergeChannelClient } from 'vs/platform/userDataSync/common/settingsSyncIpc';
import { createChannelSender } from 'vs/base/parts/ipc/node/ipcChannelCreator';
import { IElectronService } from 'vs/platform/electron/node/electron';
import { LoggerService } from 'vs/platform/log/node/loggerService';
import { UserDataSyncLogService } from 'vs/platform/userDataSync/common/userDataSyncLog';
export interface ISharedProcessConfiguration {
readonly machineId: string;
readonly windowId: number;
}
export function startup(configuration: ISharedProcessConfiguration) {
@@ -115,12 +119,16 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat
services.set(ILogService, logService);
services.set(IConfigurationService, configurationService);
services.set(IRequestService, new SyncDescriptor(RequestService));
services.set(ILoggerService, new SyncDescriptor(LoggerService));
const mainProcessService = new MainProcessService(server, mainRouter);
services.set(IMainProcessService, mainProcessService);
const windowsService = new WindowsService(mainProcessService);
services.set(IWindowsService, windowsService);
const electronService = createChannelSender<IElectronService>(mainProcessService.getChannel('electron'), { context: configuration.windowId });
services.set(IElectronService, electronService);
const activeWindowManager = new ActiveWindowManager(electronService);
const activeWindowRouter = new StaticRouter(ctx => activeWindowManager.getActiveClientId().then(id => ctx === id));
// Files
const fileService = new FileService(logService);
@@ -169,9 +177,7 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat
services.set(ILocalizationsService, new SyncDescriptor(LocalizationsService));
services.set(IDiagnosticsService, new SyncDescriptor(DiagnosticsService));
// User Data Sync Contributions
const activeWindowManager = new ActiveWindowManager(windowsService);
const activeWindowRouter = new StaticRouter(ctx => activeWindowManager.getActiveClientId().then(id => ctx === id));
services.set(IUserDataSyncLogService, new SyncDescriptor(UserDataSyncLogService));
const settingsMergeChannel = server.getChannel('settingsMerge', activeWindowRouter);
services.set(ISettingsMergeService, new SettingsMergeChannelClient(settingsMergeChannel));
services.set(IUserDataSyncStoreService, new SyncDescriptor(UserDataSyncStoreService));

View File

@@ -6,9 +6,8 @@
import { app, ipcMain as ipc, systemPreferences, shell, Event, contentTracing, protocol, powerMonitor, IpcMainEvent } from 'electron';
import { IProcessEnvironment, isWindows, isMacintosh } from 'vs/base/common/platform';
import { WindowsManager } from 'vs/code/electron-main/windows';
import { IWindowsService, OpenContext, ActiveWindowManager, IURIToOpen } from 'vs/platform/windows/common/windows';
import { WindowsChannel } from 'vs/platform/windows/common/windowsIpc';
import { LegacyWindowsMainService } from 'vs/platform/windows/electron-main/legacyWindowsMainService';
import { OpenContext, IWindowOpenable } from 'vs/platform/windows/common/windows';
import { ActiveWindowManager } from 'vs/code/node/activeWindowTracker';
import { ILifecycleMainService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMainService';
import { getShellEnvironment } from 'vs/code/node/shellEnv';
import { IUpdateService } from 'vs/platform/update/common/update';
@@ -22,7 +21,7 @@ import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiati
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { ILogService } from 'vs/platform/log/common/log';
import { IStateService } from 'vs/platform/state/common/state';
import { IStateService } from 'vs/platform/state/node/state';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IURLService } from 'vs/platform/url/common/url';
@@ -33,7 +32,7 @@ import { TelemetryAppenderClient } from 'vs/platform/telemetry/node/telemetryIpc
import { TelemetryService, ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService';
import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProperties';
import { getDelayedChannel, StaticRouter } from 'vs/base/parts/ipc/common/ipc';
import { SimpleServiceProxyChannel } from 'vs/platform/ipc/node/simpleIpcProxy';
import { createChannelReceiver } from 'vs/base/parts/ipc/node/ipcChannelCreator';
import product from 'vs/platform/product/common/product';
import { ProxyAuthHandler } from 'vs/code/electron-main/auth';
import { Disposable } from 'vs/base/common/lifecycle';
@@ -65,7 +64,7 @@ import { GlobalStorageDatabaseChannel } from 'vs/platform/storage/node/storageIp
import { startsWith } from 'vs/base/common/strings';
import { BackupMainService } from 'vs/platform/backup/electron-main/backupMainService';
import { IBackupMainService } from 'vs/platform/backup/electron-main/backup';
import { HistoryMainService, IHistoryMainService } from 'vs/platform/history/electron-main/historyMainService';
import { WorkspacesHistoryMainService, IWorkspacesHistoryMainService } from 'vs/platform/workspaces/electron-main/workspacesHistoryMainService';
import { URLService } from 'vs/platform/url/node/urlService';
import { WorkspacesMainService, IWorkspacesMainService } from 'vs/platform/workspaces/electron-main/workspacesMainService';
import { statSync } from 'fs';
@@ -78,6 +77,7 @@ import { ExtensionHostDebugBroadcastChannel } from 'vs/platform/debug/common/ext
import { IElectronService } from 'vs/platform/electron/node/electron';
import { ElectronMainService } from 'vs/platform/electron/electron-main/electronMainService';
import { ISharedProcessMainService, SharedProcessMainService } from 'vs/platform/ipc/electron-main/sharedProcessMainService';
import { assign } from 'vs/base/common/objects';
export class CodeApplication extends Disposable {
@@ -213,14 +213,14 @@ export class CodeApplication extends Disposable {
});
});
let macOpenFileURIs: IURIToOpen[] = [];
let macOpenFileURIs: IWindowOpenable[] = [];
let runningTimeout: NodeJS.Timeout | null = null;
app.on('open-file', (event: Event, path: string) => {
this.logService.trace('App#open-file: ', path);
event.preventDefault();
// Keep in array because more might come!
macOpenFileURIs.push(this.getURIToOpenFromPathSync(path));
macOpenFileURIs.push(this.getWindowOpenableFromPathSync(path));
// Clear previous handler if any
if (runningTimeout !== null) {
@@ -450,7 +450,6 @@ export class CodeApplication extends Disposable {
services.set(IWindowsMainService, new SyncDescriptor(WindowsManager, [machineId, this.userEnv]));
services.set(ISharedProcessMainService, new SyncDescriptor(SharedProcessMainService, [sharedProcess]));
services.set(IWindowsService, new SyncDescriptor(LegacyWindowsMainService));
services.set(ILaunchMainService, new SyncDescriptor(LaunchMainService));
const diagnosticsChannel = getDelayedChannel(sharedProcessClient.then(client => client.getChannel('diagnostics')));
@@ -467,7 +466,7 @@ export class CodeApplication extends Disposable {
const backupMainService = new BackupMainService(this.environmentService, this.configurationService, this.logService);
services.set(IBackupMainService, backupMainService);
services.set(IHistoryMainService, new SyncDescriptor(HistoryMainService));
services.set(IWorkspacesHistoryMainService, new SyncDescriptor(WorkspacesHistoryMainService));
services.set(IURLService, new SyncDescriptor(URLService));
services.set(IWorkspacesMainService, new SyncDescriptor(WorkspacesMainService));
@@ -540,28 +539,24 @@ export class CodeApplication extends Disposable {
electronIpcServer.registerChannel('update', updateChannel);
const issueService = accessor.get(IIssueService);
const issueChannel = new SimpleServiceProxyChannel(issueService);
const issueChannel = createChannelReceiver(issueService);
electronIpcServer.registerChannel('issue', issueChannel);
const electronService = accessor.get(IElectronService);
const electronChannel = new SimpleServiceProxyChannel(electronService);
const electronChannel = createChannelReceiver(electronService);
electronIpcServer.registerChannel('electron', electronChannel);
sharedProcessClient.then(client => client.registerChannel('electron', electronChannel));
const sharedProcessMainService = accessor.get(ISharedProcessMainService);
const sharedProcessChannel = new SimpleServiceProxyChannel(sharedProcessMainService);
const sharedProcessChannel = createChannelReceiver(sharedProcessMainService);
electronIpcServer.registerChannel('sharedProcess', sharedProcessChannel);
const workspacesMainService = accessor.get(IWorkspacesMainService);
const workspacesChannel = new WorkspacesChannel(workspacesMainService, accessor.get(IWindowsMainService));
electronIpcServer.registerChannel('workspaces', workspacesChannel);
const windowsService = accessor.get(IWindowsService);
const windowsChannel = new WindowsChannel(windowsService);
electronIpcServer.registerChannel('windows', windowsChannel);
sharedProcessClient.then(client => client.registerChannel('windows', windowsChannel));
const menubarService = accessor.get(IMenubarService);
const menubarChannel = new SimpleServiceProxyChannel(menubarService);
const menubarChannel = createChannelReceiver(menubarService);
electronIpcServer.registerChannel('menubar', menubarChannel);
const urlService = accessor.get(IURLService);
@@ -585,8 +580,27 @@ export class CodeApplication extends Disposable {
// Propagate to clients
const windowsMainService = this.windowsMainService = accessor.get(IWindowsMainService);
// Create a URL handler to open file URIs in the active window
const environmentService = accessor.get(IEnvironmentService);
urlService.registerHandler({
async handleURL(uri: URI): Promise<boolean> {
// Catch file URLs
if (uri.authority === Schemas.file && !!uri.path) {
const cli = assign(Object.create(null), environmentService.args);
const urisToOpen = [{ fileUri: uri }];
windowsMainService.open({ context: OpenContext.API, cli, urisToOpen, gotoLineMode: true });
return true;
}
return false;
}
});
// Create a URL handler which forwards to the last active window
const activeWindowManager = new ActiveWindowManager(windowsService);
const activeWindowManager = new ActiveWindowManager(electronService);
const activeWindowRouter = new StaticRouter(ctx => activeWindowManager.getActiveClientId().then(id => ctx === id));
const urlHandlerRouter = new URLHandlerRouter(activeWindowRouter);
const urlHandlerChannel = electronIpcServer.getChannel('urlHandler', urlHandlerRouter);
@@ -595,8 +609,6 @@ export class CodeApplication extends Disposable {
// On Mac, Code can be running without any open windows, so we must create a window to handle urls,
// if there is none
if (isMacintosh) {
const environmentService = accessor.get(IEnvironmentService);
urlService.registerHandler({
async handleURL(uri: URI): Promise<boolean> {
if (windowsMainService.getWindowCount() === 0) {
@@ -649,7 +661,7 @@ export class CodeApplication extends Disposable {
return windowsMainService.open({
context: OpenContext.DOCK,
cli: args,
urisToOpen: macOpenFiles.map(file => this.getURIToOpenFromPathSync(file)),
urisToOpen: macOpenFiles.map(file => this.getWindowOpenableFromPathSync(file)),
noRecentEntry,
waitMarkerFileURI,
gotoLineMode: false,
@@ -670,7 +682,7 @@ export class CodeApplication extends Disposable {
});
}
private getURIToOpenFromPathSync(path: string): IURIToOpen {
private getWindowOpenableFromPathSync(path: string): IWindowOpenable {
try {
const fileStat = statSync(path);
if (fileStat.isDirectory()) {

View File

@@ -21,7 +21,7 @@ import { ServiceCollection } from 'vs/platform/instantiation/common/serviceColle
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { ILogService, ConsoleLogMainService, MultiplexLogService, getLogLevel } from 'vs/platform/log/common/log';
import { StateService } from 'vs/platform/state/node/stateService';
import { IStateService } from 'vs/platform/state/common/state';
import { IStateService } from 'vs/platform/state/node/state';
import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment';
import { EnvironmentService, xdgRuntimeDir } from 'vs/platform/environment/node/environmentService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';

View File

@@ -45,7 +45,8 @@ export class SharedProcess implements ISharedProcess {
appRoot: this.environmentService.appRoot,
machineId: this.machineId,
nodeCachedDataDir: this.environmentService.nodeCachedDataDir,
userEnv: this.userEnv
userEnv: this.userEnv,
windowId: this.window.id
});
const url = `${require.toUrl('vs/code/electron-browser/sharedProcess/sharedProcess.html')}?config=${encodeURIComponent(JSON.stringify(config))}`;

View File

@@ -11,23 +11,24 @@ import { assign, mixin } from 'vs/base/common/objects';
import { IBackupMainService } from 'vs/platform/backup/electron-main/backup';
import { IEmptyWindowBackupInfo } from 'vs/platform/backup/node/backup';
import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment';
import { IStateService } from 'vs/platform/state/common/state';
import { IStateService } from 'vs/platform/state/node/state';
import { CodeWindow, defaultWindowState } from 'vs/code/electron-main/window';
import { ipcMain as ipc, screen, BrowserWindow, dialog, systemPreferences, FileFilter, shell, MessageBoxReturnValue, MessageBoxOptions, SaveDialogOptions, SaveDialogReturnValue, OpenDialogOptions, OpenDialogReturnValue, Display } from 'electron';
import { parseLineAndColumnAware } from 'vs/code/node/paths';
import { ILifecycleMainService, UnloadReason, LifecycleMainService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMainService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ILogService } from 'vs/platform/log/common/log';
import { IWindowSettings, OpenContext, IPath, IWindowConfiguration, INativeOpenDialogOptions, IPathsToWaitFor, IEnterWorkspaceResult, IURIToOpen, isFileToOpen, isWorkspaceToOpen, isFolderToOpen } from 'vs/platform/windows/common/windows';
import { IWindowSettings, OpenContext, IPath, IWindowConfiguration, IPathsToWaitFor, isFileToOpen, isWorkspaceToOpen, isFolderToOpen, IWindowOpenable, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows';
import { INativeOpenDialogOptions } from 'vs/platform/dialogs/node/dialogs';
import { getLastActiveWindow, findBestWindowOrFolderForFile, findWindowOnWorkspace, findWindowOnExtensionDevelopmentPath, findWindowOnWorkspaceOrFolderUri } from 'vs/code/node/windowsFinder';
import { Event as CommonEvent, Emitter } from 'vs/base/common/event';
import product from 'vs/platform/product/common/product';
import { ITelemetryService, ITelemetryData } from 'vs/platform/telemetry/common/telemetry';
import { IWindowsMainService, IOpenConfiguration, IWindowsCountChangedEvent, ICodeWindow, IWindowState as ISingleWindowState, WindowMode } from 'vs/platform/windows/electron-main/windows';
import { IRecent } from 'vs/platform/history/common/history';
import { IHistoryMainService } from 'vs/platform/history/electron-main/historyMainService';
import { IRecent } from 'vs/platform/workspaces/common/workspacesHistory';
import { IWorkspacesHistoryMainService } from 'vs/platform/workspaces/electron-main/workspacesHistoryMainService';
import { IProcessEnvironment, isMacintosh, isWindows } from 'vs/base/common/platform';
import { IWorkspaceIdentifier, WORKSPACE_FILTER, isSingleFolderWorkspaceIdentifier, hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces';
import { IWorkspaceIdentifier, WORKSPACE_FILTER, isSingleFolderWorkspaceIdentifier, hasWorkspaceFileExtension, IEnterWorkspaceResult } from 'vs/platform/workspaces/common/workspaces';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { mnemonicButtonLabel } from 'vs/base/common/labels';
import { Schemas } from 'vs/base/common/network';
@@ -192,7 +193,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
@IBackupMainService private readonly backupMainService: IBackupMainService,
@ITelemetryService private readonly telemetryService: ITelemetryService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IHistoryMainService private readonly historyMainService: IHistoryMainService,
@IWorkspacesHistoryMainService private readonly workspacesHistoryMainService: IWorkspacesHistoryMainService,
@IWorkspacesMainService private readonly workspacesMainService: IWorkspacesMainService,
@IInstantiationService private readonly instantiationService: IInstantiationService
) {
@@ -508,7 +509,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
recents.push({ label: pathToOpen.label, fileUri: pathToOpen.fileUri });
}
}
this.historyMainService.addRecentlyOpened(recents);
this.workspacesHistoryMainService.addRecentlyOpened(recents);
}
// If we got started with --wait from the CLI, we need to signal to the outside when the window
@@ -1018,13 +1019,14 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
return undefined;
}
private parseUri(uriToOpen: IURIToOpen, options: IPathParseOptions = {}): IPathToOpen | undefined {
if (!uriToOpen) {
private parseUri(toOpen: IWindowOpenable, options: IPathParseOptions = {}): IPathToOpen | undefined {
if (!toOpen) {
return undefined;
}
let uri = resourceFromURIToOpen(uriToOpen);
let uri = resourceFromURIToOpen(toOpen);
if (uri.scheme === Schemas.file) {
return this.parsePath(uri.fsPath, options, isFileToOpen(uriToOpen));
return this.parsePath(uri.fsPath, options, isFileToOpen(toOpen));
}
// open remote if either specified in the cli or if it's a remotehost URI
@@ -1038,7 +1040,8 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
uri = removeTrailingPathSeparator(uri);
}
if (isFileToOpen(uriToOpen)) {
// File
if (isFileToOpen(toOpen)) {
if (options.gotoLineMode) {
const parsedPath = parseLineAndColumnAware(uri.path);
return {
@@ -1052,12 +1055,17 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
fileUri: uri,
remoteAuthority
};
} else if (isWorkspaceToOpen(uriToOpen)) {
}
// Workspace
else if (isWorkspaceToOpen(toOpen)) {
return {
workspace: getWorkspaceIdentifier(uri),
remoteAuthority
};
}
// Folder
return {
folderUri: uri,
remoteAuthority
@@ -1121,7 +1129,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
}
} catch (error) {
const fileUri = URI.file(candidate);
this.historyMainService.removeFromRecentlyOpened([fileUri]); // since file does not seem to exist anymore, remove from recent
this.workspacesHistoryMainService.removeFromRecentlyOpened([fileUri]); // since file does not seem to exist anymore, remove from recent
// assume this is a file that does not yet exist
if (options && options.ignoreFileNotFound) {
@@ -1582,7 +1590,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
private doEnterWorkspace(win: ICodeWindow, result: IEnterWorkspaceResult): IEnterWorkspaceResult {
// Mark as recently opened
this.historyMainService.addRecentlyOpened([{ workspace: result.workspace }]);
this.workspacesHistoryMainService.addRecentlyOpened([{ workspace: result.workspace }]);
// Trigger Eevent to indicate load of workspace into window
this._onWindowReady.fire(win);
@@ -1610,7 +1618,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
return getLastActiveWindow(WindowsManager.WINDOWS.filter(window => window.remoteAuthority === remoteAuthority));
}
openEmptyWindow(context: OpenContext, options?: { reuse?: boolean, remoteAuthority?: string }): ICodeWindow[] {
openEmptyWindow(context: OpenContext, options?: IOpenEmptyWindowOptions): ICodeWindow[] {
let cli = this.environmentService.args;
const remote = options && options.remoteAuthority;
if (cli && (cli.remote !== remote)) {
@@ -2098,14 +2106,14 @@ class WorkspacesManager {
}
}
function resourceFromURIToOpen(u: IURIToOpen): URI {
if (isWorkspaceToOpen(u)) {
return u.workspaceUri;
function resourceFromURIToOpen(openable: IWindowOpenable): URI {
if (isWorkspaceToOpen(openable)) {
return openable.workspaceUri;
}
if (isFolderToOpen(u)) {
return u.folderUri;
if (isFolderToOpen(openable)) {
return openable.folderUri;
}
return u.fileUri;
return openable.fileUri;
}

View File

@@ -0,0 +1,51 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Event } from 'vs/base/common/event';
import { DisposableStore, Disposable } from 'vs/base/common/lifecycle';
import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async';
import { IElectronService } from 'vs/platform/electron/node/electron';
export class ActiveWindowManager extends Disposable {
private readonly disposables = this._register(new DisposableStore());
private firstActiveWindowIdPromise: CancelablePromise<number | undefined> | undefined;
private activeWindowId: number | undefined;
constructor(@IElectronService electronService: IElectronService) {
super();
// remember last active window id upon events
const onActiveWindowChange = Event.latch(Event.any(electronService.onWindowOpen, electronService.onWindowFocus));
onActiveWindowChange(this.setActiveWindow, this, this.disposables);
// resolve current active window
this.firstActiveWindowIdPromise = createCancelablePromise(() => electronService.getActiveWindowId());
(async () => {
try {
const windowId = await this.firstActiveWindowIdPromise;
this.activeWindowId = (typeof this.activeWindowId === 'number') ? this.activeWindowId : windowId;
} finally {
this.firstActiveWindowIdPromise = undefined;
}
})();
}
private setActiveWindow(windowId: number | undefined) {
if (this.firstActiveWindowIdPromise) {
this.firstActiveWindowIdPromise.cancel();
this.firstActiveWindowIdPromise = undefined;
}
this.activeWindowId = windowId;
}
async getActiveClientId(): Promise<string | undefined> {
const id = this.firstActiveWindowIdPromise ? (await this.firstActiveWindowIdPromise) : this.activeWindowId;
return `window:${id}`;
}
}

View File

@@ -28,7 +28,7 @@ import { ConfigurationService } from 'vs/platform/configuration/node/configurati
import { AppInsightsAppender } from 'vs/platform/telemetry/node/appInsightsAppender';
import { mkdirp, writeFile } from 'vs/base/node/pfs';
import { getBaseLabel } from 'vs/base/common/labels';
import { IStateService } from 'vs/platform/state/common/state';
import { IStateService } from 'vs/platform/state/node/state';
import { StateService } from 'vs/platform/state/node/stateService';
import { ILogService, getLogLevel } from 'vs/platform/log/common/log';
import { isPromiseCanceledError } from 'vs/base/common/errors';

View File

@@ -14,4 +14,7 @@
*/
.monaco-editor .margin-view-overlays .cgmr {
position: absolute;
display: flex;
align-items: center;
justify-content: center;
}

View File

@@ -1405,7 +1405,7 @@ export interface IWebviewPanelOptions {
/**
* @internal
*/
export const enum WebviewEditorState {
export const enum WebviewContentState {
Readonly = 1,
Unchanged = 2,
Dirty = 3,

View File

@@ -95,7 +95,7 @@ export class MarkerDecorationsService extends Disposable implements IMarkerDecor
return markerDecorations ? markerDecorations.getMarkers() : [];
}
private _handleMarkerChange(changedResources: URI[]): void {
private _handleMarkerChange(changedResources: readonly URI[]): void {
changedResources.forEach((resource) => {
const markerDecorations = this._markerDecorations.get(MODEL_ID(resource));
if (markerDecorations) {

View File

@@ -18,6 +18,7 @@ import { IEditorProgressService } from 'vs/platform/progress/common/progress';
import { getCodeActions, CodeActionSet } from './codeAction';
import { CodeActionTrigger } from './codeActionTrigger';
import { EditorOption } from 'vs/editor/common/config/editorOptions';
import { isEqual } from 'vs/base/common/resources';
export const SUPPORTED_CODE_ACTIONS = new RawContextKey<string>('supportedCodeAction', '');
@@ -47,13 +48,13 @@ class CodeActionOracle extends Disposable {
return this._createEventAndSignalChange(trigger, selection);
}
private _onMarkerChanges(resources: URI[]): void {
private _onMarkerChanges(resources: readonly URI[]): void {
const model = this._editor.getModel();
if (!model) {
return;
}
if (resources.some(resource => resource.toString() === model.uri.toString())) {
if (resources.some(resource => isEqual(resource, model.uri))) {
this._autoTriggerTimer.cancelAndSet(() => {
this.trigger({ type: 'auto' });
}, this._delay);

View File

@@ -3,7 +3,8 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor .margin-view-overlays .codicon {
.monaco-editor .margin-view-overlays .codicon-chevron-right,
.monaco-editor .margin-view-overlays .codicon-chevron-down {
cursor: pointer;
opacity: 0;
transition: opacity 0.5s;

View File

@@ -29,6 +29,7 @@ import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService
import { CancellationToken } from 'vs/base/common/cancellation';
import { Disposable } from 'vs/base/common/lifecycle';
import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async';
import { withNullAsUndefined } from 'vs/base/common/types';
class RenameSkeleton {
@@ -45,15 +46,15 @@ class RenameSkeleton {
return this._providers.length > 0;
}
async resolveRenameLocation(token: CancellationToken): Promise<RenameLocation & Rejection | null | undefined> {
async resolveRenameLocation(token: CancellationToken): Promise<RenameLocation & Rejection | undefined> {
const firstProvider = this._providers[0];
if (!firstProvider) {
return undefined;
}
let res: RenameLocation & Rejection | null | undefined;
let res: RenameLocation & Rejection | undefined;
if (firstProvider.resolveRenameLocation) {
res = await firstProvider.resolveRenameLocation(this.model, this.position, token);
res = withNullAsUndefined(await firstProvider.resolveRenameLocation(this.model, this.position, token));
}
if (!res) {
@@ -160,7 +161,7 @@ class RenameController extends Disposable implements IEditorContribution {
return undefined;
}
let loc: RenameLocation & Rejection | null | undefined;
let loc: RenameLocation & Rejection | undefined;
try {
const resolveLocationOperation = skeleton.resolveRenameLocation(token);
this._progressService.showWhile(resolveLocationOperation, 250);
@@ -254,6 +255,8 @@ class RenameController extends Disposable implements IEditorContribution {
if (this._activeRename) {
this._activeRename.operation.cancel();
this._activeRename = undefined;
this.cancelRenameInput();
}
}
}

View File

@@ -11,7 +11,7 @@ import { Event, Emitter } from 'vs/base/common/event';
import { onUnexpectedError } from 'vs/base/common/errors';
import { IDisposable, dispose, toDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle';
import { addClass, append, $, hide, removeClass, show, toggleClass, getDomNodePagePosition, hasClass, addDisposableListener, addStandardDisposableListener } from 'vs/base/browser/dom';
import { IListVirtualDelegate, IListEvent, IListRenderer, IListMouseEvent } from 'vs/base/browser/ui/list/list';
import { IListVirtualDelegate, IListEvent, IListRenderer, IListMouseEvent, IListGestureEvent } from 'vs/base/browser/ui/list/list';
import { List } from 'vs/base/browser/ui/list/listWidget';
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
@@ -524,7 +524,8 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
}));
this.toDispose.add(themeService.onThemeChange(t => this.onThemeChange(t)));
this.toDispose.add(editor.onDidLayoutChange(() => this.onEditorLayoutChange()));
this.toDispose.add(this.list.onMouseDown(e => this.onListMouseDown(e)));
this.toDispose.add(this.list.onMouseDown(e => this.onListMouseDownOrTap(e)));
this.toDispose.add(this.list.onTap(e => this.onListMouseDownOrTap(e)));
this.toDispose.add(this.list.onSelectionChange(e => this.onListSelection(e)));
this.toDispose.add(this.list.onFocusChange(e => this.onListFocus(e)));
this.toDispose.add(this.editor.onDidChangeCursorSelection(() => this.onCursorSelectionChanged()));
@@ -572,7 +573,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
}
}
private onListMouseDown(e: IListMouseEvent<CompletionItem>): void {
private onListMouseDownOrTap(e: IListMouseEvent<CompletionItem> | IListGestureEvent<CompletionItem>): void {
if (typeof e.element === 'undefined' || typeof e.index === 'undefined') {
return;
}

View File

@@ -63,6 +63,7 @@ export interface PerformanceInfo {
export interface IWorkspaceInformation extends IWorkspace {
telemetryId: string | undefined;
rendererSessionId: string;
}
export function isRemoteDiagnosticError(x: any): x is IRemoteDiagnosticError {

View File

@@ -539,21 +539,46 @@ export class DiagnosticsService implements IDiagnosticsService {
collectWorkspaceStats(folder, ['node_modules', '.git']).then(stats => {
type WorkspaceStatsClassification = {
'workspace.id': { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
fileTypes: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true };
configTypes: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true };
launchConfigs: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true };
rendererSessionId: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
};
type WorkspaceStatsEvent = {
'workspace.id': string | undefined;
fileTypes: WorkspaceStatItem[];
configTypes: WorkspaceStatItem[];
launchConfigs: WorkspaceStatItem[];
rendererSessionId: string;
};
this.telemetryService.publicLog2<WorkspaceStatsEvent, WorkspaceStatsClassification>('workspace.stats', {
'workspace.id': workspace.telemetryId,
fileTypes: stats.fileTypes,
configTypes: stats.configFiles,
launchConfigs: stats.launchConfigFiles
rendererSessionId: workspace.rendererSessionId
});
type WorkspaceStatsFileClassification = {
rendererSessionId: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
name: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true };
count: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true };
};
type WorkspaceStatsFileEvent = {
rendererSessionId: string;
name: string;
count: number;
};
stats.fileTypes.forEach(e => {
this.telemetryService.publicLog2<WorkspaceStatsFileEvent, WorkspaceStatsFileClassification>('workspace.stats.file', {
rendererSessionId: workspace.rendererSessionId,
name: e.name,
count: e.count
});
});
stats.launchConfigFiles.forEach(e => {
this.telemetryService.publicLog2<WorkspaceStatsFileEvent, WorkspaceStatsFileClassification>('workspace.stats.launchConfigFile', {
rendererSessionId: workspace.rendererSessionId,
name: e.name,
count: e.count
});
});
stats.configFiles.forEach(e => {
this.telemetryService.publicLog2<WorkspaceStatsFileEvent, WorkspaceStatsFileClassification>('workspace.stats.configFiles', {
rendererSessionId: workspace.rendererSessionId,
name: e.name,
count: e.count
});
});
}).catch(_ => {
// Report nothing if collecting metadata fails.

View File

@@ -8,9 +8,13 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
import { URI } from 'vs/base/common/uri';
import { basename } from 'vs/base/common/resources';
import { localize } from 'vs/nls';
import { FileFilter } from 'vs/platform/windows/common/windows';
import { ITelemetryData } from 'vs/platform/telemetry/common/telemetry';
export interface FileFilter {
extensions: string[];
name: string;
}
export type DialogType = 'none' | 'info' | 'error' | 'question' | 'warning';
export interface IConfirmation {
@@ -90,7 +94,7 @@ export interface ISaveDialogOptions {
* Specifies a list of schemas for the file systems the user can save to. If not specified, uses the schema of the defaultURI or, if also not specified,
* the schema of the current window.
*/
availableFileSystems?: string[];
availableFileSystems?: readonly string[];
}
export interface IOpenDialogOptions {
@@ -134,7 +138,7 @@ export interface IOpenDialogOptions {
* Specifies a list of schemas for the file systems the user can load from. If not specified, uses the schema of the defaultURI or, if also not available,
* the schema of the current window.
*/
availableFileSystems?: string[];
availableFileSystems?: readonly string[];
}

View File

@@ -0,0 +1,15 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ITelemetryData } from 'vs/platform/telemetry/common/telemetry';
export interface INativeOpenDialogOptions {
forceNewWindow?: boolean;
defaultPath?: string;
telemetryEventName?: string;
telemetryExtraData?: ITelemetryData;
}

View File

@@ -8,7 +8,6 @@ import { WindowDriverChannel, WindowDriverRegistryChannelClient } from 'vs/platf
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService';
import * as electron from 'electron';
import { IWindowService } from 'vs/platform/windows/common/windows';
import { timeout } from 'vs/base/common/async';
import { BaseWindowDriver } from 'vs/platform/driver/browser/baseDriver';
import { IElectronService } from 'vs/platform/electron/node/electron';
@@ -46,10 +45,9 @@ class WindowDriver extends BaseWindowDriver {
}
}
export async function registerWindowDriver(accessor: ServicesAccessor): Promise<IDisposable> {
export async function registerWindowDriver(accessor: ServicesAccessor, windowId: number): Promise<IDisposable> {
const instantiationService = accessor.get(IInstantiationService);
const mainProcessService = accessor.get(IMainProcessService);
const windowService = accessor.get(IWindowService);
const windowDriver = instantiationService.createInstance(WindowDriver);
const windowDriverChannel = new WindowDriverChannel(windowDriver);
@@ -58,12 +56,12 @@ export async function registerWindowDriver(accessor: ServicesAccessor): Promise<
const windowDriverRegistryChannel = mainProcessService.getChannel('windowDriverRegistry');
const windowDriverRegistry = new WindowDriverRegistryChannelClient(windowDriverRegistryChannel);
await windowDriverRegistry.registerWindowDriver(windowService.windowId);
await windowDriverRegistry.registerWindowDriver(windowId);
// const options = await windowDriverRegistry.registerWindowDriver(windowId);
// if (options.verbose) {
// windowDriver.openDevTools();
// }
return toDisposable(() => windowDriverRegistry.reloadWindowDriver(windowService.windowId));
return toDisposable(() => windowDriverRegistry.reloadWindowDriver(windowId));
}

View File

@@ -3,35 +3,97 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Event } from 'vs/base/common/event';
import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows';
import { MessageBoxOptions, MessageBoxReturnValue, shell, OpenDevToolsOptions, SaveDialogOptions, SaveDialogReturnValue, OpenDialogOptions, OpenDialogReturnValue, CrashReporterStartOptions, crashReporter, Menu } from 'electron';
import { MessageBoxOptions, MessageBoxReturnValue, shell, OpenDevToolsOptions, SaveDialogOptions, SaveDialogReturnValue, OpenDialogOptions, OpenDialogReturnValue, CrashReporterStartOptions, crashReporter, Menu, BrowserWindow, app } from 'electron';
import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService';
import { OpenContext, INativeOpenDialogOptions } from 'vs/platform/windows/common/windows';
import { isMacintosh } from 'vs/base/common/platform';
import { IOpenedWindow, OpenContext, IWindowOpenable, IOpenInWindowOptions, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows';
import { INativeOpenDialogOptions } from 'vs/platform/dialogs/node/dialogs';
import { isMacintosh, IProcessEnvironment } from 'vs/base/common/platform';
import { IElectronService } from 'vs/platform/electron/node/electron';
import { ISerializableCommandAction } from 'vs/platform/actions/common/actions';
import { AddContextToFunctions } from 'vs/platform/ipc/node/simpleIpcProxy';
import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment';
import { AddFirstParameterToFunctions } from 'vs/base/common/types';
import { IWorkspacesHistoryMainService } from 'vs/platform/workspaces/electron-main/workspacesHistoryMainService';
import { IRecentlyOpened, IRecent } from 'vs/platform/workspaces/common/workspacesHistory';
import { URI } from 'vs/base/common/uri';
export class ElectronMainService implements AddContextToFunctions<IElectronService, number> {
export class ElectronMainService implements AddFirstParameterToFunctions<IElectronService, Promise<any> /* only methods, not events */, number /* window ID */> {
_serviceBrand: undefined;
constructor(
@IWindowsMainService private readonly windowsMainService: IWindowsMainService,
@ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService
@ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService,
@IEnvironmentService private readonly environmentService: IEnvironmentService,
@IWorkspacesHistoryMainService private readonly workspacesHistoryMainService: IWorkspacesHistoryMainService
) {
}
//#region Events
readonly onWindowOpen: Event<number> = Event.filter(Event.fromNodeEventEmitter(app, 'browser-window-created', (_, window: BrowserWindow) => window.id), windowId => !!this.windowsMainService.getWindowById(windowId));
readonly onWindowMaximize: Event<number> = Event.filter(Event.fromNodeEventEmitter(app, 'browser-window-maximize', (_, window: BrowserWindow) => window.id), windowId => !!this.windowsMainService.getWindowById(windowId));
readonly onWindowUnmaximize: Event<number> = Event.filter(Event.fromNodeEventEmitter(app, 'browser-window-unmaximize', (_, window: BrowserWindow) => window.id), windowId => !!this.windowsMainService.getWindowById(windowId));
readonly onWindowBlur: Event<number> = Event.filter(Event.fromNodeEventEmitter(app, 'browser-window-blur', (_, window: BrowserWindow) => window.id), windowId => !!this.windowsMainService.getWindowById(windowId));
readonly onWindowFocus: Event<number> = Event.any(
Event.map(Event.filter(Event.map(this.windowsMainService.onWindowsCountChanged, () => this.windowsMainService.getLastActiveWindow()), window => !!window), window => window!.id),
Event.filter(Event.fromNodeEventEmitter(app, 'browser-window-focus', (_, window: BrowserWindow) => window.id), windowId => !!this.windowsMainService.getWindowById(windowId))
);
//#endregion
//#region Window
async windowCount(windowId: number): Promise<number> {
async getWindows(): Promise<IOpenedWindow[]> {
const windows = this.windowsMainService.getWindows();
return windows.map(window => ({
id: window.id,
workspace: window.openedWorkspace,
folderUri: window.openedFolderUri,
title: window.win.getTitle(),
filename: window.getRepresentedFilename()
}));
}
async getWindowCount(windowId: number): Promise<number> {
return this.windowsMainService.getWindowCount();
}
async openEmptyWindow(windowId: number, options?: { reuse?: boolean, remoteAuthority?: string }): Promise<void> {
async getActiveWindowId(windowId: number): Promise<number | undefined> {
const activeWindow = this.windowsMainService.getFocusedWindow() || this.windowsMainService.getLastActiveWindow();
if (activeWindow) {
return activeWindow.id;
}
return undefined;
}
async openEmptyWindow(windowId: number, options?: IOpenEmptyWindowOptions): Promise<void> {
this.windowsMainService.openEmptyWindow(OpenContext.API, options);
}
async openInWindow(windowId: number, toOpen: IWindowOpenable[], options: IOpenInWindowOptions = Object.create(null)): Promise<void> {
if (toOpen.length > 0) {
this.windowsMainService.open({
context: OpenContext.API,
contextWindowId: windowId,
urisToOpen: toOpen,
cli: this.environmentService.args,
forceNewWindow: options.forceNewWindow,
forceReuseWindow: options.forceReuseWindow,
diffMode: options.diffMode,
addMode: options.addMode,
gotoLineMode: options.gotoLineMode,
noRecentEntry: options.noRecentEntry,
waitMarkerFileURI: options.waitMarkerFileURI
});
}
}
async toggleFullScreen(windowId: number): Promise<void> {
const window = this.windowsMainService.getWindowById(windowId);
if (window) {
@@ -76,6 +138,30 @@ export class ElectronMainService implements AddContextToFunctions<IElectronServi
}
}
async isWindowFocused(windowId: number): Promise<boolean> {
const window = this.windowsMainService.getWindowById(windowId);
if (window) {
return window.win.isFocused();
}
return false;
}
async focusWindow(windowId: number, options?: { windowId?: number; }): Promise<void> {
if (options && typeof options.windowId === 'number') {
windowId = options.windowId;
}
const window = this.windowsMainService.getWindowById(windowId);
if (window) {
if (isMacintosh) {
window.win.show();
} else {
window.win.focus();
}
}
}
//#endregion
//#region Dialog
@@ -245,4 +331,48 @@ export class ElectronMainService implements AddContextToFunctions<IElectronServi
}
//#endregion
//#region Workspaces History
readonly onRecentlyOpenedChange = this.workspacesHistoryMainService.onRecentlyOpenedChange;
async getRecentlyOpened(windowId: number): Promise<IRecentlyOpened> {
const window = this.windowsMainService.getWindowById(windowId);
if (window) {
return this.workspacesHistoryMainService.getRecentlyOpened(window.config.workspace, window.config.folderUri, window.config.filesToOpenOrCreate);
}
return this.workspacesHistoryMainService.getRecentlyOpened();
}
async addRecentlyOpened(windowId: number, recents: IRecent[]): Promise<void> {
return this.workspacesHistoryMainService.addRecentlyOpened(recents);
}
async removeFromRecentlyOpened(windowId: number, paths: URI[]): Promise<void> {
return this.workspacesHistoryMainService.removeFromRecentlyOpened(paths);
}
async clearRecentlyOpened(windowId: number): Promise<void> {
return this.workspacesHistoryMainService.clearRecentlyOpened();
}
//#endregion
//#region Debug
// TODO@Isidor move into debug IPC channel (https://github.com/microsoft/vscode/issues/81060)
async openExtensionDevelopmentHostWindow(windowId: number, args: ParsedArgs, env: IProcessEnvironment): Promise<void> {
const extDevPaths = args.extensionDevelopmentPath;
if (extDevPaths) {
this.windowsMainService.openExtensionDevelopmentHostWindow(extDevPaths, {
context: OpenContext.API,
cli: args,
userEnv: Object.keys(env).length > 0 ? env : undefined
});
}
}
//#endregion
}

View File

@@ -3,10 +3,16 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Event } from 'vs/base/common/event';
import { MessageBoxOptions, MessageBoxReturnValue, OpenDevToolsOptions, SaveDialogOptions, OpenDialogOptions, OpenDialogReturnValue, SaveDialogReturnValue, CrashReporterStartOptions } from 'electron';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { INativeOpenDialogOptions } from 'vs/platform/windows/common/windows';
import { IWindowOpenable, IOpenInWindowOptions, IOpenEmptyWindowOptions, IOpenedWindow } from 'vs/platform/windows/common/windows';
import { INativeOpenDialogOptions } from 'vs/platform/dialogs/node/dialogs';
import { ISerializableCommandAction } from 'vs/platform/actions/common/actions';
import { IRecentlyOpened, IRecent } from 'vs/platform/workspaces/common/workspacesHistory';
import { URI } from 'vs/base/common/uri';
import { ParsedArgs } from 'vscode-minimist';
import { IProcessEnvironment } from 'vs/base/common/platform';
export const IElectronService = createDecorator<IElectronService>('electronService');
@@ -14,10 +20,25 @@ export interface IElectronService {
_serviceBrand: undefined;
// Events
readonly onWindowOpen: Event<number>;
readonly onWindowMaximize: Event<number>;
readonly onWindowUnmaximize: Event<number>;
readonly onWindowFocus: Event<number>;
readonly onWindowBlur: Event<number>;
// Window
windowCount(): Promise<number>;
openEmptyWindow(options?: { reuse?: boolean, remoteAuthority?: string }): Promise<void>;
getWindows(): Promise<IOpenedWindow[]>;
getWindowCount(): Promise<number>;
getActiveWindowId(): Promise<number | undefined>;
openEmptyWindow(options?: IOpenEmptyWindowOptions): Promise<void>;
openInWindow(toOpen: IWindowOpenable[], options?: IOpenInWindowOptions): Promise<void>;
toggleFullScreen(): Promise<void>;
handleTitleDoubleClick(): Promise<void>;
isMaximized(): Promise<boolean>;
@@ -25,6 +46,9 @@ export interface IElectronService {
unmaximizeWindow(): Promise<void>;
minimizeWindow(): Promise<void>;
isWindowFocused(): Promise<boolean>;
focusWindow(options?: { windowId?: number }): Promise<void>;
// Dialogs
showMessageBox(options: MessageBoxOptions): Promise<MessageBoxReturnValue>;
showSaveDialog(options: SaveDialogOptions): Promise<SaveDialogReturnValue>;
@@ -64,4 +88,14 @@ export interface IElectronService {
// Connectivity
resolveProxy(url: string): Promise<string | undefined>;
// Workspaces History
readonly onRecentlyOpenedChange: Event<void>;
getRecentlyOpened(): Promise<IRecentlyOpened>;
addRecentlyOpened(recents: IRecent[]): Promise<void>;
removeFromRecentlyOpened(paths: URI[]): Promise<void>;
clearRecentlyOpened(): Promise<void>;
// Debug (TODO@Isidor move into debug IPC channel (https://github.com/microsoft/vscode/issues/81060)
openExtensionDevelopmentHostWindow(args: ParsedArgs, env: IProcessEnvironment): Promise<void>;
}

View File

@@ -123,11 +123,14 @@ export interface IEnvironmentService {
// user roaming data
userRoamingDataHome: URI;
settingsResource: URI;
settingsSyncPreviewResource: URI;
keybindingsResource: URI;
keyboardLayoutResource: URI;
localeResource: URI;
// sync resources
userDataSyncLogResource: URI;
settingsSyncPreviewResource: URI;
machineSettingsHome: URI;
machineSettingsResource: URI;

View File

@@ -119,6 +119,9 @@ export class EnvironmentService implements IEnvironmentService {
@memoize
get settingsSyncPreviewResource(): URI { return resources.joinPath(this.userRoamingDataHome, '.settings.json'); }
@memoize
get userDataSyncLogResource(): URI { return URI.file(path.join(this.logsPath, 'userDataSync.log')); }
@memoize
get machineSettingsHome(): URI { return URI.file(path.join(this.userDataPath, 'Machine')); }

View File

@@ -209,7 +209,7 @@ export interface IFileSystemProvider {
readonly onDidErrorOccur?: Event<string>; // TODO@ben remove once file watchers are solid
readonly onDidChangeFile: Event<IFileChange[]>;
readonly onDidChangeFile: Event<readonly IFileChange[]>;
watch(resource: URI, opts: IWatchOptions): IDisposable;
stat(resource: URI): Promise<IStat>;
@@ -389,19 +389,19 @@ export interface IFileChange {
/**
* The type of change that occurred to the file.
*/
type: FileChangeType;
readonly type: FileChangeType;
/**
* The unified resource identifier of the file that changed.
*/
resource: URI;
readonly resource: URI;
}
export class FileChangesEvent {
private _changes: IFileChange[];
private readonly _changes: readonly IFileChange[];
constructor(changes: IFileChange[]) {
constructor(changes: readonly IFileChange[]) {
this._changes = changes;
}

View File

@@ -449,8 +449,8 @@ export class DiskFileSystemProvider extends Disposable implements IFileSystemPro
private _onDidWatchErrorOccur: Emitter<string> = this._register(new Emitter<string>());
readonly onDidErrorOccur: Event<string> = this._onDidWatchErrorOccur.event;
private _onDidChangeFile: Emitter<IFileChange[]> = this._register(new Emitter<IFileChange[]>());
get onDidChangeFile(): Event<IFileChange[]> { return this._onDidChangeFile.event; }
private _onDidChangeFile = this._register(new Emitter<readonly IFileChange[]>());
get onDidChangeFile(): Event<readonly IFileChange[]> { return this._onDidChangeFile.event; }
private recursiveWatcher: WindowsWatcherService | UnixWatcherService | NsfwWatcherService | undefined;
private recursiveFoldersToWatch: { path: string, excludes: string[] }[] = [];

View File

@@ -13,7 +13,7 @@ export class NullFileSystemProvider implements IFileSystemProvider {
capabilities: FileSystemProviderCapabilities = FileSystemProviderCapabilities.Readonly;
onDidChangeCapabilities: Event<void> = Event.None;
onDidChangeFile: Event<IFileChange[]> = Event.None;
onDidChangeFile: Event<readonly IFileChange[]> = Event.None;
constructor(private disposableFactory: () => IDisposable = () => Disposable.None) { }
@@ -30,4 +30,4 @@ export class NullFileSystemProvider implements IFileSystemProvider {
close?(fd: number): Promise<void> { return Promise.resolve(undefined!); }
read?(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise<number> { return Promise.resolve(undefined!); }
write?(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise<number> { return Promise.resolve(undefined!); }
}
}

View File

@@ -1918,7 +1918,7 @@ suite('Disk File Service', function () {
});
}
function hasChange(changes: IFileChange[], type: FileChangeType, resource: URI): boolean {
function hasChange(changes: readonly IFileChange[], type: FileChangeType, resource: URI): boolean {
return changes.some(change => change.type === type && isEqual(change.resource, resource));
}

View File

@@ -206,7 +206,7 @@ export class InstantiationService implements IInstantiationService {
} else if (this._parent) {
return this._parent._createServiceInstanceWithOwner(id, ctor, args, supportsDelayedInstantiation, _trace);
} else {
throw new Error('illegalState - creating UNKNOWN service instance');
throw new Error(`illegalState - creating UNKNOWN service instance ${ctor.name}`);
}
}

View File

@@ -4,12 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { Client } from 'vs/base/parts/ipc/common/ipc.net';
import { connect } from 'vs/base/parts/ipc/node/ipc.net';
import { IWindowService } from 'vs/platform/windows/common/windows';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IChannel, IServerChannel, getDelayedChannel } from 'vs/base/parts/ipc/common/ipc';
import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService';
import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc';
export const ISharedProcessService = createDecorator<ISharedProcessService>('sharedProcessService');
@@ -23,38 +18,3 @@ export interface ISharedProcessService {
whenSharedProcessReady(): Promise<void>;
toggleSharedProcessWindow(): Promise<void>;
}
export class SharedProcessService implements ISharedProcessService {
_serviceBrand: undefined;
private withSharedProcessConnection: Promise<Client<string>>;
private sharedProcessMainChannel: IChannel;
constructor(
@IMainProcessService mainProcessService: IMainProcessService,
@IWindowService windowService: IWindowService,
@IEnvironmentService environmentService: IEnvironmentService
) {
this.sharedProcessMainChannel = mainProcessService.getChannel('sharedProcess');
this.withSharedProcessConnection = this.whenSharedProcessReady()
.then(() => connect(environmentService.sharedIPCHandle, `window:${windowService.windowId}`));
}
whenSharedProcessReady(): Promise<void> {
return this.sharedProcessMainChannel.call('whenSharedProcessReady');
}
getChannel(channelName: string): IChannel {
return getDelayedChannel(this.withSharedProcessConnection.then(connection => connection.getChannel(channelName)));
}
registerChannel(channelName: string, channel: IServerChannel<string>): void {
this.withSharedProcessConnection.then(connection => connection.registerChannel(channelName, channel));
}
toggleSharedProcessWindow(): Promise<void> {
return this.sharedProcessMainChannel.call('toggleSharedProcessWindow');
}
}

View File

@@ -1,90 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Event } from 'vs/base/common/event';
import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc';
//
// Use both `SimpleServiceProxyChannel` and `createSimpleChannelProxy`
// for a very basic process <=> process communication over methods.
//
export type AddContextToFunctions<Target, Context> = {
// For every property: IF property is a FUNCTION ADD context as first parameter and original parameters afterwards with same return type, otherwise preserve as is
[K in keyof Target]: Target[K] extends (...args: any) => any ? (context: Context, ...args: Parameters<Target[K]>) => ReturnType<Target[K]> : Target[K]
};
interface ISimpleChannelProxyContext {
__$simpleIPCContextMarker: boolean;
proxyContext: unknown;
}
function serializeContext(proxyContext?: unknown): ISimpleChannelProxyContext | undefined {
if (proxyContext) {
return { __$simpleIPCContextMarker: true, proxyContext };
}
return undefined;
}
function deserializeContext(candidate?: ISimpleChannelProxyContext | undefined): unknown | undefined {
if (candidate && candidate.__$simpleIPCContextMarker === true) {
return candidate.proxyContext;
}
return undefined;
}
export class SimpleServiceProxyChannel implements IServerChannel {
private service: { [key: string]: unknown };
constructor(service: unknown) {
this.service = service as { [key: string]: unknown };
}
listen<T>(_: unknown, event: string): Event<T> {
throw new Error(`Events are currently unsupported by SimpleServiceProxyChannel: ${event}`);
}
call(_: unknown, command: string, args?: any[]): Promise<any> {
const target = this.service[command];
if (typeof target === 'function') {
if (Array.isArray(args)) {
const context = deserializeContext(args[0]);
if (context) {
args[0] = context;
}
}
return target.apply(this.service, args);
}
throw new Error(`Method not found: ${command}`);
}
}
export function createSimpleChannelProxy<T>(channel: IChannel, context?: unknown): T {
const serializedContext = serializeContext(context);
return new Proxy({}, {
get(_target, propKey, _receiver) {
if (typeof propKey === 'string') {
return function (...args: any[]) {
let methodArgs: any[];
if (serializedContext) {
methodArgs = [context, ...args];
} else {
methodArgs = args;
}
return channel.call(propKey, methodArgs);
};
}
throw new Error(`Unable to provide main channel proxy implementation for: ${String(propKey)}`);
}
}) as T;
}

View File

@@ -5,13 +5,13 @@
import { IIssueService } from 'vs/platform/issue/node/issue';
import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService';
import { createSimpleChannelProxy } from 'vs/platform/ipc/node/simpleIpcProxy';
import { createChannelSender } from 'vs/base/parts/ipc/node/ipcChannelCreator';
export class IssueService {
_serviceBrand: undefined;
constructor(@IMainProcessService mainProcessService: IMainProcessService) {
return createSimpleChannelProxy<IIssueService>(mainProcessService.getChannel('issue'));
return createChannelSender<IIssueService>(mainProcessService.getChannel('issue'));
}
}

View File

@@ -5,7 +5,7 @@
import { ipcMain as ipc, app } from 'electron';
import { ILogService } from 'vs/platform/log/common/log';
import { IStateService } from 'vs/platform/state/common/state';
import { IStateService } from 'vs/platform/state/node/state';
import { Event, Emitter } from 'vs/base/common/event';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { ICodeWindow } from 'vs/platform/windows/electron-main/windows';

View File

@@ -7,7 +7,7 @@ import { ILogService, LogLevel, AbstractLogService, DEFAULT_LOG_LEVEL } from 'vs
interface ILog {
level: LogLevel;
args: IArguments;
args: any[];
}
function getLogFunction(logger: ILogService, level: LogLevel): Function {
@@ -49,7 +49,7 @@ export class BufferLogService extends AbstractLogService implements ILogService
this.buffer = [];
}
private _log(level: LogLevel, args: IArguments): void {
private _log(level: LogLevel, ...args: any[]): void {
if (this._logger) {
const fn = getLogFunction(this._logger, level);
fn.apply(this._logger, args);
@@ -58,28 +58,28 @@ export class BufferLogService extends AbstractLogService implements ILogService
}
}
trace(): void {
this._log(LogLevel.Trace, arguments);
trace(message: string, ...args: any[]): void {
this._log(LogLevel.Trace, message, ...args);
}
debug(): void {
this._log(LogLevel.Debug, arguments);
debug(message: string, ...args: any[]): void {
this._log(LogLevel.Debug, message, ...args);
}
info(): void {
this._log(LogLevel.Info, arguments);
info(message: string, ...args: any[]): void {
this._log(LogLevel.Info, message, ...args);
}
warn(): void {
this._log(LogLevel.Warning, arguments);
warn(message: string, ...args: any[]): void {
this._log(LogLevel.Warning, message, ...args);
}
error(): void {
this._log(LogLevel.Error, arguments);
error(message: string | Error, ...args: any[]): void {
this._log(LogLevel.Error, message, ...args);
}
critical(): void {
this._log(LogLevel.Critical, arguments);
critical(message: string | Error, ...args: any[]): void {
this._log(LogLevel.Critical, message, ...args);
}
dispose(): void {

View File

@@ -3,12 +3,14 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ILogService, LogLevel, AbstractLogService } from 'vs/platform/log/common/log';
import { ILogService, LogLevel, AbstractLogService, ILoggerService, ILogger } from 'vs/platform/log/common/log';
import { URI } from 'vs/base/common/uri';
import { IFileService } from 'vs/platform/files/common/files';
import { Queue } from 'vs/base/common/async';
import { VSBuffer } from 'vs/base/common/buffer';
import { dirname, joinPath, basename } from 'vs/base/common/resources';
import { Disposable } from 'vs/base/common/lifecycle';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
const MAX_FILE_SIZE = 1024 * 1024 * 5;
@@ -16,6 +18,7 @@ export class FileLogService extends AbstractLogService implements ILogService {
_serviceBrand: undefined;
private readonly initializePromise: Promise<void>;
private readonly queue: Queue<void>;
private backupIndex: number = 1;
@@ -28,6 +31,7 @@ export class FileLogService extends AbstractLogService implements ILogService {
super();
this.setLevel(level);
this.queue = this._register(new Queue<void>());
this.initializePromise = this.initialize();
}
trace(): void {
@@ -82,8 +86,13 @@ export class FileLogService extends AbstractLogService implements ILogService {
this._log(level, this.format(args));
}
private async initialize(): Promise<void> {
await this.fileService.createFile(this.resource);
}
private _log(level: LogLevel, message: string): void {
this.queue.queue(async () => {
await this.initializePromise;
let content = await this.loadContent();
if (content.length > MAX_FILE_SIZE) {
await this.fileService.writeFile(this.getBackupResource(), VSBuffer.fromString(content));
@@ -145,3 +154,33 @@ export class FileLogService extends AbstractLogService implements ILogService {
return result;
}
}
export class FileLoggerService extends Disposable implements ILoggerService {
_serviceBrand: undefined;
private readonly loggers = new Map<string, ILogger>();
constructor(
@ILogService private logService: ILogService,
@IInstantiationService private instantiationService: IInstantiationService,
) {
super();
this._register(logService.onDidChangeLogLevel(level => this.loggers.forEach(logger => logger.setLevel(level))));
}
getLogger(resource: URI): ILogger {
let logger = this.loggers.get(resource.toString());
if (!logger) {
logger = this.instantiationService.createInstance(FileLogService, basename(resource), resource, this.logService.getLevel());
this.loggers.set(resource.toString(), logger);
}
return logger;
}
dispose(): void {
this.loggers.forEach(logger => logger.dispose());
this.loggers.clear();
super.dispose();
}
}

View File

@@ -9,8 +9,10 @@ import { isWindows } from 'vs/base/common/platform';
import { Event, Emitter } from 'vs/base/common/event';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { LoggerChannelClient } from 'vs/platform/log/common/logIpc';
import { URI } from 'vs/base/common/uri';
export const ILogService = createServiceDecorator<ILogService>('logService');
export const ILoggerService = createServiceDecorator<ILoggerService>('loggerService');
function now(): string {
return new Date().toISOString();
@@ -28,12 +30,11 @@ export enum LogLevel {
export const DEFAULT_LOG_LEVEL: LogLevel = LogLevel.Info;
export interface ILogService extends IDisposable {
_serviceBrand: undefined;
export interface ILogger extends IDisposable {
onDidChangeLogLevel: Event<LogLevel>;
getLevel(): LogLevel;
setLevel(level: LogLevel): void;
trace(message: string, ...args: any[]): void;
debug(message: string, ...args: any[]): void;
info(message: string, ...args: any[]): void;
@@ -42,6 +43,16 @@ export interface ILogService extends IDisposable {
critical(message: string | Error, ...args: any[]): void;
}
export interface ILogService extends ILogger {
_serviceBrand: undefined;
}
export interface ILoggerService {
_serviceBrand: undefined;
getLogger(file: URI): ILogger;
}
export abstract class AbstractLogService extends Disposable {
private level: LogLevel = DEFAULT_LOG_LEVEL;

View File

@@ -0,0 +1,50 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ILogService, ILoggerService, ILogger } from 'vs/platform/log/common/log';
import { Disposable } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri';
import { basename, extname, dirname } from 'vs/base/common/resources';
import { Schemas } from 'vs/base/common/network';
import { FileLogService } from 'vs/platform/log/common/fileLogService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { SpdLogService } from 'vs/platform/log/node/spdlogService';
export class LoggerService extends Disposable implements ILoggerService {
_serviceBrand: undefined;
private readonly loggers = new Map<string, ILogger>();
constructor(
@ILogService private logService: ILogService,
@IInstantiationService private instantiationService: IInstantiationService,
) {
super();
this._register(logService.onDidChangeLogLevel(level => this.loggers.forEach(logger => logger.setLevel(level))));
}
getLogger(resource: URI): ILogger {
let logger = this.loggers.get(resource.toString());
if (!logger) {
if (resource.scheme === Schemas.file) {
const baseName = basename(resource);
const ext = extname(resource);
logger = new SpdLogService(baseName.substring(0, baseName.length - ext.length), dirname(resource).path, this.logService.getLevel());
} else {
logger = this.instantiationService.createInstance(FileLogService, basename(resource), resource, this.logService.getLevel());
}
this.loggers.set(resource.toString(), logger);
}
return logger;
}
dispose(): void {
this.loggers.forEach(logger => logger.dispose());
this.loggers.clear();
super.dispose();
}
}

View File

@@ -30,16 +30,19 @@ interface ILog {
message: string;
}
function log(logger: spdlog.RotatingLogger, level: LogLevel, message: string): void {
function log(logger: spdlog.RotatingLogger, level: LogLevel, message: string, sync: boolean): void {
switch (level) {
case LogLevel.Trace: return logger.trace(message);
case LogLevel.Debug: return logger.debug(message);
case LogLevel.Info: return logger.info(message);
case LogLevel.Warning: return logger.warn(message);
case LogLevel.Error: return logger.error(message);
case LogLevel.Critical: return logger.critical(message);
case LogLevel.Trace: logger.trace(message); break;
case LogLevel.Debug: logger.debug(message); break;
case LogLevel.Info: logger.info(message); break;
case LogLevel.Warning: logger.warn(message); break;
case LogLevel.Error: logger.error(message); break;
case LogLevel.Critical: logger.critical(message); break;
default: throw new Error('Invalid log level');
}
if (sync) {
logger.flush();
}
}
export class SpdLogService extends AbstractLogService implements ILogService {
@@ -50,7 +53,7 @@ export class SpdLogService extends AbstractLogService implements ILogService {
private _loggerCreationPromise: Promise<void> | undefined = undefined;
private _logger: spdlog.RotatingLogger | undefined;
constructor(private readonly name: string, private readonly logsFolder: string, level: LogLevel) {
constructor(private readonly name: string, private readonly logsFolder: string, level: LogLevel, private readonly sync: boolean = false) {
super();
this.setLevel(level);
this._createSpdLogLogger();
@@ -69,7 +72,7 @@ export class SpdLogService extends AbstractLogService implements ILogService {
this._logger = logger;
this._logger.setLevel(this.getLevel());
for (const { level, message } of this.buffer) {
log(this._logger, level, message);
log(this._logger, level, message, this.sync);
}
this.buffer = [];
}
@@ -80,53 +83,52 @@ export class SpdLogService extends AbstractLogService implements ILogService {
private _log(level: LogLevel, message: string): void {
if (this._logger) {
log(this._logger, level, message);
log(this._logger, level, message, this.sync);
} else if (this.getLevel() <= level) {
this.buffer.push({ level, message });
}
}
trace(): void {
trace(message: string, ...args: any[]): void {
if (this.getLevel() <= LogLevel.Trace) {
this._log(LogLevel.Trace, this.format(arguments));
this._log(LogLevel.Trace, this.format([message, ...args]));
}
}
debug(): void {
debug(message: string, ...args: any[]): void {
if (this.getLevel() <= LogLevel.Debug) {
this._log(LogLevel.Debug, this.format(arguments));
this._log(LogLevel.Debug, this.format([message, ...args]));
}
}
info(): void {
info(message: string, ...args: any[]): void {
if (this.getLevel() <= LogLevel.Info) {
this._log(LogLevel.Info, this.format(arguments));
this._log(LogLevel.Info, this.format([message, ...args]));
}
}
warn(): void {
warn(message: string, ...args: any[]): void {
if (this.getLevel() <= LogLevel.Warning) {
this._log(LogLevel.Warning, this.format(arguments));
this._log(LogLevel.Warning, this.format([message, ...args]));
}
}
error(): void {
error(message: string | Error, ...args: any[]): void {
if (this.getLevel() <= LogLevel.Error) {
const arg = arguments[0];
if (arg instanceof Error) {
if (message instanceof Error) {
const array = Array.prototype.slice.call(arguments) as any[];
array[0] = arg.stack;
array[0] = message.stack;
this._log(LogLevel.Error, this.format(array));
} else {
this._log(LogLevel.Error, this.format(arguments));
this._log(LogLevel.Error, this.format([message, ...args]));
}
}
}
critical(): void {
critical(message: string | Error, ...args: any[]): void {
if (this.getLevel() <= LogLevel.Critical) {
this._log(LogLevel.Critical, this.format(arguments));
this._log(LogLevel.Critical, this.format([message, ...args]));
}
}
@@ -163,4 +165,4 @@ export class SpdLogService extends AbstractLogService implements ILogService {
return result;
}
}
}

View File

@@ -123,8 +123,8 @@ export class MarkerService implements IMarkerService {
_serviceBrand: undefined;
private readonly _onMarkerChanged = new Emitter<URI[]>();
private _onMarkerChangedEvent: Event<URI[]> = Event.debounce(this._onMarkerChanged.event, MarkerService._debouncer, 0);
private readonly _onMarkerChanged = new Emitter<readonly URI[]>();
private _onMarkerChangedEvent: Event<readonly URI[]> = Event.debounce(this._onMarkerChanged.event, MarkerService._debouncer, 0);
private _byResource: MapMap<IMarker[]> = Object.create(null);
private _byOwner: MapMap<IMarker[]> = Object.create(null);
private _stats: MarkerStats;
@@ -137,7 +137,7 @@ export class MarkerService implements IMarkerService {
this._stats.dispose();
}
get onMarkerChanged(): Event<URI[]> {
get onMarkerChanged(): Event<readonly URI[]> {
return this._onMarkerChangedEvent;
}

View File

@@ -22,7 +22,7 @@ export interface IMarkerService {
read(filter?: { owner?: string; resource?: URI; severities?: number, take?: number; }): IMarker[];
onMarkerChanged: Event<URI[]>;
readonly onMarkerChanged: Event<readonly URI[]>;
}
/**

View File

@@ -5,13 +5,13 @@
import { IMenubarService } from 'vs/platform/menubar/node/menubar';
import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService';
import { createSimpleChannelProxy } from 'vs/platform/ipc/node/simpleIpcProxy';
import { createChannelSender } from 'vs/base/parts/ipc/node/ipcChannelCreator';
export class MenubarService {
_serviceBrand: undefined;
constructor(@IMainProcessService mainProcessService: IMainProcessService) {
return createSimpleChannelProxy<IMenubarService>(mainProcessService.getChannel('menubar'));
return createChannelSender<IMenubarService>(mainProcessService.getChannel('menubar'));
}
}

View File

@@ -7,7 +7,7 @@ import * as nls from 'vs/nls';
import { isMacintosh, language } from 'vs/base/common/platform';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { app, shell, Menu, MenuItem, BrowserWindow, MenuItemConstructorOptions, WebContents, Event, KeyboardEvent } from 'electron';
import { OpenContext, IRunActionInWindowRequest, getTitleBarStyle, IRunKeybindingInWindowRequest, IURIToOpen } from 'vs/platform/windows/common/windows';
import { OpenContext, IRunActionInWindowRequest, getTitleBarStyle, IRunKeybindingInWindowRequest, IWindowOpenable } from 'vs/platform/windows/common/windows';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IUpdateService, StateType } from 'vs/platform/update/common/update';
@@ -16,10 +16,10 @@ import { RunOnceScheduler } from 'vs/base/common/async';
import { ILogService } from 'vs/platform/log/common/log';
import { mnemonicMenuLabel as baseMnemonicLabel } from 'vs/base/common/labels';
import { IWindowsMainService, IWindowsCountChangedEvent } from 'vs/platform/windows/electron-main/windows';
import { IHistoryMainService } from 'vs/platform/history/electron-main/historyMainService';
import { IWorkspacesHistoryMainService } from 'vs/platform/workspaces/electron-main/workspacesHistoryMainService';
import { IMenubarData, IMenubarKeybinding, MenubarMenuItem, isMenubarMenuItemSeparator, isMenubarMenuItemSubmenu, isMenubarMenuItemAction, IMenubarMenu, isMenubarMenuItemUriAction } from 'vs/platform/menubar/node/menubar';
import { URI } from 'vs/base/common/uri';
import { IStateService } from 'vs/platform/state/common/state';
import { IStateService } from 'vs/platform/state/node/state';
import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService';
import { WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions';
@@ -66,7 +66,7 @@ export class Menubar {
@IWindowsMainService private readonly windowsMainService: IWindowsMainService,
@IEnvironmentService private readonly environmentService: IEnvironmentService,
@ITelemetryService private readonly telemetryService: ITelemetryService,
@IHistoryMainService private readonly historyMainService: IHistoryMainService,
@IWorkspacesHistoryMainService private readonly workspacesHistoryMainService: IWorkspacesHistoryMainService,
@IStateService private readonly stateService: IStateService,
@ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService,
@ILogService private readonly logService: ILogService
@@ -115,7 +115,7 @@ export class Menubar {
this.fallbackMenuHandlers['workbench.action.openWorkspace'] = (menuItem, win, event) => this.windowsMainService.pickWorkspaceAndOpen({ forceNewWindow: this.isOptionClick(event), telemetryExtraData: { from: telemetryFrom } });
// Recent Menu Items
this.fallbackMenuHandlers['workbench.action.clearRecentFiles'] = () => this.historyMainService.clearRecentlyOpened();
this.fallbackMenuHandlers['workbench.action.clearRecentFiles'] = () => this.workspacesHistoryMainService.clearRecentlyOpened();
// Help Menu Items
const twitterUrl = product.twitterUrl;
@@ -480,7 +480,7 @@ export class Menubar {
private createOpenRecentMenuItem(uri: URI, label: string, commandId: string): MenuItem {
const revivedUri = URI.revive(uri);
const uriToOpen: IURIToOpen =
const openable: IWindowOpenable =
(commandId === 'openRecentFile') ? { fileUri: revivedUri } :
(commandId === 'openRecentWorkspace') ? { workspaceUri: revivedUri } : { folderUri: revivedUri };
@@ -491,13 +491,13 @@ export class Menubar {
const success = this.windowsMainService.open({
context: OpenContext.MENU,
cli: this.environmentService.args,
urisToOpen: [uriToOpen],
urisToOpen: [openable],
forceNewWindow: openInNewWindow,
gotoLineMode: false
}).length > 0;
if (!success) {
this.historyMainService.removeFromRecentlyOpened([revivedUri]);
this.workspacesHistoryMainService.removeFromRecentlyOpened([revivedUri]);
}
}
}, false));

View File

@@ -24,8 +24,8 @@ export class RemoteExtensionsFileSystemProvider extends Disposable implements IF
private readonly session: string = generateUuid();
private readonly _onDidChange = this._register(new Emitter<IFileChange[]>());
readonly onDidChangeFile: Event<IFileChange[]> = this._onDidChange.event;
private readonly _onDidChange = this._register(new Emitter<readonly IFileChange[]>());
readonly onDidChangeFile: Event<readonly IFileChange[]> = this._onDidChange.event;
private _onDidWatchErrorOccur: Emitter<string> = this._register(new Emitter<string>());
readonly onDidErrorOccur: Event<string> = this._onDidWatchErrorOccur.event;

View File

@@ -8,7 +8,7 @@ import * as fs from 'fs';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { writeFileSync, readFile } from 'vs/base/node/pfs';
import { isUndefined, isUndefinedOrNull } from 'vs/base/common/types';
import { IStateService } from 'vs/platform/state/common/state';
import { IStateService } from 'vs/platform/state/node/state';
import { ILogService } from 'vs/platform/log/common/log';
type StorageDatebase = { [key: string]: any; };

View File

@@ -16,7 +16,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment'
import { IWorkspaceInitializationPayload, isWorkspaceIdentifier, isSingleFolderWorkspaceInitializationPayload } from 'vs/platform/workspaces/common/workspaces';
import { onUnexpectedError } from 'vs/base/common/errors';
export class StorageService extends Disposable implements IStorageService {
export class NativeStorageService extends Disposable implements IStorageService {
_serviceBrand: undefined;
@@ -83,7 +83,7 @@ export class StorageService extends Disposable implements IStorageService {
// Create workspace storage and initialize
mark('willInitWorkspaceStorage');
try {
await this.createWorkspaceStorage(useInMemoryStorage ? SQLiteStorageDatabase.IN_MEMORY_PATH : join(result.path, StorageService.WORKSPACE_STORAGE_NAME), result.wasCreated ? StorageHint.STORAGE_DOES_NOT_EXIST : undefined).init();
await this.createWorkspaceStorage(useInMemoryStorage ? SQLiteStorageDatabase.IN_MEMORY_PATH : join(result.path, NativeStorageService.WORKSPACE_STORAGE_NAME), result.wasCreated ? StorageHint.STORAGE_DOES_NOT_EXIST : undefined).init();
} finally {
mark('didInitWorkspaceStorage');
}
@@ -144,7 +144,7 @@ export class StorageService extends Disposable implements IStorageService {
}
if (meta) {
const workspaceStorageMetaPath = join(this.getWorkspaceStorageFolderPath(payload), StorageService.WORKSPACE_META_NAME);
const workspaceStorageMetaPath = join(this.getWorkspaceStorageFolderPath(payload), NativeStorageService.WORKSPACE_META_NAME);
(async function () {
try {
const storageExists = await exists(workspaceStorageMetaPath);
@@ -220,7 +220,7 @@ export class StorageService extends Disposable implements IStorageService {
// Prepare new workspace storage folder
const result = await this.prepareWorkspaceStorageFolder(toWorkspace);
const newWorkspaceStoragePath = join(result.path, StorageService.WORKSPACE_STORAGE_NAME);
const newWorkspaceStoragePath = join(result.path, NativeStorageService.WORKSPACE_STORAGE_NAME);
// Copy current storage over to new workspace storage
await copy(this.workspaceStoragePath, newWorkspaceStoragePath);

Some files were not shown because too many files have changed in this diff Show More