mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-03-27 07:10:30 -04:00
Merge from vscode 011858832762aaff245b2336fb1c38166e7a10fb (#4663)
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { localize } from 'vs/nls';
|
||||
@@ -123,7 +123,7 @@ registerEditorAction(class extends EditorAction {
|
||||
alias: 'Call Hierarchy',
|
||||
menuOpts: {
|
||||
group: 'navigation',
|
||||
order: 111
|
||||
order: 1.48
|
||||
},
|
||||
kbOpts: {
|
||||
kbExpr: EditorContextKeys.editorTextFocus,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./media/callHierarchy';
|
||||
@@ -11,7 +11,7 @@ import { CallHierarchyProvider, CallHierarchyDirection, CallHierarchyItem } from
|
||||
import { WorkbenchAsyncDataTree } from 'vs/platform/list/browser/listService';
|
||||
import { FuzzyScore } from 'vs/base/common/filters';
|
||||
import * as callHTree from 'vs/workbench/contrib/callHierarchy/browser/callHierarchyTree';
|
||||
import { IAsyncDataTreeOptions } from 'vs/base/browser/ui/tree/asyncDataTree';
|
||||
import { IAsyncDataTreeOptions, IAsyncDataTreeViewState } from 'vs/base/browser/ui/tree/asyncDataTree';
|
||||
import { localize } from 'vs/nls';
|
||||
import { ScrollType } from 'vs/editor/common/editorCommon';
|
||||
import { IRange, Range } from 'vs/editor/common/core/range';
|
||||
@@ -40,25 +40,29 @@ const enum State {
|
||||
Data = 'data'
|
||||
}
|
||||
|
||||
class ToggleHierarchyDirectionAction extends Action {
|
||||
class ChangeHierarchyDirectionAction extends Action {
|
||||
|
||||
constructor(public direction: () => CallHierarchyDirection, callback: () => void) {
|
||||
super('toggle.dir', undefined, 'call-hierarchy-toggle', true, () => {
|
||||
callback();
|
||||
this._update();
|
||||
constructor(direction: CallHierarchyDirection, updateDirection: (direction: CallHierarchyDirection) => void) {
|
||||
super('', undefined, '', true, () => {
|
||||
if (direction === CallHierarchyDirection.CallsTo) {
|
||||
direction = CallHierarchyDirection.CallsFrom;
|
||||
} else {
|
||||
direction = CallHierarchyDirection.CallsTo;
|
||||
}
|
||||
updateDirection(direction);
|
||||
update();
|
||||
return Promise.resolve();
|
||||
});
|
||||
this._update();
|
||||
}
|
||||
|
||||
private _update() {
|
||||
if (this.direction() === CallHierarchyDirection.CallsFrom) {
|
||||
this.label = localize('toggle.from', "Calls From...");
|
||||
this.checked = true;
|
||||
} else {
|
||||
this.label = localize('toggle.to', "Calls To...");
|
||||
this.checked = false;
|
||||
}
|
||||
const update = () => {
|
||||
if (direction === CallHierarchyDirection.CallsFrom) {
|
||||
this.label = localize('toggle.from', "Showing Calls");
|
||||
this.class = 'calls-from';
|
||||
} else {
|
||||
this.label = localize('toggle.to', "Showing Callers");
|
||||
this.class = 'calls-to';
|
||||
}
|
||||
};
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,11 +90,12 @@ class LayoutInfo {
|
||||
|
||||
export class CallHierarchyTreePeekWidget extends PeekViewWidget {
|
||||
|
||||
private _toggleDirection: ToggleHierarchyDirectionAction;
|
||||
private _changeDirectionAction: ChangeHierarchyDirectionAction;
|
||||
private _parent: HTMLElement;
|
||||
private _message: HTMLElement;
|
||||
private _splitView: SplitView;
|
||||
private _tree: WorkbenchAsyncDataTree<CallHierarchyItem, callHTree.Call, FuzzyScore>;
|
||||
private _treeViewStates = new Map<CallHierarchyDirection, IAsyncDataTreeViewState>();
|
||||
private _editor: EmbeddedCodeEditorWidget;
|
||||
private _dim: Dimension;
|
||||
private _layoutInfo: LayoutInfo;
|
||||
@@ -311,7 +316,7 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget {
|
||||
this._tree.onDidChangeSelection(e => {
|
||||
const [element] = e.elements;
|
||||
// don't close on click
|
||||
if (element && isNonEmptyArray(element.locations) && !(e.browserEvent instanceof MouseEvent)) {
|
||||
if (element && isNonEmptyArray(element.locations) && e.browserEvent instanceof KeyboardEvent) {
|
||||
this.dispose();
|
||||
this._editorService.openEditor({
|
||||
resource: element.item.uri,
|
||||
@@ -338,7 +343,8 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget {
|
||||
async showItem(item: CallHierarchyItem): Promise<void> {
|
||||
|
||||
this._show();
|
||||
await this._tree.setInput(item);
|
||||
const viewState = this._treeViewStates.get(this._direction);
|
||||
await this._tree.setInput(item, viewState);
|
||||
|
||||
const [root] = this._tree.getNode(item).children;
|
||||
await this._tree.expand(root.element as callHTree.Call);
|
||||
@@ -352,24 +358,26 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget {
|
||||
} else {
|
||||
this._parent.dataset['state'] = State.Data;
|
||||
this._tree.domFocus();
|
||||
this._tree.setFocus([firstChild]);
|
||||
if (!viewState) {
|
||||
this._tree.setFocus([firstChild]);
|
||||
}
|
||||
this.setTitle(
|
||||
item.name,
|
||||
item.detail || this._labelService.getUriLabel(item.uri, { relative: true }),
|
||||
);
|
||||
}
|
||||
|
||||
if (!this._toggleDirection) {
|
||||
this._toggleDirection = new ToggleHierarchyDirectionAction(
|
||||
() => this._direction,
|
||||
() => {
|
||||
let newDirection = this._direction === CallHierarchyDirection.CallsFrom ? CallHierarchyDirection.CallsTo : CallHierarchyDirection.CallsFrom;
|
||||
if (!this._changeDirectionAction) {
|
||||
const changeDirection = (newDirection: CallHierarchyDirection) => {
|
||||
if (this._direction !== newDirection) {
|
||||
this._treeViewStates.set(this._direction, this._tree.getViewState());
|
||||
this._direction = newDirection;
|
||||
this.showItem(item);
|
||||
}
|
||||
);
|
||||
this._actionbarWidget.push(this._toggleDirection, { label: false, icon: true });
|
||||
this._disposables.push(this._toggleDirection);
|
||||
};
|
||||
this._changeDirectionAction = new ChangeHierarchyDirectionAction(this._direction, changeDirection);
|
||||
this._disposables.push(this._changeDirectionAction);
|
||||
this._actionbarWidget.push(this._changeDirectionAction, { icon: true, label: false });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IAsyncDataSource, ITreeRenderer, ITreeNode } from 'vs/base/browser/ui/tree/tree';
|
||||
@@ -12,6 +12,7 @@ import { IconLabel } from 'vs/base/browser/ui/iconLabel/iconLabel';
|
||||
import { symbolKindToCssClass, Location } from 'vs/editor/common/modes';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { hash } from 'vs/base/common/hash';
|
||||
|
||||
export class Call {
|
||||
constructor(
|
||||
@@ -52,7 +53,7 @@ export class SingleDirectionDataSource implements IAsyncDataSource<CallHierarchy
|
||||
|
||||
export class IdentityProvider implements IIdentityProvider<Call> {
|
||||
getId(element: Call): { toString(): string; } {
|
||||
return element.item._id;
|
||||
return hash(element.item.uri.toString(), hash(JSON.stringify(element.item.range)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><style type="text/css">.icon-canvas-transparent{opacity:0;fill:#F6F6F6;} .icon-vs-out{fill:#F6F6F6;} .icon-vs-bg{fill:#424242;} .icon-vs-action-blue{fill:#00539C;}</style><path class="icon-canvas-transparent" d="M16 16h-16v-16h16v16z" id="canvas"/><path class="icon-vs-out" d="M15.989 8l-2 2h2v4h-2l2 2h-6l-3.989-3.989v2.287l-.497.289c-.464.27-.983.413-1.503.413-1.654 0-3-1.346-3-3v-6c0-1.654 1.346-3 3-3 .52 0 1.039.143 1.503.413l.497.289v4.298h-2v2h2v1.989l3.989-3.989h-3l2-2h-2v-4h2l-2-2h6l3 3 .011 1.989-3.011 3.011h3z" id="outline"/><path class="icon-vs-bg" d="M4 4c.366 0 .705.105 1 .277v2.723h-2v4h2v2.723c-.295.171-.634.277-1 .277-1.104 0-2-.896-2-2v-6c0-1.104.896-2 2-2z" id="iconBg"/><path class="icon-vs-action-blue" d="M11.989 1h-2l2 2h-4v2h4l-2 2h2l3-3-3-3zm-4 11l3 3h2l-2-2h4v-2h-4l2-2h-2l-3 3z" id="colorAction"/></svg>
|
||||
|
Before Width: | Height: | Size: 898 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><style>.icon-canvas-transparent{opacity:0;fill:#f6f6f6}.icon-vs-out{fill:#f6f6f6}.icon-vs-bg{fill:#424242}.icon-vs-action-blue{fill:#00539c}</style><path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/><path class="icon-vs-out" d="M15.989 8l-2 2h2v4h-2l2 2h-6L6 12.011v2.287l-.497.289C5.039 14.857 4.52 15 4 15c-1.654 0-3-1.346-3-3V6c0-1.654 1.346-3 3-3 .52 0 1.039.143 1.503.413L6 3.702V8H4v2h2v1.989L9.989 8h-3l2-2h-2V2h2l-2-2h6l3 3L16 4.989 12.989 8h3z" id="outline"/><path class="icon-vs-bg" d="M4 4c.366 0 .705.105 1 .277V7H3v4h2v2.723A1.987 1.987 0 0 1 4 14a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z" id="iconBg"/><path class="icon-vs-action-blue" d="M11.989 1h-2l2 2h-4v2h4l-2 2h2l3-3-3-3zm-4 11l3 3h2l-2-2h4v-2h-4l2-2h-2l-3 3z" id="colorAction"/></svg>
|
||||
|
Before Width: | Height: | Size: 831 B |
@@ -1,6 +1,6 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.monaco-workbench .call-hierarchy .results,
|
||||
@@ -18,16 +18,18 @@
|
||||
padding-top: 3em;
|
||||
}
|
||||
|
||||
.monaco-workbench .call-hierarchy-toggle {
|
||||
background-image: url(CallerOrCalleeView_16x.svg);
|
||||
.monaco-workbench .action-label.calls-to {
|
||||
background-image: url(files_CallTo_CallTo_16x.svg);
|
||||
background-size: 14px 14px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: left center;
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .call-hierarchy-toggle,
|
||||
.hc-dark .monaco-workbench .call-hierarchy-toggle {
|
||||
background-image: url(CallerOrCalleeView_16x_dark.svg);
|
||||
.monaco-workbench .action-label.calls-from {
|
||||
background-image: url(files_CallFrom_CallFrom_16x.svg);
|
||||
background-size: 14px 14px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: left center;
|
||||
}
|
||||
|
||||
.monaco-workbench .call-hierarchy .monaco-split-view2.horizontal > .split-view-container > .split-view-view{
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><style>.icon-canvas-transparent{opacity:0;fill:#f6f6f6}.icon-vs-out{fill:#f6f6f6}.icon-vs-bg{fill:#424242}</style><path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/><path class="icon-vs-out" d="M12 6v4h2v4.987l-.398.3A3.46 3.46 0 0 1 11.5 16C9.57 16 8 14.43 8 12.5V9.006H6.344l1.318 1.322-2.119 2.119L1 7.92v-.798l4.55-4.55 2.12 2.12-1.309 1.313H8V3.5C8 1.57 9.57 0 11.5 0a3.46 3.46 0 0 1 2.102.713l.398.3V6h-2z" id="outline"/><path class="icon-vs-bg" d="M11 10.051V11h2v3.489a2.476 2.476 0 0 1-1.5.511A2.5 2.5 0 0 1 9 12.5v-9A2.5 2.5 0 0 1 11.5 1c.565 0 1.081.194 1.5.511V5h-2v5.051zM6.257 4.693l-.707-.707L2.016 7.52l3.526 3.514.707-.707-2.314-2.322h4.12v-1H3.953l2.304-2.312z" id="iconBg"/></svg>
|
||||
|
After Width: | Height: | Size: 781 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><style>.icon-canvas-transparent{opacity:0;fill:#f6f6f6}.icon-vs-out{fill:#f6f6f6}.icon-vs-bg{fill:#424242}</style><path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/><path class="icon-vs-out" d="M3.727 9.006H1.016v-3h2.693L2.4 4.692l2.12-2.12L8 6.052V3.5C8 1.57 9.57 0 11.5 0c.758 0 1.485.247 2.103.713l.362.273v14.028l-.362.273A3.465 3.465 0 0 1 11.5 16C9.57 16 8 14.43 8 12.5V8.986l-3.473 3.461-2.119-2.119 1.319-1.322z" id="outline"/><path class="icon-vs-bg" d="M11 10.051V11h2v3.489a2.476 2.476 0 0 1-1.5.511A2.5 2.5 0 0 1 9 12.5v-9A2.5 2.5 0 0 1 11.5 1c.565 0 1.081.194 1.5.511V5h-2v5.051zM3.813 4.693l2.305 2.312H2.016v1h4.12l-2.314 2.322.707.707L8.055 7.52 4.52 3.986l-.707.707z" id="iconBg"/></svg>
|
||||
|
After Width: | Height: | Size: 787 B |
@@ -1,6 +1,6 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IPosition } from 'vs/editor/common/core/position';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import './menuPreventer';
|
||||
|
||||
@@ -60,7 +60,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
|
||||
private _resizeObserver: any;
|
||||
private _onDidClose = new Emitter<ReviewZoneWidget | undefined>();
|
||||
private _onDidCreateThread = new Emitter<ReviewZoneWidget>();
|
||||
private _isCollapsed;
|
||||
private _isCollapsed: boolean;
|
||||
private _collapseAction: Action;
|
||||
private _commentGlyph?: CommentGlyphWidget;
|
||||
private _submitActionsDisposables: IDisposable[];
|
||||
|
||||
@@ -95,7 +95,7 @@ export class DebugToolbar extends Themable implements IWorkbenchContribution {
|
||||
return new MenuItemActionItem(action, this.keybindingService, this.notificationService, contextMenuService);
|
||||
}
|
||||
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ export class DebugViewlet extends ViewContainerViewlet {
|
||||
return [this.selectAndStartAction, this.configureAction, this.toggleReplAction];
|
||||
}
|
||||
|
||||
getActionItem(action: IAction): IActionItem | null {
|
||||
getActionItem(action: IAction): IActionItem | undefined {
|
||||
if (action.id === StartAction.ID) {
|
||||
this.startDebugActionItem = this.instantiationService.createInstance(StartDebugActionItem, null, action);
|
||||
return this.startDebugActionItem;
|
||||
@@ -141,7 +141,7 @@ export class DebugViewlet extends ViewContainerViewlet {
|
||||
return new MenuItemActionItem(action, this.keybindingService, this.notificationService, this.contextMenuService);
|
||||
}
|
||||
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
focusView(id: string): void {
|
||||
|
||||
@@ -33,9 +33,13 @@ import { WorkbenchAsyncDataTree, TreeResourceNavigator2 } from 'vs/platform/list
|
||||
import { dispose } from 'vs/base/common/lifecycle';
|
||||
import { createMatches, FuzzyScore } from 'vs/base/common/filters';
|
||||
import { DebugContentProvider } from 'vs/workbench/contrib/debug/common/debugContentProvider';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
|
||||
const SMART = true;
|
||||
|
||||
// RFC 2396, Appendix A: https://www.ietf.org/rfc/rfc2396.txt
|
||||
const URI_SCHEMA_PATTERN = /^[a-zA-Z][a-zA-Z0-9\+\-\.]+:/;
|
||||
|
||||
type LoadedScriptsItem = BaseTreeItem;
|
||||
|
||||
class BaseTreeItem {
|
||||
@@ -217,7 +221,7 @@ class RootFolderTreeItem extends BaseTreeItem {
|
||||
|
||||
class RootTreeItem extends BaseTreeItem {
|
||||
|
||||
constructor(private _debugModel: IDebugModel, private _environmentService: IEnvironmentService, private _contextService: IWorkspaceContextService) {
|
||||
constructor(private _debugModel: IDebugModel, private _environmentService: IEnvironmentService, private _contextService: IWorkspaceContextService, private _labelService: ILabelService) {
|
||||
super(undefined, 'Root');
|
||||
this._debugModel.getSessions().forEach(session => {
|
||||
this.add(session);
|
||||
@@ -225,7 +229,7 @@ class RootTreeItem extends BaseTreeItem {
|
||||
}
|
||||
|
||||
add(session: IDebugSession): SessionTreeItem {
|
||||
return this.createIfNeeded(session.getId(), () => new SessionTreeItem(this, session, this._environmentService, this._contextService));
|
||||
return this.createIfNeeded(session.getId(), () => new SessionTreeItem(this._labelService, this, session, this._environmentService, this._contextService));
|
||||
}
|
||||
|
||||
find(session: IDebugSession): SessionTreeItem {
|
||||
@@ -240,9 +244,11 @@ class SessionTreeItem extends BaseTreeItem {
|
||||
private _session: IDebugSession;
|
||||
private _initialized: boolean;
|
||||
private _map: Map<string, BaseTreeItem>;
|
||||
private _labelService: ILabelService;
|
||||
|
||||
constructor(parent: BaseTreeItem, session: IDebugSession, private _environmentService: IEnvironmentService, private rootProvider: IWorkspaceContextService) {
|
||||
constructor(labelService: ILabelService, parent: BaseTreeItem, session: IDebugSession, private _environmentService: IEnvironmentService, private rootProvider: IWorkspaceContextService) {
|
||||
super(parent, session.getLabel());
|
||||
this._labelService = labelService;
|
||||
this._initialized = false;
|
||||
this._session = session;
|
||||
this._map = new Map();
|
||||
@@ -309,6 +315,10 @@ class SessionTreeItem extends BaseTreeItem {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._labelService && URI_SCHEMA_PATTERN.test(path)) {
|
||||
path = this._labelService.getUriLabel(URI.parse(path));
|
||||
}
|
||||
|
||||
const match = SessionTreeItem.URL_REGEXP.exec(path);
|
||||
if (match && match.length === 3) {
|
||||
url = match[1];
|
||||
@@ -390,6 +400,7 @@ export class LoadedScriptsView extends ViewletPanel {
|
||||
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
|
||||
@IEnvironmentService private readonly environmentService: IEnvironmentService,
|
||||
@IDebugService private readonly debugService: IDebugService,
|
||||
@ILabelService private readonly labelService: ILabelService
|
||||
) {
|
||||
super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: nls.localize('loadedScriptsSection', "Loaded Scripts Section") }, keybindingService, contextMenuService, configurationService);
|
||||
this.loadedScriptsItemType = CONTEXT_LOADED_SCRIPTS_ITEM_TYPE.bindTo(contextKeyService);
|
||||
@@ -403,7 +414,7 @@ export class LoadedScriptsView extends ViewletPanel {
|
||||
|
||||
this.filter = new LoadedScriptsFilter();
|
||||
|
||||
const root = new RootTreeItem(this.debugService.getModel(), this.environmentService, this.contextService);
|
||||
const root = new RootTreeItem(this.debugService.getModel(), this.environmentService, this.contextService, this.labelService);
|
||||
|
||||
this.treeLabels = this.instantiationService.createInstance(ResourceLabels, { onDidChangeVisibility: this.onDidChangeBodyVisibility } as IResourceLabelsContainer);
|
||||
this.disposables.push(this.treeLabels);
|
||||
|
||||
@@ -309,12 +309,12 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati
|
||||
this.replInput.focus();
|
||||
}
|
||||
|
||||
getActionItem(action: IAction): IActionItem | null {
|
||||
getActionItem(action: IAction): IActionItem | undefined {
|
||||
if (action.id === SelectReplAction.ID) {
|
||||
return this.instantiationService.createInstance(SelectReplActionItem, this.selectReplAction);
|
||||
}
|
||||
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
getActions(): IAction[] {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
|
||||
@@ -40,7 +40,7 @@ suite('Debug - Source', () => {
|
||||
});
|
||||
|
||||
test('get encoded debug data', () => {
|
||||
const checkData = (uri: uri, expectedName, expectedPath, expectedSourceReference, expectedSessionId) => {
|
||||
const checkData = (uri: uri, expectedName: string, expectedPath: string, expectedSourceReference: number | undefined, expectedSessionId?: number) => {
|
||||
let { name, path, sourceReference, sessionId } = Source.getEncodedDebugData(uri);
|
||||
assert.equal(name, expectedName);
|
||||
assert.equal(path, expectedPath);
|
||||
|
||||
@@ -27,7 +27,7 @@ import { LanguageId, LanguageIdentifier } from 'vs/editor/common/modes';
|
||||
//
|
||||
|
||||
class MockGrammarContributions implements IGrammarContributions {
|
||||
private scopeName;
|
||||
private scopeName: string;
|
||||
|
||||
constructor(scopeName: string) {
|
||||
this.scopeName = scopeName;
|
||||
|
||||
@@ -7,9 +7,9 @@ import * as assert from 'assert';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { INotificationService, IPromptChoice, Severity } from 'vs/platform/notification/common/notification';
|
||||
import { INotificationService, IPromptChoice, Severity, IPromptOptions } from 'vs/platform/notification/common/notification';
|
||||
import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
|
||||
import { ExperimentalPrompts } from 'vs/workbench/contrib/experiments/electron-browser/experimentalPrompt';
|
||||
@@ -59,11 +59,11 @@ suite('Experimental Prompts', () => {
|
||||
|
||||
setup(() => {
|
||||
storageData = {};
|
||||
instantiationService.stub(IStorageService, {
|
||||
get: (a, b, c) => a === 'experiments.experiment1' ? JSON.stringify(storageData) : c,
|
||||
instantiationService.stub(IStorageService, <Partial<IStorageService>>{
|
||||
get: (a: string, b: StorageScope, c?: string) => a === 'experiments.experiment1' ? JSON.stringify(storageData) : c,
|
||||
store: (a, b, c) => {
|
||||
if (a === 'experiments.experiment1') {
|
||||
storageData = JSON.parse(b);
|
||||
storageData = JSON.parse(b + '');
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -91,7 +91,7 @@ suite('Experimental Prompts', () => {
|
||||
};
|
||||
|
||||
instantiationService.stub(INotificationService, {
|
||||
prompt: (a: Severity, b: string, c: IPromptChoice[], options) => {
|
||||
prompt: (a: Severity, b: string, c: IPromptChoice[], options: IPromptOptions) => {
|
||||
assert.equal(b, promptText);
|
||||
assert.equal(c.length, 2);
|
||||
c[0].run();
|
||||
@@ -116,7 +116,7 @@ suite('Experimental Prompts', () => {
|
||||
};
|
||||
|
||||
instantiationService.stub(INotificationService, {
|
||||
prompt: (a: Severity, b: string, c: IPromptChoice[], options) => {
|
||||
prompt: (a: Severity, b: string, c: IPromptChoice[]) => {
|
||||
assert.equal(b, promptText);
|
||||
assert.equal(c.length, 2);
|
||||
c[1].run();
|
||||
@@ -141,10 +141,10 @@ suite('Experimental Prompts', () => {
|
||||
};
|
||||
|
||||
instantiationService.stub(INotificationService, {
|
||||
prompt: (a: Severity, b: string, c: IPromptChoice[], options) => {
|
||||
prompt: (a: Severity, b: string, c: IPromptChoice[], options: IPromptOptions) => {
|
||||
assert.equal(b, promptText);
|
||||
assert.equal(c.length, 2);
|
||||
options.onCancel();
|
||||
options.onCancel!();
|
||||
return undefined!;
|
||||
}
|
||||
});
|
||||
@@ -194,4 +194,4 @@ suite('Experimental Prompts', () => {
|
||||
assert.equal(ExperimentalPrompts.getLocalizedText(englishUSTextCase.promptText, 'fr'), englishUSTextCase.promptText['en-us']);
|
||||
assert.equal(!!ExperimentalPrompts.getLocalizedText(noEnglishTextCase.promptText, 'fr'), false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -30,7 +30,7 @@ export class Query {
|
||||
return [];
|
||||
}
|
||||
if (subcommands[command]) {
|
||||
return subcommands[command].map(subcommand => `@${command}:${subcommand}${subcommand === '' ? '' : ' '}`);
|
||||
return subcommands[command].map((subcommand: string) => `@${command}:${subcommand}${subcommand === '' ? '' : ' '}`);
|
||||
}
|
||||
else {
|
||||
return [`@${command} `];
|
||||
|
||||
@@ -51,7 +51,7 @@ import { KeybindingParser } from 'vs/base/common/keybindingParser';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { getDefaultValue } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { isUndefined } from 'vs/base/common/types';
|
||||
import { isUndefined, withUndefinedAsNull } from 'vs/base/common/types';
|
||||
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
@@ -258,7 +258,7 @@ export class ExtensionEditor extends BaseEditor {
|
||||
if (action instanceof ExtensionEditorDropDownAction) {
|
||||
return action.createActionItem();
|
||||
}
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -729,7 +729,7 @@ export class ExtensionEditor extends BaseEditor {
|
||||
|
||||
constructor(extension: IExtension, parent?: IExtensionData) {
|
||||
this.extension = extension;
|
||||
this.parent = parent || null;
|
||||
this.parent = withUndefinedAsNull(parent);
|
||||
}
|
||||
|
||||
get hasChildren(): boolean {
|
||||
|
||||
@@ -161,12 +161,14 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
case 'name': options = assign(options, { sortBy: SortBy.Title }); break;
|
||||
}
|
||||
|
||||
const successCallback = model => {
|
||||
const successCallback = (model: IPagedModel<IExtension>) => {
|
||||
this.queryRequest = null;
|
||||
this.setModel(model);
|
||||
return model;
|
||||
};
|
||||
const errorCallback = e => {
|
||||
|
||||
|
||||
const errorCallback = (e: Error) => {
|
||||
const model = new PagedModel([]);
|
||||
if (!isPromiseCanceledError(e)) {
|
||||
this.queryRequest = null;
|
||||
@@ -534,7 +536,7 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
return Promise.all([othersPromise, workspacePromise])
|
||||
.then(([others, workspaceRecommendations]) => {
|
||||
fileBasedRecommendations = fileBasedRecommendations.filter(x => workspaceRecommendations.every(({ extensionId }) => x.extensionId !== extensionId));
|
||||
others = others.filter(x => x => workspaceRecommendations.every(({ extensionId }) => x.extensionId !== extensionId));
|
||||
others = others.filter(x => workspaceRecommendations.every(({ extensionId }) => x.extensionId !== extensionId));
|
||||
|
||||
const names = this.getTrimmedRecommendations(local, value, fileBasedRecommendations, others, []);
|
||||
const recommendationsWithReason = this.tipsService.getAllRecommendationsWithReason();
|
||||
|
||||
@@ -12,7 +12,7 @@ import { localize } from 'vs/nls';
|
||||
import { IExtensionManagementServerService, IExtensionTipsService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { extensionButtonProminentBackground, extensionButtonProminentForeground } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService';
|
||||
import { STATUS_BAR_HOST_NAME_BACKGROUND, STATUS_BAR_FOREGROUND, STATUS_BAR_NO_FOLDER_FOREGROUND } from 'vs/workbench/common/theme';
|
||||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
|
||||
@@ -178,7 +178,7 @@ export class RecommendationWidget extends ExtensionWidget {
|
||||
this.element = append(this.parent, $('div.bookmark'));
|
||||
const recommendation = append(this.element, $('.recommendation'));
|
||||
append(recommendation, $('span.octicon.octicon-star'));
|
||||
const applyBookmarkStyle = (theme) => {
|
||||
const applyBookmarkStyle = (theme: ITheme) => {
|
||||
const bgColor = theme.getColor(extensionButtonProminentBackground);
|
||||
const fgColor = theme.getColor(extensionButtonProminentForeground);
|
||||
recommendation.style.borderTopColor = bgColor ? bgColor.toString() : 'transparent';
|
||||
|
||||
@@ -69,9 +69,9 @@ suite('ExtensionsWorkbenchServiceTest', () => {
|
||||
instantiationService.stub(ISharedProcessService, TestSharedProcessService);
|
||||
|
||||
instantiationService.stub(IWorkspaceContextService, new TestContextService());
|
||||
instantiationService.stub(IConfigurationService, {
|
||||
instantiationService.stub(IConfigurationService, <Partial<IConfigurationService>>{
|
||||
onDidChangeConfiguration: () => { return undefined!; },
|
||||
getValue: (key?) => {
|
||||
getValue: (key?: string) => {
|
||||
return (key === AutoCheckUpdatesConfigurationKey || key === AutoUpdateConfigurationKey) ? true : undefined;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -27,6 +27,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
|
||||
import { IEditorGroupsService, IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { ResourceQueue, timeout } from 'vs/base/common/async';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
import { QueryInput } from 'sql/parts/query/common/queryInput';
|
||||
@@ -284,7 +285,7 @@ export class FileEditorTracker extends Disposable implements IWorkbenchContribut
|
||||
if (editorResource && resource.toString() === editorResource.toString()) {
|
||||
const control = editor.getControl();
|
||||
if (isCodeEditor(control)) {
|
||||
return control.saveViewState() || undefined;
|
||||
return withNullAsUndefined(control.saveViewState());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,7 +144,7 @@ export class NewFileAction extends BaseErrorReportingAction {
|
||||
}
|
||||
|
||||
const stat = new ExplorerItem(PLACEHOLDER_URI, folder, false);
|
||||
return folder.fetchChildren(this.fileService).then(() => {
|
||||
return folder.fetchChildren(this.fileService, this.explorerService).then(() => {
|
||||
folder.addChild(stat);
|
||||
|
||||
const onSuccess = (value: string) => {
|
||||
@@ -212,7 +212,7 @@ export class NewFolderAction extends BaseErrorReportingAction {
|
||||
}
|
||||
|
||||
const stat = new ExplorerItem(PLACEHOLDER_URI, folder, true);
|
||||
return folder.fetchChildren(this.fileService).then(() => {
|
||||
return folder.fetchChildren(this.fileService, this.explorerService).then(() => {
|
||||
folder.addChild(stat);
|
||||
|
||||
const onSuccess = (value: string) => {
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
import * as nls from 'vs/nls';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import * as perf from 'vs/base/common/performance';
|
||||
import { sequence } from 'vs/base/common/async';
|
||||
import { Action, IAction } from 'vs/base/common/actions';
|
||||
import { memoize } from 'vs/base/common/decorators';
|
||||
import { IFilesConfiguration, ExplorerFolderContext, FilesExplorerFocusedContext, ExplorerFocusedContext, ExplorerRootContext, ExplorerResourceReadonlyContext, IExplorerService, ExplorerResourceCut } from 'vs/workbench/contrib/files/common/files';
|
||||
@@ -49,6 +48,9 @@ import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { isEqualOrParent } from 'vs/base/common/resources';
|
||||
import { values } from 'vs/base/common/map';
|
||||
import { first } from 'vs/base/common/arrays';
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
|
||||
export class ExplorerView extends ViewletPanel {
|
||||
@@ -188,7 +190,7 @@ export class ExplorerView extends ViewletPanel {
|
||||
this.tree.domFocus();
|
||||
}
|
||||
}));
|
||||
this.disposables.push(this.explorerService.onDidSelectItem(e => this.onSelectItem(e.item, e.reveal)));
|
||||
this.disposables.push(this.explorerService.onDidSelectResource(e => this.onSelectResource(e.resource, e.reveal)));
|
||||
this.disposables.push(this.explorerService.onDidCopyItems(e => this.onCopyItems(e.items, e.cut, e.previouslyCutItems)));
|
||||
|
||||
// Update configuration
|
||||
@@ -507,27 +509,27 @@ export class ExplorerView extends ViewletPanel {
|
||||
return withNullAsUndefined(toResource(input, { supportSideBySide: true }));
|
||||
}
|
||||
|
||||
private onSelectItem(fileStat: ExplorerItem | undefined, reveal = this.autoReveal): Promise<void> {
|
||||
if (!fileStat || !this.isBodyVisible() || this.tree.getInput() === fileStat) {
|
||||
return Promise.resolve(undefined);
|
||||
private async onSelectResource(resource: URI | undefined, reveal = this.autoReveal): Promise<void> {
|
||||
if (!resource || !this.isBodyVisible()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Expand all stats in the parent chain
|
||||
const toExpand: ExplorerItem[] = [];
|
||||
let parent = fileStat.parent;
|
||||
while (parent) {
|
||||
toExpand.push(parent);
|
||||
parent = parent.parent;
|
||||
let item: ExplorerItem | undefined = this.explorerService.roots.filter(i => isEqualOrParent(resource, i.resource))[0];
|
||||
|
||||
while (item && item.resource.toString() !== resource.toString()) {
|
||||
await this.tree.expand(item);
|
||||
item = first(values(item.children), i => isEqualOrParent(resource, i.resource));
|
||||
}
|
||||
|
||||
return sequence(toExpand.reverse().map(s => () => this.tree.expand(s))).then(() => {
|
||||
if (item && item.parent) {
|
||||
if (reveal) {
|
||||
this.tree.reveal(fileStat, 0.5);
|
||||
this.tree.reveal(item, 0.5);
|
||||
}
|
||||
|
||||
this.tree.setFocus([fileStat]);
|
||||
this.tree.setSelection([fileStat]);
|
||||
});
|
||||
this.tree.setFocus([item]);
|
||||
this.tree.setSelection([item]);
|
||||
}
|
||||
}
|
||||
|
||||
private onCopyItems(stats: ExplorerItem[], cut: boolean, previousCut: ExplorerItem[] | undefined): void {
|
||||
|
||||
@@ -9,7 +9,7 @@ import * as glob from 'vs/base/common/glob';
|
||||
import { IListVirtualDelegate, ListDragOverEffect } from 'vs/base/browser/ui/list/list';
|
||||
import { IProgressService } from 'vs/platform/progress/common/progress';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { IFileService, FileKind, IFileStat, FileOperationError, FileOperationResult } from 'vs/platform/files/common/files';
|
||||
import { IFileService, FileKind, FileOperationError, FileOperationResult } from 'vs/platform/files/common/files';
|
||||
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { IDisposable, Disposable, dispose, toDisposable } from 'vs/base/common/lifecycle';
|
||||
@@ -63,10 +63,11 @@ export class ExplorerDelegate implements IListVirtualDelegate<ExplorerItem> {
|
||||
export class ExplorerDataSource implements IAsyncDataSource<ExplorerItem | ExplorerItem[], ExplorerItem> {
|
||||
|
||||
constructor(
|
||||
@IProgressService private progressService: IProgressService,
|
||||
@INotificationService private notificationService: INotificationService,
|
||||
@IWorkbenchLayoutService private layoutService: IWorkbenchLayoutService,
|
||||
@IFileService private fileService: IFileService
|
||||
@IProgressService private readonly progressService: IProgressService,
|
||||
@INotificationService private readonly notificationService: INotificationService,
|
||||
@IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService,
|
||||
@IFileService private readonly fileService: IFileService,
|
||||
@IExplorerService private readonly explorerService: IExplorerService
|
||||
) { }
|
||||
|
||||
hasChildren(element: ExplorerItem | ExplorerItem[]): boolean {
|
||||
@@ -78,7 +79,7 @@ export class ExplorerDataSource implements IAsyncDataSource<ExplorerItem | Explo
|
||||
return Promise.resolve(element);
|
||||
}
|
||||
|
||||
const promise = element.fetchChildren(this.fileService).then(undefined, e => {
|
||||
const promise = element.fetchChildren(this.fileService, this.explorerService).then(undefined, e => {
|
||||
// Do not show error for roots since we already use an explorer decoration to notify user
|
||||
if (!(element instanceof ExplorerItem && element.isRoot)) {
|
||||
this.notificationService.error(e);
|
||||
@@ -635,12 +636,12 @@ export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
|
||||
if (resources && resources.length > 0) {
|
||||
|
||||
// Resolve target to check for name collisions and ask user
|
||||
return this.fileService.resolveFile(target.resource).then((targetStat: IFileStat) => {
|
||||
return this.fileService.resolveFile(target.resource).then(targetStat => {
|
||||
|
||||
// Check for name collisions
|
||||
const targetNames = new Set<string>();
|
||||
if (targetStat.children) {
|
||||
targetStat.children.forEach((child) => {
|
||||
targetStat.children.forEach(child => {
|
||||
targetNames.add(isLinux ? child.name : child.name.toLowerCase());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { memoize } from 'vs/base/common/decorators';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { IExplorerService } from 'vs/workbench/contrib/files/common/files';
|
||||
|
||||
export class ExplorerModel implements IDisposable {
|
||||
|
||||
@@ -85,7 +86,6 @@ export class ExplorerItem {
|
||||
private _isReadonly?: boolean,
|
||||
private _name: string = resources.basenameOrAuthority(resource),
|
||||
private _mtime?: number,
|
||||
private _etag?: string,
|
||||
) {
|
||||
this._isDirectoryResolved = false;
|
||||
}
|
||||
@@ -106,10 +106,6 @@ export class ExplorerItem {
|
||||
return !!this._isReadonly;
|
||||
}
|
||||
|
||||
get etag(): string | undefined {
|
||||
return this._etag;
|
||||
}
|
||||
|
||||
get mtime(): number | undefined {
|
||||
return this._mtime;
|
||||
}
|
||||
@@ -154,7 +150,7 @@ export class ExplorerItem {
|
||||
}
|
||||
|
||||
static create(raw: IFileStat, parent: ExplorerItem | undefined, resolveTo?: URI[]): ExplorerItem {
|
||||
const stat = new ExplorerItem(raw.resource, parent, raw.isDirectory, raw.isSymbolicLink, raw.isReadonly, raw.name, raw.mtime, raw.etag);
|
||||
const stat = new ExplorerItem(raw.resource, parent, raw.isDirectory, raw.isSymbolicLink, raw.isReadonly, raw.name, raw.mtime);
|
||||
|
||||
// Recursively add children if present
|
||||
if (stat.isDirectory) {
|
||||
@@ -247,10 +243,13 @@ export class ExplorerItem {
|
||||
return this.children.get(this.getPlatformAwareName(name));
|
||||
}
|
||||
|
||||
fetchChildren(fileService: IFileService): Promise<ExplorerItem[]> {
|
||||
fetchChildren(fileService: IFileService, explorerService: IExplorerService): Promise<ExplorerItem[]> {
|
||||
let promise: Promise<any> = Promise.resolve(undefined);
|
||||
if (!this._isDirectoryResolved) {
|
||||
promise = fileService.resolveFile(this.resource, { resolveSingleChildDescendants: true }).then(stat => {
|
||||
// Resolve metadata only when the mtime is needed since this can be expensive
|
||||
// Mtime is only used when the sort order is 'modified'
|
||||
const resolveMetadata = explorerService.sortOrder === 'modified';
|
||||
promise = fileService.resolveFile(this.resource, { resolveSingleChildDescendants: true, resolveMetadata }).then(stat => {
|
||||
const resolved = ExplorerItem.create(stat, this);
|
||||
ExplorerItem.mergeLocalWithDisk(resolved, this);
|
||||
this._isDirectoryResolved = true;
|
||||
|
||||
@@ -34,7 +34,7 @@ export class ExplorerService implements IExplorerService {
|
||||
private _onDidChangeRoots = new Emitter<void>();
|
||||
private _onDidChangeItem = new Emitter<ExplorerItem | undefined>();
|
||||
private _onDidChangeEditable = new Emitter<ExplorerItem>();
|
||||
private _onDidSelectItem = new Emitter<{ item?: ExplorerItem, reveal?: boolean }>();
|
||||
private _onDidSelectResource = new Emitter<{ resource?: URI, reveal?: boolean }>();
|
||||
private _onDidCopyItems = new Emitter<{ items: ExplorerItem[], cut: boolean, previouslyCutItems: ExplorerItem[] | undefined }>();
|
||||
private disposables: IDisposable[] = [];
|
||||
private editable: { stat: ExplorerItem, data: IEditableData } | undefined;
|
||||
@@ -68,8 +68,8 @@ export class ExplorerService implements IExplorerService {
|
||||
return this._onDidChangeEditable.event;
|
||||
}
|
||||
|
||||
get onDidSelectItem(): Event<{ item?: ExplorerItem, reveal?: boolean }> {
|
||||
return this._onDidSelectItem.event;
|
||||
get onDidSelectResource(): Event<{ resource?: URI, reveal?: boolean }> {
|
||||
return this._onDidSelectResource.event;
|
||||
}
|
||||
|
||||
get onDidCopyItems(): Event<{ items: ExplorerItem[], cut: boolean, previouslyCutItems: ExplorerItem[] | undefined }> {
|
||||
@@ -142,12 +142,12 @@ export class ExplorerService implements IExplorerService {
|
||||
select(resource: URI, reveal?: boolean): Promise<void> {
|
||||
const fileStat = this.findClosest(resource);
|
||||
if (fileStat) {
|
||||
this._onDidSelectItem.fire({ item: fileStat, reveal });
|
||||
this._onDidSelectResource.fire({ resource: fileStat.resource, reveal });
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
// Stat needs to be resolved first and then revealed
|
||||
const options: IResolveFileOptions = { resolveTo: [resource] };
|
||||
const options: IResolveFileOptions = { resolveTo: [resource], resolveMetadata: false };
|
||||
const workspaceFolder = this.contextService.getWorkspaceFolder(resource);
|
||||
const rootUri = workspaceFolder ? workspaceFolder.uri : this.roots[0].resource;
|
||||
const root = this.roots.filter(r => r.resource.toString() === rootUri.toString()).pop()!;
|
||||
@@ -161,7 +161,7 @@ export class ExplorerService implements IExplorerService {
|
||||
this._onDidChangeItem.fire(item ? item.parent : undefined);
|
||||
|
||||
// Select and Reveal
|
||||
this._onDidSelectItem.fire({ item: item || undefined, reveal });
|
||||
this._onDidSelectResource.fire({ resource: item ? item.resource : undefined, reveal });
|
||||
}, () => {
|
||||
root.isError = true;
|
||||
this._onDidChangeItem.fire(root);
|
||||
@@ -192,7 +192,8 @@ export class ExplorerService implements IExplorerService {
|
||||
// Add the new file to its parent (Model)
|
||||
parents.forEach(p => {
|
||||
// We have to check if the parent is resolved #29177
|
||||
const thenable: Promise<IFileStat | undefined> = p.isDirectoryResolved ? Promise.resolve(undefined) : this.fileService.resolveFile(p.resource);
|
||||
const resolveMetadata = this.sortOrder === `modified`;
|
||||
const thenable: Promise<IFileStat | undefined> = p.isDirectoryResolved ? Promise.resolve(undefined) : this.fileService.resolveFile(p.resource, { resolveMetadata });
|
||||
thenable.then(stat => {
|
||||
if (stat) {
|
||||
const modelStat = ExplorerItem.create(stat, p.parent);
|
||||
@@ -357,10 +358,10 @@ export class ExplorerService implements IExplorerService {
|
||||
private onConfigurationUpdated(configuration: IFilesConfiguration, event?: IConfigurationChangeEvent): void {
|
||||
const configSortOrder = configuration && configuration.explorer && configuration.explorer.sortOrder || 'default';
|
||||
if (this._sortOrder !== configSortOrder) {
|
||||
const shouldFire = this._sortOrder !== undefined;
|
||||
const shouldRefresh = this._sortOrder !== undefined;
|
||||
this._sortOrder = configSortOrder;
|
||||
if (shouldFire) {
|
||||
this._onDidChangeRoots.fire();
|
||||
if (shouldRefresh) {
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ export interface IExplorerService {
|
||||
readonly onDidChangeRoots: Event<void>;
|
||||
readonly onDidChangeItem: Event<ExplorerItem | undefined>;
|
||||
readonly onDidChangeEditable: Event<ExplorerItem>;
|
||||
readonly onDidSelectItem: Event<{ item?: ExplorerItem, reveal?: boolean }>;
|
||||
readonly onDidSelectResource: Event<{ resource?: URI, reveal?: boolean }>;
|
||||
readonly onDidCopyItems: Event<{ items: ExplorerItem[], cut: boolean, previouslyCutItems: ExplorerItem[] | undefined }>;
|
||||
|
||||
setEditable(stat: ExplorerItem, data: IEditableData | null): void;
|
||||
|
||||
@@ -147,7 +147,6 @@ suite('Files - View Model', function () {
|
||||
assert.strictEqual(s1.find(toResource.call(this, 'foobar')), null);
|
||||
|
||||
assert.strictEqual(s1.find(toResource.call(this, '/')), s1);
|
||||
// assert.strictEqual(s1.find(toResource.call(this, '')), s1); //TODO@isidor this fails with proper paths usage
|
||||
});
|
||||
|
||||
test('Find with mixed case', function () {
|
||||
@@ -244,21 +243,19 @@ suite('Files - View Model', function () {
|
||||
});
|
||||
|
||||
test('Merge Local with Disk', function () {
|
||||
const d = new Date().toUTCString();
|
||||
|
||||
const merge1 = new ExplorerItem(URI.file(join('C:\\', '/path/to')), undefined, true, false, false, 'to', Date.now(), d);
|
||||
const merge2 = new ExplorerItem(URI.file(join('C:\\', '/path/to')), undefined, true, false, false, 'to', Date.now(), new Date(0).toUTCString());
|
||||
const merge1 = new ExplorerItem(URI.file(join('C:\\', '/path/to')), undefined, true, false, false, 'to', Date.now());
|
||||
const merge2 = new ExplorerItem(URI.file(join('C:\\', '/path/to')), undefined, true, false, false, 'to', Date.now());
|
||||
|
||||
// Merge Properties
|
||||
ExplorerItem.mergeLocalWithDisk(merge2, merge1);
|
||||
assert.strictEqual(merge1.mtime, merge2.mtime);
|
||||
|
||||
// Merge Child when isDirectoryResolved=false is a no-op
|
||||
merge2.addChild(new ExplorerItem(URI.file(join('C:\\', '/path/to/foo.html')), undefined, true, false, false, 'foo.html', Date.now(), d));
|
||||
merge2.addChild(new ExplorerItem(URI.file(join('C:\\', '/path/to/foo.html')), undefined, true, false, false, 'foo.html', Date.now()));
|
||||
ExplorerItem.mergeLocalWithDisk(merge2, merge1);
|
||||
|
||||
// Merge Child with isDirectoryResolved=true
|
||||
const child = new ExplorerItem(URI.file(join('C:\\', '/path/to/foo.html')), undefined, true, false, false, 'foo.html', Date.now(), d);
|
||||
const child = new ExplorerItem(URI.file(join('C:\\', '/path/to/foo.html')), undefined, true, false, false, 'foo.html', Date.now());
|
||||
merge2.removeChild(child);
|
||||
merge2.addChild(child);
|
||||
(<any>merge2)._isDirectoryResolved = true;
|
||||
|
||||
@@ -3,57 +3,6 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { Extensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions';
|
||||
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
||||
import { setFormatterConflictCallback, FormatMode, FormatKind } from 'vs/editor/contrib/format/format';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { VIEWLET_ID, IExtensionsViewlet } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||
|
||||
|
||||
class FormattingConflictHandler {
|
||||
|
||||
private _registration: IDisposable;
|
||||
|
||||
constructor(
|
||||
@INotificationService notificationService: INotificationService,
|
||||
@IViewletService private readonly _viewletService: IViewletService,
|
||||
) {
|
||||
|
||||
this._registration = setFormatterConflictCallback((ids, model, mode) => {
|
||||
if (mode & FormatMode.Auto) {
|
||||
return;
|
||||
}
|
||||
if (ids.length === 0) {
|
||||
const langName = model.getLanguageIdentifier().language;
|
||||
const message = mode & FormatKind.Document
|
||||
? localize('no.documentprovider', "There is no document formatter for '{0}'-files installed.", langName)
|
||||
: localize('no.selectionprovider', "There is no selection formatter for '{0}'-files installed.", langName);
|
||||
|
||||
const choice = {
|
||||
label: localize('install.formatter', "Install Formatter..."),
|
||||
run: () => {
|
||||
return this._viewletService.openViewlet(VIEWLET_ID, true).then(viewlet => {
|
||||
if (viewlet) {
|
||||
(viewlet as IExtensionsViewlet).search(`category:formatters ${langName}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
notificationService.prompt(Severity.Info, message, [choice]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._registration.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
Registry.as<IWorkbenchContributionsRegistry>(Extensions.Workbench).registerWorkbenchContribution(
|
||||
FormattingConflictHandler,
|
||||
LifecyclePhase.Restored
|
||||
);
|
||||
import 'vs/css!./media/format.contribution';
|
||||
import './formatActionsMultiple';
|
||||
import './formatActionsNone';
|
||||
|
||||
138
src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts
Normal file
138
src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts
Normal file
@@ -0,0 +1,138 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { EditorAction, registerEditorAction, ServicesAccessor } from 'vs/editor/browser/editorExtensions';
|
||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
import { DocumentRangeFormattingEditProviderRegistry } from 'vs/editor/common/modes';
|
||||
import * as nls from 'vs/nls';
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { IQuickInputService, IQuickPickItem, IQuickInputButton } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { formatDocumentRangeWithProvider, formatDocumentWithProvider, getRealAndSyntheticDocumentFormattersOrdered } from 'vs/editor/contrib/format/format';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { showExtensionQuery } from 'vs/workbench/contrib/format/browser/showExtensionQuery';
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
|
||||
interface IIndexedPick extends IQuickPickItem {
|
||||
index: number;
|
||||
}
|
||||
|
||||
const openExtensionAction: IQuickInputButton = {
|
||||
tooltip: nls.localize('show.ext', "Show extension..."),
|
||||
iconClass: 'format-show-extension'
|
||||
};
|
||||
|
||||
registerEditorAction(class FormatDocumentMultipleAction extends EditorAction {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: 'editor.action.formatDocument.multiple',
|
||||
label: nls.localize('formatDocument.label.multiple', "Format Document..."),
|
||||
alias: 'Format Document...',
|
||||
precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasMultipleDocumentFormattingProvider),
|
||||
kbOpts: {
|
||||
kbExpr: EditorContextKeys.editorTextFocus,
|
||||
primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_F,
|
||||
linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_I },
|
||||
weight: KeybindingWeight.EditorContrib,
|
||||
},
|
||||
menuOpts: {
|
||||
group: '1_modification',
|
||||
order: 1.3
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async run(accessor: ServicesAccessor, editor: ICodeEditor, args: any): Promise<void> {
|
||||
if (!editor.hasModel()) {
|
||||
return;
|
||||
}
|
||||
const instaService = accessor.get(IInstantiationService);
|
||||
const quickPickService = accessor.get(IQuickInputService);
|
||||
const viewletService = accessor.get(IViewletService);
|
||||
const model = editor.getModel();
|
||||
|
||||
const provider = getRealAndSyntheticDocumentFormattersOrdered(model);
|
||||
const picks = provider.map((provider, index) => {
|
||||
return <IIndexedPick>{
|
||||
index,
|
||||
label: provider.displayName || '',
|
||||
buttons: [openExtensionAction]
|
||||
};
|
||||
});
|
||||
|
||||
const pick = await quickPickService.pick(picks, {
|
||||
placeHolder: nls.localize('format.placeHolder', "Select a formatter"),
|
||||
onDidTriggerItemButton: (e) => {
|
||||
const { extensionId } = provider[e.item.index];
|
||||
return showExtensionQuery(viewletService, `@id:${extensionId!.value}`);
|
||||
}
|
||||
});
|
||||
if (pick) {
|
||||
await instaService.invokeFunction(formatDocumentWithProvider, provider[pick.index], editor, CancellationToken.None);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
registerEditorAction(class FormatSelectionMultipleAction extends EditorAction {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: 'editor.action.formatSelection.multiple',
|
||||
label: nls.localize('formatSelection.label.multiple', "Format Selection..."),
|
||||
alias: 'Format Code...',
|
||||
precondition: ContextKeyExpr.and(ContextKeyExpr.and(EditorContextKeys.writable), EditorContextKeys.hasMultipleDocumentSelectionFormattingProvider),
|
||||
kbOpts: {
|
||||
kbExpr: EditorContextKeys.editorTextFocus,
|
||||
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_F),
|
||||
weight: KeybindingWeight.EditorContrib
|
||||
},
|
||||
menuOpts: {
|
||||
when: ContextKeyExpr.and(EditorContextKeys.hasNonEmptySelection),
|
||||
group: '1_modification',
|
||||
order: 1.31
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async run(accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> {
|
||||
if (!editor.hasModel()) {
|
||||
return;
|
||||
}
|
||||
const instaService = accessor.get(IInstantiationService);
|
||||
const quickPickService = accessor.get(IQuickInputService);
|
||||
const viewletService = accessor.get(IViewletService);
|
||||
const model = editor.getModel();
|
||||
|
||||
let range: Range = editor.getSelection();
|
||||
if (range.isEmpty()) {
|
||||
range = new Range(range.startLineNumber, 1, range.startLineNumber, model.getLineMaxColumn(range.startLineNumber));
|
||||
}
|
||||
|
||||
const provider = DocumentRangeFormattingEditProviderRegistry.ordered(model);
|
||||
const picks = provider.map((provider, index) => {
|
||||
return <IIndexedPick>{
|
||||
index,
|
||||
label: provider.displayName || '',
|
||||
buttons: [openExtensionAction]
|
||||
};
|
||||
});
|
||||
|
||||
const pick = await quickPickService.pick(picks, {
|
||||
placeHolder: nls.localize('format.placeHolder', "Select a formatter"),
|
||||
onDidTriggerItemButton: (e) => {
|
||||
const { extensionId } = provider[e.item.index];
|
||||
return showExtensionQuery(viewletService, `@id:${extensionId!.value}`);
|
||||
}
|
||||
});
|
||||
if (pick) {
|
||||
await instaService.invokeFunction(formatDocumentRangeWithProvider, provider[pick.index], editor, range, CancellationToken.None);
|
||||
}
|
||||
}
|
||||
});
|
||||
61
src/vs/workbench/contrib/format/browser/formatActionsNone.ts
Normal file
61
src/vs/workbench/contrib/format/browser/formatActionsNone.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { EditorAction, registerEditorAction, ServicesAccessor } from 'vs/editor/browser/editorExtensions';
|
||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
import { DocumentFormattingEditProviderRegistry } from 'vs/editor/common/modes';
|
||||
import * as nls from 'vs/nls';
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
||||
import { showExtensionQuery } from 'vs/workbench/contrib/format/browser/showExtensionQuery';
|
||||
|
||||
registerEditorAction(class FormatDocumentMultipleAction extends EditorAction {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: 'editor.action.formatDocument.none',
|
||||
label: nls.localize('formatDocument.label.multiple', "Format Document"),
|
||||
alias: 'Format Document',
|
||||
precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasDocumentFormattingProvider.toNegated()),
|
||||
kbOpts: {
|
||||
kbExpr: ContextKeyExpr.and(EditorContextKeys.editorTextFocus, EditorContextKeys.hasDocumentFormattingProvider.toNegated()),
|
||||
primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_F,
|
||||
linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_I },
|
||||
weight: KeybindingWeight.EditorContrib,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async run(accessor: ServicesAccessor, editor: ICodeEditor, args: any): Promise<void> {
|
||||
if (!editor.hasModel()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const commandService = accessor.get(ICommandService);
|
||||
const viewletService = accessor.get(IViewletService);
|
||||
const notificationService = accessor.get(INotificationService);
|
||||
const model = editor.getModel();
|
||||
const formatterCount = DocumentFormattingEditProviderRegistry.all(model).length;
|
||||
|
||||
if (formatterCount > 1) {
|
||||
return commandService.executeCommand('editor.action.formatDocument.multiple');
|
||||
} else if (formatterCount === 1) {
|
||||
return commandService.executeCommand('editor.action.formatDocument');
|
||||
} else {
|
||||
const langName = model.getLanguageIdentifier().language;
|
||||
const message = nls.localize('no.rovider', "There is no formatter for '{0}'-files installed.", langName);
|
||||
const choice = {
|
||||
label: nls.localize('install.formatter', "Install Formatter..."),
|
||||
run: () => showExtensionQuery(viewletService, `category:formatters ${langName}`)
|
||||
};
|
||||
notificationService.prompt(Severity.Info, message, [choice]);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><g fill="#C5C5C5"><path d="M12.714 9.603c-.07.207-.15.407-.246.601l1.017 2.139c-.335.424-.718.807-1.142 1.143l-2.14-1.018c-.193.097-.394.176-.601.247l-.795 2.235c-.265.03-.534.05-.807.05-.272 0-.541-.02-.806-.05l-.795-2.235c-.207-.071-.408-.15-.602-.247l-2.14 1.017c-.424-.336-.807-.719-1.143-1.143l1.017-2.139c-.094-.193-.175-.393-.245-.6l-2.236-.796c-.03-.265-.05-.534-.05-.807s.02-.542.05-.807l2.236-.795c.07-.207.15-.407.246-.601l-1.016-2.139c.336-.423.719-.807 1.143-1.142l2.14 1.017c.193-.096.394-.176.602-.247l.793-2.236c.265-.03.534-.05.806-.05.273 0 .542.02.808.05l.795 2.236c.207.07.407.15.601.246l2.14-1.017c.424.335.807.719 1.142 1.142l-1.017 2.139c.096.194.176.394.246.601l2.236.795c.029.266.049.535.049.808s-.02.542-.05.807l-2.236.796zm-4.714-4.603c-1.657 0-3 1.343-3 3s1.343 3 3 3 3-1.343 3-3-1.343-3-3-3z"/><circle cx="8" cy="8" r="1.5"/></g></svg>
|
||||
|
After Width: | Height: | Size: 927 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><g fill="#424242"><path d="M12.714 9.603c-.07.207-.15.407-.246.601l1.017 2.139c-.335.424-.718.807-1.142 1.143l-2.14-1.018c-.193.097-.394.176-.601.247l-.795 2.235c-.265.03-.534.05-.807.05-.272 0-.541-.02-.806-.05l-.795-2.235c-.207-.071-.408-.15-.602-.247l-2.14 1.017c-.424-.336-.807-.719-1.143-1.143l1.017-2.139c-.094-.193-.175-.393-.245-.6l-2.236-.796c-.03-.265-.05-.534-.05-.807s.02-.542.05-.807l2.236-.795c.07-.207.15-.407.246-.601l-1.016-2.139c.336-.423.719-.807 1.143-1.142l2.14 1.017c.193-.096.394-.176.602-.247l.793-2.236c.265-.03.534-.05.806-.05.273 0 .542.02.808.05l.795 2.236c.207.07.407.15.601.246l2.14-1.017c.424.335.807.719 1.142 1.142l-1.017 2.139c.096.194.176.394.246.601l2.236.795c.029.266.049.535.049.808s-.02.542-.05.807l-2.236.796zm-4.714-4.603c-1.657 0-3 1.343-3 3s1.343 3 3 3 3-1.343 3-3-1.343-3-3-3z"/><circle cx="8" cy="8" r="1.5"/></g></svg>
|
||||
|
After Width: | Height: | Size: 927 B |
@@ -0,0 +1,13 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.monaco-workbench .format-show-extension {
|
||||
background-image: url('configure.svg');
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .format-show-extension,
|
||||
.hc-black .monaco-workbench .format-show-extension {
|
||||
background-image: url('configure-inverse.svg');
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { VIEWLET_ID, IExtensionsViewlet } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||
|
||||
export function showExtensionQuery(viewletService: IViewletService, query: string) {
|
||||
return viewletService.openViewlet(VIEWLET_ID, true).then(viewlet => {
|
||||
if (viewlet) {
|
||||
(viewlet as IExtensionsViewlet).search(query);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -38,7 +38,7 @@ class LogOutputChannels extends Disposable implements IWorkbenchContribution {
|
||||
outputChannelRegistry.registerChannel({ id: Constants.sqlToolsLogChannellId, label: nls.localize('sqlToolsLog', "Log (SqlTools)"), file: URI.file(toolsServiceLogFile), log: true });
|
||||
// {{SQL CARBON EDIT}} - End
|
||||
|
||||
const registerTelemetryChannel = (level) => {
|
||||
const registerTelemetryChannel = (level: LogLevel) => {
|
||||
if (level === LogLevel.Trace && !outputChannelRegistry.getChannel(Constants.telemetryLogChannelId)) {
|
||||
outputChannelRegistry.registerChannel({ id: Constants.telemetryLogChannelId, label: nls.localize('telemetryLog', "Telemetry"), file: URI.file(join(environmentService.logsPath, `telemetry.log`)), log: true });
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import { values } from 'vs/base/common/map';
|
||||
import { memoize } from 'vs/base/common/decorators';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { Hasher } from 'vs/base/common/hash';
|
||||
import { withUndefinedAsNull } from 'vs/base/common/types';
|
||||
|
||||
function compareUris(a: URI, b: URI) {
|
||||
const astr = a.toString();
|
||||
@@ -138,7 +139,7 @@ export class MarkersModel {
|
||||
}
|
||||
|
||||
getResourceMarkers(resource: URI): ResourceMarkers | null {
|
||||
return this.resourcesByUri.get(resource.toString()) || null;
|
||||
return withUndefinedAsNull(this.resourcesByUri.get(resource.toString()));
|
||||
}
|
||||
|
||||
setResourceMarkers(resource: URI, rawMarkers: IMarker[]): void {
|
||||
|
||||
@@ -628,7 +628,7 @@ export class MarkersPanel extends Panel implements IMarkerFilterController {
|
||||
if (keybinding) {
|
||||
return new ActionItem(action, action, { label: true, keybinding: keybinding.getLabel() });
|
||||
}
|
||||
return null;
|
||||
return undefined;
|
||||
},
|
||||
onHide: (wasCancelled?: boolean) => {
|
||||
if (wasCancelled) {
|
||||
@@ -670,7 +670,7 @@ export class MarkersPanel extends Panel implements IMarkerFilterController {
|
||||
return this.tree.getFocus()[0];
|
||||
}
|
||||
|
||||
public getActionItem(action: IAction): IActionItem | null {
|
||||
public getActionItem(action: IAction): IActionItem | undefined {
|
||||
if (action.id === MarkersFilterAction.ID) {
|
||||
this.filterInputActionItem = this.instantiationService.createInstance(MarkersFilterActionItem, this.filterAction, this);
|
||||
return this.filterInputActionItem;
|
||||
|
||||
@@ -253,7 +253,7 @@ class MarkerWidget extends Disposable {
|
||||
) {
|
||||
super();
|
||||
this.actionBar = this._register(new ActionBar(dom.append(parent, dom.$('.actions')), {
|
||||
actionItemProvider: (action) => action.id === QuickFixAction.ID ? instantiationService.createInstance(QuickFixActionItem, action) : null
|
||||
actionItemProvider: (action) => action.id === QuickFixAction.ID ? instantiationService.createInstance(QuickFixActionItem, action) : undefined
|
||||
}));
|
||||
this.icon = dom.append(parent, dom.$('.icon'));
|
||||
this.multilineActionbar = this._register(new ActionBar(dom.append(parent, dom.$('.multiline-actions'))));
|
||||
|
||||
@@ -75,7 +75,7 @@ export class OutputPanel extends AbstractTextResourceEditor {
|
||||
return this.actions;
|
||||
}
|
||||
|
||||
public getActionItem(action: Action): IActionItem | null {
|
||||
public getActionItem(action: Action): IActionItem | undefined {
|
||||
if (action.id === SwitchOutputAction.ID) {
|
||||
return this.instantiationService.createInstance(SwitchOutputActionItem, action);
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ export class OutputService extends Disposable implements IOutputService, ITextMo
|
||||
|
||||
private channels: Map<string, OutputChannel> = new Map<string, OutputChannel>();
|
||||
private activeChannelIdInStorage: string;
|
||||
private activeChannel: OutputChannel | null;
|
||||
private activeChannel?: OutputChannel;
|
||||
|
||||
private readonly _onActiveOutputChannel = new Emitter<string>();
|
||||
readonly onActiveOutputChannel: Event<string> = this._onActiveOutputChannel.event;
|
||||
@@ -105,7 +105,7 @@ export class OutputService extends Disposable implements IOutputService, ITextMo
|
||||
// Set active channel to first channel if not set
|
||||
if (!this.activeChannel) {
|
||||
const channels = this.getChannelDescriptors();
|
||||
this.activeChannel = channels && channels.length > 0 ? this.getChannel(channels[0].id) : null;
|
||||
this.activeChannel = channels && channels.length > 0 ? this.getChannel(channels[0].id) : undefined;
|
||||
}
|
||||
|
||||
this._register(this.lifecycleService.onShutdown(() => this.dispose()));
|
||||
@@ -140,15 +140,15 @@ export class OutputService extends Disposable implements IOutputService, ITextMo
|
||||
return promise.then(() => this._onActiveOutputChannel.fire(id));
|
||||
}
|
||||
|
||||
getChannel(id: string): OutputChannel | null {
|
||||
return this.channels.get(id) || null;
|
||||
getChannel(id: string): OutputChannel | undefined {
|
||||
return this.channels.get(id);
|
||||
}
|
||||
|
||||
getChannelDescriptors(): IOutputChannelDescriptor[] {
|
||||
return Registry.as<IOutputChannelRegistry>(Extensions.OutputChannels).getChannels();
|
||||
}
|
||||
|
||||
getActiveChannel(): IOutputChannel | null {
|
||||
getActiveChannel(): IOutputChannel | undefined {
|
||||
return this.activeChannel;
|
||||
}
|
||||
|
||||
@@ -194,7 +194,7 @@ export class OutputService extends Disposable implements IOutputService, ITextMo
|
||||
channel.model.onDispose(() => {
|
||||
if (this.activeChannel === channel) {
|
||||
const channels = this.getChannelDescriptors();
|
||||
const channel = channels.length ? this.getChannel(channels[0].id) : null;
|
||||
const channel = channels.length ? this.getChannel(channels[0].id) : undefined;
|
||||
if (channel && this.isPanelShown()) {
|
||||
this.showChannel(channel.id, true);
|
||||
} else {
|
||||
|
||||
@@ -68,7 +68,7 @@ export interface IOutputService {
|
||||
* Given the channel id returns the output channel instance.
|
||||
* Channel should be first registered via OutputChannelRegistry.
|
||||
*/
|
||||
getChannel(id: string): IOutputChannel | null;
|
||||
getChannel(id: string): IOutputChannel | undefined;
|
||||
|
||||
/**
|
||||
* Returns an array of all known output channels descriptors.
|
||||
@@ -79,7 +79,7 @@ export interface IOutputService {
|
||||
* Returns the currently active channel.
|
||||
* Only one channel can be active at a given moment.
|
||||
*/
|
||||
getActiveChannel(): IOutputChannel | null;
|
||||
getActiveChannel(): IOutputChannel | undefined;
|
||||
|
||||
/**
|
||||
* Show the channel with the passed id.
|
||||
|
||||
@@ -376,7 +376,7 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor
|
||||
if (action.id === this.recordKeysAction.id) {
|
||||
return new CheckboxActionItem(null, action);
|
||||
}
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
@@ -424,7 +424,7 @@ export class FolderSettingsActionItem extends BaseActionItem {
|
||||
this.contextMenuService.showContextMenu({
|
||||
getAnchor: () => this.container,
|
||||
getActions: () => this.getDropdownMenuActions(),
|
||||
getActionItem: () => null,
|
||||
getActionItem: () => undefined,
|
||||
onHide: () => {
|
||||
this.anchorElement.blur();
|
||||
}
|
||||
@@ -495,7 +495,7 @@ export class SettingsTargetsWidget extends Widget {
|
||||
orientation: ActionsOrientation.HORIZONTAL,
|
||||
ariaLabel: localize('settingsSwitcherBarAriaLabel', "Settings Switcher"),
|
||||
animated: false,
|
||||
actionItemProvider: (action: Action) => action.id === 'folderSettings' ? this.folderSettings : null
|
||||
actionItemProvider: (action: Action) => action.id === 'folderSettings' ? this.folderSettings : undefined
|
||||
}));
|
||||
|
||||
this.userSettings = new Action('userSettings', localize('userSettings', "User Settings"), '.settings-tab', true, () => this.updateTarget(ConfigurationTarget.USER));
|
||||
|
||||
@@ -439,7 +439,7 @@ export abstract class AbstractSettingRenderer implements ITreeRenderer<SettingsT
|
||||
}
|
||||
}
|
||||
|
||||
const onChange = value => this._onDidChangeSetting.fire({ key: element.setting.key, value, type: template.context!.valueType });
|
||||
const onChange = (value: any) => this._onDidChangeSetting.fire({ key: element.setting.key, value, type: template.context!.valueType });
|
||||
template.deprecationWarningElement.innerText = element.setting.deprecationMessage || '';
|
||||
this.renderValue(element, <ISettingItemTemplate>template, onChange);
|
||||
|
||||
@@ -698,7 +698,7 @@ export class SettingExcludeRenderer extends AbstractSettingRenderer implements I
|
||||
}
|
||||
}
|
||||
|
||||
const sortKeys = (obj) => {
|
||||
const sortKeys = (obj: Object) => {
|
||||
const keyArray = Object.keys(obj)
|
||||
.map(key => ({ key, val: obj[key] }))
|
||||
.sort((a, b) => a.key.localeCompare(b.key));
|
||||
@@ -901,7 +901,7 @@ export class SettingNumberRenderer extends AbstractSettingRenderer implements IT
|
||||
? parseInt : parseFloat;
|
||||
|
||||
const nullNumParseFn = (dataElement.valueType === 'nullable-integer' || dataElement.valueType === 'nullable-number')
|
||||
? (v => v === '' ? null : numParseFn(v)) : numParseFn;
|
||||
? ((v: string) => v === '' ? null : numParseFn(v)) : numParseFn;
|
||||
|
||||
const label = this.setElementAriaLabels(dataElement, SETTINGS_NUMBER_TEMPLATE_ID, template);
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as arrays from 'vs/base/common/arrays';
|
||||
import { isArray } from 'vs/base/common/types';
|
||||
import { isArray, withUndefinedAsNull } from 'vs/base/common/types';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { localize } from 'vs/nls';
|
||||
import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
@@ -262,11 +262,11 @@ export class SettingsTreeModel {
|
||||
}
|
||||
|
||||
getElementById(id: string): SettingsTreeElement | null {
|
||||
return this._treeElementsById.get(id) || null;
|
||||
return withUndefinedAsNull(this._treeElementsById.get(id));
|
||||
}
|
||||
|
||||
getElementsByName(name: string): SettingsTreeSettingElement[] | null {
|
||||
return this._treeElementsBySettingName.get(name) || null;
|
||||
return withUndefinedAsNull(this._treeElementsBySettingName.get(name));
|
||||
}
|
||||
|
||||
updateElementsByName(name: string): void {
|
||||
@@ -378,7 +378,7 @@ function wordifyKey(key: string): string {
|
||||
}
|
||||
|
||||
function trimCategoryForGroup(category: string, groupId: string): string {
|
||||
const doTrim = forward => {
|
||||
const doTrim = (forward: boolean) => {
|
||||
const parts = groupId.split('.');
|
||||
while (parts.length) {
|
||||
const reg = new RegExp(`^${parts.join('\\.')}(\\.|$)`, 'i');
|
||||
|
||||
@@ -403,7 +403,7 @@ export class ExcludeSettingWidget extends Disposable {
|
||||
private renderEditItem(item: IExcludeViewItem): HTMLElement {
|
||||
const rowElement = $('.setting-exclude-edit-row');
|
||||
|
||||
const onSubmit = edited => {
|
||||
const onSubmit = (edited: boolean) => {
|
||||
this.model.setEditKey(null);
|
||||
const pattern = patternInput.value.trim();
|
||||
if (edited && pattern) {
|
||||
|
||||
@@ -88,7 +88,7 @@ interface ISerializedPreferencesEditorInput {
|
||||
// Register Preferences Editor Input Factory
|
||||
class PreferencesEditorInputFactory implements IEditorInputFactory {
|
||||
|
||||
serialize(editorInput: EditorInput): string | null {
|
||||
serialize(editorInput: EditorInput): string | undefined {
|
||||
const input = <PreferencesEditorInput>editorInput;
|
||||
|
||||
if (input.details && input.master) {
|
||||
@@ -113,10 +113,10 @@ class PreferencesEditorInputFactory implements IEditorInputFactory {
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): EditorInput | null {
|
||||
deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): EditorInput | undefined {
|
||||
const deserialized: ISerializedPreferencesEditorInput = JSON.parse(serializedEditorInput);
|
||||
|
||||
const registry = Registry.as<IEditorInputFactoryRegistry>(EditorInputExtensions.EditorInputFactories);
|
||||
@@ -132,7 +132,7 @@ class PreferencesEditorInputFactory implements IEditorInputFactory {
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -287,7 +287,7 @@ class RemoteSearchProvider implements ISearchProvider {
|
||||
const timestamp = Date.now();
|
||||
const duration = timestamp - start;
|
||||
const remoteSettings: IRemoteSetting[] = (result.value || [])
|
||||
.map(r => {
|
||||
.map((r: any) => {
|
||||
const key = JSON.parse(r.setting || r.Setting);
|
||||
const packageId = r['packageid'];
|
||||
const id = getSettingKey(key, packageId);
|
||||
@@ -447,7 +447,7 @@ class SettingMatches {
|
||||
|
||||
readonly matches: IRange[];
|
||||
|
||||
constructor(searchString: string, setting: ISetting, private requireFullQueryMatch: boolean, private searchDescription, private valuesMatcher: (filter: string, setting: ISetting) => IRange[]) {
|
||||
constructor(searchString: string, setting: ISetting, private requireFullQueryMatch: boolean, private searchDescription: boolean, private valuesMatcher: (filter: string, setting: ISetting) => IRange[]) {
|
||||
this.matches = distinct(this._findMatchesInSetting(searchString, setting), (match) => `${match.startLineNumber}_${match.startColumn}_${match.endLineNumber}_${match.endColumn}_`);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cance
|
||||
import * as collections from 'vs/base/common/collections';
|
||||
import { getErrorMessage, isPromiseCanceledError } from 'vs/base/common/errors';
|
||||
import { Iterator } from 'vs/base/common/iterator';
|
||||
import { isArray } from 'vs/base/common/types';
|
||||
import { isArray, withNullAsUndefined } from 'vs/base/common/types';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import 'vs/css!./media/settingsEditor2';
|
||||
import { localize } from 'vs/nls';
|
||||
@@ -573,7 +573,7 @@ export class SettingsEditor2 extends BaseEditor {
|
||||
this.tocTree.setSelection(element ? [element] : []);
|
||||
if (this.searchResultModel) {
|
||||
if (this.viewState.filterToCategory !== element) {
|
||||
this.viewState.filterToCategory = element || undefined;
|
||||
this.viewState.filterToCategory = withNullAsUndefined(element);
|
||||
this.renderTree();
|
||||
this.settingsTree.scrollTop = 0;
|
||||
}
|
||||
|
||||
@@ -74,8 +74,8 @@ export class GotoLineAction extends QuickOpenAction {
|
||||
}
|
||||
|
||||
class GotoLineEntry extends EditorQuickOpenEntry {
|
||||
private line: number;
|
||||
private column: number;
|
||||
private line!: number;
|
||||
private column!: number;
|
||||
private handler: GotoLineHandler;
|
||||
|
||||
constructor(line: string, editorService: IEditorService, handler: GotoLineHandler) {
|
||||
@@ -140,7 +140,7 @@ class GotoLineEntry extends EditorQuickOpenEntry {
|
||||
}
|
||||
|
||||
getInput(): IEditorInput | null {
|
||||
return this.editorService.activeEditor || null;
|
||||
return types.withUndefinedAsNull(this.editorService.activeEditor);
|
||||
}
|
||||
|
||||
getOptions(pinned?: boolean): ITextEditorOptions {
|
||||
@@ -218,8 +218,8 @@ export class GotoLineHandler extends QuickOpenHandler {
|
||||
|
||||
static readonly ID = 'workbench.picker.line';
|
||||
|
||||
private rangeHighlightDecorationId: IEditorLineDecoration | null;
|
||||
private lastKnownEditorViewState: IEditorViewState | null;
|
||||
private rangeHighlightDecorationId: IEditorLineDecoration | null = null;
|
||||
private lastKnownEditorViewState: IEditorViewState | null = null;
|
||||
|
||||
constructor(@IEditorService private readonly editorService: IEditorService) {
|
||||
super();
|
||||
|
||||
@@ -289,7 +289,7 @@ class SymbolEntry extends EditorQuickOpenEntryGroup {
|
||||
}
|
||||
|
||||
getInput(): IEditorInput | null {
|
||||
return this.editorService.activeEditor || null;
|
||||
return types.withUndefinedAsNull(this.editorService.activeEditor);
|
||||
}
|
||||
|
||||
getOptions(pinned?: boolean): ITextEditorOptions {
|
||||
|
||||
@@ -137,7 +137,7 @@ export class ViewPickerHandler extends QuickOpenHandler {
|
||||
const result: ViewEntry[] = [];
|
||||
if (views.length) {
|
||||
for (const view of views) {
|
||||
if (this.contextKeyService.contextMatchesRules(view.when || null)) {
|
||||
if (this.contextKeyService.contextMatchesRules(view.when)) {
|
||||
result.push(new ViewEntry(view.name, viewlet.name, () => this.viewsService.openView(view.id, true)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,9 +294,9 @@ class DirtyDiffWidget extends PeekViewWidget {
|
||||
};
|
||||
}
|
||||
|
||||
getActionItem(action: IAction): IActionItem | null {
|
||||
getActionItem(action: IAction): IActionItem | undefined {
|
||||
if (!(action instanceof MenuItemAction)) {
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return new DiffMenuItemActionItem(action, this.keybindingService, this.notificationService, this.contextMenuService);
|
||||
|
||||
@@ -918,9 +918,9 @@ export class RepositoryPanel extends ViewletPanel {
|
||||
return this.menus.getTitleSecondaryActions();
|
||||
}
|
||||
|
||||
getActionItem(action: IAction): IActionItem | null {
|
||||
getActionItem(action: IAction): IActionItem | undefined {
|
||||
if (!(action instanceof MenuItemAction)) {
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return new ContextAwareMenuItemActionItem(action, this.keybindingService, this.notificationService, this.contextMenuService);
|
||||
@@ -1221,9 +1221,9 @@ export class SCMViewlet extends ViewContainerViewlet implements IViewModel {
|
||||
}
|
||||
}
|
||||
|
||||
getActionItem(action: IAction): IActionItem | null {
|
||||
getActionItem(action: IAction): IActionItem | undefined {
|
||||
if (!(action instanceof MenuItemAction)) {
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return new ContextAwareMenuItemActionItem(action, this.keybindingService, this.notificationService, this.contextMenuService);
|
||||
|
||||
@@ -25,6 +25,7 @@ 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 { withUndefinedAsNull } from 'vs/base/common/types';
|
||||
|
||||
class SymbolEntry extends EditorQuickOpenEntry {
|
||||
private bearingResolve: Promise<this | undefined>;
|
||||
@@ -58,7 +59,7 @@ class SymbolEntry extends EditorQuickOpenEntry {
|
||||
return this.labelService.getUriLabel(this.bearing.location.uri, { relative: true });
|
||||
}
|
||||
|
||||
return containerName || null;
|
||||
return withUndefinedAsNull(containerName);
|
||||
}
|
||||
|
||||
getIcon(): string {
|
||||
|
||||
@@ -26,6 +26,7 @@ import { overviewRulerFindMatchForeground } from 'vs/platform/theme/common/color
|
||||
import { themeColorFromId } from 'vs/platform/theme/common/themeService';
|
||||
import { IReplaceService } from 'vs/workbench/contrib/search/common/replace';
|
||||
import { editorMatchesToTextSearchResults } from 'vs/workbench/services/search/common/searchHelpers';
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
|
||||
export class Match {
|
||||
|
||||
@@ -440,7 +441,7 @@ export class BaseFolderMatch extends Disposable {
|
||||
}
|
||||
|
||||
name(): string {
|
||||
return getBaseLabel(this.resource() || undefined) || '';
|
||||
return getBaseLabel(withNullAsUndefined(this.resource())) || '';
|
||||
}
|
||||
|
||||
parent(): SearchResult {
|
||||
|
||||
@@ -7,7 +7,7 @@ import { localize } from 'vs/nls';
|
||||
import * as crypto from 'crypto';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IFileService, IFileStat, IResolveFileResult } from 'vs/platform/files/common/files';
|
||||
import { IFileService, IFileStat, IResolveFileResult, IContent } from 'vs/platform/files/common/files';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
@@ -196,12 +196,15 @@ export function getHashedRemotesFromConfig(text: string, stripEndingDotGit: bool
|
||||
export function getHashedRemotesFromUri(workspaceUri: URI, fileService: IFileService, stripEndingDotGit: boolean = false): Promise<string[]> {
|
||||
const path = workspaceUri.path;
|
||||
const uri = workspaceUri.with({ path: `${path !== '/' ? path : ''}/.git/config` });
|
||||
return fileService.resolveFile(uri).then(() => {
|
||||
return fileService.existsFile(uri).then(exists => {
|
||||
if (!exists) {
|
||||
return [];
|
||||
}
|
||||
return fileService.resolveContent(uri, { acceptTextOnly: true }).then(
|
||||
content => getHashedRemotesFromConfig(content.value, stripEndingDotGit),
|
||||
err => [] // ignore missing or binary file
|
||||
);
|
||||
}, err => []);
|
||||
});
|
||||
}
|
||||
|
||||
export class WorkspaceStats implements IWorkbenchContribution {
|
||||
@@ -431,10 +434,14 @@ export class WorkspaceStats implements IWorkbenchContribution {
|
||||
tags['workspace.android.cpp'] = true;
|
||||
}
|
||||
|
||||
function getFilePromises(filename, fileService, contentHandler): Promise<void>[] {
|
||||
function getFilePromises(filename: string, fileService: IFileService, contentHandler: (content: IContent) => void): Promise<void>[] {
|
||||
return !nameSet.has(filename) ? [] : (folders as URI[]).map(workspaceUri => {
|
||||
const uri = workspaceUri.with({ path: `${workspaceUri.path !== '/' ? workspaceUri.path : ''}/${filename}` });
|
||||
return fileService.resolveFile(uri).then(() => {
|
||||
return fileService.existsFile(uri).then(exists => {
|
||||
if (!exists) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return fileService.resolveContent(uri, { acceptTextOnly: true }).then(contentHandler);
|
||||
}, err => {
|
||||
// Ignore missing file
|
||||
@@ -613,12 +620,15 @@ export class WorkspaceStats implements IWorkbenchContribution {
|
||||
Promise.all<string[]>(workspaceUris.map(workspaceUri => {
|
||||
const path = workspaceUri.path;
|
||||
const uri = workspaceUri.with({ path: `${path !== '/' ? path : ''}/.git/config` });
|
||||
return this.fileService.resolveFile(uri).then(() => {
|
||||
return this.fileService.existsFile(uri).then(exists => {
|
||||
if (!exists) {
|
||||
return [];
|
||||
}
|
||||
return this.fileService.resolveContent(uri, { acceptTextOnly: true }).then(
|
||||
content => getDomainsOfRemotes(content.value, SecondLevelDomainWhitelist),
|
||||
err => [] // ignore missing or binary file
|
||||
);
|
||||
}, err => []);
|
||||
});
|
||||
})).then(domains => {
|
||||
const set = domains.reduce((set, list) => list.reduce((set, item) => set.add(item), set), new Set<string>());
|
||||
const list: string[] = [];
|
||||
@@ -679,12 +689,15 @@ export class WorkspaceStats implements IWorkbenchContribution {
|
||||
return Promise.all(workspaceUris.map(workspaceUri => {
|
||||
const path = workspaceUri.path;
|
||||
const uri = workspaceUri.with({ path: `${path !== '/' ? path : ''}/pom.xml` });
|
||||
return this.fileService.resolveFile(uri).then(stats => {
|
||||
return this.fileService.existsFile(uri).then(exists => {
|
||||
if (!exists) {
|
||||
return false;
|
||||
}
|
||||
return this.fileService.resolveContent(uri, { acceptTextOnly: true }).then(
|
||||
content => !!content.value.match(/azure/i),
|
||||
err => false
|
||||
);
|
||||
}, err => false);
|
||||
});
|
||||
})).then(javas => {
|
||||
if (javas.indexOf(true) !== -1) {
|
||||
tags['java'] = true;
|
||||
|
||||
@@ -841,7 +841,9 @@ export class ProblemPatternParser extends Parser {
|
||||
|
||||
private createSingleProblemPattern(value: Config.CheckedProblemPattern): ProblemPattern | null {
|
||||
let result = this.doCreateSingleProblemPattern(value, true);
|
||||
if (result.kind === undefined) {
|
||||
if (result === undefined) {
|
||||
return null;
|
||||
} else if (result.kind === undefined) {
|
||||
result.kind = ProblemLocationKind.Location;
|
||||
}
|
||||
return this.validateProblemPattern([result]) ? result : null;
|
||||
@@ -864,6 +866,9 @@ export class ProblemPatternParser extends Parser {
|
||||
let result: MultiLineProblemPattern = [];
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
let pattern = this.doCreateSingleProblemPattern(values[i], false);
|
||||
if (pattern === undefined) {
|
||||
return null;
|
||||
}
|
||||
if (i < values.length - 1) {
|
||||
if (!Types.isUndefined(pattern.loop) && pattern.loop) {
|
||||
pattern.loop = false;
|
||||
@@ -878,10 +883,10 @@ export class ProblemPatternParser extends Parser {
|
||||
return this.validateProblemPattern(result) ? result : null;
|
||||
}
|
||||
|
||||
private doCreateSingleProblemPattern(value: Config.CheckedProblemPattern, setDefaults: boolean): ProblemPattern {
|
||||
private doCreateSingleProblemPattern(value: Config.CheckedProblemPattern, setDefaults: boolean): ProblemPattern | undefined {
|
||||
const regexp = this.createRegularExpression(value.regexp);
|
||||
if (regexp === undefined) {
|
||||
throw new Error('Invalid regular expression');
|
||||
return undefined;
|
||||
}
|
||||
let result: ProblemPattern = { regexp };
|
||||
if (value.kind) {
|
||||
@@ -1680,7 +1685,7 @@ export interface IProblemMatcherRegistry {
|
||||
onReady(): Promise<void>;
|
||||
get(name: string): NamedProblemMatcher;
|
||||
keys(): string[];
|
||||
readonly onMatcherChanged;
|
||||
readonly onMatcherChanged: Event<void>;
|
||||
}
|
||||
|
||||
class ProblemMatcherRegistryImpl implements IProblemMatcherRegistry {
|
||||
|
||||
@@ -18,11 +18,8 @@ import {
|
||||
} from 'vs/workbench/contrib/tasks/common/problemMatcher';
|
||||
|
||||
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
|
||||
import * as Tasks from '../common/tasks';
|
||||
import { TaskDefinitionRegistry } from '../common/taskDefinitionRegistry';
|
||||
|
||||
import { TaskDefinition } from 'vs/workbench/contrib/tasks/node/tasks';
|
||||
import * as Tasks from './tasks';
|
||||
import { TaskDefinitionRegistry } from './taskDefinitionRegistry';
|
||||
import { ConfiguredInput } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
|
||||
|
||||
export const enum ShellQuoting {
|
||||
@@ -932,7 +929,7 @@ namespace CommandConfiguration {
|
||||
}
|
||||
|
||||
function fromBase(this: void, config: BaseCommandConfiguationShape, context: ParseContext): Tasks.CommandConfiguration | undefined {
|
||||
let name: Tasks.CommandString = ShellString.from(config.command)!;
|
||||
let name: Tasks.CommandString | undefined = ShellString.from(config.command);
|
||||
let runtime: Tasks.RuntimeType;
|
||||
if (Types.isString(config.type)) {
|
||||
if (config.type === 'shell' || config.type === 'process') {
|
||||
@@ -947,7 +944,7 @@ namespace CommandConfiguration {
|
||||
}
|
||||
|
||||
let result: Tasks.CommandConfiguration = {
|
||||
name: name!,
|
||||
name: name,
|
||||
runtime: runtime!,
|
||||
presentation: PresentationOptions.from(config, context)!
|
||||
};
|
||||
@@ -1200,7 +1197,7 @@ namespace TaskDependency {
|
||||
if (Types.isString(external)) {
|
||||
return { workspaceFolder: context.workspaceFolder, task: external };
|
||||
} else if (TaskIdentifier.is(external)) {
|
||||
return { workspaceFolder: context.workspaceFolder, task: TaskDefinition.createTaskIdentifier(external as Tasks.TaskIdentifier, context.problemReporter) };
|
||||
return { workspaceFolder: context.workspaceFolder, task: Tasks.TaskDefinition.createTaskIdentifier(external as Tasks.TaskIdentifier, context.problemReporter) };
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
@@ -1332,7 +1329,7 @@ namespace ConfiguringTask {
|
||||
));
|
||||
return undefined;
|
||||
}
|
||||
let taskIdentifier: Tasks.KeyedTaskIdentifier | undefined = TaskDefinition.createTaskIdentifier(identifier, context.problemReporter);
|
||||
let taskIdentifier: Tasks.KeyedTaskIdentifier | undefined = Tasks.TaskDefinition.createTaskIdentifier(identifier, context.problemReporter);
|
||||
if (taskIdentifier === undefined) {
|
||||
context.problemReporter.error(nls.localize(
|
||||
'ConfigurationParser.incorrectType',
|
||||
@@ -74,7 +74,7 @@ export interface ITaskService {
|
||||
getRecentlyUsedTasks(): LinkedMap<string, string>;
|
||||
createSorter(): TaskSorter;
|
||||
|
||||
needsFolderQualification();
|
||||
needsFolderQualification(): boolean;
|
||||
canCustomize(task: ContributedTask | CustomTask): boolean;
|
||||
customize(task: ContributedTask | CustomTask, properties?: {}, openConfig?: boolean): Promise<void>;
|
||||
openConfig(task: CustomTask | undefined): Promise<void>;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import * as Types from 'vs/base/common/types';
|
||||
import { IJSONSchemaMap } from 'vs/base/common/jsonSchema';
|
||||
import * as Objects from 'vs/base/common/objects';
|
||||
@@ -12,6 +13,7 @@ import { ProblemMatcher } from 'vs/workbench/contrib/tasks/common/problemMatcher
|
||||
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { TaskDefinitionRegistry } from 'vs/workbench/contrib/tasks/common/taskDefinitionRegistry';
|
||||
|
||||
export const TASK_RUNNING_STATE = new RawContextKey<boolean>('taskRunning', false);
|
||||
|
||||
@@ -341,7 +343,7 @@ export interface TaskSourceConfigElement {
|
||||
}
|
||||
|
||||
interface BaseTaskSource {
|
||||
readonly kind;
|
||||
readonly kind: string;
|
||||
readonly label: string;
|
||||
}
|
||||
|
||||
@@ -467,7 +469,7 @@ export abstract class CommonTask {
|
||||
*/
|
||||
_label: string;
|
||||
|
||||
type;
|
||||
type?: string;
|
||||
|
||||
runOptions: RunOptions;
|
||||
|
||||
@@ -477,7 +479,7 @@ export abstract class CommonTask {
|
||||
|
||||
private _taskLoadMessages: string[] | undefined;
|
||||
|
||||
protected constructor(id: string, label: string | undefined, type, runOptions: RunOptions,
|
||||
protected constructor(id: string, label: string | undefined, type: string | undefined, runOptions: RunOptions,
|
||||
configurationProperties: ConfigurationProperties, source: BaseTaskSource) {
|
||||
this._id = id;
|
||||
if (label) {
|
||||
@@ -575,7 +577,7 @@ export class CustomTask extends CommonTask {
|
||||
*/
|
||||
command: CommandConfiguration;
|
||||
|
||||
public constructor(id: string, source: WorkspaceTaskSource, label: string, type, command: CommandConfiguration | undefined,
|
||||
public constructor(id: string, source: WorkspaceTaskSource, label: string, type: string, command: CommandConfiguration | undefined,
|
||||
hasDefinedMatchers: boolean, runOptions: RunOptions, configurationProperties: ConfigurationProperties) {
|
||||
super(id, label, undefined, runOptions, configurationProperties, source);
|
||||
this._source = source;
|
||||
@@ -677,7 +679,7 @@ export class ConfiguringTask extends CommonTask {
|
||||
|
||||
configures: KeyedTaskIdentifier;
|
||||
|
||||
public constructor(id: string, source: WorkspaceTaskSource, label: string | undefined, type,
|
||||
public constructor(id: string, source: WorkspaceTaskSource, label: string | undefined, type: string | undefined,
|
||||
configures: KeyedTaskIdentifier, runOptions: RunOptions, configurationProperties: ConfigurationProperties) {
|
||||
super(id, label, type, runOptions, configurationProperties, source);
|
||||
this._source = source;
|
||||
@@ -710,7 +712,7 @@ export class ContributedTask extends CommonTask {
|
||||
*/
|
||||
command: CommandConfiguration;
|
||||
|
||||
public constructor(id: string, source: ExtensionTaskSource, label: string, type, defines: KeyedTaskIdentifier,
|
||||
public constructor(id: string, source: ExtensionTaskSource, label: string, type: string | undefined, defines: KeyedTaskIdentifier,
|
||||
command: CommandConfiguration, hasDefinedMatchers: boolean, runOptions: RunOptions,
|
||||
configurationProperties: ConfigurationProperties) {
|
||||
super(id, label, type, runOptions, configurationProperties, source);
|
||||
@@ -770,7 +772,7 @@ export class InMemoryTask extends CommonTask {
|
||||
|
||||
type: 'inMemory';
|
||||
|
||||
public constructor(id: string, source: InMemoryTaskSource, label: string, type,
|
||||
public constructor(id: string, source: InMemoryTaskSource, label: string, type: string,
|
||||
runOptions: RunOptions, configurationProperties: ConfigurationProperties) {
|
||||
super(id, label, type, runOptions, configurationProperties, source);
|
||||
this._source = source;
|
||||
@@ -921,4 +923,76 @@ export namespace TaskEvent {
|
||||
return Object.freeze({ kind: TaskEventKind.Changed });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export namespace KeyedTaskIdentifier {
|
||||
function sortedStringify(literal: any): string {
|
||||
const keys = Object.keys(literal).sort();
|
||||
let result: string = '';
|
||||
for (let position in keys) {
|
||||
let stringified = literal[keys[position]];
|
||||
if (stringified instanceof Object) {
|
||||
stringified = sortedStringify(test);
|
||||
} else if (typeof stringified === 'string') {
|
||||
stringified = stringified.replace(/,/g, ',,');
|
||||
}
|
||||
result += keys[position] + ',' + stringified + ',';
|
||||
}
|
||||
return result;
|
||||
}
|
||||
export function create(value: TaskIdentifier): KeyedTaskIdentifier {
|
||||
const resultKey = sortedStringify(value);
|
||||
console.log(resultKey);
|
||||
return { _key: resultKey, type: value.taskType };
|
||||
}
|
||||
}
|
||||
|
||||
export namespace TaskDefinition {
|
||||
export function createTaskIdentifier(external: TaskIdentifier, reporter: { error(message: string): void; }): KeyedTaskIdentifier | undefined {
|
||||
let definition = TaskDefinitionRegistry.get(external.type);
|
||||
if (definition === undefined) {
|
||||
// We have no task definition so we can't sanitize the literal. Take it as is
|
||||
let copy = Objects.deepClone(external);
|
||||
delete copy._key;
|
||||
return KeyedTaskIdentifier.create(copy);
|
||||
}
|
||||
|
||||
let literal: { type: string;[name: string]: any } = Object.create(null);
|
||||
literal.type = definition.taskType;
|
||||
let required: Set<string> = new Set();
|
||||
definition.required.forEach(element => required.add(element));
|
||||
|
||||
let properties = definition.properties;
|
||||
for (let property of Object.keys(properties)) {
|
||||
let value = external[property];
|
||||
if (value !== undefined && value !== null) {
|
||||
literal[property] = value;
|
||||
} else if (required.has(property)) {
|
||||
let schema = properties[property];
|
||||
if (schema.default !== undefined) {
|
||||
literal[property] = Objects.deepClone(schema.default);
|
||||
} else {
|
||||
switch (schema.type) {
|
||||
case 'boolean':
|
||||
literal[property] = false;
|
||||
break;
|
||||
case 'number':
|
||||
case 'integer':
|
||||
literal[property] = 0;
|
||||
break;
|
||||
case 'string':
|
||||
literal[property] = '';
|
||||
break;
|
||||
default:
|
||||
reporter.error(nls.localize(
|
||||
'TaskDefinition.missingRequiredProperty',
|
||||
'Error: the task identifier \'{0}\' is missing the required property \'{1}\'. The task identifier will be ignored.', JSON.stringify(external, undefined, 0), property
|
||||
));
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return KeyedTaskIdentifier.create(literal);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,14 +73,13 @@ import { ITaskSystem, ITaskResolver, ITaskSummary, TaskExecuteKind, TaskError, T
|
||||
import {
|
||||
Task, CustomTask, ConfiguringTask, ContributedTask, InMemoryTask, TaskEvent,
|
||||
TaskEventKind, TaskSet, TaskGroup, GroupType, ExecutionEngine, JsonSchemaVersion, TaskSourceKind,
|
||||
TaskSorter, TaskIdentifier, KeyedTaskIdentifier, TASK_RUNNING_STATE, TaskRunSource
|
||||
TaskSorter, TaskIdentifier, KeyedTaskIdentifier, TASK_RUNNING_STATE, TaskRunSource,
|
||||
KeyedTaskIdentifier as NKeyedTaskIdentifier, TaskDefinition
|
||||
} from 'vs/workbench/contrib/tasks/common/tasks';
|
||||
import { ITaskService, ITaskProvider, ProblemMatcherRunOptions, CustomizationProperties, TaskFilter, WorkspaceFolderTaskResult } from 'vs/workbench/contrib/tasks/common/taskService';
|
||||
import { getTemplates as getTaskTemplates } from 'vs/workbench/contrib/tasks/common/taskTemplates';
|
||||
|
||||
import { KeyedTaskIdentifier as NKeyedTaskIdentifier, TaskDefinition } from 'vs/workbench/contrib/tasks/node/tasks';
|
||||
|
||||
import * as TaskConfig from '../node/taskConfiguration';
|
||||
import * as TaskConfig from '../common/taskConfiguration';
|
||||
import { ProcessTaskSystem } from 'vs/workbench/contrib/tasks/node/processTaskSystem';
|
||||
import { TerminalTaskSystem } from './terminalTaskSystem';
|
||||
import { ProcessRunnerDetector } from 'vs/workbench/contrib/tasks/node/processRunnerDetector';
|
||||
@@ -156,9 +155,9 @@ class BuildStatusBarItem extends Themable implements IStatusbarItem {
|
||||
const info = document.createElement('div');
|
||||
const building = document.createElement('div');
|
||||
|
||||
const errorTitle = n => nls.localize('totalErrors', "{0} Errors", n);
|
||||
const warningTitle = n => nls.localize('totalWarnings', "{0} Warnings", n);
|
||||
const infoTitle = n => nls.localize('totalInfos', "{0} Infos", n);
|
||||
const errorTitle = (n: number) => nls.localize('totalErrors', "{0} Errors", n);
|
||||
const warningTitle = (n: number) => nls.localize('totalWarnings', "{0} Warnings", n);
|
||||
const infoTitle = (n: number) => nls.localize('totalInfos', "{0} Infos", n);
|
||||
|
||||
Dom.addClass(element, 'task-statusbar-item');
|
||||
element.title = nls.localize('problems', "Problems");
|
||||
@@ -211,7 +210,7 @@ class BuildStatusBarItem extends Themable implements IStatusbarItem {
|
||||
}));
|
||||
|
||||
const manyProblems = nls.localize('manyProblems', "10K+");
|
||||
const packNumber = n => n > 9999 ? manyProblems : n > 999 ? n.toString().charAt(0) + 'K' : n.toString();
|
||||
const packNumber = (n: number) => n > 9999 ? manyProblems : n > 999 ? n.toString().charAt(0) + 'K' : n.toString();
|
||||
let updateLabel = (stats: MarkerStatistics) => {
|
||||
error.innerHTML = packNumber(stats.errors);
|
||||
error.title = errorIcon.title = errorTitle(stats.errors);
|
||||
|
||||
@@ -1097,7 +1097,7 @@ export class TerminalTaskSystem implements ITaskSystem {
|
||||
}
|
||||
|
||||
private collectTaskVariables(variables: Set<string>, task: CustomTask | ContributedTask): void {
|
||||
if (task.command) {
|
||||
if (task.command && task.command.name) {
|
||||
this.collectCommandVariables(variables, task.command, task);
|
||||
}
|
||||
this.collectMatcherVariables(variables, task.configurationProperties.problemMatchers);
|
||||
|
||||
@@ -14,7 +14,7 @@ import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { IWorkspaceContextService, IWorkspaceFolder, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
|
||||
import * as Tasks from '../common/tasks';
|
||||
import * as TaskConfig from './taskConfiguration';
|
||||
import * as TaskConfig from '../common/taskConfiguration';
|
||||
|
||||
const build = 'build';
|
||||
const test = 'test';
|
||||
|
||||
@@ -319,7 +319,7 @@ export class ProcessTaskSystem implements ITaskSystem {
|
||||
this.activeTask = task;
|
||||
const inactiveEvent = TaskEvent.create(TaskEventKind.Inactive, task);
|
||||
let processStartedSignaled: boolean = false;
|
||||
const onProgress = (progress) => {
|
||||
const onProgress = (progress: LineData) => {
|
||||
let line = Strings.removeAnsiEscapeCodes(progress.line);
|
||||
this.appendOutput(line + '\n');
|
||||
startStopProblemMatcher.processLine(line);
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 crypto from 'crypto';
|
||||
|
||||
import * as Objects from 'vs/base/common/objects';
|
||||
|
||||
import { TaskIdentifier, KeyedTaskIdentifier, TaskDefinition } from 'vs/workbench/contrib/tasks/common/tasks';
|
||||
import { TaskDefinitionRegistry } from 'vs/workbench/contrib/tasks/common/taskDefinitionRegistry';
|
||||
|
||||
namespace KeyedTaskIdentifier {
|
||||
export function create(value: TaskIdentifier): KeyedTaskIdentifier {
|
||||
const hash = crypto.createHash('md5');
|
||||
hash.update(JSON.stringify(value));
|
||||
let result = { _key: hash.digest('hex'), type: value.taskType };
|
||||
Objects.assign(result, value);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
namespace TaskDefinition {
|
||||
export function createTaskIdentifier(external: TaskIdentifier, reporter: { error(message: string): void; }): KeyedTaskIdentifier | undefined {
|
||||
let definition = TaskDefinitionRegistry.get(external.type);
|
||||
if (definition === undefined) {
|
||||
// We have no task definition so we can't sanitize the literal. Take it as is
|
||||
let copy = Objects.deepClone(external);
|
||||
delete copy._key;
|
||||
return KeyedTaskIdentifier.create(copy);
|
||||
}
|
||||
|
||||
let literal: { type: string;[name: string]: any } = Object.create(null);
|
||||
literal.type = definition.taskType;
|
||||
let required: Set<string> = new Set();
|
||||
definition.required.forEach(element => required.add(element));
|
||||
|
||||
let properties = definition.properties;
|
||||
for (let property of Object.keys(properties)) {
|
||||
let value = external[property];
|
||||
if (value !== undefined && value !== null) {
|
||||
literal[property] = value;
|
||||
} else if (required.has(property)) {
|
||||
let schema = properties[property];
|
||||
if (schema.default !== undefined) {
|
||||
literal[property] = Objects.deepClone(schema.default);
|
||||
} else {
|
||||
switch (schema.type) {
|
||||
case 'boolean':
|
||||
literal[property] = false;
|
||||
break;
|
||||
case 'number':
|
||||
case 'integer':
|
||||
literal[property] = 0;
|
||||
break;
|
||||
case 'string':
|
||||
literal[property] = '';
|
||||
break;
|
||||
default:
|
||||
reporter.error(nls.localize(
|
||||
'TaskDefinition.missingRequiredProperty',
|
||||
'Error: the task identifier \'{0}\' is missing the required property \'{1}\'. The task identifier will be ignored.', JSON.stringify(external, undefined, 0), property
|
||||
));
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return KeyedTaskIdentifier.create(literal);
|
||||
}
|
||||
}
|
||||
|
||||
export { KeyedTaskIdentifier, TaskDefinition };
|
||||
@@ -13,7 +13,7 @@ import { ProblemMatcher, FileLocationKind, ProblemPattern, ApplyToKind } from 'v
|
||||
import { IWorkspaceFolder, WorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
|
||||
import * as Tasks from 'vs/workbench/contrib/tasks/common/tasks';
|
||||
import { parse, ParseResult, IProblemReporter, ExternalTaskRunnerConfiguration, CustomTask } from 'vs/workbench/contrib/tasks/node/taskConfiguration';
|
||||
import { parse, ParseResult, IProblemReporter, ExternalTaskRunnerConfiguration, CustomTask } from 'vs/workbench/contrib/tasks/common/taskConfiguration';
|
||||
|
||||
const workspaceFolder: IWorkspaceFolder = new WorkspaceFolder({
|
||||
uri: URI.file('/workspace/folderOne'),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
|
||||
@@ -34,6 +34,7 @@ import { IHistoryService } from 'vs/workbench/services/history/common/history';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { isWindows } from 'vs/base/common/platform';
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
|
||||
export const TERMINAL_PICKER_PREFIX = 'term ';
|
||||
|
||||
@@ -291,7 +292,7 @@ export class SendSequenceTerminalCommand extends Command {
|
||||
const workspaceContextService = accessor.get(IWorkspaceContextService);
|
||||
const historyService = accessor.get(IHistoryService);
|
||||
const activeWorkspaceRootUri = historyService.getLastActiveWorkspaceRoot(Schemas.file);
|
||||
const lastActiveWorkspaceRoot = activeWorkspaceRootUri ? workspaceContextService.getWorkspaceFolder(activeWorkspaceRootUri) || undefined : undefined;
|
||||
const lastActiveWorkspaceRoot = activeWorkspaceRootUri ? withNullAsUndefined(workspaceContextService.getWorkspaceFolder(activeWorkspaceRootUri)) : undefined;
|
||||
const resolvedText = configurationResolverService.resolve(lastActiveWorkspaceRoot, args.text);
|
||||
terminalInstance.sendText(resolvedText, false);
|
||||
}
|
||||
|
||||
@@ -894,9 +894,12 @@ export class TerminalInstance implements ITerminalInstance {
|
||||
|
||||
if (platform.isWindows) {
|
||||
this._processManager.ptyProcessReady.then(() => {
|
||||
if (this._processManager!.remoteAuthority) {
|
||||
return;
|
||||
}
|
||||
this._xtermReadyPromise.then(() => {
|
||||
if (!this._isDisposed) {
|
||||
this._terminalInstanceService.createWindowsShellHelper(this._processManager!.shellProcessId, this, this._xterm);
|
||||
this._windowsShellHelper = this._terminalInstanceService.createWindowsShellHelper(this._processManager!.shellProcessId, this, this._xterm);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -161,7 +161,7 @@ export class TerminalPanel extends Panel {
|
||||
return this._contextMenuActions;
|
||||
}
|
||||
|
||||
public getActionItem(action: Action): IActionItem | null {
|
||||
public getActionItem(action: Action): IActionItem | undefined {
|
||||
if (action.id === SwitchTerminalAction.ID) {
|
||||
return this._instantiationService.createInstance(SwitchTerminalActionItem, action);
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment'
|
||||
import { IProductService } from 'vs/platform/product/common/product';
|
||||
import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IRemoteEnvironmentService } from 'vs/workbench/services/remote/common/remoteEnvironmentService';
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
|
||||
/** The amount of time to consider terminal errors to be related to the launch */
|
||||
const LAUNCHING_DURATION = 500;
|
||||
@@ -77,7 +77,7 @@ export class TerminalProcessManager implements ITerminalProcessManager {
|
||||
@IEnvironmentService private readonly _environmentService: IEnvironmentService,
|
||||
@IProductService private readonly _productService: IProductService,
|
||||
@ITerminalInstanceService private readonly _terminalInstanceService: ITerminalInstanceService,
|
||||
@IRemoteEnvironmentService private readonly _remoteEnvironmentService: IRemoteEnvironmentService
|
||||
@IRemoteAgentService private readonly _remoteAgentService: IRemoteAgentService
|
||||
) {
|
||||
this.ptyProcessReady = new Promise<void>(c => {
|
||||
this.onProcessReady(() => {
|
||||
@@ -123,7 +123,7 @@ export class TerminalProcessManager implements ITerminalProcessManager {
|
||||
this.os = platform.OS;
|
||||
if (launchRemotely) {
|
||||
if (hasRemoteAuthority) {
|
||||
this._remoteEnvironmentService.remoteEnvironment.then(env => {
|
||||
this._remoteAgentService.getEnvironment().then(env => {
|
||||
if (!env) {
|
||||
return;
|
||||
}
|
||||
@@ -250,6 +250,7 @@ export class TerminalProcessManager implements ITerminalProcessManager {
|
||||
}
|
||||
|
||||
public async getLatency(): Promise<number> {
|
||||
await this.ptyProcessReady;
|
||||
if (!this._process) {
|
||||
return Promise.resolve(0);
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ function getMockTheme(type: ThemeType): ITheme {
|
||||
selector: '',
|
||||
label: '',
|
||||
type: type,
|
||||
getColor: (colorId: ColorIdentifier) => themingRegistry.resolveDefaultColor(colorId, theme),
|
||||
getColor: (colorId: ColorIdentifier): Color | undefined => themingRegistry.resolveDefaultColor(colorId, theme),
|
||||
defines: () => true
|
||||
};
|
||||
return theme;
|
||||
|
||||
@@ -53,7 +53,7 @@ export class SelectColorThemeAction extends Action {
|
||||
//configurationEntries(this.extensionGalleryService, localize('installColorThemes', "Install Additional Color Themes..."))
|
||||
);
|
||||
|
||||
const selectTheme = (theme, applyTheme: boolean) => {
|
||||
const selectTheme = (theme: IColorTheme, applyTheme: boolean) => {
|
||||
if (typeof theme.id === 'undefined') { // 'pick in marketplace' entry
|
||||
if (applyTheme) {
|
||||
openExtensionViewlet(this.viewletService, 'category:themes ');
|
||||
|
||||
@@ -245,6 +245,7 @@ export class WebviewEditor extends BaseEditor {
|
||||
webview.update(input.html, {
|
||||
allowScripts: input.options.enableScripts,
|
||||
localResourceRoots: input.options.localResourceRoots || this.getDefaultLocalResourceRoots(),
|
||||
portMappings: input.options.portMapping,
|
||||
}, !!input.options.retainContextWhenHidden);
|
||||
|
||||
if (this._webviewContent) {
|
||||
|
||||
@@ -9,9 +9,8 @@ import { URI } from 'vs/base/common/uri';
|
||||
import { IEditorModel } from 'vs/platform/editor/common/editor';
|
||||
import { EditorInput, EditorModel, GroupIdentifier, IEditorInput } from 'vs/workbench/common/editor';
|
||||
import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import * as vscode from 'vscode';
|
||||
import { WebviewEvents, WebviewInputOptions } from './webviewEditorService';
|
||||
import { WebviewElement } from './webviewElement';
|
||||
import { WebviewElement, WebviewOptions } from './webviewElement';
|
||||
|
||||
export class WebviewEditorInput extends EditorInput {
|
||||
private static handlePool = 0;
|
||||
@@ -195,7 +194,7 @@ export class WebviewEditorInput extends EditorInput {
|
||||
return this._options;
|
||||
}
|
||||
|
||||
public setOptions(value: vscode.WebviewOptions) {
|
||||
public setOptions(value: WebviewOptions) {
|
||||
this._options = {
|
||||
...this._options,
|
||||
...value
|
||||
@@ -204,7 +203,8 @@ export class WebviewEditorInput extends EditorInput {
|
||||
if (this._webview) {
|
||||
this._webview.options = {
|
||||
allowScripts: this._options.enableScripts,
|
||||
localResourceRoots: this._options.localResourceRoots
|
||||
localResourceRoots: this._options.localResourceRoots,
|
||||
portMappings: this._options.portMapping,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,9 +35,9 @@ export class WebviewEditorInputFactory implements IEditorInputFactory {
|
||||
|
||||
public serialize(
|
||||
input: WebviewEditorInput
|
||||
): string | null {
|
||||
): string | undefined {
|
||||
if (!this._webviewService.shouldPersist(input)) {
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const data: SerializedWebview = {
|
||||
@@ -54,7 +54,7 @@ export class WebviewEditorInputFactory implements IEditorInputFactory {
|
||||
try {
|
||||
return JSON.stringify(data);
|
||||
} catch {
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ import { createDecorator, IInstantiationService } from 'vs/platform/instantiatio
|
||||
import { GroupIdentifier } from 'vs/workbench/common/editor';
|
||||
import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { ACTIVE_GROUP_TYPE, IEditorService, SIDE_GROUP_TYPE } from 'vs/workbench/services/editor/common/editorService';
|
||||
import * as vscode from 'vscode';
|
||||
import { RevivedWebviewEditorInput, WebviewEditorInput } from './webviewEditorInput';
|
||||
import { IWebviewOptions, IWebviewPanelOptions } from 'vs/editor/common/modes';
|
||||
|
||||
export const IWebviewEditorService = createDecorator<IWebviewEditorService>('webviewEditorService');
|
||||
|
||||
@@ -72,10 +72,10 @@ export interface WebviewReviver {
|
||||
export interface WebviewEvents {
|
||||
onMessage?(message: any): void;
|
||||
onDispose?(): void;
|
||||
onDidClickLink?(link: URI, options: vscode.WebviewOptions): void;
|
||||
onDidClickLink?(link: URI, options: IWebviewOptions): void;
|
||||
}
|
||||
|
||||
export interface WebviewInputOptions extends vscode.WebviewOptions, vscode.WebviewPanelOptions {
|
||||
export interface WebviewInputOptions extends IWebviewOptions, IWebviewPanelOptions {
|
||||
tryRestoreScrollPosition?: boolean;
|
||||
}
|
||||
|
||||
@@ -85,7 +85,8 @@ export function areWebviewInputOptionsEqual(a: WebviewInputOptions, b: WebviewIn
|
||||
&& a.enableScripts === b.enableScripts
|
||||
&& a.retainContextWhenHidden === b.retainContextWhenHidden
|
||||
&& a.tryRestoreScrollPosition === b.tryRestoreScrollPosition
|
||||
&& (a.localResourceRoots === b.localResourceRoots || (Array.isArray(a.localResourceRoots) && Array.isArray(b.localResourceRoots) && equals(a.localResourceRoots, b.localResourceRoots, (a, b) => a.toString() === b.toString())));
|
||||
&& (a.localResourceRoots === b.localResourceRoots || (Array.isArray(a.localResourceRoots) && Array.isArray(b.localResourceRoots) && equals(a.localResourceRoots, b.localResourceRoots, (a, b) => a.toString() === b.toString())))
|
||||
&& (a.portMapping === b.portMapping || (Array.isArray(a.portMapping) && Array.isArray(b.portMapping) && equals(a.portMapping, b.portMapping, (a, b) => a.from === b.from && a.to === b.to)));
|
||||
}
|
||||
|
||||
function canRevive(reviver: WebviewReviver, webview: WebviewEditorInput): boolean {
|
||||
@@ -128,11 +129,11 @@ export class WebviewEditorService implements IWebviewEditorService {
|
||||
viewType: string,
|
||||
title: string,
|
||||
showOptions: ICreateWebViewShowOptions,
|
||||
options: vscode.WebviewOptions,
|
||||
options: IWebviewOptions,
|
||||
extensionLocation: URI | undefined,
|
||||
events: WebviewEvents
|
||||
): WebviewEditorInput {
|
||||
const webviewInput = this._instantiationService.createInstance(WebviewEditorInput, viewType, undefined, title, options, {}, events, extensionLocation, undefined);
|
||||
const webviewInput = this._instantiationService.createInstance(WebviewEditorInput, viewType, undefined, title, options, {}, events, extensionLocation);
|
||||
this._editorService.openEditor(webviewInput, { pinned: true, preserveFocus: showOptions.preserveFocus }, showOptions.group);
|
||||
return webviewInput;
|
||||
}
|
||||
|
||||
@@ -3,9 +3,13 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { OnBeforeRequestDetails, OnHeadersReceivedDetails, Response } from 'electron';
|
||||
import { addClass, addDisposableListener } from 'vs/base/browser/dom';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { once } from 'vs/base/common/functional';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
import { endsWith } from 'vs/base/common/strings';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
@@ -15,8 +19,16 @@ import { DARK, ITheme, IThemeService, LIGHT } from 'vs/platform/theme/common/the
|
||||
import { registerFileProtocol, WebviewProtocol } from 'vs/workbench/contrib/webview/electron-browser/webviewProtocols';
|
||||
import { areWebviewInputOptionsEqual } from './webviewEditorService';
|
||||
import { WebviewFindWidget } from './webviewFindWidget';
|
||||
import { endsWith } from 'vs/base/common/strings';
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
|
||||
export interface WebviewPortMapping {
|
||||
readonly port: number;
|
||||
readonly resolvedPort: number;
|
||||
}
|
||||
|
||||
export interface WebviewPortMapping {
|
||||
readonly port: number;
|
||||
readonly resolvedPort: number;
|
||||
}
|
||||
|
||||
export interface WebviewOptions {
|
||||
readonly allowSvgs?: boolean;
|
||||
@@ -28,6 +40,7 @@ export interface WebviewContentOptions {
|
||||
readonly allowScripts?: boolean;
|
||||
readonly svgWhiteList?: string[];
|
||||
readonly localResourceRoots?: ReadonlyArray<URI>;
|
||||
readonly portMappings?: ReadonlyArray<WebviewPortMapping>;
|
||||
}
|
||||
|
||||
interface IKeydownEvent {
|
||||
@@ -41,6 +54,58 @@ interface IKeydownEvent {
|
||||
repeat: boolean;
|
||||
}
|
||||
|
||||
type OnBeforeRequestDelegate = (details: OnBeforeRequestDetails) => Promise<Response | undefined>;
|
||||
type OnHeadersReceivedDelegate = (details: OnHeadersReceivedDetails) => { cancel: boolean } | undefined;
|
||||
|
||||
class WebviewSession extends Disposable {
|
||||
|
||||
private readonly _onBeforeRequestDelegates: Array<OnBeforeRequestDelegate> = [];
|
||||
private readonly _onHeadersReceivedDelegates: Array<OnHeadersReceivedDelegate> = [];
|
||||
|
||||
public constructor(
|
||||
webview: Electron.WebviewTag,
|
||||
) {
|
||||
super();
|
||||
|
||||
this._register(addDisposableListener(webview, 'did-start-loading', once(() => {
|
||||
const contents = webview.getWebContents();
|
||||
if (!contents) {
|
||||
return;
|
||||
}
|
||||
|
||||
contents.session.webRequest.onBeforeRequest(async (details, callback) => {
|
||||
for (const delegate of this._onBeforeRequestDelegates) {
|
||||
const result = await delegate(details);
|
||||
if (typeof result !== 'undefined') {
|
||||
callback(result);
|
||||
return;
|
||||
}
|
||||
}
|
||||
callback({});
|
||||
});
|
||||
|
||||
contents.session.webRequest.onHeadersReceived((details, callback) => {
|
||||
for (const delegate of this._onHeadersReceivedDelegates) {
|
||||
const result = delegate(details);
|
||||
if (typeof result !== 'undefined') {
|
||||
callback(result);
|
||||
return;
|
||||
}
|
||||
}
|
||||
callback({ cancel: false, responseHeaders: details.responseHeaders });
|
||||
});
|
||||
})));
|
||||
}
|
||||
|
||||
public onBeforeRequest(delegate: OnBeforeRequestDelegate) {
|
||||
this._onBeforeRequestDelegates.push(delegate);
|
||||
}
|
||||
|
||||
public onHeadersReceived(delegate: OnHeadersReceivedDelegate) {
|
||||
this._onHeadersReceivedDelegates.push(delegate);
|
||||
}
|
||||
}
|
||||
|
||||
class WebviewProtocolProvider extends Disposable {
|
||||
constructor(
|
||||
webview: Electron.WebviewTag,
|
||||
@@ -51,21 +116,15 @@ class WebviewProtocolProvider extends Disposable {
|
||||
) {
|
||||
super();
|
||||
|
||||
let loaded = false;
|
||||
this._register(addDisposableListener(webview, 'did-start-loading', () => {
|
||||
if (loaded) {
|
||||
return;
|
||||
}
|
||||
loaded = true;
|
||||
|
||||
this._register(addDisposableListener(webview, 'did-start-loading', once(() => {
|
||||
const contents = webview.getWebContents();
|
||||
if (contents) {
|
||||
this.registerFileProtocols(contents);
|
||||
this.registerProtocols(contents);
|
||||
}
|
||||
}));
|
||||
})));
|
||||
}
|
||||
|
||||
private registerFileProtocols(contents: Electron.WebContents) {
|
||||
private registerProtocols(contents: Electron.WebContents) {
|
||||
if (contents.isDestroyed()) {
|
||||
return;
|
||||
}
|
||||
@@ -82,52 +141,73 @@ class WebviewProtocolProvider extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
class WebviewPortMappingProvider extends Disposable {
|
||||
|
||||
constructor(
|
||||
session: WebviewSession,
|
||||
mappings: () => ReadonlyArray<WebviewPortMapping>
|
||||
) {
|
||||
super();
|
||||
|
||||
session.onBeforeRequest(async (details) => {
|
||||
const uri = URI.parse(details.url);
|
||||
if (uri.scheme !== 'http' && uri.scheme !== 'https') {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const localhostMatch = /^localhost:(\d+)$/.exec(uri.authority);
|
||||
if (localhostMatch) {
|
||||
const port = +localhostMatch[1];
|
||||
for (const mapping of mappings()) {
|
||||
if (mapping.port === port && mapping.port !== mapping.resolvedPort) {
|
||||
return {
|
||||
redirectURL: details.url.replace(
|
||||
new RegExp(`^${uri.scheme}://localhost:${mapping.port}/`),
|
||||
`${uri.scheme}://localhost:${mapping.resolvedPort}/`)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class SvgBlocker extends Disposable {
|
||||
|
||||
private readonly _onDidBlockSvg = this._register(new Emitter<void>());
|
||||
public readonly onDidBlockSvg = this._onDidBlockSvg.event;
|
||||
|
||||
constructor(
|
||||
webview: Electron.WebviewTag,
|
||||
session: WebviewSession,
|
||||
private readonly _options: WebviewContentOptions,
|
||||
) {
|
||||
super();
|
||||
|
||||
let loaded = false;
|
||||
this._register(addDisposableListener(webview, 'did-start-loading', () => {
|
||||
if (loaded) {
|
||||
return;
|
||||
}
|
||||
loaded = true;
|
||||
|
||||
const contents = webview.getWebContents();
|
||||
if (!contents) {
|
||||
return;
|
||||
session.onBeforeRequest(async (details) => {
|
||||
if (details.url.indexOf('.svg') > 0) {
|
||||
const uri = URI.parse(details.url);
|
||||
if (uri && !uri.scheme.match(/file/i) && endsWith(uri.path, '.svg') && !this.isAllowedSvg(uri)) {
|
||||
this._onDidBlockSvg.fire();
|
||||
return { cancel: true };
|
||||
}
|
||||
}
|
||||
|
||||
contents.session.webRequest.onBeforeRequest((details, callback) => {
|
||||
if (details.url.indexOf('.svg') > 0) {
|
||||
const uri = URI.parse(details.url);
|
||||
if (uri && !uri.scheme.match(/file/i) && endsWith(uri.path, '.svg') && !this.isAllowedSvg(uri)) {
|
||||
this._onDidBlockSvg.fire();
|
||||
return callback({ cancel: true });
|
||||
}
|
||||
}
|
||||
return callback({});
|
||||
});
|
||||
return undefined;
|
||||
});
|
||||
|
||||
contents.session.webRequest.onHeadersReceived((details, callback) => {
|
||||
const contentType: string[] = details.responseHeaders['content-type'] || details.responseHeaders['Content-Type'];
|
||||
if (contentType && Array.isArray(contentType) && contentType.some(x => x.toLowerCase().indexOf('image/svg') >= 0)) {
|
||||
const uri = URI.parse(details.url);
|
||||
if (uri && !this.isAllowedSvg(uri)) {
|
||||
this._onDidBlockSvg.fire();
|
||||
return callback({ cancel: true });
|
||||
}
|
||||
session.onHeadersReceived((details) => {
|
||||
const contentType: string[] = details.responseHeaders['content-type'] || details.responseHeaders['Content-Type'];
|
||||
if (contentType && Array.isArray(contentType) && contentType.some(x => x.toLowerCase().indexOf('image/svg') >= 0)) {
|
||||
const uri = URI.parse(details.url);
|
||||
if (uri && !this.isAllowedSvg(uri)) {
|
||||
this._onDidBlockSvg.fire();
|
||||
return { cancel: true };
|
||||
}
|
||||
return callback({ cancel: false, responseHeaders: details.responseHeaders });
|
||||
});
|
||||
}));
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
|
||||
private isAllowedSvg(uri: URI): boolean {
|
||||
@@ -236,7 +316,7 @@ export class WebviewElement extends Disposable {
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IEnvironmentService environmentService: IEnvironmentService,
|
||||
@IFileService fileService: IFileService
|
||||
@IFileService fileService: IFileService,
|
||||
) {
|
||||
super();
|
||||
this._webview = document.createElement('webview');
|
||||
@@ -264,16 +344,23 @@ export class WebviewElement extends Disposable {
|
||||
}));
|
||||
});
|
||||
|
||||
this._register(
|
||||
new WebviewProtocolProvider(
|
||||
this._webview,
|
||||
this._options.extensionLocation,
|
||||
() => (this._contentOptions.localResourceRoots || []),
|
||||
environmentService,
|
||||
fileService));
|
||||
const session = this._register(new WebviewSession(this._webview));
|
||||
|
||||
this._register(new WebviewProtocolProvider(
|
||||
this._webview,
|
||||
this._options.extensionLocation,
|
||||
() => (this._contentOptions.localResourceRoots || []),
|
||||
environmentService,
|
||||
fileService));
|
||||
|
||||
this._register(new WebviewPortMappingProvider(
|
||||
session,
|
||||
() => (this._contentOptions.portMappings || [])
|
||||
));
|
||||
|
||||
|
||||
if (!this._options.allowSvgs) {
|
||||
const svgBlocker = this._register(new SvgBlocker(this._webview, this._contentOptions));
|
||||
const svgBlocker = this._register(new SvgBlocker(session, this._contentOptions));
|
||||
svgBlocker.onDidBlockSvg(() => this.onDidBlockSvg());
|
||||
}
|
||||
|
||||
@@ -496,7 +583,7 @@ export class WebviewElement extends Disposable {
|
||||
if (!window || !window.webContents || window.webContents.isDestroyed()) {
|
||||
return;
|
||||
}
|
||||
window.webContents.getZoomFactor(factor => {
|
||||
window.webContents.getZoomFactor((factor: number) => {
|
||||
if (contents.isDestroyed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { extname, sep } from 'vs/base/common/path';
|
||||
import { getMediaMime, MIME_UNKNOWN } from 'vs/base/common/mime';
|
||||
import { extname, sep } from 'vs/base/common/path';
|
||||
import { startsWith } from 'vs/base/common/strings';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
@@ -11,7 +11,7 @@ import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
|
||||
|
||||
export const enum WebviewProtocol {
|
||||
CoreResource = 'vscode-core-resource',
|
||||
VsCodeResource = 'vscode-resource'
|
||||
VsCodeResource = 'vscode-resource',
|
||||
}
|
||||
|
||||
function resolveContent(fileService: IFileService, resource: URI, mime: string, callback: any): void {
|
||||
@@ -60,7 +60,7 @@ export function registerFileProtocol(
|
||||
callback({ error: -10 /* ACCESS_DENIED: https://cs.chromium.org/chromium/src/net/base/net_error_list.h */ });
|
||||
}, (error) => {
|
||||
if (error) {
|
||||
console.error('Failed to register protocol ' + protocol);
|
||||
console.error(`Failed to register '${protocol}' protocol`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ export class GettingStarted implements IWorkbenchContribution {
|
||||
|
||||
private static readonly hideWelcomeSettingskey = 'workbench.hide.welcome';
|
||||
|
||||
private welcomePageURL: string;
|
||||
private welcomePageURL?: string;
|
||||
private appName: string;
|
||||
|
||||
constructor(
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
|
||||
suite('Workbench - GettingStarted', () => {
|
||||
let instantiation: TestInstantiationService | null = null;
|
||||
let hideWelcomeSettingsValue: string | null = null;
|
||||
|
||||
suiteSetup(() => {
|
||||
instantiation = new TestInstantiationService();
|
||||
instantiation.stub(IWorkspaceContextService, {
|
||||
|
||||
});
|
||||
instantiation.stub(IStorageService, <Partial<IStorageService>>{
|
||||
get: () => hideWelcomeSettingsValue,
|
||||
store: (value) => hideWelcomeSettingsValue = value
|
||||
});
|
||||
});
|
||||
|
||||
suiteTeardown(() => {
|
||||
instantiation = null;
|
||||
});
|
||||
|
||||
setup(() => {
|
||||
hideWelcomeSettingsValue = null;
|
||||
});
|
||||
});
|
||||
@@ -48,7 +48,7 @@ export class WalkThroughInput extends EditorInput {
|
||||
|
||||
private disposables: IDisposable[] = [];
|
||||
|
||||
private promise: Promise<WalkThroughModel> | null;
|
||||
private promise: Promise<WalkThroughModel> | null = null;
|
||||
|
||||
private maxTopScroll = 0;
|
||||
private maxBottomScroll = 0;
|
||||
|
||||
Reference in New Issue
Block a user