mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-03-30 08:40:29 -04:00
Merge from vscode 8c426f9f3b6b18935cc6c2ec8aa6d45ccd88021e
This commit is contained in:
@@ -689,7 +689,7 @@ export class Breakpoint extends BaseBreakpoint implements IBreakpoint {
|
||||
|
||||
toJSON(): any {
|
||||
const result = super.toJSON();
|
||||
result.uri = this.uri;
|
||||
result.uri = this._uri;
|
||||
result.lineNumber = this._lineNumber;
|
||||
result.column = this._column;
|
||||
result.adapterData = this.adapterData;
|
||||
|
||||
@@ -1775,6 +1775,29 @@ export class ShowPopularExtensionsAction extends Action {
|
||||
}
|
||||
}
|
||||
|
||||
export class RecentlyPublishedExtensionsAction extends Action {
|
||||
|
||||
static readonly ID = 'workbench.extensions.action.recentlyPublishedExtensions';
|
||||
static readonly LABEL = localize('recentlyPublishedExtensions', "Recently Published Extensions");
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IViewletService private readonly viewletService: IViewletService
|
||||
) {
|
||||
super(id, label, undefined, true);
|
||||
}
|
||||
|
||||
run(): Promise<void> {
|
||||
return this.viewletService.openViewlet(VIEWLET_ID, true)
|
||||
.then(viewlet => viewlet?.getViewPaneContainer() as IExtensionsViewPaneContainer)
|
||||
.then(viewlet => {
|
||||
viewlet.search('@sort:publishedDate ');
|
||||
viewlet.focus();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class ShowRecommendedExtensionsAction extends Action {
|
||||
|
||||
static readonly ID = 'workbench.extensions.action.showRecommendedExtensions';
|
||||
@@ -2050,6 +2073,27 @@ export class ShowAzureExtensionsAction extends Action {
|
||||
}
|
||||
}
|
||||
|
||||
export class SearchCategoryAction extends Action {
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
private readonly category: string,
|
||||
@IViewletService private readonly viewletService: IViewletService
|
||||
) {
|
||||
super(id, label, undefined, true);
|
||||
}
|
||||
|
||||
run(): Promise<void> {
|
||||
return this.viewletService.openViewlet(VIEWLET_ID, true)
|
||||
.then(viewlet => viewlet?.getViewPaneContainer() as IExtensionsViewPaneContainer)
|
||||
.then(viewlet => {
|
||||
viewlet.search(`@category:"${this.category.toLowerCase()}"`);
|
||||
viewlet.focus();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class ChangeSortAction extends Action {
|
||||
|
||||
private query: Query;
|
||||
|
||||
@@ -11,23 +11,23 @@ import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Event as EventOf, Emitter } from 'vs/base/common/event';
|
||||
import { IAction, Action } from 'vs/base/common/actions';
|
||||
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { Separator, IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { IViewlet } from 'vs/workbench/common/viewlet';
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { append, $, addClass, toggleClass, Dimension, hide, show } from 'vs/base/browser/dom';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IExtensionsWorkbenchService, IExtensionsViewPaneContainer, VIEWLET_ID, AutoUpdateConfigurationKey, ShowRecommendationsOnlyOnDemandKey, CloseExtensionDetailsOnViewChangeKey } from '../common/extensions';
|
||||
import { IExtensionsWorkbenchService, IExtensionsViewPaneContainer, VIEWLET_ID, AutoUpdateConfigurationKey, CloseExtensionDetailsOnViewChangeKey } from '../common/extensions';
|
||||
import {
|
||||
ShowEnabledExtensionsAction, ShowInstalledExtensionsAction, ShowRecommendedExtensionsAction, /*ShowPopularExtensionsAction,*/ ShowDisabledExtensionsAction,
|
||||
ShowOutdatedExtensionsAction, ClearExtensionsInputAction, ChangeSortAction, UpdateAllAction, CheckForUpdatesAction, DisableAllAction, EnableAllAction,
|
||||
EnableAutoUpdateAction, DisableAutoUpdateAction, ShowBuiltInExtensionsAction, InstallVSIXAction
|
||||
ShowRecommendedExtensionsAction, /*ShowPopularExtensionsAction,*/
|
||||
ClearExtensionsInputAction, ChangeSortAction, UpdateAllAction, CheckForUpdatesAction, DisableAllAction, EnableAllAction,
|
||||
EnableAutoUpdateAction, DisableAutoUpdateAction, ShowBuiltInExtensionsAction, InstallVSIXAction, SearchCategoryAction, /*RecentlyPublishedExtensionsAction, */ShowInstalledExtensionsAction, ShowOutdatedExtensionsAction, ShowDisabledExtensionsAction, ShowEnabledExtensionsAction
|
||||
} from 'vs/workbench/contrib/extensions/browser/extensionsActions';
|
||||
import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { IWorkbenchExtensionEnablementService, IExtensionManagementServerService, IExtensionManagementServer } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
||||
import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput';
|
||||
import { ExtensionsListView, EnabledExtensionsView, DisabledExtensionsView, RecommendedExtensionsView, WorkspaceRecommendedExtensionsView, BuiltInExtensionsView, BuiltInThemesExtensionsView, BuiltInBasicsExtensionsView, ServerExtensionsView, DefaultRecommendedExtensionsView } from 'vs/workbench/contrib/extensions/browser/extensionsViews';
|
||||
import { ExtensionsListView, EnabledExtensionsView, DisabledExtensionsView, RecommendedExtensionsView, WorkspaceRecommendedExtensionsView, BuiltInFeatureExtensionsView, BuiltInThemesExtensionsView, BuiltInProgrammingLanguageExtensionsView, ServerExtensionsView, DefaultRecommendedExtensionsView, OutdatedExtensionsView, InstalledExtensionsView, SearchBuiltInExtensionsView } from 'vs/workbench/contrib/extensions/browser/extensionsViews';
|
||||
import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
@@ -50,9 +50,8 @@ import { SuggestEnabledInput, attachSuggestEnabledInputBoxStyler } from 'vs/work
|
||||
import { alert } from 'vs/base/browser/ui/aria/aria';
|
||||
import { createErrorWithActions } from 'vs/base/common/errorsWithActions';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtensionType, EXTENSION_CATEGORIES } from 'vs/platform/extensions/common/extensions';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { RemoteNameContext } from 'vs/workbench/browser/contextkeys';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { MementoObject } from 'vs/workbench/common/memento';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
@@ -60,6 +59,8 @@ import { IPreferencesService } from 'vs/workbench/services/preferences/common/pr
|
||||
import { DragAndDropObserver } from 'vs/workbench/browser/dnd';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { SIDE_BAR_DRAG_AND_DROP_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { ContextSubMenu } from 'vs/base/browser/contextmenu';
|
||||
import { DropdownMenuActionViewItem } from 'vs/base/browser/ui/dropdown/dropdown';
|
||||
|
||||
const NonEmptyWorkspaceContext = new RawContextKey<boolean>('nonEmptyWorkspace', false);
|
||||
const DefaultViewsContext = new RawContextKey<boolean>('defaultExtensionViews', true);
|
||||
@@ -69,25 +70,9 @@ const SearchOutdatedExtensionsContext = new RawContextKey<boolean>('searchOutdat
|
||||
const SearchEnabledExtensionsContext = new RawContextKey<boolean>('searchEnabledExtensions', false);
|
||||
const SearchDisabledExtensionsContext = new RawContextKey<boolean>('searchDisabledExtensions', false);
|
||||
const HasInstalledExtensionsContext = new RawContextKey<boolean>('hasInstalledExtensions', true);
|
||||
const BuiltInExtensionsContext = new RawContextKey<boolean>('builtInExtensions', false);
|
||||
const SearchBuiltInExtensionsContext = new RawContextKey<boolean>('searchBuiltInExtensions', false);
|
||||
const RecommendedExtensionsContext = new RawContextKey<boolean>('recommendedExtensions', false);
|
||||
const DefaultRecommendedExtensionsContext = new RawContextKey<boolean>('defaultRecommendedExtensions', false);
|
||||
const viewIdNameMappings: { [id: string]: string } = {
|
||||
'extensions.listView': localize('marketPlace', "Marketplace"),
|
||||
'extensions.enabledExtensionList': localize('enabledExtensions', "Enabled"),
|
||||
'extensions.enabledExtensionList2': localize('enabledExtensions', "Enabled"),
|
||||
'extensions.disabledExtensionList': localize('disabledExtensions', "Disabled"),
|
||||
'extensions.disabledExtensionList2': localize('disabledExtensions', "Disabled"),
|
||||
// {{SQL CARBON EDIT}}
|
||||
// 'extensions.popularExtensionsList': localize('popularExtensions', "Popular"),
|
||||
'extensions.recommendedList': localize('recommendedExtensions', "Recommended"),
|
||||
'extensions.otherrecommendedList': localize('otherRecommendedExtensions', "Other Recommendations"),
|
||||
'extensions.workspaceRecommendedList': localize('workspaceRecommendedExtensions', "Workspace Recommendations"),
|
||||
'extensions.builtInExtensionsList': localize('builtInExtensions', "Features"),
|
||||
'extensions.builtInThemesExtensionsList': localize('builtInThemesExtensions', "Themes"),
|
||||
'extensions.builtInBasicsExtensionsList': localize('builtInBasicsExtensions', "Programming Languages"),
|
||||
'extensions.syncedExtensionsList': localize('syncedExtensions', "My Account"),
|
||||
};
|
||||
|
||||
export class ExtensionsViewletViewsContribution implements IWorkbenchContribution {
|
||||
|
||||
@@ -103,223 +88,233 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio
|
||||
}
|
||||
|
||||
private registerViews(): void {
|
||||
let viewDescriptors: IViewDescriptor[] = [];
|
||||
viewDescriptors.push(this.createMarketPlaceExtensionsListViewDescriptor());
|
||||
viewDescriptors.push(this.createDefaultEnabledExtensionsListViewDescriptor());
|
||||
viewDescriptors.push(this.createDefaultDisabledExtensionsListViewDescriptor());
|
||||
// {{SQL CARBON EDIT}}
|
||||
// viewDescriptors.push(this.createDefaultPopularExtensionsListViewDescriptor());
|
||||
viewDescriptors.push(this.createEnabledExtensionsListViewDescriptor());
|
||||
viewDescriptors.push(this.createDisabledExtensionsListViewDescriptor());
|
||||
viewDescriptors.push(this.createBuiltInExtensionsListViewDescriptor());
|
||||
viewDescriptors.push(this.createBuiltInBasicsExtensionsListViewDescriptor());
|
||||
viewDescriptors.push(this.createBuiltInThemesExtensionsListViewDescriptor());
|
||||
viewDescriptors.push(this.createDefaultRecommendedExtensionsListViewDescriptor());
|
||||
viewDescriptors.push(this.createOtherRecommendedExtensionsListViewDescriptor());
|
||||
viewDescriptors.push(this.createWorkspaceRecommendedExtensionsListViewDescriptor());
|
||||
const viewDescriptors: IViewDescriptor[] = [];
|
||||
|
||||
if (this.extensionManagementServerService.localExtensionManagementServer) {
|
||||
viewDescriptors.push(...this.createExtensionsViewDescriptorsForServer(this.extensionManagementServerService.localExtensionManagementServer));
|
||||
}
|
||||
if (this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||
viewDescriptors.push(...this.createExtensionsViewDescriptorsForServer(this.extensionManagementServerService.remoteExtensionManagementServer));
|
||||
}
|
||||
/* Default views */
|
||||
viewDescriptors.push(...this.createDefaultExtensionsViewDescriptors());
|
||||
|
||||
/* Search views */
|
||||
viewDescriptors.push(...this.createSearchExtensionsViewDescriptors());
|
||||
|
||||
/* Recommendations views */
|
||||
viewDescriptors.push(...this.createRecommendedExtensionsViewDescriptors());
|
||||
|
||||
/* Built-in extensions views */
|
||||
viewDescriptors.push(...this.createBuiltinExtensionsViewDescriptors());
|
||||
|
||||
Registry.as<IViewsRegistry>(Extensions.ViewsRegistry).registerViews(viewDescriptors, this.container);
|
||||
}
|
||||
|
||||
// View used for any kind of searching
|
||||
private createMarketPlaceExtensionsListViewDescriptor(): IViewDescriptor {
|
||||
const id = 'extensions.listView';
|
||||
return {
|
||||
id,
|
||||
name: viewIdNameMappings[id],
|
||||
private createDefaultExtensionsViewDescriptors(): IViewDescriptor[] {
|
||||
const viewDescriptors: IViewDescriptor[] = [];
|
||||
|
||||
/*
|
||||
* Default popular extensions view
|
||||
* Separate view for popular extensions required as we need to show popular and recommended sections
|
||||
* in the default view when there is no search text, and user has no installed extensions.
|
||||
*/
|
||||
// viewDescriptors.push({ {{SQL CARBON EDIT}} remove popular
|
||||
// id: 'workbench.views.extensions.popular',
|
||||
// name: localize('popularExtensions', "Popular"),
|
||||
// ctorDescriptor: new SyncDescriptor(ExtensionsListView),
|
||||
// when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.not('hasInstalledExtensions')),
|
||||
// weight: 60,
|
||||
// order: 1,
|
||||
// });
|
||||
|
||||
/*
|
||||
* Default installed extensions views - Shows all user installed extensions.
|
||||
*/
|
||||
const servers: IExtensionManagementServer[] = [];
|
||||
if (this.extensionManagementServerService.localExtensionManagementServer) {
|
||||
servers.push(this.extensionManagementServerService.localExtensionManagementServer);
|
||||
}
|
||||
if (this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||
servers.push(this.extensionManagementServerService.remoteExtensionManagementServer);
|
||||
}
|
||||
const getViewName = (viewTitle: string, server: IExtensionManagementServer): string => {
|
||||
return servers.length > 1 ? `${server.label} - ${viewTitle}` : viewTitle;
|
||||
};
|
||||
for (const server of servers) {
|
||||
const getInstalledViewName = (): string => getViewName(localize('installed', "Installed"), server);
|
||||
const onDidChangeServerLabel: EventOf<void> = EventOf.map(this.labelService.onDidChangeFormatters, () => undefined);
|
||||
viewDescriptors.push({
|
||||
id: servers.length > 1 ? `workbench.views.extensions.${server.id}.installed` : `workbench.views.extensions.installed`,
|
||||
get name() { return getInstalledViewName(); },
|
||||
ctorDescriptor: new SyncDescriptor(ServerExtensionsView, [server, EventOf.map<void, string>(onDidChangeServerLabel, () => getInstalledViewName())]),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions')),
|
||||
weight: 100,
|
||||
order: 2,
|
||||
/* Installed extensions views shall not be hidden when there are more than one server */
|
||||
canToggleVisibility: servers.length === 1
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Default recommended extensions view
|
||||
* When user has installed extensions, this is shown along with the views for enabled & disabled extensions
|
||||
* When user has no installed extensions, this is shown along with the view for popular extensions
|
||||
*/
|
||||
viewDescriptors.push({
|
||||
id: 'extensions.recommendedList',
|
||||
name: localize('recommendedExtensions', "Recommended"),
|
||||
ctorDescriptor: new SyncDescriptor(DefaultRecommendedExtensionsView),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.not('config.extensions.showRecommendationsOnlyOnDemand')),
|
||||
weight: 40,
|
||||
order: 3,
|
||||
canToggleVisibility: true
|
||||
});
|
||||
|
||||
/* Installed views shall be default in multi server window */
|
||||
if (servers.length === 1) {
|
||||
/*
|
||||
* Default enabled extensions view - Shows all user installed enabled extensions.
|
||||
* Hidden by default
|
||||
*/
|
||||
viewDescriptors.push({
|
||||
id: 'workbench.views.extensions.enabled',
|
||||
name: localize('enabledExtensions', "Enabled"),
|
||||
ctorDescriptor: new SyncDescriptor(EnabledExtensionsView),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions')),
|
||||
hideByDefault: true,
|
||||
weight: 40,
|
||||
order: 4,
|
||||
canToggleVisibility: true
|
||||
});
|
||||
|
||||
/*
|
||||
* Default disabled extensions view - Shows all disabled extensions.
|
||||
* Hidden by default
|
||||
*/
|
||||
viewDescriptors.push({
|
||||
id: 'workbench.views.extensions.disabled',
|
||||
name: localize('disabledExtensions', "Disabled"),
|
||||
ctorDescriptor: new SyncDescriptor(DisabledExtensionsView),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions')),
|
||||
hideByDefault: true,
|
||||
weight: 10,
|
||||
order: 5,
|
||||
canToggleVisibility: true
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
return viewDescriptors;
|
||||
}
|
||||
|
||||
private createSearchExtensionsViewDescriptors(): IViewDescriptor[] {
|
||||
const viewDescriptors: IViewDescriptor[] = [];
|
||||
|
||||
/*
|
||||
* View used for searching Marketplace
|
||||
*/
|
||||
viewDescriptors.push({
|
||||
id: 'workbench.views.extensions.marketplace',
|
||||
name: localize('marketPlace', "Marketplace"),
|
||||
ctorDescriptor: new SyncDescriptor(ExtensionsListView),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('searchMarketplaceExtensions')),
|
||||
weight: 100
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// Separate view for enabled extensions required as we need to show enabled, disabled and recommended sections
|
||||
// in the default view when there is no search text, but user has installed extensions.
|
||||
private createDefaultEnabledExtensionsListViewDescriptor(): IViewDescriptor {
|
||||
const id = 'extensions.enabledExtensionList';
|
||||
return {
|
||||
id,
|
||||
name: viewIdNameMappings[id],
|
||||
ctorDescriptor: new SyncDescriptor(EnabledExtensionsView),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions'), RemoteNameContext.isEqualTo('')),
|
||||
weight: 40,
|
||||
canToggleVisibility: true,
|
||||
order: 1
|
||||
};
|
||||
}
|
||||
|
||||
// Separate view for disabled extensions required as we need to show enabled, disabled and recommended sections
|
||||
// in the default view when there is no search text, but user has installed extensions.
|
||||
private createDefaultDisabledExtensionsListViewDescriptor(): IViewDescriptor {
|
||||
const id = 'extensions.disabledExtensionList';
|
||||
return {
|
||||
id,
|
||||
name: viewIdNameMappings[id],
|
||||
ctorDescriptor: new SyncDescriptor(DisabledExtensionsView),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions'), RemoteNameContext.isEqualTo('')),
|
||||
weight: 10,
|
||||
canToggleVisibility: true,
|
||||
order: 3,
|
||||
collapsed: true
|
||||
};
|
||||
}
|
||||
|
||||
/* // {{SQL CARBON EDIT}}
|
||||
// Separate view for popular extensions required as we need to show popular and recommended sections
|
||||
// in the default view when there is no search text, and user has no installed extensions.
|
||||
private createDefaultPopularExtensionsListViewDescriptor(): IViewDescriptor {
|
||||
const id = 'extensions.popularExtensionsList';
|
||||
return {
|
||||
id,
|
||||
name: viewIdNameMappings[id],
|
||||
ctorDescriptor: new SyncDescriptor(ExtensionsListView),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.not('hasInstalledExtensions')),
|
||||
weight: 60,
|
||||
order: 1
|
||||
};
|
||||
}
|
||||
*/
|
||||
|
||||
private createExtensionsViewDescriptorsForServer(server: IExtensionManagementServer): IViewDescriptor[] {
|
||||
const getViewName = (viewTitle: string, server: IExtensionManagementServer): string => {
|
||||
const serverLabel = server.label;
|
||||
if (viewTitle && this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||
return `${serverLabel} - ${viewTitle}`;
|
||||
}
|
||||
return viewTitle ? viewTitle : serverLabel;
|
||||
};
|
||||
const getInstalledViewName = (): string => getViewName(localize('installed', "Installed"), server);
|
||||
const getOutdatedViewName = (): string => getViewName(localize('outdated', "Outdated"), server);
|
||||
const onDidChangeServerLabel: EventOf<void> = EventOf.map(this.labelService.onDidChangeFormatters, () => undefined);
|
||||
return [{
|
||||
id: `extensions.${server.id}.installed`,
|
||||
get name() { return getInstalledViewName(); },
|
||||
ctorDescriptor: new SyncDescriptor(ServerExtensionsView, [server, EventOf.map<void, string>(onDidChangeServerLabel, () => getInstalledViewName())]),
|
||||
/*
|
||||
* View used for searching all installed extensions
|
||||
*/
|
||||
viewDescriptors.push({
|
||||
id: 'workbench.views.extensions.searchInstalled',
|
||||
name: localize('installed', "Installed"),
|
||||
ctorDescriptor: new SyncDescriptor(InstalledExtensionsView),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('searchInstalledExtensions')),
|
||||
weight: 100
|
||||
}, {
|
||||
id: `extensions.${server.id}.outdated`,
|
||||
get name() { return getOutdatedViewName(); },
|
||||
ctorDescriptor: new SyncDescriptor(ServerExtensionsView, [server, EventOf.map<void, string>(onDidChangeServerLabel, () => getOutdatedViewName())]),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('searchOutdatedExtensions')),
|
||||
weight: 100
|
||||
}, {
|
||||
id: `extensions.${server.id}.default`,
|
||||
get name() { return getInstalledViewName(); },
|
||||
ctorDescriptor: new SyncDescriptor(ServerExtensionsView, [server, EventOf.map<void, string>(onDidChangeServerLabel, () => getInstalledViewName())]),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions'), RemoteNameContext.notEqualsTo('')),
|
||||
weight: 40,
|
||||
order: 1
|
||||
}];
|
||||
}
|
||||
});
|
||||
|
||||
// Separate view for recommended extensions required as we need to show it along with other views when there is no search text.
|
||||
// When user has installed extensions, this is shown along with the views for enabled & disabled extensions
|
||||
// When user has no installed extensions, this is shown along with the view for popular extensions
|
||||
private createDefaultRecommendedExtensionsListViewDescriptor(): IViewDescriptor {
|
||||
const id = 'extensions.recommendedList';
|
||||
return {
|
||||
id,
|
||||
name: viewIdNameMappings[id],
|
||||
ctorDescriptor: new SyncDescriptor(DefaultRecommendedExtensionsView),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('defaultRecommendedExtensions')),
|
||||
weight: 40,
|
||||
order: 2,
|
||||
canToggleVisibility: true
|
||||
};
|
||||
}
|
||||
|
||||
// Separate view for recommedations that are not workspace recommendations.
|
||||
// Shown along with view for workspace recommendations, when using the command that shows recommendations
|
||||
private createOtherRecommendedExtensionsListViewDescriptor(): IViewDescriptor {
|
||||
const id = 'extensions.otherrecommendedList';
|
||||
return {
|
||||
id,
|
||||
name: viewIdNameMappings[id],
|
||||
ctorDescriptor: new SyncDescriptor(RecommendedExtensionsView),
|
||||
when: ContextKeyExpr.has('recommendedExtensions'),
|
||||
weight: 50,
|
||||
order: 2
|
||||
};
|
||||
}
|
||||
|
||||
// Separate view for workspace recommendations.
|
||||
// Shown along with view for other recommendations, when using the command that shows recommendations
|
||||
private createWorkspaceRecommendedExtensionsListViewDescriptor(): IViewDescriptor {
|
||||
const id = 'extensions.workspaceRecommendedList';
|
||||
return {
|
||||
id,
|
||||
name: viewIdNameMappings[id],
|
||||
ctorDescriptor: new SyncDescriptor(WorkspaceRecommendedExtensionsView),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('recommendedExtensions'), ContextKeyExpr.has('nonEmptyWorkspace')),
|
||||
weight: 50,
|
||||
order: 1
|
||||
};
|
||||
}
|
||||
|
||||
private createEnabledExtensionsListViewDescriptor(): IViewDescriptor {
|
||||
const id = 'extensions.enabledExtensionList2';
|
||||
return {
|
||||
id,
|
||||
name: viewIdNameMappings[id],
|
||||
/*
|
||||
* View used for searching enabled extensions
|
||||
*/
|
||||
viewDescriptors.push({
|
||||
id: 'workbench.views.extensions.searchEnabled',
|
||||
name: localize('enabled', "Enabled"),
|
||||
ctorDescriptor: new SyncDescriptor(EnabledExtensionsView),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('searchEnabledExtensions')),
|
||||
weight: 40,
|
||||
order: 1
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
private createDisabledExtensionsListViewDescriptor(): IViewDescriptor {
|
||||
const id = 'extensions.disabledExtensionList2';
|
||||
return {
|
||||
id,
|
||||
name: viewIdNameMappings[id],
|
||||
/*
|
||||
* View used for searching disabled extensions
|
||||
*/
|
||||
viewDescriptors.push({
|
||||
id: 'workbench.views.extensions.searchDisabled',
|
||||
name: localize('disabled', "Disabled"),
|
||||
ctorDescriptor: new SyncDescriptor(DisabledExtensionsView),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('searchDisabledExtensions')),
|
||||
weight: 10,
|
||||
order: 3,
|
||||
collapsed: true
|
||||
};
|
||||
});
|
||||
|
||||
/*
|
||||
* View used for searching outdated extensions
|
||||
*/
|
||||
viewDescriptors.push({
|
||||
id: 'workbench.views.extensions.searchOutdated',
|
||||
name: localize('outdated', "Outdated"),
|
||||
ctorDescriptor: new SyncDescriptor(OutdatedExtensionsView),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('searchOutdatedExtensions')),
|
||||
});
|
||||
|
||||
/*
|
||||
* View used for searching builtin extensions
|
||||
*/
|
||||
viewDescriptors.push({
|
||||
id: 'workbench.views.extensions.searchBuiltin',
|
||||
name: localize('builtin', "Builtin"),
|
||||
ctorDescriptor: new SyncDescriptor(SearchBuiltInExtensionsView),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('searchBuiltInExtensions')),
|
||||
});
|
||||
|
||||
return viewDescriptors;
|
||||
}
|
||||
|
||||
private createBuiltInExtensionsListViewDescriptor(): IViewDescriptor {
|
||||
const id = 'extensions.builtInExtensionsList';
|
||||
return {
|
||||
id,
|
||||
name: viewIdNameMappings[id],
|
||||
ctorDescriptor: new SyncDescriptor(BuiltInExtensionsView),
|
||||
when: ContextKeyExpr.has('searchBuiltInExtensions'),
|
||||
weight: 100
|
||||
};
|
||||
private createRecommendedExtensionsViewDescriptors(): IViewDescriptor[] {
|
||||
const viewDescriptors: IViewDescriptor[] = [];
|
||||
|
||||
viewDescriptors.push({
|
||||
id: 'workbench.views.extensions.workspaceRecommendations',
|
||||
name: localize('workspaceRecommendedExtensions', "Workspace Recommendations"),
|
||||
ctorDescriptor: new SyncDescriptor(WorkspaceRecommendedExtensionsView),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('recommendedExtensions'), ContextKeyExpr.has('nonEmptyWorkspace')),
|
||||
order: 1
|
||||
});
|
||||
|
||||
viewDescriptors.push({
|
||||
id: 'workbench.views.extensions.otherRecommendations',
|
||||
name: localize('otherRecommendedExtensions', "Other Recommendations"),
|
||||
ctorDescriptor: new SyncDescriptor(RecommendedExtensionsView),
|
||||
when: ContextKeyExpr.has('recommendedExtensions'),
|
||||
order: 2
|
||||
});
|
||||
|
||||
return viewDescriptors;
|
||||
}
|
||||
|
||||
private createBuiltInThemesExtensionsListViewDescriptor(): IViewDescriptor {
|
||||
const id = 'extensions.builtInThemesExtensionsList';
|
||||
return {
|
||||
id,
|
||||
name: viewIdNameMappings[id],
|
||||
private createBuiltinExtensionsViewDescriptors(): IViewDescriptor[] {
|
||||
const viewDescriptors: IViewDescriptor[] = [];
|
||||
|
||||
viewDescriptors.push({
|
||||
id: 'workbench.views.extensions.builtinFeatureExtensions',
|
||||
name: localize('builtinFeatureExtensions', "Features"),
|
||||
ctorDescriptor: new SyncDescriptor(BuiltInFeatureExtensionsView),
|
||||
when: ContextKeyExpr.has('builtInExtensions'),
|
||||
});
|
||||
|
||||
viewDescriptors.push({
|
||||
id: 'workbench.views.extensions.builtinThemeExtensions',
|
||||
name: localize('builtInThemesExtensions', "Themes"),
|
||||
ctorDescriptor: new SyncDescriptor(BuiltInThemesExtensionsView),
|
||||
when: ContextKeyExpr.has('searchBuiltInExtensions'),
|
||||
weight: 100
|
||||
};
|
||||
}
|
||||
when: ContextKeyExpr.has('builtInExtensions'),
|
||||
});
|
||||
|
||||
private createBuiltInBasicsExtensionsListViewDescriptor(): IViewDescriptor {
|
||||
const id = 'extensions.builtInBasicsExtensionsList';
|
||||
return {
|
||||
id,
|
||||
name: viewIdNameMappings[id],
|
||||
ctorDescriptor: new SyncDescriptor(BuiltInBasicsExtensionsView),
|
||||
when: ContextKeyExpr.has('searchBuiltInExtensions'),
|
||||
weight: 100
|
||||
};
|
||||
viewDescriptors.push({
|
||||
id: 'workbench.views.extensions.builtinProgrammingLanguageExtensions',
|
||||
name: localize('builtinProgrammingLanguageExtensions', "Programming Languages"),
|
||||
ctorDescriptor: new SyncDescriptor(BuiltInProgrammingLanguageExtensionsView),
|
||||
when: ContextKeyExpr.has('builtInExtensions'),
|
||||
});
|
||||
|
||||
return viewDescriptors;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -336,15 +331,13 @@ export class ExtensionsViewPaneContainer extends ViewPaneContainer implements IE
|
||||
private searchEnabledExtensionsContextKey: IContextKey<boolean>;
|
||||
private searchDisabledExtensionsContextKey: IContextKey<boolean>;
|
||||
private hasInstalledExtensionsContextKey: IContextKey<boolean>;
|
||||
private builtInExtensionsContextKey: IContextKey<boolean>;
|
||||
private searchBuiltInExtensionsContextKey: IContextKey<boolean>;
|
||||
private recommendedExtensionsContextKey: IContextKey<boolean>;
|
||||
private defaultRecommendedExtensionsContextKey: IContextKey<boolean>;
|
||||
|
||||
private searchDelayer: Delayer<void>;
|
||||
private root: HTMLElement | undefined;
|
||||
private searchBox: SuggestEnabledInput | undefined;
|
||||
private primaryActions: IAction[] | undefined;
|
||||
private secondaryActions: IAction[] | null = null;
|
||||
private readonly searchViewletState: MementoObject;
|
||||
|
||||
constructor(
|
||||
@@ -364,7 +357,7 @@ export class ExtensionsViewPaneContainer extends ViewPaneContainer implements IE
|
||||
@IContextMenuService contextMenuService: IContextMenuService,
|
||||
@IExtensionService extensionService: IExtensionService,
|
||||
@IViewDescriptorService viewDescriptorService: IViewDescriptorService,
|
||||
@IPreferencesService private readonly preferencesService: IPreferencesService
|
||||
@IPreferencesService private readonly preferencesService: IPreferencesService,
|
||||
) {
|
||||
super(VIEWLET_ID, { mergeViewWithContainerWhenSingleView: true }, instantiationService, configurationService, layoutService, contextMenuService, telemetryService, extensionService, themeService, storageService, contextService, viewDescriptorService);
|
||||
|
||||
@@ -377,10 +370,9 @@ export class ExtensionsViewPaneContainer extends ViewPaneContainer implements IE
|
||||
this.searchEnabledExtensionsContextKey = SearchEnabledExtensionsContext.bindTo(contextKeyService);
|
||||
this.searchDisabledExtensionsContextKey = SearchDisabledExtensionsContext.bindTo(contextKeyService);
|
||||
this.hasInstalledExtensionsContextKey = HasInstalledExtensionsContext.bindTo(contextKeyService);
|
||||
this.builtInExtensionsContextKey = BuiltInExtensionsContext.bindTo(contextKeyService);
|
||||
this.searchBuiltInExtensionsContextKey = SearchBuiltInExtensionsContext.bindTo(contextKeyService);
|
||||
this.recommendedExtensionsContextKey = RecommendedExtensionsContext.bindTo(contextKeyService);
|
||||
this.defaultRecommendedExtensionsContextKey = DefaultRecommendedExtensionsContext.bindTo(contextKeyService);
|
||||
this.defaultRecommendedExtensionsContextKey.set(!this.configurationService.getValue<boolean>(ShowRecommendationsOnlyOnDemandKey));
|
||||
this._register(this.viewletService.onDidViewletOpen(this.onViewletOpen, this));
|
||||
this.searchViewletState = this.getMemento(StorageScope.WORKSPACE);
|
||||
|
||||
@@ -390,12 +382,8 @@ export class ExtensionsViewPaneContainer extends ViewPaneContainer implements IE
|
||||
|
||||
this._register(this.configurationService.onDidChangeConfiguration(e => {
|
||||
if (e.affectsConfiguration(AutoUpdateConfigurationKey)) {
|
||||
this.secondaryActions = null;
|
||||
this.updateTitleArea();
|
||||
}
|
||||
if (e.affectedKeys.indexOf(ShowRecommendationsOnlyOnDemandKey) > -1) {
|
||||
this.defaultRecommendedExtensionsContextKey.set(!this.configurationService.getValue<boolean>(ShowRecommendationsOnlyOnDemandKey));
|
||||
}
|
||||
}, this));
|
||||
}
|
||||
|
||||
@@ -509,40 +497,57 @@ export class ExtensionsViewPaneContainer extends ViewPaneContainer implements IE
|
||||
}
|
||||
|
||||
getActions(): IAction[] {
|
||||
if (!this.primaryActions) {
|
||||
this.primaryActions = [
|
||||
this.instantiationService.createInstance(ClearExtensionsInputAction, ClearExtensionsInputAction.ID, ClearExtensionsInputAction.LABEL, this.onSearchChange, this.searchBox ? this.searchBox.getValue() : '')
|
||||
];
|
||||
return [
|
||||
new Action('workbench.extensions.action.filterExtensions', localize('filterExtensions', "Filter Extensions..."), 'codicon-filter', true),
|
||||
this.instantiationService.createInstance(ClearExtensionsInputAction, ClearExtensionsInputAction.ID, ClearExtensionsInputAction.LABEL, this.onSearchChange, this.searchBox ? this.searchBox.getValue() : ''),
|
||||
];
|
||||
}
|
||||
|
||||
getActionViewItem(action: IAction): IActionViewItem | undefined {
|
||||
if (action.id === 'workbench.extensions.action.filterExtensions') {
|
||||
return new DropdownMenuActionViewItem(action,
|
||||
[
|
||||
// this.instantiationService.createInstance(ShowPopularExtensionsAction, ShowPopularExtensionsAction.ID, localize('most popular filter', "Most Popular")), // {{SQL CARBON EDIT}}
|
||||
// this.instantiationService.createInstance(RecentlyPublishedExtensionsAction, RecentlyPublishedExtensionsAction.ID, localize('recently published filter', "Recently Published")), // {{SQL CARBON EDIT}}
|
||||
this.instantiationService.createInstance(ShowRecommendedExtensionsAction, ShowRecommendedExtensionsAction.ID, localize('recomended filter', "Recommended")),
|
||||
new ContextSubMenu(localize('filter by category', "Category"), EXTENSION_CATEGORIES.map(category => this.instantiationService.createInstance(SearchCategoryAction, `extensions.actions.searchByCategory.${category}`, category, category))),
|
||||
|
||||
new Separator(),
|
||||
this.instantiationService.createInstance(ShowBuiltInExtensionsAction, ShowBuiltInExtensionsAction.ID, localize('builtin filter', "Built-in")),
|
||||
this.instantiationService.createInstance(ShowInstalledExtensionsAction, ShowInstalledExtensionsAction.ID, localize('installed filter', "Installed")),
|
||||
this.instantiationService.createInstance(ShowEnabledExtensionsAction, ShowEnabledExtensionsAction.ID, localize('enabled filter', "Enabled")),
|
||||
this.instantiationService.createInstance(ShowDisabledExtensionsAction, ShowDisabledExtensionsAction.ID, localize('disabled filter', "Disabled")),
|
||||
this.instantiationService.createInstance(ShowOutdatedExtensionsAction, ShowOutdatedExtensionsAction.ID, localize('outdated filter', "Outdated")),
|
||||
|
||||
new Separator(),
|
||||
new ContextSubMenu(localize('sorty by', "Sort By"), [
|
||||
// this.instantiationService.createInstance(ChangeSortAction, 'extensions.sort.install', localize('sort by installs', "Install Count"), this.onSearchChange, 'installs'), // {{SQL CARBON EDIT}}
|
||||
// this.instantiationService.createInstance(ChangeSortAction, 'extensions.sort.rating', localize('sort by rating', "Rating"), this.onSearchChange, 'rating'), // {{SQL CARBON EDIT}}
|
||||
this.instantiationService.createInstance(ChangeSortAction, 'extensions.sort.name', localize('sort by name', "Name"), this.onSearchChange, 'name'),
|
||||
this.instantiationService.createInstance(ChangeSortAction, 'extensions.sort.publishedDate', localize('sort by date', "Published Date"), this.onSearchChange, 'publishedDate'),
|
||||
]),
|
||||
],
|
||||
this.contextMenuService, undefined, undefined, undefined, 'codicon-filter', undefined, true);
|
||||
}
|
||||
return this.primaryActions;
|
||||
return super.getActionViewItem(action);
|
||||
}
|
||||
|
||||
getSecondaryActions(): IAction[] {
|
||||
if (!this.secondaryActions) {
|
||||
this.secondaryActions = [
|
||||
this.instantiationService.createInstance(ShowInstalledExtensionsAction, ShowInstalledExtensionsAction.ID, ShowInstalledExtensionsAction.LABEL),
|
||||
this.instantiationService.createInstance(ShowOutdatedExtensionsAction, ShowOutdatedExtensionsAction.ID, ShowOutdatedExtensionsAction.LABEL),
|
||||
this.instantiationService.createInstance(ShowEnabledExtensionsAction, ShowEnabledExtensionsAction.ID, ShowEnabledExtensionsAction.LABEL),
|
||||
this.instantiationService.createInstance(ShowDisabledExtensionsAction, ShowDisabledExtensionsAction.ID, ShowDisabledExtensionsAction.LABEL),
|
||||
this.instantiationService.createInstance(ShowBuiltInExtensionsAction, ShowBuiltInExtensionsAction.ID, ShowBuiltInExtensionsAction.LABEL),
|
||||
this.instantiationService.createInstance(ShowRecommendedExtensionsAction, ShowRecommendedExtensionsAction.ID, ShowRecommendedExtensionsAction.LABEL),
|
||||
// this.instantiationService.createInstance(ShowPopularExtensionsAction, ShowPopularExtensionsAction.ID, ShowPopularExtensionsAction.LABEL), // {{SQL CARBON EDIT}}
|
||||
new Separator(),
|
||||
// {{SQL CARBON EDIT}}
|
||||
//this.instantiationService.createInstance(ChangeSortAction, 'extensions.sort.install', localize('sort by installs', "Sort By: Install Count"), this.onSearchChange, 'installs'),
|
||||
//this.instantiationService.createInstance(ChangeSortAction, 'extensions.sort.rating', localize('sort by rating', "Sort By: Rating"), this.onSearchChange, 'rating'),
|
||||
this.instantiationService.createInstance(ChangeSortAction, 'extensions.sort.name', localize('sort by name', "Sort By: Name"), this.onSearchChange, 'name'),
|
||||
new Separator(),
|
||||
this.instantiationService.createInstance(CheckForUpdatesAction, CheckForUpdatesAction.ID, CheckForUpdatesAction.LABEL),
|
||||
...(this.configurationService.getValue(AutoUpdateConfigurationKey) ? [this.instantiationService.createInstance(DisableAutoUpdateAction, DisableAutoUpdateAction.ID, DisableAutoUpdateAction.LABEL)] : [this.instantiationService.createInstance(UpdateAllAction, UpdateAllAction.ID, UpdateAllAction.LABEL), this.instantiationService.createInstance(EnableAutoUpdateAction, EnableAutoUpdateAction.ID, EnableAutoUpdateAction.LABEL)]),
|
||||
this.instantiationService.createInstance(InstallVSIXAction, InstallVSIXAction.ID, InstallVSIXAction.LABEL),
|
||||
new Separator(),
|
||||
this.instantiationService.createInstance(DisableAllAction, DisableAllAction.ID, DisableAllAction.LABEL),
|
||||
this.instantiationService.createInstance(EnableAllAction, EnableAllAction.ID, EnableAllAction.LABEL)
|
||||
];
|
||||
}
|
||||
const actions: IAction[] = [];
|
||||
|
||||
return this.secondaryActions;
|
||||
actions.push(this.instantiationService.createInstance(CheckForUpdatesAction, CheckForUpdatesAction.ID, CheckForUpdatesAction.LABEL));
|
||||
if (this.configurationService.getValue(AutoUpdateConfigurationKey)) {
|
||||
actions.push(this.instantiationService.createInstance(DisableAutoUpdateAction, DisableAutoUpdateAction.ID, DisableAutoUpdateAction.LABEL));
|
||||
} else {
|
||||
actions.push(this.instantiationService.createInstance(UpdateAllAction, UpdateAllAction.ID, UpdateAllAction.LABEL), this.instantiationService.createInstance(EnableAutoUpdateAction, EnableAutoUpdateAction.ID, EnableAutoUpdateAction.LABEL));
|
||||
}
|
||||
actions.push(this.instantiationService.createInstance(InstallVSIXAction, InstallVSIXAction.ID, InstallVSIXAction.LABEL));
|
||||
|
||||
actions.push(new Separator());
|
||||
actions.push(this.instantiationService.createInstance(DisableAllAction, DisableAllAction.ID, DisableAllAction.LABEL));
|
||||
actions.push(this.instantiationService.createInstance(EnableAllAction, EnableAllAction.ID, EnableAllAction.LABEL));
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
search(value: string, refresh: boolean = false): void {
|
||||
@@ -580,7 +585,8 @@ export class ExtensionsViewPaneContainer extends ViewPaneContainer implements IE
|
||||
this.searchOutdatedExtensionsContextKey.set(ExtensionsListView.isOutdatedExtensionsQuery(value));
|
||||
this.searchEnabledExtensionsContextKey.set(ExtensionsListView.isEnabledExtensionsQuery(value));
|
||||
this.searchDisabledExtensionsContextKey.set(ExtensionsListView.isDisabledExtensionsQuery(value));
|
||||
this.searchBuiltInExtensionsContextKey.set(ExtensionsListView.isBuiltInExtensionsQuery(value));
|
||||
this.searchBuiltInExtensionsContextKey.set(ExtensionsListView.isSearchBuiltInExtensionsQuery(value));
|
||||
this.builtInExtensionsContextKey.set(ExtensionsListView.isBuiltInExtensionsQuery(value));
|
||||
this.recommendedExtensionsContextKey.set(isRecommendedExtensionsQuery);
|
||||
this.searchMarketplaceExtensionsContextKey.set(!!value && !ExtensionsListView.isLocalExtensionsQuery(value) && !isRecommendedExtensionsQuery);
|
||||
this.nonEmptyWorkspaceContextKey.set(this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY);
|
||||
@@ -602,19 +608,20 @@ export class ExtensionsViewPaneContainer extends ViewPaneContainer implements IE
|
||||
}
|
||||
|
||||
private alertSearchResult(count: number, viewId: string): void {
|
||||
const view = this.viewContainerModel.visibleViewDescriptors.find(view => view.id === viewId);
|
||||
switch (count) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
if (viewIdNameMappings[viewId]) {
|
||||
alert(localize('extensionFoundInSection', "1 extension found in the {0} section.", viewIdNameMappings[viewId]));
|
||||
if (view) {
|
||||
alert(localize('extensionFoundInSection', "1 extension found in the {0} section.", view.name));
|
||||
} else {
|
||||
alert(localize('extensionFound', "1 extension found."));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (viewIdNameMappings[viewId]) {
|
||||
alert(localize('extensionsFoundInSection', "{0} extensions found in the {1} section.", count, viewIdNameMappings[viewId]));
|
||||
if (view) {
|
||||
alert(localize('extensionsFoundInSection', "{0} extensions found in the {1} section.", count, view.name));
|
||||
} else {
|
||||
alert(localize('extensionsFound', "{0} extensions found.", count));
|
||||
}
|
||||
|
||||
@@ -197,6 +197,7 @@ export class ExtensionsListView extends ViewPane {
|
||||
case 'installs': options = assign(options, { sortBy: SortBy.InstallCount }); break;
|
||||
case 'rating': options = assign(options, { sortBy: SortBy.WeightedRating }); break;
|
||||
case 'name': options = assign(options, { sortBy: SortBy.Title }); break;
|
||||
case 'publishedDate': options = assign(options, { sortBy: SortBy.PublishedDate }); break;
|
||||
}
|
||||
|
||||
const successCallback = (model: IPagedModel<IExtension>) => {
|
||||
@@ -882,16 +883,21 @@ export class ExtensionsListView extends ViewPane {
|
||||
this.list = null;
|
||||
}
|
||||
|
||||
static isBuiltInExtensionsQuery(query: string): boolean {
|
||||
return /^\s*@builtin\s*$/i.test(query);
|
||||
}
|
||||
|
||||
static isLocalExtensionsQuery(query: string): boolean {
|
||||
return this.isInstalledExtensionsQuery(query)
|
||||
|| this.isOutdatedExtensionsQuery(query)
|
||||
|| this.isEnabledExtensionsQuery(query)
|
||||
|| this.isDisabledExtensionsQuery(query)
|
||||
|| this.isBuiltInExtensionsQuery(query);
|
||||
|| this.isBuiltInExtensionsQuery(query)
|
||||
|| this.isSearchBuiltInExtensionsQuery(query);
|
||||
}
|
||||
|
||||
static isSearchBuiltInExtensionsQuery(query: string): boolean {
|
||||
return /@builtin\s.+/i.test(query);
|
||||
}
|
||||
|
||||
static isBuiltInExtensionsQuery(query: string): boolean {
|
||||
return /@builtin$/i.test(query.trim());
|
||||
}
|
||||
|
||||
static isInstalledExtensionsQuery(query: string): boolean {
|
||||
@@ -977,7 +983,7 @@ export class ServerExtensionsView extends ExtensionsListView {
|
||||
|
||||
async show(query: string): Promise<IPagedModel<IExtension>> {
|
||||
query = query ? query : '@installed';
|
||||
if (!ExtensionsListView.isLocalExtensionsQuery(query) && !ExtensionsListView.isBuiltInExtensionsQuery(query)) {
|
||||
if (!ExtensionsListView.isLocalExtensionsQuery(query)) {
|
||||
query = query += ' @installed';
|
||||
}
|
||||
return super.show(query.trim());
|
||||
@@ -1009,7 +1015,29 @@ export class DisabledExtensionsView extends ExtensionsListView {
|
||||
}
|
||||
}
|
||||
|
||||
export class BuiltInExtensionsView extends ExtensionsListView {
|
||||
export class OutdatedExtensionsView extends ExtensionsListView {
|
||||
|
||||
async show(query: string): Promise<IPagedModel<IExtension>> {
|
||||
query = query || '@outdated';
|
||||
return ExtensionsListView.isOutdatedExtensionsQuery(query) ? super.show(query) : this.showEmptyModel();
|
||||
}
|
||||
}
|
||||
|
||||
export class InstalledExtensionsView extends ExtensionsListView {
|
||||
|
||||
async show(query: string): Promise<IPagedModel<IExtension>> {
|
||||
query = query || '@installed';
|
||||
return ExtensionsListView.isInstalledExtensionsQuery(query) ? super.show(query) : this.showEmptyModel();
|
||||
}
|
||||
}
|
||||
|
||||
export class SearchBuiltInExtensionsView extends ExtensionsListView {
|
||||
async show(query: string): Promise<IPagedModel<IExtension>> {
|
||||
return ExtensionsListView.isSearchBuiltInExtensionsQuery(query) ? super.show(query) : this.showEmptyModel();
|
||||
}
|
||||
}
|
||||
|
||||
export class BuiltInFeatureExtensionsView extends ExtensionsListView {
|
||||
async show(query: string): Promise<IPagedModel<IExtension>> {
|
||||
return (query && query.trim() !== '@builtin') ? this.showEmptyModel() : super.show('@builtin:features');
|
||||
}
|
||||
@@ -1021,7 +1049,7 @@ export class BuiltInThemesExtensionsView extends ExtensionsListView {
|
||||
}
|
||||
}
|
||||
|
||||
export class BuiltInBasicsExtensionsView extends ExtensionsListView {
|
||||
export class BuiltInProgrammingLanguageExtensionsView extends ExtensionsListView {
|
||||
async show(query: string): Promise<IPagedModel<IExtension>> {
|
||||
return (query && query.trim() !== '@builtin') ? this.showEmptyModel() : super.show('@builtin:basics');
|
||||
}
|
||||
|
||||
@@ -13,7 +13,8 @@ export const CELL_RUN_GUTTER = 28;
|
||||
export const CODE_CELL_LEFT_MARGIN = 32;
|
||||
|
||||
export const EDITOR_TOOLBAR_HEIGHT = 0;
|
||||
export const BOTTOM_CELL_TOOLBAR_HEIGHT = 28;
|
||||
export const BOTTOM_CELL_TOOLBAR_HEIGHT = 18;
|
||||
export const BOTTOM_CELL_TOOLBAR_OFFSET = 12;
|
||||
export const CELL_STATUSBAR_HEIGHT = 22;
|
||||
|
||||
// Margin above editor
|
||||
|
||||
@@ -74,7 +74,8 @@ const FOCUS_OUT_OUTPUT_COMMAND_ID = 'notebook.cell.focusOutOutput';
|
||||
|
||||
export const NOTEBOOK_ACTIONS_CATEGORY = { value: localize('notebookActions.category', "Notebook"), original: 'Notebook' };
|
||||
|
||||
export const CELL_TITLE_GROUP_ID = 'inline';
|
||||
export const CELL_TITLE_CELL_GROUP_ID = 'inline/cell';
|
||||
export const CELL_TITLE_OUTPUT_GROUP_ID = 'inline/output';
|
||||
|
||||
const EDITOR_WIDGET_ACTION_WEIGHT = KeybindingWeight.EditorContrib; // smaller than Suggest Widget, etc
|
||||
|
||||
@@ -407,6 +408,11 @@ registerAction2(class extends NotebookCellAction {
|
||||
weight: KeybindingWeight.WorkbenchContrib
|
||||
},
|
||||
precondition: ContextKeyExpr.and(NOTEBOOK_IS_ACTIVE_EDITOR),
|
||||
menu: {
|
||||
id: MenuId.NotebookCellTitle,
|
||||
when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_CELL_EDITABLE),
|
||||
group: '2_edit',
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -425,6 +431,11 @@ registerAction2(class extends NotebookCellAction {
|
||||
primary: KeyCode.KEY_M,
|
||||
weight: KeybindingWeight.WorkbenchContrib
|
||||
},
|
||||
menu: {
|
||||
id: MenuId.NotebookCellTitle,
|
||||
when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_CELL_EDITABLE),
|
||||
group: '2_edit',
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -601,7 +612,7 @@ registerAction2(class extends NotebookCellAction {
|
||||
NOTEBOOK_CELL_MARKDOWN_EDIT_MODE.toNegated(),
|
||||
NOTEBOOK_CELL_EDITABLE),
|
||||
order: CellToolbarOrder.EditCell,
|
||||
group: CELL_TITLE_GROUP_ID
|
||||
group: CELL_TITLE_CELL_GROUP_ID
|
||||
},
|
||||
icon: { id: 'codicon/pencil' }
|
||||
});
|
||||
@@ -625,7 +636,7 @@ registerAction2(class extends NotebookCellAction {
|
||||
NOTEBOOK_CELL_MARKDOWN_EDIT_MODE,
|
||||
NOTEBOOK_CELL_EDITABLE),
|
||||
order: CellToolbarOrder.SaveCell,
|
||||
group: CELL_TITLE_GROUP_ID
|
||||
group: CELL_TITLE_CELL_GROUP_ID
|
||||
},
|
||||
icon: { id: 'codicon/check' },
|
||||
keybinding: {
|
||||
@@ -659,7 +670,7 @@ registerAction2(class extends NotebookCellAction {
|
||||
id: MenuId.NotebookCellTitle,
|
||||
order: CellToolbarOrder.DeleteCell,
|
||||
when: NOTEBOOK_EDITOR_EDITABLE,
|
||||
group: CELL_TITLE_GROUP_ID
|
||||
group: CELL_TITLE_CELL_GROUP_ID
|
||||
},
|
||||
keybinding: {
|
||||
primary: KeyCode.Delete,
|
||||
@@ -758,6 +769,11 @@ registerAction2(class extends NotebookCellAction {
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_C,
|
||||
weight: EDITOR_WIDGET_ACTION_WEIGHT
|
||||
},
|
||||
menu: {
|
||||
id: MenuId.NotebookCellTitle,
|
||||
when: NOTEBOOK_EDITOR_FOCUSED,
|
||||
group: '1_copy',
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -780,6 +796,11 @@ registerAction2(class extends NotebookCellAction {
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_X,
|
||||
weight: EDITOR_WIDGET_ACTION_WEIGHT
|
||||
},
|
||||
menu: {
|
||||
id: MenuId.NotebookCellTitle,
|
||||
when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_CELL_EDITABLE),
|
||||
group: '1_copy',
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -864,6 +885,11 @@ registerAction2(class extends NotebookAction {
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_V,
|
||||
weight: EDITOR_WIDGET_ACTION_WEIGHT
|
||||
},
|
||||
menu: {
|
||||
id: MenuId.NotebookCellTitle,
|
||||
when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_EDITOR_EDITABLE),
|
||||
group: '1_copy',
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1176,7 +1202,7 @@ registerAction2(class extends NotebookCellAction {
|
||||
id: MenuId.NotebookCellTitle,
|
||||
when: ContextKeyExpr.and(NOTEBOOK_CELL_TYPE.isEqualTo('code'), NOTEBOOK_EDITOR_RUNNABLE),
|
||||
order: CellToolbarOrder.ClearCellOutput,
|
||||
group: CELL_TITLE_GROUP_ID
|
||||
group: CELL_TITLE_OUTPUT_GROUP_ID
|
||||
},
|
||||
keybinding: {
|
||||
when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, ContextKeyExpr.not(InputFocusedContextKey), NOTEBOOK_CELL_HAS_OUTPUTS),
|
||||
@@ -1339,7 +1365,11 @@ registerAction2(class extends NotebookCellAction {
|
||||
id: MenuId.NotebookCellTitle,
|
||||
when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_CELL_EDITABLE, InputFocusedContext),
|
||||
order: CellToolbarOrder.SplitCell,
|
||||
group: CELL_TITLE_GROUP_ID
|
||||
group: CELL_TITLE_CELL_GROUP_ID,
|
||||
// alt: {
|
||||
// id: JOIN_CELL_BELOW_COMMAND_ID,
|
||||
// title: localize('notebookActions.joinCellBelow', "Join with Next Cell")
|
||||
// }
|
||||
},
|
||||
icon: { id: 'codicon/split-vertical' },
|
||||
keybinding: {
|
||||
@@ -1392,6 +1422,11 @@ registerAction2(class extends NotebookCellAction {
|
||||
when: NOTEBOOK_EDITOR_FOCUSED,
|
||||
primary: KeyMod.WinCtrl | KeyMod.Alt | KeyCode.KEY_J,
|
||||
weight: KeybindingWeight.WorkbenchContrib
|
||||
},
|
||||
menu: {
|
||||
id: MenuId.NotebookCellTitle,
|
||||
when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_CELL_EDITABLE),
|
||||
group: '2_edit',
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -166,8 +166,7 @@ export class KernelStatus extends Disposable implements IWorkbenchContribution {
|
||||
|
||||
const activeEditor = getActiveNotebookEditor(this._editorService);
|
||||
|
||||
if (activeEditor && activeEditor.multipleKernelsAvailable) {
|
||||
this.showKernelStatus(activeEditor.activeKernel);
|
||||
if (activeEditor) {
|
||||
this._editorDisposable.add(activeEditor.onDidChangeKernel(() => {
|
||||
if (activeEditor.multipleKernelsAvailable) {
|
||||
this.showKernelStatus(activeEditor.activeKernel);
|
||||
@@ -175,6 +174,18 @@ export class KernelStatus extends Disposable implements IWorkbenchContribution {
|
||||
this.kernelInfoElement.clear();
|
||||
}
|
||||
}));
|
||||
|
||||
this._editorDisposable.add(activeEditor.onDidChangeAvailableKernels(() => {
|
||||
if (activeEditor.multipleKernelsAvailable) {
|
||||
this.showKernelStatus(activeEditor.activeKernel);
|
||||
} else {
|
||||
this.kernelInfoElement.clear();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
if (activeEditor && activeEditor.multipleKernelsAvailable) {
|
||||
this.showKernelStatus(activeEditor.activeKernel);
|
||||
} else {
|
||||
this.kernelInfoElement.clear();
|
||||
}
|
||||
|
||||
@@ -488,6 +488,9 @@
|
||||
.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-bottom-toolbar-container {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
z-index: 30; /* over the focus outline on the editor */
|
||||
width: 100%;
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
cursor: auto;
|
||||
@@ -531,19 +534,8 @@
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-bottom-toolbar-container .separator {
|
||||
height: 1px;
|
||||
flex-grow: 1;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-bottom-toolbar-container .action-item:first-child::after {
|
||||
content: ' ';
|
||||
display: block;
|
||||
height: 1px;
|
||||
width: 16px;
|
||||
align-self: center;
|
||||
margin: 0px 8px;
|
||||
.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-bottom-toolbar-container .action-item:first-child {
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-bottom-toolbar-container span.codicon {
|
||||
@@ -699,7 +691,7 @@
|
||||
|
||||
.monaco-workbench .notebookOverlay > .cell-list-container .notebook-folding-indicator .codicon {
|
||||
visibility: visible;
|
||||
padding: 8px 0 0 10px;
|
||||
padding: 10px 0 0 10px;
|
||||
}
|
||||
|
||||
/** Theming */
|
||||
@@ -739,3 +731,11 @@
|
||||
.monaco-workbench.vs-dark .monaco-workbench .notebookOverlay .cell.markdown table > tbody > tr > td {
|
||||
border-color: rgba(255, 255, 255, 0.18);
|
||||
} */
|
||||
|
||||
.monaco-action-bar .action-item.verticalSeparator {
|
||||
width: 1px !important;
|
||||
background-color: #bbb;
|
||||
height: 16px !important;
|
||||
margin: 5px 4px !important;
|
||||
cursor: none;
|
||||
}
|
||||
|
||||
@@ -180,6 +180,7 @@ export interface INotebookEditor extends IEditor {
|
||||
isNotebookEditor: boolean;
|
||||
activeKernel: INotebookKernelInfo | INotebookKernelInfo2 | undefined;
|
||||
multipleKernelsAvailable: boolean;
|
||||
readonly onDidChangeAvailableKernels: Event<void>;
|
||||
readonly onDidChangeKernel: Event<void>;
|
||||
|
||||
isDisposed: boolean;
|
||||
@@ -240,10 +241,16 @@ export interface INotebookEditor extends IEditor {
|
||||
moveCellDown(cell: ICellViewModel): Promise<ICellViewModel | null>;
|
||||
|
||||
/**
|
||||
* @deprecated Note that this method doesn't support batch operations, use #moveCellToIdx instead.
|
||||
* Move a cell above or below another cell
|
||||
*/
|
||||
moveCell(cell: ICellViewModel, relativeToCell: ICellViewModel, direction: 'above' | 'below'): Promise<ICellViewModel | null>;
|
||||
|
||||
/**
|
||||
* Move a cell to a specific position
|
||||
*/
|
||||
moveCellToIdx(cell: ICellViewModel, index: number): Promise<ICellViewModel | null>;
|
||||
|
||||
/**
|
||||
* Focus the container of a cell (the monaco editor inside is not focused).
|
||||
*/
|
||||
|
||||
@@ -75,6 +75,8 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
||||
private _overlayContainer!: HTMLElement;
|
||||
private _body!: HTMLElement;
|
||||
private _webview: BackLayerWebView | null = null;
|
||||
private _webviewResolved: boolean = false;
|
||||
private _webviewResolvePromise: Promise<BackLayerWebView | null> | null = null;
|
||||
private _webviewTransparentCover: HTMLElement | null = null;
|
||||
private _list: INotebookCellList | undefined;
|
||||
private _dndController: CellDragAndDropController | null = null;
|
||||
@@ -135,6 +137,8 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
||||
private _activeKernel: INotebookKernelInfo | INotebookKernelInfo2 | undefined = undefined;
|
||||
private readonly _onDidChangeKernel = this._register(new Emitter<void>());
|
||||
readonly onDidChangeKernel: Event<void> = this._onDidChangeKernel.event;
|
||||
private readonly _onDidChangeAvailableKernels = this._register(new Emitter<void>());
|
||||
readonly onDidChangeAvailableKernels: Event<void> = this._onDidChangeAvailableKernels.event;
|
||||
|
||||
get activeKernel() {
|
||||
return this._activeKernel;
|
||||
@@ -150,7 +154,16 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
||||
}
|
||||
|
||||
private _currentKernelTokenSource: CancellationTokenSource | undefined = undefined;
|
||||
multipleKernelsAvailable: boolean = false;
|
||||
private _multipleKernelsAvailable: boolean = false;
|
||||
|
||||
get multipleKernelsAvailable() {
|
||||
return this._multipleKernelsAvailable;
|
||||
}
|
||||
|
||||
set multipleKernelsAvailable(state: boolean) {
|
||||
this._multipleKernelsAvailable = state;
|
||||
this._onDidChangeAvailableKernels.fire();
|
||||
}
|
||||
|
||||
private readonly _onDidChangeActiveEditor = this._register(new Emitter<this>());
|
||||
readonly onDidChangeActiveEditor: Event<this> = this._onDidChangeActiveEditor.event;
|
||||
@@ -572,7 +585,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
||||
// @deprecated
|
||||
if (provider && provider.kernel) {
|
||||
// it has a builtin kernel, don't automatically choose a kernel
|
||||
this._loadKernelPreloads(provider.providerExtensionLocation, provider.kernel);
|
||||
await this._loadKernelPreloads(provider.providerExtensionLocation, provider.kernel);
|
||||
tokenSource.dispose();
|
||||
return;
|
||||
}
|
||||
@@ -591,7 +604,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
||||
// the provider doesn't have a builtin kernel, choose a kernel
|
||||
this.activeKernel = availableKernels[0];
|
||||
if (this.activeKernel) {
|
||||
this._loadKernelPreloads(this.activeKernel.extensionLocation, this.activeKernel);
|
||||
await this._loadKernelPreloads(this.activeKernel.extensionLocation, this.activeKernel);
|
||||
}
|
||||
|
||||
tokenSource.dispose();
|
||||
@@ -611,7 +624,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
||||
}
|
||||
|
||||
if (this.activeKernel) {
|
||||
this._loadKernelPreloads(this.activeKernel.extensionLocation, this.activeKernel);
|
||||
await this._loadKernelPreloads(this.activeKernel.extensionLocation, this.activeKernel);
|
||||
await (this.activeKernel as INotebookKernelInfo2).resolve(this.viewModel!.uri, this.getId(), tokenSource.token); // {{SQL CARBON EDIT}} strict-null-checks
|
||||
}
|
||||
|
||||
@@ -624,7 +637,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
||||
if (kernelsFromSameExtension.length) {
|
||||
const preferedKernel = kernelsFromSameExtension.find(kernel => kernel.isPreferred) || kernelsFromSameExtension[0];
|
||||
this.activeKernel = preferedKernel;
|
||||
this._loadKernelPreloads(this.activeKernel.extensionLocation, this.activeKernel);
|
||||
await this._loadKernelPreloads(this.activeKernel.extensionLocation, this.activeKernel);
|
||||
await preferedKernel.resolve(this.viewModel!.uri, this.getId(), tokenSource.token);
|
||||
tokenSource.dispose();
|
||||
return;
|
||||
@@ -633,15 +646,16 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
||||
// the provider doesn't have a builtin kernel, choose a kernel
|
||||
this.activeKernel = kernels[0];
|
||||
if (this.activeKernel) {
|
||||
this._loadKernelPreloads(this.activeKernel.extensionLocation, this.activeKernel);
|
||||
await this._loadKernelPreloads(this.activeKernel.extensionLocation, this.activeKernel);
|
||||
await this.activeKernel.resolve(this.viewModel!.uri, this.getId(), tokenSource.token);
|
||||
}
|
||||
|
||||
tokenSource.dispose();
|
||||
}
|
||||
|
||||
private _loadKernelPreloads(extensionLocation: URI, kernel: INotebookKernelInfoDto) {
|
||||
if (kernel.preloads) {
|
||||
private async _loadKernelPreloads(extensionLocation: URI, kernel: INotebookKernelInfoDto) {
|
||||
if (kernel.preloads && kernel.preloads.length) {
|
||||
await this._resolveWebview();
|
||||
this._webview?.updateKernelPreloads([extensionLocation], kernel.preloads.map(preload => URI.revive(preload)));
|
||||
}
|
||||
}
|
||||
@@ -656,34 +670,63 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
||||
this._notebookExecuting?.set(notebookMetadata.runState === NotebookRunState.Running);
|
||||
}
|
||||
|
||||
private async _resolveWebview(): Promise<BackLayerWebView | null> {
|
||||
if (!this.textModel) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (this._webviewResolvePromise) {
|
||||
return this._webviewResolvePromise;
|
||||
}
|
||||
|
||||
if (!this._webview) {
|
||||
this._webview = this.instantiationService.createInstance(BackLayerWebView, this, this.getId(), this.textModel!.uri);
|
||||
// attach the webview container to the DOM tree first
|
||||
this._list?.rowsContainer.insertAdjacentElement('afterbegin', this._webview.element);
|
||||
}
|
||||
|
||||
this._webviewResolvePromise = new Promise(async resolve => {
|
||||
await this._webview!.createWebview();
|
||||
this._webview!.webview!.onDidBlur(() => {
|
||||
this._outputFocus?.set(false);
|
||||
this.updateEditorFocus();
|
||||
|
||||
if (this._overlayContainer.contains(document.activeElement)) {
|
||||
this._webiewFocused = false;
|
||||
}
|
||||
});
|
||||
this._webview!.webview!.onDidFocus(() => {
|
||||
this._outputFocus?.set(true);
|
||||
this.updateEditorFocus();
|
||||
this._onDidFocusEmitter.fire();
|
||||
|
||||
if (this._overlayContainer.contains(document.activeElement)) {
|
||||
this._webiewFocused = true;
|
||||
}
|
||||
});
|
||||
|
||||
this._localStore.add(this._webview!.onMessage(({ message, forRenderer }) => {
|
||||
if (this.viewModel) {
|
||||
this.notebookService.onDidReceiveMessage(this.viewModel.viewType, this.getId(), forRenderer, message);
|
||||
}
|
||||
}));
|
||||
|
||||
if (this.viewModel && this.viewModel!.renderers.size) {
|
||||
this._webview?.updateRendererPreloads(this.viewModel!.renderers);
|
||||
}
|
||||
|
||||
this._webviewResolved = true;
|
||||
|
||||
resolve(this._webview!);
|
||||
});
|
||||
|
||||
return this._webviewResolvePromise;
|
||||
}
|
||||
|
||||
private async _createWebview(id: string, resource: URI): Promise<void> {
|
||||
this._webview = this.instantiationService.createInstance(BackLayerWebView, this, id, resource);
|
||||
// attach the webview container to the DOM tree first
|
||||
this._list?.rowsContainer.insertAdjacentElement('afterbegin', this._webview.element);
|
||||
await this._webview.createWebview();
|
||||
this._webview.webview.onDidBlur(() => {
|
||||
this._outputFocus?.set(false);
|
||||
this.updateEditorFocus();
|
||||
|
||||
if (this._overlayContainer.contains(document.activeElement)) {
|
||||
this._webiewFocused = false;
|
||||
}
|
||||
});
|
||||
this._webview.webview.onDidFocus(() => {
|
||||
this._outputFocus?.set(true);
|
||||
this.updateEditorFocus();
|
||||
this._onDidFocusEmitter.fire();
|
||||
|
||||
if (this._overlayContainer.contains(document.activeElement)) {
|
||||
this._webiewFocused = true;
|
||||
}
|
||||
});
|
||||
|
||||
this._localStore.add(this._webview.onMessage(({ message, forRenderer }) => {
|
||||
if (this.viewModel) {
|
||||
this.notebookService.onDidReceiveMessage(this.viewModel.viewType, this.getId(), forRenderer, message);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private async _attachModel(textModel: NotebookTextModel, viewState: INotebookEditorViewState | undefined) {
|
||||
@@ -717,10 +760,17 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
||||
}
|
||||
}
|
||||
|
||||
this._webview?.updateRendererPreloads(this.viewModel.renderers);
|
||||
if (this.viewModel.renderers.size) {
|
||||
await this._resolveWebview();
|
||||
this._webview?.updateRendererPreloads(this.viewModel.renderers);
|
||||
}
|
||||
|
||||
this._localStore.add(this._list!.onWillScroll(e => {
|
||||
this._webview!.updateViewScrollTop(-e.scrollTop, []);
|
||||
if (!this._webviewResolved) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._webview?.updateViewScrollTop(-e.scrollTop, []);
|
||||
this._webviewTransparentCover!.style.top = `${e.scrollTop}px`;
|
||||
}));
|
||||
|
||||
@@ -732,6 +782,11 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
||||
|
||||
const scrollTop = this._list?.scrollTop || 0;
|
||||
const scrollHeight = this._list?.scrollHeight || 0;
|
||||
|
||||
if (!this._webviewResolved) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._webview!.element.style.height = `${scrollHeight}px`;
|
||||
|
||||
if (this._webview?.insetMapping) {
|
||||
@@ -1128,6 +1183,15 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
||||
return this._moveCellToIndex(originalIdx, newIdx);
|
||||
}
|
||||
|
||||
async moveCellToIdx(cell: ICellViewModel, index: number): Promise<ICellViewModel | null> {
|
||||
if (!this._notebookViewModel!.metadata.editable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const originalIdx = this._notebookViewModel!.getCellIndex(cell);
|
||||
return this._moveCellToIndex(originalIdx, index);
|
||||
}
|
||||
|
||||
private async _moveCellToIndex(index: number, newIdx: number): Promise<ICellViewModel | null> {
|
||||
if (index === newIdx) {
|
||||
return null;
|
||||
@@ -1356,6 +1420,8 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
||||
return;
|
||||
}
|
||||
|
||||
await this._resolveWebview();
|
||||
|
||||
let preloads = this._notebookViewModel!.renderers;
|
||||
|
||||
if (!this._webview!.insetMapping.has(output)) {
|
||||
@@ -1370,7 +1436,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
||||
}
|
||||
|
||||
removeInset(output: IProcessedOutput) {
|
||||
if (!this._webview) {
|
||||
if (!this._webview || !this._webviewResolved) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1378,7 +1444,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
||||
}
|
||||
|
||||
hideInset(output: IProcessedOutput) {
|
||||
if (!this._webview) {
|
||||
if (!this._webview || !this._webviewResolved) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1390,10 +1456,14 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
||||
}
|
||||
|
||||
postMessage(forRendererId: string | undefined, message: any) {
|
||||
if (!this._webview || !this._webviewResolved) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (forRendererId === undefined) {
|
||||
this._webview?.webview.postMessage(message);
|
||||
this._webview.webview?.postMessage(message);
|
||||
} else {
|
||||
this._webview?.postRendererMessage(forRendererId, message);
|
||||
this._webview.postRendererMessage(forRendererId, message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1600,13 +1670,13 @@ registerThemingParticipant((theme, collector) => {
|
||||
collector.addRule(`.notebookOverlay .cell-statusbar-container { border-top: solid 1px ${editorBackgroundColor}; }`);
|
||||
collector.addRule(`.notebookOverlay .monaco-list-row > .monaco-toolbar { background-color: ${editorBackgroundColor}; }`);
|
||||
collector.addRule(`.notebookOverlay .monaco-list-row.cell-drag-image { background-color: ${editorBackgroundColor}; }`);
|
||||
collector.addRule(`.notebookOverlay .cell-bottom-toolbar-container .action-item { background-color: ${editorBackgroundColor} }`);
|
||||
}
|
||||
|
||||
const cellToolbarSeperator = theme.getColor(CELL_TOOLBAR_SEPERATOR);
|
||||
if (cellToolbarSeperator) {
|
||||
collector.addRule(`.notebookOverlay .cell-bottom-toolbar-container .separator { background-color: ${cellToolbarSeperator} }`);
|
||||
collector.addRule(`.notebookOverlay .cell-bottom-toolbar-container .action-item:first-child::after { background-color: ${cellToolbarSeperator} }`);
|
||||
collector.addRule(`.notebookOverlay .monaco-list-row > .monaco-toolbar { border: solid 1px ${cellToolbarSeperator}; }`);
|
||||
collector.addRule(`.notebookOverlay .cell-bottom-toolbar-container .action-item { border: solid 1px ${cellToolbarSeperator} }`);
|
||||
}
|
||||
|
||||
const focusedCellBackgroundColor = theme.getColor(focusedCellBackground);
|
||||
@@ -1643,14 +1713,10 @@ registerThemingParticipant((theme, collector) => {
|
||||
collector.addRule(`.notebookOverlay .monaco-list-row.cell-editor-focus .cell-editor-part:before { outline: solid 1px ${focusedEditorBorderColorColor}; }`);
|
||||
}
|
||||
|
||||
const editorBorderColor = theme.getColor(notebookCellBorder);
|
||||
if (editorBorderColor) {
|
||||
collector.addRule(`.notebookOverlay .monaco-list-row .cell-editor-part:before { outline: solid 1px ${editorBorderColor}; }`);
|
||||
}
|
||||
|
||||
const headingBorderColor = theme.getColor(notebookCellBorder);
|
||||
if (headingBorderColor) {
|
||||
collector.addRule(`.notebookOverlay .cell.markdown h1 { border-color: ${headingBorderColor}; }`);
|
||||
const cellBorderColor = theme.getColor(notebookCellBorder);
|
||||
if (cellBorderColor) {
|
||||
collector.addRule(`.notebookOverlay .cell.markdown h1 { border-color: ${cellBorderColor}; }`);
|
||||
collector.addRule(`.notebookOverlay .monaco-list-row .cell-editor-part:before { outline: solid 1px ${cellBorderColor}; }`);
|
||||
}
|
||||
|
||||
const cellStatusSuccessIcon = theme.getColor(cellStatusIconSuccess);
|
||||
@@ -1701,10 +1767,8 @@ registerThemingParticipant((theme, collector) => {
|
||||
collector.addRule(`.notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row > div.cell.code { margin-left: ${CODE_CELL_LEFT_MARGIN}px; }`);
|
||||
collector.addRule(`.notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row { padding-top: ${EDITOR_TOP_MARGIN}px; }`);
|
||||
collector.addRule(`.notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .markdown-cell-row { padding-bottom: ${CELL_BOTTOM_MARGIN}px; }`);
|
||||
collector.addRule(`.notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .markdown-cell-row .cell-bottom-toolbar-container { margin-top: ${CELL_BOTTOM_MARGIN}px; }`);
|
||||
collector.addRule(`.notebookOverlay .output { margin: 0px ${CELL_MARGIN}px 0px ${CODE_CELL_LEFT_MARGIN + CELL_RUN_GUTTER}px; }`);
|
||||
collector.addRule(`.notebookOverlay .output { width: calc(100% - ${CODE_CELL_LEFT_MARGIN + CELL_RUN_GUTTER + (CELL_MARGIN * 2)}px); }`);
|
||||
collector.addRule(`.notebookOverlay .cell-bottom-toolbar-container { width: calc(100% - ${CELL_MARGIN * 2 + CELL_RUN_GUTTER}px); margin: 0px ${CELL_MARGIN * 2}px 0px ${CELL_MARGIN + CELL_RUN_GUTTER}px; }`);
|
||||
|
||||
collector.addRule(`.notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row > div.cell.markdown { padding-left: ${CELL_RUN_GUTTER}px; }`);
|
||||
collector.addRule(`.notebookOverlay .cell .run-button-container { width: ${CELL_RUN_GUTTER}px; }`);
|
||||
|
||||
@@ -219,7 +219,7 @@ export interface INotebookWebviewMessage {
|
||||
let version = 0;
|
||||
export class BackLayerWebView extends Disposable {
|
||||
element: HTMLElement;
|
||||
webview!: WebviewElement;
|
||||
webview: WebviewElement | undefined = undefined;
|
||||
insetMapping: Map<IProcessedOutput, ICachedInset> = new Map();
|
||||
hiddenInsetMapping: Set<IProcessedOutput> = new Set();
|
||||
reversedInsetMapping: Map<string, IProcessedOutput> = new Map();
|
||||
@@ -714,7 +714,7 @@ ${loaderJs}
|
||||
return;
|
||||
}
|
||||
|
||||
this.webview.focus();
|
||||
this.webview?.focus();
|
||||
}
|
||||
|
||||
focusOutput(cellId: string) {
|
||||
@@ -722,7 +722,7 @@ ${loaderJs}
|
||||
return;
|
||||
}
|
||||
|
||||
this.webview.focus();
|
||||
this.webview?.focus();
|
||||
setTimeout(() => { // Need this, or focus decoration is not shown. No clue.
|
||||
this._sendMessageToWebview({
|
||||
type: 'focus-output',
|
||||
@@ -814,6 +814,10 @@ ${loaderJs}
|
||||
}
|
||||
|
||||
private _updatePreloads(resources: IPreloadResource[], source: 'renderer' | 'kernel') {
|
||||
if (!this.webview) {
|
||||
return;
|
||||
}
|
||||
|
||||
const mixedResourceRoots = [...(this.localResourceRootsCache || []), ...this.rendererRootsCache, ...this.kernelRootsCache];
|
||||
|
||||
this.webview.localResourcesRoot = mixedResourceRoots;
|
||||
@@ -830,7 +834,7 @@ ${loaderJs}
|
||||
return;
|
||||
}
|
||||
|
||||
this.webview.postMessage(message);
|
||||
this.webview?.postMessage(message);
|
||||
}
|
||||
|
||||
clearPreloadsCache() {
|
||||
@@ -839,7 +843,7 @@ ${loaderJs}
|
||||
|
||||
dispose() {
|
||||
this._disposed = true;
|
||||
this.webview.dispose();
|
||||
this.webview?.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { Action, IAction } from 'vs/base/common/actions';
|
||||
import { BaseActionViewItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { IMenu, IMenuActionOptions, MenuItemAction, SubmenuItemAction } from 'vs/platform/actions/common/actions';
|
||||
import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
|
||||
|
||||
export class VerticalSeparator extends Action {
|
||||
static readonly ID = 'vs.actions.verticalSeparator';
|
||||
|
||||
constructor(
|
||||
label?: string
|
||||
) {
|
||||
super(VerticalSeparator.ID, label, label ? 'verticalSeparator text' : 'verticalSeparator');
|
||||
this.checked = false;
|
||||
this.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
export class VerticalSeparatorViewItem extends BaseActionViewItem {
|
||||
render(container: HTMLElement) {
|
||||
DOM.addClass(container, 'verticalSeparator');
|
||||
// const iconContainer = DOM.append(container, $('.verticalSeparator'));
|
||||
// DOM.addClasses(iconContainer, 'codicon', 'codicon-chrome-minimize');
|
||||
}
|
||||
}
|
||||
|
||||
export function createAndFillInActionBarActionsWithVerticalSeparators(menu: IMenu, options: IMenuActionOptions | undefined, target: IAction[] | { primary: IAction[]; secondary: IAction[]; }, isPrimaryGroup?: (group: string) => boolean): IDisposable {
|
||||
const groups = menu.getActions(options);
|
||||
// Action bars handle alternative actions on their own so the alternative actions should be ignored
|
||||
fillInActions(groups, target, false, isPrimaryGroup);
|
||||
return asDisposable(groups);
|
||||
}
|
||||
|
||||
function fillInActions(groups: ReadonlyArray<[string, ReadonlyArray<MenuItemAction | SubmenuItemAction>]>, target: IAction[] | { primary: IAction[]; secondary: IAction[]; }, useAlternativeActions: boolean, isPrimaryGroup: (group: string) => boolean = group => group === 'navigation'): void {
|
||||
for (let tuple of groups) {
|
||||
let [group, actions] = tuple;
|
||||
if (useAlternativeActions) {
|
||||
actions = actions.map(a => (a instanceof MenuItemAction) && !!a.alt ? a.alt : a);
|
||||
}
|
||||
|
||||
if (isPrimaryGroup(group)) {
|
||||
const to = Array.isArray<IAction>(target) ? target : target.primary;
|
||||
|
||||
if (to.length > 0) {
|
||||
to.push(new VerticalSeparator());
|
||||
}
|
||||
|
||||
to.push(...actions);
|
||||
} else {
|
||||
const to = Array.isArray<IAction>(target) ? target : target.secondary;
|
||||
|
||||
if (to.length > 0) {
|
||||
to.push(new Separator());
|
||||
}
|
||||
|
||||
to.push(...actions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function asDisposable(groups: ReadonlyArray<[string, ReadonlyArray<MenuItemAction | SubmenuItemAction>]>): IDisposable {
|
||||
const disposables = new DisposableStore();
|
||||
for (const [, actions] of groups) {
|
||||
for (const action of actions) {
|
||||
disposables.add(action);
|
||||
}
|
||||
}
|
||||
return disposables;
|
||||
}
|
||||
@@ -3,16 +3,12 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
|
||||
import { IMenu, IMenuService, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
|
||||
export class CellMenus {
|
||||
constructor(
|
||||
@IMenuService private readonly menuService: IMenuService,
|
||||
@IContextMenuService private readonly contextMenuService: IContextMenuService
|
||||
) { }
|
||||
|
||||
getCellTitleMenu(contextKeyService: IContextKeyService): IMenu {
|
||||
@@ -26,11 +22,6 @@ export class CellMenus {
|
||||
private getMenu(menuId: MenuId, contextKeyService: IContextKeyService): IMenu {
|
||||
const menu = this.menuService.createMenu(menuId, contextKeyService);
|
||||
|
||||
const primary: IAction[] = [];
|
||||
const secondary: IAction[] = [];
|
||||
const result = { primary, secondary };
|
||||
|
||||
createAndFillInContextMenuActions(menu, { shouldForwardArgs: true }, result, this.contextMenuService, g => /^inline/.test(g));
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
@@ -36,17 +36,18 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { BOTTOM_CELL_TOOLBAR_HEIGHT, EDITOR_BOTTOM_PADDING, EDITOR_TOOLBAR_HEIGHT, EDITOR_TOP_MARGIN, EDITOR_TOP_PADDING, CELL_BOTTOM_MARGIN } from 'vs/workbench/contrib/notebook/browser/constants';
|
||||
import { CancelCellAction, ChangeCellLanguageAction, ExecuteCellAction, INotebookCellActionContext, CELL_TITLE_GROUP_ID } from 'vs/workbench/contrib/notebook/browser/contrib/coreActions';
|
||||
import { BaseCellRenderTemplate, CellEditState, CodeCellRenderTemplate, ICellViewModel, INotebookCellList, INotebookEditor, MarkdownCellRenderTemplate, isCodeCellRenderTemplate } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||
import { BOTTOM_CELL_TOOLBAR_HEIGHT, CELL_BOTTOM_MARGIN, EDITOR_BOTTOM_PADDING, EDITOR_TOOLBAR_HEIGHT, EDITOR_TOP_MARGIN, EDITOR_TOP_PADDING } from 'vs/workbench/contrib/notebook/browser/constants';
|
||||
import { CancelCellAction, ChangeCellLanguageAction, ExecuteCellAction, INotebookCellActionContext } from 'vs/workbench/contrib/notebook/browser/contrib/coreActions';
|
||||
import { BaseCellRenderTemplate, CellEditState, CodeCellRenderTemplate, ICellViewModel, INotebookCellList, INotebookEditor, isCodeCellRenderTemplate, MarkdownCellRenderTemplate } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||
import { CellContextKeyManager } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellContextKeys';
|
||||
import { CellMenus } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellMenus';
|
||||
import { CodeCell } from 'vs/workbench/contrib/notebook/browser/view/renderers/codeCell';
|
||||
import { StatefullMarkdownCell } from 'vs/workbench/contrib/notebook/browser/view/renderers/markdownCell';
|
||||
import { StatefulMarkdownCell } from 'vs/workbench/contrib/notebook/browser/view/renderers/markdownCell';
|
||||
import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel';
|
||||
import { MarkdownCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/markdownCellViewModel';
|
||||
import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
|
||||
import { CellKind, NotebookCellRunState, NotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { CellContextKeyManager } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellContextKeys';
|
||||
import { CellKind, NotebookCellMetadata, NotebookCellRunState } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { VerticalSeparator, createAndFillInActionBarActionsWithVerticalSeparators, VerticalSeparatorViewItem } from './cellActionView';
|
||||
|
||||
const $ = DOM.$;
|
||||
|
||||
@@ -204,9 +205,6 @@ abstract class AbstractCellRenderer {
|
||||
}
|
||||
});
|
||||
|
||||
toolbar.getContainer().style.height = `${BOTTOM_CELL_TOOLBAR_HEIGHT}px`;
|
||||
container.style.height = `${BOTTOM_CELL_TOOLBAR_HEIGHT}px`;
|
||||
|
||||
const cellMenu = this.instantiationService.createInstance(CellMenus);
|
||||
const menu = disposables.add(cellMenu.getCellInsertionMenu(contextKeyService));
|
||||
|
||||
@@ -220,25 +218,28 @@ abstract class AbstractCellRenderer {
|
||||
templateData.betweenCellToolbar.context = context;
|
||||
|
||||
const container = templateData.bottomCellContainer;
|
||||
if (element instanceof CodeCellViewModel) {
|
||||
const bottomToolbarOffset = element.layoutInfo.bottomToolbarOffset;
|
||||
container.style.top = `${bottomToolbarOffset}px`;
|
||||
|
||||
templateData.elementDisposables.add(element.onDidChangeLayout(() => {
|
||||
const bottomToolbarOffset = element.layoutInfo.bottomToolbarOffset;
|
||||
container.style.top = `${bottomToolbarOffset}px`;
|
||||
|
||||
templateData.elementDisposables.add(element.onDidChangeLayout(() => {
|
||||
const bottomToolbarOffset = element.layoutInfo.bottomToolbarOffset;
|
||||
container.style.top = `${bottomToolbarOffset}px`;
|
||||
}));
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
protected createToolbar(container: HTMLElement): ToolBar {
|
||||
const toolbar = new ToolBar(container, this.contextMenuService, {
|
||||
getKeyBinding: action => this.keybindingService.lookupKeybinding(action.id),
|
||||
actionViewItemProvider: action => {
|
||||
if (action instanceof MenuItemAction) {
|
||||
const item = new ContextAwareMenuEntryActionViewItem(action, this.keybindingService, this.notificationService, this.contextMenuService);
|
||||
return item;
|
||||
}
|
||||
|
||||
if (action.id === VerticalSeparator.ID) {
|
||||
return new VerticalSeparatorViewItem(undefined, action);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
});
|
||||
@@ -249,16 +250,11 @@ abstract class AbstractCellRenderer {
|
||||
private getCellToolbarActions(menu: IMenu): { primary: IAction[], secondary: IAction[] } {
|
||||
const primary: IAction[] = [];
|
||||
const secondary: IAction[] = [];
|
||||
const actions = menu.getActions({ shouldForwardArgs: true });
|
||||
for (let [id, menuActions] of actions) {
|
||||
if (id === CELL_TITLE_GROUP_ID) {
|
||||
primary.push(...menuActions);
|
||||
} else {
|
||||
secondary.push(...menuActions);
|
||||
}
|
||||
}
|
||||
const result = { primary, secondary };
|
||||
|
||||
return { primary, secondary };
|
||||
createAndFillInActionBarActionsWithVerticalSeparators(menu, { shouldForwardArgs: true }, result, g => /^inline/.test(g));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected setupCellToolbarActions(templateData: BaseCellRenderTemplate, disposables: DisposableStore): void {
|
||||
@@ -351,9 +347,7 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR
|
||||
const foldingIndicator = DOM.append(focusIndicator, DOM.$('.notebook-folding-indicator'));
|
||||
|
||||
const bottomCellContainer = DOM.append(container, $('.cell-bottom-toolbar-container'));
|
||||
DOM.append(bottomCellContainer, $('.separator'));
|
||||
const betweenCellToolbar = disposables.add(this.createBetweenCellToolbar(bottomCellContainer, disposables, contextKeyService));
|
||||
DOM.append(bottomCellContainer, $('.separator'));
|
||||
|
||||
const statusBar = this.instantiationService.createInstance(CellEditorStatusBar, editorPart);
|
||||
const titleMenu = disposables.add(this.cellMenus.getCellTitleMenu(contextKeyService));
|
||||
@@ -439,7 +433,8 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR
|
||||
|
||||
this.setBetweenCellToolbarContext(templateData, element, toolbarContext);
|
||||
|
||||
const markdownCell = this.instantiationService.createInstance(StatefullMarkdownCell, this.notebookEditor, element, templateData, this.editorOptions.value, this.renderedEditors);
|
||||
const scopedInstaService = this.instantiationService.createChild(new ServiceCollection([IContextKeyService, templateData.contextKeyService]));
|
||||
const markdownCell = scopedInstaService.createInstance(StatefulMarkdownCell, this.notebookEditor, element, templateData, this.editorOptions.value, this.renderedEditors);
|
||||
elementDisposables.add(this.editorOptions.onDidChange(newValue => markdownCell.updateEditorOptions(newValue)));
|
||||
elementDisposables.add(markdownCell);
|
||||
|
||||
@@ -611,6 +606,18 @@ export class CellDragAndDropController extends Disposable {
|
||||
|
||||
private onCellDrop(event: CellDragEvent): void {
|
||||
const draggedCell = this.currentDraggedCell!;
|
||||
let draggedCells: ICellViewModel[] = [draggedCell];
|
||||
|
||||
if (draggedCell.cellKind === CellKind.Markdown) {
|
||||
const currCellIndex = this.notebookEditor.viewModel!.getCellIndex(draggedCell);
|
||||
const nextVisibleCellIndex = this.notebookEditor.viewModel!.getNextVisibleCellIndex(currCellIndex);
|
||||
|
||||
if (nextVisibleCellIndex > currCellIndex + 1) {
|
||||
// folding ;)
|
||||
draggedCells = this.notebookEditor.viewModel!.viewCells.slice(currCellIndex, nextVisibleCellIndex);
|
||||
}
|
||||
}
|
||||
|
||||
this.dragCleanup();
|
||||
|
||||
const isCopy = (event.browserEvent.ctrlKey && !platform.isMacintosh) || (event.browserEvent.altKey && platform.isMacintosh);
|
||||
@@ -625,9 +632,9 @@ export class CellDragAndDropController extends Disposable {
|
||||
}
|
||||
|
||||
if (isCopy) {
|
||||
this.copyCell(draggedCell, event.draggedOverCell, dropDirection);
|
||||
this.copyCells(draggedCells, event.draggedOverCell, dropDirection);
|
||||
} else {
|
||||
this.moveCell(draggedCell, event.draggedOverCell, dropDirection);
|
||||
this.moveCells(draggedCells, event.draggedOverCell, dropDirection);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -673,16 +680,37 @@ export class CellDragAndDropController extends Disposable {
|
||||
}));
|
||||
}
|
||||
|
||||
private async moveCell(draggedCell: ICellViewModel, ontoCell: ICellViewModel, direction: 'above' | 'below') {
|
||||
await this.notebookEditor.moveCell(draggedCell, ontoCell, direction);
|
||||
private async moveCells(draggedCells: ICellViewModel[], ontoCell: ICellViewModel, direction: 'above' | 'below') {
|
||||
const relativeToIndex = this.notebookEditor!.viewModel!.getCellIndex(ontoCell);
|
||||
const newIdx = direction === 'above' ? relativeToIndex : relativeToIndex + 1;
|
||||
|
||||
this.notebookEditor.textModel!.pushStackElement('Move Cells');
|
||||
for (let i = draggedCells.length - 1; i >= 0; i--) {
|
||||
await this.notebookEditor.moveCellToIdx(draggedCells[i], newIdx);
|
||||
}
|
||||
|
||||
this.notebookEditor.textModel!.pushStackElement('Move Cells');
|
||||
}
|
||||
|
||||
private copyCell(draggedCell: ICellViewModel, ontoCell: ICellViewModel, direction: 'above' | 'below') {
|
||||
const editState = draggedCell.editState;
|
||||
const newCell = this.notebookEditor.insertNotebookCell(ontoCell, draggedCell.cellKind, direction, draggedCell.getText());
|
||||
if (newCell) {
|
||||
this.notebookEditor.focusNotebookCell(newCell, editState === CellEditState.Editing ? 'editor' : 'container');
|
||||
private copyCells(draggedCells: ICellViewModel[], ontoCell: ICellViewModel, direction: 'above' | 'below') {
|
||||
this.notebookEditor.textModel!.pushStackElement('Copy Cells');
|
||||
let firstNewCell: ICellViewModel | undefined = undefined;
|
||||
let firstNewCellState: CellEditState = CellEditState.Preview;
|
||||
for (let i = 0; i < draggedCells.length; i++) {
|
||||
const draggedCell = draggedCells[i];
|
||||
const newCell = this.notebookEditor.insertNotebookCell(ontoCell, draggedCell.cellKind, direction, draggedCell.getText());
|
||||
|
||||
if (newCell && !firstNewCell) {
|
||||
firstNewCell = newCell;
|
||||
firstNewCellState = draggedCell.editState;
|
||||
}
|
||||
}
|
||||
|
||||
if (firstNewCell) {
|
||||
this.notebookEditor.focusNotebookCell(firstNewCell, firstNewCellState === CellEditState.Editing ? 'editor' : 'container');
|
||||
}
|
||||
|
||||
this.notebookEditor.textModel!.pushStackElement('Copy Cells');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -912,11 +940,8 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende
|
||||
const focusSinkElement = DOM.append(container, $('.cell-editor-focus-sink'));
|
||||
focusSinkElement.setAttribute('tabindex', '0');
|
||||
const bottomCellContainer = DOM.append(container, $('.cell-bottom-toolbar-container'));
|
||||
DOM.append(bottomCellContainer, $('.separator'));
|
||||
const betweenCellToolbar = this.createBetweenCellToolbar(bottomCellContainer, disposables, contextKeyService);
|
||||
DOM.append(bottomCellContainer, $('.separator'));
|
||||
|
||||
const focusIndicatorBottom = DOM.append(container, $('.cell-focus-indicator.cell-focus-indicator-bottom'));
|
||||
const betweenCellToolbar = this.createBetweenCellToolbar(bottomCellContainer, disposables, contextKeyService);
|
||||
|
||||
const titleMenu = disposables.add(this.cellMenus.getCellTitleMenu(contextKeyService));
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ import { ServiceCollection } from 'vs/platform/instantiation/common/serviceColle
|
||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
import { getResizesObserver } from 'vs/workbench/contrib/notebook/browser/view/renderers/sizeObserver';
|
||||
|
||||
export class StatefullMarkdownCell extends Disposable {
|
||||
export class StatefulMarkdownCell extends Disposable {
|
||||
|
||||
private editor: CodeEditorWidget | null = null;
|
||||
private markdownContainer: HTMLElement;
|
||||
@@ -95,7 +95,7 @@ export class StatefullMarkdownCell extends Disposable {
|
||||
|
||||
this._register(viewCell.onDidChangeLayout((e) => {
|
||||
const layoutInfo = this.editor?.getLayoutInfo();
|
||||
if (e.outerWidth && layoutInfo && layoutInfo.width !== viewCell.layoutInfo.editorWidth) {
|
||||
if (e.outerWidth && this.viewCell.editState === CellEditState.Editing && layoutInfo && layoutInfo.width !== viewCell.layoutInfo.editorWidth) {
|
||||
this.onCellEditorWidthChange();
|
||||
} else if (e.totalHeight || e.outerWidth) {
|
||||
this.relayoutCell();
|
||||
|
||||
@@ -8,7 +8,7 @@ import * as UUID from 'vs/base/common/uuid';
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
import * as model from 'vs/editor/common/model';
|
||||
import { PrefixSumComputer } from 'vs/editor/common/viewModel/prefixSumComputer';
|
||||
import { BOTTOM_CELL_TOOLBAR_HEIGHT, CELL_MARGIN, CELL_RUN_GUTTER, CELL_STATUSBAR_HEIGHT, EDITOR_BOTTOM_PADDING, EDITOR_TOOLBAR_HEIGHT, EDITOR_TOP_MARGIN, EDITOR_TOP_PADDING, CELL_BOTTOM_MARGIN, CODE_CELL_LEFT_MARGIN } from 'vs/workbench/contrib/notebook/browser/constants';
|
||||
import { BOTTOM_CELL_TOOLBAR_HEIGHT, CELL_MARGIN, CELL_RUN_GUTTER, CELL_STATUSBAR_HEIGHT, EDITOR_BOTTOM_PADDING, EDITOR_TOOLBAR_HEIGHT, EDITOR_TOP_MARGIN, EDITOR_TOP_PADDING, CELL_BOTTOM_MARGIN, CODE_CELL_LEFT_MARGIN, BOTTOM_CELL_TOOLBAR_OFFSET } from 'vs/workbench/contrib/notebook/browser/constants';
|
||||
import { CellEditState, CellFindMatch, CodeCellLayoutChangeEvent, CodeCellLayoutInfo, ICellViewModel, NotebookLayoutInfo, CodeCellLayoutState } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
|
||||
import { CellKind, NotebookCellOutputsSplice, INotebookSearchOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
@@ -122,7 +122,7 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod
|
||||
|
||||
const indicatorHeight = editorHeight + CELL_STATUSBAR_HEIGHT + outputTotalHeight;
|
||||
const outputContainerOffset = EDITOR_TOOLBAR_HEIGHT + EDITOR_TOP_MARGIN + editorHeight + CELL_STATUSBAR_HEIGHT;
|
||||
const bottomToolbarOffset = totalHeight - BOTTOM_CELL_TOOLBAR_HEIGHT;
|
||||
const bottomToolbarOffset = totalHeight - BOTTOM_CELL_TOOLBAR_HEIGHT - BOTTOM_CELL_TOOLBAR_OFFSET;
|
||||
const editorWidth = state.outerWidth !== undefined ? this.computeEditorWidth(state.outerWidth) : this._layoutInfo?.editorWidth;
|
||||
|
||||
this._layoutInfo = {
|
||||
|
||||
@@ -8,7 +8,7 @@ import { Emitter, Event } from 'vs/base/common/event';
|
||||
import * as UUID from 'vs/base/common/uuid';
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
import * as model from 'vs/editor/common/model';
|
||||
import { BOTTOM_CELL_TOOLBAR_HEIGHT, CELL_MARGIN, CELL_STATUSBAR_HEIGHT, EDITOR_TOP_MARGIN, CELL_BOTTOM_MARGIN, CODE_CELL_LEFT_MARGIN } from 'vs/workbench/contrib/notebook/browser/constants';
|
||||
import { BOTTOM_CELL_TOOLBAR_HEIGHT, CELL_MARGIN, CELL_STATUSBAR_HEIGHT, EDITOR_TOP_MARGIN, CELL_BOTTOM_MARGIN, CODE_CELL_LEFT_MARGIN, BOTTOM_CELL_TOOLBAR_OFFSET } from 'vs/workbench/contrib/notebook/browser/constants';
|
||||
import { CellFindMatch, ICellViewModel, MarkdownCellLayoutChangeEvent, MarkdownCellLayoutInfo, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||
import { MarkdownRenderer } from 'vs/workbench/contrib/notebook/browser/view/renderers/mdRenderer';
|
||||
import { BaseCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/baseCellViewModel';
|
||||
@@ -93,13 +93,14 @@ export class MarkdownCellViewModel extends BaseCellViewModel implements ICellVie
|
||||
layoutChange(state: MarkdownCellLayoutChangeEvent) {
|
||||
// recompute
|
||||
const editorWidth = state.outerWidth !== undefined ? this.computeEditorWidth(state.outerWidth) : this._layoutInfo.editorWidth;
|
||||
const totalHeight = state.totalHeight === undefined ? this._layoutInfo.totalHeight : state.totalHeight;
|
||||
|
||||
this._layoutInfo = {
|
||||
fontInfo: state.font || this._layoutInfo.fontInfo,
|
||||
editorWidth,
|
||||
editorHeight: this._editorHeight,
|
||||
bottomToolbarOffset: BOTTOM_CELL_TOOLBAR_HEIGHT,
|
||||
totalHeight: state.totalHeight === undefined ? this._layoutInfo.totalHeight : state.totalHeight
|
||||
bottomToolbarOffset: totalHeight - BOTTOM_CELL_TOOLBAR_HEIGHT - BOTTOM_CELL_TOOLBAR_OFFSET,
|
||||
totalHeight
|
||||
};
|
||||
|
||||
this._onDidChangeLayout.fire(state);
|
||||
@@ -115,6 +116,7 @@ export class MarkdownCellViewModel extends BaseCellViewModel implements ICellVie
|
||||
totalHeight: totalHeight,
|
||||
editorHeight: this._editorHeight
|
||||
};
|
||||
this.layoutChange({});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ export class InsertCellEdit implements IResourceUndoRedoElement {
|
||||
) {
|
||||
}
|
||||
|
||||
undo(): void | Promise<void> {
|
||||
undo(): void {
|
||||
if (!this.editingDelegate.deleteCell) {
|
||||
throw new Error('Notebook Delete Cell not implemented for Undo/Redo');
|
||||
}
|
||||
@@ -41,7 +41,7 @@ export class InsertCellEdit implements IResourceUndoRedoElement {
|
||||
this.editingDelegate.emitSelections(this.beforedSelections);
|
||||
}
|
||||
}
|
||||
redo(): void | Promise<void> {
|
||||
redo(): void {
|
||||
if (!this.editingDelegate.insertCell) {
|
||||
throw new Error('Notebook Insert Cell not implemented for Undo/Redo');
|
||||
}
|
||||
@@ -70,7 +70,7 @@ export class DeleteCellEdit implements IResourceUndoRedoElement {
|
||||
// this._rawCell.source = [cell.getText()];
|
||||
}
|
||||
|
||||
undo(): void | Promise<void> {
|
||||
undo(): void {
|
||||
if (!this.editingDelegate.insertCell) {
|
||||
throw new Error('Notebook Insert Cell not implemented for Undo/Redo');
|
||||
}
|
||||
@@ -81,7 +81,7 @@ export class DeleteCellEdit implements IResourceUndoRedoElement {
|
||||
}
|
||||
}
|
||||
|
||||
redo(): void | Promise<void> {
|
||||
redo(): void {
|
||||
if (!this.editingDelegate.deleteCell) {
|
||||
throw new Error('Notebook Delete Cell not implemented for Undo/Redo');
|
||||
}
|
||||
@@ -95,7 +95,7 @@ export class DeleteCellEdit implements IResourceUndoRedoElement {
|
||||
|
||||
export class MoveCellEdit implements IResourceUndoRedoElement {
|
||||
type: UndoRedoElementType.Resource = UndoRedoElementType.Resource;
|
||||
label: string = 'Delete Cell';
|
||||
label: string = 'Move Cell';
|
||||
|
||||
constructor(
|
||||
public resource: URI,
|
||||
@@ -107,7 +107,7 @@ export class MoveCellEdit implements IResourceUndoRedoElement {
|
||||
) {
|
||||
}
|
||||
|
||||
undo(): void | Promise<void> {
|
||||
undo(): void {
|
||||
if (!this.editingDelegate.moveCell) {
|
||||
throw new Error('Notebook Move Cell not implemented for Undo/Redo');
|
||||
}
|
||||
@@ -118,7 +118,7 @@ export class MoveCellEdit implements IResourceUndoRedoElement {
|
||||
}
|
||||
}
|
||||
|
||||
redo(): void | Promise<void> {
|
||||
redo(): void {
|
||||
if (!this.editingDelegate.moveCell) {
|
||||
throw new Error('Notebook Move Cell not implemented for Undo/Redo');
|
||||
}
|
||||
@@ -142,7 +142,7 @@ export class SpliceCellsEdit implements IResourceUndoRedoElement {
|
||||
) {
|
||||
}
|
||||
|
||||
undo(): void | Promise<void> {
|
||||
undo(): void {
|
||||
if (!this.editingDelegate.deleteCell || !this.editingDelegate.insertCell) {
|
||||
throw new Error('Notebook Insert/Delete Cell not implemented for Undo/Redo');
|
||||
}
|
||||
@@ -162,7 +162,7 @@ export class SpliceCellsEdit implements IResourceUndoRedoElement {
|
||||
}
|
||||
}
|
||||
|
||||
redo(): void | Promise<void> {
|
||||
redo(): void {
|
||||
if (!this.editingDelegate.deleteCell || !this.editingDelegate.insertCell) {
|
||||
throw new Error('Notebook Insert/Delete Cell not implemented for Undo/Redo');
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import { URI } from 'vs/base/common/uri';
|
||||
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
|
||||
import { INotebookTextModel, NotebookCellOutputsSplice, NotebookCellTextModelSplice, NotebookDocumentMetadata, NotebookCellMetadata, ICellEditOperation, CellEditType, CellUri, ICellInsertEdit, NotebookCellsChangedEvent, CellKind, IProcessedOutput, notebookDocumentMetadataDefaults, diff, ICellDeleteEdit, NotebookCellsChangeType, ICellDto2, IMainCellDto } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { ITextSnapshot } from 'vs/editor/common/model';
|
||||
import { IUndoRedoService, UndoRedoElementType } from 'vs/platform/undoRedo/common/undoRedo';
|
||||
import { IUndoRedoService, UndoRedoElementType, IUndoRedoElement, IResourceUndoRedoElement } from 'vs/platform/undoRedo/common/undoRedo';
|
||||
import { InsertCellEdit, DeleteCellEdit, MoveCellEdit, SpliceCellsEdit } from 'vs/workbench/contrib/notebook/common/model/cellEdit';
|
||||
import { ITextModelService } from 'vs/editor/common/services/resolverService';
|
||||
|
||||
@@ -66,6 +66,53 @@ export class NotebookTextModelSnapshot implements ITextSnapshot {
|
||||
|
||||
}
|
||||
|
||||
class StackOperation implements IResourceUndoRedoElement {
|
||||
type: UndoRedoElementType.Resource;
|
||||
|
||||
private _operations: IUndoRedoElement[] = [];
|
||||
|
||||
constructor(readonly resource: URI, readonly label: string) {
|
||||
this.type = UndoRedoElementType.Resource;
|
||||
}
|
||||
|
||||
pushEditOperation(element: IUndoRedoElement) {
|
||||
this._operations.push(element);
|
||||
}
|
||||
|
||||
undo(): void {
|
||||
this._operations.reverse().forEach(o => o.undo());
|
||||
}
|
||||
redo(): void | Promise<void> {
|
||||
this._operations.forEach(o => o.redo());
|
||||
}
|
||||
}
|
||||
|
||||
export class NotebookOperationManager {
|
||||
private _pendingStackOperation: StackOperation | null = null;
|
||||
constructor(private _undoService: IUndoRedoService, private _resource: URI) {
|
||||
|
||||
}
|
||||
|
||||
pushStackElement(label: string) {
|
||||
if (this._pendingStackOperation) {
|
||||
this._undoService.pushElement(this._pendingStackOperation);
|
||||
this._pendingStackOperation = null;
|
||||
return;
|
||||
}
|
||||
|
||||
this._pendingStackOperation = new StackOperation(this._resource, label);
|
||||
}
|
||||
|
||||
pushEditOperation(element: IUndoRedoElement) {
|
||||
if (this._pendingStackOperation) {
|
||||
this._pendingStackOperation.pushEditOperation(element);
|
||||
return;
|
||||
}
|
||||
|
||||
this._undoService.pushElement(element);
|
||||
}
|
||||
}
|
||||
|
||||
export class NotebookTextModel extends Disposable implements INotebookTextModel {
|
||||
|
||||
private _cellhandlePool: number = 0;
|
||||
@@ -112,6 +159,8 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
||||
protected readonly _onDidChangeDirty = this._register(new Emitter<void>());
|
||||
readonly onDidChangeDirty = this._onDidChangeDirty.event;
|
||||
|
||||
private _operationManager: NotebookOperationManager;
|
||||
|
||||
constructor(
|
||||
public handle: number,
|
||||
public viewType: string,
|
||||
@@ -122,6 +171,8 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
||||
) {
|
||||
super();
|
||||
this.cells = [];
|
||||
|
||||
this._operationManager = new NotebookOperationManager(this._undoService, uri);
|
||||
}
|
||||
|
||||
get isDirty() {
|
||||
@@ -173,6 +224,10 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
||||
this._increaseVersionId();
|
||||
}
|
||||
|
||||
pushStackElement(label: string) {
|
||||
this._operationManager.pushStackElement(label);
|
||||
}
|
||||
|
||||
$applyEdit(modelVersionId: number, rawEdits: ICellEditOperation[], synchronous: boolean): boolean {
|
||||
if (modelVersionId !== this._versionId) {
|
||||
return false;
|
||||
@@ -255,7 +310,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
||||
return [diff[0], deletedCells, diff[2]] as [number, NotebookCellTextModel[], NotebookCellTextModel[]];
|
||||
});
|
||||
|
||||
this._undoService.pushElement(new SpliceCellsEdit(this.uri, undoDiff, {
|
||||
this._operationManager.pushEditOperation(new SpliceCellsEdit(this.uri, undoDiff, {
|
||||
insertCell: this._insertCellDelegate.bind(this),
|
||||
deleteCell: this._deleteCellDelegate.bind(this),
|
||||
emitSelections: this._emitSelectionsDelegate.bind(this)
|
||||
@@ -266,7 +321,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
||||
}
|
||||
|
||||
$handleEdit(label: string | undefined, undo: () => void, redo: () => void): void {
|
||||
this._undoService.pushElement({
|
||||
this._operationManager.pushEditOperation({
|
||||
type: UndoRedoElementType.Resource,
|
||||
resource: this.uri,
|
||||
label: label ?? nls.localize('defaultEditLabel', "Edit"),
|
||||
@@ -502,7 +557,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
||||
const cell = this.createCellTextModel(source, language, type, [], metadata);
|
||||
|
||||
if (pushUndoStop) {
|
||||
this._undoService.pushElement(new InsertCellEdit(this.uri, index, cell, {
|
||||
this._operationManager.pushEditOperation(new InsertCellEdit(this.uri, index, cell, {
|
||||
insertCell: this._insertCellDelegate.bind(this),
|
||||
deleteCell: this._deleteCellDelegate.bind(this),
|
||||
emitSelections: this._emitSelectionsDelegate.bind(this)
|
||||
@@ -522,7 +577,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
||||
|
||||
insertCell2(index: number, cell: NotebookCellTextModel, synchronous: boolean, pushUndoStop: boolean): void {
|
||||
if (pushUndoStop) {
|
||||
this._undoService.pushElement(new InsertCellEdit(this.uri, index, cell, {
|
||||
this._operationManager.pushEditOperation(new InsertCellEdit(this.uri, index, cell, {
|
||||
insertCell: this._insertCellDelegate.bind(this),
|
||||
deleteCell: this._deleteCellDelegate.bind(this),
|
||||
emitSelections: this._emitSelectionsDelegate.bind(this)
|
||||
@@ -536,7 +591,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
||||
deleteCell2(index: number, synchronous: boolean, pushUndoStop: boolean, beforeSelections: number[] | undefined, endSelections: number[] | undefined) {
|
||||
const cell = this.cells[index];
|
||||
if (pushUndoStop) {
|
||||
this._undoService.pushElement(new DeleteCellEdit(this.uri, index, cell, {
|
||||
this._operationManager.pushEditOperation(new DeleteCellEdit(this.uri, index, cell, {
|
||||
insertCell: this._insertCellDelegate.bind(this),
|
||||
deleteCell: this._deleteCellDelegate.bind(this),
|
||||
emitSelections: this._emitSelectionsDelegate.bind(this)
|
||||
@@ -553,7 +608,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
||||
moveCellToIdx2(index: number, newIdx: number, synchronous: boolean, pushedToUndoStack: boolean, beforeSelections: number[] | undefined, endSelections: number[] | undefined): boolean {
|
||||
const cell = this.cells[index];
|
||||
if (pushedToUndoStack) {
|
||||
this._undoService.pushElement(new MoveCellEdit(this.uri, index, newIdx, {
|
||||
this._operationManager.pushEditOperation(new MoveCellEdit(this.uri, index, newIdx, {
|
||||
moveCell: (fromIndex: number, toIndex: number, beforeSelections: number[] | undefined, endSelections: number[] | undefined) => {
|
||||
this.moveCellToIdx2(fromIndex, toIndex, true, false, beforeSelections, endSelections);
|
||||
},
|
||||
|
||||
@@ -63,6 +63,8 @@ export class TestNotebookEditor implements INotebookEditor {
|
||||
) { }
|
||||
|
||||
multipleKernelsAvailable: boolean = false;
|
||||
onDidChangeAvailableKernels: Event<void> = new Emitter<void>().event;
|
||||
|
||||
|
||||
uri?: URI | undefined;
|
||||
textModel?: NotebookTextModel | undefined;
|
||||
@@ -158,6 +160,10 @@ export class TestNotebookEditor implements INotebookEditor {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
moveCellToIdx(cell: ICellViewModel, index: number): Promise<ICellViewModel | null> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
moveCell(cell: ICellViewModel, relativeToCell: ICellViewModel, direction: 'above' | 'below'): Promise<ICellViewModel | null> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
@@ -883,7 +883,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
|
||||
resolve(undefined);
|
||||
}
|
||||
} else {
|
||||
resolve(this.executeTask(task, resolver));
|
||||
resolve(this.executeTask(task, resolver, runSource));
|
||||
}
|
||||
}).then((value) => {
|
||||
if (runSource === TaskRunSource.User) {
|
||||
@@ -1452,7 +1452,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
|
||||
};
|
||||
}
|
||||
|
||||
private executeTask(task: Task, resolver: ITaskResolver): Promise<ITaskSummary> {
|
||||
private executeTask(task: Task, resolver: ITaskResolver, runSource?: TaskRunSource): Promise<ITaskSummary> {
|
||||
enum SaveBeforeRunConfigOptions {
|
||||
Always = 'always',
|
||||
Never = 'never',
|
||||
@@ -1464,7 +1464,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
|
||||
const execTask = async (task: Task, resolver: ITaskResolver): Promise<ITaskSummary> => {
|
||||
return ProblemMatcherRegistry.onReady().then(() => {
|
||||
let executeResult = this.getTaskSystem().run(task, resolver);
|
||||
return this.handleExecuteResult(executeResult);
|
||||
return this.handleExecuteResult(executeResult, runSource);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1501,7 +1501,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
|
||||
}
|
||||
}
|
||||
|
||||
private async handleExecuteResult(executeResult: ITaskExecuteResult): Promise<ITaskSummary> {
|
||||
private async handleExecuteResult(executeResult: ITaskExecuteResult, runSource?: TaskRunSource): Promise<ITaskSummary> {
|
||||
if (executeResult.task.taskLoadMessages && executeResult.task.taskLoadMessages.length > 0) {
|
||||
executeResult.task.taskLoadMessages.forEach(loadMessage => {
|
||||
this._outputChannel.append(loadMessage + '\n');
|
||||
@@ -1509,7 +1509,9 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
|
||||
this.showOutput();
|
||||
}
|
||||
|
||||
await this.setRecentlyUsedTask(executeResult.task);
|
||||
if (runSource === TaskRunSource.User) {
|
||||
await this.setRecentlyUsedTask(executeResult.task);
|
||||
}
|
||||
if (executeResult.kind === TaskExecuteKind.Active) {
|
||||
let active = executeResult.active;
|
||||
if (active && active.same) {
|
||||
|
||||
@@ -840,6 +840,9 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
|
||||
setTimeout(() => this.layout(this._timeoutDimension!), 0);
|
||||
}
|
||||
}
|
||||
if (!visible) {
|
||||
this._widgetManager.hideHovers();
|
||||
}
|
||||
}
|
||||
|
||||
public scrollDownLine(): void {
|
||||
|
||||
@@ -110,6 +110,8 @@ export class TerminalViewPane extends ViewPane {
|
||||
} else {
|
||||
this.layoutBody(this._bodyDimensions.height, this._bodyDimensions.width);
|
||||
}
|
||||
} else {
|
||||
this._terminalService.getActiveTab()?.setVisible(false);
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
@@ -5,11 +5,15 @@
|
||||
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { ITerminalWidget } from 'vs/workbench/contrib/terminal/browser/widgets/widgets';
|
||||
import { IHoverService } from 'vs/workbench/services/hover/browser/hover';
|
||||
|
||||
export class TerminalWidgetManager implements IDisposable {
|
||||
private _container: HTMLElement | undefined;
|
||||
private _attached: Map<string, ITerminalWidget> = new Map();
|
||||
|
||||
constructor(@IHoverService private readonly _hoverService: IHoverService) {
|
||||
}
|
||||
|
||||
attachToElement(terminalWrapper: HTMLElement) {
|
||||
if (!this._container) {
|
||||
this._container = document.createElement('div');
|
||||
@@ -25,6 +29,10 @@ export class TerminalWidgetManager implements IDisposable {
|
||||
}
|
||||
}
|
||||
|
||||
hideHovers(): void {
|
||||
this._hoverService.hideHover();
|
||||
}
|
||||
|
||||
attachWidget(widget: ITerminalWidget): IDisposable | undefined {
|
||||
if (!this._container) {
|
||||
return undefined; // {{SQL CARBON EDIT}} strict-null-check
|
||||
|
||||
@@ -16,7 +16,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { Disposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
import { IUserDataSyncWorkbenchService, getSyncAreaLabel, IUserDataSyncPreview, IUserDataSyncResource, MANUAL_SYNC_VIEW_ID } from 'vs/workbench/services/userDataSync/common/userDataSync';
|
||||
import { IUserDataSyncWorkbenchService, getSyncAreaLabel, IUserDataSyncPreview, IUserDataSyncResource, SYNC_MERGES_VIEW_ID } from 'vs/workbench/services/userDataSync/common/userDataSync';
|
||||
import { isEqual, basename } from 'vs/base/common/resources';
|
||||
import { IDecorationsProvider, IDecorationData, IDecorationsService } from 'vs/workbench/services/decorations/browser/decorations';
|
||||
import { IProgressService } from 'vs/platform/progress/common/progress';
|
||||
@@ -39,7 +39,7 @@ import { registerEditorContribution } from 'vs/editor/browser/editorExtensions';
|
||||
import { Severity } from 'vs/platform/notification/common/notification';
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
|
||||
export class UserDataManualSyncViewPane extends TreeViewPane {
|
||||
export class UserDataSyncMergesViewPane extends TreeViewPane {
|
||||
|
||||
private userDataSyncPreview: IUserDataSyncPreview;
|
||||
|
||||
@@ -83,7 +83,7 @@ export class UserDataManualSyncViewPane extends TreeViewPane {
|
||||
this.createButtons(container);
|
||||
|
||||
const that = this;
|
||||
this.treeView.message = localize('explanation', "Please go through each entry and accept the change to enable sync.");
|
||||
this.treeView.message = localize('explanation', "Please go through each entry and merge to enable sync.");
|
||||
this.treeView.dataProvider = { getChildren() { return that.getTreeItems(); } };
|
||||
}
|
||||
|
||||
@@ -164,7 +164,7 @@ export class UserDataManualSyncViewPane extends TreeViewPane {
|
||||
icon: Codicon.cloudDownload,
|
||||
menu: {
|
||||
id: MenuId.ViewItemContext,
|
||||
when: ContextKeyExpr.and(ContextKeyEqualsExpr.create('view', MANUAL_SYNC_VIEW_ID), ContextKeyExpr.equals('viewItem', 'sync-resource-preview')),
|
||||
when: ContextKeyExpr.and(ContextKeyEqualsExpr.create('view', SYNC_MERGES_VIEW_ID), ContextKeyExpr.equals('viewItem', 'sync-resource-preview')),
|
||||
group: 'inline',
|
||||
order: 1,
|
||||
},
|
||||
@@ -184,7 +184,7 @@ export class UserDataManualSyncViewPane extends TreeViewPane {
|
||||
icon: Codicon.cloudUpload,
|
||||
menu: {
|
||||
id: MenuId.ViewItemContext,
|
||||
when: ContextKeyExpr.and(ContextKeyEqualsExpr.create('view', MANUAL_SYNC_VIEW_ID), ContextKeyExpr.equals('viewItem', 'sync-resource-preview')),
|
||||
when: ContextKeyExpr.and(ContextKeyEqualsExpr.create('view', SYNC_MERGES_VIEW_ID), ContextKeyExpr.equals('viewItem', 'sync-resource-preview')),
|
||||
group: 'inline',
|
||||
order: 2,
|
||||
},
|
||||
@@ -204,7 +204,7 @@ export class UserDataManualSyncViewPane extends TreeViewPane {
|
||||
icon: Codicon.merge,
|
||||
menu: {
|
||||
id: MenuId.ViewItemContext,
|
||||
when: ContextKeyExpr.and(ContextKeyEqualsExpr.create('view', MANUAL_SYNC_VIEW_ID), ContextKeyExpr.equals('viewItem', 'sync-resource-preview')),
|
||||
when: ContextKeyExpr.and(ContextKeyEqualsExpr.create('view', SYNC_MERGES_VIEW_ID), ContextKeyExpr.equals('viewItem', 'sync-resource-preview')),
|
||||
group: 'inline',
|
||||
order: 3,
|
||||
},
|
||||
@@ -224,7 +224,7 @@ export class UserDataManualSyncViewPane extends TreeViewPane {
|
||||
icon: Codicon.discard,
|
||||
menu: {
|
||||
id: MenuId.ViewItemContext,
|
||||
when: ContextKeyExpr.and(ContextKeyEqualsExpr.create('view', MANUAL_SYNC_VIEW_ID), ContextKeyExpr.or(ContextKeyExpr.equals('viewItem', 'sync-resource-accepted'), ContextKeyExpr.equals('viewItem', 'sync-resource-conflict'))),
|
||||
when: ContextKeyExpr.and(ContextKeyEqualsExpr.create('view', SYNC_MERGES_VIEW_ID), ContextKeyExpr.or(ContextKeyExpr.equals('viewItem', 'sync-resource-accepted'), ContextKeyExpr.equals('viewItem', 'sync-resource-conflict'))),
|
||||
group: 'inline',
|
||||
order: 3,
|
||||
},
|
||||
@@ -270,7 +270,7 @@ export class UserDataManualSyncViewPane extends TreeViewPane {
|
||||
previewResource = this.userDataSyncPreview.resources.find(({ local }) => isEqual(local, previewResource.local))!;
|
||||
await this.reopen(previewResource);
|
||||
if (previewResource.mergeState === MergeState.Conflict) {
|
||||
await this.dialogService.show(Severity.Warning, localize('conflicts detected', "Conflicts Detected."), [], {
|
||||
await this.dialogService.show(Severity.Warning, localize('conflicts detected', "Conflicts Detected"), [], {
|
||||
detail: localize('resolve', "Unable to merge due to conflicts. Please resolve them to continue.")
|
||||
});
|
||||
}
|
||||
@@ -373,7 +373,7 @@ export class UserDataManualSyncViewPane extends TreeViewPane {
|
||||
}
|
||||
|
||||
private withProgress(task: () => Promise<void>): Promise<void> {
|
||||
return this.progressService.withProgress({ location: MANUAL_SYNC_VIEW_ID, delay: 500 }, task);
|
||||
return this.progressService.withProgress({ location: SYNC_MERGES_VIEW_ID, delay: 500 }, task);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -30,13 +30,13 @@ import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IAction, Action } from 'vs/base/common/actions';
|
||||
import { IUserDataSyncWorkbenchService, CONTEXT_SYNC_STATE, getSyncAreaLabel, CONTEXT_ACCOUNT_STATE, AccountStatus, CONTEXT_ENABLE_ACTIVITY_VIEWS, SHOW_SYNC_LOG_COMMAND_ID, CONFIGURE_SYNC_COMMAND_ID, MANUAL_SYNC_VIEW_ID, CONTEXT_ENABLE_MANUAL_SYNC_VIEW } from 'vs/workbench/services/userDataSync/common/userDataSync';
|
||||
import { IUserDataSyncWorkbenchService, CONTEXT_SYNC_STATE, getSyncAreaLabel, CONTEXT_ACCOUNT_STATE, AccountStatus, CONTEXT_ENABLE_ACTIVITY_VIEWS, SHOW_SYNC_LOG_COMMAND_ID, CONFIGURE_SYNC_COMMAND_ID, SYNC_MERGES_VIEW_ID, CONTEXT_ENABLE_SYNC_MERGES_VIEW } from 'vs/workbench/services/userDataSync/common/userDataSync';
|
||||
import { IUserDataSyncMachinesService, IUserDataSyncMachine } from 'vs/platform/userDataSync/common/userDataSyncMachines';
|
||||
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
||||
import { TreeView } from 'vs/workbench/contrib/views/browser/treeView';
|
||||
import { flatten } from 'vs/base/common/arrays';
|
||||
import { UserDataManualSyncViewPane } from 'vs/workbench/contrib/userDataSync/browser/userDataManualSyncView';
|
||||
import { UserDataSyncMergesViewPane } from 'vs/workbench/contrib/userDataSync/browser/userDataSyncMergesView';
|
||||
|
||||
export class UserDataSyncViewPaneContainer extends ViewPaneContainer {
|
||||
|
||||
@@ -86,7 +86,7 @@ export class UserDataSyncDataViews extends Disposable {
|
||||
}
|
||||
|
||||
private registerViews(container: ViewContainer): void {
|
||||
this.registerManualSyncView(container);
|
||||
this.registerMergesView(container);
|
||||
|
||||
this.registerActivityView(container, true);
|
||||
this.registerMachinesView(container);
|
||||
@@ -94,17 +94,17 @@ export class UserDataSyncDataViews extends Disposable {
|
||||
this.registerActivityView(container, false);
|
||||
}
|
||||
|
||||
private registerManualSyncView(container: ViewContainer): void {
|
||||
private registerMergesView(container: ViewContainer): void {
|
||||
const viewsRegistry = Registry.as<IViewsRegistry>(Extensions.ViewsRegistry);
|
||||
const viewName = localize('manual sync', "Manual Sync");
|
||||
const viewName = localize('merges', "Merges");
|
||||
viewsRegistry.registerViews([<ITreeViewDescriptor>{
|
||||
id: MANUAL_SYNC_VIEW_ID,
|
||||
id: SYNC_MERGES_VIEW_ID,
|
||||
name: viewName,
|
||||
ctorDescriptor: new SyncDescriptor(UserDataManualSyncViewPane),
|
||||
when: CONTEXT_ENABLE_MANUAL_SYNC_VIEW,
|
||||
ctorDescriptor: new SyncDescriptor(UserDataSyncMergesViewPane),
|
||||
when: CONTEXT_ENABLE_SYNC_MERGES_VIEW,
|
||||
canToggleVisibility: false,
|
||||
canMoveView: false,
|
||||
treeView: this.instantiationService.createInstance(TreeView, MANUAL_SYNC_VIEW_ID, viewName),
|
||||
treeView: this.instantiationService.createInstance(TreeView, SYNC_MERGES_VIEW_ID, viewName),
|
||||
collapsed: false,
|
||||
order: 100,
|
||||
}], container);
|
||||
|
||||
Reference in New Issue
Block a user