mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Merge from vscode 6fded8a497cd0142de3a1c607649a5423a091a25
This commit is contained in:
@@ -16,6 +16,7 @@ import { ITextModel } from 'vs/editor/common/model';
|
||||
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
|
||||
/**
|
||||
* Shows a message when semantic tokens are shown the first time.
|
||||
@@ -24,32 +25,34 @@ export class SemanticTokensHelp extends Disposable implements IEditorContributio
|
||||
|
||||
public static readonly ID = 'editor.contrib.semanticHighlightHelp';
|
||||
|
||||
private static notificationShown = false;
|
||||
|
||||
constructor(
|
||||
_editor: ICodeEditor,
|
||||
@INotificationService _notificationService: INotificationService,
|
||||
@IOpenerService _openerService: IOpenerService,
|
||||
@IWorkbenchThemeService _themeService: IWorkbenchThemeService,
|
||||
@IEditorService _editorService: IEditorService,
|
||||
@IStorageService _storageService: IStorageService,
|
||||
@IStorageKeysSyncRegistryService storageKeysSyncRegistryService: IStorageKeysSyncRegistryService
|
||||
) {
|
||||
super();
|
||||
|
||||
// opt-in to syncing
|
||||
const neverShowAgainId = 'editor.contrib.semanticTokensHelp';
|
||||
|
||||
if (_storageService.getBoolean(neverShowAgainId, StorageScope.GLOBAL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
storageKeysSyncRegistryService.registerStorageKey({ key: neverShowAgainId, version: 1 });
|
||||
|
||||
const toDispose = this._register(new DisposableStore());
|
||||
const localToDispose = toDispose.add(new DisposableStore());
|
||||
const installChangeTokenListener = (model: ITextModel) => {
|
||||
localToDispose.add(model.onDidChangeTokens((e) => {
|
||||
if (SemanticTokensHelp.notificationShown) {
|
||||
toDispose.dispose();
|
||||
if (!e.semanticTokensApplied) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!e.semanticTokensApplied) {
|
||||
if (_storageService.getBoolean(neverShowAgainId, StorageScope.GLOBAL)) {
|
||||
toDispose.dispose();
|
||||
return;
|
||||
}
|
||||
const activeEditorControl = _editorService.activeTextEditorControl;
|
||||
@@ -58,7 +61,7 @@ export class SemanticTokensHelp extends Disposable implements IEditorContributio
|
||||
}
|
||||
|
||||
toDispose.dispose(); // uninstall all listeners, make sure the notification is only shown once per window
|
||||
SemanticTokensHelp.notificationShown = true;
|
||||
_storageService.store(neverShowAgainId, true, StorageScope.GLOBAL); // never show again
|
||||
|
||||
const message = nls.localize(
|
||||
{
|
||||
@@ -81,7 +84,7 @@ export class SemanticTokensHelp extends Disposable implements IEditorContributio
|
||||
_openerService.open(URI.parse(url));
|
||||
}
|
||||
}
|
||||
], { neverShowAgain: { id: neverShowAgainId } });
|
||||
]);
|
||||
}));
|
||||
};
|
||||
|
||||
|
||||
@@ -89,18 +89,11 @@
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.monaco-editor.vs-dark .review-widget .body .comment-body h4 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.monaco-editor .review-widget .body .review-comment .review-comment-contents .author {
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
.monaco-editor.vs-dark .review-widget .body .review-comment .review-comment-contents .author {
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.monaco-editor .review-widget .body .review-comment .review-comment-contents .isPending {
|
||||
margin: 0 5px 0 5px;
|
||||
@@ -108,7 +101,7 @@
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.monaco-editor.vs-dark .review-widget .body .review-comment .review-comment-contents .comment-body {
|
||||
.monaco-editor .review-widget .body .review-comment .review-comment-contents .comment-body {
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
@@ -183,10 +176,6 @@
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.monaco-editor.vs-dark .review-widget .body span.created_at {
|
||||
color: #e0e0e0;
|
||||
}
|
||||
|
||||
.monaco-editor .review-widget .body .comment-body p,
|
||||
.monaco-editor .review-widget .body .comment-body ul {
|
||||
margin: 8px 0;
|
||||
|
||||
@@ -27,7 +27,7 @@ export class CustomEditorInput extends LazilyResolvedWebviewEditorInput {
|
||||
public static typeId = 'workbench.editors.webviewEditor';
|
||||
|
||||
private readonly _editorResource: URI;
|
||||
private readonly _fromBackup: boolean;
|
||||
private readonly _startsDirty: boolean | undefined;
|
||||
|
||||
get resource() { return this._editorResource; }
|
||||
|
||||
@@ -38,7 +38,7 @@ export class CustomEditorInput extends LazilyResolvedWebviewEditorInput {
|
||||
viewType: string,
|
||||
id: string,
|
||||
webview: Lazy<WebviewOverlay>,
|
||||
fromBackup: boolean,
|
||||
options: { startsDirty?: boolean },
|
||||
@IWebviewService webviewService: IWebviewService,
|
||||
@IWebviewWorkbenchService webviewWorkbenchService: IWebviewWorkbenchService,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@@ -51,7 +51,7 @@ export class CustomEditorInput extends LazilyResolvedWebviewEditorInput {
|
||||
) {
|
||||
super(id, viewType, '', webview, webviewService, webviewWorkbenchService);
|
||||
this._editorResource = resource;
|
||||
this._fromBackup = fromBackup;
|
||||
this._startsDirty = options.startsDirty;
|
||||
}
|
||||
|
||||
public getTypeId(): string {
|
||||
@@ -110,7 +110,7 @@ export class CustomEditorInput extends LazilyResolvedWebviewEditorInput {
|
||||
|
||||
public isDirty(): boolean {
|
||||
if (!this._modelRef) {
|
||||
return this._fromBackup;
|
||||
return !!this._startsDirty;
|
||||
}
|
||||
return this._modelRef.object.isDirty();
|
||||
}
|
||||
@@ -201,7 +201,7 @@ export class CustomEditorInput extends LazilyResolvedWebviewEditorInput {
|
||||
this.viewType,
|
||||
this.id,
|
||||
new Lazy(() => undefined!),
|
||||
this._fromBackup); // this webview is replaced in the transfer call
|
||||
{ startsDirty: this._startsDirty }); // this webview is replaced in the transfer call
|
||||
this.transfer(newEditor);
|
||||
newEditor.updateGroup(group);
|
||||
return newEditor;
|
||||
|
||||
@@ -11,7 +11,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
||||
import { IEditorInput } from 'vs/workbench/common/editor';
|
||||
import { CustomEditorInput } from 'vs/workbench/contrib/customEditor/browser/customEditorInput';
|
||||
import { IWebviewService } from 'vs/workbench/contrib/webview/browser/webview';
|
||||
import { WebviewEditorInputFactory } from 'vs/workbench/contrib/webview/browser/webviewEditorInputFactory';
|
||||
import { WebviewEditorInputFactory, SerializedWebview } from 'vs/workbench/contrib/webview/browser/webviewEditorInputFactory';
|
||||
import { IWebviewWorkbenchService, WebviewInputOptions } from 'vs/workbench/contrib/webview/browser/webviewWorkbenchService';
|
||||
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
|
||||
|
||||
@@ -30,6 +30,12 @@ export interface CustomDocumentBackupData {
|
||||
};
|
||||
}
|
||||
|
||||
interface SerializedCustomEditor extends SerializedWebview {
|
||||
readonly editorResource: UriComponents;
|
||||
readonly dirty?: boolean;
|
||||
}
|
||||
|
||||
|
||||
export class CustomEditorInputFactory extends WebviewEditorInputFactory {
|
||||
|
||||
public static readonly ID = CustomEditorInput.typeId;
|
||||
@@ -43,9 +49,10 @@ export class CustomEditorInputFactory extends WebviewEditorInputFactory {
|
||||
}
|
||||
|
||||
public serialize(input: CustomEditorInput): string | undefined {
|
||||
const data = {
|
||||
const data: SerializedCustomEditor = {
|
||||
...this.toJson(input),
|
||||
editorResource: input.resource.toJSON(),
|
||||
dirty: input.isDirty(),
|
||||
};
|
||||
|
||||
try {
|
||||
@@ -78,7 +85,7 @@ export class CustomEditorInputFactory extends WebviewEditorInputFactory {
|
||||
return webview;
|
||||
});
|
||||
|
||||
const customInput = this._instantiationService.createInstance(CustomEditorInput, URI.from((data as any).editorResource), data.viewType, id, webview, false);
|
||||
const customInput = this._instantiationService.createInstance(CustomEditorInput, URI.from((data as any).editorResource), data.viewType, id, webview, { startsDirty: (data as any).dirty });
|
||||
if (typeof data.group === 'number') {
|
||||
customInput.updateGroup(data.group);
|
||||
}
|
||||
@@ -112,7 +119,7 @@ export class CustomEditorInputFactory extends WebviewEditorInputFactory {
|
||||
return webview;
|
||||
});
|
||||
|
||||
const editor = instantiationService.createInstance(CustomEditorInput, URI.revive(backupData.editorResource), backupData.viewType, id, webview, true);
|
||||
const editor = instantiationService.createInstance(CustomEditorInput, URI.revive(backupData.editorResource), backupData.viewType, id, webview, { startsDirty: true });
|
||||
editor.updateGroup(0);
|
||||
return editor;
|
||||
});
|
||||
|
||||
@@ -23,7 +23,7 @@ import { EditorServiceImpl } from 'vs/workbench/browser/parts/editor/editor';
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { EditorInput, EditorOptions, GroupIdentifier, IEditorInput, IEditorPane } from 'vs/workbench/common/editor';
|
||||
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
|
||||
import { webviewEditorsExtensionPoint } from 'vs/workbench/contrib/customEditor/browser/extensionPoint';
|
||||
import { webviewEditorsExtensionPoint, IWebviewEditorsExtensionPoint } from 'vs/workbench/contrib/customEditor/browser/extensionPoint';
|
||||
import { CONTEXT_CUSTOM_EDITORS, CONTEXT_FOCUSED_CUSTOM_EDITOR_IS_EDITABLE, CustomEditorInfo, CustomEditorInfoCollection, CustomEditorPriority, CustomEditorSelector, ICustomEditorService } from 'vs/workbench/contrib/customEditor/common/customEditor';
|
||||
import { CustomEditorModelManager } from 'vs/workbench/contrib/customEditor/common/customEditorModelManager';
|
||||
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
|
||||
@@ -31,12 +31,16 @@ import { IWebviewService, webviewHasOwnEditFunctionsContext } from 'vs/workbench
|
||||
import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IEditorService, IOpenEditorOverride } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { CustomEditorInput } from './customEditorInput';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
|
||||
export const defaultEditorId = 'default';
|
||||
|
||||
const builtinProviderDisplayName = nls.localize('builtinProviderDisplayName', "Built-in");
|
||||
|
||||
const defaultEditorInfo = new CustomEditorInfo({
|
||||
id: defaultEditorId,
|
||||
displayName: nls.localize('promptOpenWith.defaultEditor', "VS Code's standard text editor"),
|
||||
displayName: nls.localize('promptOpenWith.defaultEditor.displayName', "Text Editor"),
|
||||
providerDisplayName: builtinProviderDisplayName,
|
||||
selector: [
|
||||
{ filenamePattern: '*' }
|
||||
],
|
||||
@@ -58,8 +62,9 @@ export class CustomEditorInfoStore extends Disposable {
|
||||
this.add(new CustomEditorInfo({
|
||||
id: webviewEditorContribution.viewType,
|
||||
displayName: webviewEditorContribution.displayName,
|
||||
providerDisplayName: extension.description.isBuiltin ? builtinProviderDisplayName : extension.description.displayName || extension.description.identifier.value,
|
||||
selector: webviewEditorContribution.selector || [],
|
||||
priority: webviewEditorContribution.priority || CustomEditorPriority.default,
|
||||
priority: getPriorityFromContribution(webviewEditorContribution, extension.description),
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -192,6 +197,7 @@ export class CustomEditorService extends Disposable implements ICustomEditorServ
|
||||
description: editorDescriptor.id === currentlyOpenedEditorType
|
||||
? nls.localize('openWithCurrentlyActive', "Currently Active")
|
||||
: undefined,
|
||||
detail: editorDescriptor.providerDisplayName,
|
||||
buttons: resourceExt ? [{
|
||||
iconClass: 'codicon-settings-gear',
|
||||
tooltip: nls.localize('promptOpenWith.setDefaultTooltip', "Set as default editor for '{0}' files", resourceExt)
|
||||
@@ -269,7 +275,7 @@ export class CustomEditorService extends Disposable implements ICustomEditorServ
|
||||
const webview = new Lazy(() => {
|
||||
return this.webviewService.createWebviewOverlay(id, { customClasses: options?.customClasses }, {});
|
||||
});
|
||||
const input = this.instantiationService.createInstance(CustomEditorInput, resource, viewType, id, webview, false);
|
||||
const input = this.instantiationService.createInstance(CustomEditorInput, resource, viewType, id, webview, {});
|
||||
if (typeof group !== 'undefined') {
|
||||
input.updateGroup(group);
|
||||
}
|
||||
@@ -569,9 +575,29 @@ export class CustomEditorContribution extends Disposable implements IWorkbenchCo
|
||||
}
|
||||
}
|
||||
|
||||
function getPriorityFromContribution(
|
||||
contribution: IWebviewEditorsExtensionPoint,
|
||||
extension: IExtensionDescription,
|
||||
): CustomEditorPriority {
|
||||
switch (contribution.priority) {
|
||||
case CustomEditorPriority.default:
|
||||
case CustomEditorPriority.option:
|
||||
return contribution.priority;
|
||||
|
||||
case CustomEditorPriority.builtin:
|
||||
// Builtin is only valid for builtin extensions
|
||||
return extension.isBuiltin ? CustomEditorPriority.builtin : CustomEditorPriority.default;
|
||||
|
||||
default:
|
||||
return CustomEditorPriority.default;
|
||||
}
|
||||
}
|
||||
|
||||
registerThemingParticipant((theme, collector) => {
|
||||
const shadow = theme.getColor(colorRegistry.scrollbarShadow);
|
||||
if (shadow) {
|
||||
collector.addRule(`.webview.modified { box-shadow: -6px 0 5px -5px ${shadow}; }`);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -16,11 +16,11 @@ namespace WebviewEditorContribution {
|
||||
export const priority = 'priority';
|
||||
}
|
||||
|
||||
interface IWebviewEditorsExtensionPoint {
|
||||
export interface IWebviewEditorsExtensionPoint {
|
||||
readonly [WebviewEditorContribution.viewType]: string;
|
||||
readonly [WebviewEditorContribution.displayName]: string;
|
||||
readonly [WebviewEditorContribution.selector]?: readonly CustomEditorSelector[];
|
||||
readonly [WebviewEditorContribution.priority]?: CustomEditorPriority;
|
||||
readonly [WebviewEditorContribution.priority]?: string;
|
||||
}
|
||||
|
||||
const webviewEditorsContribution: IJSONSchema = {
|
||||
@@ -75,12 +75,10 @@ const webviewEditorsContribution: IJSONSchema = {
|
||||
enum: [
|
||||
CustomEditorPriority.default,
|
||||
CustomEditorPriority.option,
|
||||
CustomEditorPriority.builtin,
|
||||
],
|
||||
markdownEnumDescriptions: [
|
||||
nls.localize('contributes.priority.default', 'Editor is automatically used for a resource if no other default custom editors are registered for it.'),
|
||||
nls.localize('contributes.priority.option', 'Editor is not automatically used but can be selected by a user.'),
|
||||
nls.localize('contributes.priority.builtin', 'Editor automatically used if no other `default` or `builtin` editors are registered for the resource.'),
|
||||
],
|
||||
default: 'default'
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import { distinct, mergeSort } from 'vs/base/common/arrays';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import * as glob from 'vs/base/common/glob';
|
||||
import { IDisposable, IReference } from 'vs/base/common/lifecycle';
|
||||
import { posix } from 'vs/base/common/path';
|
||||
import { basename } from 'vs/base/common/resources';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
@@ -75,17 +76,20 @@ export class CustomEditorInfo {
|
||||
|
||||
public readonly id: string;
|
||||
public readonly displayName: string;
|
||||
public readonly providerDisplayName: string | undefined;
|
||||
public readonly priority: CustomEditorPriority;
|
||||
public readonly selector: readonly CustomEditorSelector[];
|
||||
|
||||
constructor(descriptor: {
|
||||
readonly id: string;
|
||||
readonly displayName: string;
|
||||
readonly providerDisplayName: string | undefined;
|
||||
readonly priority: CustomEditorPriority;
|
||||
readonly selector: readonly CustomEditorSelector[];
|
||||
}) {
|
||||
this.id = descriptor.id;
|
||||
this.displayName = descriptor.displayName;
|
||||
this.providerDisplayName = descriptor.providerDisplayName;
|
||||
this.priority = descriptor.priority;
|
||||
this.selector = descriptor.selector;
|
||||
}
|
||||
@@ -96,7 +100,9 @@ export class CustomEditorInfo {
|
||||
|
||||
static selectorMatches(selector: CustomEditorSelector, resource: URI): boolean {
|
||||
if (selector.filenamePattern) {
|
||||
if (glob.match(selector.filenamePattern.toLowerCase(), basename(resource).toLowerCase())) {
|
||||
const matchOnPath = selector.filenamePattern.indexOf(posix.sep) >= 0;
|
||||
const target = matchOnPath ? resource.path : basename(resource);
|
||||
if (glob.match(selector.filenamePattern.toLowerCase(), target.toLowerCase())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,7 +133,11 @@ export class CallStackView extends ViewPane {
|
||||
this.needsRefresh = false;
|
||||
this.dataSource.deemphasizedStackFramesToShow = [];
|
||||
this.tree.updateChildren().then(() => {
|
||||
this.parentSessionToExpand.forEach(s => this.tree.expand(s));
|
||||
try {
|
||||
this.parentSessionToExpand.forEach(s => this.tree.expand(s));
|
||||
} catch (e) {
|
||||
// Ignore tree expand errors if element no longer present
|
||||
}
|
||||
this.parentSessionToExpand.clear();
|
||||
if (this.selectionNeedsUpdate) {
|
||||
this.selectionNeedsUpdate = false;
|
||||
|
||||
@@ -44,7 +44,7 @@ import { ClearReplAction, Repl } from 'vs/workbench/contrib/debug/browser/repl';
|
||||
import { DebugContentProvider } from 'vs/workbench/contrib/debug/common/debugContentProvider';
|
||||
import { WelcomeView } from 'vs/workbench/contrib/debug/browser/welcomeView';
|
||||
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
|
||||
import { DebugViewPaneContainer, OpenDebugPanelAction } from 'vs/workbench/contrib/debug/browser/debugViewlet';
|
||||
import { DebugViewPaneContainer, OpenDebugConsoleAction } from 'vs/workbench/contrib/debug/browser/debugViewlet';
|
||||
import { registerEditorContribution } from 'vs/editor/browser/editorExtensions';
|
||||
import { CallStackEditorContribution } from 'vs/workbench/contrib/debug/browser/callStackEditorContribution';
|
||||
import { BreakpointEditorContribution } from 'vs/workbench/contrib/debug/browser/breakpointEditorContribution';
|
||||
@@ -91,7 +91,7 @@ const VIEW_CONTAINER: ViewContainer = Registry.as<IViewContainersRegistry>(ViewE
|
||||
name: nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'debugPanel' }, 'Debug Console'),
|
||||
ctorDescriptor: new SyncDescriptor(ViewPaneContainer, [DEBUG_PANEL_ID, DEBUG_PANEL_ID, { mergeViewWithContainerWhenSingleView: true, donotShowContainerTitleWhenMergedWithContainer: true }]),
|
||||
focusCommand: {
|
||||
id: OpenDebugPanelAction.ID,
|
||||
id: OpenDebugConsoleAction.ID,
|
||||
keybindings: openPanelKb
|
||||
},
|
||||
order: 3,
|
||||
@@ -120,7 +120,7 @@ registerCommands();
|
||||
|
||||
// register action to open viewlet
|
||||
const registry = Registry.as<IWorkbenchActionRegistry>(WorkbenchActionRegistryExtensions.WorkbenchActions);
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenDebugPanelAction, OpenDebugPanelAction.ID, OpenDebugPanelAction.LABEL, openPanelKb), 'View: Debug Console', nls.localize('view', "View"));
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenDebugConsoleAction, OpenDebugConsoleAction.ID, OpenDebugConsoleAction.LABEL, openPanelKb), 'View: Debug Console', nls.localize('view', "View"));
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenDebugViewletAction, OpenDebugViewletAction.ID, OpenDebugViewletAction.LABEL, openViewletKb), 'View: Show Run and Debug', nls.localize('view', "View"));
|
||||
|
||||
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugToolBar, LifecyclePhase.Restored);
|
||||
@@ -173,7 +173,7 @@ Registry.as<IQuickAccessRegistry>(QuickAccessExtensions.Quickaccess).registerQui
|
||||
prefix: StartDebugQuickAccessProvider.PREFIX,
|
||||
contextKey: 'inLaunchConfigurationsPicker',
|
||||
placeholder: nls.localize('startDebugPlaceholder', "Type the name of a launch configuration to run."),
|
||||
helpEntries: [{ description: nls.localize('startDebugHelp', "Start Debug Configurations"), needsEditor: false }]
|
||||
helpEntries: [{ description: nls.localize('startDebuggingHelp', "Start Debugging"), needsEditor: false }]
|
||||
});
|
||||
|
||||
// register service
|
||||
@@ -363,7 +363,7 @@ registerEditorContribution(BREAKPOINT_EDITOR_CONTRIBUTION_ID, BreakpointEditorCo
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
|
||||
group: '4_panels',
|
||||
command: {
|
||||
id: OpenDebugPanelAction.ID,
|
||||
id: OpenDebugConsoleAction.ID,
|
||||
title: nls.localize({ key: 'miToggleDebugConsole', comment: ['&& denotes a mnemonic'] }, "De&&bug Console")
|
||||
},
|
||||
order: 2
|
||||
|
||||
@@ -346,7 +346,7 @@ export class ConfigurationManager implements IConfigurationManager {
|
||||
private setCompoundSchemaValues(): void {
|
||||
const compoundConfigurationsSchema = (<IJSONSchema>launchSchema.properties!['compounds'].items).properties!['configurations'];
|
||||
const launchNames = this.launches.map(l =>
|
||||
l.getConfigurationNames(false)).reduce((first, second) => first.concat(second), []);
|
||||
l.getConfigurationNames(true)).reduce((first, second) => first.concat(second), []);
|
||||
(<IJSONSchema>compoundConfigurationsSchema.items).oneOf![0].enum = launchNames;
|
||||
(<IJSONSchema>compoundConfigurationsSchema.items).oneOf![1].properties!.name.enum = launchNames;
|
||||
|
||||
@@ -523,7 +523,7 @@ abstract class AbstractLaunch {
|
||||
return config.compounds.filter(compound => compound.name === name).pop();
|
||||
}
|
||||
|
||||
getConfigurationNames(includeCompounds = true): string[] {
|
||||
getConfigurationNames(ignoreCompoundsAndPresentation = false): string[] {
|
||||
const config = this.getConfig();
|
||||
if (!config || (!Array.isArray(config.configurations) && !Array.isArray(config.compounds))) {
|
||||
return [];
|
||||
@@ -532,12 +532,14 @@ abstract class AbstractLaunch {
|
||||
if (config.configurations) {
|
||||
configurations.push(...config.configurations.filter(cfg => cfg && typeof cfg.name === 'string'));
|
||||
}
|
||||
if (includeCompounds && config.compounds) {
|
||||
if (config.compounds) {
|
||||
configurations.push(...config.compounds.filter(compound => typeof compound.name === 'string' && compound.configurations && compound.configurations.length));
|
||||
}
|
||||
|
||||
if (ignoreCompoundsAndPresentation) {
|
||||
return configurations.map(c => c.name);
|
||||
}
|
||||
|
||||
if (config.compounds) {
|
||||
configurations.push(...config.compounds.filter(compound => typeof compound.name === 'string' && compound.configurations && compound.configurations.length));
|
||||
}
|
||||
return getVisibleAndSorted(configurations).map(c => c.name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,17 +43,26 @@ export class DebugProgressContribution implements IWorkbenchContribution {
|
||||
source,
|
||||
delay: 500
|
||||
}, progressStep => {
|
||||
let increment = 0;
|
||||
let total = 0;
|
||||
const reportProgress = (progress: { message?: string, percentage?: number }) => {
|
||||
let increment = undefined;
|
||||
if (typeof progress.percentage === 'number') {
|
||||
increment = progress.percentage - total;
|
||||
total += increment;
|
||||
}
|
||||
progressStep.report({
|
||||
message: progress.message,
|
||||
increment,
|
||||
total: typeof increment === 'number' ? 100 : undefined,
|
||||
});
|
||||
};
|
||||
|
||||
if (progressStartEvent.body.message) {
|
||||
reportProgress(progressStartEvent.body);
|
||||
}
|
||||
const progressUpdateListener = session.onDidProgressUpdate(e => {
|
||||
if (e.body.progressId === progressStartEvent.body.progressId) {
|
||||
if (typeof e.body.percentage === 'number') {
|
||||
increment = e.body.percentage - increment;
|
||||
}
|
||||
progressStep.report({
|
||||
message: e.body.message,
|
||||
increment: typeof e.body.percentage === 'number' ? increment : undefined,
|
||||
total: typeof e.body.percentage === 'number' ? 100 : undefined,
|
||||
});
|
||||
reportProgress(e.body);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -24,7 +24,11 @@ export class StartDebugQuickAccessProvider extends PickerQuickAccessProvider<IPi
|
||||
@ICommandService private readonly commandService: ICommandService,
|
||||
@INotificationService private readonly notificationService: INotificationService
|
||||
) {
|
||||
super(StartDebugQuickAccessProvider.PREFIX);
|
||||
super(StartDebugQuickAccessProvider.PREFIX, {
|
||||
noResultsPick: {
|
||||
label: localize('noDebugResults', "No matching launch configurations")
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected getPicks(filter: string): (IQuickPickSeparator | IPickerQuickAccessItem)[] {
|
||||
@@ -47,7 +51,6 @@ export class StartDebugQuickAccessProvider extends PickerQuickAccessProvider<IPi
|
||||
// Launch entry
|
||||
picks.push({
|
||||
label: config.name,
|
||||
ariaLabel: localize('entryAriaLabel', "{0}, debug picker", config.name),
|
||||
description: this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE ? config.launch.name : '',
|
||||
highlights: { label: highlights },
|
||||
buttons: [{
|
||||
@@ -89,7 +92,6 @@ export class StartDebugQuickAccessProvider extends PickerQuickAccessProvider<IPi
|
||||
// Add Config entry
|
||||
picks.push({
|
||||
label,
|
||||
ariaLabel: localize('entryAriaLabel', "{0}, debug picker", label),
|
||||
description: this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE ? launch.name : '',
|
||||
highlights: { label: withNullAsUndefined(matchesFuzzy(filter, label, true)) },
|
||||
accept: () => this.commandService.executeCommand('debug.addConfiguration', launch.uri.toString())
|
||||
|
||||
@@ -34,6 +34,7 @@ import { distinct } from 'vs/base/common/arrays';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { localize } from 'vs/nls';
|
||||
import { canceled } from 'vs/base/common/errors';
|
||||
|
||||
export class DebugSession implements IDebugSession {
|
||||
|
||||
@@ -250,6 +251,9 @@ export class DebugSession implements IDebugSession {
|
||||
if (!this.raw) {
|
||||
throw new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'launch or attach'));
|
||||
}
|
||||
if (this.parentSession && this.parentSession.state === State.Inactive) {
|
||||
throw canceled();
|
||||
}
|
||||
|
||||
// __sessionID only used for EH debugging (but we add it always for now...)
|
||||
config.__sessionId = this.getId();
|
||||
|
||||
@@ -8,7 +8,7 @@ import * as nls from 'vs/nls';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { IDebugService, VIEWLET_ID, State, BREAKPOINTS_VIEW_ID, IDebugConfiguration, DEBUG_PANEL_ID, CONTEXT_DEBUG_UX, CONTEXT_DEBUG_UX_KEY } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { IDebugService, VIEWLET_ID, State, BREAKPOINTS_VIEW_ID, IDebugConfiguration, CONTEXT_DEBUG_UX, CONTEXT_DEBUG_UX_KEY, REPL_VIEW_ID } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { StartAction, ConfigureAction, SelectAndStartAction, FocusSessionAction } from 'vs/workbench/contrib/debug/browser/debugActions';
|
||||
import { StartDebugActionViewItem, FocusSessionActionViewItem } from 'vs/workbench/contrib/debug/browser/debugActionViewItems';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
@@ -30,10 +30,9 @@ import { IMenu, MenuId, IMenuService, MenuItemAction } from 'vs/platform/actions
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { MenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { TogglePanelAction } from 'vs/workbench/browser/panel';
|
||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { IViewDescriptorService } from 'vs/workbench/common/views';
|
||||
import { IViewDescriptorService, IViewsService } from 'vs/workbench/common/views';
|
||||
import { WelcomeView } from 'vs/workbench/contrib/debug/browser/welcomeView';
|
||||
import { ToggleViewAction } from 'vs/workbench/browser/actions/layoutActions';
|
||||
|
||||
export class DebugViewPaneContainer extends ViewPaneContainer {
|
||||
|
||||
@@ -107,8 +106,8 @@ export class DebugViewPaneContainer extends ViewPaneContainer {
|
||||
}
|
||||
|
||||
@memoize
|
||||
private get toggleReplAction(): OpenDebugPanelAction {
|
||||
return this._register(this.instantiationService.createInstance(OpenDebugPanelAction, OpenDebugPanelAction.ID, OpenDebugPanelAction.LABEL));
|
||||
private get toggleReplAction(): OpenDebugConsoleAction {
|
||||
return this._register(this.instantiationService.createInstance(OpenDebugConsoleAction, OpenDebugConsoleAction.ID, OpenDebugConsoleAction.LABEL));
|
||||
}
|
||||
|
||||
@memoize
|
||||
@@ -231,16 +230,18 @@ export class DebugViewPaneContainer extends ViewPaneContainer {
|
||||
}
|
||||
}
|
||||
|
||||
export class OpenDebugPanelAction extends TogglePanelAction {
|
||||
export class OpenDebugConsoleAction extends ToggleViewAction {
|
||||
public static readonly ID = 'workbench.debug.action.toggleRepl';
|
||||
public static readonly LABEL = nls.localize('toggleDebugPanel', "Debug Console");
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IPanelService panelService: IPanelService,
|
||||
@IViewsService viewsService: IViewsService,
|
||||
@IViewDescriptorService viewDescriptorService: IViewDescriptorService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService
|
||||
) {
|
||||
super(id, label, DEBUG_PANEL_ID, panelService, layoutService, 'codicon-repl');
|
||||
super(id, label, REPL_VIEW_ID, viewsService, viewDescriptorService, contextKeyService, layoutService, 'codicon-debug-console');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,6 +75,11 @@ export class WelcomeView extends ViewPane {
|
||||
};
|
||||
this._register(editorService.onDidActiveEditorChange(setContextKey));
|
||||
this._register(this.debugService.getConfigurationManager().onDidRegisterDebugger(setContextKey));
|
||||
this._register(this.onDidChangeBodyVisibility(visible => {
|
||||
if (visible) {
|
||||
setContextKey();
|
||||
}
|
||||
}));
|
||||
setContextKey();
|
||||
|
||||
const debugKeybinding = this.keybindingService.lookupKeybinding(StartAction.ID);
|
||||
|
||||
@@ -710,7 +710,7 @@ export interface ILaunch {
|
||||
* Returns the names of all configurations and compounds.
|
||||
* Ignores configurations which are invalid.
|
||||
*/
|
||||
getConfigurationNames(includeCompounds?: boolean): string[];
|
||||
getConfigurationNames(ignoreCompoundsAndPresentation?: boolean): string[];
|
||||
|
||||
/**
|
||||
* Opens the launch.json file. Creates if it does not exist.
|
||||
|
||||
@@ -862,7 +862,15 @@ export class ExtensionEditor extends BaseEditor {
|
||||
extensionPackReadme.style.maxWidth = '882px';
|
||||
|
||||
const extensionPack = append(extensionPackReadme, $('div', { class: 'extension-pack' }));
|
||||
toggleClass(extensionPackReadme, 'narrow', manifest.extensionPack!.length <= 2);
|
||||
if (manifest.extensionPack!.length <= 3) {
|
||||
addClass(extensionPackReadme, 'one-row');
|
||||
} else if (manifest.extensionPack!.length <= 6) {
|
||||
addClass(extensionPackReadme, 'two-rows');
|
||||
} else if (manifest.extensionPack!.length <= 9) {
|
||||
addClass(extensionPackReadme, 'three-rows');
|
||||
} else {
|
||||
addClass(extensionPackReadme, 'more-rows');
|
||||
}
|
||||
|
||||
const extensionPackHeader = append(extensionPack, $('div.header'));
|
||||
extensionPackHeader.textContent = localize('extension pack', "Extension Pack ({0})", manifest.extensionPack!.length);
|
||||
|
||||
@@ -2605,7 +2605,7 @@ export class MaliciousStatusLabelAction extends ExtensionAction {
|
||||
|
||||
export class SyncIgnoredIconAction extends ExtensionAction {
|
||||
|
||||
private static readonly ENABLE_CLASS = `${ExtensionAction.ICON_ACTION_CLASS} codicon-eye-closed`;
|
||||
private static readonly ENABLE_CLASS = `${ExtensionAction.ICON_ACTION_CLASS} codicon-sync-ignored`;
|
||||
private static readonly DISABLE_CLASS = `${SyncIgnoredIconAction.ENABLE_CLASS} hide`;
|
||||
|
||||
constructor(
|
||||
|
||||
@@ -54,7 +54,7 @@ export class ExtensionsGridView extends Disposable {
|
||||
private renderExtension(extension: IExtension, index: number): void {
|
||||
const extensionContainer = dom.append(this.element, dom.$('.extension-container'));
|
||||
extensionContainer.style.height = `${this.delegate.getHeight()}px`;
|
||||
extensionContainer.style.width = `350px`;
|
||||
extensionContainer.style.width = `275px`;
|
||||
extensionContainer.setAttribute('tabindex', '0');
|
||||
|
||||
const template = this.renderer.renderTemplate(extensionContainer);
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
|
||||
.monaco-action-bar .action-item.disabled .action-label.extension-action {
|
||||
opacity: 1;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.monaco-action-bar .action-item.disabled .action-label.extension-action.text {
|
||||
|
||||
@@ -277,16 +277,36 @@
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.extension-editor > .body > .content > .extension-pack-readme.narrow > .extension-pack {
|
||||
.extension-editor > .body > .content > .extension-pack-readme.one-row > .extension-pack {
|
||||
height: 142px;
|
||||
}
|
||||
|
||||
.extension-editor > .body > .content > .extension-pack-readme > .readme-content {
|
||||
.extension-editor > .body > .content > .extension-pack-readme.two-rows > .extension-pack {
|
||||
height: 224px;
|
||||
}
|
||||
|
||||
.extension-editor > .body > .content > .extension-pack-readme.three-rows > .extension-pack {
|
||||
height: 306px;
|
||||
}
|
||||
|
||||
.extension-editor > .body > .content > .extension-pack-readme.more-rows > .extension-pack {
|
||||
height: 326px;
|
||||
}
|
||||
|
||||
.extension-editor > .body > .content > .extension-pack-readme.one-row > .readme-content {
|
||||
height: calc(100% - 142px);
|
||||
}
|
||||
|
||||
.extension-editor > .body > .content > .extension-pack-readme.two-rows > .readme-content {
|
||||
height: calc(100% - 224px);
|
||||
}
|
||||
|
||||
.extension-editor > .body > .content > .extension-pack-readme.narrow > .readme-content {
|
||||
height: calc(100% - 142px);
|
||||
.extension-editor > .body > .content > .extension-pack-readme.three-rows > .readme-content {
|
||||
height: calc(100% - 306px);
|
||||
}
|
||||
|
||||
.extension-editor > .body > .content > .extension-pack-readme.more-rows > .readme-content {
|
||||
height: calc(100% - 326px);
|
||||
}
|
||||
|
||||
.extension-editor > .body > .content > .extension-pack-readme > .extension-pack > .header,
|
||||
@@ -483,6 +503,12 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.extension-editor .extensions-grid-view .extension-list-item > .details > .header-container > .header > .version,
|
||||
.extension-editor .extensions-grid-view .extension-list-item > .details > .header-container > .header > .ratings,
|
||||
.extension-editor .extensions-grid-view .extension-list-item > .details > .header-container > .header > .install-count {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.extension-editor .extensions-grid-view > .extension-container:focus > .extension-list-item > .details .header > .name,
|
||||
.extension-editor .extensions-grid-view > .extension-container:focus > .extension-list-item > .details .header > .name:hover {
|
||||
text-decoration: underline;
|
||||
|
||||
@@ -89,8 +89,4 @@ export class EmptyView extends ViewPane {
|
||||
this.updateTitle(this.title);
|
||||
}
|
||||
}
|
||||
|
||||
layoutBody(_size: number): void {
|
||||
// no-op
|
||||
}
|
||||
}
|
||||
|
||||
@@ -499,7 +499,13 @@ export class ExplorerView extends ViewPane {
|
||||
|
||||
const actions: IAction[] = [];
|
||||
const roots = this.explorerService.roots; // If the click is outside of the elements pass the root resource if there is only one root. If there are multiple roots pass empty object.
|
||||
const arg = stat instanceof ExplorerItem ? stat.resource : roots.length === 1 ? roots[0].resource : {};
|
||||
let arg: URI | {};
|
||||
if (stat instanceof ExplorerItem) {
|
||||
const compressedController = this.renderer.getCompressedNavigationController(stat);
|
||||
arg = compressedController ? compressedController.current.resource : stat.resource;
|
||||
} else {
|
||||
arg = roots.length === 1 ? roots[0].resource : {};
|
||||
}
|
||||
disposables.add(createAndFillInContextMenuActions(this.contributedContextMenu, { arg, shouldForwardArgs: true }, actions, this.contextMenuService));
|
||||
|
||||
this.contextMenuService.showContextMenu({
|
||||
|
||||
@@ -4,9 +4,8 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/workbench/contrib/markers/browser/markersFileDecorations';
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
|
||||
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
@@ -14,7 +13,6 @@ import { localize } from 'vs/nls';
|
||||
import { Marker, RelatedInformation } from 'vs/workbench/contrib/markers/browser/markersModel';
|
||||
import { MarkersView } from 'vs/workbench/contrib/markers/browser/markersView';
|
||||
import { MenuId, MenuRegistry, SyncActionDescriptor, registerAction2, Action2 } from 'vs/platform/actions/common/actions';
|
||||
import { TogglePanelAction } from 'vs/workbench/browser/panel';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { ShowProblemsPanelAction } from 'vs/workbench/contrib/markers/browser/markersViewActions';
|
||||
import Constants from 'vs/workbench/contrib/markers/browser/constants';
|
||||
@@ -28,11 +26,12 @@ import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment, IStatusbarEntry } from 'vs/workbench/services/statusbar/common/statusbar';
|
||||
import { IMarkerService, MarkerStatistics } from 'vs/platform/markers/common/markers';
|
||||
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
import { ViewContainer, IViewContainersRegistry, Extensions as ViewContainerExtensions, ViewContainerLocation, IViewsRegistry, IViewsService, getVisbileViewContextKey, FocusedViewContext } from 'vs/workbench/common/views';
|
||||
import { ViewContainer, IViewContainersRegistry, Extensions as ViewContainerExtensions, ViewContainerLocation, IViewsRegistry, IViewsService, getVisbileViewContextKey, FocusedViewContext, IViewDescriptorService } from 'vs/workbench/common/views';
|
||||
import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer';
|
||||
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import type { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ToggleViewAction } from 'vs/workbench/browser/actions/layoutActions';
|
||||
|
||||
registerSingleton(IMarkersWorkbenchService, MarkersWorkbenchService, false);
|
||||
|
||||
@@ -94,16 +93,18 @@ Registry.as<IConfigurationRegistry>(Extensions.Configuration).registerConfigurat
|
||||
}
|
||||
});
|
||||
|
||||
class ToggleMarkersPanelAction extends TogglePanelAction {
|
||||
class ToggleMarkersPanelAction extends ToggleViewAction {
|
||||
|
||||
public static readonly ID = 'workbench.actions.view.problems';
|
||||
public static readonly LABEL = Messages.MARKERS_PANEL_TOGGLE_LABEL;
|
||||
|
||||
constructor(id: string, label: string,
|
||||
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
|
||||
@IPanelService panelService: IPanelService
|
||||
@IViewsService viewsService: IViewsService,
|
||||
@IViewDescriptorService viewDescriptorService: IViewDescriptorService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService
|
||||
) {
|
||||
super(id, label, Constants.MARKERS_CONTAINER_ID, panelService, layoutService);
|
||||
super(id, label, Constants.MARKERS_VIEW_ID, viewsService, viewDescriptorService, contextKeyService, layoutService);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,26 +3,6 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export const INSERT_CODE_CELL_ABOVE_COMMAND_ID = 'workbench.notebook.code.insertCellAbove';
|
||||
export const INSERT_CODE_CELL_BELOW_COMMAND_ID = 'workbench.notebook.code.insertCellBelow';
|
||||
export const INSERT_MARKDOWN_CELL_ABOVE_COMMAND_ID = 'workbench.notebook.markdown.insertCellAbove';
|
||||
export const INSERT_MARKDOWN_CELL_BELOW_COMMAND_ID = 'workbench.notebook.markdown.insertCellBelow';
|
||||
|
||||
export const EDIT_CELL_COMMAND_ID = 'workbench.notebook.cell.edit';
|
||||
export const SAVE_CELL_COMMAND_ID = 'workbench.notebook.cell.save';
|
||||
export const DELETE_CELL_COMMAND_ID = 'workbench.notebook.cell.delete';
|
||||
|
||||
export const MOVE_CELL_UP_COMMAND_ID = 'workbench.notebook.cell.moveUp';
|
||||
export const MOVE_CELL_DOWN_COMMAND_ID = 'workbench.notebook.cell.moveDown';
|
||||
export const COPY_CELL_UP_COMMAND_ID = 'workbench.notebook.cell.copyUp';
|
||||
export const COPY_CELL_DOWN_COMMAND_ID = 'workbench.notebook.cell.copyDown';
|
||||
|
||||
export const EXECUTE_CELL_COMMAND_ID = 'workbench.notebook.cell.execute';
|
||||
export const EXECUTE_ACTIVE_CELL_COMMAND_ID = 'workbench.notebook.cell.executeActive';
|
||||
export const CANCEL_CELL_COMMAND_ID = 'workbench.notebook.cell.cancelExecution';
|
||||
export const EXECUTE_NOTEBOOK_COMMAND_ID = 'workbench.notebook.executeNotebook';
|
||||
export const CANCEL_NOTEBOOK_COMMAND_ID = 'workbench.notebook.cancelExecution';
|
||||
|
||||
// Cell sizing related
|
||||
export const CELL_MARGIN = 20;
|
||||
export const CELL_RUN_GUTTER = 32; // TODO should be dynamic based on execution order width, and runnable enablement
|
||||
|
||||
@@ -12,11 +12,33 @@ import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/commo
|
||||
import { InputFocusedContext, InputFocusedContextKey, IsDevelopmentContext } from 'vs/platform/contextkey/common/contextkeys';
|
||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { CANCEL_CELL_COMMAND_ID, CANCEL_NOTEBOOK_COMMAND_ID, COPY_CELL_DOWN_COMMAND_ID, COPY_CELL_UP_COMMAND_ID, DELETE_CELL_COMMAND_ID, EDIT_CELL_COMMAND_ID, EXECUTE_ACTIVE_CELL_COMMAND_ID, EXECUTE_CELL_COMMAND_ID, EXECUTE_NOTEBOOK_COMMAND_ID, INSERT_CODE_CELL_ABOVE_COMMAND_ID, INSERT_CODE_CELL_BELOW_COMMAND_ID, INSERT_MARKDOWN_CELL_ABOVE_COMMAND_ID, INSERT_MARKDOWN_CELL_BELOW_COMMAND_ID, MOVE_CELL_DOWN_COMMAND_ID, MOVE_CELL_UP_COMMAND_ID, NOTEBOOK_CELL_EDITABLE_CONTEXT_KEY, NOTEBOOK_CELL_MARKDOWN_EDIT_MODE_CONTEXT_KEY, NOTEBOOK_CELL_TYPE_CONTEXT_KEY, NOTEBOOK_EDITABLE_CONTEXT_KEY, NOTEBOOK_EXECUTING_KEY, SAVE_CELL_COMMAND_ID } from 'vs/workbench/contrib/notebook/browser/constants';
|
||||
import { NOTEBOOK_CELL_EDITABLE_CONTEXT_KEY, NOTEBOOK_CELL_MARKDOWN_EDIT_MODE_CONTEXT_KEY, NOTEBOOK_CELL_TYPE_CONTEXT_KEY, NOTEBOOK_EDITABLE_CONTEXT_KEY, NOTEBOOK_EXECUTING_KEY } from 'vs/workbench/contrib/notebook/browser/constants';
|
||||
import { BaseCellRenderTemplate, CellEditState, CellRunState, ICellViewModel, INotebookEditor, KEYBINDING_CONTEXT_NOTEBOOK_FIND_WIDGET_FOCUSED, NOTEBOOK_EDITOR_EXECUTING_NOTEBOOK, NOTEBOOK_EDITOR_FOCUSED } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||
import { CellKind, NOTEBOOK_EDITOR_CURSOR_BOUNDARY } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
|
||||
const INSERT_CODE_CELL_ABOVE_COMMAND_ID = 'workbench.notebook.code.insertCellAbove';
|
||||
const INSERT_CODE_CELL_BELOW_COMMAND_ID = 'workbench.notebook.code.insertCellBelow';
|
||||
const INSERT_MARKDOWN_CELL_ABOVE_COMMAND_ID = 'workbench.notebook.markdown.insertCellAbove';
|
||||
const INSERT_MARKDOWN_CELL_BELOW_COMMAND_ID = 'workbench.notebook.markdown.insertCellBelow';
|
||||
|
||||
const EDIT_CELL_COMMAND_ID = 'workbench.notebook.cell.edit';
|
||||
const SAVE_CELL_COMMAND_ID = 'workbench.notebook.cell.save';
|
||||
const DELETE_CELL_COMMAND_ID = 'workbench.notebook.cell.delete';
|
||||
|
||||
const MOVE_CELL_UP_COMMAND_ID = 'workbench.notebook.cell.moveUp';
|
||||
const MOVE_CELL_DOWN_COMMAND_ID = 'workbench.notebook.cell.moveDown';
|
||||
const COPY_CELL_UP_COMMAND_ID = 'workbench.notebook.cell.copyUp';
|
||||
const COPY_CELL_DOWN_COMMAND_ID = 'workbench.notebook.cell.copyDown';
|
||||
|
||||
const EXECUTE_CELL_COMMAND_ID = 'workbench.notebook.cell.execute';
|
||||
const EXECUTE_ACTIVE_CELL_COMMAND_ID = 'workbench.notebook.cell.executeActive';
|
||||
const CANCEL_CELL_COMMAND_ID = 'workbench.notebook.cell.cancelExecution';
|
||||
const EXECUTE_NOTEBOOK_COMMAND_ID = 'workbench.notebook.executeNotebook';
|
||||
const CANCEL_NOTEBOOK_COMMAND_ID = 'workbench.notebook.cancelExecution';
|
||||
|
||||
const NOTEBOOK_ACTIONS_CATEGORY = localize('notebookActions.category', "Notebook");
|
||||
|
||||
const enum CellToolbarOrder {
|
||||
MoveCellUp,
|
||||
MoveCellDown,
|
||||
@@ -30,7 +52,8 @@ registerAction2(class extends Action2 {
|
||||
constructor() {
|
||||
super({
|
||||
id: EXECUTE_CELL_COMMAND_ID,
|
||||
title: localize('notebookActions.execute', "Execute Notebook Cell"),
|
||||
category: NOTEBOOK_ACTIONS_CATEGORY,
|
||||
title: localize('notebookActions.execute', "Execute Cell"),
|
||||
keybinding: {
|
||||
when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, InputFocusedContext),
|
||||
primary: KeyMod.WinCtrl | KeyCode.Enter,
|
||||
@@ -39,7 +62,8 @@ registerAction2(class extends Action2 {
|
||||
},
|
||||
weight: KeybindingWeight.WorkbenchContrib
|
||||
},
|
||||
icon: { id: 'codicon/play' }
|
||||
icon: { id: 'codicon/play' },
|
||||
f1: true
|
||||
});
|
||||
}
|
||||
|
||||
@@ -59,8 +83,8 @@ registerAction2(class extends Action2 {
|
||||
constructor() {
|
||||
super({
|
||||
id: CANCEL_CELL_COMMAND_ID,
|
||||
title: localize('notebookActions.cancel', "Cancel Execution"),
|
||||
icon: { id: 'codicon/stop' }
|
||||
title: localize('notebookActions.cancel', "Stop Execution"),
|
||||
icon: { id: 'codicon/primitive-square' }
|
||||
});
|
||||
}
|
||||
|
||||
@@ -103,7 +127,7 @@ export class CancelCellAction extends MenuItemAction {
|
||||
{
|
||||
id: CANCEL_CELL_COMMAND_ID,
|
||||
title: localize('notebookActions.CancelCell', "Cancel Execution"),
|
||||
icon: { id: 'codicon/stop' }
|
||||
icon: { id: 'codicon/primitive-square' }
|
||||
},
|
||||
undefined,
|
||||
{ shouldForwardArgs: true },
|
||||
@@ -331,8 +355,8 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, {
|
||||
MenuRegistry.appendMenuItem(MenuId.EditorTitle, {
|
||||
command: {
|
||||
id: CANCEL_NOTEBOOK_COMMAND_ID,
|
||||
title: localize('notebookActions.menu.cancelNotebook', "Cancel Notebook Execution"),
|
||||
icon: { id: 'codicon/stop' }
|
||||
title: localize('notebookActions.menu.cancelNotebook', "Stop Notebook Execution"),
|
||||
icon: { id: 'codicon/primitive-square' }
|
||||
},
|
||||
order: -1,
|
||||
group: 'navigation',
|
||||
@@ -346,7 +370,7 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, {
|
||||
title: localize('notebookActions.menu.execute', "Execute Notebook Cell"),
|
||||
icon: { id: 'codicon/run' }
|
||||
},
|
||||
order: -1,
|
||||
order: 0,
|
||||
group: 'navigation',
|
||||
when: NOTEBOOK_EDITOR_FOCUSED
|
||||
});
|
||||
@@ -387,7 +411,7 @@ registerAction2(class extends Action2 {
|
||||
}
|
||||
});
|
||||
|
||||
function getActiveNotebookEditor(editorService: IEditorService): INotebookEditor | undefined {
|
||||
export function getActiveNotebookEditor(editorService: IEditorService): INotebookEditor | undefined {
|
||||
// TODO can `isNotebookEditor` be on INotebookEditor to avoid a circular dependency?
|
||||
const activeEditorPane = editorService.activeEditorPane as any | undefined;
|
||||
return activeEditorPane?.isNotebookEditor ? activeEditorPane : undefined;
|
||||
@@ -531,6 +555,7 @@ registerAction2(class extends InsertCellCommand {
|
||||
{
|
||||
id: INSERT_CODE_CELL_BELOW_COMMAND_ID,
|
||||
title: localize('notebookActions.insertCodeCellBelow', "Insert Code Cell Below"),
|
||||
category: NOTEBOOK_ACTIONS_CATEGORY,
|
||||
icon: { id: 'codicon/add' },
|
||||
menu: {
|
||||
id: MenuId.NotebookCellTitle,
|
||||
@@ -541,7 +566,8 @@ registerAction2(class extends InsertCellCommand {
|
||||
icon: { id: 'codicon/add' },
|
||||
},
|
||||
when: ContextKeyExpr.equals(NOTEBOOK_EDITABLE_CONTEXT_KEY, true)
|
||||
}
|
||||
},
|
||||
f1: true
|
||||
},
|
||||
CellKind.Code,
|
||||
'below');
|
||||
@@ -661,12 +687,14 @@ registerAction2(class extends Action2 {
|
||||
{
|
||||
id: DELETE_CELL_COMMAND_ID,
|
||||
title: localize('notebookActions.deleteCell', "Delete Cell"),
|
||||
category: NOTEBOOK_ACTIONS_CATEGORY,
|
||||
menu: {
|
||||
id: MenuId.NotebookCellTitle,
|
||||
order: CellToolbarOrder.DeleteCell,
|
||||
when: ContextKeyExpr.equals(NOTEBOOK_EDITABLE_CONTEXT_KEY, true)
|
||||
},
|
||||
icon: { id: 'codicon/trash' }
|
||||
icon: { id: 'codicon/trash' },
|
||||
f1: true
|
||||
});
|
||||
}
|
||||
|
||||
@@ -700,6 +728,7 @@ registerAction2(class extends Action2 {
|
||||
{
|
||||
id: MOVE_CELL_UP_COMMAND_ID,
|
||||
title: localize('notebookActions.moveCellUp', "Move Cell Up"),
|
||||
category: NOTEBOOK_ACTIONS_CATEGORY,
|
||||
icon: { id: 'codicon/arrow-up' },
|
||||
menu: {
|
||||
id: MenuId.NotebookCellTitle,
|
||||
@@ -711,6 +740,7 @@ registerAction2(class extends Action2 {
|
||||
},
|
||||
when: ContextKeyExpr.equals(NOTEBOOK_EDITABLE_CONTEXT_KEY, true)
|
||||
},
|
||||
f1: true
|
||||
});
|
||||
}
|
||||
|
||||
@@ -732,6 +762,7 @@ registerAction2(class extends Action2 {
|
||||
{
|
||||
id: MOVE_CELL_DOWN_COMMAND_ID,
|
||||
title: localize('notebookActions.moveCellDown', "Move Cell Down"),
|
||||
category: NOTEBOOK_ACTIONS_CATEGORY,
|
||||
icon: { id: 'codicon/arrow-down' },
|
||||
menu: {
|
||||
id: MenuId.NotebookCellTitle,
|
||||
@@ -743,6 +774,7 @@ registerAction2(class extends Action2 {
|
||||
},
|
||||
when: ContextKeyExpr.equals(NOTEBOOK_EDITABLE_CONTEXT_KEY, true)
|
||||
},
|
||||
f1: true
|
||||
});
|
||||
}
|
||||
|
||||
@@ -950,6 +982,7 @@ registerAction2(class extends Action2 {
|
||||
super({
|
||||
id: 'workbench.action.notebook.testResize',
|
||||
title: 'Notebook Test Cell Resize',
|
||||
category: NOTEBOOK_ACTIONS_CATEGORY,
|
||||
keybinding: {
|
||||
when: IsDevelopmentContext,
|
||||
primary: undefined,
|
||||
|
||||
@@ -27,7 +27,7 @@ import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { assertType } from 'vs/base/common/types';
|
||||
import { parse } from 'vs/base/common/marshalling';
|
||||
import { CellUri } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { CellUri, CellKind } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { ResourceMap } from 'vs/base/common/map';
|
||||
|
||||
// Output renderers registration
|
||||
@@ -177,10 +177,11 @@ class CellContentProvider implements ITextModelContentProvider {
|
||||
}
|
||||
for (let cell of notebook.cells) {
|
||||
if (cell.uri.toString() === resource.toString()) {
|
||||
let bufferFactory = cell.resolveTextBufferFactory();
|
||||
const bufferFactory = cell.resolveTextBufferFactory();
|
||||
const language = cell.cellKind === CellKind.Markdown ? this._modeService.create('markdown') : (cell.language ? this._modeService.create(cell.language) : this._modeService.createByFilepathOrFirstLine(resource, cell.source[0]));
|
||||
return this._modelService.createModel(
|
||||
bufferFactory,
|
||||
cell.language ? this._modeService.create(cell.language) : this._modeService.createByFilepathOrFirstLine(resource, cell.source[0]),
|
||||
language,
|
||||
resource
|
||||
);
|
||||
}
|
||||
|
||||
@@ -30,6 +30,11 @@
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.monaco-workbench .part.editor > .content .notebook-editor .cell-list-container .webview-cover {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell {
|
||||
display: flex;
|
||||
}
|
||||
@@ -206,6 +211,8 @@
|
||||
position: absolute;
|
||||
display: flex;
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
cursor: auto;
|
||||
}
|
||||
|
||||
.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-bottom-toolbar-container:hover {
|
||||
@@ -230,6 +237,7 @@
|
||||
align-self: center;
|
||||
align-items: center;
|
||||
white-space: pre;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-bottom-toolbar-container span.codicon {
|
||||
|
||||
@@ -18,6 +18,7 @@ import { NOTEBOOK_EDITABLE_CONTEXT_KEY, NOTEBOOK_EXECUTING_KEY } from 'vs/workbe
|
||||
import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer';
|
||||
import { CellViewModel, IModelDecorationsChangeAccessor, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
|
||||
import { CellKind, IOutput, IRenderOutput, NotebookCellMetadata, NotebookDocumentMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { Webview } from 'vs/workbench/contrib/webview/browser/webview';
|
||||
|
||||
export const KEYBINDING_CONTEXT_NOTEBOOK_FIND_WIDGET_FOCUSED = new RawContextKey<boolean>('notebookFindWidgetFocused', false);
|
||||
|
||||
@@ -59,11 +60,14 @@ export interface CodeCellLayoutChangeEvent {
|
||||
export interface MarkdownCellLayoutInfo {
|
||||
readonly fontInfo: BareFontInfo | null;
|
||||
readonly editorWidth: number;
|
||||
readonly bottomToolbarOffset: number;
|
||||
readonly totalHeight: number;
|
||||
}
|
||||
|
||||
export interface MarkdownCellLayoutChangeEvent {
|
||||
font?: BareFontInfo;
|
||||
outerWidth?: number;
|
||||
totalHeight?: number;
|
||||
}
|
||||
|
||||
export interface ICellViewModel {
|
||||
@@ -89,6 +93,8 @@ export interface INotebookEditor {
|
||||
|
||||
isNotebookEditor: boolean;
|
||||
|
||||
getInnerWebview(): Webview | undefined;
|
||||
|
||||
/**
|
||||
* Focus the notebook editor cell list
|
||||
*/
|
||||
@@ -268,6 +274,7 @@ export interface BaseCellRenderTemplate {
|
||||
toolbar: ToolBar;
|
||||
focusIndicator: HTMLElement;
|
||||
disposables: DisposableStore;
|
||||
bottomCellContainer: HTMLElement;
|
||||
toJSON: () => any;
|
||||
}
|
||||
|
||||
@@ -283,7 +290,6 @@ export interface CodeCellRenderTemplate extends BaseCellRenderTemplate {
|
||||
outputContainer: HTMLElement;
|
||||
editor: CodeEditorWidget;
|
||||
progressBar: ProgressBar;
|
||||
betweenCellContainer: HTMLElement;
|
||||
}
|
||||
|
||||
export interface IOutputTransformContribution {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { getZoomLevel } from 'vs/base/browser/browser';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent';
|
||||
import { IMouseWheelEvent, StandardMouseEvent } from 'vs/base/browser/mouseEvent';
|
||||
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { Color, RGBA } from 'vs/base/common/color';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
@@ -43,6 +43,7 @@ import { CellViewModel, IModelDecorationsChangeAccessor, INotebookEditorViewStat
|
||||
import { CellKind, CellUri, IOutput } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { getExtraColor } from 'vs/workbench/contrib/welcome/walkThrough/common/walkThroughUtils';
|
||||
import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { Webview } from 'vs/workbench/contrib/webview/browser/webview';
|
||||
|
||||
const $ = DOM.$;
|
||||
const NOTEBOOK_EDITOR_VIEW_STATE_PREFERENCE_KEY = 'NotebookEditorViewState';
|
||||
@@ -91,6 +92,7 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
|
||||
private rootElement!: HTMLElement;
|
||||
private body!: HTMLElement;
|
||||
private webview: BackLayerWebView | null = null;
|
||||
private webviewTransparentCover: HTMLElement | null = null;
|
||||
private list: NotebookCellList | undefined;
|
||||
private control: ICompositeCodeEditor | undefined;
|
||||
private renderedEditors: Map<ICellViewModel, ICodeEditor | undefined> = new Map();
|
||||
@@ -231,13 +233,36 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
|
||||
}
|
||||
}));
|
||||
this.list.rowsContainer.appendChild(this.webview.element);
|
||||
|
||||
this._register(this.list);
|
||||
|
||||
// transparent cover
|
||||
this.webviewTransparentCover = DOM.append(this.list.rowsContainer, $('.webview-cover'));
|
||||
this.webviewTransparentCover.style.display = 'none';
|
||||
|
||||
this._register(DOM.addStandardDisposableGenericMouseDownListner(this.rootElement, (e: StandardMouseEvent) => {
|
||||
if (DOM.hasClass(e.target, 'slider') && this.webviewTransparentCover) {
|
||||
this.webviewTransparentCover.style.display = 'block';
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(DOM.addStandardDisposableGenericMouseUpListner(this.rootElement, (e: StandardMouseEvent) => {
|
||||
if (this.webviewTransparentCover) {
|
||||
// no matter when
|
||||
this.webviewTransparentCover.style.display = 'none';
|
||||
}
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
getControl() {
|
||||
return this.control;
|
||||
}
|
||||
|
||||
getInnerWebview(): Webview | undefined {
|
||||
return this.webview?.webview;
|
||||
}
|
||||
|
||||
onHide() {
|
||||
this.editorFocus?.set(false);
|
||||
if (this.webview) {
|
||||
@@ -290,6 +315,7 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
|
||||
const cellOptions = options.cellOptions;
|
||||
const cell = this.notebookViewModel!.viewCells.find(cell => cell.uri.toString() === cellOptions.resource.toString());
|
||||
if (cell) {
|
||||
this.selectElement(cell);
|
||||
this.revealInCenterIfOutsideViewport(cell);
|
||||
const editor = this.renderedEditors.get(cell)!;
|
||||
if (editor) {
|
||||
@@ -324,6 +350,7 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
|
||||
this.webview?.clearInsets();
|
||||
this.webview?.clearPreloadsCache();
|
||||
this.findWidget.clear();
|
||||
this.list?.splice(0, this.list?.length || 0);
|
||||
}
|
||||
|
||||
private async attachModel(input: NotebookEditorInput, model: NotebookEditorModel) {
|
||||
@@ -339,14 +366,6 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
|
||||
const viewState = this.loadTextEditorViewState(input);
|
||||
this.notebookViewModel.restoreEditorViewState(viewState);
|
||||
|
||||
if (viewState?.scrollPosition !== undefined) {
|
||||
this.list!.scrollTop = viewState!.scrollPosition.top;
|
||||
this.list!.scrollLeft = viewState!.scrollPosition.left;
|
||||
} else {
|
||||
this.list!.scrollTop = 0;
|
||||
this.list!.scrollLeft = 0;
|
||||
}
|
||||
|
||||
this.localStore.add(this.eventDispatcher.onDidChangeMetadata((e) => {
|
||||
this.editorEditable?.set(e.source.editable);
|
||||
}));
|
||||
@@ -385,6 +404,7 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
|
||||
|
||||
this.localStore.add(this.list!.onWillScroll(e => {
|
||||
this.webview!.updateViewScrollTop(-e.scrollTop, []);
|
||||
this.webviewTransparentCover!.style.top = `${e.scrollTop}px`;
|
||||
}));
|
||||
|
||||
this.localStore.add(this.list!.onDidChangeContentHeight(() => {
|
||||
@@ -413,9 +433,16 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
|
||||
}
|
||||
}));
|
||||
|
||||
this.list?.splice(0, this.list?.length || 0);
|
||||
this.list?.splice(0, 0, this.notebookViewModel!.viewCells as CellViewModel[]);
|
||||
this.list?.layout();
|
||||
|
||||
if (viewState?.scrollPosition !== undefined) {
|
||||
this.list!.scrollTop = viewState!.scrollPosition.top;
|
||||
this.list!.scrollLeft = viewState!.scrollPosition.left;
|
||||
} else {
|
||||
this.list!.scrollTop = 0;
|
||||
this.list!.scrollLeft = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private saveTextEditorViewState(input: NotebookEditorInput): void {
|
||||
@@ -423,6 +450,17 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
|
||||
const state = this.notebookViewModel.saveEditorViewState();
|
||||
if (this.list) {
|
||||
state.scrollPosition = { left: this.list.scrollLeft, top: this.list.scrollTop };
|
||||
let cellHeights: { [key: number]: number } = {};
|
||||
for (let i = 0; i < this.list.length; i++) {
|
||||
const elm = this.list.element(i)!;
|
||||
if (elm.cellKind === CellKind.Code) {
|
||||
cellHeights[i] = elm.layoutInfo.totalHeight;
|
||||
} else {
|
||||
cellHeights[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
state.cellTotalHeights = cellHeights;
|
||||
}
|
||||
|
||||
this.editorMemento.saveEditorState(this.group, input.resource, state);
|
||||
@@ -444,6 +482,12 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
|
||||
DOM.size(this.body, dimension.width, dimension.height);
|
||||
this.list?.updateOptions({ additionalScrollHeight: dimension.height });
|
||||
this.list?.layout(dimension.height, dimension.width);
|
||||
|
||||
if (this.webviewTransparentCover) {
|
||||
this.webviewTransparentCover.style.height = `${dimension.height}px`;
|
||||
this.webviewTransparentCover.style.width = `${dimension.width}px`;
|
||||
}
|
||||
|
||||
this.eventDispatcher?.emit([new NotebookLayoutChangedEvent({ width: true, fontInfo: true }, this.getLayoutInfo())]);
|
||||
}
|
||||
|
||||
|
||||
@@ -123,6 +123,14 @@ export class NotebookCellList extends WorkbenchList<CellViewModel> implements ID
|
||||
return this.view.elementTop(index);
|
||||
}
|
||||
|
||||
getElementHeight(index: number): number {
|
||||
if (index < 0 || index >= this.length) {
|
||||
throw new ListError(this.listUser, `Invalid index ${index}`);
|
||||
}
|
||||
|
||||
return this.view.elementHeight(index);
|
||||
}
|
||||
|
||||
triggerScrollFromMouseWheelEvent(browserEvent: IMouseWheelEvent) {
|
||||
this.view.triggerScrollFromMouseWheelEvent(browserEvent);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IRenderOutput, CellOutputKind } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { IRenderOutput, CellOutputKind, IErrorOutput } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { registerOutputTransform } from 'vs/workbench/contrib/notebook/browser/notebookRegistry';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { RGBA, Color } from 'vs/base/common/color';
|
||||
@@ -18,7 +18,15 @@ class ErrorTransform implements IOutputTransformContribution {
|
||||
) {
|
||||
}
|
||||
|
||||
render(output: any, container: HTMLElement): IRenderOutput {
|
||||
render(output: IErrorOutput, container: HTMLElement): IRenderOutput {
|
||||
const header = document.createElement('div');
|
||||
const headerMessage = output.ename && output.evalue
|
||||
? `${output.ename}: ${output.evalue}`
|
||||
: output.ename || output.evalue;
|
||||
if (headerMessage) {
|
||||
header.innerText = headerMessage;
|
||||
container.appendChild(header);
|
||||
}
|
||||
const traceback = document.createElement('pre');
|
||||
DOM.addClasses(traceback, 'traceback');
|
||||
if (output.traceback) {
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import * as path from 'vs/base/common/path';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import * as UUID from 'vs/base/common/uuid';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||
import { INotebookService } from 'vs/workbench/contrib/notebook/browser/notebookService';
|
||||
import { IOutput } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
@@ -26,6 +26,12 @@ export interface IDimentionMessage {
|
||||
data: DOM.Dimension;
|
||||
}
|
||||
|
||||
export interface IWheelMessage {
|
||||
__vscode_notebook_message: boolean;
|
||||
type: 'did-scroll-wheel';
|
||||
payload: any;
|
||||
}
|
||||
|
||||
|
||||
export interface IScrollAckMessage {
|
||||
__vscode_notebook_message: boolean;
|
||||
@@ -73,7 +79,7 @@ export interface IUpdatePreloadResourceMessage {
|
||||
resources: string[];
|
||||
}
|
||||
|
||||
type IMessage = IDimentionMessage | IScrollAckMessage;
|
||||
type IMessage = IDimentionMessage | IScrollAckMessage | IWheelMessage;
|
||||
|
||||
let version = 0;
|
||||
export class BackLayerWebView extends Disposable {
|
||||
@@ -92,7 +98,6 @@ export class BackLayerWebView extends Disposable {
|
||||
public notebookEditor: INotebookEditor,
|
||||
@IWebviewService webviewService: IWebviewService,
|
||||
@IOpenerService openerService: IOpenerService,
|
||||
@IEnvironmentService private readonly environmentSerice: IEnvironmentService,
|
||||
@INotebookService private readonly notebookService: INotebookService,
|
||||
) {
|
||||
super();
|
||||
@@ -186,6 +191,45 @@ export class BackLayerWebView extends Disposable {
|
||||
observers.push(resizeObserver);
|
||||
}
|
||||
|
||||
function scrollWillGoToParent(event) {
|
||||
for (let node = event.target; node; node = node.parentNode) {
|
||||
if (node.id === 'container') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (event.deltaY < 0 && node.scrollTop > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (event.deltaY > 0 && node.scrollTop + node.clientHeight < node.scrollHeight) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const handleWheel = (event) => {
|
||||
if (event.defaultPrevented || scrollWillGoToParent(event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
vscode.postMessage({
|
||||
__vscode_notebook_message: true,
|
||||
type: 'did-scroll-wheel',
|
||||
payload: {
|
||||
deltaMode: event.deltaMode,
|
||||
deltaX: event.deltaX,
|
||||
deltaY: event.deltaY,
|
||||
deltaZ: event.deltaZ,
|
||||
detail: event.detail,
|
||||
type: event.type
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
window.addEventListener('wheel', handleWheel);
|
||||
|
||||
window.addEventListener('message', event => {
|
||||
let id = event.data.id;
|
||||
|
||||
@@ -276,10 +320,6 @@ export class BackLayerWebView extends Disposable {
|
||||
openerService.open(link, { fromUserGesture: true });
|
||||
}));
|
||||
|
||||
this._register(this.webview.onDidWheel(e => {
|
||||
this.notebookEditor.triggerScroll(e);
|
||||
}));
|
||||
|
||||
this._register(this.webview.onMessage((data: IMessage) => {
|
||||
if (data.__vscode_notebook_message) {
|
||||
if (data.type === 'dimension') {
|
||||
@@ -302,6 +342,8 @@ export class BackLayerWebView extends Disposable {
|
||||
// const date = new Date();
|
||||
// const top = data.data.top;
|
||||
// console.log('ack top ', top, ' version: ', data.version, ' - ', date.getMinutes() + ':' + date.getSeconds() + ':' + date.getMilliseconds());
|
||||
} else if (data.type === 'did-scroll-wheel') {
|
||||
this.notebookEditor.triggerScroll(data.payload);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -311,7 +353,8 @@ export class BackLayerWebView extends Disposable {
|
||||
}
|
||||
|
||||
private _createInset(webviewService: IWebviewService, content: string) {
|
||||
this.localResourceRootsCache = [...this.notebookService.getNotebookProviderResourceRoots(), URI.file(this.environmentSerice.appRoot)];
|
||||
const rootPath = URI.file(path.dirname(getPathFromAmdModule(require, '')));
|
||||
this.localResourceRootsCache = [...this.notebookService.getNotebookProviderResourceRoots(), rootPath];
|
||||
const webview = webviewService.createWebviewElement('' + UUID.generateUuid(), {
|
||||
enableFindWidget: false,
|
||||
}, {
|
||||
|
||||
@@ -84,6 +84,7 @@ export class CodiconActionViewItem extends ContextAwareMenuEntryActionViewItem {
|
||||
|
||||
abstract class AbstractCellRenderer {
|
||||
protected editorOptions: IEditorOptions;
|
||||
private actionRunner = new ActionRunner();
|
||||
|
||||
constructor(
|
||||
protected readonly instantiationService: IInstantiationService,
|
||||
@@ -138,6 +139,45 @@ abstract class AbstractCellRenderer {
|
||||
return toolbar;
|
||||
}
|
||||
|
||||
protected setupBetweenCellToolbarActions(element: CodeCellViewModel | MarkdownCellViewModel, templateData: BaseCellRenderTemplate, disposables: DisposableStore, context: INotebookCellActionContext): void {
|
||||
const container = templateData.bottomCellContainer;
|
||||
container.innerHTML = '';
|
||||
container.style.height = `${BOTTOM_CELL_TOOLBAR_HEIGHT}px`;
|
||||
|
||||
DOM.append(container, $('.seperator'));
|
||||
const addCodeCell = DOM.append(container, $('span.button'));
|
||||
addCodeCell.innerHTML = renderCodicons(escape(`$(add) Code `));
|
||||
const insertCellBelow = this.instantiationService.createInstance(InsertCodeCellAction);
|
||||
|
||||
disposables.add(DOM.addDisposableListener(addCodeCell, DOM.EventType.CLICK, () => {
|
||||
this.actionRunner.run(insertCellBelow, context);
|
||||
}));
|
||||
|
||||
DOM.append(container, $('.seperator-short'));
|
||||
const addMarkdownCell = DOM.append(container, $('span.button'));
|
||||
addMarkdownCell.innerHTML = renderCodicons(escape('$(add) Markdown '));
|
||||
const insertMarkdownBelow = this.instantiationService.createInstance(InsertMarkdownCellAction);
|
||||
disposables.add(DOM.addDisposableListener(addMarkdownCell, DOM.EventType.CLICK, () => {
|
||||
this.actionRunner.run(insertMarkdownBelow, context);
|
||||
}));
|
||||
|
||||
DOM.append(container, $('.seperator'));
|
||||
|
||||
if (element instanceof CodeCellViewModel) {
|
||||
const bottomToolbarOffset = element.layoutInfo.bottomToolbarOffset;
|
||||
container.style.top = `${bottomToolbarOffset}px`;
|
||||
|
||||
disposables.add(element.onDidChangeLayout(() => {
|
||||
const bottomToolbarOffset = element.layoutInfo.bottomToolbarOffset;
|
||||
container.style.top = `${bottomToolbarOffset}px`;
|
||||
}));
|
||||
} else {
|
||||
container.style.position = 'static';
|
||||
container.style.height = '22px';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected createToolbar(container: HTMLElement): ToolBar {
|
||||
const toolbar = new ToolBar(container, this.contextMenuService, {
|
||||
actionViewItemProvider: action => {
|
||||
@@ -226,6 +266,7 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR
|
||||
container.appendChild(innerContent);
|
||||
|
||||
const focusIndicator = DOM.append(container, DOM.$('.notebook-cell-focus-indicator'));
|
||||
const bottomCellContainer = DOM.append(container, $('.cell-bottom-toolbar-container'));
|
||||
|
||||
return {
|
||||
container,
|
||||
@@ -234,6 +275,7 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR
|
||||
focusIndicator,
|
||||
disposables,
|
||||
toolbar,
|
||||
bottomCellContainer: bottomCellContainer,
|
||||
toJSON: () => { return {}; }
|
||||
};
|
||||
}
|
||||
@@ -258,9 +300,16 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR
|
||||
const contextKeyService = this.contextKeyService.createScoped(templateData.container);
|
||||
contextKeyService.createKey(NOTEBOOK_CELL_TYPE_CONTEXT_KEY, 'markdown');
|
||||
contextKeyService.createKey(NOTEBOOK_VIEW_TYPE, element.viewType);
|
||||
|
||||
const cellEditableKey = contextKeyService.createKey(NOTEBOOK_CELL_EDITABLE_CONTEXT_KEY, !!(element.metadata?.editable));
|
||||
const updateForMetadata = () => {
|
||||
const metadata = element.getEvaluatedMetadata(this.notebookEditor.viewModel!.notebookDocument.metadata);
|
||||
cellEditableKey.set(!!metadata.editable);
|
||||
};
|
||||
|
||||
updateForMetadata();
|
||||
elementDisposable.add(element.onDidChangeMetadata(() => {
|
||||
cellEditableKey.set(!!element.metadata?.editable);
|
||||
updateForMetadata();
|
||||
}));
|
||||
|
||||
const editModeKey = contextKeyService.createKey(NOTEBOOK_CELL_MARKDOWN_EDIT_MODE_CONTEXT_KEY, element.editState === CellEditState.Editing);
|
||||
@@ -269,13 +318,18 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR
|
||||
}));
|
||||
|
||||
this.setupCellToolbarActions(contextKeyService, templateData, elementDisposable);
|
||||
|
||||
const toolbarContext = <INotebookCellActionContext>{
|
||||
cell: element,
|
||||
notebookEditor: this.notebookEditor,
|
||||
$mid: 12
|
||||
};
|
||||
templateData.toolbar.context = toolbarContext;
|
||||
|
||||
this.setupBetweenCellToolbarActions(element, templateData, elementDisposable, toolbarContext);
|
||||
element.totalHeight = height;
|
||||
}
|
||||
|
||||
templateData.toolbar.context = <INotebookCellActionContext>{
|
||||
cell: element,
|
||||
notebookEditor: this.notebookEditor,
|
||||
$mid: 12
|
||||
};
|
||||
}
|
||||
|
||||
disposeTemplate(templateData: MarkdownCellRenderTemplate): void {
|
||||
@@ -292,8 +346,6 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR
|
||||
export class CodeCellRenderer extends AbstractCellRenderer implements IListRenderer<CodeCellViewModel, CodeCellRenderTemplate> {
|
||||
static readonly TEMPLATE_ID = 'code_cell';
|
||||
private disposables: Map<ICellViewModel, DisposableStore> = new Map();
|
||||
private actionRunner = new ActionRunner();
|
||||
|
||||
|
||||
constructor(
|
||||
protected notebookEditor: INotebookEditor,
|
||||
@@ -322,7 +374,7 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende
|
||||
const runToolbar = this.createToolbar(runButtonContainer);
|
||||
disposables.add(runToolbar);
|
||||
|
||||
const betweenCellContainer = DOM.append(container, $('.cell-bottom-toolbar-container'));
|
||||
const bottomCellContainer = DOM.append(container, $('.cell-bottom-toolbar-container'));
|
||||
|
||||
const executionOrderLabel = DOM.append(runButtonContainer, $('div.execution-count-label'));
|
||||
|
||||
@@ -358,44 +410,11 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende
|
||||
outputContainer,
|
||||
editor,
|
||||
disposables,
|
||||
betweenCellContainer: betweenCellContainer,
|
||||
bottomCellContainer: bottomCellContainer,
|
||||
toJSON: () => { return {}; }
|
||||
};
|
||||
}
|
||||
|
||||
protected setupBetweenCellToolbarActions(element: CodeCellViewModel, templateData: CodeCellRenderTemplate, disposables: DisposableStore, context: INotebookCellActionContext): void {
|
||||
const container = templateData.betweenCellContainer;
|
||||
container.innerHTML = '';
|
||||
container.style.height = `${BOTTOM_CELL_TOOLBAR_HEIGHT}px`;
|
||||
|
||||
DOM.append(container, $('.seperator'));
|
||||
const addCodeCell = DOM.append(container, $('span.button'));
|
||||
addCodeCell.innerHTML = renderCodicons(escape(`$(add) Code `));
|
||||
const insertCellBelow = this.instantiationService.createInstance(InsertCodeCellAction);
|
||||
|
||||
disposables.add(DOM.addDisposableListener(addCodeCell, DOM.EventType.CLICK, () => {
|
||||
this.actionRunner.run(insertCellBelow, context);
|
||||
}));
|
||||
|
||||
DOM.append(container, $('.seperator-short'));
|
||||
const addMarkdownCell = DOM.append(container, $('span.button'));
|
||||
addMarkdownCell.innerHTML = renderCodicons(escape('$(add) Markdown '));
|
||||
const insertMarkdownBelow = this.instantiationService.createInstance(InsertMarkdownCellAction);
|
||||
disposables.add(DOM.addDisposableListener(addMarkdownCell, DOM.EventType.CLICK, () => {
|
||||
this.actionRunner.run(insertMarkdownBelow, context);
|
||||
}));
|
||||
|
||||
DOM.append(container, $('.seperator'));
|
||||
|
||||
const bottomToolbarOffset = element.layoutInfo.bottomToolbarOffset;
|
||||
container.style.top = `${bottomToolbarOffset}px`;
|
||||
|
||||
disposables.add(element.onDidChangeLayout(() => {
|
||||
const bottomToolbarOffset = element.layoutInfo.bottomToolbarOffset;
|
||||
container.style.top = `${bottomToolbarOffset}px`;
|
||||
}));
|
||||
}
|
||||
|
||||
private updateForRunState(element: CodeCellViewModel, templateData: CodeCellRenderTemplate, runStateKey: IContextKey<string>): void {
|
||||
runStateKey.set(CellRunState[element.runState]);
|
||||
if (element.runState === CellRunState.Running) {
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { raceCancellation } from 'vs/base/common/async';
|
||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { debounce } from 'vs/base/common/decorators';
|
||||
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import * as nls from 'vs/nls';
|
||||
@@ -45,7 +44,7 @@ export class CodeCell extends Disposable {
|
||||
height: totalHeight
|
||||
}
|
||||
);
|
||||
viewCell.editorHeight = totalHeight;
|
||||
// viewCell.editorHeight = totalHeight;
|
||||
|
||||
const cts = new CancellationTokenSource();
|
||||
this._register({ dispose() { cts.dispose(true); } });
|
||||
@@ -211,6 +210,12 @@ export class CodeCell extends Disposable {
|
||||
}));
|
||||
|
||||
if (viewCell.outputs.length > 0) {
|
||||
let layoutCache = false;
|
||||
if (this.viewCell.layoutInfo.totalHeight !== 0) {
|
||||
layoutCache = true;
|
||||
this.relayoutCell();
|
||||
}
|
||||
|
||||
this.templateData.outputContainer!.style.display = 'block';
|
||||
// there are outputs, we need to calcualte their sizes and trigger relayout
|
||||
// @todo, if there is no resizable output, we should not check their height individually, which hurts the performance
|
||||
@@ -222,9 +227,15 @@ export class CodeCell extends Disposable {
|
||||
}
|
||||
|
||||
viewCell.editorHeight = totalHeight;
|
||||
this.relayoutCell();
|
||||
if (layoutCache) {
|
||||
this.relayoutCellDebounced();
|
||||
} else {
|
||||
this.relayoutCell();
|
||||
}
|
||||
} else {
|
||||
// noop
|
||||
viewCell.editorHeight = totalHeight;
|
||||
this.relayoutCell();
|
||||
this.templateData.outputContainer!.style.display = 'none';
|
||||
}
|
||||
}
|
||||
@@ -390,12 +401,21 @@ export class CodeCell extends Disposable {
|
||||
}
|
||||
|
||||
relayoutCell() {
|
||||
if (this._timer !== null) {
|
||||
clearTimeout(this._timer);
|
||||
}
|
||||
|
||||
this.notebookEditor.layoutNotebookCell(this.viewCell, this.viewCell.layoutInfo.totalHeight);
|
||||
}
|
||||
|
||||
@debounce(500)
|
||||
private _timer: any = null;
|
||||
|
||||
relayoutCellDebounced() {
|
||||
this.notebookEditor.layoutNotebookCell(this.viewCell, this.viewCell.layoutInfo.totalHeight);
|
||||
clearTimeout(this._timer);
|
||||
this._timer = setTimeout(() => {
|
||||
this.notebookEditor.layoutNotebookCell(this.viewCell, this.viewCell.layoutInfo.totalHeight);
|
||||
this._timer = null;
|
||||
}, 500);
|
||||
}
|
||||
|
||||
dispose() {
|
||||
|
||||
@@ -101,6 +101,7 @@ export class StatefullMarkdownCell extends Disposable {
|
||||
}
|
||||
|
||||
const clientHeight = this.cellContainer.clientHeight;
|
||||
this.viewCell.totalHeight = totalHeight + 32 + clientHeight;
|
||||
notebookEditor.layoutNotebookCell(viewCell, totalHeight + 32 + clientHeight);
|
||||
this.editor.focus();
|
||||
} else {
|
||||
@@ -109,6 +110,7 @@ export class StatefullMarkdownCell extends Disposable {
|
||||
// switch from editing mode
|
||||
this.editingContainer!.style.display = 'none';
|
||||
const clientHeight = templateData.container.clientHeight;
|
||||
this.viewCell.totalHeight = clientHeight;
|
||||
notebookEditor.layoutNotebookCell(viewCell, clientHeight);
|
||||
} else {
|
||||
// first time, readonly mode
|
||||
@@ -123,6 +125,7 @@ export class StatefullMarkdownCell extends Disposable {
|
||||
|
||||
this.localDisposables.add(markdownRenderer.onDidUpdateRender(() => {
|
||||
const clientHeight = templateData.container.clientHeight;
|
||||
this.viewCell.totalHeight = clientHeight;
|
||||
notebookEditor.layoutNotebookCell(viewCell, clientHeight);
|
||||
}));
|
||||
|
||||
@@ -162,7 +165,8 @@ export class StatefullMarkdownCell extends Disposable {
|
||||
clientHeight = this.cellContainer.clientHeight;
|
||||
}
|
||||
|
||||
this.notebookEditor.layoutNotebookCell(this.viewCell, this.editor!.getContentHeight() + 32 + clientHeight);
|
||||
this.viewCell.totalHeight = this.editor!.getContentHeight() + 32 + clientHeight;
|
||||
this.notebookEditor.layoutNotebookCell(this.viewCell, this.viewCell.layoutInfo.totalHeight);
|
||||
}));
|
||||
|
||||
this.localDisposables.add(this.editor!.onDidContentSizeChange(e => {
|
||||
@@ -176,7 +180,8 @@ export class StatefullMarkdownCell extends Disposable {
|
||||
}
|
||||
);
|
||||
const clientHeight = this.cellContainer.clientHeight;
|
||||
this.notebookEditor.layoutNotebookCell(this.viewCell, e.contentHeight + 32 + clientHeight);
|
||||
this.viewCell.totalHeight = e.contentHeight + 32 + clientHeight;
|
||||
this.notebookEditor.layoutNotebookCell(this.viewCell, this.viewCell.layoutInfo.totalHeight);
|
||||
}
|
||||
}));
|
||||
|
||||
@@ -219,7 +224,8 @@ export class StatefullMarkdownCell extends Disposable {
|
||||
this.cellContainer.appendChild(renderedHTML);
|
||||
this.localDisposables.add(markdownRenderer.onDidUpdateRender(() => {
|
||||
const clientHeight = this.cellContainer.clientHeight;
|
||||
this.notebookEditor.layoutNotebookCell(this.viewCell, clientHeight);
|
||||
this.viewCell.totalHeight = clientHeight;
|
||||
this.notebookEditor.layoutNotebookCell(this.viewCell, this.viewCell.layoutInfo.totalHeight);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,7 +204,7 @@ export abstract class BaseCellViewModel extends Disposable implements ICellViewM
|
||||
return this._editorViewStates;
|
||||
}
|
||||
|
||||
restoreEditorViewState(editorViewStates: editorCommon.ICodeEditorViewState | null) {
|
||||
restoreEditorViewState(editorViewStates: editorCommon.ICodeEditorViewState | null, totalHeight?: number) {
|
||||
this._editorViewStates = editorViewStates;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import { CellEditState, ICellViewModel, CellFindMatch, CodeCellLayoutChangeEvent
|
||||
import { CellKind, ICell, NotebookCellOutputsSplice } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { BaseCellViewModel } from './baseCellViewModel';
|
||||
import { NotebookEventDispatcher } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher';
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
|
||||
export class CodeCellViewModel extends BaseCellViewModel implements ICellViewModel {
|
||||
cellKind: CellKind.Code = CellKind.Code;
|
||||
@@ -135,6 +136,22 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod
|
||||
this._onDidChangeLayout.fire(state);
|
||||
}
|
||||
|
||||
restoreEditorViewState(editorViewStates: editorCommon.ICodeEditorViewState | null, totalHeight?: number) {
|
||||
super.restoreEditorViewState(editorViewStates);
|
||||
if (totalHeight !== undefined) {
|
||||
this._layoutInfo = {
|
||||
fontInfo: this._layoutInfo.fontInfo,
|
||||
editorHeight: this._layoutInfo.editorHeight,
|
||||
editorWidth: this._layoutInfo.editorWidth,
|
||||
outputContainerOffset: this._layoutInfo.outputContainerOffset,
|
||||
outputTotalHeight: this._layoutInfo.outputTotalHeight,
|
||||
totalHeight: totalHeight,
|
||||
indicatorHeight: this._layoutInfo.indicatorHeight,
|
||||
bottomToolbarOffset: this._layoutInfo.bottomToolbarOffset
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
hasDynamicHeight() {
|
||||
if (this.selfSizeMonitoring) {
|
||||
// if there is an output rendered in the webview, it should always be false
|
||||
@@ -153,7 +170,11 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod
|
||||
}
|
||||
|
||||
getHeight(lineHeight: number) {
|
||||
return EDITOR_TOOLBAR_HEIGHT + EDITOR_TOP_MARGIN + this.lineCount * lineHeight + EDITOR_TOP_PADDING + EDITOR_BOTTOM_PADDING + BOTTOM_CELL_TOOLBAR_HEIGHT;
|
||||
if (this._layoutInfo.totalHeight === 0) {
|
||||
return EDITOR_TOOLBAR_HEIGHT + EDITOR_TOP_MARGIN + this.lineCount * lineHeight + EDITOR_TOP_PADDING + EDITOR_BOTTOM_PADDING + BOTTOM_CELL_TOOLBAR_HEIGHT;
|
||||
} else {
|
||||
return this._layoutInfo.totalHeight;
|
||||
}
|
||||
}
|
||||
|
||||
save() {
|
||||
|
||||
@@ -12,8 +12,9 @@ import { ICellViewModel, CellFindMatch, MarkdownCellLayoutInfo, MarkdownCellLayo
|
||||
import { MarkdownRenderer } from 'vs/workbench/contrib/notebook/browser/view/renderers/mdRenderer';
|
||||
import { BaseCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/baseCellViewModel';
|
||||
import { CellKind, ICell } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { CELL_MARGIN, CELL_RUN_GUTTER } from 'vs/workbench/contrib/notebook/browser/constants';
|
||||
import { CELL_MARGIN, CELL_RUN_GUTTER, BOTTOM_CELL_TOOLBAR_HEIGHT } from 'vs/workbench/contrib/notebook/browser/constants';
|
||||
import { NotebookEventDispatcher } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher';
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
|
||||
export class MarkdownCellViewModel extends BaseCellViewModel implements ICellViewModel {
|
||||
cellKind: CellKind.Markdown = CellKind.Markdown;
|
||||
@@ -28,6 +29,14 @@ export class MarkdownCellViewModel extends BaseCellViewModel implements ICellVie
|
||||
return this._layoutInfo;
|
||||
}
|
||||
|
||||
set totalHeight(newHeight: number) {
|
||||
this.layoutChange({ totalHeight: newHeight });
|
||||
}
|
||||
|
||||
get totalHeight() {
|
||||
throw new Error('MarkdownCellViewModel.totalHeight is write only');
|
||||
}
|
||||
|
||||
protected readonly _onDidChangeLayout = new Emitter<MarkdownCellLayoutChangeEvent>();
|
||||
readonly onDidChangeLayout = this._onDidChangeLayout.event;
|
||||
|
||||
@@ -43,7 +52,9 @@ export class MarkdownCellViewModel extends BaseCellViewModel implements ICellVie
|
||||
|
||||
this._layoutInfo = {
|
||||
fontInfo: initialNotebookLayoutInfo?.fontInfo || null,
|
||||
editorWidth: initialNotebookLayoutInfo?.width || 0
|
||||
editorWidth: initialNotebookLayoutInfo?.width || 0,
|
||||
bottomToolbarOffset: BOTTOM_CELL_TOOLBAR_HEIGHT,
|
||||
totalHeight: 0
|
||||
};
|
||||
|
||||
this._register(eventDispatcher.onDidChangeLayout((e) => {
|
||||
@@ -59,18 +70,36 @@ export class MarkdownCellViewModel extends BaseCellViewModel implements ICellVie
|
||||
|
||||
this._layoutInfo = {
|
||||
fontInfo: state.font || null,
|
||||
editorWidth
|
||||
editorWidth,
|
||||
bottomToolbarOffset: BOTTOM_CELL_TOOLBAR_HEIGHT,
|
||||
totalHeight: state.totalHeight === undefined ? this._layoutInfo.totalHeight : state.totalHeight
|
||||
};
|
||||
|
||||
this._onDidChangeLayout.fire(state);
|
||||
}
|
||||
|
||||
restoreEditorViewState(editorViewStates: editorCommon.ICodeEditorViewState | null, totalHeight?: number) {
|
||||
super.restoreEditorViewState(editorViewStates);
|
||||
if (totalHeight !== undefined) {
|
||||
this._layoutInfo = {
|
||||
fontInfo: this._layoutInfo.fontInfo,
|
||||
editorWidth: this._layoutInfo.editorWidth,
|
||||
bottomToolbarOffset: this._layoutInfo.bottomToolbarOffset,
|
||||
totalHeight: totalHeight
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
hasDynamicHeight() {
|
||||
return true;
|
||||
}
|
||||
|
||||
getHeight(lineHeight: number) {
|
||||
return 100;
|
||||
if (this._layoutInfo.totalHeight === 0) {
|
||||
return 100;
|
||||
} else {
|
||||
return this._layoutInfo.totalHeight;
|
||||
}
|
||||
}
|
||||
|
||||
setText(strs: string[]) {
|
||||
|
||||
@@ -26,6 +26,7 @@ import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
export interface INotebookEditorViewState {
|
||||
editingCells: { [key: number]: boolean };
|
||||
editorViewStates: { [key: number]: editorCommon.ICodeEditorViewState | null };
|
||||
cellTotalHeights?: { [key: number]: number };
|
||||
scrollPosition?: { left: number; top: number; };
|
||||
}
|
||||
|
||||
@@ -272,12 +273,13 @@ export class NotebookViewModel extends Disposable {
|
||||
return;
|
||||
}
|
||||
|
||||
this._viewCells.forEach(cell => {
|
||||
this._viewCells.forEach((cell, index) => {
|
||||
const isEditing = viewState.editingCells && viewState.editingCells[cell.handle];
|
||||
const editorViewState = viewState.editorViewStates && viewState.editorViewStates[cell.handle];
|
||||
|
||||
cell.editState = isEditing ? CellEditState.Editing : CellEditState.Preview;
|
||||
cell.restoreEditorViewState(editorViewState);
|
||||
const cellHeight = viewState.cellTotalHeights ? viewState.cellTotalHeights[index] : undefined;
|
||||
cell.restoreEditorViewState(editorViewState, cellHeight);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
import { registerAction2 } from 'vs/platform/actions/common/actions';
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import * as webviewCommands from 'vs/workbench/contrib/webview/electron-browser/webviewCommands';
|
||||
import { NotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookEditor';
|
||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ElectronWebviewBasedWebview } from 'vs/workbench/contrib/webview/electron-browser/webviewElement';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { getActiveNotebookEditor } from 'vs/workbench/contrib/notebook/browser/contrib/notebookActions';
|
||||
|
||||
function getActiveElectronBasedWebviewDelegate(accessor: ServicesAccessor): ElectronWebviewBasedWebview | undefined {
|
||||
|
||||
const editorService = accessor.get(IEditorService);
|
||||
const editor = getActiveNotebookEditor(editorService);
|
||||
|
||||
const webview = editor?.getInnerWebview();
|
||||
|
||||
if (webview && webview instanceof ElectronWebviewBasedWebview) {
|
||||
return webview;
|
||||
}
|
||||
|
||||
return undefined; // {{SQL CARBON EDIT}} struct-null-checks
|
||||
}
|
||||
|
||||
function registerNotebookCommands(editorId: string): void {
|
||||
const contextKeyExpr = ContextKeyExpr.and(ContextKeyExpr.equals('activeEditor', editorId), ContextKeyExpr.not('editorFocus') /* https://github.com/Microsoft/vscode/issues/58668 */)!;
|
||||
|
||||
// These commands are only needed on MacOS where we have to disable the menu bar commands
|
||||
if (isMacintosh) {
|
||||
registerAction2(class extends webviewCommands.CopyWebviewEditorCommand { constructor() { super(contextKeyExpr, getActiveElectronBasedWebviewDelegate); } });
|
||||
registerAction2(class extends webviewCommands.PasteWebviewEditorCommand { constructor() { super(contextKeyExpr, getActiveElectronBasedWebviewDelegate); } });
|
||||
registerAction2(class extends webviewCommands.CutWebviewEditorCommand { constructor() { super(contextKeyExpr, getActiveElectronBasedWebviewDelegate); } });
|
||||
registerAction2(class extends webviewCommands.UndoWebviewEditorCommand { constructor() { super(contextKeyExpr, getActiveElectronBasedWebviewDelegate); } });
|
||||
registerAction2(class extends webviewCommands.RedoWebviewEditorCommand { constructor() { super(contextKeyExpr, getActiveElectronBasedWebviewDelegate); } });
|
||||
}
|
||||
}
|
||||
|
||||
registerNotebookCommands(NotebookEditor.ID);
|
||||
@@ -20,6 +20,7 @@ import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
|
||||
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
|
||||
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
|
||||
import { NotebookEventDispatcher } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher';
|
||||
import { Webview } from 'vs/workbench/contrib/webview/browser/webview';
|
||||
|
||||
export class TestCell implements ICell {
|
||||
uri: URI;
|
||||
@@ -80,6 +81,9 @@ export class TestNotebookEditor implements INotebookEditor {
|
||||
|
||||
constructor(
|
||||
) { }
|
||||
getInnerWebview(): Webview | undefined {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
cancelNotebookCellExecution(cell: ICellViewModel): void {
|
||||
throw new Error('Method not implemented.');
|
||||
|
||||
@@ -51,7 +51,6 @@ import { IViewDescriptorService } from 'vs/workbench/common/views';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys';
|
||||
|
||||
class RequestState {
|
||||
|
||||
@@ -177,13 +176,6 @@ class OutlineViewState {
|
||||
private readonly _onDidChange = new Emitter<{ followCursor?: boolean, sortBy?: boolean, filterOnType?: boolean }>();
|
||||
readonly onDidChange = this._onDidChange.event;
|
||||
|
||||
constructor(
|
||||
@IStorageService private readonly _storageService: IStorageService,
|
||||
@IStorageKeysSyncRegistryService storageKeysSyncService: IStorageKeysSyncRegistryService
|
||||
) {
|
||||
storageKeysSyncService.registerStorageKey({ key: 'outline/state', version: 1 });
|
||||
}
|
||||
|
||||
set followCursor(value: boolean) {
|
||||
if (value !== this._followCursor) {
|
||||
this._followCursor = value;
|
||||
@@ -217,16 +209,16 @@ class OutlineViewState {
|
||||
return this._sortBy;
|
||||
}
|
||||
|
||||
persist(): void {
|
||||
this._storageService.store('outline/state', JSON.stringify({
|
||||
persist(storageService: IStorageService): void {
|
||||
storageService.store('outline/state', JSON.stringify({
|
||||
followCursor: this.followCursor,
|
||||
sortBy: this.sortBy,
|
||||
filterOnType: this.filterOnType,
|
||||
}), StorageScope.WORKSPACE);
|
||||
}
|
||||
|
||||
restore(): void {
|
||||
let raw = this._storageService.get('outline/state', StorageScope.WORKSPACE);
|
||||
restore(storageService: IStorageService): void {
|
||||
let raw = storageService.get('outline/state', StorageScope.WORKSPACE);
|
||||
if (!raw) {
|
||||
return;
|
||||
}
|
||||
@@ -249,7 +241,7 @@ export class OutlinePane extends ViewPane {
|
||||
private _disposables = new Array<IDisposable>();
|
||||
|
||||
private _editorDisposables = new DisposableStore();
|
||||
private _outlineViewState: OutlineViewState;
|
||||
private _outlineViewState = new OutlineViewState();
|
||||
private _requestOracle?: RequestOracle;
|
||||
private _domNode!: HTMLElement;
|
||||
private _message!: HTMLDivElement;
|
||||
@@ -270,6 +262,7 @@ export class OutlinePane extends ViewPane {
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||
@IViewDescriptorService viewDescriptorService: IViewDescriptorService,
|
||||
@IThemeService private readonly _themeService: IThemeService,
|
||||
@IStorageService private readonly _storageService: IStorageService,
|
||||
@ICodeEditorService private readonly _editorService: ICodeEditorService,
|
||||
@IMarkerDecorationsService private readonly _markerDecorationService: IMarkerDecorationsService,
|
||||
@IConfigurationService private readonly _configurationService: IConfigurationService,
|
||||
@@ -281,7 +274,7 @@ export class OutlinePane extends ViewPane {
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
) {
|
||||
super(options, keybindingService, contextMenuService, _configurationService, contextKeyService, viewDescriptorService, _instantiationService, openerService, themeService, telemetryService);
|
||||
this._outlineViewState = this.instantiationService.createInstance(OutlineViewState);
|
||||
this._outlineViewState.restore(this._storageService);
|
||||
this._contextKeyFocused = OutlineViewFocused.bindTo(contextKeyService);
|
||||
this._contextKeyFiltered = OutlineViewFiltered.bindTo(contextKeyService);
|
||||
this._disposables.push(this.onDidFocus(_ => this._contextKeyFocused.set(true)));
|
||||
@@ -441,7 +434,7 @@ export class OutlinePane extends ViewPane {
|
||||
}
|
||||
|
||||
private _onDidChangeUserState(e: { followCursor?: boolean, sortBy?: boolean, filterOnType?: boolean }) {
|
||||
this._outlineViewState.persist();
|
||||
this._outlineViewState.persist(this._storageService);
|
||||
if (e.followCursor) {
|
||||
// todo@joh update immediately
|
||||
}
|
||||
|
||||
32
src/vs/workbench/contrib/output/browser/media/output.css
Normal file
32
src/vs/workbench/contrib/output/browser/media/output.css
Normal file
@@ -0,0 +1,32 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.monaco-workbench .part > .title > .title-actions .switch-output {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 11px;
|
||||
margin-right: 0.3em;
|
||||
height: 20px;
|
||||
flex-shrink: 1;
|
||||
margin-top: 7px;
|
||||
}
|
||||
|
||||
.monaco-workbench.mac .part > .title > .title-actions .switch-output {
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.monaco-workbench .part > .title > .title-actions .switch-output > .monaco-select-box {
|
||||
border: none !important;
|
||||
display: block !important;
|
||||
background-color: unset !important;
|
||||
}
|
||||
|
||||
.monaco-pane-view .pane > .pane-header .monaco-action-bar .switch-output.action-item.select-container {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.monaco-workbench .part > .title > .title-actions .switch-output > .monaco-select-box {
|
||||
padding: 0 22px 0 6px;
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import * as aria from 'vs/base/browser/ui/aria/aria';
|
||||
import 'vs/css!./media/output';
|
||||
import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { ModesRegistry } from 'vs/editor/common/modes/modesRegistry';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
@@ -20,7 +21,7 @@ import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWo
|
||||
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ITextModelService } from 'vs/editor/common/services/resolverService';
|
||||
import { ViewContainer, IViewContainersRegistry, ViewContainerLocation, Extensions as ViewContainerExtensions, IViewsRegistry, IViewsService } from 'vs/workbench/common/views';
|
||||
import { ViewContainer, IViewContainersRegistry, ViewContainerLocation, Extensions as ViewContainerExtensions, IViewsRegistry, IViewsService, IViewDescriptorService } from 'vs/workbench/common/views';
|
||||
import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer';
|
||||
import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
@@ -28,10 +29,9 @@ import { IQuickPickItem, IQuickInputService } from 'vs/platform/quickinput/commo
|
||||
import { IOutputChannelDescriptor, IFileOutputChannelDescriptor } from 'vs/workbench/services/output/common/output';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { assertIsDefined } from 'vs/base/common/types';
|
||||
import { TogglePanelAction } from 'vs/workbench/browser/panel';
|
||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { ContextKeyEqualsExpr, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ContextKeyEqualsExpr, ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ToggleViewAction } from 'vs/workbench/browser/actions/layoutActions';
|
||||
|
||||
// Register Service
|
||||
registerSingleton(IOutputService, OutputService);
|
||||
@@ -228,11 +228,13 @@ registerAction2(class extends Action2 {
|
||||
});
|
||||
}
|
||||
async run(accessor: ServicesAccessor): Promise<void> {
|
||||
const panelService = accessor.get(IPanelService);
|
||||
const viewsService = accessor.get(IViewsService);
|
||||
const viewDescriptorService = accessor.get(IViewDescriptorService);
|
||||
const contextKeyService = accessor.get(IContextKeyService);
|
||||
const layoutService = accessor.get(IWorkbenchLayoutService);
|
||||
return new class ToggleOutputAction extends TogglePanelAction {
|
||||
return new class ToggleOutputAction extends ToggleViewAction {
|
||||
constructor() {
|
||||
super(toggleOutputAcitonId, 'Toggle Output', OUTPUT_VIEW_ID, panelService, layoutService);
|
||||
super(toggleOutputAcitonId, 'Toggle Output', OUTPUT_VIEW_ID, viewsService, viewDescriptorService, contextKeyService, layoutService);
|
||||
}
|
||||
}().run();
|
||||
}
|
||||
|
||||
@@ -31,11 +31,11 @@ import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorIn
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { IOutputChannelDescriptor, IOutputChannelRegistry, Extensions } from 'vs/workbench/services/output/common/output';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { attachSelectBoxStyler } from 'vs/platform/theme/common/styler';
|
||||
import { attachSelectBoxStyler, attachStylerCallback } from 'vs/platform/theme/common/styler';
|
||||
import { ISelectOptionItem } from 'vs/base/browser/ui/selectBox/selectBox';
|
||||
import { groupBy } from 'vs/base/common/arrays';
|
||||
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { editorBackground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { editorBackground, selectBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { addClass } from 'vs/base/browser/dom';
|
||||
|
||||
export class OutputViewPane extends ViewPane {
|
||||
@@ -43,7 +43,6 @@ export class OutputViewPane extends ViewPane {
|
||||
private readonly editor: OutputEditor;
|
||||
private channelId: string | undefined;
|
||||
private editorPromise: Promise<OutputEditor> | null = null;
|
||||
private actions: IAction[] | undefined;
|
||||
|
||||
private readonly scrollLockContextKey: IContextKey<boolean>;
|
||||
get scrollLock(): boolean { return !!this.scrollLockContextKey.get(); }
|
||||
@@ -109,7 +108,7 @@ export class OutputViewPane extends ViewPane {
|
||||
}
|
||||
|
||||
const model = codeEditor.getModel();
|
||||
if (model && this.actions) {
|
||||
if (model) {
|
||||
const newPositionLine = e.position.lineNumber;
|
||||
const lastLine = model.getLineCount();
|
||||
this.scrollLock = lastLine !== newPositionLine;
|
||||
@@ -276,7 +275,7 @@ class SwitchOutputActionViewItem extends SelectActionViewItem {
|
||||
constructor(
|
||||
action: IAction,
|
||||
@IOutputService private readonly outputService: IOutputService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IThemeService private readonly themeService: IThemeService,
|
||||
@IContextViewService contextViewService: IContextViewService
|
||||
) {
|
||||
super(null, action, [], 0, contextViewService, { ariaLabel: nls.localize('outputChannels', 'Output Channels.') });
|
||||
@@ -290,6 +289,14 @@ class SwitchOutputActionViewItem extends SelectActionViewItem {
|
||||
this.updateOtions();
|
||||
}
|
||||
|
||||
render(container: HTMLElement): void {
|
||||
super.render(container);
|
||||
addClass(container, 'switch-output');
|
||||
this._register(attachStylerCallback(this.themeService, { selectBorder }, colors => {
|
||||
container.style.border = colors.selectBorder ? `1px solid ${colors.selectBorder}` : '';
|
||||
}));
|
||||
}
|
||||
|
||||
protected getActionContext(option: string, index: number): string {
|
||||
const channel = index < this.outputChannels.length ? this.outputChannels[index] : this.logChannels[index - this.outputChannels.length - 1];
|
||||
return channel ? channel.id : option;
|
||||
|
||||
@@ -341,7 +341,7 @@ export abstract class AbstractSettingRenderer extends Disposable implements ITre
|
||||
protected createSyncIgnoredElement(container: HTMLElement): HTMLElement {
|
||||
const syncIgnoredElement = DOM.append(container, $('span.setting-item-ignored'));
|
||||
const syncIgnoredLabel = new CodiconLabel(syncIgnoredElement);
|
||||
syncIgnoredLabel.text = `($(eye-closed) ${localize('extensionSyncIgnoredLabel', 'Sync: Ignored')})`;
|
||||
syncIgnoredLabel.text = `($(sync-ignored) ${localize('extensionSyncIgnoredLabel', 'Sync: Ignored')})`;
|
||||
|
||||
return syncIgnoredElement;
|
||||
}
|
||||
|
||||
@@ -60,7 +60,13 @@ export class CommandsQuickAccessProvider extends AbstractEditorCommandsQuickAcce
|
||||
@INotificationService notificationService: INotificationService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService
|
||||
) {
|
||||
super({ showAlias: !Language.isDefaultVariant() }, instantiationService, keybindingService, commandService, telemetryService, notificationService);
|
||||
super({
|
||||
showAlias: !Language.isDefaultVariant(),
|
||||
noResultsPick: {
|
||||
label: localize('noCommandResults', "No matching commands"),
|
||||
commandId: ''
|
||||
}
|
||||
}, instantiationService, keybindingService, commandService, telemetryService, notificationService);
|
||||
}
|
||||
|
||||
private get configuration() {
|
||||
|
||||
@@ -8,10 +8,10 @@ import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IQuickPickSeparator, IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { IPickerQuickAccessItem, PickerQuickAccessProvider } from 'vs/platform/quickinput/browser/pickerQuickAccess';
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { IViewDescriptorService, IViewsService, ViewContainer, IViewsRegistry, Extensions as ViewExtensions, IViewContainersRegistry } from 'vs/workbench/common/views';
|
||||
import { IViewDescriptorService, IViewsService, ViewContainer, Extensions as ViewExtensions, IViewContainersRegistry } from 'vs/workbench/common/views';
|
||||
import { IOutputService } from 'vs/workbench/contrib/output/common/output';
|
||||
import { ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { IPanelService, IPanelIdentifier } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ViewletDescriptor } from 'vs/workbench/browser/viewlet';
|
||||
import { matchesFuzzy } from 'vs/base/common/filters';
|
||||
@@ -37,7 +37,12 @@ export class ViewQuickAccessProvider extends PickerQuickAccessProvider<IViewQuic
|
||||
@IPanelService private readonly panelService: IPanelService,
|
||||
@IContextKeyService private readonly contextKeyService: IContextKeyService
|
||||
) {
|
||||
super(ViewQuickAccessProvider.PREFIX);
|
||||
super(ViewQuickAccessProvider.PREFIX, {
|
||||
noResultsPick: {
|
||||
label: localize('noViewResults', "No matching views"),
|
||||
containerLabel: ''
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected getPicks(filter: string): Array<IViewQuickPickItem | IQuickPickSeparator> {
|
||||
@@ -91,13 +96,12 @@ export class ViewQuickAccessProvider extends PickerQuickAccessProvider<IViewQuic
|
||||
const viewEntries: Array<IViewQuickPickItem> = [];
|
||||
|
||||
const getViewEntriesForViewlet = (viewlet: ViewletDescriptor, viewContainer: ViewContainer): IViewQuickPickItem[] => {
|
||||
const views = Registry.as<IViewsRegistry>(ViewExtensions.ViewsRegistry).getViews(viewContainer);
|
||||
const viewDescriptors = this.viewDescriptorService.getViewDescriptors(viewContainer);
|
||||
const result: IViewQuickPickItem[] = [];
|
||||
for (const view of views) {
|
||||
for (const view of viewDescriptors.allViewDescriptors) {
|
||||
if (this.contextKeyService.contextMatchesRules(view.when)) {
|
||||
result.push({
|
||||
label: view.name,
|
||||
ariaLabel: localize('viewPickAriaLabel', "{0}, view picker", view.name),
|
||||
containerLabel: viewlet.name,
|
||||
accept: () => this.viewsService.openView(view.id, true)
|
||||
});
|
||||
@@ -110,10 +114,9 @@ export class ViewQuickAccessProvider extends PickerQuickAccessProvider<IViewQuic
|
||||
// Viewlets
|
||||
const viewlets = this.viewletService.getViewlets();
|
||||
for (const viewlet of viewlets) {
|
||||
if (this.includeViewlet(viewlet)) {
|
||||
if (this.includeViewContainer(viewlet)) {
|
||||
viewEntries.push({
|
||||
label: viewlet.name,
|
||||
ariaLabel: localize('viewPickAriaLabel', "{0}, view picker", viewlet.name),
|
||||
containerLabel: localize('views', "Side Bar"),
|
||||
accept: () => this.viewletService.openViewlet(viewlet.id, true)
|
||||
});
|
||||
@@ -123,12 +126,13 @@ export class ViewQuickAccessProvider extends PickerQuickAccessProvider<IViewQuic
|
||||
// Panels
|
||||
const panels = this.panelService.getPanels();
|
||||
for (const panel of panels) {
|
||||
viewEntries.push({
|
||||
label: panel.name,
|
||||
ariaLabel: localize('viewPickAriaLabel', "{0}, view picker", panel.name),
|
||||
containerLabel: localize('panels', "Panel"),
|
||||
accept: () => this.panelService.openPanel(panel.id, true)
|
||||
});
|
||||
if (this.includeViewContainer(panel)) {
|
||||
viewEntries.push({
|
||||
label: panel.name,
|
||||
containerLabel: localize('panels', "Panel"),
|
||||
accept: () => this.panelService.openPanel(panel.id, true)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Viewlet Views
|
||||
@@ -145,7 +149,6 @@ export class ViewQuickAccessProvider extends PickerQuickAccessProvider<IViewQuic
|
||||
const label = localize('terminalTitle', "{0}: {1}", `${tabIndex + 1}.${terminalIndex + 1}`, terminal.title);
|
||||
viewEntries.push({
|
||||
label,
|
||||
ariaLabel: localize('viewPickAriaLabel', "{0}, view picker", label),
|
||||
containerLabel: localize('terminals', "Terminal"),
|
||||
accept: async () => {
|
||||
await this.terminalService.showPanel(true);
|
||||
@@ -162,20 +165,16 @@ export class ViewQuickAccessProvider extends PickerQuickAccessProvider<IViewQuic
|
||||
const label = channel.log ? localize('logChannel', "Log ({0})", channel.label) : channel.label;
|
||||
viewEntries.push({
|
||||
label,
|
||||
ariaLabel: localize('viewPickAriaLabel', "{0}, view picker", label),
|
||||
containerLabel: localize('channels', "Output"),
|
||||
accept: () => this.outputService.showChannel(channel.id)
|
||||
});
|
||||
}
|
||||
|
||||
// Add generic ARIA label
|
||||
viewEntries.forEach(entry => entry.ariaLabel = localize('entryAriaLabel', "{0}, view picker", entry.label));
|
||||
|
||||
return viewEntries;
|
||||
}
|
||||
|
||||
private includeViewlet(viewlet: ViewletDescriptor): boolean {
|
||||
const viewContainer = Registry.as<IViewContainersRegistry>(ViewExtensions.ViewContainersRegistry).get(viewlet.id);
|
||||
private includeViewContainer(container: ViewletDescriptor | IPanelIdentifier): boolean {
|
||||
const viewContainer = Registry.as<IViewContainersRegistry>(ViewExtensions.ViewContainersRegistry).get(container.id);
|
||||
if (viewContainer?.hideIfEmpty) {
|
||||
return this.viewDescriptorService.getViewDescriptors(viewContainer).activeViewDescriptors.length > 0;
|
||||
}
|
||||
|
||||
@@ -151,10 +151,7 @@ interface ResourceTemplate {
|
||||
|
||||
class RepositoryPaneActionRunner extends ActionRunner {
|
||||
|
||||
constructor(
|
||||
private getSelectedResources: () => (ISCMResource | IResourceNode<ISCMResource, ISCMResourceGroup>)[],
|
||||
private focus: () => void
|
||||
) {
|
||||
constructor(private getSelectedResources: () => (ISCMResource | IResourceNode<ISCMResource, ISCMResourceGroup>)[]) {
|
||||
super();
|
||||
}
|
||||
|
||||
@@ -168,7 +165,6 @@ class RepositoryPaneActionRunner extends ActionRunner {
|
||||
const actualContext = contextIsSelected ? selection : [context];
|
||||
const args = flatten(actualContext.map(e => ResourceTree.isResourceNode(e) ? ResourceTree.collect(e) : [e]));
|
||||
await action.run(...args);
|
||||
this.focus();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,8 +177,7 @@ class ResourceRenderer implements ICompressibleTreeRenderer<ISCMResource | IReso
|
||||
private viewModelProvider: () => ViewModel,
|
||||
private labels: ResourceLabels,
|
||||
private actionViewItemProvider: IActionViewItemProvider,
|
||||
private getSelectedResources: () => (ISCMResource | IResourceNode<ISCMResource, ISCMResourceGroup>)[],
|
||||
private focus: () => void,
|
||||
private actionRunner: ActionRunner,
|
||||
private themeService: IThemeService,
|
||||
private menus: SCMMenus
|
||||
) { }
|
||||
@@ -194,7 +189,7 @@ class ResourceRenderer implements ICompressibleTreeRenderer<ISCMResource | IReso
|
||||
const actionsContainer = append(fileLabel.element, $('.actions'));
|
||||
const actionBar = new ActionBar(actionsContainer, {
|
||||
actionViewItemProvider: this.actionViewItemProvider,
|
||||
actionRunner: new RepositoryPaneActionRunner(this.getSelectedResources, this.focus)
|
||||
actionRunner: this.actionRunner
|
||||
});
|
||||
|
||||
const decorationIcon = append(element, $('.decoration-icon'));
|
||||
@@ -830,9 +825,19 @@ export class RepositoryPane extends ViewPane {
|
||||
this.listLabels = this.instantiationService.createInstance(ResourceLabels, { onDidChangeVisibility: this.onDidChangeBodyVisibility });
|
||||
this._register(this.listLabels);
|
||||
|
||||
const actionRunner = new RepositoryPaneActionRunner(() => this.getSelectedResources());
|
||||
this._register(actionRunner);
|
||||
this._register(actionRunner.onDidRun(() => {
|
||||
if (this.repository.input.visible && this.inputEditor.hasWidgetFocus()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.tree.domFocus();
|
||||
}));
|
||||
|
||||
const renderers = [
|
||||
new ResourceGroupRenderer(actionViewItemProvider, this.themeService, this.menus),
|
||||
new ResourceRenderer(() => this.viewModel, this.listLabels, actionViewItemProvider, () => this.getSelectedResources(), () => this.tree.domFocus(), this.themeService, this.menus)
|
||||
new ResourceRenderer(() => this.viewModel, this.listLabels, actionViewItemProvider, actionRunner, this.themeService, this.menus)
|
||||
];
|
||||
|
||||
const filter = new SCMTreeFilter();
|
||||
@@ -1032,11 +1037,14 @@ export class RepositoryPane extends ViewPane {
|
||||
actions = this.menus.getResourceContextActions(element);
|
||||
}
|
||||
|
||||
const actionRunner = new RepositoryPaneActionRunner(() => this.getSelectedResources());
|
||||
actionRunner.onDidRun(() => this.tree.domFocus());
|
||||
|
||||
this.contextMenuService.showContextMenu({
|
||||
getAnchor: () => e.anchor,
|
||||
getActions: () => actions,
|
||||
getActionsContext: () => element,
|
||||
actionRunner: new RepositoryPaneActionRunner(() => this.getSelectedResources(), () => this.tree.domFocus())
|
||||
actionRunner
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./media/anythingQuickAccess';
|
||||
import { IQuickInputButton, IKeyMods, quickPickItemScorerAccessor, QuickPickItemScorerAccessor, IQuickPick } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { IQuickInputButton, IKeyMods, quickPickItemScorerAccessor, QuickPickItemScorerAccessor, IQuickPick, IQuickPickItemWithResource } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { IPickerQuickAccessItem, PickerQuickAccessProvider, TriggerAction, FastAndSlowPicks, Picks, PicksWithActive } from 'vs/platform/quickinput/browser/pickerQuickAccess';
|
||||
import { prepareQuery, IPreparedQuery, compareItemsByScore, scoreItem, ScorerCache } from 'vs/base/common/fuzzyScorer';
|
||||
import { prepareQuery, IPreparedQuery, compareItemsByFuzzyScore, scoreItemFuzzy, FuzzyScorerCache } from 'vs/base/common/fuzzyScorer';
|
||||
import { IFileQueryBuilderOptions, QueryBuilder } from 'vs/workbench/contrib/search/common/queryBuilder';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { getOutOfWorkspaceEditorResources, extractRangeFromFilter, IWorkbenchSearchConfiguration } from 'vs/workbench/contrib/search/common/search';
|
||||
@@ -50,9 +50,7 @@ import { getCodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
import { stripCodicons } from 'vs/base/common/codicons';
|
||||
|
||||
interface IAnythingQuickPickItem extends IPickerQuickAccessItem {
|
||||
resource: URI | undefined;
|
||||
}
|
||||
interface IAnythingQuickPickItem extends IPickerQuickAccessItem, IQuickPickItemWithResource { }
|
||||
|
||||
interface IEditorSymbolAnythingQuickPickItem extends IAnythingQuickPickItem {
|
||||
resource: URI;
|
||||
@@ -83,7 +81,7 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
|
||||
state: ICodeEditorViewState | IDiffEditorViewState | undefined
|
||||
} | undefined = undefined;
|
||||
|
||||
scorerCache: ScorerCache = Object.create(null);
|
||||
scorerCache: FuzzyScorerCache = Object.create(null);
|
||||
fileQueryCache: FileQueryCacheState | undefined = undefined;
|
||||
|
||||
lastOriginalFilter: string | undefined = undefined;
|
||||
@@ -163,7 +161,12 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
|
||||
@IFilesConfigurationService private readonly filesConfigurationService: IFilesConfigurationService,
|
||||
@ITextModelService private readonly textModelService: ITextModelService
|
||||
) {
|
||||
super(AnythingQuickAccessProvider.PREFIX, { canAcceptInBackground: true });
|
||||
super(AnythingQuickAccessProvider.PREFIX, {
|
||||
canAcceptInBackground: true,
|
||||
noResultsPick: {
|
||||
label: localize('noAnythingResults', "No matching results")
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private get configuration() {
|
||||
@@ -268,6 +271,7 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
|
||||
}
|
||||
|
||||
// Remember as last filter
|
||||
const lastWasFiltering = !!this.pickState.lastOriginalFilter;
|
||||
this.pickState.lastOriginalFilter = originalFilter;
|
||||
this.pickState.lastFilter = filter;
|
||||
|
||||
@@ -286,18 +290,28 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
|
||||
}
|
||||
}
|
||||
|
||||
return this.doGetPicks(filter, disposables, token);
|
||||
// `enableEditorSymbolSearch`: this will enable local editor symbol
|
||||
// search if the filter value includes `@` character. We only want
|
||||
// to enable this support though if the user was filtering in the
|
||||
// picker because this feature depends on an active item in the result
|
||||
// list to get symbols from. If we would simply trigger editor symbol
|
||||
// search without prior filtering, you could not paste a file name
|
||||
// including the `@` character to open it (e.g. /some/file@path)
|
||||
// refs: https://github.com/microsoft/vscode/issues/93845
|
||||
return this.doGetPicks(filter, { enableEditorSymbolSearch: lastWasFiltering }, disposables, token);
|
||||
}
|
||||
|
||||
private doGetPicks(filter: string, disposables: DisposableStore, token: CancellationToken): Picks<IAnythingQuickPickItem> | Promise<Picks<IAnythingQuickPickItem>> | FastAndSlowPicks<IAnythingQuickPickItem> | null {
|
||||
private doGetPicks(filter: string, options: { enableEditorSymbolSearch: boolean }, disposables: DisposableStore, token: CancellationToken): Picks<IAnythingQuickPickItem> | Promise<Picks<IAnythingQuickPickItem>> | FastAndSlowPicks<IAnythingQuickPickItem> {
|
||||
const query = prepareQuery(filter);
|
||||
|
||||
// Return early if we have editor symbol picks. We support this by:
|
||||
// - having a previously active global pick (e.g. a file)
|
||||
// - the user typing `@` to start the local symbol query
|
||||
const editorSymbolPicks = this.getEditorSymbolPicks(query, disposables, token);
|
||||
if (editorSymbolPicks) {
|
||||
return editorSymbolPicks;
|
||||
if (options.enableEditorSymbolSearch) {
|
||||
const editorSymbolPicks = this.getEditorSymbolPicks(query, disposables, token);
|
||||
if (editorSymbolPicks) {
|
||||
return editorSymbolPicks;
|
||||
}
|
||||
}
|
||||
|
||||
// If we have a known last active editor symbol pick, we try to restore
|
||||
@@ -361,7 +375,7 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
|
||||
// Perform sorting (top results by score)
|
||||
const sortedAnythingPicks = top(
|
||||
[...filePicks, ...symbolPicks],
|
||||
(anyPickA, anyPickB) => compareItemsByScore(anyPickA, anyPickB, query, true, quickPickItemScorerAccessor, this.pickState.scorerCache),
|
||||
(anyPickA, anyPickB) => compareItemsByFuzzyScore(anyPickA, anyPickB, query, true, quickPickItemScorerAccessor, this.pickState.scorerCache),
|
||||
AnythingQuickAccessProvider.MAX_RESULTS
|
||||
);
|
||||
|
||||
@@ -376,7 +390,7 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
|
||||
|
||||
// Otherwise, do the scoring and matching here
|
||||
else {
|
||||
const { score, labelMatch, descriptionMatch } = scoreItem(anythingPick, query, true, quickPickItemScorerAccessor, this.pickState.scorerCache);
|
||||
const { score, labelMatch, descriptionMatch } = scoreItemFuzzy(anythingPick, query, true, quickPickItemScorerAccessor, this.pickState.scorerCache);
|
||||
if (!score) {
|
||||
continue;
|
||||
}
|
||||
@@ -421,7 +435,7 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
|
||||
|
||||
const editorHistoryPick = this.createAnythingPick(editor, configuration);
|
||||
|
||||
const { score, labelMatch, descriptionMatch } = scoreItem(editorHistoryPick, query, false, editorHistoryScorerAccessor, this.pickState.scorerCache);
|
||||
const { score, labelMatch, descriptionMatch } = scoreItemFuzzy(editorHistoryPick, query, false, editorHistoryScorerAccessor, this.pickState.scorerCache);
|
||||
if (!score) {
|
||||
continue; // exclude editors not matching query
|
||||
}
|
||||
@@ -440,7 +454,7 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
|
||||
}
|
||||
|
||||
// Perform sorting
|
||||
return editorHistoryPicks.sort((editorA, editorB) => compareItemsByScore(editorA, editorB, query, false, editorHistoryScorerAccessor, this.pickState.scorerCache));
|
||||
return editorHistoryPicks.sort((editorA, editorB) => compareItemsByFuzzyScore(editorA, editorB, query, false, editorHistoryScorerAccessor, this.pickState.scorerCache));
|
||||
}
|
||||
|
||||
//#endregion
|
||||
@@ -716,7 +730,8 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
|
||||
private readonly editorSymbolsQuickAccess = this.instantiationService.createInstance(GotoSymbolQuickAccessProvider);
|
||||
|
||||
private getEditorSymbolPicks(query: IPreparedQuery, disposables: DisposableStore, token: CancellationToken): Promise<Picks<IAnythingQuickPickItem>> | null {
|
||||
const filter = query.original.split(GotoSymbolQuickAccessProvider.PREFIX)[1]?.trim();
|
||||
const filterSegments = query.original.split(GotoSymbolQuickAccessProvider.PREFIX);
|
||||
const filter = filterSegments.length > 1 ? filterSegments[filterSegments.length - 1].trim() : undefined;
|
||||
if (typeof filter !== 'string') {
|
||||
return null; // we need to be searched for editor symbols via `@`
|
||||
}
|
||||
@@ -731,6 +746,12 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
|
||||
return null; // we need a resource that we can resolve
|
||||
}
|
||||
|
||||
if (activeGlobalPick.label.includes(GotoSymbolQuickAccessProvider.PREFIX) || activeGlobalPick.description?.includes(GotoSymbolQuickAccessProvider.PREFIX)) {
|
||||
if (filterSegments.length < 3) {
|
||||
return null; // require at least 2 `@` if our active pick contains `@` in label or description
|
||||
}
|
||||
}
|
||||
|
||||
return this.doGetEditorSymbolPicks(activeGlobalPick, activeGlobalResource, filter, disposables, token);
|
||||
}
|
||||
|
||||
@@ -834,9 +855,7 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
|
||||
return {
|
||||
resource,
|
||||
label,
|
||||
ariaLabel: isEditorHistoryEntry ?
|
||||
localize('historyPickAriaLabel', "{0}, recently opened", label) :
|
||||
localize('filePickAriaLabel', "{0}, file picker", label),
|
||||
ariaLabel: isDirty ? localize('filePickAriaLabelDirty', "{0}, dirty", label) : label,
|
||||
description,
|
||||
iconClasses: getIconClasses(this.modelService, this.modeService, resource),
|
||||
buttons: (() => {
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
import { localize } from 'vs/nls';
|
||||
import { IPickerQuickAccessItem, PickerQuickAccessProvider, TriggerAction } from 'vs/platform/quickinput/browser/pickerQuickAccess';
|
||||
import { fuzzyScore, createMatches, FuzzyScore } from 'vs/base/common/filters';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { ThrottledDelayer } from 'vs/base/common/async';
|
||||
@@ -18,20 +17,16 @@ import { IEditorService, SIDE_GROUP, ACTIVE_GROUP } from 'vs/workbench/services/
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IWorkbenchEditorConfiguration } from 'vs/workbench/common/editor';
|
||||
import { IKeyMods } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { createResourceExcludeMatcher } from 'vs/workbench/services/search/common/search';
|
||||
import { ResourceMap } from 'vs/base/common/map';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IKeyMods, IQuickPickItemWithResource } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { getSelectionSearchString } from 'vs/editor/contrib/find/findController';
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
import { prepareQuery, IPreparedQuery } from 'vs/base/common/fuzzyScorer';
|
||||
import { prepareQuery, IPreparedQuery, scoreFuzzy2, pieceToQuery } from 'vs/base/common/fuzzyScorer';
|
||||
import { IMatch } from 'vs/base/common/filters';
|
||||
|
||||
interface ISymbolQuickPickItem extends IPickerQuickAccessItem {
|
||||
resource: URI | undefined;
|
||||
score: FuzzyScore | undefined;
|
||||
symbol: IWorkspaceSymbol;
|
||||
interface ISymbolQuickPickItem extends IPickerQuickAccessItem, IQuickPickItemWithResource {
|
||||
score?: number;
|
||||
symbol?: IWorkspaceSymbol;
|
||||
}
|
||||
|
||||
export class SymbolsQuickAccessProvider extends PickerQuickAccessProvider<ISymbolQuickPickItem> {
|
||||
@@ -52,8 +47,6 @@ export class SymbolsQuickAccessProvider extends PickerQuickAccessProvider<ISymbo
|
||||
|
||||
private delayer = this._register(new ThrottledDelayer<ISymbolQuickPickItem[]>(SymbolsQuickAccessProvider.TYPING_SEARCH_DELAY));
|
||||
|
||||
private readonly resourceExcludeMatcher = this._register(createResourceExcludeMatcher(this.instantiationService, this.configurationService));
|
||||
|
||||
get defaultFilterValue(): string | undefined {
|
||||
|
||||
// Prefer the word under the cursor in the active editor as default filter
|
||||
@@ -70,10 +63,14 @@ export class SymbolsQuickAccessProvider extends PickerQuickAccessProvider<ISymbo
|
||||
@IOpenerService private readonly openerService: IOpenerService,
|
||||
@IEditorService private readonly editorService: IEditorService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@ICodeEditorService private readonly codeEditorService: ICodeEditorService
|
||||
) {
|
||||
super(SymbolsQuickAccessProvider.PREFIX, { canAcceptInBackground: true });
|
||||
super(SymbolsQuickAccessProvider.PREFIX, {
|
||||
canAcceptInBackground: true,
|
||||
noResultsPick: {
|
||||
label: localize('noSymbolResults', "No matching workspace symbols")
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private get configuration() {
|
||||
@@ -100,26 +97,27 @@ export class SymbolsQuickAccessProvider extends PickerQuickAccessProvider<ISymbo
|
||||
}
|
||||
|
||||
private async doGetSymbolPicks(query: IPreparedQuery, options: { skipLocal?: boolean, skipSorting?: boolean } | undefined, token: CancellationToken): Promise<Array<ISymbolQuickPickItem>> {
|
||||
const workspaceSymbols = await getWorkspaceSymbols(query.original, token);
|
||||
|
||||
// Split between symbol and container query
|
||||
let symbolQuery: IPreparedQuery;
|
||||
let containerQuery: IPreparedQuery | undefined;
|
||||
if (query.values && query.values.length > 1) {
|
||||
symbolQuery = pieceToQuery(query.values[0]); // symbol: only match on first part
|
||||
containerQuery = pieceToQuery(query.values.slice(1)); // container: match on all but first parts
|
||||
} else {
|
||||
symbolQuery = query;
|
||||
}
|
||||
|
||||
// Run the workspace symbol query
|
||||
const workspaceSymbols = await getWorkspaceSymbols(symbolQuery.original, token);
|
||||
if (token.isCancellationRequested) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const symbolPicks: Array<ISymbolQuickPickItem> = [];
|
||||
|
||||
// Split between symbol and container query
|
||||
let symbolQuery: IPreparedQuery;
|
||||
let containerQuery: IPreparedQuery | undefined;
|
||||
if (query.values && query.values.length > 1) {
|
||||
symbolQuery = prepareQuery(query.values[0].original);
|
||||
containerQuery = prepareQuery(query.values[1].original);
|
||||
} else {
|
||||
symbolQuery = query;
|
||||
}
|
||||
|
||||
// Convert to symbol picks and apply filtering
|
||||
const openSideBySideDirection = this.configuration.openSideBySideDirection;
|
||||
const symbolsExcludedByResource = new ResourceMap<boolean>();
|
||||
for (const [provider, symbols] of workspaceSymbols) {
|
||||
for (const symbol of symbols) {
|
||||
|
||||
@@ -130,11 +128,18 @@ export class SymbolsQuickAccessProvider extends PickerQuickAccessProvider<ISymbo
|
||||
continue;
|
||||
}
|
||||
|
||||
// Score by symbol label
|
||||
const symbolLabel = symbol.name;
|
||||
const symbolScore = fuzzyScore(symbolQuery.original, symbolQuery.originalLowercase, 0, symbolLabel, symbolLabel.toLowerCase(), 0, true);
|
||||
if (!symbolScore) {
|
||||
continue;
|
||||
const symbolLabelWithIcon = `$(symbol-${SymbolKinds.toString(symbol.kind) || 'property'}) ${symbolLabel}`;
|
||||
|
||||
|
||||
// Score by symbol label if searching
|
||||
let symbolScore: number | undefined = undefined;
|
||||
let symbolMatches: IMatch[] | undefined = undefined;
|
||||
if (symbolQuery.original.length > 0) {
|
||||
[symbolScore, symbolMatches] = scoreFuzzy2(symbolLabel, symbolQuery, 0, symbolLabelWithIcon.length - symbolLabel.length /* Readjust matches to account for codicons in label */);
|
||||
if (!symbolScore) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
const symbolUri = symbol.location.uri;
|
||||
@@ -148,32 +153,23 @@ export class SymbolsQuickAccessProvider extends PickerQuickAccessProvider<ISymbo
|
||||
}
|
||||
}
|
||||
|
||||
// Score by container if specified
|
||||
let containerScore: FuzzyScore | undefined = undefined;
|
||||
if (containerQuery) {
|
||||
// Score by container if specified and searching
|
||||
let containerScore: number | undefined = undefined;
|
||||
let containerMatches: IMatch[] | undefined = undefined;
|
||||
if (containerQuery && containerQuery.original.length > 0) {
|
||||
if (containerLabel) {
|
||||
containerScore = fuzzyScore(containerQuery.original, containerQuery.originalLowercase, 0, containerLabel, containerLabel.toLowerCase(), 0, true);
|
||||
[containerScore, containerMatches] = scoreFuzzy2(containerLabel, containerQuery);
|
||||
}
|
||||
|
||||
if (!containerScore) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Filter out symbols that match the global resource filter
|
||||
if (symbolUri) {
|
||||
let excludeSymbolByResource = symbolsExcludedByResource.get(symbolUri);
|
||||
if (typeof excludeSymbolByResource === 'undefined') {
|
||||
excludeSymbolByResource = this.resourceExcludeMatcher.matches(symbolUri);
|
||||
symbolsExcludedByResource.set(symbolUri, excludeSymbolByResource);
|
||||
}
|
||||
|
||||
if (excludeSymbolByResource) {
|
||||
continue;
|
||||
if (symbolScore) {
|
||||
symbolScore += containerScore; // boost symbolScore by containerScore
|
||||
}
|
||||
}
|
||||
|
||||
const symbolLabelWithIcon = `$(symbol-${SymbolKinds.toString(symbol.kind) || 'property'}) ${symbolLabel}`;
|
||||
const deprecated = symbol.tags ? symbol.tags.indexOf(SymbolTag.Deprecated) >= 0 : false;
|
||||
|
||||
symbolPicks.push({
|
||||
@@ -181,10 +177,10 @@ export class SymbolsQuickAccessProvider extends PickerQuickAccessProvider<ISymbo
|
||||
resource: symbolUri,
|
||||
score: symbolScore,
|
||||
label: symbolLabelWithIcon,
|
||||
ariaLabel: localize('symbolAriaLabel', "{0}, symbols picker", symbolLabel),
|
||||
ariaLabel: symbolLabel,
|
||||
highlights: deprecated ? undefined : {
|
||||
label: createMatches(symbolScore, symbolLabelWithIcon.length - symbolLabel.length /* Readjust matches to account for codicons in label */),
|
||||
description: createMatches(containerScore)
|
||||
label: symbolMatches,
|
||||
description: containerMatches
|
||||
},
|
||||
description: containerLabel,
|
||||
strikethrough: deprecated,
|
||||
@@ -246,24 +242,32 @@ export class SymbolsQuickAccessProvider extends PickerQuickAccessProvider<ISymbo
|
||||
|
||||
// By score
|
||||
if (symbolA.score && symbolB.score) {
|
||||
if (symbolA.score[0] > symbolB.score[0]) {
|
||||
if (symbolA.score > symbolB.score) {
|
||||
return -1;
|
||||
} else if (symbolA.score[0] < symbolB.score[0]) {
|
||||
}
|
||||
|
||||
if (symbolA.score < symbolB.score) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// By name
|
||||
const symbolAName = symbolA.symbol.name.toLowerCase();
|
||||
const symbolBName = symbolB.symbol.name.toLowerCase();
|
||||
const res = symbolAName.localeCompare(symbolBName);
|
||||
if (res !== 0) {
|
||||
return res;
|
||||
if (symbolA.symbol && symbolB.symbol) {
|
||||
const symbolAName = symbolA.symbol.name.toLowerCase();
|
||||
const symbolBName = symbolB.symbol.name.toLowerCase();
|
||||
const res = symbolAName.localeCompare(symbolBName);
|
||||
if (res !== 0) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
// By kind
|
||||
const symbolAKind = SymbolKinds.toCssClassName(symbolA.symbol.kind);
|
||||
const symbolBKind = SymbolKinds.toCssClassName(symbolB.symbol.kind);
|
||||
return symbolAKind.localeCompare(symbolBKind);
|
||||
if (symbolA.symbol && symbolB.symbol) {
|
||||
const symbolAKind = SymbolKinds.toCssClassName(symbolA.symbol.kind);
|
||||
const symbolBKind = SymbolKinds.toCssClassName(symbolB.symbol.kind);
|
||||
return symbolAKind.localeCompare(symbolBKind);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,8 +156,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
when: ContextKeyExpr.and(SearchEditorConstants.InSearchEditor),
|
||||
handler: (accessor: ServicesAccessor) => modifySearchEditorContextLinesCommand(accessor, true),
|
||||
primary: KeyMod.Alt | KeyCode.KEY_L,
|
||||
mac: { primary: KeyMod.Alt | KeyCode.US_EQUAL }
|
||||
primary: KeyMod.Alt | KeyCode.US_EQUAL
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
@@ -165,8 +164,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
when: ContextKeyExpr.and(SearchEditorConstants.InSearchEditor),
|
||||
handler: (accessor: ServicesAccessor) => modifySearchEditorContextLinesCommand(accessor, false),
|
||||
primary: KeyMod.Alt | KeyCode.KEY_L,
|
||||
mac: { primary: KeyMod.Alt | KeyCode.US_MINUS }
|
||||
primary: KeyMod.Alt | KeyCode.US_MINUS
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
|
||||
@@ -240,7 +240,9 @@ export class TaskQuickPick extends Disposable {
|
||||
let taskQuickPickEntries: QuickPickInput<TaskTwoLevelQuickPickEntry>[];
|
||||
if (tasks.length > 0) {
|
||||
taskQuickPickEntries = tasks.map(task => this.createTaskEntry(task));
|
||||
taskQuickPickEntries.unshift({
|
||||
taskQuickPickEntries.push({
|
||||
type: 'separator'
|
||||
}, {
|
||||
label: nls.localize('TaskQuickPick.goBack', 'Go back ↩'),
|
||||
task: null
|
||||
});
|
||||
|
||||
@@ -28,7 +28,11 @@ export class TasksQuickAccessProvider extends PickerQuickAccessProvider<IPickerQ
|
||||
@IConfigurationService private configurationService: IConfigurationService,
|
||||
@IQuickInputService private quickInputService: IQuickInputService
|
||||
) {
|
||||
super(TasksQuickAccessProvider.PREFIX);
|
||||
super(TasksQuickAccessProvider.PREFIX, {
|
||||
noResultsPick: {
|
||||
label: localize('noTaskResults', "No matching tasks")
|
||||
}
|
||||
});
|
||||
|
||||
this.activationPromise = extensionService.activateByEvent('onCommand:workbench.action.tasks.runTask');
|
||||
}
|
||||
@@ -46,16 +50,17 @@ export class TasksQuickAccessProvider extends PickerQuickAccessProvider<IPickerQ
|
||||
const taskPicks: Array<IPickerQuickAccessItem | IQuickPickSeparator> = [];
|
||||
|
||||
for (const entry of topLevelPicks.entries) {
|
||||
if (entry.type === 'separator') {
|
||||
taskPicks.push(entry);
|
||||
}
|
||||
const highlights = matchesFuzzy(filter, entry.label!, true);
|
||||
if (!highlights) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entry.type === 'separator') {
|
||||
taskPicks.push(entry);
|
||||
}
|
||||
|
||||
const task: Task | ConfiguringTask | string = (<TaskTwoLevelQuickPickEntry>entry).task!;
|
||||
const quickAccessEntry: IPickerQuickAccessItem = <TaskTwoLevelQuickPickEntry>entry;
|
||||
quickAccessEntry.ariaLabel = localize('entryAriaLabel', "{0}, tasks picker", entry.label!);
|
||||
quickAccessEntry.highlights = { label: highlights };
|
||||
quickAccessEntry.trigger = () => {
|
||||
if (ContributedTask.is(task)) {
|
||||
|
||||
@@ -160,3 +160,32 @@
|
||||
.monaco-workbench .part.sidebar .title-actions .terminal-action.codicon-split-horizontal {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
.monaco-workbench .part > .title > .title-actions .switch-terminal {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 11px;
|
||||
margin-right: 0.3em;
|
||||
height: 20px;
|
||||
flex-shrink: 1;
|
||||
margin-top: 7px;
|
||||
}
|
||||
|
||||
.monaco-workbench.mac .part > .title > .title-actions .switch-terminal {
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.monaco-workbench .part > .title > .title-actions .switch-terminal > .monaco-select-box {
|
||||
border: none !important;
|
||||
display: block !important;
|
||||
background-color: unset !important;
|
||||
}
|
||||
|
||||
.monaco-pane-view .pane > .pane-header .monaco-action-bar .switch-terminal.action-item.select-container {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.monaco-workbench .part > .title > .title-actions .switch-terminal > .monaco-select-box {
|
||||
padding: 0 22px 0 6px;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,10 +9,8 @@ import { EndOfLinePreference } from 'vs/editor/common/model';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { TERMINAL_VIEW_ID, ITerminalConfigHelper, TitleEventSource, TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { SelectActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { TogglePanelAction } from 'vs/workbench/browser/panel';
|
||||
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { attachSelectBoxStyler } from 'vs/platform/theme/common/styler';
|
||||
import { attachSelectBoxStyler, attachStylerCallback } from 'vs/platform/theme/common/styler';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IQuickInputService, IPickOptions, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
@@ -32,6 +30,11 @@ import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
import { ITerminalInstance, ITerminalService, Direction } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||
import { Action2 } from 'vs/platform/actions/common/actions';
|
||||
import { TerminalQuickAccessProvider } from 'vs/workbench/contrib/terminal/browser/terminalsQuickAccess';
|
||||
import { ToggleViewAction } from 'vs/workbench/browser/actions/layoutActions';
|
||||
import { IViewsService, IViewDescriptorService } from 'vs/workbench/common/views';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { addClass } from 'vs/base/browser/dom';
|
||||
import { selectBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||
|
||||
async function getCwdForSplit(configHelper: ITerminalConfigHelper, instance: ITerminalInstance, folders?: IWorkspaceFolder[], commandService?: ICommandService): Promise<string | URI | undefined> {
|
||||
switch (configHelper.config.splitCwd) {
|
||||
@@ -60,18 +63,20 @@ async function getCwdForSplit(configHelper: ITerminalConfigHelper, instance: ITe
|
||||
}
|
||||
}
|
||||
|
||||
export class ToggleTerminalAction extends TogglePanelAction {
|
||||
export class ToggleTerminalAction extends ToggleViewAction {
|
||||
|
||||
public static readonly ID = TERMINAL_COMMAND_ID.TOGGLE;
|
||||
public static readonly LABEL = nls.localize('workbench.action.terminal.toggleTerminal', "Toggle Integrated Terminal");
|
||||
|
||||
constructor(
|
||||
id: string, label: string,
|
||||
@IPanelService panelService: IPanelService,
|
||||
@IViewsService viewsService: IViewsService,
|
||||
@IViewDescriptorService viewDescriptorService: IViewDescriptorService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
|
||||
@ITerminalService private readonly terminalService: ITerminalService
|
||||
) {
|
||||
super(id, label, TERMINAL_VIEW_ID, panelService, layoutService);
|
||||
super(id, label, TERMINAL_VIEW_ID, viewsService, viewDescriptorService, contextKeyService, layoutService);
|
||||
}
|
||||
|
||||
public run(event?: any): Promise<any> {
|
||||
@@ -717,7 +722,7 @@ export class SwitchTerminalActionViewItem extends SelectActionViewItem {
|
||||
constructor(
|
||||
action: IAction,
|
||||
@ITerminalService private readonly terminalService: ITerminalService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IThemeService private readonly themeService: IThemeService,
|
||||
@IContextViewService contextViewService: IContextViewService
|
||||
) {
|
||||
super(null, action, terminalService.getTabLabels().map(label => <ISelectOptionItem>{ text: label }), terminalService.activeTabIndex, contextViewService, { ariaLabel: nls.localize('terminals', 'Open Terminals.') });
|
||||
@@ -729,6 +734,14 @@ export class SwitchTerminalActionViewItem extends SelectActionViewItem {
|
||||
this._register(attachSelectBoxStyler(this.selectBox, themeService));
|
||||
}
|
||||
|
||||
render(container: HTMLElement): void {
|
||||
super.render(container);
|
||||
addClass(container, 'switch-terminal');
|
||||
this._register(attachStylerCallback(this.themeService, { selectBorder }, colors => {
|
||||
container.style.border = colors.selectBorder ? `1px solid ${colors.selectBorder}` : '';
|
||||
}));
|
||||
}
|
||||
|
||||
private _updateItems(): void {
|
||||
const items = this.terminalService.getTabLabels().map(label => <ISelectOptionItem>{ text: label });
|
||||
items.push({ text: SwitchTerminalActionViewItem.SEPARATOR, isDisabled: true });
|
||||
|
||||
@@ -244,7 +244,7 @@ export class TerminalLinkHandler extends DisposableStore {
|
||||
const wasHandled = await new Promise<boolean>(r => {
|
||||
const timeoutId = setTimeout(() => {
|
||||
canceled = true;
|
||||
this._logService.error('An extension intecepted a terminal link but did not return');
|
||||
this._logService.error(`An extension intecepted a terminal link but it timed out after ${TerminalLinkHandler.LINK_INTERCEPT_THRESHOLD / 1000} seconds`);
|
||||
r(false);
|
||||
}, TerminalLinkHandler.LINK_INTERCEPT_THRESHOLD);
|
||||
let canceled = false;
|
||||
|
||||
@@ -36,7 +36,6 @@ export class TerminalQuickAccessProvider extends PickerQuickAccessProvider<IPick
|
||||
if (highlights) {
|
||||
terminalPicks.push({
|
||||
label,
|
||||
ariaLabel: localize('termEntryAriaLabel', "{0}, terminal picker", label),
|
||||
highlights: { label: highlights },
|
||||
buttons: [
|
||||
{
|
||||
@@ -76,7 +75,7 @@ export class TerminalQuickAccessProvider extends PickerQuickAccessProvider<IPick
|
||||
const createTerminalLabel = localize("workbench.action.terminal.newplus", "Create New Integrated Terminal");
|
||||
terminalPicks.push({
|
||||
label: `$(plus) ${createTerminalLabel}`,
|
||||
ariaLabel: localize('termEntryAriaLabel', "{0}, terminal picker", createTerminalLabel),
|
||||
ariaLabel: createTerminalLabel,
|
||||
accept: () => this.commandService.executeCommand('workbench.action.terminal.new')
|
||||
});
|
||||
|
||||
|
||||
@@ -762,7 +762,11 @@ export class TimelinePane extends ViewPane {
|
||||
const changed = super.setExpanded(expanded);
|
||||
|
||||
if (changed && this.isBodyVisible()) {
|
||||
this.onActiveEditorChanged();
|
||||
if (!this.followActiveEditor) {
|
||||
this.setUriCore(this.uri, true);
|
||||
} else {
|
||||
this.onActiveEditorChanged();
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
@@ -1102,8 +1106,7 @@ class TimelinePaneCommands extends Disposable {
|
||||
this._register(MenuRegistry.appendMenuItem(MenuId.TimelineTitle, ({
|
||||
command: {
|
||||
id: 'timeline.toggleFollowActiveEditor',
|
||||
title: { value: localize('timeline.toggleFollowActiveEditorCommand', "Toggle Active Editor Following"), original: 'Toggle Active Editor Following' },
|
||||
// title: localize(`timeline.toggleFollowActiveEditorCommand.stop`, "Stop following the Active Editor"),
|
||||
title: { value: localize('timeline.toggleFollowActiveEditorCommand.follow', "Automatically Follows the Active Editor"), original: 'Automatically Follows the Active Editor' },
|
||||
icon: { id: 'codicon/eye' },
|
||||
category: { value: localize('timeline', "Timeline"), original: 'Timeline' },
|
||||
},
|
||||
@@ -1115,8 +1118,7 @@ class TimelinePaneCommands extends Disposable {
|
||||
this._register(MenuRegistry.appendMenuItem(MenuId.TimelineTitle, ({
|
||||
command: {
|
||||
id: 'timeline.toggleFollowActiveEditor',
|
||||
title: { value: localize('timeline.toggleFollowActiveEditorCommand', "Toggle Active Editor Following"), original: 'Toggle Active Editor Following' },
|
||||
// title: localize(`timeline.toggleFollowActiveEditorCommand.stop`, "Stop following the Active Editor"),
|
||||
title: { value: localize('timeline.toggleFollowActiveEditorCommand.unfollow', "Not Following Active Editor"), original: 'Not Following Active Editor' },
|
||||
icon: { id: 'codicon/eye-closed' },
|
||||
category: { value: localize('timeline', "Timeline"), original: 'Timeline' },
|
||||
},
|
||||
|
||||
@@ -251,7 +251,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
|
||||
return new Promise((resolve, _) => {
|
||||
const quickPick = this.quickInputService.createQuickPick<{ label: string, session: AuthenticationSession }>();
|
||||
quickPick.title = localize('chooseAccountTitle', "Preferences Sync: Choose Account");
|
||||
quickPick.placeholder = localize('chooseAccount', "Choose an account you would like to use for settings sync");
|
||||
quickPick.placeholder = localize('chooseAccount', "Choose an account you would like to use for preferences sync");
|
||||
const dedupedSessions = distinct(sessions, (session) => session.accountName);
|
||||
quickPick.items = dedupedSessions.map(session => {
|
||||
return {
|
||||
@@ -287,10 +287,16 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
|
||||
if (this.activeAccount) {
|
||||
if (event.removed.length) {
|
||||
const activeWasRemoved = !!event.removed.find(removed => removed === this.activeAccount!.id);
|
||||
// If the current account was removed, offer to turn off sync
|
||||
if (activeWasRemoved) {
|
||||
await this.turnOff();
|
||||
this.setActiveAccount(undefined);
|
||||
this.notificationService.notify({
|
||||
severity: Severity.Info,
|
||||
message: localize('turned off on logout', "Sync has stopped because you are no longer signed in."),
|
||||
actions: {
|
||||
primary: [new Action('turn on sync', localize('turn on sync', "Turn on Sync"), undefined, true, () => this.turnOn())]
|
||||
}
|
||||
});
|
||||
return;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -683,7 +689,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
|
||||
}
|
||||
await this.handleFirstTimeSync();
|
||||
this.userDataSyncEnablementService.setEnablement(true);
|
||||
this.notificationService.info(localize('sync turned on', "Sync will happen automatically from now on."));
|
||||
this.notificationService.info(localize('sync turned on', "Preferences sync is turned on"));
|
||||
this.storageService.store('sync.donotAskPreviewConfirmation', true, StorageScope.GLOBAL);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ import { URI } from 'vs/base/common/uri';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { FolderThemeIcon } from 'vs/platform/theme/common/themeService';
|
||||
import { fromNow } from 'vs/base/common/date';
|
||||
import { pad } from 'vs/base/common/strings';
|
||||
import { pad, uppercaseFirstLetter } from 'vs/base/common/strings';
|
||||
import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer';
|
||||
|
||||
export class UserDataSyncViewContribution implements IWorkbenchContribution {
|
||||
@@ -101,7 +101,7 @@ export class UserDataSyncViewContribution implements IWorkbenchContribution {
|
||||
constructor() {
|
||||
super({
|
||||
id: `workbench.actions.sync.resolveResource`,
|
||||
title: localize('workbench.actions.sync.resolveResourceRef', "Show full content"),
|
||||
title: localize('workbench.actions.sync.resolveResourceRef', "Show raw JSON sync data"),
|
||||
menu: {
|
||||
id: MenuId.ViewItemContext,
|
||||
when: ContextKeyExpr.and(ContextKeyEqualsExpr.create('view', viewId), ContextKeyExpr.regex('viewItem', /sync-resource-.*/i))
|
||||
@@ -156,7 +156,7 @@ class UserDataSyncHistoryViewDataProvider implements ITreeViewDataProvider {
|
||||
return ALL_SYNC_RESOURCES.map(resourceKey => ({
|
||||
handle: resourceKey,
|
||||
collapsibleState: TreeItemCollapsibleState.Collapsed,
|
||||
label: { label: resourceKey },
|
||||
label: { label: uppercaseFirstLetter(resourceKey) },
|
||||
themeIcon: FolderThemeIcon,
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ interface SerializedIconPath {
|
||||
dark: string | UriComponents;
|
||||
}
|
||||
|
||||
interface SerializedWebview {
|
||||
export interface SerializedWebview {
|
||||
readonly id?: string;
|
||||
readonly viewType: string;
|
||||
readonly title: string;
|
||||
|
||||
@@ -42,7 +42,7 @@ export class CopyWebviewEditorCommand extends Action2 {
|
||||
public static readonly ID = 'editor.action.webvieweditor.copy';
|
||||
public static readonly LABEL = nls.localize('editor.action.webvieweditor.copy', "Copy2");
|
||||
|
||||
constructor(contextKeyExpr: ContextKeyExpression) {
|
||||
constructor(contextKeyExpr: ContextKeyExpression, readonly getActiveElectronBasedWebviewDelegate: (accessor: ServicesAccessor) => ElectronWebviewBasedWebview | undefined = getActiveElectronBasedWebview) {
|
||||
super({
|
||||
id: CopyWebviewEditorCommand.ID,
|
||||
title: CopyWebviewEditorCommand.LABEL,
|
||||
@@ -55,7 +55,7 @@ export class CopyWebviewEditorCommand extends Action2 {
|
||||
}
|
||||
|
||||
public run(accessor: ServicesAccessor): void {
|
||||
getActiveElectronBasedWebview(accessor)?.copy();
|
||||
this.getActiveElectronBasedWebviewDelegate(accessor)?.copy();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ export class PasteWebviewEditorCommand extends Action2 {
|
||||
public static readonly ID = 'editor.action.webvieweditor.paste';
|
||||
public static readonly LABEL = nls.localize('editor.action.webvieweditor.paste', 'Paste');
|
||||
|
||||
constructor(contextKeyExpr: ContextKeyExpression) {
|
||||
constructor(contextKeyExpr: ContextKeyExpression, readonly getActiveElectronBasedWebviewDelegate: (accessor: ServicesAccessor) => ElectronWebviewBasedWebview | undefined = getActiveElectronBasedWebview) {
|
||||
super({
|
||||
id: PasteWebviewEditorCommand.ID,
|
||||
title: PasteWebviewEditorCommand.LABEL,
|
||||
@@ -76,7 +76,7 @@ export class PasteWebviewEditorCommand extends Action2 {
|
||||
}
|
||||
|
||||
public run(accessor: ServicesAccessor): void {
|
||||
getActiveElectronBasedWebview(accessor)?.paste();
|
||||
this.getActiveElectronBasedWebviewDelegate(accessor)?.paste();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ export class CutWebviewEditorCommand extends Action2 {
|
||||
public static readonly ID = 'editor.action.webvieweditor.cut';
|
||||
public static readonly LABEL = nls.localize('editor.action.webvieweditor.cut', 'Cut');
|
||||
|
||||
constructor(contextKeyExpr: ContextKeyExpression) {
|
||||
constructor(contextKeyExpr: ContextKeyExpression, readonly getActiveElectronBasedWebviewDelegate: (accessor: ServicesAccessor) => ElectronWebviewBasedWebview | undefined = getActiveElectronBasedWebview) {
|
||||
super({
|
||||
id: CutWebviewEditorCommand.ID,
|
||||
title: CutWebviewEditorCommand.LABEL,
|
||||
@@ -97,7 +97,7 @@ export class CutWebviewEditorCommand extends Action2 {
|
||||
}
|
||||
|
||||
public run(accessor: ServicesAccessor): void {
|
||||
getActiveElectronBasedWebview(accessor)?.cut();
|
||||
this.getActiveElectronBasedWebviewDelegate(accessor)?.cut();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ export class UndoWebviewEditorCommand extends Action2 {
|
||||
public static readonly ID = 'editor.action.webvieweditor.undo';
|
||||
public static readonly LABEL = nls.localize('editor.action.webvieweditor.undo', "Undo");
|
||||
|
||||
constructor(contextKeyExpr: ContextKeyExpression) {
|
||||
constructor(contextKeyExpr: ContextKeyExpression, readonly getActiveElectronBasedWebviewDelegate: (accessor: ServicesAccessor) => ElectronWebviewBasedWebview | undefined = getActiveElectronBasedWebview) {
|
||||
super({
|
||||
id: UndoWebviewEditorCommand.ID,
|
||||
title: UndoWebviewEditorCommand.LABEL,
|
||||
@@ -118,7 +118,7 @@ export class UndoWebviewEditorCommand extends Action2 {
|
||||
}
|
||||
|
||||
public run(accessor: ServicesAccessor): void {
|
||||
getActiveElectronBasedWebview(accessor)?.undo();
|
||||
this.getActiveElectronBasedWebviewDelegate(accessor)?.undo();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ export class RedoWebviewEditorCommand extends Action2 {
|
||||
public static readonly ID = 'editor.action.webvieweditor.redo';
|
||||
public static readonly LABEL = nls.localize('editor.action.webvieweditor.redo', "Redo");
|
||||
|
||||
constructor(contextKeyExpr: ContextKeyExpression) {
|
||||
constructor(contextKeyExpr: ContextKeyExpression, readonly getActiveElectronBasedWebviewDelegate: (accessor: ServicesAccessor) => ElectronWebviewBasedWebview | undefined = getActiveElectronBasedWebview) {
|
||||
super({
|
||||
id: RedoWebviewEditorCommand.ID,
|
||||
title: RedoWebviewEditorCommand.LABEL,
|
||||
@@ -141,7 +141,7 @@ export class RedoWebviewEditorCommand extends Action2 {
|
||||
}
|
||||
|
||||
public run(accessor: ServicesAccessor): void {
|
||||
getActiveElectronBasedWebview(accessor)?.redo();
|
||||
this.getActiveElectronBasedWebviewDelegate(accessor)?.redo();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,8 +38,17 @@ const viewsWelcomeExtensionPointSchema = Object.freeze<IConfigurationPropertySch
|
||||
],
|
||||
properties: {
|
||||
[ViewsWelcomeExtensionPointFields.view]: {
|
||||
type: 'string',
|
||||
description: nls.localize('contributes.viewsWelcome.view.view', "Target view identifier for this welcome content."),
|
||||
anyOf: [
|
||||
{
|
||||
type: 'string',
|
||||
description: nls.localize('contributes.viewsWelcome.view.view', "Target view identifier for this welcome content.")
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
description: nls.localize('contributes.viewsWelcome.view.view', "Target view identifier for this welcome content."),
|
||||
enum: Object.keys(ViewIdentifierMap)
|
||||
}
|
||||
]
|
||||
},
|
||||
[ViewsWelcomeExtensionPointFields.contents]: {
|
||||
type: 'string',
|
||||
|
||||
Reference in New Issue
Block a user