Merge from vscode 52dcb723a39ae75bee1bd56b3312d7fcdc87aeed (#6719)

This commit is contained in:
Anthony Dresser
2019-08-12 21:31:51 -07:00
committed by GitHub
parent 00250839fc
commit 7eba8c4c03
616 changed files with 9472 additions and 7087 deletions

View File

@@ -16,7 +16,7 @@ const AUTO_SAVE_AFTER_DELAY_DISABLED_TIME = CONTENT_CHANGE_EVENT_BUFFER_DELAY +
export class BackupModelTracker extends Disposable implements IWorkbenchContribution {
private configuredAutoSaveAfterDelay: boolean;
private configuredAutoSaveAfterDelay = false;
constructor(
@IBackupFileService private readonly backupFileService: IBackupFileService,
@@ -47,11 +47,11 @@ export class BackupModelTracker extends Disposable implements IWorkbenchContribu
private onConfigurationChange(configuration: IFilesConfiguration): void {
if (!configuration || !configuration.files) {
this.configuredAutoSaveAfterDelay = false;
return;
}
this.configuredAutoSaveAfterDelay =
(configuration.files.autoSave === AutoSaveConfiguration.AFTER_DELAY &&
configuration.files.autoSaveDelay <= AUTO_SAVE_AFTER_DELAY_DISABLED_TIME);
this.configuredAutoSaveAfterDelay = (configuration.files.autoSave === AutoSaveConfiguration.AFTER_DELAY && configuration.files.autoSaveDelay <= AUTO_SAVE_AFTER_DELAY_DISABLED_TIME);
}
private onTextFileModelChanged(event: TextFileModelChangeEvent): void {
@@ -81,4 +81,4 @@ export class BackupModelTracker extends Disposable implements IWorkbenchContribu
private discardBackup(resource: Uri): void {
this.backupFileService.discardResourceBackup(resource);
}
}
}

View File

@@ -91,15 +91,15 @@ class LayoutInfo {
export class CallHierarchyTreePeekWidget extends PeekViewWidget {
private _changeDirectionAction: ChangeHierarchyDirectionAction;
private _parent: HTMLElement;
private _message: HTMLElement;
private _splitView: SplitView;
private _tree: WorkbenchAsyncDataTree<CallHierarchyItem, callHTree.Call, FuzzyScore>;
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;
private _editor!: EmbeddedCodeEditorWidget;
private _dim!: Dimension;
private _layoutInfo!: LayoutInfo;
constructor(
editor: ICodeEditor,
@@ -386,7 +386,7 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget {
};
this._changeDirectionAction = new ChangeHierarchyDirectionAction(this._direction, changeDirection);
this._disposables.add(this._changeDirectionAction);
this._actionbarWidget.push(this._changeDirectionAction, { icon: true, label: false });
this._actionbarWidget!.push(this._changeDirectionAction, { icon: true, label: false });
}
}

View File

@@ -58,7 +58,9 @@ export class IdentityProvider implements IIdentityProvider<Call> {
}
class CallRenderingTemplate {
readonly iconLabel: IconLabel;
constructor(
readonly iconLabel: IconLabel
) { }
}
export class CallRenderer implements ITreeRenderer<Call, FuzzyScore, CallRenderingTemplate> {
@@ -69,7 +71,7 @@ export class CallRenderer implements ITreeRenderer<Call, FuzzyScore, CallRenderi
renderTemplate(container: HTMLElement): CallRenderingTemplate {
const iconLabel = new IconLabel(container, { supportHighlights: true });
return { iconLabel };
return new CallRenderingTemplate(iconLabel);
}
renderElement(node: ITreeNode<Call, FuzzyScore>, _index: number, template: CallRenderingTemplate): void {
const { element, filterData } = node;

View File

@@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.14646 9.76783L8.14644 14.7678L8.85355 14.7678L13.8535 9.76783L13.1464 9.06072L9 13.2072L9 1.00006L8 1.00006L8 13.2072L3.85356 9.06072L3.14646 9.76783Z" fill="#C5C5C5"/>
</svg>

After

Width:  |  Height:  |  Size: 324 B

View File

@@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.14646 9.76783L8.14644 14.7678L8.85355 14.7678L13.8535 9.76783L13.1464 9.06072L9 13.2072L9 1.00006L8 1.00006L8 13.2072L3.85356 9.06072L3.14646 9.76783Z" fill="#424242"/>
</svg>

After

Width:  |  Height:  |  Size: 324 B

View File

@@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.8535 6.29284L8.85356 1.29285H8.14645L3.14645 6.29284L3.85356 6.99995L8 2.85351V15.0606H9V2.85351L13.1464 6.99995L13.8535 6.29284Z" fill="#C5C5C5"/>
</svg>

After

Width:  |  Height:  |  Size: 304 B

View File

@@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.8535 6.29284L8.85356 1.29285H8.14645L3.14645 6.29284L3.85356 6.99995L8 2.85351V15.0606H9V2.85351L13.1464 6.99995L13.8535 6.29284Z" fill="#424242"/>
</svg>

After

Width:  |  Height:  |  Size: 304 B

View File

@@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 8.70714L11.6464 12.3536L12.3536 11.6465L8.70711 8.00004L12.3536 4.35359L11.6464 3.64648L8 7.29293L4.35355 3.64648L3.64645 4.35359L7.29289 8.00004L3.64645 11.6465L4.35355 12.3536L8 8.70714Z" fill="#C5C5C5"/>
</svg>

After

Width:  |  Height:  |  Size: 362 B

View File

@@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 8.70714L11.6464 12.3536L12.3536 11.6465L8.70711 8.00004L12.3536 4.35359L11.6464 3.64648L8 7.29293L4.35355 3.64648L3.64645 4.35359L7.29289 8.00004L3.64645 11.6465L4.35355 12.3536L8 8.70714Z" fill="#424242"/>
</svg>

After

Width:  |  Height:  |  Size: 362 B

View File

@@ -0,0 +1,84 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-workbench .simple-find-part-wrapper {
overflow: hidden;
z-index: 10;
position: absolute;
top: 0;
right: 18px;
width: 220px;
max-width: calc(100% - 28px - 28px - 8px);
pointer-events: none;
padding: 0 10px 10px;
}
.monaco-workbench .simple-find-part {
visibility: hidden; /* Use visibility to maintain flex layout while hidden otherwise interferes with transition */
z-index: 10;
position: relative;
top: -45px;
display: flex;
padding: 4px;
align-items: center;
pointer-events: all;
transition: top 200ms linear;
}
.monaco-workbench .simple-find-part.visible {
visibility: visible;
}
.monaco-workbench .simple-find-part.visible-transition {
top: 0;
}
.monaco-workbench .simple-find-part .monaco-findInput {
flex: 1;
}
.monaco-workbench .simple-find-part .button {
min-width: 20px;
width: 20px;
height: 20px;
display: flex;
flex: initial;
margin-left: 3px;
background-position: center center;
background-repeat: no-repeat;
cursor: pointer;
}
.monaco-workbench .simple-find-part .button.previous {
background-image: url('images/chevron-previous-light.svg');
}
.monaco-workbench .simple-find-part .button.next {
background-image: url('images/chevron-next-light.svg');
}
.monaco-workbench .simple-find-part .button.close-fw {
background-image: url('images/close-light.svg');
}
.hc-black .monaco-workbench .simple-find-part .button.previous,
.vs-dark .monaco-workbench .simple-find-part .button.previous {
background-image: url('images/chevron-previous-dark.svg');
}
.hc-black .monaco-workbench .simple-find-part .button.next,
.vs-dark .monaco-workbench .simple-find-part .button.next {
background-image: url('images/chevron-next-dark.svg');
}
.hc-black .monaco-workbench .simple-find-part .button.close-fw,
.vs-dark .monaco-workbench .simple-find-part .button.close-fw {
background-image: url('images/close-dark.svg');
}
.monaco-workbench .simple-find-part .button.disabled {
opacity: 0.3;
cursor: default;
}

View File

@@ -0,0 +1,301 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./simpleFindWidget';
import * as nls from 'vs/nls';
import * as dom from 'vs/base/browser/dom';
import { FindInput, IFindInputStyles } from 'vs/base/browser/ui/findinput/findInput';
import { Widget } from 'vs/base/browser/ui/widget';
import { Delayer } from 'vs/base/common/async';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { FindReplaceState } from 'vs/editor/contrib/find/findState';
import { IMessage as InputBoxMessage } from 'vs/base/browser/ui/inputbox/inputBox';
import { SimpleButton } from 'vs/editor/contrib/find/findWidget';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
import { editorWidgetBackground, inputActiveOptionBorder, inputActiveOptionBackground, inputBackground, inputBorder, inputForeground, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground, inputValidationInfoBackground, inputValidationInfoBorder, inputValidationInfoForeground, inputValidationWarningBackground, inputValidationWarningBorder, inputValidationWarningForeground, widgetShadow } from 'vs/platform/theme/common/colorRegistry';
import { ITheme, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { ContextScopedFindInput } from 'vs/platform/browser/contextScopedHistoryWidget';
const NLS_FIND_INPUT_LABEL = nls.localize('label.find', "Find");
const NLS_FIND_INPUT_PLACEHOLDER = nls.localize('placeholder.find', "Find");
const NLS_PREVIOUS_MATCH_BTN_LABEL = nls.localize('label.previousMatchButton', "Previous match");
const NLS_NEXT_MATCH_BTN_LABEL = nls.localize('label.nextMatchButton', "Next match");
const NLS_CLOSE_BTN_LABEL = nls.localize('label.closeButton', "Close");
export abstract class SimpleFindWidget extends Widget {
private readonly _findInput: FindInput;
private readonly _domNode: HTMLElement;
private readonly _innerDomNode: HTMLElement;
private _isVisible: boolean = false;
private readonly _focusTracker: dom.IFocusTracker;
private readonly _findInputFocusTracker: dom.IFocusTracker;
private readonly _updateHistoryDelayer: Delayer<void>;
private prevBtn: SimpleButton;
private nextBtn: SimpleButton;
private foundMatch: boolean;
constructor(
@IContextViewService private readonly _contextViewService: IContextViewService,
@IContextKeyService contextKeyService: IContextKeyService,
private readonly _state: FindReplaceState = new FindReplaceState(),
showOptionButtons?: boolean,
private readonly _invertDefaultDirection: boolean = false
) {
super();
this._findInput = this._register(new ContextScopedFindInput(null, this._contextViewService, {
label: NLS_FIND_INPUT_LABEL,
placeholder: NLS_FIND_INPUT_PLACEHOLDER,
validation: (value: string): InputBoxMessage | null => {
if (value.length === 0 || !this._findInput.getRegex()) {
return null;
}
try {
/* tslint:disable-next-line:no-unused-expression */
new RegExp(value);
return null;
} catch (e) {
this.foundMatch = false;
this._updateButtons();
return { content: e.message };
}
}
}, contextKeyService, showOptionButtons));
// Find History with update delayer
this._updateHistoryDelayer = new Delayer<void>(500);
this.oninput(this._findInput.domNode, (e) => {
this.foundMatch = this.onInputChanged();
this._updateButtons();
this._delayedUpdateHistory();
});
this._findInput.setRegex(!!this._state.isRegex);
this._findInput.setCaseSensitive(!!this._state.matchCase);
this._findInput.setWholeWords(!!this._state.wholeWord);
this._register(this._findInput.onDidOptionChange(() => {
this._state.change({
isRegex: this._findInput.getRegex(),
wholeWord: this._findInput.getWholeWords(),
matchCase: this._findInput.getCaseSensitive()
}, true);
}));
this._register(this._state.onFindReplaceStateChange(() => {
this._findInput.setRegex(this._state.isRegex);
this._findInput.setWholeWords(this._state.wholeWord);
this._findInput.setCaseSensitive(this._state.matchCase);
this.findFirst();
}));
this._register(this._findInput.onKeyDown((e) => {
if (e.equals(KeyCode.Enter)) {
this.find(this._invertDefaultDirection);
e.preventDefault();
return;
}
if (e.equals(KeyMod.Shift | KeyCode.Enter)) {
this.find(!this._invertDefaultDirection);
e.preventDefault();
return;
}
}));
this.prevBtn = this._register(new SimpleButton({
label: NLS_PREVIOUS_MATCH_BTN_LABEL,
className: 'previous',
onTrigger: () => {
this.find(true);
}
}));
this.nextBtn = this._register(new SimpleButton({
label: NLS_NEXT_MATCH_BTN_LABEL,
className: 'next',
onTrigger: () => {
this.find(false);
}
}));
const closeBtn = this._register(new SimpleButton({
label: NLS_CLOSE_BTN_LABEL,
className: 'close-fw',
onTrigger: () => {
this.hide();
}
}));
this._innerDomNode = document.createElement('div');
this._innerDomNode.classList.add('simple-find-part');
this._innerDomNode.appendChild(this._findInput.domNode);
this._innerDomNode.appendChild(this.prevBtn.domNode);
this._innerDomNode.appendChild(this.nextBtn.domNode);
this._innerDomNode.appendChild(closeBtn.domNode);
// _domNode wraps _innerDomNode, ensuring that
this._domNode = document.createElement('div');
this._domNode.classList.add('simple-find-part-wrapper');
this._domNode.appendChild(this._innerDomNode);
this.onkeyup(this._innerDomNode, e => {
if (e.equals(KeyCode.Escape)) {
this.hide();
e.preventDefault();
return;
}
});
this._focusTracker = this._register(dom.trackFocus(this._innerDomNode));
this._register(this._focusTracker.onDidFocus(this.onFocusTrackerFocus.bind(this)));
this._register(this._focusTracker.onDidBlur(this.onFocusTrackerBlur.bind(this)));
this._findInputFocusTracker = this._register(dom.trackFocus(this._findInput.domNode));
this._register(this._findInputFocusTracker.onDidFocus(this.onFindInputFocusTrackerFocus.bind(this)));
this._register(this._findInputFocusTracker.onDidBlur(this.onFindInputFocusTrackerBlur.bind(this)));
this._register(dom.addDisposableListener(this._innerDomNode, 'click', (event) => {
event.stopPropagation();
}));
}
protected abstract onInputChanged(): boolean;
protected abstract find(previous: boolean): void;
protected abstract findFirst(): void;
protected abstract onFocusTrackerFocus(): void;
protected abstract onFocusTrackerBlur(): void;
protected abstract onFindInputFocusTrackerFocus(): void;
protected abstract onFindInputFocusTrackerBlur(): void;
protected get inputValue() {
return this._findInput.getValue();
}
public get focusTracker(): dom.IFocusTracker {
return this._focusTracker;
}
public updateTheme(theme: ITheme): void {
const inputStyles: IFindInputStyles = {
inputActiveOptionBorder: theme.getColor(inputActiveOptionBorder),
inputActiveOptionBackground: theme.getColor(inputActiveOptionBackground),
inputBackground: theme.getColor(inputBackground),
inputForeground: theme.getColor(inputForeground),
inputBorder: theme.getColor(inputBorder),
inputValidationInfoBackground: theme.getColor(inputValidationInfoBackground),
inputValidationInfoForeground: theme.getColor(inputValidationInfoForeground),
inputValidationInfoBorder: theme.getColor(inputValidationInfoBorder),
inputValidationWarningBackground: theme.getColor(inputValidationWarningBackground),
inputValidationWarningForeground: theme.getColor(inputValidationWarningForeground),
inputValidationWarningBorder: theme.getColor(inputValidationWarningBorder),
inputValidationErrorBackground: theme.getColor(inputValidationErrorBackground),
inputValidationErrorForeground: theme.getColor(inputValidationErrorForeground),
inputValidationErrorBorder: theme.getColor(inputValidationErrorBorder)
};
this._findInput.style(inputStyles);
}
dispose() {
super.dispose();
if (this._domNode && this._domNode.parentElement) {
this._domNode.parentElement.removeChild(this._domNode);
}
}
public getDomNode() {
return this._domNode;
}
public reveal(initialInput?: string): void {
if (initialInput) {
this._findInput.setValue(initialInput);
}
if (this._isVisible) {
this._findInput.select();
return;
}
this._isVisible = true;
this._updateButtons();
setTimeout(() => {
dom.addClass(this._innerDomNode, 'visible');
dom.addClass(this._innerDomNode, 'visible-transition');
this._innerDomNode.setAttribute('aria-hidden', 'false');
this._findInput.select();
}, 0);
}
public show(initialInput?: string): void {
if (initialInput && !this._isVisible) {
this._findInput.setValue(initialInput);
}
this._isVisible = true;
setTimeout(() => {
dom.addClass(this._innerDomNode, 'visible');
dom.addClass(this._innerDomNode, 'visible-transition');
this._innerDomNode.setAttribute('aria-hidden', 'false');
}, 0);
}
public hide(): void {
if (this._isVisible) {
dom.removeClass(this._innerDomNode, 'visible-transition');
this._innerDomNode.setAttribute('aria-hidden', 'true');
// Need to delay toggling visibility until after Transition, then visibility hidden - removes from tabIndex list
setTimeout(() => {
this._isVisible = false;
this._updateButtons();
dom.removeClass(this._innerDomNode, 'visible');
}, 200);
}
}
protected _delayedUpdateHistory() {
this._updateHistoryDelayer.trigger(this._updateHistory.bind(this));
}
protected _updateHistory() {
this._findInput.inputBox.addToHistory();
}
protected _getRegexValue(): boolean {
return this._findInput.getRegex();
}
protected _getWholeWordValue(): boolean {
return this._findInput.getWholeWords();
}
protected _getCaseSensitiveValue(): boolean {
return this._findInput.getCaseSensitive();
}
private _updateButtons() {
let hasInput = this.inputValue.length > 0;
this.prevBtn.setEnabled(this._isVisible && hasInput && this.foundMatch);
this.nextBtn.setEnabled(this._isVisible && hasInput && this.foundMatch);
}
}
// theming
registerThemingParticipant((theme, collector) => {
const findWidgetBGColor = theme.getColor(editorWidgetBackground);
if (findWidgetBGColor) {
collector.addRule(`.monaco-workbench .simple-find-part { background-color: ${findWidgetBGColor} !important; }`);
}
const widgetShadowColor = theme.getColor(widgetShadow);
if (widgetShadowColor) {
collector.addRule(`.monaco-workbench .simple-find-part { box-shadow: 0 2px 8px ${widgetShadowColor}; }`);
}
});

View File

@@ -11,7 +11,6 @@ import { registerEditorContribution } from 'vs/editor/browser/editorExtensions';
import { IEditorContribution } from 'vs/editor/common/editorCommon';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
/**
* Shows a message when opening a large file which has been memory optimized (and features disabled).
@@ -20,26 +19,19 @@ export class LargeFileOptimizationsWarner extends Disposable implements IEditorC
private static readonly ID = 'editor.contrib.largeFileOptimizationsWarner';
private _isDisabled: boolean;
constructor(
private readonly _editor: ICodeEditor,
@INotificationService private readonly _notificationService: INotificationService,
@IConfigurationService private readonly _configurationService: IConfigurationService,
@IStorageService private readonly _storageService: IStorageService,
) {
super();
this._isDisabled = Boolean(this._storageService.getBoolean('editor.neverPromptForLargeFiles', StorageScope.GLOBAL, false));
this._register(this._editor.onDidChangeModel((e) => {
const model = this._editor.getModel();
if (!model) {
return;
}
if (this._isDisabled) {
return;
}
if (model.isTooLargeForTokenization()) {
const message = nls.localize(
@@ -54,13 +46,6 @@ export class LargeFileOptimizationsWarner extends Disposable implements IEditorC
);
this._notificationService.prompt(Severity.Info, message, [
{
label: nls.localize('dontShowAgain', "Don't Show Again"),
run: () => {
this._isDisabled = true;
this._storageService.store('editor.neverPromptForLargeFiles', true, StorageScope.GLOBAL);
}
},
{
label: nls.localize('removeOptimizations', "Forcefully enable features"),
run: () => {
@@ -71,7 +56,7 @@ export class LargeFileOptimizationsWarner extends Disposable implements IEditorC
});
}
}
]);
], { neverShowAgain: { id: 'editor.contrib.largeFileOptimizationsWarner' } });
}
}));
}

View File

@@ -14,7 +14,7 @@ import { IThemeService } from 'vs/platform/theme/common/themeService';
export class CommentFormActions implements IDisposable {
private _buttonElements: HTMLElement[] = [];
private readonly _toDispose = new DisposableStore();
private _actions: IAction[];
private _actions: IAction[] = [];
constructor(
private container: HTMLElement,
@@ -59,4 +59,4 @@ export class CommentFormActions implements IDisposable {
dispose() {
this._toDispose.dispose();
}
}
}

View File

@@ -16,7 +16,7 @@ const overviewRulerDefault = new Color(new RGBA(197, 197, 197, 1));
export const overviewRulerCommentingRangeForeground = registerColor('editorGutter.commentRangeForeground', { dark: overviewRulerDefault, light: overviewRulerDefault, hc: overviewRulerDefault }, nls.localize('editorGutterCommentRangeForeground', 'Editor gutter decoration color for commenting ranges.'));
export class CommentGlyphWidget {
private _lineNumber: number;
private _lineNumber!: number;
private _editor: ICodeEditor;
private commentsDecorations: string[] = [];
private _commentsOptions: ModelDecorationOptions;

View File

@@ -40,22 +40,22 @@ export class CommentNode extends Disposable {
private _md: HTMLElement;
private _clearTimeout: any;
private _editAction: Action;
private _commentEditContainer: HTMLElement;
private _editAction: Action | null = null;
private _commentEditContainer: HTMLElement | null = null;
private _commentDetailsContainer: HTMLElement;
private _actionsToolbarContainer: HTMLElement;
private _actionsToolbarContainer!: HTMLElement;
private _reactionsActionBar?: ActionBar;
private _reactionActionsContainer?: HTMLElement;
private _commentEditor: SimpleCommentEditor | null;
private _commentEditor: SimpleCommentEditor | null = null;
private _commentEditorDisposables: IDisposable[] = [];
private _commentEditorModel: ITextModel;
private _isPendingLabel: HTMLElement;
private _commentEditorModel: ITextModel | null = null;
private _isPendingLabel!: HTMLElement;
private _contextKeyService: IContextKeyService;
private _commentContextValue: IContextKey<string>;
protected actionRunner?: IActionRunner;
protected toolbar: ToolBar | undefined;
private _commentFormActions: CommentFormActions;
private _commentFormActions: CommentFormActions | null = null;
private _onDidDelete = new Emitter<CommentNode>();
@@ -63,7 +63,7 @@ export class CommentNode extends Disposable {
return this._domNode;
}
public isEditing: boolean;
public isEditing: boolean = false;
constructor(
private commentThread: modes.CommentThread,
@@ -326,8 +326,8 @@ export class CommentNode extends Disposable {
}
}
private createCommentEditor(): void {
const container = dom.append(this._commentEditContainer, dom.$('.edit-textarea'));
private createCommentEditor(editContainer: HTMLElement): void {
const container = dom.append(editContainer, dom.$('.edit-textarea'));
this._commentEditor = this.instantiationService.createInstance(SimpleCommentEditor, container, SimpleCommentEditor.getEditorOptions(), this.parentEditor, this.parentThread);
const resource = URI.parse(`comment:commentinput-${this.comment.uniqueIdInThread}-${Date.now()}.md`);
this._commentEditorModel = this.modelService.createModel('', this.modeService.createByFilepathOrFirstLine(resource), resource, false);
@@ -390,7 +390,7 @@ export class CommentNode extends Disposable {
this._commentEditor = null;
}
this._commentEditContainer.remove();
this._commentEditContainer!.remove();
}
public switchToEditMode() {
@@ -401,7 +401,7 @@ export class CommentNode extends Disposable {
this.isEditing = true;
this._body.classList.add('hidden');
this._commentEditContainer = dom.append(this._commentDetailsContainer, dom.$('.edit-container'));
this.createCommentEditor();
this.createCommentEditor(this._commentEditContainer);
const formActions = dom.append(this._commentEditContainer, dom.$('.form-actions'));
const menus = this.commentService.getCommentMenus(this.owner);
@@ -409,7 +409,9 @@ export class CommentNode extends Disposable {
this._register(menu);
this._register(menu.onDidChange(() => {
this._commentFormActions.setActions(menu);
if (this._commentFormActions) {
this._commentFormActions.setActions(menu);
}
}));
this._commentFormActions = new CommentFormActions(formActions, (action: IAction): void => {

View File

@@ -4,34 +4,31 @@
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/panel';
import * as nls from 'vs/nls';
import * as dom from 'vs/base/browser/dom';
import { IAction } from 'vs/base/common/actions';
import { Event } from 'vs/base/common/event';
import { CollapseAllAction, DefaultAccessibilityProvider, DefaultController, DefaultDragAndDrop } from 'vs/base/parts/tree/browser/treeDefaults';
import { IAction, Action } from 'vs/base/common/actions';
import { CollapseAllAction } from 'vs/base/browser/ui/tree/treeDefaults';
import { isCodeEditor } from 'vs/editor/browser/editorBrowser';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { TreeResourceNavigator, WorkbenchTree } from 'vs/platform/list/browser/listService';
import { TreeResourceNavigator2 } from 'vs/platform/list/browser/listService';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { Panel } from 'vs/workbench/browser/panel';
import { CommentNode, CommentsModel, ResourceWithCommentThreads, ICommentThreadChangedEvent } from 'vs/workbench/contrib/comments/common/commentModel';
import { ReviewController } from 'vs/workbench/contrib/comments/browser/commentsEditorContribution';
import { CommentsDataFilter, CommentsDataSource, CommentsModelRenderer } from 'vs/workbench/contrib/comments/browser/commentsTreeViewer';
import { ICommentService, IWorkspaceCommentThreadsEvent } from 'vs/workbench/contrib/comments/browser/commentService';
import { IEditorService, ACTIVE_GROUP, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { textLinkForeground, textLinkActiveForeground, focusBorder, textPreformatForeground } from 'vs/platform/theme/common/colorRegistry';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { ResourceLabels } from 'vs/workbench/browser/labels';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { CommentsList, COMMENTS_PANEL_ID, COMMENTS_PANEL_TITLE } from 'vs/workbench/contrib/comments/browser/commentsTreeViewer';
export const COMMENTS_PANEL_ID = 'workbench.panel.comments';
export const COMMENTS_PANEL_TITLE = 'Comments';
export class CommentsPanel extends Panel {
private treeLabels: ResourceLabels;
private tree: WorkbenchTree;
private tree: CommentsList;
private treeContainer: HTMLElement;
private messageBoxContainer: HTMLElement;
private messageBox: HTMLElement;
@@ -42,7 +39,6 @@ export class CommentsPanel extends Panel {
@IInstantiationService private readonly instantiationService: IInstantiationService,
@ICommentService private readonly commentService: ICommentService,
@IEditorService private readonly editorService: IEditorService,
@IOpenerService private readonly openerService: IOpenerService,
@ITelemetryService telemetryService: ITelemetryService,
@IThemeService themeService: IThemeService,
@IStorageService storageService: IStorageService
@@ -113,7 +109,7 @@ export class CommentsPanel extends Panel {
public getActions(): IAction[] {
if (!this.collapseAllAction) {
this.collapseAllAction = this.instantiationService.createInstance(CollapseAllAction, this.tree, this.commentsModel.hasCommentThreads());
this.collapseAllAction = new Action('vs.tree.collapse', nls.localize('collapseAll', "Collapse All"), 'monaco-tree-action collapse-all', true, () => this.tree ? new CollapseAllAction<any, any>(this.tree, true).run() : Promise.resolve());
this._register(this.collapseAllAction);
}
@@ -141,22 +137,11 @@ export class CommentsPanel extends Panel {
private createTree(): void {
this.treeLabels = this._register(this.instantiationService.createInstance(ResourceLabels, this));
this.tree = this._register(this.instantiationService.createInstance(CommentsList, this.treeLabels, this.treeContainer));
this.tree = this._register(this.instantiationService.createInstance(WorkbenchTree, this.treeContainer, {
dataSource: new CommentsDataSource(),
renderer: new CommentsModelRenderer(this.treeLabels, this.openerService),
accessibilityProvider: new DefaultAccessibilityProvider,
controller: new DefaultController(),
dnd: new DefaultDragAndDrop(),
filter: new CommentsDataFilter()
}, {
twistiePixels: 20,
ariaLabel: COMMENTS_PANEL_TITLE
}));
const commentsNavigator = this._register(new TreeResourceNavigator(this.tree, { openOnFocus: true }));
this._register(Event.debounce(commentsNavigator.openResource, (last, event) => event, 100, true)(options => {
this.openFile(options.element, options.editorOptions.pinned, options.editorOptions.preserveFocus, options.sideBySide);
const commentsNavigator = this._register(new TreeResourceNavigator2(this.tree, { openOnFocus: true }));
this._register(commentsNavigator.onDidOpenResource(e => {
this.openFile(e.element, e.editorOptions.pinned, e.editorOptions.preserveFocus, e.sideBySide);
}));
}
@@ -213,7 +198,7 @@ export class CommentsPanel extends Panel {
this.collapseAllAction.enabled = this.commentsModel.hasCommentThreads();
dom.toggleClass(this.treeContainer, 'hidden', !this.commentsModel.hasCommentThreads());
this.tree.refresh().then(() => {
this.tree.updateChildren().then(() => {
this.renderMessage();
}, (e) => {
console.log(e);
@@ -243,4 +228,4 @@ CommandsRegistry.registerCommand({
panelService.openPanel(COMMENTS_PANEL_ID, true);
}
}
});
});

View File

@@ -9,30 +9,28 @@ import { renderMarkdown } from 'vs/base/browser/htmlContentRenderer';
import { onUnexpectedError } from 'vs/base/common/errors';
import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri';
import { IDataSource, IFilter, IRenderer as ITreeRenderer, ITree } from 'vs/base/parts/tree/browser/tree';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { IResourceLabel, ResourceLabels } from 'vs/workbench/browser/labels';
import { CommentNode, CommentsModel, ResourceWithCommentThreads } from 'vs/workbench/contrib/comments/common/commentModel';
import { IAsyncDataSource, ITreeNode } from 'vs/base/browser/ui/tree/tree';
import { IListVirtualDelegate, IListRenderer } from 'vs/base/browser/ui/list/list';
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { WorkbenchAsyncDataTree, IListService } from 'vs/platform/list/browser/listService';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
export class CommentsDataSource implements IDataSource {
public getId(tree: ITree, element: any): string {
if (element instanceof CommentsModel) {
return 'root';
}
if (element instanceof ResourceWithCommentThreads) {
return `${element.owner}-${element.id}`;
}
if (element instanceof CommentNode) {
return `${element.owner}-${element.resource.toString()}-${element.threadId}-${element.comment.uniqueIdInThread}` + (element.isRoot ? '-root' : '');
}
return '';
}
export const COMMENTS_PANEL_ID = 'workbench.panel.comments';
export const COMMENTS_PANEL_TITLE = 'Comments';
public hasChildren(tree: ITree, element: any): boolean {
export class CommentsAsyncDataSource implements IAsyncDataSource<any, any> {
hasChildren(element: any): boolean {
return element instanceof CommentsModel || element instanceof ResourceWithCommentThreads || (element instanceof CommentNode && !!element.replies.length);
}
public getChildren(tree: ITree, element: any): Promise<ResourceWithCommentThreads[] | CommentNode[]> {
getChildren(element: any): any[] | Promise<any[]> {
if (element instanceof CommentsModel) {
return Promise.resolve(element.resourceCommentThreads);
}
@@ -44,14 +42,6 @@ export class CommentsDataSource implements IDataSource {
}
return Promise.resolve([]);
}
public getParent(tree: ITree, element: any): Promise<void> {
return Promise.resolve(undefined);
}
public shouldAutoexpand(tree: ITree, element: any): boolean {
return true;
}
}
interface IResourceTemplateData {
@@ -65,61 +55,36 @@ interface ICommentThreadTemplateData {
disposables: IDisposable[];
}
export class CommentsModelRenderer implements ITreeRenderer {
export class CommentsModelVirualDelegate implements IListVirtualDelegate<any> {
private static RESOURCE_ID = 'resource-with-comments';
private static COMMENT_ID = 'comment-node';
constructor(
private labels: ResourceLabels,
@IOpenerService private readonly openerService: IOpenerService
) {
}
public getHeight(tree: ITree, element: any): number {
getHeight(element: any): number {
return 22;
}
public getTemplateId(tree: ITree, element: any): string {
public getTemplateId(element: any): string {
if (element instanceof ResourceWithCommentThreads) {
return CommentsModelRenderer.RESOURCE_ID;
return CommentsModelVirualDelegate.RESOURCE_ID;
}
if (element instanceof CommentNode) {
return CommentsModelRenderer.COMMENT_ID;
return CommentsModelVirualDelegate.COMMENT_ID;
}
return '';
}
}
public renderTemplate(ITree: ITree, templateId: string, container: HTMLElement): any {
switch (templateId) {
case CommentsModelRenderer.RESOURCE_ID:
return this.renderResourceTemplate(container);
case CommentsModelRenderer.COMMENT_ID:
return this.renderCommentTemplate(container);
}
export class ResourceWithCommentsRenderer implements IListRenderer<ITreeNode<ResourceWithCommentThreads>, IResourceTemplateData> {
templateId: string = 'resource-with-comments';
constructor(
private labels: ResourceLabels
) {
}
public disposeTemplate(tree: ITree, templateId: string, templateData: any): void {
switch (templateId) {
case CommentsModelRenderer.RESOURCE_ID:
(<IResourceTemplateData>templateData).resourceLabel.dispose();
break;
case CommentsModelRenderer.COMMENT_ID:
(<ICommentThreadTemplateData>templateData).disposables.forEach(disposeable => disposeable.dispose());
break;
}
}
public renderElement(tree: ITree, element: any, templateId: string, templateData: any): void {
switch (templateId) {
case CommentsModelRenderer.RESOURCE_ID:
return this.renderResourceElement(tree, element, templateData);
case CommentsModelRenderer.COMMENT_ID:
return this.renderCommentElement(tree, element, templateData);
}
}
private renderResourceTemplate(container: HTMLElement): IResourceTemplateData {
renderTemplate(container: HTMLElement) {
const data = <IResourceTemplateData>Object.create(null);
const labelContainer = dom.append(container, dom.$('.resource-container'));
data.resourceLabel = this.labels.create(labelContainer);
@@ -127,7 +92,23 @@ export class CommentsModelRenderer implements ITreeRenderer {
return data;
}
private renderCommentTemplate(container: HTMLElement): ICommentThreadTemplateData {
renderElement(node: ITreeNode<ResourceWithCommentThreads>, index: number, templateData: IResourceTemplateData, height: number | undefined): void {
templateData.resourceLabel.setFile(node.element.resource);
}
disposeTemplate(templateData: IResourceTemplateData): void {
templateData.resourceLabel.dispose();
}
}
export class CommentNodeRenderer implements IListRenderer<ITreeNode<CommentNode>, ICommentThreadTemplateData> {
templateId: string = 'comment-node';
constructor(
@IOpenerService private readonly openerService: IOpenerService
) { }
renderTemplate(container: HTMLElement) {
const data = <ICommentThreadTemplateData>Object.create(null);
const labelContainer = dom.append(container, dom.$('.comment-container'));
data.userName = dom.append(labelContainer, dom.$('.user'));
@@ -137,16 +118,12 @@ export class CommentsModelRenderer implements ITreeRenderer {
return data;
}
private renderResourceElement(tree: ITree, element: ResourceWithCommentThreads, templateData: IResourceTemplateData) {
templateData.resourceLabel.setFile(element.resource);
}
private renderCommentElement(tree: ITree, element: CommentNode, templateData: ICommentThreadTemplateData) {
templateData.userName.textContent = element.comment.userName;
renderElement(node: ITreeNode<CommentNode>, index: number, templateData: ICommentThreadTemplateData, height: number | undefined): void {
templateData.userName.textContent = node.element.comment.userName;
templateData.commentText.innerHTML = '';
const disposables = new DisposableStore();
templateData.disposables.push(disposables);
const renderedComment = renderMarkdown(element.comment.body, {
const renderedComment = renderMarkdown(node.element.comment.body, {
inline: true,
actionHandler: {
callback: (content) => {
@@ -171,16 +148,71 @@ export class CommentsModelRenderer implements ITreeRenderer {
templateData.commentText.appendChild(renderedComment);
}
}
export class CommentsDataFilter implements IFilter {
public isVisible(tree: ITree, element: any): boolean {
if (element instanceof CommentsModel) {
return element.resourceCommentThreads.length > 0;
}
if (element instanceof ResourceWithCommentThreads) {
return element.commentThreads.length > 0;
}
return true;
disposeTemplate(templateData: ICommentThreadTemplateData): void {
templateData.disposables.forEach(disposeable => disposeable.dispose());
}
}
export class CommentsList extends WorkbenchAsyncDataTree<any, any> {
constructor(
labels: ResourceLabels,
container: HTMLElement,
@IContextKeyService contextKeyService: IContextKeyService,
@IListService listService: IListService,
@IThemeService themeService: IThemeService,
@IInstantiationService instantiationService: IInstantiationService,
@IConfigurationService configurationService: IConfigurationService,
@IKeybindingService keybindingService: IKeybindingService,
@IAccessibilityService accessibilityService: IAccessibilityService
) {
const delegate = new CommentsModelVirualDelegate();
const dataSource = new CommentsAsyncDataSource();
const renderers = [
instantiationService.createInstance(ResourceWithCommentsRenderer, labels),
instantiationService.createInstance(CommentNodeRenderer)
];
super(
container,
delegate,
renderers,
dataSource,
{
ariaLabel: COMMENTS_PANEL_TITLE,
keyboardSupport: true,
identityProvider: {
getId: (element: any) => {
if (element instanceof CommentsModel) {
return 'root';
}
if (element instanceof ResourceWithCommentThreads) {
return `${element.owner}-${element.id}`;
}
if (element instanceof CommentNode) {
return `${element.owner}-${element.resource.toString()}-${element.threadId}-${element.comment.uniqueIdInThread}` + (element.isRoot ? '-root' : '');
}
return '';
}
},
expandOnlyOnTwistieClick: (element: any) => {
if (element instanceof CommentsModel || element instanceof ResourceWithCommentThreads) {
return false;
}
return true;
},
collapseByDefault: () => {
return false;
}
},
contextKeyService,
listService,
themeService,
configurationService,
keybindingService,
accessibilityService
);
}
}

View File

@@ -11,11 +11,10 @@ import { URI, UriComponents } from 'vs/base/common/uri';
export class ToggleReactionsAction extends Action {
static readonly ID = 'toolbar.toggle.pickReactions';
private _menuActions: IAction[];
private _menuActions: IAction[] = [];
private toggleDropdownMenu: () => void;
constructor(toggleDropdownMenu: () => void, title?: string) {
title = title || nls.localize('pickReactions', "Pick Reactions...");
super(ToggleReactionsAction.ID, title, 'toggle-reactions', true);
super(ToggleReactionsAction.ID, title || nls.localize('pickReactions', "Pick Reactions..."), 'toggle-reactions', true);
this.toggleDropdownMenu = toggleDropdownMenu;
}
run(): Promise<any> {

View File

@@ -45,10 +45,10 @@ export interface IPrivateBreakpointWidgetService {
const DECORATION_KEY = 'breakpointwidgetdecoration';
export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWidgetService {
public _serviceBrand: any;
_serviceBrand: any;
private selectContainer: HTMLElement;
private input: IActiveCodeEditor;
private selectContainer!: HTMLElement;
private input!: IActiveCodeEditor;
private toDispose: lifecycle.IDisposable[];
private conditionInput = '';
private hitCountInput = '';
@@ -130,12 +130,12 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi
}
}
public show(rangeOrPos: IRange | IPosition, heightInLines: number) {
show(rangeOrPos: IRange | IPosition, heightInLines: number) {
const lineNum = this.input.getModel().getLineCount();
super.show(rangeOrPos, lineNum + 1);
}
public fitHeightToContent() {
fitHeightToContent() {
const lineNum = this.input.getModel().getLineCount();
this._relayout(lineNum + 1);
}
@@ -165,50 +165,6 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi
setTimeout(() => this.input.focus(), 150);
}
public close(success: boolean): void {
if (success) {
// if there is already a breakpoint on this location - remove it.
let condition = this.breakpoint && this.breakpoint.condition;
let hitCondition = this.breakpoint && this.breakpoint.hitCondition;
let logMessage = this.breakpoint && this.breakpoint.logMessage;
this.rememberInput();
if (this.conditionInput || this.context === Context.CONDITION) {
condition = this.conditionInput;
}
if (this.hitCountInput || this.context === Context.HIT_COUNT) {
hitCondition = this.hitCountInput;
}
if (this.logMessageInput || this.context === Context.LOG_MESSAGE) {
logMessage = this.logMessageInput;
}
if (this.breakpoint) {
const data = new Map<string, IBreakpointUpdateData>();
data.set(this.breakpoint.getId(), {
condition,
hitCondition,
logMessage
});
this.debugService.updateBreakpoints(this.breakpoint.uri, data, false).then(undefined, onUnexpectedError);
} else {
const model = this.editor.getModel();
if (model) {
this.debugService.addBreakpoints(model.uri, [{
lineNumber: this.lineNumber,
enabled: true,
condition,
hitCondition,
logMessage
}], `breakpointWidget`);
}
}
}
this.dispose();
}
protected _doLayout(heightInPixel: number, widthInPixel: number): void {
this.input.layout({ height: heightInPixel, width: widthInPixel - 113 });
}
@@ -305,7 +261,51 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi
return false;
}
public dispose(): void {
close(success: boolean): void {
if (success) {
// if there is already a breakpoint on this location - remove it.
let condition = this.breakpoint && this.breakpoint.condition;
let hitCondition = this.breakpoint && this.breakpoint.hitCondition;
let logMessage = this.breakpoint && this.breakpoint.logMessage;
this.rememberInput();
if (this.conditionInput || this.context === Context.CONDITION) {
condition = this.conditionInput;
}
if (this.hitCountInput || this.context === Context.HIT_COUNT) {
hitCondition = this.hitCountInput;
}
if (this.logMessageInput || this.context === Context.LOG_MESSAGE) {
logMessage = this.logMessageInput;
}
if (this.breakpoint) {
const data = new Map<string, IBreakpointUpdateData>();
data.set(this.breakpoint.getId(), {
condition,
hitCondition,
logMessage
});
this.debugService.updateBreakpoints(this.breakpoint.uri, data, false).then(undefined, onUnexpectedError);
} else {
const model = this.editor.getModel();
if (model) {
this.debugService.addBreakpoints(model.uri, [{
lineNumber: this.lineNumber,
enabled: true,
condition,
hitCondition,
logMessage
}], `breakpointWidget`);
}
}
}
this.dispose();
}
dispose(): void {
super.dispose();
this.input.dispose();
lifecycle.dispose(this.toDispose);
@@ -327,7 +327,7 @@ class AcceptBreakpointWidgetInputAction extends EditorCommand {
});
}
public runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor): void {
runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor): void {
accessor.get(IPrivateBreakpointWidgetService).close(true);
}
}
@@ -347,7 +347,7 @@ class CloseBreakpointWidgetCommand extends EditorCommand {
});
}
public runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void {
runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void {
const debugContribution = editor.getContribution<IDebugEditorContribution>(EDITOR_CONTRIBUTION_ID);
if (debugContribution) {
// if focus is in outer editor we need to use the debug contribution to close

View File

@@ -45,8 +45,8 @@ function createCheckbox(): HTMLInputElement {
export class BreakpointsView extends ViewletPanel {
private static readonly MAX_VISIBLE_FILES = 9;
private list: WorkbenchList<IEnablement>;
private needsRefresh: boolean;
private list!: WorkbenchList<IEnablement>;
private needsRefresh = false;
constructor(
options: IViewletViewOptions,

View File

@@ -37,15 +37,15 @@ type CallStackItem = IStackFrame | IThread | IDebugSession | string | ThreadAndS
export class CallStackView extends ViewletPanel {
private pauseMessage: HTMLSpanElement;
private pauseMessageLabel: HTMLSpanElement;
private pauseMessage!: HTMLSpanElement;
private pauseMessageLabel!: HTMLSpanElement;
private onCallStackChangeScheduler: RunOnceScheduler;
private needsRefresh: boolean;
private ignoreSelectionChangedEvent: boolean;
private ignoreFocusStackFrameEvent: boolean;
private needsRefresh = false;
private ignoreSelectionChangedEvent = false;
private ignoreFocusStackFrameEvent = false;
private callStackItemType: IContextKey<string>;
private dataSource: CallStackDataSource;
private tree: WorkbenchAsyncDataTree<CallStackItem | IDebugModel, CallStackItem, FuzzyScore>;
private dataSource!: CallStackDataSource;
private tree!: WorkbenchAsyncDataTree<CallStackItem | IDebugModel, CallStackItem, FuzzyScore>;
private contributedContextMenu: IMenu;
private parentSessionToExpand = new Set<IDebugSession>();
@@ -584,7 +584,7 @@ function isDeemphasized(frame: IStackFrame): boolean {
}
class CallStackDataSource implements IAsyncDataSource<IDebugModel, CallStackItem> {
deemphasizedStackFramesToShow: IStackFrame[];
deemphasizedStackFramesToShow: IStackFrame[] = [];
constructor(private debugService: IDebugService) { }

View File

@@ -260,6 +260,11 @@ configurationRegistry.registerConfiguration({
description: nls.localize({ comment: ['This is the description for a setting'], key: 'launch' }, "Global debug launch configuration. Should be used as an alternative to 'launch.json' that is shared across workspaces."),
default: { configurations: [], compounds: [] },
$ref: launchSchemaId
},
'debug.focusWindowOnBreak': {
type: 'boolean',
description: nls.localize('debug.focusWindowOnBreak', "Controls whether the workbench window should be focused when the debugger breaks."),
default: true
}
}
});

View File

@@ -27,13 +27,13 @@ export class StartDebugActionViewItem implements IActionViewItem {
private static readonly SEPARATOR = '─────────';
public actionRunner: IActionRunner;
private container: HTMLElement;
private start: HTMLElement;
actionRunner!: IActionRunner;
private container!: HTMLElement;
private start!: HTMLElement;
private selectBox: SelectBox;
private options: { label: string, handler?: (() => boolean) }[];
private options: { label: string, handler?: (() => boolean) }[] = [];
private toDispose: IDisposable[];
private selected: number;
private selected = 0;
constructor(
private context: any,
@@ -66,7 +66,7 @@ export class StartDebugActionViewItem implements IActionViewItem {
}));
}
public render(container: HTMLElement): void {
render(container: HTMLElement): void {
this.container = container;
dom.addClass(container, 'start-debug-action-item');
this.start = dom.append(container, $('.icon'));
@@ -129,15 +129,15 @@ export class StartDebugActionViewItem implements IActionViewItem {
this.updateOptions();
}
public setActionContext(context: any): void {
setActionContext(context: any): void {
this.context = context;
}
public isEnabled(): boolean {
isEnabled(): boolean {
return true;
}
public focus(fromRight?: boolean): void {
focus(fromRight?: boolean): void {
if (fromRight) {
this.selectBox.focus();
} else {
@@ -145,11 +145,11 @@ export class StartDebugActionViewItem implements IActionViewItem {
}
}
public blur(): void {
blur(): void {
this.container.blur();
}
public dispose(): void {
dispose(): void {
this.toDispose = dispose(this.toDispose);
}

View File

@@ -34,6 +34,7 @@ import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { onUnexpectedError } from 'vs/base/common/errors';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { CancellationToken } from 'vs/base/common/cancellation';
const jsonRegistry = Registry.as<IJSONContributionRegistry>(JSONExtensions.JSONContribution);
jsonRegistry.registerSchema(launchSchemaId, launchSchema);
@@ -44,7 +45,7 @@ const DEBUG_SELECTED_ROOT = 'debug.selectedroot';
export class ConfigurationManager implements IConfigurationManager {
private debuggers: Debugger[];
private breakpointModeIdsSet = new Set<string>();
private launches: ILaunch[];
private launches!: ILaunch[];
private selectedName: string | undefined;
private selectedLaunch: ILaunch | undefined;
private toDispose: IDisposable[];
@@ -180,7 +181,7 @@ export class ConfigurationManager implements IConfigurationManager {
return providers.length > 0;
}
resolveConfigurationByProviders(folderUri: uri | undefined, type: string | undefined, debugConfiguration: IConfig): Promise<IConfig | null | undefined> {
resolveConfigurationByProviders(folderUri: uri | undefined, type: string | undefined, debugConfiguration: IConfig, token: CancellationToken): Promise<IConfig | null | undefined> {
return this.activateDebuggers('onDebugResolve', type).then(() => {
// pipe the config through the promises sequentially. Append at the end the '*' types
const providers = this.configProviders.filter(p => p.type === type && p.resolveDebugConfiguration)
@@ -189,7 +190,7 @@ export class ConfigurationManager implements IConfigurationManager {
return providers.reduce((promise, provider) => {
return promise.then(config => {
if (config) {
return provider.resolveDebugConfiguration!(folderUri, config);
return provider.resolveDebugConfiguration!(folderUri, config, token);
} else {
return Promise.resolve(config);
}
@@ -198,9 +199,9 @@ export class ConfigurationManager implements IConfigurationManager {
});
}
provideDebugConfigurations(folderUri: uri | undefined, type: string): Promise<any[]> {
provideDebugConfigurations(folderUri: uri | undefined, type: string, token: CancellationToken): Promise<any[]> {
return this.activateDebuggers('onDebugInitialConfigurations')
.then(() => Promise.all(this.configProviders.filter(p => p.type === type && p.provideDebugConfigurations).map(p => p.provideDebugConfigurations!(folderUri)))
.then(() => Promise.all(this.configProviders.filter(p => p.type === type && p.provideDebugConfigurations).map(p => p.provideDebugConfigurations!(folderUri, token)))
.then(results => results.reduce((first, second) => first.concat(second), [])));
}
@@ -531,7 +532,7 @@ class Launch extends AbstractLaunch implements ILaunch {
return this.configurationService.inspect<IGlobalConfig>('launch', { resource: this.workspace.uri }).workspaceFolder;
}
openConfigFile(sideBySide: boolean, preserveFocus: boolean, type?: string): Promise<{ editor: IEditor | null, created: boolean }> {
openConfigFile(sideBySide: boolean, preserveFocus: boolean, type?: string, token?: CancellationToken): Promise<{ editor: IEditor | null, created: boolean }> {
const resource = this.uri;
let created = false;
@@ -539,7 +540,7 @@ class Launch extends AbstractLaunch implements ILaunch {
// launch.json not found: create one by collecting launch configs from debugConfigProviders
return this.configurationManager.guessDebugger(type).then(adapter => {
if (adapter) {
return this.configurationManager.provideDebugConfigurations(this.workspace.uri, adapter.type).then(initialConfigs => {
return this.configurationManager.provideDebugConfigurations(this.workspace.uri, adapter.type, token || CancellationToken.None).then(initialConfigs => {
return adapter.getInitialConfigurationContent(initialConfigs);
});
} else {

View File

@@ -57,8 +57,8 @@ export class DebugEditorContribution implements IDebugEditorContribution {
private toDispose: lifecycle.IDisposable[];
private hoverWidget: DebugHoverWidget;
private nonDebugHoverPosition: Position;
private hoverRange: Range;
private nonDebugHoverPosition: Position | undefined;
private hoverRange: Range | null = null;
private mouseDown = false;
private breakpointHintDecoration: string[];
@@ -68,7 +68,7 @@ export class DebugEditorContribution implements IDebugEditorContribution {
private exceptionWidget: ExceptionWidget | undefined;
private configurationWidget: FloatingClickWidget;
private configurationWidget: FloatingClickWidget | undefined;
constructor(
private editor: ICodeEditor,
@@ -377,7 +377,11 @@ export class DebugEditorContribution implements IDebugEditorContribution {
@memoize
private get showHoverScheduler(): RunOnceScheduler {
const scheduler = new RunOnceScheduler(() => this.showHover(this.hoverRange, false), HOVER_DELAY);
const scheduler = new RunOnceScheduler(() => {
if (this.hoverRange) {
this.showHover(this.hoverRange, false);
}
}, HOVER_DELAY);
this.toDispose.push(scheduler);
return scheduler;
@@ -385,7 +389,11 @@ export class DebugEditorContribution implements IDebugEditorContribution {
@memoize
private get hideHoverScheduler(): RunOnceScheduler {
const scheduler = new RunOnceScheduler(() => this.hoverWidget.hide(), 2 * HOVER_DELAY);
const scheduler = new RunOnceScheduler(() => {
if (!this.hoverWidget.isHovered()) {
this.hoverWidget.hide();
}
}, 2 * HOVER_DELAY);
this.toDispose.push(scheduler);
return scheduler;
@@ -394,7 +402,7 @@ export class DebugEditorContribution implements IDebugEditorContribution {
@memoize
private get provideNonDebugHoverScheduler(): RunOnceScheduler {
const scheduler = new RunOnceScheduler(() => {
if (this.editor.hasModel()) {
if (this.editor.hasModel() && this.nonDebugHoverPosition) {
getHover(this.editor.getModel(), this.nonDebugHoverPosition, CancellationToken.None);
}
}, HOVER_DELAY);

View File

@@ -36,7 +36,7 @@ export class DebugEditorModelManager implements IWorkbenchContribution {
static readonly STICKINESS = TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges;
private modelDataMap: Map<string, IDebugEditorModelData>;
private toDispose: lifecycle.IDisposable[];
private ignoreDecorationsChangedEvent: boolean;
private ignoreDecorationsChangedEvent = false;
constructor(
@IModelService private readonly modelService: IModelService,

View File

@@ -1,21 +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 { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
import { IDebugHelperService } from 'vs/workbench/contrib/debug/common/debug';
import { TelemetryService } from 'vs/platform/telemetry/common/telemetryService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
export class BrowserDebugHelperService implements IDebugHelperService {
_serviceBrand: ServiceIdentifier<IDebugHelperService>;
createTelemetryService(configurationService: IConfigurationService, args: string[]): TelemetryService | undefined {
return undefined;
}
}
registerSingleton(IDebugHelperService, BrowserDebugHelperService);

View File

@@ -41,17 +41,16 @@ export class DebugHoverWidget implements IContentWidget {
allowEditorOverflow = true;
private _isVisible: boolean;
private domNode: HTMLElement;
private tree: AsyncDataTree<IExpression, IExpression, any>;
private domNode!: HTMLElement;
private tree!: AsyncDataTree<IExpression, IExpression, any>;
private showAtPosition: Position | null;
private highlightDecorations: string[];
private complexValueContainer: HTMLElement;
private complexValueTitle: HTMLElement;
private valueContainer: HTMLElement;
private treeContainer: HTMLElement;
private complexValueContainer!: HTMLElement;
private complexValueTitle!: HTMLElement;
private valueContainer!: HTMLElement;
private treeContainer!: HTMLElement;
private toDispose: lifecycle.IDisposable[];
private scrollbar: DomScrollableElement;
private dataSource: DebugHoverDataSource;
private scrollbar!: DomScrollableElement;
constructor(
private editor: ICodeEditor,
@@ -72,10 +71,10 @@ export class DebugHoverWidget implements IContentWidget {
this.complexValueTitle = dom.append(this.complexValueContainer, $('.title'));
this.treeContainer = dom.append(this.complexValueContainer, $('.debug-hover-tree'));
this.treeContainer.setAttribute('role', 'tree');
this.dataSource = new DebugHoverDataSource();
const dataSource = new DebugHoverDataSource();
this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, this.treeContainer, new DebugHoverDelegate(), [this.instantiationService.createInstance(VariablesRenderer)],
this.dataSource, {
dataSource, {
ariaLabel: nls.localize('treeAriaLabel', "Debug Hover"),
accessibilityProvider: new DebugHoverAccessibilityProvider(),
mouseSupport: false,
@@ -122,6 +121,10 @@ export class DebugHoverWidget implements IContentWidget {
}));
}
isHovered(): boolean {
return this.domNode.matches(':hover');
}
isVisible(): boolean {
return this._isVisible;
}

View File

@@ -77,7 +77,7 @@ export class DebugQuickOpenHandler extends QuickOpenHandler {
public static readonly ID = 'workbench.picker.launch';
private autoFocusIndex: number;
private autoFocusIndex: number | undefined;
constructor(
@IDebugService private readonly debugService: IDebugService,

View File

@@ -47,6 +47,7 @@ import { isErrorWithActions, createErrorWithActions } from 'vs/base/common/error
import { RunOnceScheduler } from 'vs/base/common/async';
import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug';
import { isCodeEditor } from 'vs/editor/browser/editorBrowser';
import { CancellationTokenSource } from 'vs/base/common/cancellation';
const DEBUG_BREAKPOINTS_KEY = 'debug.breakpoint';
const DEBUG_BREAKPOINTS_ACTIVATED_KEY = 'debug.breakpointactivated';
@@ -87,7 +88,8 @@ export class DebugService implements IDebugService {
private inDebugMode: IContextKey<boolean>;
private breakpointsToSendOnResourceSaved: Set<string>;
private initializing = false;
private previousState: State;
private previousState: State | undefined;
private initCancellationToken: CancellationTokenSource | undefined;
constructor(
@IStorageService private readonly storageService: IStorageService,
@@ -211,6 +213,10 @@ export class DebugService implements IDebugService {
}
private endInitializingState() {
if (this.initCancellationToken) {
this.initCancellationToken.cancel();
this.initCancellationToken = undefined;
}
if (this.initializing) {
this.initializing = false;
this.onStateChange();
@@ -355,8 +361,9 @@ export class DebugService implements IDebugService {
}
const debuggerThenable: Promise<void> = type ? Promise.resolve() : this.configurationManager.guessDebugger().then(dbgr => { type = dbgr && dbgr.type; });
return debuggerThenable.then(() =>
this.configurationManager.resolveConfigurationByProviders(launch && launch.workspace ? launch.workspace.uri : undefined, type, config!).then(config => {
return debuggerThenable.then(() => {
this.initCancellationToken = new CancellationTokenSource();
return this.configurationManager.resolveConfigurationByProviders(launch && launch.workspace ? launch.workspace.uri : undefined, type, config!, this.initCancellationToken.token).then(config => {
// a falsy config indicates an aborted launch
if (config && config.type) {
return this.substituteVariables(launch, config).then(resolvedConfig => {
@@ -396,17 +403,17 @@ export class DebugService implements IDebugService {
.then(() => false);
}
return launch && launch.openConfigFile(false, true).then(() => false);
return launch && launch.openConfigFile(false, true, undefined, this.initCancellationToken ? this.initCancellationToken.token : undefined).then(() => false);
});
}
if (launch && type && config === null) { // show launch.json only for "config" being "null".
return launch.openConfigFile(false, true, type).then(() => false);
return launch.openConfigFile(false, true, type, this.initCancellationToken ? this.initCancellationToken.token : undefined).then(() => false);
}
return false;
})
);
});
});
}
/**
@@ -587,7 +594,8 @@ export class DebugService implements IDebugService {
let substitutionThenable: Promise<IConfig | null | undefined> = Promise.resolve(session.configuration);
if (launch && needsToSubstitute && unresolved) {
substitutionThenable = this.configurationManager.resolveConfigurationByProviders(launch.workspace ? launch.workspace.uri : undefined, unresolved.type, unresolved)
this.initCancellationToken = new CancellationTokenSource();
substitutionThenable = this.configurationManager.resolveConfigurationByProviders(launch.workspace ? launch.workspace.uri : undefined, unresolved.type, unresolved, this.initCancellationToken.token)
.then(resolved => {
if (resolved) {
// start debugging

View File

@@ -42,7 +42,7 @@ export class DebugSession implements IDebugSession {
private sources = new Map<string, Source>();
private threads = new Map<number, Thread>();
private rawListeners: IDisposable[] = [];
private fetchThreadsScheduler: RunOnceScheduler;
private fetchThreadsScheduler: RunOnceScheduler | undefined;
private repl: ReplModel;
private readonly _onDidChangeState = new Emitter<void>();
@@ -169,7 +169,7 @@ export class DebugSession implements IDebugSession {
this.raw = new RawDebugSession(debugAdapter, dbgr, this.telemetryService, customTelemetryService, this.windowsService);
return this.raw!.start().then(() => {
return this.raw.start().then(() => {
this.registerListeners();
@@ -674,7 +674,10 @@ export class DebugSession implements IDebugSession {
if (this.configurationService.getValue<IDebugConfiguration>('debug').openDebug === 'openOnDebugBreak') {
this.viewletService.openViewlet(VIEWLET_ID);
}
this.windowService.focusWindow();
if (this.configurationService.getValue<IDebugConfiguration>('debug').focusWindowOnBreak) {
this.windowService.focusWindow();
}
}
}
};

View File

@@ -13,7 +13,7 @@ import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
export class DebugStatusContribution implements IWorkbenchContribution {
private showInStatusBar: 'never' | 'always' | 'onFirstSessionStart';
private showInStatusBar!: 'never' | 'always' | 'onFirstSessionStart';
private toDispose: IDisposable[] = [];
private entryAccessor: IStatusbarEntryAccessor | undefined;

View File

@@ -55,10 +55,10 @@ export class DebugToolBar extends Themable implements IWorkbenchContribution {
private activeActions: IAction[];
private updateScheduler: RunOnceScheduler;
private debugToolBarMenu: IMenu;
private disposeOnUpdate: IDisposable;
private disposeOnUpdate: IDisposable | undefined;
private isVisible: boolean;
private isBuilt: boolean;
private isVisible = false;
private isBuilt = false;
constructor(
@INotificationService private readonly notificationService: INotificationService,
@@ -126,7 +126,6 @@ export class DebugToolBar extends Themable implements IWorkbenchContribution {
this.registerListeners();
this.hide();
this.isBuilt = false;
}
private registerListeners(): void {

View File

@@ -36,12 +36,12 @@ import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
export class DebugViewlet extends ViewContainerViewlet {
private startDebugActionViewItem: StartDebugActionViewItem;
private startDebugActionViewItem: StartDebugActionViewItem | undefined;
private progressResolve: (() => void) | undefined;
private breakpointView: ViewletPanel;
private breakpointView: ViewletPanel | undefined;
private panelListeners = new Map<string, IDisposable>();
private debugToolBarMenu: IMenu;
private disposeOnTitleUpdate: IDisposable;
private debugToolBarMenu: IMenu | undefined;
private disposeOnTitleUpdate: IDisposable | undefined;
constructor(
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,

View File

@@ -63,8 +63,8 @@ export class ExceptionWidget extends ZoneWidget {
this.setCssClass('exception-widget');
// Set the font size and line height to the one from the editor configuration.
const fontInfo = this.editor.getConfiguration().fontInfo;
this.container.style.fontSize = `${fontInfo.fontSize}px`;
this.container.style.lineHeight = `${fontInfo.lineHeight}px`;
container.style.fontSize = `${fontInfo.fontSize}px`;
container.style.lineHeight = `${fontInfo.lineHeight}px`;
let title = $('.title');
title.textContent = this.exceptionInfo.id ? nls.localize('exceptionThrownWithId', 'Exception has occurred: {0}', this.exceptionInfo.id) : nls.localize('exceptionThrown', 'Exception has occurred.');
@@ -87,11 +87,11 @@ export class ExceptionWidget extends ZoneWidget {
protected _doLayout(_heightInPixel: number | undefined, _widthInPixel: number | undefined): void {
// Reload the height with respect to the exception text content and relayout it to match the line count.
this.container.style.height = 'initial';
this.container!.style.height = 'initial';
const lineHeight = this.editor.getConfiguration().lineHeight;
const arrowHeight = Math.round(lineHeight / 3);
const computedLinesNumber = Math.ceil((this.container.offsetHeight + arrowHeight) / lineHeight);
const computedLinesNumber = Math.ceil((this.container!.offsetHeight + arrowHeight) / lineHeight);
this._relayout(computedLinesNumber);
}

View File

@@ -0,0 +1,57 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ExtensionHostDebugChannelClient, ExtensionHostDebugBroadcastChannel } from 'vs/platform/debug/common/extensionHostDebugIpc';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug';
import { IDebugHelperService } from 'vs/workbench/contrib/debug/common/debug';
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { TelemetryService } from 'vs/platform/telemetry/common/telemetryService';
class BrowserExtensionHostDebugService extends ExtensionHostDebugChannelClient {
constructor(
@IRemoteAgentService remoteAgentService: IRemoteAgentService,
//@IWindowService windowService: IWindowService,
@IEnvironmentService environmentService: IEnvironmentService
) {
const connection = remoteAgentService.getConnection();
if (!connection) {
throw new Error('Missing agent connection');
}
super(connection.getChannel(ExtensionHostDebugBroadcastChannel.ChannelName));
this._register(this.onReload(event => {
if (environmentService.isExtensionDevelopment && environmentService.debugExtensionHost.debugId === event.sessionId) {
//windowService.reloadWindow();
window.location.reload();
}
}));
this._register(this.onClose(event => {
if (environmentService.isExtensionDevelopment && environmentService.debugExtensionHost.debugId === event.sessionId) {
//this._windowService.closeWindow();
window.close();
}
}));
}
}
registerSingleton(IExtensionHostDebugService, BrowserExtensionHostDebugService);
class BrowserDebugHelperService implements IDebugHelperService {
_serviceBrand!: ServiceIdentifier<IDebugHelperService>;
createTelemetryService(configurationService: IConfigurationService, args: string[]): TelemetryService | undefined {
return undefined;
}
}
registerSingleton(IDebugHelperService, BrowserDebugHelperService);

View File

@@ -46,7 +46,7 @@ class BaseTreeItem {
private _showedMoreThanOne: boolean;
private _children = new Map<string, BaseTreeItem>();
private _source: Source;
private _source: Source | undefined;
constructor(private _parent: BaseTreeItem | undefined, private _label: string) {
this._showedMoreThanOne = false;
@@ -184,7 +184,7 @@ class BaseTreeItem {
}
// skips intermediate single-child nodes
getSource(): Source {
getSource(): Source | undefined {
const child = this.oneChild();
if (child) {
return child.getSource();
@@ -381,13 +381,13 @@ class SessionTreeItem extends BaseTreeItem {
export class LoadedScriptsView extends ViewletPanel {
private treeContainer: HTMLElement;
private treeContainer!: HTMLElement;
private loadedScriptsItemType: IContextKey<string>;
private tree: WorkbenchAsyncDataTree<LoadedScriptsItem, LoadedScriptsItem, FuzzyScore>;
private treeLabels: ResourceLabels;
private changeScheduler: RunOnceScheduler;
private treeNeedsRefreshOnVisible: boolean;
private filter: LoadedScriptsFilter;
private tree!: WorkbenchAsyncDataTree<LoadedScriptsItem, LoadedScriptsItem, FuzzyScore>;
private treeLabels!: ResourceLabels;
private changeScheduler!: RunOnceScheduler;
private treeNeedsRefreshOnVisible = false;
private filter!: LoadedScriptsFilter;
constructor(
options: IViewletViewOptions,
@@ -635,7 +635,7 @@ class LoadedSciptsAccessibilityProvider implements IAccessibilityProvider<Loaded
class LoadedScriptsFilter implements ITreeFilter<BaseTreeItem, FuzzyScore> {
private filterText: string;
private filterText: string | undefined;
setFilter(filterText: string) {
this.filterText = filterText;

View File

@@ -37,19 +37,19 @@ interface ILaunchVSCodeArguments {
*/
export class RawDebugSession {
private allThreadsContinued: boolean;
private _readyForBreakpoints: boolean;
private allThreadsContinued = true;
private _readyForBreakpoints = false;
private _capabilities: DebugProtocol.Capabilities;
// shutdown
private debugAdapterStopped: boolean;
private inShutdown: boolean;
private terminated: boolean;
private firedAdapterExitEvent: boolean;
private debugAdapterStopped = false;
private inShutdown = false;
private terminated = false;
private firedAdapterExitEvent = false;
// telemetry
private startTime: number;
private didReceiveStoppedEvent: boolean;
private startTime = 0;
private didReceiveStoppedEvent = false;
// DAP events
private readonly _onDidInitialize: Emitter<DebugProtocol.InitializedEvent>;
@@ -78,13 +78,6 @@ export class RawDebugSession {
) {
this.debugAdapter = debugAdapter;
this._capabilities = Object.create(null);
this._readyForBreakpoints = false;
this.inShutdown = false;
this.debugAdapterStopped = false;
this.firedAdapterExitEvent = false;
this.didReceiveStoppedEvent = false;
this.allThreadsContinued = true;
this._onDidInitialize = new Emitter<DebugProtocol.InitializedEvent>();
this._onDidStop = new Emitter<DebugProtocol.StoppedEvent>();

View File

@@ -92,18 +92,18 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati
private static readonly REPL_INPUT_MAX_HEIGHT = 170;
private history: HistoryNavigator<string>;
private tree: WorkbenchAsyncDataTree<IDebugSession, IReplElement, FuzzyScore>;
private replDelegate: ReplDelegate;
private container: HTMLElement;
private replInput: CodeEditorWidget;
private replInputContainer: HTMLElement;
private dimension: dom.Dimension;
private tree!: WorkbenchAsyncDataTree<IDebugSession, IReplElement, FuzzyScore>;
private replDelegate!: ReplDelegate;
private container!: HTMLElement;
private replInput!: CodeEditorWidget;
private replInputContainer!: HTMLElement;
private dimension!: dom.Dimension;
private replInputHeight: number;
private model: ITextModel;
private historyNavigationEnablement: IContextKey<boolean>;
private scopedInstantiationService: IInstantiationService;
private replElementsChangeListener: IDisposable;
private styleElement: HTMLStyleElement;
private model!: ITextModel;
private historyNavigationEnablement!: IContextKey<boolean>;
private scopedInstantiationService!: IInstantiationService;
private replElementsChangeListener: IDisposable | undefined;
private styleElement: HTMLStyleElement | undefined;
constructor(
@IDebugService private readonly debugService: IDebugService,

View File

@@ -34,7 +34,7 @@ export const STATUS_BAR_DEBUGGING_BORDER = registerColor('statusBar.debuggingBor
}, localize('statusBarDebuggingBorder', "Status bar border color separating to the sidebar and editor when a program is being debugged. The status bar is shown in the bottom of the window"));
export class StatusBarColorProvider extends Themable implements IWorkbenchContribution {
private styleElement: HTMLStyleElement;
private styleElement: HTMLStyleElement | undefined;
constructor(
@IThemeService themeService: IThemeService,

View File

@@ -39,8 +39,8 @@ export const variableSetEmitter = new Emitter<void>();
export class VariablesView extends ViewletPanel {
private onFocusStackFrameScheduler: RunOnceScheduler;
private needsRefresh: boolean;
private tree: WorkbenchAsyncDataTree<IViewModel | IExpression | IScope, IExpression | IScope, FuzzyScore>;
private needsRefresh = false;
private tree!: WorkbenchAsyncDataTree<IViewModel | IExpression | IScope, IExpression | IScope, FuzzyScore>;
private savedViewState: IAsyncDataTreeViewState | undefined;
constructor(

View File

@@ -36,8 +36,8 @@ const MAX_VALUE_RENDER_LENGTH_IN_VIEWLET = 1024;
export class WatchExpressionsView extends ViewletPanel {
private onWatchExpressionsUpdatedScheduler: RunOnceScheduler;
private needsRefresh: boolean;
private tree: WorkbenchAsyncDataTree<IDebugService | IExpression, IExpression, FuzzyScore>;
private needsRefresh = false;
private tree!: WorkbenchAsyncDataTree<IDebugService | IExpression, IExpression, FuzzyScore>;
constructor(
options: IViewletViewOptions,

View File

@@ -14,9 +14,9 @@ export abstract class AbstractDebugAdapter implements IDebugAdapter {
private sequence: number;
private pendingRequests = new Map<number, (e: DebugProtocol.Response) => void>();
private requestCallback: (request: DebugProtocol.Request) => void;
private eventCallback: (request: DebugProtocol.Event) => void;
private messageCallback: (message: DebugProtocol.ProtocolMessage) => void;
private requestCallback: ((request: DebugProtocol.Request) => void) | undefined;
private eventCallback: ((request: DebugProtocol.Event) => void) | undefined;
private messageCallback: ((message: DebugProtocol.ProtocolMessage) => void) | undefined;
protected readonly _onError: Emitter<Error>;
protected readonly _onExit: Emitter<number | null>;

View File

@@ -25,6 +25,7 @@ import { Registry } from 'vs/platform/registry/common/platform';
import { TaskIdentifier } from 'vs/workbench/contrib/tasks/common/tasks';
import { TelemetryService } from 'vs/platform/telemetry/common/telemetryService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { CancellationToken } from 'vs/base/common/cancellation';
export const VIEWLET_ID = 'workbench.view.debug';
export const VIEW_CONTAINER: ViewContainer = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry).registerViewContainer(VIEWLET_ID);
@@ -133,7 +134,7 @@ export function getStateLabel(state: State): string {
}
}
export class AdapterEndEvent {
export interface AdapterEndEvent {
error?: Error;
sessionLengthInSeconds: number;
emittedStopped: boolean;
@@ -440,6 +441,7 @@ export interface IDebugConfiguration {
lineHeight: number;
wordWrap: boolean;
};
focusWindowOnBreak: boolean;
}
export interface IGlobalConfig {
@@ -556,8 +558,8 @@ export interface IDebuggerContribution extends IPlatformSpecificAdapterContribut
export interface IDebugConfigurationProvider {
readonly type: string;
resolveDebugConfiguration?(folderUri: uri | undefined, debugConfiguration: IConfig): Promise<IConfig | null | undefined>;
provideDebugConfigurations?(folderUri: uri | undefined): Promise<IConfig[]>;
resolveDebugConfiguration?(folderUri: uri | undefined, debugConfiguration: IConfig, token: CancellationToken): Promise<IConfig | null | undefined>;
provideDebugConfigurations?(folderUri: uri | undefined, token: CancellationToken): Promise<IConfig[]>;
debugAdapterExecutable?(folderUri: uri | undefined): Promise<IAdapterDescriptor>; // TODO@AW legacy
}
@@ -609,7 +611,7 @@ export interface IConfigurationManager {
registerDebugAdapterDescriptorFactory(debugAdapterDescriptorFactory: IDebugAdapterDescriptorFactory): IDisposable;
unregisterDebugAdapterDescriptorFactory(debugAdapterDescriptorFactory: IDebugAdapterDescriptorFactory): void;
resolveConfigurationByProviders(folderUri: uri | undefined, type: string | undefined, debugConfiguration: any): Promise<any>;
resolveConfigurationByProviders(folderUri: uri | undefined, type: string | undefined, debugConfiguration: any, token: CancellationToken): Promise<any>;
getDebugAdapterDescriptor(session: IDebugSession): Promise<IAdapterDescriptor | undefined>;
registerDebugAdapterFactory(debugTypes: string[], debugAdapterFactory: IDebugAdapterFactory): IDisposable;
@@ -662,7 +664,7 @@ export interface ILaunch {
/**
* Opens the launch.json file. Creates if it does not exist.
*/
openConfigFile(sideBySide: boolean, preserveFocus: boolean, type?: string): Promise<{ editor: IEditor | null, created: boolean }>;
openConfigFile(sideBySide: boolean, preserveFocus: boolean, type?: string, token?: CancellationToken): Promise<{ editor: IEditor | null, created: boolean }>;
}
// Debug service interfaces

View File

@@ -94,8 +94,8 @@ export class ExpressionContainer implements IExpressionContainer {
// Use chunks to support variable paging #9537
private static readonly BASE_CHUNK_SIZE = 100;
public valueChanged: boolean;
private _value: string;
public valueChanged = false;
private _value: string = '';
protected children?: Promise<IExpression[]>;
constructor(
@@ -201,7 +201,7 @@ export class Expression extends ExpressionContainer implements IExpression {
static DEFAULT_VALUE = nls.localize('notAvailable', "not available");
public available: boolean;
public type: string;
public type: string | undefined;
constructor(public name: string, id = generateUuid()) {
super(undefined, 0, id);

View File

@@ -0,0 +1,20 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug';
import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService';
import { ExtensionHostDebugChannelClient, ExtensionHostDebugBroadcastChannel } from 'vs/platform/debug/common/extensionHostDebugIpc';
export class ExtensionHostDebugService extends ExtensionHostDebugChannelClient {
constructor(
@IMainProcessService readonly windowService: IMainProcessService,
) {
super(windowService.getChannel(ExtensionHostDebugBroadcastChannel.ChannelName));
}
}
registerSingleton(IExtensionHostDebugService, ExtensionHostDebugService, true);

View File

@@ -27,9 +27,9 @@ export abstract class StreamDebugAdapter extends AbstractDebugAdapter {
private static readonly HEADER_LINESEPARATOR = /\r?\n/; // allow for non-RFC 2822 conforming line separators
private static readonly HEADER_FIELDSEPARATOR = /: */;
private outputStream: stream.Writable;
private rawData: Buffer;
private contentLength: number;
private outputStream!: stream.Writable;
private rawData = Buffer.allocUnsafe(0);
private contentLength = -1;
constructor() {
super();
@@ -145,7 +145,7 @@ export class SocketDebugAdapter extends StreamDebugAdapter {
*/
export class ExecutableDebugAdapter extends StreamDebugAdapter {
private serverProcess: cp.ChildProcess;
private serverProcess: cp.ChildProcess | undefined;
constructor(private adapterExecutable: IDebugAdapterExecutable, private debugType: string, private readonly outputService?: IOutputService) {
super();
@@ -266,7 +266,7 @@ export class ExecutableDebugAdapter extends StreamDebugAdapter {
// processes. Therefore we use TASKKILL.EXE
if (platform.isWindows) {
return new Promise<void>((c, e) => {
const killer = cp.exec(`taskkill /F /T /PID ${this.serverProcess.pid}`, function (err, stdout, stderr) {
const killer = cp.exec(`taskkill /F /T /PID ${this.serverProcess!.pid}`, function (err, stdout, stderr) {
if (err) {
return e(err);
}

View File

@@ -155,7 +155,7 @@ export class MockSession implements IDebugSession {
configuration: IConfig = { type: 'mock', name: 'mock', request: 'launch' };
unresolvedConfiguration: IConfig = { type: 'mock', name: 'mock', request: 'launch' };
state = State.Stopped;
root: IWorkspaceFolder;
root!: IWorkspaceFolder;
capabilities: DebugProtocol.Capabilities = {};
getId(): string {
@@ -301,9 +301,9 @@ export class MockSession implements IDebugSession {
export class MockRawSession {
capabilities: DebugProtocol.Capabilities;
disconnected: boolean;
sessionLengthInSeconds: number;
capabilities: DebugProtocol.Capabilities = {};
disconnected = false;
sessionLengthInSeconds: number = 0;
public readyForBreakpoints = true;
public emittedStopped = true;

View File

@@ -50,29 +50,10 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten
import { getDefaultValue } from 'vs/platform/configuration/common/configurationRegistry';
import { isUndefined } from 'vs/base/common/types';
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { URI } from 'vs/base/common/uri';
import { IWebviewService, Webview } from 'vs/workbench/contrib/webview/common/webview';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
// {{SQL CARBON EDIT}}
import { renderDashboardContributions } from 'sql/workbench/parts/extensions/browser/contributionRenders';
// {{SQL CARBON EDIT}} - End
function renderBody(body: string): string {
const styleSheetPath = require.toUrl('./media/markdown.css').replace('file://', 'vscode-resource://');
return `<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src https: data:; media-src https:; script-src 'none'; style-src vscode-resource:; child-src 'none'; frame-src 'none';">
<link rel="stylesheet" type="text/css" href="${styleSheetPath}">
</head>
<body>
<a id="scroll-to-top" role="button" aria-label="scroll to top" href="#"><span class="icon"></span></a>
${body}
</body>
</html>`;
}
import { renderDashboardContributions } from 'sql/workbench/parts/extensions/browser/contributionRenders'; // {{SQL CARBON EDIT}}
import { generateUuid } from 'vs/base/common/uuid';
function removeEmbeddedSVGs(documentContent: string): string {
const newDocument = new DOMParser().parseFromString(documentContent, 'text/html');
@@ -200,7 +181,7 @@ export class ExtensionEditor extends BaseEditor {
@IStorageService storageService: IStorageService,
@IExtensionService private readonly extensionService: IExtensionService,
@IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService,
@IWebviewService private readonly webviewService: IWebviewService
@IWebviewService private readonly webviewService: IWebviewService,
) {
super(ExtensionEditor.ID, telemetryService, themeService, storageService);
this.extensionReadme = null;
@@ -565,7 +546,7 @@ export class ExtensionEditor extends BaseEditor {
private openMarkdown(cacheResult: CacheResult<string>, noContentCopy: string): Promise<IActiveElement> {
return this.loadContents(() => cacheResult)
.then(marked.parse)
.then(renderBody)
.then(content => this.renderBody(content))
.then(removeEmbeddedSVGs)
.then(body => {
const webviewElement = this.webviewService.createWebview('extensionEditor',
@@ -574,9 +555,6 @@ export class ExtensionEditor extends BaseEditor {
},
{
svgWhiteList: this.extensionsWorkbenchService.allowedBadgeProviders,
localResourceRoots: [
URI.parse(require.toUrl('./media'))
]
});
webviewElement.mountTo(this.content);
this.contentDisposables.add(webviewElement.onDidFocus(() => this.fireOnDidFocus()));
@@ -603,6 +581,194 @@ export class ExtensionEditor extends BaseEditor {
});
}
private async renderBody(body: string): Promise<string> {
const nonce = generateUuid();
return `<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src https: data:; media-src https:; script-src 'none'; style-src 'nonce-${nonce}';">
<style nonce="${nonce}">
body {
padding: 10px 20px;
line-height: 22px;
}
img {
max-width: 100%;
max-height: 100%;
}
a {
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
a:focus,
input:focus,
select:focus,
textarea:focus {
outline: 1px solid -webkit-focus-ring-color;
outline-offset: -1px;
}
hr {
border: 0;
height: 2px;
border-bottom: 2px solid;
}
h1 {
padding-bottom: 0.3em;
line-height: 1.2;
border-bottom-width: 1px;
border-bottom-style: solid;
}
h1, h2, h3 {
font-weight: normal;
}
table {
border-collapse: collapse;
}
table > thead > tr > th {
text-align: left;
border-bottom: 1px solid;
}
table > thead > tr > th,
table > thead > tr > td,
table > tbody > tr > th,
table > tbody > tr > td {
padding: 5px 10px;
}
table > tbody > tr + tr > td {
border-top: 1px solid;
}
blockquote {
margin: 0 7px 0 5px;
padding: 0 16px 0 10px;
border-left-width: 5px;
border-left-style: solid;
}
code {
font-family: Menlo, Monaco, Consolas, "Droid Sans Mono", "Courier New", monospace, "Droid Sans Fallback";
font-size: 14px;
line-height: 19px;
}
.mac code {
font-size: 12px;
line-height: 18px;
}
code > div {
padding: 16px;
border-radius: 3px;
overflow: auto;
}
#scroll-to-top {
position: fixed;
width: 40px;
height: 40px;
right: 25px;
bottom: 25px;
background-color:#444444;
border-radius: 50%;
cursor: pointer;
box-shadow: 1px 1px 1px rgba(0,0,0,.25);
outline: none;
display: flex;
justify-content: center;
align-items: center;
}
#scroll-to-top:hover {
background-color:#007acc;
box-shadow: 2px 2px 2px rgba(0,0,0,.25);
}
body.vscode-light #scroll-to-top {
background-color: #949494;
}
body.vscode-high-contrast #scroll-to-top:hover {
background-color: #007acc;
}
body.vscode-high-contrast #scroll-to-top {
background-color: black;
border: 2px solid #6fc3df;
box-shadow: none;
}
body.vscode-high-contrast #scroll-to-top:hover {
background-color: #007acc;
}
#scroll-to-top span.icon::before {
content: "";
display: block;
/* Chevron up icon */
background:url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE5LjIuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHZpZXdCb3g9IjAgMCAxNiAxNiIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgMTYgMTY7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KCS5zdDB7ZmlsbDojRkZGRkZGO30KCS5zdDF7ZmlsbDpub25lO30KPC9zdHlsZT4KPHRpdGxlPnVwY2hldnJvbjwvdGl0bGU+CjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik04LDUuMWwtNy4zLDcuM0wwLDExLjZsOC04bDgsOGwtMC43LDAuN0w4LDUuMXoiLz4KPHJlY3QgY2xhc3M9InN0MSIgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2Ii8+Cjwvc3ZnPgo=');
width: 16px;
height: 16px;
}
/** Theming */
.vscode-light code > div {
background-color: rgba(220, 220, 220, 0.4);
}
.vscode-dark code > div {
background-color: rgba(10, 10, 10, 0.4);
}
.vscode-high-contrast code > div {
background-color: rgb(0, 0, 0);
}
.vscode-high-contrast h1 {
border-color: rgb(0, 0, 0);
}
.vscode-light table > thead > tr > th {
border-color: rgba(0, 0, 0, 0.69);
}
.vscode-dark table > thead > tr > th {
border-color: rgba(255, 255, 255, 0.69);
}
.vscode-light h1,
.vscode-light hr,
.vscode-light table > tbody > tr + tr > td {
border-color: rgba(0, 0, 0, 0.18);
}
.vscode-dark h1,
.vscode-dark hr,
.vscode-dark table > tbody > tr + tr > td {
border-color: rgba(255, 255, 255, 0.18);
}
</style>
</head>
<body>
<a id="scroll-to-top" role="button" aria-label="scroll to top" href="#"><span class="icon"></span></a>
${body}
</body>
</html>`;
}
private openReadme(): Promise<IActiveElement> {
return this.openMarkdown(this.extensionReadme!.get(), localize('noReadme', "No README available."));
}

View File

@@ -61,6 +61,10 @@
padding-left: 5px;
}
.extensions-viewlet > .extensions .message-container .severity-icon {
flex-shrink: 0;
}
.extensions-viewlet > .extensions .monaco-list-row > .bookmark {
display: inline-block;
height: 20px;

View File

@@ -1,175 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
body {
padding: 10px 20px;
line-height: 22px;
}
img {
max-width: 100%;
max-height: 100%;
}
a {
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
a:focus,
input:focus,
select:focus,
textarea:focus {
outline: 1px solid -webkit-focus-ring-color;
outline-offset: -1px;
}
hr {
border: 0;
height: 2px;
border-bottom: 2px solid;
}
h1 {
padding-bottom: 0.3em;
line-height: 1.2;
border-bottom-width: 1px;
border-bottom-style: solid;
}
h1, h2, h3 {
font-weight: normal;
}
table {
border-collapse: collapse;
}
table > thead > tr > th {
text-align: left;
border-bottom: 1px solid;
}
table > thead > tr > th,
table > thead > tr > td,
table > tbody > tr > th,
table > tbody > tr > td {
padding: 5px 10px;
}
table > tbody > tr + tr > td {
border-top: 1px solid;
}
blockquote {
margin: 0 7px 0 5px;
padding: 0 16px 0 10px;
border-left-width: 5px;
border-left-style: solid;
}
code {
font-family: Menlo, Monaco, Consolas, "Droid Sans Mono", "Courier New", monospace, "Droid Sans Fallback";
font-size: 14px;
line-height: 19px;
}
.mac code {
font-size: 12px;
line-height: 18px;
}
code > div {
padding: 16px;
border-radius: 3px;
overflow: auto;
}
#scroll-to-top {
position: fixed;
width: 40px;
height: 40px;
right: 25px;
bottom: 25px;
background-color:#444444;
border-radius: 50%;
cursor: pointer;
box-shadow: 1px 1px 1px rgba(0,0,0,.25);
outline: none;
display: flex;
justify-content: center;
align-items: center;
}
#scroll-to-top:hover {
background-color:#007acc;
box-shadow: 2px 2px 2px rgba(0,0,0,.25);
}
body.vscode-light #scroll-to-top {
background-color: #949494;
}
body.vscode-high-contrast #scroll-to-top:hover {
background-color: #007acc;
}
body.vscode-high-contrast #scroll-to-top {
background-color: black;
border: 2px solid #6fc3df;
box-shadow: none;
}
body.vscode-high-contrast #scroll-to-top:hover {
background-color: #007acc;
}
#scroll-to-top span.icon::before {
content: "";
display: block;
/* Chevron up icon */
background:url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE5LjIuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHZpZXdCb3g9IjAgMCAxNiAxNiIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgMTYgMTY7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KCS5zdDB7ZmlsbDojRkZGRkZGO30KCS5zdDF7ZmlsbDpub25lO30KPC9zdHlsZT4KPHRpdGxlPnVwY2hldnJvbjwvdGl0bGU+CjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik04LDUuMWwtNy4zLDcuM0wwLDExLjZsOC04bDgsOGwtMC43LDAuN0w4LDUuMXoiLz4KPHJlY3QgY2xhc3M9InN0MSIgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2Ii8+Cjwvc3ZnPgo=');
width: 16px;
height: 16px;
}
/** Theming */
.vscode-light code > div {
background-color: rgba(220, 220, 220, 0.4);
}
.vscode-dark code > div {
background-color: rgba(10, 10, 10, 0.4);
}
.vscode-high-contrast code > div {
background-color: rgb(0, 0, 0);
}
.vscode-high-contrast h1 {
border-color: rgb(0, 0, 0);
}
.vscode-light table > thead > tr > th {
border-color: rgba(0, 0, 0, 0.69);
}
.vscode-dark table > thead > tr > th {
border-color: rgba(255, 255, 255, 0.69);
}
.vscode-light h1,
.vscode-light hr,
.vscode-light table > tbody > tr + tr > td {
border-color: rgba(0, 0, 0, 0.18);
}
.vscode-dark h1,
.vscode-dark hr,
.vscode-dark table > tbody > tr + tr > td {
border-color: rgba(255, 255, 255, 0.18);
}

View File

@@ -5,7 +5,7 @@
import * as nls from 'vs/nls';
import { Event, Emitter } from 'vs/base/common/event';
import { IInstantiationService, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IExtensionHostProfile, ProfileSession, IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { Disposable, toDisposable, MutableDisposable } from 'vs/base/common/lifecycle';
import { onUnexpectedError } from 'vs/base/common/errors';
@@ -23,7 +23,7 @@ import { CommandsRegistry } from 'vs/platform/commands/common/commands';
export class ExtensionHostProfileService extends Disposable implements IExtensionHostProfileService {
_serviceBrand: ServiceIdentifier<IExtensionHostProfileService>;
_serviceBrand: any;
private readonly _onDidChangeState: Emitter<void> = this._register(new Emitter<void>());
public readonly onDidChangeState: Event<void> = this._onDidChangeState.event;
@@ -34,7 +34,7 @@ export class ExtensionHostProfileService extends Disposable implements IExtensio
private readonly _unresponsiveProfiles = new Map<string, IExtensionHostProfile>();
private _profile: IExtensionHostProfile | null;
private _profileSession: ProfileSession | null;
private _state: ProfileSessionState;
private _state: ProfileSessionState = ProfileSessionState.None;
private profilingStatusBarIndicator: IStatusbarEntryAccessor | undefined;
private readonly profilingStatusBarIndicatorLabelUpdater = this._register(new MutableDisposable());

View File

@@ -19,9 +19,9 @@ import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import Severity from 'vs/base/common/severity';
abstract class RepoInfo {
readonly base: string;
readonly owner: string;
readonly repo: string;
abstract get base(): string;
abstract get owner(): string;
abstract get repo(): string;
static fromExtension(desc: IExtensionDescription): RepoInfo | undefined {

View File

@@ -46,13 +46,13 @@ export class FeedbackDropdown extends Dropdown {
private readonly feedbackDelegate: IFeedbackDelegate;
private feedbackForm: HTMLFormElement | null;
private feedbackDescriptionInput: HTMLTextAreaElement | null;
private smileyInput: HTMLElement | null;
private frownyInput: HTMLElement | null;
private sendButton: Button;
private hideButton: HTMLInputElement;
private remainingCharacterCount: HTMLElement;
private feedbackForm: HTMLFormElement | null = null;
private feedbackDescriptionInput: HTMLTextAreaElement | null = null;
private smileyInput: HTMLElement | null = null;
private frownyInput: HTMLElement | null = null;
private sendButton: Button | null = null;
private hideButton: HTMLInputElement | null = null;
private remainingCharacterCount: HTMLElement | null = null;
private requestFeatureLink: string | undefined;
@@ -253,7 +253,7 @@ export class FeedbackDropdown extends Dropdown {
// Checkbox: Hide Feedback Smiley
const hideButtonContainer = dom.append(buttonsContainer, dom.$('div.hide-button-container'));
this.hideButton = dom.append(hideButtonContainer, dom.$('input.hide-button'));
this.hideButton = dom.append(hideButtonContainer, dom.$('input.hide-button')) as HTMLInputElement;
this.hideButton.type = 'checkbox';
this.hideButton.checked = true;
this.hideButton.id = 'hide-button';
@@ -316,7 +316,7 @@ export class FeedbackDropdown extends Dropdown {
}
private updateCharCountText(): void {
if (this.feedbackDescriptionInput) {
if (this.feedbackDescriptionInput && this.remainingCharacterCount && this.sendButton) {
this.remainingCharacterCount.innerText = this.getCharCountText(this.feedbackDescriptionInput.value.length);
this.sendButton.enabled = this.feedbackDescriptionInput.value.length > 0;
}
@@ -434,4 +434,4 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
if (linkColor) {
collector.addRule(`.monaco-workbench .feedback-form .content .channels a { color: ${linkColor}; }`);
}
});
});

View File

@@ -47,8 +47,8 @@ class TwitterFeedbackService implements IFeedbackDelegate {
}
export class FeedbackStatusbarConribution extends Disposable implements IWorkbenchContribution {
private dropdown: FeedbackDropdown;
private entry: IStatusbarEntryAccessor;
private dropdown: FeedbackDropdown | undefined;
private entry: IStatusbarEntryAccessor | undefined;
constructor(
@IStatusbarService statusbarService: IStatusbarService,
@@ -72,15 +72,17 @@ export class FeedbackStatusbarConribution extends Disposable implements IWorkben
this.dropdown = this._register(this.instantiationService.createInstance(FeedbackDropdown, statusContainr.getElementsByClassName('octicon').item(0), {
contextViewProvider: this.contextViewService,
feedbackService: this.instantiationService.createInstance(TwitterFeedbackService),
onFeedbackVisibilityChange: visible => this.entry.update(this.getStatusEntry(visible))
onFeedbackVisibilityChange: visible => this.entry!.update(this.getStatusEntry(visible))
}));
}
}
if (!this.dropdown.isVisible()) {
this.dropdown.show();
} else {
this.dropdown.hide();
if (this.dropdown) {
if (!this.dropdown.isVisible()) {
this.dropdown.show();
} else {
this.dropdown.hide();
}
}
}
@@ -92,4 +94,4 @@ export class FeedbackStatusbarConribution extends Disposable implements IWorkben
};
}
}
}

View File

@@ -33,7 +33,7 @@ import { QueryInput } from 'sql/workbench/parts/query/common/queryInput';
export class FileEditorTracker extends Disposable implements IWorkbenchContribution {
private closeOnFileDelete: boolean;
private closeOnFileDelete: boolean | undefined;
private modelLoadQueue = new ResourceQueue();
private activeOutOfWorkspaceWatchers = new ResourceMap<IDisposable>();

View File

@@ -40,7 +40,7 @@ export class TextFileEditor extends BaseTextEditor {
static readonly ID = TEXT_FILE_EDITOR_ID;
private restoreViewState: boolean;
private restoreViewState: boolean | undefined;
private readonly groupListener = this._register(new MutableDisposable());
constructor(

View File

@@ -37,7 +37,7 @@ import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/
export class ExplorerViewletViewsContribution extends Disposable implements IWorkbenchContribution {
private openEditorsVisibleContextKey: IContextKey<boolean>;
private openEditorsVisibleContextKey!: IContextKey<boolean>;
constructor(
@IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService,

View File

@@ -5,7 +5,7 @@
import * as nls from 'vs/nls';
import { Registry } from 'vs/platform/registry/common/platform';
import { ToggleAutoSaveAction, GlobalNewUntitledFileAction, ShowOpenedFileInNewWindow, FocusFilesExplorer, GlobalCompareResourcesAction, SaveAllAction, ShowActiveFileInExplorer, CollapseExplorerView, RefreshExplorerView, CompareWithClipboardAction, NEW_FILE_COMMAND_ID, NEW_FILE_LABEL, NEW_FOLDER_COMMAND_ID, NEW_FOLDER_LABEL, TRIGGER_RENAME_LABEL, MOVE_FILE_TO_TRASH_LABEL, COPY_FILE_LABEL, PASTE_FILE_LABEL, FileCopiedContext, renameHandler, moveFileToTrashHandler, copyFileHandler, pasteFileHandler, deleteFileHandler, cutFileHandler, DOWNLOAD_COMMAND_ID, GlobalNewUntitledPlainFileAction } from 'vs/workbench/contrib/files/browser/fileActions';
import { ToggleAutoSaveAction, GlobalNewUntitledFileAction, ShowOpenedFileInNewWindow, FocusFilesExplorer, GlobalCompareResourcesAction, SaveAllAction, ShowActiveFileInExplorer, CollapseExplorerView, RefreshExplorerView, CompareWithClipboardAction, NEW_FILE_COMMAND_ID, NEW_FILE_LABEL, NEW_FOLDER_COMMAND_ID, NEW_FOLDER_LABEL, TRIGGER_RENAME_LABEL, MOVE_FILE_TO_TRASH_LABEL, COPY_FILE_LABEL, PASTE_FILE_LABEL, FileCopiedContext, renameHandler, moveFileToTrashHandler, copyFileHandler, pasteFileHandler, deleteFileHandler, cutFileHandler, DOWNLOAD_COMMAND_ID, GlobalNewUntitledPlainFileAction, openFilePreserveFocusHandler } from 'vs/workbench/contrib/files/browser/fileActions';
import { revertLocalChangesCommand, acceptLocalChangesCommand, CONFLICT_RESOLUTION_CONTEXT } from 'vs/workbench/contrib/files/browser/saveErrorHandler';
import { SyncActionDescriptor, MenuId, MenuRegistry, ILocalizedString } from 'vs/platform/actions/common/actions';
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
@@ -188,6 +188,14 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'filesExplorer.openFilePreserveFocus',
weight: KeybindingWeight.WorkbenchContrib + explorerCommandsWeightBonus,
when: ContextKeyExpr.and(FilesExplorerFocusCondition, ExplorerFolderContext.toNegated()),
primary: KeyCode.Space,
handler: openFilePreserveFocusHandler
});
const copyPathCommand = {
id: COPY_PATH_COMMAND_ID,
title: nls.localize('copyPath', "Copy Path")

View File

@@ -15,7 +15,7 @@ import { toErrorMessage } from 'vs/base/common/errorMessage';
import * as strings from 'vs/base/common/strings';
import { Action } from 'vs/base/common/actions';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { VIEWLET_ID, IExplorerService } from 'vs/workbench/contrib/files/common/files';
import { VIEWLET_ID, IExplorerService, IFilesConfiguration } from 'vs/workbench/contrib/files/common/files';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { IFileService, AutoSaveConfiguration } from 'vs/platform/files/common/files';
import { toResource, SideBySideEditor } from 'vs/workbench/common/editor';
@@ -360,7 +360,7 @@ function containsBothDirectoryAndFile(distinctElements: ExplorerItem[]): boolean
}
export function findValidPasteFileTarget(targetFolder: ExplorerItem, fileToPaste: { resource: URI, isDirectory?: boolean, allowOverwrite: boolean }): URI {
export function findValidPasteFileTarget(targetFolder: ExplorerItem, fileToPaste: { resource: URI, isDirectory?: boolean, allowOverwrite: boolean }, incrementalNaming: 'simple' | 'smart'): URI {
let name = resources.basenameOrAuthority(fileToPaste.resource);
let candidate = resources.joinPath(targetFolder.resource, name);
@@ -369,37 +369,104 @@ export function findValidPasteFileTarget(targetFolder: ExplorerItem, fileToPaste
break;
}
name = incrementFileName(name, !!fileToPaste.isDirectory);
name = incrementFileName(name, !!fileToPaste.isDirectory, incrementalNaming);
candidate = resources.joinPath(targetFolder.resource, name);
}
return candidate;
}
export function incrementFileName(name: string, isFolder: boolean): string {
let namePrefix = name;
let extSuffix = '';
if (!isFolder) {
extSuffix = extname(name);
namePrefix = basename(name, extSuffix);
export function incrementFileName(name: string, isFolder: boolean, incrementalNaming: 'simple' | 'smart'): string {
if (incrementalNaming === 'simple') {
let namePrefix = name;
let extSuffix = '';
if (!isFolder) {
extSuffix = extname(name);
namePrefix = basename(name, extSuffix);
}
// name copy 5(.txt) => name copy 6(.txt)
// name copy(.txt) => name copy 2(.txt)
const suffixRegex = /^(.+ copy)( \d+)?$/;
if (suffixRegex.test(namePrefix)) {
return namePrefix.replace(suffixRegex, (match, g1?, g2?) => {
let number = (g2 ? parseInt(g2) : 1);
return number === 0
? `${g1}`
: (number < Constants.MAX_SAFE_SMALL_INTEGER
? `${g1} ${number + 1}`
: `${g1}${g2} copy`);
}) + extSuffix;
}
// name(.txt) => name copy(.txt)
return `${namePrefix} copy${extSuffix}`;
}
// name copy 5(.txt) => name copy 6(.txt)
// name copy(.txt) => name copy 2(.txt)
const suffixRegex = /^(.+ copy)( \d+)?$/;
if (suffixRegex.test(namePrefix)) {
return namePrefix.replace(suffixRegex, (match, g1?, g2?) => {
let number = (g2 ? parseInt(g2) : 1);
return number === 0
? `${g1}`
: (number < Constants.MAX_SAFE_SMALL_INTEGER
? `${g1} ${number + 1}`
: `${g1}${g2} copy`);
}) + extSuffix;
const separators = '[\\.\\-_]';
const maxNumber = Constants.MAX_SAFE_SMALL_INTEGER;
// file.1.txt=>file.2.txt
let suffixFileRegex = RegExp('(.*' + separators + ')(\\d+)(\\..*)$');
if (!isFolder && name.match(suffixFileRegex)) {
return name.replace(suffixFileRegex, (match, g1?, g2?, g3?) => {
let number = parseInt(g2);
return number < maxNumber
? g1 + strings.pad(number + 1, g2.length) + g3
: strings.format('{0}{1}.1{2}', g1, g2, g3);
});
}
// name(.txt) => name copy(.txt)
return `${namePrefix} copy${extSuffix}`;
// 1.file.txt=>2.file.txt
let prefixFileRegex = RegExp('(\\d+)(' + separators + '.*)(\\..*)$');
if (!isFolder && name.match(prefixFileRegex)) {
return name.replace(prefixFileRegex, (match, g1?, g2?, g3?) => {
let number = parseInt(g1);
return number < maxNumber
? strings.pad(number + 1, g1.length) + g2 + g3
: strings.format('{0}{1}.1{2}', g1, g2, g3);
});
}
// 1.txt=>2.txt
let prefixFileNoNameRegex = RegExp('(\\d+)(\\..*)$');
if (!isFolder && name.match(prefixFileNoNameRegex)) {
return name.replace(prefixFileNoNameRegex, (match, g1?, g2?) => {
let number = parseInt(g1);
return number < maxNumber
? strings.pad(number + 1, g1.length) + g2
: strings.format('{0}.1{1}', g1, g2);
});
}
// file.txt=>file.1.txt
const lastIndexOfDot = name.lastIndexOf('.');
if (!isFolder && lastIndexOfDot >= 0) {
return strings.format('{0}.1{1}', name.substr(0, lastIndexOfDot), name.substr(lastIndexOfDot));
}
// folder.1=>folder.2
if (isFolder && name.match(/(\d+)$/)) {
return name.replace(/(\d+)$/, (match: string, ...groups: any[]) => {
let number = parseInt(groups[0]);
return number < maxNumber
? strings.pad(number + 1, groups[0].length)
: strings.format('{0}.1', groups[0]);
});
}
// 1.folder=>2.folder
if (isFolder && name.match(/^(\d+)/)) {
return name.replace(/^(\d+)(.*)$/, (match: string, ...groups: any[]) => {
let number = parseInt(groups[0]);
return number < maxNumber
? strings.pad(number + 1, groups[0].length) + groups[1]
: strings.format('{0}{1}.1', groups[0], groups[1]);
});
}
// file/folder=>file.1/folder.1
return strings.format('{0}.1', name);
}
// Global Compare with
@@ -1038,6 +1105,7 @@ export const pasteFileHandler = async (accessor: ServicesAccessor) => {
const textFileService = accessor.get(ITextFileService);
const notificationService = accessor.get(INotificationService);
const editorService = accessor.get(IEditorService);
const configurationService = accessor.get(IConfigurationService);
if (listService.lastFocusedList) {
const explorerContext = getContext(listService.lastFocusedList);
@@ -1062,7 +1130,8 @@ export const pasteFileHandler = async (accessor: ServicesAccessor) => {
target = element.isDirectory ? element : element.parent!;
}
const targetFile = findValidPasteFileTarget(target, { resource: fileToPaste, isDirectory: fileToPasteStat.isDirectory, allowOverwrite: pasteShouldMove });
const incrementalNaming = configurationService.getValue<IFilesConfiguration>().explorer.incrementalNaming;
const targetFile = findValidPasteFileTarget(target, { resource: fileToPaste, isDirectory: fileToPasteStat.isDirectory, allowOverwrite: pasteShouldMove }, incrementalNaming);
// Move/Copy File
if (pasteShouldMove) {
@@ -1091,3 +1160,19 @@ export const pasteFileHandler = async (accessor: ServicesAccessor) => {
}
}
};
export const openFilePreserveFocusHandler = async (accessor: ServicesAccessor) => {
const listService = accessor.get(IListService);
const editorService = accessor.get(IEditorService);
if (listService.lastFocusedList) {
const explorerContext = getContext(listService.lastFocusedList);
if (explorerContext.stat) {
const stats = explorerContext.selection.length > 1 ? explorerContext.selection : [explorerContext.stat];
await editorService.openEditors(stats.filter(s => !s.isDirectory).map(s => ({
resource: s.resource,
options: { preserveFocus: true }
})));
}
}
};

View File

@@ -38,7 +38,6 @@ import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { IEditorService, SIDE_GROUP, IResourceEditorReplacement } from 'vs/workbench/services/editor/common/editorService';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { ILabelService } from 'vs/platform/label/common/label';
import { onUnexpectedError } from 'vs/base/common/errors';
import { basename, toLocalResource, joinPath } from 'vs/base/common/resources';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
@@ -111,7 +110,7 @@ export const newWindowCommand = (accessor: ServicesAccessor, options?: INewWindo
};
// {{SQL CARBON EDIT}}
function save(
async function save(
resource: URI | null,
isSaveAs: boolean,
options: ISaveOptions | undefined,
@@ -123,109 +122,123 @@ function save(
queryEditorService: IQueryEditorService,
environmentService: IWorkbenchEnvironmentService
): Promise<any> {
if (!resource || (!fileService.canHandleResource(resource) && resource.scheme !== Schemas.untitled)) {
return; // save is not supported
}
function ensureForcedSave(options?: ISaveOptions): ISaveOptions {
if (!options) {
options = { force: true };
} else {
options.force = true;
}
return options;
// Save As (or Save untitled with associated path)
if (isSaveAs || resource.scheme === Schemas.untitled) {
return doSaveAs(resource, isSaveAs, options, editorService, fileService, untitledEditorService, textFileService, editorGroupService, queryEditorService, environmentService); // {{SQL CARBON EDIT}} add paramater
}
if (resource && (fileService.canHandleResource(resource) || resource.scheme === Schemas.untitled)) {
// {{SQL CARBON EDIT}}
let editorInput = editorService.activeEditor;
if (editorInput instanceof EditorInput && !(<EditorInput>editorInput).savingSupported) {
return Promise.resolve(false);
return;
}
// Save As (or Save untitled with associated path)
if (isSaveAs || resource.scheme === Schemas.untitled) {
let encodingOfSource: string | undefined;
if (resource.scheme === Schemas.untitled) {
encodingOfSource = untitledEditorService.getEncoding(resource);
} else if (fileService.canHandleResource(resource)) {
const textModel = textFileService.models.get(resource);
encodingOfSource = textModel && textModel.getEncoding(); // text model can be null e.g. if this is a binary file!
}
let viewStateOfSource: IEditorViewState | null;
const activeTextEditorWidget = getCodeEditor(editorService.activeTextEditorWidget);
if (activeTextEditorWidget) {
const activeResource = toResource(editorService.activeEditor, { supportSideBySide: SideBySideEditor.MASTER });
if (activeResource && (fileService.canHandleResource(activeResource) || resource.scheme === Schemas.untitled) && activeResource.toString() === resource.toString()) {
viewStateOfSource = activeTextEditorWidget.saveViewState();
}
}
// Special case: an untitled file with associated path gets saved directly unless "saveAs" is true
let savePromise: Promise<URI | undefined>;
if (!isSaveAs && resource.scheme === Schemas.untitled && untitledEditorService.hasAssociatedFilePath(resource)) {
savePromise = textFileService.save(resource, options).then(result => {
if (result) {
return toLocalResource(resource, environmentService.configuration.remoteAuthority);
}
return undefined;
});
}
// Otherwise, really "Save As..."
else {
// Force a change to the file to trigger external watchers if any
// fixes https://github.com/Microsoft/vscode/issues/59655
options = ensureForcedSave(options);
savePromise = textFileService.saveAs(resource, undefined, options);
}
return savePromise.then(target => {
if (!target || target.toString() === resource.toString()) {
return false; // save canceled or same resource used
}
const replacement: IResourceInput = {
resource: target,
encoding: encodingOfSource,
options: {
pinned: true,
viewState: viewStateOfSource || undefined
}
};
return Promise.all(editorGroupService.groups.map(g =>
editorService.replaceEditors([{
editor: { resource },
replacement
}], g))).then(() => {
// {{SQL CARBON EDIT}}
queryEditorService.onSaveAsCompleted(resource, target);
return true;
});
});
}
// Pin the active editor if we are saving it
const activeControl = editorService.activeControl;
const activeEditorResource = activeControl && activeControl.input && activeControl.input.getResource();
if (activeControl && activeEditorResource && activeEditorResource.toString() === resource.toString()) {
activeControl.group.pinEditor(activeControl.input);
}
// Just save (force a change to the file to trigger external watchers if any)
options = ensureForcedSave(options);
return textFileService.save(resource, options);
}
return Promise.resolve(false);
// Save
return doSave(resource, options, editorService, textFileService);
}
function saveAll(saveAllArguments: any, editorService: IEditorService, untitledEditorService: IUntitledEditorService,
async function doSaveAs(
resource: URI,
isSaveAs: boolean,
options: ISaveOptions | undefined,
editorService: IEditorService,
fileService: IFileService,
untitledEditorService: IUntitledEditorService,
textFileService: ITextFileService,
editorGroupService: IEditorGroupsService,
queryEditorService: IQueryEditorService,
environmentService: IWorkbenchEnvironmentService
): Promise<boolean> {
let viewStateOfSource: IEditorViewState | null = null;
const activeTextEditorWidget = getCodeEditor(editorService.activeTextEditorWidget);
if (activeTextEditorWidget) {
const activeResource = toResource(editorService.activeEditor, { supportSideBySide: SideBySideEditor.MASTER });
if (activeResource && (fileService.canHandleResource(activeResource) || resource.scheme === Schemas.untitled) && activeResource.toString() === resource.toString()) {
viewStateOfSource = activeTextEditorWidget.saveViewState();
}
}
// Special case: an untitled file with associated path gets saved directly unless "saveAs" is true
let target: URI | undefined;
if (!isSaveAs && resource.scheme === Schemas.untitled && untitledEditorService.hasAssociatedFilePath(resource)) {
const result = await textFileService.save(resource, options);
if (result) {
target = toLocalResource(resource, environmentService.configuration.remoteAuthority);
}
}
// Otherwise, really "Save As..."
else {
// Force a change to the file to trigger external watchers if any
// fixes https://github.com/Microsoft/vscode/issues/59655
options = ensureForcedSave(options);
target = await textFileService.saveAs(resource, undefined, options);
}
if (!target || target.toString() === resource.toString()) {
return false; // save canceled or same resource used
}
const replacement: IResourceInput = {
resource: target,
options: {
pinned: true,
viewState: viewStateOfSource || undefined
}
};
await Promise.all(editorGroupService.groups.map(group =>
editorService.replaceEditors([{
editor: { resource },
replacement
}], group))).then(() => {
// {{SQL CARBON EDIT}}
queryEditorService.onSaveAsCompleted(resource, target);
return true;
});
return true;
}
async function doSave(
resource: URI,
options: ISaveOptions | undefined,
editorService: IEditorService,
textFileService: ITextFileService
): Promise<boolean> {
// Pin the active editor if we are saving it
const activeControl = editorService.activeControl;
const activeEditorResource = activeControl && activeControl.input && activeControl.input.getResource();
if (activeControl && activeEditorResource && activeEditorResource.toString() === resource.toString()) {
activeControl.group.pinEditor(activeControl.input);
}
// Just save (force a change to the file to trigger external watchers if any)
options = ensureForcedSave(options);
return textFileService.save(resource, options);
}
function ensureForcedSave(options?: ISaveOptions): ISaveOptions {
if (!options) {
options = { force: true };
} else {
options.force = true;
}
return options;
}
async function saveAll(saveAllArguments: any, editorService: IEditorService, untitledEditorService: IUntitledEditorService,
textFileService: ITextFileService, editorGroupService: IEditorGroupsService): Promise<any> {
// Store some properties per untitled file to restore later after save is completed
@@ -255,30 +268,30 @@ function saveAll(saveAllArguments: any, editorService: IEditorService, untitledE
});
// Save all
return textFileService.saveAll(saveAllArguments).then(result => {
groupIdToUntitledResourceInput.forEach((inputs, groupId) => {
// {{SQL CARBON EDIT}}
// Update untitled resources to the saved ones, so we open the proper files
const result = await textFileService.saveAll(saveAllArguments);
let replacementPairs: IResourceEditorReplacement[] = [];
inputs.forEach(i => {
const targetResult = result.results.filter(r => r.success && r.source.toString() === i.resource.toString()).pop();
if (targetResult && targetResult.target) {
//i.resource = targetResult.target;
let editor = i;
const replacement: IResourceInput = {
resource: targetResult.target,
encoding: i.encoding,
options: {
pinned: true,
viewState: undefined
}
};
replacementPairs.push({ editor: editor, replacement: replacement });
}
});
editorService.replaceEditors(replacementPairs, groupId);
// Update untitled resources to the saved ones, so we open the proper files
groupIdToUntitledResourceInput.forEach((inputs, groupId) => {
// {{SQL CARBON EDIT}} Update untitled resources to the saved ones, so we open the proper files
const replacementPairs: IResourceEditorReplacement[] = [];
inputs.forEach(i => {
const targetResult = result.results.filter(r => r.success && r.source.toString() === i.resource.toString()).pop();
if (targetResult && targetResult.target) {
// i.resource = targetResult.target;let editor = i;
const editor = i;
const replacement: IResourceInput = {
resource: targetResult.target,
encoding: i.encoding,
options: {
pinned: true,
viewState: undefined
}
};
replacementPairs.push({ editor: editor, replacement: replacement });
}
});
editorService.replaceEditors(replacementPairs, groupId);
});
}
@@ -286,7 +299,7 @@ function saveAll(saveAllArguments: any, editorService: IEditorService, untitledE
CommandsRegistry.registerCommand({
id: REVERT_FILE_COMMAND_ID,
handler: (accessor, resource: URI | object) => {
handler: async (accessor, resource: URI | object) => {
const editorService = accessor.get(IEditorService);
const textFileService = accessor.get(ITextFileService);
const notificationService = accessor.get(INotificationService);
@@ -294,12 +307,12 @@ CommandsRegistry.registerCommand({
.filter(resource => resource.scheme !== Schemas.untitled);
if (resources.length) {
return textFileService.revertAll(resources, { force: true }).then(undefined, error => {
try {
await textFileService.revertAll(resources, { force: true });
} catch (error) {
notificationService.error(nls.localize('genericRevertError', "Failed to revert '{0}': {1}", resources.map(r => basename(r)).join(', '), toErrorMessage(error, false)));
});
}
}
return Promise.resolve(true);
}
});
@@ -310,7 +323,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
mac: {
primary: KeyMod.WinCtrl | KeyCode.Enter
},
id: OPEN_TO_SIDE_COMMAND_ID, handler: (accessor, resource: URI | object) => {
id: OPEN_TO_SIDE_COMMAND_ID, handler: async (accessor, resource: URI | object) => {
const editorService = accessor.get(IEditorService);
const listService = accessor.get(IListService);
const fileService = accessor.get(IFileService);
@@ -318,16 +331,13 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
// Set side input
if (resources.length) {
return fileService.resolveAll(resources.map(resource => ({ resource }))).then(resolved => {
const editors = resolved.filter(r => r.stat && r.success && !r.stat.isDirectory).map(r => ({
resource: r.stat!.resource
}));
const resolved = await fileService.resolveAll(resources.map(resource => ({ resource })));
const editors = resolved.filter(r => r.stat && r.success && !r.stat.isDirectory).map(r => ({
resource: r.stat!.resource
}));
return editorService.openEditors(editors, SIDE_GROUP);
});
await editorService.openEditors(editors, SIDE_GROUP);
}
return Promise.resolve(true);
}
});
@@ -422,7 +432,7 @@ CommandsRegistry.registerCommand({
editorService.openEditor({
leftResource: globalResourceToCompare,
rightResource
}).then(undefined, onUnexpectedError);
});
}
}
});
@@ -521,27 +531,28 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
CommandsRegistry.registerCommand({
id: REVEAL_IN_EXPLORER_COMMAND_ID,
handler: (accessor, resource: URI | object) => {
handler: async (accessor, resource: URI | object) => {
const viewletService = accessor.get(IViewletService);
const contextService = accessor.get(IWorkspaceContextService);
const explorerService = accessor.get(IExplorerService);
const uri = getResourceForCommand(resource, accessor.get(IListService), accessor.get(IEditorService));
viewletService.openViewlet(VIEWLET_ID, false).then((viewlet: ExplorerViewlet) => {
if (uri && contextService.isInsideWorkspace(uri)) {
const explorerView = viewlet.getExplorerView();
if (explorerView) {
explorerView.setExpanded(true);
explorerService.select(uri, true).then(() => explorerView.focus(), onUnexpectedError);
}
} else {
const openEditorsView = viewlet.getOpenEditorsView();
if (openEditorsView) {
openEditorsView.setExpanded(true);
openEditorsView.focus();
}
const viewlet = await viewletService.openViewlet(VIEWLET_ID, false) as ExplorerViewlet;
if (uri && contextService.isInsideWorkspace(uri)) {
const explorerView = viewlet.getExplorerView();
if (explorerView) {
explorerView.setExpanded(true);
await explorerService.select(uri, true);
explorerView.focus();
}
});
} else {
const openEditorsView = viewlet.getOpenEditorsView();
if (openEditorsView) {
openEditorsView.setExpanded(true);
openEditorsView.focus();
}
}
}
});
@@ -610,7 +621,7 @@ CommandsRegistry.registerCommand({
CommandsRegistry.registerCommand({
id: SAVE_ALL_IN_GROUP_COMMAND_ID,
handler: (accessor, resource: URI | object, editorContext: IEditorCommandsContext) => {
handler: (accessor, _: URI | object, editorContext: IEditorCommandsContext) => {
const contexts = getMultiSelectedEditorContexts(editorContext, accessor.get(IListService), accessor.get(IEditorGroupsService));
const editorGroupService = accessor.get(IEditorGroupsService);
let saveAllArg: any;

View File

@@ -428,6 +428,15 @@ configurationRegistry.registerConfiguration({
description: nls.localize('explorer.decorations.badges', "Controls whether file decorations should use badges."),
default: true
},
'explorer.incrementalNaming': {
enum: ['simple', 'smart'],
enumDescriptions: [
nls.localize('simple', "Appends the word \"copy\" at the end of the duplicated name potentially followed by a number"),
nls.localize('smart', "Adds a number at the end of the duplicated name. If some number is already part of the name, tries to increase that number")
],
description: nls.localize('explorer.incrementalNaming', "Controls what naming strategy to use when a giving a new name to a duplicated explorer item on paste."),
default: 'simple'
}
}
});

View File

@@ -32,9 +32,9 @@ export class EmptyView extends ViewletPanel {
static readonly ID: string = 'workbench.explorer.emptyView';
static readonly NAME = nls.localize('noWorkspace', "No Folder Opened");
private button: Button;
private messageElement: HTMLElement;
private titleElement: HTMLElement;
private button!: Button;
private messageElement!: HTMLElement;
private titleElement!: HTMLElement;
constructor(
options: IViewletViewOptions,

View File

@@ -55,8 +55,8 @@ export class ExplorerView extends ViewletPanel {
static readonly ID: string = 'workbench.explorer.fileView';
static readonly TREE_VIEW_STATE_STORAGE_KEY: string = 'workbench.explorer.treeViewState';
private tree: WorkbenchAsyncDataTree<ExplorerItem | ExplorerItem[], ExplorerItem, FuzzyScore>;
private filter: FilesFilter;
private tree!: WorkbenchAsyncDataTree<ExplorerItem | ExplorerItem[], ExplorerItem, FuzzyScore>;
private filter!: FilesFilter;
private resourceContext: ResourceContextKey;
private folderContext: IContextKey<boolean>;
@@ -66,7 +66,7 @@ export class ExplorerView extends ViewletPanel {
// Refresh is needed on the initial explorer open
private shouldRefresh = true;
private dragHandler: DelayedDragHandler;
private dragHandler!: DelayedDragHandler;
private autoReveal = false;
constructor(
@@ -301,7 +301,8 @@ export class ExplorerView extends ViewletPanel {
filter: this.filter,
sorter: this.instantiationService.createInstance(FileSorter),
dnd: this.instantiationService.createInstance(FileDragAndDrop),
autoExpandSingleChildren: true
autoExpandSingleChildren: true,
additionalScrollHeight: ExplorerDelegate.ITEM_HEIGHT
});
this._register(this.tree);

View File

@@ -49,7 +49,7 @@ import { FuzzyScore, createMatches } from 'vs/base/common/filters';
export class ExplorerDelegate implements IListVirtualDelegate<ExplorerItem> {
private static readonly ITEM_HEIGHT = 22;
static readonly ITEM_HEIGHT = 22;
getHeight(element: ExplorerItem): number {
return ExplorerDelegate.ITEM_HEIGHT;
@@ -440,7 +440,7 @@ export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
private static readonly CONFIRM_DND_SETTING_KEY = 'explorer.confirmDragAndDrop';
private toDispose: IDisposable[];
private dropEnabled: boolean;
private dropEnabled = false;
constructor(
@INotificationService private notificationService: INotificationService,
@@ -808,8 +808,8 @@ export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
private doHandleExplorerDrop(source: ExplorerItem, target: ExplorerItem, isCopy: boolean): Promise<void> {
// Reuse duplicate action if user copies
if (isCopy) {
return this.fileService.copy(source.resource, findValidPasteFileTarget(target, { resource: source.resource, isDirectory: source.isDirectory, allowOverwrite: false })).then(stat => {
const incrementalNaming = this.configurationService.getValue<IFilesConfiguration>().explorer.incrementalNaming;
return this.fileService.copy(source.resource, findValidPasteFileTarget(target, { resource: source.resource, isDirectory: source.isDirectory, allowOverwrite: false }, incrementalNaming)).then(stat => {
if (!stat.isDirectory) {
return this.editorService.openEditor({ resource: stat.resource, options: { pinned: true } }).then(() => undefined);
}

View File

@@ -51,16 +51,16 @@ export class OpenEditorsView extends ViewletPanel {
static readonly ID = 'workbench.explorer.openEditorsView';
static NAME = nls.localize({ key: 'openEditors', comment: ['Open is an adjective'] }, "Open Editors");
private dirtyCountElement: HTMLElement;
private dirtyCountElement!: HTMLElement;
private listRefreshScheduler: RunOnceScheduler;
private structuralRefreshDelay: number;
private list: WorkbenchList<OpenEditor | IEditorGroup>;
private listLabels: ResourceLabels;
private contributedContextMenu: IMenu;
private needsRefresh: boolean;
private resourceContext: ResourceContextKey;
private groupFocusedContext: IContextKey<boolean>;
private dirtyEditorFocusedContext: IContextKey<boolean>;
private list!: WorkbenchList<OpenEditor | IEditorGroup>;
private listLabels: ResourceLabels | undefined;
private contributedContextMenu!: IMenu;
private needsRefresh = false;
private resourceContext!: ResourceContextKey;
private groupFocusedContext!: IContextKey<boolean>;
private dirtyEditorFocusedContext!: IContextKey<boolean>;
constructor(
options: IViewletViewOptions,
@@ -129,7 +129,7 @@ export class OpenEditorsView extends ViewletPanel {
const index = this.getIndex(group, e.editor);
switch (e.kind) {
case GroupChangeKind.GROUP_LABEL: {
case GroupChangeKind.GROUP_INDEX: {
if (this.showGroups) {
this.list.splice(index, 1, [group]);
}
@@ -466,9 +466,13 @@ interface IEditorGroupTemplateData {
}
class OpenEditorActionRunner extends ActionRunner {
public editor: OpenEditor;
public editor: OpenEditor | undefined;
run(action: IAction, context?: any): Promise<void> {
if (!this.editor) {
return Promise.resolve();
}
return super.run(action, { groupId: this.editor.groupId, editorIndex: this.editor.editorIndex });
}
}

View File

@@ -19,7 +19,7 @@ import { IEditorService, ACTIVE_GROUP } from 'vs/workbench/services/editor/commo
export class DirtyFilesTracker extends Disposable implements IWorkbenchContribution {
private isDocumentedEdited: boolean;
private lastDirtyCount: number;
private lastKnownDirtyCount: number | undefined;
private readonly badgeHandle = this._register(new MutableDisposable());
constructor(
@@ -50,6 +50,10 @@ export class DirtyFilesTracker extends Disposable implements IWorkbenchContribut
this.lifecycleService.onShutdown(this.dispose, this);
}
private get hasDirtyCount(): boolean {
return typeof this.lastKnownDirtyCount === 'number' && this.lastKnownDirtyCount > 0;
}
private onUntitledDidChangeDirty(resource: URI): void {
const gotDirty = this.untitledEditorService.isDirty(resource);
@@ -57,7 +61,7 @@ export class DirtyFilesTracker extends Disposable implements IWorkbenchContribut
this.updateDocumentEdited();
}
if (gotDirty || this.lastDirtyCount > 0) {
if (gotDirty || this.hasDirtyCount) {
this.updateActivityBadge();
}
}
@@ -100,7 +104,7 @@ export class DirtyFilesTracker extends Disposable implements IWorkbenchContribut
this.updateDocumentEdited();
}
if (this.lastDirtyCount > 0) {
if (this.hasDirtyCount) {
this.updateActivityBadge();
}
}
@@ -118,15 +122,17 @@ export class DirtyFilesTracker extends Disposable implements IWorkbenchContribut
this.updateDocumentEdited();
}
if (this.lastDirtyCount > 0) {
if (this.hasDirtyCount) {
this.updateActivityBadge();
}
}
private updateActivityBadge(): void {
const dirtyCount = this.textFileService.getDirty().length;
this.lastDirtyCount = dirtyCount;
this.lastKnownDirtyCount = dirtyCount;
this.badgeHandle.clear();
if (dirtyCount > 0) {
this.badgeHandle.value = this.activityService.showActivity(VIEWLET_ID, new NumberBadge(dirtyCount, num => num === 1 ? nls.localize('dirtyFile', "1 unsaved file") : nls.localize('dirtyFiles', "{0} unsaved files", dirtyCount)), 'explorer-viewlet-label');
}

View File

@@ -19,7 +19,7 @@ import { IExplorerService } from 'vs/workbench/contrib/files/common/files';
export class ExplorerModel implements IDisposable {
private _roots: ExplorerItem[];
private _roots!: ExplorerItem[];
private _listener: IDisposable;
private _onDidChangeRoots = new Emitter<void>();
@@ -75,7 +75,7 @@ export class ExplorerModel implements IDisposable {
export class ExplorerItem {
private _isDirectoryResolved: boolean;
public isError: boolean;
public isError = false;
constructor(
public resource: URI,
@@ -367,4 +367,4 @@ export class NewExplorerItem extends ExplorerItem {
constructor(parent: ExplorerItem, isDirectory: boolean) {
super(URI.file(''), parent, isDirectory);
}
}
}

View File

@@ -114,6 +114,7 @@ export interface IFilesConfiguration extends IFilesConfiguration, IWorkbenchEdit
colors: boolean;
badges: boolean;
};
incrementalNaming: 'simple' | 'smart';
};
editor: IEditorOptions;
}

View File

@@ -6,132 +6,292 @@
import * as assert from 'assert';
import { incrementFileName } from 'vs/workbench/contrib/files/browser/fileActions';
suite('Files - Increment file name', () => {
suite('Files - Increment file name simple', () => {
test('Increment file name without any version', function () {
const name = 'test.js';
const result = incrementFileName(name, false);
const result = incrementFileName(name, false, 'simple');
assert.strictEqual(result, 'test copy.js');
});
test('Increment file name with suffix version', function () {
const name = 'test copy.js';
const result = incrementFileName(name, false);
const result = incrementFileName(name, false, 'simple');
assert.strictEqual(result, 'test copy 2.js');
});
test('Increment file name with suffix version with leading zeros', function () {
const name = 'test copy 005.js';
const result = incrementFileName(name, false);
const result = incrementFileName(name, false, 'simple');
assert.strictEqual(result, 'test copy 6.js');
});
test('Increment file name with suffix version, too big number', function () {
const name = 'test copy 9007199254740992.js';
const result = incrementFileName(name, false);
const result = incrementFileName(name, false, 'simple');
assert.strictEqual(result, 'test copy 9007199254740992 copy.js');
});
test('Increment file name with just version in name', function () {
const name = 'copy.js';
const result = incrementFileName(name, false);
const result = incrementFileName(name, false, 'simple');
assert.strictEqual(result, 'copy copy.js');
});
test('Increment file name with just version in name, v2', function () {
const name = 'copy 2.js';
const result = incrementFileName(name, false);
const result = incrementFileName(name, false, 'simple');
assert.strictEqual(result, 'copy 2 copy.js');
});
test('Increment file name without any extension or version', function () {
const name = 'test';
const result = incrementFileName(name, false);
const result = incrementFileName(name, false, 'simple');
assert.strictEqual(result, 'test copy');
});
test('Increment file name without any extension or version, trailing dot', function () {
const name = 'test.';
const result = incrementFileName(name, false);
const result = incrementFileName(name, false, 'simple');
assert.strictEqual(result, 'test copy.');
});
test('Increment file name without any extension or version, leading dot', function () {
const name = '.test';
const result = incrementFileName(name, false);
const result = incrementFileName(name, false, 'simple');
assert.strictEqual(result, '.test copy');
});
test('Increment file name without any extension or version, leading dot v2', function () {
const name = '..test';
const result = incrementFileName(name, false);
const result = incrementFileName(name, false, 'simple');
assert.strictEqual(result, '. copy.test');
});
test('Increment file name without any extension but with suffix version', function () {
const name = 'test copy 5';
const result = incrementFileName(name, false);
const result = incrementFileName(name, false, 'simple');
assert.strictEqual(result, 'test copy 6');
});
test('Increment folder name without any version', function () {
const name = 'test';
const result = incrementFileName(name, true);
const result = incrementFileName(name, true, 'simple');
assert.strictEqual(result, 'test copy');
});
test('Increment folder name with suffix version', function () {
const name = 'test copy';
const result = incrementFileName(name, true);
const result = incrementFileName(name, true, 'simple');
assert.strictEqual(result, 'test copy 2');
});
test('Increment folder name with suffix version, leading zeros', function () {
const name = 'test copy 005';
const result = incrementFileName(name, true);
const result = incrementFileName(name, true, 'simple');
assert.strictEqual(result, 'test copy 6');
});
test('Increment folder name with suffix version, too big number', function () {
const name = 'test copy 9007199254740992';
const result = incrementFileName(name, true);
const result = incrementFileName(name, true, 'simple');
assert.strictEqual(result, 'test copy 9007199254740992 copy');
});
test('Increment folder name with just version in name', function () {
const name = 'copy';
const result = incrementFileName(name, true);
const result = incrementFileName(name, true, 'simple');
assert.strictEqual(result, 'copy copy');
});
test('Increment folder name with just version in name, v2', function () {
const name = 'copy 2';
const result = incrementFileName(name, true);
const result = incrementFileName(name, true, 'simple');
assert.strictEqual(result, 'copy 2 copy');
});
test('Increment folder name "with extension" but without any version', function () {
const name = 'test.js';
const result = incrementFileName(name, true);
const result = incrementFileName(name, true, 'simple');
assert.strictEqual(result, 'test.js copy');
});
test('Increment folder name "with extension" and with suffix version', function () {
const name = 'test.js copy 5';
const result = incrementFileName(name, true);
const result = incrementFileName(name, true, 'simple');
assert.strictEqual(result, 'test.js copy 6');
});
test('Increment file/folder name with suffix version, special case 1', function () {
const name = 'test copy 0';
const result = incrementFileName(name, true);
const result = incrementFileName(name, true, 'simple');
assert.strictEqual(result, 'test copy');
});
test('Increment file/folder name with suffix version, special case 2', function () {
const name = 'test copy 1';
const result = incrementFileName(name, true);
const result = incrementFileName(name, true, 'simple');
assert.strictEqual(result, 'test copy 2');
});
});
suite('Files - Increment file name smart', () => {
test('Increment file name without any version', function () {
const name = 'test.js';
const result = incrementFileName(name, false, 'smart');
assert.strictEqual(result, 'test.1.js');
});
test('Increment folder name without any version', function () {
const name = 'test';
const result = incrementFileName(name, true, 'smart');
assert.strictEqual(result, 'test.1');
});
test('Increment file name with suffix version', function () {
const name = 'test.1.js';
const result = incrementFileName(name, false, 'smart');
assert.strictEqual(result, 'test.2.js');
});
test('Increment file name with suffix version with trailing zeros', function () {
const name = 'test.001.js';
const result = incrementFileName(name, false, 'smart');
assert.strictEqual(result, 'test.002.js');
});
test('Increment file name with suffix version with trailing zeros, changing length', function () {
const name = 'test.009.js';
const result = incrementFileName(name, false, 'smart');
assert.strictEqual(result, 'test.010.js');
});
test('Increment file name with suffix version with `-` as separator', function () {
const name = 'test-1.js';
const result = incrementFileName(name, false, 'smart');
assert.strictEqual(result, 'test-2.js');
});
test('Increment file name with suffix version with `-` as separator, trailing zeros', function () {
const name = 'test-001.js';
const result = incrementFileName(name, false, 'smart');
assert.strictEqual(result, 'test-002.js');
});
test('Increment file name with suffix version with `-` as separator, trailing zeros, changnig length', function () {
const name = 'test-099.js';
const result = incrementFileName(name, false, 'smart');
assert.strictEqual(result, 'test-100.js');
});
test('Increment file name with suffix version with `_` as separator', function () {
const name = 'test_1.js';
const result = incrementFileName(name, false, 'smart');
assert.strictEqual(result, 'test_2.js');
});
test('Increment folder name with suffix version', function () {
const name = 'test.1';
const result = incrementFileName(name, true, 'smart');
assert.strictEqual(result, 'test.2');
});
test('Increment folder name with suffix version, trailing zeros', function () {
const name = 'test.001';
const result = incrementFileName(name, true, 'smart');
assert.strictEqual(result, 'test.002');
});
test('Increment folder name with suffix version with `-` as separator', function () {
const name = 'test-1';
const result = incrementFileName(name, true, 'smart');
assert.strictEqual(result, 'test-2');
});
test('Increment folder name with suffix version with `_` as separator', function () {
const name = 'test_1';
const result = incrementFileName(name, true, 'smart');
assert.strictEqual(result, 'test_2');
});
test('Increment file name with suffix version, too big number', function () {
const name = 'test.9007199254740992.js';
const result = incrementFileName(name, false, 'smart');
assert.strictEqual(result, 'test.9007199254740992.1.js');
});
test('Increment folder name with suffix version, too big number', function () {
const name = 'test.9007199254740992';
const result = incrementFileName(name, true, 'smart');
assert.strictEqual(result, 'test.9007199254740992.1');
});
test('Increment file name with prefix version', function () {
const name = '1.test.js';
const result = incrementFileName(name, false, 'smart');
assert.strictEqual(result, '2.test.js');
});
test('Increment file name with just version in name', function () {
const name = '1.js';
const result = incrementFileName(name, false, 'smart');
assert.strictEqual(result, '2.js');
});
test('Increment file name with just version in name, too big number', function () {
const name = '9007199254740992.js';
const result = incrementFileName(name, false, 'smart');
assert.strictEqual(result, '9007199254740992.1.js');
});
test('Increment file name with prefix version, trailing zeros', function () {
const name = '001.test.js';
const result = incrementFileName(name, false, 'smart');
assert.strictEqual(result, '002.test.js');
});
test('Increment file name with prefix version with `-` as separator', function () {
const name = '1-test.js';
const result = incrementFileName(name, false, 'smart');
assert.strictEqual(result, '2-test.js');
});
test('Increment file name with prefix version with `-` as separator', function () {
const name = '1_test.js';
const result = incrementFileName(name, false, 'smart');
assert.strictEqual(result, '2_test.js');
});
test('Increment file name with prefix version, too big number', function () {
const name = '9007199254740992.test.js';
const result = incrementFileName(name, false, 'smart');
assert.strictEqual(result, '9007199254740992.test.1.js');
});
test('Increment folder name with prefix version', function () {
const name = '1.test';
const result = incrementFileName(name, true, 'smart');
assert.strictEqual(result, '2.test');
});
test('Increment folder name with prefix version, too big number', function () {
const name = '9007199254740992.test';
const result = incrementFileName(name, true, 'smart');
assert.strictEqual(result, '9007199254740992.test.1');
});
test('Increment folder name with prefix version, trailing zeros', function () {
const name = '001.test';
const result = incrementFileName(name, true, 'smart');
assert.strictEqual(result, '002.test');
});
test('Increment folder name with prefix version with `-` as separator', function () {
const name = '1-test';
const result = incrementFileName(name, true, 'smart');
assert.strictEqual(result, '2-test');
});
});

View File

@@ -56,8 +56,8 @@ class MarkersDecorationsProvider implements IDecorationsProvider {
class MarkersFileDecorations implements IWorkbenchContribution {
private readonly _disposables: IDisposable[];
private _provider: IDisposable;
private _enabled: boolean;
private _provider?: IDisposable;
private _enabled?: boolean;
constructor(
@IMarkerService private readonly _markerService: IMarkerService,

View File

@@ -334,9 +334,11 @@ class MarkerWidget extends Disposable {
const sourceMatches = filterData && filterData.sourceMatches || [];
source.set(marker.source, sourceMatches);
const code = new HighlightedLabel(dom.append(parent, dom.$('.marker-code')), false);
const codeMatches = filterData && filterData.codeMatches || [];
code.set(marker.code, codeMatches);
if (marker.code) {
const code = new HighlightedLabel(dom.append(parent, dom.$('.marker-code')), false);
const codeMatches = filterData && filterData.codeMatches || [];
code.set(marker.code, codeMatches);
}
}
const lnCol = dom.append(parent, dom.$('span.marker-line'));

View File

@@ -238,14 +238,14 @@ export class OutlinePanel extends ViewletPanel {
private _editorDisposables = new DisposableStore();
private _outlineViewState = new OutlineViewState();
private _requestOracle?: RequestOracle;
private _domNode: HTMLElement;
private _message: HTMLDivElement;
private _inputContainer: HTMLDivElement;
private _progressBar: ProgressBar;
private _tree: WorkbenchDataTree<OutlineModel, OutlineItem, FuzzyScore>;
private _treeDataSource: OutlineDataSource;
private _treeRenderer: OutlineElementRenderer;
private _treeComparator: OutlineItemComparator;
private _domNode!: HTMLElement;
private _message!: HTMLDivElement;
private _inputContainer!: HTMLDivElement;
private _progressBar!: ProgressBar;
private _tree!: WorkbenchDataTree<OutlineModel, OutlineItem, FuzzyScore>;
private _treeDataSource!: OutlineDataSource;
private _treeRenderer!: OutlineElementRenderer;
private _treeComparator!: OutlineItemComparator;
private _treeStates = new LRUCache<string, IDataTreeViewState>(10);
private _treeFakeUIEvent = new UIEvent('me');

View File

@@ -122,8 +122,8 @@ export class SwitchOutputActionViewItem extends SelectActionViewItem {
private static readonly SEPARATOR = '─────────';
private outputChannels: IOutputChannelDescriptor[];
private logChannels: IOutputChannelDescriptor[];
private outputChannels: IOutputChannelDescriptor[] = [];
private logChannels: IOutputChannelDescriptor[] = [];
constructor(
action: IAction,
@@ -267,4 +267,4 @@ export class OpenOutputLogFileAction extends Action {
return undefined;
});
}
}
}

View File

@@ -29,9 +29,9 @@ import { IWindowService } from 'vs/platform/windows/common/windows';
import { CursorChangeReason } from 'vs/editor/common/controller/cursorEvents';
export class OutputPanel extends AbstractTextResourceEditor {
private actions: IAction[];
private actions: IAction[] | undefined;
private scopedInstantiationService: IInstantiationService;
private _focus: boolean;
private _focus = false;
constructor(
@ITelemetryService telemetryService: ITelemetryService,
@@ -155,7 +155,7 @@ export class OutputPanel extends AbstractTextResourceEditor {
}
const model = codeEditor.getModel();
if (model) {
if (model && this.actions) {
const newPositionLine = e.position.lineNumber;
const lastLine = model.getLineCount();
const newLockState = lastLine !== newPositionLine;

View File

@@ -71,7 +71,7 @@ export class OutputService extends Disposable implements IOutputService, ITextMo
private readonly _onActiveOutputChannel = this._register(new Emitter<string>());
readonly onActiveOutputChannel: Event<string> = this._onActiveOutputChannel.event;
private _outputPanel: OutputPanel;
private _outputPanel: OutputPanel | undefined;
constructor(
@IStorageService private readonly storageService: IStorageService,
@@ -224,7 +224,7 @@ export class OutputService extends Disposable implements IOutputService, ITextMo
CONTEXT_ACTIVE_LOG_OUTPUT.bindTo(this.contextKeyService).set(!!channel.outputChannelDescriptor.file && channel.outputChannelDescriptor.log);
return this._outputPanel.setInput(this.createInput(channel), EditorOptions.create({ preserveFocus }), CancellationToken.None)
.then(() => {
if (!preserveFocus) {
if (!preserveFocus && this._outputPanel) {
this._outputPanel.focus();
}
});

View File

@@ -152,8 +152,8 @@ class PerfModelContentProvider implements ITextModelContentProvider {
table.push(['nls:start => nls:end', metrics.timers.ellapsedNlsGeneration, '[main]', `initial startup: ${metrics.initialStartup}`]);
table.push(['require(main.bundle.js)', metrics.initialStartup ? perf.getDuration('willLoadMainBundle', 'didLoadMainBundle') : undefined, '[main]', `initial startup: ${metrics.initialStartup}`]);
table.push(['app.isReady => window.loadUrl()', metrics.timers.ellapsedWindowLoad, '[main]', `initial startup: ${metrics.initialStartup}`]);
table.push(['window.loadUrl() => begin to require(workbench.main.js)', metrics.timers.ellapsedWindowLoadToRequire, '[main->renderer]', StartupKindToString(metrics.windowKind)]);
table.push(['require(workbench.main.js)', metrics.timers.ellapsedRequire, '[renderer]', `cached data: ${(metrics.didUseCachedData ? 'YES' : 'NO')}${stats ? `, node_modules took ${stats.nodeRequireTotal}ms` : ''}`]);
table.push(['window.loadUrl() => begin to require(workbench.desktop.main.js)', metrics.timers.ellapsedWindowLoadToRequire, '[main->renderer]', StartupKindToString(metrics.windowKind)]);
table.push(['require(workbench.desktop.main.js)', metrics.timers.ellapsedRequire, '[renderer]', `cached data: ${(metrics.didUseCachedData ? 'YES' : 'NO')}${stats ? `, node_modules took ${stats.nodeRequireTotal}ms` : ''}`]);
table.push(['require & init workspace storage', metrics.timers.ellapsedWorkspaceStorageInit, '[renderer]', undefined]);
table.push(['init workspace service', metrics.timers.ellapsedWorkspaceServiceInit, '[renderer]', undefined]);
table.push(['register extensions & spawn extension host', metrics.timers.ellapsedExtensions, '[renderer]', undefined]);
@@ -262,11 +262,11 @@ class PerfModelContentProvider implements ITextModelContentProvider {
}
abstract class LoaderStats {
readonly amdLoad: (string | number)[][];
readonly amdInvoke: (string | number)[][];
readonly nodeRequire: (string | number)[][];
readonly nodeEval: (string | number)[][];
readonly nodeRequireTotal: number;
abstract get amdLoad(): (string | number)[][];
abstract get amdInvoke(): (string | number)[][];
abstract get nodeRequire(): (string | number)[][];
abstract get nodeEval(): (string | number)[][];
abstract get nodeRequireTotal(): number;
static get(): LoaderStats {

View File

@@ -143,7 +143,7 @@
max-width: 952px;
/* 1000 - 24*2 padding */
margin-left: -476px;
z-index: 1000;
z-index: 11;
}
.settings-editor > .settings-body .settings-tree-container .setting-toolbar-container {
@@ -182,7 +182,7 @@
.settings-editor > .settings-body .settings-toc-container {
width: 100%;
pointer-events: none;
z-index: 100;
z-index: 10;
position: absolute;
}
@@ -511,4 +511,4 @@
.settings-editor.search-mode > .settings-body .settings-toc-container .monaco-list-row .settings-toc-count {
display: block;
}
}

View File

@@ -29,7 +29,7 @@
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-value,
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-sibling {
display: inline-block;
line-height: 22px;
line-height: 24px;
}
/* Use monospace to display glob patterns in exclude widget */
@@ -49,12 +49,11 @@
display: none;
position: absolute;
right: 0px;
margin-top: 1px;
}
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row {
position: relative;
max-height: 22px;
max-height: 24px;
}
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row:focus {
@@ -68,7 +67,7 @@
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row .monaco-action-bar .action-label {
width: 16px;
height: 16px;
height: 20px;
padding: 2px;
margin-right: 2px;
}
@@ -103,6 +102,7 @@
}
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .monaco-text-button.setting-list-addButton {
margin-top: 4px;
margin-right: 10px;
}
@@ -112,7 +112,7 @@
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-valueInput,
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-siblingInput {
height: 22px;
height: 24px;
max-width: 320px;
flex: 1;
margin-right: 10px;

View File

@@ -289,6 +289,11 @@ export class SettingsEditor2 extends BaseEditor {
layout(dimension: DOM.Dimension): void {
this.dimension = dimension;
if (!this.isVisible()) {
return;
}
this.layoutTrees(dimension);
const innerWidth = Math.min(1000, dimension.width) - 24 * 2; // 24px padding on left and right;
@@ -978,14 +983,9 @@ export class SettingsEditor2 extends BaseEditor {
// If a single setting is being refreshed, it's ok to refresh now if that is not the focused setting
if (key) {
const focusedKey = focusedSetting.getAttribute(AbstractSettingRenderer.SETTING_KEY_ATTR);
/**
* Update `list`s live if focused item is whole list or list item,
* as they have a separate "submit edit" step built in before this
*/
if (
focusedKey === key &&
!DOM.hasClass(focusedSetting, 'setting-item-list') &&
!DOM.hasClass(focusedSetting, 'setting-item-contents')
if (focusedKey === key &&
// update `list`s live, as they have a separate "submit edit" step built in before this
(focusedSetting.parentElement && !DOM.hasClass(focusedSetting.parentElement, 'setting-item-list'))
) {
this.updateModifiedLabelForKey(key);

View File

@@ -100,6 +100,11 @@ export const tocData: ITOCEntry = {
id: 'workbench/zenmode',
label: localize('zenMode', "Zen Mode"),
settings: ['zenmode.*']
},
{
id: 'workbench/screencastmode',
label: localize('screencastMode', "Screencast Mode"),
settings: ['screencastMode.*']
}
]
},

View File

@@ -16,7 +16,7 @@ import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import 'vs/css!./media/settingsWidgets';
import { localize } from 'vs/nls';
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
import { foreground, inputBackground, inputBorder, inputForeground, listActiveSelectionBackground, listActiveSelectionForeground, listHoverBackground, listHoverForeground, listInactiveSelectionBackground, listInactiveSelectionForeground, registerColor, selectBackground, selectBorder, selectForeground, textLinkForeground, textPreformatForeground, editorWidgetBorder, textLinkActiveForeground } from 'vs/platform/theme/common/colorRegistry';
import { foreground, inputBackground, inputBorder, inputForeground, listActiveSelectionBackground, listActiveSelectionForeground, listHoverBackground, listHoverForeground, listInactiveSelectionBackground, listInactiveSelectionForeground, registerColor, selectBackground, selectBorder, selectForeground, textLinkForeground, textPreformatForeground, editorWidgetBorder, textLinkActiveForeground, simpleCheckboxBackground, simpleCheckboxForeground, simpleCheckboxBorder } from 'vs/platform/theme/common/colorRegistry';
import { attachButtonStyler, attachInputBoxStyler } from 'vs/platform/theme/common/styler';
import { ICssStyleCollector, ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { disposableTimeout } from 'vs/base/common/async';
@@ -37,9 +37,9 @@ export const settingsSelectBorder = registerColor('settings.dropdownBorder', { d
export const settingsSelectListBorder = registerColor('settings.dropdownListBorder', { dark: editorWidgetBorder, light: editorWidgetBorder, hc: editorWidgetBorder }, localize('settingsDropdownListBorder', "(For settings editor preview) Settings editor dropdown list border. This surrounds the options and separates the options from the description."));
// Bool control colors
export const settingsCheckboxBackground = registerColor('settings.checkboxBackground', { dark: selectBackground, light: selectBackground, hc: selectBackground }, localize('settingsCheckboxBackground', "(For settings editor preview) Settings editor checkbox background."));
export const settingsCheckboxForeground = registerColor('settings.checkboxForeground', { dark: selectForeground, light: selectForeground, hc: selectForeground }, localize('settingsCheckboxForeground', "(For settings editor preview) Settings editor checkbox foreground."));
export const settingsCheckboxBorder = registerColor('settings.checkboxBorder', { dark: selectBorder, light: selectBorder, hc: selectBorder }, localize('settingsCheckboxBorder', "(For settings editor preview) Settings editor checkbox border."));
export const settingsCheckboxBackground = registerColor('settings.checkboxBackground', { dark: simpleCheckboxBackground, light: simpleCheckboxBackground, hc: simpleCheckboxBackground }, localize('settingsCheckboxBackground', "(For settings editor preview) Settings editor checkbox background."));
export const settingsCheckboxForeground = registerColor('settings.checkboxForeground', { dark: simpleCheckboxForeground, light: simpleCheckboxForeground, hc: simpleCheckboxForeground }, localize('settingsCheckboxForeground', "(For settings editor preview) Settings editor checkbox foreground."));
export const settingsCheckboxBorder = registerColor('settings.checkboxBorder', { dark: simpleCheckboxBorder, light: simpleCheckboxBorder, hc: simpleCheckboxBorder }, localize('settingsCheckboxBorder', "(For settings editor preview) Settings editor checkbox border."));
// Text control colors
export const settingsTextInputBackground = registerColor('settings.textInputBackground', { dark: inputBackground, light: inputBackground, hc: inputBackground }, localize('textInputBoxBackground', "(For settings editor preview) Settings editor text input box background."));
@@ -346,7 +346,7 @@ export class ListSettingWidget extends Disposable {
.map((item, i) => this.renderItem(item, i, focused))
.forEach(itemElement => this.listElement.appendChild(itemElement));
const listHeight = 22 * this.model.items.length;
const listHeight = 24 * this.model.items.length;
this.listElement.style.height = listHeight + 'px';
}

View File

@@ -366,7 +366,7 @@ export class GotoSymbolHandler extends QuickOpenHandler {
static readonly ID = 'workbench.picker.filesymbols';
private rangeHighlightDecorationId?: IEditorLineDecoration;
private lastKnownEditorViewState: IEditorViewState | null;
private lastKnownEditorViewState: IEditorViewState | null = null;
private cachedOutlineRequest?: Promise<OutlineModel | null>;
private pendingOutlineRequest?: CancellationTokenSource;

View File

@@ -15,7 +15,7 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten
import { RunOnceScheduler } from 'vs/base/common/async';
import { URI } from 'vs/base/common/uri';
import { isEqual } from 'vs/base/common/resources';
import { isMacintosh } from 'vs/base/common/platform';
import { isMacintosh, isNative } from 'vs/base/common/platform';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
@@ -23,7 +23,6 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/
interface IConfiguration extends IWindowsConfiguration {
update: { mode: string; };
telemetry: { enableCrashReporter: boolean };
keyboard: { touchbar: { enabled: boolean } };
workbench: { list: { horizontalScrolling: boolean }, useExperimentalGridLayout: boolean };
debug: { console: { wordWrap: boolean } };
}
@@ -36,7 +35,6 @@ export class SettingsChangeRelauncher extends Disposable implements IWorkbenchCo
private clickThroughInactive: boolean;
private updateMode: string;
private enableCrashReporter: boolean;
private touchbarEnabled: boolean;
private treeHorizontalScrolling: boolean;
private useGridLayout: boolean;
private debugConsoleWordWrap: boolean;
@@ -57,48 +55,6 @@ export class SettingsChangeRelauncher extends Disposable implements IWorkbenchCo
private onConfigurationChange(config: IConfiguration, notify: boolean): void {
let changed = false;
// Titlebar style
if (config.window && config.window.titleBarStyle !== this.titleBarStyle && (config.window.titleBarStyle === 'native' || config.window.titleBarStyle === 'custom')) {
this.titleBarStyle = config.window.titleBarStyle;
changed = true;
}
// macOS: Native tabs
if (isMacintosh && config.window && typeof config.window.nativeTabs === 'boolean' && config.window.nativeTabs !== this.nativeTabs) {
this.nativeTabs = config.window.nativeTabs;
changed = true;
}
// macOS: Native fullscreen
if (isMacintosh && config.window && typeof config.window.nativeFullScreen === 'boolean' && config.window.nativeFullScreen !== this.nativeFullScreen) {
this.nativeFullScreen = config.window.nativeFullScreen;
changed = true;
}
// macOS: Click through (accept first mouse)
if (isMacintosh && config.window && typeof config.window.clickThroughInactive === 'boolean' && config.window.clickThroughInactive !== this.clickThroughInactive) {
this.clickThroughInactive = config.window.clickThroughInactive;
changed = true;
}
// Update channel
if (config.update && typeof config.update.mode === 'string' && config.update.mode !== this.updateMode) {
this.updateMode = config.update.mode;
changed = true;
}
// Crash reporter
if (config.telemetry && typeof config.telemetry.enableCrashReporter === 'boolean' && config.telemetry.enableCrashReporter !== this.enableCrashReporter) {
this.enableCrashReporter = config.telemetry.enableCrashReporter;
changed = true;
}
// macOS: Touchbar config
if (isMacintosh && config.keyboard && config.keyboard.touchbar && typeof config.keyboard.touchbar.enabled === 'boolean' && config.keyboard.touchbar.enabled !== this.touchbarEnabled) {
this.touchbarEnabled = config.keyboard.touchbar.enabled;
changed = true;
}
// Tree horizontal scrolling support
if (config.workbench && config.workbench.list && typeof config.workbench.list.horizontalScrolling === 'boolean' && config.workbench.list.horizontalScrolling !== this.treeHorizontalScrolling) {
this.treeHorizontalScrolling = config.workbench.list.horizontalScrolling;
@@ -117,12 +73,57 @@ export class SettingsChangeRelauncher extends Disposable implements IWorkbenchCo
changed = true;
}
if (isNative) {
// Titlebar style
if (config.window && config.window.titleBarStyle !== this.titleBarStyle && (config.window.titleBarStyle === 'native' || config.window.titleBarStyle === 'custom')) {
this.titleBarStyle = config.window.titleBarStyle;
changed = true;
}
// macOS: Native tabs
if (isMacintosh && config.window && typeof config.window.nativeTabs === 'boolean' && config.window.nativeTabs !== this.nativeTabs) {
this.nativeTabs = config.window.nativeTabs;
changed = true;
}
// macOS: Native fullscreen
if (isMacintosh && config.window && typeof config.window.nativeFullScreen === 'boolean' && config.window.nativeFullScreen !== this.nativeFullScreen) {
this.nativeFullScreen = config.window.nativeFullScreen;
changed = true;
}
// macOS: Click through (accept first mouse)
if (isMacintosh && config.window && typeof config.window.clickThroughInactive === 'boolean' && config.window.clickThroughInactive !== this.clickThroughInactive) {
this.clickThroughInactive = config.window.clickThroughInactive;
changed = true;
}
// Update channel
if (config.update && typeof config.update.mode === 'string' && config.update.mode !== this.updateMode) {
this.updateMode = config.update.mode;
changed = true;
}
// Crash reporter
if (config.telemetry && typeof config.telemetry.enableCrashReporter === 'boolean' && config.telemetry.enableCrashReporter !== this.enableCrashReporter) {
this.enableCrashReporter = config.telemetry.enableCrashReporter;
changed = true;
}
}
// Notify only when changed and we are the focused window (avoids notification spam across windows)
if (notify && changed) {
this.doConfirm(
localize('relaunchSettingMessage', "A setting has changed that requires a restart to take effect."),
localize('relaunchSettingDetail', "Press the restart button to restart {0} and enable the setting.", this.envService.appNameLong),
localize('restart', "&&Restart"),
isNative ?
localize('relaunchSettingMessage', "A setting has changed that requires a restart to take effect.") :
localize('relaunchSettingMessageWeb', "A setting has changed that requires a reload to take effect."),
isNative ?
localize('relaunchSettingDetail', "Press the restart button to restart {0} and enable the setting.", this.envService.appNameLong) :
localize('relaunchSettingDetailWeb', "Press the reload button to reload {0} and enable the setting.", this.envService.appNameLong),
isNative ?
localize('restart', "&&Restart") :
localize('restartWeb', "&&Reload"),
() => this.windowsService.relaunch(Object.create(null))
);
}
@@ -167,8 +168,9 @@ export class WorkspaceChangeExtHostRelauncher extends Disposable implements IWor
if (!!environmentService.extensionTestsLocationURI) {
return; // no restart when in tests: see https://github.com/Microsoft/vscode/issues/66936
}
if (environmentService.configuration.remoteAuthority) {
windowSevice.reloadWindow(); // TODO aeschli, workaround
windowSevice.reloadWindow(); // TODO@aeschli, workaround
} else {
extensionService.restartExtensionHost();
}

View File

@@ -85,7 +85,7 @@ export class RemoteWindowActiveIndicator extends Disposable implements IWorkbenc
group: '6_close',
command: {
id: CLOSE_REMOTE_COMMAND_ID,
title: nls.localize({ key: 'miCloseRemote', comment: ['&& denotes a mnemonic'] }, "C&&lose Remote Connection")
title: nls.localize({ key: 'miCloseRemote', comment: ['&& denotes a mnemonic'] }, "Close Re&&mote Connection")
},
order: 3.5
});

View File

@@ -4,8 +4,6 @@
*--------------------------------------------------------------------------------------------*/
import { URI } from 'vs/base/common/uri';
import { generateUuid } from 'vs/base/common/uuid';
import { getMediaMime } from 'vs/base/common/mime';
//https://stackoverflow.com/questions/56356655/structuring-a-typescript-project-with-workers/56374158#56374158
declare var self: ServiceWorkerGlobalScope;
@@ -35,8 +33,8 @@ self.addEventListener('activate', event => {
//#region --- fetching/caching
const _cacheName = 'vscode-resources';
const _resourcePrefix = '/vscode-resources/fetch';
const _cacheName = 'vscode-extension-resources';
const _resourcePrefix = '/vscode-remote';
const _pendingFetch = new Map<string, Function>();
self.addEventListener('message', event => {
@@ -71,38 +69,18 @@ async function respondWithDefault(event: FetchEvent): Promise<Response> {
}
async function respondWithResource(event: FetchEvent, uri: URI): Promise<Response> {
const cacheKey = event.request.url.replace('&r=1', '');
const cachedValue = await caches.open(_cacheName).then(cache => cache.match(cacheKey));
const cachedValue = await caches.open(_cacheName).then(cache => cache.match(event.request));
if (cachedValue) {
return cachedValue;
}
return new Promise<Response>(resolve => {
const response: Response = await event.preloadResponse || await fetch(event.request);
if (response.headers.get('X-VSCode-Extension') === 'true') {
await caches.open(_cacheName).then(cache => cache.put(event.request, response.clone()));
}
const token = generateUuid();
const [first] = uri.query.split('&');
const components = JSON.parse(first.substr(2));
_pendingFetch.set(token, async (data: ArrayBuffer, isExtensionResource: boolean) => {
const res = new Response(data, {
status: 200,
headers: { 'Content-Type': getMediaMime(components.path) || 'text/plain' }
});
if (isExtensionResource) {
// only cache extension resources but not other
// resources, esp not workspace resources
await caches.open(_cacheName).then(cache => cache.put(cacheKey, res.clone()));
}
return resolve(res);
});
self.clients.get(event.clientId).then(client => {
client.postMessage({ uri: components, token });
});
});
return response;
}
//#endregion

View File

@@ -3,145 +3,41 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IFileService } from 'vs/platform/files/common/files';
import { URI } from 'vs/base/common/uri';
import { Registry } from 'vs/platform/registry/common/platform';
import { IWorkbenchContributionsRegistry, Extensions } from 'vs/workbench/common/contributions';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { isEqualOrParent } from 'vs/base/common/resources';
import { ILogService } from 'vs/platform/log/common/log';
// load and start service worker as soon as this file
// is being loaded and later, when services are ready,
// claim this service worker so that messages can be
// replied to
const _serviceWorker = new class ServiceWorkerStarter {
private static _url = require.toUrl('./resourceServiceWorkerMain.js');
private _beforeReadyEvents: ExtendableMessageEvent[] = [];
private _messageHandler?: (event: ExtendableMessageEvent) => void;
constructor() {
navigator.serviceWorker.register(ServiceWorkerStarter._url, { scope: '/' }).then(reg => {
// console.debug('SW#reg', reg);
return reg.update();
// }).then(() => {
// // console.debug('SW#updated', reg);
// return navigator.serviceWorker.ready;
}).then(() => {
console.info('SW#ready');
}).catch(err => {
console.error('SW#init', err);
});
const handleMessage = (event: ExtendableMessageEvent) => {
if (!this._messageHandler) {
this._beforeReadyEvents.push(event);
console.debug('SW#buffered', event.data);
} else {
this._messageHandler(event);
}
};
navigator.serviceWorker.addEventListener('message', e => handleMessage(e as ExtendableMessageEvent));
}
dispose(): void {
// when to dispose?
}
claim(handler: (event: ExtendableMessageEvent) => void): void {
this._messageHandler = handler;
this._beforeReadyEvents.forEach(this._messageHandler);
}
};
import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle';
class ResourceServiceWorker {
private static _url = require.toUrl('./resourceServiceWorkerMain.js');
private readonly _disposables = new DisposableStore();
constructor(
@IFileService private readonly _fileService: IFileService,
@IExtensionService private readonly _extensionService: IExtensionService,
@ILogService private readonly _logService: ILogService,
) {
this._updateEarlyResourceUris();
_serviceWorker.claim(e => this._handleMessage(e));
navigator.serviceWorker.register(ResourceServiceWorker._url, { scope: '/' }).then(reg => {
this._logService.trace('SW#reg', reg);
return reg.update();
}).then(() => {
this._logService.info('SW#ready');
}).catch(err => {
this._logService.error('SW#init', err);
});
const handler = (e: ExtendableMessageEvent) => this._handleMessage(e);
navigator.serviceWorker.addEventListener('message', handler);
this._disposables.add(toDisposable(() => navigator.serviceWorker.removeEventListener('message', handler)));
}
dispose(): void {
this._disposables.dispose();
}
private _handleMessage(event: ExtendableMessageEvent): void {
this._logService.trace('SW - fetch', event.data.uri);
const uri = URI.revive(event.data.uri);
Promise.all([
this._fileService.readFile(uri),
this._isExtensionResource(uri)
]).then(([file, isExtensionResource]) => {
if (!event.source) {
return;
}
event.source.postMessage({
token: event.data.token,
data: file.value.buffer.buffer,
isExtensionResource
}, [file.value.buffer.buffer]);
});
}
private async _isExtensionResource(uri: URI): Promise<boolean> {
for (const ext of await this._extensionService.getExtensions()) {
if (isEqualOrParent(uri, ext.extensionLocation)) {
return true;
}
}
return false;
}
private _updateEarlyResourceUris(): void {
let updateCount = 0;
// find style-tags
const styleElements = document.querySelectorAll('style');
for (let i = 0; i < styleElements.length; i++) {
const el = styleElements.item(i);
if (!el.sheet) {
continue;
}
const rules = (<CSSStyleSheet>el.sheet).rules;
for (let j = 0; j < rules.length; j++) {
const rule = rules[j];
const newCssText = this._updateResourceUris(rule.cssText);
if (newCssText) {
(<CSSStyleSheet>el.sheet).deleteRule(j);
(<CSSStyleSheet>el.sheet).insertRule(newCssText, j);
updateCount += 1;
}
}
}
// find any tag using remote uris
const htmlElements = document.querySelectorAll('[style*="/vscode-resources/fetch"]');
for (let i = 0; i < htmlElements.length; i++) {
const el = <HTMLElement>htmlElements.item(i);
const newCssText = this._updateResourceUris(el.style.cssText);
if (newCssText) {
el.style.cssText = newCssText;
updateCount += 1;
}
}
this._logService.trace('SW - count of changed, early dom element: ', updateCount);
}
private _updateResourceUris(cssText: string): string | undefined {
let changed = false;
let newCssText = cssText.replace(/url\((["'])?(.+?\/vscode-resources\/fetch\?.+?)\1\)/g, (_match, g1, g2, _offset, _input) => {
changed = true;
return `url(${g1 || ''}${g2}&r=1${g1 || ''})`;
});
return changed ? newCssText : undefined;
this._logService.trace('SW', event.data);
}
}

View File

@@ -10,7 +10,7 @@
// statement.
// trigger service worker updates
const _tag = 'a6f9835e-c10e-4299-ab39-b8e29547c20a';
const _tag = '52278406-3ca9-48af-a8fb-8495add5bb4e';
// loader world
const baseUrl = '../../../../../';

View File

@@ -234,7 +234,7 @@ class DirtyDiffWidget extends PeekViewWidget {
const changeTypeColor = getChangeTypeColor(this.themeService.getTheme(), changeType);
this.style({ frameColor: changeTypeColor, arrowColor: changeTypeColor });
this._actionbarWidget.context = [this.model.modified!.uri, this.model.changes, index];
this._actionbarWidget!.context = [this.model.modified!.uri, this.model.changes, index];
this.show(position, height);
this.editor.focus();
}
@@ -255,11 +255,11 @@ class DirtyDiffWidget extends PeekViewWidget {
this._disposables.add(previous);
this._disposables.add(next);
this._actionbarWidget.push([previous, next], { label: false, icon: true });
this._actionbarWidget!.push([previous, next], { label: false, icon: true });
const actions: IAction[] = [];
this._disposables.add(createAndFillInActionBarActions(this.menu, { shouldForwardArgs: true }, actions));
this._actionbarWidget.push(actions, { label: false, icon: true });
this._actionbarWidget!.push(actions, { label: false, icon: true });
}
protected _getActionBarOptions(): IActionBarOptions {

View File

@@ -13,10 +13,10 @@ import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions } fro
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { StatusUpdater, StatusBarController } from './scmActivity';
import { SCMStatusController } from './scmActivity';
import { SCMViewlet } from 'vs/workbench/contrib/scm/browser/scmViewlet';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry';
import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { ICommandService } from 'vs/platform/commands/common/commands';
@@ -48,10 +48,7 @@ Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets).registerViewlet(new Vie
));
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench)
.registerWorkbenchContribution(StatusUpdater, LifecyclePhase.Restored);
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench)
.registerWorkbenchContribution(StatusBarController, LifecyclePhase.Restored);
.registerWorkbenchContribution(SCMStatusController, LifecyclePhase.Restored);
// Register Action to Open Viewlet
Registry.as<IWorkbenchActionRegistry>(WorkbenchActionExtensions.WorkbenchActions).registerWorkbenchAction(
@@ -70,10 +67,11 @@ Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration).regis
order: 5,
title: localize('scmConfigurationTitle', "SCM"),
type: 'object',
scope: ConfigurationScope.RESOURCE,
properties: {
'scm.alwaysShowProviders': {
type: 'boolean',
description: localize('alwaysShowProviders', "Controls whether to always show the Source Control Provider section."),
description: localize('alwaysShowProviders', "Controls whether to show the Source Control Provider section even when there's only one Provider registered."),
default: false
},
'scm.providers.visible': {
@@ -97,6 +95,17 @@ Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration).regis
type: 'boolean',
description: localize('alwaysShowActions', "Controls whether inline actions are always visible in the Source Control view."),
default: false
},
'scm.countBadge': {
type: 'string',
enum: ['all', 'focused', 'off'],
enumDescriptions: [
localize('scm.countBadge.all', "Show the sum of all Source Control Providers count badges."),
localize('scm.countBadge.focused', "Show the count badge of the focused Source Control Provider."),
localize('scm.countBadge.off', "Disable the Source Control count badge.")
],
description: localize('scm.countBadge', "Controls the Source Control count badge."),
default: 'all'
}
}
});

View File

@@ -14,92 +14,45 @@ import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/c
import { IStatusbarService, StatusbarAlignment as MainThreadStatusBarAlignment } from 'vs/platform/statusbar/common/statusbar';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { commonPrefixLength } from 'vs/base/common/strings';
import { ILogService } from 'vs/platform/log/common/log';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
export class StatusUpdater implements IWorkbenchContribution {
private readonly badgeDisposable = new MutableDisposable<IDisposable>();
private disposables: IDisposable[] = [];
constructor(
@ISCMService private readonly scmService: ISCMService,
@IActivityService private readonly activityService: IActivityService,
@ILogService private readonly logService: ILogService
) {
for (const repository of this.scmService.repositories) {
this.onDidAddRepository(repository);
}
this.scmService.onDidAddRepository(this.onDidAddRepository, this, this.disposables);
this.render();
}
private onDidAddRepository(repository: ISCMRepository): void {
const provider = repository.provider;
const onDidChange = Event.any(provider.onDidChange, provider.onDidChangeResources);
const changeDisposable = onDidChange(() => this.render());
const onDidRemove = Event.filter(this.scmService.onDidRemoveRepository, e => e === repository);
const removeDisposable = onDidRemove(() => {
disposable.dispose();
this.disposables = this.disposables.filter(d => d !== removeDisposable);
this.render();
});
const disposable = combinedDisposable(changeDisposable, removeDisposable);
this.disposables.push(disposable);
}
private render(): void {
this.badgeDisposable.clear();
const count = this.scmService.repositories.reduce((r, repository) => {
if (typeof repository.provider.count === 'number') {
return r + repository.provider.count;
} else {
return r + repository.provider.groups.elements.reduce<number>((r, g) => r + g.elements.length, 0);
}
}, 0);
// TODO@joao: remove
this.logService.trace('SCM#StatusUpdater.render', count);
if (count > 0) {
const badge = new NumberBadge(count, num => localize('scmPendingChangesBadge', '{0} pending changes', num));
this.badgeDisposable.value = this.activityService.showActivity(VIEWLET_ID, badge, 'scm-viewlet-label');
} else {
this.badgeDisposable.clear();
}
}
dispose(): void {
this.badgeDisposable.dispose();
this.disposables = dispose(this.disposables);
function getCount(repository: ISCMRepository): number {
if (typeof repository.provider.count === 'number') {
return repository.provider.count;
} else {
return repository.provider.groups.elements.reduce<number>((r, g) => r + g.elements.length, 0);
}
}
export class StatusBarController implements IWorkbenchContribution {
export class SCMStatusController implements IWorkbenchContribution {
private statusBarDisposable: IDisposable = Disposable.None;
private focusDisposable: IDisposable = Disposable.None;
private focusedRepository: ISCMRepository | undefined = undefined;
private focusedProviderContextKey: IContextKey<string | undefined>;
private readonly badgeDisposable = new MutableDisposable<IDisposable>();
private disposables: IDisposable[] = [];
constructor(
@ISCMService private readonly scmService: ISCMService,
@IStatusbarService private readonly statusbarService: IStatusbarService,
@IContextKeyService contextKeyService: IContextKeyService,
@IEditorService private readonly editorService: IEditorService
@IContextKeyService readonly contextKeyService: IContextKeyService,
@IActivityService private readonly activityService: IActivityService,
@IEditorService private readonly editorService: IEditorService,
@IConfigurationService private readonly configurationService: IConfigurationService
) {
this.focusedProviderContextKey = contextKeyService.createKey<string | undefined>('scmProvider', undefined);
this.scmService.onDidAddRepository(this.onDidAddRepository, this, this.disposables);
const onDidChangeSCMCountBadge = Event.filter(configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('scm.countBadge'));
onDidChangeSCMCountBadge(this.renderActivityCount, this, this.disposables);
for (const repository of this.scmService.repositories) {
this.onDidAddRepository(repository);
}
editorService.onDidActiveEditorChange(this.onDidActiveEditorChange, this, this.disposables);
this.renderActivityCount();
}
private onDidActiveEditorChange(): void {
@@ -138,7 +91,11 @@ export class StatusBarController implements IWorkbenchContribution {
}
private onDidAddRepository(repository: ISCMRepository): void {
const changeDisposable = repository.onDidFocus(() => this.onDidFocusRepository(repository));
const focusDisposable = repository.onDidFocus(() => this.onDidFocusRepository(repository));
const onDidChange = Event.any(repository.provider.onDidChange, repository.provider.onDidChangeResources);
const changeDisposable = onDidChange(() => this.renderActivityCount());
const onDidRemove = Event.filter(this.scmService.onDidRemoveRepository, e => e === repository);
const removeDisposable = onDidRemove(() => {
disposable.dispose();
@@ -149,9 +106,11 @@ export class StatusBarController implements IWorkbenchContribution {
} else if (this.focusedRepository === repository) {
this.scmService.repositories[0].focus();
}
this.renderActivityCount();
});
const disposable = combinedDisposable(changeDisposable, removeDisposable);
const disposable = combinedDisposable(focusDisposable, changeDisposable, removeDisposable);
this.disposables.push(disposable);
if (!this.focusedRepository) {
@@ -169,13 +128,14 @@ export class StatusBarController implements IWorkbenchContribution {
this.focusDisposable.dispose();
if (repository && repository.provider.onDidChangeStatusBarCommands) {
this.focusDisposable = repository.provider.onDidChangeStatusBarCommands(() => this.render(repository));
this.focusDisposable = repository.provider.onDidChangeStatusBarCommands(() => this.renderStatusBar(repository));
}
this.render(repository);
this.renderStatusBar(repository);
this.renderActivityCount();
}
private render(repository: ISCMRepository | undefined): void {
private renderStatusBar(repository: ISCMRepository | undefined): void {
this.statusBarDisposable.dispose();
if (!repository) {
@@ -200,9 +160,31 @@ export class StatusBarController implements IWorkbenchContribution {
this.statusBarDisposable = disposables;
}
private renderActivityCount(): void {
this.badgeDisposable.clear();
const countBadgeType = this.configurationService.getValue<'all' | 'focused' | 'off'>('scm.countBadge');
let count = 0;
if (countBadgeType === 'all') {
count = this.scmService.repositories.reduce((r, repository) => r + getCount(repository), 0);
} else if (countBadgeType === 'focused' && this.focusedRepository) {
count = getCount(this.focusedRepository);
}
if (count > 0) {
const badge = new NumberBadge(count, num => localize('scmPendingChangesBadge', '{0} pending changes', num));
this.badgeDisposable.value = this.activityService.showActivity(VIEWLET_ID, badge, 'scm-viewlet-label');
} else {
this.badgeDisposable.clear();
}
}
dispose(): void {
this.focusDisposable.dispose();
this.statusBarDisposable.dispose();
this.badgeDisposable.dispose();
this.disposables = dispose(this.disposables);
}
}

View File

@@ -49,6 +49,7 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IViewsRegistry, IViewDescriptor, Extensions } from 'vs/workbench/common/views';
import { Registry } from 'vs/platform/registry/common/platform';
import { nextTick } from 'vs/base/common/process';
export interface ISpliceEvent<T> {
index: number;
@@ -324,7 +325,7 @@ export class MainPanel extends ViewletPanel {
}
private onListSelectionChange(e: IListEvent<ISCMRepository>): void {
if (e.elements.length > 0) {
if (e.browserEvent && e.elements.length > 0) {
const scrollTop = this.list.scrollTop;
this.viewModel.setVisibleRepositories(e.elements);
this.list.scrollTop = scrollTop;
@@ -332,7 +333,7 @@ export class MainPanel extends ViewletPanel {
}
private onListFocusChange(e: IListEvent<ISCMRepository>): void {
if (e.elements.length > 0) {
if (e.browserEvent && e.elements.length > 0) {
e.elements[0].focus();
}
}
@@ -797,7 +798,7 @@ export class RepositoryPanel extends ViewletPanel {
const triggerValidation = () => validationDelayer.trigger(validate);
this.inputBox = new InputBox(this.inputBoxContainer, this.contextViewService, { flexibleHeight: true });
this.inputBox = new InputBox(this.inputBoxContainer, this.contextViewService, { flexibleHeight: true, flexibleMaxHeight: 134 });
this.inputBox.setEnabled(this.isBodyVisible());
this._register(attachInputBoxStyler(this.inputBox, this.themeService));
this._register(this.inputBox);
@@ -896,11 +897,8 @@ export class RepositoryPanel extends ViewletPanel {
const listHeight = height - (editorHeight + 12 /* margin */);
this.listContainer.style.height = `${listHeight}px`;
this.list.layout(listHeight, width);
toggleClass(this.inputBoxContainer, 'scroll', editorHeight >= 134);
} else {
addClass(this.inputBoxContainer, 'hidden');
removeClass(this.inputBoxContainer, 'scroll');
this.listContainer.style.height = `${height}px`;
this.list.layout(height, width);
@@ -1105,6 +1103,9 @@ export class SCMViewlet extends ViewContainerViewlet implements IViewModel {
}
}
private readonly _onDidChangeRepositories = new Emitter<void>();
private readonly onDidFinishStartup = Event.once(Event.debounce(this._onDidChangeRepositories.event, () => null, 1000));
constructor(
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
@ITelemetryService telemetryService: ITelemetryService,
@@ -1133,6 +1134,9 @@ export class SCMViewlet extends ViewContainerViewlet implements IViewModel {
this.onDidChangeRepositories();
}
}));
this._register(this.onDidFinishStartup(this.onAfterStartup, this));
this._register(this.viewsModel.onDidRemove(this.onDidHideView, this));
}
create(parent: HTMLElement): void {
@@ -1193,20 +1197,28 @@ export class SCMViewlet extends ViewContainerViewlet implements IViewModel {
if (alwaysShowProviders && repositoryCount > 0) {
this.viewsModel.setVisible(MainPanel.ID, true);
} else if (!alwaysShowProviders && repositoryCount === 1) {
this.viewsModel.setVisible(MainPanel.ID, false);
} else if (this.repositoryCount < 2 && repositoryCount >= 2) {
this.viewsModel.setVisible(MainPanel.ID, true);
} else if (this.repositoryCount >= 2 && repositoryCount === 1) {
this.viewsModel.setVisible(MainPanel.ID, false);
}
if (repositoryCount === 1) {
this.viewsModel.setVisible(this.viewDescriptors[0].id, true);
}
toggleClass(this.el, 'empty', repositoryCount === 0);
this.repositoryCount = repositoryCount;
this._onDidChangeRepositories.fire();
}
private onAfterStartup(): void {
if (this.repositoryCount > 0 && this.viewDescriptors.every(d => !this.viewsModel.isVisible(d.id))) {
this.viewsModel.setVisible(this.viewDescriptors[0].id, true);
}
}
private onDidHideView(): void {
nextTick(() => {
if (this.repositoryCount > 0 && this.viewDescriptors.every(d => !this.viewsModel.isVisible(d.id))) {
const alwaysShowProviders = this.configurationService.getValue<boolean>('scm.alwaysShowProviders') || false;
this.viewsModel.setVisible(MainPanel.ID, alwaysShowProviders || this.repositoryCount > 1);
this.viewsModel.setVisible(this.viewDescriptors[0].id, true);
}
});
}
focus(): void {

View File

@@ -44,7 +44,7 @@ export class FileQuickOpenModel extends QuickOpenModel {
}
export class FileEntry extends EditorQuickOpenEntry {
private range: IRange | null;
private range: IRange | null = null;
constructor(
private resource: URI,
@@ -112,7 +112,7 @@ export interface IOpenFileOptions {
}
export class OpenFileHandler extends QuickOpenHandler {
private options: IOpenFileOptions;
private options: IOpenFileOptions | undefined;
private queryBuilder: QueryBuilder;
private cacheState: CacheState;
@@ -277,7 +277,7 @@ export class CacheState {
private query: IFileQuery;
private loadingPhase = LoadingPhase.Created;
private promise: Promise<void>;
private promise: Promise<void> | undefined;
constructor(cacheQuery: (cacheKey: string) => IFileQuery, private doLoad: (query: IFileQuery) => Promise<any>, private doDispose: (cacheKey: string) => Promise<void>, private previous: CacheState | null) {
this.query = cacheQuery(this._cacheKey);

View File

@@ -27,7 +27,7 @@ import { Schemas } from 'vs/base/common/network';
import { IOpenerService } from 'vs/platform/opener/common/opener';
class SymbolEntry extends EditorQuickOpenEntry {
private bearingResolve: Promise<this | undefined>;
private bearingResolve: Promise<this | undefined> | undefined;
constructor(
private bearing: IWorkspaceSymbol,

View File

@@ -14,7 +14,7 @@ import * as objects from 'vs/base/common/objects';
import { lcut } from 'vs/base/common/strings';
import { URI } from 'vs/base/common/uri';
import { Range } from 'vs/editor/common/core/range';
import { FindMatch, IModelDeltaDecoration, ITextModel, OverviewRulerLane, TrackedRangeStickiness } from 'vs/editor/common/model';
import { FindMatch, IModelDeltaDecoration, ITextModel, OverviewRulerLane, TrackedRangeStickiness, MinimapPosition } from 'vs/editor/common/model';
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
import { IModelService } from 'vs/editor/common/services/modelService';
import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
@@ -22,11 +22,12 @@ import { IProgress, IProgressStep } from 'vs/platform/progress/common/progress';
import { ReplacePattern } from 'vs/workbench/services/search/common/replace';
import { IFileMatch, IPatternInfo, ISearchComplete, ISearchProgressItem, ISearchService, ITextQuery, ITextSearchPreviewOptions, ITextSearchMatch, ITextSearchStats, resultIsMatch, ISearchRange, OneLineRange } from 'vs/workbench/services/search/common/search';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { overviewRulerFindMatchForeground } from 'vs/platform/theme/common/colorRegistry';
import { overviewRulerFindMatchForeground, minimapFindMatch } from 'vs/platform/theme/common/colorRegistry';
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';
import { memoize } from 'vs/base/common/decorators';
export class Match {
@@ -74,6 +75,7 @@ export class Match {
return this._range;
}
@memoize
preview(): { before: string; inside: string; after: string; } {
let before = this._oneLinePreviewText.substring(0, this._rangeInPreviewText.startColumn - 1),
inside = this.getMatchString(),
@@ -155,6 +157,10 @@ export class FileMatch extends Disposable implements IFileMatch {
overviewRuler: {
color: themeColorFromId(overviewRulerFindMatchForeground),
position: OverviewRulerLane.Center
},
minimap: {
color: themeColorFromId(minimapFindMatch),
position: MinimapPosition.Inline
}
});
@@ -164,6 +170,10 @@ export class FileMatch extends Disposable implements IFileMatch {
overviewRuler: {
color: themeColorFromId(overviewRulerFindMatchForeground),
position: OverviewRulerLane.Center
},
minimap: {
color: themeColorFromId(minimapFindMatch),
position: MinimapPosition.Inline
}
});
@@ -713,11 +723,19 @@ export class SearchResult extends Disposable {
this.disposeMatches();
}
remove(matches: FileMatch | FileMatch[]): void {
remove(matches: FileMatch | FolderMatch | (FileMatch | FolderMatch)[]): void {
if (!Array.isArray(matches)) {
matches = [matches];
}
matches.forEach(m => {
if (m instanceof FolderMatch) {
m.clear();
}
});
matches = matches.filter(m => m instanceof FileMatch);
const { byFolder, other } = this.groupFilesByFolder(matches);
byFolder.forEach(matches => {
if (!matches.length) {
@@ -732,10 +750,6 @@ export class SearchResult extends Disposable {
}
}
removeFolder(match: FolderMatch): void {
match.clear();
}
replace(match: FileMatch): Promise<any> {
return this.getFolderMatch(match.resource).replace(match);
}

View File

@@ -21,7 +21,7 @@ export class SnippetCompletion implements CompletionItem {
label: string;
detail: string;
insertText: string;
documentation: MarkdownString;
documentation?: MarkdownString;
range: IRange;
sortText: string;
kind: CompletionItemKind;

View File

@@ -31,8 +31,8 @@ export class TabCompletionController implements editorCommon.IEditorContribution
private _hasSnippets: IContextKey<boolean>;
private _activeSnippets: Snippet[] = [];
private _enabled: boolean;
private _selectionListener: IDisposable;
private _enabled?: boolean;
private _selectionListener?: IDisposable;
private readonly _configListener: IDisposable;
constructor(

View File

@@ -32,8 +32,8 @@ class PartsSplash {
private readonly _disposables = new DisposableStore();
private _didChangeTitleBarStyle: boolean;
private _lastBaseTheme: string;
private _didChangeTitleBarStyle?: boolean;
private _lastBaseTheme?: string;
private _lastBackground?: string;
constructor(

View File

@@ -15,6 +15,7 @@ import { endsWith } from 'vs/base/common/strings';
import { ITextFileService, } from 'vs/workbench/services/textfile/common/textfiles';
import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService';
import { IWorkspaceStatsService, Tags } from 'vs/workbench/contrib/stats/electron-browser/workspaceStatsService';
import { IWorkspaceInformation } from 'vs/platform/diagnostics/common/diagnosticsService';
const SshProtocolMatcher = /^([^@:]+@)?([^:]+):/;
const SshUrlMatcher = /^([^@:]+@)?([^:]+):(.+)$/;
@@ -175,10 +176,20 @@ export class WorkspaceStats implements IWorkbenchContribution {
this.reportProxyStats();
const diagnosticsChannel = this.sharedProcessService.getChannel('diagnostics');
diagnosticsChannel.call('reportWorkspaceStats', this.contextService.getWorkspace());
diagnosticsChannel.call('reportWorkspaceStats', this.getWorkspaceInformation());
}
private getWorkspaceInformation(): IWorkspaceInformation {
const workspace = this.contextService.getWorkspace();
const state = this.contextService.getWorkbenchState();
const id = this.workspaceStatsService.getTelemetryWorkspaceId(workspace, state);
return {
id: workspace.id,
telemetryId: id,
folders: workspace.folders,
configuration: workspace.configuration
};
}
private reportWorkspaceTags(tags: Tags): void {
/* __GDPR__

View File

@@ -5,7 +5,7 @@
import * as crypto from 'crypto';
import { IFileService, IResolveFileResult, IFileStat } from 'vs/platform/files/common/files';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { IWorkspaceContextService, WorkbenchState, IWorkspace } from 'vs/platform/workspace/common/workspace';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { IWindowService, IWindowConfiguration } from 'vs/platform/windows/common/windows';
import { INotificationService, IPromptChoice } from 'vs/platform/notification/common/notification';
@@ -19,6 +19,7 @@ import { localize } from 'vs/nls';
import Severity from 'vs/base/common/severity';
import { joinPath } from 'vs/base/common/resources';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
export type Tags = { [index: string]: boolean | number | string | undefined };
@@ -97,6 +98,12 @@ export const IWorkspaceStatsService = createDecorator<IWorkspaceStatsService>('w
export interface IWorkspaceStatsService {
_serviceBrand: any;
getTags(): Promise<Tags>;
/**
* Returns an id for the workspace, different from the id returned by the context service. A hash based
* on the folder uri or workspace configuration, not time-based, and undefined for empty workspaces.
*/
getTelemetryWorkspaceId(workspace: IWorkspace, state: WorkbenchState): string | undefined;
}
@@ -123,6 +130,28 @@ export class WorkspaceStatsService implements IWorkspaceStatsService {
return this._tags;
}
public getTelemetryWorkspaceId(workspace: IWorkspace, state: WorkbenchState): string | undefined {
function createHash(uri: URI): string {
return crypto.createHash('sha1').update(uri.scheme === Schemas.file ? uri.fsPath : uri.toString()).digest('hex');
}
let workspaceId: string | undefined;
switch (state) {
case WorkbenchState.EMPTY:
workspaceId = undefined;
break;
case WorkbenchState.FOLDER:
workspaceId = createHash(workspace.folders[0].uri);
break;
case WorkbenchState.WORKSPACE:
if (workspace.configuration) {
workspaceId = createHash(workspace.configuration);
}
}
return workspaceId;
}
/* __GDPR__FRAGMENT__
"WorkspaceTags" : {
"workbench.filesToOpenOrCreate" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
@@ -225,25 +254,7 @@ export class WorkspaceStatsService implements IWorkspaceStatsService {
const state = this.contextService.getWorkbenchState();
const workspace = this.contextService.getWorkspace();
function createHash(uri: URI): string {
return crypto.createHash('sha1').update(uri.scheme === Schemas.file ? uri.fsPath : uri.toString()).digest('hex');
}
let workspaceId: string | undefined;
switch (state) {
case WorkbenchState.EMPTY:
workspaceId = undefined;
break;
case WorkbenchState.FOLDER:
workspaceId = createHash(workspace.folders[0].uri);
break;
case WorkbenchState.WORKSPACE:
if (workspace.configuration) {
workspaceId = createHash(workspace.configuration);
}
}
tags['workspace.id'] = workspaceId;
tags['workspace.id'] = this.getTelemetryWorkspaceId(workspace, state);
const { filesToOpenOrCreate, filesToDiff } = configuration;
tags['workbench.filesToOpenOrCreate'] = filesToOpenOrCreate && filesToOpenOrCreate.length || 0;
@@ -503,3 +514,5 @@ export class WorkspaceStatsService implements IWorkspaceStatsService {
return arr.some(v => v.search(regEx) > -1) || undefined;
}
}
registerSingleton(IWorkspaceStatsService, WorkspaceStatsService, true);

Some files were not shown because too many files have changed in this diff Show More