Merge from vscode e0762af258c0b20320ed03f3871a41967acc4421 (#7404)
* Merge from vscode e0762af258c0b20320ed03f3871a41967acc4421 * readd svgs
5
.vscode/launch.json
vendored
@@ -165,7 +165,10 @@
|
||||
"cwd": "${workspaceFolder}",
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/out/**/*.js"
|
||||
]
|
||||
],
|
||||
"env": {
|
||||
"MOCHA_COLORS": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "chrome",
|
||||
|
||||
6
.vscode/tasks.json
vendored
@@ -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": []
|
||||
},
|
||||
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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');
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"name": "image-preview",
|
||||
"displayName": "%displayName%",
|
||||
"description": "%description%",
|
||||
"extensionKind": "ui",
|
||||
"version": "1.0.0",
|
||||
"publisher": "vscode",
|
||||
"icon": "icon.png",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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==
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
30
src/typings/xterm.d.ts
vendored
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
3
src/vs/base/browser/ui/menu/menu.svg
Normal 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 |
@@ -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 = /(&)?(&)([^\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`;
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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" }
|
||||
|
||||
|
Before Width: | Height: | Size: 130 KiB |
@@ -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" }
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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]
|
||||
};
|
||||
|
||||
124
src/vs/base/parts/ipc/node/ipcChannelCreator.ts
Normal 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));
|
||||
}
|
||||
@@ -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');
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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))}`;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
51
src/vs/code/node/activeWindowTracker.ts
Normal 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}`;
|
||||
}
|
||||
}
|
||||
@@ -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';
|
||||
|
||||
@@ -14,4 +14,7 @@
|
||||
*/
|
||||
.monaco-editor .margin-view-overlays .cgmr {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
@@ -1405,7 +1405,7 @@ export interface IWebviewPanelOptions {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export const enum WebviewEditorState {
|
||||
export const enum WebviewContentState {
|
||||
Readonly = 1,
|
||||
Unchanged = 2,
|
||||
Dirty = 3,
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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[];
|
||||
}
|
||||
|
||||
|
||||
|
||||
15
src/vs/platform/dialogs/node/dialogs.ts
Normal 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;
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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>;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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')); }
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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[] }[] = [];
|
||||
|
||||
@@ -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!); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
50
src/vs/platform/log/node/loggerService.ts
Normal 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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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[]>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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; };
|
||||
|
||||
@@ -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);
|
||||
|
||||