Merge from vscode e3b9b8eefc062d68ba8a4b6a817162d132f3b533 (#6932)

* Merge from vscode e3b9b8eefc062d68ba8a4b6a817162d132f3b533

* skip failing test

* add comment
This commit is contained in:
Anthony Dresser
2019-08-24 00:19:48 -07:00
committed by GitHub
parent 023d06d114
commit 92a3acbfe8
77 changed files with 992 additions and 559 deletions

View File

@@ -1,6 +1,3 @@
pool:
vmImage: 'Ubuntu-16.04'
trigger:
branches:
include: ['master', 'release/*']

View File

@@ -13,18 +13,28 @@ steps:
inputs:
versionSpec: "10.15.1"
- task: AzureKeyVault@1
displayName: 'Azure Key Vault: Get Secrets'
inputs:
azureSubscription: 'vscode-builds-subscription'
KeyVaultName: vscode
- script: |
set -e
cat << EOF > ~/.netrc
machine github.com
login vscode
password $(github-distro-mixin-password)
EOF
git config user.email "vscode@microsoft.com"
git config user.name "VSCode"
git checkout origin/ben/electron-test
git checkout origin/electron-6.0.x
git merge origin/master
# Push master branch into exploration branch
git push origin HEAD:ben/electron-test
git push origin HEAD:electron-6.0.x
displayName: Sync & Merge Exploration

View File

@@ -143,8 +143,8 @@ trigger: none
pr: none
schedules:
- cron: "10 5 * * Mon-Fri"
displayName: Mon-Fri at 7:10
- cron: "0 5 * * Mon-Fri"
displayName: Mon-Fri at 7:00
branches:
include:
- master

View File

@@ -129,6 +129,13 @@
"type": "string",
"description": "The service you want to work on."
},
"runServices": {
"type": "array",
"description": "An array of services that should be started and stopped.",
"items": {
"type": "string"
}
},
"workspaceFolder": {
"type": "string",
"description": "The path of the workspace folder inside the container."
@@ -178,4 +185,4 @@
"$ref": "#/definitions/devContainerCommon"
}
]
}
}

View File

@@ -11,14 +11,9 @@ VSCODE_PATH="$(dirname "$(dirname "$(realpath "$0")")")"
ELECTRON="$VSCODE_PATH/$NAME.exe"
if grep -qi Microsoft /proc/version; then
# in a wsl shell
if [ "$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
WSL_BUILD=$(uname -r | sed -E 's/^[0-9.]+-([0-9]+)-Microsoft|([0-9]+).([0-9]+).([0-9]+)-microsoft-standard|.*/\1\2\3\4/')
if [ -z "$WSL_BUILD" ]; then
WSL_BUILD=0
fi
if [ $WSL_BUILD -ge 17063 ]; then
@@ -30,7 +25,18 @@ if grep -qi Microsoft /proc/version; then
# use the Remote WSL extension if installed
WSL_EXT_ID="ms-vscode-remote.remote-wsl"
WSL_EXT_WLOC=$(ELECTRON_RUN_AS_NODE=1 "$ELECTRON" "$CLI" --locate-extension $WSL_EXT_ID)
if [ $WSL_BUILD -ge 41955 ]; then
# WSL2 in workaround for https://github.com/microsoft/WSL/issues/4337
CWD="$(pwd)"
cd "$VSCODE_PATH"
cmd.exe /C ".\\bin\\$APP_NAME.cmd --locate-extension $WSL_EXT_ID >remote-wsl-loc.txt"
WSL_EXT_WLOC="$(cat ./remote-wsl-loc.txt)"
rm remote-wsl-loc.txt
cd "$CWD"
else
WSL_EXT_WLOC=$(ELECTRON_RUN_AS_NODE=1 "$ELECTRON" "$CLI" --locate-extension $WSL_EXT_ID)
fi
if [ -n "$WSL_EXT_WLOC" ]; then
# replace \r\n with \n in WSL_EXT_WLOC
WSL_CODE=$(wslpath -u "${WSL_EXT_WLOC%%[[:cntrl:]]}")/scripts/wslCode.sh

View File

@@ -8,14 +8,6 @@ import { CharCode } from 'vs/base/common/charCode';
import { Iterator, IteratorResult, FIN } from './iterator';
export function fromArray<T>(array: readonly T[]): Set<T> {
const result = new Set<T>();
for (const element of array) {
result.add(element);
}
return result;
}
export function values<V = any>(set: Set<V>): V[];
export function values<K = any, V = any>(map: Map<K, V>): V[];
export function values<V>(forEachable: { forEach(callback: (value: V, ...more: any[]) => any): void }): V[] {

View File

@@ -405,42 +405,53 @@ export class Client<TContext = string> extends IPCClient<TContext> {
/**
* Will ensure no messages are lost if there are no event listeners.
*/
export function createBufferedEvent<T>(source: Event<T>): Event<T> {
let emitter: Emitter<T>;
let hasListeners = false;
let isDeliveringMessages = false;
let bufferedMessages: T[] = [];
export class BufferedEmitter<T> {
private _emitter: Emitter<T>;
public readonly event: Event<T>;
const deliverMessages = () => {
if (isDeliveringMessages) {
private _hasListeners = false;
private _isDeliveringMessages = false;
private _bufferedMessages: T[] = [];
constructor() {
this._emitter = new Emitter<T>({
onFirstListenerAdd: () => {
this._hasListeners = true;
// it is important to deliver these messages after this call, but before
// other messages have a chance to be received (to guarantee in order delivery)
// that's why we're using here nextTick and not other types of timeouts
process.nextTick(() => this._deliverMessages);
},
onLastListenerRemove: () => {
this._hasListeners = false;
}
});
this.event = this._emitter.event;
}
private _deliverMessages(): void {
if (this._isDeliveringMessages) {
return;
}
isDeliveringMessages = true;
while (hasListeners && bufferedMessages.length > 0) {
emitter.fire(bufferedMessages.shift()!);
this._isDeliveringMessages = true;
while (this._hasListeners && this._bufferedMessages.length > 0) {
this._emitter.fire(this._bufferedMessages.shift()!);
}
isDeliveringMessages = false;
};
this._isDeliveringMessages = false;
}
source((e: T) => {
bufferedMessages.push(e);
deliverMessages();
});
emitter = new Emitter<T>({
onFirstListenerAdd: () => {
hasListeners = true;
// it is important to deliver these messages after this call, but before
// other messages have a chance to be received (to guarantee in order delivery)
// that's why we're using here nextTick and not other types of timeouts
process.nextTick(deliverMessages);
},
onLastListenerRemove: () => {
hasListeners = false;
public fire(event: T): void {
if (this._hasListeners) {
this._emitter.fire(event);
} else {
this._bufferedMessages.push(event);
}
});
}
return emitter.event;
public flushBuffer(): void {
this._bufferedMessages = [];
}
}
class QueueElement<T> {
@@ -530,20 +541,20 @@ export class PersistentProtocol implements IMessagePassingProtocol {
private _socketReader: ProtocolReader;
private _socketDisposables: IDisposable[];
private _onControlMessage = new Emitter<VSBuffer>();
readonly onControlMessage: Event<VSBuffer> = createBufferedEvent(this._onControlMessage.event);
private readonly _onControlMessage = new BufferedEmitter<VSBuffer>();
readonly onControlMessage: Event<VSBuffer> = this._onControlMessage.event;
private _onMessage = new Emitter<VSBuffer>();
readonly onMessage: Event<VSBuffer> = createBufferedEvent(this._onMessage.event);
private readonly _onMessage = new BufferedEmitter<VSBuffer>();
readonly onMessage: Event<VSBuffer> = this._onMessage.event;
private _onClose = new Emitter<void>();
readonly onClose: Event<void> = createBufferedEvent(this._onClose.event);
private readonly _onClose = new BufferedEmitter<void>();
readonly onClose: Event<void> = this._onClose.event;
private _onSocketClose = new Emitter<void>();
readonly onSocketClose: Event<void> = createBufferedEvent(this._onSocketClose.event);
private readonly _onSocketClose = new BufferedEmitter<void>();
readonly onSocketClose: Event<void> = this._onSocketClose.event;
private _onSocketTimeout = new Emitter<void>();
readonly onSocketTimeout: Event<void> = createBufferedEvent(this._onSocketTimeout.event);
private readonly _onSocketTimeout = new BufferedEmitter<void>();
readonly onSocketTimeout: Event<void> = this._onSocketTimeout.event;
public get unacknowledgedCount(): number {
return this._outgoingMsgId - this._outgoingAckId;
@@ -656,6 +667,10 @@ export class PersistentProtocol implements IMessagePassingProtocol {
this._isReconnecting = true;
this._socketDisposables = dispose(this._socketDisposables);
this._onControlMessage.flushBuffer();
this._onSocketClose.flushBuffer();
this._onSocketTimeout.flushBuffer();
this._socket.dispose();
this._socket = socket;
this._socketWriter = new ProtocolWriter(this._socket);

View File

@@ -10,7 +10,6 @@ import { ITree, IActionProvider } from 'vs/base/parts/tree/browser/tree';
import { IconLabel, IIconLabelValueOptions } from 'vs/base/browser/ui/iconLabel/iconLabel';
import { IQuickNavigateConfiguration, IModel, IDataSource, IFilter, IAccessiblityProvider, IRenderer, IRunner, Mode, IEntryRunContext } from 'vs/base/parts/quickopen/common/quickOpen';
import { IAction, IActionRunner } from 'vs/base/common/actions';
import { compareAnything } from 'vs/base/common/comparers';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel';
import * as DOM from 'vs/base/browser/dom';
@@ -576,37 +575,3 @@ export class QuickOpenModel implements
return entry.run(mode, context);
}
}
/**
* A good default sort implementation for quick open entries respecting highlight information
* as well as associated resources.
*/
export function compareEntries(elementA: QuickOpenEntry, elementB: QuickOpenEntry, lookFor: string): number {
// Give matches with label highlights higher priority over
// those with only description highlights
const labelHighlightsA = elementA.getHighlights()[0] || [];
const labelHighlightsB = elementB.getHighlights()[0] || [];
if (labelHighlightsA.length && !labelHighlightsB.length) {
return -1;
}
if (!labelHighlightsA.length && labelHighlightsB.length) {
return 1;
}
// Fallback to the full path if labels are identical and we have associated resources
let nameA = elementA.getLabel()!;
let nameB = elementB.getLabel()!;
if (nameA === nameB) {
const resourceA = elementA.getResource();
const resourceB = elementB.getResource();
if (resourceA && resourceB) {
nameA = resourceA.fsPath;
nameB = resourceB.fsPath;
}
}
return compareAnything(nameA, nameB, lookFor);
}

View File

@@ -4,29 +4,32 @@
<head>
<meta charset="utf-8" />
<link rel="icon" href="/favicon.ico" type="image/x-icon" />
<!-- Disable pinch zooming -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
<meta http-equiv="Content-Security-Policy"
content="default-src 'none'; img-src 'self' https: data: blob:; media-src 'none'; frame-src 'self' {{WEBVIEW_ENDPOINT}} https://*.vscode-webview-test.com; script-src 'self' https://az416426.vo.msecnd.net 'unsafe-eval' https:; style-src 'self' 'unsafe-inline'; connect-src 'self' ws: wss: https:; font-src 'self' blob:;">
<!-- Content Security Policy -->
<meta
http-equiv="Content-Security-Policy"
content="default-src 'none'; img-src 'self' https: data: blob:; media-src 'none'; frame-src 'self' {{WEBVIEW_ENDPOINT}} https://*.vscode-webview-test.com; script-src 'self' https://az416426.vo.msecnd.net 'unsafe-eval' https:; style-src 'self' 'unsafe-inline'; connect-src 'self' ws: wss: https:; font-src 'self' blob:;"
>
<!-- Workbench Configuration -->
<meta id="vscode-workbench-web-configuration" data-settings="{{WORKBENCH_WEB_CONGIGURATION}}">
<!-- Workaround to pass remote user data uri-->
<!-- Workarounds/Hacks (remote user data uri, product configuration ) -->
<meta id="vscode-remote-user-data-uri" data-settings="{{REMOTE_USER_DATA_URI}}">
<!-- Workaround to pass product configuration-->
<meta id="vscode-remote-product-configuration" data-settings="{{PRODUCT_CONFIGURATION}}">
<!-- Workbench Icon/CSS -->
<link rel="icon" href="/favicon.ico" type="image/x-icon" />
<link data-name="vs/workbench/workbench.web.api" rel="stylesheet" href="./static/out/vs/workbench/workbench.web.api.css">
</head>
<body aria-label="">
</body>
<!-- Require our AMD loader -->
<!-- Startup (do not modify order of script tags!) -->
<script src="./static/out/vs/loader.js"></script>
<!-- Startup via workbench.js -->
<script src="./static/out/vs/workbench/workbench.web.api.nls.js"></script>
<script src="./static/out/vs/code/browser/workbench/workbench.js"></script>
</html>

View File

@@ -3,11 +3,15 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
//@ts-check
'use strict';
(function () {
require.config({
/** @type any */
const amdLoader = require;
amdLoader.config({
baseUrl: `${window.location.origin}/static/out`,
paths: {
'vscode-textmate': `${window.location.origin}/static/node_modules/vscode-textmate/release/main`,
@@ -20,7 +24,7 @@
}
});
require(['vs/workbench/workbench.web.api'], function (api) {
amdLoader(['vs/workbench/workbench.web.api'], function (api) {
const options = JSON.parse(document.getElementById('vscode-workbench-web-configuration').getAttribute('data-settings'));
api.create(document.body, options);

View File

@@ -14,7 +14,10 @@ const bootstrapWindow = require('../../../../bootstrap-window');
// Setup shell environment
process['lazyEnv'] = getLazyEnv();
// Load workbench main
// Load workbench main JS, CSS and NLS all in parallel. This is an
// optimization to prevent a waterfall of loading to happen, because
// we know for a fact that workbench.desktop.main will depend on
// the related CSS and NLS counterparts.
bootstrapWindow.load([
'vs/workbench/workbench.desktop.main',
'vs/nls!vs/workbench/workbench.desktop.main',

View File

@@ -40,8 +40,10 @@ import { ServiceCollection } from 'vs/platform/instantiation/common/serviceColle
import { INotificationService } from 'vs/platform/notification/common/notification';
import { defaultInsertColor, defaultRemoveColor, diffBorder, diffInserted, diffInsertedOutline, diffRemoved, diffRemovedOutline, scrollbarShadow } from 'vs/platform/theme/common/colorRegistry';
import { ITheme, IThemeService, getThemeTypeSelector, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
// {{SQL CARBON EDIT}}
import { reverseLineChanges } from 'sql/editor/browser/diffEditorHelper';
import { reverseLineChanges } from 'sql/editor/browser/diffEditorHelper'; // {{SQL CARBON EDIT}}
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IDiffLinesChange, InlineDiffMargin } from 'vs/editor/browser/widget/inlineDiffMargin';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
interface IEditorDiffDecorations {
decorations: IModelDeltaDecoration[];
@@ -49,7 +51,7 @@ interface IEditorDiffDecorations {
}
interface IEditorDiffDecorationsWithZones extends IEditorDiffDecorations {
zones: editorBrowser.IViewZone[];
zones: IMyViewZone[];
}
interface IEditorsDiffDecorationsWithZones {
@@ -58,8 +60,8 @@ interface IEditorsDiffDecorationsWithZones {
}
interface IEditorsZones {
original: editorBrowser.IViewZone[];
modified: editorBrowser.IViewZone[];
original: IMyViewZone[];
modified: IMyViewZone[];
}
interface IDiffEditorWidgetStyle {
@@ -73,11 +75,16 @@ interface IDiffEditorWidgetStyle {
class VisualEditorState {
private _zones: string[];
private inlineDiffMargins: InlineDiffMargin[];
private _zonesMap: { [zoneId: string]: boolean; };
private _decorations: string[];
constructor() {
constructor(
private _contextMenuService: IContextMenuService,
private _clipboardService: IClipboardService
) {
this._zones = [];
this.inlineDiffMargins = [];
this._zonesMap = {};
this._decorations = [];
}
@@ -111,13 +118,22 @@ class VisualEditorState {
for (let i = 0, length = this._zones.length; i < length; i++) {
viewChangeAccessor.removeZone(this._zones[i]);
}
for (let i = 0, length = this.inlineDiffMargins.length; i < length; i++) {
this.inlineDiffMargins[i].dispose();
}
this._zones = [];
this._zonesMap = {};
this.inlineDiffMargins = [];
for (let i = 0, length = newDecorations.zones.length; i < length; i++) {
newDecorations.zones[i].suppressMouseDown = true;
let zoneId = viewChangeAccessor.addZone(newDecorations.zones[i]);
const viewZone = <editorBrowser.IViewZone>newDecorations.zones[i];
viewZone.suppressMouseDown = false;
let zoneId = viewChangeAccessor.addZone(viewZone);
this._zones.push(zoneId);
this._zonesMap[String(zoneId)] = true;
if (newDecorations.zones[i].diff && viewZone.marginDomNode) {
this.inlineDiffMargins.push(new InlineDiffMargin(viewZone.marginDomNode, editor, newDecorations.zones[i].diff!, this._contextMenuService, this._clipboardService));
}
}
});
@@ -207,7 +223,9 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
@IInstantiationService instantiationService: IInstantiationService,
@ICodeEditorService codeEditorService: ICodeEditorService,
@IThemeService themeService: IThemeService,
@INotificationService notificationService: INotificationService
@INotificationService notificationService: INotificationService,
@IContextMenuService contextMenuService: IContextMenuService,
@IClipboardService clipboardService: IClipboardService
) {
super();
@@ -289,8 +307,8 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
this._currentlyChangingViewZones = false;
this._diffComputationToken = 0;
this._originalEditorState = new VisualEditorState();
this._modifiedEditorState = new VisualEditorState();
this._originalEditorState = new VisualEditorState(contextMenuService, clipboardService);
this._modifiedEditorState = new VisualEditorState(contextMenuService, clipboardService);
this._isVisible = true;
this._isHandlingScrollEvent = false;
@@ -1278,6 +1296,7 @@ interface IMyViewZone {
minWidthInPx?: number;
domNode: HTMLElement | null;
marginDomNode?: HTMLElement | null;
diff?: IDiffLinesChange;
}
class ForeignViewZonesIterator {
@@ -1489,12 +1508,12 @@ abstract class ViewZonesComputer {
};
}
private static _ensureDomNodes(zones: IMyViewZone[]): editorBrowser.IViewZone[] {
private static _ensureDomNodes(zones: IMyViewZone[]): IMyViewZone[] {
return zones.map((z) => {
if (!z.domNode) {
z.domNode = createFakeLinesDiv();
}
return <editorBrowser.IViewZone>z;
return z;
});
}
@@ -1997,8 +2016,10 @@ class InlineViewZonesComputer extends ViewZonesComputer {
let lineHeight = this.modifiedEditorConfiguration.lineHeight;
const typicalHalfwidthCharacterWidth = this.modifiedEditorConfiguration.fontInfo.typicalHalfwidthCharacterWidth;
let maxCharsPerLine = 0;
const originalContent: string[] = [];
for (let lineNumber = lineChange.originalStartLineNumber; lineNumber <= lineChange.originalEndLineNumber; lineNumber++) {
maxCharsPerLine = Math.max(maxCharsPerLine, this._renderOriginalLine(lineNumber - lineChange.originalStartLineNumber, this.originalModel, this.modifiedEditorConfiguration, this.modifiedEditorTabSize, lineNumber, decorations, sb));
originalContent.push(this.originalModel.getLineContent(lineNumber));
if (this.renderIndicators) {
let index = lineNumber - lineChange.originalStartLineNumber;
@@ -2025,7 +2046,14 @@ class InlineViewZonesComputer extends ViewZonesComputer {
heightInLines: lineChangeOriginalLength,
minWidthInPx: (maxCharsPerLine * typicalHalfwidthCharacterWidth),
domNode: domNode,
marginDomNode: marginDomNode
marginDomNode: marginDomNode,
diff: {
originalStartLineNumber: lineChange.originalStartLineNumber,
originalEndLineNumber: lineChange.originalEndLineNumber,
modifiedStartLineNumber: lineChange.modifiedStartLineNumber,
modifiedEndLineNumber: lineChange.modifiedEndLineNumber,
originalContent: originalContent
}
};
}

View File

@@ -16,6 +16,8 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
export class EmbeddedCodeEditorWidget extends CodeEditorWidget {
@@ -74,9 +76,11 @@ export class EmbeddedDiffEditorWidget extends DiffEditorWidget {
@IInstantiationService instantiationService: IInstantiationService,
@ICodeEditorService codeEditorService: ICodeEditorService,
@IThemeService themeService: IThemeService,
@INotificationService notificationService: INotificationService
@INotificationService notificationService: INotificationService,
@IContextMenuService contextMenuService: IContextMenuService,
@IClipboardService clipboardService: IClipboardService
) {
super(domElement, parentEditor.getRawConfiguration(), editorWorkerService, contextKeyService, instantiationService, codeEditorService, themeService, notificationService);
super(domElement, parentEditor.getRawConfiguration(), editorWorkerService, contextKeyService, instantiationService, codeEditorService, themeService, notificationService, contextMenuService, clipboardService);
this._parentEditor = parentEditor;
this._overwriteOptions = options;

View File

@@ -0,0 +1,139 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import * as dom from 'vs/base/browser/dom';
import { Action } from 'vs/base/common/actions';
import { Disposable } from 'vs/base/common/lifecycle';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { Range } from 'vs/editor/common/core/range';
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
export interface IDiffLinesChange {
readonly originalStartLineNumber: number;
readonly originalEndLineNumber: number;
readonly modifiedStartLineNumber: number;
readonly modifiedEndLineNumber: number;
readonly originalContent: string[];
}
export class InlineDiffMargin extends Disposable {
private readonly _lightBulb: HTMLElement;
constructor(
marginDomNode: HTMLElement,
public editor: CodeEditorWidget,
public diff: IDiffLinesChange,
private _contextMenuService: IContextMenuService,
private _clipboardService: IClipboardService
) {
super();
// make sure the diff margin shows above overlay.
marginDomNode.style.zIndex = '10';
this._lightBulb = document.createElement('div');
this._lightBulb.className = 'lightbulb-glyph';
this._lightBulb.style.position = 'absolute';
const lineHeight = editor.getConfiguration().lineHeight;
const lineFeed = editor.getModel()!.getEOL();
this._lightBulb.style.right = '0px';
this._lightBulb.style.visibility = 'hidden';
this._lightBulb.style.height = `${lineHeight}px`;
marginDomNode.appendChild(this._lightBulb);
const actions = [
new Action(
'diff.clipboard.copyDeletedContent',
nls.localize('diff.clipboard.copyDeletedContent.label', "Copy deleted lines content to clipboard"),
undefined,
true,
async () => {
await this._clipboardService.writeText(diff.originalContent.join(lineFeed) + lineFeed);
}
)
];
let currentLineNumberOffset = 0;
const copyLineAction = new Action(
'diff.clipboard.copyDeletedLineContent',
nls.localize('diff.clipboard.copyDeletedLineContent.label', "Copy deleted line {0} content to clipboard", diff.originalStartLineNumber),
undefined,
true,
async () => {
await this._clipboardService.writeText(diff.originalContent[currentLineNumberOffset]);
}
);
actions.push(copyLineAction);
const readOnly = editor.getConfiguration().readOnly;
if (!readOnly) {
actions.push(new Action('diff.inline.revertChange', nls.localize('diff.inline.revertChange.label', "Revert this change"), undefined, true, async () => {
if (diff.modifiedEndLineNumber === 0) {
// deletion only
const column = editor.getModel()!.getLineMaxColumn(diff.modifiedStartLineNumber);
editor.executeEdits('diffEditor', [
{
range: new Range(diff.modifiedStartLineNumber, column, diff.modifiedStartLineNumber, column),
text: lineFeed + diff.originalContent.join(lineFeed)
}
]);
} else {
const column = editor.getModel()!.getLineMaxColumn(diff.modifiedEndLineNumber);
editor.executeEdits('diffEditor', [
{
range: new Range(diff.modifiedStartLineNumber, 1, diff.modifiedEndLineNumber, column),
text: diff.originalContent.join(lineFeed)
}
]);
}
}));
}
this._register(dom.addStandardDisposableListener(marginDomNode, 'mouseenter', e => {
this._lightBulb.style.visibility = 'visible';
currentLineNumberOffset = this._updateLightBulbPosition(marginDomNode, e.y, lineHeight);
}));
this._register(dom.addStandardDisposableListener(marginDomNode, 'mouseleave', e => {
this._lightBulb.style.visibility = 'hidden';
}));
this._register(dom.addStandardDisposableListener(marginDomNode, 'mousemove', e => {
currentLineNumberOffset = this._updateLightBulbPosition(marginDomNode, e.y, lineHeight);
}));
this._register(dom.addStandardDisposableListener(this._lightBulb, 'mousedown', e => {
const { top, height } = dom.getDomNodePagePosition(this._lightBulb);
let pad = Math.floor(lineHeight / 3) + lineHeight;
this._contextMenuService.showContextMenu({
getAnchor: () => {
return {
x: e.posx,
y: top + height + pad
};
},
getActions: () => {
copyLineAction.label = nls.localize('diff.clipboard.copyDeletedLineContent.label', "Copy deleted line {0} content to clipboard", diff.originalStartLineNumber + currentLineNumberOffset);
return actions;
},
autoSelectFirstItem: true
});
}));
}
private _updateLightBulbPosition(marginDomNode: HTMLElement, y: number, lineHeight: number): number {
const { top } = dom.getDomNodePagePosition(marginDomNode);
const offset = y - top;
const lineNumberOffset = Math.floor(offset / lineHeight);
const newTop = lineNumberOffset * lineHeight;
this._lightBulb.style.top = `${newTop}px`;
return lineNumberOffset;
}
}

View File

@@ -2191,7 +2191,7 @@ export class InternalEditorOptionsFactory {
selectOnLineNumbers: opts.viewInfo.selectOnLineNumbers,
glyphMargin: opts.viewInfo.glyphMargin,
revealHorizontalRightPadding: opts.viewInfo.revealHorizontalRightPadding,
roundedSelection: (accessibilityIsOn ? false : opts.viewInfo.roundedSelection), // DISABLED WHEN SCREEN READER IS ATTACHED
roundedSelection: opts.viewInfo.roundedSelection,
overviewRulerLanes: opts.viewInfo.overviewRulerLanes,
overviewRulerBorder: opts.viewInfo.overviewRulerBorder,
cursorBlinking: opts.viewInfo.cursorBlinking,
@@ -2204,15 +2204,15 @@ export class InternalEditorOptionsFactory {
scrollBeyondLastColumn: opts.viewInfo.scrollBeyondLastColumn,
smoothScrolling: opts.viewInfo.smoothScrolling,
stopRenderingLineAfter: opts.viewInfo.stopRenderingLineAfter,
renderWhitespace: (accessibilityIsOn ? 'none' : opts.viewInfo.renderWhitespace), // DISABLED WHEN SCREEN READER IS ATTACHED
renderControlCharacters: (accessibilityIsOn ? false : opts.viewInfo.renderControlCharacters), // DISABLED WHEN SCREEN READER IS ATTACHED
renderWhitespace: opts.viewInfo.renderWhitespace,
renderControlCharacters: opts.viewInfo.renderControlCharacters,
fontLigatures: opts.viewInfo.fontLigatures,
renderIndentGuides: (accessibilityIsOn ? false : opts.viewInfo.renderIndentGuides), // DISABLED WHEN SCREEN READER IS ATTACHED
renderIndentGuides: opts.viewInfo.renderIndentGuides,
highlightActiveIndentGuide: opts.viewInfo.highlightActiveIndentGuide,
renderLineHighlight: opts.viewInfo.renderLineHighlight,
scrollbar: opts.viewInfo.scrollbar,
minimap: {
enabled: (accessibilityIsOn ? false : opts.viewInfo.minimap.enabled), // DISABLED WHEN SCREEN READER IS ATTACHED
enabled: opts.viewInfo.minimap.enabled,
side: opts.viewInfo.minimap.side,
renderCharacters: opts.viewInfo.minimap.renderCharacters,
showSlider: opts.viewInfo.minimap.showSlider,
@@ -2224,7 +2224,7 @@ export class InternalEditorOptionsFactory {
contribInfo: {
selectionClipboard: opts.contribInfo.selectionClipboard,
hover: opts.contribInfo.hover,
links: (accessibilityIsOn ? false : opts.contribInfo.links), // DISABLED WHEN SCREEN READER IS ATTACHED
links: opts.contribInfo.links,
contextmenu: opts.contribInfo.contextmenu,
quickSuggestions: opts.contribInfo.quickSuggestions,
quickSuggestionsDelay: opts.contribInfo.quickSuggestionsDelay,
@@ -2241,13 +2241,13 @@ export class InternalEditorOptionsFactory {
tabCompletion: opts.contribInfo.tabCompletion,
suggest: opts.contribInfo.suggest,
gotoLocation: opts.contribInfo.gotoLocation,
selectionHighlight: (accessibilityIsOn ? false : opts.contribInfo.selectionHighlight), // DISABLED WHEN SCREEN READER IS ATTACHED
occurrencesHighlight: (accessibilityIsOn ? false : opts.contribInfo.occurrencesHighlight), // DISABLED WHEN SCREEN READER IS ATTACHED
codeLens: (accessibilityIsOn ? false : opts.contribInfo.codeLens), // DISABLED WHEN SCREEN READER IS ATTACHED
selectionHighlight: opts.contribInfo.selectionHighlight,
occurrencesHighlight: opts.contribInfo.occurrencesHighlight,
codeLens: opts.contribInfo.codeLens,
folding: (accessibilityIsOn ? false : opts.contribInfo.folding), // DISABLED WHEN SCREEN READER IS ATTACHED
foldingStrategy: opts.contribInfo.foldingStrategy,
showFoldingControls: opts.contribInfo.showFoldingControls,
matchBrackets: (accessibilityIsOn ? false : opts.contribInfo.matchBrackets), // DISABLED WHEN SCREEN READER IS ATTACHED
matchBrackets: opts.contribInfo.matchBrackets,
find: opts.contribInfo.find,
colorDecorators: opts.contribInfo.colorDecorators,
lightbulbEnabled: opts.contribInfo.lightbulbEnabled,

View File

@@ -367,7 +367,7 @@ export let completionKindFromString: {
};
})();
export const enum CompletionItemKindModifier {
export const enum CompletionItemTag {
Deprecated = 1
}
@@ -404,7 +404,7 @@ export interface CompletionItem {
* A modifier to the `kind` which affect how the item
* is rendered, e.g. Deprecated is rendered with a strikeout
*/
kindModifier?: Set<CompletionItemKindModifier>;
tags?: ReadonlyArray<CompletionItemTag>;
/**
* A human-readable string with additional information
* about this item, like type or symbol information.
@@ -867,7 +867,7 @@ export const enum SymbolKind {
TypeParameter = 25
}
export const enum SymbolKindTag {
export const enum SymbolTag {
Deprecated = 1,
}
@@ -913,7 +913,7 @@ export interface DocumentSymbol {
name: string;
detail: string;
kind: SymbolKind;
kindTags: SymbolKindTag[];
tags: ReadonlyArray<SymbolTag>;
containerName?: string;
range: IRange;
selectionRange: IRange;

View File

@@ -581,7 +581,7 @@ export enum CompletionItemKind {
Snippet = 25
}
export enum CompletionItemKindModifier {
export enum CompletionItemTag {
Deprecated = 1
}
@@ -662,6 +662,6 @@ export enum SymbolKind {
TypeParameter = 25
}
export enum SymbolKindTag {
export enum SymbolTag {
Deprecated = 1
}

View File

@@ -32,7 +32,7 @@ export class CodeLensContribution implements editorCommon.IEditorContribution {
private _currentCodeLensModel: CodeLensModel | undefined;
private _modelChangeCounter: number = 0;
private _currentResolveCodeLensSymbolsPromise: CancelablePromise<any> | undefined;
private _detectVisibleLenses!: RunOnceScheduler;
private _detectVisibleLenses: RunOnceScheduler | undefined;
constructor(
private readonly _editor: editorBrowser.ICodeEditor,
@@ -121,9 +121,7 @@ export class CodeLensContribution implements editorCommon.IEditorContribution {
}
}
this._detectVisibleLenses = new RunOnceScheduler(() => {
this._onViewportChanged();
}, 250);
const detectVisibleLenses = this._detectVisibleLenses = new RunOnceScheduler(() => this._onViewportChanged(), 250);
const scheduler = new RunOnceScheduler(() => {
const counterValue = ++this._modelChangeCounter;
@@ -145,12 +143,12 @@ export class CodeLensContribution implements editorCommon.IEditorContribution {
// render lenses
this._renderCodeLensSymbols(result);
this._detectVisibleLenses.schedule();
detectVisibleLenses.schedule();
}
}, onUnexpectedError);
}, 250);
this._localToDispose.add(scheduler);
this._localToDispose.add(this._detectVisibleLenses);
this._localToDispose.add(detectVisibleLenses);
this._localToDispose.add(this._editor.onDidChangeModelContent(() => {
this._editor.changeDecorations(decorationsAccessor => {
this._editor.changeViewZones(viewZonesAccessor => {
@@ -179,17 +177,17 @@ export class CodeLensContribution implements editorCommon.IEditorContribution {
});
// Compute new `visible` code lenses
this._detectVisibleLenses.schedule();
detectVisibleLenses.schedule();
// Ask for all references again
scheduler.schedule();
}));
this._localToDispose.add(this._editor.onDidScrollChange(e => {
if (e.scrollTopChanged && this._lenses.length > 0) {
this._detectVisibleLenses.schedule();
detectVisibleLenses.schedule();
}
}));
this._localToDispose.add(this._editor.onDidLayoutChange(() => {
this._detectVisibleLenses.schedule();
detectVisibleLenses.schedule();
}));
this._localToDispose.add(toDisposable(() => {
if (this._editor.getModel()) {
@@ -281,7 +279,7 @@ export class CodeLensContribution implements editorCommon.IEditorContribution {
groupsIndex++;
codeLensIndex++;
} else {
this._lenses.splice(codeLensIndex, 0, new CodeLensWidget(groups[groupsIndex], this._editor, helper, viewZoneAccessor, () => this._detectVisibleLenses.schedule()));
this._lenses.splice(codeLensIndex, 0, new CodeLensWidget(groups[groupsIndex], this._editor, helper, viewZoneAccessor, () => this._detectVisibleLenses && this._detectVisibleLenses.schedule()));
codeLensIndex++;
groupsIndex++;
}
@@ -295,7 +293,7 @@ export class CodeLensContribution implements editorCommon.IEditorContribution {
// Create extra symbols
while (groupsIndex < groups.length) {
this._lenses.push(new CodeLensWidget(groups[groupsIndex], this._editor, helper, viewZoneAccessor, () => this._detectVisibleLenses.schedule()));
this._lenses.push(new CodeLensWidget(groups[groupsIndex], this._editor, helper, viewZoneAccessor, () => this._detectVisibleLenses && this._detectVisibleLenses.schedule()));
groupsIndex++;
}

View File

@@ -20,11 +20,6 @@
color: var(--outline-element-color);
}
.monaco-list .outline-element .deprecated {
text-decoration: line-through;
opacity: 0.66;
}
.monaco-tree .monaco-tree-row.focused .outline-element .outline-element-detail {
visibility: inherit;
}

View File

@@ -3,6 +3,11 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-workbench .monaco-icon-label.deprecated {
text-decoration: line-through;
opacity: 0.66;
}
.monaco-workbench .symbol-icon.inline {
background-position: left center;
padding-left: 20px;

View File

@@ -12,7 +12,7 @@ import { createMatches, FuzzyScore } from 'vs/base/common/filters';
import 'vs/css!./media/outlineTree';
import 'vs/css!./media/symbol-icons';
import { Range } from 'vs/editor/common/core/range';
import { SymbolKind, symbolKindToCssClass, SymbolKindTag } from 'vs/editor/common/modes';
import { SymbolKind, symbolKindToCssClass, SymbolTag } from 'vs/editor/common/modes';
import { OutlineElement, OutlineGroup, OutlineModel } from 'vs/editor/contrib/documentSymbols/outlineModel';
import { localize } from 'vs/nls';
import { IconLabel } from 'vs/base/browser/ui/iconLabel/iconLabel';
@@ -127,7 +127,7 @@ export class OutlineElementRenderer implements ITreeRenderer<OutlineElement, Fuz
// add styles for the icons
options.extraClasses.push(`outline-element-icon ${symbolKindToCssClass(element.symbol.kind, true)}`);
}
if (element.symbol.kindTags.indexOf(SymbolKindTag.Deprecated) >= 0) {
if (element.symbol.tags.indexOf(SymbolTag.Deprecated) >= 0) {
options.extraClasses.push(`deprecated`);
options.matches = [];
}

View File

@@ -76,7 +76,7 @@ suite('OutlineModel', function () {
name,
detail: 'fake',
kind: SymbolKind.Boolean,
kindTags: [],
tags: [],
selectionRange: range,
range: range
};

View File

@@ -5,7 +5,7 @@
import * as nls from 'vs/nls';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { dispose } from 'vs/base/common/lifecycle';
import { Disposable } from 'vs/base/common/lifecycle';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IEditorContribution } from 'vs/editor/common/editorCommon';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
@@ -18,7 +18,7 @@ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegis
import * as modes from 'vs/editor/common/modes';
import { TriggerContext } from 'vs/editor/contrib/parameterHints/parameterHintsModel';
class ParameterHintsController implements IEditorContribution {
class ParameterHintsController extends Disposable implements IEditorContribution {
private static readonly ID = 'editor.controller.parameterHints';
@@ -30,8 +30,9 @@ class ParameterHintsController implements IEditorContribution {
private readonly widget: ParameterHintsWidget;
constructor(editor: ICodeEditor, @IInstantiationService instantiationService: IInstantiationService) {
super();
this.editor = editor;
this.widget = instantiationService.createInstance(ParameterHintsWidget, this.editor);
this.widget = this._register(instantiationService.createInstance(ParameterHintsWidget, this.editor));
}
getId(): string {
@@ -53,10 +54,6 @@ class ParameterHintsController implements IEditorContribution {
trigger(context: TriggerContext): void {
this.widget.trigger(context);
}
dispose(): void {
dispose(this.widget);
}
}
export class TriggerParameterHintsAction extends EditorAction {
@@ -76,7 +73,7 @@ export class TriggerParameterHintsAction extends EditorAction {
}
public run(accessor: ServicesAccessor, editor: ICodeEditor): void {
let controller = ParameterHintsController.get(editor);
const controller = ParameterHintsController.get(editor);
if (controller) {
controller.trigger({
triggerKind: modes.SignatureHelpTriggerKind.Invoke

View File

@@ -3,44 +3,41 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { illegalArgument, onUnexpectedExternalError } from 'vs/base/common/errors';
import { illegalArgument } from 'vs/base/common/errors';
import { URI } from 'vs/base/common/uri';
import { Range } from 'vs/editor/common/core/range';
import { ITextModel } from 'vs/editor/common/model';
import { registerLanguageCommand } from 'vs/editor/browser/editorExtensions';
import { DocumentSymbol, DocumentSymbolProviderRegistry } from 'vs/editor/common/modes';
import { DocumentSymbol } from 'vs/editor/common/modes';
import { IModelService } from 'vs/editor/common/services/modelService';
import { CancellationToken } from 'vs/base/common/cancellation';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { OutlineModel, OutlineElement } from 'vs/editor/contrib/documentSymbols/outlineModel';
import { values } from 'vs/base/common/collections';
export function getDocumentSymbols(model: ITextModel, flat: boolean, token: CancellationToken): Promise<DocumentSymbol[]> {
export async function getDocumentSymbols(document: ITextModel, flat: boolean, token: CancellationToken): Promise<DocumentSymbol[]> {
let roots: DocumentSymbol[] = [];
let promises = DocumentSymbolProviderRegistry.all(model).map(support => {
return Promise.resolve(support.provideDocumentSymbols(model, token)).then(result => {
if (Array.isArray(result)) {
roots.push(...result);
}
}, err => {
onUnexpectedExternalError(err);
});
});
return Promise.all(promises).then(() => {
let flatEntries: DocumentSymbol[] = [];
if (token.isCancellationRequested) {
return flatEntries;
}
if (flat) {
flatten(flatEntries, roots, '');
const model = await OutlineModel.create(document, token);
const roots: DocumentSymbol[] = [];
for (const child of values(model.children)) {
if (child instanceof OutlineElement) {
roots.push(child.symbol);
} else {
flatEntries = roots;
roots.push(...values(child.children).map(child => child.symbol));
}
flatEntries.sort(compareEntriesUsingStart);
}
let flatEntries: DocumentSymbol[] = [];
if (token.isCancellationRequested) {
return flatEntries;
});
}
if (flat) {
flatten(flatEntries, roots, '');
} else {
flatEntries = roots;
}
return flatEntries.sort(compareEntriesUsingStart);
}
function compareEntriesUsingStart(a: DocumentSymbol, b: DocumentSymbol): number {
@@ -51,7 +48,7 @@ function flatten(bucket: DocumentSymbol[], entries: DocumentSymbol[], overrideCo
for (let entry of entries) {
bucket.push({
kind: entry.kind,
kindTags: [],
tags: entry.tags,
name: entry.name,
detail: entry.detail,
containerName: entry.containerName || overrideContainerLabel,

View File

@@ -30,7 +30,7 @@ import { MarkdownRenderer } from 'vs/editor/contrib/markdown/markdownRenderer';
import { IModeService } from 'vs/editor/common/services/modeService';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { TimeoutTimer, CancelablePromise, createCancelablePromise, disposableTimeout } from 'vs/base/common/async';
import { CompletionItemKind, completionKindToCssClass, CompletionItemKindModifier } from 'vs/editor/common/modes';
import { CompletionItemKind, completionKindToCssClass, CompletionItemTag } from 'vs/editor/common/modes';
import { IconLabel, IIconLabelValueOptions } from 'vs/base/browser/ui/iconLabel/iconLabel';
import { getIconClasses } from 'vs/editor/common/services/getIconClasses';
import { IModelService } from 'vs/editor/common/services/modelService';
@@ -193,7 +193,7 @@ class Renderer implements IListRenderer<CompletionItem, ISuggestionTemplateData>
];
}
if (suggestion.kindModifier && suggestion.kindModifier.has(CompletionItemKindModifier.Deprecated)) {
if (suggestion.tags && suggestion.tags.indexOf(CompletionItemTag.Deprecated) >= 0) {
labelOptions.extraClasses = (labelOptions.extraClasses || []).concat(['deprecated']);
labelOptions.matches = [];
}

View File

@@ -45,6 +45,7 @@ import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platf
import { ILayoutService, IDimension } from 'vs/platform/layout/browser/layoutService';
import { SimpleServicesNLS } from 'vs/editor/common/standaloneStrings';
import { ClassifiedEvent, StrictPropertyCheck, GDPRClassification } from 'vs/platform/telemetry/common/gdprTypings';
import { basename } from 'vs/base/common/resources';
export class SimpleModel implements IResolvedTextEditorModel {
@@ -656,6 +657,7 @@ export class SimpleBulkEditService implements IBulkEditService {
}
export class SimpleUriLabelService implements ILabelService {
_serviceBrand: any;
private readonly _onDidRegisterFormatter = new Emitter<void>();
@@ -668,6 +670,10 @@ export class SimpleUriLabelService implements ILabelService {
return resource.path;
}
getUriBasenameLabel(resource: URI): string {
return basename(resource);
}
public getWorkspaceLabel(workspace: IWorkspaceIdentifier | URI | IWorkspace, options?: { verbose: boolean; }): string {
return '';
}

View File

@@ -21,7 +21,7 @@ import { IMenuItem, MenuId, MenuRegistry } from 'vs/platform/actions/common/acti
import { CommandsRegistry, ICommandHandler, ICommandService } from 'vs/platform/commands/common/commands';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ContextKeyExpr, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
import { IContextViewService, IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { ContextViewService } from 'vs/platform/contextview/browser/contextViewService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
@@ -29,6 +29,7 @@ import { INotificationService } from 'vs/platform/notification/common/notificati
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
import { StandaloneCodeEditorNLS } from 'vs/editor/common/standaloneStrings';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
/**
* Description of an action contribution
@@ -373,7 +374,9 @@ export class StandaloneDiffEditor extends DiffEditorWidget implements IStandalon
@ICodeEditorService codeEditorService: ICodeEditorService,
@IStandaloneThemeService themeService: IStandaloneThemeService,
@INotificationService notificationService: INotificationService,
@IConfigurationService configurationService: IConfigurationService
@IConfigurationService configurationService: IConfigurationService,
@IContextMenuService contextMenuService: IContextMenuService,
@IClipboardService clipboardService: IClipboardService
) {
applyConfigurationValues(configurationService, options, true);
options = options || {};
@@ -381,7 +384,7 @@ export class StandaloneDiffEditor extends DiffEditorWidget implements IStandalon
options.theme = themeService.setTheme(options.theme);
}
super(domElement, options, editorWorkerService, contextKeyService, instantiationService, codeEditorService, themeService, notificationService);
super(domElement, options, editorWorkerService, contextKeyService, instantiationService, codeEditorService, themeService, notificationService, contextMenuService, clipboardService);
this._contextViewService = <ContextViewService>contextViewService;
this._configurationService = configurationService;

View File

@@ -30,7 +30,7 @@ import { IStandaloneThemeData, IStandaloneThemeService } from 'vs/editor/standal
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
import { IContextViewService, IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IMarker, IMarkerData } from 'vs/platform/markers/common/markers';
@@ -38,6 +38,7 @@ import { INotificationService } from 'vs/platform/notification/common/notificati
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
import { clearAllFontInfos } from 'vs/editor/browser/config/configuration';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
@@ -119,6 +120,8 @@ export function createDiffEditor(domElement: HTMLElement, options?: IDiffEditorC
services.get(IStandaloneThemeService),
services.get(INotificationService),
services.get(IConfigurationService),
services.get(IContextMenuService),
services.get(IClipboardService)
);
});
}

View File

@@ -562,10 +562,10 @@ export function createMonacoLanguagesAPI(): typeof monaco.languages {
// enums
DocumentHighlightKind: standaloneEnums.DocumentHighlightKind,
CompletionItemKind: standaloneEnums.CompletionItemKind,
CompletionItemKindModifier: standaloneEnums.CompletionItemKindModifier,
CompletionItemTag: standaloneEnums.CompletionItemTag,
CompletionItemInsertTextRule: standaloneEnums.CompletionItemInsertTextRule,
SymbolKind: standaloneEnums.SymbolKind,
SymbolKindTag: standaloneEnums.SymbolKindTag,
SymbolTag: standaloneEnums.SymbolTag,
IndentAction: standaloneEnums.IndentAction,
CompletionTriggerKind: standaloneEnums.CompletionTriggerKind,
SignatureHelpTriggerKind: standaloneEnums.SignatureHelpTriggerKind,

8
src/vs/monaco.d.ts vendored
View File

@@ -4790,7 +4790,7 @@ declare namespace monaco.languages {
Snippet = 25
}
export enum CompletionItemKindModifier {
export enum CompletionItemTag {
Deprecated = 1
}
@@ -4826,7 +4826,7 @@ declare namespace monaco.languages {
* A modifier to the `kind` which affect how the item
* is rendered, e.g. Deprecated is rendered with a strikeout
*/
kindModifier?: Set<CompletionItemKindModifier>;
tags?: ReadonlyArray<CompletionItemTag>;
/**
* A human-readable string with additional information
* about this item, like type or symbol information.
@@ -5236,7 +5236,7 @@ declare namespace monaco.languages {
TypeParameter = 25
}
export enum SymbolKindTag {
export enum SymbolTag {
Deprecated = 1
}
@@ -5244,7 +5244,7 @@ declare namespace monaco.languages {
name: string;
detail: string;
kind: SymbolKind;
kindTags: SymbolKindTag[];
tags: ReadonlyArray<SymbolTag>;
containerName?: string;
range: IRange;
selectionRange: IRange;

View File

@@ -21,6 +21,7 @@ export interface ILabelService {
* If noPrefix is passed does not tildify the label and also does not prepand the root name for relative labels in a multi root scenario.
*/
getUriLabel(resource: URI, options?: { relative?: boolean, noPrefix?: boolean, endWithSeparator?: boolean }): string;
getUriBasenameLabel(resource: URI): string;
getWorkspaceLabel(workspace: (IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IWorkspace), options?: { verbose: boolean }): string;
getHostLabel(scheme: string, authority?: string): string;
getSeparator(scheme: string, authority?: string): '/' | '\\';

View File

@@ -8,7 +8,6 @@ import { ILogService } from 'vs/platform/log/common/log';
import { AbstractLifecycleService } from 'vs/platform/lifecycle/common/lifecycleService';
import { localize } from 'vs/nls';
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
import { addDisposableListener, EventType } from 'vs/base/browser/dom';
export class BrowserLifecycleService extends AbstractLifecycleService {
@@ -23,7 +22,9 @@ export class BrowserLifecycleService extends AbstractLifecycleService {
}
private registerListeners(): void {
addDisposableListener(window, EventType.BEFORE_UNLOAD, () => this.onBeforeUnload());
// Note: we cannot change this to window.addEventListener('beforeUnload')
// because it seems that mechanism does not allow for preventing the unload
window.onbeforeunload = () => this.onBeforeUnload();
}
private onBeforeUnload(): string | null {

View File

@@ -89,7 +89,6 @@ export interface IProductConfiguration {
readonly 'linux-x64': string;
readonly 'darwin': string;
};
readonly logUploaderUrl: string;
readonly portable?: string;
readonly uiExtensions?: readonly string[];
}

View File

@@ -10,9 +10,10 @@ import { Disposable } from 'vs/base/common/lifecycle';
import { VSBuffer } from 'vs/base/common/buffer';
import { Emitter } from 'vs/base/common/event';
import { RemoteAuthorityResolverError } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { isPromiseCanceledError } from 'vs/base/common/errors';
import { isPromiseCanceledError, onUnexpectedError } from 'vs/base/common/errors';
import { ISignService } from 'vs/platform/sign/common/sign';
import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async';
import { ILogService } from 'vs/platform/log/common/log';
export const enum ConnectionType {
Management = 1,
@@ -20,6 +21,17 @@ export const enum ConnectionType {
Tunnel = 3,
}
function connectionTypeToString(connectionType: ConnectionType): string {
switch (connectionType) {
case ConnectionType.Management:
return 'Management';
case ConnectionType.ExtensionHost:
return 'ExtensionHost';
case ConnectionType.Tunnel:
return 'Tunnel';
}
}
export interface AuthRequest {
type: 'auth';
auth: string;
@@ -58,6 +70,7 @@ interface ISimpleConnectionOptions {
reconnectionProtocol: PersistentProtocol | null;
socketFactory: ISocketFactory;
signService: ISignService;
logService: ILogService;
}
export interface IConnectCallback {
@@ -68,29 +81,46 @@ export interface ISocketFactory {
connect(host: string, port: number, query: string, callback: IConnectCallback): void;
}
async function connectToRemoteExtensionHostAgent(options: ISimpleConnectionOptions, connectionType: ConnectionType, args: any | undefined): Promise<PersistentProtocol> {
const protocol = await new Promise<PersistentProtocol>((c, e) => {
async function connectToRemoteExtensionHostAgent(options: ISimpleConnectionOptions, connectionType: ConnectionType, args: any | undefined): Promise<{ protocol: PersistentProtocol; ownsProtocol: boolean; }> {
const logPrefix = connectLogPrefix(options, connectionType);
const { protocol, ownsProtocol } = await new Promise<{ protocol: PersistentProtocol; ownsProtocol: boolean; }>((c, e) => {
options.logService.trace(`${logPrefix} 1/6. invoking socketFactory.connect().`);
options.socketFactory.connect(
options.host,
options.port,
`reconnectionToken=${options.reconnectionToken}&reconnection=${options.reconnectionProtocol ? 'true' : 'false'}`,
(err: any, socket: ISocket) => {
if (err) {
options.logService.error(`${logPrefix} socketFactory.connect() failed. Error:`);
options.logService.error(err);
e(err);
return;
}
options.logService.trace(`${logPrefix} 2/6. socketFactory.connect() was successful.`);
if (options.reconnectionProtocol) {
options.reconnectionProtocol.beginAcceptReconnection(socket, null);
c(options.reconnectionProtocol);
c({ protocol: options.reconnectionProtocol, ownsProtocol: false });
} else {
c(new PersistentProtocol(socket, null));
c({ protocol: new PersistentProtocol(socket, null), ownsProtocol: true });
}
}
);
});
return new Promise<PersistentProtocol>((c, e) => {
return new Promise<{ protocol: PersistentProtocol; ownsProtocol: boolean; }>((c, e) => {
const errorTimeoutToken = setTimeout(() => {
const error: any = new Error('handshake timeout');
error.code = 'ETIMEDOUT';
error.syscall = 'connect';
options.logService.error(`${logPrefix} the handshake took longer than 10 seconds. Error:`);
options.logService.error(error);
if (ownsProtocol) {
safeDisposeProtocolAndSocket(protocol);
}
e(error);
}, 10000);
const messageRegistration = protocol.onControlMessage(async raw => {
const msg = <HandshakeMessage>JSON.parse(raw.toString());
@@ -99,11 +129,16 @@ async function connectToRemoteExtensionHostAgent(options: ISimpleConnectionOptio
const error = getErrorFromMessage(msg);
if (error) {
options.logService.error(`${logPrefix} received error control message when negotiating connection. Error:`);
options.logService.error(error);
if (ownsProtocol) {
safeDisposeProtocolAndSocket(protocol);
}
return e(error);
}
if (msg.type === 'sign') {
options.logService.trace(`${logPrefix} 4/6. received SignRequest control message.`);
const signed = await options.signService.sign(msg.data);
const connTypeRequest: ConnectionTypeRequest = {
type: 'connectionType',
@@ -114,17 +149,22 @@ async function connectToRemoteExtensionHostAgent(options: ISimpleConnectionOptio
if (args) {
connTypeRequest.args = args;
}
options.logService.trace(`${logPrefix} 5/6. sending ConnectionTypeRequest control message.`);
protocol.sendControl(VSBuffer.fromString(JSON.stringify(connTypeRequest)));
c(protocol);
clearTimeout(errorTimeoutToken);
c({ protocol, ownsProtocol });
} else {
e(new Error('handshake error'));
const error = new Error('handshake error');
options.logService.error(`${logPrefix} received unexpected control message. Error:`);
options.logService.error(error);
if (ownsProtocol) {
safeDisposeProtocolAndSocket(protocol);
}
e(error);
}
});
setTimeout(() => {
e(new Error('handshake timeout'));
}, 2000);
options.logService.trace(`${logPrefix} 3/6. sending AuthRequest control message.`);
// TODO@vs-remote: use real nonce here
const authRequest: AuthRequest = {
type: 'auth',
@@ -138,24 +178,37 @@ interface IManagementConnectionResult {
protocol: PersistentProtocol;
}
async function doConnectRemoteAgentManagement(options: ISimpleConnectionOptions): Promise<IManagementConnectionResult> {
const protocol = await connectToRemoteExtensionHostAgent(options, ConnectionType.Management, undefined);
return new Promise<IManagementConnectionResult>((c, e) => {
async function connectToRemoteExtensionHostAgentAndReadOneMessage(options: ISimpleConnectionOptions, connectionType: ConnectionType, args: any | undefined): Promise<{ protocol: PersistentProtocol; firstMessage: any }> {
const startTime = Date.now();
const logPrefix = connectLogPrefix(options, connectionType);
const { protocol, ownsProtocol } = await connectToRemoteExtensionHostAgent(options, connectionType, args);
return new Promise<{ protocol: PersistentProtocol; firstMessage: any }>((c, e) => {
const registration = protocol.onControlMessage(raw => {
registration.dispose();
const msg = JSON.parse(raw.toString());
const error = getErrorFromMessage(msg);
if (error) {
options.logService.error(`${logPrefix} received error control message when negotiating connection. Error:`);
options.logService.error(error);
if (ownsProtocol) {
safeDisposeProtocolAndSocket(protocol);
}
return e(error);
}
if (options.reconnectionProtocol) {
options.reconnectionProtocol.endAcceptReconnection();
}
c({ protocol });
options.logService.trace(`${logPrefix} 6/6. handshake finished, connection is up and running after ${logElapsed(startTime)}!`);
c({ protocol, firstMessage: msg });
});
});
}
async function doConnectRemoteAgentManagement(options: ISimpleConnectionOptions): Promise<IManagementConnectionResult> {
const { protocol } = await connectToRemoteExtensionHostAgentAndReadOneMessage(options, ConnectionType.Management, undefined);
return { protocol };
}
export interface IRemoteExtensionHostStartParams {
language: string;
debugId?: string;
@@ -170,22 +223,9 @@ interface IExtensionHostConnectionResult {
}
async function doConnectRemoteAgentExtensionHost(options: ISimpleConnectionOptions, startArguments: IRemoteExtensionHostStartParams): Promise<IExtensionHostConnectionResult> {
const protocol = await connectToRemoteExtensionHostAgent(options, ConnectionType.ExtensionHost, startArguments);
return new Promise<IExtensionHostConnectionResult>((c, e) => {
const registration = protocol.onControlMessage(raw => {
registration.dispose();
const msg = JSON.parse(raw.toString());
const error = getErrorFromMessage(msg);
if (error) {
return e(error);
}
const debugPort = msg && msg.debugPort;
if (options.reconnectionProtocol) {
options.reconnectionProtocol.endAcceptReconnection();
}
c({ protocol, debugPort });
});
});
const { protocol, firstMessage } = await connectToRemoteExtensionHostAgentAndReadOneMessage(options, ConnectionType.ExtensionHost, startArguments);
const debugPort = firstMessage && firstMessage.debugPort;
return { protocol, debugPort };
}
export interface ITunnelConnectionStartParams {
@@ -193,7 +233,10 @@ export interface ITunnelConnectionStartParams {
}
async function doConnectRemoteAgentTunnel(options: ISimpleConnectionOptions, startParams: ITunnelConnectionStartParams): Promise<PersistentProtocol> {
const protocol = await connectToRemoteExtensionHostAgent(options, ConnectionType.Tunnel, startParams);
const startTime = Date.now();
const logPrefix = connectLogPrefix(options, ConnectionType.Tunnel);
const { protocol } = await connectToRemoteExtensionHostAgent(options, ConnectionType.Tunnel, startParams);
options.logService.trace(`${logPrefix} 6/6. handshake finished, connection is up and running after ${logElapsed(startTime)}!`);
return protocol;
}
@@ -202,6 +245,7 @@ export interface IConnectionOptions {
socketFactory: ISocketFactory;
addressProvider: IAddressProvider;
signService: ISignService;
logService: ILogService;
}
async function resolveConnectionOptions(options: IConnectionOptions, reconnectionToken: string, reconnectionProtocol: PersistentProtocol | null): Promise<ISimpleConnectionOptions> {
@@ -213,7 +257,8 @@ async function resolveConnectionOptions(options: IConnectionOptions, reconnectio
reconnectionToken: reconnectionToken,
reconnectionProtocol: reconnectionProtocol,
socketFactory: options.socketFactory,
signService: options.signService
signService: options.signService,
logService: options.logService
};
}
@@ -227,22 +272,36 @@ export interface IAddressProvider {
}
export async function connectRemoteAgentManagement(options: IConnectionOptions, remoteAuthority: string, clientId: string): Promise<ManagementPersistentConnection> {
const reconnectionToken = generateUuid();
const simpleOptions = await resolveConnectionOptions(options, reconnectionToken, null);
const { protocol } = await doConnectRemoteAgentManagement(simpleOptions);
return new ManagementPersistentConnection(options, remoteAuthority, clientId, reconnectionToken, protocol);
try {
const reconnectionToken = generateUuid();
const simpleOptions = await resolveConnectionOptions(options, reconnectionToken, null);
const { protocol } = await connectWithTimeLimit(simpleOptions.logService, doConnectRemoteAgentManagement(simpleOptions), 30 * 1000 /*30s*/);
return new ManagementPersistentConnection(options, remoteAuthority, clientId, reconnectionToken, protocol);
} catch (err) {
options.logService.error(`[remote-connection] An error occurred in the very first connect attempt, it will be treated as a permanent error! Error:`);
options.logService.error(err);
PersistentConnection.triggerPermanentFailure();
throw err;
}
}
export async function connectRemoteAgentExtensionHost(options: IConnectionOptions, startArguments: IRemoteExtensionHostStartParams): Promise<ExtensionHostPersistentConnection> {
const reconnectionToken = generateUuid();
const simpleOptions = await resolveConnectionOptions(options, reconnectionToken, null);
const { protocol, debugPort } = await doConnectRemoteAgentExtensionHost(simpleOptions, startArguments);
return new ExtensionHostPersistentConnection(options, startArguments, reconnectionToken, protocol, debugPort);
try {
const reconnectionToken = generateUuid();
const simpleOptions = await resolveConnectionOptions(options, reconnectionToken, null);
const { protocol, debugPort } = await connectWithTimeLimit(simpleOptions.logService, doConnectRemoteAgentExtensionHost(simpleOptions, startArguments), 30 * 1000 /*30s*/);
return new ExtensionHostPersistentConnection(options, startArguments, reconnectionToken, protocol, debugPort);
} catch (err) {
options.logService.error(`[remote-connection] An error occurred in the very first connect attempt, it will be treated as a permanent error! Error:`);
options.logService.error(err);
PersistentConnection.triggerPermanentFailure();
throw err;
}
}
export async function connectRemoteAgentTunnel(options: IConnectionOptions, tunnelRemotePort: number): Promise<PersistentProtocol> {
const simpleOptions = await resolveConnectionOptions(options, generateUuid(), null);
const protocol = await doConnectRemoteAgentTunnel(simpleOptions, { port: tunnelRemotePort });
const protocol = await connectWithTimeLimit(simpleOptions.logService, doConnectRemoteAgentTunnel(simpleOptions, { port: tunnelRemotePort }), 30 * 1000 /*30s*/);
return protocol;
}
@@ -292,6 +351,13 @@ export type PersistenConnectionEvent = ConnectionGainEvent | ConnectionLostEvent
abstract class PersistentConnection extends Disposable {
public static triggerPermanentFailure(): void {
this._permanentFailure = true;
this._instances.forEach(instance => instance._gotoPermanentFailure());
}
private static _permanentFailure: boolean = false;
private static _instances: PersistentConnection[] = [];
private readonly _onDidStateChange = this._register(new Emitter<PersistenConnectionEvent>());
public readonly onDidStateChange = this._onDidStateChange.event;
@@ -300,20 +366,24 @@ abstract class PersistentConnection extends Disposable {
public readonly protocol: PersistentProtocol;
private _isReconnecting: boolean;
private _permanentFailure: boolean;
constructor(options: IConnectionOptions, reconnectionToken: string, protocol: PersistentProtocol) {
constructor(private readonly _connectionType: ConnectionType, options: IConnectionOptions, reconnectionToken: string, protocol: PersistentProtocol) {
super();
this._options = options;
this.reconnectionToken = reconnectionToken;
this.protocol = protocol;
this._isReconnecting = false;
this._permanentFailure = false;
this._onDidStateChange.fire(new ConnectionGainEvent());
this._register(protocol.onSocketClose(() => this._beginReconnecting()));
this._register(protocol.onSocketTimeout(() => this._beginReconnecting()));
PersistentConnection._instances.push(this);
if (PersistentConnection._permanentFailure) {
this._gotoPermanentFailure();
}
}
private async _beginReconnecting(): Promise<void> {
@@ -330,10 +400,12 @@ abstract class PersistentConnection extends Disposable {
}
private async _runReconnectingLoop(): Promise<void> {
if (this._permanentFailure) {
if (PersistentConnection._permanentFailure) {
// no more attempts!
return;
}
const logPrefix = commonLogPrefix(this._connectionType, this.reconnectionToken, true);
this._options.logService.info(`${logPrefix} starting reconnecting loop. You can get more information with the trace log level.`);
this._onDidStateChange.fire(new ConnectionLostEvent());
const TIMES = [5, 5, 10, 10, 10, 10, 10, 30];
const disconnectStartTime = Date.now();
@@ -345,59 +417,68 @@ abstract class PersistentConnection extends Disposable {
const sleepPromise = sleep(waitTime);
this._onDidStateChange.fire(new ReconnectionWaitEvent(waitTime, sleepPromise));
this._options.logService.info(`${logPrefix} waiting for ${waitTime} seconds before reconnecting...`);
try {
await sleepPromise;
} catch { } // User canceled timer
if (PersistentConnection._permanentFailure) {
this._options.logService.error(`${logPrefix} permanent failure occurred while running the reconnecting loop.`);
break;
}
// connection was lost, let's try to re-establish it
this._onDidStateChange.fire(new ReconnectionRunningEvent());
this._options.logService.info(`${logPrefix} resolving connection...`);
const simpleOptions = await resolveConnectionOptions(this._options, this.reconnectionToken, this.protocol);
await connectWithTimeLimit(this._reconnect(simpleOptions), 30 * 1000 /*30s*/);
this._options.logService.info(`${logPrefix} connecting to ${simpleOptions.host}:${simpleOptions.port}...`);
await connectWithTimeLimit(simpleOptions.logService, this._reconnect(simpleOptions), 30 * 1000 /*30s*/);
this._options.logService.info(`${logPrefix} reconnected!`);
this._onDidStateChange.fire(new ConnectionGainEvent());
break;
} catch (err) {
if (err.code === 'VSCODE_CONNECTION_ERROR') {
console.error(`A permanent connection error occurred`);
console.error(err);
this._permanentFailure = true;
this._onDidStateChange.fire(new ReconnectionPermanentFailureEvent());
this.protocol.acceptDisconnect();
this._options.logService.error(`${logPrefix} A permanent error occurred in the reconnecting loop! Will give up now! Error:`);
this._options.logService.error(err);
PersistentConnection.triggerPermanentFailure();
break;
}
if (Date.now() - disconnectStartTime > ProtocolConstants.ReconnectionGraceTime) {
console.error(`Giving up after reconnection grace time has expired!`);
this._permanentFailure = true;
this._onDidStateChange.fire(new ReconnectionPermanentFailureEvent());
this.protocol.acceptDisconnect();
this._options.logService.error(`${logPrefix} An error occurred while reconnecting, but it will be treated as a permanent error because the reconnection grace time has expired! Will give up now! Error:`);
this._options.logService.error(err);
PersistentConnection.triggerPermanentFailure();
break;
}
if (RemoteAuthorityResolverError.isTemporarilyNotAvailable(err)) {
console.warn(`A temporarily not available error occured while trying to reconnect:`);
console.warn(err);
this._options.logService.info(`${logPrefix} A temporarily not available error occured while trying to reconnect, will try again...`);
this._options.logService.trace(err);
// try again!
continue;
}
if ((err.code === 'ETIMEDOUT' || err.code === 'ENETUNREACH' || err.code === 'ECONNREFUSED' || err.code === 'ECONNRESET') && err.syscall === 'connect') {
console.warn(`A connect error occured while trying to reconnect:`);
console.warn(err);
this._options.logService.info(`${logPrefix} A network error occured while trying to reconnect, will try again...`);
this._options.logService.trace(err);
// try again!
continue;
}
if (isPromiseCanceledError(err)) {
console.warn(`A cancel error occured while trying to reconnect:`);
console.warn(err);
this._options.logService.info(`${logPrefix} A promise cancelation error occured while trying to reconnect, will try again...`);
this._options.logService.trace(err);
// try again!
continue;
}
console.error(`An error occured while trying to reconnect:`);
console.error(err);
this._permanentFailure = true;
this._onDidStateChange.fire(new ReconnectionPermanentFailureEvent());
this.protocol.acceptDisconnect();
this._options.logService.error(`${logPrefix} An unknown error occured while trying to reconnect, since this is an unknown case, it will be treated as a permanent error! Will give up now! Error:`);
this._options.logService.error(err);
PersistentConnection.triggerPermanentFailure();
break;
}
} while (!this._permanentFailure);
} while (!PersistentConnection._permanentFailure);
}
private _gotoPermanentFailure(): void {
this._onDidStateChange.fire(new ReconnectionPermanentFailureEvent());
safeDisposeProtocolAndSocket(this.protocol);
}
protected abstract _reconnect(options: ISimpleConnectionOptions): Promise<void>;
@@ -408,7 +489,7 @@ export class ManagementPersistentConnection extends PersistentConnection {
public readonly client: Client<RemoteAgentConnectionContext>;
constructor(options: IConnectionOptions, remoteAuthority: string, clientId: string, reconnectionToken: string, protocol: PersistentProtocol) {
super(options, reconnectionToken, protocol);
super(ConnectionType.Management, options, reconnectionToken, protocol);
this.client = this._register(new Client<RemoteAgentConnectionContext>(protocol, {
remoteAuthority: remoteAuthority,
clientId: clientId
@@ -426,7 +507,7 @@ export class ExtensionHostPersistentConnection extends PersistentConnection {
public readonly debugPort: number | undefined;
constructor(options: IConnectionOptions, startArguments: IRemoteExtensionHostStartParams, reconnectionToken: string, protocol: PersistentProtocol, debugPort: number | undefined) {
super(options, reconnectionToken, protocol);
super(ConnectionType.ExtensionHost, options, reconnectionToken, protocol);
this._startArguments = startArguments;
this.debugPort = debugPort;
}
@@ -436,17 +517,19 @@ export class ExtensionHostPersistentConnection extends PersistentConnection {
}
}
function connectWithTimeLimit(p: Promise<void>, timeLimit: number): Promise<void> {
return new Promise<void>((resolve, reject) => {
function connectWithTimeLimit<T>(logService: ILogService, p: Promise<T>, timeLimit: number): Promise<T> {
return new Promise<T>((resolve, reject) => {
let timeout = setTimeout(() => {
const err: any = new Error('Time limit reached');
err.code = 'ETIMEDOUT';
err.syscall = 'connect';
logService.error(`[remote-connection] The time limit has been reached for a connection. Error:`);
logService.error(err);
reject(err);
}, timeLimit);
p.then(() => {
p.then((value) => {
clearTimeout(timeout);
resolve();
resolve(value);
}, (err) => {
clearTimeout(timeout);
reject(err);
@@ -454,6 +537,17 @@ function connectWithTimeLimit(p: Promise<void>, timeLimit: number): Promise<void
});
}
function safeDisposeProtocolAndSocket(protocol: PersistentProtocol): void {
try {
protocol.acceptDisconnect();
const socket = protocol.getSocket();
protocol.dispose();
socket.dispose();
} catch (err) {
onUnexpectedError(err);
}
}
function getErrorFromMessage(msg: any): Error | null {
if (msg && msg.type === 'error') {
const error = new Error(`Connection error: ${msg.reason}`);
@@ -462,3 +556,22 @@ function getErrorFromMessage(msg: any): Error | null {
}
return null;
}
function stringRightPad(str: string, len: number): string {
while (str.length < len) {
str += ' ';
}
return str;
}
function commonLogPrefix(connectionType: ConnectionType, reconnectionToken: string, isReconnect: boolean): string {
return `[remote-connection][${stringRightPad(connectionTypeToString(connectionType), 13)}][${reconnectionToken.substr(0, 5)}…][${isReconnect ? 'reconnect' : 'initial'}]`;
}
function connectLogPrefix(options: ISimpleConnectionOptions, connectionType: ConnectionType): string {
return `${commonLogPrefix(connectionType, options.reconnectionToken, !!options.reconnectionProtocol)}[${options.host}:${options.port}]`;
}
function logElapsed(startTime: number): string {
return `${Date.now() - startTime} ms`;
}

View File

@@ -1138,9 +1138,27 @@ declare module 'vscode' {
//#endregion
//#region Joh - CompletionItemKindModifier, https://github.com/microsoft/vscode/issues/23927
//#region Joh - CompletionItemTag, https://github.com/microsoft/vscode/issues/23927
export enum CompletionItemKindModifier {
export enum SymbolTag {
Deprecated = 1
}
export interface SymbolInformation {
/**
*
*/
tags?: ReadonlyArray<SymbolTag>;
}
export interface DocumentSymbol {
/**
*
*/
tags?: ReadonlyArray<SymbolTag>;
}
export enum CompletionItemTag {
Deprecated = 1
}
@@ -1149,7 +1167,7 @@ declare module 'vscode' {
/**
*
*/
kind2?: CompletionItemKind | { base: CompletionItemKind, modifier: ReadonlyArray<CompletionItemKindModifier> };
tags?: ReadonlyArray<CompletionItemTag>;
}
//#endregion

View File

@@ -21,7 +21,6 @@ import { Selection } from 'vs/editor/common/core/selection';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import * as callh from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
import { mixin } from 'vs/base/common/objects';
import { fromArray } from 'vs/base/common/map';
@extHostNamedCustomer(MainContext.MainThreadLanguageFeatures)
export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesShape {
@@ -331,7 +330,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
return {
label: data.a,
kind: data.b,
kindModifier: data.n && fromArray(data.n),
tags: data.n,
detail: data.c,
documentation: data.d,
sortText: data.e,

View File

@@ -544,9 +544,14 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
};
// namespace: workspace
let warnedRootPathDeprecated = false;
const workspace: typeof vscode.workspace = {
get rootPath() {
console.warn(`[Deprecation Warning] 'workspace.rootPath' is deprecated and should no longer be used. Please use 'workspace.workspaceFolders' instead. (${extension.publisher}.${extension.name})`);
if (extension.isUnderDevelopment && !warnedRootPathDeprecated) {
warnedRootPathDeprecated = true;
console.warn(`[Deprecation Warning] 'workspace.rootPath' is deprecated and should no longer be used. Please use 'workspace.workspaceFolders' instead. More details: https://aka.ms/vscode-eliminating-rootpath`);
}
return extHostWorkspace.getPath();
},
set rootPath(value) {
@@ -815,7 +820,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
CommentMode: extHostTypes.CommentMode,
CompletionItem: extHostTypes.CompletionItem,
CompletionItemKind: extHostTypes.CompletionItemKind,
CompletionItemKindModifier: extHostTypes.CompletionItemKindModifier,
CompletionItemTag: extHostTypes.CompletionItemTag,
CompletionList: extHostTypes.CompletionList,
CompletionTriggerKind: extHostTypes.CompletionTriggerKind,
ConfigurationTarget: extHostTypes.ConfigurationTarget,
@@ -870,6 +875,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
StatusBarAlignment: extHostTypes.StatusBarAlignment,
SymbolInformation: extHostTypes.SymbolInformation,
SymbolKind: extHostTypes.SymbolKind,
SymbolTag: extHostTypes.SymbolTag,
Task: extHostTypes.Task,
Task2: extHostTypes.Task,
TaskGroup: extHostTypes.TaskGroup,

View File

@@ -940,7 +940,7 @@ export interface ISuggestDataDto {
k/* commitCharacters */?: string[];
l/* additionalTextEdits */?: ISingleEditOperation[];
m/* command */?: modes.Command;
n/* kindModifier */?: modes.CompletionItemKindModifier[];
n/* kindModifier */?: modes.CompletionItemTag[];
// not-standard
x?: ChainedCacheId;
}

View File

@@ -70,8 +70,8 @@ class DocumentSymbolAdapter {
const element = <modes.DocumentSymbol>{
name: info.name || '!!MISSING: name!!',
kind: typeConvert.SymbolKind.from(info.kind),
kindTags: [],
detail: undefined!, // Strict null override — avoid changing behavior
tags: info.tags && info.tags.map(typeConvert.SymbolTag.from),
detail: '',
containerName: info.containerName,
range: typeConvert.Range.from(info.location.range),
selectionRange: typeConvert.Range.from(info.location.range),
@@ -728,6 +728,7 @@ class SuggestAdapter {
//
a: item.label,
b: typeConvert.CompletionItemKind.from(item.kind),
n: item.tags && item.tags.map(typeConvert.CompletionItemTag.from),
c: item.detail,
d: typeof item.documentation === 'undefined' ? undefined : typeConvert.MarkdownString.fromStrict(item.documentation),
e: item.sortText,
@@ -739,12 +740,6 @@ class SuggestAdapter {
m: this._commands.toInternal(item.command, disposables),
};
// kind2
if (typeof item.kind2 === 'object') {
result.b = typeConvert.CompletionItemKind.from(item.kind2.base);
result.n = item.kind2.modifier.map(typeConvert.CompletionItemKindModifier.from);
}
// 'insertText'-logic
if (item.textEdit) {
result.h = item.textEdit.newText;

View File

@@ -28,7 +28,7 @@ import * as marked from 'vs/base/common/marked/marked';
import { parse } from 'vs/base/common/marshalling';
import { cloneAndChange } from 'vs/base/common/objects';
import { LogLevel as _MainLogLevel } from 'vs/platform/log/common/log';
import { coalesce } from 'vs/base/common/arrays';
import { coalesce, isNonEmptyArray } from 'vs/base/common/arrays';
import { RenderLineNumbersType } from 'vs/editor/common/config/editorOptions';
export interface PositionLike {
@@ -556,22 +556,40 @@ export namespace SymbolKind {
}
}
export namespace SymbolTag {
export function from(kind: types.SymbolTag): modes.SymbolTag {
switch (kind) {
case types.SymbolTag.Deprecated: return modes.SymbolTag.Deprecated;
}
}
export function to(kind: modes.SymbolTag): types.SymbolTag {
switch (kind) {
case modes.SymbolTag.Deprecated: return types.SymbolTag.Deprecated;
}
}
}
export namespace WorkspaceSymbol {
export function from(info: vscode.SymbolInformation): search.IWorkspaceSymbol {
return <search.IWorkspaceSymbol>{
name: info.name,
kind: SymbolKind.from(info.kind),
tags: info.tags && info.tags.map(SymbolTag.from),
containerName: info.containerName,
location: location.from(info.location)
};
}
export function to(info: search.IWorkspaceSymbol): types.SymbolInformation {
return new types.SymbolInformation(
const result = new types.SymbolInformation(
info.name,
SymbolKind.to(info.kind),
info.containerName,
location.to(info.location)
);
result.tags = info.tags && info.tags.map(SymbolTag.to);
return result;
}
}
@@ -583,7 +601,7 @@ export namespace DocumentSymbol {
range: Range.from(info.range),
selectionRange: Range.from(info.selectionRange),
kind: SymbolKind.from(info.kind),
kindTags: []
tags: info.tags ? info.tags.map(SymbolTag.from) : []
};
if (info.children) {
result.children = info.children.map(from);
@@ -598,6 +616,9 @@ export namespace DocumentSymbol {
Range.to(info.range),
Range.to(info.selectionRange),
);
if (isNonEmptyArray(info.tags)) {
result.tags = info.tags.map(SymbolTag.to);
}
if (info.children) {
result.children = info.children.map(to) as any;
}
@@ -682,17 +703,17 @@ export namespace CompletionContext {
}
}
export namespace CompletionItemKindModifier {
export namespace CompletionItemTag {
export function from(kind: types.CompletionItemKindModifier): modes.CompletionItemKindModifier {
export function from(kind: types.CompletionItemTag): modes.CompletionItemTag {
switch (kind) {
case types.CompletionItemKindModifier.Deprecated: return modes.CompletionItemKindModifier.Deprecated;
case types.CompletionItemTag.Deprecated: return modes.CompletionItemTag.Deprecated;
}
}
export function to(kind: modes.CompletionItemKindModifier): types.CompletionItemKindModifier {
export function to(kind: modes.CompletionItemTag): types.CompletionItemTag {
switch (kind) {
case modes.CompletionItemKindModifier.Deprecated: return types.CompletionItemKindModifier.Deprecated;
case modes.CompletionItemTag.Deprecated: return types.CompletionItemTag.Deprecated;
}
}
}
@@ -768,6 +789,7 @@ export namespace CompletionItem {
const result = new types.CompletionItem(suggestion.label);
result.insertText = suggestion.insertText;
result.kind = CompletionItemKind.to(suggestion.kind);
result.tags = suggestion.tags && suggestion.tags.map(CompletionItemTag.to);
result.detail = suggestion.detail;
result.documentation = htmlContent.isMarkdownString(suggestion.documentation) ? MarkdownString.to(suggestion.documentation) : suggestion.documentation;
result.sortText = suggestion.sortText;

View File

@@ -979,6 +979,10 @@ export enum SymbolKind {
TypeParameter = 25
}
export enum SymbolTag {
Deprecated = 1,
}
@es5ClassCompat
export class SymbolInformation {
@@ -991,6 +995,7 @@ export class SymbolInformation {
name: string;
location!: Location;
kind: SymbolKind;
tags?: SymbolTag[];
containerName: string | undefined;
constructor(name: string, kind: SymbolKind, containerName: string | undefined, location: Location);
@@ -1041,6 +1046,7 @@ export class DocumentSymbol {
name: string;
detail: string;
kind: SymbolKind;
tags?: SymbolTag[];
range: Range;
selectionRange: Range;
children: DocumentSymbol[];
@@ -1308,7 +1314,7 @@ export enum CompletionItemKind {
TypeParameter = 24
}
export enum CompletionItemKindModifier {
export enum CompletionItemTag {
Deprecated = 1,
}
@@ -1317,7 +1323,7 @@ export class CompletionItem implements vscode.CompletionItem {
label: string;
kind?: CompletionItemKind;
kind2?: CompletionItemKind | { base: CompletionItemKind, modifier: CompletionItemKindModifier[] };
tags?: CompletionItemTag[];
detail?: string;
documentation?: string | MarkdownString;
sortText?: string;

View File

@@ -299,7 +299,24 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
}
public $onDidChangeWebviewPanelViewStates(newStates: WebviewPanelViewStateData): void {
for (const handle of Object.keys(newStates)) {
const handles = Object.keys(newStates);
// Notify webviews of state changes in the following order:
// - Non-visible
// - Visible
// - Active
handles.sort((a, b) => {
const stateA = newStates[a];
const stateB = newStates[b];
if (stateA.active) {
return 1;
}
if (stateB.active) {
return -1;
}
return (+stateA.visible) - (+stateB.visible);
});
for (const handle of handles) {
const panel = this.getWebviewPanel(handle);
if (!panel || panel._isDisposed) {
continue;

View File

@@ -40,7 +40,6 @@ import { IStorageService } from 'vs/platform/storage/common/storage';
import { getThemeTypeSelector, DARK, HIGH_CONTRAST, LIGHT } from 'vs/platform/theme/common/themeService';
import { InMemoryUserDataProvider } from 'vs/workbench/services/userData/common/inMemoryUserDataProvider';
import { registerWindowDriver } from 'vs/platform/driver/browser/driver';
import { StaticExtensionsService, IStaticExtensionsService } from 'vs/workbench/services/extensions/common/staticExtensions';
import { BufferLogService } from 'vs/platform/log/common/bufferLog';
import { FileLogService } from 'vs/platform/log/common/fileLogService';
import { toLocalISOString } from 'vs/base/common/date';
@@ -90,7 +89,7 @@ class CodeRendererMain extends Disposable {
// Driver
if (this.configuration.driver) {
registerWindowDriver().then(d => this._register(d));
(async () => this._register(await registerWindowDriver()))();
}
// Startup
@@ -144,7 +143,7 @@ class CodeRendererMain extends Disposable {
serviceCollection.set(ISignService, signService);
// Remote Agent
const remoteAgentService = this._register(new RemoteAgentService(this.configuration.webSocketFactory, environmentService, productService, remoteAuthorityResolverService, signService));
const remoteAgentService = this._register(new RemoteAgentService(this.configuration.webSocketFactory, environmentService, productService, remoteAuthorityResolverService, signService, logService));
serviceCollection.set(IRemoteAgentService, remoteAgentService);
// Files
@@ -153,23 +152,24 @@ class CodeRendererMain extends Disposable {
// Logger
const indexedDBLogProvider = new IndexedDBLogProvider(logsPath.scheme);
indexedDBLogProvider.database.then(
() => fileService.registerProvider(logsPath.scheme, indexedDBLogProvider),
e => {
(async () => {
try {
await indexedDBLogProvider.database;
fileService.registerProvider(logsPath.scheme, indexedDBLogProvider);
} catch (error) {
(<ILogService>logService).info('Error while creating indexedDB log provider. Falling back to in-memory log provider.');
(<ILogService>logService).error(e);
(<ILogService>logService).error(error);
fileService.registerProvider(logsPath.scheme, new InMemoryLogProvider(logsPath.scheme));
}
).then(() => {
const consoleLogService = new ConsoleLogService(logService.getLevel());
const fileLogService = new FileLogService('window', environmentService.logFile, logService.getLevel(), fileService);
logService.logger = new MultiplexLogService([consoleLogService, fileLogService]);
});
// Static Extensions
const staticExtensions = new StaticExtensionsService(this.configuration.staticExtensions || []);
serviceCollection.set(IStaticExtensionsService, staticExtensions);
})();
// User Data Provider
let userDataProvider: IFileSystemProvider | undefined = this.configuration.userDataProvider;
const connection = remoteAgentService.getConnection();
if (connection) {
@@ -185,14 +185,12 @@ class CodeRendererMain extends Disposable {
}
}
}
if (!userDataProvider) {
userDataProvider = this._register(new InMemoryUserDataProvider());
}
// User Data Provider
fileService.registerProvider(Schemas.userData, userDataProvider);
// Long running services (workspace, config, storage)
const services = await Promise.all([
this.createWorkspaceService(payload, environmentService, fileService, remoteAgentService, logService).then(service => {

View File

@@ -7,7 +7,6 @@ import { URI } from 'vs/base/common/uri';
import { suggestFilename } from 'vs/base/common/mime';
import { memoize } from 'vs/base/common/decorators';
import { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry';
import { basename } from 'vs/base/common/path';
import { basenameOrAuthority, dirname } from 'vs/base/common/resources';
import { EditorInput, IEncodingSupport, EncodingMode, ConfirmResult, Verbosity, IModeSupport } from 'vs/workbench/common/editor';
import { UntitledEditorModel } from 'vs/workbench/common/editor/untitledEditorModel';
@@ -64,7 +63,7 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport
@memoize
private get shortDescription(): string {
return basename(this.labelService.getUriLabel(dirname(this.resource)));
return this.labelService.getUriBasenameLabel(dirname(this.resource));
}
@memoize

View File

@@ -170,7 +170,11 @@ export class FilesRenderer implements ITreeRenderer<ExplorerItem, FuzzyScore, IF
});
templateData.elementDisposable = templateData.label.onDidRender(() => {
this.updateWidth(stat);
try {
this.updateWidth(stat);
} catch (e) {
// noop since the element might no longer be in the tree, no update of width necessery
}
});
}

View File

@@ -5,7 +5,6 @@
import { localize } from 'vs/nls';
import { memoize } from 'vs/base/common/decorators';
import { basename } from 'vs/base/common/path';
import { dirname } from 'vs/base/common/resources';
import { URI } from 'vs/base/common/uri';
import { EncodingMode, ConfirmResult, EditorInput, IFileEditorInput, ITextEditorModel, Verbosity, IRevertOptions } from 'vs/workbench/common/editor';
@@ -147,14 +146,14 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput {
getName(): string {
if (!this.name) {
this.name = basename(this.labelService.getUriLabel(this.resource));
this.name = this.labelService.getUriBasenameLabel(this.resource);
}
return this.decorateLabel(this.name);
}
private get shortDescription(): string {
return basename(this.labelService.getUriLabel(dirname(this.resource)));
return this.labelService.getUriBasenameLabel(dirname(this.resource));
}
private get mediumDescription(): string {

View File

@@ -37,7 +37,7 @@ suite('Files - FileEditorInput', () => {
accessor = instantiationService.createInstance(ServiceAccessor);
});
test('Basics', async function () {
test.skip('Basics', async function () { // {{SQL CARBON EDIT}} skip test
let input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/file.js'), undefined, undefined);
const otherInput = instantiationService.createInstance(FileEditorInput, toResource.call(this, 'foo/bar/otherfile.js'), undefined, undefined);
const otherInputSame = instantiationService.createInstance(FileEditorInput, toResource.call(this, 'foo/bar/file.js'), undefined, undefined);

View File

@@ -16,15 +16,15 @@ import { IModelDecorationsChangeAccessor, OverviewRulerLane, IModelDeltaDecorati
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
import { ITextEditorOptions } from 'vs/platform/editor/common/editor';
import { getDocumentSymbols } from 'vs/editor/contrib/quickOpen/quickOpen';
import { DocumentSymbolProviderRegistry, DocumentSymbol, symbolKindToCssClass, SymbolKind } from 'vs/editor/common/modes';
import { DocumentSymbolProviderRegistry, DocumentSymbol, symbolKindToCssClass, SymbolKind, SymbolTag } from 'vs/editor/common/modes';
import { IRange } from 'vs/editor/common/core/range';
import { themeColorFromId } from 'vs/platform/theme/common/themeService';
import { overviewRulerRangeHighlight } from 'vs/editor/common/view/editorColorRegistry';
import { GroupIdentifier, IEditorInput } from 'vs/workbench/common/editor';
import { IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService';
import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService';
import { asPromise } from 'vs/base/common/async';
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
import { IIconLabelValueOptions } from 'vs/base/browser/ui/iconLabel/iconLabel';
export const GOTO_SYMBOL_PREFIX = '@';
export const SCOPE_PREFIX = ':';
@@ -73,10 +73,8 @@ class OutlineModel extends QuickOpenModel {
applyFilter(searchValue: string): void {
// Normalize search
let normalizedSearchValue = searchValue;
if (searchValue.indexOf(SCOPE_PREFIX) === 0) {
normalizedSearchValue = normalizedSearchValue.substr(SCOPE_PREFIX.length);
}
const searchValueLow = searchValue.toLowerCase();
const searchValuePos = searchValue.indexOf(SCOPE_PREFIX) === 0 ? 1 : 0;
// Check for match and update visibility and group label
this.entries.forEach((entry: SymbolEntry) => {
@@ -84,34 +82,24 @@ class OutlineModel extends QuickOpenModel {
// Clear all state first
entry.setGroupLabel(undefined);
entry.setShowBorder(false);
entry.setHighlights([]);
entry.setScore(undefined);
entry.setHidden(false);
// Filter by search
if (normalizedSearchValue) {
const highlights = filters.matchesFuzzy2(normalizedSearchValue, entry.getLabel());
if (highlights) {
entry.setHighlights(highlights);
entry.setHidden(false);
} else if (!entry.isHidden()) {
entry.setHidden(true);
}
if (searchValue.length > searchValuePos) {
const score = filters.fuzzyScore(
searchValue.substr(searchValuePos), searchValueLow.substr(searchValuePos), 0,
entry.getLabel(), entry.getLabel().toLowerCase(), 0,
true
);
entry.setScore(score);
entry.setHidden(!score);
}
});
// Sort properly if actually searching
if (searchValue) {
if (searchValue.indexOf(SCOPE_PREFIX) === 0) {
this.entries.sort(this.sortScoped.bind(this, searchValue.toLowerCase()));
} else {
this.entries.sort(this.sortNormal.bind(this, searchValue.toLowerCase()));
}
}
this.entries.sort(SymbolEntry.compareByRank);
// Otherwise restore order as appearing in outline
else {
this.entries.sort((a: SymbolEntry, b: SymbolEntry) => a.getIndex() - b.getIndex());
}
// Mark all type groups
const visibleResults = <SymbolEntry[]>this.getEntries(true);
@@ -156,74 +144,6 @@ class OutlineModel extends QuickOpenModel {
}
}
private sortNormal(searchValue: string, elementA: SymbolEntry, elementB: SymbolEntry): number {
// Handle hidden elements
if (elementA.isHidden() && elementB.isHidden()) {
return 0;
} else if (elementA.isHidden()) {
return 1;
} else if (elementB.isHidden()) {
return -1;
}
const elementAName = elementA.getLabel().toLowerCase();
const elementBName = elementB.getLabel().toLowerCase();
// Compare by name
const r = elementAName.localeCompare(elementBName);
if (r !== 0) {
return r;
}
// If name identical sort by range instead
const elementARange = elementA.getRange();
const elementBRange = elementB.getRange();
return elementARange.startLineNumber - elementBRange.startLineNumber;
}
private sortScoped(searchValue: string, elementA: SymbolEntry, elementB: SymbolEntry): number {
// Handle hidden elements
if (elementA.isHidden() && elementB.isHidden()) {
return 0;
} else if (elementA.isHidden()) {
return 1;
} else if (elementB.isHidden()) {
return -1;
}
// Remove scope char
searchValue = searchValue.substr(SCOPE_PREFIX.length);
// Sort by type first if scoped search
const elementATypeLabel = NLS_SYMBOL_KIND_CACHE[elementA.getKind()] || FALLBACK_NLS_SYMBOL_KIND;
const elementBTypeLabel = NLS_SYMBOL_KIND_CACHE[elementB.getKind()] || FALLBACK_NLS_SYMBOL_KIND;
let r = elementATypeLabel.localeCompare(elementBTypeLabel);
if (r !== 0) {
return r;
}
// Special sort when searching in scoped mode
if (searchValue) {
const elementAName = elementA.getLabel().toLowerCase();
const elementBName = elementB.getLabel().toLowerCase();
// Compare by name
r = elementAName.localeCompare(elementBName);
if (r !== 0) {
return r;
}
}
// Default to sort by range
const elementARange = elementA.getRange();
const elementBRange = elementB.getRange();
return elementARange.startLineNumber - elementBRange.startLineNumber;
}
private renderGroupLabel(type: SymbolKind, count: number): string {
let pattern = NLS_SYMBOL_KIND_CACHE[type];
if (!pattern) {
@@ -235,33 +155,26 @@ class OutlineModel extends QuickOpenModel {
}
class SymbolEntry extends EditorQuickOpenEntryGroup {
private editorService: IEditorService;
private index: number;
private name: string;
private kind: SymbolKind;
private icon: string;
private description: string;
private range: IRange;
private revealRange: IRange;
private handler: GotoSymbolHandler;
constructor(index: number, name: string, kind: SymbolKind, description: string, icon: string, range: IRange, revealRange: IRange, highlights: IHighlight[], editorService: IEditorService, handler: GotoSymbolHandler) {
private score?: filters.FuzzyScore;
constructor(
private readonly index: number,
private readonly name: string,
private readonly kind: SymbolKind,
private readonly description: string,
private readonly icon: string,
private readonly deprecated: boolean,
private readonly range: IRange,
private readonly revealRange: IRange,
private readonly editorService: IEditorService,
private readonly handler: GotoSymbolHandler
) {
super();
this.index = index;
this.name = name;
this.kind = kind;
this.icon = icon;
this.description = description;
this.range = range;
this.revealRange = revealRange || range;
this.setHighlights(highlights);
this.editorService = editorService;
this.handler = handler;
}
getIndex(): number {
return this.index;
setScore(score: filters.FuzzyScore | undefined): void {
this.score = score;
}
getLabel(): string {
@@ -276,6 +189,18 @@ class SymbolEntry extends EditorQuickOpenEntryGroup {
return this.icon;
}
getLabelOptions(): IIconLabelValueOptions | undefined {
return this.deprecated ? { extraClasses: ['deprecated'] } : undefined;
}
getHighlights(): [IHighlight[], IHighlight[] | undefined, IHighlight[] | undefined] {
return [
this.deprecated ? [] : filters.createMatches(this.score),
undefined,
undefined
];
}
getDescription(): string {
return this.description;
}
@@ -294,7 +219,7 @@ class SymbolEntry extends EditorQuickOpenEntryGroup {
getOptions(pinned?: boolean): ITextEditorOptions {
return {
selection: this.toSelection(),
selection: this.revealRange,
pinned
};
}
@@ -317,7 +242,7 @@ class SymbolEntry extends EditorQuickOpenEntryGroup {
// Apply selection and focus
else {
const range = this.toSelection();
const range = this.revealRange;
const activeTextEditorWidget = this.editorService.activeTextEditorWidget;
if (activeTextEditorWidget) {
activeTextEditorWidget.setSelection(range);
@@ -331,7 +256,7 @@ class SymbolEntry extends EditorQuickOpenEntryGroup {
private runPreview(): boolean {
// Select Outline Position
const range = this.toSelection();
const range = this.revealRange;
const activeTextEditorWidget = this.editorService.activeTextEditorWidget;
if (activeTextEditorWidget) {
activeTextEditorWidget.revealRangeInCenter(range, ScrollType.Smooth);
@@ -345,13 +270,36 @@ class SymbolEntry extends EditorQuickOpenEntryGroup {
return false;
}
private toSelection(): IRange {
return {
startLineNumber: this.revealRange.startLineNumber,
startColumn: this.revealRange.startColumn || 1,
endLineNumber: this.revealRange.startLineNumber,
endColumn: this.revealRange.startColumn || 1
};
static compareByRank(a: SymbolEntry, b: SymbolEntry): number {
if (!a.score && b.score) {
return 1;
} else if (a.score && !b.score) {
return -1;
}
if (a.score && b.score) {
if (a.score[0] > b.score[0]) {
return -1;
} else if (a.score[0] < b.score[0]) {
return 1;
}
}
if (a.index < b.index) {
return -1;
} else if (a.index > b.index) {
return 1;
}
return 0;
}
static compareByKindAndRank(a: SymbolEntry, b: SymbolEntry): number {
// Sort by type first if scoped search
const kindA = NLS_SYMBOL_KIND_CACHE[a.getKind()] || FALLBACK_NLS_SYMBOL_KIND;
const kindB = NLS_SYMBOL_KIND_CACHE[b.getKind()] || FALLBACK_NLS_SYMBOL_KIND;
let r = kindA.localeCompare(kindB);
if (r === 0) {
r = this.compareByRank(a, b);
}
return r;
}
}
@@ -466,11 +414,11 @@ export class GotoSymbolHandler extends QuickOpenHandler {
};
}
private toQuickOpenEntries(flattened: DocumentSymbol[]): SymbolEntry[] {
private toQuickOpenEntries(symbols: DocumentSymbol[]): SymbolEntry[] {
const results: SymbolEntry[] = [];
for (let i = 0; i < flattened.length; i++) {
const element = flattened[i];
for (let i = 0; i < symbols.length; i++) {
const element = symbols[i];
const label = strings.trim(element.name);
// Show parent scope as description
@@ -479,8 +427,8 @@ export class GotoSymbolHandler extends QuickOpenHandler {
// Add
results.push(new SymbolEntry(i,
label, element.kind, description, `symbol-icon ${icon}`,
element.range, element.selectionRange, [], this.editorService, this
label, element.kind, description, `symbol-icon ${icon}`, element.tags && element.tags.indexOf(SymbolTag.Deprecated) >= 0,
element.range, element.selectionRange, this.editorService, this
));
}
@@ -504,7 +452,7 @@ export class GotoSymbolHandler extends QuickOpenHandler {
}
if (model && types.isFunction((<ITextModel>model).getLanguageIdentifier)) {
const entries = await asPromise(() => getDocumentSymbols(<ITextModel>model, true, this.pendingOutlineRequest!.token));
const entries = await getDocumentSymbols(<ITextModel>model, true, this.pendingOutlineRequest!.token);
return new OutlineModel(this.toQuickOpenEntries(entries));
}

View File

@@ -7,8 +7,7 @@ import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as
import { Registry } from 'vs/platform/registry/common/platform';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
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 { OperatingSystem } from 'vs/base/common/platform';
import { Schemas } from 'vs/base/common/network';
import { IRemoteAgentService, RemoteExtensionLogFileName } from 'vs/workbench/services/remote/common/remoteAgentService';
import { ILogService } from 'vs/platform/log/common/log';
@@ -49,28 +48,24 @@ export const VIEW_CONTAINER: ViewContainer = Registry.as<IViewContainersRegistry
export class LabelContribution implements IWorkbenchContribution {
constructor(
@ILabelService private readonly labelService: ILabelService,
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
@IRemoteAgentService private readonly remoteAgentService: IRemoteAgentService) {
this.registerFormatters();
}
private registerFormatters(): void {
if (isWeb) {
this.remoteAgentService.getEnvironment().then(remoteEnvironment => {
if (remoteEnvironment) {
this.labelService.registerFormatter({
scheme: Schemas.vscodeRemote,
authority: this.environmentService.configuration.remoteAuthority,
formatting: {
label: '${path}',
separator: remoteEnvironment.os === OperatingSystem.Windows ? '\\' : '/',
tildify: remoteEnvironment.os !== OperatingSystem.Windows,
normalizeDriveLetter: remoteEnvironment.os === OperatingSystem.Windows
}
});
}
});
}
this.remoteAgentService.getEnvironment().then(remoteEnvironment => {
if (remoteEnvironment) {
this.labelService.registerFormatter({
scheme: Schemas.vscodeRemote,
formatting: {
label: '${path}',
separator: remoteEnvironment.os === OperatingSystem.Windows ? '\\' : '/',
tildify: remoteEnvironment.os !== OperatingSystem.Windows,
normalizeDriveLetter: remoteEnvironment.os === OperatingSystem.Windows
}
});
}
});
}
}

View File

@@ -309,7 +309,8 @@ class RemoteAgentConnectionStatusListener implements IWorkbenchContribution {
@IRemoteAgentService remoteAgentService: IRemoteAgentService,
@IProgressService progressService: IProgressService,
@IDialogService dialogService: IDialogService,
@ICommandService commandService: ICommandService
@ICommandService commandService: ICommandService,
@IContextKeyService contextKeyService: IContextKeyService
) {
const connection = remoteAgentService.getConnection();
if (connection) {
@@ -318,6 +319,7 @@ class RemoteAgentConnectionStatusListener implements IWorkbenchContribution {
let lastLocation: ProgressLocation | null = null;
let currentTimer: ReconnectionTimer | null = null;
let reconnectWaitEvent: ReconnectionWaitEvent | null = null;
let disposableListener: IDisposable | null = null;
function showProgress(location: ProgressLocation, buttons?: string[]) {
if (currentProgressPromiseResolve) {
@@ -331,7 +333,7 @@ class RemoteAgentConnectionStatusListener implements IWorkbenchContribution {
// Show dialog
progressService!.withProgress(
{ location: ProgressLocation.Dialog, buttons },
(progress) => { progressReporter = new ProgressReporter(progress); return promise; },
(progress) => { if (progressReporter) { progressReporter.currentProgress = progress; } return promise; },
(choice?) => {
// Handle choice from dialog
if (choice === 0 && buttons && reconnectWaitEvent) {
@@ -351,7 +353,6 @@ class RemoteAgentConnectionStatusListener implements IWorkbenchContribution {
// Handle choice from notification
if (choice === 0 && buttons && reconnectWaitEvent) {
reconnectWaitEvent.skipWait();
progressReporter!.report();
} else {
hideProgress();
}
@@ -365,7 +366,6 @@ class RemoteAgentConnectionStatusListener implements IWorkbenchContribution {
}
currentProgressPromiseResolve = null;
progressReporter = null;
}
connection.onDidStateChange((e) => {
@@ -373,9 +373,15 @@ class RemoteAgentConnectionStatusListener implements IWorkbenchContribution {
currentTimer.dispose();
currentTimer = null;
}
if (disposableListener) {
disposableListener.dispose();
disposableListener = null;
}
switch (e.type) {
case PersistentConnectionEventType.ConnectionLost:
if (!currentProgressPromiseResolve) {
progressReporter = new ProgressReporter(null);
showProgress(ProgressLocation.Dialog, [nls.localize('reconnectNow', "Reconnect Now")]);
}
@@ -391,9 +397,24 @@ class RemoteAgentConnectionStatusListener implements IWorkbenchContribution {
hideProgress();
showProgress(lastLocation || ProgressLocation.Notification);
progressReporter!.report(nls.localize('reconnectionRunning', "Attempting to reconnect..."));
// Register to listen for quick input is opened
disposableListener = contextKeyService.onDidChangeContext((contextKeyChangeEvent) => {
const reconnectInteraction = new Set<string>(['inQuickOpen']);
if (contextKeyChangeEvent.affectsSome(reconnectInteraction)) {
// Need to move from dialog if being shown and user needs to type in a prompt
if (lastLocation === ProgressLocation.Dialog && progressReporter !== null) {
hideProgress();
showProgress(ProgressLocation.Notification);
progressReporter.report();
}
}
});
break;
case PersistentConnectionEventType.ReconnectionPermanentFailure:
hideProgress();
progressReporter = null;
dialogService.show(Severity.Error, nls.localize('reconnectionPermanentFailure', "Cannot reconnect. Please reload the window."), [nls.localize('reloadWindow', "Reload Window"), nls.localize('cancel', "Cancel")], { cancelId: 1 }).then(choice => {
// Reload the window
@@ -404,6 +425,7 @@ class RemoteAgentConnectionStatusListener implements IWorkbenchContribution {
break;
case PersistentConnectionEventType.ConnectionGain:
hideProgress();
progressReporter = null;
break;
}
});

View File

@@ -8,13 +8,13 @@ import { URI } from 'vs/base/common/uri';
import { onUnexpectedError } from 'vs/base/common/errors';
import { ThrottledDelayer } from 'vs/base/common/async';
import { QuickOpenHandler, EditorQuickOpenEntry } from 'vs/workbench/browser/quickopen';
import { QuickOpenModel, QuickOpenEntry, compareEntries } from 'vs/base/parts/quickopen/browser/quickOpenModel';
import { QuickOpenModel, QuickOpenEntry, IHighlight } from 'vs/base/parts/quickopen/browser/quickOpenModel';
import { IAutoFocus, Mode, IEntryRunContext } from 'vs/base/parts/quickopen/common/quickOpen';
import * as filters from 'vs/base/common/filters';
import * as strings from 'vs/base/common/strings';
import { Range } from 'vs/editor/common/core/range';
import { IWorkbenchEditorConfiguration } from 'vs/workbench/common/editor';
import { symbolKindToCssClass } from 'vs/editor/common/modes';
import { symbolKindToCssClass, SymbolTag } from 'vs/editor/common/modes';
import { IResourceInput } from 'vs/platform/editor/common/editor';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
@@ -25,9 +25,12 @@ import { ILabelService } from 'vs/platform/label/common/label';
import { CancellationToken } from 'vs/base/common/cancellation';
import { Schemas } from 'vs/base/common/network';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { IIconLabelValueOptions } from 'vs/base/browser/ui/iconLabel/iconLabel';
class SymbolEntry extends EditorQuickOpenEntry {
private bearingResolve: Promise<this | undefined> | undefined;
private bearingResolve?: Promise<this | undefined>;
private score?: filters.FuzzyScore;
constructor(
private bearing: IWorkspaceSymbol,
@@ -40,6 +43,14 @@ class SymbolEntry extends EditorQuickOpenEntry {
super(editorService);
}
setScore(score: filters.FuzzyScore | undefined) {
this.score = score;
}
getHighlights(): [IHighlight[] /* Label */, IHighlight[] | undefined /* Description */, IHighlight[] | undefined /* Detail */] {
return [this.isDeprecated() ? [] : filters.createMatches(this.score), undefined, undefined];
}
getLabel(): string {
return this.bearing.name;
}
@@ -65,10 +76,18 @@ class SymbolEntry extends EditorQuickOpenEntry {
return symbolKindToCssClass(this.bearing.kind);
}
getLabelOptions(): IIconLabelValueOptions | undefined {
return this.isDeprecated() ? { extraClasses: ['deprecated'] } : undefined;
}
getResource(): URI {
return this.bearing.location.uri;
}
private isDeprecated(): boolean {
return this.bearing.tags ? this.bearing.tags.indexOf(SymbolTag.Deprecated) >= 0 : false;
}
run(mode: Mode, context: IEntryRunContext): boolean {
// resolve this type bearing if neccessary
@@ -111,18 +130,24 @@ class SymbolEntry extends EditorQuickOpenEntry {
return input;
}
static compare(elementA: SymbolEntry, elementB: SymbolEntry, searchValue: string): number {
// Sort by Type if name is identical
const elementAName = elementA.getLabel().toLowerCase();
const elementBName = elementB.getLabel().toLowerCase();
if (elementAName === elementBName) {
let elementAType = symbolKindToCssClass(elementA.bearing.kind);
let elementBType = symbolKindToCssClass(elementB.bearing.kind);
return elementAType.localeCompare(elementBType);
static compare(a: SymbolEntry, b: SymbolEntry, searchValue: string): number {
// order: score, name, kind
if (a.score && b.score) {
if (a.score[0] > b.score[0]) {
return -1;
} else if (a.score[0] < b.score[0]) {
return 1;
}
}
return compareEntries(elementA, elementB, searchValue);
const aName = a.getLabel().toLowerCase();
const bName = b.getLabel().toLowerCase();
let res = aName.localeCompare(bName);
if (res !== 0) {
return res;
}
let aKind = symbolKindToCssClass(a.bearing.kind);
let bKind = symbolKindToCssClass(b.bearing.kind);
return aKind.localeCompare(bKind);
}
}
@@ -198,6 +223,9 @@ export class OpenSymbolHandler extends QuickOpenHandler {
private fillInSymbolEntries(bucket: SymbolEntry[], provider: IWorkspaceSymbolProvider, types: IWorkspaceSymbol[], searchValue: string): void {
const pattern = strings.stripWildcards(searchValue);
const patternLow = pattern.toLowerCase();
// Convert to Entries
for (let element of types) {
if (this.options.skipLocalSymbols && !!element.containerName) {
@@ -205,7 +233,11 @@ export class OpenSymbolHandler extends QuickOpenHandler {
}
const entry = this.instantiationService.createInstance(SymbolEntry, element, provider);
entry.setHighlights(filters.matchesFuzzy2(searchValue, entry.getLabel()) || []);
entry.setScore(filters.fuzzyScore(
pattern, patternLow, 0,
entry.getLabel(), entry.getLabel().toLowerCase(), 0,
true
));
bucket.push(entry);
}
}

View File

@@ -6,7 +6,7 @@
import { onUnexpectedError } from 'vs/base/common/errors';
import { IDisposable } from 'vs/base/common/lifecycle';
import { ISearchConfiguration, ISearchConfigurationProperties } from 'vs/workbench/services/search/common/search';
import { SymbolKind, Location, ProviderResult } from 'vs/editor/common/modes';
import { SymbolKind, Location, ProviderResult, SymbolTag } from 'vs/editor/common/modes';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { URI } from 'vs/base/common/uri';
import { toResource, SideBySideEditor } from 'vs/workbench/common/editor';
@@ -19,6 +19,7 @@ export interface IWorkspaceSymbol {
name: string;
containerName?: string;
kind: SymbolKind;
tags?: SymbolTag[];
location: Location;
}

View File

@@ -340,9 +340,7 @@ export class TerminalTaskSystem implements ITaskSystem {
private async executeTask(task: Task, resolver: ITaskResolver, trigger: string): Promise<ITaskSummary> {
let promises: Promise<ITaskSummary>[] = [];
if (task.configurationProperties.dependsOn) {
// tslint:disable-next-line: no-for-in-array
for (let index in task.configurationProperties.dependsOn) {
const dependency = task.configurationProperties.dependsOn[index];
for (const dependency of task.configurationProperties.dependsOn) {
let dependencyTask = resolver.resolve(dependency.workspaceFolder, dependency.task!);
if (dependencyTask) {
let key = dependencyTask.getMapKey();

View File

@@ -216,11 +216,11 @@ export async function getResource(filename: string, matcher: ProblemMatcher, fil
if (fullPath === undefined) {
throw new Error('FileLocationKind is not actionable. Does the matcher have a filePrefix? This should never happen.');
}
fullPath = normalize(fullPath);
fullPath = fullPath.replace(/\\/g, '/');
if (fullPath[0] !== '/') {
fullPath = '/' + fullPath;
}
fullPath = normalize(fullPath);
if (matcher.uriProvider !== undefined) {
return matcher.uriProvider(fullPath);
} else {

View File

@@ -27,9 +27,10 @@ const dotnetBuild: TaskEntry = {
'\t"tasks": [',
'\t\t{',
'\t\t\t"label": "build",',
'\t\t\t"command": "dotnet build",',
'\t\t\t"command": "dotnet",',
'\t\t\t"type": "shell",',
'\t\t\t"args": [',
'\t\t\t\t"build",',
'\t\t\t\t// Ask dotnet build to generate full paths for file names.',
'\t\t\t\t"/property:GenerateFullPaths=true",',
'\t\t\t\t// Do not generate summary otherwise it leads to duplicate errors in Problems panel',

View File

@@ -985,15 +985,14 @@ export namespace KeyedTaskIdentifier {
function sortedStringify(literal: any): string {
const keys = Object.keys(literal).sort();
let result: string = '';
// tslint:disable-next-line: no-for-in-array
for (let position in keys) {
let stringified = literal[keys[position]];
for (const key of keys) {
let stringified = literal[key];
if (stringified instanceof Object) {
stringified = sortedStringify(stringified);
} else if (typeof stringified === 'string') {
stringified = stringified.replace(/,/g, ',,');
}
result += keys[position] + ',' + stringified + ',';
result += key + ',' + stringified + ',';
}
return result;
}

View File

@@ -52,7 +52,10 @@ Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions).registe
const DEAFULT_TRUSTED_DOMAINS = [
'https://code.visualstudio.com',
'https://go.microsoft.com'
'https://go.microsoft.com',
'https://github.com',
'https://marketplace.visualstudio.com',
'https://vscode-auth.github.com'
];
const configureTrustedDomainsHandler = async (

View File

@@ -194,7 +194,7 @@ class CodeRendererMain extends Disposable {
const signService = new SignService();
serviceCollection.set(ISignService, signService);
const remoteAgentService = this._register(new RemoteAgentService(this.environmentService.configuration, this.environmentService, remoteAuthorityResolverService, signService));
const remoteAgentService = this._register(new RemoteAgentService(this.environmentService.configuration, this.environmentService, remoteAuthorityResolverService, signService, logService));
serviceCollection.set(IRemoteAgentService, remoteAgentService);
// Files

View File

@@ -55,7 +55,7 @@ export abstract class BaseConfigurationResolverService extends AbstractVariableR
if (activeEditor instanceof DiffEditorInput) {
activeEditor = activeEditor.modifiedInput;
}
const fileResource = toResource(activeEditor, { filterByScheme: Schemas.file });
const fileResource = toResource(activeEditor, { filterByScheme: [Schemas.file, Schemas.userData] });
if (!fileResource) {
return undefined;
}

View File

@@ -79,7 +79,8 @@ export class RemoteExtensionHostClient extends Disposable implements IExtensionH
return { host: authority.host, port: authority.port };
}
},
signService: this._signService
signService: this._signService,
logService: this._logService
};
return this.remoteAuthorityResolverService.resolveAuthority(this._initDataProvider.remoteAuthority).then((resolverResult) => {

View File

@@ -4,8 +4,10 @@
*--------------------------------------------------------------------------------------------*/
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IExtensionDescription, IExtensionManifest, ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { UriComponents, URI } from 'vs/base/common/uri';
import { IExtensionDescription, ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { URI } from 'vs/base/common/uri';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
export const IStaticExtensionsService = createDecorator<IStaticExtensionsService>('IStaticExtensionsService');
@@ -20,7 +22,9 @@ export class StaticExtensionsService implements IStaticExtensionsService {
private readonly _descriptions: IExtensionDescription[] = [];
constructor(staticExtensions: { packageJSON: IExtensionManifest, extensionLocation: UriComponents }[]) {
constructor(@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService) {
const staticExtensions = environmentService.options && Array.isArray(environmentService.options.staticExtensions) ? environmentService.options.staticExtensions : [];
this._descriptions = staticExtensions.map(data => <IExtensionDescription>{
identifier: new ExtensionIdentifier(`${data.packageJSON.publisher}.${data.packageJSON.name}`),
extensionLocation: URI.revive(data.extensionLocation),
@@ -32,3 +36,5 @@ export class StaticExtensionsService implements IStaticExtensionsService {
return this._descriptions;
}
}
registerSingleton(IStaticExtensionsService, StaticExtensionsService, true);

View File

@@ -7,9 +7,9 @@ import * as nativeWatchdog from 'native-watchdog';
import * as net from 'net';
import * as minimist from 'vscode-minimist';
import { onUnexpectedError } from 'vs/base/common/errors';
import { Event, Emitter } from 'vs/base/common/event';
import { Event } from 'vs/base/common/event';
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
import { PersistentProtocol, ProtocolConstants, createBufferedEvent } from 'vs/base/parts/ipc/common/ipc.net';
import { PersistentProtocol, ProtocolConstants, BufferedEmitter } from 'vs/base/parts/ipc/common/ipc.net';
import { NodeSocket, WebSocketNodeSocket } from 'vs/base/parts/ipc/node/ipc.net';
import product from 'vs/platform/product/node/product';
import { IInitData } from 'vs/workbench/api/common/extHost.protocol';
@@ -164,8 +164,8 @@ async function createExtHostProtocol(): Promise<IMessagePassingProtocol> {
return new class implements IMessagePassingProtocol {
private readonly _onMessage = new Emitter<VSBuffer>();
readonly onMessage: Event<VSBuffer> = createBufferedEvent(this._onMessage.event);
private readonly _onMessage = new BufferedEmitter<VSBuffer>();
readonly onMessage: Event<VSBuffer> = this._onMessage.event;
private _terminating: boolean;

View File

@@ -12,15 +12,31 @@ import { ExtensionHostMain } from 'vs/workbench/services/extensions/common/exten
import { IHostUtils } from 'vs/workbench/api/common/extHostExtensionService';
import 'vs/workbench/services/extensions/worker/extHost.services';
// worker-self
//#region --- Define, capture, and override some globals
//todo@joh do not allow extensions to call postMessage and other globals...
declare namespace self {
function close(): void;
let close: any;
let postMessage: any;
let addEventLister: any;
let indexedDB: any;
let caches: any;
}
// do not allow extensions to call terminate
const nativeClose = self.close.bind(self);
self.close = () => console.trace('An extension called terminate and this was prevented');
let onTerminate = nativeClose;
self.close = () => console.trace(`'close' has been blocked`);
const nativePostMessage = postMessage.bind(self);
self.postMessage = () => console.trace(`'postMessage' has been blocked`);
const nativeAddEventLister = addEventListener.bind(self);
self.addEventLister = () => console.trace(`'addEventListener' has been blocked`);
// readonly, cannot redefine...
// self.indexedDB = undefined;
// self.caches = undefined;
//#endregion ---
const hostUtil = new class implements IHostUtils {
_serviceBrand: any;
@@ -35,7 +51,6 @@ const hostUtil = new class implements IHostUtils {
}
};
//todo@joh do not allow extensions to call postMessage and other globals...
class ExtensionWorker {
@@ -47,7 +62,8 @@ class ExtensionWorker {
let emitter = new Emitter<VSBuffer>();
let terminating = false;
onmessage = event => {
nativeAddEventLister('message', event => {
const { data } = event;
if (!(data instanceof ArrayBuffer)) {
console.warn('UNKNOWN data received', data);
@@ -64,14 +80,14 @@ class ExtensionWorker {
// emit non-terminate messages to the outside
emitter.fire(msg);
};
});
this.protocol = {
onMessage: emitter.event,
send: vsbuf => {
if (!terminating) {
const data = vsbuf.buffer.buffer.slice(vsbuf.buffer.byteOffset, vsbuf.buffer.byteOffset + vsbuf.buffer.byteLength);
postMessage(data, [data]);
nativePostMessage(data, [data]);
}
}
};
@@ -94,6 +110,8 @@ function connectToRenderer(protocol: IMessagePassingProtocol): Promise<IRenderer
});
}
let onTerminate = nativeClose;
(function create(): void {
const res = new ExtensionWorker();

View File

@@ -6,6 +6,7 @@
import { localize } from 'vs/nls';
import { URI } from 'vs/base/common/uri';
import { IDisposable } from 'vs/base/common/lifecycle';
import * as paths from 'vs/base/common/path';
import { Event, Emitter } from 'vs/base/common/event';
import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry, IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { Registry } from 'vs/platform/registry/common/platform';
@@ -159,6 +160,16 @@ export class LabelService implements ILabelService {
return options.endWithSeparator ? this.appendSeparatorIfMissing(label, formatting) : label;
}
getUriBasenameLabel(resource: URI): string {
const label = this.getUriLabel(resource);
const formatting = this.findFormatting(resource);
if (formatting && formatting.separator === '\\') {
return paths.win32.basename(label);
}
return paths.posix.basename(label);
}
getWorkspaceLabel(workspace: (IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IWorkspace), options?: { verbose: boolean }): string {
if (IWorkspace.isIWorkspace(workspace)) {
const identifier = toWorkspaceIdentifier(workspace);

View File

@@ -33,9 +33,11 @@ suite('URI Label', () => {
const uri1 = TestWorkspace.folders[0].uri.with({ path: TestWorkspace.folders[0].uri.path.concat('/a/b/c/d') });
assert.equal(labelService.getUriLabel(uri1, { relative: true }), isWindows ? 'a\\b\\c\\d' : 'a/b/c/d');
assert.equal(labelService.getUriLabel(uri1, { relative: false }), isWindows ? 'C:\\testWorkspace\\a\\b\\c\\d' : '/testWorkspace/a/b/c/d');
assert.equal(labelService.getUriBasenameLabel(uri1), 'd');
const uri2 = URI.file('c:\\1/2/3');
assert.equal(labelService.getUriLabel(uri2, { relative: false }), isWindows ? 'C:\\1\\2\\3' : '/c:\\1/2/3');
assert.equal(labelService.getUriBasenameLabel(uri2), '3');
});
test('custom scheme', function () {
@@ -51,6 +53,23 @@ suite('URI Label', () => {
const uri1 = URI.parse('vscode://microsoft.com/1/2/3/4/5');
assert.equal(labelService.getUriLabel(uri1, { relative: false }), 'LABEL//1/2/3/4/5/microsoft.com/END');
assert.equal(labelService.getUriBasenameLabel(uri1), 'END');
});
test('separator', function () {
labelService.registerFormatter({
scheme: 'vscode',
formatting: {
label: 'LABEL\\${path}\\${authority}\\END',
separator: '\\',
tildify: true,
normalizeDriveLetter: true
}
});
const uri1 = URI.parse('vscode://microsoft.com/1/2/3/4/5');
assert.equal(labelService.getUriLabel(uri1, { relative: false }), 'LABEL\\\\1\\2\\3\\4\\5\\microsoft.com\\END');
assert.equal(labelService.getUriBasenameLabel(uri1), 'END');
});
test('custom authority', function () {
@@ -65,6 +84,7 @@ suite('URI Label', () => {
const uri1 = URI.parse('vscode://microsoft.com/1/2/3/4/5');
assert.equal(labelService.getUriLabel(uri1, { relative: false }), 'LABEL//1/2/3/4/5/microsoft.com/END');
assert.equal(labelService.getUriBasenameLabel(uri1), 'END');
});
test('mulitple authority', function () {
@@ -96,6 +116,7 @@ suite('URI Label', () => {
// Make sure the most specific authority is picked
const uri1 = URI.parse('vscode://microsoft.com/1/2/3/4/5');
assert.equal(labelService.getUriLabel(uri1, { relative: false }), 'second');
assert.equal(labelService.getUriBasenameLabel(uri1), 'second');
});
test('custom query', function () {

View File

@@ -11,6 +11,7 @@ import { IProductService } from 'vs/platform/product/common/product';
import { IWebSocketFactory, BrowserSocketFactory } from 'vs/platform/remote/browser/browserSocketFactory';
import { ISignService } from 'vs/platform/sign/common/sign';
import { ISocketFactory } from 'vs/platform/remote/common/remoteAgentConnection';
import { ILogService } from 'vs/platform/log/common/log';
export class RemoteAgentService extends AbstractRemoteAgentService implements IRemoteAgentService {
@@ -23,12 +24,13 @@ export class RemoteAgentService extends AbstractRemoteAgentService implements IR
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService,
@IProductService productService: IProductService,
@IRemoteAuthorityResolverService remoteAuthorityResolverService: IRemoteAuthorityResolverService,
@ISignService signService: ISignService
@ISignService signService: ISignService,
@ILogService logService: ILogService
) {
super(environmentService);
this.socketFactory = new BrowserSocketFactory(webSocketFactory);
this._connection = this._register(new RemoteAgentConnection(environmentService.configuration.remoteAuthority!, productService.commit, this.socketFactory, remoteAuthorityResolverService, signService));
this._connection = this._register(new RemoteAgentConnection(environmentService.configuration.remoteAuthority!, productService.commit, this.socketFactory, remoteAuthorityResolverService, signService, logService));
}
getConnection(): IRemoteAgentConnection | null {

View File

@@ -20,6 +20,7 @@ import { INotificationService } from 'vs/platform/notification/common/notificati
import { IDiagnosticInfoOptions, IDiagnosticInfo } from 'vs/platform/diagnostics/common/diagnostics';
import { Emitter } from 'vs/base/common/event';
import { ISignService } from 'vs/platform/sign/common/sign';
import { ILogService } from 'vs/platform/log/common/log';
export abstract class AbstractRemoteAgentService extends Disposable {
@@ -86,7 +87,8 @@ export class RemoteAgentConnection extends Disposable implements IRemoteAgentCon
private readonly _commit: string | undefined,
private readonly _socketFactory: ISocketFactory,
private readonly _remoteAuthorityResolverService: IRemoteAuthorityResolverService,
private readonly _signService: ISignService
private readonly _signService: ISignService,
private readonly _logService: ILogService
) {
super();
this.remoteAuthority = remoteAuthority;
@@ -124,7 +126,8 @@ export class RemoteAgentConnection extends Disposable implements IRemoteAgentCon
return { host: authority.host, port: authority.port };
}
},
signService: this._signService
signService: this._signService,
logService: this._logService
};
const connection = this._register(await connectRemoteAgentManagement(options, this.remoteAuthority, `renderer`));
this._register(connection.onDidStateChange(e => this._onDidStateChange.fire(e)));

View File

@@ -12,6 +12,7 @@ import { nodeSocketFactory } from 'vs/platform/remote/node/nodeSocketFactory';
import { AbstractRemoteAgentService, RemoteAgentConnection } from 'vs/workbench/services/remote/common/abstractRemoteAgentService';
import { ISignService } from 'vs/platform/sign/common/sign';
import { ISocketFactory } from 'vs/platform/remote/common/remoteAgentConnection';
import { ILogService } from 'vs/platform/log/common/log';
export class RemoteAgentService extends AbstractRemoteAgentService implements IRemoteAgentService {
@@ -22,12 +23,13 @@ export class RemoteAgentService extends AbstractRemoteAgentService implements IR
constructor({ remoteAuthority }: IWindowConfiguration,
@IEnvironmentService environmentService: IEnvironmentService,
@IRemoteAuthorityResolverService remoteAuthorityResolverService: IRemoteAuthorityResolverService,
@ISignService signService: ISignService
@ISignService signService: ISignService,
@ILogService logService: ILogService
) {
super(environmentService);
this.socketFactory = nodeSocketFactory;
if (remoteAuthority) {
this._connection = this._register(new RemoteAgentConnection(remoteAuthority, product.commit, nodeSocketFactory, remoteAuthorityResolverService, signService));
this._connection = this._register(new RemoteAgentConnection(remoteAuthority, product.commit, nodeSocketFactory, remoteAuthorityResolverService, signService, logService));
}
}

View File

@@ -15,6 +15,7 @@ import { ITunnelService, RemoteTunnel } from 'vs/platform/remote/common/tunnel';
import { nodeSocketFactory } from 'vs/platform/remote/node/nodeSocketFactory';
import { ISignService } from 'vs/platform/sign/common/sign';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { ILogService } from 'vs/platform/log/common/log';
export async function createRemoteTunnel(options: IConnectionOptions, tunnelRemotePort: number): Promise<RemoteTunnel> {
const tunnel = new NodeRemoteTunnel(options, tunnelRemotePort);
@@ -90,7 +91,8 @@ export class TunnelService implements ITunnelService {
public constructor(
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
@IRemoteAuthorityResolverService private readonly remoteAuthorityResolverService: IRemoteAuthorityResolverService,
@ISignService private readonly signService: ISignService
@ISignService private readonly signService: ISignService,
@ILogService private readonly logService: ILogService
) {
}
@@ -109,7 +111,8 @@ export class TunnelService implements ITunnelService {
return { host: authority.host, port: authority.port };
}
},
signService: this.signService
signService: this.signService,
logService: this.logService
};
return createRemoteTunnel(options, remotePort);
}

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { TextFileService } from 'vs/workbench/services/textfile/common/textFileService';
import { ITextFileService, IResourceEncodings, IResourceEncoding } from 'vs/workbench/services/textfile/common/textfiles';
import { ITextFileService, IResourceEncodings, IResourceEncoding, ModelState } from 'vs/workbench/services/textfile/common/textfiles';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { ShutdownReason } from 'vs/platform/lifecycle/common/lifecycle';
import { Schemas } from 'vs/base/common/network';
@@ -26,6 +26,10 @@ export class BrowserTextFileService extends TextFileService {
}
private doBeforeShutdownSync(): boolean {
if (this.models.getAll().some(model => model.hasState(ModelState.PENDING_SAVE) || model.hasState(ModelState.PENDING_AUTO_SAVE))) {
return true; // files are pending to be saved: veto
}
const dirtyResources = this.getDirty();
if (!dirtyResources.length) {
return false; // no dirty: no veto

View File

@@ -593,6 +593,9 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
// Create new save timer and store it for disposal as needed
const handle = setTimeout(() => {
// Clear the timeout now that we are running
this.autoSaveDisposable.clear();
// Only trigger save if the version id has not changed meanwhile
if (versionId === this.versionId) {
this.doSave(versionId, { reason: SaveReason.AUTO }); // Very important here to not return the promise because if the timeout promise is canceled it will bubble up the error otherwise - do not change
@@ -943,6 +946,8 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
return this.inOrphanMode;
case ModelState.PENDING_SAVE:
return this.saveSequentializer.hasPendingSave();
case ModelState.PENDING_AUTO_SAVE:
return !!this.autoSaveDisposable.value;
case ModelState.SAVED:
return !this.dirty;
}

View File

@@ -248,10 +248,15 @@ export const enum ModelState {
DIRTY,
/**
* A model is transitioning from dirty to saved.
* A model is currently being saved but this operation has not completed yet.
*/
PENDING_SAVE,
/**
* A model is marked for being saved after a specific timeout.
*/
PENDING_AUTO_SAVE,
/**
* A model is in conflict mode when changes cannot be saved because the
* underlying file has changed. Models in conflict mode are always dirty.

View File

@@ -52,6 +52,7 @@ suite('Files - TextFileEditorModel', () => {
model.textEditorModel!.setValue('bar');
assert.ok(getLastModifiedTime(model) <= Date.now());
assert.ok(model.hasState(ModelState.DIRTY));
let savedEvent = false;
model.onDidStateChange(e => {
@@ -60,9 +61,13 @@ suite('Files - TextFileEditorModel', () => {
}
});
await model.save();
const pendingSave = model.save();
assert.ok(model.hasState(ModelState.PENDING_SAVE));
await pendingSave;
assert.ok(model.getLastSaveAttemptTime() <= Date.now());
assert.ok(model.hasState(ModelState.SAVED));
assert.ok(!model.isDirty());
assert.ok(savedEvent);

View File

@@ -75,6 +75,7 @@ import 'vs/workbench/services/themes/browser/workbenchThemeService';
import 'vs/workbench/services/label/common/labelService';
import 'vs/workbench/services/extensionManagement/common/extensionEnablementService';
import 'vs/workbench/services/notification/common/notificationService';
import 'vs/workbench/services/extensions/common/staticExtensions';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService';

View File

@@ -71,7 +71,6 @@ import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces';
import { WorkspacesService } from 'vs/platform/workspaces/electron-browser/workspacesService';
import { IMenubarService } from 'vs/platform/menubar/node/menubar';
import { MenubarService } from 'vs/platform/menubar/electron-browser/menubarService';
import { StaticExtensionsService, IStaticExtensionsService } from 'vs/workbench/services/extensions/common/staticExtensions';
registerSingleton(IClipboardService, ClipboardService, true);
registerSingleton(IRequestService, RequestService, true);
@@ -83,7 +82,6 @@ registerSingleton(IUpdateService, UpdateService);
registerSingleton(IIssueService, IssueService);
registerSingleton(IWorkspacesService, WorkspacesService);
registerSingleton(IMenubarService, MenubarService);
registerSingleton(IStaticExtensionsService, class extends StaticExtensionsService { constructor() { super([]); } });
//#endregion

View File

@@ -4,6 +4,3 @@
*--------------------------------------------------------------------------------------------*/
/* NOTE: THIS FILE WILL BE OVERWRITTEN DURING BUILD TIME, DO NOT EDIT */
div.monaco.main.css {
}

View File

@@ -4,5 +4,3 @@
*--------------------------------------------------------------------------------------------*/
// NOTE: THIS FILE WILL BE OVERWRITTEN DURING BUILD TIME, DO NOT EDIT
define([], {});