mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-13 17:22:15 -05:00
Merge from vscode 8b5ebbb1b8f6b2127bbbd551ac10cc080482d5b4 (#5041)
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
"vscode": "^1.20.0"
|
||||
},
|
||||
"main": "./out/extension",
|
||||
"extensionKind": "ui",
|
||||
"categories": [
|
||||
"Programming Languages"
|
||||
],
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
"selection.background": "#ccccc7",
|
||||
"editor.selectionHighlightBackground": "#575b6180",
|
||||
"editor.selectionBackground": "#878b9180",
|
||||
"editor.wordHighlightBackground": "#4a4a7680",
|
||||
"editor.wordHighlightStrongBackground": "#6a6a9680",
|
||||
"editor.wordHighlightBackground": "#4a4a7680",
|
||||
"editor.wordHighlightStrongBackground": "#6a6a9680",
|
||||
"editor.lineHighlightBackground": "#3e3d32",
|
||||
"editorLineNumber.activeForeground": "#c2c2bf",
|
||||
"editorCursor.foreground": "#f8f8f0",
|
||||
|
||||
@@ -163,7 +163,7 @@ function darkenColor(color) {
|
||||
for (let i = 1; i < 7; i += 2) {
|
||||
let newVal = Math.round(parseInt('0x' + color.substr(i, 2), 16) * 0.9);
|
||||
let hex = newVal.toString(16);
|
||||
if (hex.length == 1) {
|
||||
if (hex.length === 1) {
|
||||
res += '0';
|
||||
}
|
||||
res += hex;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
COMMIT="@@COMMIT@@"
|
||||
APP_NAME="@@APPNAME@@"
|
||||
QUALITY="@@QUALITY@@"
|
||||
NAME="@@NAME@@"
|
||||
|
||||
set -e
|
||||
|
||||
@@ -22,6 +23,8 @@ if grep -qi Microsoft /proc/version; then
|
||||
fi
|
||||
fi
|
||||
|
||||
VSCODE_PATH="$(dirname "$(dirname "$(realpath "$0")")")"
|
||||
|
||||
if [ -x "$(command -v cygpath)" ]; then
|
||||
CLI=$(cygpath -m "$VSCODE_PATH/resources/app/out/cli.js")
|
||||
else
|
||||
|
||||
@@ -59,19 +59,19 @@ function code-wsl()
|
||||
{
|
||||
# in a wsl shell
|
||||
local WIN_CODE_CLI_CMD=$(wslpath -w "$ROOT/scripts/code-cli.bat")
|
||||
|
||||
local WSL_EXT_ID="ms-vscode.remote-wsl"
|
||||
local WSL_EXT_WLOC=$(cmd.exe /c "$WIN_CODE_CLI_CMD" --locate-extension $WSL_EXT_ID)
|
||||
if ! [ -z "$WSL_EXT_WLOC" ]; then
|
||||
# replace \r\n with \n in WSL_EXT_WLOC
|
||||
local WSL_CODE=$(wslpath -u "${WSL_EXT_WLOC%%[[:cntrl:]]}")/scripts/wslCode-dev.sh
|
||||
$WSL_CODE "$ROOT" "$@"
|
||||
exit $?
|
||||
if ! [ -z "$WIN_CODE_CLI_CMD" ]; then
|
||||
local WSL_EXT_ID="ms-vscode.remote-wsl"
|
||||
local WSL_EXT_WLOC=$(cmd.exe /c "$WIN_CODE_CLI_CMD" --locate-extension $WSL_EXT_ID)
|
||||
if ! [ -z "$WSL_EXT_WLOC" ]; then
|
||||
# replace \r\n with \n in WSL_EXT_WLOC
|
||||
local WSL_CODE=$(wslpath -u "${WSL_EXT_WLOC%%[[:cntrl:]]}")/scripts/wslCode-dev.sh
|
||||
$WSL_CODE "$ROOT" "$@"
|
||||
exit $?
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
if [ -z ${IN_WSL+x} ]; then
|
||||
code "$@"
|
||||
else
|
||||
if ! [ -z ${IN_WSL+x} ]; then
|
||||
code-wsl "$@"
|
||||
fi
|
||||
fi
|
||||
code "$@"
|
||||
@@ -20,6 +20,7 @@ export interface IDialogOptions {
|
||||
cancelId?: number;
|
||||
detail?: string;
|
||||
type?: 'none' | 'info' | 'error' | 'question' | 'warning' | 'pending';
|
||||
keyEventProcessor?: (event: StandardKeyboardEvent) => void;
|
||||
}
|
||||
|
||||
export interface IDialogStyles extends IButtonStyles {
|
||||
@@ -103,19 +104,26 @@ export class Dialog extends Disposable {
|
||||
return;
|
||||
}
|
||||
|
||||
let eventHandled = false;
|
||||
if (this.buttonGroup) {
|
||||
if (evt.equals(KeyMod.Shift | KeyCode.Tab) || evt.equals(KeyCode.LeftArrow)) {
|
||||
focusedButton = focusedButton + this.buttonGroup.buttons.length - 1;
|
||||
focusedButton = focusedButton % this.buttonGroup.buttons.length;
|
||||
this.buttonGroup.buttons[focusedButton].focus();
|
||||
eventHandled = true;
|
||||
} else if (evt.equals(KeyCode.Tab) || evt.equals(KeyCode.RightArrow)) {
|
||||
focusedButton++;
|
||||
focusedButton = focusedButton % this.buttonGroup.buttons.length;
|
||||
this.buttonGroup.buttons[focusedButton].focus();
|
||||
eventHandled = true;
|
||||
}
|
||||
}
|
||||
|
||||
EventHelper.stop(e, true);
|
||||
if (eventHandled) {
|
||||
EventHelper.stop(e, true);
|
||||
} else if (this.options.keyEventProcessor) {
|
||||
this.options.keyEventProcessor(evt);
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(domEvent(window, 'keyup', true)((e: KeyboardEvent) => {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
.monaco-sash {
|
||||
position: absolute;
|
||||
z-index: 90;
|
||||
z-index: 35;
|
||||
touch-action: none;
|
||||
}
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ export default (): string => `
|
||||
<input class="sendData" type="checkbox" id="includeSystemInfo" checked/>
|
||||
<label class="caption" for="includeSystemInfo">${escape(localize({
|
||||
key: 'sendSystemInfo',
|
||||
comment: ['{0} is either "show" or "hide" and is a button to toggle the visibililty of the system information']
|
||||
comment: ['{0} is either "show" or "hide" and is a button to toggle the visibility of the system information']
|
||||
}, "Include my system information ({0})")).replace('{0}', `<a href="#" class="showInfo">${escape(localize('show', "show"))}</a>`)}</label>
|
||||
<div class="block-info hidden">
|
||||
<!-- To be dynamically filled -->
|
||||
@@ -73,7 +73,7 @@ export default (): string => `
|
||||
<input class="sendData" type="checkbox" id="includeProcessInfo" checked/>
|
||||
<label class="caption" for="includeProcessInfo">${escape(localize({
|
||||
key: 'sendProcessInfo',
|
||||
comment: ['{0} is either "show" or "hide" and is a button to toggle the visibililty of the process info']
|
||||
comment: ['{0} is either "show" or "hide" and is a button to toggle the visibility of the process info']
|
||||
}, "Include my currently running processes ({0})")).replace('{0}', `<a href="#" class="showInfo">${escape(localize('show', "show"))}</a>`)}</label>
|
||||
<pre class="block-info hidden">
|
||||
<code>
|
||||
@@ -85,7 +85,7 @@ export default (): string => `
|
||||
<input class="sendData" type="checkbox" id="includeWorkspaceInfo" checked/>
|
||||
<label class="caption" for="includeWorkspaceInfo">${escape(localize({
|
||||
key: 'sendWorkspaceInfo',
|
||||
comment: ['{0} is either "show" or "hide" and is a button to toggle the visibililty of the workspace information']
|
||||
comment: ['{0} is either "show" or "hide" and is a button to toggle the visibility of the workspace information']
|
||||
}, "Include my workspace metadata ({0})")).replace('{0}', `<a href="#" class="showInfo">${escape(localize('show', "show"))}</a>`)}</label>
|
||||
<pre id="systemInfo" class="block-info hidden">
|
||||
<code>
|
||||
@@ -97,7 +97,7 @@ export default (): string => `
|
||||
<input class="sendData" type="checkbox" id="includeExtensions" checked/>
|
||||
<label class="caption" for="includeExtensions">${escape(localize({
|
||||
key: 'sendExtensions',
|
||||
comment: ['{0} is either "show" or "hide" and is a button to toggle the visibililty of the enabled extensions list']
|
||||
comment: ['{0} is either "show" or "hide" and is a button to toggle the visibility of the enabled extensions list']
|
||||
}, "Include my enabled extensions ({0})")).replace('{0}', `<a href="#" class="showInfo">${escape(localize('show', "show"))}</a>`)}</label>
|
||||
<div id="systemInfo" class="block-info hidden">
|
||||
<!-- To be dynamically filled -->
|
||||
@@ -107,7 +107,7 @@ export default (): string => `
|
||||
<input class="sendData" type="checkbox" id="includeSearchedExtensions" checked/>
|
||||
<label class="caption" for="includeSearchedExtensions">${escape(localize({
|
||||
key: 'sendSearchedExtensions',
|
||||
comment: ['{0} is either "show" or "hide" and is a button to toggle the visibililty of the searched extensions']
|
||||
comment: ['{0} is either "show" or "hide" and is a button to toggle the visibility of the searched extensions']
|
||||
}, "Send searched extensions ({0})")).replace('{0}', `<a href="#" class="showInfo">${escape(localize('show', "show"))}</a>`)}</label>
|
||||
<div class="block-info hidden">
|
||||
<!-- To be dynamically filled -->
|
||||
@@ -117,7 +117,7 @@ export default (): string => `
|
||||
<input class="sendData" type="checkbox" id="includeSettingsSearchDetails" checked/>
|
||||
<label class="caption" for="includeSettingsSearchDetails">${escape(localize({
|
||||
key: 'sendSettingsSearchDetails',
|
||||
comment: ['{0} is either "show" or "hide" and is a button to toggle the visibililty of the search details']
|
||||
comment: ['{0} is either "show" or "hide" and is a button to toggle the visibility of the search details']
|
||||
}, "Send settings search details ({0})")).replace('{0}', `<a href="#" class="showInfo">${escape(localize('show', "show"))}</a>`)}</label>
|
||||
<div class="block-info hidden">
|
||||
<!-- To be dynamically filled -->
|
||||
|
||||
@@ -543,7 +543,7 @@ export class TextAreaHandler extends ViewPart {
|
||||
}
|
||||
|
||||
// (in WebKit the textarea is 1px by 1px because it cannot handle input to a 0x0 textarea)
|
||||
// specifically, when doing Korean IME, setting the textare to 0x0 breaks IME badly.
|
||||
// specifically, when doing Korean IME, setting the textarea to 0x0 breaks IME badly.
|
||||
|
||||
ta.setWidth(1);
|
||||
ta.setHeight(1);
|
||||
|
||||
@@ -344,7 +344,7 @@ export class TextAreaInput extends Disposable {
|
||||
//
|
||||
// The problems with the `selectionchange` event are:
|
||||
// * the event is emitted when the textarea is focused programmatically -- textarea.focus()
|
||||
// * the event is emitted when the selection is changed in the textarea programatically -- textarea.setSelectionRange(...)
|
||||
// * the event is emitted when the selection is changed in the textarea programmatically -- textarea.setSelectionRange(...)
|
||||
// * the event is emitted when the value of the textarea is changed programmatically -- textarea.value = '...'
|
||||
// * the event is emitted when tabbing into the textarea
|
||||
// * the event is emitted asynchronously (sometimes with a delay as high as a few tens of ms)
|
||||
|
||||
@@ -1408,6 +1408,14 @@ export interface WorkspaceCommentProvider {
|
||||
onDidChangeCommentThreads(): Event<CommentThreadChangedEvent>;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export interface IWebviewPortMapping {
|
||||
webviewPort: number;
|
||||
extensionHostPort: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
@@ -1415,7 +1423,7 @@ export interface IWebviewOptions {
|
||||
readonly enableScripts?: boolean;
|
||||
readonly enableCommandUris?: boolean;
|
||||
readonly localResourceRoots?: ReadonlyArray<URI>;
|
||||
readonly portMapping?: ReadonlyArray<{ port: number, resolvedPort: number }>;
|
||||
readonly portMapping?: ReadonlyArray<IWebviewPortMapping>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,6 +13,8 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { attachDialogStyler } from 'vs/platform/theme/common/styler';
|
||||
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { EventHelper } from 'vs/base/browser/dom';
|
||||
|
||||
export class DialogService implements IDialogService {
|
||||
_serviceBrand: any;
|
||||
@@ -76,7 +78,10 @@ export class DialogService implements IDialogService {
|
||||
{
|
||||
detail: options ? options.detail : undefined,
|
||||
cancelId: options ? options.cancelId : undefined,
|
||||
type: this.getDialogType(severity)
|
||||
type: this.getDialogType(severity),
|
||||
keyEventProcessor: (event: StandardKeyboardEvent) => {
|
||||
EventHelper.stop(event, true);
|
||||
}
|
||||
});
|
||||
|
||||
dialogDisposables.push(dialog);
|
||||
|
||||
@@ -206,12 +206,14 @@ export function buildHelpMessage(productName: string, executableName: string, ve
|
||||
help.push('');
|
||||
help.push(`${localize('usage', "Usage")}: ${executableName} [${localize('options', "options")}][${localize('paths', 'paths')}...]`);
|
||||
help.push('');
|
||||
if (os.platform() === 'win32') {
|
||||
help.push(localize('stdinWindows', "To read output from another program, append '-' (e.g. 'echo Hello World | {0} -')", executableName));
|
||||
} else {
|
||||
help.push(localize('stdinUnix', "To read from stdin, append '-' (e.g. 'ps aux | grep code | {0} -')", executableName));
|
||||
if (isPipeSupported) {
|
||||
if (os.platform() === 'win32') {
|
||||
help.push(localize('stdinWindows', "To read output from another program, append '-' (e.g. 'echo Hello World | {0} -')", executableName));
|
||||
} else {
|
||||
help.push(localize('stdinUnix', "To read from stdin, append '-' (e.g. 'ps aux | grep code | {0} -')", executableName));
|
||||
}
|
||||
help.push('');
|
||||
}
|
||||
help.push('');
|
||||
for (let key in categories) {
|
||||
let categoryOptions = options.filter(o => !!o.description && o.cat === key && isOptionSupported(o));
|
||||
if (categoryOptions.length) {
|
||||
|
||||
@@ -12,13 +12,11 @@ import product from 'vs/platform/product/node/product';
|
||||
export function isUIExtension(manifest: IExtensionManifest, uiContributions: string[], configurationService: IConfigurationService): boolean {
|
||||
const extensionId = getGalleryExtensionId(manifest.publisher, manifest.name);
|
||||
const configuredUIExtensions = configurationService.getValue<string[]>('_workbench.uiExtensions') || [];
|
||||
if (configuredUIExtensions.length) {
|
||||
if (configuredUIExtensions.indexOf(extensionId) !== -1) {
|
||||
return true;
|
||||
}
|
||||
if (configuredUIExtensions.indexOf(`-${extensionId}`) !== -1) {
|
||||
return false;
|
||||
}
|
||||
if (configuredUIExtensions.some(id => areSameExtensions({ id }, { id: extensionId }))) {
|
||||
return true;
|
||||
}
|
||||
if (configuredUIExtensions.some(id => areSameExtensions({ id }, { id: `-${extensionId}` }))) {
|
||||
return false;
|
||||
}
|
||||
switch (manifest.extensionKind) {
|
||||
case 'ui': return true;
|
||||
|
||||
@@ -162,6 +162,16 @@ export interface IQuickPick<T extends IQuickPickItem> extends IQuickInput {
|
||||
|
||||
readonly onDidAccept: Event<void>;
|
||||
|
||||
ok: boolean;
|
||||
|
||||
readonly onDidCustom: Event<void>;
|
||||
|
||||
customButton: boolean;
|
||||
|
||||
customLabel: string;
|
||||
|
||||
customHover: string;
|
||||
|
||||
buttons: ReadonlyArray<IQuickInputButton>;
|
||||
|
||||
readonly onDidTriggerButton: Event<IQuickInputButton>;
|
||||
|
||||
@@ -7,6 +7,7 @@ import { Client, PersistentProtocol, ISocket } from 'vs/base/parts/ipc/common/ip
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { RemoteAgentConnectionContext } from 'vs/platform/remote/common/remoteAgentEnvironment';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
|
||||
export const enum ConnectionType {
|
||||
Management = 1,
|
||||
@@ -147,8 +148,38 @@ export async function connectRemoteAgentTunnel(options: IConnectionOptions, tunn
|
||||
return protocol;
|
||||
}
|
||||
|
||||
export const enum PersistenConnectionEventType {
|
||||
ConnectionLost,
|
||||
ReconnectionWait,
|
||||
ReconnectionRunning,
|
||||
ReconnectionPermanentFailure,
|
||||
ConnectionGain
|
||||
}
|
||||
export class ConnectionLostEvent {
|
||||
public readonly type = PersistenConnectionEventType.ConnectionLost;
|
||||
}
|
||||
export class ReconnectionWaitEvent {
|
||||
public readonly type = PersistenConnectionEventType.ReconnectionWait;
|
||||
constructor(
|
||||
public readonly durationSeconds: number
|
||||
) { }
|
||||
}
|
||||
export class ReconnectionRunningEvent {
|
||||
public readonly type = PersistenConnectionEventType.ReconnectionRunning;
|
||||
}
|
||||
export class ConnectionGainEvent {
|
||||
public readonly type = PersistenConnectionEventType.ConnectionGain;
|
||||
}
|
||||
export class ReconnectionPermanentFailureEvent {
|
||||
public readonly type = PersistenConnectionEventType.ReconnectionPermanentFailure;
|
||||
}
|
||||
export type PersistenConnectionEvent = ConnectionLostEvent | ReconnectionWaitEvent | ReconnectionRunningEvent | ConnectionGainEvent | ReconnectionPermanentFailureEvent;
|
||||
|
||||
abstract class PersistentConnection extends Disposable {
|
||||
|
||||
private readonly _onDidStateChange = this._register(new Emitter<PersistenConnectionEvent>());
|
||||
public readonly onDidStateChange = this._onDidStateChange.event;
|
||||
|
||||
protected readonly _options: IConnectionOptions;
|
||||
public readonly reconnectionToken: string;
|
||||
public readonly protocol: PersistentProtocol;
|
||||
|
||||
27
src/vs/vscode.d.ts
vendored
27
src/vs/vscode.d.ts
vendored
@@ -5714,6 +5714,21 @@ declare module 'vscode' {
|
||||
copy?(source: Uri, destination: Uri, options: { overwrite: boolean }): void | Thenable<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines a port mapping used for localhost inside the webview.
|
||||
*/
|
||||
export interface WebviewPortMapping {
|
||||
/**
|
||||
* Localhost port to remap inside the webview.
|
||||
*/
|
||||
readonly webviewPort: number;
|
||||
|
||||
/**
|
||||
* Destination port. The `webviewPort` is resolved to this port.
|
||||
*/
|
||||
readonly extensionHostPort: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Content settings for a webview.
|
||||
*/
|
||||
@@ -5740,6 +5755,18 @@ declare module 'vscode' {
|
||||
* Pass in an empty array to disallow access to any local resources.
|
||||
*/
|
||||
readonly localResourceRoots?: ReadonlyArray<Uri>;
|
||||
|
||||
/**
|
||||
* Mappings of localhost ports used inside the webview.
|
||||
*
|
||||
* Port mapping allow webviews to transparently define how localhost ports are resolved. This can be used
|
||||
* to allow using a static localhost port inside the webview that is resolved to random port that a service is
|
||||
* running on.
|
||||
*
|
||||
* If a webview accesses localhost content, we recomend that you specify port mappings even if
|
||||
* the `webviewPort` and `extensionHostPort` ports are the same.
|
||||
*/
|
||||
readonly portMapping?: ReadonlyArray<WebviewPortMapping>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
31
src/vs/vscode.proposed.d.ts
vendored
31
src/vs/vscode.proposed.d.ts
vendored
@@ -1360,35 +1360,4 @@ declare module 'vscode' {
|
||||
group?: string;
|
||||
}
|
||||
//#endregion
|
||||
|
||||
//#region Webview Port mapping— mjbvz
|
||||
/**
|
||||
* Defines a port mapping used for localhost inside the webview.
|
||||
*/
|
||||
export interface WebviewPortMapping {
|
||||
/**
|
||||
* Localhost port to remap inside the webview.
|
||||
*/
|
||||
readonly port: number;
|
||||
|
||||
/**
|
||||
* Destination port. The `port` is resolved to this port.
|
||||
*/
|
||||
readonly resolvedPort: number;
|
||||
}
|
||||
|
||||
export interface WebviewOptions {
|
||||
/**
|
||||
* Mappings of localhost ports used inside the webview.
|
||||
*
|
||||
* Port mapping allow webviews to transparently define how localhost ports are resolved. This can be used
|
||||
* to allow using a static localhost port inside the webview that is resolved to random port that a service is
|
||||
* running on.
|
||||
*
|
||||
* If a webview accesses localhost content, we recomend that you specify port mappings even if
|
||||
* the `port` and `resolvedPort` ports are the same.
|
||||
*/
|
||||
readonly portMapping?: ReadonlyArray<WebviewPortMapping>;
|
||||
}
|
||||
//#endregion
|
||||
}
|
||||
|
||||
@@ -51,6 +51,8 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
if (activeInstance) {
|
||||
this._proxy.$acceptActiveTerminalChanged(activeInstance.id);
|
||||
}
|
||||
|
||||
this.terminalService.extHostReady(extHostContext.remoteAuthority);
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
|
||||
@@ -8,7 +8,7 @@ import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { ExtHostContext, ExtHostWindowShape, IExtHostContext, MainContext, MainThreadWindowShape } from '../common/extHost.protocol';
|
||||
import { ExtHostContext, ExtHostWindowShape, IExtHostContext, MainContext, MainThreadWindowShape, IOpenUriOptions } from '../common/extHost.protocol';
|
||||
import { ITunnelService, RemoteTunnel } from 'vs/platform/remote/common/tunnel';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
|
||||
@@ -45,9 +45,9 @@ export class MainThreadWindow implements MainThreadWindowShape {
|
||||
return this.windowService.isFocused();
|
||||
}
|
||||
|
||||
async $openUri(uriComponent: UriComponents): Promise<boolean> {
|
||||
async $openUri(uriComponent: UriComponents, options: IOpenUriOptions): Promise<boolean> {
|
||||
const uri = URI.revive(uriComponent);
|
||||
if (!!this.environmentService.configuration.remoteAuthority) {
|
||||
if (options.allowTunneling && !!this.environmentService.configuration.remoteAuthority) {
|
||||
if (uri.scheme === 'http' || uri.scheme === 'https') {
|
||||
const port = this.getLocalhostPort(uri);
|
||||
if (typeof port === 'number') {
|
||||
|
||||
@@ -539,7 +539,7 @@ export interface ExtHostWebviewsShape {
|
||||
$onMessage(handle: WebviewPanelHandle, message: any): void;
|
||||
$onDidChangeWebviewPanelViewState(handle: WebviewPanelHandle, newState: WebviewPanelViewState): void;
|
||||
$onDidDisposeWebviewPanel(handle: WebviewPanelHandle): Promise<void>;
|
||||
$deserializeWebviewPanel(newWebviewHandle: WebviewPanelHandle, viewType: string, title: string, state: any, position: EditorViewColumn, options: modes.IWebviewOptions): Promise<void>;
|
||||
$deserializeWebviewPanel(newWebviewHandle: WebviewPanelHandle, viewType: string, title: string, state: any, position: EditorViewColumn, options: modes.IWebviewOptions & modes.IWebviewPanelOptions): Promise<void>;
|
||||
}
|
||||
|
||||
export interface MainThreadUrlsShape extends IDisposable {
|
||||
@@ -689,9 +689,13 @@ export interface MainThreadDebugServiceShape extends IDisposable {
|
||||
$unregisterBreakpoints(breakpointIds: string[], functionBreakpointIds: string[]): Promise<void>;
|
||||
}
|
||||
|
||||
export interface IOpenUriOptions {
|
||||
readonly allowTunneling?: boolean;
|
||||
}
|
||||
|
||||
export interface MainThreadWindowShape extends IDisposable {
|
||||
$getWindowVisibility(): Promise<boolean>;
|
||||
$openUri(uri: UriComponents): Promise<boolean>;
|
||||
$openUri(uri: UriComponents, options: IOpenUriOptions): Promise<boolean>;
|
||||
}
|
||||
|
||||
// -- extension host
|
||||
|
||||
@@ -11,6 +11,7 @@ import * as vscode from 'vscode';
|
||||
import { ExtHostWebviewsShape, IMainContext, MainContext, MainThreadWebviewsShape, WebviewPanelHandle, WebviewPanelViewState, WebviewInsetHandle } from './extHost.protocol';
|
||||
import { Disposable } from './extHostTypes';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
|
||||
type IconPath = URI | { light: URI, dark: URI };
|
||||
|
||||
@@ -58,7 +59,7 @@ export class ExtHostWebview implements vscode.Webview {
|
||||
|
||||
public set options(newOptions: vscode.WebviewOptions) {
|
||||
this.assertNotDisposed();
|
||||
this._proxy.$setOptions(this._handle, newOptions);
|
||||
this._proxy.$setOptions(this._handle, convertWebviewOptions(newOptions));
|
||||
this._options = newOptions;
|
||||
}
|
||||
|
||||
@@ -257,7 +258,7 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
|
||||
};
|
||||
|
||||
const handle = ExtHostWebviews.newHandle();
|
||||
this._proxy.$createWebviewPanel(handle, viewType, title, webviewShowOptions, options, extension.identifier, extension.extensionLocation);
|
||||
this._proxy.$createWebviewPanel(handle, viewType, title, webviewShowOptions, convertWebviewOptions(options), extension.identifier, extension.extensionLocation);
|
||||
|
||||
const webview = new ExtHostWebview(handle, this._proxy, options);
|
||||
const panel = new ExtHostWebviewPanel(handle, this._proxy, viewType, title, viewColumn, options, webview);
|
||||
@@ -325,7 +326,7 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
|
||||
title: string,
|
||||
state: any,
|
||||
position: EditorViewColumn,
|
||||
options: vscode.WebviewOptions & vscode.WebviewPanelOptions
|
||||
options: modes.IWebviewOptions & modes.IWebviewPanelOptions
|
||||
): Promise<void> {
|
||||
const serializer = this._serializers.get(viewType);
|
||||
if (!serializer) {
|
||||
@@ -342,3 +343,20 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
|
||||
return this._webviewPanels.get(handle);
|
||||
}
|
||||
}
|
||||
|
||||
function convertWebviewOptions(
|
||||
options: vscode.WebviewPanelOptions & vscode.WebviewOptions
|
||||
): modes.IWebviewOptions {
|
||||
return {
|
||||
...options,
|
||||
portMapping: options.portMapping
|
||||
? options.portMapping.map((x): modes.IWebviewPortMapping => {
|
||||
// Handle old proposed api
|
||||
if ('port' in x) {
|
||||
return { webviewPort: (x as any).port, extensionHostPort: (x as any).resolvedPort };
|
||||
}
|
||||
return { webviewPort: x.webviewPort, extensionHostPort: x.extensionHostPort };
|
||||
})
|
||||
: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { ExtHostWindowShape, MainContext, MainThreadWindowShape, IMainContext } from './extHost.protocol';
|
||||
import { ExtHostWindowShape, MainContext, MainThreadWindowShape, IMainContext, IOpenUriOptions } from './extHost.protocol';
|
||||
import { WindowState } from 'vscode';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
@@ -38,7 +38,7 @@ export class ExtHostWindow implements ExtHostWindowShape {
|
||||
this._onDidChangeWindowState.fire(this._state);
|
||||
}
|
||||
|
||||
openUri(stringOrUri: string | URI): Promise<boolean> {
|
||||
openUri(stringOrUri: string | URI, options: IOpenUriOptions): Promise<boolean> {
|
||||
if (typeof stringOrUri === 'string') {
|
||||
try {
|
||||
stringOrUri = URI.parse(stringOrUri);
|
||||
@@ -51,6 +51,6 @@ export class ExtHostWindow implements ExtHostWindowShape {
|
||||
} else if (stringOrUri.scheme === Schemas.command) {
|
||||
return Promise.reject(`Invalid scheme '${stringOrUri.scheme}'`);
|
||||
}
|
||||
return this._proxy.$openUri(stringOrUri);
|
||||
return this._proxy.$openUri(stringOrUri, options);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import * as map from 'vs/base/common/map';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { IWebviewOptions } from 'vs/editor/common/modes';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { localize } from 'vs/nls';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
@@ -122,7 +122,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
||||
$createWebviewCodeInset(
|
||||
handle: WebviewInsetHandle,
|
||||
symbolId: string,
|
||||
options: IWebviewOptions,
|
||||
options: modes.IWebviewOptions,
|
||||
extensionId: ExtensionIdentifier,
|
||||
extensionLocation: UriComponents
|
||||
): void {
|
||||
@@ -189,7 +189,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
||||
}
|
||||
}
|
||||
|
||||
public $setOptions(handle: WebviewPanelHandle | WebviewInsetHandle, options: IWebviewOptions): void {
|
||||
public $setOptions(handle: WebviewPanelHandle | WebviewInsetHandle, options: modes.IWebviewOptions): void {
|
||||
if (typeof handle === 'number') {
|
||||
this.getWebviewElement(handle).options = reviveWebviewOptions(options as any /*todo@mat */);
|
||||
} else {
|
||||
|
||||
@@ -257,7 +257,7 @@ export function createApiFactory(
|
||||
return extHostClipboard;
|
||||
},
|
||||
openExternal(uri: URI) {
|
||||
return extHostWindow.openUri(uri);
|
||||
return extHostWindow.openUri(uri, { allowTunneling: !!initData.remoteAuthority });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -202,9 +202,9 @@ export class OpenNodeModuleFactory implements INodeModuleFactory {
|
||||
return this.callOriginal(target, options);
|
||||
}
|
||||
if (uri.scheme === 'http' || uri.scheme === 'https') {
|
||||
return mainThreadWindow.$openUri(uri);
|
||||
return mainThreadWindow.$openUri(uri, { allowTunneling: true });
|
||||
} else if (uri.scheme === 'mailto') {
|
||||
return mainThreadWindow.$openUri(uri);
|
||||
return mainThreadWindow.$openUri(uri, {});
|
||||
}
|
||||
return this.callOriginal(target, options);
|
||||
};
|
||||
|
||||
@@ -68,9 +68,11 @@ interface QuickInputUI {
|
||||
visibleCount: CountBadge;
|
||||
count: CountBadge;
|
||||
message: HTMLElement;
|
||||
customButton: Button;
|
||||
progressBar: ProgressBar;
|
||||
list: QuickInputList;
|
||||
onDidAccept: Event<void>;
|
||||
onDidCustom: Event<void>;
|
||||
onDidTriggerButton: Event<IQuickInputButton>;
|
||||
ignoreFocusOut: boolean;
|
||||
keyMods: Writeable<IKeyMods>;
|
||||
@@ -92,6 +94,7 @@ type Visibilities = {
|
||||
message?: boolean;
|
||||
list?: boolean;
|
||||
ok?: boolean;
|
||||
customButton?: boolean;
|
||||
};
|
||||
|
||||
class QuickInput implements IQuickInput {
|
||||
@@ -312,6 +315,7 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
|
||||
private _placeholder: string;
|
||||
private onDidChangeValueEmitter = new Emitter<string>();
|
||||
private onDidAcceptEmitter = new Emitter<void>();
|
||||
private onDidCustomEmitter = new Emitter<void>();
|
||||
private _items: Array<T | IQuickPickSeparator> = [];
|
||||
private itemsUpdated = false;
|
||||
private _canSelectMany = false;
|
||||
@@ -331,6 +335,10 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
|
||||
private _valueSelection: Readonly<[number, number]>;
|
||||
private valueSelectionUpdated = true;
|
||||
private _validationMessage: string;
|
||||
private _ok: boolean;
|
||||
private _customButton: boolean;
|
||||
private _customButtonLabel: string;
|
||||
private _customButtonHover: string;
|
||||
|
||||
quickNavigate: IQuickNavigateConfiguration;
|
||||
|
||||
@@ -339,6 +347,7 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
|
||||
this.disposables.push(
|
||||
this.onDidChangeValueEmitter,
|
||||
this.onDidAcceptEmitter,
|
||||
this.onDidCustomEmitter,
|
||||
this.onDidChangeActiveEmitter,
|
||||
this.onDidChangeSelectionEmitter,
|
||||
this.onDidTriggerItemButtonEmitter,
|
||||
@@ -367,6 +376,8 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
|
||||
|
||||
onDidAccept = this.onDidAcceptEmitter.event;
|
||||
|
||||
onDidCustom = this.onDidCustomEmitter.event;
|
||||
|
||||
get items() {
|
||||
return this._items;
|
||||
}
|
||||
@@ -463,6 +474,42 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
|
||||
this.update();
|
||||
}
|
||||
|
||||
get customButton() {
|
||||
return this._customButton;
|
||||
}
|
||||
|
||||
set customButton(showCustomButton: boolean) {
|
||||
this._customButton = showCustomButton;
|
||||
this.update();
|
||||
}
|
||||
|
||||
get customLabel() {
|
||||
return this._customButtonLabel;
|
||||
}
|
||||
|
||||
set customLabel(label: string) {
|
||||
this._customButtonLabel = label;
|
||||
this.update();
|
||||
}
|
||||
|
||||
get customHover() {
|
||||
return this._customButtonHover;
|
||||
}
|
||||
|
||||
set customHover(hover: string) {
|
||||
this._customButtonHover = hover;
|
||||
this.update();
|
||||
}
|
||||
|
||||
get ok() {
|
||||
return this._ok;
|
||||
}
|
||||
|
||||
set ok(showOkButton: boolean) {
|
||||
this._ok = showOkButton;
|
||||
this.update();
|
||||
}
|
||||
|
||||
public inputHasFocus(): boolean {
|
||||
return this.visible ? this.ui.inputBox.hasFocus() : false;
|
||||
}
|
||||
@@ -547,6 +594,9 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
|
||||
}
|
||||
this.onDidAcceptEmitter.fire(undefined);
|
||||
}),
|
||||
this.ui.onDidCustom(() => {
|
||||
this.onDidCustomEmitter.fire(undefined);
|
||||
}),
|
||||
this.ui.list.onDidChangeFocus(focusedItems => {
|
||||
if (this.activeItemsUpdated) {
|
||||
return; // Expect another event.
|
||||
@@ -697,12 +747,14 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
|
||||
this.ui.message.textContent = null;
|
||||
this.ui.inputBox.showDecoration(Severity.Ignore);
|
||||
}
|
||||
this.ui.customButton.label = this.customLabel;
|
||||
this.ui.customButton.element.title = this.customHover;
|
||||
this.ui.list.matchOnDescription = this.matchOnDescription;
|
||||
this.ui.list.matchOnDetail = this.matchOnDetail;
|
||||
this.ui.list.matchOnLabel = this.matchOnLabel;
|
||||
this.ui.setComboboxAccessibility(true);
|
||||
this.ui.inputBox.setAttribute('aria-label', QuickPick.INPUT_BOX_ARIA_LABEL);
|
||||
this.ui.setVisibilities(this.canSelectMany ? { title: !!this.title || !!this.step, checkAll: true, inputBox: true, visibleCount: true, count: true, ok: true, list: true, message: !!this.validationMessage } : { title: !!this.title || !!this.step, inputBox: true, visibleCount: true, list: true, message: !!this.validationMessage });
|
||||
this.ui.setVisibilities(this.canSelectMany ? { title: !!this.title || !!this.step, checkAll: true, inputBox: true, visibleCount: true, count: true, ok: true, list: true, message: !!this.validationMessage } : { title: !!this.title || !!this.step, inputBox: true, visibleCount: true, list: true, message: !!this.validationMessage, customButton: this.customButton, ok: this.ok });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -848,6 +900,7 @@ export class QuickInputService extends Component implements IQuickInputService {
|
||||
private countContainer: HTMLElement;
|
||||
private okContainer: HTMLElement;
|
||||
private ok: Button;
|
||||
private customButtonContainer: HTMLElement;
|
||||
private ui: QuickInputUI;
|
||||
private comboboxAccessibility = false;
|
||||
private enabled = true;
|
||||
@@ -855,6 +908,7 @@ export class QuickInputService extends Component implements IQuickInputService {
|
||||
private inQuickOpenContext: IContextKey<boolean>;
|
||||
private contexts: { [id: string]: IContextKey<boolean>; } = Object.create(null);
|
||||
private onDidAcceptEmitter = this._register(new Emitter<void>());
|
||||
private onDidCustomEmitter = this._register(new Emitter<void>());
|
||||
private onDidTriggerButtonEmitter = this._register(new Emitter<IQuickInputButton>());
|
||||
private keyMods: Writeable<IKeyMods> = { ctrlCmd: false, alt: false };
|
||||
|
||||
@@ -1013,6 +1067,14 @@ export class QuickInputService extends Component implements IQuickInputService {
|
||||
this.onDidAcceptEmitter.fire();
|
||||
}));
|
||||
|
||||
this.customButtonContainer = dom.append(headerContainer, $('.quick-input-action'));
|
||||
const customButton = new Button(this.customButtonContainer);
|
||||
attachButtonStyler(customButton, this.themeService);
|
||||
customButton.label = localize('custom', "Custom");
|
||||
this._register(customButton.onDidClick(e => {
|
||||
this.onDidCustomEmitter.fire();
|
||||
}));
|
||||
|
||||
const message = dom.append(container, $(`#${this.idPrefix}message.quick-input-message`));
|
||||
|
||||
const progressBar = new ProgressBar(container);
|
||||
@@ -1098,9 +1160,11 @@ export class QuickInputService extends Component implements IQuickInputService {
|
||||
visibleCount,
|
||||
count,
|
||||
message,
|
||||
customButton,
|
||||
progressBar,
|
||||
list,
|
||||
onDidAccept: this.onDidAcceptEmitter.event,
|
||||
onDidCustom: this.onDidCustomEmitter.event,
|
||||
onDidTriggerButton: this.onDidTriggerButtonEmitter.event,
|
||||
ignoreFocusOut: false,
|
||||
keyMods: this.keyMods,
|
||||
@@ -1330,6 +1394,7 @@ export class QuickInputService extends Component implements IQuickInputService {
|
||||
this.visibleCountContainer.style.display = visibilities.visibleCount ? '' : 'none';
|
||||
this.countContainer.style.display = visibilities.count ? '' : 'none';
|
||||
this.okContainer.style.display = visibilities.ok ? '' : 'none';
|
||||
this.customButtonContainer.style.display = visibilities.customButton ? '' : 'none';
|
||||
this.ui.message.style.display = visibilities.message ? '' : 'none';
|
||||
this.ui.list.display(!!visibilities.list);
|
||||
this.ui.container.classList[visibilities.checkAll ? 'add' : 'remove']('show-checkboxes');
|
||||
|
||||
@@ -1060,10 +1060,10 @@ export class SCMViewlet extends ViewContainerViewlet implements IViewModel {
|
||||
const visibleViewDescriptors = this.viewsModel.visibleViewDescriptors;
|
||||
|
||||
const toSetVisible = this.viewsModel.viewDescriptors
|
||||
.filter(d => d instanceof RepositoryViewDescriptor && repositories.indexOf(d.repository) > -1 && visibleViewDescriptors.indexOf(d) === -1);
|
||||
.filter((d): d is RepositoryViewDescriptor => d instanceof RepositoryViewDescriptor && repositories.indexOf(d.repository) > -1 && visibleViewDescriptors.indexOf(d) === -1);
|
||||
|
||||
const toSetInvisible = visibleViewDescriptors
|
||||
.filter(d => d instanceof RepositoryViewDescriptor && repositories.indexOf(d.repository) === -1);
|
||||
.filter((d): d is RepositoryViewDescriptor => d instanceof RepositoryViewDescriptor && repositories.indexOf(d.repository) === -1);
|
||||
|
||||
let size: number | undefined;
|
||||
const oneToOne = toSetVisible.length === 1 && toSetInvisible.length === 1;
|
||||
@@ -1077,10 +1077,12 @@ export class SCMViewlet extends ViewContainerViewlet implements IViewModel {
|
||||
}
|
||||
}
|
||||
|
||||
viewDescriptor.repository.setSelected(false);
|
||||
this.viewsModel.setVisible(viewDescriptor.id, false);
|
||||
}
|
||||
|
||||
for (const viewDescriptor of toSetVisible) {
|
||||
viewDescriptor.repository.setSelected(true);
|
||||
this.viewsModel.setVisible(viewDescriptor.id, true, size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1972,7 +1972,7 @@ class TaskService extends Disposable implements ITaskService {
|
||||
return entries;
|
||||
}
|
||||
|
||||
private showQuickPick(tasks: Promise<Task[]> | Task[], placeHolder: string, defaultEntry?: TaskQuickPickEntry, group: boolean = false, sort: boolean = false, selectedEntry?: TaskQuickPickEntry): Promise<Task | undefined | null> {
|
||||
private showQuickPick(tasks: Promise<Task[]> | Task[], placeHolder: string, defaultEntry?: TaskQuickPickEntry, group: boolean = false, sort: boolean = false, selectedEntry?: TaskQuickPickEntry, additionalEntries?: TaskQuickPickEntry[]): Promise<TaskQuickPickEntry | undefined | null> {
|
||||
let _createEntries = (): Promise<TaskQuickPickEntry[]> => {
|
||||
if (Array.isArray(tasks)) {
|
||||
return Promise.resolve(this.createTaskQuickPickEntries(tasks, group, sort, selectedEntry));
|
||||
@@ -1984,6 +1984,9 @@ class TaskService extends Disposable implements ITaskService {
|
||||
if ((entries.length === 0) && defaultEntry) {
|
||||
entries.push(defaultEntry);
|
||||
}
|
||||
else if (entries.length > 1 && additionalEntries && additionalEntries.length > 0) {
|
||||
entries.push(additionalEntries[0]);
|
||||
}
|
||||
return entries;
|
||||
}), {
|
||||
placeHolder,
|
||||
@@ -1997,7 +2000,7 @@ class TaskService extends Disposable implements ITaskService {
|
||||
this.openConfig(task);
|
||||
}
|
||||
}
|
||||
}).then(entry => entry ? entry.task : undefined);
|
||||
});
|
||||
}
|
||||
|
||||
private showIgnoredFoldersMessage(): Promise<void> {
|
||||
@@ -2057,7 +2060,8 @@ class TaskService extends Disposable implements ITaskService {
|
||||
task: null
|
||||
},
|
||||
true).
|
||||
then((task) => {
|
||||
then((entry) => {
|
||||
let task: Task | undefined | null = entry ? entry.task : undefined;
|
||||
if (task === undefined) {
|
||||
return;
|
||||
}
|
||||
@@ -2137,7 +2141,8 @@ class TaskService extends Disposable implements ITaskService {
|
||||
label: nls.localize('TaskService.noBuildTask', 'No build task to run found. Configure Build Task...'),
|
||||
task: null
|
||||
},
|
||||
true).then((task) => {
|
||||
true).then((entry) => {
|
||||
let task: Task | undefined | null = entry ? entry.task : undefined;
|
||||
if (task === undefined) {
|
||||
return;
|
||||
}
|
||||
@@ -2185,7 +2190,8 @@ class TaskService extends Disposable implements ITaskService {
|
||||
label: nls.localize('TaskService.noTestTaskTerminal', 'No test task to run found. Configure Tasks...'),
|
||||
task: null
|
||||
}, true
|
||||
).then((task) => {
|
||||
).then((entry) => {
|
||||
let task: Task | undefined | null = entry ? entry.task : undefined;
|
||||
if (task === undefined) {
|
||||
return;
|
||||
}
|
||||
@@ -2206,15 +2212,29 @@ class TaskService extends Disposable implements ITaskService {
|
||||
if (!this.canRunCommand()) {
|
||||
return;
|
||||
}
|
||||
if (arg === 'terminateAll') {
|
||||
this.terminateAll();
|
||||
return;
|
||||
}
|
||||
let runQuickPick = (promise?: Promise<Task[]>) => {
|
||||
this.showQuickPick(promise || this.getActiveTasks(),
|
||||
nls.localize('TaskService.taskToTerminate', 'Select task to terminate'),
|
||||
{
|
||||
label: nls.localize('TaskService.noTaskRunning', 'No task is currently running'),
|
||||
task: null
|
||||
task: undefined
|
||||
},
|
||||
false, true
|
||||
).then(task => {
|
||||
false, true,
|
||||
undefined,
|
||||
[{
|
||||
label: nls.localize('TaskService.terminateAllRunningTasks', 'All running tasks'),
|
||||
id: 'terminateAll',
|
||||
task: undefined
|
||||
}]
|
||||
).then(entry => {
|
||||
if (entry && entry.id === 'terminateAll') {
|
||||
this.terminateAll();
|
||||
}
|
||||
let task: Task | undefined | null = entry ? entry.task : undefined;
|
||||
if (task === undefined || task === null) {
|
||||
return;
|
||||
}
|
||||
@@ -2270,7 +2290,8 @@ class TaskService extends Disposable implements ITaskService {
|
||||
task: null
|
||||
},
|
||||
false, true
|
||||
).then(task => {
|
||||
).then(entry => {
|
||||
let task: Task | undefined | null = entry ? entry.task : undefined;
|
||||
if (task === undefined || task === null) {
|
||||
return;
|
||||
}
|
||||
@@ -2482,7 +2503,8 @@ class TaskService extends Disposable implements ITaskService {
|
||||
this.showIgnoredFoldersMessage().then(() => {
|
||||
this.showQuickPick(tasks,
|
||||
nls.localize('TaskService.pickDefaultBuildTask', 'Select the task to be used as the default build task'), undefined, true, false, selectedEntry).
|
||||
then((task) => {
|
||||
then((entry) => {
|
||||
let task: Task | undefined | null = entry ? entry.task : undefined;
|
||||
if ((task === undefined) || (task === null)) {
|
||||
return;
|
||||
}
|
||||
@@ -2532,7 +2554,8 @@ class TaskService extends Disposable implements ITaskService {
|
||||
|
||||
this.showIgnoredFoldersMessage().then(() => {
|
||||
this.showQuickPick(tasks,
|
||||
nls.localize('TaskService.pickDefaultTestTask', 'Select the task to be used as the default test task'), undefined, true, false, selectedEntry).then((task) => {
|
||||
nls.localize('TaskService.pickDefaultTestTask', 'Select the task to be used as the default test task'), undefined, true, false, selectedEntry).then((entry) => {
|
||||
let task: Task | undefined | null = entry ? entry.task : undefined;
|
||||
if (!task) {
|
||||
return;
|
||||
}
|
||||
@@ -2565,7 +2588,8 @@ class TaskService extends Disposable implements ITaskService {
|
||||
task: null
|
||||
},
|
||||
false, true
|
||||
).then((task) => {
|
||||
).then((entry) => {
|
||||
let task: Task | undefined | null = entry ? entry.task : undefined;
|
||||
if (task === undefined || task === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -433,12 +433,10 @@ actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ResizePaneRightT
|
||||
}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Resize Pane Right', category);
|
||||
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ResizePaneUpTerminalAction, ResizePaneUpTerminalAction.ID, ResizePaneUpTerminalAction.LABEL, {
|
||||
primary: 0,
|
||||
linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.UpArrow },
|
||||
mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.UpArrow }
|
||||
}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Resize Pane Up', category);
|
||||
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ResizePaneDownTerminalAction, ResizePaneDownTerminalAction.ID, ResizePaneDownTerminalAction.LABEL, {
|
||||
primary: 0,
|
||||
linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.DownArrow },
|
||||
mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.DownArrow }
|
||||
}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Resize Pane Down', category);
|
||||
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ScrollToPreviousCommandAction, ScrollToPreviousCommandAction.ID, ScrollToPreviousCommandAction.LABEL, {
|
||||
|
||||
@@ -135,47 +135,7 @@ export class TerminalProcessManager implements ITerminalProcessManager {
|
||||
const activeWorkspaceRootUri = this._historyService.getLastActiveWorkspaceRoot(hasRemoteAuthority ? REMOTE_HOST_SCHEME : undefined);
|
||||
this._process = this._instantiationService.createInstance(TerminalProcessExtHostProxy, this._terminalId, shellLaunchConfig, activeWorkspaceRootUri, cols, rows);
|
||||
} else {
|
||||
if (!shellLaunchConfig.executable) {
|
||||
this._configHelper.mergeDefaultShellPathAndArgs(shellLaunchConfig);
|
||||
}
|
||||
|
||||
const activeWorkspaceRootUri = this._historyService.getLastActiveWorkspaceRoot(Schemas.file);
|
||||
const initialCwd = terminalEnvironment.getCwd(shellLaunchConfig, this._environmentService.userHome, activeWorkspaceRootUri, this._configHelper.config.cwd);
|
||||
|
||||
// Compel type system as process.env should not have any undefined entries
|
||||
let env: platform.IProcessEnvironment = {};
|
||||
|
||||
if (shellLaunchConfig.strictEnv) {
|
||||
// Only base the terminal process environment on this environment and add the
|
||||
// various mixins when strictEnv is false
|
||||
env = { ...shellLaunchConfig.env } as any;
|
||||
} else {
|
||||
// Merge process env with the env from config and from shellLaunchConfig
|
||||
env = { ...process.env } as any;
|
||||
|
||||
// Resolve env vars from config and shell
|
||||
const lastActiveWorkspaceRoot = activeWorkspaceRootUri ? this._workspaceContextService.getWorkspaceFolder(activeWorkspaceRootUri) : null;
|
||||
const platformKey = platform.isWindows ? 'windows' : (platform.isMacintosh ? 'osx' : 'linux');
|
||||
const isWorkspaceShellAllowed = this._configHelper.checkWorkspaceShellPermissions();
|
||||
const envFromConfigValue = this._workspaceConfigurationService.inspect<{ [key: string]: string }>(`terminal.integrated.env.${platformKey}`);
|
||||
const allowedEnvFromConfig = (isWorkspaceShellAllowed ? envFromConfigValue.value : envFromConfigValue.user);
|
||||
const envFromConfig = terminalEnvironment.resolveConfigurationVariables(this._configurationResolverService, { ...allowedEnvFromConfig }, lastActiveWorkspaceRoot);
|
||||
const envFromShell = terminalEnvironment.resolveConfigurationVariables(this._configurationResolverService, { ...shellLaunchConfig.env }, lastActiveWorkspaceRoot);
|
||||
shellLaunchConfig.env = envFromShell;
|
||||
|
||||
terminalEnvironment.mergeEnvironments(env, envFromConfig);
|
||||
terminalEnvironment.mergeEnvironments(env, shellLaunchConfig.env);
|
||||
|
||||
// Sanitize the environment, removing any undesirable VS Code and Electron environment
|
||||
// variables
|
||||
sanitizeProcessEnvironment(env, 'VSCODE_IPC_HOOK_CLI');
|
||||
|
||||
// Adding other env keys necessary to create the process
|
||||
terminalEnvironment.addTerminalEnvironmentKeys(env, this._productService.version, platform.locale, this._configHelper.config.setLocaleVariables);
|
||||
}
|
||||
|
||||
this._logService.debug(`Terminal process launching`, shellLaunchConfig, initialCwd, cols, rows, env);
|
||||
this._process = this._terminalInstanceService.createTerminalProcess(shellLaunchConfig, initialCwd, cols, rows, env, this._configHelper.config.windowsEnableConpty);
|
||||
this._process = this._launchProcess(shellLaunchConfig, cols, rows);
|
||||
}
|
||||
this.processState = ProcessState.LAUNCHING;
|
||||
|
||||
@@ -211,6 +171,50 @@ export class TerminalProcessManager implements ITerminalProcessManager {
|
||||
}, LAUNCHING_DURATION);
|
||||
}
|
||||
|
||||
private _launchProcess(shellLaunchConfig: IShellLaunchConfig, cols: number, rows: number): ITerminalChildProcess {
|
||||
if (!shellLaunchConfig.executable) {
|
||||
this._configHelper.mergeDefaultShellPathAndArgs(shellLaunchConfig);
|
||||
}
|
||||
|
||||
const activeWorkspaceRootUri = this._historyService.getLastActiveWorkspaceRoot(Schemas.file);
|
||||
const initialCwd = terminalEnvironment.getCwd(shellLaunchConfig, this._environmentService.userHome, activeWorkspaceRootUri, this._configHelper.config.cwd);
|
||||
|
||||
// Compel type system as process.env should not have any undefined entries
|
||||
let env: platform.IProcessEnvironment = {};
|
||||
|
||||
if (shellLaunchConfig.strictEnv) {
|
||||
// Only base the terminal process environment on this environment and add the
|
||||
// various mixins when strictEnv is false
|
||||
env = { ...shellLaunchConfig.env } as any;
|
||||
} else {
|
||||
// Merge process env with the env from config and from shellLaunchConfig
|
||||
env = { ...process.env } as any;
|
||||
|
||||
// Resolve env vars from config and shell
|
||||
const lastActiveWorkspaceRoot = activeWorkspaceRootUri ? this._workspaceContextService.getWorkspaceFolder(activeWorkspaceRootUri) : null;
|
||||
const platformKey = platform.isWindows ? 'windows' : (platform.isMacintosh ? 'osx' : 'linux');
|
||||
const isWorkspaceShellAllowed = this._configHelper.checkWorkspaceShellPermissions();
|
||||
const envFromConfigValue = this._workspaceConfigurationService.inspect<{ [key: string]: string }>(`terminal.integrated.env.${platformKey}`);
|
||||
const allowedEnvFromConfig = (isWorkspaceShellAllowed ? envFromConfigValue.value : envFromConfigValue.user);
|
||||
const envFromConfig = terminalEnvironment.resolveConfigurationVariables(this._configurationResolverService, { ...allowedEnvFromConfig }, lastActiveWorkspaceRoot);
|
||||
const envFromShell = terminalEnvironment.resolveConfigurationVariables(this._configurationResolverService, { ...shellLaunchConfig.env }, lastActiveWorkspaceRoot);
|
||||
shellLaunchConfig.env = envFromShell;
|
||||
|
||||
terminalEnvironment.mergeEnvironments(env, envFromConfig);
|
||||
terminalEnvironment.mergeEnvironments(env, shellLaunchConfig.env);
|
||||
|
||||
// Sanitize the environment, removing any undesirable VS Code and Electron environment
|
||||
// variables
|
||||
sanitizeProcessEnvironment(env, 'VSCODE_IPC_HOOK_CLI');
|
||||
|
||||
// Adding other env keys necessary to create the process
|
||||
terminalEnvironment.addTerminalEnvironmentKeys(env, this._productService.version, platform.locale, this._configHelper.config.setLocaleVariables);
|
||||
}
|
||||
|
||||
this._logService.debug(`Terminal process launching`, shellLaunchConfig, initialCwd, cols, rows, env);
|
||||
return this._terminalInstanceService.createTerminalProcess(shellLaunchConfig, initialCwd, cols, rows, env, this._configHelper.config.windowsEnableConpty);
|
||||
}
|
||||
|
||||
public setDimensions(cols: number, rows: number): void {
|
||||
if (!this._process) {
|
||||
return;
|
||||
|
||||
@@ -22,6 +22,7 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { TerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminalInstance';
|
||||
import { IBrowserTerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
|
||||
export abstract class TerminalService extends CommonTerminalService implements ITerminalService {
|
||||
protected _configHelper: IBrowserTerminalConfigHelper;
|
||||
@@ -38,8 +39,9 @@ export abstract class TerminalService extends CommonTerminalService implements I
|
||||
@IWorkbenchEnvironmentService private _environmentService: IWorkbenchEnvironmentService,
|
||||
@IExtensionService extensionService: IExtensionService,
|
||||
@IFileService fileService: IFileService,
|
||||
@IRemoteAgentService remoteAgentService: IRemoteAgentService
|
||||
) {
|
||||
super(contextKeyService, panelService, lifecycleService, storageService, notificationService, dialogService, extensionService, fileService);
|
||||
super(contextKeyService, panelService, lifecycleService, storageService, notificationService, dialogService, extensionService, fileService, remoteAgentService);
|
||||
}
|
||||
|
||||
protected abstract _getDefaultShell(p: platform.Platform): string;
|
||||
|
||||
@@ -267,6 +267,7 @@ export interface ITerminalService {
|
||||
*/
|
||||
preparePathForTerminalAsync(path: string, executable: string | undefined, title: string): Promise<string>;
|
||||
|
||||
extHostReady(remoteAuthority: string): void;
|
||||
requestExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI, cols: number, rows: number): void;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { ITerminalService, ITerminalProcessExtHostProxy, IShellLaunchConfig, ITerminalChildProcess } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
|
||||
export class TerminalProcessExtHostProxy implements ITerminalChildProcess, ITerminalProcessExtHostProxy {
|
||||
private _disposables: IDisposable[] = [];
|
||||
@@ -44,15 +43,10 @@ export class TerminalProcessExtHostProxy implements ITerminalChildProcess, ITerm
|
||||
activeWorkspaceRootUri: URI,
|
||||
cols: number,
|
||||
rows: number,
|
||||
@ITerminalService private readonly _terminalService: ITerminalService,
|
||||
@IExtensionService private readonly _extensionService: IExtensionService
|
||||
@ITerminalService private readonly _terminalService: ITerminalService
|
||||
) {
|
||||
this._extensionService.whenInstalledExtensionsRegistered().then(() => {
|
||||
// TODO: MainThreadTerminalService is not ready at this point, fix this
|
||||
setTimeout(() => {
|
||||
this._terminalService.requestExtHostProcess(this, shellLaunchConfig, activeWorkspaceRootUri, cols, rows);
|
||||
}, 0);
|
||||
});
|
||||
this._terminalService.requestExtHostProcess(this, shellLaunchConfig, activeWorkspaceRootUri, cols, rows);
|
||||
setTimeout(() => this._onProcessTitleChanged.fire('Starting...'), 0);
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
|
||||
@@ -19,6 +19,8 @@ import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { escapeNonWindowsPath } from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
|
||||
import { isWindows } from 'vs/base/common/platform';
|
||||
import { basename } from 'vs/base/common/path';
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
|
||||
export abstract class TerminalService implements ITerminalService {
|
||||
public _serviceBrand: any;
|
||||
@@ -32,7 +34,7 @@ export abstract class TerminalService implements ITerminalService {
|
||||
return this._terminalTabs.reduce((p, c) => p.concat(c.terminalInstances), <ITerminalInstance[]>[]);
|
||||
}
|
||||
private _findState: FindReplaceState;
|
||||
|
||||
private _extHostsReady: { [authority: string]: boolean } = {};
|
||||
private _activeTabIndex: number;
|
||||
|
||||
public get activeTabIndex(): number { return this._activeTabIndex; }
|
||||
@@ -65,12 +67,13 @@ export abstract class TerminalService implements ITerminalService {
|
||||
constructor(
|
||||
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
|
||||
@IPanelService protected readonly _panelService: IPanelService,
|
||||
@ILifecycleService lifecycleService: ILifecycleService,
|
||||
@ILifecycleService readonly lifecycleService: ILifecycleService,
|
||||
@IStorageService protected readonly _storageService: IStorageService,
|
||||
@INotificationService protected readonly _notificationService: INotificationService,
|
||||
@IDialogService private readonly _dialogService: IDialogService,
|
||||
@IExtensionService private readonly _extensionService: IExtensionService,
|
||||
@IFileService protected readonly _fileService: IFileService
|
||||
@IFileService protected readonly _fileService: IFileService,
|
||||
@IRemoteAgentService readonly _remoteAgentService: IRemoteAgentService
|
||||
) {
|
||||
this._activeTabIndex = 0;
|
||||
this._isShuttingDown = false;
|
||||
@@ -116,15 +119,22 @@ export abstract class TerminalService implements ITerminalService {
|
||||
}
|
||||
|
||||
public requestExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI, cols: number, rows: number): void {
|
||||
// Ensure extension host is ready before requesting a process
|
||||
this._extensionService.whenInstalledExtensionsRegistered().then(() => {
|
||||
// TODO: MainThreadTerminalService is not ready at this point, fix this
|
||||
setTimeout(() => {
|
||||
this._onInstanceRequestExtHostProcess.fire({ proxy, shellLaunchConfig, activeWorkspaceRootUri, cols, rows });
|
||||
}, 500);
|
||||
this._extensionService.whenInstalledExtensionsRegistered().then(async () => {
|
||||
// Wait for the remoteAuthority to be ready (and listening for events) before proceeding
|
||||
const conn = this._remoteAgentService.getConnection();
|
||||
const remoteAuthority = conn ? conn.remoteAuthority : 'null';
|
||||
let retries = 0;
|
||||
while (!this._extHostsReady[remoteAuthority] && ++retries < 50) {
|
||||
await timeout(100);
|
||||
}
|
||||
this._onInstanceRequestExtHostProcess.fire({ proxy, shellLaunchConfig, activeWorkspaceRootUri, cols, rows });
|
||||
});
|
||||
}
|
||||
|
||||
public extHostReady(remoteAuthority: string): void {
|
||||
this._extHostsReady[remoteAuthority] = true;
|
||||
}
|
||||
|
||||
private _onBeforeShutdown(): boolean | Promise<boolean> {
|
||||
if (this.terminalInstances.length === 0) {
|
||||
// No terminal instances, don't veto
|
||||
|
||||
@@ -28,6 +28,7 @@ import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { escapeNonWindowsPath } from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
|
||||
import { execFile } from 'child_process';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
|
||||
export class TerminalService extends BrowserTerminalService implements ITerminalService {
|
||||
public get configHelper(): ITerminalConfigHelper { return this._configHelper; }
|
||||
@@ -45,9 +46,10 @@ export class TerminalService extends BrowserTerminalService implements ITerminal
|
||||
@IDialogService dialogService: IDialogService,
|
||||
@IExtensionService extensionService: IExtensionService,
|
||||
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService,
|
||||
@IFileService fileService: IFileService
|
||||
@IFileService fileService: IFileService,
|
||||
@IRemoteAgentService remoteAgentService: IRemoteAgentService
|
||||
) {
|
||||
super(contextKeyService, panelService, layoutService, lifecycleService, storageService, notificationService, dialogService, instantiationService, environmentService, extensionService, fileService);
|
||||
super(contextKeyService, panelService, layoutService, lifecycleService, storageService, notificationService, dialogService, instantiationService, environmentService, extensionService, fileService, remoteAgentService);
|
||||
|
||||
this._configHelper = this._instantiationService.createInstance(TerminalConfigHelper, linuxDistro);
|
||||
ipc.on('vscode:openFiles', (_event: any, request: IOpenFileRequest) => {
|
||||
|
||||
@@ -8,6 +8,7 @@ import { URI } from 'vs/base/common/uri';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
|
||||
/**
|
||||
* Set when the find widget in a webview is visible.
|
||||
@@ -28,11 +29,6 @@ export interface IWebviewService {
|
||||
): Webview;
|
||||
}
|
||||
|
||||
export interface WebviewPortMapping {
|
||||
readonly port: number;
|
||||
readonly resolvedPort: number;
|
||||
}
|
||||
|
||||
export interface WebviewOptions {
|
||||
readonly allowSvgs?: boolean;
|
||||
readonly extension?: {
|
||||
@@ -46,7 +42,7 @@ export interface WebviewContentOptions {
|
||||
readonly allowScripts?: boolean;
|
||||
readonly svgWhiteList?: string[];
|
||||
readonly localResourceRoots?: ReadonlyArray<URI>;
|
||||
readonly portMappings?: ReadonlyArray<WebviewPortMapping>;
|
||||
readonly portMappings?: ReadonlyArray<modes.IWebviewPortMapping>;
|
||||
}
|
||||
|
||||
export interface Webview {
|
||||
|
||||
@@ -11,21 +11,22 @@ import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
import { endsWith } from 'vs/base/common/strings';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { EDITOR_FONT_DEFAULTS, IEditorOptions } from 'vs/editor/common/config/editorOptions';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
|
||||
import { ITunnelService, RemoteTunnel } from 'vs/platform/remote/common/tunnel';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import * as colorRegistry from 'vs/platform/theme/common/colorRegistry';
|
||||
import { DARK, ITheme, IThemeService, LIGHT } from 'vs/platform/theme/common/themeService';
|
||||
import { Webview, WebviewContentOptions, WebviewOptions } from 'vs/workbench/contrib/webview/common/webview';
|
||||
import { registerFileProtocol, WebviewProtocol } from 'vs/workbench/contrib/webview/electron-browser/webviewProtocols';
|
||||
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { areWebviewInputOptionsEqual } from '../browser/webviewEditorService';
|
||||
import { WebviewFindWidget } from '../browser/webviewFindWidget';
|
||||
import { WebviewContentOptions, WebviewPortMapping, WebviewOptions, Webview } from 'vs/workbench/contrib/webview/common/webview';
|
||||
import { ITunnelService, RemoteTunnel } from 'vs/platform/remote/common/tunnel';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IEditorOptions, EDITOR_FONT_DEFAULTS } from 'vs/editor/common/config/editorOptions';
|
||||
|
||||
export interface WebviewPortMapping {
|
||||
readonly port: number;
|
||||
@@ -153,7 +154,7 @@ class WebviewPortMappingProvider extends Disposable {
|
||||
constructor(
|
||||
session: WebviewSession,
|
||||
extensionLocation: URI | undefined,
|
||||
mappings: () => ReadonlyArray<WebviewPortMapping>,
|
||||
mappings: () => ReadonlyArray<modes.IWebviewPortMapping>,
|
||||
private readonly tunnelService: ITunnelService,
|
||||
extensionId: ExtensionIdentifier | undefined,
|
||||
@ITelemetryService telemetryService: ITelemetryService
|
||||
@@ -183,23 +184,23 @@ class WebviewPortMappingProvider extends Disposable {
|
||||
|
||||
const port = +localhostMatch[1];
|
||||
for (const mapping of mappings()) {
|
||||
if (mapping.port === port) {
|
||||
if (mapping.webviewPort === port) {
|
||||
if (extensionLocation && extensionLocation.scheme === REMOTE_HOST_SCHEME) {
|
||||
const tunnel = await this.getOrCreateTunnel(mapping.resolvedPort);
|
||||
const tunnel = await this.getOrCreateTunnel(mapping.extensionHostPort);
|
||||
if (tunnel) {
|
||||
return {
|
||||
redirectURL: details.url.replace(
|
||||
new RegExp(`^${uri.scheme}://localhost:${mapping.port}/`),
|
||||
new RegExp(`^${uri.scheme}://localhost:${mapping.webviewPort}/`),
|
||||
`${uri.scheme}://localhost:${tunnel.tunnelLocalPort}/`)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (mapping.port !== mapping.resolvedPort) {
|
||||
if (mapping.webviewPort !== mapping.extensionHostPort) {
|
||||
return {
|
||||
redirectURL: details.url.replace(
|
||||
new RegExp(`^${uri.scheme}://localhost:${mapping.port}/`),
|
||||
`${uri.scheme}://localhost:${mapping.resolvedPort}/`)
|
||||
new RegExp(`^${uri.scheme}://localhost:${mapping.webviewPort}/`),
|
||||
`${uri.scheme}://localhost:${mapping.extensionHostPort}/`)
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -416,7 +417,7 @@ export class WebviewElement extends Disposable implements Webview {
|
||||
this._register(new WebviewPortMappingProvider(
|
||||
session,
|
||||
_options.extension ? _options.extension.location : undefined,
|
||||
() => (this._contentOptions.portMappings || [{ port: 3000, resolvedPort: 4000 }]),
|
||||
() => (this._contentOptions.portMappings || []),
|
||||
tunnelService,
|
||||
_options.extension ? _options.extension.id : undefined,
|
||||
telemetryService
|
||||
|
||||
@@ -72,8 +72,8 @@ export class FileDialogService implements IFileDialogService {
|
||||
}
|
||||
}
|
||||
|
||||
// ...then fallback to default folder path
|
||||
return this.defaultFolderPath(schemeFilter);
|
||||
// ...then fallback to default file path
|
||||
return this.defaultFilePath(schemeFilter);
|
||||
}
|
||||
|
||||
private toNativeOpenDialogOptions(options: IPickAndOpenOptions): INativeOpenDialogOptions {
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="-2 -2 16 16" enable-background="new -2 -2 16 16"><polygon fill="#C5C5C5" points="9,0 4.5,9 3,6 0,6 3,12 6,12 12,0"/></svg>
|
||||
|
Before Width: | Height: | Size: 194 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><style type="text/css">.icon-canvas-transparent{opacity:0;fill:#F6F6F6;} .icon-vs-out{opacity:0;fill:#F6F6F6;} .icon-vs-fg{fill:#F0EFF1;} .icon-folder{fill:#656565;}</style><path class="icon-canvas-transparent" d="M16 16h-16v-16h16v16z" id="canvas"/><path class="icon-vs-out" d="M16 2.5v10c0 .827-.673 1.5-1.5 1.5h-11.996c-.827 0-1.5-.673-1.5-1.5v-8c0-.827.673-1.5 1.5-1.5h2.886l1-2h8.11c.827 0 1.5.673 1.5 1.5z" id="outline"/><path class="icon-folder" d="M14.5 2h-7.492l-1 2h-3.504c-.277 0-.5.224-.5.5v8c0 .276.223.5.5.5h11.996c.275 0 .5-.224.5-.5v-10c0-.276-.225-.5-.5-.5zm-.496 2h-6.496l.5-1h5.996v1z" id="iconBg"/><path class="icon-vs-fg" d="M14 3v1h-6.5l.5-1h6z" id="iconFg"/></svg>
|
||||
|
Before Width: | Height: | Size: 750 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><polygon points="5.382,13 2.382,7 6.618,7 7,7.764 9.382,3 13.618,3 8.618,13" fill="#F6F6F6"/><path d="M12 4l-4 8h-2l-2-4h2l1 2 3-6h2z" fill="#424242"/></svg>
|
||||
|
Before Width: | Height: | Size: 221 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><style type="text/css">.icon-canvas-transparent{opacity:0;fill:#F6F6F6;} .icon-vs-out{opacity:0;fill:#F6F6F6;} .icon-vs-fg{opacity:0;fill:#F0EFF1;} .icon-folder{fill:#C5C5C5;}</style><path class="icon-canvas-transparent" d="M16 16h-16v-16h16v16z" id="canvas"/><path class="icon-vs-out" d="M16 2.5v10c0 .827-.673 1.5-1.5 1.5h-11.996c-.827 0-1.5-.673-1.5-1.5v-8c0-.827.673-1.5 1.5-1.5h2.886l1-2h8.11c.827 0 1.5.673 1.5 1.5z" id="outline"/><path class="icon-folder" d="M14.5 2h-7.492l-1 2h-3.504c-.277 0-.5.224-.5.5v8c0 .276.223.5.5.5h11.996c.275 0 .5-.224.5-.5v-10c0-.276-.225-.5-.5-.5zm-.496 2h-6.496l.5-1h5.996v1z" id="iconBg"/><path class="icon-vs-fg" d="M14 3v1h-6.5l.5-1h6z" id="iconFg"/></svg>
|
||||
|
Before Width: | Height: | Size: 760 B |
@@ -7,7 +7,7 @@ import * as nls from 'vs/nls';
|
||||
import * as resources from 'vs/base/common/resources';
|
||||
import * as objects from 'vs/base/common/objects';
|
||||
import { IFileService, IFileStat, FileKind } from 'vs/platform/files/common/files';
|
||||
import { IQuickInputService, IQuickPickItem, IQuickPick, IQuickInputButton } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { IQuickInputService, IQuickPickItem, IQuickPick } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { isWindows } from 'vs/base/common/platform';
|
||||
import { ISaveDialogOptions, IOpenDialogOptions, IFileDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
@@ -23,20 +23,26 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { RemoteFileDialogContext } from 'vs/workbench/common/contextkeys';
|
||||
import { equalsIgnoreCase } from 'vs/base/common/strings';
|
||||
import { equalsIgnoreCase, format } from 'vs/base/common/strings';
|
||||
import { OpenLocalFileAction, OpenLocalFileFolderAction, OpenLocalFolderAction } from 'vs/workbench/browser/actions/workspaceActions';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
|
||||
interface FileQuickPickItem extends IQuickPickItem {
|
||||
uri: URI;
|
||||
isFolder: boolean;
|
||||
}
|
||||
|
||||
enum UpdateResult {
|
||||
Updated,
|
||||
NotUpdated,
|
||||
InvalidPath
|
||||
}
|
||||
|
||||
// Reference: https://en.wikipedia.org/wiki/Filename
|
||||
const INVALID_FILE_CHARS = isWindows ? /[\\/:\*\?"<>\|]/g : /[\\/]/g;
|
||||
const WINDOWS_FORBIDDEN_NAMES = /^(con|prn|aux|clock\$|nul|lpt[0-9]|com[0-9])$/i;
|
||||
|
||||
export class RemoteFileDialog {
|
||||
private acceptButton: IQuickInputButton;
|
||||
private fallbackListItem: FileQuickPickItem | undefined;
|
||||
private options: IOpenDialogOptions;
|
||||
private currentFolder: URI;
|
||||
private filePickBox: IQuickPick<FileQuickPickItem>;
|
||||
@@ -52,6 +58,7 @@ export class RemoteFileDialog {
|
||||
private autoCompletePathSegment: string;
|
||||
private activeItem: FileQuickPickItem;
|
||||
private userHome: URI;
|
||||
private badPath: string | undefined;
|
||||
|
||||
constructor(
|
||||
@IFileService private readonly fileService: IFileService,
|
||||
@@ -64,8 +71,8 @@ export class RemoteFileDialog {
|
||||
@IModeService private readonly modeService: IModeService,
|
||||
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
|
||||
@IRemoteAgentService private readonly remoteAgentService: IRemoteAgentService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService
|
||||
|
||||
@IKeybindingService private readonly keybindingService: IKeybindingService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
) {
|
||||
this.remoteAuthority = this.environmentService.configuration.remoteAuthority;
|
||||
this.contextKey = RemoteFileDialogContext.bindTo(contextKeyService);
|
||||
@@ -79,13 +86,6 @@ export class RemoteFileDialog {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
this.options = newOptions;
|
||||
|
||||
const openFileString = nls.localize('remoteFileDialog.localFileFallback', '(Open Local File)');
|
||||
const openFolderString = nls.localize('remoteFileDialog.localFolderFallback', '(Open Local Folder)');
|
||||
const openFileFolderString = nls.localize('remoteFileDialog.localFileFolderFallback', '(Open Local File or Folder)');
|
||||
let fallbackLabel = options.canSelectFiles ? (options.canSelectFolders ? openFileFolderString : openFileString) : openFolderString;
|
||||
this.fallbackListItem = this.getFallbackFileSystem(fallbackLabel);
|
||||
|
||||
return this.pickResource();
|
||||
}
|
||||
|
||||
@@ -100,7 +100,6 @@ export class RemoteFileDialog {
|
||||
this.options = newOptions;
|
||||
this.options.canSelectFolders = true;
|
||||
this.options.canSelectFiles = true;
|
||||
this.fallbackListItem = this.getFallbackFileSystem(nls.localize('remoteFileDialog.localSaveFallback', '(Save Local File)'));
|
||||
|
||||
return new Promise<URI | undefined>((resolve) => {
|
||||
this.pickResource(true).then(folderUri => {
|
||||
@@ -129,20 +128,13 @@ export class RemoteFileDialog {
|
||||
|
||||
private remoteUriFrom(path: string): URI {
|
||||
path = path.replace(/\\/g, '/');
|
||||
return resources.toLocalResource(URI.from({ scheme: this.scheme, path }), this.remoteAuthority);
|
||||
return resources.toLocalResource(URI.from({ scheme: this.scheme, path }), this.scheme === Schemas.file ? undefined : this.remoteAuthority);
|
||||
}
|
||||
|
||||
private getScheme(defaultUri: URI | undefined, available: string[] | undefined): string {
|
||||
return defaultUri ? defaultUri.scheme : (available ? available[0] : Schemas.file);
|
||||
}
|
||||
|
||||
private getFallbackFileSystem(label: string): FileQuickPickItem | undefined {
|
||||
if (this.options && this.options.availableFileSystems && (this.options.availableFileSystems.length > 1)) {
|
||||
return { label: label, uri: URI.from({ scheme: this.options.availableFileSystems[1] }), isFolder: true };
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private async getUserHome(): Promise<URI> {
|
||||
if (this.scheme !== Schemas.file) {
|
||||
const env = await this.remoteAgentService.getEnvironment();
|
||||
@@ -182,33 +174,34 @@ export class RemoteFileDialog {
|
||||
}
|
||||
}
|
||||
}
|
||||
this.acceptButton = { iconPath: this.getDialogIcons('accept'), tooltip: this.options.title };
|
||||
|
||||
return new Promise<URI | undefined>(async (resolve) => {
|
||||
this.filePickBox = this.quickInputService.createQuickPick<FileQuickPickItem>();
|
||||
this.filePickBox.matchOnLabel = false;
|
||||
this.filePickBox.autoFocusOnList = false;
|
||||
this.filePickBox.ok = true;
|
||||
if (this.options && this.options.availableFileSystems && (this.options.availableFileSystems.length > 1)) {
|
||||
this.filePickBox.customButton = true;
|
||||
this.filePickBox.customLabel = nls.localize('remoteFileDialog.local', 'Show Local');
|
||||
const action = this.allowFileSelection ? (this.allowFolderSelection ? OpenLocalFileFolderAction : OpenLocalFileAction) : OpenLocalFolderAction;
|
||||
const keybinding = this.keybindingService.lookupKeybinding(action.ID);
|
||||
if (keybinding) {
|
||||
const label = keybinding.getLabel();
|
||||
if (label) {
|
||||
this.filePickBox.customHover = format('{0} ({1})', action.LABEL, label);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let isResolving = false;
|
||||
let isAcceptHandled = false;
|
||||
this.currentFolder = homedir;
|
||||
this.userEnteredPathSegment = '';
|
||||
this.autoCompletePathSegment = '';
|
||||
this.filePickBox.buttons = [this.acceptButton];
|
||||
this.filePickBox.onDidTriggerButton(_ => {
|
||||
// accept button
|
||||
const resolveValue = this.addPostfix(this.remoteUriFrom(this.filePickBox.value));
|
||||
this.validate(resolveValue).then(validated => {
|
||||
if (validated) {
|
||||
isResolving = true;
|
||||
this.filePickBox.hide();
|
||||
doResolve(this, resolveValue);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
this.filePickBox.title = this.options.title;
|
||||
this.filePickBox.value = this.pathFromUri(this.currentFolder);
|
||||
this.filePickBox.value = this.pathFromUri(this.currentFolder, true);
|
||||
this.filePickBox.valueSelection = [this.filePickBox.value.length, this.filePickBox.value.length];
|
||||
this.filePickBox.items = [];
|
||||
|
||||
function doResolve(dialog: RemoteFileDialog, uri: URI | undefined) {
|
||||
@@ -217,6 +210,28 @@ export class RemoteFileDialog {
|
||||
dialog.filePickBox.dispose();
|
||||
}
|
||||
|
||||
this.filePickBox.onDidCustom(() => {
|
||||
if (isAcceptHandled || this.filePickBox.busy) {
|
||||
return undefined; // {{SQL CARBON EDIT}} @todo anthonydresser return to return; when we do strict null checks
|
||||
}
|
||||
|
||||
isAcceptHandled = true;
|
||||
isResolving = true;
|
||||
if (this.options.availableFileSystems && (this.options.availableFileSystems.length > 1)) {
|
||||
this.options.availableFileSystems.shift();
|
||||
}
|
||||
this.options.defaultUri = undefined;
|
||||
if (this.requiresTrailing) {
|
||||
return this.fileDialogService.showSaveDialog(this.options).then(result => {
|
||||
doResolve(this, result);
|
||||
});
|
||||
} else {
|
||||
return this.fileDialogService.showOpenDialog(this.options).then(result => {
|
||||
doResolve(this, result ? result[0] : undefined);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
this.filePickBox.onDidAccept(_ => {
|
||||
if (isAcceptHandled || this.filePickBox.busy) {
|
||||
return;
|
||||
@@ -247,15 +262,16 @@ export class RemoteFileDialog {
|
||||
this.filePickBox.onDidChangeValue(async value => {
|
||||
// onDidChangeValue can also be triggered by the auto complete, so if it looks like the auto complete, don't do anything
|
||||
if (this.isChangeFromUser()) {
|
||||
if (value !== this.constructFullUserPath()) {
|
||||
// If the user has just entered more bad path, don't change anything
|
||||
if (value !== this.constructFullUserPath() && !this.isBadSubpath(value)) {
|
||||
this.filePickBox.validationMessage = undefined;
|
||||
this.shouldOverwriteFile = false;
|
||||
const valueUri = this.remoteUriFrom(this.trimTrailingSlash(this.filePickBox.value));
|
||||
let isUpdate = false;
|
||||
let updated: UpdateResult = UpdateResult.NotUpdated;
|
||||
if (!resources.isEqual(this.remoteUriFrom(this.trimTrailingSlash(this.pathFromUri(this.currentFolder))), valueUri, true)) {
|
||||
isUpdate = await this.tryUpdateItems(value, this.remoteUriFrom(this.filePickBox.value));
|
||||
updated = await this.tryUpdateItems(value, this.remoteUriFrom(this.filePickBox.value));
|
||||
}
|
||||
if (!isUpdate) {
|
||||
if (updated === UpdateResult.NotUpdated) {
|
||||
this.setActiveItems(value);
|
||||
}
|
||||
} else {
|
||||
@@ -281,6 +297,10 @@ export class RemoteFileDialog {
|
||||
});
|
||||
}
|
||||
|
||||
private isBadSubpath(value: string) {
|
||||
return this.badPath && (value.length > this.badPath.length) && equalsIgnoreCase(value.substring(0, this.badPath.length), this.badPath);
|
||||
}
|
||||
|
||||
private isChangeFromUser(): boolean {
|
||||
if ((this.filePickBox.value === this.pathAppend(this.currentFolder, this.userEnteredPathSegment + this.autoCompletePathSegment))
|
||||
&& (this.activeItem === (this.filePickBox.activeItems ? this.filePickBox.activeItems[0] : undefined))) {
|
||||
@@ -294,24 +314,6 @@ export class RemoteFileDialog {
|
||||
}
|
||||
|
||||
private async onDidAccept(): Promise<URI | undefined> {
|
||||
// Check if Open Local has been selected
|
||||
const selectedItems: ReadonlyArray<FileQuickPickItem> = this.filePickBox.selectedItems;
|
||||
if (selectedItems && (selectedItems.length > 0) && (selectedItems[0] === this.fallbackListItem)) {
|
||||
if (this.options.availableFileSystems && (this.options.availableFileSystems.length > 1)) {
|
||||
this.options.availableFileSystems.shift();
|
||||
}
|
||||
this.options.defaultUri = undefined;
|
||||
if (this.requiresTrailing) {
|
||||
return this.fileDialogService.showSaveDialog(this.options).then(result => {
|
||||
return result;
|
||||
});
|
||||
} else {
|
||||
return this.fileDialogService.showOpenDialog(this.options).then(result => {
|
||||
return result ? result[0] : undefined;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let resolveValue: URI | undefined;
|
||||
let navigateValue: URI | undefined;
|
||||
const trimmedPickBoxValue = ((this.filePickBox.value.length > 1) && this.endsWithSlash(this.filePickBox.value)) ? this.filePickBox.value.substr(0, this.filePickBox.value.length - 1) : this.filePickBox.value;
|
||||
@@ -360,10 +362,11 @@ export class RemoteFileDialog {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
private async tryUpdateItems(value: string, valueUri: URI): Promise<boolean> {
|
||||
private async tryUpdateItems(value: string, valueUri: URI): Promise<UpdateResult> {
|
||||
if (value[value.length - 1] === '~') {
|
||||
await this.updateItems(this.userHome);
|
||||
return true;
|
||||
this.badPath = undefined;
|
||||
return UpdateResult.Updated;
|
||||
} else if (this.endsWithSlash(value) || (!resources.isEqual(this.currentFolder, resources.dirname(valueUri), true) && resources.isEqualOrParent(this.currentFolder, resources.dirname(valueUri), true))) {
|
||||
let stat: IFileStat | undefined;
|
||||
try {
|
||||
@@ -373,7 +376,14 @@ export class RemoteFileDialog {
|
||||
}
|
||||
if (stat && stat.isDirectory && (resources.basename(valueUri) !== '.') && this.endsWithSlash(value)) {
|
||||
await this.updateItems(valueUri);
|
||||
return true;
|
||||
return UpdateResult.Updated;
|
||||
} else if (this.endsWithSlash(value)) {
|
||||
// The input box contains a path that doesn't exist on the system.
|
||||
this.filePickBox.validationMessage = nls.localize('remoteFileDialog.badPath', 'The path does not exist.');
|
||||
// Save this bad path. It can take too long to to a stat on every user entered character, but once a user enters a bad path they are likely
|
||||
// to keep typing more bad path. We can compare against this bad path and see if the user entered path starts with it.
|
||||
this.badPath = value;
|
||||
return UpdateResult.InvalidPath;
|
||||
} else {
|
||||
const inputUriDirname = resources.dirname(valueUri);
|
||||
if (!resources.isEqual(this.remoteUriFrom(this.trimTrailingSlash(this.pathFromUri(this.currentFolder))), inputUriDirname, true)) {
|
||||
@@ -385,12 +395,14 @@ export class RemoteFileDialog {
|
||||
}
|
||||
if (statWithoutTrailing && statWithoutTrailing.isDirectory && (resources.basename(valueUri) !== '.')) {
|
||||
await this.updateItems(inputUriDirname, resources.basename(valueUri));
|
||||
return true;
|
||||
this.badPath = undefined;
|
||||
return UpdateResult.Updated;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
this.badPath = undefined;
|
||||
return UpdateResult.NotUpdated;
|
||||
}
|
||||
|
||||
private setActiveItems(value: string) {
|
||||
@@ -428,7 +440,7 @@ export class RemoteFileDialog {
|
||||
this.autoCompletePathSegment = '';
|
||||
return false;
|
||||
}
|
||||
const itemBasename = (quickPickItem.label === '..') ? quickPickItem.label : resources.basename(quickPickItem.uri);
|
||||
const itemBasename = quickPickItem.label;
|
||||
// Either force the autocomplete, or the old value should be one smaller than the new value and match the new value.
|
||||
if (!force && (itemBasename.length >= startingBasename.length) && equalsIgnoreCase(itemBasename.substr(0, startingBasename.length), startingBasename)) {
|
||||
this.userEnteredPathSegment = startingBasename;
|
||||
@@ -582,8 +594,11 @@ export class RemoteFileDialog {
|
||||
if (this.allowFolderSelection) {
|
||||
this.filePickBox.activeItems = [];
|
||||
}
|
||||
this.filePickBox.valueSelection = [0, this.filePickBox.value.length];
|
||||
this.insertText(newValue, newValue);
|
||||
if (!equalsIgnoreCase(this.filePickBox.value, newValue)) {
|
||||
this.filePickBox.valueSelection = [0, this.filePickBox.value.length];
|
||||
this.insertText(newValue, newValue);
|
||||
}
|
||||
this.filePickBox.valueSelection = [this.filePickBox.value.length, this.filePickBox.value.length];
|
||||
this.filePickBox.busy = false;
|
||||
});
|
||||
}
|
||||
@@ -687,10 +702,6 @@ export class RemoteFileDialog {
|
||||
if (backDir) {
|
||||
sorted.unshift(backDir);
|
||||
}
|
||||
|
||||
if (this.fallbackListItem) {
|
||||
sorted.push(this.fallbackListItem);
|
||||
}
|
||||
return sorted;
|
||||
}
|
||||
|
||||
@@ -724,11 +735,4 @@ export class RemoteFileDialog {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
private getDialogIcons(name: string): { light: URI, dark: URI } {
|
||||
return {
|
||||
dark: URI.parse(require.toUrl(`vs/workbench/services/dialogs/browser/media/dark/${name}.svg`)),
|
||||
light: URI.parse(require.toUrl(`vs/workbench/services/dialogs/browser/media/light/${name}.svg`))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,8 +12,8 @@ import { Extensions, IJSONContributionRegistry } from 'vs/platform/jsonschemas/c
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IMessage } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { values } from 'vs/base/common/map';
|
||||
|
||||
const hasOwnProperty = Object.hasOwnProperty;
|
||||
const schemaRegistry = Registry.as<IJSONContributionRegistry>(Extensions.JSONContribution);
|
||||
export type ExtensionKind = 'workspace' | 'ui' | undefined;
|
||||
|
||||
@@ -370,18 +370,14 @@ export interface IExtensionPointDescriptor {
|
||||
|
||||
export class ExtensionsRegistryImpl {
|
||||
|
||||
private _extensionPoints: { [extPoint: string]: ExtensionPoint<any>; };
|
||||
|
||||
constructor() {
|
||||
this._extensionPoints = {};
|
||||
}
|
||||
private readonly _extensionPoints = new Map<string, ExtensionPoint<any>>();
|
||||
|
||||
public registerExtensionPoint<T>(desc: IExtensionPointDescriptor): IExtensionPoint<T> {
|
||||
if (hasOwnProperty.call(this._extensionPoints, desc.extensionPoint)) {
|
||||
if (this._extensionPoints.has(desc.extensionPoint)) {
|
||||
throw new Error('Duplicate extension point: ' + desc.extensionPoint);
|
||||
}
|
||||
let result = new ExtensionPoint<T>(desc.extensionPoint, desc.defaultExtensionKind);
|
||||
this._extensionPoints[desc.extensionPoint] = result;
|
||||
const result = new ExtensionPoint<T>(desc.extensionPoint, desc.defaultExtensionKind);
|
||||
this._extensionPoints.set(desc.extensionPoint, result);
|
||||
|
||||
schema.properties['contributes'].properties[desc.extensionPoint] = desc.jsonSchema;
|
||||
schemaRegistry.registerSchema(schemaId, schema);
|
||||
@@ -390,11 +386,7 @@ export class ExtensionsRegistryImpl {
|
||||
}
|
||||
|
||||
public getExtensionPoints(): ExtensionPoint<any>[] {
|
||||
return Object.keys(this._extensionPoints).map(point => this._extensionPoints[point]);
|
||||
}
|
||||
|
||||
public getExtensionPointsMap(): { [extPoint: string]: ExtensionPoint<any>; } {
|
||||
return this._extensionPoints;
|
||||
return values(this._extensionPoints);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,9 @@ import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
|
||||
import { Dialog } from 'vs/base/browser/ui/dialog/dialog';
|
||||
import { attachDialogStyler } from 'vs/platform/theme/common/styler';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { EventHelper } from 'vs/base/browser/dom';
|
||||
|
||||
export class ProgressService2 implements IProgressService2 {
|
||||
|
||||
@@ -34,7 +37,8 @@ export class ProgressService2 implements IProgressService2 {
|
||||
@INotificationService private readonly _notificationService: INotificationService,
|
||||
@IStatusbarService private readonly _statusbarService: IStatusbarService,
|
||||
@ILayoutService private readonly _layoutService: ILayoutService,
|
||||
@IThemeService private readonly _themeService: IThemeService
|
||||
@IThemeService private readonly _themeService: IThemeService,
|
||||
@IKeybindingService private readonly _keybindingService: IKeybindingService
|
||||
) { }
|
||||
|
||||
withProgress<R = unknown>(options: IProgressOptions, task: (progress: IProgress<IProgressStep>) => Promise<R>, onDidCancel?: () => void): Promise<R> {
|
||||
@@ -276,6 +280,10 @@ export class ProgressService2 implements IProgressService2 {
|
||||
|
||||
private _withDialogProgress<P extends Promise<R>, R = unknown>(options: IProgressOptions, task: (progress: IProgress<{ message?: string, increment?: number }>) => P, onDidCancel?: () => void): P {
|
||||
const disposables: IDisposable[] = [];
|
||||
const allowableCommands = [
|
||||
'workbench.action.quit',
|
||||
'workbench.action.reloadWindow'
|
||||
];
|
||||
|
||||
let dialog: Dialog;
|
||||
|
||||
@@ -284,7 +292,17 @@ export class ProgressService2 implements IProgressService2 {
|
||||
this._layoutService.container,
|
||||
message,
|
||||
[options.cancellable ? localize('cancel', "Cancel") : localize('dismiss', "Dismiss")],
|
||||
{ type: 'pending' }
|
||||
{
|
||||
type: 'pending',
|
||||
keyEventProcessor: (event: StandardKeyboardEvent) => {
|
||||
const resolved = this._keybindingService.softDispatch(event, this._layoutService.container);
|
||||
if (resolved && resolved.commandId) {
|
||||
if (allowableCommands.indexOf(resolved.commandId) === -1) {
|
||||
EventHelper.stop(event, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
disposables.push(dialog);
|
||||
|
||||
@@ -8,7 +8,7 @@ import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IChannel, IServerChannel, getDelayedChannel } from 'vs/base/parts/ipc/common/ipc';
|
||||
import { Client } from 'vs/base/parts/ipc/common/ipc.net';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { connectRemoteAgentManagement, IConnectionOptions, IWebSocketFactory } from 'vs/platform/remote/common/remoteAgentConnection';
|
||||
import { connectRemoteAgentManagement, IConnectionOptions, IWebSocketFactory, PersistenConnectionEvent } from 'vs/platform/remote/common/remoteAgentConnection';
|
||||
import { IRemoteAgentConnection, IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
@@ -73,15 +73,18 @@ export class RemoteAgentConnection extends Disposable implements IRemoteAgentCon
|
||||
private readonly _onReconnecting = this._register(new Emitter<void>());
|
||||
public readonly onReconnecting = this._onReconnecting.event;
|
||||
|
||||
private readonly _onDidStateChange = this._register(new Emitter<PersistenConnectionEvent>());
|
||||
public readonly onDidStateChange = this._onDidStateChange.event;
|
||||
|
||||
readonly remoteAuthority: string;
|
||||
private _connection: Promise<Client<RemoteAgentConnectionContext>> | null;
|
||||
|
||||
constructor(
|
||||
remoteAuthority: string,
|
||||
private _commit: string | undefined,
|
||||
private _webSocketFactory: IWebSocketFactory,
|
||||
private _environmentService: IEnvironmentService,
|
||||
private _remoteAuthorityResolverService: IRemoteAuthorityResolverService
|
||||
private readonly _commit: string | undefined,
|
||||
private readonly _webSocketFactory: IWebSocketFactory,
|
||||
private readonly _environmentService: IEnvironmentService,
|
||||
private readonly _remoteAuthorityResolverService: IRemoteAuthorityResolverService
|
||||
) {
|
||||
super();
|
||||
this.remoteAuthority = remoteAuthority;
|
||||
@@ -121,8 +124,8 @@ export class RemoteAgentConnection extends Disposable implements IRemoteAgentCon
|
||||
}
|
||||
}
|
||||
};
|
||||
const connection = await connectRemoteAgentManagement(options, this.remoteAuthority, `renderer`);
|
||||
this._register(connection);
|
||||
const connection = this._register(await connectRemoteAgentManagement(options, this.remoteAuthority, `renderer`));
|
||||
this._register(connection.onDidStateChange(e => this._onDidStateChange.fire(e)));
|
||||
return connection.client;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import { RemoteAgentConnectionContext, IRemoteAgentEnvironment } from 'vs/platfo
|
||||
import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc';
|
||||
import { IDiagnosticInfoOptions, IDiagnosticInfo } from 'vs/platform/diagnostics/common/diagnosticsService';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { PersistenConnectionEvent } from 'vs/platform/remote/common/remoteAgentConnection';
|
||||
|
||||
export const RemoteExtensionLogFileName = 'remoteagent';
|
||||
|
||||
@@ -25,7 +26,9 @@ export interface IRemoteAgentService {
|
||||
export interface IRemoteAgentConnection {
|
||||
readonly remoteAuthority: string;
|
||||
|
||||
readonly onReconnecting: Event<void>;
|
||||
readonly onDidStateChange: Event<PersistenConnectionEvent>;
|
||||
|
||||
getChannel<T extends IChannel>(channelName: string): T;
|
||||
registerChannel<T extends IServerChannel<RemoteAgentConnectionContext>>(channelName: string, channel: T): void;
|
||||
onReconnecting: Event<void>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user