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"
|
"vscode": "^1.20.0"
|
||||||
},
|
},
|
||||||
"main": "./out/extension",
|
"main": "./out/extension",
|
||||||
|
"extensionKind": "ui",
|
||||||
"categories": [
|
"categories": [
|
||||||
"Programming Languages"
|
"Programming Languages"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -23,8 +23,8 @@
|
|||||||
"selection.background": "#ccccc7",
|
"selection.background": "#ccccc7",
|
||||||
"editor.selectionHighlightBackground": "#575b6180",
|
"editor.selectionHighlightBackground": "#575b6180",
|
||||||
"editor.selectionBackground": "#878b9180",
|
"editor.selectionBackground": "#878b9180",
|
||||||
"editor.wordHighlightBackground": "#4a4a7680",
|
"editor.wordHighlightBackground": "#4a4a7680",
|
||||||
"editor.wordHighlightStrongBackground": "#6a6a9680",
|
"editor.wordHighlightStrongBackground": "#6a6a9680",
|
||||||
"editor.lineHighlightBackground": "#3e3d32",
|
"editor.lineHighlightBackground": "#3e3d32",
|
||||||
"editorLineNumber.activeForeground": "#c2c2bf",
|
"editorLineNumber.activeForeground": "#c2c2bf",
|
||||||
"editorCursor.foreground": "#f8f8f0",
|
"editorCursor.foreground": "#f8f8f0",
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ function darkenColor(color) {
|
|||||||
for (let i = 1; i < 7; i += 2) {
|
for (let i = 1; i < 7; i += 2) {
|
||||||
let newVal = Math.round(parseInt('0x' + color.substr(i, 2), 16) * 0.9);
|
let newVal = Math.round(parseInt('0x' + color.substr(i, 2), 16) * 0.9);
|
||||||
let hex = newVal.toString(16);
|
let hex = newVal.toString(16);
|
||||||
if (hex.length == 1) {
|
if (hex.length === 1) {
|
||||||
res += '0';
|
res += '0';
|
||||||
}
|
}
|
||||||
res += hex;
|
res += hex;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
COMMIT="@@COMMIT@@"
|
COMMIT="@@COMMIT@@"
|
||||||
APP_NAME="@@APPNAME@@"
|
APP_NAME="@@APPNAME@@"
|
||||||
QUALITY="@@QUALITY@@"
|
QUALITY="@@QUALITY@@"
|
||||||
|
NAME="@@NAME@@"
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
@@ -22,6 +23,8 @@ if grep -qi Microsoft /proc/version; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
VSCODE_PATH="$(dirname "$(dirname "$(realpath "$0")")")"
|
||||||
|
|
||||||
if [ -x "$(command -v cygpath)" ]; then
|
if [ -x "$(command -v cygpath)" ]; then
|
||||||
CLI=$(cygpath -m "$VSCODE_PATH/resources/app/out/cli.js")
|
CLI=$(cygpath -m "$VSCODE_PATH/resources/app/out/cli.js")
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -59,19 +59,19 @@ function code-wsl()
|
|||||||
{
|
{
|
||||||
# in a wsl shell
|
# in a wsl shell
|
||||||
local WIN_CODE_CLI_CMD=$(wslpath -w "$ROOT/scripts/code-cli.bat")
|
local WIN_CODE_CLI_CMD=$(wslpath -w "$ROOT/scripts/code-cli.bat")
|
||||||
|
if ! [ -z "$WIN_CODE_CLI_CMD" ]; then
|
||||||
local WSL_EXT_ID="ms-vscode.remote-wsl"
|
local WSL_EXT_ID="ms-vscode.remote-wsl"
|
||||||
local WSL_EXT_WLOC=$(cmd.exe /c "$WIN_CODE_CLI_CMD" --locate-extension $WSL_EXT_ID)
|
local WSL_EXT_WLOC=$(cmd.exe /c "$WIN_CODE_CLI_CMD" --locate-extension $WSL_EXT_ID)
|
||||||
if ! [ -z "$WSL_EXT_WLOC" ]; then
|
if ! [ -z "$WSL_EXT_WLOC" ]; then
|
||||||
# replace \r\n with \n in WSL_EXT_WLOC
|
# replace \r\n with \n in WSL_EXT_WLOC
|
||||||
local WSL_CODE=$(wslpath -u "${WSL_EXT_WLOC%%[[:cntrl:]]}")/scripts/wslCode-dev.sh
|
local WSL_CODE=$(wslpath -u "${WSL_EXT_WLOC%%[[:cntrl:]]}")/scripts/wslCode-dev.sh
|
||||||
$WSL_CODE "$ROOT" "$@"
|
$WSL_CODE "$ROOT" "$@"
|
||||||
exit $?
|
exit $?
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
if [ -z ${IN_WSL+x} ]; then
|
if ! [ -z ${IN_WSL+x} ]; then
|
||||||
code "$@"
|
|
||||||
else
|
|
||||||
code-wsl "$@"
|
code-wsl "$@"
|
||||||
fi
|
fi
|
||||||
|
code "$@"
|
||||||
@@ -20,6 +20,7 @@ export interface IDialogOptions {
|
|||||||
cancelId?: number;
|
cancelId?: number;
|
||||||
detail?: string;
|
detail?: string;
|
||||||
type?: 'none' | 'info' | 'error' | 'question' | 'warning' | 'pending';
|
type?: 'none' | 'info' | 'error' | 'question' | 'warning' | 'pending';
|
||||||
|
keyEventProcessor?: (event: StandardKeyboardEvent) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IDialogStyles extends IButtonStyles {
|
export interface IDialogStyles extends IButtonStyles {
|
||||||
@@ -103,19 +104,26 @@ export class Dialog extends Disposable {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let eventHandled = false;
|
||||||
if (this.buttonGroup) {
|
if (this.buttonGroup) {
|
||||||
if (evt.equals(KeyMod.Shift | KeyCode.Tab) || evt.equals(KeyCode.LeftArrow)) {
|
if (evt.equals(KeyMod.Shift | KeyCode.Tab) || evt.equals(KeyCode.LeftArrow)) {
|
||||||
focusedButton = focusedButton + this.buttonGroup.buttons.length - 1;
|
focusedButton = focusedButton + this.buttonGroup.buttons.length - 1;
|
||||||
focusedButton = focusedButton % this.buttonGroup.buttons.length;
|
focusedButton = focusedButton % this.buttonGroup.buttons.length;
|
||||||
this.buttonGroup.buttons[focusedButton].focus();
|
this.buttonGroup.buttons[focusedButton].focus();
|
||||||
|
eventHandled = true;
|
||||||
} else if (evt.equals(KeyCode.Tab) || evt.equals(KeyCode.RightArrow)) {
|
} else if (evt.equals(KeyCode.Tab) || evt.equals(KeyCode.RightArrow)) {
|
||||||
focusedButton++;
|
focusedButton++;
|
||||||
focusedButton = focusedButton % this.buttonGroup.buttons.length;
|
focusedButton = focusedButton % this.buttonGroup.buttons.length;
|
||||||
this.buttonGroup.buttons[focusedButton].focus();
|
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) => {
|
this._register(domEvent(window, 'keyup', true)((e: KeyboardEvent) => {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
.monaco-sash {
|
.monaco-sash {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 90;
|
z-index: 35;
|
||||||
touch-action: none;
|
touch-action: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ export default (): string => `
|
|||||||
<input class="sendData" type="checkbox" id="includeSystemInfo" checked/>
|
<input class="sendData" type="checkbox" id="includeSystemInfo" checked/>
|
||||||
<label class="caption" for="includeSystemInfo">${escape(localize({
|
<label class="caption" for="includeSystemInfo">${escape(localize({
|
||||||
key: 'sendSystemInfo',
|
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>
|
}, "Include my system information ({0})")).replace('{0}', `<a href="#" class="showInfo">${escape(localize('show', "show"))}</a>`)}</label>
|
||||||
<div class="block-info hidden">
|
<div class="block-info hidden">
|
||||||
<!-- To be dynamically filled -->
|
<!-- To be dynamically filled -->
|
||||||
@@ -73,7 +73,7 @@ export default (): string => `
|
|||||||
<input class="sendData" type="checkbox" id="includeProcessInfo" checked/>
|
<input class="sendData" type="checkbox" id="includeProcessInfo" checked/>
|
||||||
<label class="caption" for="includeProcessInfo">${escape(localize({
|
<label class="caption" for="includeProcessInfo">${escape(localize({
|
||||||
key: 'sendProcessInfo',
|
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>
|
}, "Include my currently running processes ({0})")).replace('{0}', `<a href="#" class="showInfo">${escape(localize('show', "show"))}</a>`)}</label>
|
||||||
<pre class="block-info hidden">
|
<pre class="block-info hidden">
|
||||||
<code>
|
<code>
|
||||||
@@ -85,7 +85,7 @@ export default (): string => `
|
|||||||
<input class="sendData" type="checkbox" id="includeWorkspaceInfo" checked/>
|
<input class="sendData" type="checkbox" id="includeWorkspaceInfo" checked/>
|
||||||
<label class="caption" for="includeWorkspaceInfo">${escape(localize({
|
<label class="caption" for="includeWorkspaceInfo">${escape(localize({
|
||||||
key: 'sendWorkspaceInfo',
|
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>
|
}, "Include my workspace metadata ({0})")).replace('{0}', `<a href="#" class="showInfo">${escape(localize('show', "show"))}</a>`)}</label>
|
||||||
<pre id="systemInfo" class="block-info hidden">
|
<pre id="systemInfo" class="block-info hidden">
|
||||||
<code>
|
<code>
|
||||||
@@ -97,7 +97,7 @@ export default (): string => `
|
|||||||
<input class="sendData" type="checkbox" id="includeExtensions" checked/>
|
<input class="sendData" type="checkbox" id="includeExtensions" checked/>
|
||||||
<label class="caption" for="includeExtensions">${escape(localize({
|
<label class="caption" for="includeExtensions">${escape(localize({
|
||||||
key: 'sendExtensions',
|
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>
|
}, "Include my enabled extensions ({0})")).replace('{0}', `<a href="#" class="showInfo">${escape(localize('show', "show"))}</a>`)}</label>
|
||||||
<div id="systemInfo" class="block-info hidden">
|
<div id="systemInfo" class="block-info hidden">
|
||||||
<!-- To be dynamically filled -->
|
<!-- To be dynamically filled -->
|
||||||
@@ -107,7 +107,7 @@ export default (): string => `
|
|||||||
<input class="sendData" type="checkbox" id="includeSearchedExtensions" checked/>
|
<input class="sendData" type="checkbox" id="includeSearchedExtensions" checked/>
|
||||||
<label class="caption" for="includeSearchedExtensions">${escape(localize({
|
<label class="caption" for="includeSearchedExtensions">${escape(localize({
|
||||||
key: 'sendSearchedExtensions',
|
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>
|
}, "Send searched extensions ({0})")).replace('{0}', `<a href="#" class="showInfo">${escape(localize('show', "show"))}</a>`)}</label>
|
||||||
<div class="block-info hidden">
|
<div class="block-info hidden">
|
||||||
<!-- To be dynamically filled -->
|
<!-- To be dynamically filled -->
|
||||||
@@ -117,7 +117,7 @@ export default (): string => `
|
|||||||
<input class="sendData" type="checkbox" id="includeSettingsSearchDetails" checked/>
|
<input class="sendData" type="checkbox" id="includeSettingsSearchDetails" checked/>
|
||||||
<label class="caption" for="includeSettingsSearchDetails">${escape(localize({
|
<label class="caption" for="includeSettingsSearchDetails">${escape(localize({
|
||||||
key: 'sendSettingsSearchDetails',
|
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>
|
}, "Send settings search details ({0})")).replace('{0}', `<a href="#" class="showInfo">${escape(localize('show', "show"))}</a>`)}</label>
|
||||||
<div class="block-info hidden">
|
<div class="block-info hidden">
|
||||||
<!-- To be dynamically filled -->
|
<!-- 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)
|
// (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.setWidth(1);
|
||||||
ta.setHeight(1);
|
ta.setHeight(1);
|
||||||
|
|||||||
@@ -344,7 +344,7 @@ export class TextAreaInput extends Disposable {
|
|||||||
//
|
//
|
||||||
// The problems with the `selectionchange` event are:
|
// 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 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 the value of the textarea is changed programmatically -- textarea.value = '...'
|
||||||
// * the event is emitted when tabbing into the textarea
|
// * 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)
|
// * 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>;
|
onDidChangeCommentThreads(): Event<CommentThreadChangedEvent>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export interface IWebviewPortMapping {
|
||||||
|
webviewPort: number;
|
||||||
|
extensionHostPort: number;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
@@ -1415,7 +1423,7 @@ export interface IWebviewOptions {
|
|||||||
readonly enableScripts?: boolean;
|
readonly enableScripts?: boolean;
|
||||||
readonly enableCommandUris?: boolean;
|
readonly enableCommandUris?: boolean;
|
||||||
readonly localResourceRoots?: ReadonlyArray<URI>;
|
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 { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||||
import { attachDialogStyler } from 'vs/platform/theme/common/styler';
|
import { attachDialogStyler } from 'vs/platform/theme/common/styler';
|
||||||
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
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 {
|
export class DialogService implements IDialogService {
|
||||||
_serviceBrand: any;
|
_serviceBrand: any;
|
||||||
@@ -76,7 +78,10 @@ export class DialogService implements IDialogService {
|
|||||||
{
|
{
|
||||||
detail: options ? options.detail : undefined,
|
detail: options ? options.detail : undefined,
|
||||||
cancelId: options ? options.cancelId : undefined,
|
cancelId: options ? options.cancelId : undefined,
|
||||||
type: this.getDialogType(severity)
|
type: this.getDialogType(severity),
|
||||||
|
keyEventProcessor: (event: StandardKeyboardEvent) => {
|
||||||
|
EventHelper.stop(event, true);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
dialogDisposables.push(dialog);
|
dialogDisposables.push(dialog);
|
||||||
|
|||||||
@@ -206,12 +206,14 @@ export function buildHelpMessage(productName: string, executableName: string, ve
|
|||||||
help.push('');
|
help.push('');
|
||||||
help.push(`${localize('usage', "Usage")}: ${executableName} [${localize('options', "options")}][${localize('paths', 'paths')}...]`);
|
help.push(`${localize('usage', "Usage")}: ${executableName} [${localize('options', "options")}][${localize('paths', 'paths')}...]`);
|
||||||
help.push('');
|
help.push('');
|
||||||
if (os.platform() === 'win32') {
|
if (isPipeSupported) {
|
||||||
help.push(localize('stdinWindows', "To read output from another program, append '-' (e.g. 'echo Hello World | {0} -')", executableName));
|
if (os.platform() === 'win32') {
|
||||||
} else {
|
help.push(localize('stdinWindows', "To read output from another program, append '-' (e.g. 'echo Hello World | {0} -')", executableName));
|
||||||
help.push(localize('stdinUnix', "To read from stdin, append '-' (e.g. 'ps aux | grep code | {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) {
|
for (let key in categories) {
|
||||||
let categoryOptions = options.filter(o => !!o.description && o.cat === key && isOptionSupported(o));
|
let categoryOptions = options.filter(o => !!o.description && o.cat === key && isOptionSupported(o));
|
||||||
if (categoryOptions.length) {
|
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 {
|
export function isUIExtension(manifest: IExtensionManifest, uiContributions: string[], configurationService: IConfigurationService): boolean {
|
||||||
const extensionId = getGalleryExtensionId(manifest.publisher, manifest.name);
|
const extensionId = getGalleryExtensionId(manifest.publisher, manifest.name);
|
||||||
const configuredUIExtensions = configurationService.getValue<string[]>('_workbench.uiExtensions') || [];
|
const configuredUIExtensions = configurationService.getValue<string[]>('_workbench.uiExtensions') || [];
|
||||||
if (configuredUIExtensions.length) {
|
if (configuredUIExtensions.some(id => areSameExtensions({ id }, { id: extensionId }))) {
|
||||||
if (configuredUIExtensions.indexOf(extensionId) !== -1) {
|
return true;
|
||||||
return true;
|
}
|
||||||
}
|
if (configuredUIExtensions.some(id => areSameExtensions({ id }, { id: `-${extensionId}` }))) {
|
||||||
if (configuredUIExtensions.indexOf(`-${extensionId}`) !== -1) {
|
return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
switch (manifest.extensionKind) {
|
switch (manifest.extensionKind) {
|
||||||
case 'ui': return true;
|
case 'ui': return true;
|
||||||
|
|||||||
@@ -162,6 +162,16 @@ export interface IQuickPick<T extends IQuickPickItem> extends IQuickInput {
|
|||||||
|
|
||||||
readonly onDidAccept: Event<void>;
|
readonly onDidAccept: Event<void>;
|
||||||
|
|
||||||
|
ok: boolean;
|
||||||
|
|
||||||
|
readonly onDidCustom: Event<void>;
|
||||||
|
|
||||||
|
customButton: boolean;
|
||||||
|
|
||||||
|
customLabel: string;
|
||||||
|
|
||||||
|
customHover: string;
|
||||||
|
|
||||||
buttons: ReadonlyArray<IQuickInputButton>;
|
buttons: ReadonlyArray<IQuickInputButton>;
|
||||||
|
|
||||||
readonly onDidTriggerButton: Event<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 { generateUuid } from 'vs/base/common/uuid';
|
||||||
import { RemoteAgentConnectionContext } from 'vs/platform/remote/common/remoteAgentEnvironment';
|
import { RemoteAgentConnectionContext } from 'vs/platform/remote/common/remoteAgentEnvironment';
|
||||||
import { Disposable } from 'vs/base/common/lifecycle';
|
import { Disposable } from 'vs/base/common/lifecycle';
|
||||||
|
import { Emitter } from 'vs/base/common/event';
|
||||||
|
|
||||||
export const enum ConnectionType {
|
export const enum ConnectionType {
|
||||||
Management = 1,
|
Management = 1,
|
||||||
@@ -147,8 +148,38 @@ export async function connectRemoteAgentTunnel(options: IConnectionOptions, tunn
|
|||||||
return protocol;
|
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 {
|
abstract class PersistentConnection extends Disposable {
|
||||||
|
|
||||||
|
private readonly _onDidStateChange = this._register(new Emitter<PersistenConnectionEvent>());
|
||||||
|
public readonly onDidStateChange = this._onDidStateChange.event;
|
||||||
|
|
||||||
protected readonly _options: IConnectionOptions;
|
protected readonly _options: IConnectionOptions;
|
||||||
public readonly reconnectionToken: string;
|
public readonly reconnectionToken: string;
|
||||||
public readonly protocol: PersistentProtocol;
|
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>;
|
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.
|
* Content settings for a webview.
|
||||||
*/
|
*/
|
||||||
@@ -5740,6 +5755,18 @@ declare module 'vscode' {
|
|||||||
* Pass in an empty array to disallow access to any local resources.
|
* Pass in an empty array to disallow access to any local resources.
|
||||||
*/
|
*/
|
||||||
readonly localResourceRoots?: ReadonlyArray<Uri>;
|
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;
|
group?: string;
|
||||||
}
|
}
|
||||||
//#endregion
|
//#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) {
|
if (activeInstance) {
|
||||||
this._proxy.$acceptActiveTerminalChanged(activeInstance.id);
|
this._proxy.$acceptActiveTerminalChanged(activeInstance.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.terminalService.extHostReady(extHostContext.remoteAuthority);
|
||||||
}
|
}
|
||||||
|
|
||||||
public dispose(): void {
|
public dispose(): void {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
|||||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||||
import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows';
|
import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows';
|
||||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
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 { ITunnelService, RemoteTunnel } from 'vs/platform/remote/common/tunnel';
|
||||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||||
|
|
||||||
@@ -45,9 +45,9 @@ export class MainThreadWindow implements MainThreadWindowShape {
|
|||||||
return this.windowService.isFocused();
|
return this.windowService.isFocused();
|
||||||
}
|
}
|
||||||
|
|
||||||
async $openUri(uriComponent: UriComponents): Promise<boolean> {
|
async $openUri(uriComponent: UriComponents, options: IOpenUriOptions): Promise<boolean> {
|
||||||
const uri = URI.revive(uriComponent);
|
const uri = URI.revive(uriComponent);
|
||||||
if (!!this.environmentService.configuration.remoteAuthority) {
|
if (options.allowTunneling && !!this.environmentService.configuration.remoteAuthority) {
|
||||||
if (uri.scheme === 'http' || uri.scheme === 'https') {
|
if (uri.scheme === 'http' || uri.scheme === 'https') {
|
||||||
const port = this.getLocalhostPort(uri);
|
const port = this.getLocalhostPort(uri);
|
||||||
if (typeof port === 'number') {
|
if (typeof port === 'number') {
|
||||||
|
|||||||
@@ -539,7 +539,7 @@ export interface ExtHostWebviewsShape {
|
|||||||
$onMessage(handle: WebviewPanelHandle, message: any): void;
|
$onMessage(handle: WebviewPanelHandle, message: any): void;
|
||||||
$onDidChangeWebviewPanelViewState(handle: WebviewPanelHandle, newState: WebviewPanelViewState): void;
|
$onDidChangeWebviewPanelViewState(handle: WebviewPanelHandle, newState: WebviewPanelViewState): void;
|
||||||
$onDidDisposeWebviewPanel(handle: WebviewPanelHandle): Promise<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 {
|
export interface MainThreadUrlsShape extends IDisposable {
|
||||||
@@ -689,9 +689,13 @@ export interface MainThreadDebugServiceShape extends IDisposable {
|
|||||||
$unregisterBreakpoints(breakpointIds: string[], functionBreakpointIds: string[]): Promise<void>;
|
$unregisterBreakpoints(breakpointIds: string[], functionBreakpointIds: string[]): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IOpenUriOptions {
|
||||||
|
readonly allowTunneling?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface MainThreadWindowShape extends IDisposable {
|
export interface MainThreadWindowShape extends IDisposable {
|
||||||
$getWindowVisibility(): Promise<boolean>;
|
$getWindowVisibility(): Promise<boolean>;
|
||||||
$openUri(uri: UriComponents): Promise<boolean>;
|
$openUri(uri: UriComponents, options: IOpenUriOptions): Promise<boolean>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- extension host
|
// -- extension host
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import * as vscode from 'vscode';
|
|||||||
import { ExtHostWebviewsShape, IMainContext, MainContext, MainThreadWebviewsShape, WebviewPanelHandle, WebviewPanelViewState, WebviewInsetHandle } from './extHost.protocol';
|
import { ExtHostWebviewsShape, IMainContext, MainContext, MainThreadWebviewsShape, WebviewPanelHandle, WebviewPanelViewState, WebviewInsetHandle } from './extHost.protocol';
|
||||||
import { Disposable } from './extHostTypes';
|
import { Disposable } from './extHostTypes';
|
||||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||||
|
import * as modes from 'vs/editor/common/modes';
|
||||||
|
|
||||||
type IconPath = URI | { light: URI, dark: URI };
|
type IconPath = URI | { light: URI, dark: URI };
|
||||||
|
|
||||||
@@ -58,7 +59,7 @@ export class ExtHostWebview implements vscode.Webview {
|
|||||||
|
|
||||||
public set options(newOptions: vscode.WebviewOptions) {
|
public set options(newOptions: vscode.WebviewOptions) {
|
||||||
this.assertNotDisposed();
|
this.assertNotDisposed();
|
||||||
this._proxy.$setOptions(this._handle, newOptions);
|
this._proxy.$setOptions(this._handle, convertWebviewOptions(newOptions));
|
||||||
this._options = newOptions;
|
this._options = newOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,7 +258,7 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handle = ExtHostWebviews.newHandle();
|
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 webview = new ExtHostWebview(handle, this._proxy, options);
|
||||||
const panel = new ExtHostWebviewPanel(handle, this._proxy, viewType, title, viewColumn, options, webview);
|
const panel = new ExtHostWebviewPanel(handle, this._proxy, viewType, title, viewColumn, options, webview);
|
||||||
@@ -325,7 +326,7 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
|
|||||||
title: string,
|
title: string,
|
||||||
state: any,
|
state: any,
|
||||||
position: EditorViewColumn,
|
position: EditorViewColumn,
|
||||||
options: vscode.WebviewOptions & vscode.WebviewPanelOptions
|
options: modes.IWebviewOptions & modes.IWebviewPanelOptions
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const serializer = this._serializers.get(viewType);
|
const serializer = this._serializers.get(viewType);
|
||||||
if (!serializer) {
|
if (!serializer) {
|
||||||
@@ -342,3 +343,20 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
|
|||||||
return this._webviewPanels.get(handle);
|
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 { 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 { WindowState } from 'vscode';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { Schemas } from 'vs/base/common/network';
|
import { Schemas } from 'vs/base/common/network';
|
||||||
@@ -38,7 +38,7 @@ export class ExtHostWindow implements ExtHostWindowShape {
|
|||||||
this._onDidChangeWindowState.fire(this._state);
|
this._onDidChangeWindowState.fire(this._state);
|
||||||
}
|
}
|
||||||
|
|
||||||
openUri(stringOrUri: string | URI): Promise<boolean> {
|
openUri(stringOrUri: string | URI, options: IOpenUriOptions): Promise<boolean> {
|
||||||
if (typeof stringOrUri === 'string') {
|
if (typeof stringOrUri === 'string') {
|
||||||
try {
|
try {
|
||||||
stringOrUri = URI.parse(stringOrUri);
|
stringOrUri = URI.parse(stringOrUri);
|
||||||
@@ -51,6 +51,6 @@ export class ExtHostWindow implements ExtHostWindowShape {
|
|||||||
} else if (stringOrUri.scheme === Schemas.command) {
|
} else if (stringOrUri.scheme === Schemas.command) {
|
||||||
return Promise.reject(`Invalid scheme '${stringOrUri.scheme}'`);
|
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 * as map from 'vs/base/common/map';
|
||||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
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 { localize } from 'vs/nls';
|
||||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
@@ -122,7 +122,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
|||||||
$createWebviewCodeInset(
|
$createWebviewCodeInset(
|
||||||
handle: WebviewInsetHandle,
|
handle: WebviewInsetHandle,
|
||||||
symbolId: string,
|
symbolId: string,
|
||||||
options: IWebviewOptions,
|
options: modes.IWebviewOptions,
|
||||||
extensionId: ExtensionIdentifier,
|
extensionId: ExtensionIdentifier,
|
||||||
extensionLocation: UriComponents
|
extensionLocation: UriComponents
|
||||||
): void {
|
): 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') {
|
if (typeof handle === 'number') {
|
||||||
this.getWebviewElement(handle).options = reviveWebviewOptions(options as any /*todo@mat */);
|
this.getWebviewElement(handle).options = reviveWebviewOptions(options as any /*todo@mat */);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -257,7 +257,7 @@ export function createApiFactory(
|
|||||||
return extHostClipboard;
|
return extHostClipboard;
|
||||||
},
|
},
|
||||||
openExternal(uri: URI) {
|
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);
|
return this.callOriginal(target, options);
|
||||||
}
|
}
|
||||||
if (uri.scheme === 'http' || uri.scheme === 'https') {
|
if (uri.scheme === 'http' || uri.scheme === 'https') {
|
||||||
return mainThreadWindow.$openUri(uri);
|
return mainThreadWindow.$openUri(uri, { allowTunneling: true });
|
||||||
} else if (uri.scheme === 'mailto') {
|
} else if (uri.scheme === 'mailto') {
|
||||||
return mainThreadWindow.$openUri(uri);
|
return mainThreadWindow.$openUri(uri, {});
|
||||||
}
|
}
|
||||||
return this.callOriginal(target, options);
|
return this.callOriginal(target, options);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -68,9 +68,11 @@ interface QuickInputUI {
|
|||||||
visibleCount: CountBadge;
|
visibleCount: CountBadge;
|
||||||
count: CountBadge;
|
count: CountBadge;
|
||||||
message: HTMLElement;
|
message: HTMLElement;
|
||||||
|
customButton: Button;
|
||||||
progressBar: ProgressBar;
|
progressBar: ProgressBar;
|
||||||
list: QuickInputList;
|
list: QuickInputList;
|
||||||
onDidAccept: Event<void>;
|
onDidAccept: Event<void>;
|
||||||
|
onDidCustom: Event<void>;
|
||||||
onDidTriggerButton: Event<IQuickInputButton>;
|
onDidTriggerButton: Event<IQuickInputButton>;
|
||||||
ignoreFocusOut: boolean;
|
ignoreFocusOut: boolean;
|
||||||
keyMods: Writeable<IKeyMods>;
|
keyMods: Writeable<IKeyMods>;
|
||||||
@@ -92,6 +94,7 @@ type Visibilities = {
|
|||||||
message?: boolean;
|
message?: boolean;
|
||||||
list?: boolean;
|
list?: boolean;
|
||||||
ok?: boolean;
|
ok?: boolean;
|
||||||
|
customButton?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
class QuickInput implements IQuickInput {
|
class QuickInput implements IQuickInput {
|
||||||
@@ -312,6 +315,7 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
|
|||||||
private _placeholder: string;
|
private _placeholder: string;
|
||||||
private onDidChangeValueEmitter = new Emitter<string>();
|
private onDidChangeValueEmitter = new Emitter<string>();
|
||||||
private onDidAcceptEmitter = new Emitter<void>();
|
private onDidAcceptEmitter = new Emitter<void>();
|
||||||
|
private onDidCustomEmitter = new Emitter<void>();
|
||||||
private _items: Array<T | IQuickPickSeparator> = [];
|
private _items: Array<T | IQuickPickSeparator> = [];
|
||||||
private itemsUpdated = false;
|
private itemsUpdated = false;
|
||||||
private _canSelectMany = false;
|
private _canSelectMany = false;
|
||||||
@@ -331,6 +335,10 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
|
|||||||
private _valueSelection: Readonly<[number, number]>;
|
private _valueSelection: Readonly<[number, number]>;
|
||||||
private valueSelectionUpdated = true;
|
private valueSelectionUpdated = true;
|
||||||
private _validationMessage: string;
|
private _validationMessage: string;
|
||||||
|
private _ok: boolean;
|
||||||
|
private _customButton: boolean;
|
||||||
|
private _customButtonLabel: string;
|
||||||
|
private _customButtonHover: string;
|
||||||
|
|
||||||
quickNavigate: IQuickNavigateConfiguration;
|
quickNavigate: IQuickNavigateConfiguration;
|
||||||
|
|
||||||
@@ -339,6 +347,7 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
|
|||||||
this.disposables.push(
|
this.disposables.push(
|
||||||
this.onDidChangeValueEmitter,
|
this.onDidChangeValueEmitter,
|
||||||
this.onDidAcceptEmitter,
|
this.onDidAcceptEmitter,
|
||||||
|
this.onDidCustomEmitter,
|
||||||
this.onDidChangeActiveEmitter,
|
this.onDidChangeActiveEmitter,
|
||||||
this.onDidChangeSelectionEmitter,
|
this.onDidChangeSelectionEmitter,
|
||||||
this.onDidTriggerItemButtonEmitter,
|
this.onDidTriggerItemButtonEmitter,
|
||||||
@@ -367,6 +376,8 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
|
|||||||
|
|
||||||
onDidAccept = this.onDidAcceptEmitter.event;
|
onDidAccept = this.onDidAcceptEmitter.event;
|
||||||
|
|
||||||
|
onDidCustom = this.onDidCustomEmitter.event;
|
||||||
|
|
||||||
get items() {
|
get items() {
|
||||||
return this._items;
|
return this._items;
|
||||||
}
|
}
|
||||||
@@ -463,6 +474,42 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
|
|||||||
this.update();
|
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 {
|
public inputHasFocus(): boolean {
|
||||||
return this.visible ? this.ui.inputBox.hasFocus() : false;
|
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.onDidAcceptEmitter.fire(undefined);
|
||||||
}),
|
}),
|
||||||
|
this.ui.onDidCustom(() => {
|
||||||
|
this.onDidCustomEmitter.fire(undefined);
|
||||||
|
}),
|
||||||
this.ui.list.onDidChangeFocus(focusedItems => {
|
this.ui.list.onDidChangeFocus(focusedItems => {
|
||||||
if (this.activeItemsUpdated) {
|
if (this.activeItemsUpdated) {
|
||||||
return; // Expect another event.
|
return; // Expect another event.
|
||||||
@@ -697,12 +747,14 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
|
|||||||
this.ui.message.textContent = null;
|
this.ui.message.textContent = null;
|
||||||
this.ui.inputBox.showDecoration(Severity.Ignore);
|
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.matchOnDescription = this.matchOnDescription;
|
||||||
this.ui.list.matchOnDetail = this.matchOnDetail;
|
this.ui.list.matchOnDetail = this.matchOnDetail;
|
||||||
this.ui.list.matchOnLabel = this.matchOnLabel;
|
this.ui.list.matchOnLabel = this.matchOnLabel;
|
||||||
this.ui.setComboboxAccessibility(true);
|
this.ui.setComboboxAccessibility(true);
|
||||||
this.ui.inputBox.setAttribute('aria-label', QuickPick.INPUT_BOX_ARIA_LABEL);
|
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 countContainer: HTMLElement;
|
||||||
private okContainer: HTMLElement;
|
private okContainer: HTMLElement;
|
||||||
private ok: Button;
|
private ok: Button;
|
||||||
|
private customButtonContainer: HTMLElement;
|
||||||
private ui: QuickInputUI;
|
private ui: QuickInputUI;
|
||||||
private comboboxAccessibility = false;
|
private comboboxAccessibility = false;
|
||||||
private enabled = true;
|
private enabled = true;
|
||||||
@@ -855,6 +908,7 @@ export class QuickInputService extends Component implements IQuickInputService {
|
|||||||
private inQuickOpenContext: IContextKey<boolean>;
|
private inQuickOpenContext: IContextKey<boolean>;
|
||||||
private contexts: { [id: string]: IContextKey<boolean>; } = Object.create(null);
|
private contexts: { [id: string]: IContextKey<boolean>; } = Object.create(null);
|
||||||
private onDidAcceptEmitter = this._register(new Emitter<void>());
|
private onDidAcceptEmitter = this._register(new Emitter<void>());
|
||||||
|
private onDidCustomEmitter = this._register(new Emitter<void>());
|
||||||
private onDidTriggerButtonEmitter = this._register(new Emitter<IQuickInputButton>());
|
private onDidTriggerButtonEmitter = this._register(new Emitter<IQuickInputButton>());
|
||||||
private keyMods: Writeable<IKeyMods> = { ctrlCmd: false, alt: false };
|
private keyMods: Writeable<IKeyMods> = { ctrlCmd: false, alt: false };
|
||||||
|
|
||||||
@@ -1013,6 +1067,14 @@ export class QuickInputService extends Component implements IQuickInputService {
|
|||||||
this.onDidAcceptEmitter.fire();
|
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 message = dom.append(container, $(`#${this.idPrefix}message.quick-input-message`));
|
||||||
|
|
||||||
const progressBar = new ProgressBar(container);
|
const progressBar = new ProgressBar(container);
|
||||||
@@ -1098,9 +1160,11 @@ export class QuickInputService extends Component implements IQuickInputService {
|
|||||||
visibleCount,
|
visibleCount,
|
||||||
count,
|
count,
|
||||||
message,
|
message,
|
||||||
|
customButton,
|
||||||
progressBar,
|
progressBar,
|
||||||
list,
|
list,
|
||||||
onDidAccept: this.onDidAcceptEmitter.event,
|
onDidAccept: this.onDidAcceptEmitter.event,
|
||||||
|
onDidCustom: this.onDidCustomEmitter.event,
|
||||||
onDidTriggerButton: this.onDidTriggerButtonEmitter.event,
|
onDidTriggerButton: this.onDidTriggerButtonEmitter.event,
|
||||||
ignoreFocusOut: false,
|
ignoreFocusOut: false,
|
||||||
keyMods: this.keyMods,
|
keyMods: this.keyMods,
|
||||||
@@ -1330,6 +1394,7 @@ export class QuickInputService extends Component implements IQuickInputService {
|
|||||||
this.visibleCountContainer.style.display = visibilities.visibleCount ? '' : 'none';
|
this.visibleCountContainer.style.display = visibilities.visibleCount ? '' : 'none';
|
||||||
this.countContainer.style.display = visibilities.count ? '' : 'none';
|
this.countContainer.style.display = visibilities.count ? '' : 'none';
|
||||||
this.okContainer.style.display = visibilities.ok ? '' : '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.message.style.display = visibilities.message ? '' : 'none';
|
||||||
this.ui.list.display(!!visibilities.list);
|
this.ui.list.display(!!visibilities.list);
|
||||||
this.ui.container.classList[visibilities.checkAll ? 'add' : 'remove']('show-checkboxes');
|
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 visibleViewDescriptors = this.viewsModel.visibleViewDescriptors;
|
||||||
|
|
||||||
const toSetVisible = this.viewsModel.viewDescriptors
|
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
|
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;
|
let size: number | undefined;
|
||||||
const oneToOne = toSetVisible.length === 1 && toSetInvisible.length === 1;
|
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);
|
this.viewsModel.setVisible(viewDescriptor.id, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const viewDescriptor of toSetVisible) {
|
for (const viewDescriptor of toSetVisible) {
|
||||||
|
viewDescriptor.repository.setSelected(true);
|
||||||
this.viewsModel.setVisible(viewDescriptor.id, true, size);
|
this.viewsModel.setVisible(viewDescriptor.id, true, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1972,7 +1972,7 @@ class TaskService extends Disposable implements ITaskService {
|
|||||||
return entries;
|
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[]> => {
|
let _createEntries = (): Promise<TaskQuickPickEntry[]> => {
|
||||||
if (Array.isArray(tasks)) {
|
if (Array.isArray(tasks)) {
|
||||||
return Promise.resolve(this.createTaskQuickPickEntries(tasks, group, sort, selectedEntry));
|
return Promise.resolve(this.createTaskQuickPickEntries(tasks, group, sort, selectedEntry));
|
||||||
@@ -1984,6 +1984,9 @@ class TaskService extends Disposable implements ITaskService {
|
|||||||
if ((entries.length === 0) && defaultEntry) {
|
if ((entries.length === 0) && defaultEntry) {
|
||||||
entries.push(defaultEntry);
|
entries.push(defaultEntry);
|
||||||
}
|
}
|
||||||
|
else if (entries.length > 1 && additionalEntries && additionalEntries.length > 0) {
|
||||||
|
entries.push(additionalEntries[0]);
|
||||||
|
}
|
||||||
return entries;
|
return entries;
|
||||||
}), {
|
}), {
|
||||||
placeHolder,
|
placeHolder,
|
||||||
@@ -1997,7 +2000,7 @@ class TaskService extends Disposable implements ITaskService {
|
|||||||
this.openConfig(task);
|
this.openConfig(task);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).then(entry => entry ? entry.task : undefined);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private showIgnoredFoldersMessage(): Promise<void> {
|
private showIgnoredFoldersMessage(): Promise<void> {
|
||||||
@@ -2057,7 +2060,8 @@ class TaskService extends Disposable implements ITaskService {
|
|||||||
task: null
|
task: null
|
||||||
},
|
},
|
||||||
true).
|
true).
|
||||||
then((task) => {
|
then((entry) => {
|
||||||
|
let task: Task | undefined | null = entry ? entry.task : undefined;
|
||||||
if (task === undefined) {
|
if (task === undefined) {
|
||||||
return;
|
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...'),
|
label: nls.localize('TaskService.noBuildTask', 'No build task to run found. Configure Build Task...'),
|
||||||
task: null
|
task: null
|
||||||
},
|
},
|
||||||
true).then((task) => {
|
true).then((entry) => {
|
||||||
|
let task: Task | undefined | null = entry ? entry.task : undefined;
|
||||||
if (task === undefined) {
|
if (task === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -2185,7 +2190,8 @@ class TaskService extends Disposable implements ITaskService {
|
|||||||
label: nls.localize('TaskService.noTestTaskTerminal', 'No test task to run found. Configure Tasks...'),
|
label: nls.localize('TaskService.noTestTaskTerminal', 'No test task to run found. Configure Tasks...'),
|
||||||
task: null
|
task: null
|
||||||
}, true
|
}, true
|
||||||
).then((task) => {
|
).then((entry) => {
|
||||||
|
let task: Task | undefined | null = entry ? entry.task : undefined;
|
||||||
if (task === undefined) {
|
if (task === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -2206,15 +2212,29 @@ class TaskService extends Disposable implements ITaskService {
|
|||||||
if (!this.canRunCommand()) {
|
if (!this.canRunCommand()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (arg === 'terminateAll') {
|
||||||
|
this.terminateAll();
|
||||||
|
return;
|
||||||
|
}
|
||||||
let runQuickPick = (promise?: Promise<Task[]>) => {
|
let runQuickPick = (promise?: Promise<Task[]>) => {
|
||||||
this.showQuickPick(promise || this.getActiveTasks(),
|
this.showQuickPick(promise || this.getActiveTasks(),
|
||||||
nls.localize('TaskService.taskToTerminate', 'Select task to terminate'),
|
nls.localize('TaskService.taskToTerminate', 'Select task to terminate'),
|
||||||
{
|
{
|
||||||
label: nls.localize('TaskService.noTaskRunning', 'No task is currently running'),
|
label: nls.localize('TaskService.noTaskRunning', 'No task is currently running'),
|
||||||
task: null
|
task: undefined
|
||||||
},
|
},
|
||||||
false, true
|
false, true,
|
||||||
).then(task => {
|
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) {
|
if (task === undefined || task === null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -2270,7 +2290,8 @@ class TaskService extends Disposable implements ITaskService {
|
|||||||
task: null
|
task: null
|
||||||
},
|
},
|
||||||
false, true
|
false, true
|
||||||
).then(task => {
|
).then(entry => {
|
||||||
|
let task: Task | undefined | null = entry ? entry.task : undefined;
|
||||||
if (task === undefined || task === null) {
|
if (task === undefined || task === null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -2482,7 +2503,8 @@ class TaskService extends Disposable implements ITaskService {
|
|||||||
this.showIgnoredFoldersMessage().then(() => {
|
this.showIgnoredFoldersMessage().then(() => {
|
||||||
this.showQuickPick(tasks,
|
this.showQuickPick(tasks,
|
||||||
nls.localize('TaskService.pickDefaultBuildTask', 'Select the task to be used as the default build task'), undefined, true, false, selectedEntry).
|
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)) {
|
if ((task === undefined) || (task === null)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -2532,7 +2554,8 @@ class TaskService extends Disposable implements ITaskService {
|
|||||||
|
|
||||||
this.showIgnoredFoldersMessage().then(() => {
|
this.showIgnoredFoldersMessage().then(() => {
|
||||||
this.showQuickPick(tasks,
|
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) {
|
if (!task) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -2565,7 +2588,8 @@ class TaskService extends Disposable implements ITaskService {
|
|||||||
task: null
|
task: null
|
||||||
},
|
},
|
||||||
false, true
|
false, true
|
||||||
).then((task) => {
|
).then((entry) => {
|
||||||
|
let task: Task | undefined | null = entry ? entry.task : undefined;
|
||||||
if (task === undefined || task === null) {
|
if (task === undefined || task === null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -433,12 +433,10 @@ actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ResizePaneRightT
|
|||||||
}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Resize Pane Right', category);
|
}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Resize Pane Right', category);
|
||||||
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ResizePaneUpTerminalAction, ResizePaneUpTerminalAction.ID, ResizePaneUpTerminalAction.LABEL, {
|
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ResizePaneUpTerminalAction, ResizePaneUpTerminalAction.ID, ResizePaneUpTerminalAction.LABEL, {
|
||||||
primary: 0,
|
primary: 0,
|
||||||
linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.UpArrow },
|
|
||||||
mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.UpArrow }
|
mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.UpArrow }
|
||||||
}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Resize Pane Up', category);
|
}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Resize Pane Up', category);
|
||||||
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ResizePaneDownTerminalAction, ResizePaneDownTerminalAction.ID, ResizePaneDownTerminalAction.LABEL, {
|
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ResizePaneDownTerminalAction, ResizePaneDownTerminalAction.ID, ResizePaneDownTerminalAction.LABEL, {
|
||||||
primary: 0,
|
primary: 0,
|
||||||
linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.DownArrow },
|
|
||||||
mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.DownArrow }
|
mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.DownArrow }
|
||||||
}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Resize Pane Down', category);
|
}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Resize Pane Down', category);
|
||||||
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ScrollToPreviousCommandAction, ScrollToPreviousCommandAction.ID, ScrollToPreviousCommandAction.LABEL, {
|
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);
|
const activeWorkspaceRootUri = this._historyService.getLastActiveWorkspaceRoot(hasRemoteAuthority ? REMOTE_HOST_SCHEME : undefined);
|
||||||
this._process = this._instantiationService.createInstance(TerminalProcessExtHostProxy, this._terminalId, shellLaunchConfig, activeWorkspaceRootUri, cols, rows);
|
this._process = this._instantiationService.createInstance(TerminalProcessExtHostProxy, this._terminalId, shellLaunchConfig, activeWorkspaceRootUri, cols, rows);
|
||||||
} else {
|
} else {
|
||||||
if (!shellLaunchConfig.executable) {
|
this._process = this._launchProcess(shellLaunchConfig, cols, rows);
|
||||||
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.processState = ProcessState.LAUNCHING;
|
this.processState = ProcessState.LAUNCHING;
|
||||||
|
|
||||||
@@ -211,6 +171,50 @@ export class TerminalProcessManager implements ITerminalProcessManager {
|
|||||||
}, LAUNCHING_DURATION);
|
}, 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 {
|
public setDimensions(cols: number, rows: number): void {
|
||||||
if (!this._process) {
|
if (!this._process) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten
|
|||||||
import { IFileService } from 'vs/platform/files/common/files';
|
import { IFileService } from 'vs/platform/files/common/files';
|
||||||
import { TerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminalInstance';
|
import { TerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminalInstance';
|
||||||
import { IBrowserTerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminal';
|
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 {
|
export abstract class TerminalService extends CommonTerminalService implements ITerminalService {
|
||||||
protected _configHelper: IBrowserTerminalConfigHelper;
|
protected _configHelper: IBrowserTerminalConfigHelper;
|
||||||
@@ -38,8 +39,9 @@ export abstract class TerminalService extends CommonTerminalService implements I
|
|||||||
@IWorkbenchEnvironmentService private _environmentService: IWorkbenchEnvironmentService,
|
@IWorkbenchEnvironmentService private _environmentService: IWorkbenchEnvironmentService,
|
||||||
@IExtensionService extensionService: IExtensionService,
|
@IExtensionService extensionService: IExtensionService,
|
||||||
@IFileService fileService: IFileService,
|
@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;
|
protected abstract _getDefaultShell(p: platform.Platform): string;
|
||||||
|
|||||||
@@ -267,6 +267,7 @@ export interface ITerminalService {
|
|||||||
*/
|
*/
|
||||||
preparePathForTerminalAsync(path: string, executable: string | undefined, title: string): Promise<string>;
|
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;
|
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 { ITerminalService, ITerminalProcessExtHostProxy, IShellLaunchConfig, ITerminalChildProcess } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
|
||||||
|
|
||||||
export class TerminalProcessExtHostProxy implements ITerminalChildProcess, ITerminalProcessExtHostProxy {
|
export class TerminalProcessExtHostProxy implements ITerminalChildProcess, ITerminalProcessExtHostProxy {
|
||||||
private _disposables: IDisposable[] = [];
|
private _disposables: IDisposable[] = [];
|
||||||
@@ -44,15 +43,10 @@ export class TerminalProcessExtHostProxy implements ITerminalChildProcess, ITerm
|
|||||||
activeWorkspaceRootUri: URI,
|
activeWorkspaceRootUri: URI,
|
||||||
cols: number,
|
cols: number,
|
||||||
rows: number,
|
rows: number,
|
||||||
@ITerminalService private readonly _terminalService: ITerminalService,
|
@ITerminalService private readonly _terminalService: ITerminalService
|
||||||
@IExtensionService private readonly _extensionService: IExtensionService
|
|
||||||
) {
|
) {
|
||||||
this._extensionService.whenInstalledExtensionsRegistered().then(() => {
|
this._terminalService.requestExtHostProcess(this, shellLaunchConfig, activeWorkspaceRootUri, cols, rows);
|
||||||
// TODO: MainThreadTerminalService is not ready at this point, fix this
|
setTimeout(() => this._onProcessTitleChanged.fire('Starting...'), 0);
|
||||||
setTimeout(() => {
|
|
||||||
this._terminalService.requestExtHostProcess(this, shellLaunchConfig, activeWorkspaceRootUri, cols, rows);
|
|
||||||
}, 0);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public dispose(): void {
|
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 { escapeNonWindowsPath } from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
|
||||||
import { isWindows } from 'vs/base/common/platform';
|
import { isWindows } from 'vs/base/common/platform';
|
||||||
import { basename } from 'vs/base/common/path';
|
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 {
|
export abstract class TerminalService implements ITerminalService {
|
||||||
public _serviceBrand: any;
|
public _serviceBrand: any;
|
||||||
@@ -32,7 +34,7 @@ export abstract class TerminalService implements ITerminalService {
|
|||||||
return this._terminalTabs.reduce((p, c) => p.concat(c.terminalInstances), <ITerminalInstance[]>[]);
|
return this._terminalTabs.reduce((p, c) => p.concat(c.terminalInstances), <ITerminalInstance[]>[]);
|
||||||
}
|
}
|
||||||
private _findState: FindReplaceState;
|
private _findState: FindReplaceState;
|
||||||
|
private _extHostsReady: { [authority: string]: boolean } = {};
|
||||||
private _activeTabIndex: number;
|
private _activeTabIndex: number;
|
||||||
|
|
||||||
public get activeTabIndex(): number { return this._activeTabIndex; }
|
public get activeTabIndex(): number { return this._activeTabIndex; }
|
||||||
@@ -65,12 +67,13 @@ export abstract class TerminalService implements ITerminalService {
|
|||||||
constructor(
|
constructor(
|
||||||
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
|
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
|
||||||
@IPanelService protected readonly _panelService: IPanelService,
|
@IPanelService protected readonly _panelService: IPanelService,
|
||||||
@ILifecycleService lifecycleService: ILifecycleService,
|
@ILifecycleService readonly lifecycleService: ILifecycleService,
|
||||||
@IStorageService protected readonly _storageService: IStorageService,
|
@IStorageService protected readonly _storageService: IStorageService,
|
||||||
@INotificationService protected readonly _notificationService: INotificationService,
|
@INotificationService protected readonly _notificationService: INotificationService,
|
||||||
@IDialogService private readonly _dialogService: IDialogService,
|
@IDialogService private readonly _dialogService: IDialogService,
|
||||||
@IExtensionService private readonly _extensionService: IExtensionService,
|
@IExtensionService private readonly _extensionService: IExtensionService,
|
||||||
@IFileService protected readonly _fileService: IFileService
|
@IFileService protected readonly _fileService: IFileService,
|
||||||
|
@IRemoteAgentService readonly _remoteAgentService: IRemoteAgentService
|
||||||
) {
|
) {
|
||||||
this._activeTabIndex = 0;
|
this._activeTabIndex = 0;
|
||||||
this._isShuttingDown = false;
|
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 {
|
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(async () => {
|
||||||
this._extensionService.whenInstalledExtensionsRegistered().then(() => {
|
// Wait for the remoteAuthority to be ready (and listening for events) before proceeding
|
||||||
// TODO: MainThreadTerminalService is not ready at this point, fix this
|
const conn = this._remoteAgentService.getConnection();
|
||||||
setTimeout(() => {
|
const remoteAuthority = conn ? conn.remoteAuthority : 'null';
|
||||||
this._onInstanceRequestExtHostProcess.fire({ proxy, shellLaunchConfig, activeWorkspaceRootUri, cols, rows });
|
let retries = 0;
|
||||||
}, 500);
|
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> {
|
private _onBeforeShutdown(): boolean | Promise<boolean> {
|
||||||
if (this.terminalInstances.length === 0) {
|
if (this.terminalInstances.length === 0) {
|
||||||
// No terminal instances, don't veto
|
// 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 { escapeNonWindowsPath } from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
|
||||||
import { execFile } from 'child_process';
|
import { execFile } from 'child_process';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
|
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||||
|
|
||||||
export class TerminalService extends BrowserTerminalService implements ITerminalService {
|
export class TerminalService extends BrowserTerminalService implements ITerminalService {
|
||||||
public get configHelper(): ITerminalConfigHelper { return this._configHelper; }
|
public get configHelper(): ITerminalConfigHelper { return this._configHelper; }
|
||||||
@@ -45,9 +46,10 @@ export class TerminalService extends BrowserTerminalService implements ITerminal
|
|||||||
@IDialogService dialogService: IDialogService,
|
@IDialogService dialogService: IDialogService,
|
||||||
@IExtensionService extensionService: IExtensionService,
|
@IExtensionService extensionService: IExtensionService,
|
||||||
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService,
|
@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);
|
this._configHelper = this._instantiationService.createInstance(TerminalConfigHelper, linuxDistro);
|
||||||
ipc.on('vscode:openFiles', (_event: any, request: IOpenFileRequest) => {
|
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 { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
|
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.
|
* Set when the find widget in a webview is visible.
|
||||||
@@ -28,11 +29,6 @@ export interface IWebviewService {
|
|||||||
): Webview;
|
): Webview;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WebviewPortMapping {
|
|
||||||
readonly port: number;
|
|
||||||
readonly resolvedPort: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface WebviewOptions {
|
export interface WebviewOptions {
|
||||||
readonly allowSvgs?: boolean;
|
readonly allowSvgs?: boolean;
|
||||||
readonly extension?: {
|
readonly extension?: {
|
||||||
@@ -46,7 +42,7 @@ export interface WebviewContentOptions {
|
|||||||
readonly allowScripts?: boolean;
|
readonly allowScripts?: boolean;
|
||||||
readonly svgWhiteList?: string[];
|
readonly svgWhiteList?: string[];
|
||||||
readonly localResourceRoots?: ReadonlyArray<URI>;
|
readonly localResourceRoots?: ReadonlyArray<URI>;
|
||||||
readonly portMappings?: ReadonlyArray<WebviewPortMapping>;
|
readonly portMappings?: ReadonlyArray<modes.IWebviewPortMapping>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Webview {
|
export interface Webview {
|
||||||
|
|||||||
@@ -11,21 +11,22 @@ import { Disposable } from 'vs/base/common/lifecycle';
|
|||||||
import { isMacintosh } from 'vs/base/common/platform';
|
import { isMacintosh } from 'vs/base/common/platform';
|
||||||
import { endsWith } from 'vs/base/common/strings';
|
import { endsWith } from 'vs/base/common/strings';
|
||||||
import { URI } from 'vs/base/common/uri';
|
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 { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||||
|
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||||
import { IFileService } from 'vs/platform/files/common/files';
|
import { IFileService } from 'vs/platform/files/common/files';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
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 * as colorRegistry from 'vs/platform/theme/common/colorRegistry';
|
||||||
import { DARK, ITheme, IThemeService, LIGHT } from 'vs/platform/theme/common/themeService';
|
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 { 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 { areWebviewInputOptionsEqual } from '../browser/webviewEditorService';
|
||||||
import { WebviewFindWidget } from '../browser/webviewFindWidget';
|
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 {
|
export interface WebviewPortMapping {
|
||||||
readonly port: number;
|
readonly port: number;
|
||||||
@@ -153,7 +154,7 @@ class WebviewPortMappingProvider extends Disposable {
|
|||||||
constructor(
|
constructor(
|
||||||
session: WebviewSession,
|
session: WebviewSession,
|
||||||
extensionLocation: URI | undefined,
|
extensionLocation: URI | undefined,
|
||||||
mappings: () => ReadonlyArray<WebviewPortMapping>,
|
mappings: () => ReadonlyArray<modes.IWebviewPortMapping>,
|
||||||
private readonly tunnelService: ITunnelService,
|
private readonly tunnelService: ITunnelService,
|
||||||
extensionId: ExtensionIdentifier | undefined,
|
extensionId: ExtensionIdentifier | undefined,
|
||||||
@ITelemetryService telemetryService: ITelemetryService
|
@ITelemetryService telemetryService: ITelemetryService
|
||||||
@@ -183,23 +184,23 @@ class WebviewPortMappingProvider extends Disposable {
|
|||||||
|
|
||||||
const port = +localhostMatch[1];
|
const port = +localhostMatch[1];
|
||||||
for (const mapping of mappings()) {
|
for (const mapping of mappings()) {
|
||||||
if (mapping.port === port) {
|
if (mapping.webviewPort === port) {
|
||||||
if (extensionLocation && extensionLocation.scheme === REMOTE_HOST_SCHEME) {
|
if (extensionLocation && extensionLocation.scheme === REMOTE_HOST_SCHEME) {
|
||||||
const tunnel = await this.getOrCreateTunnel(mapping.resolvedPort);
|
const tunnel = await this.getOrCreateTunnel(mapping.extensionHostPort);
|
||||||
if (tunnel) {
|
if (tunnel) {
|
||||||
return {
|
return {
|
||||||
redirectURL: details.url.replace(
|
redirectURL: details.url.replace(
|
||||||
new RegExp(`^${uri.scheme}://localhost:${mapping.port}/`),
|
new RegExp(`^${uri.scheme}://localhost:${mapping.webviewPort}/`),
|
||||||
`${uri.scheme}://localhost:${tunnel.tunnelLocalPort}/`)
|
`${uri.scheme}://localhost:${tunnel.tunnelLocalPort}/`)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mapping.port !== mapping.resolvedPort) {
|
if (mapping.webviewPort !== mapping.extensionHostPort) {
|
||||||
return {
|
return {
|
||||||
redirectURL: details.url.replace(
|
redirectURL: details.url.replace(
|
||||||
new RegExp(`^${uri.scheme}://localhost:${mapping.port}/`),
|
new RegExp(`^${uri.scheme}://localhost:${mapping.webviewPort}/`),
|
||||||
`${uri.scheme}://localhost:${mapping.resolvedPort}/`)
|
`${uri.scheme}://localhost:${mapping.extensionHostPort}/`)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -416,7 +417,7 @@ export class WebviewElement extends Disposable implements Webview {
|
|||||||
this._register(new WebviewPortMappingProvider(
|
this._register(new WebviewPortMappingProvider(
|
||||||
session,
|
session,
|
||||||
_options.extension ? _options.extension.location : undefined,
|
_options.extension ? _options.extension.location : undefined,
|
||||||
() => (this._contentOptions.portMappings || [{ port: 3000, resolvedPort: 4000 }]),
|
() => (this._contentOptions.portMappings || []),
|
||||||
tunnelService,
|
tunnelService,
|
||||||
_options.extension ? _options.extension.id : undefined,
|
_options.extension ? _options.extension.id : undefined,
|
||||||
telemetryService
|
telemetryService
|
||||||
|
|||||||
@@ -72,8 +72,8 @@ export class FileDialogService implements IFileDialogService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ...then fallback to default folder path
|
// ...then fallback to default file path
|
||||||
return this.defaultFolderPath(schemeFilter);
|
return this.defaultFilePath(schemeFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
private toNativeOpenDialogOptions(options: IPickAndOpenOptions): INativeOpenDialogOptions {
|
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 resources from 'vs/base/common/resources';
|
||||||
import * as objects from 'vs/base/common/objects';
|
import * as objects from 'vs/base/common/objects';
|
||||||
import { IFileService, IFileStat, FileKind } from 'vs/platform/files/common/files';
|
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 { URI } from 'vs/base/common/uri';
|
||||||
import { isWindows } from 'vs/base/common/platform';
|
import { isWindows } from 'vs/base/common/platform';
|
||||||
import { ISaveDialogOptions, IOpenDialogOptions, IFileDialogService } from 'vs/platform/dialogs/common/dialogs';
|
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 { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||||
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||||
import { RemoteFileDialogContext } from 'vs/workbench/common/contextkeys';
|
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 {
|
interface FileQuickPickItem extends IQuickPickItem {
|
||||||
uri: URI;
|
uri: URI;
|
||||||
isFolder: boolean;
|
isFolder: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum UpdateResult {
|
||||||
|
Updated,
|
||||||
|
NotUpdated,
|
||||||
|
InvalidPath
|
||||||
|
}
|
||||||
|
|
||||||
// Reference: https://en.wikipedia.org/wiki/Filename
|
// Reference: https://en.wikipedia.org/wiki/Filename
|
||||||
const INVALID_FILE_CHARS = isWindows ? /[\\/:\*\?"<>\|]/g : /[\\/]/g;
|
const INVALID_FILE_CHARS = isWindows ? /[\\/:\*\?"<>\|]/g : /[\\/]/g;
|
||||||
const WINDOWS_FORBIDDEN_NAMES = /^(con|prn|aux|clock\$|nul|lpt[0-9]|com[0-9])$/i;
|
const WINDOWS_FORBIDDEN_NAMES = /^(con|prn|aux|clock\$|nul|lpt[0-9]|com[0-9])$/i;
|
||||||
|
|
||||||
export class RemoteFileDialog {
|
export class RemoteFileDialog {
|
||||||
private acceptButton: IQuickInputButton;
|
|
||||||
private fallbackListItem: FileQuickPickItem | undefined;
|
|
||||||
private options: IOpenDialogOptions;
|
private options: IOpenDialogOptions;
|
||||||
private currentFolder: URI;
|
private currentFolder: URI;
|
||||||
private filePickBox: IQuickPick<FileQuickPickItem>;
|
private filePickBox: IQuickPick<FileQuickPickItem>;
|
||||||
@@ -52,6 +58,7 @@ export class RemoteFileDialog {
|
|||||||
private autoCompletePathSegment: string;
|
private autoCompletePathSegment: string;
|
||||||
private activeItem: FileQuickPickItem;
|
private activeItem: FileQuickPickItem;
|
||||||
private userHome: URI;
|
private userHome: URI;
|
||||||
|
private badPath: string | undefined;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@IFileService private readonly fileService: IFileService,
|
@IFileService private readonly fileService: IFileService,
|
||||||
@@ -64,8 +71,8 @@ export class RemoteFileDialog {
|
|||||||
@IModeService private readonly modeService: IModeService,
|
@IModeService private readonly modeService: IModeService,
|
||||||
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
|
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
|
||||||
@IRemoteAgentService private readonly remoteAgentService: IRemoteAgentService,
|
@IRemoteAgentService private readonly remoteAgentService: IRemoteAgentService,
|
||||||
@IContextKeyService contextKeyService: IContextKeyService
|
@IKeybindingService private readonly keybindingService: IKeybindingService,
|
||||||
|
@IContextKeyService contextKeyService: IContextKeyService,
|
||||||
) {
|
) {
|
||||||
this.remoteAuthority = this.environmentService.configuration.remoteAuthority;
|
this.remoteAuthority = this.environmentService.configuration.remoteAuthority;
|
||||||
this.contextKey = RemoteFileDialogContext.bindTo(contextKeyService);
|
this.contextKey = RemoteFileDialogContext.bindTo(contextKeyService);
|
||||||
@@ -79,13 +86,6 @@ export class RemoteFileDialog {
|
|||||||
return Promise.resolve(undefined);
|
return Promise.resolve(undefined);
|
||||||
}
|
}
|
||||||
this.options = newOptions;
|
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();
|
return this.pickResource();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +100,6 @@ export class RemoteFileDialog {
|
|||||||
this.options = newOptions;
|
this.options = newOptions;
|
||||||
this.options.canSelectFolders = true;
|
this.options.canSelectFolders = true;
|
||||||
this.options.canSelectFiles = true;
|
this.options.canSelectFiles = true;
|
||||||
this.fallbackListItem = this.getFallbackFileSystem(nls.localize('remoteFileDialog.localSaveFallback', '(Save Local File)'));
|
|
||||||
|
|
||||||
return new Promise<URI | undefined>((resolve) => {
|
return new Promise<URI | undefined>((resolve) => {
|
||||||
this.pickResource(true).then(folderUri => {
|
this.pickResource(true).then(folderUri => {
|
||||||
@@ -129,20 +128,13 @@ export class RemoteFileDialog {
|
|||||||
|
|
||||||
private remoteUriFrom(path: string): URI {
|
private remoteUriFrom(path: string): URI {
|
||||||
path = path.replace(/\\/g, '/');
|
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 {
|
private getScheme(defaultUri: URI | undefined, available: string[] | undefined): string {
|
||||||
return defaultUri ? defaultUri.scheme : (available ? available[0] : Schemas.file);
|
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> {
|
private async getUserHome(): Promise<URI> {
|
||||||
if (this.scheme !== Schemas.file) {
|
if (this.scheme !== Schemas.file) {
|
||||||
const env = await this.remoteAgentService.getEnvironment();
|
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) => {
|
return new Promise<URI | undefined>(async (resolve) => {
|
||||||
this.filePickBox = this.quickInputService.createQuickPick<FileQuickPickItem>();
|
this.filePickBox = this.quickInputService.createQuickPick<FileQuickPickItem>();
|
||||||
this.filePickBox.matchOnLabel = false;
|
this.filePickBox.matchOnLabel = false;
|
||||||
this.filePickBox.autoFocusOnList = 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 isResolving = false;
|
||||||
let isAcceptHandled = false;
|
let isAcceptHandled = false;
|
||||||
this.currentFolder = homedir;
|
this.currentFolder = homedir;
|
||||||
this.userEnteredPathSegment = '';
|
this.userEnteredPathSegment = '';
|
||||||
this.autoCompletePathSegment = '';
|
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.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 = [];
|
this.filePickBox.items = [];
|
||||||
|
|
||||||
function doResolve(dialog: RemoteFileDialog, uri: URI | undefined) {
|
function doResolve(dialog: RemoteFileDialog, uri: URI | undefined) {
|
||||||
@@ -217,6 +210,28 @@ export class RemoteFileDialog {
|
|||||||
dialog.filePickBox.dispose();
|
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(_ => {
|
this.filePickBox.onDidAccept(_ => {
|
||||||
if (isAcceptHandled || this.filePickBox.busy) {
|
if (isAcceptHandled || this.filePickBox.busy) {
|
||||||
return;
|
return;
|
||||||
@@ -247,15 +262,16 @@ export class RemoteFileDialog {
|
|||||||
this.filePickBox.onDidChangeValue(async value => {
|
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
|
// 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 (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.filePickBox.validationMessage = undefined;
|
||||||
this.shouldOverwriteFile = false;
|
this.shouldOverwriteFile = false;
|
||||||
const valueUri = this.remoteUriFrom(this.trimTrailingSlash(this.filePickBox.value));
|
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)) {
|
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);
|
this.setActiveItems(value);
|
||||||
}
|
}
|
||||||
} else {
|
} 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 {
|
private isChangeFromUser(): boolean {
|
||||||
if ((this.filePickBox.value === this.pathAppend(this.currentFolder, this.userEnteredPathSegment + this.autoCompletePathSegment))
|
if ((this.filePickBox.value === this.pathAppend(this.currentFolder, this.userEnteredPathSegment + this.autoCompletePathSegment))
|
||||||
&& (this.activeItem === (this.filePickBox.activeItems ? this.filePickBox.activeItems[0] : undefined))) {
|
&& (this.activeItem === (this.filePickBox.activeItems ? this.filePickBox.activeItems[0] : undefined))) {
|
||||||
@@ -294,24 +314,6 @@ export class RemoteFileDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async onDidAccept(): Promise<URI | undefined> {
|
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 resolveValue: URI | undefined;
|
||||||
let navigateValue: 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;
|
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);
|
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] === '~') {
|
if (value[value.length - 1] === '~') {
|
||||||
await this.updateItems(this.userHome);
|
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))) {
|
} 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;
|
let stat: IFileStat | undefined;
|
||||||
try {
|
try {
|
||||||
@@ -373,7 +376,14 @@ export class RemoteFileDialog {
|
|||||||
}
|
}
|
||||||
if (stat && stat.isDirectory && (resources.basename(valueUri) !== '.') && this.endsWithSlash(value)) {
|
if (stat && stat.isDirectory && (resources.basename(valueUri) !== '.') && this.endsWithSlash(value)) {
|
||||||
await this.updateItems(valueUri);
|
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 {
|
} else {
|
||||||
const inputUriDirname = resources.dirname(valueUri);
|
const inputUriDirname = resources.dirname(valueUri);
|
||||||
if (!resources.isEqual(this.remoteUriFrom(this.trimTrailingSlash(this.pathFromUri(this.currentFolder))), inputUriDirname, true)) {
|
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) !== '.')) {
|
if (statWithoutTrailing && statWithoutTrailing.isDirectory && (resources.basename(valueUri) !== '.')) {
|
||||||
await this.updateItems(inputUriDirname, 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) {
|
private setActiveItems(value: string) {
|
||||||
@@ -428,7 +440,7 @@ export class RemoteFileDialog {
|
|||||||
this.autoCompletePathSegment = '';
|
this.autoCompletePathSegment = '';
|
||||||
return false;
|
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.
|
// 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)) {
|
if (!force && (itemBasename.length >= startingBasename.length) && equalsIgnoreCase(itemBasename.substr(0, startingBasename.length), startingBasename)) {
|
||||||
this.userEnteredPathSegment = startingBasename;
|
this.userEnteredPathSegment = startingBasename;
|
||||||
@@ -582,8 +594,11 @@ export class RemoteFileDialog {
|
|||||||
if (this.allowFolderSelection) {
|
if (this.allowFolderSelection) {
|
||||||
this.filePickBox.activeItems = [];
|
this.filePickBox.activeItems = [];
|
||||||
}
|
}
|
||||||
this.filePickBox.valueSelection = [0, this.filePickBox.value.length];
|
if (!equalsIgnoreCase(this.filePickBox.value, newValue)) {
|
||||||
this.insertText(newValue, 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;
|
this.filePickBox.busy = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -687,10 +702,6 @@ export class RemoteFileDialog {
|
|||||||
if (backDir) {
|
if (backDir) {
|
||||||
sorted.unshift(backDir);
|
sorted.unshift(backDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.fallbackListItem) {
|
|
||||||
sorted.push(this.fallbackListItem);
|
|
||||||
}
|
|
||||||
return sorted;
|
return sorted;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -724,11 +735,4 @@ export class RemoteFileDialog {
|
|||||||
return undefined;
|
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 { Registry } from 'vs/platform/registry/common/platform';
|
||||||
import { IMessage } from 'vs/workbench/services/extensions/common/extensions';
|
import { IMessage } from 'vs/workbench/services/extensions/common/extensions';
|
||||||
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/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);
|
const schemaRegistry = Registry.as<IJSONContributionRegistry>(Extensions.JSONContribution);
|
||||||
export type ExtensionKind = 'workspace' | 'ui' | undefined;
|
export type ExtensionKind = 'workspace' | 'ui' | undefined;
|
||||||
|
|
||||||
@@ -370,18 +370,14 @@ export interface IExtensionPointDescriptor {
|
|||||||
|
|
||||||
export class ExtensionsRegistryImpl {
|
export class ExtensionsRegistryImpl {
|
||||||
|
|
||||||
private _extensionPoints: { [extPoint: string]: ExtensionPoint<any>; };
|
private readonly _extensionPoints = new Map<string, ExtensionPoint<any>>();
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this._extensionPoints = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
public registerExtensionPoint<T>(desc: IExtensionPointDescriptor): IExtensionPoint<T> {
|
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);
|
throw new Error('Duplicate extension point: ' + desc.extensionPoint);
|
||||||
}
|
}
|
||||||
let result = new ExtensionPoint<T>(desc.extensionPoint, desc.defaultExtensionKind);
|
const result = new ExtensionPoint<T>(desc.extensionPoint, desc.defaultExtensionKind);
|
||||||
this._extensionPoints[desc.extensionPoint] = result;
|
this._extensionPoints.set(desc.extensionPoint, result);
|
||||||
|
|
||||||
schema.properties['contributes'].properties[desc.extensionPoint] = desc.jsonSchema;
|
schema.properties['contributes'].properties[desc.extensionPoint] = desc.jsonSchema;
|
||||||
schemaRegistry.registerSchema(schemaId, schema);
|
schemaRegistry.registerSchema(schemaId, schema);
|
||||||
@@ -390,11 +386,7 @@ export class ExtensionsRegistryImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getExtensionPoints(): ExtensionPoint<any>[] {
|
public getExtensionPoints(): ExtensionPoint<any>[] {
|
||||||
return Object.keys(this._extensionPoints).map(point => this._extensionPoints[point]);
|
return values(this._extensionPoints);
|
||||||
}
|
|
||||||
|
|
||||||
public getExtensionPointsMap(): { [extPoint: string]: ExtensionPoint<any>; } {
|
|
||||||
return this._extensionPoints;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,9 @@ import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
|
|||||||
import { Dialog } from 'vs/base/browser/ui/dialog/dialog';
|
import { Dialog } from 'vs/base/browser/ui/dialog/dialog';
|
||||||
import { attachDialogStyler } from 'vs/platform/theme/common/styler';
|
import { attachDialogStyler } from 'vs/platform/theme/common/styler';
|
||||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
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 {
|
export class ProgressService2 implements IProgressService2 {
|
||||||
|
|
||||||
@@ -34,7 +37,8 @@ export class ProgressService2 implements IProgressService2 {
|
|||||||
@INotificationService private readonly _notificationService: INotificationService,
|
@INotificationService private readonly _notificationService: INotificationService,
|
||||||
@IStatusbarService private readonly _statusbarService: IStatusbarService,
|
@IStatusbarService private readonly _statusbarService: IStatusbarService,
|
||||||
@ILayoutService private readonly _layoutService: ILayoutService,
|
@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> {
|
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 {
|
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 disposables: IDisposable[] = [];
|
||||||
|
const allowableCommands = [
|
||||||
|
'workbench.action.quit',
|
||||||
|
'workbench.action.reloadWindow'
|
||||||
|
];
|
||||||
|
|
||||||
let dialog: Dialog;
|
let dialog: Dialog;
|
||||||
|
|
||||||
@@ -284,7 +292,17 @@ export class ProgressService2 implements IProgressService2 {
|
|||||||
this._layoutService.container,
|
this._layoutService.container,
|
||||||
message,
|
message,
|
||||||
[options.cancellable ? localize('cancel', "Cancel") : localize('dismiss', "Dismiss")],
|
[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);
|
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 { IChannel, IServerChannel, getDelayedChannel } from 'vs/base/parts/ipc/common/ipc';
|
||||||
import { Client } from 'vs/base/parts/ipc/common/ipc.net';
|
import { Client } from 'vs/base/parts/ipc/common/ipc.net';
|
||||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
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 { IRemoteAgentConnection, IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||||
import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||||
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
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>());
|
private readonly _onReconnecting = this._register(new Emitter<void>());
|
||||||
public readonly onReconnecting = this._onReconnecting.event;
|
public readonly onReconnecting = this._onReconnecting.event;
|
||||||
|
|
||||||
|
private readonly _onDidStateChange = this._register(new Emitter<PersistenConnectionEvent>());
|
||||||
|
public readonly onDidStateChange = this._onDidStateChange.event;
|
||||||
|
|
||||||
readonly remoteAuthority: string;
|
readonly remoteAuthority: string;
|
||||||
private _connection: Promise<Client<RemoteAgentConnectionContext>> | null;
|
private _connection: Promise<Client<RemoteAgentConnectionContext>> | null;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
remoteAuthority: string,
|
remoteAuthority: string,
|
||||||
private _commit: string | undefined,
|
private readonly _commit: string | undefined,
|
||||||
private _webSocketFactory: IWebSocketFactory,
|
private readonly _webSocketFactory: IWebSocketFactory,
|
||||||
private _environmentService: IEnvironmentService,
|
private readonly _environmentService: IEnvironmentService,
|
||||||
private _remoteAuthorityResolverService: IRemoteAuthorityResolverService
|
private readonly _remoteAuthorityResolverService: IRemoteAuthorityResolverService
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this.remoteAuthority = remoteAuthority;
|
this.remoteAuthority = remoteAuthority;
|
||||||
@@ -121,8 +124,8 @@ export class RemoteAgentConnection extends Disposable implements IRemoteAgentCon
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const connection = await connectRemoteAgentManagement(options, this.remoteAuthority, `renderer`);
|
const connection = this._register(await connectRemoteAgentManagement(options, this.remoteAuthority, `renderer`));
|
||||||
this._register(connection);
|
this._register(connection.onDidStateChange(e => this._onDidStateChange.fire(e)));
|
||||||
return connection.client;
|
return connection.client;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { RemoteAgentConnectionContext, IRemoteAgentEnvironment } from 'vs/platfo
|
|||||||
import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc';
|
import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc';
|
||||||
import { IDiagnosticInfoOptions, IDiagnosticInfo } from 'vs/platform/diagnostics/common/diagnosticsService';
|
import { IDiagnosticInfoOptions, IDiagnosticInfo } from 'vs/platform/diagnostics/common/diagnosticsService';
|
||||||
import { Event } from 'vs/base/common/event';
|
import { Event } from 'vs/base/common/event';
|
||||||
|
import { PersistenConnectionEvent } from 'vs/platform/remote/common/remoteAgentConnection';
|
||||||
|
|
||||||
export const RemoteExtensionLogFileName = 'remoteagent';
|
export const RemoteExtensionLogFileName = 'remoteagent';
|
||||||
|
|
||||||
@@ -25,7 +26,9 @@ export interface IRemoteAgentService {
|
|||||||
export interface IRemoteAgentConnection {
|
export interface IRemoteAgentConnection {
|
||||||
readonly remoteAuthority: string;
|
readonly remoteAuthority: string;
|
||||||
|
|
||||||
|
readonly onReconnecting: Event<void>;
|
||||||
|
readonly onDidStateChange: Event<PersistenConnectionEvent>;
|
||||||
|
|
||||||
getChannel<T extends IChannel>(channelName: string): T;
|
getChannel<T extends IChannel>(channelName: string): T;
|
||||||
registerChannel<T extends IServerChannel<RemoteAgentConnectionContext>>(channelName: string, channel: T): void;
|
registerChannel<T extends IServerChannel<RemoteAgentConnectionContext>>(channelName: string, channel: T): void;
|
||||||
onReconnecting: Event<void>;
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user