mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-04-01 09:30:31 -04:00
Merge from vscode 52dcb723a39ae75bee1bd56b3312d7fcdc87aeed (#6719)
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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;
|
||||
}
|
||||
@@ -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}; }`);
|
||||
}
|
||||
});
|
||||
@@ -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' } });
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 => {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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) { }
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
|
||||
@@ -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>();
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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>;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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."));
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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());
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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}; }`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>();
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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 }
|
||||
})));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,6 +114,7 @@ export interface IFilesConfiguration extends IFilesConfiguration, IWorkbenchEdit
|
||||
colors: boolean;
|
||||
badges: boolean;
|
||||
};
|
||||
incrementalNaming: 'simple' | 'smart';
|
||||
};
|
||||
editor: IEditorOptions;
|
||||
}
|
||||
|
||||
@@ -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');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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'));
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.*']
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -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';
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
|
||||
});
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 = '../../../../../';
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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__
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user