提交 3769ce2d 编写于 作者: P Peng Lyu

Merge remote-tracking branch 'upstream/master' into rebornix/keyboardlayouts

......@@ -105,7 +105,7 @@
{
type: 'comment',
name: 'a11ymas',
allowUsers: ['AccessibilityTestingTeam-TCS'],
allowUsers: ['AccessibilityTestingTeam-TCS', 'dixitsonali95', 'Mohini78', 'ChitrarupaSharma', 'mspatil110', 'umasarath52', 'v-umnaik'],
action: 'updateLabels',
addLabel: 'a11ymas'
},
......
......@@ -19,6 +19,8 @@ const untar = require('gulp-untar');
const File = require('vinyl');
const fs = require('fs');
const cp = require('child_process');
const REPO_ROOT = path.dirname(__dirname);
const noop = () => { return Promise.resolve(); };
......@@ -115,3 +117,33 @@ function nodejs(platform, arch) {
}))
);
}
function mixinServer(watch) {
const packageJSONPath = path.join(path.dirname(__dirname), 'package.json');
function exec(cmdLine) {
console.log(cmdLine);
cp.execSync(cmdLine, { stdio: "inherit" });
}
function checkout() {
const packageJSON = JSON.parse(fs.readFileSync(packageJSONPath).toString());
exec('git fetch distro');
exec(`git checkout ${packageJSON['distro']} -- src/vs/server resources/server`);
exec('git reset HEAD src/vs/server resources/server');
}
checkout();
if (watch) {
console.log('Enter watch mode (observing package.json)');
const watcher = fs.watch(packageJSONPath);
watcher.addListener('change', () => {
try {
checkout();
} catch (e) {
console.log(e);
}
});
}
return Promise.resolve();
}
gulp.task(task.define('mixin-server', () => mixinServer(false)));
gulp.task(task.define('mixin-server-watch', () => mixinServer(true)));
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
const cp = require('child_process');
function exec(cmdLine) {
console.log(cmdLine);
cp.execSync(cmdLine, {stdio: "inherit"});
}
exec('git fetch distro');
exec(`git checkout ${process.env['npm_package_distro']} -- src/vs/server resources/server`);
exec('git reset HEAD src/vs/server resources/server');
\ No newline at end of file
......@@ -14,7 +14,7 @@
"id": "shellscript",
"aliases": ["Shell Script", "shellscript", "bash", "sh", "zsh", "ksh"],
"extensions": [".sh", ".bash", ".bashrc", ".bash_aliases", ".bash_profile", ".bash_login", ".ebuild", ".install", ".profile", ".bash_logout", ".zsh", ".zshrc", ".zprofile", ".zlogin", ".zlogout", ".zshenv", ".zsh-theme", ".ksh"],
"filenames": ["PKGBUILD"],
"filenames": ["APKBUILD", "PKGBUILD"],
"firstLine": "^#!.*\\b(bash|zsh|sh|tcsh|ksh|ash|qsh).*|^#\\s*-\\*-[^*]*mode:\\s*shell-script[^*]*-\\*-",
"configuration": "./language-configuration.json",
"mimetypes": ["text/x-shellscript"]
......
......@@ -37,10 +37,18 @@ export default class TypeScriptDefinitionProvider extends DefinitionProviderBase
return response.body.definitions
.map((location): vscode.DefinitionLink => {
const target = typeConverters.Location.fromTextSpan(this.client.toResource(location.file), location);
if ((location as any).contextStart) {
return {
originSelectionRange: span,
targetRange: typeConverters.Range.fromLocations((location as any).contextStart, (location as any).contextEnd),
targetUri: target.uri,
targetSelectionRange: target.range,
};
}
return {
originSelectionRange: span,
targetRange: target.range,
targetUri: target.uri,
targetUri: target.uri
};
});
}
......
......@@ -13,9 +13,12 @@ import { ITypeScriptServiceClient } from '../typescriptService';
export namespace Range {
export const fromTextSpan = (span: Proto.TextSpan): vscode.Range =>
fromLocations(span.start, span.end);
export const fromLocations = (start: Proto.Location, end: Proto.Location): vscode.Range =>
new vscode.Range(
Math.max(0, span.start.line - 1), Math.max(span.start.offset - 1, 0),
Math.max(0, span.end.line - 1), Math.max(0, span.end.offset - 1));
Math.max(0, start.line - 1), Math.max(start.offset - 1, 0),
Math.max(0, end.line - 1), Math.max(0, end.offset - 1));
export const toFileRangeRequestArgs = (file: string, range: vscode.Range): Proto.FileRangeRequestArgs => ({
file,
......
......@@ -513,28 +513,28 @@ suite('workspace-namespace', () => {
});
});
test('findFiles', () => {
(process.platform === 'win32' ? test.skip /* https://github.com/microsoft/vscode/issues/74898 */ : test)('findFiles', () => {
return vscode.workspace.findFiles('**/*.png').then((res) => {
assert.equal(res.length, 2);
assert.equal(basename(vscode.workspace.asRelativePath(res[0])), 'image.png');
});
});
test('findFiles - exclude', () => {
(process.platform === 'win32' ? test.skip /* https://github.com/microsoft/vscode/issues/74898 */ : test)('findFiles - exclude', () => {
return vscode.workspace.findFiles('**/*.png').then((res) => {
assert.equal(res.length, 2);
assert.equal(basename(vscode.workspace.asRelativePath(res[0])), 'image.png');
});
});
test('findFiles, exclude', () => {
(process.platform === 'win32' ? test.skip /* https://github.com/microsoft/vscode/issues/74898 */ : test)('findFiles, exclude', () => {
return vscode.workspace.findFiles('**/*.png', '**/sub/**').then((res) => {
assert.equal(res.length, 1);
assert.equal(basename(vscode.workspace.asRelativePath(res[0])), 'image.png');
});
});
test('findFiles, cancellation', () => {
(process.platform === 'win32' ? test.skip /* https://github.com/microsoft/vscode/issues/74898 */ : test)('findFiles, cancellation', () => {
const source = new vscode.CancellationTokenSource();
const token = source.token; // just to get an instance first
......@@ -545,7 +545,7 @@ suite('workspace-namespace', () => {
});
});
test('findTextInFiles', async () => {
(process.platform === 'win32' ? test.skip /* https://github.com/microsoft/vscode/issues/74898 */ : test)('findTextInFiles', async () => {
const options: vscode.FindTextInFilesOptions = {
include: '*.ts',
previewOptions: {
......@@ -565,7 +565,7 @@ suite('workspace-namespace', () => {
assert.equal(vscode.workspace.asRelativePath(match.uri), '10linefile.ts');
});
test('findTextInFiles, cancellation', async () => {
(process.platform === 'win32' ? suite.skip /* https://github.com/microsoft/vscode/issues/74898 */ : suite)('findTextInFiles, cancellation', async () => {
const results: vscode.TextSearchResult[] = [];
const cancellation = new vscode.CancellationTokenSource();
cancellation.cancel();
......
{
"name": "code-oss-dev",
"version": "1.36.0",
"distro": "c1ec2234fb5dc62f2bf9689f41dc1cd0a507a581",
"distro": "26125d2b5b10bac3b3de09f4ee565ea4d5c1c7bc",
"author": {
"name": "Microsoft Corporation"
},
......@@ -24,10 +24,7 @@
"smoketest": "cd test/smoke && node test/index.js",
"download-builtin-extensions": "node build/lib/builtInExtensions.js",
"monaco-compile-check": "tsc -p src/tsconfig.monaco.json --noEmit",
"strict-initialization-watch": "tsc --watch -p src/tsconfig.json --noEmit --strictPropertyInitialization",
"web": "node resources/server/bin-dev/code-web.js --port 9888",
"web-selfhost": "node resources/server/bin-dev/code-web.js --port 9777 --selfhost",
"install-server": "node build/npm/install-server.js"
"strict-initialization-watch": "tsc --watch -p src/tsconfig.json --noEmit --strictPropertyInitialization"
},
"dependencies": {
"applicationinsights": "1.0.8",
......
......@@ -11,8 +11,18 @@ VSCODE_PATH="$(dirname "$(dirname "$(realpath "$0")")")"
ELECTRON="$VSCODE_PATH/$NAME.exe"
if grep -qi Microsoft /proc/version; then
# in a wsl shell
WSL_BUILD=$(uname -r | sed -E 's/^.+-([0-9]+)-[Mm]icrosoft/\1/')
if [ $WSL_BUILD -ge 17063 ] 2> /dev/null; then
if ! [ -z "$WSL_DISTRO_NAME"]; then
# $WSL_DISTRO_NAME is available since WSL builds 18362, also for WSL2
WSL_BUILD=18362
else
WSL_BUILD=$(uname -r | sed -E 's/^.+-([0-9]+)-Microsoft/\1/')
if ! [ -z "$WSL_BUILD" ]; then
WSL_BUILD=0
fi
fi
if [ $WSL_BUILD -ge 17063 ]; then
# $WSL_DISTRO_NAME is available since WSL builds 18362, also for WSL2
# WSLPATH is available since WSL build 17046
# WSLENV is available since WSL build 17063
export WSLENV=ELECTRON_RUN_AS_NODE/w:$WSLENV
......
......@@ -21,9 +21,9 @@ cd $ROOT
./scripts/code.sh $ROOT/extensions/vscode-colorize-tests/test --extensionDevelopmentPath=$ROOT/extensions/vscode-colorize-tests --extensionTestsPath=$ROOT/extensions/vscode-colorize-tests/out --disable-extensions --user-data-dir=$VSCODEUSERDATADIR --skip-getting-started
./scripts/code.sh $ROOT/extensions/markdown-language-features/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/markdown-language-features --extensionTestsPath=$ROOT/extensions/markdown-language-features/out/test --disable-extensions --user-data-dir=$VSCODEUSERDATADIR --skip-getting-started
mkdir -p $ROOT/extensions/emmet/test-fixtures
./scripts/code.sh $ROOT/extensions/emmet/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/emmet --extensionTestsPath=$ROOT/extensions/emmet/out/test --disable-extensions --user-data-dir=$VSCODEUSERDATADIR --skip-getting-started
rm -rf $ROOT/extensions/emmet/test-fixtures
# mkdir -p $ROOT/extensions/emmet/test-fixtures
# ./scripts/code.sh $ROOT/extensions/emmet/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/emmet --extensionTestsPath=$ROOT/extensions/emmet/out/test --disable-extensions --user-data-dir=$VSCODEUSERDATADIR --skip-getting-started
# rm -rf $ROOT/extensions/emmet/test-fixtures
if [ -f ./resources/server/test/test-remote-integration.sh ]; then
./resources/server/test/test-remote-integration.sh
......
......@@ -804,8 +804,7 @@ export function createCSSRule(selector: string, cssText: string, style: HTMLStyl
if (!style || !cssText) {
return;
}
(<CSSStyleSheet>style.sheet).insertRule(selector + '{' + cssText + '}', 0);
style.textContent = `${selector}{${cssText}}\n${style.textContent}`;
}
export function removeCSSRulesContainingSelector(ruleName: string, style: HTMLStyleElement = getSharedStyleSheet()): void {
......
......@@ -18,6 +18,7 @@ import { KeyCode, ResolvedKeybinding } from 'vs/base/common/keyCodes';
import { Disposable, dispose, IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { withNullAsUndefined } from 'vs/base/common/types';
import { asArray } from 'vs/base/common/arrays';
import { ScanCodeUtils, ScanCode } from 'vs/base/common/scanCode';
const $ = DOM.$;
......@@ -777,6 +778,13 @@ export class MenuBar extends Disposable {
return;
}
// Prevent alt-key default if the menu is not hidden and we use alt to focus
if (modifierKeyStatus.event && !this.options.disableAltFocus) {
if (ScanCodeUtils.toEnum(modifierKeyStatus.event.code) === ScanCode.AltLeft) {
modifierKeyStatus.event.preventDefault();
}
}
// Alt key pressed while menu is focused. This should return focus away from the menubar
if (this.isFocused && modifierKeyStatus.lastKeyPressed === 'alt' && modifierKeyStatus.altKey) {
this.setUnfocusedState();
......@@ -892,6 +900,7 @@ interface IModifierKeyStatus {
ctrlKey: boolean;
lastKeyPressed?: ModifierKey;
lastKeyReleased?: ModifierKey;
event?: KeyboardEvent;
}
......@@ -930,6 +939,7 @@ class ModifierKeyEmitter extends Emitter<IModifierKeyStatus> {
this._keyStatus.shiftKey = e.shiftKey;
if (this._keyStatus.lastKeyPressed) {
this._keyStatus.event = e;
this.fire(this._keyStatus);
}
}));
......@@ -954,6 +964,7 @@ class ModifierKeyEmitter extends Emitter<IModifierKeyStatus> {
this._keyStatus.shiftKey = e.shiftKey;
if (this._keyStatus.lastKeyReleased) {
this._keyStatus.event = e;
this.fire(this._keyStatus);
}
}));
......
......@@ -381,12 +381,14 @@ class TreeRenderer<T, TFilterData, TTemplateData> implements IListRenderer<ITree
const disposableStore = new DisposableStore();
const width = this.indent * target.depth;
const virtualWidth = width * window.devicePixelRatio;
const virtualHeight = height * window.devicePixelRatio;
const svg = $.SVG('svg', {
'shape-rendering': 'crispEdges',
preserveAspectRatio: 'none',
width: `${width}`,
height: `${height}`,
viewBox: `0 0 ${width} ${height}`
viewBox: `0 0 ${virtualWidth} ${virtualHeight}`
});
let node = target;
......@@ -394,8 +396,8 @@ class TreeRenderer<T, TFilterData, TTemplateData> implements IListRenderer<ITree
while (node.parent && node.parent.parent) {
const parent = node.parent;
const x = Math.floor((target.depth - i - 1) * this.indent) + 2;
const line = $.SVG<SVGLineElement>('line', { x1: x, y1: 0, x2: x, y2: height });
const x = Math.floor((target.depth - i - 1) * this.indent * window.devicePixelRatio) + 2.5;
const line = $.SVG<SVGLineElement>('line', { x1: x, y1: 0, x2: x, y2: virtualHeight });
if (this.activeParentNodes.has(parent)) {
addClass(line, 'active');
......
......@@ -14,10 +14,19 @@
height: 100%;
position: absolute;
top: 0;
left: 16px;
left: 14px;
pointer-events: none;
}
.hide-arrows .monaco-tl-indent {
left: 10px;
}
/* TODO @misolori remove before shipping stable */
body:not([data-exploration="icon-exploration"]) .monaco-tl-indent {
left: 16px;
}
.monaco-tl-indent > svg {
overflow: visible;
}
......
......@@ -6,25 +6,25 @@
<!-- Disable pinch zooming -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<meta http-equiv="Content-Security-Policy"
content="default-src 'none'; img-src 'self' https: data: blob: vscode-remote:; media-src 'none'; child-src 'self' {{WEBVIEW_ENDPOINT}}; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; connect-src 'self' ws: wss: https:; font-src 'self' blob: vscode-remote:;">
<meta id="vscode-workbench-web-configuration" data-settings="{{WORKBENCH_WEB_CONGIGURATION}}">
<!-- Workaround to pass remote user data uri-->
<meta id="vscode-remote-user-data-uri" data-settings="{{REMOTE_USER_DATA_URI}}">
<!-- Workaround to pass remote connection token-->
<meta id="vscode-remote-connection-token" data-settings="{{CONNECTION_AUTH_TOKEN}}">
</head>
<body class="vs-dark" aria-label="">
</body>
<!-- Require our AMD loader -->
<script src="./out/vs/loader.js"></script>
<!-- Window Configuration from Server -->
<script>
self.WORKBENCH_WEB_CONFIGURATION = {
connectionAuthToken: '{{CONNECTION_AUTH_TOKEN}}',
folderUri: '{{FOLDER}}',
workspaceUri: '{{WORKSPACE}}',
userDataUri: '{{USER_DATA}}',
remoteAuthority: '{{AUTHORITY}}',
webviewEndpoint: '{{WEBVIEW_ENDPOINT}}'
}
</script>
<!-- Startup via workbench.js -->
<script src="./out/vs/code/browser/workbench/workbench.js"></script>
</html>
\ No newline at end of file
......@@ -3,12 +3,10 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
//@ts-check
'use strict';
(function () {
// @ts-ignore
require.config({
baseUrl: `${window.location.origin}/out`,
paths: {
......@@ -20,9 +18,9 @@
}
});
// @ts-ignore
require(['vs/workbench/workbench.web.api'], function (api) {
// @ts-ignore
api.create(document.body, self.WORKBENCH_WEB_CONFIGURATION);
const options = JSON.parse(document.getElementById('vscode-workbench-web-configuration').getAttribute('data-settings'));
api.create(document.body, options);
});
})();
\ No newline at end of file
......@@ -55,7 +55,7 @@ export class OpenerService implements IOpenerService {
if (equalsIgnoreCase(scheme, Schemas.http) || equalsIgnoreCase(scheme, Schemas.https) || equalsIgnoreCase(scheme, Schemas.mailto)) {
// open http or default mail application
dom.windowOpenNoOpener(encodeURI(resource.toString(true)));
dom.windowOpenNoOpener(resource.toString());
return Promise.resolve(true);
} else if (equalsIgnoreCase(scheme, Schemas.command)) {
......
......@@ -225,11 +225,11 @@ export class OutlineItemComparator implements ITreeSorter<OutlineItem> {
} else if (a instanceof OutlineElement && b instanceof OutlineElement) {
if (this.type === OutlineSortOrder.ByKind) {
return a.symbol.kind - b.symbol.kind || a.symbol.name.localeCompare(b.symbol.name);
return a.symbol.kind - b.symbol.kind || a.symbol.name.localeCompare(b.symbol.name, undefined, { numeric: true });
} else if (this.type === OutlineSortOrder.ByName) {
return a.symbol.name.localeCompare(b.symbol.name) || Range.compareRangesUsingStarts(a.symbol.range, b.symbol.range);
return a.symbol.name.localeCompare(b.symbol.name, undefined, { numeric: true }) || Range.compareRangesUsingStarts(a.symbol.range, b.symbol.range);
} else if (this.type === OutlineSortOrder.ByPosition) {
return Range.compareRangesUsingStarts(a.symbol.range, b.symbol.range) || a.symbol.name.localeCompare(b.symbol.name);
return Range.compareRangesUsingStarts(a.symbol.range, b.symbol.range) || a.symbol.name.localeCompare(b.symbol.name, undefined, { numeric: true });
}
}
return 0;
......
......@@ -10,7 +10,7 @@ import { CancellationToken } from 'vs/base/common/cancellation';
import { onUnexpectedError } from 'vs/base/common/errors';
import { MarkdownString } from 'vs/base/common/htmlContent';
import { IModeService } from 'vs/editor/common/services/modeService';
import { Range } from 'vs/editor/common/core/range';
import { Range, IRange } from 'vs/editor/common/core/range';
import * as editorCommon from 'vs/editor/common/editorCommon';
import { DefinitionProviderRegistry, LocationLink } from 'vs/editor/common/modes';
import { ICodeEditor, IMouseTarget, MouseTargetType } from 'vs/editor/browser/editorBrowser';
......@@ -150,7 +150,7 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC
return;
}
const previewValue = this.getPreviewValue(textEditorModel, startLineNumber);
const previewValue = this.getPreviewValue(textEditorModel, startLineNumber, result);
let wordRange: Range;
if (result.originSelectionRange) {
......@@ -170,8 +170,8 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC
}).then(undefined, onUnexpectedError);
}
private getPreviewValue(textEditorModel: ITextModel, startLineNumber: number) {
let rangeToUse = this.getPreviewRangeBasedOnBrackets(textEditorModel, startLineNumber);
private getPreviewValue(textEditorModel: ITextModel, startLineNumber: number, result: LocationLink) {
let rangeToUse = result.targetSelectionRange ? result.range : this.getPreviewRangeBasedOnBrackets(textEditorModel, startLineNumber);
const numberOfLinesInRange = rangeToUse.endLineNumber - rangeToUse.startLineNumber;
if (numberOfLinesInRange >= GotoDefinitionWithMouseEditorContribution.MAX_SOURCE_PREVIEW_LINES) {
rangeToUse = this.getPreviewRangeBasedOnIndentation(textEditorModel, startLineNumber);
......@@ -181,7 +181,7 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC
return previewValue;
}
private stripIndentationFromPreviewRange(textEditorModel: ITextModel, startLineNumber: number, previewRange: Range) {
private stripIndentationFromPreviewRange(textEditorModel: ITextModel, startLineNumber: number, previewRange: IRange) {
const startIndent = textEditorModel.getLineFirstNonWhitespaceColumn(startLineNumber);
let minIndent = startIndent;
......
......@@ -25,7 +25,7 @@ import { basename } from 'vs/base/common/resources';
import { IAction } from 'vs/base/common/actions';
import { IActionBarOptions, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar';
import { peekViewTitleForeground, peekViewTitleInfoForeground } from 'vs/editor/contrib/referenceSearch/referencesWidget';
import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
import * as aria from 'vs/base/browser/ui/aria/aria';
import { SeverityIcon } from 'vs/platform/severityIcon/common/severityIcon';
class MessageWidget {
......@@ -287,9 +287,7 @@ export class MarkerNavigationWidget extends PeekViewWidget {
this.editor.revealPositionInCenter(position, ScrollType.Smooth);
if (this.editor.getConfiguration().accessibilitySupport !== AccessibilitySupport.Disabled) {
this.focus();
}
aria.alert(marker.message);
}
updateMarker(marker: IMarker): void {
......
......@@ -9,7 +9,6 @@ import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
import { ILogService } from 'vs/platform/log/common/log';
import Severity from 'vs/base/common/severity';
import { Dialog } from 'vs/base/browser/ui/dialog/dialog';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { attachDialogStyler } from 'vs/platform/theme/common/styler';
import { DisposableStore } from 'vs/base/common/lifecycle';
......@@ -93,5 +92,3 @@ export class DialogService implements IDialogService {
return choice;
}
}
registerSingleton(IDialogService, DialogService, true);
......@@ -69,6 +69,7 @@ export interface ParsedArgs {
'driver-verbose'?: boolean;
remote?: string;
'disable-user-env-probe'?: boolean;
'enable-remote-auto-shutdown'?: boolean;
}
export const IEnvironmentService = createDecorator<IEnvironmentService>('environmentService');
......
......@@ -104,6 +104,9 @@ export class EnvironmentService implements IEnvironmentService {
return parseUserDataDir(this._args, process);
}
@memoize
get webUserDataHome(): URI { return URI.file(parsePathArg(this._args['web-user-data-dir'], process) || this.userDataPath); }
get appNameLong(): string { return product.nameLong; }
get appQuality(): string | undefined { return product.quality; }
......
......@@ -11,6 +11,6 @@ export class SignService implements ISignService {
_serviceBrand: ServiceIdentifier<ISignService>;
async sign(value: string): Promise<string> {
return Promise.resolve((<any>self).WORKBENCH_WEB_CONFIGURATION.connectionAuthToken);
return Promise.resolve(document.getElementById('vscode-remote-connection-token')!.getAttribute('data-settings')!);
}
}
\ No newline at end of file
......@@ -36,6 +36,7 @@ class EditorWebviewZone implements IViewZone {
readonly webview: Webview,
) {
this.domNode = document.createElement('div');
this.domNode.style.zIndex = '10'; // without this, the webview is not interactive
this.afterLineNumber = range.startLineNumber;
this.afterColumn = range.startColumn;
this.heightInLines = range.endLineNumber - range.startLineNumber;
......@@ -92,7 +93,8 @@ export class MainThreadEditorInsets implements MainThreadEditorInsetsShape {
allowSvgs: false,
extension: { id: extensionId, location: URI.revive(extensionLocation) }
}, {
allowScripts: options.enableScripts
allowScripts: options.enableScripts,
localResourceRoots: options.localResourceRoots ? options.localResourceRoots.map(uri => URI.revive(uri)) : undefined
});
const webviewZone = new EditorWebviewZone(editor, range, webview);
......
......@@ -59,7 +59,7 @@ export class MainThreadWindow implements MainThreadWindowShape {
}
}
return this.windowsService.openExternal(encodeURI(uri.toString(true)));
return this.windowsService.openExternal(uri.toString());
}
private getLocalhostPort(uri: URI): number | undefined {
......
......@@ -18,6 +18,7 @@ import { CustomCodeAction } from 'vs/workbench/api/common/extHostLanguageFeature
import { ICommandsExecutor, OpenFolderAPICommand, DiffAPICommand, OpenAPICommand, RemoveFromRecentlyOpenedAPICommand, SetEditorLayoutAPICommand, OpenIssueReporter } from './apiCommands';
import { EditorGroupLayout } from 'vs/workbench/services/editor/common/editorGroupsService';
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
import { IRange } from 'vs/editor/common/core/range';
export class ExtHostApiCommands {
......@@ -414,15 +415,21 @@ export class ExtHostApiCommands {
});
}
private _executeSelectionRangeProvider(resource: URI, positions: types.Position[]): Promise<vscode.SelectionRange[][]> {
private _executeSelectionRangeProvider(resource: URI, positions: types.Position[]): Promise<vscode.SelectionRange[]> {
const pos = positions.map(typeConverters.Position.from);
const args = {
resource,
position: pos[0],
positions: pos
};
return this._commands.executeCommand<modes.SelectionRange[][]>('_executeSelectionRangeProvider', args).then(result => {
return result.map(oneResult => oneResult.map(typeConverters.SelectionRange.to));
return this._commands.executeCommand<IRange[][]>('_executeSelectionRangeProvider', args).then(result => {
return result.map(ranges => {
let node: types.SelectionRange | undefined;
for (const range of ranges.reverse()) {
node = new types.SelectionRange(typeConverters.Range.to(range), node);
}
return node!;
});
});
}
......
......@@ -210,7 +210,7 @@ export class CommandsConverter {
this._commands.registerCommand(true, this._delegatingCommandId, this._executeConvertedCommand, this);
}
toInternal2(command: vscode.Command | undefined, disposables: DisposableStore): CommandDto | undefined {
toInternal(command: vscode.Command | undefined, disposables: DisposableStore): CommandDto | undefined {
if (!command) {
return undefined;
......@@ -240,40 +240,6 @@ export class CommandsConverter {
return result;
}
toInternal(command: vscode.Command): CommandDto;
toInternal(command: undefined): undefined;
toInternal(command: vscode.Command | undefined): CommandDto | undefined;
toInternal(command: vscode.Command | undefined): CommandDto | undefined {
if (!command) {
return undefined;
}
const result: CommandDto = {
$ident: undefined,
id: command.command,
title: command.title,
};
if (command.command && isNonEmptyArray(command.arguments)) {
// we have a contributed command with arguments. that
// means we don't want to send the arguments around
const id = ++this._cachIdPool;
this._cache.set(id, command);
result.$ident = id;
result.id = this._delegatingCommandId;
result.arguments = [id];
}
if (command.tooltip) {
result.tooltip = command.tooltip;
}
return result;
}
fromInternal(command: modes.Command): vscode.Command | undefined {
const id = ObjectIdentifier.of(command);
......
......@@ -650,9 +650,9 @@ export class ExtHostCommentThread implements vscode.CommentThread {
const label = this.label;
const contextValue = this.contextValue;
const comments = this._comments.map(cmt => { return convertToModeComment2(this, this._commentController, cmt, this._commandsConverter, this._commentsMap, this._acceptInputDisposables.value!); });
const acceptInputCommand = this._acceptInputCommand ? this._commandsConverter.toInternal2(this._acceptInputCommand, this._acceptInputDisposables.value) : undefined;
const additionalCommands = (this._additionalCommands ? this._additionalCommands.map(x => this._commandsConverter.toInternal2(x, this._acceptInputDisposables.value!)) : []) as CommandDto[];
const deleteCommand = this._deleteCommand ? this._commandsConverter.toInternal2(this._deleteCommand, this._acceptInputDisposables.value) : undefined;
const acceptInputCommand = this._acceptInputCommand ? this._commandsConverter.toInternal(this._acceptInputCommand, this._acceptInputDisposables.value) : undefined;
const additionalCommands = (this._additionalCommands ? this._additionalCommands.map(x => this._commandsConverter.toInternal(x, this._acceptInputDisposables.value!)) : []) as CommandDto[];
const deleteCommand = this._deleteCommand ? this._commandsConverter.toInternal(this._deleteCommand, this._acceptInputDisposables.value) : undefined;
const collapsibleState = convertToCollapsibleState(this._collapseState);
this._proxy.$updateCommentThread(
......@@ -951,9 +951,9 @@ function convertToModeComment2(thread: ExtHostCommentThread, commentController:
userName: vscodeComment.author ? vscodeComment.author.name : vscodeComment.userName,
userIconPath: iconPath,
isDraft: vscodeComment.isDraft,
selectCommand: vscodeComment.selectCommand ? commandsConverter.toInternal2(vscodeComment.selectCommand, disposables) : undefined,
editCommand: vscodeComment.editCommand ? commandsConverter.toInternal2(vscodeComment.editCommand, disposables) : undefined,
deleteCommand: vscodeComment.deleteCommand ? commandsConverter.toInternal2(vscodeComment.deleteCommand, disposables) : undefined,
selectCommand: vscodeComment.selectCommand ? commandsConverter.toInternal(vscodeComment.selectCommand, disposables) : undefined,
editCommand: vscodeComment.editCommand ? commandsConverter.toInternal(vscodeComment.editCommand, disposables) : undefined,
deleteCommand: vscodeComment.deleteCommand ? commandsConverter.toInternal(vscodeComment.deleteCommand, disposables) : undefined,
label: vscodeComment.label,
commentReactions: reactions ? reactions.map(reaction => convertToReaction2(commentController.reactionProvider, reaction)) : undefined
};
......@@ -971,7 +971,7 @@ function convertToComment(provider: vscode.DocumentCommentProvider | vscode.Work
userIconPath: iconPath,
canEdit: canEdit,
canDelete: canDelete,
selectCommand: vscodeComment.command ? commandsConverter.toInternal2(vscodeComment.command, disposables) : undefined,
selectCommand: vscodeComment.command ? commandsConverter.toInternal(vscodeComment.command, disposables) : undefined,
isDraft: vscodeComment.isDraft,
commentReactions: vscodeComment.commentReactions ? vscodeComment.commentReactions.map(reaction => convertToReaction(provider, reaction)) : undefined
};
......
......@@ -133,7 +133,7 @@ class CodeLensAdapter {
result.lenses.push({
cacheId: [cacheId, i],
range: typeConvert.Range.from(lenses[i].range),
command: this._commands.toInternal2(lenses[i].command, disposables)
command: this._commands.toInternal(lenses[i].command, disposables)
});
}
......@@ -167,7 +167,7 @@ class CodeLensAdapter {
}
newLens = newLens || lens;
symbol.command = this._commands.toInternal2(newLens.command || CodeLensAdapter._badCmd, disposables);
symbol.command = this._commands.toInternal(newLens.command || CodeLensAdapter._badCmd, disposables);
return symbol;
});
}
......@@ -368,7 +368,7 @@ class CodeActionAdapter {
actions.push({
_isSynthetic: true,
title: candidate.title,
command: this._commands.toInternal2(candidate, disposables),
command: this._commands.toInternal(candidate, disposables),
});
} else {
if (codeActionContext.only) {
......@@ -382,7 +382,7 @@ class CodeActionAdapter {
// new school: convert code action
actions.push({
title: candidate.title,
command: candidate.command && this._commands.toInternal2(candidate.command, disposables),
command: candidate.command && this._commands.toInternal(candidate.command, disposables),
diagnostics: candidate.diagnostics && candidate.diagnostics.map(typeConvert.Diagnostic.from),
edit: candidate.edit && typeConvert.WorkspaceEdit.from(candidate.edit),
kind: candidate.kind && candidate.kind.value,
......@@ -735,7 +735,7 @@ class SuggestAdapter {
i: item.keepWhitespace ? modes.CompletionItemInsertTextRule.KeepWhitespace : 0,
k: item.commitCharacters,
l: item.additionalTextEdits && item.additionalTextEdits.map(typeConvert.TextEdit.from),
m: this._commands.toInternal2(item.command, disposables),
m: this._commands.toInternal(item.command, disposables),
};
// 'insertText'-logic
......
......@@ -427,7 +427,7 @@ class ExtHostSourceControl implements vscode.SourceControl {
this._acceptInputCommand = acceptInputCommand;
const internal = this._commands.converter.toInternal2(acceptInputCommand, this._acceptInputDisposables.value);
const internal = this._commands.converter.toInternal(acceptInputCommand, this._acceptInputDisposables.value);
this._proxy.$updateSourceControl(this.handle, { acceptInputCommand: internal });
}
......@@ -447,7 +447,7 @@ class ExtHostSourceControl implements vscode.SourceControl {
this._statusBarCommands = statusBarCommands;
const internal = (statusBarCommands || []).map(c => this._commands.converter.toInternal2(c, this._statusBarDisposables.value!)) as CommandDto[];
const internal = (statusBarCommands || []).map(c => this._commands.converter.toInternal(c, this._statusBarDisposables.value!)) as CommandDto[];
this._proxy.$updateSourceControl(this.handle, { statusBarCommands: internal });
}
......
......@@ -452,7 +452,7 @@ class ExtHostTreeView<T> extends Disposable {
description: extensionTreeItem.description,
resourceUri: extensionTreeItem.resourceUri,
tooltip: typeof extensionTreeItem.tooltip === 'string' ? extensionTreeItem.tooltip : undefined,
command: extensionTreeItem.command ? this.commands.toInternal2(extensionTreeItem.command, disposable) : undefined,
command: extensionTreeItem.command ? this.commands.toInternal(extensionTreeItem.command, disposable) : undefined,
contextValue: extensionTreeItem.contextValue,
icon,
iconDark: this.getDarkIconPath(extensionTreeItem) || icon,
......
......@@ -67,8 +67,13 @@ body[data-exploration^="icon-exploration"] .monaco-workbench .part > .title > .t
body[data-exploration^="icon-exploration"] .monaco-workbench .part > .title > .title-actions .actions-container[aria-label="Source Control: Git actions"] .icon[data-title="git.refresh"],
body[data-exploration^="icon-exploration"] .monaco-workbench .part > .title > .title-actions .actions-container[aria-label="Debug actions"] .icon,
body[data-exploration^="icon-exploration"] .monaco-workbench .part > .title > .title-actions .actions-container[aria-label^="Extensions"] .icon,
body[data-exploration^="icon-exploration"] .scm-viewlet .monaco-list-row > .resource-group > .actions .action-label[data-title^="git."],
body[data-exploration^="icon-exploration"] .scm-viewlet .monaco-list-row > .resource > .name > .monaco-icon-label > .actions .action-label,
body[data-exploration^="icon-exploration"] .scm-viewlet .monaco-list-row > .resource > .name > .monaco-icon-label > .actions .action-label[data-title^="git.unstage"],
body[data-exploration^="icon-exploration"] .scm-viewlet .monaco-list-row > .resource > .name > .monaco-icon-label > .actions .action-label[data-title^="git.stage"],
body[data-exploration^="icon-exploration"] .scm-viewlet .monaco-list-row > .resource > .name > .monaco-icon-label > .actions .action-label[data-title^="git.openChange"],
body[data-exploration^="icon-exploration"] .scm-viewlet .monaco-list-row > .resource > .name > .monaco-icon-label > .actions .action-label[data-title^="git.clean"],
body[data-exploration^="icon-exploration"] .scm-viewlet .monaco-list-row > .resource-group > .actions .action-label[data-title="git.cleanAll"],
body[data-exploration^="icon-exploration"] .scm-viewlet .monaco-list-row > .resource-group > .actions .action-label[data-title="git.stageAll"],
body[data-exploration^="icon-exploration"] .scm-viewlet .monaco-list-row > .resource-group > .actions .action-label[data-title="git.unstageAll"],
body[data-exploration^="icon-exploration"] .monaco-workbench .part > .content > .debug-viewlet .actions .action-label.icon,
body[data-exploration^="icon-exploration"] .monaco-workbench .debug-toolbar .drag-area,
body[data-exploration^="icon-exploration"] .monaco-workbench .debug-toolbar .action-label,
......
......@@ -327,6 +327,7 @@ export class BreadcrumbsControl {
// show picker
let picker: BreadcrumbsPicker;
let pickerAnchor: { x: number; y: number };
let editor = this._getActiveCodeEditor();
let editorDecorations: string[] = [];
let editorViewState: ICodeEditorViewState | undefined;
......@@ -393,34 +394,37 @@ export class BreadcrumbsControl {
);
},
getAnchor: () => {
let maxInnerWidth = window.innerWidth - 8 /*a little less the full widget*/;
let maxHeight = Math.min(window.innerHeight * 0.7, 300);
let pickerWidth = Math.min(maxInnerWidth, Math.max(240, maxInnerWidth / 4.17));
let pickerArrowSize = 8;
let pickerArrowOffset: number;
let data = dom.getDomNodePagePosition(event.node.firstChild as HTMLElement);
let y = data.top + data.height + pickerArrowSize;
if (y + maxHeight >= window.innerHeight) {
maxHeight = window.innerHeight - y - 30 /* room for shadow and status bar*/;
}
let x = data.left;
if (x + pickerWidth >= maxInnerWidth) {
x = maxInnerWidth - pickerWidth;
}
if (event.payload instanceof StandardMouseEvent) {
let maxPickerArrowOffset = pickerWidth - 2 * pickerArrowSize;
pickerArrowOffset = event.payload.posx - x;
if (pickerArrowOffset > maxPickerArrowOffset) {
x = Math.min(maxInnerWidth - pickerWidth, x + pickerArrowOffset - maxPickerArrowOffset);
pickerArrowOffset = maxPickerArrowOffset;
if (!pickerAnchor) {
let maxInnerWidth = window.innerWidth - 8 /*a little less the full widget*/;
let maxHeight = Math.min(window.innerHeight * 0.7, 300);
let pickerWidth = Math.min(maxInnerWidth, Math.max(240, maxInnerWidth / 4.17));
let pickerArrowSize = 8;
let pickerArrowOffset: number;
let data = dom.getDomNodePagePosition(event.node.firstChild as HTMLElement);
let y = data.top + data.height + pickerArrowSize;
if (y + maxHeight >= window.innerHeight) {
maxHeight = window.innerHeight - y - 30 /* room for shadow and status bar*/;
}
let x = data.left;
if (x + pickerWidth >= maxInnerWidth) {
x = maxInnerWidth - pickerWidth;
}
if (event.payload instanceof StandardMouseEvent) {
let maxPickerArrowOffset = pickerWidth - 2 * pickerArrowSize;
pickerArrowOffset = event.payload.posx - x;
if (pickerArrowOffset > maxPickerArrowOffset) {
x = Math.min(maxInnerWidth - pickerWidth, x + pickerArrowOffset - maxPickerArrowOffset);
pickerArrowOffset = maxPickerArrowOffset;
}
} else {
pickerArrowOffset = (data.left + (data.width * 0.3)) - x;
}
} else {
pickerArrowOffset = (data.left + (data.width * 0.3)) - x;
picker.show(element, maxHeight, pickerWidth, pickerArrowSize, Math.max(0, pickerArrowOffset));
pickerAnchor = { x, y };
}
picker.show(element, maxHeight, pickerWidth, pickerArrowSize, Math.max(0, pickerArrowOffset));
return { x, y };
return pickerAnchor;
},
onHide: (data) => {
if (editor) {
......
......@@ -34,6 +34,8 @@ import { assign } from 'vs/base/common/objects';
import { mnemonicMenuLabel, unmnemonicLabel } from 'vs/base/common/labels';
import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
import { withNullAsUndefined } from 'vs/base/common/types';
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { isFullscreen } from 'vs/base/browser/browser';
export abstract class MenubarControl extends Disposable {
......@@ -106,8 +108,6 @@ export abstract class MenubarControl extends Disposable {
this.menuUpdater = this._register(new RunOnceScheduler(() => this.doUpdateMenubar(false), 200));
this.notifyUserOfCustomMenubarAccessibility();
this.registerListeners();
}
protected abstract doUpdateMenubar(firstTime: boolean): void;
......@@ -300,6 +300,8 @@ export class NativeMenubarControl extends MenubarControl {
this.doUpdateMenubar(true);
});
this.registerListeners();
}
protected doUpdateMenubar(firstTime: boolean): void {
......@@ -457,7 +459,8 @@ export class CustomMenubarControl extends MenubarControl {
@IPreferencesService preferencesService: IPreferencesService,
@IEnvironmentService environmentService: IEnvironmentService,
@IAccessibilityService accessibilityService: IAccessibilityService,
@IThemeService private readonly themeService: IThemeService
@IThemeService private readonly themeService: IThemeService,
@IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService
) {
super(
......@@ -482,6 +485,8 @@ export class CustomMenubarControl extends MenubarControl {
this.recentlyOpened = recentlyOpened;
});
this.registerListeners();
registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
const menubarActiveWindowFgColor = theme.getColor(TITLE_BAR_ACTIVE_FOREGROUND);
if (menubarActiveWindowFgColor) {
......@@ -642,7 +647,7 @@ export class CustomMenubarControl extends MenubarControl {
enableMenuBarMnemonics = true;
}
return enableMenuBarMnemonics;
return enableMenuBarMnemonics && (!isWeb || isFullscreen());
}
private setupCustomMenubar(firstTime: boolean): void {
......@@ -750,6 +755,11 @@ export class CustomMenubarControl extends MenubarControl {
this._register(DOM.addDisposableListener(window, DOM.EventType.RESIZE, () => {
this.menubar.blur();
}));
// Mnemonics require fullscreen in web
if (isWeb) {
this._register(this.layoutService.onFullscreenChange(e => this.updateMenubar()));
}
}
get onVisibilityChange(): Event<boolean> {
......
......@@ -6,7 +6,7 @@
import { Registry } from 'vs/platform/registry/common/platform';
import * as nls from 'vs/nls';
import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
import { isMacintosh } from 'vs/base/common/platform';
import { isMacintosh, isWindows, isLinux, isWeb } from 'vs/base/common/platform';
// Configuration
(function registerConfiguration(): void {
......@@ -278,6 +278,34 @@ import { isMacintosh } from 'vs/base/common/platform';
'type': 'string',
'default': isMacintosh ? '${activeEditorShort}${separator}${rootName}' : '${dirty}${activeEditorShort}${separator}${rootName}${separator}${appName}',
'markdownDescription': windowTitleDescription
},
'window.menuBarVisibility': {
'type': 'string',
'enum': ['default', 'visible', 'toggle', 'hidden'],
'enumDescriptions': [
nls.localize('window.menuBarVisibility.default', "Menu is only hidden in full screen mode."),
nls.localize('window.menuBarVisibility.visible', "Menu is always visible even in full screen mode."),
nls.localize('window.menuBarVisibility.toggle', "Menu is hidden but can be displayed via Alt key."),
nls.localize('window.menuBarVisibility.hidden', "Menu is always hidden.")
],
'default': 'default',
'scope': ConfigurationScope.APPLICATION,
'description': nls.localize('menuBarVisibility', "Control the visibility of the menu bar. A setting of 'toggle' means that the menu bar is hidden and a single press of the Alt key will show it. By default, the menu bar will be visible, unless the window is full screen."),
'included': isWindows || isLinux || isWeb
},
'window.enableMenuBarMnemonics': {
'type': 'boolean',
'default': true,
'scope': ConfigurationScope.APPLICATION,
'description': nls.localize('enableMenuBarMnemonics', "If enabled, the main menus can be opened via Alt-key shortcuts. Disabling mnemonics allows to bind these Alt-key shortcuts to editor commands instead."),
'included': isWindows || isLinux || isWeb
},
'window.disableCustomMenuBarAltFocus': {
'type': 'boolean',
'default': false,
'scope': ConfigurationScope.APPLICATION,
'markdownDescription': nls.localize('disableCustomMenuBarAltFocus', "If enabled, disables the ability to focus the menu bar with the Alt-key when not set to toggle."),
'included': isWindows || isLinux || isWeb
}
}
});
......
......@@ -73,8 +73,8 @@ export class ConfigurationManager implements IConfigurationManager {
this.adapterDescriptorFactories = [];
this.debuggers = [];
this.toDispose = [];
this.registerListeners(lifecycleService);
this.initLaunches();
this.registerListeners(lifecycleService);
const previousSelectedRoot = this.storageService.get(DEBUG_SELECTED_ROOT, StorageScope.WORKSPACE);
const previousSelectedLaunch = this.launches.filter(l => l.uri.toString() === previousSelectedRoot).pop();
this.debugConfigurationTypeContext = CONTEXT_DEBUG_CONFIGURATION_TYPE.bindTo(contextKeyService);
......
......@@ -4,74 +4,11 @@
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { join } from 'vs/base/common/path';
import { Registry } from 'vs/platform/registry/common/platform';
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { IOutputChannelRegistry, Extensions as OutputExt, } from 'vs/workbench/contrib/output/common/output';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { Disposable } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri';
import * as Constants from 'vs/workbench/contrib/logs/common/logConstants';
import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions } from 'vs/workbench/common/actions';
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { OpenLogsFolderAction, SetLogLevelAction } from 'vs/workbench/contrib/logs/common/logsActions';
import { ILogService, LogLevel } from 'vs/platform/log/common/log';
import { IFileService, FileChangeType } from 'vs/platform/files/common/files';
import { dirname, joinPath } from 'vs/base/common/resources';
import { IRemoteAgentService, RemoteExtensionLogFileName } from 'vs/workbench/services/remote/common/remoteAgentService';
import { SetLogLevelAction } from 'vs/workbench/contrib/logs/common/logsActions';
class LogOutputChannels extends Disposable implements IWorkbenchContribution {
constructor(
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService,
@ILogService logService: ILogService,
@IFileService private readonly fileService: IFileService,
@IRemoteAgentService remoteAgentService: IRemoteAgentService
) {
super();
this.registerLogChannel(Constants.mainLogChannelId, nls.localize('mainLog', "Main"), URI.file(join(environmentService.logsPath, `main.log`)));
this.registerLogChannel(Constants.sharedLogChannelId, nls.localize('sharedLog', "Shared"), URI.file(join(environmentService.logsPath, `sharedprocess.log`)));
this.registerLogChannel(Constants.rendererLogChannelId, nls.localize('rendererLog', "Window"), URI.file(join(environmentService.logsPath, `renderer${environmentService.configuration.windowId}.log`)));
remoteAgentService.getEnvironment().then(remoteEnv => {
if (remoteEnv) {
const outputChannelRegistry = Registry.as<IOutputChannelRegistry>(OutputExt.OutputChannels);
outputChannelRegistry.registerChannel({ id: 'remoteExtensionLog', label: nls.localize('remoteExtensionLog', "Remote Server"), file: joinPath(remoteEnv.logsPath, `${RemoteExtensionLogFileName}.log`), log: true });
}
});
const registerTelemetryChannel = (level: LogLevel) => {
if (level === LogLevel.Trace && !Registry.as<IOutputChannelRegistry>(OutputExt.OutputChannels).getChannel(Constants.telemetryLogChannelId)) {
this.registerLogChannel(Constants.telemetryLogChannelId, nls.localize('telemetryLog', "Telemetry"), URI.file(join(environmentService.logsPath, `telemetry.log`)));
}
};
registerTelemetryChannel(logService.getLevel());
logService.onDidChangeLogLevel(registerTelemetryChannel);
const workbenchActionsRegistry = Registry.as<IWorkbenchActionRegistry>(WorkbenchActionExtensions.WorkbenchActions);
const devCategory = nls.localize('developer', "Developer");
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenLogsFolderAction, OpenLogsFolderAction.ID, OpenLogsFolderAction.LABEL), 'Developer: Open Logs Folder', devCategory);
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(SetLogLevelAction, SetLogLevelAction.ID, SetLogLevelAction.LABEL), 'Developer: Set Log Level...', devCategory);
}
private async registerLogChannel(id: string, label: string, file: URI): Promise<void> {
const outputChannelRegistry = Registry.as<IOutputChannelRegistry>(OutputExt.OutputChannels);
const exists = await this.fileService.exists(file);
if (exists) {
outputChannelRegistry.registerChannel({ id, label, file, log: true });
return;
}
const watcher = this.fileService.watch(dirname(file));
const disposable = this.fileService.onFileChanges(e => {
if (e.contains(file, FileChangeType.ADDED)) {
watcher.dispose();
disposable.dispose();
outputChannelRegistry.registerChannel({ id, label, file, log: true });
}
});
}
}
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(LogOutputChannels, LifecyclePhase.Restored);
\ No newline at end of file
const workbenchActionsRegistry = Registry.as<IWorkbenchActionRegistry>(WorkbenchActionExtensions.WorkbenchActions);
const devCategory = nls.localize('developer', "Developer");
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(SetLogLevelAction, SetLogLevelAction.ID, SetLogLevelAction.LABEL), 'Developer: Set Log Level...', devCategory);
\ No newline at end of file
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { join } from 'vs/base/common/path';
import { Registry } from 'vs/platform/registry/common/platform';
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { IOutputChannelRegistry, Extensions as OutputExt, } from 'vs/workbench/contrib/output/common/output';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { Disposable } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri';
import * as Constants from 'vs/workbench/contrib/logs/common/logConstants';
import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions } from 'vs/workbench/common/actions';
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { OpenLogsFolderAction } from 'vs/workbench/contrib/logs/common/logsActions';
import { ILogService, LogLevel } from 'vs/platform/log/common/log';
import { IFileService, FileChangeType } from 'vs/platform/files/common/files';
import { dirname } from 'vs/base/common/resources';
class LogOutputChannels extends Disposable implements IWorkbenchContribution {
constructor(
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService,
@ILogService logService: ILogService,
@IFileService private readonly fileService: IFileService
) {
super();
this.registerLogChannel(Constants.mainLogChannelId, nls.localize('mainLog', "Main"), URI.file(join(environmentService.logsPath, `main.log`)));
this.registerLogChannel(Constants.sharedLogChannelId, nls.localize('sharedLog', "Shared"), URI.file(join(environmentService.logsPath, `sharedprocess.log`)));
this.registerLogChannel(Constants.rendererLogChannelId, nls.localize('rendererLog', "Window"), URI.file(join(environmentService.logsPath, `renderer${environmentService.configuration.windowId}.log`)));
const registerTelemetryChannel = (level: LogLevel) => {
if (level === LogLevel.Trace && !Registry.as<IOutputChannelRegistry>(OutputExt.OutputChannels).getChannel(Constants.telemetryLogChannelId)) {
this.registerLogChannel(Constants.telemetryLogChannelId, nls.localize('telemetryLog', "Telemetry"), URI.file(join(environmentService.logsPath, `telemetry.log`)));
}
};
registerTelemetryChannel(logService.getLevel());
logService.onDidChangeLogLevel(registerTelemetryChannel);
const workbenchActionsRegistry = Registry.as<IWorkbenchActionRegistry>(WorkbenchActionExtensions.WorkbenchActions);
const devCategory = nls.localize('developer', "Developer");
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenLogsFolderAction, OpenLogsFolderAction.ID, OpenLogsFolderAction.LABEL), 'Developer: Open Logs Folder', devCategory);
}
private async registerLogChannel(id: string, label: string, file: URI): Promise<void> {
const outputChannelRegistry = Registry.as<IOutputChannelRegistry>(OutputExt.OutputChannels);
const exists = await this.fileService.exists(file);
if (exists) {
outputChannelRegistry.registerChannel({ id, label, file, log: true });
return;
}
const watcher = this.fileService.watch(dirname(file));
const disposable = this.fileService.onFileChanges(e => {
if (e.contains(file, FileChangeType.ADDED)) {
watcher.dispose();
disposable.dispose();
outputChannelRegistry.registerChannel({ id, label, file, log: true });
}
});
}
}
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(LogOutputChannels, LifecyclePhase.Restored);
\ No newline at end of file
......@@ -10,9 +10,12 @@ import { ILabelService } from 'vs/platform/label/common/label';
import { isWeb, OperatingSystem } from 'vs/base/common/platform';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { Schemas } from 'vs/base/common/network';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { IRemoteAgentService, RemoteExtensionLogFileName } from 'vs/workbench/services/remote/common/remoteAgentService';
import { ILogService } from 'vs/platform/log/common/log';
import { LogLevelSetterChannel } from 'vs/platform/log/common/logIpc';
import { IOutputChannelRegistry, Extensions as OutputExt, } from 'vs/workbench/contrib/output/common/output';
import { localize } from 'vs/nls';
import { joinPath } from 'vs/base/common/resources';
export class LabelContribution implements IWorkbenchContribution {
constructor(
......@@ -54,6 +57,21 @@ class RemoteChannelsContribution implements IWorkbenchContribution {
}
}
class RemoteLogOutputChannels implements IWorkbenchContribution {
constructor(
@IRemoteAgentService remoteAgentService: IRemoteAgentService
) {
remoteAgentService.getEnvironment().then(remoteEnv => {
if (remoteEnv) {
const outputChannelRegistry = Registry.as<IOutputChannelRegistry>(OutputExt.OutputChannels);
outputChannelRegistry.registerChannel({ id: 'remoteExtensionLog', label: localize('remoteExtensionLog', "Remote Server"), file: joinPath(remoteEnv.logsPath, `${RemoteExtensionLogFileName}.log`), log: true });
}
});
}
}
const workbenchContributionsRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
workbenchContributionsRegistry.registerWorkbenchContribution(LabelContribution, LifecyclePhase.Starting);
workbenchContributionsRegistry.registerWorkbenchContribution(RemoteChannelsContribution, LifecyclePhase.Starting);
workbenchContributionsRegistry.registerWorkbenchContribution(RemoteLogOutputChannels, LifecyclePhase.Restored);
......@@ -189,20 +189,12 @@ export class StatusBarController implements IWorkbenchContribution {
const disposables = new DisposableStore();
for (const c of commands) {
const statusId = `status.scm.${repository.provider.id}.${c.tooltip}`; // needs to be unique, but c.id is too random
let statusLabel: string;
if (c.tooltip) {
statusLabel = localize('status.scm', "Source Control ({0}): {1}", repository.provider.label, c.tooltip.replace('...', ''));
} else {
statusLabel = localize('status.scm.short', "Source Control ({0})", repository.provider.label);
}
disposables.add(this.statusbarService.addEntry({
text: c.title,
tooltip: `${label} - ${c.tooltip}`,
command: c.id,
arguments: c.arguments
}, statusId, statusLabel, MainThreadStatusBarAlignment.LEFT, 10000));
}, 'status.scm', localize('status.scm', "Source Control"), MainThreadStatusBarAlignment.LEFT, 10000));
}
this.statusBarDisposable = disposables;
......
......@@ -23,7 +23,7 @@ import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/wor
import { AllowWorkspaceShellTerminalCommand, ClearSelectionTerminalAction, ClearTerminalAction, CopyTerminalSelectionAction, CreateNewInActiveWorkspaceTerminalAction, CreateNewTerminalAction, DeleteToLineStartTerminalAction, DeleteWordLeftTerminalAction, DeleteWordRightTerminalAction, DisallowWorkspaceShellTerminalCommand, FindNext, FindPrevious, FocusActiveTerminalAction, FocusNextPaneTerminalAction, FocusNextTerminalAction, FocusPreviousPaneTerminalAction, FocusPreviousTerminalAction, FocusTerminalFindWidgetAction, HideTerminalFindWidgetAction, KillTerminalAction, MoveToLineEndTerminalAction, MoveToLineStartTerminalAction, QuickOpenActionTermContributor, QuickOpenTermAction, RenameTerminalAction, ResizePaneDownTerminalAction, ResizePaneLeftTerminalAction, ResizePaneRightTerminalAction, ResizePaneUpTerminalAction, RunActiveFileInTerminalAction, RunSelectedTextInTerminalAction, ScrollDownPageTerminalAction, ScrollDownTerminalAction, ScrollToBottomTerminalAction, ScrollToNextCommandAction, ScrollToPreviousCommandAction, ScrollToTopTerminalAction, ScrollUpPageTerminalAction, ScrollUpTerminalAction, SelectAllTerminalAction, SelectDefaultShellWindowsTerminalAction, SelectToNextCommandAction, SelectToNextLineAction, SelectToPreviousCommandAction, SelectToPreviousLineAction, SendSequenceTerminalCommand, SplitInActiveWorkspaceTerminalAction, SplitTerminalAction, TerminalPasteAction, TERMINAL_PICKER_PREFIX, ToggleCaseSensitiveCommand, ToggleEscapeSequenceLoggingAction, ToggleRegexCommand, ToggleTerminalAction, ToggleWholeWordCommand } from 'vs/workbench/contrib/terminal/browser/terminalActions';
import { TerminalPanel } from 'vs/workbench/contrib/terminal/browser/terminalPanel';
import { TerminalPickerHandler } from 'vs/workbench/contrib/terminal/browser/terminalQuickOpen';
import { KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_NOT_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, TERMINAL_PANEL_ID, DEFAULT_LETTER_SPACING, DEFAULT_LINE_HEIGHT, TerminalCursorStyle, ITerminalService } from 'vs/workbench/contrib/terminal/common/terminal';
import { KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_NOT_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, TERMINAL_PANEL_ID, DEFAULT_LETTER_SPACING, DEFAULT_LINE_HEIGHT, TerminalCursorStyle, ITerminalService, TERMINAL_ACTION_CATEGORY } from 'vs/workbench/contrib/terminal/common/terminal';
import { registerColors } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry';
import { setupTerminalCommands, TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminalCommands';
import { setupTerminalMenu } from 'vs/workbench/contrib/terminal/common/terminalMenu';
......@@ -302,7 +302,7 @@ actionBarRegistry.registerActionBarContributor(Scope.VIEWER, QuickOpenActionTerm
Registry.as<panel.PanelRegistry>(panel.Extensions.Panels).setDefaultPanelId(TERMINAL_PANEL_ID);
// On mac cmd+` is reserved to cycle between windows, that's why the keybindings use WinCtrl
const category = nls.localize('terminalCategory', "Terminal");
const category = TERMINAL_ACTION_CATEGORY;
const actionRegistry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(KillTerminalAction, KillTerminalAction.ID, KillTerminalAction.LABEL), 'Terminal: Kill the Active Terminal Instance', category);
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(CopyTerminalSelectionAction, CopyTerminalSelectionAction.ID, CopyTerminalSelectionAction.LABEL, {
......
......@@ -3,6 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { Event } from 'vs/base/common/event';
import { IDisposable } from 'vs/base/common/lifecycle';
import { RawContextKey, ContextKeyExpr, IContextKey } from 'vs/platform/contextkey/common/contextkey';
......@@ -56,6 +57,8 @@ export const TerminalCursorStyle = {
export const TERMINAL_CONFIG_SECTION = 'terminal.integrated';
export const TERMINAL_ACTION_CATEGORY = nls.localize('terminalCategory', "Terminal");
export const DEFAULT_LETTER_SPACING = 0;
export const MINIMUM_LETTER_SPACING = -5;
export const DEFAULT_LINE_HEIGHT = 1;
......
......@@ -22,6 +22,7 @@ export const enum TERMINAL_COMMAND_ID {
MOVE_TO_LINE_START = 'workbench.action.terminal.moveToLineStart',
MOVE_TO_LINE_END = 'workbench.action.terminal.moveToLineEnd',
NEW = 'workbench.action.terminal.new',
NEW_LOCAL = 'workbench.action.terminal.newLocal',
NEW_IN_ACTIVE_WORKSPACE = 'workbench.action.terminal.newInActiveWorkspace',
SPLIT = 'workbench.action.terminal.split',
SPLIT_IN_ACTIVE_WORKSPACE = 'workbench.action.terminal.splitInActiveWorkspace',
......
......@@ -13,6 +13,9 @@ import { escapeNonWindowsPath } from 'vs/workbench/contrib/terminal/common/termi
import { execFile } from 'child_process';
import { Emitter, Event } from 'vs/base/common/event';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { registerRemoteContributions } from 'vs/workbench/contrib/terminal/node/terminalRemote';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { isWeb } from 'vs/base/common/platform';
export class TerminalNativeService implements ITerminalNativeService {
public _serviceBrand: any;
......@@ -27,9 +30,17 @@ export class TerminalNativeService implements ITerminalNativeService {
constructor(
@IFileService private readonly _fileService: IFileService,
@IInstantiationService readonly instantiationService: IInstantiationService,
@IRemoteAgentService remoteAgentService: IRemoteAgentService
) {
ipc.on('vscode:openFiles', (_event: any, request: IOpenFileRequest) => this._onOpenFileRequest.fire(request));
ipc.on('vscode:osResume', () => this._onOsResume.fire());
if (!isWeb) {
const connection = remoteAgentService.getConnection();
if (connection && connection.remoteAuthority) {
registerRemoteContributions();
}
}
}
public whenFileDeleted(path: URI): Promise<void> {
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { Registry } from 'vs/platform/registry/common/platform';
import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions';
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { TERMINAL_ACTION_CATEGORY, ITerminalService } from 'vs/workbench/contrib/terminal/common/terminal';
import { TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminalCommands';
import { Action } from 'vs/base/common/actions';
import { URI } from 'vs/base/common/uri';
import { homedir } from 'os';
export function registerRemoteContributions() {
const actionRegistry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(CreateNewLocalTerminalAction, CreateNewLocalTerminalAction.ID, CreateNewLocalTerminalAction.LABEL), 'Terminal: Create New Integrated Terminal (Local)', TERMINAL_ACTION_CATEGORY);
}
export class CreateNewLocalTerminalAction extends Action {
public static readonly ID = TERMINAL_COMMAND_ID.NEW_LOCAL;
public static readonly LABEL = nls.localize('workbench.action.terminal.newLocal', "Create New Integrated Terminal (Local)");
constructor(
id: string, label: string,
@ITerminalService private readonly terminalService: ITerminalService
) {
super(id, label);
}
public run(event?: any): Promise<any> {
const instance = this.terminalService.createTerminal({ cwd: URI.file(homedir()) });
if (!instance) {
return Promise.resolve(undefined);
}
// Append (Local) to the first title that comes back, the title will then become static
const disposable = instance.onTitleChanged(() => {
if (instance.title && instance.title.trim().length > 0) {
disposable.dispose();
instance.setTitle(`${instance.title} (Local)`, false);
}
});
this.terminalService.setActiveInstance(instance);
return this.terminalService.showPanel(true);
}
}
......@@ -16,7 +16,7 @@ suite('Workbench - TerminalConfigHelper', () => {
fixture = document.body;
});
test('TerminalConfigHelper - getFont fontFamily', function () {
test.skip('TerminalConfigHelper - getFont fontFamily', function () {
const configurationService = new TestConfigurationService();
configurationService.setUserConfiguration('editor', { fontFamily: 'foo' });
configurationService.setUserConfiguration('terminal', { integrated: { fontFamily: 'bar' } });
......
......@@ -123,16 +123,18 @@
navigator.serviceWorker.register('service-worker.js');
navigator.serviceWorker.ready.then(registration => {
host.onMessage('loaded-resource', event => {
registration.active.postMessage({ channel: 'loaded-resource', data: event.data.args });
});
function forwardFromHostToWorker(channel) {
host.onMessage(channel, event => {
registration.active.postMessage({ channel: channel, data: event.data.args });
});
}
forwardFromHostToWorker('did-load-resource');
forwardFromHostToWorker('did-load-localhost');
});
navigator.serviceWorker.addEventListener('message', event => {
switch (event.data.channel) {
case 'load-resource':
host.postMessage('load-resource', { path: event.data.path });
return;
if (['load-resource', 'load-localhost'].includes(event.data.channel)) {
host.postMessage(event.data.channel, event.data);
}
});
}
......
......@@ -8,25 +8,26 @@
const resourceRoot = '/vscode-resource';
/**
* @template T
* @typedef {{
* resolve: () => void,
* promise: Promise<Response>
* }} ResourcePathEntry
* resolve: (x: T) => void,
* promise: Promise<T>
* }} RequestStoreEntry
*/
/**
* Map of requested paths to responses.
* @template T
*/
const resourceRequestManager = new class ResourceRequestManager {
class RequestStore {
constructor() {
/** @type {Map<string, ResourcePathEntry>} */
/** @type {Map<string, RequestStoreEntry<T>>} */
this.map = new Map();
}
/**
* @param {string} webviewId
* @param {string} path
* @return {ResourcePathEntry | undefined}
* @return {RequestStoreEntry<T> | undefined}
*/
get(webviewId, path) {
return this.map.get(this._key(webviewId, path));
......@@ -35,19 +36,31 @@ const resourceRequestManager = new class ResourceRequestManager {
/**
* @param {string} webviewId
* @param {string} path
* @return {boolean}
*/
has(webviewId, path) {
return this.map.has(this._key(webviewId, path));
create(webviewId, path) {
const existing = this.get(webviewId, path);
if (existing) {
return existing.promise;
}
let resolve;
const promise = new Promise(r => resolve = r);
this.map.set(this._key(webviewId, path), { resolve, promise });
return promise;
}
/**
* @param {string} webviewId
* @param {string} path
* @param {ResourcePathEntry} entry
* @param {T} result
* @return {boolean}
*/
set(webviewId, path, entry) {
this.map.set(this._key(webviewId, path), entry);
resolve(webviewId, path, result) {
const entry = this.get(webviewId, path);
if (!entry) {
return false;
}
entry.resolve(result);
return true;
}
/**
......@@ -58,31 +71,49 @@ const resourceRequestManager = new class ResourceRequestManager {
_key(webviewId, path) {
return `${webviewId}@@@${path}`;
}
}();
}
/**
* Map of requested paths to responses.
*
* @type {RequestStore<{ body: any, mime: string } | undefined>}
*/
const resourceRequestStore = new RequestStore();
/**
* Map of requested localhost origins to optional redirects.
*
* @type {RequestStore<string | undefined>}
*/
const localhostRequestStore = new RequestStore();
const notFoundResponse = new Response('Not Found', {
status: 404,
});
self.addEventListener('message', (event) => {
switch (event.data.channel) {
case 'loaded-resource':
case 'did-load-resource':
{
const webviewId = getWebviewIdForClient(event.source);
const data = event.data.data;
const target = resourceRequestManager.get(webviewId, data.path);
if (!target) {
console.log('Loaded unknown resource', data.path);
return;
const response = data.status === 200
? { body: data.data, mime: data.mime }
: undefined;
if (!resourceRequestStore.resolve(webviewId, data.path, response)) {
console.log('Could not resolve unknown resource', data.path);
}
return;
}
if (data.status === 200) {
target.resolve(new Response(data.data, {
status: 200,
headers: { 'Content-Type': data.mime },
}));
} else {
target.resolve(notFoundResponse.clone());
case 'did-load-localhost':
{
const webviewId = getWebviewIdForClient(event.source);
const data = event.data.data;
if (!localhostRequestStore.resolve(webviewId, data.origin, data.location)) {
console.log('Could not resolve unknown localhost', data.origin);
}
return;
}
......@@ -94,59 +125,123 @@ self.addEventListener('message', (event) => {
self.addEventListener('fetch', (event) => {
const requestUrl = new URL(event.request.url);
if (!requestUrl.pathname.startsWith(resourceRoot + '/')) {
return event.respondWith(fetch(event.request));
// See if it's a resource request
if (requestUrl.origin === self.origin && requestUrl.pathname.startsWith(resourceRoot + '/')) {
return event.respondWith(processResourceRequest(event, requestUrl));
}
// See if it's a localhost request
if (requestUrl.origin !== self.origin && requestUrl.host.match(/^localhost:(\d+)$/)) {
return event.respondWith(processLocalhostRequest(event, requestUrl));
}
});
self.addEventListener('install', (event) => {
event.waitUntil(self.skipWaiting()); // Activate worker immediately
});
self.addEventListener('activate', (event) => {
event.waitUntil(self.clients.claim()); // Become available to all pages
});
async function processResourceRequest(event, requestUrl) {
const client = await self.clients.get(event.clientId);
if (!client) {
console.log('Could not find inner client for request');
return notFoundResponse.clone();
}
event.respondWith((async () => {
const client = await self.clients.get(event.clientId);
if (!client) {
console.log('Could not find inner client for request');
const webviewId = getWebviewIdForClient(client);
const resourcePath = requestUrl.pathname.replace(resourceRoot, '');
function resolveResourceEntry(entry) {
if (!entry) {
return notFoundResponse.clone();
}
return new Response(entry.body, {
status: 200,
headers: { 'Content-Type': entry.mime }
});
}
const parentClient = await getOuterIframeClient(webviewId);
if (!parentClient) {
console.log('Could not find parent client for request');
return notFoundResponse.clone();
}
const webviewId = getWebviewIdForClient(client);
const resourcePath = requestUrl.pathname.replace(resourceRoot, '');
// Check if we've already resolved this request
const existing = resourceRequestStore.get(webviewId, resourcePath);
if (existing) {
return existing.promise.then(resolveResourceEntry);
}
const allClients = await self.clients.matchAll({ includeUncontrolled: true });
parentClient.postMessage({
channel: 'load-resource',
path: resourcePath
});
// Check if we've already resolved this request
const existing = resourceRequestManager.get(webviewId, resourcePath);
if (existing) {
return existing.promise.then(r => r.clone());
}
return resourceRequestStore.create(webviewId, resourcePath)
.then(resolveResourceEntry);
}
// Find parent iframe
for (const client of allClients) {
const clientUrl = new URL(client.url);
if (clientUrl.pathname === '/' && clientUrl.search.match(new RegExp('\\bid=' + webviewId))) {
client.postMessage({
channel: 'load-resource',
path: resourcePath
});
let resolve;
const promise = new Promise(r => resolve = r);
resourceRequestManager.set(webviewId, resourcePath, { resolve, promise });
return promise.then(r => r.clone());
}
/**
* @param {*} event
* @param {URL} requestUrl
*/
async function processLocalhostRequest(event, requestUrl) {
const client = await self.clients.get(event.clientId);
if (!client) {
// This is expected when requesting resources on other localhost ports
// that are not spawned by vs code
return undefined;
}
const webviewId = getWebviewIdForClient(client);
const origin = requestUrl.origin;
const resolveRedirect = redirectOrigin => {
if (!redirectOrigin) {
return fetch(event.request);
}
const location = event.request.url.replace(new RegExp(`^${requestUrl.origin}(/|$)`), `${redirectOrigin}$1`);
return new Response(null, {
status: 302,
headers: {
Location: location
}
});
};
const parentClient = await getOuterIframeClient(webviewId);
if (!parentClient) {
console.log('Could not find parent client for request');
return notFoundResponse.clone();
})());
});
}
self.addEventListener('install', (event) => {
event.waitUntil(self.skipWaiting()); // Activate worker immediately
});
// Check if we've already resolved this request
const existing = localhostRequestStore.get(webviewId, origin);
if (existing) {
return existing.promise.then(resolveRedirect);
}
self.addEventListener('activate', (event) => {
event.waitUntil(self.clients.claim()); // Become available to all pages
});
parentClient.postMessage({
channel: 'load-localhost',
origin: origin
});
return localhostRequestStore.create(webviewId, origin)
.then(resolveRedirect);
}
function getWebviewIdForClient(client) {
const requesterClientUrl = new URL(client.url);
return requesterClientUrl.search.match(/\bid=([a-z0-9-]+)/i)[1];
}
async function getOuterIframeClient(webviewId) {
const allClients = await self.clients.matchAll({ includeUncontrolled: true });
return allClients.find(client => {
const clientUrl = new URL(client.url);
return clientUrl.pathname === '/' && clientUrl.search.match(new RegExp('\\bid=' + webviewId));
});
}
\ No newline at end of file
......@@ -15,6 +15,8 @@ import { addDisposableListener, addClass } from 'vs/base/browser/dom';
import { getWebviewThemeData } from 'vs/workbench/contrib/webview/common/themeing';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { loadLocalResource } from 'vs/workbench/contrib/webview/common/resourceLoader';
import { WebviewPortMappingManager } from 'vs/workbench/contrib/webview/common/portMapping';
import { ITunnelService } from 'vs/platform/remote/common/tunnel';
interface WebviewContent {
readonly html: string;
......@@ -32,11 +34,14 @@ export class IFrameWebview extends Disposable implements Webview {
private readonly id: string;
private readonly _portMappingManager: WebviewPortMappingManager;
constructor(
private _options: WebviewOptions,
contentOptions: WebviewContentOptions,
@IThemeService themeService: IThemeService,
@IEnvironmentService environmentService: IEnvironmentService,
@ITunnelService tunnelService: ITunnelService,
@IFileService private readonly fileService: IFileService,
@IConfigurationService private readonly _configurationService: IConfigurationService,
) {
......@@ -45,6 +50,12 @@ export class IFrameWebview extends Disposable implements Webview {
throw new Error('To use iframe based webviews, you must configure `environmentService.webviewEndpoint`');
}
this._portMappingManager = this._register(new WebviewPortMappingManager(
this._options.extension ? this._options.extension.location : undefined,
() => this.content.options.portMappings || [],
tunnelService
));
this.content = {
html: '',
options: contentOptions,
......@@ -103,11 +114,16 @@ export class IFrameWebview extends Disposable implements Webview {
case 'load-resource':
{
const path = e.data.data.path;
const uri = URI.file(path);
const uri = URI.file(e.data.data.path);
this.loadResource(uri);
return;
}
case 'load-localhost':
{
this.localLocalhost(e.data.data.origin);
return;
}
}
}));
......@@ -289,7 +305,7 @@ export class IFrameWebview extends Disposable implements Webview {
() => (this.content.options.localResourceRoots || []));
if (result.type === 'success') {
return this._send('loaded-resource', {
return this._send('did-load-resource', {
status: 200,
path: uri.path,
mime: result.mimeType,
......@@ -300,10 +316,18 @@ export class IFrameWebview extends Disposable implements Webview {
// noop
}
return this._send('loaded-resource', {
return this._send('did-load-resource', {
status: 404,
path: uri.path
});
}
private async localLocalhost(origin: string) {
const redirect = await this._portMappingManager.getRedirect(origin);
return this._send('did-load-localhost', {
origin,
location: redirect
});
}
}
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Disposable } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri';
import * as modes from 'vs/editor/common/modes';
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
import { ITunnelService, RemoteTunnel } from 'vs/platform/remote/common/tunnel';
export class WebviewPortMappingManager extends Disposable {
private readonly _tunnels = new Map<number, Promise<RemoteTunnel>>();
constructor(
private readonly extensionLocation: URI | undefined,
private readonly mappings: () => ReadonlyArray<modes.IWebviewPortMapping>,
private readonly tunnelService: ITunnelService
) {
super();
}
public async getRedirect(url: string): Promise<string | undefined> {
const uri = URI.parse(url);
if (uri.scheme !== 'http' && uri.scheme !== 'https') {
return undefined;
}
const localhostMatch = /^localhost:(\d+)$/.exec(uri.authority);
if (!localhostMatch) {
return undefined;
}
const port = +localhostMatch[1];
for (const mapping of this.mappings()) {
if (mapping.webviewPort === port) {
if (this.extensionLocation && this.extensionLocation.scheme === REMOTE_HOST_SCHEME) {
const tunnel = await this.getOrCreateTunnel(mapping.extensionHostPort);
if (tunnel) {
return url.replace(
new RegExp(`^${uri.scheme}://localhost:${mapping.webviewPort}(/|$)`),
`${uri.scheme}://localhost:${tunnel.tunnelLocalPort}$1`);
}
}
if (mapping.webviewPort !== mapping.extensionHostPort) {
return url.replace(
new RegExp(`^${uri.scheme}://localhost:${mapping.webviewPort}(/|$)`),
`${uri.scheme}://localhost:${mapping.extensionHostPort}$1`);
}
}
}
return undefined;
}
dispose() {
super.dispose();
for (const tunnel of this._tunnels.values()) {
tunnel.then(tunnel => tunnel.dispose());
}
this._tunnels.clear();
}
private getOrCreateTunnel(remotePort: number): Promise<RemoteTunnel> | undefined {
const existing = this._tunnels.get(remotePort);
if (existing) {
return existing;
}
const tunnel = this.tunnelService.openTunnel(remotePort);
if (tunnel) {
this._tunnels.set(remotePort, tunnel);
}
return tunnel;
}
}
\ No newline at end of file
......@@ -13,19 +13,17 @@ import { endsWith } from 'vs/base/common/strings';
import { URI } from 'vs/base/common/uri';
import * as modes from 'vs/editor/common/modes';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { IFileService } from 'vs/platform/files/common/files';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
import { ITunnelService, RemoteTunnel } from 'vs/platform/remote/common/tunnel';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { ITunnelService } from 'vs/platform/remote/common/tunnel';
import { ITheme, IThemeService } from 'vs/platform/theme/common/themeService';
import { WebviewPortMappingManager } from 'vs/workbench/contrib/webview/common/portMapping';
import { getWebviewThemeData } from 'vs/workbench/contrib/webview/common/themeing';
import { Webview, WebviewContentOptions, WebviewOptions, WebviewResourceScheme } from 'vs/workbench/contrib/webview/common/webview';
import { registerFileProtocol } from 'vs/workbench/contrib/webview/electron-browser/webviewProtocols';
import { areWebviewInputOptionsEqual } from '../browser/webviewEditorService';
import { WebviewFindWidget } from '../browser/webviewFindWidget';
import { getWebviewThemeData } from 'vs/workbench/contrib/webview/common/themeing';
export interface WebviewPortMapping {
readonly port: number;
......@@ -141,88 +139,22 @@ class WebviewProtocolProvider extends Disposable {
class WebviewPortMappingProvider extends Disposable {
private readonly _tunnels = new Map<number, Promise<RemoteTunnel>>();
private readonly _manager: WebviewPortMappingManager;
constructor(
session: WebviewSession,
extensionLocation: URI | undefined,
mappings: () => ReadonlyArray<modes.IWebviewPortMapping>,
private readonly tunnelService: ITunnelService,
extensionId: ExtensionIdentifier | undefined,
@ITelemetryService telemetryService: ITelemetryService
tunnelService: ITunnelService,
) {
super();
this._manager = this._register(new WebviewPortMappingManager(extensionLocation, mappings, tunnelService));
let hasLogged = false;
session.onBeforeRequest(async (details) => {
const uri = URI.parse(details.url);
if (uri.scheme !== 'http' && uri.scheme !== 'https') {
return undefined;
}
const localhostMatch = /^localhost:(\d+)$/.exec(uri.authority);
if (localhostMatch) {
if (!hasLogged && extensionId) {
hasLogged = true;
/* __GDPR__
"webview.accessLocalhost" : {
"extension" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
}
*/
telemetryService.publicLog('webview.accessLocalhost', { extension: extensionId.value });
}
const port = +localhostMatch[1];
for (const mapping of mappings()) {
if (mapping.webviewPort === port) {
if (extensionLocation && extensionLocation.scheme === REMOTE_HOST_SCHEME) {
const tunnel = await this.getOrCreateTunnel(mapping.extensionHostPort);
if (tunnel) {
return {
redirectURL: details.url.replace(
new RegExp(`^${uri.scheme}://localhost:${mapping.webviewPort}/`),
`${uri.scheme}://localhost:${tunnel.tunnelLocalPort}/`)
};
}
}
if (mapping.webviewPort !== mapping.extensionHostPort) {
return {
redirectURL: details.url.replace(
new RegExp(`^${uri.scheme}://localhost:${mapping.webviewPort}/`),
`${uri.scheme}://localhost:${mapping.extensionHostPort}/`)
};
}
}
}
}
return undefined;
session.onBeforeRequest(async details => {
const redirect = await this._manager.getRedirect(details.url);
return redirect ? { redirectURL: redirect } : undefined;
});
}
dispose() {
super.dispose();
for (const tunnel of this._tunnels.values()) {
tunnel.then(tunnel => tunnel.dispose());
}
this._tunnels.clear();
}
private getOrCreateTunnel(remotePort: number): Promise<RemoteTunnel> | undefined {
const existing = this._tunnels.get(remotePort);
if (existing) {
return existing;
}
const tunnel = this.tunnelService.openTunnel(remotePort);
if (tunnel) {
this._tunnels.set(remotePort, tunnel);
}
return tunnel;
}
}
class SvgBlocker extends Disposable {
......@@ -370,10 +302,8 @@ export class WebviewElement extends Disposable implements Webview {
contentOptions: WebviewContentOptions,
@IInstantiationService instantiationService: IInstantiationService,
@IThemeService themeService: IThemeService,
@IEnvironmentService environmentService: IEnvironmentService,
@IFileService fileService: IFileService,
@ITunnelService tunnelService: ITunnelService,
@ITelemetryService telemetryService: ITelemetryService,
@IConfigurationService private readonly _configurationService: IConfigurationService,
) {
super();
......@@ -420,8 +350,6 @@ export class WebviewElement extends Disposable implements Webview {
_options.extension ? _options.extension.location : undefined,
() => (this.content.options.portMappings || []),
tunnelService,
_options.extension ? _options.extension.id : undefined,
telemetryService
));
if (!this._options.allowSvgs) {
......
......@@ -151,7 +151,7 @@ const extensionPacks: ExtensionSuggestion[] = [
// { name: localize('welcomePage.go', "Go"), id: 'lukehoban.go' },
{ name: localize('welcomePage.php', "PHP"), id: 'felixfbecker.php-pack' },
{ name: localize('welcomePage.azure', "Azure"), title: localize('welcomePage.showAzureExtensions', "Show Azure extensions"), id: 'workbench.extensions.action.showAzureExtensions', isCommand: true },
{ name: localize('welcomePage.docker', "Docker"), id: 'peterjausovec.vscode-docker' },
{ name: localize('welcomePage.docker', "Docker"), id: 'ms-azuretools.vscode-docker' },
];
const keymapExtensions: ExtensionSuggestion[] = [
......
......@@ -591,34 +591,6 @@ import product from 'vs/platform/product/node/product';
'default': false,
'description': nls.localize('closeWhenEmpty', "Controls whether closing the last editor should also close the window. This setting only applies for windows that do not show folders.")
},
'window.menuBarVisibility': {
'type': 'string',
'enum': ['default', 'visible', 'toggle', 'hidden'],
'enumDescriptions': [
nls.localize('window.menuBarVisibility.default', "Menu is only hidden in full screen mode."),
nls.localize('window.menuBarVisibility.visible', "Menu is always visible even in full screen mode."),
nls.localize('window.menuBarVisibility.toggle', "Menu is hidden but can be displayed via Alt key."),
nls.localize('window.menuBarVisibility.hidden', "Menu is always hidden.")
],
'default': 'default',
'scope': ConfigurationScope.APPLICATION,
'description': nls.localize('menuBarVisibility', "Control the visibility of the menu bar. A setting of 'toggle' means that the menu bar is hidden and a single press of the Alt key will show it. By default, the menu bar will be visible, unless the window is full screen."),
'included': isWindows || isLinux
},
'window.enableMenuBarMnemonics': {
'type': 'boolean',
'default': true,
'scope': ConfigurationScope.APPLICATION,
'description': nls.localize('enableMenuBarMnemonics', "If enabled, the main menus can be opened via Alt-key shortcuts. Disabling mnemonics allows to bind these Alt-key shortcuts to editor commands instead."),
'included': isWindows || isLinux
},
'window.disableCustomMenuBarAltFocus': {
'type': 'boolean',
'default': false,
'scope': ConfigurationScope.APPLICATION,
'markdownDescription': nls.localize('disableCustomMenuBarAltFocus', "If enabled, disables the ability to focus the menu bar with the Alt-key when not set to toggle."),
'included': isWindows || isLinux
},
'window.autoDetectHighContrast': {
'type': 'boolean',
'default': true,
......
......@@ -19,8 +19,9 @@ import { AbstractVariableResolverService } from 'vs/workbench/services/configura
import { isCodeEditor } from 'vs/editor/browser/editorBrowser';
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
import { IQuickInputService, IInputOptions, IQuickPickItem, IPickOptions } from 'vs/platform/quickinput/common/quickInput';
import { ConfiguredInput } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
import { ConfiguredInput, IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
import { IProcessEnvironment } from 'vs/base/common/platform';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
export abstract class BaseConfigurationResolverService extends AbstractVariableResolverService {
......@@ -304,4 +305,6 @@ export class ConfigurationResolverService extends BaseConfigurationResolverServi
) {
super(environmentService.configuration.userEnv, editorService, environmentService, configurationService, commandService, workspaceContextService, quickInputService);
}
}
\ No newline at end of file
}
registerSingleton(IConfigurationResolverService, ConfigurationResolverService, true);
\ No newline at end of file
......@@ -69,7 +69,7 @@ export class BrowserWorkbenchEnvironmentService implements IEnvironmentService {
this.configuration.remoteAuthority = configuration.remoteAuthority;
this.appSettingsHome = joinPath(URI.revive(configuration.userDataUri), 'User');
this.appSettingsHome = joinPath(URI.revive(JSON.parse(document.getElementById('vscode-remote-user-data-uri')!.getAttribute('data-settings')!)), 'User');
this.settingsResource = joinPath(this.appSettingsHome, 'settings.json');
this.keybindingsResource = joinPath(this.appSettingsHome, 'keybindings.json');
this.keyboardLayoutResource = joinPath(this.appSettingsHome, 'keyboardLayout.json');
......
......@@ -20,6 +20,7 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten
import { deserializeSearchError, FileMatch, ICachedSearchStats, IFileMatch, IFileQuery, IFileSearchStats, IFolderQuery, IProgressMessage, ISearchComplete, ISearchEngineStats, ISearchProgressItem, ISearchQuery, ISearchResultProvider, ISearchService, ITextQuery, pathIncludedInQuery, QueryType, SearchError, SearchErrorCode, SearchProviderType, isFileMatch, isProgressMessage } from 'vs/workbench/services/search/common/search';
import { addContextToEditorMatches, editorMatchesToTextSearchResults } from 'vs/workbench/services/search/common/searchHelpers';
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
export class SearchService extends Disposable implements ISearchService {
_serviceBrand: any;
......@@ -421,3 +422,4 @@ export class RemoteSearchService extends SearchService {
}
}
registerSingleton(ISearchService, RemoteSearchService, true);
......@@ -796,9 +796,9 @@ suite('ExtHostLanguageFeatureCommands', function () {
}));
await rpcProtocol.sync();
let value = await commands.executeCommand<vscode.SelectionRange[][]>('vscode.executeSelectionRangeProvider', model.uri, [new types.Position(0, 10)]);
let value = await commands.executeCommand<vscode.SelectionRange[]>('vscode.executeSelectionRangeProvider', model.uri, [new types.Position(0, 10)]);
assert.equal(value.length, 1);
assert.ok(value[0].length >= 2);
assert.ok(value[0].parent);
});
});
......@@ -71,6 +71,8 @@ import { IRequestService } from 'vs/platform/request/node/request';
import { RequestService } from 'vs/platform/request/electron-browser/requestService';
import { LifecycleService } from 'vs/platform/lifecycle/electron-browser/lifecycleService';
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { DialogService } from 'vs/platform/dialogs/browser/dialogService';
import { ILocalizationsService } from 'vs/platform/localizations/common/localizations';
import { LocalizationsService } from 'vs/platform/localizations/electron-browser/localizationsService';
import { ISharedProcessService, SharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService';
......@@ -90,8 +92,6 @@ import { IURLService } from 'vs/platform/url/common/url';
import { RelayURLService } from 'vs/platform/url/electron-browser/urlService';
import { ITunnelService } from 'vs/platform/remote/common/tunnel';
import { TunnelService } from 'vs/workbench/services/remote/node/tunnelService';
import { ConfigurationResolverService } from 'vs/workbench/services/configurationResolver/electron-browser/configurationResolverService';
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
import { ICredentialsService } from 'vs/platform/credentials/common/credentials';
import { KeytarCredentialsService } from 'vs/platform/credentials/node/credentialsService';
......@@ -136,7 +136,9 @@ import 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl';
import 'vs/workbench/services/notification/common/notificationService';
import 'vs/workbench/services/window/electron-browser/windowService';
import 'vs/workbench/services/telemetry/electron-browser/telemetryService';
import 'vs/workbench/services/configurationResolver/electron-browser/configurationResolverService';
registerSingleton(IDialogService, DialogService, true);
registerSingleton(IMenuService, MenuService, true);
registerSingleton(IListService, ListService, true);
registerSingleton(IOpenerService, OpenerService, true);
......@@ -163,7 +165,6 @@ registerSingleton(IWorkspacesService, WorkspacesService);
registerSingleton(IMenubarService, MenubarService);
registerSingleton(IURLService, RelayURLService);
registerSingleton(ITunnelService, TunnelService, true);
registerSingleton(IConfigurationResolverService, ConfigurationResolverService, true);
registerSingleton(ICredentialsService, KeytarCredentialsService, true);
//#endregion
......@@ -203,6 +204,7 @@ registerSingleton(IPreferencesSearchService, PreferencesSearchService, true);
// Logs
import 'vs/workbench/contrib/logs/common/logs.contribution';
import 'vs/workbench/contrib/logs/electron-browser/logs.contribution';
// Quick Open Handlers
import 'vs/workbench/contrib/quickopen/browser/quickopen.contribution';
......@@ -276,6 +278,7 @@ import { ITaskService } from 'vs/workbench/contrib/tasks/common/taskService';
registerSingleton(ITaskService, TaskService, true);
// Remote
import 'vs/workbench/contrib/remote/common/remote.contribution';
import 'vs/workbench/contrib/remote/electron-browser/remote.contribution';
// Emmet
......
......@@ -6,16 +6,21 @@
import 'vs/workbench/workbench.web.main';
import { main } from 'vs/workbench/browser/web.main';
import { UriComponents } from 'vs/base/common/uri';
import { Event } from 'vs/base/common/event';
export interface IWorkbenchConstructionOptions {
remoteAuthority: string;
userDataUri: UriComponents;
webviewEndpoint?: string;
folderUri?: UriComponents;
workspaceUri?: UriComponents;
userData?: {
read(key: string): Promise<string>;
write(key: string, value: string): Promise<void>;
onDidChange: Event<string>;
};
}
function create(domElement: HTMLElement, options: IWorkbenchConstructionOptions): Promise<void> {
......
......@@ -9,7 +9,6 @@ import 'vs/editor/editor.all';
import 'vs/workbench/api/browser/extensionHost.contribution';
// import 'vs/workbench/electron-browser/main.contribution';
import 'vs/workbench/browser/workbench.contribution';
import 'vs/workbench/browser/web.main';
......@@ -63,14 +62,15 @@ import { ITextResourceConfigurationService } from 'vs/editor/common/services/res
import { TextResourceConfigurationService } from 'vs/editor/common/services/resourceConfigurationImpl';
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
import { BrowserAccessibilityService } from 'vs/platform/accessibility/common/accessibilityService';
import { IContextViewService, IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { ContextMenuService } from 'vs/platform/contextview/browser/contextMenuService';
// import { IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ContextViewService } from 'vs/platform/contextview/browser/contextViewService';
// import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService';
// import { IRequestService } from 'vs/platform/request/node/request';
// import { RequestService } from 'vs/platform/request/electron-browser/requestService';
import { BrowserLifecycleService } from 'vs/platform/lifecycle/browser/lifecycleService';
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { DialogService } from 'vs/platform/dialogs/browser/dialogService';
// import { ILocalizationsService } from 'vs/platform/localizations/common/localizations';
// import { LocalizationsService } from 'vs/platform/localizations/electron-browser/localizationsService';
// import { ISharedProcessService, SharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService';
......@@ -90,11 +90,8 @@ import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
// import { RelayURLService } from 'vs/platform/url/electron-browser/urlService';
// import { ITunnelService } from 'vs/platform/remote/common/tunnel';
// import { TunnelService } from 'vs/workbench/services/remote/node/tunnelService';
import { ConfigurationResolverService } from 'vs/workbench/services/configurationResolver/browser/configurationResolverService';
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
import { ISearchService } from 'vs/workbench/services/search/common/search';
import { RemoteSearchService } from 'vs/workbench/services/search/common/searchService';
import 'vs/platform/dialogs/browser/dialogService';
// import { ICredentialsService } from 'vs/platform/credentials/common/credentials';
// import { KeytarCredentialsService } from 'vs/platform/credentials/node/credentialsService';
import 'vs/workbench/services/bulkEdit/browser/bulkEditService';
// import 'vs/workbench/services/integrity/node/integrityService';
import 'vs/workbench/services/keybinding/common/keybindingEditing';
......@@ -102,7 +99,7 @@ import 'vs/workbench/services/textMate/browser/textMateService';
// import 'vs/workbench/services/workspace/electron-browser/workspaceEditingService';
// import 'vs/workbench/services/extensions/electron-browser/inactiveExtensionUrlHandler';
import 'vs/workbench/services/decorations/browser/decorationsService';
// import 'vs/workbench/services/search/node/searchService';
import 'vs/workbench/services/search/common/searchService';
import 'vs/workbench/services/progress/browser/progressService';
import 'vs/workbench/services/editor/browser/codeEditorService';
// import 'vs/workbench/services/extensions/electron-browser/extensionHostDebugService';
......@@ -135,9 +132,13 @@ import 'vs/workbench/services/label/common/labelService';
import 'vs/workbench/services/notification/common/notificationService';
// import 'vs/workbench/services/window/electron-browser/windowService';
// import 'vs/workbench/services/telemetry/electron-browser/telemetryService';
import 'vs/workbench/services/configurationResolver/browser/configurationResolverService';
import { IContextViewService, IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { ContextMenuService } from 'vs/platform/contextview/browser/contextMenuService';
import 'vs/workbench/browser/web.simpleservices';
registerSingleton(IDialogService, DialogService, true);
registerSingleton(IMenuService, MenuService, true);
registerSingleton(IListService, ListService, true);
registerSingleton(IOpenerService, OpenerService, true);
......@@ -163,9 +164,9 @@ registerSingleton(ILifecycleService, BrowserLifecycleService);
// registerSingleton(IWorkspacesService, WorkspacesService);
// registerSingleton(IMenubarService, MenubarService);
// registerSingleton(IURLService, RelayURLService);
registerSingleton(ISearchService, RemoteSearchService, true);
// registerSingleton(ITunnelService, TunnelService, true);
// registerSingleton(ICredentialsService, KeytarCredentialsService, true);
registerSingleton(IContextMenuService, ContextMenuService);
registerSingleton(IConfigurationResolverService, ConfigurationResolverService, true);
//#endregion
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册