mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-13 17:22:15 -05:00
Merge from vscode e3b9b8eefc062d68ba8a4b6a817162d132f3b533 (#6932)
* Merge from vscode e3b9b8eefc062d68ba8a4b6a817162d132f3b533 * skip failing test * add comment
This commit is contained in:
@@ -1,6 +1,3 @@
|
||||
pool:
|
||||
vmImage: 'Ubuntu-16.04'
|
||||
|
||||
trigger:
|
||||
branches:
|
||||
include: ['master', 'release/*']
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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[] {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
139
src/vs/editor/browser/widget/inlineDiffMargin.ts
Normal file
139
src/vs/editor/browser/widget/inlineDiffMargin.ts
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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++;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 = [];
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ suite('OutlineModel', function () {
|
||||
name,
|
||||
detail: 'fake',
|
||||
kind: SymbolKind.Boolean,
|
||||
kindTags: [],
|
||||
tags: [],
|
||||
selectionRange: range,
|
||||
range: range
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 = [];
|
||||
}
|
||||
|
||||
@@ -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 '';
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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
8
src/vs/monaco.d.ts
vendored
@@ -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;
|
||||
|
||||
@@ -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): '/' | '\\';
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -89,7 +89,6 @@ export interface IProductConfiguration {
|
||||
readonly 'linux-x64': string;
|
||||
readonly 'darwin': string;
|
||||
};
|
||||
readonly logUploaderUrl: string;
|
||||
readonly portable?: string;
|
||||
readonly uiExtensions?: readonly string[];
|
||||
}
|
||||
|
||||
@@ -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`;
|
||||
}
|
||||
|
||||
24
src/vs/vscode.proposed.d.ts
vendored
24
src/vs/vscode.proposed.d.ts
vendored
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 => {
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 () {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)));
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -4,6 +4,3 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/* NOTE: THIS FILE WILL BE OVERWRITTEN DURING BUILD TIME, DO NOT EDIT */
|
||||
|
||||
div.monaco.main.css {
|
||||
}
|
||||
@@ -4,5 +4,3 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
// NOTE: THIS FILE WILL BE OVERWRITTEN DURING BUILD TIME, DO NOT EDIT
|
||||
|
||||
define([], {});
|
||||
Reference in New Issue
Block a user