mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 18:46:40 -05:00
Merge from vscode 0f73473c08055054f317c1c94502f7f39fdbb164 (#6892)
* Merge from vscode 0f73473c08055054f317c1c94502f7f39fdbb164 * fix tslinting
This commit is contained in:
@@ -283,17 +283,30 @@ export class EditorService extends Disposable implements EditorServiceImpl {
|
||||
}
|
||||
|
||||
// Respect option to reveal an editor if it is open (not necessarily visible)
|
||||
// Still prefer to reveal an editor in a group where the editor is active though.
|
||||
if (!targetGroup) {
|
||||
if ((options && options.revealIfOpened) || this.configurationService.getValue<boolean>('workbench.editor.revealIfOpen')) {
|
||||
let groupWithInputActive: IEditorGroup | undefined = undefined;
|
||||
let groupWithInputOpened: IEditorGroup | undefined = undefined;
|
||||
|
||||
for (const group of groupsByLastActive) {
|
||||
if (group.isOpened(input) && group.isActive(input)) {
|
||||
targetGroup = group;
|
||||
break;
|
||||
if (group.isOpened(input)) {
|
||||
if (!groupWithInputOpened) {
|
||||
groupWithInputOpened = group;
|
||||
}
|
||||
|
||||
if (!groupWithInputActive && group.isActive(input)) {
|
||||
groupWithInputActive = group;
|
||||
}
|
||||
}
|
||||
if (group.isOpened(input) && !targetGroup) {
|
||||
targetGroup = group;
|
||||
|
||||
if (groupWithInputOpened && groupWithInputActive) {
|
||||
break; // we found all groups we wanted
|
||||
}
|
||||
}
|
||||
|
||||
// Prefer a target group where the input is visible
|
||||
targetGroup = groupWithInputActive || groupWithInputOpened;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@ import { IWindowService } from 'vs/platform/windows/common/windows';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { MenuRegistry } from 'vs/platform/actions/common/actions';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
// tslint:disable-next-line: import-patterns
|
||||
import { commandsExtensionPoint } from 'vs/workbench/api/common/menusExtensionPoint';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
|
||||
@@ -5,23 +5,21 @@
|
||||
|
||||
import { KeyValueLogProvider } from 'vs/workbench/services/log/common/keyValueLogProvider';
|
||||
|
||||
export const INDEXEDDB_LOG_SCHEME = 'vscode-logs-indexedbd';
|
||||
export const INDEXEDDB_LOGS_DB = 'vscode-logs-db';
|
||||
export const INDEXEDDB_VSCODE_DB = 'vscode-web-db';
|
||||
export const INDEXEDDB_LOGS_OBJECT_STORE = 'vscode-logs-store';
|
||||
|
||||
export class IndexedDBLogProvider extends KeyValueLogProvider {
|
||||
|
||||
private readonly database: Promise<IDBDatabase>;
|
||||
readonly database: Promise<IDBDatabase>;
|
||||
|
||||
constructor(
|
||||
) {
|
||||
super(INDEXEDDB_LOG_SCHEME);
|
||||
constructor(scheme: string) {
|
||||
super(scheme);
|
||||
this.database = this.openDatabase(1);
|
||||
}
|
||||
|
||||
private openDatabase(version: number): Promise<IDBDatabase> {
|
||||
return new Promise((c, e) => {
|
||||
const request = window.indexedDB.open(INDEXEDDB_LOGS_DB, version);
|
||||
const request = window.indexedDB.open(INDEXEDDB_VSCODE_DB, version);
|
||||
request.onerror = (err) => e(request.error);
|
||||
request.onsuccess = () => {
|
||||
const db = request.result;
|
||||
|
||||
@@ -6,17 +6,10 @@
|
||||
import { KeyValueLogProvider } from 'vs/workbench/services/log/common/keyValueLogProvider';
|
||||
import { keys } from 'vs/base/common/map';
|
||||
|
||||
export const INMEMORY_LOG_SCHEME = 'vscode-logs-inmemory';
|
||||
|
||||
export class InMemoryLogProvider extends KeyValueLogProvider {
|
||||
|
||||
private readonly logs: Map<string, string> = new Map<string, string>();
|
||||
|
||||
constructor(
|
||||
) {
|
||||
super(INMEMORY_LOG_SCHEME);
|
||||
}
|
||||
|
||||
protected async getAllKeys(): Promise<string[]> {
|
||||
return keys(this.logs);
|
||||
}
|
||||
|
||||
@@ -1028,6 +1028,67 @@ class SettingsContentBuilder {
|
||||
}
|
||||
|
||||
export function createValidator(prop: IConfigurationPropertySchema): (value: any) => (string | null) {
|
||||
// Only for array of string
|
||||
if (prop.type === 'array' && prop.items && !isArray(prop.items) && prop.items.type === 'string') {
|
||||
const propItems = prop.items;
|
||||
if (propItems && !isArray(propItems) && propItems.type === 'string') {
|
||||
const withQuotes = (s: string) => `'` + s + `'`;
|
||||
|
||||
return value => {
|
||||
if (!value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let message = '';
|
||||
|
||||
const stringArrayValue = value as string[];
|
||||
|
||||
if (prop.minItems && stringArrayValue.length < prop.minItems) {
|
||||
message += nls.localize('validations.stringArrayMinItem', 'Array must have at least {0} items', prop.minItems);
|
||||
message += '\n';
|
||||
}
|
||||
|
||||
if (prop.maxItems && stringArrayValue.length > prop.maxItems) {
|
||||
message += nls.localize('validations.stringArrayMaxItem', 'Array must have less than {0} items', prop.maxItems);
|
||||
message += '\n';
|
||||
}
|
||||
|
||||
if (typeof propItems.pattern === 'string') {
|
||||
const patternRegex = new RegExp(propItems.pattern);
|
||||
stringArrayValue.forEach(v => {
|
||||
if (!patternRegex.test(v)) {
|
||||
message +=
|
||||
propItems.patternErrorMessage ||
|
||||
nls.localize(
|
||||
'validations.stringArrayItemPattern',
|
||||
'Value {0} must match regex {1}.',
|
||||
withQuotes(v),
|
||||
withQuotes(propItems.pattern!)
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const propItemsEnum = propItems.enum;
|
||||
if (propItemsEnum) {
|
||||
stringArrayValue.forEach(v => {
|
||||
if (propItemsEnum.indexOf(v) === -1) {
|
||||
message += nls.localize(
|
||||
'validations.stringArrayItemEnum',
|
||||
'Value {0} is not one of {1}',
|
||||
withQuotes(v),
|
||||
'[' + propItemsEnum.map(withQuotes).join(', ') + ']'
|
||||
);
|
||||
message += '\n';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return message;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return value => {
|
||||
let exclusiveMax: number | undefined;
|
||||
let exclusiveMin: number | undefined;
|
||||
|
||||
@@ -250,4 +250,82 @@ suite('Preferences Model test', () => {
|
||||
withMessage.rejects(' ').withMessage('always error!');
|
||||
withMessage.rejects('1').withMessage('always error!');
|
||||
});
|
||||
});
|
||||
|
||||
class ArrayTester {
|
||||
private validator: (value: any) => string | null;
|
||||
|
||||
constructor(private settings: IConfigurationPropertySchema) {
|
||||
this.validator = createValidator(settings)!;
|
||||
}
|
||||
|
||||
public accepts(input: string[]) {
|
||||
assert.equal(this.validator(input), '', `Expected ${JSON.stringify(this.settings)} to accept \`${JSON.stringify(input)}\`. Got ${this.validator(input)}.`);
|
||||
}
|
||||
|
||||
public rejects(input: any[]) {
|
||||
assert.notEqual(this.validator(input), '', `Expected ${JSON.stringify(this.settings)} to reject \`${JSON.stringify(input)}\`.`);
|
||||
return {
|
||||
withMessage:
|
||||
(message: string) => {
|
||||
const actual = this.validator(input);
|
||||
assert.ok(actual);
|
||||
assert(actual!.indexOf(message) > -1,
|
||||
`Expected error of ${JSON.stringify(this.settings)} on \`${input}\` to contain ${message}. Got ${this.validator(input)}.`);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
test('simple array', () => {
|
||||
{
|
||||
const arr = new ArrayTester({ type: 'array', items: { type: 'string' } });
|
||||
arr.accepts([]);
|
||||
arr.accepts(['foo']);
|
||||
arr.accepts(['foo', 'bar']);
|
||||
}
|
||||
});
|
||||
|
||||
test('min-max items array', () => {
|
||||
{
|
||||
const arr = new ArrayTester({ type: 'array', items: { type: 'string' }, minItems: 1, maxItems: 2 });
|
||||
arr.rejects([]).withMessage('Array must have at least 1 items');
|
||||
arr.accepts(['a']);
|
||||
arr.accepts(['a', 'a']);
|
||||
arr.rejects(['a', 'a', 'a']).withMessage('Array must have less than 2 items');
|
||||
}
|
||||
});
|
||||
|
||||
test('array of enums', () => {
|
||||
{
|
||||
const arr = new ArrayTester({ type: 'array', items: { type: 'string', enum: ['a', 'b'] } });
|
||||
arr.accepts(['a']);
|
||||
arr.accepts(['a', 'b']);
|
||||
|
||||
arr.rejects(['c']).withMessage(`Value 'c' is not one of`);
|
||||
arr.rejects(['a', 'c']).withMessage(`Value 'c' is not one of`);
|
||||
|
||||
arr.rejects(['c', 'd']).withMessage(`Value 'c' is not one of`);
|
||||
arr.rejects(['c', 'd']).withMessage(`Value 'd' is not one of`);
|
||||
}
|
||||
});
|
||||
|
||||
test('min-max and enum', () => {
|
||||
const arr = new ArrayTester({ type: 'array', items: { type: 'string', enum: ['a', 'b'] }, minItems: 1, maxItems: 2 });
|
||||
|
||||
arr.rejects(['a', 'b', 'c']).withMessage('Array must have less than 2 items');
|
||||
arr.rejects(['a', 'b', 'c']).withMessage(`Value 'c' is not one of`);
|
||||
});
|
||||
|
||||
test('pattern', () => {
|
||||
const arr = new ArrayTester({ type: 'array', items: { type: 'string', pattern: '^(hello)*$' } });
|
||||
|
||||
arr.accepts(['hello']);
|
||||
arr.rejects(['a']).withMessage(`Value 'a' must match regex`);
|
||||
});
|
||||
|
||||
test('pattern with error message', () => {
|
||||
const arr = new ArrayTester({ type: 'array', items: { type: 'string', pattern: '^(hello)*$', patternErrorMessage: 'err: must be friendly' } });
|
||||
|
||||
arr.rejects(['a']).withMessage(`err: must be friendly`);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -46,7 +46,7 @@ export class ProgressService extends Disposable implements IProgressService {
|
||||
super();
|
||||
}
|
||||
|
||||
withProgress<R = unknown>(options: IProgressOptions, task: (progress: IProgress<IProgressStep>) => Promise<R>, onDidCancel?: () => void): Promise<R> {
|
||||
withProgress<R = unknown>(options: IProgressOptions, task: (progress: IProgress<IProgressStep>) => Promise<R>, onDidCancel?: (choice?: number) => void): Promise<R> {
|
||||
const { location } = options;
|
||||
if (typeof location === 'string') {
|
||||
if (this.viewletService.getProgressIndicator(location)) {
|
||||
@@ -142,7 +142,7 @@ export class ProgressService extends Disposable implements IProgressService {
|
||||
}
|
||||
}
|
||||
|
||||
private withNotificationProgress<P extends Promise<R>, R = unknown>(options: IProgressNotificationOptions, callback: (progress: IProgress<{ message?: string, increment?: number }>) => P, onDidCancel?: () => void): P {
|
||||
private withNotificationProgress<P extends Promise<R>, R = unknown>(options: IProgressNotificationOptions, callback: (progress: IProgress<{ message?: string, increment?: number }>) => P, onDidCancel?: (choice?: number) => void): P {
|
||||
const toDispose = new DisposableStore();
|
||||
|
||||
const createNotification = (message: string | undefined, increment?: number): INotificationHandle | undefined => {
|
||||
@@ -152,6 +152,29 @@ export class ProgressService extends Disposable implements IProgressService {
|
||||
|
||||
const primaryActions = options.primaryActions ? Array.from(options.primaryActions) : [];
|
||||
const secondaryActions = options.secondaryActions ? Array.from(options.secondaryActions) : [];
|
||||
|
||||
if (options.buttons) {
|
||||
options.buttons.forEach((button, index) => {
|
||||
const buttonAction = new class extends Action {
|
||||
constructor() {
|
||||
super(`progress.button.${button}`, button, undefined, true);
|
||||
}
|
||||
|
||||
run(): Promise<any> {
|
||||
if (typeof onDidCancel === 'function') {
|
||||
onDidCancel(index);
|
||||
}
|
||||
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
};
|
||||
|
||||
toDispose.add(buttonAction);
|
||||
|
||||
primaryActions.push(buttonAction);
|
||||
});
|
||||
}
|
||||
|
||||
if (options.cancellable) {
|
||||
const cancelAction = new class extends Action {
|
||||
constructor() {
|
||||
@@ -182,6 +205,10 @@ export class ProgressService extends Disposable implements IProgressService {
|
||||
updateProgress(handle, increment);
|
||||
|
||||
Event.once(handle.onDidClose)(() => {
|
||||
if (typeof onDidCancel === 'function') {
|
||||
onDidCancel();
|
||||
}
|
||||
|
||||
toDispose.dispose();
|
||||
});
|
||||
|
||||
@@ -317,7 +344,7 @@ export class ProgressService extends Disposable implements IProgressService {
|
||||
return promise;
|
||||
}
|
||||
|
||||
private withDialogProgress<P extends Promise<R>, R = unknown>(options: IProgressOptions, task: (progress: IProgress<IProgressStep>) => P, onDidCancel?: () => void): P {
|
||||
private withDialogProgress<P extends Promise<R>, R = unknown>(options: IProgressOptions, task: (progress: IProgress<IProgressStep>) => P, onDidCancel?: (choice?: number) => void): P {
|
||||
const disposables = new DisposableStore();
|
||||
const allowableCommands = [
|
||||
'workbench.action.quit',
|
||||
@@ -327,12 +354,17 @@ export class ProgressService extends Disposable implements IProgressService {
|
||||
let dialog: Dialog;
|
||||
|
||||
const createDialog = (message: string) => {
|
||||
|
||||
const buttons = options.buttons || [];
|
||||
buttons.push(options.cancellable ? localize('cancel', "Cancel") : localize('dismiss', "Dismiss"));
|
||||
|
||||
dialog = new Dialog(
|
||||
this.layoutService.container,
|
||||
message,
|
||||
[options.cancellable ? localize('cancel', "Cancel") : localize('dismiss', "Dismiss")],
|
||||
buttons,
|
||||
{
|
||||
type: 'pending',
|
||||
cancelId: buttons.length - 1,
|
||||
keyEventProcessor: (event: StandardKeyboardEvent) => {
|
||||
const resolved = this.keybindingService.softDispatch(event, this.layoutService.container);
|
||||
if (resolved && resolved.commandId) {
|
||||
@@ -347,9 +379,9 @@ export class ProgressService extends Disposable implements IProgressService {
|
||||
disposables.add(dialog);
|
||||
disposables.add(attachDialogStyler(dialog, this.themeService));
|
||||
|
||||
dialog.show().then(() => {
|
||||
dialog.show().then((dialogResult) => {
|
||||
if (typeof onDidCancel === 'function') {
|
||||
onDidCancel();
|
||||
onDidCancel(dialogResult.button);
|
||||
}
|
||||
|
||||
dispose(dialog);
|
||||
|
||||
177
src/vs/workbench/services/url/browser/urlService.ts
Normal file
177
src/vs/workbench/services/url/browser/urlService.ts
Normal file
@@ -0,0 +1,177 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IURLService } from 'vs/platform/url/common/url';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { ServiceIdentifier, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { AbstractURLService } from 'vs/platform/url/common/urlService';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IRequestService } from 'vs/platform/request/common/request';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { streamToBuffer } from 'vs/base/common/buffer';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
|
||||
export interface IURLCallbackProvider {
|
||||
|
||||
/**
|
||||
* Indicates that a Uri has been opened outside of VSCode. The Uri
|
||||
* will be forwarded to all installed Uri handlers in the system.
|
||||
*/
|
||||
readonly onCallback: Event<URI>;
|
||||
|
||||
/**
|
||||
* Creates a Uri that - if opened in a browser - must result in
|
||||
* the `onCallback` to fire.
|
||||
*
|
||||
* The optional `Partial<UriComponents>` must be properly restored for
|
||||
* the Uri passed to the `onCallback` handler.
|
||||
*
|
||||
* For example: if a Uri is to be created with `scheme:"vscode"`,
|
||||
* `authority:"foo"` and `path:"bar"` the `onCallback` should fire
|
||||
* with a Uri `vscode://foo/bar`.
|
||||
*
|
||||
* If there are additional `query` values in the Uri, they should
|
||||
* be added to the list of provided `query` arguments from the
|
||||
* `Partial<UriComponents>`.
|
||||
*/
|
||||
create(options?: Partial<UriComponents>): URI;
|
||||
}
|
||||
|
||||
export class BrowserURLService extends AbstractURLService {
|
||||
|
||||
_serviceBrand!: ServiceIdentifier<any>;
|
||||
|
||||
private provider: IURLCallbackProvider;
|
||||
|
||||
constructor(
|
||||
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService,
|
||||
@IInstantiationService instantiationService: IInstantiationService
|
||||
) {
|
||||
super();
|
||||
|
||||
this.provider = environmentService.options && environmentService.options.urlCallbackProvider ? environmentService.options.urlCallbackProvider : instantiationService.createInstance(SelfhostURLCallbackProvider);
|
||||
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
this._register(this.provider.onCallback(uri => this.open(uri)));
|
||||
}
|
||||
|
||||
create(options?: Partial<UriComponents>): URI {
|
||||
return this.provider.create(options);
|
||||
}
|
||||
}
|
||||
|
||||
class SelfhostURLCallbackProvider extends Disposable implements IURLCallbackProvider {
|
||||
|
||||
static FETCH_INTERVAL = 500; // fetch every 500ms
|
||||
static FETCH_TIMEOUT = 5 * 60 * 1000; // ...but stop after 5min
|
||||
|
||||
static QUERY_KEYS = {
|
||||
REQUEST_ID: 'vscode-requestId',
|
||||
SCHEME: 'vscode-scheme',
|
||||
AUTHORITY: 'vscode-authority',
|
||||
PATH: 'vscode-path',
|
||||
QUERY: 'vscode-query',
|
||||
FRAGMENT: 'vscode-fragment'
|
||||
};
|
||||
|
||||
private readonly _onCallback: Emitter<URI> = this._register(new Emitter<URI>());
|
||||
readonly onCallback: Event<URI> = this._onCallback.event;
|
||||
|
||||
constructor(
|
||||
@IRequestService private readonly requestService: IRequestService,
|
||||
@ILogService private readonly logService: ILogService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
create(options?: Partial<UriComponents>): URI {
|
||||
const queryValues: Map<string, string> = new Map();
|
||||
|
||||
const requestId = generateUuid();
|
||||
queryValues.set(SelfhostURLCallbackProvider.QUERY_KEYS.REQUEST_ID, requestId);
|
||||
|
||||
const { scheme, authority, path, query, fragment } = options ? options : { scheme: undefined, authority: undefined, path: undefined, query: undefined, fragment: undefined };
|
||||
|
||||
if (scheme) {
|
||||
queryValues.set(SelfhostURLCallbackProvider.QUERY_KEYS.SCHEME, scheme);
|
||||
}
|
||||
|
||||
if (authority) {
|
||||
queryValues.set(SelfhostURLCallbackProvider.QUERY_KEYS.AUTHORITY, authority);
|
||||
}
|
||||
|
||||
if (path) {
|
||||
queryValues.set(SelfhostURLCallbackProvider.QUERY_KEYS.PATH, path);
|
||||
}
|
||||
|
||||
if (query) {
|
||||
queryValues.set(SelfhostURLCallbackProvider.QUERY_KEYS.QUERY, query);
|
||||
}
|
||||
|
||||
if (fragment) {
|
||||
queryValues.set(SelfhostURLCallbackProvider.QUERY_KEYS.FRAGMENT, fragment);
|
||||
}
|
||||
|
||||
// Start to poll on the callback being fired
|
||||
this.periodicFetchCallback(requestId, Date.now());
|
||||
|
||||
return this.doCreateUri('/callback', queryValues);
|
||||
}
|
||||
|
||||
private async periodicFetchCallback(requestId: string, startTime: number): Promise<void> {
|
||||
|
||||
// Ask server for callback results
|
||||
const queryValues: Map<string, string> = new Map();
|
||||
queryValues.set(SelfhostURLCallbackProvider.QUERY_KEYS.REQUEST_ID, requestId);
|
||||
|
||||
const result = await this.requestService.request({
|
||||
url: this.doCreateUri('/fetch-callback', queryValues).toString(true)
|
||||
}, CancellationToken.None);
|
||||
|
||||
// Check for callback results
|
||||
const content = await streamToBuffer(result.stream);
|
||||
if (content.byteLength > 0) {
|
||||
try {
|
||||
this._onCallback.fire(URI.revive(JSON.parse(content.toString())));
|
||||
} catch (error) {
|
||||
this.logService.error(error);
|
||||
}
|
||||
|
||||
return; // done
|
||||
}
|
||||
|
||||
// Continue fetching unless we hit the timeout
|
||||
if (Date.now() - startTime < SelfhostURLCallbackProvider.FETCH_TIMEOUT) {
|
||||
setTimeout(() => this.periodicFetchCallback(requestId, startTime), SelfhostURLCallbackProvider.FETCH_INTERVAL);
|
||||
}
|
||||
}
|
||||
|
||||
private doCreateUri(path: string, queryValues: Map<string, string>): URI {
|
||||
let query: string | undefined = undefined;
|
||||
|
||||
if (queryValues) {
|
||||
let index = 0;
|
||||
queryValues.forEach((value, key) => {
|
||||
if (!query) {
|
||||
query = '';
|
||||
}
|
||||
|
||||
const prefix = (index++ === 0) ? '' : '&';
|
||||
query += `${prefix}${key}=${encodeURIComponent(value)}`;
|
||||
});
|
||||
}
|
||||
|
||||
return URI.parse(window.location.href).with({ path, query });
|
||||
}
|
||||
}
|
||||
|
||||
registerSingleton(IURLService, BrowserURLService, true);
|
||||
48
src/vs/workbench/services/url/electron-browser/urlService.ts
Normal file
48
src/vs/workbench/services/url/electron-browser/urlService.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IURLService, IURLHandler } from 'vs/platform/url/common/url';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService';
|
||||
import { URLServiceChannelClient, URLHandlerChannel } from 'vs/platform/url/node/urlIpc';
|
||||
import { URLService } from 'vs/platform/url/node/urlService';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import product from 'vs/platform/product/node/product';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
|
||||
export class RelayURLService extends URLService implements IURLHandler {
|
||||
|
||||
private urlService: IURLService;
|
||||
|
||||
constructor(
|
||||
@IMainProcessService mainProcessService: IMainProcessService,
|
||||
@IOpenerService openerService: IOpenerService
|
||||
) {
|
||||
super();
|
||||
|
||||
this.urlService = new URLServiceChannelClient(mainProcessService.getChannel('url'));
|
||||
|
||||
mainProcessService.registerChannel('urlHandler', new URLHandlerChannel(this));
|
||||
openerService.registerOpener(this);
|
||||
}
|
||||
|
||||
async open(resource: URI, options?: { openToSide?: boolean, openExternal?: boolean }): Promise<boolean> {
|
||||
if (options && options.openExternal) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (resource.scheme !== product.urlProtocol) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return await this.urlService.open(resource);
|
||||
}
|
||||
|
||||
handleURL(uri: URI): Promise<boolean> {
|
||||
return super.open(uri);
|
||||
}
|
||||
}
|
||||
|
||||
registerSingleton(IURLService, RelayURLService);
|
||||
Reference in New Issue
Block a user