mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 18:46:40 -05:00
Merge from vscode 777931080477e28b7c27e8f7d4b0d69897945946 (#9220)
This commit is contained in:
@@ -25,6 +25,7 @@ import { basename } from 'vs/base/common/resources';
|
||||
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
|
||||
import { WorkspaceFileEdit } from 'vs/editor/common/modes';
|
||||
import { compare } from 'vs/base/common/strings';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
||||
// --- VIEW MODEL
|
||||
|
||||
@@ -420,6 +421,12 @@ export class CategoryElementRenderer implements ITreeRenderer<CategoryElement, F
|
||||
const className = ThemeIcon.asClassName(metadata.iconPath);
|
||||
template.icon.className = className ? `theme-icon ${className}` : '';
|
||||
|
||||
} else if (URI.isUri(metadata.iconPath)) {
|
||||
// background-image
|
||||
template.icon.className = 'uri-icon';
|
||||
template.icon.style.setProperty('--background-dark', `url("${metadata.iconPath.toString(true)}")`);
|
||||
template.icon.style.setProperty('--background-light', `url("${metadata.iconPath.toString(true)}")`);
|
||||
|
||||
} else if (metadata.iconPath) {
|
||||
// background-image
|
||||
template.icon.className = 'uri-icon';
|
||||
|
||||
@@ -7,7 +7,7 @@ import { coalesce } from 'vs/base/common/arrays';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { Lazy } from 'vs/base/common/lazy';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { basename, isEqual } from 'vs/base/common/resources';
|
||||
import { basename, isEqual, extname } from 'vs/base/common/resources';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import * as nls from 'vs/nls';
|
||||
@@ -180,21 +180,62 @@ export class CustomEditorService extends Disposable implements ICustomEditorServ
|
||||
}
|
||||
}
|
||||
|
||||
const resourceExt = extname(resource);
|
||||
|
||||
const items = customEditors.allEditors.map((editorDescriptor): IQuickPickItem => ({
|
||||
label: editorDescriptor.displayName,
|
||||
id: editorDescriptor.id,
|
||||
description: editorDescriptor.id === currentlyOpenedEditorType
|
||||
? nls.localize('openWithCurrentlyActive', "Currently Active")
|
||||
: undefined
|
||||
: undefined,
|
||||
buttons: resourceExt ? [{
|
||||
iconClass: 'codicon-settings-gear',
|
||||
tooltip: nls.localize('promptOpenWith.setDefaultTooltip', "Set as default editor for '{0}' files", resourceExt)
|
||||
}] : undefined
|
||||
}));
|
||||
const pick = await this.quickInputService.pick(items, {
|
||||
placeHolder: nls.localize('promptOpenWith.placeHolder', "Select editor to use for '{0}'...", basename(resource)),
|
||||
|
||||
const picker = this.quickInputService.createQuickPick();
|
||||
picker.items = items;
|
||||
picker.placeholder = nls.localize('promptOpenWith.placeHolder', "Select editor to use for '{0}'...", basename(resource));
|
||||
|
||||
const pick = await new Promise<string | undefined>(resolve => {
|
||||
picker.onDidAccept(() => {
|
||||
resolve(picker.selectedItems.length === 1 ? picker.selectedItems[0].id : undefined);
|
||||
picker.dispose();
|
||||
});
|
||||
picker.onDidTriggerItemButton(e => {
|
||||
const pick = e.item.id;
|
||||
resolve(pick); // open the view
|
||||
picker.dispose();
|
||||
|
||||
// And persist the setting
|
||||
if (pick) {
|
||||
const newAssociation: CustomEditorAssociation = { viewType: pick, filenamePattern: '*' + resourceExt };
|
||||
const currentAssociations = [...this.configurationService.getValue<CustomEditorsAssociations>(customEditorsAssociationsKey)] || [];
|
||||
|
||||
// First try updating existing association
|
||||
for (let i = 0; i < currentAssociations.length; ++i) {
|
||||
const existing = currentAssociations[i];
|
||||
if (existing.filenamePattern === newAssociation.filenamePattern) {
|
||||
currentAssociations.splice(i, 1, newAssociation);
|
||||
this.configurationService.updateValue(customEditorsAssociationsKey, currentAssociations);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, create a new one
|
||||
currentAssociations.unshift(newAssociation);
|
||||
this.configurationService.updateValue(customEditorsAssociationsKey, currentAssociations);
|
||||
}
|
||||
});
|
||||
picker.show();
|
||||
});
|
||||
|
||||
if (!pick || !pick.id) {
|
||||
if (!pick) {
|
||||
return undefined; // {{SQL CARBON EDIT}} strict-null-check
|
||||
}
|
||||
return this.openWith(resource, pick.id, options, group);
|
||||
|
||||
return this.openWith(resource, pick, options, group);
|
||||
}
|
||||
|
||||
public openWith(
|
||||
@@ -312,7 +353,11 @@ export class CustomEditorService extends Disposable implements ICustomEditorServ
|
||||
|
||||
export const customEditorsAssociationsKey = 'workbench.experimental.editorAssociations';
|
||||
|
||||
export type CustomEditorsAssociations = readonly (CustomEditorSelector & { readonly viewType: string; })[];
|
||||
export type CustomEditorAssociation = CustomEditorSelector & {
|
||||
readonly viewType: string;
|
||||
};
|
||||
|
||||
export type CustomEditorsAssociations = readonly CustomEditorAssociation[];
|
||||
|
||||
export class CustomEditorContribution extends Disposable implements IWorkbenchContribution {
|
||||
constructor(
|
||||
|
||||
@@ -915,14 +915,13 @@ export class DebugSession implements IDebugSession {
|
||||
// Disconnects and clears state. Session can be initialized again for a new connection.
|
||||
private shutdown(): void {
|
||||
dispose(this.rawListeners);
|
||||
if (this.raw) {
|
||||
this.raw.disconnect();
|
||||
this.raw.dispose();
|
||||
this.raw = undefined;
|
||||
}
|
||||
this.fetchThreadsScheduler = undefined;
|
||||
this.model.clearThreads(this.getId(), true);
|
||||
if (this.raw) {
|
||||
const raw = this.raw;
|
||||
this.raw = undefined;
|
||||
raw.disconnect();
|
||||
raw.dispose();
|
||||
}
|
||||
this._onDidChangeState.fire();
|
||||
}
|
||||
|
||||
|
||||
@@ -13,31 +13,6 @@
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.debug-pane .debug-start-view {
|
||||
padding: 0 20px 0 20px;
|
||||
}
|
||||
|
||||
.debug-pane .debug-start-view .monaco-button,
|
||||
.debug-pane .debug-start-view .section {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.debug-pane .debug-start-view .top-section {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.debug-pane .debug-start-view .monaco-button {
|
||||
max-width: 260px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.debug-pane .debug-start-view .click {
|
||||
cursor: pointer;
|
||||
color: #007ACC;
|
||||
}
|
||||
|
||||
.monaco-workbench .debug-action.notification:after {
|
||||
content: '';
|
||||
width: 6px;
|
||||
|
||||
@@ -3,64 +3,33 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { Button } from 'vs/base/browser/ui/button/button';
|
||||
import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet';
|
||||
import { attachButtonStyler } from 'vs/platform/theme/common/styler';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IContextKeyService, RawContextKey, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { localize } from 'vs/nls';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { StartAction, ConfigureAction } from 'vs/workbench/contrib/debug/browser/debugActions';
|
||||
import { IDebugService } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { equals } from 'vs/base/common/arrays';
|
||||
import { IViewPaneOptions, ViewPane } from 'vs/workbench/browser/parts/views/viewPaneContainer';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IViewDescriptorService } from 'vs/workbench/common/views';
|
||||
import { IViewDescriptorService, IViewsRegistry, Extensions } from 'vs/workbench/common/views';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
const $ = dom.$;
|
||||
import { WorkbenchStateContext } from 'vs/workbench/browser/contextkeys';
|
||||
import { OpenFolderAction, OpenFileAction, OpenFileFolderAction } from 'vs/workbench/browser/actions/workspaceActions';
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
|
||||
interface DebugStartMetrics {
|
||||
debuggers?: string[];
|
||||
}
|
||||
type DebugStartMetricsClassification = {
|
||||
debuggers?: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
|
||||
};
|
||||
|
||||
function createClickElement(textContent: string, action: () => any): HTMLSpanElement {
|
||||
const clickElement = $('span.click');
|
||||
clickElement.textContent = textContent;
|
||||
clickElement.onclick = action;
|
||||
clickElement.tabIndex = 0;
|
||||
clickElement.onkeyup = (e) => {
|
||||
const keyboardEvent = new StandardKeyboardEvent(e);
|
||||
if (keyboardEvent.keyCode === KeyCode.Enter || (keyboardEvent.keyCode === KeyCode.Space)) {
|
||||
action();
|
||||
}
|
||||
};
|
||||
|
||||
return clickElement;
|
||||
}
|
||||
const CONTEXT_DEBUGGER_INTERESTED = new RawContextKey<boolean>('debuggerInterested', false);
|
||||
|
||||
export class StartView extends ViewPane {
|
||||
|
||||
static ID = 'workbench.debug.startView';
|
||||
static LABEL = localize('start', "Start");
|
||||
|
||||
private debugButton!: Button;
|
||||
private firstMessageContainer!: HTMLElement;
|
||||
private secondMessageContainer!: HTMLElement;
|
||||
private clickElement: HTMLElement | undefined;
|
||||
private debuggerLabels: string[] | undefined = undefined;
|
||||
private debuggerInterestedContext: IContextKey<boolean>;
|
||||
|
||||
constructor(
|
||||
options: IViewletViewOptions,
|
||||
@@ -69,125 +38,45 @@ export class StartView extends ViewPane {
|
||||
@IContextMenuService contextMenuService: IContextMenuService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@ICommandService private readonly commandService: ICommandService,
|
||||
@IDebugService private readonly debugService: IDebugService,
|
||||
@IEditorService private readonly editorService: IEditorService,
|
||||
@IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService,
|
||||
@IFileDialogService private readonly dialogService: IFileDialogService,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@IViewDescriptorService viewDescriptorService: IViewDescriptorService,
|
||||
@ITelemetryService private readonly telemetryService: ITelemetryService,
|
||||
@IOpenerService openerService: IOpenerService,
|
||||
) {
|
||||
super({ ...(options as IViewPaneOptions), ariaHeaderLabel: localize('debugStart', "Debug Start Section") }, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService);
|
||||
this._register(editorService.onDidActiveEditorChange(() => this.updateView()));
|
||||
this._register(this.debugService.getConfigurationManager().onDidRegisterDebugger(() => this.updateView()));
|
||||
|
||||
this.debuggerInterestedContext = CONTEXT_DEBUGGER_INTERESTED.bindTo(contextKeyService);
|
||||
const setContextKey = () => {
|
||||
const activeEditor = this.editorService.activeTextEditorWidget;
|
||||
const debuggerLabels = this.debugService.getConfigurationManager().getDebuggerLabelsForEditor(activeEditor);
|
||||
this.debuggerInterestedContext.set(debuggerLabels.length > 0);
|
||||
};
|
||||
this._register(editorService.onDidActiveEditorChange(setContextKey));
|
||||
this._register(this.debugService.getConfigurationManager().onDidRegisterDebugger(setContextKey));
|
||||
}
|
||||
|
||||
private updateView(): void {
|
||||
const activeEditor = this.editorService.activeTextEditorWidget;
|
||||
const debuggerLabels = this.debugService.getConfigurationManager().getDebuggerLabelsForEditor(activeEditor);
|
||||
if (!equals(this.debuggerLabels, debuggerLabels)) {
|
||||
this.debuggerLabels = debuggerLabels;
|
||||
const enabled = this.debuggerLabels.length > 0;
|
||||
|
||||
this.debugButton.enabled = enabled;
|
||||
const debugKeybinding = this.keybindingService.lookupKeybinding(StartAction.ID);
|
||||
let debugLabel = this.debuggerLabels.length !== 1 ? localize('debug', "Run and Debug") : localize('debugWith', "Run and Debug {0}", this.debuggerLabels[0]);
|
||||
if (debugKeybinding) {
|
||||
debugLabel += ` (${debugKeybinding.getLabel()})`;
|
||||
}
|
||||
this.debugButton.label = debugLabel;
|
||||
|
||||
const emptyWorkbench = this.workspaceContextService.getWorkbenchState() === WorkbenchState.EMPTY;
|
||||
this.firstMessageContainer.innerHTML = '';
|
||||
this.secondMessageContainer.innerHTML = '';
|
||||
const secondMessageElement = $('span');
|
||||
this.secondMessageContainer.appendChild(secondMessageElement);
|
||||
|
||||
const setSecondMessage = () => {
|
||||
secondMessageElement.textContent = localize('specifyHowToRun', "To customize Run and Debug");
|
||||
this.clickElement = createClickElement(localize('configure', " create a launch.json file."), () => {
|
||||
this.telemetryService.publicLog2<DebugStartMetrics, DebugStartMetricsClassification>('debugStart.configure', { debuggers: this.debuggerLabels });
|
||||
this.commandService.executeCommand(ConfigureAction.ID);
|
||||
});
|
||||
this.secondMessageContainer.appendChild(this.clickElement);
|
||||
};
|
||||
const setSecondMessageWithFolder = () => {
|
||||
secondMessageElement.textContent = localize('noLaunchConfiguration', "To customize Run and Debug, ");
|
||||
this.clickElement = createClickElement(localize('openFolder', " open a folder"), () => {
|
||||
this.telemetryService.publicLog2<DebugStartMetrics, DebugStartMetricsClassification>('debugStart.openFolder', { debuggers: this.debuggerLabels });
|
||||
this.dialogService.pickFolderAndOpen({ forceNewWindow: false });
|
||||
});
|
||||
this.secondMessageContainer.appendChild(this.clickElement);
|
||||
|
||||
const moreText = $('span.moreText');
|
||||
moreText.textContent = localize('andconfigure', " and create a launch.json file.");
|
||||
this.secondMessageContainer.appendChild(moreText);
|
||||
};
|
||||
|
||||
if (enabled && !emptyWorkbench) {
|
||||
setSecondMessage();
|
||||
}
|
||||
|
||||
if (enabled && emptyWorkbench) {
|
||||
setSecondMessageWithFolder();
|
||||
}
|
||||
|
||||
if (!enabled && !emptyWorkbench) {
|
||||
const firstMessageElement = $('span');
|
||||
this.firstMessageContainer.appendChild(firstMessageElement);
|
||||
firstMessageElement.textContent = localize('simplyDebugAndRun', "Open a file which can be debugged or run.");
|
||||
|
||||
setSecondMessage();
|
||||
}
|
||||
|
||||
if (!enabled && emptyWorkbench) {
|
||||
this.clickElement = createClickElement(localize('openFile', "Open a file"), () => {
|
||||
this.telemetryService.publicLog2<DebugStartMetrics, DebugStartMetricsClassification>('debugStart.openFile');
|
||||
this.dialogService.pickFileAndOpen({ forceNewWindow: false });
|
||||
});
|
||||
this.firstMessageContainer.appendChild(this.clickElement);
|
||||
const firstMessageElement = $('span');
|
||||
this.firstMessageContainer.appendChild(firstMessageElement);
|
||||
firstMessageElement.textContent = localize('canBeDebuggedOrRun', " which can be debugged or run.");
|
||||
|
||||
setSecondMessageWithFolder();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected renderBody(container: HTMLElement): void {
|
||||
super.renderBody(container);
|
||||
|
||||
this.firstMessageContainer = $('.top-section');
|
||||
container.appendChild(this.firstMessageContainer);
|
||||
|
||||
this.debugButton = new Button(container);
|
||||
this._register(this.debugButton.onDidClick(() => {
|
||||
this.commandService.executeCommand(StartAction.ID);
|
||||
this.telemetryService.publicLog2<DebugStartMetrics, DebugStartMetricsClassification>('debugStart.runAndDebug', { debuggers: this.debuggerLabels });
|
||||
}));
|
||||
attachButtonStyler(this.debugButton, this.themeService);
|
||||
|
||||
dom.addClass(this.element, 'debug-pane');
|
||||
dom.addClass(container, 'debug-start-view');
|
||||
|
||||
this.secondMessageContainer = $('.section');
|
||||
container.appendChild(this.secondMessageContainer);
|
||||
|
||||
this.updateView();
|
||||
}
|
||||
|
||||
protected layoutBody(_: number, __: number): void {
|
||||
// no-op
|
||||
}
|
||||
|
||||
focus(): void {
|
||||
if (this.debugButton.enabled) {
|
||||
this.debugButton.focus();
|
||||
} else if (this.clickElement) {
|
||||
this.clickElement.focus();
|
||||
}
|
||||
shouldShowWelcome(): boolean {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const viewsRegistry = Registry.as<IViewsRegistry>(Extensions.ViewsRegistry);
|
||||
viewsRegistry.registerViewWelcomeContent(StartView.ID, {
|
||||
content: localize('openAFileWhichCanBeDebugged', "[Open a file](command:{0}) which can be debugged or run.", isMacintosh ? OpenFileFolderAction.ID : OpenFileAction.ID),
|
||||
when: CONTEXT_DEBUGGER_INTERESTED.toNegated()
|
||||
});
|
||||
|
||||
viewsRegistry.registerViewWelcomeContent(StartView.ID, {
|
||||
content: localize('runAndDebugAction', "[Run and Debug](command:{0})", StartAction.ID)
|
||||
});
|
||||
|
||||
viewsRegistry.registerViewWelcomeContent(StartView.ID, {
|
||||
content: localize('customizeRunAndDebug', "To customize Run and Debug [create a launch.json file](command:{0}).", ConfigureAction.ID),
|
||||
when: WorkbenchStateContext.notEqualsTo('empty')
|
||||
});
|
||||
|
||||
viewsRegistry.registerViewWelcomeContent(StartView.ID, {
|
||||
content: localize('customizeRunAndDebugOpenFolder', "To customize Run and Debug, [open a folder](command:{0}) and create a launch.json file.", isMacintosh ? OpenFileFolderAction.ID : OpenFolderAction.ID),
|
||||
when: WorkbenchStateContext.isEqualTo('empty')
|
||||
});
|
||||
|
||||
@@ -1773,6 +1773,16 @@ declare module DebugProtocol {
|
||||
If missing the value 0 is assumed which results in the completion text being inserted.
|
||||
*/
|
||||
length?: number;
|
||||
/** Determines the start of the new selection after the text has been inserted (or replaced).
|
||||
The start position must in the range 0 and length of the completion text.
|
||||
If omitted the selection starts at the end of the completion text.
|
||||
*/
|
||||
selectionStart?: number;
|
||||
/** Determines the length of the new selection after the text has been inserted (or replaced).
|
||||
The selection can not extend beyond the bounds of the completion text.
|
||||
If omitted the length is assumed to be 0.
|
||||
*/
|
||||
selectionLength?: number;
|
||||
}
|
||||
|
||||
/** Some predefined types for the CompletionItem. Please note that not all clients have specific icons for all of them. */
|
||||
|
||||
@@ -14,7 +14,7 @@ import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions } fro
|
||||
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { IOutputChannelRegistry, Extensions as OutputExtensions } from 'vs/workbench/services/output/common/output';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { VIEWLET_ID, IExtensionsWorkbenchService, IExtensionsViewPaneContainer } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||
import { VIEWLET_ID, IExtensionsWorkbenchService, IExtensionsViewPaneContainer, TOGGLE_IGNORE_EXTENSION_ACTION_ID } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||
import { ExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/browser/extensionsWorkbenchService';
|
||||
import {
|
||||
OpenExtensionsViewletAction, InstallExtensionsAction, ShowOutdatedExtensionsAction, ShowRecommendedExtensionsAction, ShowRecommendedKeymapExtensionsAction, ShowPopularExtensionsAction,
|
||||
@@ -48,6 +48,8 @@ import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService
|
||||
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
|
||||
import { CONTEXT_SYNC_ENABLEMENT } from 'vs/platform/userDataSync/common/userDataSync';
|
||||
|
||||
// Singletons
|
||||
registerSingleton(IExtensionsWorkbenchService, ExtensionsWorkbenchService);
|
||||
@@ -443,6 +445,33 @@ registerAction2(class extends Action2 {
|
||||
}
|
||||
});
|
||||
|
||||
registerAction2(class extends Action2 {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: TOGGLE_IGNORE_EXTENSION_ACTION_ID,
|
||||
title: { value: localize('workbench.extensions.action.toggleIgnoreExtension', "Don't Sync This Extension"), original: `Don't Sync This Extension` },
|
||||
menu: {
|
||||
id: MenuId.ExtensionContext,
|
||||
group: '2_configure',
|
||||
when: CONTEXT_SYNC_ENABLEMENT
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async run(accessor: ServicesAccessor, id: string) {
|
||||
const configurationService = accessor.get(IConfigurationService);
|
||||
const ignoredExtensions = [...configurationService.getValue<string[]>('sync.ignoredExtensions')];
|
||||
const index = ignoredExtensions.findIndex(ignoredExtension => areSameExtensions({ id: ignoredExtension }, { id }));
|
||||
if (index !== -1) {
|
||||
ignoredExtensions.splice(index, 1);
|
||||
} else {
|
||||
ignoredExtensions.push(id);
|
||||
}
|
||||
return configurationService.updateValue('sync.ignoredExtensions', ignoredExtensions.length ? ignoredExtensions : undefined, ConfigurationTarget.USER);
|
||||
}
|
||||
});
|
||||
|
||||
const workbenchRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
|
||||
|
||||
class ExtensionsContributions implements IWorkbenchContribution {
|
||||
|
||||
@@ -13,7 +13,7 @@ import * as json from 'vs/base/common/json';
|
||||
import { ActionViewItem, Separator, IActionViewItemOptions } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { dispose, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IExtension, ExtensionState, IExtensionsWorkbenchService, VIEWLET_ID, IExtensionsViewPaneContainer, AutoUpdateConfigurationKey, IExtensionContainer, EXTENSIONS_CONFIG } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||
import { IExtension, ExtensionState, IExtensionsWorkbenchService, VIEWLET_ID, IExtensionsViewPaneContainer, AutoUpdateConfigurationKey, IExtensionContainer, EXTENSIONS_CONFIG, TOGGLE_IGNORE_EXTENSION_ACTION_ID } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||
import { ExtensionsConfigurationInitialContent } from 'vs/workbench/contrib/extensions/common/extensionsFileTemplate';
|
||||
import { ExtensionsLabel, IGalleryExtension, IExtensionGalleryService, INSTALL_ERROR_MALICIOUS, INSTALL_ERROR_INCOMPATIBLE, IGalleryExtensionVersion, ILocalExtension, INSTALL_ERROR_NOT_SUPPORTED } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { IWorkbenchExtensionEnablementService, EnablementState, IExtensionManagementServerService, IExtensionTipsService, IExtensionRecommendation, IExtensionsConfigContent, IExtensionManagementServer } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
||||
@@ -679,7 +679,7 @@ export class DropDownMenuActionViewItem extends ExtensionActionViewItem {
|
||||
}
|
||||
}
|
||||
|
||||
export function getContextMenuActions(menuService: IMenuService, contextKeyService: IContextKeyService, extension: IExtension | undefined | null): ExtensionAction[][] {
|
||||
export function getContextMenuActions(menuService: IMenuService, contextKeyService: IContextKeyService, instantiationService: IInstantiationService, extension: IExtension | undefined | null): ExtensionAction[][] {
|
||||
const scopedContextKeyService = contextKeyService.createScoped();
|
||||
if (extension) {
|
||||
scopedContextKeyService.createKey<boolean>('isBuiltinExtension', extension.type === ExtensionType.System);
|
||||
@@ -691,7 +691,7 @@ export function getContextMenuActions(menuService: IMenuService, contextKeyServi
|
||||
|
||||
const groups: ExtensionAction[][] = [];
|
||||
const menu = menuService.createMenu(MenuId.ExtensionContext, scopedContextKeyService);
|
||||
menu.getActions({ shouldForwardArgs: true }).forEach(([, actions]) => groups.push(actions.map(action => new MenuItemExtensionAction(action))));
|
||||
menu.getActions({ shouldForwardArgs: true }).forEach(([, actions]) => groups.push(actions.map(action => instantiationService.createInstance(MenuItemExtensionAction, action))));
|
||||
menu.dispose();
|
||||
|
||||
return groups;
|
||||
@@ -745,7 +745,7 @@ export class ManageExtensionAction extends ExtensionDropDownAction {
|
||||
groups.push([this.instantiationService.createInstance(UninstallAction)]);
|
||||
groups.push([this.instantiationService.createInstance(InstallAnotherVersionAction)]);
|
||||
|
||||
getContextMenuActions(this.menuService, this.contextKeyService, this.extension).forEach(actions => groups.push(actions));
|
||||
getContextMenuActions(this.menuService, this.contextKeyService, this.instantiationService, this.extension).forEach(actions => groups.push(actions));
|
||||
|
||||
groups.forEach(group => group.forEach(extensionAction => extensionAction.extension = this.extension));
|
||||
|
||||
@@ -773,11 +773,21 @@ export class ManageExtensionAction extends ExtensionDropDownAction {
|
||||
|
||||
export class MenuItemExtensionAction extends ExtensionAction {
|
||||
|
||||
constructor(private readonly action: IAction) {
|
||||
constructor(
|
||||
private readonly action: IAction,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService
|
||||
) {
|
||||
super(action.id, action.label);
|
||||
}
|
||||
|
||||
update() { }
|
||||
update() {
|
||||
if (!this.extension) {
|
||||
return;
|
||||
}
|
||||
if (this.action.id === TOGGLE_IGNORE_EXTENSION_ACTION_ID) {
|
||||
this.checked = this.configurationService.getValue<string[]>('sync.ignoredExtensions').some(id => areSameExtensions({ id }, this.extension!.identifier));
|
||||
}
|
||||
}
|
||||
|
||||
async run(): Promise<void> {
|
||||
if (this.extension) {
|
||||
|
||||
@@ -247,7 +247,7 @@ export class ExtensionsListView extends ViewPane {
|
||||
getActions: () => actions.slice(0, actions.length - 1)
|
||||
});
|
||||
} else if (e.element) {
|
||||
const groups = getContextMenuActions(this.menuService, this.contextKeyService.createScoped(), e.element);
|
||||
const groups = getContextMenuActions(this.menuService, this.contextKeyService.createScoped(), this.instantiationService, e.element);
|
||||
groups.forEach(group => group.forEach(extensionAction => extensionAction.extension = e.element!));
|
||||
let actions: IAction[] = [];
|
||||
for (const menuActions of groups) {
|
||||
|
||||
@@ -143,3 +143,5 @@ export class ExtensionContainers extends Disposable {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const TOGGLE_IGNORE_EXTENSION_ACTION_ID = 'workbench.extensions.action.toggleIgnoreExtension';
|
||||
|
||||
@@ -13,13 +13,15 @@ export class ExtensionsInput extends EditorInput {
|
||||
static readonly ID = 'workbench.extensions.input2';
|
||||
get extension(): IExtension { return this._extension; }
|
||||
|
||||
readonly resource = URI.from({
|
||||
scheme: 'extension',
|
||||
path: this.extension.identifier.id
|
||||
});
|
||||
get resource() {
|
||||
return URI.from({
|
||||
scheme: 'extension',
|
||||
path: this.extension.identifier.id
|
||||
});
|
||||
}
|
||||
|
||||
constructor(
|
||||
private _extension: IExtension,
|
||||
private readonly _extension: IExtension
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
@@ -16,10 +16,6 @@ export class RuntimeExtensionsInput extends EditorInput {
|
||||
path: 'default'
|
||||
});
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
getTypeId(): string {
|
||||
return RuntimeExtensionsInput.ID;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IEditorViewState } from 'vs/editor/common/editorCommon';
|
||||
import { toResource, SideBySideEditorInput, IWorkbenchEditorConfiguration, SideBySideEditor as SideBySideEditorChoice } from 'vs/workbench/common/editor';
|
||||
import { ITextFileService, ModelState } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { ITextFileService, TextFileEditorModelState } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { FileOperationEvent, FileOperation, IFileService, FileChangeType, FileChangesEvent, FileSystemProviderCapabilities } from 'vs/platform/files/common/files';
|
||||
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
|
||||
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
@@ -62,9 +62,9 @@ export class FileEditorTracker extends Disposable implements IWorkbenchContribut
|
||||
this._register(this.fileService.onDidFilesChange(e => this.onDidFilesChange(e)));
|
||||
|
||||
// Ensure dirty text file and untitled models are always opened as editors
|
||||
this._register(this.textFileService.files.onDidChangeDirty(m => this.ensureDirtyFilesAreOpenedWorker.work(m.resource)));
|
||||
this._register(this.textFileService.files.onDidSaveError(m => this.ensureDirtyFilesAreOpenedWorker.work(m.resource)));
|
||||
this._register(this.textFileService.untitled.onDidChangeDirty(r => this.ensureDirtyFilesAreOpenedWorker.work(r)));
|
||||
this._register(this.textFileService.files.onDidChangeDirty(model => this.ensureDirtyFilesAreOpenedWorker.work(model.resource)));
|
||||
this._register(this.textFileService.files.onDidSaveError(model => this.ensureDirtyFilesAreOpenedWorker.work(model.resource)));
|
||||
this._register(this.textFileService.untitled.onDidChangeDirty(model => this.ensureDirtyFilesAreOpenedWorker.work(model.resource)));
|
||||
|
||||
// Out of workspace file watchers
|
||||
this._register(this.editorService.onDidVisibleEditorsChange(() => this.onDidVisibleEditorsChange()));
|
||||
@@ -290,7 +290,7 @@ export class FileEditorTracker extends Disposable implements IWorkbenchContribut
|
||||
}
|
||||
|
||||
const model = this.textFileService.files.get(resource);
|
||||
if (model?.hasState(ModelState.PENDING_SAVE)) {
|
||||
if (model?.hasState(TextFileEditorModelState.PENDING_SAVE)) {
|
||||
return false; // resource must not be pending to save
|
||||
}
|
||||
|
||||
@@ -369,18 +369,14 @@ export class FileEditorTracker extends Disposable implements IWorkbenchContribut
|
||||
}
|
||||
|
||||
const model = this.textFileService.files.get(resource);
|
||||
if (!model) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (model.isDirty()) {
|
||||
if (!model || model.isDirty() || !model.isResolved()) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return model;
|
||||
})),
|
||||
model => model.resource.toString()
|
||||
).forEach(model => model.load());
|
||||
).forEach(model => this.textFileService.files.resolve(model.resource, { reload: { async: true } }));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import { isValidBasename } from 'vs/base/common/extpath';
|
||||
import { basename } from 'vs/base/common/resources';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { VIEWLET_ID, TEXT_FILE_EDITOR_ID, IExplorerService } from 'vs/workbench/contrib/files/common/files';
|
||||
import { ITextFileEditorModel, ITextFileService, TextFileOperationError, TextFileOperationResult } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { ITextFileService, TextFileOperationError, TextFileOperationResult } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { BaseTextEditor, IEditorConfiguration } from 'vs/workbench/browser/parts/editor/textEditor';
|
||||
import { EditorOptions, TextEditorOptions, IEditorCloseEvent } from 'vs/workbench/common/editor';
|
||||
import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel';
|
||||
@@ -135,7 +135,7 @@ export class TextFileEditor extends BaseTextEditor {
|
||||
return this.openAsBinary(input, options);
|
||||
}
|
||||
|
||||
const textFileModel = <ITextFileEditorModel>resolvedModel;
|
||||
const textFileModel = resolvedModel;
|
||||
|
||||
// Editor
|
||||
const textEditor = assertIsDefined(this.getControl());
|
||||
|
||||
@@ -221,13 +221,11 @@ class DoNotShowResolveConflictLearnMoreAction extends Action {
|
||||
super('workbench.files.action.resolveConflictLearnMoreDoNotShowAgain', nls.localize('dontShowAgain', "Don't Show Again"));
|
||||
}
|
||||
|
||||
run(notification: IDisposable): Promise<any> {
|
||||
async run(notification: IDisposable): Promise<any> {
|
||||
this.storageService.store(LEARN_MORE_DIRTY_WRITE_IGNORE_KEY, true, StorageScope.GLOBAL);
|
||||
|
||||
// Hide notification
|
||||
notification.dispose();
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,8 +260,6 @@ class ResolveSaveConflictAction extends Action {
|
||||
Event.once(handle.onDidClose)(() => dispose(actions.primary!));
|
||||
pendingResolveSaveConflictMessages.push(handle);
|
||||
}
|
||||
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,7 +272,7 @@ class SaveElevatedAction extends Action {
|
||||
super('workbench.files.action.saveElevated', triedToMakeWriteable ? isWindows ? nls.localize('overwriteElevated', "Overwrite as Admin...") : nls.localize('overwriteElevatedSudo', "Overwrite as Sudo...") : isWindows ? nls.localize('saveElevated', "Retry as Admin...") : nls.localize('saveElevatedSudo', "Retry as Sudo..."));
|
||||
}
|
||||
|
||||
run(): Promise<any> {
|
||||
async run(): Promise<any> {
|
||||
if (!this.model.isDisposed()) {
|
||||
this.model.save({
|
||||
writeElevated: true,
|
||||
@@ -284,8 +280,6 @@ class SaveElevatedAction extends Action {
|
||||
reason: SaveReason.EXPLICIT
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,12 +291,10 @@ class OverwriteReadonlyAction extends Action {
|
||||
super('workbench.files.action.overwrite', nls.localize('overwrite', "Overwrite"));
|
||||
}
|
||||
|
||||
run(): Promise<any> {
|
||||
async run(): Promise<any> {
|
||||
if (!this.model.isDisposed()) {
|
||||
this.model.save({ overwriteReadonly: true, reason: SaveReason.EXPLICIT });
|
||||
}
|
||||
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -314,12 +306,10 @@ class SaveIgnoreModifiedSinceAction extends Action {
|
||||
super('workbench.files.action.saveIgnoreModifiedSince', nls.localize('overwrite', "Overwrite"));
|
||||
}
|
||||
|
||||
run(): Promise<any> {
|
||||
async run(): Promise<any> {
|
||||
if (!this.model.isDisposed()) {
|
||||
this.model.save({ ignoreModifiedSince: true, reason: SaveReason.EXPLICIT });
|
||||
}
|
||||
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -331,10 +321,8 @@ class ConfigureSaveConflictAction extends Action {
|
||||
super('workbench.files.action.configureSaveConflict', nls.localize('configure', "Configure"));
|
||||
}
|
||||
|
||||
run(): Promise<any> {
|
||||
async run(): Promise<any> {
|
||||
this.preferencesService.openSettings(undefined, 'files.saveConflictResolution');
|
||||
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten
|
||||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IContextKeyService, IContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IViewsRegistry, IViewDescriptor, Extensions, ViewContainer, IViewContainersRegistry, ViewContainerLocation, IViewDescriptorService } from 'vs/workbench/common/views';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
@@ -34,6 +34,9 @@ import { KeyChord, KeyMod, KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { WorkbenchStateContext, RemoteNameContext, IsWebContext } from 'vs/workbench/browser/contextkeys';
|
||||
import { AddRootFolderAction, OpenFolderAction, OpenFileFolderAction } from 'vs/workbench/browser/actions/workspaceActions';
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
|
||||
export class ExplorerViewletViewsContribution extends Disposable implements IWorkbenchContribution {
|
||||
|
||||
@@ -61,6 +64,23 @@ export class ExplorerViewletViewsContribution extends Disposable implements IWor
|
||||
|
||||
private registerViews(): void {
|
||||
const viewsRegistry = Registry.as<IViewsRegistry>(Extensions.ViewsRegistry);
|
||||
|
||||
viewsRegistry.registerViewWelcomeContent(EmptyView.ID, {
|
||||
content: localize('noWorkspaceHelp', "You have not yet added a folder to the workspace.\n[Add Folder](command:{0})", AddRootFolderAction.ID),
|
||||
when: WorkbenchStateContext.isEqualTo('workspace')
|
||||
});
|
||||
|
||||
const commandId = isMacintosh ? OpenFileFolderAction.ID : OpenFolderAction.ID;
|
||||
viewsRegistry.registerViewWelcomeContent(EmptyView.ID, {
|
||||
content: localize('remoteNoFolderHelp', "Connected to remote.\n[Open Folder](command:{0})", commandId),
|
||||
when: ContextKeyExpr.and(WorkbenchStateContext.notEqualsTo('workspace'), RemoteNameContext.notEqualsTo(''), IsWebContext.toNegated())
|
||||
});
|
||||
|
||||
viewsRegistry.registerViewWelcomeContent(EmptyView.ID, {
|
||||
content: localize('noFolderHelp', "You have not yet opened a folder.\n[Open Folder](command:{0})", commandId),
|
||||
when: ContextKeyExpr.or(ContextKeyExpr.and(WorkbenchStateContext.notEqualsTo('workspace'), RemoteNameContext.isEqualTo('')), ContextKeyExpr.and(WorkbenchStateContext.notEqualsTo('workspace'), IsWebContext))
|
||||
});
|
||||
|
||||
const viewDescriptors = viewsRegistry.getViews(VIEW_CONTAINER);
|
||||
|
||||
let viewDescriptorsToRegister: IViewDescriptor[] = [];
|
||||
|
||||
@@ -166,7 +166,7 @@ export class GlobalNewUntitledFileAction extends Action {
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteFiles(workingCopyService: IWorkingCopyService, workingCopyFileService: IWorkingCopyFileService, dialogService: IDialogService, configurationService: IConfigurationService, elements: ExplorerItem[], useTrash: boolean, skipConfirm = false): Promise<void> {
|
||||
async function deleteFiles(workingCopyFileService: IWorkingCopyFileService, dialogService: IDialogService, configurationService: IConfigurationService, elements: ExplorerItem[], useTrash: boolean, skipConfirm = false): Promise<void> {
|
||||
let primaryButton: string;
|
||||
if (useTrash) {
|
||||
primaryButton = isWindows ? nls.localize('deleteButtonLabelRecycleBin', "&&Move to Recycle Bin") : nls.localize({ key: 'deleteButtonLabelTrash', comment: ['&& denotes a mnemonic'] }, "&&Move to Trash");
|
||||
@@ -174,20 +174,24 @@ async function deleteFiles(workingCopyService: IWorkingCopyService, workingCopyF
|
||||
primaryButton = nls.localize({ key: 'deleteButtonLabel', comment: ['&& denotes a mnemonic'] }, "&&Delete");
|
||||
}
|
||||
|
||||
const distinctElements = resources.distinctParents(elements, e => e.resource);
|
||||
|
||||
// Handle dirty
|
||||
const distinctElements = resources.distinctParents(elements, e => e.resource);
|
||||
const dirtyWorkingCopies = new Set<IWorkingCopy>();
|
||||
for (const distinctElement of distinctElements) {
|
||||
for (const dirtyWorkingCopy of workingCopyFileService.getDirty(distinctElement.resource)) {
|
||||
dirtyWorkingCopies.add(dirtyWorkingCopy);
|
||||
}
|
||||
}
|
||||
let confirmed = true;
|
||||
const dirtyWorkingCopies = workingCopyService.dirtyWorkingCopies.filter(workingCopy => distinctElements.some(e => resources.isEqualOrParent(workingCopy.resource, e.resource)));
|
||||
if (dirtyWorkingCopies.length) {
|
||||
if (dirtyWorkingCopies.size) {
|
||||
let message: string;
|
||||
if (distinctElements.length > 1) {
|
||||
message = nls.localize('dirtyMessageFilesDelete', "You are deleting files with unsaved changes. Do you want to continue?");
|
||||
} else if (distinctElements[0].isDirectory) {
|
||||
if (dirtyWorkingCopies.length === 1) {
|
||||
if (dirtyWorkingCopies.size === 1) {
|
||||
message = nls.localize('dirtyMessageFolderOneDelete', "You are deleting a folder {0} with unsaved changes in 1 file. Do you want to continue?", distinctElements[0].name);
|
||||
} else {
|
||||
message = nls.localize('dirtyMessageFolderDelete', "You are deleting a folder {0} with unsaved changes in {1} files. Do you want to continue?", distinctElements[0].name, dirtyWorkingCopies.length);
|
||||
message = nls.localize('dirtyMessageFolderDelete', "You are deleting a folder {0} with unsaved changes in {1} files. Do you want to continue?", distinctElements[0].name, dirtyWorkingCopies.size);
|
||||
}
|
||||
} else {
|
||||
message = nls.localize('dirtyMessageFileDelete', "You are deleting {0} with unsaved changes. Do you want to continue?", distinctElements[0].name);
|
||||
@@ -204,7 +208,6 @@ async function deleteFiles(workingCopyService: IWorkingCopyService, workingCopyF
|
||||
confirmed = false;
|
||||
} else {
|
||||
skipConfirm = true;
|
||||
await Promise.all(dirtyWorkingCopies.map(dirty => dirty.revert()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,7 +299,7 @@ async function deleteFiles(workingCopyService: IWorkingCopyService, workingCopyF
|
||||
|
||||
skipConfirm = true;
|
||||
|
||||
return deleteFiles(workingCopyService, workingCopyFileService, dialogService, configurationService, elements, useTrash, skipConfirm);
|
||||
return deleteFiles(workingCopyFileService, dialogService, configurationService, elements, useTrash, skipConfirm);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -989,7 +992,7 @@ export const moveFileToTrashHandler = async (accessor: ServicesAccessor) => {
|
||||
const explorerService = accessor.get(IExplorerService);
|
||||
const stats = explorerService.getContext(true).filter(s => !s.isRoot);
|
||||
if (stats.length) {
|
||||
await deleteFiles(accessor.get(IWorkingCopyService), accessor.get(IWorkingCopyFileService), accessor.get(IDialogService), accessor.get(IConfigurationService), stats, true);
|
||||
await deleteFiles(accessor.get(IWorkingCopyFileService), accessor.get(IDialogService), accessor.get(IConfigurationService), stats, true);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -998,7 +1001,7 @@ export const deleteFileHandler = async (accessor: ServicesAccessor) => {
|
||||
const stats = explorerService.getContext(true).filter(s => !s.isRoot);
|
||||
|
||||
if (stats.length) {
|
||||
await deleteFiles(accessor.get(IWorkingCopyService), accessor.get(IWorkingCopyFileService), accessor.get(IDialogService), accessor.get(IConfigurationService), stats, false);
|
||||
await deleteFiles(accessor.get(IWorkingCopyFileService), accessor.get(IDialogService), accessor.get(IConfigurationService), stats, false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -66,17 +66,6 @@
|
||||
border-radius: 0; /* goes better when ellipsis shows up on narrow sidebar */
|
||||
}
|
||||
|
||||
.explorer-viewlet .explorer-empty-view {
|
||||
padding: 0 20px 0 20px;
|
||||
}
|
||||
|
||||
.explorer-viewlet .explorer-empty-view .monaco-button {
|
||||
max-width: 260px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.explorer-viewlet .explorer-item.nonexistent-root {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
@@ -4,13 +4,8 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { Button } from 'vs/base/browser/ui/button/button';
|
||||
import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { OpenFolderAction, AddRootFolderAction } from 'vs/workbench/browser/actions/workspaceActions';
|
||||
import { attachButtonStyler } from 'vs/platform/theme/common/styler';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
@@ -20,10 +15,7 @@ import { ViewPane, IViewPaneOptions } from 'vs/workbench/browser/parts/views/vie
|
||||
import { ResourcesDropHandler, DragAndDropObserver } from 'vs/workbench/browser/dnd';
|
||||
import { listDropBackground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { isWeb } from 'vs/base/common/platform';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IViewDescriptorService } from 'vs/workbench/common/views';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
@@ -33,9 +25,6 @@ export class EmptyView extends ViewPane {
|
||||
static readonly ID: string = 'workbench.explorer.emptyView';
|
||||
static readonly NAME = nls.localize('noWorkspace', "No Folder Opened");
|
||||
|
||||
private button!: Button;
|
||||
private messageElement!: HTMLElement;
|
||||
|
||||
constructor(
|
||||
options: IViewletViewOptions,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@@ -45,55 +34,31 @@ export class EmptyView extends ViewPane {
|
||||
@IContextMenuService contextMenuService: IContextMenuService,
|
||||
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@IWorkbenchEnvironmentService private environmentService: IWorkbenchEnvironmentService,
|
||||
@ILabelService private labelService: ILabelService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IOpenerService openerService: IOpenerService
|
||||
) {
|
||||
super({ ...(options as IViewPaneOptions), ariaHeaderLabel: nls.localize('explorerSection', "Explorer Section: No Folder Opened") }, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService);
|
||||
this._register(this.contextService.onDidChangeWorkbenchState(() => this.setLabels()));
|
||||
this._register(this.labelService.onDidChangeFormatters(() => this.setLabels()));
|
||||
|
||||
this._register(this.contextService.onDidChangeWorkbenchState(() => this.refreshTitle()));
|
||||
this._register(this.labelService.onDidChangeFormatters(() => this.refreshTitle()));
|
||||
}
|
||||
|
||||
shouldShowWelcome(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected renderBody(container: HTMLElement): void {
|
||||
super.renderBody(container);
|
||||
|
||||
DOM.addClass(container, 'explorer-empty-view');
|
||||
container.tabIndex = 0;
|
||||
|
||||
const messageContainer = document.createElement('div');
|
||||
DOM.addClass(messageContainer, 'section');
|
||||
container.appendChild(messageContainer);
|
||||
|
||||
this.messageElement = document.createElement('p');
|
||||
messageContainer.appendChild(this.messageElement);
|
||||
|
||||
this.button = new Button(messageContainer);
|
||||
attachButtonStyler(this.button, this.themeService);
|
||||
|
||||
this._register(this.button.onDidClick(() => {
|
||||
if (!this.actionRunner) {
|
||||
return;
|
||||
}
|
||||
const action = this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE
|
||||
? this.instantiationService.createInstance(AddRootFolderAction, AddRootFolderAction.ID, AddRootFolderAction.LABEL)
|
||||
: this.instantiationService.createInstance(OpenFolderAction, OpenFolderAction.ID, OpenFolderAction.LABEL);
|
||||
this.actionRunner.run(action).then(() => {
|
||||
action.dispose();
|
||||
}, err => {
|
||||
action.dispose();
|
||||
errors.onUnexpectedError(err);
|
||||
});
|
||||
}));
|
||||
|
||||
this._register(new DragAndDropObserver(container, {
|
||||
onDrop: e => {
|
||||
const color = this.themeService.getTheme().getColor(SIDE_BAR_BACKGROUND);
|
||||
container.style.backgroundColor = color ? color.toString() : '';
|
||||
const dropHandler = this.instantiationService.createInstance(ResourcesDropHandler, { allowWorkspaceOpen: true });
|
||||
dropHandler.handleDrop(e, () => undefined, targetGroup => undefined);
|
||||
dropHandler.handleDrop(e, () => undefined, () => undefined);
|
||||
},
|
||||
onDragEnter: (e) => {
|
||||
onDragEnter: () => {
|
||||
const color = this.themeService.getTheme().getColor(listDropBackground);
|
||||
container.style.backgroundColor = color ? color.toString() : '';
|
||||
},
|
||||
@@ -112,26 +77,13 @@ export class EmptyView extends ViewPane {
|
||||
}
|
||||
}));
|
||||
|
||||
this.setLabels();
|
||||
this.refreshTitle();
|
||||
}
|
||||
|
||||
private setLabels(): void {
|
||||
private refreshTitle(): void {
|
||||
if (this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) {
|
||||
this.messageElement.textContent = nls.localize('noWorkspaceHelp', "You have not yet added a folder to the workspace.");
|
||||
if (this.button) {
|
||||
this.button.label = nls.localize('addFolder', "Add Folder");
|
||||
}
|
||||
this.updateTitle(EmptyView.NAME);
|
||||
} else {
|
||||
if (this.environmentService.configuration.remoteAuthority && !isWeb) {
|
||||
const hostLabel = this.labelService.getHostLabel(Schemas.vscodeRemote, this.environmentService.configuration.remoteAuthority);
|
||||
this.messageElement.textContent = hostLabel ? nls.localize('remoteNoFolderHelp', "Connected to {0}", hostLabel) : nls.localize('connecting', "Connecting...");
|
||||
} else {
|
||||
this.messageElement.textContent = nls.localize('noFolderHelp', "You have not yet opened a folder.");
|
||||
}
|
||||
if (this.button) {
|
||||
this.button.label = nls.localize('openFolder', "Open Folder");
|
||||
}
|
||||
this.updateTitle(this.title);
|
||||
}
|
||||
}
|
||||
@@ -139,9 +91,4 @@ export class EmptyView extends ViewPane {
|
||||
layoutBody(_size: number): void {
|
||||
// no-op
|
||||
}
|
||||
|
||||
focus(): void {
|
||||
this.button.element.focus();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -55,7 +55,6 @@ import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { isNumber } from 'vs/base/common/types';
|
||||
import { domEvent } from 'vs/base/browser/event';
|
||||
import { IEditableData } from 'vs/workbench/common/views';
|
||||
import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService';
|
||||
|
||||
export class ExplorerDelegate implements IListVirtualDelegate<ExplorerItem> {
|
||||
|
||||
@@ -643,8 +642,7 @@ export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
|
||||
@IInstantiationService private instantiationService: IInstantiationService,
|
||||
@IWorkingCopyFileService private workingCopyFileService: IWorkingCopyFileService,
|
||||
@IHostService private hostService: IHostService,
|
||||
@IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService,
|
||||
@IWorkingCopyService private workingCopyService: IWorkingCopyService
|
||||
@IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService
|
||||
) {
|
||||
this.toDispose = [];
|
||||
|
||||
@@ -945,15 +943,7 @@ export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
|
||||
const sourceFile = resource;
|
||||
const targetFile = joinPath(target.resource, basename(sourceFile));
|
||||
|
||||
// if the target exists and is dirty, make sure to revert it. otherwise the dirty contents
|
||||
// of the target file would replace the contents of the added file. since we already
|
||||
// confirmed the overwrite before, this is OK.
|
||||
if (this.workingCopyService.isDirty(targetFile)) {
|
||||
await Promise.all(this.workingCopyService.getWorkingCopies(targetFile).map(workingCopy => workingCopy.revert({ soft: true })));
|
||||
}
|
||||
|
||||
const copyTarget = joinPath(target.resource, basename(sourceFile));
|
||||
const stat = await this.workingCopyFileService.copy(sourceFile, copyTarget, true);
|
||||
const stat = await this.workingCopyFileService.copy(sourceFile, targetFile, true);
|
||||
// if we only add one file, just open it directly
|
||||
if (resources.length === 1 && !stat.isDirectory) {
|
||||
this.editorService.openEditor({ resource: stat.resource, options: { pinned: true } });
|
||||
|
||||
@@ -8,7 +8,7 @@ import { URI } from 'vs/base/common/uri';
|
||||
import { EncodingMode, IFileEditorInput, Verbosity, TextResourceEditorInput } from 'vs/workbench/common/editor';
|
||||
import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel';
|
||||
import { FileOperationError, FileOperationResult, IFileService } from 'vs/platform/files/common/files';
|
||||
import { ITextFileService, ModelState, LoadReason, TextFileOperationError, TextFileOperationResult, ITextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { ITextFileService, TextFileEditorModelState, TextFileLoadReason, TextFileOperationError, TextFileOperationResult, ITextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IReference, dispose, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { ITextModelService } from 'vs/editor/common/services/resolverService';
|
||||
@@ -56,6 +56,8 @@ export class FileEditorInput extends TextResourceEditorInput implements IFileEdi
|
||||
) {
|
||||
super(resource, editorService, editorGroupService, textFileService, labelService, fileService, filesConfigurationService);
|
||||
|
||||
this.model = this.textFileService.files.get(resource);
|
||||
|
||||
if (preferredEncoding) {
|
||||
this.setPreferredEncoding(preferredEncoding);
|
||||
}
|
||||
@@ -63,6 +65,11 @@ export class FileEditorInput extends TextResourceEditorInput implements IFileEdi
|
||||
if (preferredMode) {
|
||||
this.setPreferredMode(preferredMode);
|
||||
}
|
||||
|
||||
// If a file model already exists, make sure to wire it in
|
||||
if (this.model) {
|
||||
this.registerModelListeners(this.model);
|
||||
}
|
||||
}
|
||||
|
||||
protected registerListeners(): void {
|
||||
@@ -98,10 +105,10 @@ export class FileEditorInput extends TextResourceEditorInput implements IFileEdi
|
||||
this.modelListeners.add(model.onDidSaveError(() => this._onDidChangeDirty.fire()));
|
||||
|
||||
// remove model association once it gets disposed
|
||||
Event.once(model.onDispose)(() => {
|
||||
this.modelListeners.add(Event.once(model.onDispose)(() => {
|
||||
this.modelListeners.clear();
|
||||
this.model = undefined;
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
getEncoding(): string | undefined {
|
||||
@@ -167,7 +174,7 @@ export class FileEditorInput extends TextResourceEditorInput implements IFileEdi
|
||||
}
|
||||
|
||||
private decorateLabel(label: string): string {
|
||||
const orphaned = this.model?.hasState(ModelState.ORPHAN);
|
||||
const orphaned = this.model?.hasState(TextFileEditorModelState.ORPHAN);
|
||||
const readonly = this.isReadonly();
|
||||
|
||||
if (orphaned && readonly) {
|
||||
@@ -198,7 +205,7 @@ export class FileEditorInput extends TextResourceEditorInput implements IFileEdi
|
||||
}
|
||||
|
||||
isSaving(): boolean {
|
||||
if (this.model?.hasState(ModelState.SAVED) || this.model?.hasState(ModelState.CONFLICT) || this.model?.hasState(ModelState.ERROR)) {
|
||||
if (this.model?.hasState(TextFileEditorModelState.SAVED) || this.model?.hasState(TextFileEditorModelState.CONFLICT) || this.model?.hasState(TextFileEditorModelState.ERROR)) {
|
||||
return false; // require the model to be dirty and not in conflict or error state
|
||||
}
|
||||
|
||||
@@ -234,7 +241,7 @@ export class FileEditorInput extends TextResourceEditorInput implements IFileEdi
|
||||
encoding: this.preferredEncoding,
|
||||
reload: { async: true }, // trigger a reload of the model if it exists already but do not wait to show the model
|
||||
allowBinary: this.forceOpenAs === ForceOpenAs.Text,
|
||||
reason: LoadReason.EDITOR
|
||||
reason: TextFileLoadReason.EDITOR
|
||||
});
|
||||
|
||||
// This is a bit ugly, because we first resolve the model and then resolve a model reference. the reason being that binary
|
||||
|
||||
@@ -28,10 +28,8 @@ export class LogViewerInput extends ResourceEditorInput {
|
||||
|
||||
static readonly ID = 'workbench.editorinputs.output';
|
||||
|
||||
readonly resource = this.outputChannelDescriptor.file;
|
||||
|
||||
constructor(
|
||||
private readonly outputChannelDescriptor: IFileOutputChannelDescriptor,
|
||||
outputChannelDescriptor: IFileOutputChannelDescriptor,
|
||||
@ITextModelService textModelResolverService: ITextModelService,
|
||||
@ITextFileService textFileService: ITextFileService,
|
||||
@IEditorService editorService: IEditorService,
|
||||
|
||||
@@ -13,16 +13,16 @@
|
||||
}
|
||||
|
||||
/* Deal with overflow */
|
||||
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-widget .setting-list-value,
|
||||
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-widget .setting-list-sibling {
|
||||
white-space: nowrap;
|
||||
.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 {
|
||||
white-space: pre;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-widget .setting-list-value {
|
||||
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-value {
|
||||
max-width: 90%;
|
||||
}
|
||||
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-widget .setting-list-sibling {
|
||||
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-sibling {
|
||||
max-width: 10%;
|
||||
}
|
||||
|
||||
|
||||
@@ -1640,12 +1640,13 @@ class StopSyncingSettingAction extends Action {
|
||||
}
|
||||
|
||||
async run(): Promise<void> {
|
||||
const currentValue = this.configService.getValue<string[]>('sync.ignoredSettings');
|
||||
let currentValue = [...this.configService.getValue<string[]>('sync.ignoredSettings')];
|
||||
if (this.checked) {
|
||||
this.configService.updateValue('sync.ignoredSettings', currentValue.filter(v => v !== this.setting.key));
|
||||
currentValue = currentValue.filter(v => v !== this.setting.key);
|
||||
} else {
|
||||
this.configService.updateValue('sync.ignoredSettings', [...currentValue, this.setting.key]);
|
||||
currentValue.push(this.setting.key);
|
||||
}
|
||||
this.configService.updateValue('sync.ignoredSettings', currentValue.length ? currentValue : undefined, ConfigurationTarget.USER);
|
||||
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
@@ -443,12 +443,12 @@ export class ListSettingWidget extends Disposable {
|
||||
|
||||
const onSubmit = (edited: boolean) => {
|
||||
this.model.setEditKey('none');
|
||||
const value = valueInput.value.trim();
|
||||
const value = valueInput.value;
|
||||
if (edited && !isUndefinedOrNull(value)) {
|
||||
this._onDidChangeList.fire({
|
||||
originalValue: item.value,
|
||||
value: value,
|
||||
sibling: siblingInput && siblingInput.value.trim(),
|
||||
sibling: siblingInput && siblingInput.value,
|
||||
targetIndex: idx
|
||||
});
|
||||
}
|
||||
|
||||
@@ -146,13 +146,16 @@ interface ResourceTemplate {
|
||||
disposables: IDisposable;
|
||||
}
|
||||
|
||||
class MultipleSelectionActionRunner extends ActionRunner {
|
||||
class RepositoryPaneActionRunner extends ActionRunner {
|
||||
|
||||
constructor(private getSelectedResources: () => (ISCMResource | IResourceNode<ISCMResource, ISCMResourceGroup>)[]) {
|
||||
constructor(
|
||||
private getSelectedResources: () => (ISCMResource | IResourceNode<ISCMResource, ISCMResourceGroup>)[],
|
||||
private focus: () => void
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
runAction(action: IAction, context: ISCMResource | IResourceNode<ISCMResource, ISCMResourceGroup>): Promise<any> {
|
||||
async runAction(action: IAction, context: ISCMResource | IResourceNode<ISCMResource, ISCMResourceGroup>): Promise<any> {
|
||||
if (!(action instanceof MenuItemAction)) {
|
||||
return super.runAction(action, context);
|
||||
}
|
||||
@@ -161,7 +164,8 @@ class MultipleSelectionActionRunner extends ActionRunner {
|
||||
const contextIsSelected = selection.some(s => s === context);
|
||||
const actualContext = contextIsSelected ? selection : [context];
|
||||
const args = flatten(actualContext.map(e => ResourceTree.isResourceNode(e) ? ResourceTree.collect(e) : [e]));
|
||||
return action.run(...args);
|
||||
await action.run(...args);
|
||||
this.focus();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,6 +179,7 @@ class ResourceRenderer implements ICompressibleTreeRenderer<ISCMResource | IReso
|
||||
private labels: ResourceLabels,
|
||||
private actionViewItemProvider: IActionViewItemProvider,
|
||||
private getSelectedResources: () => (ISCMResource | IResourceNode<ISCMResource, ISCMResourceGroup>)[],
|
||||
private focus: () => void,
|
||||
private themeService: IThemeService,
|
||||
private menus: SCMMenus
|
||||
) { }
|
||||
@@ -186,7 +191,7 @@ class ResourceRenderer implements ICompressibleTreeRenderer<ISCMResource | IReso
|
||||
const actionsContainer = append(fileLabel.element, $('.actions'));
|
||||
const actionBar = new ActionBar(actionsContainer, {
|
||||
actionViewItemProvider: this.actionViewItemProvider,
|
||||
actionRunner: new MultipleSelectionActionRunner(this.getSelectedResources)
|
||||
actionRunner: new RepositoryPaneActionRunner(this.getSelectedResources, this.focus)
|
||||
});
|
||||
|
||||
const decorationIcon = append(element, $('.decoration-icon'));
|
||||
@@ -730,7 +735,8 @@ export class RepositoryPane extends ViewPane {
|
||||
wrappingStrategy: 'advanced',
|
||||
wrappingIndent: 'none',
|
||||
padding: { top: 3, bottom: 3 },
|
||||
suggest: { showWords: false }
|
||||
suggest: { showWords: false },
|
||||
quickSuggestions: false
|
||||
};
|
||||
|
||||
const codeEditorWidgetOptions: ICodeEditorWidgetOptions = {
|
||||
@@ -820,7 +826,7 @@ export class RepositoryPane extends ViewPane {
|
||||
|
||||
const renderers = [
|
||||
new ResourceGroupRenderer(actionViewItemProvider, this.themeService, this.menus),
|
||||
new ResourceRenderer(() => this.viewModel, this.listLabels, actionViewItemProvider, () => this.getSelectedResources(), this.themeService, this.menus)
|
||||
new ResourceRenderer(() => this.viewModel, this.listLabels, actionViewItemProvider, () => this.getSelectedResources(), () => this.tree.domFocus(), this.themeService, this.menus)
|
||||
];
|
||||
|
||||
const filter = new SCMTreeFilter();
|
||||
@@ -1024,7 +1030,7 @@ export class RepositoryPane extends ViewPane {
|
||||
getAnchor: () => e.anchor,
|
||||
getActions: () => actions,
|
||||
getActionsContext: () => element,
|
||||
actionRunner: new MultipleSelectionActionRunner(() => this.getSelectedResources())
|
||||
actionRunner: new RepositoryPaneActionRunner(() => this.getSelectedResources(), () => this.tree.domFocus())
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -104,14 +104,7 @@ export class ReplaceService implements IReplaceService {
|
||||
const edits: WorkspaceTextEdit[] = this.createEdits(arg, resource);
|
||||
await this.bulkEditorService.apply({ edits }, { progress });
|
||||
|
||||
return Promise.all(edits.map(e => {
|
||||
const model = this.textFileService.files.get(e.resource);
|
||||
if (model) {
|
||||
return model.save();
|
||||
}
|
||||
|
||||
return Promise.resolve(undefined);
|
||||
}));
|
||||
return Promise.all(edits.map(e => this.textFileService.files.get(e.resource)?.save()));
|
||||
}
|
||||
|
||||
async openReplacePreview(element: FileMatchOrMatch, preserveFocus?: boolean, sideBySide?: boolean, pinned?: boolean): Promise<any> {
|
||||
|
||||
@@ -9,7 +9,7 @@ import * as aria from 'vs/base/browser/ui/aria/aria';
|
||||
import { MessageType } from 'vs/base/browser/ui/inputbox/inputBox';
|
||||
import { IIdentityProvider } from 'vs/base/browser/ui/list/list';
|
||||
import { ITreeContextMenuEvent, ITreeElement } from 'vs/base/browser/ui/tree/tree';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import { IAction, ActionRunner } from 'vs/base/common/actions';
|
||||
import { Delayer } from 'vs/base/common/async';
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
@@ -213,7 +213,7 @@ export class SearchView extends ViewPane {
|
||||
this.viewletState = this.memento.getMemento(StorageScope.WORKSPACE);
|
||||
|
||||
this._register(this.fileService.onDidFilesChange(e => this.onFilesChanged(e)));
|
||||
this._register(this.textFileService.untitled.onDidDisposeModel(e => this.onUntitledDidDispose(e)));
|
||||
this._register(this.textFileService.untitled.onDidDispose(model => this.onUntitledDidDispose(model.resource)));
|
||||
this._register(this.contextService.onDidChangeWorkbenchState(() => this.onDidChangeWorkbenchState()));
|
||||
this._register(this.searchHistoryService.onDidClearHistory(() => this.clearHistory()));
|
||||
|
||||
@@ -1584,6 +1584,7 @@ export class SearchView extends ViewPane {
|
||||
const openFolderLink = dom.append(textEl,
|
||||
$('a.pointer.prominent', { tabindex: 0 }, nls.localize('openFolder', "Open Folder")));
|
||||
|
||||
const actionRunner = new ActionRunner();
|
||||
this.messageDisposables.push(dom.addDisposableListener(openFolderLink, dom.EventType.CLICK, (e: MouseEvent) => {
|
||||
dom.EventHelper.stop(e, false);
|
||||
|
||||
@@ -1591,7 +1592,7 @@ export class SearchView extends ViewPane {
|
||||
this.instantiationService.createInstance(OpenFileFolderAction, OpenFileFolderAction.ID, OpenFileFolderAction.LABEL) :
|
||||
this.instantiationService.createInstance(OpenFolderAction, OpenFolderAction.ID, OpenFolderAction.LABEL);
|
||||
|
||||
this.actionRunner!.run(action).then(() => {
|
||||
actionRunner.run(action).then(() => {
|
||||
action.dispose();
|
||||
}, err => {
|
||||
action.dispose();
|
||||
|
||||
@@ -53,8 +53,7 @@ class LanguageSurvey extends Disposable {
|
||||
// Process model-save event every 250ms to reduce load
|
||||
const onModelsSavedWorker = this._register(new RunOnceWorker<ITextFileEditorModel>(models => {
|
||||
models.forEach(m => {
|
||||
const model = modelService.getModel(m.resource);
|
||||
if (model && model.getModeId() === data.languageId && date !== storageService.get(EDITED_LANGUAGE_DATE_KEY, StorageScope.GLOBAL)) {
|
||||
if (m.getMode() === data.languageId && date !== storageService.get(EDITED_LANGUAGE_DATE_KEY, StorageScope.GLOBAL)) {
|
||||
const editedCount = storageService.getNumber(EDITED_LANGUAGE_COUNT_KEY, StorageScope.GLOBAL, 0) + 1;
|
||||
storageService.store(EDITED_LANGUAGE_COUNT_KEY, editedCount, StorageScope.GLOBAL);
|
||||
storageService.store(EDITED_LANGUAGE_DATE_KEY, date, StorageScope.GLOBAL);
|
||||
|
||||
@@ -19,7 +19,7 @@ import ErrorTelemetry from 'vs/platform/telemetry/browser/errorTelemetry';
|
||||
import { configurationTelemetry } from 'vs/platform/telemetry/common/telemetryUtils';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { ITextFileService, ITextFileModelSaveEvent, ITextFileModelLoadEvent } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { ITextFileService, ITextFileSaveEvent, ITextFileLoadEvent } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { extname, basename, isEqual, isEqualOrParent, joinPath } from 'vs/base/common/resources';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
@@ -58,7 +58,7 @@ export class TelemetryContribution extends Disposable implements IWorkbenchContr
|
||||
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@IViewletService viewletService: IViewletService,
|
||||
@ITextFileService textFileService: ITextFileService,
|
||||
@ITextFileService textFileService: ITextFileService
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -131,7 +131,7 @@ export class TelemetryContribution extends Disposable implements IWorkbenchContr
|
||||
this._register(lifecycleService.onShutdown(() => this.dispose()));
|
||||
}
|
||||
|
||||
private onTextFileModelLoaded(e: ITextFileModelLoadEvent): void {
|
||||
private onTextFileModelLoaded(e: ITextFileLoadEvent): void {
|
||||
const settingsType = this.getTypeIfSettings(e.model.resource);
|
||||
if (settingsType) {
|
||||
type SettingsReadClassification = {
|
||||
@@ -146,7 +146,7 @@ export class TelemetryContribution extends Disposable implements IWorkbenchContr
|
||||
}
|
||||
}
|
||||
|
||||
private onTextFileModelSaved(e: ITextFileModelSaveEvent): void {
|
||||
private onTextFileModelSaved(e: ITextFileSaveEvent): void {
|
||||
const settingsType = this.getTypeIfSettings(e.model.resource);
|
||||
if (settingsType) {
|
||||
type SettingsWrittenClassification = {
|
||||
|
||||
@@ -690,6 +690,8 @@ export class RunActiveFileInTerminalAction extends Action {
|
||||
if (!instance) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
await instance.processReady;
|
||||
|
||||
const editor = this.codeEditorService.getActiveCodeEditor();
|
||||
if (!editor || !editor.hasModel()) {
|
||||
return Promise.resolve(undefined);
|
||||
|
||||
@@ -21,7 +21,7 @@ import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { ITextModelContentProvider, ITextModelService } from 'vs/editor/common/services/resolverService';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IMenuItem, MenuId, MenuRegistry } from 'vs/platform/actions/common/actions';
|
||||
import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions';
|
||||
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ContextKeyExpr, IContextKey, IContextKeyService, RawContextKey, ContextKeyRegexExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
@@ -31,7 +31,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
||||
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
||||
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { CONTEXT_SYNC_STATE, getSyncSourceFromRemoteContentResource, getUserDataSyncStore, ISyncConfiguration, IUserDataAuthTokenService, IUserDataAutoSyncService, IUserDataSyncService, IUserDataSyncStore, registerConfiguration, SyncSource, SyncStatus, toRemoteContentResource, UserDataSyncError, UserDataSyncErrorCode, USER_DATA_SYNC_SCHEME, IUserDataSyncEnablementService, ResourceKey, getSyncSourceFromPreviewResource } from 'vs/platform/userDataSync/common/userDataSync';
|
||||
import { CONTEXT_SYNC_STATE, getSyncSourceFromRemoteContentResource, getUserDataSyncStore, ISyncConfiguration, IUserDataAuthTokenService, IUserDataAutoSyncService, IUserDataSyncService, IUserDataSyncStore, registerConfiguration, SyncSource, SyncStatus, toRemoteContentResource, UserDataSyncError, UserDataSyncErrorCode, USER_DATA_SYNC_SCHEME, IUserDataSyncEnablementService, ResourceKey, getSyncSourceFromPreviewResource, CONTEXT_SYNC_ENABLEMENT } from 'vs/platform/userDataSync/common/userDataSync';
|
||||
import { FloatingClickWidget } from 'vs/workbench/browser/parts/editor/editorWidgets';
|
||||
import { GLOBAL_ACTIVITY_ID } from 'vs/workbench/common/activity';
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
@@ -52,7 +52,6 @@ const enum AuthStatus {
|
||||
SignedOut = 'SignedOut',
|
||||
Unavailable = 'Unavailable'
|
||||
}
|
||||
const CONTEXT_SYNC_ENABLEMENT = new RawContextKey<boolean>('syncEnabled', false);
|
||||
const CONTEXT_AUTH_TOKEN_STATE = new RawContextKey<string>('authTokenStatus', AuthStatus.Initializing);
|
||||
const CONTEXT_CONFLICTS_SOURCES = new RawContextKey<string>('conflictsSources', '');
|
||||
|
||||
@@ -547,7 +546,6 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
|
||||
} else {
|
||||
await this.userDataSyncService.resetLocal();
|
||||
}
|
||||
await this.signOut();
|
||||
this.disableSync();
|
||||
}
|
||||
}
|
||||
@@ -574,13 +572,6 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
|
||||
}
|
||||
}
|
||||
|
||||
private async signOut(): Promise<void> {
|
||||
if (this.activeAccount) {
|
||||
await this.authenticationService.logout(this.userDataSyncStore!.authenticationProviderId, this.activeAccount.id);
|
||||
await this.setActiveAccount(undefined);
|
||||
}
|
||||
}
|
||||
|
||||
private getConflictsEditorInput(source: SyncSource): IEditorInput | undefined {
|
||||
const previewResource = source === SyncSource.Settings ? this.workbenchEnvironmentService.settingsSyncPreviewResource
|
||||
: source === SyncSource.Keybindings ? this.workbenchEnvironmentService.keybindingsSyncPreviewResource
|
||||
@@ -652,6 +643,14 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
|
||||
},
|
||||
when: turnOnSyncWhenContext,
|
||||
});
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarPreferencesMenu, {
|
||||
group: '5_sync',
|
||||
command: {
|
||||
id: turnOnSyncCommandId,
|
||||
title: localize('global activity turn on sync', "Turn on Sync...")
|
||||
},
|
||||
when: turnOnSyncWhenContext,
|
||||
});
|
||||
|
||||
const signInCommandId = 'workbench.userData.actions.signin';
|
||||
const signInWhenContext = ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), CONTEXT_SYNC_ENABLEMENT, CONTEXT_AUTH_TOKEN_STATE.isEqualTo(AuthStatus.SignedOut));
|
||||
@@ -697,6 +696,14 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
|
||||
},
|
||||
when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), CONTEXT_SYNC_ENABLEMENT),
|
||||
});
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarPreferencesMenu, {
|
||||
group: '5_sync',
|
||||
command: {
|
||||
id: stopSyncCommandId,
|
||||
title: localize('global activity stop sync', "Turn off Sync")
|
||||
},
|
||||
when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), CONTEXT_SYNC_ENABLEMENT),
|
||||
});
|
||||
|
||||
const resolveSettingsConflictsCommandId = 'workbench.userData.actions.resolveSettingsConflicts';
|
||||
const resolveSettingsConflictsWhenContext = ContextKeyRegexExpr.create(CONTEXT_CONFLICTS_SOURCES.keys()[0], /.*settings.*/i);
|
||||
@@ -736,17 +743,6 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
|
||||
when: resolveKeybindingsConflictsWhenContext,
|
||||
});
|
||||
|
||||
const signOutMenuItem: IMenuItem = {
|
||||
group: '5_sync',
|
||||
command: {
|
||||
id: 'workbench.userData.actions.signout',
|
||||
title: localize('sign out', "Sync: Sign out")
|
||||
},
|
||||
when: ContextKeyExpr.and(CONTEXT_AUTH_TOKEN_STATE.isEqualTo(AuthStatus.SignedIn)),
|
||||
};
|
||||
CommandsRegistry.registerCommand(signOutMenuItem.command.id, () => this.signOut());
|
||||
MenuRegistry.appendMenuItem(MenuId.CommandPalette, signOutMenuItem);
|
||||
|
||||
const configureSyncCommandId = 'workbench.userData.actions.configureSync';
|
||||
CommandsRegistry.registerCommand(configureSyncCommandId, () => this.configureSyncOptions());
|
||||
MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
|
||||
@@ -767,15 +763,6 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
|
||||
when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized)),
|
||||
});
|
||||
|
||||
const resetLocalCommandId = 'workbench.userData.actions.resetLocal';
|
||||
CommandsRegistry.registerCommand(resetLocalCommandId, () => this.userDataSyncService.resetLocal());
|
||||
MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
|
||||
command: {
|
||||
id: resetLocalCommandId,
|
||||
title: localize('reset local', "Developer: Reset Local (Sync)")
|
||||
},
|
||||
when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized)),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,10 +26,12 @@ export class WebviewInput extends EditorInput {
|
||||
private readonly _onDisposeWebview = this._register(new Emitter<void>());
|
||||
readonly onDisposeWebview = this._onDisposeWebview.event;
|
||||
|
||||
readonly resource = URI.from({
|
||||
scheme: WebviewPanelResourceScheme,
|
||||
path: `webview-panel/webview-${this.id}`
|
||||
});
|
||||
get resource() {
|
||||
return URI.from({
|
||||
scheme: WebviewPanelResourceScheme,
|
||||
path: `webview-panel/webview-${this.id}`
|
||||
});
|
||||
}
|
||||
|
||||
constructor(
|
||||
public readonly id: string,
|
||||
|
||||
@@ -53,10 +53,10 @@ export class WalkThroughInput extends EditorInput {
|
||||
private maxTopScroll = 0;
|
||||
private maxBottomScroll = 0;
|
||||
|
||||
readonly resource = this.options.resource;
|
||||
get resource() { return this.options.resource; }
|
||||
|
||||
constructor(
|
||||
private options: WalkThroughInputOptions,
|
||||
private readonly options: WalkThroughInputOptions,
|
||||
@ITextModelService private readonly textModelResolverService: ITextModelService
|
||||
) {
|
||||
super();
|
||||
|
||||
Reference in New Issue
Block a user