Merge from vscode 6fded8a497cd0142de3a1c607649a5423a091a25

This commit is contained in:
ADS Merger
2020-04-04 04:30:52 +00:00
parent 00cc0074f7
commit 35f1a014d5
184 changed files with 3043 additions and 2285 deletions

View File

@@ -16,6 +16,7 @@ import { ITextModel } from 'vs/editor/common/model';
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
/**
* Shows a message when semantic tokens are shown the first time.
@@ -24,32 +25,34 @@ export class SemanticTokensHelp extends Disposable implements IEditorContributio
public static readonly ID = 'editor.contrib.semanticHighlightHelp';
private static notificationShown = false;
constructor(
_editor: ICodeEditor,
@INotificationService _notificationService: INotificationService,
@IOpenerService _openerService: IOpenerService,
@IWorkbenchThemeService _themeService: IWorkbenchThemeService,
@IEditorService _editorService: IEditorService,
@IStorageService _storageService: IStorageService,
@IStorageKeysSyncRegistryService storageKeysSyncRegistryService: IStorageKeysSyncRegistryService
) {
super();
// opt-in to syncing
const neverShowAgainId = 'editor.contrib.semanticTokensHelp';
if (_storageService.getBoolean(neverShowAgainId, StorageScope.GLOBAL)) {
return;
}
storageKeysSyncRegistryService.registerStorageKey({ key: neverShowAgainId, version: 1 });
const toDispose = this._register(new DisposableStore());
const localToDispose = toDispose.add(new DisposableStore());
const installChangeTokenListener = (model: ITextModel) => {
localToDispose.add(model.onDidChangeTokens((e) => {
if (SemanticTokensHelp.notificationShown) {
toDispose.dispose();
if (!e.semanticTokensApplied) {
return;
}
if (!e.semanticTokensApplied) {
if (_storageService.getBoolean(neverShowAgainId, StorageScope.GLOBAL)) {
toDispose.dispose();
return;
}
const activeEditorControl = _editorService.activeTextEditorControl;
@@ -58,7 +61,7 @@ export class SemanticTokensHelp extends Disposable implements IEditorContributio
}
toDispose.dispose(); // uninstall all listeners, make sure the notification is only shown once per window
SemanticTokensHelp.notificationShown = true;
_storageService.store(neverShowAgainId, true, StorageScope.GLOBAL); // never show again
const message = nls.localize(
{
@@ -81,7 +84,7 @@ export class SemanticTokensHelp extends Disposable implements IEditorContributio
_openerService.open(URI.parse(url));
}
}
], { neverShowAgain: { id: neverShowAgainId } });
]);
}));
};

View File

@@ -89,18 +89,11 @@
white-space: pre;
}
.monaco-editor.vs-dark .review-widget .body .comment-body h4 {
margin: 0;
}
.monaco-editor .review-widget .body .review-comment .review-comment-contents .author {
line-height: 22px;
}
.monaco-editor.vs-dark .review-widget .body .review-comment .review-comment-contents .author {
color: #fff;
font-weight: 600;
}
.monaco-editor .review-widget .body .review-comment .review-comment-contents .isPending {
margin: 0 5px 0 5px;
@@ -108,7 +101,7 @@
font-style: italic;
}
.monaco-editor.vs-dark .review-widget .body .review-comment .review-comment-contents .comment-body {
.monaco-editor .review-widget .body .review-comment .review-comment-contents .comment-body {
padding-top: 4px;
}
@@ -183,10 +176,6 @@
opacity: 0.6;
}
.monaco-editor.vs-dark .review-widget .body span.created_at {
color: #e0e0e0;
}
.monaco-editor .review-widget .body .comment-body p,
.monaco-editor .review-widget .body .comment-body ul {
margin: 8px 0;

View File

@@ -27,7 +27,7 @@ export class CustomEditorInput extends LazilyResolvedWebviewEditorInput {
public static typeId = 'workbench.editors.webviewEditor';
private readonly _editorResource: URI;
private readonly _fromBackup: boolean;
private readonly _startsDirty: boolean | undefined;
get resource() { return this._editorResource; }
@@ -38,7 +38,7 @@ export class CustomEditorInput extends LazilyResolvedWebviewEditorInput {
viewType: string,
id: string,
webview: Lazy<WebviewOverlay>,
fromBackup: boolean,
options: { startsDirty?: boolean },
@IWebviewService webviewService: IWebviewService,
@IWebviewWorkbenchService webviewWorkbenchService: IWebviewWorkbenchService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@@ -51,7 +51,7 @@ export class CustomEditorInput extends LazilyResolvedWebviewEditorInput {
) {
super(id, viewType, '', webview, webviewService, webviewWorkbenchService);
this._editorResource = resource;
this._fromBackup = fromBackup;
this._startsDirty = options.startsDirty;
}
public getTypeId(): string {
@@ -110,7 +110,7 @@ export class CustomEditorInput extends LazilyResolvedWebviewEditorInput {
public isDirty(): boolean {
if (!this._modelRef) {
return this._fromBackup;
return !!this._startsDirty;
}
return this._modelRef.object.isDirty();
}
@@ -201,7 +201,7 @@ export class CustomEditorInput extends LazilyResolvedWebviewEditorInput {
this.viewType,
this.id,
new Lazy(() => undefined!),
this._fromBackup); // this webview is replaced in the transfer call
{ startsDirty: this._startsDirty }); // this webview is replaced in the transfer call
this.transfer(newEditor);
newEditor.updateGroup(group);
return newEditor;

View File

@@ -11,7 +11,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import { IEditorInput } from 'vs/workbench/common/editor';
import { CustomEditorInput } from 'vs/workbench/contrib/customEditor/browser/customEditorInput';
import { IWebviewService } from 'vs/workbench/contrib/webview/browser/webview';
import { WebviewEditorInputFactory } from 'vs/workbench/contrib/webview/browser/webviewEditorInputFactory';
import { WebviewEditorInputFactory, SerializedWebview } from 'vs/workbench/contrib/webview/browser/webviewEditorInputFactory';
import { IWebviewWorkbenchService, WebviewInputOptions } from 'vs/workbench/contrib/webview/browser/webviewWorkbenchService';
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
@@ -30,6 +30,12 @@ export interface CustomDocumentBackupData {
};
}
interface SerializedCustomEditor extends SerializedWebview {
readonly editorResource: UriComponents;
readonly dirty?: boolean;
}
export class CustomEditorInputFactory extends WebviewEditorInputFactory {
public static readonly ID = CustomEditorInput.typeId;
@@ -43,9 +49,10 @@ export class CustomEditorInputFactory extends WebviewEditorInputFactory {
}
public serialize(input: CustomEditorInput): string | undefined {
const data = {
const data: SerializedCustomEditor = {
...this.toJson(input),
editorResource: input.resource.toJSON(),
dirty: input.isDirty(),
};
try {
@@ -78,7 +85,7 @@ export class CustomEditorInputFactory extends WebviewEditorInputFactory {
return webview;
});
const customInput = this._instantiationService.createInstance(CustomEditorInput, URI.from((data as any).editorResource), data.viewType, id, webview, false);
const customInput = this._instantiationService.createInstance(CustomEditorInput, URI.from((data as any).editorResource), data.viewType, id, webview, { startsDirty: (data as any).dirty });
if (typeof data.group === 'number') {
customInput.updateGroup(data.group);
}
@@ -112,7 +119,7 @@ export class CustomEditorInputFactory extends WebviewEditorInputFactory {
return webview;
});
const editor = instantiationService.createInstance(CustomEditorInput, URI.revive(backupData.editorResource), backupData.viewType, id, webview, true);
const editor = instantiationService.createInstance(CustomEditorInput, URI.revive(backupData.editorResource), backupData.viewType, id, webview, { startsDirty: true });
editor.updateGroup(0);
return editor;
});

View File

@@ -23,7 +23,7 @@ import { EditorServiceImpl } from 'vs/workbench/browser/parts/editor/editor';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { EditorInput, EditorOptions, GroupIdentifier, IEditorInput, IEditorPane } from 'vs/workbench/common/editor';
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
import { webviewEditorsExtensionPoint } from 'vs/workbench/contrib/customEditor/browser/extensionPoint';
import { webviewEditorsExtensionPoint, IWebviewEditorsExtensionPoint } from 'vs/workbench/contrib/customEditor/browser/extensionPoint';
import { CONTEXT_CUSTOM_EDITORS, CONTEXT_FOCUSED_CUSTOM_EDITOR_IS_EDITABLE, CustomEditorInfo, CustomEditorInfoCollection, CustomEditorPriority, CustomEditorSelector, ICustomEditorService } from 'vs/workbench/contrib/customEditor/common/customEditor';
import { CustomEditorModelManager } from 'vs/workbench/contrib/customEditor/common/customEditorModelManager';
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
@@ -31,12 +31,16 @@ import { IWebviewService, webviewHasOwnEditFunctionsContext } from 'vs/workbench
import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IEditorService, IOpenEditorOverride } from 'vs/workbench/services/editor/common/editorService';
import { CustomEditorInput } from './customEditorInput';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
export const defaultEditorId = 'default';
const builtinProviderDisplayName = nls.localize('builtinProviderDisplayName', "Built-in");
const defaultEditorInfo = new CustomEditorInfo({
id: defaultEditorId,
displayName: nls.localize('promptOpenWith.defaultEditor', "VS Code's standard text editor"),
displayName: nls.localize('promptOpenWith.defaultEditor.displayName', "Text Editor"),
providerDisplayName: builtinProviderDisplayName,
selector: [
{ filenamePattern: '*' }
],
@@ -58,8 +62,9 @@ export class CustomEditorInfoStore extends Disposable {
this.add(new CustomEditorInfo({
id: webviewEditorContribution.viewType,
displayName: webviewEditorContribution.displayName,
providerDisplayName: extension.description.isBuiltin ? builtinProviderDisplayName : extension.description.displayName || extension.description.identifier.value,
selector: webviewEditorContribution.selector || [],
priority: webviewEditorContribution.priority || CustomEditorPriority.default,
priority: getPriorityFromContribution(webviewEditorContribution, extension.description),
}));
}
}
@@ -192,6 +197,7 @@ export class CustomEditorService extends Disposable implements ICustomEditorServ
description: editorDescriptor.id === currentlyOpenedEditorType
? nls.localize('openWithCurrentlyActive', "Currently Active")
: undefined,
detail: editorDescriptor.providerDisplayName,
buttons: resourceExt ? [{
iconClass: 'codicon-settings-gear',
tooltip: nls.localize('promptOpenWith.setDefaultTooltip', "Set as default editor for '{0}' files", resourceExt)
@@ -269,7 +275,7 @@ export class CustomEditorService extends Disposable implements ICustomEditorServ
const webview = new Lazy(() => {
return this.webviewService.createWebviewOverlay(id, { customClasses: options?.customClasses }, {});
});
const input = this.instantiationService.createInstance(CustomEditorInput, resource, viewType, id, webview, false);
const input = this.instantiationService.createInstance(CustomEditorInput, resource, viewType, id, webview, {});
if (typeof group !== 'undefined') {
input.updateGroup(group);
}
@@ -569,9 +575,29 @@ export class CustomEditorContribution extends Disposable implements IWorkbenchCo
}
}
function getPriorityFromContribution(
contribution: IWebviewEditorsExtensionPoint,
extension: IExtensionDescription,
): CustomEditorPriority {
switch (contribution.priority) {
case CustomEditorPriority.default:
case CustomEditorPriority.option:
return contribution.priority;
case CustomEditorPriority.builtin:
// Builtin is only valid for builtin extensions
return extension.isBuiltin ? CustomEditorPriority.builtin : CustomEditorPriority.default;
default:
return CustomEditorPriority.default;
}
}
registerThemingParticipant((theme, collector) => {
const shadow = theme.getColor(colorRegistry.scrollbarShadow);
if (shadow) {
collector.addRule(`.webview.modified { box-shadow: -6px 0 5px -5px ${shadow}; }`);
}
});

View File

@@ -16,11 +16,11 @@ namespace WebviewEditorContribution {
export const priority = 'priority';
}
interface IWebviewEditorsExtensionPoint {
export interface IWebviewEditorsExtensionPoint {
readonly [WebviewEditorContribution.viewType]: string;
readonly [WebviewEditorContribution.displayName]: string;
readonly [WebviewEditorContribution.selector]?: readonly CustomEditorSelector[];
readonly [WebviewEditorContribution.priority]?: CustomEditorPriority;
readonly [WebviewEditorContribution.priority]?: string;
}
const webviewEditorsContribution: IJSONSchema = {
@@ -75,12 +75,10 @@ const webviewEditorsContribution: IJSONSchema = {
enum: [
CustomEditorPriority.default,
CustomEditorPriority.option,
CustomEditorPriority.builtin,
],
markdownEnumDescriptions: [
nls.localize('contributes.priority.default', 'Editor is automatically used for a resource if no other default custom editors are registered for it.'),
nls.localize('contributes.priority.option', 'Editor is not automatically used but can be selected by a user.'),
nls.localize('contributes.priority.builtin', 'Editor automatically used if no other `default` or `builtin` editors are registered for the resource.'),
],
default: 'default'
}

View File

@@ -7,6 +7,7 @@ import { distinct, mergeSort } from 'vs/base/common/arrays';
import { Event } from 'vs/base/common/event';
import * as glob from 'vs/base/common/glob';
import { IDisposable, IReference } from 'vs/base/common/lifecycle';
import { posix } from 'vs/base/common/path';
import { basename } from 'vs/base/common/resources';
import { URI } from 'vs/base/common/uri';
import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
@@ -75,17 +76,20 @@ export class CustomEditorInfo {
public readonly id: string;
public readonly displayName: string;
public readonly providerDisplayName: string | undefined;
public readonly priority: CustomEditorPriority;
public readonly selector: readonly CustomEditorSelector[];
constructor(descriptor: {
readonly id: string;
readonly displayName: string;
readonly providerDisplayName: string | undefined;
readonly priority: CustomEditorPriority;
readonly selector: readonly CustomEditorSelector[];
}) {
this.id = descriptor.id;
this.displayName = descriptor.displayName;
this.providerDisplayName = descriptor.providerDisplayName;
this.priority = descriptor.priority;
this.selector = descriptor.selector;
}
@@ -96,7 +100,9 @@ export class CustomEditorInfo {
static selectorMatches(selector: CustomEditorSelector, resource: URI): boolean {
if (selector.filenamePattern) {
if (glob.match(selector.filenamePattern.toLowerCase(), basename(resource).toLowerCase())) {
const matchOnPath = selector.filenamePattern.indexOf(posix.sep) >= 0;
const target = matchOnPath ? resource.path : basename(resource);
if (glob.match(selector.filenamePattern.toLowerCase(), target.toLowerCase())) {
return true;
}
}

View File

@@ -133,7 +133,11 @@ export class CallStackView extends ViewPane {
this.needsRefresh = false;
this.dataSource.deemphasizedStackFramesToShow = [];
this.tree.updateChildren().then(() => {
this.parentSessionToExpand.forEach(s => this.tree.expand(s));
try {
this.parentSessionToExpand.forEach(s => this.tree.expand(s));
} catch (e) {
// Ignore tree expand errors if element no longer present
}
this.parentSessionToExpand.clear();
if (this.selectionNeedsUpdate) {
this.selectionNeedsUpdate = false;

View File

@@ -44,7 +44,7 @@ import { ClearReplAction, Repl } from 'vs/workbench/contrib/debug/browser/repl';
import { DebugContentProvider } from 'vs/workbench/contrib/debug/common/debugContentProvider';
import { WelcomeView } from 'vs/workbench/contrib/debug/browser/welcomeView';
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
import { DebugViewPaneContainer, OpenDebugPanelAction } from 'vs/workbench/contrib/debug/browser/debugViewlet';
import { DebugViewPaneContainer, OpenDebugConsoleAction } from 'vs/workbench/contrib/debug/browser/debugViewlet';
import { registerEditorContribution } from 'vs/editor/browser/editorExtensions';
import { CallStackEditorContribution } from 'vs/workbench/contrib/debug/browser/callStackEditorContribution';
import { BreakpointEditorContribution } from 'vs/workbench/contrib/debug/browser/breakpointEditorContribution';
@@ -91,7 +91,7 @@ const VIEW_CONTAINER: ViewContainer = Registry.as<IViewContainersRegistry>(ViewE
name: nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'debugPanel' }, 'Debug Console'),
ctorDescriptor: new SyncDescriptor(ViewPaneContainer, [DEBUG_PANEL_ID, DEBUG_PANEL_ID, { mergeViewWithContainerWhenSingleView: true, donotShowContainerTitleWhenMergedWithContainer: true }]),
focusCommand: {
id: OpenDebugPanelAction.ID,
id: OpenDebugConsoleAction.ID,
keybindings: openPanelKb
},
order: 3,
@@ -120,7 +120,7 @@ registerCommands();
// register action to open viewlet
const registry = Registry.as<IWorkbenchActionRegistry>(WorkbenchActionRegistryExtensions.WorkbenchActions);
registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenDebugPanelAction, OpenDebugPanelAction.ID, OpenDebugPanelAction.LABEL, openPanelKb), 'View: Debug Console', nls.localize('view', "View"));
registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenDebugConsoleAction, OpenDebugConsoleAction.ID, OpenDebugConsoleAction.LABEL, openPanelKb), 'View: Debug Console', nls.localize('view', "View"));
registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenDebugViewletAction, OpenDebugViewletAction.ID, OpenDebugViewletAction.LABEL, openViewletKb), 'View: Show Run and Debug', nls.localize('view', "View"));
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugToolBar, LifecyclePhase.Restored);
@@ -173,7 +173,7 @@ Registry.as<IQuickAccessRegistry>(QuickAccessExtensions.Quickaccess).registerQui
prefix: StartDebugQuickAccessProvider.PREFIX,
contextKey: 'inLaunchConfigurationsPicker',
placeholder: nls.localize('startDebugPlaceholder', "Type the name of a launch configuration to run."),
helpEntries: [{ description: nls.localize('startDebugHelp', "Start Debug Configurations"), needsEditor: false }]
helpEntries: [{ description: nls.localize('startDebuggingHelp', "Start Debugging"), needsEditor: false }]
});
// register service
@@ -363,7 +363,7 @@ registerEditorContribution(BREAKPOINT_EDITOR_CONTRIBUTION_ID, BreakpointEditorCo
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
group: '4_panels',
command: {
id: OpenDebugPanelAction.ID,
id: OpenDebugConsoleAction.ID,
title: nls.localize({ key: 'miToggleDebugConsole', comment: ['&& denotes a mnemonic'] }, "De&&bug Console")
},
order: 2

View File

@@ -346,7 +346,7 @@ export class ConfigurationManager implements IConfigurationManager {
private setCompoundSchemaValues(): void {
const compoundConfigurationsSchema = (<IJSONSchema>launchSchema.properties!['compounds'].items).properties!['configurations'];
const launchNames = this.launches.map(l =>
l.getConfigurationNames(false)).reduce((first, second) => first.concat(second), []);
l.getConfigurationNames(true)).reduce((first, second) => first.concat(second), []);
(<IJSONSchema>compoundConfigurationsSchema.items).oneOf![0].enum = launchNames;
(<IJSONSchema>compoundConfigurationsSchema.items).oneOf![1].properties!.name.enum = launchNames;
@@ -523,7 +523,7 @@ abstract class AbstractLaunch {
return config.compounds.filter(compound => compound.name === name).pop();
}
getConfigurationNames(includeCompounds = true): string[] {
getConfigurationNames(ignoreCompoundsAndPresentation = false): string[] {
const config = this.getConfig();
if (!config || (!Array.isArray(config.configurations) && !Array.isArray(config.compounds))) {
return [];
@@ -532,12 +532,14 @@ abstract class AbstractLaunch {
if (config.configurations) {
configurations.push(...config.configurations.filter(cfg => cfg && typeof cfg.name === 'string'));
}
if (includeCompounds && config.compounds) {
if (config.compounds) {
configurations.push(...config.compounds.filter(compound => typeof compound.name === 'string' && compound.configurations && compound.configurations.length));
}
if (ignoreCompoundsAndPresentation) {
return configurations.map(c => c.name);
}
if (config.compounds) {
configurations.push(...config.compounds.filter(compound => typeof compound.name === 'string' && compound.configurations && compound.configurations.length));
}
return getVisibleAndSorted(configurations).map(c => c.name);
}
}

View File

@@ -43,17 +43,26 @@ export class DebugProgressContribution implements IWorkbenchContribution {
source,
delay: 500
}, progressStep => {
let increment = 0;
let total = 0;
const reportProgress = (progress: { message?: string, percentage?: number }) => {
let increment = undefined;
if (typeof progress.percentage === 'number') {
increment = progress.percentage - total;
total += increment;
}
progressStep.report({
message: progress.message,
increment,
total: typeof increment === 'number' ? 100 : undefined,
});
};
if (progressStartEvent.body.message) {
reportProgress(progressStartEvent.body);
}
const progressUpdateListener = session.onDidProgressUpdate(e => {
if (e.body.progressId === progressStartEvent.body.progressId) {
if (typeof e.body.percentage === 'number') {
increment = e.body.percentage - increment;
}
progressStep.report({
message: e.body.message,
increment: typeof e.body.percentage === 'number' ? increment : undefined,
total: typeof e.body.percentage === 'number' ? 100 : undefined,
});
reportProgress(e.body);
}
});

View File

@@ -24,7 +24,11 @@ export class StartDebugQuickAccessProvider extends PickerQuickAccessProvider<IPi
@ICommandService private readonly commandService: ICommandService,
@INotificationService private readonly notificationService: INotificationService
) {
super(StartDebugQuickAccessProvider.PREFIX);
super(StartDebugQuickAccessProvider.PREFIX, {
noResultsPick: {
label: localize('noDebugResults', "No matching launch configurations")
}
});
}
protected getPicks(filter: string): (IQuickPickSeparator | IPickerQuickAccessItem)[] {
@@ -47,7 +51,6 @@ export class StartDebugQuickAccessProvider extends PickerQuickAccessProvider<IPi
// Launch entry
picks.push({
label: config.name,
ariaLabel: localize('entryAriaLabel', "{0}, debug picker", config.name),
description: this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE ? config.launch.name : '',
highlights: { label: highlights },
buttons: [{
@@ -89,7 +92,6 @@ export class StartDebugQuickAccessProvider extends PickerQuickAccessProvider<IPi
// Add Config entry
picks.push({
label,
ariaLabel: localize('entryAriaLabel', "{0}, debug picker", label),
description: this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE ? launch.name : '',
highlights: { label: withNullAsUndefined(matchesFuzzy(filter, label, true)) },
accept: () => this.commandService.executeCommand('debug.addConfiguration', launch.uri.toString())

View File

@@ -34,6 +34,7 @@ import { distinct } from 'vs/base/common/arrays';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
import { localize } from 'vs/nls';
import { canceled } from 'vs/base/common/errors';
export class DebugSession implements IDebugSession {
@@ -250,6 +251,9 @@ export class DebugSession implements IDebugSession {
if (!this.raw) {
throw new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'launch or attach'));
}
if (this.parentSession && this.parentSession.state === State.Inactive) {
throw canceled();
}
// __sessionID only used for EH debugging (but we add it always for now...)
config.__sessionId = this.getId();

View File

@@ -8,7 +8,7 @@ import * as nls from 'vs/nls';
import { IAction } from 'vs/base/common/actions';
import * as DOM from 'vs/base/browser/dom';
import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { IDebugService, VIEWLET_ID, State, BREAKPOINTS_VIEW_ID, IDebugConfiguration, DEBUG_PANEL_ID, CONTEXT_DEBUG_UX, CONTEXT_DEBUG_UX_KEY } from 'vs/workbench/contrib/debug/common/debug';
import { IDebugService, VIEWLET_ID, State, BREAKPOINTS_VIEW_ID, IDebugConfiguration, CONTEXT_DEBUG_UX, CONTEXT_DEBUG_UX_KEY, REPL_VIEW_ID } from 'vs/workbench/contrib/debug/common/debug';
import { StartAction, ConfigureAction, SelectAndStartAction, FocusSessionAction } from 'vs/workbench/contrib/debug/browser/debugActions';
import { StartDebugActionViewItem, FocusSessionActionViewItem } from 'vs/workbench/contrib/debug/browser/debugActionViewItems';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
@@ -30,10 +30,9 @@ import { IMenu, MenuId, IMenuService, MenuItemAction } from 'vs/platform/actions
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { MenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { TogglePanelAction } from 'vs/workbench/browser/panel';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { IViewDescriptorService } from 'vs/workbench/common/views';
import { IViewDescriptorService, IViewsService } from 'vs/workbench/common/views';
import { WelcomeView } from 'vs/workbench/contrib/debug/browser/welcomeView';
import { ToggleViewAction } from 'vs/workbench/browser/actions/layoutActions';
export class DebugViewPaneContainer extends ViewPaneContainer {
@@ -107,8 +106,8 @@ export class DebugViewPaneContainer extends ViewPaneContainer {
}
@memoize
private get toggleReplAction(): OpenDebugPanelAction {
return this._register(this.instantiationService.createInstance(OpenDebugPanelAction, OpenDebugPanelAction.ID, OpenDebugPanelAction.LABEL));
private get toggleReplAction(): OpenDebugConsoleAction {
return this._register(this.instantiationService.createInstance(OpenDebugConsoleAction, OpenDebugConsoleAction.ID, OpenDebugConsoleAction.LABEL));
}
@memoize
@@ -231,16 +230,18 @@ export class DebugViewPaneContainer extends ViewPaneContainer {
}
}
export class OpenDebugPanelAction extends TogglePanelAction {
export class OpenDebugConsoleAction extends ToggleViewAction {
public static readonly ID = 'workbench.debug.action.toggleRepl';
public static readonly LABEL = nls.localize('toggleDebugPanel', "Debug Console");
constructor(
id: string,
label: string,
@IPanelService panelService: IPanelService,
@IViewsService viewsService: IViewsService,
@IViewDescriptorService viewDescriptorService: IViewDescriptorService,
@IContextKeyService contextKeyService: IContextKeyService,
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService
) {
super(id, label, DEBUG_PANEL_ID, panelService, layoutService, 'codicon-repl');
super(id, label, REPL_VIEW_ID, viewsService, viewDescriptorService, contextKeyService, layoutService, 'codicon-debug-console');
}
}

View File

@@ -75,6 +75,11 @@ export class WelcomeView extends ViewPane {
};
this._register(editorService.onDidActiveEditorChange(setContextKey));
this._register(this.debugService.getConfigurationManager().onDidRegisterDebugger(setContextKey));
this._register(this.onDidChangeBodyVisibility(visible => {
if (visible) {
setContextKey();
}
}));
setContextKey();
const debugKeybinding = this.keybindingService.lookupKeybinding(StartAction.ID);

View File

@@ -710,7 +710,7 @@ export interface ILaunch {
* Returns the names of all configurations and compounds.
* Ignores configurations which are invalid.
*/
getConfigurationNames(includeCompounds?: boolean): string[];
getConfigurationNames(ignoreCompoundsAndPresentation?: boolean): string[];
/**
* Opens the launch.json file. Creates if it does not exist.

View File

@@ -862,7 +862,15 @@ export class ExtensionEditor extends BaseEditor {
extensionPackReadme.style.maxWidth = '882px';
const extensionPack = append(extensionPackReadme, $('div', { class: 'extension-pack' }));
toggleClass(extensionPackReadme, 'narrow', manifest.extensionPack!.length <= 2);
if (manifest.extensionPack!.length <= 3) {
addClass(extensionPackReadme, 'one-row');
} else if (manifest.extensionPack!.length <= 6) {
addClass(extensionPackReadme, 'two-rows');
} else if (manifest.extensionPack!.length <= 9) {
addClass(extensionPackReadme, 'three-rows');
} else {
addClass(extensionPackReadme, 'more-rows');
}
const extensionPackHeader = append(extensionPack, $('div.header'));
extensionPackHeader.textContent = localize('extension pack', "Extension Pack ({0})", manifest.extensionPack!.length);

View File

@@ -2605,7 +2605,7 @@ export class MaliciousStatusLabelAction extends ExtensionAction {
export class SyncIgnoredIconAction extends ExtensionAction {
private static readonly ENABLE_CLASS = `${ExtensionAction.ICON_ACTION_CLASS} codicon-eye-closed`;
private static readonly ENABLE_CLASS = `${ExtensionAction.ICON_ACTION_CLASS} codicon-sync-ignored`;
private static readonly DISABLE_CLASS = `${SyncIgnoredIconAction.ENABLE_CLASS} hide`;
constructor(

View File

@@ -54,7 +54,7 @@ export class ExtensionsGridView extends Disposable {
private renderExtension(extension: IExtension, index: number): void {
const extensionContainer = dom.append(this.element, dom.$('.extension-container'));
extensionContainer.style.height = `${this.delegate.getHeight()}px`;
extensionContainer.style.width = `350px`;
extensionContainer.style.width = `275px`;
extensionContainer.setAttribute('tabindex', '0');
const template = this.renderer.renderTemplate(extensionContainer);

View File

@@ -55,6 +55,7 @@
.monaco-action-bar .action-item.disabled .action-label.extension-action {
opacity: 1;
pointer-events: none;
}
.monaco-action-bar .action-item.disabled .action-label.extension-action.text {

View File

@@ -277,16 +277,36 @@
padding-left: 20px;
}
.extension-editor > .body > .content > .extension-pack-readme.narrow > .extension-pack {
.extension-editor > .body > .content > .extension-pack-readme.one-row > .extension-pack {
height: 142px;
}
.extension-editor > .body > .content > .extension-pack-readme > .readme-content {
.extension-editor > .body > .content > .extension-pack-readme.two-rows > .extension-pack {
height: 224px;
}
.extension-editor > .body > .content > .extension-pack-readme.three-rows > .extension-pack {
height: 306px;
}
.extension-editor > .body > .content > .extension-pack-readme.more-rows > .extension-pack {
height: 326px;
}
.extension-editor > .body > .content > .extension-pack-readme.one-row > .readme-content {
height: calc(100% - 142px);
}
.extension-editor > .body > .content > .extension-pack-readme.two-rows > .readme-content {
height: calc(100% - 224px);
}
.extension-editor > .body > .content > .extension-pack-readme.narrow > .readme-content {
height: calc(100% - 142px);
.extension-editor > .body > .content > .extension-pack-readme.three-rows > .readme-content {
height: calc(100% - 306px);
}
.extension-editor > .body > .content > .extension-pack-readme.more-rows > .readme-content {
height: calc(100% - 326px);
}
.extension-editor > .body > .content > .extension-pack-readme > .extension-pack > .header,
@@ -483,6 +503,12 @@
cursor: pointer;
}
.extension-editor .extensions-grid-view .extension-list-item > .details > .header-container > .header > .version,
.extension-editor .extensions-grid-view .extension-list-item > .details > .header-container > .header > .ratings,
.extension-editor .extensions-grid-view .extension-list-item > .details > .header-container > .header > .install-count {
display: none;
}
.extension-editor .extensions-grid-view > .extension-container:focus > .extension-list-item > .details .header > .name,
.extension-editor .extensions-grid-view > .extension-container:focus > .extension-list-item > .details .header > .name:hover {
text-decoration: underline;

View File

@@ -89,8 +89,4 @@ export class EmptyView extends ViewPane {
this.updateTitle(this.title);
}
}
layoutBody(_size: number): void {
// no-op
}
}

View File

@@ -499,7 +499,13 @@ export class ExplorerView extends ViewPane {
const actions: IAction[] = [];
const roots = this.explorerService.roots; // If the click is outside of the elements pass the root resource if there is only one root. If there are multiple roots pass empty object.
const arg = stat instanceof ExplorerItem ? stat.resource : roots.length === 1 ? roots[0].resource : {};
let arg: URI | {};
if (stat instanceof ExplorerItem) {
const compressedController = this.renderer.getCompressedNavigationController(stat);
arg = compressedController ? compressedController.current.resource : stat.resource;
} else {
arg = roots.length === 1 ? roots[0].resource : {};
}
disposables.add(createAndFillInContextMenuActions(this.contributedContextMenu, { arg, shouldForwardArgs: true }, actions, this.contextMenuService));
this.contextMenuService.showContextMenu({

View File

@@ -4,9 +4,8 @@
*--------------------------------------------------------------------------------------------*/
import 'vs/workbench/contrib/markers/browser/markersFileDecorations';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
@@ -14,7 +13,6 @@ import { localize } from 'vs/nls';
import { Marker, RelatedInformation } from 'vs/workbench/contrib/markers/browser/markersModel';
import { MarkersView } from 'vs/workbench/contrib/markers/browser/markersView';
import { MenuId, MenuRegistry, SyncActionDescriptor, registerAction2, Action2 } from 'vs/platform/actions/common/actions';
import { TogglePanelAction } from 'vs/workbench/browser/panel';
import { Registry } from 'vs/platform/registry/common/platform';
import { ShowProblemsPanelAction } from 'vs/workbench/contrib/markers/browser/markersViewActions';
import Constants from 'vs/workbench/contrib/markers/browser/constants';
@@ -28,11 +26,12 @@ import { Disposable } from 'vs/base/common/lifecycle';
import { IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment, IStatusbarEntry } from 'vs/workbench/services/statusbar/common/statusbar';
import { IMarkerService, MarkerStatistics } from 'vs/platform/markers/common/markers';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { ViewContainer, IViewContainersRegistry, Extensions as ViewContainerExtensions, ViewContainerLocation, IViewsRegistry, IViewsService, getVisbileViewContextKey, FocusedViewContext } from 'vs/workbench/common/views';
import { ViewContainer, IViewContainersRegistry, Extensions as ViewContainerExtensions, ViewContainerLocation, IViewsRegistry, IViewsService, getVisbileViewContextKey, FocusedViewContext, IViewDescriptorService } from 'vs/workbench/common/views';
import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer';
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import type { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { ToggleViewAction } from 'vs/workbench/browser/actions/layoutActions';
registerSingleton(IMarkersWorkbenchService, MarkersWorkbenchService, false);
@@ -94,16 +93,18 @@ Registry.as<IConfigurationRegistry>(Extensions.Configuration).registerConfigurat
}
});
class ToggleMarkersPanelAction extends TogglePanelAction {
class ToggleMarkersPanelAction extends ToggleViewAction {
public static readonly ID = 'workbench.actions.view.problems';
public static readonly LABEL = Messages.MARKERS_PANEL_TOGGLE_LABEL;
constructor(id: string, label: string,
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
@IPanelService panelService: IPanelService
@IViewsService viewsService: IViewsService,
@IViewDescriptorService viewDescriptorService: IViewDescriptorService,
@IContextKeyService contextKeyService: IContextKeyService,
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService
) {
super(id, label, Constants.MARKERS_CONTAINER_ID, panelService, layoutService);
super(id, label, Constants.MARKERS_VIEW_ID, viewsService, viewDescriptorService, contextKeyService, layoutService);
}
}

View File

@@ -3,26 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export const INSERT_CODE_CELL_ABOVE_COMMAND_ID = 'workbench.notebook.code.insertCellAbove';
export const INSERT_CODE_CELL_BELOW_COMMAND_ID = 'workbench.notebook.code.insertCellBelow';
export const INSERT_MARKDOWN_CELL_ABOVE_COMMAND_ID = 'workbench.notebook.markdown.insertCellAbove';
export const INSERT_MARKDOWN_CELL_BELOW_COMMAND_ID = 'workbench.notebook.markdown.insertCellBelow';
export const EDIT_CELL_COMMAND_ID = 'workbench.notebook.cell.edit';
export const SAVE_CELL_COMMAND_ID = 'workbench.notebook.cell.save';
export const DELETE_CELL_COMMAND_ID = 'workbench.notebook.cell.delete';
export const MOVE_CELL_UP_COMMAND_ID = 'workbench.notebook.cell.moveUp';
export const MOVE_CELL_DOWN_COMMAND_ID = 'workbench.notebook.cell.moveDown';
export const COPY_CELL_UP_COMMAND_ID = 'workbench.notebook.cell.copyUp';
export const COPY_CELL_DOWN_COMMAND_ID = 'workbench.notebook.cell.copyDown';
export const EXECUTE_CELL_COMMAND_ID = 'workbench.notebook.cell.execute';
export const EXECUTE_ACTIVE_CELL_COMMAND_ID = 'workbench.notebook.cell.executeActive';
export const CANCEL_CELL_COMMAND_ID = 'workbench.notebook.cell.cancelExecution';
export const EXECUTE_NOTEBOOK_COMMAND_ID = 'workbench.notebook.executeNotebook';
export const CANCEL_NOTEBOOK_COMMAND_ID = 'workbench.notebook.cancelExecution';
// Cell sizing related
export const CELL_MARGIN = 20;
export const CELL_RUN_GUTTER = 32; // TODO should be dynamic based on execution order width, and runnable enablement

View File

@@ -12,11 +12,33 @@ import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/commo
import { InputFocusedContext, InputFocusedContextKey, IsDevelopmentContext } from 'vs/platform/contextkey/common/contextkeys';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { CANCEL_CELL_COMMAND_ID, CANCEL_NOTEBOOK_COMMAND_ID, COPY_CELL_DOWN_COMMAND_ID, COPY_CELL_UP_COMMAND_ID, DELETE_CELL_COMMAND_ID, EDIT_CELL_COMMAND_ID, EXECUTE_ACTIVE_CELL_COMMAND_ID, EXECUTE_CELL_COMMAND_ID, EXECUTE_NOTEBOOK_COMMAND_ID, INSERT_CODE_CELL_ABOVE_COMMAND_ID, INSERT_CODE_CELL_BELOW_COMMAND_ID, INSERT_MARKDOWN_CELL_ABOVE_COMMAND_ID, INSERT_MARKDOWN_CELL_BELOW_COMMAND_ID, MOVE_CELL_DOWN_COMMAND_ID, MOVE_CELL_UP_COMMAND_ID, NOTEBOOK_CELL_EDITABLE_CONTEXT_KEY, NOTEBOOK_CELL_MARKDOWN_EDIT_MODE_CONTEXT_KEY, NOTEBOOK_CELL_TYPE_CONTEXT_KEY, NOTEBOOK_EDITABLE_CONTEXT_KEY, NOTEBOOK_EXECUTING_KEY, SAVE_CELL_COMMAND_ID } from 'vs/workbench/contrib/notebook/browser/constants';
import { NOTEBOOK_CELL_EDITABLE_CONTEXT_KEY, NOTEBOOK_CELL_MARKDOWN_EDIT_MODE_CONTEXT_KEY, NOTEBOOK_CELL_TYPE_CONTEXT_KEY, NOTEBOOK_EDITABLE_CONTEXT_KEY, NOTEBOOK_EXECUTING_KEY } from 'vs/workbench/contrib/notebook/browser/constants';
import { BaseCellRenderTemplate, CellEditState, CellRunState, ICellViewModel, INotebookEditor, KEYBINDING_CONTEXT_NOTEBOOK_FIND_WIDGET_FOCUSED, NOTEBOOK_EDITOR_EXECUTING_NOTEBOOK, NOTEBOOK_EDITOR_FOCUSED } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { CellKind, NOTEBOOK_EDITOR_CURSOR_BOUNDARY } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
const INSERT_CODE_CELL_ABOVE_COMMAND_ID = 'workbench.notebook.code.insertCellAbove';
const INSERT_CODE_CELL_BELOW_COMMAND_ID = 'workbench.notebook.code.insertCellBelow';
const INSERT_MARKDOWN_CELL_ABOVE_COMMAND_ID = 'workbench.notebook.markdown.insertCellAbove';
const INSERT_MARKDOWN_CELL_BELOW_COMMAND_ID = 'workbench.notebook.markdown.insertCellBelow';
const EDIT_CELL_COMMAND_ID = 'workbench.notebook.cell.edit';
const SAVE_CELL_COMMAND_ID = 'workbench.notebook.cell.save';
const DELETE_CELL_COMMAND_ID = 'workbench.notebook.cell.delete';
const MOVE_CELL_UP_COMMAND_ID = 'workbench.notebook.cell.moveUp';
const MOVE_CELL_DOWN_COMMAND_ID = 'workbench.notebook.cell.moveDown';
const COPY_CELL_UP_COMMAND_ID = 'workbench.notebook.cell.copyUp';
const COPY_CELL_DOWN_COMMAND_ID = 'workbench.notebook.cell.copyDown';
const EXECUTE_CELL_COMMAND_ID = 'workbench.notebook.cell.execute';
const EXECUTE_ACTIVE_CELL_COMMAND_ID = 'workbench.notebook.cell.executeActive';
const CANCEL_CELL_COMMAND_ID = 'workbench.notebook.cell.cancelExecution';
const EXECUTE_NOTEBOOK_COMMAND_ID = 'workbench.notebook.executeNotebook';
const CANCEL_NOTEBOOK_COMMAND_ID = 'workbench.notebook.cancelExecution';
const NOTEBOOK_ACTIONS_CATEGORY = localize('notebookActions.category', "Notebook");
const enum CellToolbarOrder {
MoveCellUp,
MoveCellDown,
@@ -30,7 +52,8 @@ registerAction2(class extends Action2 {
constructor() {
super({
id: EXECUTE_CELL_COMMAND_ID,
title: localize('notebookActions.execute', "Execute Notebook Cell"),
category: NOTEBOOK_ACTIONS_CATEGORY,
title: localize('notebookActions.execute', "Execute Cell"),
keybinding: {
when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, InputFocusedContext),
primary: KeyMod.WinCtrl | KeyCode.Enter,
@@ -39,7 +62,8 @@ registerAction2(class extends Action2 {
},
weight: KeybindingWeight.WorkbenchContrib
},
icon: { id: 'codicon/play' }
icon: { id: 'codicon/play' },
f1: true
});
}
@@ -59,8 +83,8 @@ registerAction2(class extends Action2 {
constructor() {
super({
id: CANCEL_CELL_COMMAND_ID,
title: localize('notebookActions.cancel', "Cancel Execution"),
icon: { id: 'codicon/stop' }
title: localize('notebookActions.cancel', "Stop Execution"),
icon: { id: 'codicon/primitive-square' }
});
}
@@ -103,7 +127,7 @@ export class CancelCellAction extends MenuItemAction {
{
id: CANCEL_CELL_COMMAND_ID,
title: localize('notebookActions.CancelCell', "Cancel Execution"),
icon: { id: 'codicon/stop' }
icon: { id: 'codicon/primitive-square' }
},
undefined,
{ shouldForwardArgs: true },
@@ -331,8 +355,8 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, {
MenuRegistry.appendMenuItem(MenuId.EditorTitle, {
command: {
id: CANCEL_NOTEBOOK_COMMAND_ID,
title: localize('notebookActions.menu.cancelNotebook', "Cancel Notebook Execution"),
icon: { id: 'codicon/stop' }
title: localize('notebookActions.menu.cancelNotebook', "Stop Notebook Execution"),
icon: { id: 'codicon/primitive-square' }
},
order: -1,
group: 'navigation',
@@ -346,7 +370,7 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, {
title: localize('notebookActions.menu.execute', "Execute Notebook Cell"),
icon: { id: 'codicon/run' }
},
order: -1,
order: 0,
group: 'navigation',
when: NOTEBOOK_EDITOR_FOCUSED
});
@@ -387,7 +411,7 @@ registerAction2(class extends Action2 {
}
});
function getActiveNotebookEditor(editorService: IEditorService): INotebookEditor | undefined {
export function getActiveNotebookEditor(editorService: IEditorService): INotebookEditor | undefined {
// TODO can `isNotebookEditor` be on INotebookEditor to avoid a circular dependency?
const activeEditorPane = editorService.activeEditorPane as any | undefined;
return activeEditorPane?.isNotebookEditor ? activeEditorPane : undefined;
@@ -531,6 +555,7 @@ registerAction2(class extends InsertCellCommand {
{
id: INSERT_CODE_CELL_BELOW_COMMAND_ID,
title: localize('notebookActions.insertCodeCellBelow', "Insert Code Cell Below"),
category: NOTEBOOK_ACTIONS_CATEGORY,
icon: { id: 'codicon/add' },
menu: {
id: MenuId.NotebookCellTitle,
@@ -541,7 +566,8 @@ registerAction2(class extends InsertCellCommand {
icon: { id: 'codicon/add' },
},
when: ContextKeyExpr.equals(NOTEBOOK_EDITABLE_CONTEXT_KEY, true)
}
},
f1: true
},
CellKind.Code,
'below');
@@ -661,12 +687,14 @@ registerAction2(class extends Action2 {
{
id: DELETE_CELL_COMMAND_ID,
title: localize('notebookActions.deleteCell', "Delete Cell"),
category: NOTEBOOK_ACTIONS_CATEGORY,
menu: {
id: MenuId.NotebookCellTitle,
order: CellToolbarOrder.DeleteCell,
when: ContextKeyExpr.equals(NOTEBOOK_EDITABLE_CONTEXT_KEY, true)
},
icon: { id: 'codicon/trash' }
icon: { id: 'codicon/trash' },
f1: true
});
}
@@ -700,6 +728,7 @@ registerAction2(class extends Action2 {
{
id: MOVE_CELL_UP_COMMAND_ID,
title: localize('notebookActions.moveCellUp', "Move Cell Up"),
category: NOTEBOOK_ACTIONS_CATEGORY,
icon: { id: 'codicon/arrow-up' },
menu: {
id: MenuId.NotebookCellTitle,
@@ -711,6 +740,7 @@ registerAction2(class extends Action2 {
},
when: ContextKeyExpr.equals(NOTEBOOK_EDITABLE_CONTEXT_KEY, true)
},
f1: true
});
}
@@ -732,6 +762,7 @@ registerAction2(class extends Action2 {
{
id: MOVE_CELL_DOWN_COMMAND_ID,
title: localize('notebookActions.moveCellDown', "Move Cell Down"),
category: NOTEBOOK_ACTIONS_CATEGORY,
icon: { id: 'codicon/arrow-down' },
menu: {
id: MenuId.NotebookCellTitle,
@@ -743,6 +774,7 @@ registerAction2(class extends Action2 {
},
when: ContextKeyExpr.equals(NOTEBOOK_EDITABLE_CONTEXT_KEY, true)
},
f1: true
});
}
@@ -950,6 +982,7 @@ registerAction2(class extends Action2 {
super({
id: 'workbench.action.notebook.testResize',
title: 'Notebook Test Cell Resize',
category: NOTEBOOK_ACTIONS_CATEGORY,
keybinding: {
when: IsDevelopmentContext,
primary: undefined,

View File

@@ -27,7 +27,7 @@ import { IModeService } from 'vs/editor/common/services/modeService';
import { IDisposable } from 'vs/base/common/lifecycle';
import { assertType } from 'vs/base/common/types';
import { parse } from 'vs/base/common/marshalling';
import { CellUri } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CellUri, CellKind } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { ResourceMap } from 'vs/base/common/map';
// Output renderers registration
@@ -177,10 +177,11 @@ class CellContentProvider implements ITextModelContentProvider {
}
for (let cell of notebook.cells) {
if (cell.uri.toString() === resource.toString()) {
let bufferFactory = cell.resolveTextBufferFactory();
const bufferFactory = cell.resolveTextBufferFactory();
const language = cell.cellKind === CellKind.Markdown ? this._modeService.create('markdown') : (cell.language ? this._modeService.create(cell.language) : this._modeService.createByFilepathOrFirstLine(resource, cell.source[0]));
return this._modelService.createModel(
bufferFactory,
cell.language ? this._modeService.create(cell.language) : this._modeService.createByFilepathOrFirstLine(resource, cell.source[0]),
language,
resource
);
}

View File

@@ -30,6 +30,11 @@
position: relative;
}
.monaco-workbench .part.editor > .content .notebook-editor .cell-list-container .webview-cover {
position: absolute;
top: 0;
}
.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell {
display: flex;
}
@@ -206,6 +211,8 @@
position: absolute;
display: flex;
opacity: 0;
transition: opacity 0.2s ease-in-out;
cursor: auto;
}
.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-bottom-toolbar-container:hover {
@@ -230,6 +237,7 @@
align-self: center;
align-items: center;
white-space: pre;
cursor: pointer;
}
.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-bottom-toolbar-container span.codicon {

View File

@@ -18,6 +18,7 @@ import { NOTEBOOK_EDITABLE_CONTEXT_KEY, NOTEBOOK_EXECUTING_KEY } from 'vs/workbe
import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer';
import { CellViewModel, IModelDecorationsChangeAccessor, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
import { CellKind, IOutput, IRenderOutput, NotebookCellMetadata, NotebookDocumentMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { Webview } from 'vs/workbench/contrib/webview/browser/webview';
export const KEYBINDING_CONTEXT_NOTEBOOK_FIND_WIDGET_FOCUSED = new RawContextKey<boolean>('notebookFindWidgetFocused', false);
@@ -59,11 +60,14 @@ export interface CodeCellLayoutChangeEvent {
export interface MarkdownCellLayoutInfo {
readonly fontInfo: BareFontInfo | null;
readonly editorWidth: number;
readonly bottomToolbarOffset: number;
readonly totalHeight: number;
}
export interface MarkdownCellLayoutChangeEvent {
font?: BareFontInfo;
outerWidth?: number;
totalHeight?: number;
}
export interface ICellViewModel {
@@ -89,6 +93,8 @@ export interface INotebookEditor {
isNotebookEditor: boolean;
getInnerWebview(): Webview | undefined;
/**
* Focus the notebook editor cell list
*/
@@ -268,6 +274,7 @@ export interface BaseCellRenderTemplate {
toolbar: ToolBar;
focusIndicator: HTMLElement;
disposables: DisposableStore;
bottomCellContainer: HTMLElement;
toJSON: () => any;
}
@@ -283,7 +290,6 @@ export interface CodeCellRenderTemplate extends BaseCellRenderTemplate {
outputContainer: HTMLElement;
editor: CodeEditorWidget;
progressBar: ProgressBar;
betweenCellContainer: HTMLElement;
}
export interface IOutputTransformContribution {

View File

@@ -5,7 +5,7 @@
import { getZoomLevel } from 'vs/base/browser/browser';
import * as DOM from 'vs/base/browser/dom';
import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent';
import { IMouseWheelEvent, StandardMouseEvent } from 'vs/base/browser/mouseEvent';
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
import { Color, RGBA } from 'vs/base/common/color';
import { Emitter, Event } from 'vs/base/common/event';
@@ -43,6 +43,7 @@ import { CellViewModel, IModelDecorationsChangeAccessor, INotebookEditorViewStat
import { CellKind, CellUri, IOutput } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { getExtraColor } from 'vs/workbench/contrib/welcome/walkThrough/common/walkThroughUtils';
import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { Webview } from 'vs/workbench/contrib/webview/browser/webview';
const $ = DOM.$;
const NOTEBOOK_EDITOR_VIEW_STATE_PREFERENCE_KEY = 'NotebookEditorViewState';
@@ -91,6 +92,7 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
private rootElement!: HTMLElement;
private body!: HTMLElement;
private webview: BackLayerWebView | null = null;
private webviewTransparentCover: HTMLElement | null = null;
private list: NotebookCellList | undefined;
private control: ICompositeCodeEditor | undefined;
private renderedEditors: Map<ICellViewModel, ICodeEditor | undefined> = new Map();
@@ -231,13 +233,36 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
}
}));
this.list.rowsContainer.appendChild(this.webview.element);
this._register(this.list);
// transparent cover
this.webviewTransparentCover = DOM.append(this.list.rowsContainer, $('.webview-cover'));
this.webviewTransparentCover.style.display = 'none';
this._register(DOM.addStandardDisposableGenericMouseDownListner(this.rootElement, (e: StandardMouseEvent) => {
if (DOM.hasClass(e.target, 'slider') && this.webviewTransparentCover) {
this.webviewTransparentCover.style.display = 'block';
}
}));
this._register(DOM.addStandardDisposableGenericMouseUpListner(this.rootElement, (e: StandardMouseEvent) => {
if (this.webviewTransparentCover) {
// no matter when
this.webviewTransparentCover.style.display = 'none';
}
}));
}
getControl() {
return this.control;
}
getInnerWebview(): Webview | undefined {
return this.webview?.webview;
}
onHide() {
this.editorFocus?.set(false);
if (this.webview) {
@@ -290,6 +315,7 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
const cellOptions = options.cellOptions;
const cell = this.notebookViewModel!.viewCells.find(cell => cell.uri.toString() === cellOptions.resource.toString());
if (cell) {
this.selectElement(cell);
this.revealInCenterIfOutsideViewport(cell);
const editor = this.renderedEditors.get(cell)!;
if (editor) {
@@ -324,6 +350,7 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
this.webview?.clearInsets();
this.webview?.clearPreloadsCache();
this.findWidget.clear();
this.list?.splice(0, this.list?.length || 0);
}
private async attachModel(input: NotebookEditorInput, model: NotebookEditorModel) {
@@ -339,14 +366,6 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
const viewState = this.loadTextEditorViewState(input);
this.notebookViewModel.restoreEditorViewState(viewState);
if (viewState?.scrollPosition !== undefined) {
this.list!.scrollTop = viewState!.scrollPosition.top;
this.list!.scrollLeft = viewState!.scrollPosition.left;
} else {
this.list!.scrollTop = 0;
this.list!.scrollLeft = 0;
}
this.localStore.add(this.eventDispatcher.onDidChangeMetadata((e) => {
this.editorEditable?.set(e.source.editable);
}));
@@ -385,6 +404,7 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
this.localStore.add(this.list!.onWillScroll(e => {
this.webview!.updateViewScrollTop(-e.scrollTop, []);
this.webviewTransparentCover!.style.top = `${e.scrollTop}px`;
}));
this.localStore.add(this.list!.onDidChangeContentHeight(() => {
@@ -413,9 +433,16 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
}
}));
this.list?.splice(0, this.list?.length || 0);
this.list?.splice(0, 0, this.notebookViewModel!.viewCells as CellViewModel[]);
this.list?.layout();
if (viewState?.scrollPosition !== undefined) {
this.list!.scrollTop = viewState!.scrollPosition.top;
this.list!.scrollLeft = viewState!.scrollPosition.left;
} else {
this.list!.scrollTop = 0;
this.list!.scrollLeft = 0;
}
}
private saveTextEditorViewState(input: NotebookEditorInput): void {
@@ -423,6 +450,17 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
const state = this.notebookViewModel.saveEditorViewState();
if (this.list) {
state.scrollPosition = { left: this.list.scrollLeft, top: this.list.scrollTop };
let cellHeights: { [key: number]: number } = {};
for (let i = 0; i < this.list.length; i++) {
const elm = this.list.element(i)!;
if (elm.cellKind === CellKind.Code) {
cellHeights[i] = elm.layoutInfo.totalHeight;
} else {
cellHeights[i] = 0;
}
}
state.cellTotalHeights = cellHeights;
}
this.editorMemento.saveEditorState(this.group, input.resource, state);
@@ -444,6 +482,12 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
DOM.size(this.body, dimension.width, dimension.height);
this.list?.updateOptions({ additionalScrollHeight: dimension.height });
this.list?.layout(dimension.height, dimension.width);
if (this.webviewTransparentCover) {
this.webviewTransparentCover.style.height = `${dimension.height}px`;
this.webviewTransparentCover.style.width = `${dimension.width}px`;
}
this.eventDispatcher?.emit([new NotebookLayoutChangedEvent({ width: true, fontInfo: true }, this.getLayoutInfo())]);
}

View File

@@ -123,6 +123,14 @@ export class NotebookCellList extends WorkbenchList<CellViewModel> implements ID
return this.view.elementTop(index);
}
getElementHeight(index: number): number {
if (index < 0 || index >= this.length) {
throw new ListError(this.listUser, `Invalid index ${index}`);
}
return this.view.elementHeight(index);
}
triggerScrollFromMouseWheelEvent(browserEvent: IMouseWheelEvent) {
this.view.triggerScrollFromMouseWheelEvent(browserEvent);
}

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IRenderOutput, CellOutputKind } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { IRenderOutput, CellOutputKind, IErrorOutput } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { registerOutputTransform } from 'vs/workbench/contrib/notebook/browser/notebookRegistry';
import * as DOM from 'vs/base/browser/dom';
import { RGBA, Color } from 'vs/base/common/color';
@@ -18,7 +18,15 @@ class ErrorTransform implements IOutputTransformContribution {
) {
}
render(output: any, container: HTMLElement): IRenderOutput {
render(output: IErrorOutput, container: HTMLElement): IRenderOutput {
const header = document.createElement('div');
const headerMessage = output.ename && output.evalue
? `${output.ename}: ${output.evalue}`
: output.ename || output.evalue;
if (headerMessage) {
header.innerText = headerMessage;
container.appendChild(header);
}
const traceback = document.createElement('pre');
DOM.addClasses(traceback, 'traceback');
if (output.traceback) {

View File

@@ -5,9 +5,9 @@
import * as DOM from 'vs/base/browser/dom';
import { Disposable } from 'vs/base/common/lifecycle';
import * as path from 'vs/base/common/path';
import { URI } from 'vs/base/common/uri';
import * as UUID from 'vs/base/common/uuid';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { INotebookService } from 'vs/workbench/contrib/notebook/browser/notebookService';
import { IOutput } from 'vs/workbench/contrib/notebook/common/notebookCommon';
@@ -26,6 +26,12 @@ export interface IDimentionMessage {
data: DOM.Dimension;
}
export interface IWheelMessage {
__vscode_notebook_message: boolean;
type: 'did-scroll-wheel';
payload: any;
}
export interface IScrollAckMessage {
__vscode_notebook_message: boolean;
@@ -73,7 +79,7 @@ export interface IUpdatePreloadResourceMessage {
resources: string[];
}
type IMessage = IDimentionMessage | IScrollAckMessage;
type IMessage = IDimentionMessage | IScrollAckMessage | IWheelMessage;
let version = 0;
export class BackLayerWebView extends Disposable {
@@ -92,7 +98,6 @@ export class BackLayerWebView extends Disposable {
public notebookEditor: INotebookEditor,
@IWebviewService webviewService: IWebviewService,
@IOpenerService openerService: IOpenerService,
@IEnvironmentService private readonly environmentSerice: IEnvironmentService,
@INotebookService private readonly notebookService: INotebookService,
) {
super();
@@ -186,6 +191,45 @@ export class BackLayerWebView extends Disposable {
observers.push(resizeObserver);
}
function scrollWillGoToParent(event) {
for (let node = event.target; node; node = node.parentNode) {
if (node.id === 'container') {
return false;
}
if (event.deltaY < 0 && node.scrollTop > 0) {
return true;
}
if (event.deltaY > 0 && node.scrollTop + node.clientHeight < node.scrollHeight) {
return true;
}
}
return false;
}
const handleWheel = (event) => {
if (event.defaultPrevented || scrollWillGoToParent(event)) {
return;
}
vscode.postMessage({
__vscode_notebook_message: true,
type: 'did-scroll-wheel',
payload: {
deltaMode: event.deltaMode,
deltaX: event.deltaX,
deltaY: event.deltaY,
deltaZ: event.deltaZ,
detail: event.detail,
type: event.type
}
});
};
window.addEventListener('wheel', handleWheel);
window.addEventListener('message', event => {
let id = event.data.id;
@@ -276,10 +320,6 @@ export class BackLayerWebView extends Disposable {
openerService.open(link, { fromUserGesture: true });
}));
this._register(this.webview.onDidWheel(e => {
this.notebookEditor.triggerScroll(e);
}));
this._register(this.webview.onMessage((data: IMessage) => {
if (data.__vscode_notebook_message) {
if (data.type === 'dimension') {
@@ -302,6 +342,8 @@ export class BackLayerWebView extends Disposable {
// const date = new Date();
// const top = data.data.top;
// console.log('ack top ', top, ' version: ', data.version, ' - ', date.getMinutes() + ':' + date.getSeconds() + ':' + date.getMilliseconds());
} else if (data.type === 'did-scroll-wheel') {
this.notebookEditor.triggerScroll(data.payload);
}
return;
}
@@ -311,7 +353,8 @@ export class BackLayerWebView extends Disposable {
}
private _createInset(webviewService: IWebviewService, content: string) {
this.localResourceRootsCache = [...this.notebookService.getNotebookProviderResourceRoots(), URI.file(this.environmentSerice.appRoot)];
const rootPath = URI.file(path.dirname(getPathFromAmdModule(require, '')));
this.localResourceRootsCache = [...this.notebookService.getNotebookProviderResourceRoots(), rootPath];
const webview = webviewService.createWebviewElement('' + UUID.generateUuid(), {
enableFindWidget: false,
}, {

View File

@@ -84,6 +84,7 @@ export class CodiconActionViewItem extends ContextAwareMenuEntryActionViewItem {
abstract class AbstractCellRenderer {
protected editorOptions: IEditorOptions;
private actionRunner = new ActionRunner();
constructor(
protected readonly instantiationService: IInstantiationService,
@@ -138,6 +139,45 @@ abstract class AbstractCellRenderer {
return toolbar;
}
protected setupBetweenCellToolbarActions(element: CodeCellViewModel | MarkdownCellViewModel, templateData: BaseCellRenderTemplate, disposables: DisposableStore, context: INotebookCellActionContext): void {
const container = templateData.bottomCellContainer;
container.innerHTML = '';
container.style.height = `${BOTTOM_CELL_TOOLBAR_HEIGHT}px`;
DOM.append(container, $('.seperator'));
const addCodeCell = DOM.append(container, $('span.button'));
addCodeCell.innerHTML = renderCodicons(escape(`$(add) Code `));
const insertCellBelow = this.instantiationService.createInstance(InsertCodeCellAction);
disposables.add(DOM.addDisposableListener(addCodeCell, DOM.EventType.CLICK, () => {
this.actionRunner.run(insertCellBelow, context);
}));
DOM.append(container, $('.seperator-short'));
const addMarkdownCell = DOM.append(container, $('span.button'));
addMarkdownCell.innerHTML = renderCodicons(escape('$(add) Markdown '));
const insertMarkdownBelow = this.instantiationService.createInstance(InsertMarkdownCellAction);
disposables.add(DOM.addDisposableListener(addMarkdownCell, DOM.EventType.CLICK, () => {
this.actionRunner.run(insertMarkdownBelow, context);
}));
DOM.append(container, $('.seperator'));
if (element instanceof CodeCellViewModel) {
const bottomToolbarOffset = element.layoutInfo.bottomToolbarOffset;
container.style.top = `${bottomToolbarOffset}px`;
disposables.add(element.onDidChangeLayout(() => {
const bottomToolbarOffset = element.layoutInfo.bottomToolbarOffset;
container.style.top = `${bottomToolbarOffset}px`;
}));
} else {
container.style.position = 'static';
container.style.height = '22px';
}
}
protected createToolbar(container: HTMLElement): ToolBar {
const toolbar = new ToolBar(container, this.contextMenuService, {
actionViewItemProvider: action => {
@@ -226,6 +266,7 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR
container.appendChild(innerContent);
const focusIndicator = DOM.append(container, DOM.$('.notebook-cell-focus-indicator'));
const bottomCellContainer = DOM.append(container, $('.cell-bottom-toolbar-container'));
return {
container,
@@ -234,6 +275,7 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR
focusIndicator,
disposables,
toolbar,
bottomCellContainer: bottomCellContainer,
toJSON: () => { return {}; }
};
}
@@ -258,9 +300,16 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR
const contextKeyService = this.contextKeyService.createScoped(templateData.container);
contextKeyService.createKey(NOTEBOOK_CELL_TYPE_CONTEXT_KEY, 'markdown');
contextKeyService.createKey(NOTEBOOK_VIEW_TYPE, element.viewType);
const cellEditableKey = contextKeyService.createKey(NOTEBOOK_CELL_EDITABLE_CONTEXT_KEY, !!(element.metadata?.editable));
const updateForMetadata = () => {
const metadata = element.getEvaluatedMetadata(this.notebookEditor.viewModel!.notebookDocument.metadata);
cellEditableKey.set(!!metadata.editable);
};
updateForMetadata();
elementDisposable.add(element.onDidChangeMetadata(() => {
cellEditableKey.set(!!element.metadata?.editable);
updateForMetadata();
}));
const editModeKey = contextKeyService.createKey(NOTEBOOK_CELL_MARKDOWN_EDIT_MODE_CONTEXT_KEY, element.editState === CellEditState.Editing);
@@ -269,13 +318,18 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR
}));
this.setupCellToolbarActions(contextKeyService, templateData, elementDisposable);
const toolbarContext = <INotebookCellActionContext>{
cell: element,
notebookEditor: this.notebookEditor,
$mid: 12
};
templateData.toolbar.context = toolbarContext;
this.setupBetweenCellToolbarActions(element, templateData, elementDisposable, toolbarContext);
element.totalHeight = height;
}
templateData.toolbar.context = <INotebookCellActionContext>{
cell: element,
notebookEditor: this.notebookEditor,
$mid: 12
};
}
disposeTemplate(templateData: MarkdownCellRenderTemplate): void {
@@ -292,8 +346,6 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR
export class CodeCellRenderer extends AbstractCellRenderer implements IListRenderer<CodeCellViewModel, CodeCellRenderTemplate> {
static readonly TEMPLATE_ID = 'code_cell';
private disposables: Map<ICellViewModel, DisposableStore> = new Map();
private actionRunner = new ActionRunner();
constructor(
protected notebookEditor: INotebookEditor,
@@ -322,7 +374,7 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende
const runToolbar = this.createToolbar(runButtonContainer);
disposables.add(runToolbar);
const betweenCellContainer = DOM.append(container, $('.cell-bottom-toolbar-container'));
const bottomCellContainer = DOM.append(container, $('.cell-bottom-toolbar-container'));
const executionOrderLabel = DOM.append(runButtonContainer, $('div.execution-count-label'));
@@ -358,44 +410,11 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende
outputContainer,
editor,
disposables,
betweenCellContainer: betweenCellContainer,
bottomCellContainer: bottomCellContainer,
toJSON: () => { return {}; }
};
}
protected setupBetweenCellToolbarActions(element: CodeCellViewModel, templateData: CodeCellRenderTemplate, disposables: DisposableStore, context: INotebookCellActionContext): void {
const container = templateData.betweenCellContainer;
container.innerHTML = '';
container.style.height = `${BOTTOM_CELL_TOOLBAR_HEIGHT}px`;
DOM.append(container, $('.seperator'));
const addCodeCell = DOM.append(container, $('span.button'));
addCodeCell.innerHTML = renderCodicons(escape(`$(add) Code `));
const insertCellBelow = this.instantiationService.createInstance(InsertCodeCellAction);
disposables.add(DOM.addDisposableListener(addCodeCell, DOM.EventType.CLICK, () => {
this.actionRunner.run(insertCellBelow, context);
}));
DOM.append(container, $('.seperator-short'));
const addMarkdownCell = DOM.append(container, $('span.button'));
addMarkdownCell.innerHTML = renderCodicons(escape('$(add) Markdown '));
const insertMarkdownBelow = this.instantiationService.createInstance(InsertMarkdownCellAction);
disposables.add(DOM.addDisposableListener(addMarkdownCell, DOM.EventType.CLICK, () => {
this.actionRunner.run(insertMarkdownBelow, context);
}));
DOM.append(container, $('.seperator'));
const bottomToolbarOffset = element.layoutInfo.bottomToolbarOffset;
container.style.top = `${bottomToolbarOffset}px`;
disposables.add(element.onDidChangeLayout(() => {
const bottomToolbarOffset = element.layoutInfo.bottomToolbarOffset;
container.style.top = `${bottomToolbarOffset}px`;
}));
}
private updateForRunState(element: CodeCellViewModel, templateData: CodeCellRenderTemplate, runStateKey: IContextKey<string>): void {
runStateKey.set(CellRunState[element.runState]);
if (element.runState === CellRunState.Running) {

View File

@@ -6,7 +6,6 @@
import * as DOM from 'vs/base/browser/dom';
import { raceCancellation } from 'vs/base/common/async';
import { CancellationTokenSource } from 'vs/base/common/cancellation';
import { debounce } from 'vs/base/common/decorators';
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { IModeService } from 'vs/editor/common/services/modeService';
import * as nls from 'vs/nls';
@@ -45,7 +44,7 @@ export class CodeCell extends Disposable {
height: totalHeight
}
);
viewCell.editorHeight = totalHeight;
// viewCell.editorHeight = totalHeight;
const cts = new CancellationTokenSource();
this._register({ dispose() { cts.dispose(true); } });
@@ -211,6 +210,12 @@ export class CodeCell extends Disposable {
}));
if (viewCell.outputs.length > 0) {
let layoutCache = false;
if (this.viewCell.layoutInfo.totalHeight !== 0) {
layoutCache = true;
this.relayoutCell();
}
this.templateData.outputContainer!.style.display = 'block';
// there are outputs, we need to calcualte their sizes and trigger relayout
// @todo, if there is no resizable output, we should not check their height individually, which hurts the performance
@@ -222,9 +227,15 @@ export class CodeCell extends Disposable {
}
viewCell.editorHeight = totalHeight;
this.relayoutCell();
if (layoutCache) {
this.relayoutCellDebounced();
} else {
this.relayoutCell();
}
} else {
// noop
viewCell.editorHeight = totalHeight;
this.relayoutCell();
this.templateData.outputContainer!.style.display = 'none';
}
}
@@ -390,12 +401,21 @@ export class CodeCell extends Disposable {
}
relayoutCell() {
if (this._timer !== null) {
clearTimeout(this._timer);
}
this.notebookEditor.layoutNotebookCell(this.viewCell, this.viewCell.layoutInfo.totalHeight);
}
@debounce(500)
private _timer: any = null;
relayoutCellDebounced() {
this.notebookEditor.layoutNotebookCell(this.viewCell, this.viewCell.layoutInfo.totalHeight);
clearTimeout(this._timer);
this._timer = setTimeout(() => {
this.notebookEditor.layoutNotebookCell(this.viewCell, this.viewCell.layoutInfo.totalHeight);
this._timer = null;
}, 500);
}
dispose() {

View File

@@ -101,6 +101,7 @@ export class StatefullMarkdownCell extends Disposable {
}
const clientHeight = this.cellContainer.clientHeight;
this.viewCell.totalHeight = totalHeight + 32 + clientHeight;
notebookEditor.layoutNotebookCell(viewCell, totalHeight + 32 + clientHeight);
this.editor.focus();
} else {
@@ -109,6 +110,7 @@ export class StatefullMarkdownCell extends Disposable {
// switch from editing mode
this.editingContainer!.style.display = 'none';
const clientHeight = templateData.container.clientHeight;
this.viewCell.totalHeight = clientHeight;
notebookEditor.layoutNotebookCell(viewCell, clientHeight);
} else {
// first time, readonly mode
@@ -123,6 +125,7 @@ export class StatefullMarkdownCell extends Disposable {
this.localDisposables.add(markdownRenderer.onDidUpdateRender(() => {
const clientHeight = templateData.container.clientHeight;
this.viewCell.totalHeight = clientHeight;
notebookEditor.layoutNotebookCell(viewCell, clientHeight);
}));
@@ -162,7 +165,8 @@ export class StatefullMarkdownCell extends Disposable {
clientHeight = this.cellContainer.clientHeight;
}
this.notebookEditor.layoutNotebookCell(this.viewCell, this.editor!.getContentHeight() + 32 + clientHeight);
this.viewCell.totalHeight = this.editor!.getContentHeight() + 32 + clientHeight;
this.notebookEditor.layoutNotebookCell(this.viewCell, this.viewCell.layoutInfo.totalHeight);
}));
this.localDisposables.add(this.editor!.onDidContentSizeChange(e => {
@@ -176,7 +180,8 @@ export class StatefullMarkdownCell extends Disposable {
}
);
const clientHeight = this.cellContainer.clientHeight;
this.notebookEditor.layoutNotebookCell(this.viewCell, e.contentHeight + 32 + clientHeight);
this.viewCell.totalHeight = e.contentHeight + 32 + clientHeight;
this.notebookEditor.layoutNotebookCell(this.viewCell, this.viewCell.layoutInfo.totalHeight);
}
}));
@@ -219,7 +224,8 @@ export class StatefullMarkdownCell extends Disposable {
this.cellContainer.appendChild(renderedHTML);
this.localDisposables.add(markdownRenderer.onDidUpdateRender(() => {
const clientHeight = this.cellContainer.clientHeight;
this.notebookEditor.layoutNotebookCell(this.viewCell, clientHeight);
this.viewCell.totalHeight = clientHeight;
this.notebookEditor.layoutNotebookCell(this.viewCell, this.viewCell.layoutInfo.totalHeight);
}));
}
}

View File

@@ -204,7 +204,7 @@ export abstract class BaseCellViewModel extends Disposable implements ICellViewM
return this._editorViewStates;
}
restoreEditorViewState(editorViewStates: editorCommon.ICodeEditorViewState | null) {
restoreEditorViewState(editorViewStates: editorCommon.ICodeEditorViewState | null, totalHeight?: number) {
this._editorViewStates = editorViewStates;
}

View File

@@ -13,6 +13,7 @@ import { CellEditState, ICellViewModel, CellFindMatch, CodeCellLayoutChangeEvent
import { CellKind, ICell, NotebookCellOutputsSplice } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { BaseCellViewModel } from './baseCellViewModel';
import { NotebookEventDispatcher } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher';
import * as editorCommon from 'vs/editor/common/editorCommon';
export class CodeCellViewModel extends BaseCellViewModel implements ICellViewModel {
cellKind: CellKind.Code = CellKind.Code;
@@ -135,6 +136,22 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod
this._onDidChangeLayout.fire(state);
}
restoreEditorViewState(editorViewStates: editorCommon.ICodeEditorViewState | null, totalHeight?: number) {
super.restoreEditorViewState(editorViewStates);
if (totalHeight !== undefined) {
this._layoutInfo = {
fontInfo: this._layoutInfo.fontInfo,
editorHeight: this._layoutInfo.editorHeight,
editorWidth: this._layoutInfo.editorWidth,
outputContainerOffset: this._layoutInfo.outputContainerOffset,
outputTotalHeight: this._layoutInfo.outputTotalHeight,
totalHeight: totalHeight,
indicatorHeight: this._layoutInfo.indicatorHeight,
bottomToolbarOffset: this._layoutInfo.bottomToolbarOffset
};
}
}
hasDynamicHeight() {
if (this.selfSizeMonitoring) {
// if there is an output rendered in the webview, it should always be false
@@ -153,7 +170,11 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod
}
getHeight(lineHeight: number) {
return EDITOR_TOOLBAR_HEIGHT + EDITOR_TOP_MARGIN + this.lineCount * lineHeight + EDITOR_TOP_PADDING + EDITOR_BOTTOM_PADDING + BOTTOM_CELL_TOOLBAR_HEIGHT;
if (this._layoutInfo.totalHeight === 0) {
return EDITOR_TOOLBAR_HEIGHT + EDITOR_TOP_MARGIN + this.lineCount * lineHeight + EDITOR_TOP_PADDING + EDITOR_BOTTOM_PADDING + BOTTOM_CELL_TOOLBAR_HEIGHT;
} else {
return this._layoutInfo.totalHeight;
}
}
save() {

View File

@@ -12,8 +12,9 @@ import { ICellViewModel, CellFindMatch, MarkdownCellLayoutInfo, MarkdownCellLayo
import { MarkdownRenderer } from 'vs/workbench/contrib/notebook/browser/view/renderers/mdRenderer';
import { BaseCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/baseCellViewModel';
import { CellKind, ICell } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CELL_MARGIN, CELL_RUN_GUTTER } from 'vs/workbench/contrib/notebook/browser/constants';
import { CELL_MARGIN, CELL_RUN_GUTTER, BOTTOM_CELL_TOOLBAR_HEIGHT } from 'vs/workbench/contrib/notebook/browser/constants';
import { NotebookEventDispatcher } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher';
import * as editorCommon from 'vs/editor/common/editorCommon';
export class MarkdownCellViewModel extends BaseCellViewModel implements ICellViewModel {
cellKind: CellKind.Markdown = CellKind.Markdown;
@@ -28,6 +29,14 @@ export class MarkdownCellViewModel extends BaseCellViewModel implements ICellVie
return this._layoutInfo;
}
set totalHeight(newHeight: number) {
this.layoutChange({ totalHeight: newHeight });
}
get totalHeight() {
throw new Error('MarkdownCellViewModel.totalHeight is write only');
}
protected readonly _onDidChangeLayout = new Emitter<MarkdownCellLayoutChangeEvent>();
readonly onDidChangeLayout = this._onDidChangeLayout.event;
@@ -43,7 +52,9 @@ export class MarkdownCellViewModel extends BaseCellViewModel implements ICellVie
this._layoutInfo = {
fontInfo: initialNotebookLayoutInfo?.fontInfo || null,
editorWidth: initialNotebookLayoutInfo?.width || 0
editorWidth: initialNotebookLayoutInfo?.width || 0,
bottomToolbarOffset: BOTTOM_CELL_TOOLBAR_HEIGHT,
totalHeight: 0
};
this._register(eventDispatcher.onDidChangeLayout((e) => {
@@ -59,18 +70,36 @@ export class MarkdownCellViewModel extends BaseCellViewModel implements ICellVie
this._layoutInfo = {
fontInfo: state.font || null,
editorWidth
editorWidth,
bottomToolbarOffset: BOTTOM_CELL_TOOLBAR_HEIGHT,
totalHeight: state.totalHeight === undefined ? this._layoutInfo.totalHeight : state.totalHeight
};
this._onDidChangeLayout.fire(state);
}
restoreEditorViewState(editorViewStates: editorCommon.ICodeEditorViewState | null, totalHeight?: number) {
super.restoreEditorViewState(editorViewStates);
if (totalHeight !== undefined) {
this._layoutInfo = {
fontInfo: this._layoutInfo.fontInfo,
editorWidth: this._layoutInfo.editorWidth,
bottomToolbarOffset: this._layoutInfo.bottomToolbarOffset,
totalHeight: totalHeight
};
}
}
hasDynamicHeight() {
return true;
}
getHeight(lineHeight: number) {
return 100;
if (this._layoutInfo.totalHeight === 0) {
return 100;
} else {
return this._layoutInfo.totalHeight;
}
}
setText(strs: string[]) {

View File

@@ -26,6 +26,7 @@ import { CancellationTokenSource } from 'vs/base/common/cancellation';
export interface INotebookEditorViewState {
editingCells: { [key: number]: boolean };
editorViewStates: { [key: number]: editorCommon.ICodeEditorViewState | null };
cellTotalHeights?: { [key: number]: number };
scrollPosition?: { left: number; top: number; };
}
@@ -272,12 +273,13 @@ export class NotebookViewModel extends Disposable {
return;
}
this._viewCells.forEach(cell => {
this._viewCells.forEach((cell, index) => {
const isEditing = viewState.editingCells && viewState.editingCells[cell.handle];
const editorViewState = viewState.editorViewStates && viewState.editorViewStates[cell.handle];
cell.editState = isEditing ? CellEditState.Editing : CellEditState.Preview;
cell.restoreEditorViewState(editorViewState);
const cellHeight = viewState.cellTotalHeights ? viewState.cellTotalHeights[index] : undefined;
cell.restoreEditorViewState(editorViewState, cellHeight);
});
}

View File

@@ -0,0 +1,43 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { isMacintosh } from 'vs/base/common/platform';
import { registerAction2 } from 'vs/platform/actions/common/actions';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import * as webviewCommands from 'vs/workbench/contrib/webview/electron-browser/webviewCommands';
import { NotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookEditor';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { ElectronWebviewBasedWebview } from 'vs/workbench/contrib/webview/electron-browser/webviewElement';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { getActiveNotebookEditor } from 'vs/workbench/contrib/notebook/browser/contrib/notebookActions';
function getActiveElectronBasedWebviewDelegate(accessor: ServicesAccessor): ElectronWebviewBasedWebview | undefined {
const editorService = accessor.get(IEditorService);
const editor = getActiveNotebookEditor(editorService);
const webview = editor?.getInnerWebview();
if (webview && webview instanceof ElectronWebviewBasedWebview) {
return webview;
}
return undefined; // {{SQL CARBON EDIT}} struct-null-checks
}
function registerNotebookCommands(editorId: string): void {
const contextKeyExpr = ContextKeyExpr.and(ContextKeyExpr.equals('activeEditor', editorId), ContextKeyExpr.not('editorFocus') /* https://github.com/Microsoft/vscode/issues/58668 */)!;
// These commands are only needed on MacOS where we have to disable the menu bar commands
if (isMacintosh) {
registerAction2(class extends webviewCommands.CopyWebviewEditorCommand { constructor() { super(contextKeyExpr, getActiveElectronBasedWebviewDelegate); } });
registerAction2(class extends webviewCommands.PasteWebviewEditorCommand { constructor() { super(contextKeyExpr, getActiveElectronBasedWebviewDelegate); } });
registerAction2(class extends webviewCommands.CutWebviewEditorCommand { constructor() { super(contextKeyExpr, getActiveElectronBasedWebviewDelegate); } });
registerAction2(class extends webviewCommands.UndoWebviewEditorCommand { constructor() { super(contextKeyExpr, getActiveElectronBasedWebviewDelegate); } });
registerAction2(class extends webviewCommands.RedoWebviewEditorCommand { constructor() { super(contextKeyExpr, getActiveElectronBasedWebviewDelegate); } });
}
}
registerNotebookCommands(NotebookEditor.ID);

View File

@@ -20,6 +20,7 @@ import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
import { NotebookEventDispatcher } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher';
import { Webview } from 'vs/workbench/contrib/webview/browser/webview';
export class TestCell implements ICell {
uri: URI;
@@ -80,6 +81,9 @@ export class TestNotebookEditor implements INotebookEditor {
constructor(
) { }
getInnerWebview(): Webview | undefined {
throw new Error('Method not implemented.');
}
cancelNotebookCellExecution(cell: ICellViewModel): void {
throw new Error('Method not implemented.');

View File

@@ -51,7 +51,6 @@ import { IViewDescriptorService } from 'vs/workbench/common/views';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys';
class RequestState {
@@ -177,13 +176,6 @@ class OutlineViewState {
private readonly _onDidChange = new Emitter<{ followCursor?: boolean, sortBy?: boolean, filterOnType?: boolean }>();
readonly onDidChange = this._onDidChange.event;
constructor(
@IStorageService private readonly _storageService: IStorageService,
@IStorageKeysSyncRegistryService storageKeysSyncService: IStorageKeysSyncRegistryService
) {
storageKeysSyncService.registerStorageKey({ key: 'outline/state', version: 1 });
}
set followCursor(value: boolean) {
if (value !== this._followCursor) {
this._followCursor = value;
@@ -217,16 +209,16 @@ class OutlineViewState {
return this._sortBy;
}
persist(): void {
this._storageService.store('outline/state', JSON.stringify({
persist(storageService: IStorageService): void {
storageService.store('outline/state', JSON.stringify({
followCursor: this.followCursor,
sortBy: this.sortBy,
filterOnType: this.filterOnType,
}), StorageScope.WORKSPACE);
}
restore(): void {
let raw = this._storageService.get('outline/state', StorageScope.WORKSPACE);
restore(storageService: IStorageService): void {
let raw = storageService.get('outline/state', StorageScope.WORKSPACE);
if (!raw) {
return;
}
@@ -249,7 +241,7 @@ export class OutlinePane extends ViewPane {
private _disposables = new Array<IDisposable>();
private _editorDisposables = new DisposableStore();
private _outlineViewState: OutlineViewState;
private _outlineViewState = new OutlineViewState();
private _requestOracle?: RequestOracle;
private _domNode!: HTMLElement;
private _message!: HTMLDivElement;
@@ -270,6 +262,7 @@ export class OutlinePane extends ViewPane {
@IInstantiationService private readonly _instantiationService: IInstantiationService,
@IViewDescriptorService viewDescriptorService: IViewDescriptorService,
@IThemeService private readonly _themeService: IThemeService,
@IStorageService private readonly _storageService: IStorageService,
@ICodeEditorService private readonly _editorService: ICodeEditorService,
@IMarkerDecorationsService private readonly _markerDecorationService: IMarkerDecorationsService,
@IConfigurationService private readonly _configurationService: IConfigurationService,
@@ -281,7 +274,7 @@ export class OutlinePane extends ViewPane {
@ITelemetryService telemetryService: ITelemetryService,
) {
super(options, keybindingService, contextMenuService, _configurationService, contextKeyService, viewDescriptorService, _instantiationService, openerService, themeService, telemetryService);
this._outlineViewState = this.instantiationService.createInstance(OutlineViewState);
this._outlineViewState.restore(this._storageService);
this._contextKeyFocused = OutlineViewFocused.bindTo(contextKeyService);
this._contextKeyFiltered = OutlineViewFiltered.bindTo(contextKeyService);
this._disposables.push(this.onDidFocus(_ => this._contextKeyFocused.set(true)));
@@ -441,7 +434,7 @@ export class OutlinePane extends ViewPane {
}
private _onDidChangeUserState(e: { followCursor?: boolean, sortBy?: boolean, filterOnType?: boolean }) {
this._outlineViewState.persist();
this._outlineViewState.persist(this._storageService);
if (e.followCursor) {
// todo@joh update immediately
}

View File

@@ -0,0 +1,32 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-workbench .part > .title > .title-actions .switch-output {
display: flex;
align-items: center;
font-size: 11px;
margin-right: 0.3em;
height: 20px;
flex-shrink: 1;
margin-top: 7px;
}
.monaco-workbench.mac .part > .title > .title-actions .switch-output {
border-radius: 4px;
}
.monaco-workbench .part > .title > .title-actions .switch-output > .monaco-select-box {
border: none !important;
display: block !important;
background-color: unset !important;
}
.monaco-pane-view .pane > .pane-header .monaco-action-bar .switch-output.action-item.select-container {
border: none !important;
}
.monaco-workbench .part > .title > .title-actions .switch-output > .monaco-select-box {
padding: 0 22px 0 6px;
}

View File

@@ -5,6 +5,7 @@
import * as nls from 'vs/nls';
import * as aria from 'vs/base/browser/ui/aria/aria';
import 'vs/css!./media/output';
import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes';
import { ModesRegistry } from 'vs/editor/common/modes/modesRegistry';
import { Registry } from 'vs/platform/registry/common/platform';
@@ -20,7 +21,7 @@ import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWo
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { ViewContainer, IViewContainersRegistry, ViewContainerLocation, Extensions as ViewContainerExtensions, IViewsRegistry, IViewsService } from 'vs/workbench/common/views';
import { ViewContainer, IViewContainersRegistry, ViewContainerLocation, Extensions as ViewContainerExtensions, IViewsRegistry, IViewsService, IViewDescriptorService } from 'vs/workbench/common/views';
import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer';
import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
@@ -28,10 +29,9 @@ import { IQuickPickItem, IQuickInputService } from 'vs/platform/quickinput/commo
import { IOutputChannelDescriptor, IFileOutputChannelDescriptor } from 'vs/workbench/services/output/common/output';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { assertIsDefined } from 'vs/base/common/types';
import { TogglePanelAction } from 'vs/workbench/browser/panel';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { ContextKeyEqualsExpr, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { ContextKeyEqualsExpr, ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { ToggleViewAction } from 'vs/workbench/browser/actions/layoutActions';
// Register Service
registerSingleton(IOutputService, OutputService);
@@ -228,11 +228,13 @@ registerAction2(class extends Action2 {
});
}
async run(accessor: ServicesAccessor): Promise<void> {
const panelService = accessor.get(IPanelService);
const viewsService = accessor.get(IViewsService);
const viewDescriptorService = accessor.get(IViewDescriptorService);
const contextKeyService = accessor.get(IContextKeyService);
const layoutService = accessor.get(IWorkbenchLayoutService);
return new class ToggleOutputAction extends TogglePanelAction {
return new class ToggleOutputAction extends ToggleViewAction {
constructor() {
super(toggleOutputAcitonId, 'Toggle Output', OUTPUT_VIEW_ID, panelService, layoutService);
super(toggleOutputAcitonId, 'Toggle Output', OUTPUT_VIEW_ID, viewsService, viewDescriptorService, contextKeyService, layoutService);
}
}().run();
}

View File

@@ -31,11 +31,11 @@ import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorIn
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { IOutputChannelDescriptor, IOutputChannelRegistry, Extensions } from 'vs/workbench/services/output/common/output';
import { Registry } from 'vs/platform/registry/common/platform';
import { attachSelectBoxStyler } from 'vs/platform/theme/common/styler';
import { attachSelectBoxStyler, attachStylerCallback } from 'vs/platform/theme/common/styler';
import { ISelectOptionItem } from 'vs/base/browser/ui/selectBox/selectBox';
import { groupBy } from 'vs/base/common/arrays';
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
import { editorBackground } from 'vs/platform/theme/common/colorRegistry';
import { editorBackground, selectBorder } from 'vs/platform/theme/common/colorRegistry';
import { addClass } from 'vs/base/browser/dom';
export class OutputViewPane extends ViewPane {
@@ -43,7 +43,6 @@ export class OutputViewPane extends ViewPane {
private readonly editor: OutputEditor;
private channelId: string | undefined;
private editorPromise: Promise<OutputEditor> | null = null;
private actions: IAction[] | undefined;
private readonly scrollLockContextKey: IContextKey<boolean>;
get scrollLock(): boolean { return !!this.scrollLockContextKey.get(); }
@@ -109,7 +108,7 @@ export class OutputViewPane extends ViewPane {
}
const model = codeEditor.getModel();
if (model && this.actions) {
if (model) {
const newPositionLine = e.position.lineNumber;
const lastLine = model.getLineCount();
this.scrollLock = lastLine !== newPositionLine;
@@ -276,7 +275,7 @@ class SwitchOutputActionViewItem extends SelectActionViewItem {
constructor(
action: IAction,
@IOutputService private readonly outputService: IOutputService,
@IThemeService themeService: IThemeService,
@IThemeService private readonly themeService: IThemeService,
@IContextViewService contextViewService: IContextViewService
) {
super(null, action, [], 0, contextViewService, { ariaLabel: nls.localize('outputChannels', 'Output Channels.') });
@@ -290,6 +289,14 @@ class SwitchOutputActionViewItem extends SelectActionViewItem {
this.updateOtions();
}
render(container: HTMLElement): void {
super.render(container);
addClass(container, 'switch-output');
this._register(attachStylerCallback(this.themeService, { selectBorder }, colors => {
container.style.border = colors.selectBorder ? `1px solid ${colors.selectBorder}` : '';
}));
}
protected getActionContext(option: string, index: number): string {
const channel = index < this.outputChannels.length ? this.outputChannels[index] : this.logChannels[index - this.outputChannels.length - 1];
return channel ? channel.id : option;

View File

@@ -341,7 +341,7 @@ export abstract class AbstractSettingRenderer extends Disposable implements ITre
protected createSyncIgnoredElement(container: HTMLElement): HTMLElement {
const syncIgnoredElement = DOM.append(container, $('span.setting-item-ignored'));
const syncIgnoredLabel = new CodiconLabel(syncIgnoredElement);
syncIgnoredLabel.text = `($(eye-closed) ${localize('extensionSyncIgnoredLabel', 'Sync: Ignored')})`;
syncIgnoredLabel.text = `($(sync-ignored) ${localize('extensionSyncIgnoredLabel', 'Sync: Ignored')})`;
return syncIgnoredElement;
}

View File

@@ -60,7 +60,13 @@ export class CommandsQuickAccessProvider extends AbstractEditorCommandsQuickAcce
@INotificationService notificationService: INotificationService,
@IConfigurationService private readonly configurationService: IConfigurationService
) {
super({ showAlias: !Language.isDefaultVariant() }, instantiationService, keybindingService, commandService, telemetryService, notificationService);
super({
showAlias: !Language.isDefaultVariant(),
noResultsPick: {
label: localize('noCommandResults', "No matching commands"),
commandId: ''
}
}, instantiationService, keybindingService, commandService, telemetryService, notificationService);
}
private get configuration() {

View File

@@ -8,10 +8,10 @@ import { Registry } from 'vs/platform/registry/common/platform';
import { IQuickPickSeparator, IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
import { IPickerQuickAccessItem, PickerQuickAccessProvider } from 'vs/platform/quickinput/browser/pickerQuickAccess';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { IViewDescriptorService, IViewsService, ViewContainer, IViewsRegistry, Extensions as ViewExtensions, IViewContainersRegistry } from 'vs/workbench/common/views';
import { IViewDescriptorService, IViewsService, ViewContainer, Extensions as ViewExtensions, IViewContainersRegistry } from 'vs/workbench/common/views';
import { IOutputService } from 'vs/workbench/contrib/output/common/output';
import { ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { IPanelService, IPanelIdentifier } from 'vs/workbench/services/panel/common/panelService';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { ViewletDescriptor } from 'vs/workbench/browser/viewlet';
import { matchesFuzzy } from 'vs/base/common/filters';
@@ -37,7 +37,12 @@ export class ViewQuickAccessProvider extends PickerQuickAccessProvider<IViewQuic
@IPanelService private readonly panelService: IPanelService,
@IContextKeyService private readonly contextKeyService: IContextKeyService
) {
super(ViewQuickAccessProvider.PREFIX);
super(ViewQuickAccessProvider.PREFIX, {
noResultsPick: {
label: localize('noViewResults', "No matching views"),
containerLabel: ''
}
});
}
protected getPicks(filter: string): Array<IViewQuickPickItem | IQuickPickSeparator> {
@@ -91,13 +96,12 @@ export class ViewQuickAccessProvider extends PickerQuickAccessProvider<IViewQuic
const viewEntries: Array<IViewQuickPickItem> = [];
const getViewEntriesForViewlet = (viewlet: ViewletDescriptor, viewContainer: ViewContainer): IViewQuickPickItem[] => {
const views = Registry.as<IViewsRegistry>(ViewExtensions.ViewsRegistry).getViews(viewContainer);
const viewDescriptors = this.viewDescriptorService.getViewDescriptors(viewContainer);
const result: IViewQuickPickItem[] = [];
for (const view of views) {
for (const view of viewDescriptors.allViewDescriptors) {
if (this.contextKeyService.contextMatchesRules(view.when)) {
result.push({
label: view.name,
ariaLabel: localize('viewPickAriaLabel', "{0}, view picker", view.name),
containerLabel: viewlet.name,
accept: () => this.viewsService.openView(view.id, true)
});
@@ -110,10 +114,9 @@ export class ViewQuickAccessProvider extends PickerQuickAccessProvider<IViewQuic
// Viewlets
const viewlets = this.viewletService.getViewlets();
for (const viewlet of viewlets) {
if (this.includeViewlet(viewlet)) {
if (this.includeViewContainer(viewlet)) {
viewEntries.push({
label: viewlet.name,
ariaLabel: localize('viewPickAriaLabel', "{0}, view picker", viewlet.name),
containerLabel: localize('views', "Side Bar"),
accept: () => this.viewletService.openViewlet(viewlet.id, true)
});
@@ -123,12 +126,13 @@ export class ViewQuickAccessProvider extends PickerQuickAccessProvider<IViewQuic
// Panels
const panels = this.panelService.getPanels();
for (const panel of panels) {
viewEntries.push({
label: panel.name,
ariaLabel: localize('viewPickAriaLabel', "{0}, view picker", panel.name),
containerLabel: localize('panels', "Panel"),
accept: () => this.panelService.openPanel(panel.id, true)
});
if (this.includeViewContainer(panel)) {
viewEntries.push({
label: panel.name,
containerLabel: localize('panels', "Panel"),
accept: () => this.panelService.openPanel(panel.id, true)
});
}
}
// Viewlet Views
@@ -145,7 +149,6 @@ export class ViewQuickAccessProvider extends PickerQuickAccessProvider<IViewQuic
const label = localize('terminalTitle', "{0}: {1}", `${tabIndex + 1}.${terminalIndex + 1}`, terminal.title);
viewEntries.push({
label,
ariaLabel: localize('viewPickAriaLabel', "{0}, view picker", label),
containerLabel: localize('terminals', "Terminal"),
accept: async () => {
await this.terminalService.showPanel(true);
@@ -162,20 +165,16 @@ export class ViewQuickAccessProvider extends PickerQuickAccessProvider<IViewQuic
const label = channel.log ? localize('logChannel', "Log ({0})", channel.label) : channel.label;
viewEntries.push({
label,
ariaLabel: localize('viewPickAriaLabel', "{0}, view picker", label),
containerLabel: localize('channels', "Output"),
accept: () => this.outputService.showChannel(channel.id)
});
}
// Add generic ARIA label
viewEntries.forEach(entry => entry.ariaLabel = localize('entryAriaLabel', "{0}, view picker", entry.label));
return viewEntries;
}
private includeViewlet(viewlet: ViewletDescriptor): boolean {
const viewContainer = Registry.as<IViewContainersRegistry>(ViewExtensions.ViewContainersRegistry).get(viewlet.id);
private includeViewContainer(container: ViewletDescriptor | IPanelIdentifier): boolean {
const viewContainer = Registry.as<IViewContainersRegistry>(ViewExtensions.ViewContainersRegistry).get(container.id);
if (viewContainer?.hideIfEmpty) {
return this.viewDescriptorService.getViewDescriptors(viewContainer).activeViewDescriptors.length > 0;
}

View File

@@ -151,10 +151,7 @@ interface ResourceTemplate {
class RepositoryPaneActionRunner extends ActionRunner {
constructor(
private getSelectedResources: () => (ISCMResource | IResourceNode<ISCMResource, ISCMResourceGroup>)[],
private focus: () => void
) {
constructor(private getSelectedResources: () => (ISCMResource | IResourceNode<ISCMResource, ISCMResourceGroup>)[]) {
super();
}
@@ -168,7 +165,6 @@ class RepositoryPaneActionRunner extends ActionRunner {
const actualContext = contextIsSelected ? selection : [context];
const args = flatten(actualContext.map(e => ResourceTree.isResourceNode(e) ? ResourceTree.collect(e) : [e]));
await action.run(...args);
this.focus();
}
}
@@ -181,8 +177,7 @@ class ResourceRenderer implements ICompressibleTreeRenderer<ISCMResource | IReso
private viewModelProvider: () => ViewModel,
private labels: ResourceLabels,
private actionViewItemProvider: IActionViewItemProvider,
private getSelectedResources: () => (ISCMResource | IResourceNode<ISCMResource, ISCMResourceGroup>)[],
private focus: () => void,
private actionRunner: ActionRunner,
private themeService: IThemeService,
private menus: SCMMenus
) { }
@@ -194,7 +189,7 @@ class ResourceRenderer implements ICompressibleTreeRenderer<ISCMResource | IReso
const actionsContainer = append(fileLabel.element, $('.actions'));
const actionBar = new ActionBar(actionsContainer, {
actionViewItemProvider: this.actionViewItemProvider,
actionRunner: new RepositoryPaneActionRunner(this.getSelectedResources, this.focus)
actionRunner: this.actionRunner
});
const decorationIcon = append(element, $('.decoration-icon'));
@@ -830,9 +825,19 @@ export class RepositoryPane extends ViewPane {
this.listLabels = this.instantiationService.createInstance(ResourceLabels, { onDidChangeVisibility: this.onDidChangeBodyVisibility });
this._register(this.listLabels);
const actionRunner = new RepositoryPaneActionRunner(() => this.getSelectedResources());
this._register(actionRunner);
this._register(actionRunner.onDidRun(() => {
if (this.repository.input.visible && this.inputEditor.hasWidgetFocus()) {
return;
}
this.tree.domFocus();
}));
const renderers = [
new ResourceGroupRenderer(actionViewItemProvider, this.themeService, this.menus),
new ResourceRenderer(() => this.viewModel, this.listLabels, actionViewItemProvider, () => this.getSelectedResources(), () => this.tree.domFocus(), this.themeService, this.menus)
new ResourceRenderer(() => this.viewModel, this.listLabels, actionViewItemProvider, actionRunner, this.themeService, this.menus)
];
const filter = new SCMTreeFilter();
@@ -1032,11 +1037,14 @@ export class RepositoryPane extends ViewPane {
actions = this.menus.getResourceContextActions(element);
}
const actionRunner = new RepositoryPaneActionRunner(() => this.getSelectedResources());
actionRunner.onDidRun(() => this.tree.domFocus());
this.contextMenuService.showContextMenu({
getAnchor: () => e.anchor,
getActions: () => actions,
getActionsContext: () => element,
actionRunner: new RepositoryPaneActionRunner(() => this.getSelectedResources(), () => this.tree.domFocus())
actionRunner
});
}

View File

@@ -4,9 +4,9 @@
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/anythingQuickAccess';
import { IQuickInputButton, IKeyMods, quickPickItemScorerAccessor, QuickPickItemScorerAccessor, IQuickPick } from 'vs/platform/quickinput/common/quickInput';
import { IQuickInputButton, IKeyMods, quickPickItemScorerAccessor, QuickPickItemScorerAccessor, IQuickPick, IQuickPickItemWithResource } from 'vs/platform/quickinput/common/quickInput';
import { IPickerQuickAccessItem, PickerQuickAccessProvider, TriggerAction, FastAndSlowPicks, Picks, PicksWithActive } from 'vs/platform/quickinput/browser/pickerQuickAccess';
import { prepareQuery, IPreparedQuery, compareItemsByScore, scoreItem, ScorerCache } from 'vs/base/common/fuzzyScorer';
import { prepareQuery, IPreparedQuery, compareItemsByFuzzyScore, scoreItemFuzzy, FuzzyScorerCache } from 'vs/base/common/fuzzyScorer';
import { IFileQueryBuilderOptions, QueryBuilder } from 'vs/workbench/contrib/search/common/queryBuilder';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { getOutOfWorkspaceEditorResources, extractRangeFromFilter, IWorkbenchSearchConfiguration } from 'vs/workbench/contrib/search/common/search';
@@ -50,9 +50,7 @@ import { getCodeEditor } from 'vs/editor/browser/editorBrowser';
import { withNullAsUndefined } from 'vs/base/common/types';
import { stripCodicons } from 'vs/base/common/codicons';
interface IAnythingQuickPickItem extends IPickerQuickAccessItem {
resource: URI | undefined;
}
interface IAnythingQuickPickItem extends IPickerQuickAccessItem, IQuickPickItemWithResource { }
interface IEditorSymbolAnythingQuickPickItem extends IAnythingQuickPickItem {
resource: URI;
@@ -83,7 +81,7 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
state: ICodeEditorViewState | IDiffEditorViewState | undefined
} | undefined = undefined;
scorerCache: ScorerCache = Object.create(null);
scorerCache: FuzzyScorerCache = Object.create(null);
fileQueryCache: FileQueryCacheState | undefined = undefined;
lastOriginalFilter: string | undefined = undefined;
@@ -163,7 +161,12 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
@IFilesConfigurationService private readonly filesConfigurationService: IFilesConfigurationService,
@ITextModelService private readonly textModelService: ITextModelService
) {
super(AnythingQuickAccessProvider.PREFIX, { canAcceptInBackground: true });
super(AnythingQuickAccessProvider.PREFIX, {
canAcceptInBackground: true,
noResultsPick: {
label: localize('noAnythingResults', "No matching results")
}
});
}
private get configuration() {
@@ -268,6 +271,7 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
}
// Remember as last filter
const lastWasFiltering = !!this.pickState.lastOriginalFilter;
this.pickState.lastOriginalFilter = originalFilter;
this.pickState.lastFilter = filter;
@@ -286,18 +290,28 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
}
}
return this.doGetPicks(filter, disposables, token);
// `enableEditorSymbolSearch`: this will enable local editor symbol
// search if the filter value includes `@` character. We only want
// to enable this support though if the user was filtering in the
// picker because this feature depends on an active item in the result
// list to get symbols from. If we would simply trigger editor symbol
// search without prior filtering, you could not paste a file name
// including the `@` character to open it (e.g. /some/file@path)
// refs: https://github.com/microsoft/vscode/issues/93845
return this.doGetPicks(filter, { enableEditorSymbolSearch: lastWasFiltering }, disposables, token);
}
private doGetPicks(filter: string, disposables: DisposableStore, token: CancellationToken): Picks<IAnythingQuickPickItem> | Promise<Picks<IAnythingQuickPickItem>> | FastAndSlowPicks<IAnythingQuickPickItem> | null {
private doGetPicks(filter: string, options: { enableEditorSymbolSearch: boolean }, disposables: DisposableStore, token: CancellationToken): Picks<IAnythingQuickPickItem> | Promise<Picks<IAnythingQuickPickItem>> | FastAndSlowPicks<IAnythingQuickPickItem> {
const query = prepareQuery(filter);
// Return early if we have editor symbol picks. We support this by:
// - having a previously active global pick (e.g. a file)
// - the user typing `@` to start the local symbol query
const editorSymbolPicks = this.getEditorSymbolPicks(query, disposables, token);
if (editorSymbolPicks) {
return editorSymbolPicks;
if (options.enableEditorSymbolSearch) {
const editorSymbolPicks = this.getEditorSymbolPicks(query, disposables, token);
if (editorSymbolPicks) {
return editorSymbolPicks;
}
}
// If we have a known last active editor symbol pick, we try to restore
@@ -361,7 +375,7 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
// Perform sorting (top results by score)
const sortedAnythingPicks = top(
[...filePicks, ...symbolPicks],
(anyPickA, anyPickB) => compareItemsByScore(anyPickA, anyPickB, query, true, quickPickItemScorerAccessor, this.pickState.scorerCache),
(anyPickA, anyPickB) => compareItemsByFuzzyScore(anyPickA, anyPickB, query, true, quickPickItemScorerAccessor, this.pickState.scorerCache),
AnythingQuickAccessProvider.MAX_RESULTS
);
@@ -376,7 +390,7 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
// Otherwise, do the scoring and matching here
else {
const { score, labelMatch, descriptionMatch } = scoreItem(anythingPick, query, true, quickPickItemScorerAccessor, this.pickState.scorerCache);
const { score, labelMatch, descriptionMatch } = scoreItemFuzzy(anythingPick, query, true, quickPickItemScorerAccessor, this.pickState.scorerCache);
if (!score) {
continue;
}
@@ -421,7 +435,7 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
const editorHistoryPick = this.createAnythingPick(editor, configuration);
const { score, labelMatch, descriptionMatch } = scoreItem(editorHistoryPick, query, false, editorHistoryScorerAccessor, this.pickState.scorerCache);
const { score, labelMatch, descriptionMatch } = scoreItemFuzzy(editorHistoryPick, query, false, editorHistoryScorerAccessor, this.pickState.scorerCache);
if (!score) {
continue; // exclude editors not matching query
}
@@ -440,7 +454,7 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
}
// Perform sorting
return editorHistoryPicks.sort((editorA, editorB) => compareItemsByScore(editorA, editorB, query, false, editorHistoryScorerAccessor, this.pickState.scorerCache));
return editorHistoryPicks.sort((editorA, editorB) => compareItemsByFuzzyScore(editorA, editorB, query, false, editorHistoryScorerAccessor, this.pickState.scorerCache));
}
//#endregion
@@ -716,7 +730,8 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
private readonly editorSymbolsQuickAccess = this.instantiationService.createInstance(GotoSymbolQuickAccessProvider);
private getEditorSymbolPicks(query: IPreparedQuery, disposables: DisposableStore, token: CancellationToken): Promise<Picks<IAnythingQuickPickItem>> | null {
const filter = query.original.split(GotoSymbolQuickAccessProvider.PREFIX)[1]?.trim();
const filterSegments = query.original.split(GotoSymbolQuickAccessProvider.PREFIX);
const filter = filterSegments.length > 1 ? filterSegments[filterSegments.length - 1].trim() : undefined;
if (typeof filter !== 'string') {
return null; // we need to be searched for editor symbols via `@`
}
@@ -731,6 +746,12 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
return null; // we need a resource that we can resolve
}
if (activeGlobalPick.label.includes(GotoSymbolQuickAccessProvider.PREFIX) || activeGlobalPick.description?.includes(GotoSymbolQuickAccessProvider.PREFIX)) {
if (filterSegments.length < 3) {
return null; // require at least 2 `@` if our active pick contains `@` in label or description
}
}
return this.doGetEditorSymbolPicks(activeGlobalPick, activeGlobalResource, filter, disposables, token);
}
@@ -834,9 +855,7 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
return {
resource,
label,
ariaLabel: isEditorHistoryEntry ?
localize('historyPickAriaLabel', "{0}, recently opened", label) :
localize('filePickAriaLabel', "{0}, file picker", label),
ariaLabel: isDirty ? localize('filePickAriaLabelDirty', "{0}, dirty", label) : label,
description,
iconClasses: getIconClasses(this.modelService, this.modeService, resource),
buttons: (() => {

View File

@@ -5,7 +5,6 @@
import { localize } from 'vs/nls';
import { IPickerQuickAccessItem, PickerQuickAccessProvider, TriggerAction } from 'vs/platform/quickinput/browser/pickerQuickAccess';
import { fuzzyScore, createMatches, FuzzyScore } from 'vs/base/common/filters';
import { CancellationToken } from 'vs/base/common/cancellation';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { ThrottledDelayer } from 'vs/base/common/async';
@@ -18,20 +17,16 @@ import { IEditorService, SIDE_GROUP, ACTIVE_GROUP } from 'vs/workbench/services/
import { Range } from 'vs/editor/common/core/range';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IWorkbenchEditorConfiguration } from 'vs/workbench/common/editor';
import { IKeyMods } from 'vs/platform/quickinput/common/quickInput';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { createResourceExcludeMatcher } from 'vs/workbench/services/search/common/search';
import { ResourceMap } from 'vs/base/common/map';
import { URI } from 'vs/base/common/uri';
import { IKeyMods, IQuickPickItemWithResource } from 'vs/platform/quickinput/common/quickInput';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { getSelectionSearchString } from 'vs/editor/contrib/find/findController';
import { withNullAsUndefined } from 'vs/base/common/types';
import { prepareQuery, IPreparedQuery } from 'vs/base/common/fuzzyScorer';
import { prepareQuery, IPreparedQuery, scoreFuzzy2, pieceToQuery } from 'vs/base/common/fuzzyScorer';
import { IMatch } from 'vs/base/common/filters';
interface ISymbolQuickPickItem extends IPickerQuickAccessItem {
resource: URI | undefined;
score: FuzzyScore | undefined;
symbol: IWorkspaceSymbol;
interface ISymbolQuickPickItem extends IPickerQuickAccessItem, IQuickPickItemWithResource {
score?: number;
symbol?: IWorkspaceSymbol;
}
export class SymbolsQuickAccessProvider extends PickerQuickAccessProvider<ISymbolQuickPickItem> {
@@ -52,8 +47,6 @@ export class SymbolsQuickAccessProvider extends PickerQuickAccessProvider<ISymbo
private delayer = this._register(new ThrottledDelayer<ISymbolQuickPickItem[]>(SymbolsQuickAccessProvider.TYPING_SEARCH_DELAY));
private readonly resourceExcludeMatcher = this._register(createResourceExcludeMatcher(this.instantiationService, this.configurationService));
get defaultFilterValue(): string | undefined {
// Prefer the word under the cursor in the active editor as default filter
@@ -70,10 +63,14 @@ export class SymbolsQuickAccessProvider extends PickerQuickAccessProvider<ISymbo
@IOpenerService private readonly openerService: IOpenerService,
@IEditorService private readonly editorService: IEditorService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@ICodeEditorService private readonly codeEditorService: ICodeEditorService
) {
super(SymbolsQuickAccessProvider.PREFIX, { canAcceptInBackground: true });
super(SymbolsQuickAccessProvider.PREFIX, {
canAcceptInBackground: true,
noResultsPick: {
label: localize('noSymbolResults', "No matching workspace symbols")
}
});
}
private get configuration() {
@@ -100,26 +97,27 @@ export class SymbolsQuickAccessProvider extends PickerQuickAccessProvider<ISymbo
}
private async doGetSymbolPicks(query: IPreparedQuery, options: { skipLocal?: boolean, skipSorting?: boolean } | undefined, token: CancellationToken): Promise<Array<ISymbolQuickPickItem>> {
const workspaceSymbols = await getWorkspaceSymbols(query.original, token);
// Split between symbol and container query
let symbolQuery: IPreparedQuery;
let containerQuery: IPreparedQuery | undefined;
if (query.values && query.values.length > 1) {
symbolQuery = pieceToQuery(query.values[0]); // symbol: only match on first part
containerQuery = pieceToQuery(query.values.slice(1)); // container: match on all but first parts
} else {
symbolQuery = query;
}
// Run the workspace symbol query
const workspaceSymbols = await getWorkspaceSymbols(symbolQuery.original, token);
if (token.isCancellationRequested) {
return [];
}
const symbolPicks: Array<ISymbolQuickPickItem> = [];
// Split between symbol and container query
let symbolQuery: IPreparedQuery;
let containerQuery: IPreparedQuery | undefined;
if (query.values && query.values.length > 1) {
symbolQuery = prepareQuery(query.values[0].original);
containerQuery = prepareQuery(query.values[1].original);
} else {
symbolQuery = query;
}
// Convert to symbol picks and apply filtering
const openSideBySideDirection = this.configuration.openSideBySideDirection;
const symbolsExcludedByResource = new ResourceMap<boolean>();
for (const [provider, symbols] of workspaceSymbols) {
for (const symbol of symbols) {
@@ -130,11 +128,18 @@ export class SymbolsQuickAccessProvider extends PickerQuickAccessProvider<ISymbo
continue;
}
// Score by symbol label
const symbolLabel = symbol.name;
const symbolScore = fuzzyScore(symbolQuery.original, symbolQuery.originalLowercase, 0, symbolLabel, symbolLabel.toLowerCase(), 0, true);
if (!symbolScore) {
continue;
const symbolLabelWithIcon = `$(symbol-${SymbolKinds.toString(symbol.kind) || 'property'}) ${symbolLabel}`;
// Score by symbol label if searching
let symbolScore: number | undefined = undefined;
let symbolMatches: IMatch[] | undefined = undefined;
if (symbolQuery.original.length > 0) {
[symbolScore, symbolMatches] = scoreFuzzy2(symbolLabel, symbolQuery, 0, symbolLabelWithIcon.length - symbolLabel.length /* Readjust matches to account for codicons in label */);
if (!symbolScore) {
continue;
}
}
const symbolUri = symbol.location.uri;
@@ -148,32 +153,23 @@ export class SymbolsQuickAccessProvider extends PickerQuickAccessProvider<ISymbo
}
}
// Score by container if specified
let containerScore: FuzzyScore | undefined = undefined;
if (containerQuery) {
// Score by container if specified and searching
let containerScore: number | undefined = undefined;
let containerMatches: IMatch[] | undefined = undefined;
if (containerQuery && containerQuery.original.length > 0) {
if (containerLabel) {
containerScore = fuzzyScore(containerQuery.original, containerQuery.originalLowercase, 0, containerLabel, containerLabel.toLowerCase(), 0, true);
[containerScore, containerMatches] = scoreFuzzy2(containerLabel, containerQuery);
}
if (!containerScore) {
continue;
}
}
// Filter out symbols that match the global resource filter
if (symbolUri) {
let excludeSymbolByResource = symbolsExcludedByResource.get(symbolUri);
if (typeof excludeSymbolByResource === 'undefined') {
excludeSymbolByResource = this.resourceExcludeMatcher.matches(symbolUri);
symbolsExcludedByResource.set(symbolUri, excludeSymbolByResource);
}
if (excludeSymbolByResource) {
continue;
if (symbolScore) {
symbolScore += containerScore; // boost symbolScore by containerScore
}
}
const symbolLabelWithIcon = `$(symbol-${SymbolKinds.toString(symbol.kind) || 'property'}) ${symbolLabel}`;
const deprecated = symbol.tags ? symbol.tags.indexOf(SymbolTag.Deprecated) >= 0 : false;
symbolPicks.push({
@@ -181,10 +177,10 @@ export class SymbolsQuickAccessProvider extends PickerQuickAccessProvider<ISymbo
resource: symbolUri,
score: symbolScore,
label: symbolLabelWithIcon,
ariaLabel: localize('symbolAriaLabel', "{0}, symbols picker", symbolLabel),
ariaLabel: symbolLabel,
highlights: deprecated ? undefined : {
label: createMatches(symbolScore, symbolLabelWithIcon.length - symbolLabel.length /* Readjust matches to account for codicons in label */),
description: createMatches(containerScore)
label: symbolMatches,
description: containerMatches
},
description: containerLabel,
strikethrough: deprecated,
@@ -246,24 +242,32 @@ export class SymbolsQuickAccessProvider extends PickerQuickAccessProvider<ISymbo
// By score
if (symbolA.score && symbolB.score) {
if (symbolA.score[0] > symbolB.score[0]) {
if (symbolA.score > symbolB.score) {
return -1;
} else if (symbolA.score[0] < symbolB.score[0]) {
}
if (symbolA.score < symbolB.score) {
return 1;
}
}
// By name
const symbolAName = symbolA.symbol.name.toLowerCase();
const symbolBName = symbolB.symbol.name.toLowerCase();
const res = symbolAName.localeCompare(symbolBName);
if (res !== 0) {
return res;
if (symbolA.symbol && symbolB.symbol) {
const symbolAName = symbolA.symbol.name.toLowerCase();
const symbolBName = symbolB.symbol.name.toLowerCase();
const res = symbolAName.localeCompare(symbolBName);
if (res !== 0) {
return res;
}
}
// By kind
const symbolAKind = SymbolKinds.toCssClassName(symbolA.symbol.kind);
const symbolBKind = SymbolKinds.toCssClassName(symbolB.symbol.kind);
return symbolAKind.localeCompare(symbolBKind);
if (symbolA.symbol && symbolB.symbol) {
const symbolAKind = SymbolKinds.toCssClassName(symbolA.symbol.kind);
const symbolBKind = SymbolKinds.toCssClassName(symbolB.symbol.kind);
return symbolAKind.localeCompare(symbolBKind);
}
return 0;
}
}

View File

@@ -156,8 +156,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
weight: KeybindingWeight.WorkbenchContrib,
when: ContextKeyExpr.and(SearchEditorConstants.InSearchEditor),
handler: (accessor: ServicesAccessor) => modifySearchEditorContextLinesCommand(accessor, true),
primary: KeyMod.Alt | KeyCode.KEY_L,
mac: { primary: KeyMod.Alt | KeyCode.US_EQUAL }
primary: KeyMod.Alt | KeyCode.US_EQUAL
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
@@ -165,8 +164,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
weight: KeybindingWeight.WorkbenchContrib,
when: ContextKeyExpr.and(SearchEditorConstants.InSearchEditor),
handler: (accessor: ServicesAccessor) => modifySearchEditorContextLinesCommand(accessor, false),
primary: KeyMod.Alt | KeyCode.KEY_L,
mac: { primary: KeyMod.Alt | KeyCode.US_MINUS }
primary: KeyMod.Alt | KeyCode.US_MINUS
});
KeybindingsRegistry.registerCommandAndKeybindingRule({

View File

@@ -240,7 +240,9 @@ export class TaskQuickPick extends Disposable {
let taskQuickPickEntries: QuickPickInput<TaskTwoLevelQuickPickEntry>[];
if (tasks.length > 0) {
taskQuickPickEntries = tasks.map(task => this.createTaskEntry(task));
taskQuickPickEntries.unshift({
taskQuickPickEntries.push({
type: 'separator'
}, {
label: nls.localize('TaskQuickPick.goBack', 'Go back ↩'),
task: null
});

View File

@@ -28,7 +28,11 @@ export class TasksQuickAccessProvider extends PickerQuickAccessProvider<IPickerQ
@IConfigurationService private configurationService: IConfigurationService,
@IQuickInputService private quickInputService: IQuickInputService
) {
super(TasksQuickAccessProvider.PREFIX);
super(TasksQuickAccessProvider.PREFIX, {
noResultsPick: {
label: localize('noTaskResults', "No matching tasks")
}
});
this.activationPromise = extensionService.activateByEvent('onCommand:workbench.action.tasks.runTask');
}
@@ -46,16 +50,17 @@ export class TasksQuickAccessProvider extends PickerQuickAccessProvider<IPickerQ
const taskPicks: Array<IPickerQuickAccessItem | IQuickPickSeparator> = [];
for (const entry of topLevelPicks.entries) {
if (entry.type === 'separator') {
taskPicks.push(entry);
}
const highlights = matchesFuzzy(filter, entry.label!, true);
if (!highlights) {
continue;
}
if (entry.type === 'separator') {
taskPicks.push(entry);
}
const task: Task | ConfiguringTask | string = (<TaskTwoLevelQuickPickEntry>entry).task!;
const quickAccessEntry: IPickerQuickAccessItem = <TaskTwoLevelQuickPickEntry>entry;
quickAccessEntry.ariaLabel = localize('entryAriaLabel', "{0}, tasks picker", entry.label!);
quickAccessEntry.highlights = { label: highlights };
quickAccessEntry.trigger = () => {
if (ContributedTask.is(task)) {

View File

@@ -160,3 +160,32 @@
.monaco-workbench .part.sidebar .title-actions .terminal-action.codicon-split-horizontal {
transform: rotate(-90deg);
}
.monaco-workbench .part > .title > .title-actions .switch-terminal {
display: flex;
align-items: center;
font-size: 11px;
margin-right: 0.3em;
height: 20px;
flex-shrink: 1;
margin-top: 7px;
}
.monaco-workbench.mac .part > .title > .title-actions .switch-terminal {
border-radius: 4px;
}
.monaco-workbench .part > .title > .title-actions .switch-terminal > .monaco-select-box {
border: none !important;
display: block !important;
background-color: unset !important;
}
.monaco-pane-view .pane > .pane-header .monaco-action-bar .switch-terminal.action-item.select-container {
border: none !important;
}
.monaco-workbench .part > .title > .title-actions .switch-terminal > .monaco-select-box {
padding: 0 22px 0 6px;
}

View File

@@ -9,10 +9,8 @@ import { EndOfLinePreference } from 'vs/editor/common/model';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { TERMINAL_VIEW_ID, ITerminalConfigHelper, TitleEventSource, TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminal';
import { SelectActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { TogglePanelAction } from 'vs/workbench/browser/panel';
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { attachSelectBoxStyler } from 'vs/platform/theme/common/styler';
import { attachSelectBoxStyler, attachStylerCallback } from 'vs/platform/theme/common/styler';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { IQuickInputService, IPickOptions, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
@@ -32,6 +30,11 @@ import { withNullAsUndefined } from 'vs/base/common/types';
import { ITerminalInstance, ITerminalService, Direction } from 'vs/workbench/contrib/terminal/browser/terminal';
import { Action2 } from 'vs/platform/actions/common/actions';
import { TerminalQuickAccessProvider } from 'vs/workbench/contrib/terminal/browser/terminalsQuickAccess';
import { ToggleViewAction } from 'vs/workbench/browser/actions/layoutActions';
import { IViewsService, IViewDescriptorService } from 'vs/workbench/common/views';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { addClass } from 'vs/base/browser/dom';
import { selectBorder } from 'vs/platform/theme/common/colorRegistry';
async function getCwdForSplit(configHelper: ITerminalConfigHelper, instance: ITerminalInstance, folders?: IWorkspaceFolder[], commandService?: ICommandService): Promise<string | URI | undefined> {
switch (configHelper.config.splitCwd) {
@@ -60,18 +63,20 @@ async function getCwdForSplit(configHelper: ITerminalConfigHelper, instance: ITe
}
}
export class ToggleTerminalAction extends TogglePanelAction {
export class ToggleTerminalAction extends ToggleViewAction {
public static readonly ID = TERMINAL_COMMAND_ID.TOGGLE;
public static readonly LABEL = nls.localize('workbench.action.terminal.toggleTerminal', "Toggle Integrated Terminal");
constructor(
id: string, label: string,
@IPanelService panelService: IPanelService,
@IViewsService viewsService: IViewsService,
@IViewDescriptorService viewDescriptorService: IViewDescriptorService,
@IContextKeyService contextKeyService: IContextKeyService,
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
@ITerminalService private readonly terminalService: ITerminalService
) {
super(id, label, TERMINAL_VIEW_ID, panelService, layoutService);
super(id, label, TERMINAL_VIEW_ID, viewsService, viewDescriptorService, contextKeyService, layoutService);
}
public run(event?: any): Promise<any> {
@@ -717,7 +722,7 @@ export class SwitchTerminalActionViewItem extends SelectActionViewItem {
constructor(
action: IAction,
@ITerminalService private readonly terminalService: ITerminalService,
@IThemeService themeService: IThemeService,
@IThemeService private readonly themeService: IThemeService,
@IContextViewService contextViewService: IContextViewService
) {
super(null, action, terminalService.getTabLabels().map(label => <ISelectOptionItem>{ text: label }), terminalService.activeTabIndex, contextViewService, { ariaLabel: nls.localize('terminals', 'Open Terminals.') });
@@ -729,6 +734,14 @@ export class SwitchTerminalActionViewItem extends SelectActionViewItem {
this._register(attachSelectBoxStyler(this.selectBox, themeService));
}
render(container: HTMLElement): void {
super.render(container);
addClass(container, 'switch-terminal');
this._register(attachStylerCallback(this.themeService, { selectBorder }, colors => {
container.style.border = colors.selectBorder ? `1px solid ${colors.selectBorder}` : '';
}));
}
private _updateItems(): void {
const items = this.terminalService.getTabLabels().map(label => <ISelectOptionItem>{ text: label });
items.push({ text: SwitchTerminalActionViewItem.SEPARATOR, isDisabled: true });

View File

@@ -244,7 +244,7 @@ export class TerminalLinkHandler extends DisposableStore {
const wasHandled = await new Promise<boolean>(r => {
const timeoutId = setTimeout(() => {
canceled = true;
this._logService.error('An extension intecepted a terminal link but did not return');
this._logService.error(`An extension intecepted a terminal link but it timed out after ${TerminalLinkHandler.LINK_INTERCEPT_THRESHOLD / 1000} seconds`);
r(false);
}, TerminalLinkHandler.LINK_INTERCEPT_THRESHOLD);
let canceled = false;

View File

@@ -36,7 +36,6 @@ export class TerminalQuickAccessProvider extends PickerQuickAccessProvider<IPick
if (highlights) {
terminalPicks.push({
label,
ariaLabel: localize('termEntryAriaLabel', "{0}, terminal picker", label),
highlights: { label: highlights },
buttons: [
{
@@ -76,7 +75,7 @@ export class TerminalQuickAccessProvider extends PickerQuickAccessProvider<IPick
const createTerminalLabel = localize("workbench.action.terminal.newplus", "Create New Integrated Terminal");
terminalPicks.push({
label: `$(plus) ${createTerminalLabel}`,
ariaLabel: localize('termEntryAriaLabel', "{0}, terminal picker", createTerminalLabel),
ariaLabel: createTerminalLabel,
accept: () => this.commandService.executeCommand('workbench.action.terminal.new')
});

View File

@@ -762,7 +762,11 @@ export class TimelinePane extends ViewPane {
const changed = super.setExpanded(expanded);
if (changed && this.isBodyVisible()) {
this.onActiveEditorChanged();
if (!this.followActiveEditor) {
this.setUriCore(this.uri, true);
} else {
this.onActiveEditorChanged();
}
}
return changed;
@@ -1102,8 +1106,7 @@ class TimelinePaneCommands extends Disposable {
this._register(MenuRegistry.appendMenuItem(MenuId.TimelineTitle, ({
command: {
id: 'timeline.toggleFollowActiveEditor',
title: { value: localize('timeline.toggleFollowActiveEditorCommand', "Toggle Active Editor Following"), original: 'Toggle Active Editor Following' },
// title: localize(`timeline.toggleFollowActiveEditorCommand.stop`, "Stop following the Active Editor"),
title: { value: localize('timeline.toggleFollowActiveEditorCommand.follow', "Automatically Follows the Active Editor"), original: 'Automatically Follows the Active Editor' },
icon: { id: 'codicon/eye' },
category: { value: localize('timeline', "Timeline"), original: 'Timeline' },
},
@@ -1115,8 +1118,7 @@ class TimelinePaneCommands extends Disposable {
this._register(MenuRegistry.appendMenuItem(MenuId.TimelineTitle, ({
command: {
id: 'timeline.toggleFollowActiveEditor',
title: { value: localize('timeline.toggleFollowActiveEditorCommand', "Toggle Active Editor Following"), original: 'Toggle Active Editor Following' },
// title: localize(`timeline.toggleFollowActiveEditorCommand.stop`, "Stop following the Active Editor"),
title: { value: localize('timeline.toggleFollowActiveEditorCommand.unfollow', "Not Following Active Editor"), original: 'Not Following Active Editor' },
icon: { id: 'codicon/eye-closed' },
category: { value: localize('timeline', "Timeline"), original: 'Timeline' },
},

View File

@@ -251,7 +251,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
return new Promise((resolve, _) => {
const quickPick = this.quickInputService.createQuickPick<{ label: string, session: AuthenticationSession }>();
quickPick.title = localize('chooseAccountTitle', "Preferences Sync: Choose Account");
quickPick.placeholder = localize('chooseAccount', "Choose an account you would like to use for settings sync");
quickPick.placeholder = localize('chooseAccount', "Choose an account you would like to use for preferences sync");
const dedupedSessions = distinct(sessions, (session) => session.accountName);
quickPick.items = dedupedSessions.map(session => {
return {
@@ -287,10 +287,16 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
if (this.activeAccount) {
if (event.removed.length) {
const activeWasRemoved = !!event.removed.find(removed => removed === this.activeAccount!.id);
// If the current account was removed, offer to turn off sync
if (activeWasRemoved) {
await this.turnOff();
this.setActiveAccount(undefined);
this.notificationService.notify({
severity: Severity.Info,
message: localize('turned off on logout', "Sync has stopped because you are no longer signed in."),
actions: {
primary: [new Action('turn on sync', localize('turn on sync', "Turn on Sync"), undefined, true, () => this.turnOn())]
}
});
return;
return;
}
}
@@ -683,7 +689,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
}
await this.handleFirstTimeSync();
this.userDataSyncEnablementService.setEnablement(true);
this.notificationService.info(localize('sync turned on', "Sync will happen automatically from now on."));
this.notificationService.info(localize('sync turned on', "Preferences sync is turned on"));
this.storageService.store('sync.donotAskPreviewConfirmation', true, StorageScope.GLOBAL);
}

View File

@@ -17,7 +17,7 @@ import { URI } from 'vs/base/common/uri';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { FolderThemeIcon } from 'vs/platform/theme/common/themeService';
import { fromNow } from 'vs/base/common/date';
import { pad } from 'vs/base/common/strings';
import { pad, uppercaseFirstLetter } from 'vs/base/common/strings';
import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer';
export class UserDataSyncViewContribution implements IWorkbenchContribution {
@@ -101,7 +101,7 @@ export class UserDataSyncViewContribution implements IWorkbenchContribution {
constructor() {
super({
id: `workbench.actions.sync.resolveResource`,
title: localize('workbench.actions.sync.resolveResourceRef', "Show full content"),
title: localize('workbench.actions.sync.resolveResourceRef', "Show raw JSON sync data"),
menu: {
id: MenuId.ViewItemContext,
when: ContextKeyExpr.and(ContextKeyEqualsExpr.create('view', viewId), ContextKeyExpr.regex('viewItem', /sync-resource-.*/i))
@@ -156,7 +156,7 @@ class UserDataSyncHistoryViewDataProvider implements ITreeViewDataProvider {
return ALL_SYNC_RESOURCES.map(resourceKey => ({
handle: resourceKey,
collapsibleState: TreeItemCollapsibleState.Collapsed,
label: { label: resourceKey },
label: { label: uppercaseFirstLetter(resourceKey) },
themeIcon: FolderThemeIcon,
}));
}

View File

@@ -16,7 +16,7 @@ interface SerializedIconPath {
dark: string | UriComponents;
}
interface SerializedWebview {
export interface SerializedWebview {
readonly id?: string;
readonly viewType: string;
readonly title: string;

View File

@@ -42,7 +42,7 @@ export class CopyWebviewEditorCommand extends Action2 {
public static readonly ID = 'editor.action.webvieweditor.copy';
public static readonly LABEL = nls.localize('editor.action.webvieweditor.copy', "Copy2");
constructor(contextKeyExpr: ContextKeyExpression) {
constructor(contextKeyExpr: ContextKeyExpression, readonly getActiveElectronBasedWebviewDelegate: (accessor: ServicesAccessor) => ElectronWebviewBasedWebview | undefined = getActiveElectronBasedWebview) {
super({
id: CopyWebviewEditorCommand.ID,
title: CopyWebviewEditorCommand.LABEL,
@@ -55,7 +55,7 @@ export class CopyWebviewEditorCommand extends Action2 {
}
public run(accessor: ServicesAccessor): void {
getActiveElectronBasedWebview(accessor)?.copy();
this.getActiveElectronBasedWebviewDelegate(accessor)?.copy();
}
}
@@ -63,7 +63,7 @@ export class PasteWebviewEditorCommand extends Action2 {
public static readonly ID = 'editor.action.webvieweditor.paste';
public static readonly LABEL = nls.localize('editor.action.webvieweditor.paste', 'Paste');
constructor(contextKeyExpr: ContextKeyExpression) {
constructor(contextKeyExpr: ContextKeyExpression, readonly getActiveElectronBasedWebviewDelegate: (accessor: ServicesAccessor) => ElectronWebviewBasedWebview | undefined = getActiveElectronBasedWebview) {
super({
id: PasteWebviewEditorCommand.ID,
title: PasteWebviewEditorCommand.LABEL,
@@ -76,7 +76,7 @@ export class PasteWebviewEditorCommand extends Action2 {
}
public run(accessor: ServicesAccessor): void {
getActiveElectronBasedWebview(accessor)?.paste();
this.getActiveElectronBasedWebviewDelegate(accessor)?.paste();
}
}
@@ -84,7 +84,7 @@ export class CutWebviewEditorCommand extends Action2 {
public static readonly ID = 'editor.action.webvieweditor.cut';
public static readonly LABEL = nls.localize('editor.action.webvieweditor.cut', 'Cut');
constructor(contextKeyExpr: ContextKeyExpression) {
constructor(contextKeyExpr: ContextKeyExpression, readonly getActiveElectronBasedWebviewDelegate: (accessor: ServicesAccessor) => ElectronWebviewBasedWebview | undefined = getActiveElectronBasedWebview) {
super({
id: CutWebviewEditorCommand.ID,
title: CutWebviewEditorCommand.LABEL,
@@ -97,7 +97,7 @@ export class CutWebviewEditorCommand extends Action2 {
}
public run(accessor: ServicesAccessor): void {
getActiveElectronBasedWebview(accessor)?.cut();
this.getActiveElectronBasedWebviewDelegate(accessor)?.cut();
}
}
@@ -105,7 +105,7 @@ export class UndoWebviewEditorCommand extends Action2 {
public static readonly ID = 'editor.action.webvieweditor.undo';
public static readonly LABEL = nls.localize('editor.action.webvieweditor.undo', "Undo");
constructor(contextKeyExpr: ContextKeyExpression) {
constructor(contextKeyExpr: ContextKeyExpression, readonly getActiveElectronBasedWebviewDelegate: (accessor: ServicesAccessor) => ElectronWebviewBasedWebview | undefined = getActiveElectronBasedWebview) {
super({
id: UndoWebviewEditorCommand.ID,
title: UndoWebviewEditorCommand.LABEL,
@@ -118,7 +118,7 @@ export class UndoWebviewEditorCommand extends Action2 {
}
public run(accessor: ServicesAccessor): void {
getActiveElectronBasedWebview(accessor)?.undo();
this.getActiveElectronBasedWebviewDelegate(accessor)?.undo();
}
}
@@ -126,7 +126,7 @@ export class RedoWebviewEditorCommand extends Action2 {
public static readonly ID = 'editor.action.webvieweditor.redo';
public static readonly LABEL = nls.localize('editor.action.webvieweditor.redo', "Redo");
constructor(contextKeyExpr: ContextKeyExpression) {
constructor(contextKeyExpr: ContextKeyExpression, readonly getActiveElectronBasedWebviewDelegate: (accessor: ServicesAccessor) => ElectronWebviewBasedWebview | undefined = getActiveElectronBasedWebview) {
super({
id: RedoWebviewEditorCommand.ID,
title: RedoWebviewEditorCommand.LABEL,
@@ -141,7 +141,7 @@ export class RedoWebviewEditorCommand extends Action2 {
}
public run(accessor: ServicesAccessor): void {
getActiveElectronBasedWebview(accessor)?.redo();
this.getActiveElectronBasedWebviewDelegate(accessor)?.redo();
}
}

View File

@@ -38,8 +38,17 @@ const viewsWelcomeExtensionPointSchema = Object.freeze<IConfigurationPropertySch
],
properties: {
[ViewsWelcomeExtensionPointFields.view]: {
type: 'string',
description: nls.localize('contributes.viewsWelcome.view.view', "Target view identifier for this welcome content."),
anyOf: [
{
type: 'string',
description: nls.localize('contributes.viewsWelcome.view.view', "Target view identifier for this welcome content.")
},
{
type: 'string',
description: nls.localize('contributes.viewsWelcome.view.view', "Target view identifier for this welcome content."),
enum: Object.keys(ViewIdentifierMap)
}
]
},
[ViewsWelcomeExtensionPointFields.contents]: {
type: 'string',