Merge from vscode 5d18ad4c5902e3bddbc9f78da82dfc2ac349e908 (#9683)

This commit is contained in:
Anthony Dresser
2020-03-20 01:17:27 -07:00
committed by GitHub
parent 1520441b84
commit dd8fb9433b
89 changed files with 3095 additions and 445 deletions

View File

@@ -8,10 +8,12 @@ import { MainContext, MainThreadNotebookShape, NotebookExtensionDescription, IEx
import { Disposable } from 'vs/base/common/lifecycle';
import { URI, UriComponents } from 'vs/base/common/uri';
import { INotebookService, IMainNotebookController } from 'vs/workbench/contrib/notebook/browser/notebookService';
import { INotebookTextModel, INotebookMimeTypeSelector, NOTEBOOK_DISPLAY_ORDER, NotebookCellsSplice, NotebookCellOutputsSplice, CellKind } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotebookTextModel, INotebookMimeTypeSelector, NOTEBOOK_DISPLAY_ORDER, NotebookCellsSplice, NotebookCellOutputsSplice, CellKind, NotebookDocumentMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
export class MainThreadNotebookDocument extends Disposable {
private _textModel: NotebookTextModel;
@@ -54,7 +56,9 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
constructor(
extHostContext: IExtHostContext,
@INotebookService private _notebookService: INotebookService,
@IConfigurationService private readonly configurationService: IConfigurationService
@IConfigurationService private readonly configurationService: IConfigurationService,
@IEditorService private readonly editorService: IEditorService,
) {
super();
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostNotebook);
@@ -123,6 +127,14 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
}
}
async $updateNotebookMetadata(viewType: string, resource: UriComponents, metadata: NotebookDocumentMetadata | undefined): Promise<void> {
let controller = this._notebookProviders.get(viewType);
if (controller) {
controller.updateNotebookMetadata(resource, metadata);
}
}
async resolveNotebook(viewType: string, uri: URI): Promise<number | undefined> {
let handle = await this._proxy.$resolveNotebook(viewType, uri);
return handle;
@@ -141,6 +153,21 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
async executeNotebook(viewType: string, uri: URI): Promise<void> {
return this._proxy.$executeNotebook(viewType, uri, undefined);
}
async $postMessage(handle: number, value: any): Promise<boolean> {
const activeEditorPane = this.editorService.activeEditorPane as any | undefined;
if (activeEditorPane?.isNotebookEditor) {
const notebookEditor = (activeEditorPane as INotebookEditor);
if (notebookEditor.viewModel?.handle === handle) {
notebookEditor.postMessage(value);
return true;
}
}
return false;
}
}
export class MainThreadNotebookController implements IMainNotebookController {
@@ -186,6 +213,10 @@ export class MainThreadNotebookController implements IMainNotebookController {
this._mainThreadNotebook.executeNotebook(viewType, uri);
}
onDidReceiveMessage(uri: UriComponents, message: any): void {
this._proxy.$onDidReceiveMessage(uri, message);
}
// Methods for ExtHost
async createNotebookDocument(handle: number, viewType: string, resource: UriComponents): Promise<void> {
let document = new MainThreadNotebookDocument(this._proxy, handle, viewType, URI.revive(resource));
@@ -197,6 +228,11 @@ export class MainThreadNotebookController implements IMainNotebookController {
document?.textModel.updateLanguages(languages);
}
updateNotebookMetadata(resource: UriComponents, metadata: NotebookDocumentMetadata | undefined) {
let document = this._mapping.get(URI.from(resource).toString());
document?.textModel.updateNotebookMetadata(metadata);
}
updateNotebookRenderers(resource: UriComponents, renderers: number[]): void {
let document = this._mapping.get(URI.from(resource).toString());
document?.textModel.updateRenderers(renderers);
@@ -227,11 +263,11 @@ export class MainThreadNotebookController implements IMainNotebookController {
return false;
}
executeNotebookActiveCell(uri: URI): void {
async executeNotebookActiveCell(uri: URI): Promise<void> {
let mainthreadNotebook = this._mapping.get(URI.from(uri).toString());
if (mainthreadNotebook && mainthreadNotebook.textModel.activeCell) {
this._proxy.$executeNotebook(this._viewType, uri, mainthreadNotebook.textModel.activeCell.handle);
return this._proxy.$executeNotebook(this._viewType, uri, mainthreadNotebook.textModel.activeCell.handle);
}
}

View File

@@ -132,7 +132,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
const extHostWindow = rpcProtocol.set(ExtHostContext.ExtHostWindow, new ExtHostWindow(rpcProtocol));
const extHostProgress = rpcProtocol.set(ExtHostContext.ExtHostProgress, new ExtHostProgress(rpcProtocol.getProxy(MainContext.MainThreadProgress)));
const extHostLabelService = rpcProtocol.set(ExtHostContext.ExtHosLabelService, new ExtHostLabelService(rpcProtocol));
const extHostNotebook = rpcProtocol.set(ExtHostContext.ExtHostNotebook, new ExtHostNotebookController(rpcProtocol, extHostDocumentsAndEditors));
const extHostNotebook = rpcProtocol.set(ExtHostContext.ExtHostNotebook, new ExtHostNotebookController(rpcProtocol, extHostCommands, extHostDocumentsAndEditors));
const extHostTheming = rpcProtocol.set(ExtHostContext.ExtHostTheming, new ExtHostTheming(rpcProtocol));
const extHostAuthentication = rpcProtocol.set(ExtHostContext.ExtHostAuthentication, new ExtHostAuthentication(rpcProtocol));
const extHostTimeline = rpcProtocol.set(ExtHostContext.ExtHostTimeline, new ExtHostTimeline(rpcProtocol, extHostCommands));

View File

@@ -51,7 +51,7 @@ import { TunnelDto } from 'vs/workbench/api/common/extHostTunnelService';
import { TunnelOptions } from 'vs/platform/remote/common/tunnel';
import { Timeline, TimelineChangeEvent, TimelineOptions, TimelineProviderDescriptor, InternalTimelineOptions } from 'vs/workbench/contrib/timeline/common/timeline';
import { revive } from 'vs/base/common/marshalling';
import { INotebookMimeTypeSelector, IOutput, INotebookDisplayOrder } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotebookMimeTypeSelector, IOutput, INotebookDisplayOrder, NotebookCellMetadata, NotebookDocumentMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CallHierarchyItem } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
import { Dto } from 'vs/base/common/types';
@@ -669,6 +669,7 @@ export interface ICellDto {
language: string;
cellKind: CellKind;
outputs: IOutput[];
metadata?: NotebookCellMetadata;
}
export type NotebookCellsSplice = [
@@ -690,8 +691,10 @@ export interface MainThreadNotebookShape extends IDisposable {
$unregisterNotebookRenderer(handle: number): Promise<void>;
$createNotebookDocument(handle: number, viewType: string, resource: UriComponents): Promise<void>;
$updateNotebookLanguages(viewType: string, resource: UriComponents, languages: string[]): Promise<void>;
$updateNotebookMetadata(viewType: string, resource: UriComponents, metadata: NotebookDocumentMetadata | undefined): Promise<void>;
$spliceNotebookCells(viewType: string, resource: UriComponents, splices: NotebookCellsSplice[], renderers: number[]): Promise<void>;
$spliceNotebookCellOutputs(viewType: string, resource: UriComponents, cellHandle: number, splices: NotebookCellOutputsSplice[], renderers: number[]): Promise<void>;
$postMessage(handle: number, value: any): Promise<boolean>;
}
export interface MainThreadUrlsShape extends IDisposable {
@@ -1531,6 +1534,7 @@ export interface ExtHostNotebookShape {
$updateActiveEditor(viewType: string, uri: UriComponents): Promise<void>;
$destoryNotebookDocument(viewType: string, uri: UriComponents): Promise<boolean>;
$acceptDisplayOrder(displayOrder: INotebookDisplayOrder): void;
$onDidReceiveMessage(uri: UriComponents, message: any): void;
}
export interface ExtHostStorageShape {

View File

@@ -14,6 +14,7 @@ import { Emitter, Event } from 'vs/base/common/event';
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
import { INotebookDisplayOrder, ITransformedDisplayOutputDto, IOrderedMimeType, IStreamOutput, IErrorOutput, mimeTypeSupportedByCore, IOutput, sortMimeTypes, diff, CellUri } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { ISplice } from 'vs/base/common/sequence';
import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
export class ExtHostCell implements vscode.NotebookCell {
@@ -31,7 +32,8 @@ export class ExtHostCell implements vscode.NotebookCell {
private _content: string,
public cellKind: CellKind,
public language: string,
outputs: any[]
outputs: any[],
public metadata: vscode.NotebookCellMetadata | undefined,
) {
this.source = this._content.split(/\r|\n|\r\n/g);
this._outputs = outputs;
@@ -129,6 +131,17 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo
this._proxy.$updateNotebookLanguages(this.viewType, this.uri, this._languages);
}
private _metadata: vscode.NotebookDocumentMetadata | undefined = undefined;
get metadata() {
return this._metadata;
}
set metadata(newMetadata: vscode.NotebookDocumentMetadata | undefined) {
this._metadata = newMetadata;
this._proxy.$updateNotebookMetadata(this.viewType, this.uri, this._metadata);
}
private _displayOrder: string[] = [];
get displayOrder() {
@@ -330,11 +343,14 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo
export class ExtHostNotebookEditor extends Disposable implements vscode.NotebookEditor {
private _viewColumn: vscode.ViewColumn | undefined;
private static _cellhandlePool: number = 0;
onDidReceiveMessage: vscode.Event<any> = this._onDidReceiveMessage.event;
constructor(
viewType: string,
readonly id: string,
public uri: URI,
private _proxy: MainThreadNotebookShape,
private _onDidReceiveMessage: Emitter<any>,
public document: ExtHostNotebookDocument,
private _documentsAndEditors: ExtHostDocumentsAndEditors
) {
@@ -362,10 +378,10 @@ export class ExtHostNotebookEditor extends Disposable implements vscode.Notebook
}));
}
createCell(content: string, language: string, type: CellKind, outputs: vscode.CellOutput[]): vscode.NotebookCell {
createCell(content: string, language: string, type: CellKind, outputs: vscode.CellOutput[], metadata: vscode.NotebookCellMetadata | undefined): vscode.NotebookCell {
const handle = ExtHostNotebookEditor._cellhandlePool++;
const uri = CellUri.generate(this.document.uri, handle);
const cell = new ExtHostCell(handle, uri, content, type, language, outputs);
const cell = new ExtHostCell(handle, uri, content, type, language, outputs, metadata);
return cell;
}
@@ -376,6 +392,11 @@ export class ExtHostNotebookEditor extends Disposable implements vscode.Notebook
set viewColumn(value) {
throw readonly('viewColumn');
}
async postMessage(message: any): Promise<boolean> {
return this._proxy.$postMessage(this.document.handle, message);
}
}
export class ExtHostNotebookOutputRenderer {
@@ -415,9 +436,9 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
private static _handlePool: number = 0;
private readonly _proxy: MainThreadNotebookShape;
private readonly _notebookProviders = new Map<string, { readonly provider: vscode.NotebookProvider, readonly extension: IExtensionDescription }>();
private readonly _notebookProviders = new Map<string, { readonly provider: vscode.NotebookProvider, readonly extension: IExtensionDescription; }>();
private readonly _documents = new Map<string, ExtHostNotebookDocument>();
private readonly _editors = new Map<string, ExtHostNotebookEditor>();
private readonly _editors = new Map<string, { editor: ExtHostNotebookEditor, onDidReceiveMessage: Emitter<any> }>();
private readonly _notebookOutputRenderers = new Map<number, ExtHostNotebookOutputRenderer>();
private _outputDisplayOrder: INotebookDisplayOrder | undefined;
@@ -431,8 +452,28 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
return this._activeNotebookDocument;
}
constructor(mainContext: IMainContext, private _documentsAndEditors: ExtHostDocumentsAndEditors) {
constructor(mainContext: IMainContext, commands: ExtHostCommands, private _documentsAndEditors: ExtHostDocumentsAndEditors) {
this._proxy = mainContext.getProxy(MainContext.MainThreadNotebook);
commands.registerArgumentProcessor({
processArgument: arg => {
if (arg && arg.$mid === 12) {
const documentHandle = arg.notebookEditor?.notebookHandle;
const cellHandle = arg.cell.handle;
for (let value of this._editors) {
if (value[1].editor.document.handle === documentHandle) {
const cell = value[1].editor.document.getCell(cellHandle);
if (cell) {
return cell;
}
}
}
return arg;
}
}
});
}
registerNotebookOutputRenderer(
@@ -494,15 +535,19 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
this._documents.set(URI.revive(uri).toString(), document);
}
const onDidReceiveMessage = new Emitter<any>();
let editor = new ExtHostNotebookEditor(
viewType,
`${ExtHostNotebookController._handlePool++}`,
URI.revive(uri),
this._proxy,
onDidReceiveMessage,
this._documents.get(URI.revive(uri).toString())!,
this._documentsAndEditors
);
this._editors.set(URI.revive(uri).toString(), editor);
this._editors.set(URI.revive(uri).toString(), { editor, onDidReceiveMessage });
await provider.provider.resolveNotebook(editor);
// await editor.document.$updateCells();
return editor.document.handle;
@@ -535,7 +580,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
let editor = this._editors.get(URI.revive(uri).toString());
let document = this._documents.get(URI.revive(uri).toString());
let rawCell = editor?.createCell('', language, type, []) as ExtHostCell;
let rawCell = editor?.editor.createCell('', language, type, [], undefined) as ExtHostCell;
document?.insertCell(index, rawCell!);
let allDocuments = this._documentsAndEditors.allDocuments();
@@ -553,6 +598,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
source: rawCell.source,
language: rawCell.language,
cellKind: rawCell.cellKind,
metadata: rawCell.metadata,
outputs: []
};
}
@@ -608,7 +654,8 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
let editor = this._editors.get(URI.revive(uri).toString());
if (editor) {
editor.dispose();
editor.editor.dispose();
editor.onDidReceiveMessage.dispose();
this._editors.delete(URI.revive(uri).toString());
}
@@ -618,4 +665,12 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
$acceptDisplayOrder(displayOrder: INotebookDisplayOrder): void {
this._outputDisplayOrder = displayOrder;
}
$onDidReceiveMessage(uri: UriComponents, message: any): void {
let editor = this._editors.get(URI.revive(uri).toString());
if (editor) {
editor.onDidReceiveMessage.fire(message);
}
}
}

View File

@@ -835,6 +835,8 @@ export namespace CompletionItemKind {
case types.CompletionItemKind.Event: return modes.CompletionItemKind.Event;
case types.CompletionItemKind.Operator: return modes.CompletionItemKind.Operator;
case types.CompletionItemKind.TypeParameter: return modes.CompletionItemKind.TypeParameter;
case types.CompletionItemKind.Issue: return modes.CompletionItemKind.Issue;
case types.CompletionItemKind.User: return modes.CompletionItemKind.User;
}
return modes.CompletionItemKind.Property;
}
@@ -866,6 +868,8 @@ export namespace CompletionItemKind {
case modes.CompletionItemKind.Event: return types.CompletionItemKind.Event;
case modes.CompletionItemKind.Operator: return types.CompletionItemKind.Operator;
case modes.CompletionItemKind.TypeParameter: return types.CompletionItemKind.TypeParameter;
case modes.CompletionItemKind.User: return types.CompletionItemKind.User;
case modes.CompletionItemKind.Issue: return types.CompletionItemKind.Issue;
}
return types.CompletionItemKind.Property;
}

View File

@@ -1348,7 +1348,9 @@ export enum CompletionItemKind {
Struct = 21,
Event = 22,
Operator = 23,
TypeParameter = 24
TypeParameter = 24,
User = 25,
Issue = 26
}
export enum CompletionItemTag {

View File

@@ -56,6 +56,7 @@ namespace schema {
case 'comments/commentThread/context': return MenuId.CommentThreadActions;
case 'comments/comment/title': return MenuId.CommentTitle;
case 'comments/comment/context': return MenuId.CommentActions;
case 'notebook/cell/title': return MenuId.NotebookCellTitle;
case 'extension/context': return MenuId.ExtensionContext;
case 'timeline/title': return MenuId.TimelineTitle;
case 'timeline/item/context': return MenuId.TimelineItemContext;
@@ -217,6 +218,11 @@ namespace schema {
type: 'array',
items: menuItem
},
'notebook/cell/title': {
description: localize('notebook.cell.title', "The contributed notebook cell title menu"),
type: 'array',
items: menuItem
},
'extension/context': {
description: localize('menus.extensionContext', "The extension context menu"),
type: 'array',

View File

@@ -16,7 +16,7 @@ import { IsFullscreenContext } from 'vs/workbench/browser/contextkeys';
import { IsMacNativeContext, IsDevelopmentContext } from 'vs/platform/contextkey/common/contextkeys';
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { IQuickInputButton, IQuickInputService, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput';
import { IQuickInputButton, IQuickInputService, IQuickPickSeparator, IKeyMods } from 'vs/platform/quickinput/common/quickInput';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { ILabelService } from 'vs/platform/label/common/label';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
@@ -27,7 +27,6 @@ import { URI } from 'vs/base/common/uri';
import { getIconClasses } from 'vs/editor/common/services/getIconClasses';
import { FileKind } from 'vs/platform/files/common/files';
import { splitName } from 'vs/base/common/labels';
import { IKeyMods } from 'vs/base/parts/quickopen/common/quickOpen';
import { isMacintosh } from 'vs/base/common/platform';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { inQuickOpenContext, getQuickNavigateHandler } from 'vs/workbench/browser/parts/quickopen/quickopen';

View File

@@ -8,16 +8,20 @@
overflow: hidden;
}
.monaco-workbench .part > .drop-block-overlay.visible {
display: block;
backdrop-filter: brightness(97%) blur(2px);
opacity: 1;
z-index: 10;
}
.monaco-workbench .part > .drop-block-overlay {
visibility: hidden; /* use visibility to ensure transitions */
transition-property: opacity;
transition-timing-function: linear;
transition-duration: 250ms;
display: none;
width: 100%;
height: 100%;
position: absolute;
top: 0;
opacity: 0;
pointer-events: none;
}

View File

@@ -7,12 +7,6 @@
width: 48px;
}
.monaco-workbench .part > .drop-block-overlay.visible {
visibility: visible;
backdrop-filter: brightness(97%) blur(2px);
opacity: 1;
}
.monaco-workbench .activitybar > .content {
height: 100%;
display: flex;

View File

@@ -26,7 +26,7 @@ import { EditorInput, IWorkbenchEditorConfiguration, IEditorInput } from 'vs/wor
import { Component } from 'vs/workbench/common/component';
import { Event, Emitter } from 'vs/base/common/event';
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { QuickOpenHandler, QuickOpenHandlerDescriptor, IQuickOpenRegistry, Extensions, EditorQuickOpenEntry, CLOSE_ON_FOCUS_LOST_CONFIG, SEARCH_EDITOR_HISTORY, PRESERVE_INPUT_CONFIG } from 'vs/workbench/browser/quickopen';
import { QuickOpenHandler, QuickOpenHandlerDescriptor, IQuickOpenRegistry, Extensions, EditorQuickOpenEntry, CLOSE_ON_FOCUS_LOST_CONFIG, SEARCH_EDITOR_HISTORY, PRESERVE_INPUT_CONFIG, ENABLE_EXPERIMENTAL_VERSION_CONFIG } from 'vs/workbench/browser/quickopen';
import * as errors from 'vs/base/common/errors';
import { IQuickOpenService, IShowOptions } from 'vs/platform/quickOpen/common/quickOpen';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
@@ -86,6 +86,10 @@ export class QuickOpenController extends Component implements IQuickOpenService
private editorHistoryHandler: EditorHistoryHandler;
private pendingGetResultsInvocation: CancellationTokenSource | null = null;
private get useNewExperimentalVersion() {
return this.configurationService.getValue(ENABLE_EXPERIMENTAL_VERSION_CONFIG) === true;
}
constructor(
@IEditorGroupsService private readonly editorGroupService: IEditorGroupsService,
@INotificationService private readonly notificationService: INotificationService,
@@ -95,7 +99,8 @@ export class QuickOpenController extends Component implements IQuickOpenService
@IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService,
@IEnvironmentService private readonly environmentService: IEnvironmentService,
@IThemeService themeService: IThemeService,
@IStorageService storageService: IStorageService
@IStorageService storageService: IStorageService,
@IQuickInputService private readonly quickInputService: IQuickInputService
) {
super(QuickOpenController.ID, themeService, storageService);
@@ -125,26 +130,42 @@ export class QuickOpenController extends Component implements IQuickOpenService
}
navigate(next: boolean, quickNavigate?: IQuickNavigateConfiguration): void {
if (this.quickOpenWidget) {
this.quickOpenWidget.navigate(next, quickNavigate);
if (this.useNewExperimentalVersion) {
// already handled
} else {
if (this.quickOpenWidget) {
this.quickOpenWidget.navigate(next, quickNavigate);
}
}
}
accept(): void {
if (this.quickOpenWidget && this.quickOpenWidget.isVisible()) {
this.quickOpenWidget.accept();
if (this.useNewExperimentalVersion) {
// already handled
} else {
if (this.quickOpenWidget && this.quickOpenWidget.isVisible()) {
this.quickOpenWidget.accept();
}
}
}
focus(): void {
if (this.quickOpenWidget && this.quickOpenWidget.isVisible()) {
this.quickOpenWidget.focus();
if (this.useNewExperimentalVersion) {
// already handled
} else {
if (this.quickOpenWidget && this.quickOpenWidget.isVisible()) {
this.quickOpenWidget.focus();
}
}
}
close(): void {
if (this.quickOpenWidget && this.quickOpenWidget.isVisible()) {
this.quickOpenWidget.hide(HideReason.CANCELED);
if (this.useNewExperimentalVersion) {
// already handled
} else {
if (this.quickOpenWidget && this.quickOpenWidget.isVisible()) {
this.quickOpenWidget.hide(HideReason.CANCELED);
}
}
}
@@ -157,6 +178,12 @@ export class QuickOpenController extends Component implements IQuickOpenService
}
show(prefix?: string, options?: IShowOptions): Promise<void> {
if (this.useNewExperimentalVersion) {
this.quickInputService.quickAccess.show(prefix, options);
return Promise.resolve();
}
let quickNavigateConfiguration = options ? options.quickNavigateConfiguration : undefined;
let inputSelection = options ? options.inputSelection : undefined;
let autoFocus = options ? options.autoFocus : undefined;

View File

@@ -336,7 +336,7 @@ export abstract class ViewPane extends Pane implements IView {
}
if (this.progressIndicator === undefined) {
this.progressIndicator = this.instantiationService.createInstance(CompositeProgressIndicator, assertIsDefined(this.progressBar), this.id, this.isVisible());
this.progressIndicator = this.instantiationService.createInstance(CompositeProgressIndicator, assertIsDefined(this.progressBar), this.id, this.isBodyVisible());
}
return this.progressIndicator;
}

View File

@@ -21,6 +21,7 @@ import { CancellationToken } from 'vs/base/common/cancellation';
export const CLOSE_ON_FOCUS_LOST_CONFIG = 'workbench.quickOpen.closeOnFocusLost';
export const PRESERVE_INPUT_CONFIG = 'workbench.quickOpen.preserveInput';
export const ENABLE_EXPERIMENTAL_VERSION_CONFIG = 'workbench.quickOpen.enableExperimentalNewVersion';
export const SEARCH_EDITOR_HISTORY = 'search.quickOpen.includeHistory';
export interface IWorkbenchQuickOpenConfiguration {
@@ -28,6 +29,9 @@ export interface IWorkbenchQuickOpenConfiguration {
commandPalette: {
history: number;
preserveInput: boolean;
},
quickOpen: {
enableExperimentalNewVersion: boolean;
}
};
}

View File

@@ -14,18 +14,22 @@ import { isSafari, isStandalone } from 'vs/base/browser/browser';
registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) => {
// Icon defaults
const iconForegroundColor = theme.getColor(iconForeground);
if (iconForegroundColor) {
collector.addRule(`.monaco-workbench .codicon { color: ${iconForegroundColor}; }`);
}
// Foreground
const windowForeground = theme.getColor(foreground);
if (windowForeground) {
collector.addRule(`.monaco-workbench { color: ${windowForeground}; }`);
}
// Background (We need to set the workbench background color so that on Windows we get subpixel-antialiasing)
const workbenchBackground = WORKBENCH_BACKGROUND(theme);
collector.addRule(`.monaco-workbench { background-color: ${workbenchBackground}; }`);
// Icon defaults
const iconForegroundColor = theme.getColor(iconForeground);
if (iconForegroundColor) {
collector.addRule(`.monaco-workbench .codicon { color: ${iconForegroundColor}; }`);
}
// Selection
const windowSelectionBackground = theme.getColor(selectionBackground);
if (windowSelectionBackground) {
@@ -58,10 +62,6 @@ registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) =
`);
}
// We need to set the workbench background color so that on Windows we get subpixel-antialiasing.
const workbenchBackground = WORKBENCH_BACKGROUND(theme);
collector.addRule(`.monaco-workbench { background-color: ${workbenchBackground}; }`);
// Scrollbars
const scrollbarShadowColor = theme.getColor(scrollbarShadow);
if (scrollbarShadowColor) {

View File

@@ -179,6 +179,11 @@ import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuratio
'description': nls.localize('workbench.quickOpen.preserveInput', "Controls whether the last typed input to Quick Open should be restored when opening it the next time."),
'default': false
},
'workbench.quickOpen.enableExperimentalNewVersion': {
'type': 'boolean',
'description': nls.localize('workbench.quickOpen.enableExperimentalNewVersion', "Will use the new quick open implementation for testing purposes."),
'default': false
},
'workbench.settings.openDefaultSettings': {
'type': 'boolean',
'description': nls.localize('openDefaultSettings', "Controls whether opening settings also opens an editor showing all default settings."),

View File

@@ -323,6 +323,9 @@ export class Workbench extends Layout {
private renderWorkbench(instantiationService: IInstantiationService, notificationService: NotificationService, storageService: IStorageService, configurationService: IConfigurationService): void {
// ARIA
this.container.setAttribute('role', 'application');
// State specific classes
const platformClass = isWindows ? 'windows' : isLinux ? 'linux' : 'mac';
const workbenchClasses = coalesce([
@@ -335,7 +338,6 @@ export class Workbench extends Layout {
addClasses(this.container, ...workbenchClasses);
addClass(document.body, platformClass); // used by our fonts
this.container.setAttribute('role', 'application');
if (isWeb) {
addClass(document.body, 'web');

View File

@@ -37,19 +37,19 @@ export class GotoLineQuickAccessProvider extends AbstractGotoLineQuickAccessProv
return this.editorService.activeTextEditorControl;
}
protected gotoLocation(editor: IEditor, range: IRange, keyMods: IKeyMods, forceSideBySide?: boolean): void {
protected gotoLocation(editor: IEditor, options: { range: IRange, keyMods: IKeyMods, forceSideBySide?: boolean }): void {
// Check for sideBySide use
if ((keyMods.ctrlCmd || forceSideBySide) && this.editorService.activeEditor) {
if ((options.keyMods.ctrlCmd || options.forceSideBySide) && this.editorService.activeEditor) {
this.editorService.openEditor(this.editorService.activeEditor, {
selection: range,
pinned: keyMods.alt || this.configuration.openEditorPinned
selection: options.range,
pinned: options.keyMods.alt || this.configuration.openEditorPinned
}, SIDE_GROUP);
}
// Otherwise let parent handle it
else {
super.gotoLocation(editor, range, keyMods);
super.gotoLocation(editor, options);
}
}
}

View File

@@ -40,19 +40,19 @@ export class GotoSymbolQuickAccessProvider extends AbstractGotoSymbolQuickAccess
return this.editorService.activeTextEditorControl;
}
protected gotoLocation(editor: IEditor, range: IRange, keyMods: IKeyMods, forceSideBySide?: boolean): void {
protected gotoLocation(editor: IEditor, options: { range: IRange, keyMods: IKeyMods, forceSideBySide?: boolean }): void {
// Check for sideBySide use
if ((keyMods.ctrlCmd || forceSideBySide) && this.editorService.activeEditor) {
if ((options.keyMods.ctrlCmd || options.forceSideBySide) && this.editorService.activeEditor) {
this.editorService.openEditor(this.editorService.activeEditor, {
selection: range,
pinned: keyMods.alt || this.configuration.openEditorPinned
selection: options.range,
pinned: options.keyMods.alt || this.configuration.openEditorPinned
}, SIDE_GROUP);
}
// Otherwise let parent handle it
else {
super.gotoLocation(editor, range, keyMods);
super.gotoLocation(editor, options);
}
}
}

View File

@@ -162,6 +162,15 @@ export class ConfigurationManager implements IConfigurationManager {
return Promise.resolve(undefined);
}
getDebuggerLabel(session: IDebugSession): string | undefined {
const dbgr = this.getDebugger(session.configuration.type);
if (dbgr) {
return dbgr.label;
}
return undefined;
}
get onDidRegisterDebugger(): Event<void> {
return this._onDidRegisterDebugger.event;
}

View File

@@ -34,12 +34,31 @@ export class DebugProgressContribution implements IWorkbenchContribution {
});
this.progressService.withProgress({ location: VIEWLET_ID }, () => promise);
const source = this.debugService.getConfigurationManager().getDebuggerLabel(session);
this.progressService.withProgress({
location: ProgressLocation.Notification,
title: progressStartEvent.body.title,
cancellable: progressStartEvent.body.cancellable,
silent: true
}, () => promise, () => session.cancel(progressStartEvent.body.progressId));
silent: true,
source,
delay: 500
}, progressStep => {
let increment = 0;
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,
});
}
});
return promise.then(() => progressUpdateListener.dispose());
}, () => session.cancel(progressStartEvent.body.progressId));
});
}
};

View File

@@ -55,6 +55,7 @@ export class DebugSession implements IDebugSession {
private readonly _onDidLoadedSource = new Emitter<LoadedSourceEvent>();
private readonly _onDidCustomEvent = new Emitter<DebugProtocol.Event>();
private readonly _onDidProgressStart = new Emitter<DebugProtocol.ProgressStartEvent>();
private readonly _onDidProgressUpdate = new Emitter<DebugProtocol.ProgressUpdateEvent>();
private readonly _onDidProgressEnd = new Emitter<DebugProtocol.ProgressEndEvent>();
private readonly _onDidChangeREPLElements = new Emitter<void>();
@@ -190,6 +191,10 @@ export class DebugSession implements IDebugSession {
return this._onDidProgressStart.event;
}
get onDidProgressUpdate(): Event<DebugProtocol.ProgressUpdateEvent> {
return this._onDidProgressUpdate.event;
}
get onDidProgressEnd(): Event<DebugProtocol.ProgressEndEvent> {
return this._onDidProgressEnd.event;
}
@@ -935,6 +940,9 @@ export class DebugSession implements IDebugSession {
this.rawListeners.push(this.raw.onDidProgressStart(event => {
this._onDidProgressStart.fire(event);
}));
this.rawListeners.push(this.raw.onDidProgressUpdate(event => {
this._onDidProgressUpdate.fire(event);
}));
this.rawListeners.push(this.raw.onDidProgressEnd(event => {
this._onDidProgressEnd.fire(event);
}));

View File

@@ -66,6 +66,7 @@ export class RawDebugSession implements IDisposable {
private readonly _onDidBreakpoint = new Emitter<DebugProtocol.BreakpointEvent>();
private readonly _onDidLoadedSource = new Emitter<DebugProtocol.LoadedSourceEvent>();
private readonly _onDidProgressStart = new Emitter<DebugProtocol.ProgressStartEvent>();
private readonly _onDidProgressUpdate = new Emitter<DebugProtocol.ProgressUpdateEvent>();
private readonly _onDidProgressEnd = new Emitter<DebugProtocol.ProgressEndEvent>();
private readonly _onDidCustomEvent = new Emitter<DebugProtocol.Event>();
private readonly _onDidEvent = new Emitter<DebugProtocol.Event>();
@@ -142,6 +143,9 @@ export class RawDebugSession implements IDisposable {
case 'progressStart':
this._onDidProgressStart.fire(event as DebugProtocol.ProgressStartEvent);
break;
case 'progressUpdate':
this._onDidProgressUpdate.fire(event as DebugProtocol.ProgressUpdateEvent);
break;
case 'progressEnd':
this._onDidProgressEnd.fire(event as DebugProtocol.ProgressEndEvent);
break;
@@ -217,6 +221,10 @@ export class RawDebugSession implements IDisposable {
return this._onDidProgressStart.event;
}
get onDidProgressUpdate(): Event<DebugProtocol.ProgressUpdateEvent> {
return this._onDidProgressUpdate.event;
}
get onDidProgressEnd(): Event<DebugProtocol.ProgressEndEvent> {
return this._onDidProgressEnd.event;
}

View File

@@ -200,6 +200,7 @@ export interface IDebugSession extends ITreeElement {
readonly onDidLoadedSource: Event<LoadedSourceEvent>;
readonly onDidCustomEvent: Event<DebugProtocol.Event>;
readonly onDidProgressStart: Event<DebugProtocol.ProgressStartEvent>;
readonly onDidProgressUpdate: Event<DebugProtocol.ProgressUpdateEvent>;
readonly onDidProgressEnd: Event<DebugProtocol.ProgressEndEvent>;
// DAP request
@@ -662,6 +663,7 @@ export interface IConfigurationManager {
resolveConfigurationByProviders(folderUri: uri | undefined, type: string | undefined, debugConfiguration: any, token: CancellationToken): Promise<any>;
getDebugAdapterDescriptor(session: IDebugSession): Promise<IAdapterDescriptor | undefined>;
getDebuggerLabel(session: IDebugSession): string | undefined;
registerDebugAdapterFactory(debugTypes: string[], debugAdapterFactory: IDebugAdapterFactory): IDisposable;
createDebugAdapter(session: IDebugSession): IDebugAdapter | undefined;

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/** Declaration module describing the VS Code debug protocol.
Auto-generated from json schema. Do not edit manually.
*/
@@ -72,12 +72,15 @@ declare module DebugProtocol {
/** Cancel request; value of command field is 'cancel'.
The 'cancel' request is used by the frontend in two situations:
- to indicate that it is no longer interested in the result produced by a specific request issued earlier
- to cancel a progress sequence.
- to cancel a progress sequence. Clients should only call this request if the capability 'supportsCancelRequest' is true.
This request has a hint characteristic: a debug adapter can only be expected to make a 'best effort' in honouring this request but there are no guarantees.
The 'cancel' request may return an error if it could not cancel an operation but a frontend should refrain from presenting this error to end users.
A frontend client should only call this request if the capability 'supportsCancelRequest' is true.
The request that got canceled still needs to send a response back. This can either be a normal result ('success' attribute true) or an error response ('success' attribute false and the 'message' set to 'cancelled'). Returning partial results from a cancelled request is possible but please note that a frontend client has no generic way for detecting that a response is partial or not.
The progress that got cancelled still needs to send a 'progressEnd' event back. A client should not assume that progress just got cancelled after sending the 'cancel' request.
The request that got canceled still needs to send a response back. This can either be a normal result ('success' attribute true)
or an error response ('success' attribute false and the 'message' set to 'cancelled').
Returning partial results from a cancelled request is possible but please note that a frontend client has no generic way for detecting that a response is partial or not.
The progress that got cancelled still needs to send a 'progressEnd' event back.
A client should not assume that progress just got cancelled after sending the 'cancel' request.
*/
export interface CancelRequest extends Request {
// command: 'cancel';
@@ -86,9 +89,13 @@ declare module DebugProtocol {
/** Arguments for 'cancel' request. */
export interface CancelArguments {
/** The ID (attribute 'seq') of the request to cancel. If missing no request is cancelled. Both a 'requestId' and a 'progressId' can be specified in one request. */
/** The ID (attribute 'seq') of the request to cancel. If missing no request is cancelled.
Both a 'requestId' and a 'progressId' can be specified in one request.
*/
requestId?: number;
/** The ID (attribute 'progressId') of the progress to cancel. If missing no progress is cancelled. Both a 'requestId' and a 'progressId' can be specified in one request. */
/** The ID (attribute 'progressId') of the progress to cancel. If missing no progress is cancelled.
Both a 'requestId' and a 'progressId' can be specified in one request.
*/
progressId?: string;
}
@@ -309,11 +316,14 @@ declare module DebugProtocol {
The event signals that a long running operation is about to start and
provides additional information for the client to set up a corresponding progress and cancellation UI.
The client is free to delay the showing of the UI in order to reduce flicker.
This event should only be sent if the client has passed the value true for the 'supportsProgressReporting' capability of the 'initialize' request.
*/
export interface ProgressStartEvent extends Event {
// event: 'progressStart';
body: {
/** An ID that must be used in subsequent 'progressUpdate' and 'progressEnd' events to make them refer to the same progress reporting. IDs must be unique within a debug session. */
/** An ID that must be used in subsequent 'progressUpdate' and 'progressEnd' events to make them refer to the same progress reporting.
IDs must be unique within a debug session.
*/
progressId: string;
/** Mandatory (short) title of the progress reporting. Shown in the UI to describe the long running operation. */
title: string;
@@ -337,6 +347,7 @@ declare module DebugProtocol {
/** Event message for 'progressUpdate' event type.
The event signals that the progress reporting needs to updated with a new message and/or percentage.
The client does not have to update the UI immediately, but the clients needs to keep track of the message and/or percentage values.
This event should only be sent if the client has passed the value true for the 'supportsProgressReporting' capability of the 'initialize' request.
*/
export interface ProgressUpdateEvent extends Event {
// event: 'progressUpdate';
@@ -352,6 +363,7 @@ declare module DebugProtocol {
/** Event message for 'progressEnd' event type.
The event signals the end of the progress reporting with an optional final message.
This event should only be sent if the client has passed the value true for the 'supportsProgressReporting' capability of the 'initialize' request.
*/
export interface ProgressEndEvent extends Event {
// event: 'progressEnd';
@@ -364,7 +376,9 @@ declare module DebugProtocol {
}
/** RunInTerminal request; value of command field is 'runInTerminal'.
This request is sent from the debug adapter to the client to run a command in a terminal. This is typically used to launch the debuggee in a terminal provided by the client.
This optional request is sent from the debug adapter to the client to run a command in a terminal.
This is typically used to launch the debuggee in a terminal provided by the client.
This request should only be called if the client has passed the value true for the 'supportsRunInTerminalRequest' capability of the 'initialize' request.
*/
export interface RunInTerminalRequest extends Request {
// command: 'runInTerminal';
@@ -396,8 +410,10 @@ declare module DebugProtocol {
}
/** Initialize request; value of command field is 'initialize'.
The 'initialize' request is sent as the first request from the client to the debug adapter in order to configure it with client capabilities and to retrieve capabilities from the debug adapter.
Until the debug adapter has responded to with an 'initialize' response, the client must not send any additional requests or events to the debug adapter. In addition the debug adapter is not allowed to send any requests or events to the client until it has responded with an 'initialize' response.
The 'initialize' request is sent as the first request from the client to the debug adapter
in order to configure it with client capabilities and to retrieve capabilities from the debug adapter.
Until the debug adapter has responded to with an 'initialize' response, the client must not send any additional requests or events to the debug adapter.
In addition the debug adapter is not allowed to send any requests or events to the client until it has responded with an 'initialize' response.
The 'initialize' request may only be sent once.
*/
export interface InitializeRequest extends Request {
@@ -442,7 +458,9 @@ declare module DebugProtocol {
}
/** ConfigurationDone request; value of command field is 'configurationDone'.
The client of the debug protocol must send this request at the end of the sequence of configuration requests (which was started by the 'initialized' event).
This optional request indicates that the client has finished initialization of the debug adapter.
So it is the last request in the sequence of configuration requests (which was started by the 'initialized' event).
Clients should only call this request if the capability 'supportsConfigurationDoneRequest' is true.
*/
export interface ConfigurationDoneRequest extends Request {
// command: 'configurationDone';
@@ -458,7 +476,8 @@ declare module DebugProtocol {
}
/** Launch request; value of command field is 'launch'.
The launch request is sent from the client to the debug adapter to start the debuggee with or without debugging (if 'noDebug' is true). Since launching is debugger/runtime specific, the arguments for this request are not part of this specification.
This launch request is sent from the client to the debug adapter to start the debuggee with or without debugging (if 'noDebug' is true).
Since launching is debugger/runtime specific, the arguments for this request are not part of this specification.
*/
export interface LaunchRequest extends Request {
// command: 'launch';
@@ -481,7 +500,8 @@ declare module DebugProtocol {
}
/** Attach request; value of command field is 'attach'.
The attach request is sent from the client to the debug adapter to attach to a debuggee that is already running. Since attaching is debugger/runtime specific, the arguments for this request are not part of this specification.
The attach request is sent from the client to the debug adapter to attach to a debuggee that is already running.
Since attaching is debugger/runtime specific, the arguments for this request are not part of this specification.
*/
export interface AttachRequest extends Request {
// command: 'attach';
@@ -502,10 +522,8 @@ declare module DebugProtocol {
}
/** Restart request; value of command field is 'restart'.
Restarts a debug session. If the capability 'supportsRestartRequest' is missing or has the value false,
the client will implement 'restart' by terminating the debug adapter first and then launching it anew.
A debug adapter can override this default behaviour by implementing a restart request
and setting the capability 'supportsRestartRequest' to true.
Restarts a debug session. Clients should only call this request if the capability 'supportsRestartRequest' is true.
If the capability is missing or has the value false, a typical client will emulate 'restart' by terminating the debug adapter first and then launching it anew.
*/
export interface RestartRequest extends Request {
// command: 'restart';
@@ -521,7 +539,11 @@ declare module DebugProtocol {
}
/** Disconnect request; value of command field is 'disconnect'.
The 'disconnect' request is sent from the client to the debug adapter in order to stop debugging. It asks the debug adapter to disconnect from the debuggee and to terminate the debug adapter. If the debuggee has been started with the 'launch' request, the 'disconnect' request terminates the debuggee. If the 'attach' request was used to connect to the debuggee, 'disconnect' does not terminate the debuggee. This behavior can be controlled with the 'terminateDebuggee' argument (if supported by the debug adapter).
The 'disconnect' request is sent from the client to the debug adapter in order to stop debugging.
It asks the debug adapter to disconnect from the debuggee and to terminate the debug adapter.
If the debuggee has been started with the 'launch' request, the 'disconnect' request terminates the debuggee.
If the 'attach' request was used to connect to the debuggee, 'disconnect' does not terminate the debuggee.
This behavior can be controlled with the 'terminateDebuggee' argument (if supported by the debug adapter).
*/
export interface DisconnectRequest extends Request {
// command: 'disconnect';
@@ -534,7 +556,7 @@ declare module DebugProtocol {
restart?: boolean;
/** Indicates whether the debuggee should be terminated when the debugger is disconnected.
If unspecified, the debug adapter is free to do whatever it thinks is best.
A client can only rely on this attribute being properly honored if a debug adapter returns true for the 'supportTerminateDebuggee' capability.
The attribute is only honored by a debug adapter if the capability 'supportTerminateDebuggee' is true.
*/
terminateDebuggee?: boolean;
}
@@ -545,6 +567,7 @@ declare module DebugProtocol {
/** Terminate request; value of command field is 'terminate'.
The 'terminate' request is sent from the client to the debug adapter in order to give the debuggee a chance for terminating itself.
Clients should only call this request if the capability 'supportsTerminateRequest' is true.
*/
export interface TerminateRequest extends Request {
// command: 'terminate';
@@ -563,6 +586,7 @@ declare module DebugProtocol {
/** BreakpointLocations request; value of command field is 'breakpointLocations'.
The 'breakpointLocations' request returns all possible locations for source breakpoints in a given range.
Clients should only call this request if the capability 'supportsBreakpointLocationsRequest' is true.
*/
export interface BreakpointLocationsRequest extends Request {
// command: 'breakpointLocations';
@@ -623,7 +647,9 @@ declare module DebugProtocol {
*/
export interface SetBreakpointsResponse extends Response {
body: {
/** Information about the breakpoints. The array elements are in the same order as the elements of the 'breakpoints' (or the deprecated 'lines') array in the arguments. */
/** Information about the breakpoints.
The array elements are in the same order as the elements of the 'breakpoints' (or the deprecated 'lines') array in the arguments.
*/
breakpoints: Breakpoint[];
};
}
@@ -632,6 +658,7 @@ declare module DebugProtocol {
Replaces all existing function breakpoints with new function breakpoints.
To clear all function breakpoints, specify an empty array.
When a function breakpoint is hit, a 'stopped' event (with reason 'function breakpoint') is generated.
Clients should only call this request if the capability 'supportsFunctionBreakpoints' is true.
*/
export interface SetFunctionBreakpointsRequest extends Request {
// command: 'setFunctionBreakpoints';
@@ -655,7 +682,9 @@ declare module DebugProtocol {
}
/** SetExceptionBreakpoints request; value of command field is 'setExceptionBreakpoints'.
The request configures the debuggers response to thrown exceptions. If an exception is configured to break, a 'stopped' event is fired (with reason 'exception').
The request configures the debuggers response to thrown exceptions.
If an exception is configured to break, a 'stopped' event is fired (with reason 'exception').
Clients should only call this request if the capability 'exceptionBreakpointFilters' returns one or more filters.
*/
export interface SetExceptionBreakpointsRequest extends Request {
// command: 'setExceptionBreakpoints';
@@ -666,7 +695,9 @@ declare module DebugProtocol {
export interface SetExceptionBreakpointsArguments {
/** IDs of checked exception options. The set of IDs is returned via the 'exceptionBreakpointFilters' capability. */
filters: string[];
/** Configuration options for selected exceptions. */
/** Configuration options for selected exceptions.
The attribute is only honored by a debug adapter if the capability 'supportsExceptionOptions' is true.
*/
exceptionOptions?: ExceptionOptions[];
}
@@ -676,6 +707,7 @@ declare module DebugProtocol {
/** DataBreakpointInfo request; value of command field is 'dataBreakpointInfo'.
Obtains information on a possible data breakpoint that could be set on an expression or variable.
Clients should only call this request if the capability 'supportsDataBreakpoints' is true.
*/
export interface DataBreakpointInfoRequest extends Request {
// command: 'dataBreakpointInfo';
@@ -686,7 +718,9 @@ declare module DebugProtocol {
export interface DataBreakpointInfoArguments {
/** Reference to the Variable container if the data breakpoint is requested for a child of the container. */
variablesReference?: number;
/** The name of the Variable's child to obtain data breakpoint information for. If variableReference isnt provided, this can be an expression. */
/** The name of the Variable's child to obtain data breakpoint information for.
If variableReference isnt provided, this can be an expression.
*/
name: string;
}
@@ -708,6 +742,7 @@ declare module DebugProtocol {
Replaces all existing data breakpoints with new data breakpoints.
To clear all data breakpoints, specify an empty array.
When a data breakpoint is hit, a 'stopped' event (with reason 'data breakpoint') is generated.
Clients should only call this request if the capability 'supportsDataBreakpoints' is true.
*/
export interface SetDataBreakpointsRequest extends Request {
// command: 'setDataBreakpoints';
@@ -740,14 +775,18 @@ declare module DebugProtocol {
/** Arguments for 'continue' request. */
export interface ContinueArguments {
/** Continue execution for the specified thread (if possible). If the backend cannot continue on a single thread but will continue on all threads, it should set the 'allThreadsContinued' attribute in the response to true. */
/** Continue execution for the specified thread (if possible).
If the backend cannot continue on a single thread but will continue on all threads, it should set the 'allThreadsContinued' attribute in the response to true.
*/
threadId: number;
}
/** Response to 'continue' request. */
export interface ContinueResponse extends Response {
body: {
/** If true, the 'continue' request has ignored the specified thread and continued all threads instead. If this attribute is missing a value of 'true' is assumed for backward compatibility. */
/** If true, the 'continue' request has ignored the specified thread and continued all threads instead.
If this attribute is missing a value of 'true' is assumed for backward compatibility.
*/
allThreadsContinued?: boolean;
};
}
@@ -817,7 +856,8 @@ declare module DebugProtocol {
/** StepBack request; value of command field is 'stepBack'.
The request starts the debuggee to run one step backwards.
The debug adapter first sends the response and then a 'stopped' event (with reason 'step') after the step has completed. Clients should only call this request if the capability 'supportsStepBack' is true.
The debug adapter first sends the response and then a 'stopped' event (with reason 'step') after the step has completed.
Clients should only call this request if the capability 'supportsStepBack' is true.
*/
export interface StepBackRequest extends Request {
// command: 'stepBack';
@@ -835,7 +875,8 @@ declare module DebugProtocol {
}
/** ReverseContinue request; value of command field is 'reverseContinue'.
The request starts the debuggee to run backward. Clients should only call this request if the capability 'supportsStepBack' is true.
The request starts the debuggee to run backward.
Clients should only call this request if the capability 'supportsStepBack' is true.
*/
export interface ReverseContinueRequest extends Request {
// command: 'reverseContinue';
@@ -855,6 +896,7 @@ declare module DebugProtocol {
/** RestartFrame request; value of command field is 'restartFrame'.
The request restarts execution of the specified stackframe.
The debug adapter first sends the response and then a 'stopped' event (with reason 'restart') after the restart has completed.
Clients should only call this request if the capability 'supportsRestartFrame' is true.
*/
export interface RestartFrameRequest extends Request {
// command: 'restartFrame';
@@ -876,6 +918,7 @@ declare module DebugProtocol {
This makes it possible to skip the execution of code or to executed code again.
The code between the current location and the goto target is not executed but skipped.
The debug adapter first sends the response and then a 'stopped' event with reason 'goto'.
Clients should only call this request if the capability 'supportsGotoTargetsRequest' is true (because only then goto targets exist that can be passed as arguments).
*/
export interface GotoRequest extends Request {
// command: 'goto';
@@ -929,7 +972,9 @@ declare module DebugProtocol {
startFrame?: number;
/** The maximum number of frames to return. If levels is not specified or 0, all frames are returned. */
levels?: number;
/** Specifies details on how to format the stack frames. */
/** Specifies details on how to format the stack frames.
The attribute is only honored by a debug adapter if the capability 'supportsValueFormattingOptions' is true.
*/
format?: StackFrameFormat;
}
@@ -986,7 +1031,9 @@ declare module DebugProtocol {
start?: number;
/** The number of variables to return. If count is missing or 0, all variables are returned. */
count?: number;
/** Specifies details on how to format the Variable values. */
/** Specifies details on how to format the Variable values.
The attribute is only honored by a debug adapter if the capability 'supportsValueFormattingOptions' is true.
*/
format?: ValueFormat;
}
@@ -999,7 +1046,7 @@ declare module DebugProtocol {
}
/** SetVariable request; value of command field is 'setVariable'.
Set the variable with the given name in the variable container to a new value.
Set the variable with the given name in the variable container to a new value. Clients should only call this request if the capability 'supportsSetVariable' is true.
*/
export interface SetVariableRequest extends Request {
// command: 'setVariable';
@@ -1025,14 +1072,18 @@ declare module DebugProtocol {
value: string;
/** The type of the new value. Typically shown in the UI when hovering over the value. */
type?: string;
/** If variablesReference is > 0, the new value is structured and its children can be retrieved by passing variablesReference to the VariablesRequest. The value should be less than or equal to 2147483647 (2^31 - 1). */
/** If variablesReference is > 0, the new value is structured and its children can be retrieved by passing variablesReference to the VariablesRequest.
The value should be less than or equal to 2147483647 (2^31 - 1).
*/
variablesReference?: number;
/** The number of named child variables.
The client can use this optional information to present the variables in a paged UI and fetch them in chunks. The value should be less than or equal to 2147483647 (2^31 - 1).
The client can use this optional information to present the variables in a paged UI and fetch them in chunks.
The value should be less than or equal to 2147483647 (2^31 - 1).
*/
namedVariables?: number;
/** The number of indexed child variables.
The client can use this optional information to present the variables in a paged UI and fetch them in chunks. The value should be less than or equal to 2147483647 (2^31 - 1).
The client can use this optional information to present the variables in a paged UI and fetch them in chunks.
The value should be less than or equal to 2147483647 (2^31 - 1).
*/
indexedVariables?: number;
};
@@ -1050,7 +1101,9 @@ declare module DebugProtocol {
export interface SourceArguments {
/** Specifies the source content to load. Either source.path or source.sourceReference must be specified. */
source?: Source;
/** The reference to the source. This is the same as source.sourceReference. This is provided for backward compatibility since old backends do not understand the 'source' attribute. */
/** The reference to the source. This is the same as source.sourceReference.
This is provided for backward compatibility since old backends do not understand the 'source' attribute.
*/
sourceReference: number;
}
@@ -1081,6 +1134,7 @@ declare module DebugProtocol {
/** TerminateThreads request; value of command field is 'terminateThreads'.
The request terminates the threads with the given ids.
Clients should only call this request if the capability 'supportsTerminateThreadsRequest' is true.
*/
export interface TerminateThreadsRequest extends Request {
// command: 'terminateThreads';
@@ -1098,7 +1152,8 @@ declare module DebugProtocol {
}
/** Modules request; value of command field is 'modules'.
Modules can be retrieved from the debug adapter with the ModulesRequest which can either return all modules or a range of modules to support paging.
Modules can be retrieved from the debug adapter with this request which can either return all modules or a range of modules to support paging.
Clients should only call this request if the capability 'supportsModulesRequest' is true.
*/
export interface ModulesRequest extends Request {
// command: 'modules';
@@ -1125,6 +1180,7 @@ declare module DebugProtocol {
/** LoadedSources request; value of command field is 'loadedSources'.
Retrieves the set of all sources currently loaded by the debugged process.
Clients should only call this request if the capability 'supportsLoadedSourcesRequest' is true.
*/
export interface LoadedSourcesRequest extends Request {
// command: 'loadedSources';
@@ -1164,10 +1220,13 @@ declare module DebugProtocol {
'repl': evaluate is run from REPL console.
'hover': evaluate is run from a data hover.
'clipboard': evaluate is run to generate the value that will be stored in the clipboard.
The attribute is only honored by a debug adapter if the capability 'supportsClipboardContext' is true.
etc.
*/
context?: string;
/** Specifies details on how to format the Evaluate result. */
/** Specifies details on how to format the Evaluate result.
The attribute is only honored by a debug adapter if the capability 'supportsValueFormattingOptions' is true.
*/
format?: ValueFormat;
}
@@ -1176,21 +1235,30 @@ declare module DebugProtocol {
body: {
/** The result of the evaluate request. */
result: string;
/** The optional type of the evaluate result. */
/** The optional type of the evaluate result.
This attribute should only be returned by a debug adapter if the client has passed the value true for the 'supportsVariableType' capability of the 'initialize' request.
*/
type?: string;
/** Properties of a evaluate result that can be used to determine how to render the result in the UI. */
presentationHint?: VariablePresentationHint;
/** If variablesReference is > 0, the evaluate result is structured and its children can be retrieved by passing variablesReference to the VariablesRequest. The value should be less than or equal to 2147483647 (2^31 - 1). */
/** If variablesReference is > 0, the evaluate result is structured and its children can be retrieved by passing variablesReference to the VariablesRequest.
The value should be less than or equal to 2147483647 (2^31 - 1).
*/
variablesReference: number;
/** The number of named child variables.
The client can use this optional information to present the variables in a paged UI and fetch them in chunks. The value should be less than or equal to 2147483647 (2^31 - 1).
The client can use this optional information to present the variables in a paged UI and fetch them in chunks.
The value should be less than or equal to 2147483647 (2^31 - 1).
*/
namedVariables?: number;
/** The number of indexed child variables.
The client can use this optional information to present the variables in a paged UI and fetch them in chunks. The value should be less than or equal to 2147483647 (2^31 - 1).
The client can use this optional information to present the variables in a paged UI and fetch them in chunks.
The value should be less than or equal to 2147483647 (2^31 - 1).
*/
indexedVariables?: number;
/** Memory reference to a location appropriate for this result. For pointer type eval results, this is generally a reference to the memory address contained in the pointer. */
/** Optional memory reference to a location appropriate for this result.
For pointer type eval results, this is generally a reference to the memory address contained in the pointer.
This attribute should be returned by a debug adapter if the client has passed the value true for the 'supportsMemoryReferences' capability of the 'initialize' request.
*/
memoryReference?: string;
};
}
@@ -1198,6 +1266,7 @@ declare module DebugProtocol {
/** SetExpression request; value of command field is 'setExpression'.
Evaluates the given 'value' expression and assigns it to the 'expression' which must be a modifiable l-value.
The expressions have access to any variables and arguments that are in scope of the specified frame.
Clients should only call this request if the capability 'supportsSetExpression' is true.
*/
export interface SetExpressionRequest extends Request {
// command: 'setExpression';
@@ -1221,18 +1290,24 @@ declare module DebugProtocol {
body: {
/** The new value of the expression. */
value: string;
/** The optional type of the value. */
/** The optional type of the value.
This attribute should only be returned by a debug adapter if the client has passed the value true for the 'supportsVariableType' capability of the 'initialize' request.
*/
type?: string;
/** Properties of a value that can be used to determine how to render the result in the UI. */
presentationHint?: VariablePresentationHint;
/** If variablesReference is > 0, the value is structured and its children can be retrieved by passing variablesReference to the VariablesRequest. The value should be less than or equal to 2147483647 (2^31 - 1). */
/** If variablesReference is > 0, the value is structured and its children can be retrieved by passing variablesReference to the VariablesRequest.
The value should be less than or equal to 2147483647 (2^31 - 1).
*/
variablesReference?: number;
/** The number of named child variables.
The client can use this optional information to present the variables in a paged UI and fetch them in chunks. The value should be less than or equal to 2147483647 (2^31 - 1).
The client can use this optional information to present the variables in a paged UI and fetch them in chunks.
The value should be less than or equal to 2147483647 (2^31 - 1).
*/
namedVariables?: number;
/** The number of indexed child variables.
The client can use this optional information to present the variables in a paged UI and fetch them in chunks. The value should be less than or equal to 2147483647 (2^31 - 1).
The client can use this optional information to present the variables in a paged UI and fetch them in chunks.
The value should be less than or equal to 2147483647 (2^31 - 1).
*/
indexedVariables?: number;
};
@@ -1242,6 +1317,7 @@ declare module DebugProtocol {
This request retrieves the possible stepIn targets for the specified stack frame.
These targets can be used in the 'stepIn' request.
The StepInTargets may only be called if the 'supportsStepInTargetsRequest' capability exists and is true.
Clients should only call this request if the capability 'supportsStepInTargetsRequest' is true.
*/
export interface StepInTargetsRequest extends Request {
// command: 'stepInTargets';
@@ -1265,7 +1341,7 @@ declare module DebugProtocol {
/** GotoTargets request; value of command field is 'gotoTargets'.
This request retrieves the possible goto targets for the specified source location.
These targets can be used in the 'goto' request.
The GotoTargets request may only be called if the 'supportsGotoTargetsRequest' capability exists and is true.
Clients should only call this request if the capability 'supportsGotoTargetsRequest' is true.
*/
export interface GotoTargetsRequest extends Request {
// command: 'gotoTargets';
@@ -1292,7 +1368,7 @@ declare module DebugProtocol {
/** Completions request; value of command field is 'completions'.
Returns a list of possible completions for a given caret position and text.
The CompletionsRequest may only be called if the 'supportsCompletionsRequest' capability exists and is true.
Clients should only call this request if the capability 'supportsCompletionsRequest' is true.
*/
export interface CompletionsRequest extends Request {
// command: 'completions';
@@ -1321,6 +1397,7 @@ declare module DebugProtocol {
/** ExceptionInfo request; value of command field is 'exceptionInfo'.
Retrieves the details of the exception that caused this event to be raised.
Clients should only call this request if the capability 'supportsExceptionInfoRequest' is true.
*/
export interface ExceptionInfoRequest extends Request {
// command: 'exceptionInfo';
@@ -1349,6 +1426,7 @@ declare module DebugProtocol {
/** ReadMemory request; value of command field is 'readMemory'.
Reads bytes from memory at the provided location.
Clients should only call this request if the capability 'supportsReadMemoryRequest' is true.
*/
export interface ReadMemoryRequest extends Request {
// command: 'readMemory';
@@ -1368,9 +1446,13 @@ declare module DebugProtocol {
/** Response to 'readMemory' request. */
export interface ReadMemoryResponse extends Response {
body?: {
/** The address of the first byte of data returned. Treated as a hex value if prefixed with '0x', or as a decimal value otherwise. */
/** The address of the first byte of data returned.
Treated as a hex value if prefixed with '0x', or as a decimal value otherwise.
*/
address: string;
/** The number of unreadable bytes encountered after the last successfully read byte. This can be used to determine the number of bytes that must be skipped before a subsequent 'readMemory' request will succeed. */
/** The number of unreadable bytes encountered after the last successfully read byte.
This can be used to determine the number of bytes that must be skipped before a subsequent 'readMemory' request will succeed.
*/
unreadableBytes?: number;
/** The bytes read from memory, encoded using base64. */
data?: string;
@@ -1379,6 +1461,7 @@ declare module DebugProtocol {
/** Disassemble request; value of command field is 'disassemble'.
Disassembles code stored at the provided location.
Clients should only call this request if the capability 'supportsDisassembleRequest' is true.
*/
export interface DisassembleRequest extends Request {
// command: 'disassemble';
@@ -1393,7 +1476,9 @@ declare module DebugProtocol {
offset?: number;
/** Optional offset (in instructions) to be applied after the byte offset (if any) before disassembling. Can be negative. */
instructionOffset?: number;
/** Number of instructions to disassemble starting at the specified location and offset. An adapter must return exactly this number of instructions - any unavailable instructions should be replaced with an implementation-defined 'invalid instruction' value. */
/** Number of instructions to disassemble starting at the specified location and offset.
An adapter must return exactly this number of instructions - any unavailable instructions should be replaced with an implementation-defined 'invalid instruction' value.
*/
instructionCount: number;
/** If true, the adapter should attempt to resolve memory addresses and other values to symbolic names. */
resolveSymbols?: boolean;
@@ -1543,7 +1628,8 @@ declare module DebugProtocol {
addressRange?: string;
}
/** A ColumnDescriptor specifies what module attribute to show in a column of the ModulesView, how to format it, and what the column's label should be.
/** A ColumnDescriptor specifies what module attribute to show in a column of the ModulesView, how to format it,
and what the column's label should be.
It is only used if the underlying UI actually supports this level of customization.
*/
export interface ColumnDescriptor {
@@ -1574,21 +1660,34 @@ declare module DebugProtocol {
name: string;
}
/** A Source is a descriptor for source code. It is returned from the debug adapter as part of a StackFrame and it is used by clients when specifying breakpoints. */
/** A Source is a descriptor for source code.
It is returned from the debug adapter as part of a StackFrame and it is used by clients when specifying breakpoints.
*/
export interface Source {
/** The short name of the source. Every source returned from the debug adapter has a name. When sending a source to the debug adapter this name is optional. */
/** The short name of the source. Every source returned from the debug adapter has a name.
When sending a source to the debug adapter this name is optional.
*/
name?: string;
/** The path of the source to be shown in the UI. It is only used to locate and load the content of the source if no sourceReference is specified (or its value is 0). */
/** The path of the source to be shown in the UI.
It is only used to locate and load the content of the source if no sourceReference is specified (or its value is 0).
*/
path?: string;
/** If sourceReference > 0 the contents of the source must be retrieved through the SourceRequest (even if a path is specified). A sourceReference is only valid for a session, so it must not be used to persist a source. The value should be less than or equal to 2147483647 (2^31 - 1). */
/** If sourceReference > 0 the contents of the source must be retrieved through the SourceRequest (even if a path is specified).
A sourceReference is only valid for a session, so it must not be used to persist a source.
The value should be less than or equal to 2147483647 (2^31 - 1).
*/
sourceReference?: number;
/** An optional hint for how to present the source in the UI. A value of 'deemphasize' can be used to indicate that the source is not available or that it is skipped on stepping. */
/** An optional hint for how to present the source in the UI.
A value of 'deemphasize' can be used to indicate that the source is not available or that it is skipped on stepping.
*/
presentationHint?: 'normal' | 'emphasize' | 'deemphasize';
/** The (optional) origin of this source: possible values 'internal module', 'inlined content from source map', etc. */
origin?: string;
/** An optional list of sources that are related to this source. These may be the source that generated this source. */
sources?: Source[];
/** Optional data that a debug adapter might want to loop through the client. The client should leave the data intact and persist it across sessions. The client should not interpret the data. */
/** Optional data that a debug adapter might want to loop through the client.
The client should leave the data intact and persist it across sessions. The client should not interpret the data.
*/
adapterData?: any;
/** The checksums associated with this file. */
checksums?: Checksum[];
@@ -1596,7 +1695,9 @@ declare module DebugProtocol {
/** A Stackframe contains the source location. */
export interface StackFrame {
/** An identifier for the stack frame. It must be unique across all threads. This id can be used to retrieve the scopes of the frame with the 'scopesRequest' or to restart the execution of a stackframe. */
/** An identifier for the stack frame. It must be unique across all threads.
This id can be used to retrieve the scopes of the frame with the 'scopesRequest' or to restart the execution of a stackframe.
*/
id: number;
/** The name of the stack frame, typically a method name. */
name: string;
@@ -1614,7 +1715,9 @@ declare module DebugProtocol {
instructionPointerReference?: string;
/** The module associated with this frame, if any. */
moduleId?: number | string;
/** An optional hint for how to present this frame in the UI. A value of 'label' can be used to indicate that the frame is an artificial frame that is used as a visual label or separator. A value of 'subtle' can be used to change the appearance of a frame in a 'subtle' way. */
/** An optional hint for how to present this frame in the UI.
A value of 'label' can be used to indicate that the frame is an artificial frame that is used as a visual label or separator. A value of 'subtle' can be used to change the appearance of a frame in a 'subtle' way.
*/
presentationHint?: 'normal' | 'label' | 'subtle';
}
@@ -1666,7 +1769,9 @@ declare module DebugProtocol {
name: string;
/** The variable's value. This can be a multi-line text, e.g. for a function the body of a function. */
value: string;
/** The type of the variable's value. Typically shown in the UI when hovering over the value. */
/** The type of the variable's value. Typically shown in the UI when hovering over the value.
This attribute should only be returned by a debug adapter if the client has passed the value true for the 'supportsVariableType' capability of the 'initialize' request.
*/
type?: string;
/** Properties of a variable that can be used to determine how to render the variable in the UI. */
presentationHint?: VariablePresentationHint;
@@ -1682,7 +1787,9 @@ declare module DebugProtocol {
The client can use this optional information to present the children in a paged UI and fetch them in chunks.
*/
indexedVariables?: number;
/** Optional memory reference for the variable if the variable represents executable code, such as a function pointer. */
/** Optional memory reference for the variable if the variable represents executable code, such as a function pointer.
This attribute is only required if the client has passed the value true for the 'supportsMemoryReferences' capability of the 'initialize' request.
*/
memoryReference?: string;
}
@@ -1699,7 +1806,8 @@ declare module DebugProtocol {
'innerClass': Indicates that the object is an inner class.
'interface': Indicates that the object is an interface.
'mostDerivedClass': Indicates that the object is the most derived class.
'virtual': Indicates that the object is virtual, that means it is a synthetic object introduced by the adapter for rendering purposes, e.g. an index range for large arrays.
'virtual': Indicates that the object is virtual, that means it is a synthetic object introducedby the
adapter for rendering purposes, e.g. an index range for large arrays.
'dataBreakpoint': Indicates that a data breakpoint is registered for the object.
etc.
*/
@@ -1740,11 +1848,19 @@ declare module DebugProtocol {
line: number;
/** An optional source column of the breakpoint. */
column?: number;
/** An optional expression for conditional breakpoints. */
/** An optional expression for conditional breakpoints.
It is only honored by a debug adapter if the capability 'supportsConditionalBreakpoints' is true.
*/
condition?: string;
/** An optional expression that controls how many hits of the breakpoint are ignored. The backend is expected to interpret the expression as needed. */
/** An optional expression that controls how many hits of the breakpoint are ignored.
The backend is expected to interpret the expression as needed.
The attribute is only honored by a debug adapter if the capability 'supportsHitConditionalBreakpoints' is true.
*/
hitCondition?: string;
/** If this attribute exists and is non-empty, the backend must not 'break' (stop) but log the message instead. Expressions within {} are interpolated. */
/** If this attribute exists and is non-empty, the backend must not 'break' (stop)
but log the message instead. Expressions within {} are interpolated.
The attribute is only honored by a debug adapter if the capability 'supportsLogPoints' is true.
*/
logMessage?: string;
}
@@ -1752,9 +1868,14 @@ declare module DebugProtocol {
export interface FunctionBreakpoint {
/** The name of the function. */
name: string;
/** An optional expression for conditional breakpoints. */
/** An optional expression for conditional breakpoints.
It is only honored by a debug adapter if the capability 'supportsConditionalBreakpoints' is true.
*/
condition?: string;
/** An optional expression that controls how many hits of the breakpoint are ignored. The backend is expected to interpret the expression as needed. */
/** An optional expression that controls how many hits of the breakpoint are ignored.
The backend is expected to interpret the expression as needed.
The attribute is only honored by a debug adapter if the capability 'supportsHitConditionalBreakpoints' is true.
*/
hitCondition?: string;
}
@@ -1769,7 +1890,9 @@ declare module DebugProtocol {
accessType?: DataBreakpointAccessType;
/** An optional expression for conditional breakpoints. */
condition?: string;
/** An optional expression that controls how many hits of the breakpoint are ignored. The backend is expected to interpret the expression as needed. */
/** An optional expression that controls how many hits of the breakpoint are ignored.
The backend is expected to interpret the expression as needed.
*/
hitCondition?: string;
}
@@ -1779,7 +1902,9 @@ declare module DebugProtocol {
id?: number;
/** If true breakpoint could be set (but not necessarily at the desired location). */
verified: boolean;
/** An optional message about the state of the breakpoint. This is shown to the user and can be used to explain why a breakpoint could not be verified. */
/** An optional message about the state of the breakpoint.
This is shown to the user and can be used to explain why a breakpoint could not be verified.
*/
message?: string;
/** The source where the breakpoint is located. */
source?: Source;
@@ -1789,7 +1914,9 @@ declare module DebugProtocol {
column?: number;
/** An optional end line of the actual range covered by the breakpoint. */
endLine?: number;
/** An optional end column of the actual range covered by the breakpoint. If no end line is given, then the end column is assumed to be in the start line. */
/** An optional end column of the actual range covered by the breakpoint.
If no end line is given, then the end column is assumed to be in the start line.
*/
endColumn?: number;
}
@@ -1891,7 +2018,9 @@ declare module DebugProtocol {
/** An ExceptionOptions assigns configuration options to a set of exceptions. */
export interface ExceptionOptions {
/** A path that selects a single or multiple exceptions in a tree. If 'path' is missing, the whole tree is selected. By convention the first segment of the path is a category that is used to group exceptions in the UI. */
/** A path that selects a single or multiple exceptions in a tree. If 'path' is missing, the whole tree is selected.
By convention the first segment of the path is a category that is used to group exceptions in the UI.
*/
path?: ExceptionPathSegment[];
/** Condition when a thrown exception should result in a break. */
breakMode: ExceptionBreakMode;
@@ -1905,7 +2034,10 @@ declare module DebugProtocol {
*/
export type ExceptionBreakMode = 'never' | 'always' | 'unhandled' | 'userUnhandled';
/** An ExceptionPathSegment represents a segment in a path that is used to match leafs or nodes in a tree of exceptions. If a segment consists of more than one name, it matches the names provided if 'negate' is false or missing or it matches anything except the names provided if 'negate' is true. */
/** An ExceptionPathSegment represents a segment in a path that is used to match leafs or nodes in a tree of exceptions.
If a segment consists of more than one name, it matches the names provided if 'negate' is false or missing or
it matches anything except the names provided if 'negate' is true.
*/
export interface ExceptionPathSegment {
/** If false or missing this segment matches the names provided, otherwise it matches anything except the names provided. */
negate?: boolean;
@@ -1939,7 +2071,10 @@ declare module DebugProtocol {
instruction: string;
/** Name of the symbol that corresponds with the location of this instruction, if any. */
symbol?: string;
/** Source location that corresponds to this instruction, if any. Should always be set (if available) on the first instruction returned, but can be omitted afterwards if this instruction maps to the same source file as the previous instruction. */
/** Source location that corresponds to this instruction, if any.
Should always be set (if available) on the first instruction returned,
but can be omitted afterwards if this instruction maps to the same source file as the previous instruction.
*/
location?: Source;
/** The line within the source location that corresponds to this instruction, if any. */
line?: number;

View File

@@ -230,6 +230,10 @@ export class MockSession implements IDebugSession {
throw new Error('not implemented');
}
get onDidProgressUpdate(): Event<DebugProtocol.ProgressUpdateEvent> {
throw new Error('not implemented');
}
get onDidProgressEnd(): Event<DebugProtocol.ProgressEndEvent> {
throw new Error('not implemented');
}

View File

@@ -28,6 +28,7 @@
height: calc(100% - 41px);
}
.extensions-viewlet > .extensions .extension-view-header .count-badge-wrapper,
.extensions-viewlet > .extensions .extension-view-header .monaco-action-bar {
margin-right: 4px;
}

View File

@@ -592,7 +592,7 @@ export class FilesFilter implements ITreeFilter<ExplorerItem, FuzzyScore> {
// Hide those that match Hidden Patterns
const cached = this.hiddenExpressionPerRoot.get(stat.root.resource.toString());
if (cached && cached.parsed(path.relative(stat.root.resource.path, stat.resource.path), stat.name, name => !!(stat.parent && stat.parent.getChild(name)))) {
if ((cached && cached.parsed(path.relative(stat.root.resource.path, stat.resource.path), stat.name, name => !!(stat.parent && stat.parent.getChild(name)))) || stat.parent?.isExcluded) {
stat.isExcluded = true;
const editors = this.editorService.visibleEditors;
const editor = editors.filter(e => e.resource && isEqualOrParent(e.resource, stat.resource)).pop();

View File

@@ -6,7 +6,7 @@
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.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';
@@ -24,3 +24,7 @@ export const CELL_MARGIN = 32;
export const EDITOR_TOP_PADDING = 8;
export const EDITOR_BOTTOM_PADDING = 8;
export const EDITOR_TOOLBAR_HEIGHT = 22;
export const RUN_BUTTON_WIDTH = 20;
// Context Keys
export const NOTEBOOK_CELL_TYPE_CONTEXT_KEY = 'notebookCellType';

View File

@@ -11,8 +11,8 @@ 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 { DELETE_CELL_COMMAND_ID, EDIT_CELL_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, SAVE_CELL_COMMAND_ID, COPY_CELL_UP_COMMAND_ID, COPY_CELL_DOWN_COMMAND_ID } from 'vs/workbench/contrib/notebook/browser/constants';
import { INotebookEditor, KEYBINDING_CONTEXT_NOTEBOOK_FIND_WIDGET_FOCUSED, NOTEBOOK_EDITOR_FOCUSED, ICellViewModel, CellState } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { COPY_CELL_DOWN_COMMAND_ID, COPY_CELL_UP_COMMAND_ID, DELETE_CELL_COMMAND_ID, EDIT_CELL_COMMAND_ID, EXECUTE_CELL_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, SAVE_CELL_COMMAND_ID } from 'vs/workbench/contrib/notebook/browser/constants';
import { CellRenderTemplate, CellState, ICellViewModel, INotebookEditor, KEYBINDING_CONTEXT_NOTEBOOK_FIND_WIDGET_FOCUSED, NOTEBOOK_EDITOR_FOCUSED } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { INotebookService } from 'vs/workbench/contrib/notebook/browser/notebookService';
import { CellKind, NOTEBOOK_EDITOR_CURSOR_BOUNDARY } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
@@ -20,7 +20,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
registerAction2(class extends Action2 {
constructor() {
super({
id: 'workbench.action.executeNotebookCell',
id: EXECUTE_CELL_COMMAND_ID,
title: localize('notebookActions.execute', "Execute Notebook Cell"),
keybinding: {
when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, InputFocusedContext),
@@ -33,11 +33,36 @@ registerAction2(class extends Action2 {
});
}
async run(accessor: ServicesAccessor): Promise<void> {
runActiveCell(accessor);
async run(accessor: ServicesAccessor, context?: INotebookCellActionContext): Promise<void> {
if (!context) {
context = getActiveCellContext(accessor);
if (!context) {
return;
}
}
runCell(accessor, context);
}
});
export class ExecuteCellAction extends MenuItemAction {
constructor(
@IContextKeyService contextKeyService: IContextKeyService,
@ICommandService commandService: ICommandService
) {
super(
{
id: EXECUTE_CELL_COMMAND_ID,
title: localize('notebookActions.executeCell', "Execute Cell"),
icon: { id: 'codicon/play' }
},
undefined,
{ shouldForwardArgs: true },
contextKeyService,
commandService);
}
}
registerAction2(class extends Action2 {
constructor() {
super({
@@ -53,7 +78,7 @@ registerAction2(class extends Action2 {
async run(accessor: ServicesAccessor): Promise<void> {
const editorService = accessor.get(IEditorService);
const activeCell = runActiveCell(accessor);
const activeCell = await runActiveCell(accessor);
if (!activeCell) {
return;
}
@@ -93,7 +118,7 @@ registerAction2(class extends Action2 {
async run(accessor: ServicesAccessor): Promise<void> {
const editorService = accessor.get(IEditorService);
const activeCell = runActiveCell(accessor);
const activeCell = await runActiveCell(accessor);
if (!activeCell) {
return;
}
@@ -273,7 +298,7 @@ function getActiveNotebookEditor(editorService: IEditorService): INotebookEditor
return activeEditorPane?.isNotebookEditor ? activeEditorPane : undefined;
}
function runActiveCell(accessor: ServicesAccessor): ICellViewModel | undefined {
async function runActiveCell(accessor: ServicesAccessor): Promise<ICellViewModel | undefined> {
const editorService = accessor.get(IEditorService);
const notebookService = accessor.get(INotebookService);
@@ -303,11 +328,41 @@ function runActiveCell(accessor: ServicesAccessor): ICellViewModel | undefined {
}
const viewType = notebookProviders[0].id;
notebookService.executeNotebookActiveCell(viewType, resource);
await notebookService.executeNotebookActiveCell(viewType, resource);
return activeCell;
}
async function runCell(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise<void> {
const progress = context.cellTemplate!.progressBar!;
progress.infinite().show(500);
const editorService = accessor.get(IEditorService);
const notebookService = accessor.get(INotebookService);
const resource = editorService.activeEditor?.resource;
if (!resource) {
return;
}
const editor = getActiveNotebookEditor(editorService);
if (!editor) {
return;
}
const notebookProviders = notebookService.getContributedNotebookProviders(resource);
if (!notebookProviders.length) {
return;
}
// Need to make active, maybe TODO
editor.focusNotebookCell(context.cell, false);
const viewType = notebookProviders[0].id;
await notebookService.executeNotebookActiveCell(viewType, resource);
progress.hide();
}
async function changeActiveCellToKind(kind: CellKind, accessor: ServicesAccessor): Promise<void> {
const editorService = accessor.get(IEditorService);
const editor = getActiveNotebookEditor(editorService);
@@ -341,6 +396,7 @@ async function changeActiveCellToKind(kind: CellKind, accessor: ServicesAccessor
}
export interface INotebookCellActionContext {
cellTemplate?: CellRenderTemplate;
cell: ICellViewModel;
notebookEditor: INotebookEditor;
}
@@ -413,7 +469,7 @@ registerAction2(class extends InsertCellCommand {
constructor() {
super(
{
id: INSERT_MARKDOWN_CELL_BELOW_COMMAND_ID,
id: INSERT_MARKDOWN_CELL_ABOVE_COMMAND_ID,
title: localize('notebookActions.insertMarkdownCellAbove', "Insert Markdown Cell Above"),
},
CellKind.Markdown,
@@ -428,7 +484,7 @@ registerAction2(class extends InsertCellCommand {
id: INSERT_MARKDOWN_CELL_BELOW_COMMAND_ID,
title: localize('notebookActions.insertMarkdownCellBelow', "Insert Markdown Cell Below"),
},
CellKind.Code,
CellKind.Markdown,
'below');
}
});

View File

@@ -17,9 +17,9 @@
white-space: initial;
}
.monaco-workbench .part.editor > .content .notebook-editor .cell-list-container .monaco-scrollable-element {
/* .monaco-workbench .part.editor > .content .notebook-editor .cell-list-container .monaco-scrollable-element {
overflow: visible !important;
}
} */
.monaco-workbench .part.editor > .content .notebook-editor .cell-list-container .monaco-list-rows {
min-height: 100%;
@@ -30,6 +30,10 @@
position: relative;
}
.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row .cell {
display: flex;
}
.monaco-workbench .part.editor > .content .notebook-editor .notebook-content-widgets {
position: absolute;
top: 0;
@@ -122,11 +126,29 @@
cursor: pointer;
}
.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row .monaco-toolbar {
.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row > .monaco-toolbar {
visibility: hidden;
margin-right: 24px;
}
.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row .cell .run-button-container .monaco-toolbar {
margin-top: 8px;
visibility: hidden;
}
.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row:hover .cell .run-button-container .monaco-toolbar,
.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row.focused .cell .run-button-container .monaco-toolbar {
visibility: visible;
}
.monaco-workbench .part.editor > .content .notebook-editor .cell .cell-editor-container {
position: relative;
}
.monaco-workbench .part.editor > .content .notebook-editor .cell .monaco-progress-container {
top: 0px;
}
.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row.focused .monaco-toolbar,
.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row:hover .monaco-toolbar {
visibility: visible;

View File

@@ -16,6 +16,7 @@ import { Range } from 'vs/editor/common/core/range';
import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri';
import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar';
export const KEYBINDING_CONTEXT_NOTEBOOK_FIND_WIDGET_FOCUSED = new RawContextKey<boolean>('notebookFindWidgetFocused', false);
@@ -44,6 +45,8 @@ export interface INotebookEditor {
*/
viewModel: NotebookViewModel | undefined;
isNotebookEditor: boolean;
/**
* Focus the notebook editor cell list
*/
@@ -121,6 +124,11 @@ export interface INotebookEditor {
*/
removeInset(output: IOutput): void;
/**
* Send message to the webview for outputs.
*/
postMessage(message: any): void;
/**
* Trigger the editor to scroll from scroll event programmatically
*/
@@ -195,12 +203,14 @@ export interface INotebookEditor {
export interface CellRenderTemplate {
container: HTMLElement;
cellContainer: HTMLElement;
menuContainer?: HTMLElement;
editorContainer?: HTMLElement;
toolbar: ToolBar;
focusIndicator?: HTMLElement;
runToolbar?: ToolBar;
editingContainer?: HTMLElement;
outputContainer?: HTMLElement;
editor?: CodeEditorWidget;
progressBar?: ProgressBar;
disposables: DisposableStore;
}

View File

@@ -42,7 +42,7 @@ import { NotebookViewModel, INotebookEditorViewState, IModelDecorationsChangeAcc
import { IEditorGroupView } from 'vs/workbench/browser/parts/editor/editor';
import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookCellViewModel';
import { Range } from 'vs/editor/common/core/range';
import { CELL_MARGIN } from 'vs/workbench/contrib/notebook/browser/constants';
import { CELL_MARGIN, RUN_BUTTON_WIDTH } from 'vs/workbench/contrib/notebook/browser/constants';
import { Color, RGBA } from 'vs/base/common/color';
const $ = DOM.$;
@@ -219,6 +219,11 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
this.control = new NotebookCodeEditors(this.list, this.renderedEditors);
this.webview = new BackLayerWebView(this.webviewService, this.notebookService, this, this.environmentSerice);
this._register(this.webview.onMessage(message => {
if (this.viewModel) {
this.notebookService.onDidReceiveMessage(this.viewModel.viewType, this.viewModel.uri, message);
}
}));
this.list.rowsContainer.appendChild(this.webview.element);
this._register(this.list);
}
@@ -697,7 +702,17 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
return this.outputRenderer;
}
postMessage(message: any) {
this.webview?.webview.sendMessage(message);
}
//#endregion
toJSON(): any {
return {
notebookHandle: this.viewModel?.handle
};
}
}
const embeddedEditorBackground = 'walkThrough.embeddedEditorBackground';
@@ -717,12 +732,12 @@ registerThemingParticipant((theme, collector) => {
}
const link = theme.getColor(textLinkForeground);
if (link) {
collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell a { color: ${link}; }`);
collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell .output a { color: ${link}; }`);
}
const activeLink = theme.getColor(textLinkActiveForeground);
if (activeLink) {
collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell a:hover,
.monaco-workbench .part.editor > .content .notebook-editor .cell a:active { color: ${activeLink}; }`);
collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell .output a:hover,
.monaco-workbench .part.editor > .content .notebook-editor .cell .output a:active { color: ${activeLink}; }`);
}
const shortcut = theme.getColor(textPreformatForeground);
if (shortcut) {
@@ -756,5 +771,7 @@ registerThemingParticipant((theme, collector) => {
// Cell Margin
collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row > div.cell { padding: 8px ${CELL_MARGIN}px 8px ${CELL_MARGIN}px; }`);
collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .output { margin: 8px ${CELL_MARGIN}px; }`);
collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .output { margin: 8px ${CELL_MARGIN}px 8px ${CELL_MARGIN + RUN_BUTTON_WIDTH}px }`);
collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell .cell-editor-container { width: calc(100% - ${RUN_BUTTON_WIDTH}px); }`);
});

View File

@@ -29,7 +29,8 @@ export interface IMainNotebookController {
updateNotebookActiveCell(uri: URI, cellHandle: number): void;
createRawCell(uri: URI, index: number, language: string, type: CellKind): Promise<NotebookCellTextModel | undefined>;
deleteCell(uri: URI, index: number): Promise<boolean>
executeNotebookActiveCell(uri: URI): void;
executeNotebookActiveCell(uri: URI): Promise<void>;
onDidReceiveMessage(uri: URI, message: any): void;
destoryNotebookDocument(notebook: INotebookTextModel): Promise<void>;
save(uri: URI): Promise<boolean>;
}
@@ -54,6 +55,7 @@ export interface INotebookService {
destoryNotebookDocument(viewType: string, notebook: INotebookTextModel): void;
updateActiveNotebookDocument(viewType: string, resource: URI): void;
save(viewType: string, resource: URI): Promise<boolean>;
onDidReceiveMessage(viewType: string, uri: URI, message: any): void;
}
export class NotebookProviderInfoStore {
@@ -325,6 +327,14 @@ export class NotebookService extends Disposable implements INotebookService {
return false;
}
onDidReceiveMessage(viewType: string, uri: URI, message: any): void {
let provider = this._notebookProviders.get(viewType);
if (provider) {
return provider.controller.onDidReceiveMessage(uri, message);
}
}
private _onWillDispose(model: INotebookTextModel): void {
let modelId = MODEL_ID(model.uri);
let modelData = this._models[modelId];

View File

@@ -16,8 +16,10 @@ import { IWebviewService, WebviewElement } from 'vs/workbench/contrib/webview/br
import { WebviewResourceScheme } from 'vs/workbench/contrib/webview/common/resourceLoader';
import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookCellViewModel';
import { CELL_MARGIN } from 'vs/workbench/contrib/notebook/browser/constants';
import { Emitter, Event } from 'vs/base/common/event';
export interface IDimentionMessage {
__vscode_notebook_message: boolean;
type: 'dimension';
id: string;
data: DOM.Dimension;
@@ -25,6 +27,7 @@ export interface IDimentionMessage {
export interface IScrollAckMessage {
__vscode_notebook_message: boolean;
type: 'scroll-ack';
data: { top: number };
version: number;
@@ -78,6 +81,9 @@ export class BackLayerWebView extends Disposable {
preloadsCache: Map<string, boolean> = new Map();
localResourceRootsCache: URI[] | undefined = undefined;
rendererRootsCache: URI[] = [];
private readonly _onMessage = this._register(new Emitter<any>());
public readonly onMessage: Event<any> = this._onMessage.event;
constructor(public webviewService: IWebviewService, public notebookService: INotebookService, public notebookEditor: INotebookEditor, public environmentSerice: IEnvironmentService) {
super();
@@ -154,6 +160,7 @@ export class BackLayerWebView extends Disposable {
for (let entry of entries) {
if (entry.target.id === id && entry.contentRect) {
vscode.postMessage({
__vscode_notebook_message: true,
type: 'dimension',
id: id,
data: {
@@ -198,6 +205,7 @@ export class BackLayerWebView extends Disposable {
resizeObserve(outputNode, outputId);
vscode.postMessage({
__vscode_notebook_message: true,
type: 'dimension',
id: outputId,
data: {
@@ -255,27 +263,32 @@ export class BackLayerWebView extends Disposable {
}));
this._register(this.webview.onMessage((data: IMessage) => {
if (data.type === 'dimension') {
let output = this.reversedInsetMapping.get(data.id);
if (data.__vscode_notebook_message) {
if (data.type === 'dimension') {
let output = this.reversedInsetMapping.get(data.id);
if (!output) {
return;
if (!output) {
return;
}
let cell = this.insetMapping.get(output)!.cell;
let height = data.data.height;
let outputHeight = height === 0 ? 0 : height + 16;
if (cell) {
let outputIndex = cell.outputs.indexOf(output);
cell.updateOutputHeight(outputIndex, outputHeight);
this.notebookEditor.layoutNotebookCell(cell, cell.getCellTotalHeight());
}
} else if (data.type === 'scroll-ack') {
// const date = new Date();
// const top = data.data.top;
// console.log('ack top ', top, ' version: ', data.version, ' - ', date.getMinutes() + ':' + date.getSeconds() + ':' + date.getMilliseconds());
}
let cell = this.insetMapping.get(output)!.cell;
let height = data.data.height;
let outputHeight = height === 0 ? 0 : height + 16;
if (cell) {
let outputIndex = cell.outputs.indexOf(output);
cell.updateOutputHeight(outputIndex, outputHeight);
this.notebookEditor.layoutNotebookCell(cell, cell.getCellTotalHeight());
}
} else if (data.type === 'scroll-ack') {
// const date = new Date();
// const top = data.data.top;
// console.log('ack top ', top, ' version: ', data.version, ' - ', date.getMinutes() + ':' + date.getSeconds() + ':' + date.getMilliseconds());
return;
}
this._onMessage.fire(data);
}));
}
@@ -284,6 +297,7 @@ export class BackLayerWebView extends Disposable {
const webview = webviewService.createWebviewElement('' + UUID.generateUuid(), {
enableFindWidget: false,
}, {
allowMultipleAPIAcquire: true,
allowScripts: true,
localResourceRoots: this.localResourceRootsCache
});
@@ -396,6 +410,7 @@ export class BackLayerWebView extends Disposable {
const mixedResourceRoots = [...(this.localResourceRootsCache || []), ...this.rendererRootsCache];
this.webview.contentOptions = {
allowMultipleAPIAcquire: true,
allowScripts: true,
enableCommandUris: true,
localResourceRoots: mixedResourceRoots

View File

@@ -0,0 +1,38 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IDisposable } from 'vs/base/common/lifecycle';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IMenuService, MenuId, IMenu } from 'vs/platform/actions/common/actions';
import { IAction } from 'vs/base/common/actions';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
export class CellMenus implements IDisposable {
constructor(
@IMenuService private readonly menuService: IMenuService,
@IContextMenuService private readonly contextMenuService: IContextMenuService
) { }
getCellTitleActions(contextKeyService: IContextKeyService): IMenu {
return this.getMenu(MenuId.NotebookCellTitle, contextKeyService);
}
private getMenu(menuId: MenuId, contextKeyService: IContextKeyService): IMenu {
const menu = this.menuService.createMenu(menuId, contextKeyService);
const primary: IAction[] = [];
const secondary: IAction[] = [];
const result = { primary, secondary };
createAndFillInContextMenuActions(menu, { shouldForwardArgs: true }, result, this.contextMenuService, g => /^inline/.test(g));
return menu;
}
dispose(): void {
}
}

View File

@@ -15,22 +15,27 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
import { BareFontInfo } from 'vs/editor/common/config/fontInfo';
import { ContextAwareMenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { MenuItemAction } from 'vs/platform/actions/common/actions';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { InsertCodeCellAboveAction, INotebookCellActionContext, InsertCodeCellBelowAction, InsertMarkdownCellAboveAction, InsertMarkdownCellBelowAction, EditCellAction, SaveCellAction, DeleteCellAction, MoveCellUpAction, MoveCellDownAction } from 'vs/workbench/contrib/notebook/browser/contrib/notebookActions';
import { CellRenderTemplate, INotebookEditor, ICellViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { EDITOR_BOTTOM_PADDING, EDITOR_TOOLBAR_HEIGHT, EDITOR_TOP_PADDING, NOTEBOOK_CELL_TYPE_CONTEXT_KEY } from 'vs/workbench/contrib/notebook/browser/constants';
import { DeleteCellAction, EditCellAction, ExecuteCellAction, INotebookCellActionContext, InsertCodeCellBelowAction, MoveCellDownAction, MoveCellUpAction, SaveCellAction, InsertCodeCellAboveAction, InsertMarkdownCellAboveAction, InsertMarkdownCellBelowAction } from 'vs/workbench/contrib/notebook/browser/contrib/notebookActions';
import { CellRenderTemplate, ICellViewModel, INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { CodeCell } from 'vs/workbench/contrib/notebook/browser/view/renderers/codeCell';
import { StatefullMarkdownCell } from 'vs/workbench/contrib/notebook/browser/view/renderers/markdownCell';
import { CellKind } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CellViewModel } from '../../viewModel/notebookCellViewModel';
import { ContextAwareMenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { MenuItemAction } from 'vs/platform/actions/common/actions';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { EDITOR_TOOLBAR_HEIGHT, EDITOR_TOP_PADDING, EDITOR_BOTTOM_PADDING } from 'vs/workbench/contrib/notebook/browser/constants';
import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { CellMenus } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellMenus';
export class NotebookCellListDelegate implements IListVirtualDelegate<ICellViewModel> {
const $ = DOM.$;
export class NotebookCellListDelegate implements IListVirtualDelegate<CellViewModel> {
private _lineHeight: number;
private _toolbarHeight = EDITOR_TOOLBAR_HEIGHT;
@@ -68,6 +73,7 @@ abstract class AbstractCellRenderer {
private readonly configurationService: IConfigurationService,
private readonly keybindingService: IKeybindingService,
private readonly notificationService: INotificationService,
protected readonly contextKeyService: IContextKeyService,
language: string,
) {
const editorOptions = deepClone(this.configurationService.getValue<IEditorOptions>('editor', { overrideIdentifier: language }));
@@ -108,6 +114,13 @@ abstract class AbstractCellRenderer {
return toolbar;
}
protected createMenu(): CellMenus {
const menu = this.instantiationService.createInstance(CellMenus);
return menu;
}
abstract getCellToolbarActions(element: CellViewModel): IAction[];
showContextMenu(listIndex: number | undefined, element: CellViewModel, x: number, y: number) {
const actions: IAction[] = [
this.instantiationService.createInstance(InsertCodeCellAboveAction),
@@ -150,8 +163,9 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR
@IContextMenuService contextMenuService: IContextMenuService,
@IKeybindingService keybindingService: IKeybindingService,
@INotificationService notificationService: INotificationService,
@IContextKeyService contextKeyService: IContextKeyService
) {
super(instantiationService, notehookEditor, contextMenuService, configurationService, keybindingService, notificationService, 'markdown');
super(instantiationService, notehookEditor, contextMenuService, configurationService, keybindingService, notificationService, contextKeyService, 'markdown');
}
get templateId() {
@@ -165,14 +179,6 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR
const disposables = new DisposableStore();
const toolbar = this.createToolbar(container);
toolbar.setActions([
this.instantiationService.createInstance(MoveCellUpAction),
this.instantiationService.createInstance(MoveCellDownAction),
this.instantiationService.createInstance(InsertCodeCellBelowAction),
this.instantiationService.createInstance(EditCellAction),
this.instantiationService.createInstance(SaveCellAction),
this.instantiationService.createInstance(DeleteCellAction)
])();
disposables.add(toolbar);
container.appendChild(codeInnerContent);
@@ -181,16 +187,11 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR
DOM.addClasses(innerContent, 'cell', 'markdown');
container.appendChild(innerContent);
const action = document.createElement('div');
DOM.addClasses(action, 'menu', 'codicon-settings-gear', 'codicon');
container.appendChild(action);
DOM.append(container, DOM.$('.notebook-cell-focus-indicator'));
return {
container: container,
cellContainer: innerContent,
menuContainer: action,
editingContainer: codeInnerContent,
disposables,
toolbar
@@ -212,32 +213,67 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR
}
let elementDisposable = this.disposables.get(element);
elementDisposable!.add(DOM.addStandardDisposableListener(templateData.menuContainer!, 'mousedown', e => {
const { top, height } = DOM.getDomNodePagePosition(templateData.menuContainer!);
e.preventDefault();
const listIndexAttr = templateData.menuContainer?.parentElement?.getAttribute('data-index');
const listIndex = listIndexAttr ? Number(listIndexAttr) : undefined;
this.showContextMenu(listIndex, element, e.posx, top + height);
}));
elementDisposable!.add(DOM.addStandardDisposableListener(templateData.menuContainer!, DOM.EventType.MOUSE_LEAVE, e => {
templateData.menuContainer?.classList.remove('mouseover');
}));
elementDisposable!.add(DOM.addStandardDisposableListener(templateData.menuContainer!, DOM.EventType.MOUSE_ENTER, e => {
templateData.menuContainer?.classList.add('mouseover');
}));
elementDisposable!.add(new StatefullMarkdownCell(this.notebookEditor, element, templateData, this.editorOptions, this.instantiationService));
const contextKeyService = this.contextKeyService.createScoped(templateData.container);
contextKeyService.createKey(NOTEBOOK_CELL_TYPE_CONTEXT_KEY, 'markdown');
const toolbarActions = this.getCellToolbarActions(element);
templateData.toolbar!.setActions(toolbarActions)();
if (templateData.focusIndicator) {
if (!toolbarActions.length) {
templateData.focusIndicator.style.top = `8px`;
} else {
templateData.focusIndicator.style.top = `24px`;
}
}
}
templateData.toolbar!.context = <INotebookCellActionContext>{
cell: element,
notebookEditor: this.notebookEditor
notebookEditor: this.notebookEditor,
$mid: 12
};
}
getCellToolbarActions(element: CellViewModel): IAction[] {
const viewModel = this.notebookEditor.viewModel;
if (!viewModel) {
return [];
}
const menu = this.createMenu().getCellTitleActions(this.contextKeyService);
const actions: IAction[] = [];
for (let [, actions] of menu.getActions({ shouldForwardArgs: true })) {
actions.push(...actions);
}
const metadata = viewModel.metadata;
if (!metadata || metadata.editable) {
actions.push(
this.instantiationService.createInstance(MoveCellUpAction),
this.instantiationService.createInstance(MoveCellDownAction),
this.instantiationService.createInstance(InsertCodeCellBelowAction)
);
}
const cellMetadata = element.metadata;
if (!cellMetadata || cellMetadata.editable) {
actions.push(
this.instantiationService.createInstance(EditCellAction),
this.instantiationService.createInstance(SaveCellAction)
);
}
if (!metadata || metadata.editable) {
this.instantiationService.createInstance(DeleteCellAction);
}
return actions;
}
getAdditionalContextMenuActions(): IAction[] {
return [
this.instantiationService.createInstance(EditCellAction),
@@ -269,8 +305,9 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende
@IInstantiationService instantiationService: IInstantiationService,
@IKeybindingService keybindingService: IKeybindingService,
@INotificationService notificationService: INotificationService,
@IContextKeyService contextKeyService: IContextKeyService
) {
super(instantiationService, notebookEditor, contextMenuService, configurationService, keybindingService, notificationService, 'python');
super(instantiationService, notebookEditor, contextMenuService, configurationService, keybindingService, notificationService, contextKeyService, 'python');
}
get templateId() {
@@ -279,9 +316,6 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende
renderTemplate(container: HTMLElement): CellRenderTemplate {
const disposables = new DisposableStore();
const toolbarContainer = document.createElement('div');
container.appendChild(toolbarContainer);
DOM.addClasses(toolbarContainer, 'menu', 'codicon-settings-gear', 'codicon');
const toolbar = this.createToolbar(container);
toolbar.setActions([
this.instantiationService.createInstance(MoveCellUpAction),
@@ -291,19 +325,22 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende
])();
disposables.add(toolbar);
const cellContainer = document.createElement('div');
DOM.addClasses(cellContainer, 'cell', 'code');
container.appendChild(cellContainer);
const editor = this.instantiationService.createInstance(CodeEditorWidget, cellContainer, {
const cellContainer = DOM.append(container, $('.cell.code'));
const runButtonContainer = DOM.append(cellContainer, $('.run-button-container'));
const runToolbar = this.createToolbar(runButtonContainer);
runToolbar.setActions([
this.instantiationService.createInstance(ExecuteCellAction)
])();
disposables.add(runToolbar);
const editorContainer = DOM.append(cellContainer, $('.cell-editor-container'));
const editor = this.instantiationService.createInstance(CodeEditorWidget, editorContainer, {
...this.editorOptions,
dimension: {
width: 0,
height: 0
}
}, {});
const menuContainer = document.createElement('div');
DOM.addClasses(menuContainer, 'menu', 'codicon-settings-gear', 'codicon');
container.appendChild(menuContainer);
const focusIndicator = DOM.append(container, DOM.$('.notebook-cell-focus-indicator'));
@@ -311,12 +348,18 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende
DOM.addClasses(outputContainer, 'output');
container.appendChild(outputContainer);
const progressBar = new ProgressBar(editorContainer);
progressBar.hide();
disposables.add(progressBar);
return {
container,
cellContainer,
menuContainer,
editorContainer,
progressBar,
focusIndicator,
toolbar,
runToolbar,
outputContainer,
editor,
disposables
@@ -339,24 +382,6 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende
const elementDisposable = this.disposables.get(element);
elementDisposable?.add(DOM.addStandardDisposableListener(templateData.menuContainer!, 'mousedown', e => {
let { top, height } = DOM.getDomNodePagePosition(templateData.menuContainer!);
e.preventDefault();
const listIndexAttr = templateData.menuContainer?.parentElement?.getAttribute('data-index');
const listIndex = listIndexAttr ? Number(listIndexAttr) : undefined;
this.showContextMenu(listIndex, element, e.posx, top + height);
}));
elementDisposable!.add(DOM.addStandardDisposableListener(templateData.menuContainer!, DOM.EventType.MOUSE_LEAVE, e => {
templateData.menuContainer?.classList.remove('mouseover');
}));
elementDisposable!.add(DOM.addStandardDisposableListener(templateData.menuContainer!, DOM.EventType.MOUSE_ENTER, e => {
templateData.menuContainer?.classList.add('mouseover');
}));
elementDisposable?.add(this.instantiationService.createInstance(CodeCell, this.notebookEditor, element, templateData));
this.renderedEditors.set(element, templateData.editor);
@@ -364,12 +389,58 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende
templateData.focusIndicator!.style.height = `${element.getIndicatorHeight()}px`;
}));
templateData.toolbar!.context = <INotebookCellActionContext>{
const toolbarContext = <INotebookCellActionContext>{
cell: element,
notebookEditor: this.notebookEditor
cellTemplate: templateData,
notebookEditor: this.notebookEditor,
$mid: 12
};
const contextKeyService = this.contextKeyService.createScoped(templateData.container);
contextKeyService.createKey(NOTEBOOK_CELL_TYPE_CONTEXT_KEY, 'code');
const toolbarActions = this.getCellToolbarActions(element);
templateData.toolbar!.setActions(toolbarActions)();
templateData.toolbar!.context = toolbarContext;
templateData.runToolbar!.context = toolbarContext;
if (templateData.focusIndicator) {
if (!toolbarActions.length) {
templateData.focusIndicator.style.top = `8px`;
} else {
templateData.focusIndicator.style.top = `24px`;
}
}
}
getCellToolbarActions(element: CellViewModel): IAction[] {
const viewModel = this.notebookEditor.viewModel;
if (!viewModel) {
return [];
}
const menu = this.createMenu().getCellTitleActions(this.contextKeyService);
const actions: IAction[] = [];
for (let [, actions] of menu.getActions({ shouldForwardArgs: true })) {
actions.push(...actions);
}
const metadata = viewModel.metadata;
if (!metadata || metadata.editable) {
actions.push(
this.instantiationService.createInstance(MoveCellUpAction),
this.instantiationService.createInstance(MoveCellDownAction),
this.instantiationService.createInstance(InsertCodeCellBelowAction),
this.instantiationService.createInstance(DeleteCellAction)
);
}
return actions;
}
getAdditionalContextMenuActions(): IAction[] {
return [];
}

View File

@@ -14,7 +14,7 @@ import { CancellationTokenSource } from 'vs/base/common/cancellation';
import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
import { INotebookService } from 'vs/workbench/contrib/notebook/browser/notebookService';
import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookCellViewModel';
import { CELL_MARGIN, EDITOR_TOP_PADDING, EDITOR_BOTTOM_PADDING } from 'vs/workbench/contrib/notebook/browser/constants';
import { CELL_MARGIN, EDITOR_TOP_PADDING, EDITOR_BOTTOM_PADDING, RUN_BUTTON_WIDTH } from 'vs/workbench/contrib/notebook/browser/constants';
interface IMimeTypeRenderer extends IQuickPickItem {
index: number;
@@ -34,7 +34,8 @@ export class CodeCell extends Disposable {
let width: number;
const listDimension = notebookEditor.getLayoutInfo();
width = listDimension.width - CELL_MARGIN * 2;
width = listDimension.width - CELL_MARGIN * 2 - RUN_BUTTON_WIDTH;
const lineNum = viewCell.lineCount;
const lineHeight = notebookEditor.getLayoutInfo().fontInfo.lineHeight;
const totalHeight = lineNum * lineHeight + EDITOR_TOP_PADDING + EDITOR_BOTTOM_PADDING;
@@ -59,7 +60,7 @@ export class CodeCell extends Disposable {
let realContentHeight = templateData.editor?.getContentHeight();
let width: number;
const listDimension = notebookEditor.getLayoutInfo();
width = listDimension.width - CELL_MARGIN * 2;
width = listDimension.width - CELL_MARGIN * 2 - RUN_BUTTON_WIDTH;
if (realContentHeight !== undefined && realContentHeight !== totalHeight) {
templateData.editor?.layout(
@@ -84,7 +85,7 @@ export class CodeCell extends Disposable {
}
}));
let cellWidthResizeObserver = getResizesObserver(templateData.cellContainer, {
let cellWidthResizeObserver = getResizesObserver(templateData.editorContainer!, {
width: width,
height: totalHeight
}, () => {
@@ -267,7 +268,7 @@ export class CodeCell extends Disposable {
let clientHeight = outputItemDiv.clientHeight;
let listDimension = this.notebookEditor.getLayoutInfo();
let dimension = listDimension ? {
width: listDimension.width - CELL_MARGIN * 2,
width: listDimension.width - CELL_MARGIN * 2 - RUN_BUTTON_WIDTH,
height: clientHeight
} : undefined;
const elementSizeObserver = getResizesObserver(outputItemDiv, dimension, () => {

View File

@@ -55,6 +55,10 @@ export class CellViewModel extends Disposable implements ICellViewModel {
return this.cell.outputs;
}
get metadata() {
return this.cell.metadata;
}
private _state: CellState = CellState.Preview;
get state(): CellState {
@@ -519,4 +523,10 @@ export class CellViewModel extends Disposable implements ICellViewModel {
this._outputsTop = new PrefixSumComputer(values);
}
}
toJSON(): any {
return {
handle: this.handle
};
}
}

View File

@@ -81,6 +81,10 @@ export class NotebookViewModel extends Disposable {
return this._model.notebook.uri;
}
get metadata() {
return this._model.notebook.metadata;
}
private readonly _onDidChangeViewCells = new Emitter<INotebookViewCellsUpdateEvent>();
get onDidChangeViewCells(): Event<INotebookViewCellsUpdateEvent> { return this._onDidChangeViewCells.event; }

View File

@@ -7,7 +7,7 @@ import { Emitter, Event } from 'vs/base/common/event';
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri';
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
import { INotebookTextModel, NotebookCellOutputsSplice, NotebookCellsSplice } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotebookTextModel, NotebookCellOutputsSplice, NotebookCellsSplice, NotebookDocumentMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
export class NotebookTextModel extends Disposable implements INotebookTextModel {
private readonly _onWillDispose: Emitter<void> = this._register(new Emitter<void>());
@@ -21,6 +21,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
cells: NotebookCellTextModel[];
activeCell: NotebookCellTextModel | undefined;
languages: string[] = [];
metadata: NotebookDocumentMetadata | undefined = undefined;
renderers = new Set<number>();
constructor(
@@ -36,6 +37,10 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
this.languages = languages;
}
updateNotebookMetadata(metadata: NotebookDocumentMetadata | undefined) {
this.metadata = metadata;
}
updateRenderers(renderers: number[]) {
renderers.forEach(render => {
this.renderers.add(render);

View File

@@ -36,6 +36,14 @@ export const NOTEBOOK_DISPLAY_ORDER = [
'text/plain'
];
export interface NotebookDocumentMetadata {
editable: boolean;
}
export interface NotebookCellMetadata {
editable: boolean;
}
export interface INotebookDisplayOrder {
defaultOrder: string[];
userOrder?: string[];
@@ -122,6 +130,7 @@ export interface ICell {
language: string;
cellKind: CellKind;
outputs: IOutput[];
metadata?: NotebookCellMetadata;
onDidChangeOutputs?: Event<NotebookCellOutputsSplice[]>;
resolveTextBufferFactory(): PieceTreeTextBufferFactory;
// TODO@rebornix it should be later on replaced by moving textmodel resolution into CellTextModel

View File

@@ -69,6 +69,12 @@ export class TestNotebookEditor implements INotebookEditor {
constructor(
) { }
isNotebookEditor = true;
postMessage(message: any): void {
throw new Error('Method not implemented.');
}
setCellSelection(cell: CellViewModel, selection: Range): void {
throw new Error('Method not implemented.');
}

View File

@@ -10,7 +10,7 @@ import { prepareQuery, IPreparedQuery, compareItemsByScore, scoreItem, ScorerCac
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';
import { ISearchService, IFileMatch } from 'vs/workbench/services/search/common/search';
import { ISearchService } from 'vs/workbench/services/search/common/search';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { untildify } from 'vs/base/common/labels';
import { IRemotePathService } from 'vs/workbench/services/path/common/remotePathService';
@@ -54,13 +54,24 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
private readonly pickState = new class {
scorerCache: ScorerCache = Object.create(null);
fileQueryCache: FileQueryCacheState | undefined;
fileQueryCache: FileQueryCacheState | undefined = undefined;
lastOriginalFilter: string | undefined = undefined;
lastFilter: string | undefined = undefined;
lastRange: IRange | undefined = undefined;
constructor(private readonly provider: AnythingQuickAccessProvider) { }
reset(): void {
// Caches
this.fileQueryCache = this.provider.createFileQueryCache();
this.scorerCache = Object.create(null);
// Other
this.lastOriginalFilter = undefined;
this.lastFilter = undefined;
this.lastRange = undefined;
}
}(this);
@@ -91,6 +102,7 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
openEditorPinned: !editorConfig.enablePreviewFromQuickOpen,
openSideBySideDirection: editorConfig.openSideBySideDirection,
includeSymbols: searchConfig.search.quickOpen.includeSymbols,
workspaceSymbolsFilter: searchConfig.search.quickOpen.workspaceSymbolsFilter,
includeHistory: searchConfig.search.quickOpen.includeHistory,
shortAutoSaveDelay: this.filesConfigurationService.getAutoSaveMode() === AutoSaveMode.AFTER_SHORT_DELAY
};
@@ -105,19 +117,37 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
return super.provide(picker, token);
}
protected getPicks(filter: string, disposables: DisposableStore, token: CancellationToken): FastAndSlowPicksType<IAnythingQuickPickItem> {
protected getPicks(originalFilter: string, disposables: DisposableStore, token: CancellationToken): FastAndSlowPicksType<IAnythingQuickPickItem> | null {
// Find a suitable range from the pattern looking for ":", "#" or ","
let range: IRange | undefined = undefined;
const filterWithRange = extractRangeFromFilter(filter);
const filterWithRange = extractRangeFromFilter(originalFilter);
// Update filter with normalized values
let filter: string;
if (filterWithRange) {
filter = filterWithRange.filter;
range = filterWithRange.range;
} else {
filter = originalFilter;
}
// Remember as last range
this.pickState.lastRange = filterWithRange?.range;
// If the original filter value has changed but the normalized
// one has not, we return early with a `null` result indicating
// that the results should preserve because the range information
// (:<line>:<column>) does not need to trigger any re-sorting.
if (originalFilter !== this.pickState.lastOriginalFilter && filter === this.pickState.lastFilter) {
return null;
}
// Remember as last filter
this.pickState.lastOriginalFilter = originalFilter;
this.pickState.lastFilter = filter;
const query = prepareQuery(filter);
const historyEditorPicks = this.getEditorHistoryPicks(query, range);
const historyEditorPicks = this.getEditorHistoryPicks(query);
return {
@@ -139,7 +169,7 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
}
}
const additionalPicks = await this.getAdditionalPicks(query, range, additionalPicksExcludes, token);
const additionalPicks = await this.getAdditionalPicks(query, additionalPicksExcludes, token);
if (token.isCancellationRequested) {
return [];
}
@@ -152,12 +182,12 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
};
}
private async getAdditionalPicks(query: IPreparedQuery, range: IRange | undefined, excludes: ResourceMap<boolean>, token: CancellationToken): Promise<Array<IAnythingQuickPickItem>> {
private async getAdditionalPicks(query: IPreparedQuery, excludes: ResourceMap<boolean>, token: CancellationToken): Promise<Array<IAnythingQuickPickItem>> {
// Resolve file and symbol picks (if enabled)
const [filePicks, symbolPicks] = await Promise.all([
this.getFilePicks(query, range, excludes, token),
this.getSymbolPicks(query, range, token)
this.getFilePicks(query, excludes, token),
this.getSymbolPicks(query, token)
]);
if (token.isCancellationRequested) {
@@ -193,11 +223,12 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
private readonly labelOnlyEditorHistoryPickAccessor = new QuickPickItemScorerAccessor({ skipDescription: true });
protected getEditorHistoryPicks(query: IPreparedQuery, range: IRange | undefined): Array<IAnythingQuickPickItem> {
protected getEditorHistoryPicks(query: IPreparedQuery): Array<IAnythingQuickPickItem> {
const configuration = this.configuration;
// Just return all history entries if not searching
if (!query.value) {
return this.historyService.getHistory().map(editor => this.createAnythingPick(editor, range));
return this.historyService.getHistory().map(editor => this.createAnythingPick(editor, configuration));
}
if (!this.configuration.includeHistory) {
@@ -215,7 +246,7 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
continue; // exclude editors without file resource if we are searching by pattern
}
const editorHistoryPick = this.createAnythingPick(editor, range);
const editorHistoryPick = this.createAnythingPick(editor, configuration);
const { score, labelMatch, descriptionMatch } = scoreItem(editorHistoryPick, query, false, editorHistoryScorerAccessor, this.pickState.scorerCache);
if (!score) {
@@ -238,7 +269,7 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
//#region File Search
private fileQueryDelayer = this._register(new ThrottledDelayer<IFileMatch[]>(AnythingQuickAccessProvider.TYPING_SEARCH_DELAY));
private fileQueryDelayer = this._register(new ThrottledDelayer<URI[]>(AnythingQuickAccessProvider.TYPING_SEARCH_DELAY));
private fileQueryBuilder = this.instantiationService.createInstance(QueryBuilder);
@@ -251,7 +282,7 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
).load();
}
protected async getFilePicks(query: IPreparedQuery, range: IRange | undefined, excludes: ResourceMap<boolean>, token: CancellationToken): Promise<Array<IAnythingQuickPickItem>> {
protected async getFilePicks(query: IPreparedQuery, excludes: ResourceMap<boolean>, token: CancellationToken): Promise<Array<IAnythingQuickPickItem>> {
if (!query.value) {
return [];
}
@@ -263,9 +294,9 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
}
// Use absolute path result as only results if present
let fileMatches: Array<IFileMatch<URI>>;
let fileMatches: Array<URI>;
if (absolutePathResult) {
fileMatches = [{ resource: absolutePathResult }];
fileMatches = [absolutePathResult];
}
// Otherwise run the file search (with a delayer if cache is not ready yet)
@@ -288,23 +319,37 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
}
// Filter excludes & convert to picks
const configuration = this.configuration;
return fileMatches
.filter(fileMatch => !excludes.has(fileMatch.resource))
.map(fileMatch => this.createAnythingPick(fileMatch.resource, range));
.filter(resource => !excludes.has(resource))
.map(resource => this.createAnythingPick(resource, configuration));
}
private async doFileSearch(query: IPreparedQuery, token: CancellationToken): Promise<IFileMatch[]> {
const { results } = await this.searchService.fileSearch(
this.fileQueryBuilder.file(
this.contextService.getWorkspace().folders,
this.getFileQueryOptions({
filePattern: query.original,
cacheKey: this.pickState.fileQueryCache?.cacheKey,
maxResults: AnythingQuickAccessProvider.MAX_RESULTS
})
), token);
private async doFileSearch(query: IPreparedQuery, token: CancellationToken): Promise<URI[]> {
const [fileSearchResults, relativePathFileResults] = await Promise.all([
return results;
// File search: this is a search over all files of the workspace using the provided pattern
this.searchService.fileSearch(
this.fileQueryBuilder.file(
this.contextService.getWorkspace().folders,
this.getFileQueryOptions({
filePattern: query.original,
cacheKey: this.pickState.fileQueryCache?.cacheKey,
maxResults: AnythingQuickAccessProvider.MAX_RESULTS
})
), token),
// Relative path search: we also want to consider results that match files inside the workspace
// by looking for relative paths that the user typed as query. This allows to return even excluded
// results into the picker if found (e.g. helps for opening compilation results that are otherwise
// excluded)
this.getRelativePathFileResults(query, token)
]);
return [
...fileSearchResults.results.map(result => result.resource),
...(relativePathFileResults || [])
];
}
private getFileQueryOptions(input: { filePattern?: string, cacheKey?: string, maxResults?: number }): IFileQueryBuilderOptions {
@@ -321,7 +366,11 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
}
private async getAbsolutePathFileResult(query: IPreparedQuery, token: CancellationToken): Promise<URI | undefined> {
const detildifiedQuery = untildify(query.original, (await this.remotePathService.userHome).path);
if (!query.containsPathSeparator) {
return undefined; // {{SQL CARBON EDIT}} strict-null
}
const detildifiedQuery = untildify(query.value, (await this.remotePathService.userHome).path);
if (token.isCancellationRequested) {
return undefined; // {{SQL CARBON EDIT}} strict-null
}
@@ -342,15 +391,52 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
}
try {
return (await this.fileService.resolve(resource)).isDirectory ? undefined : resource;
if ((await this.fileService.resolve(resource)).isFile) {
return resource;
}
} catch (error) {
// ignore
// ignore if file does not exist
}
}
return undefined; // {{SQL CARBON EDIT}} strict-null
}
private async getRelativePathFileResults(query: IPreparedQuery, token: CancellationToken): Promise<URI[] | undefined> {
if (!query.containsPathSeparator) {
return undefined; // {{SQL CARBON EDIT}} strict-null
}
// Convert relative paths to absolute paths over all folders of the workspace
// and return them as results if the absolute paths exist
const isAbsolutePathQuery = (await this.remotePathService.path).isAbsolute(query.value);
if (!isAbsolutePathQuery) {
const resources: URI[] = [];
for (const folder of this.contextService.getWorkspace().folders) {
if (token.isCancellationRequested) {
break;
}
const resource = toLocalResource(
folder.toResource(query.value),
this.environmentService.configuration.remoteAuthority
);
try {
if ((await this.fileService.resolve(resource)).isFile) {
resources.push(resource);
}
} catch (error) {
// ignore if file does not exist
}
}
return resources;
}
return undefined; // {{SQL CARBON EDIT}} strict-null
}
//#endregion
@@ -358,18 +444,23 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
private symbolsQuickAccess = this._register(this.instantiationService.createInstance(SymbolsQuickAccessProvider));
protected async getSymbolPicks(query: IPreparedQuery, range: IRange | undefined, token: CancellationToken): Promise<Array<IAnythingQuickPickItem>> {
protected async getSymbolPicks(query: IPreparedQuery, token: CancellationToken): Promise<Array<IAnythingQuickPickItem>> {
const configuration = this.configuration;
if (
!query.value || // we need a value for search for
!this.configuration.includeSymbols || // we need to enable symbols in search
range // a range is an indicator for just searching for files
!query.value || // we need a value for search for
!configuration.includeSymbols || // we need to enable symbols in search
this.pickState.lastRange // a range is an indicator for just searching for files
) {
return [];
}
// Delegate to the existing symbols quick access
// but skip local results and also do not sort
return this.symbolsQuickAccess.getSymbolPicks(query.value, { skipLocal: true, skipSorting: true, delay: AnythingQuickAccessProvider.TYPING_SEARCH_DELAY }, token);
return this.symbolsQuickAccess.getSymbolPicks(query.value, {
skipLocal: configuration.workspaceSymbolsFilter !== 'all',
skipSorting: true,
delay: AnythingQuickAccessProvider.TYPING_SEARCH_DELAY
}, token);
}
//#endregion
@@ -377,7 +468,7 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
//#region Helpers
private createAnythingPick(resourceOrEditor: URI | IEditorInput | IResourceEditorInput, range: IRange | undefined): IAnythingQuickPickItem {
private createAnythingPick(resourceOrEditor: URI | IEditorInput | IResourceEditorInput, configuration: { shortAutoSaveDelay: boolean, openSideBySideDirection: 'right' | 'down' | undefined }): IAnythingQuickPickItem {
const isEditorHistoryEntry = !URI.isUri(resourceOrEditor);
let resource: URI | undefined;
@@ -394,7 +485,7 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
resource = URI.isUri(resourceOrEditor) ? resourceOrEditor : (resourceOrEditor as IResourceEditorInput).resource;
label = basenameOrAuthority(resource);
description = this.labelService.getUriLabel(dirname(resource), { relative: true });
isDirty = this.workingCopyService.isDirty(resource) && !this.configuration.shortAutoSaveDelay;
isDirty = this.workingCopyService.isDirty(resource) && !configuration.shortAutoSaveDelay;
}
return {
@@ -406,7 +497,7 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
description,
iconClasses: getIconClasses(this.modelService, this.modeService, resource),
buttons: (() => {
const openSideBySideDirection = this.configuration.openSideBySideDirection;
const openSideBySideDirection = configuration.openSideBySideDirection;
const buttons: IQuickInputButton[] = [];
// Open to side / below
@@ -431,7 +522,7 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
// Open to side / below
case 0:
this.openAnything(resourceOrEditor, { keyMods, range, forceOpenSideBySide: true });
this.openAnything(resourceOrEditor, { keyMods, range: this.pickState.lastRange, forceOpenSideBySide: true });
return TriggerAction.CLOSE_PICKER;
// Remove from History
@@ -445,7 +536,7 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
return TriggerAction.NO_ACTION;
},
accept: (keyMods, event) => this.openAnything(resourceOrEditor, { keyMods, range, preserveFocus: event.inBackground })
accept: (keyMods, event) => this.openAnything(resourceOrEditor, { keyMods, range: this.pickState.lastRange, preserveFocus: event.inBackground })
};
}

View File

@@ -734,6 +734,17 @@ configurationRegistry.registerConfiguration({
description: nls.localize('search.quickOpen.includeSymbols', "Whether to include results from a global symbol search in the file results for Quick Open."),
default: false
},
'search.quickOpen.workspaceSymbolsFilter': {
type: 'string',
enum: ['default', 'reduced', 'all'],
markdownEnumDescriptions: [
nls.localize('search.quickOpen.workspaceSymbolsFilter.default', "All symbols including local variables are included in the specific workspace symbols picker but excluded from the files picker when `#search.quickOpen.includeSymbols#` is enabled."),
nls.localize('search.quickOpen.workspaceSymbolsFilter.reduced', "Some symbols like local variables are excluded in all pickers."),
nls.localize('search.quickOpen.workspaceSymbolsFilter.all', "All symbols including local variables are included in all pickers.")
],
default: 'default',
description: nls.localize('search.quickOpen.workspaceSymbolsFilter', "Controls the filter to apply for the workspace symbols search in quick open. Depending on the setting, some symbols like local variables will be excluded to reduce the total number of results."),
},
'search.quickOpen.includeHistory': {
type: 'boolean',
description: nls.localize('search.quickOpen.includeHistory', "Whether to include results from recently opened files in the file results for Quick Open."),
@@ -766,7 +777,7 @@ configurationRegistry.registerConfiguration({
type: 'string',
enum: ['auto', 'alwaysCollapse', 'alwaysExpand'],
enumDescriptions: [
'Files with less than 10 results are expanded. Others are collapsed.',
nls.localize('search.collapseResults.auto', "Files with less than 10 results are expanded. Others are collapsed."),
'',
''
],

View File

@@ -10,8 +10,8 @@ import { stripWildcards } from 'vs/base/common/strings';
import { CancellationToken } from 'vs/base/common/cancellation';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { ThrottledDelayer } from 'vs/base/common/async';
import { getWorkspaceSymbols, IWorkspaceSymbol, IWorkspaceSymbolProvider } from 'vs/workbench/contrib/search/common/search';
import { SymbolKinds, SymbolTag } from 'vs/editor/common/modes';
import { getWorkspaceSymbols, IWorkspaceSymbol, IWorkspaceSymbolProvider, IWorkbenchSearchConfiguration } from 'vs/workbench/contrib/search/common/search';
import { SymbolKinds, SymbolTag, SymbolKind } from 'vs/editor/common/modes';
import { ILabelService } from 'vs/platform/label/common/label';
import { Schemas } from 'vs/base/common/network';
import { IOpenerService } from 'vs/platform/opener/common/opener';
@@ -37,6 +37,16 @@ export class SymbolsQuickAccessProvider extends PickerQuickAccessProvider<ISymbo
private static readonly TYPING_SEARCH_DELAY = 200; // this delay accommodates for the user typing a word and then stops typing to start searching
private static TREAT_AS_GLOBAL_SYMBOL_TYPES = new Set<SymbolKind>([
SymbolKind.Class,
SymbolKind.Enum,
SymbolKind.File,
SymbolKind.Interface,
SymbolKind.Namespace,
SymbolKind.Package,
SymbolKind.Module
]);
private delayer = this._register(new ThrottledDelayer<ISymbolQuickPickItem[]>(SymbolsQuickAccessProvider.TYPING_SEARCH_DELAY));
private readonly resourceExcludeMatcher = this._register(createResourceExcludeMatcher(this.instantiationService, this.configurationService));
@@ -53,18 +63,20 @@ export class SymbolsQuickAccessProvider extends PickerQuickAccessProvider<ISymbo
private get configuration() {
const editorConfig = this.configurationService.getValue<IWorkbenchEditorConfiguration>().workbench.editor;
const searchConfig = this.configurationService.getValue<IWorkbenchSearchConfiguration>();
return {
openEditorPinned: !editorConfig.enablePreviewFromQuickOpen,
openSideBySideDirection: editorConfig.openSideBySideDirection
openSideBySideDirection: editorConfig.openSideBySideDirection,
workspaceSymbolsFilter: searchConfig.search.quickOpen.workspaceSymbolsFilter
};
}
protected getPicks(filter: string, disposables: DisposableStore, token: CancellationToken): Promise<Array<ISymbolQuickPickItem>> {
return this.getSymbolPicks(filter, undefined, token);
return this.getSymbolPicks(filter, { skipLocal: this.configuration.workspaceSymbolsFilter === 'reduced' }, token);
}
async getSymbolPicks(filter: string, options: { skipLocal: boolean, skipSorting: boolean, delay: number } | undefined, token: CancellationToken): Promise<Array<ISymbolQuickPickItem>> {
async getSymbolPicks(filter: string, options: { skipLocal?: boolean, skipSorting?: boolean, delay?: number } | undefined, token: CancellationToken): Promise<Array<ISymbolQuickPickItem>> {
return this.delayer.trigger(async () => {
if (token.isCancellationRequested) {
return [];
@@ -74,7 +86,7 @@ export class SymbolsQuickAccessProvider extends PickerQuickAccessProvider<ISymbo
}, options?.delay);
}
private async doGetSymbolPicks(filter: string, options: { skipLocal: boolean, skipSorting: boolean } | undefined, token: CancellationToken): Promise<Array<ISymbolQuickPickItem>> {
private async doGetSymbolPicks(filter: string, options: { skipLocal?: boolean, skipSorting?: boolean } | undefined, token: CancellationToken): Promise<Array<ISymbolQuickPickItem>> {
const workspaceSymbols = await getWorkspaceSymbols(filter, token);
if (token.isCancellationRequested) {
return [];
@@ -92,8 +104,12 @@ export class SymbolsQuickAccessProvider extends PickerQuickAccessProvider<ISymbo
const symbolsExcludedByResource = new ResourceMap<boolean>();
for (const [provider, symbols] of workspaceSymbols) {
for (const symbol of symbols) {
if (options?.skipLocal && !!symbol.containerName) {
continue; // ignore local symbols if we are told so
// Depending on the workspace symbols filter setting, skip over symbols that:
// - do not have a container
// - and are not treated explicitly as global symbols (e.g. classes)
if (options?.skipLocal && !SymbolsQuickAccessProvider.TREAT_AS_GLOBAL_SYMBOL_TYPES.has(symbol.kind) && !!symbol.containerName) {
continue;
}
// Score by symbol label

View File

@@ -77,6 +77,7 @@ export interface IWorkbenchSearchConfigurationProperties extends ISearchConfigur
quickOpen: {
includeSymbols: boolean;
includeHistory: boolean;
workspaceSymbolsFilter: 'default' | 'reduced' | 'all';
};
}
@@ -102,7 +103,12 @@ export function getOutOfWorkspaceEditorResources(accessor: ServicesAccessor): UR
// Supports patterns of <path><#|:|(><line><#|:|,><col?>
const LINE_COLON_PATTERN = /\s?[#:\(](\d*)([#:,](\d*))?\)?\s*$/;
export function extractRangeFromFilter(filter: string): { filter: string, range: IRange } | undefined {
export interface IFilterAndRange {
filter: string;
range: IRange;
}
export function extractRangeFromFilter(filter: string): IFilterAndRange | undefined {
if (!filter) {
return undefined;
}
@@ -151,7 +157,7 @@ export function extractRangeFromFilter(filter: string): { filter: string, range:
if (patternMatch && range) {
return {
filter: filter.substr(0, patternMatch.index), // clear range suffix from search value
range: range
range
};
}

View File

@@ -87,7 +87,7 @@ async function computePicks(snippetService: ISnippetsService, envService: IEnvir
}
}
const dir = joinPath(envService.userRoamingDataHome, 'snippets');
const dir = envService.snippetsHome;
for (const mode of modeService.getRegisteredModes()) {
const label = modeService.getLanguageName(mode);
if (label && !seen.has(mode)) {
@@ -219,7 +219,7 @@ CommandsRegistry.registerCommand(id, async (accessor): Promise<any> => {
const globalSnippetPicks: SnippetPick[] = [{
scope: nls.localize('new.global_scope', 'global'),
label: nls.localize('new.global', "New Global Snippets file..."),
uri: joinPath(envService.userRoamingDataHome, 'snippets')
uri: envService.snippetsHome
}];
const workspaceSnippetPicks: SnippetPick[] = [];

View File

@@ -289,7 +289,7 @@ class SnippetsService implements ISnippetsService {
}
private _initUserSnippets(): Promise<any> {
const userSnippetsFolder = resources.joinPath(this._environmentService.userRoamingDataHome, 'snippets');
const userSnippetsFolder = this._environmentService.snippetsHome;
return this._fileService.createFolder(userSnippetsFolder).then(() => this._initFolderSnippets(SnippetSource.User, userSnippetsFolder, this._disposables));
}

View File

@@ -368,11 +368,7 @@ export class TerminalTaskSystem implements ITaskSystem {
});
}
private removeFromActiveTasks(task: Task): void {
if (!this.activeTasks[task.getMapKey()]) {
return;
}
delete this.activeTasks[task.getMapKey()];
private removeInstances(task: Task) {
let commonKey = task._id.split('|')[0];
if (this.instances[commonKey]) {
this.instances[commonKey].removeInstance();
@@ -382,6 +378,14 @@ export class TerminalTaskSystem implements ITaskSystem {
}
}
private removeFromActiveTasks(task: Task): void {
if (!this.activeTasks[task.getMapKey()]) {
return;
}
delete this.activeTasks[task.getMapKey()];
this.removeInstances(task);
}
public terminate(task: Task): Promise<TaskTerminateResponse> {
let activeTerminal = this.activeTasks[task.getMapKey()];
if (!activeTerminal) {
@@ -466,6 +470,7 @@ export class TerminalTaskSystem implements ITaskSystem {
return Promise.all(promises).then((summaries): Promise<ITaskSummary> | ITaskSummary => {
for (let summary of summaries) {
if (summary.exitCode !== 0) {
this.removeInstances(task);
return { exitCode: summary.exitCode };
}
}

View File

@@ -20,7 +20,7 @@ import { configurationTelemetry } from 'vs/platform/telemetry/common/telemetryUt
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { ITextFileService, ITextFileSaveEvent, ITextFileLoadEvent } from 'vs/workbench/services/textfile/common/textfiles';
import { extname, basename, isEqual, isEqualOrParent, joinPath } from 'vs/base/common/resources';
import { extname, basename, isEqual, isEqualOrParent } from 'vs/base/common/resources';
import { URI } from 'vs/base/common/uri';
import { Schemas } from 'vs/base/common/network';
import { guessMimeTypes } from 'vs/base/common/mime';
@@ -175,7 +175,7 @@ export class TelemetryContribution extends Disposable implements IWorkbenchContr
}
// Check for snippets
if (isEqualOrParent(resource, joinPath(this.environmentService.userRoamingDataHome, 'snippets'))) {
if (isEqualOrParent(resource, this.environmentService.snippetsHome)) {
return 'snippets';
}

View File

@@ -9,7 +9,7 @@ import { canceled, isPromiseCanceledError } from 'vs/base/common/errors';
import { Event } from 'vs/base/common/event';
import { Disposable, DisposableStore, dispose, MutableDisposable, toDisposable, IDisposable } from 'vs/base/common/lifecycle';
import { isWeb } from 'vs/base/common/platform';
import { isEqual } from 'vs/base/common/resources';
import { isEqual, basename } from 'vs/base/common/resources';
import { URI } from 'vs/base/common/uri';
import type { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { registerEditorContribution, ServicesAccessor } from 'vs/editor/browser/editorExtensions';
@@ -32,7 +32,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import {
CONTEXT_SYNC_STATE, getUserDataSyncStore, ISyncConfiguration, IUserDataAutoSyncService, IUserDataSyncService, IUserDataSyncStore, registerConfiguration,
SyncResource, SyncStatus, UserDataSyncError, UserDataSyncErrorCode, USER_DATA_SYNC_SCHEME, IUserDataSyncEnablementService, CONTEXT_SYNC_ENABLEMENT,
SyncResourceConflicts, Conflict, getSyncResourceFromLocalPreview, getSyncResourceFromRemotePreview
SyncResourceConflicts, Conflict, getSyncResourceFromLocalPreview
} from 'vs/platform/userDataSync/common/userDataSync';
import { FloatingClickWidget } from 'vs/workbench/browser/parts/editor/editorWidgets';
import { GLOBAL_ACTIVITY_ID } from 'vs/workbench/common/activity';
@@ -69,6 +69,7 @@ function getSyncAreaLabel(source: SyncResource): string {
switch (source) {
case SyncResource.Settings: return localize('settings', "Settings");
case SyncResource.Keybindings: return localize('keybindings', "Keyboard Shortcuts");
case SyncResource.Snippets: return localize('snippets', "User Snippets");
case SyncResource.Extensions: return localize('extensions', "Extensions");
case SyncResource.GlobalState: return localize('ui state label', "UI State");
}
@@ -100,6 +101,7 @@ const signInCommand = { id: 'workbench.userData.actions.signin', title: localize
const stopSyncCommand = { id: 'workbench.userData.actions.stopSync', title(authenticationProviderId: string, account: AuthenticationSession | undefined, authenticationService: IAuthenticationService) { return getIdentityTitle(localize('stop sync', "Sync: Turn off Sync"), authenticationProviderId, account, authenticationService); } };
const resolveSettingsConflictsCommand = { id: 'workbench.userData.actions.resolveSettingsConflicts', title: localize('showConflicts', "Sync: Show Settings Conflicts") };
const resolveKeybindingsConflictsCommand = { id: 'workbench.userData.actions.resolveKeybindingsConflicts', title: localize('showKeybindingsConflicts', "Sync: Show Keybindings Conflicts") };
const resolveSnippetsConflictsCommand = { id: 'workbench.userData.actions.resolveSnippetsConflicts', title: localize('showSnippetsConflicts', "Sync: Show User Snippets Conflicts") };
const configureSyncCommand = { id: 'workbench.userData.actions.configureSync', title: localize('configure sync', "Sync: Configure") };
const showSyncActivityCommand = {
id: 'workbench.userData.actions.showSyncActivity', title(userDataSyncService: IUserDataSyncService): string {
@@ -291,6 +293,9 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
if (conflicts.length) {
const conflictsSources: SyncResource[] = conflicts.map(conflict => conflict.syncResource);
this.conflictsSources.set(conflictsSources.join(','));
if (conflictsSources.indexOf(SyncResource.Snippets) !== -1) {
this.registerShowSnippetsConflictsAction();
}
// Clear and dispose conflicts those were cleared
this.conflictsDisposables.forEach((disposable, conflictsSource) => {
@@ -301,8 +306,19 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
});
for (const { syncResource, conflicts } of this.userDataSyncService.conflicts) {
const conflictsEditorInput = this.getConflictsEditorInput(syncResource);
if (!conflictsEditorInput && !this.conflictsDisposables.has(syncResource)) {
const conflictsEditorInputs = this.getConflictsEditorInputs(syncResource);
// close stale conflicts editor previews
if (conflictsEditorInputs.length) {
conflictsEditorInputs.forEach(input => {
if (!conflicts.some(({ local }) => isEqual(local, input.master.resource))) {
input.dispose();
}
});
}
// Show conflicts notification if not shown before
else if (!this.conflictsDisposables.has(syncResource)) {
const conflictsArea = getSyncAreaLabel(syncResource);
const handle = this.notificationService.prompt(Severity.Warning, localize('conflicts detected', "Unable to sync due to conflicts in {0}. Please resolve them to continue.", conflictsArea.toLowerCase()),
[
@@ -338,9 +354,9 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
handle.close();
// close opened conflicts editor previews
const conflictsEditorInput = this.getConflictsEditorInput(syncResource);
if (conflictsEditorInput) {
conflictsEditorInput.dispose();
const conflictsEditorInputs = this.getConflictsEditorInputs(syncResource);
if (conflictsEditorInputs.length) {
conflictsEditorInputs.forEach(input => input.dispose());
}
this.conflictsDisposables.delete(syncResource);
@@ -496,7 +512,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
if (this.userDataSyncService.status !== SyncStatus.Uninitialized && this.userDataSyncEnablementService.isEnabled() && this.authenticationState.get() === AuthStatus.SignedOut) {
badge = new NumberBadge(1, () => localize('sign in to sync', "Sign in to Sync"));
} else if (this.userDataSyncService.conflicts.length) {
badge = new NumberBadge(this.userDataSyncService.conflicts.length, () => localize('has conflicts', "Sync: Conflicts Detected"));
badge = new NumberBadge(this.userDataSyncService.conflicts.reduce((result, syncResourceConflict) => { return result + syncResourceConflict.conflicts.length; }, 0), () => localize('has conflicts', "Sync: Conflicts Detected"));
}
if (badge) {
@@ -605,6 +621,9 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
}, {
id: SyncResource.Keybindings,
label: getSyncAreaLabel(SyncResource.Keybindings)
}, {
id: SyncResource.Snippets,
label: getSyncAreaLabel(SyncResource.Snippets)
}, {
id: SyncResource.Extensions,
label: getSyncAreaLabel(SyncResource.Extensions)
@@ -712,6 +731,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
switch (source) {
case SyncResource.Settings: return this.userDataSyncEnablementService.setResourceEnablement(SyncResource.Settings, false);
case SyncResource.Keybindings: return this.userDataSyncEnablementService.setResourceEnablement(SyncResource.Keybindings, false);
case SyncResource.Snippets: return this.userDataSyncEnablementService.setResourceEnablement(SyncResource.Snippets, false);
case SyncResource.Extensions: return this.userDataSyncEnablementService.setResourceEnablement(SyncResource.Extensions, false);
case SyncResource.GlobalState: return this.userDataSyncEnablementService.setResourceEnablement(SyncResource.GlobalState, false);
}
@@ -727,8 +747,11 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
}
}
private getConflictsEditorInput(syncResource: SyncResource): IEditorInput | undefined {
return this.editorService.editors.filter(input => input instanceof DiffEditorInput && getSyncResourceFromLocalPreview(input.master.resource!, this.workbenchEnvironmentService) === syncResource)[0];
private getConflictsEditorInputs(syncResource: SyncResource): DiffEditorInput[] {
return this.editorService.editors.filter(input => {
const resource = input instanceof DiffEditorInput ? input.master.resource : input.resource;
return getSyncResourceFromLocalPreview(resource!, this.workbenchEnvironmentService) === syncResource;
}) as DiffEditorInput[];
}
private getAllConflictsEditorInputs(): IEditorInput[] {
@@ -752,6 +775,8 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
label = localize('settings conflicts preview', "Settings Conflicts (Remote ↔ Local)");
} else if (syncResource === SyncResource.Keybindings) {
label = localize('keybindings conflicts preview', "Keybindings Conflicts (Remote ↔ Local)");
} else if (syncResource === SyncResource.Snippets) {
label = localize('snippets conflicts preview', "User Snippet Conflicts (Remote ↔ Local) - {0}", basename(conflict.local));
}
await this.editorService.openEditor({
leftResource: conflict.remote,
@@ -775,6 +800,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
this.registerSignInAction();
this.registerShowSettingsConflictsAction();
this.registerShowKeybindingsConflictsAction();
this.registerShowSnippetsConflictsAction();
this.registerSyncStatusAction();
this.registerTurnOffSyncAction();
@@ -894,7 +920,36 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
command: resolveKeybindingsConflictsCommand,
when: resolveKeybindingsConflictsWhenContext,
});
}
private _snippetsConflictsActionsDisposable: DisposableStore = new DisposableStore();
private registerShowSnippetsConflictsAction(): void {
this._snippetsConflictsActionsDisposable.clear();
const resolveSnippetsConflictsWhenContext = ContextKeyExpr.regex(CONTEXT_CONFLICTS_SOURCES.keys()[0], /.*snippets.*/i);
const conflicts: Conflict[] | undefined = this.userDataSyncService.conflicts.filter(({ syncResource }) => syncResource === SyncResource.Snippets)[0]?.conflicts;
this._snippetsConflictsActionsDisposable.add(CommandsRegistry.registerCommand(resolveSnippetsConflictsCommand.id, () => this.handleSyncResourceConflicts(SyncResource.Snippets)));
this._snippetsConflictsActionsDisposable.add(MenuRegistry.appendMenuItem(MenuId.GlobalActivity, {
group: '5_sync',
command: {
id: resolveSnippetsConflictsCommand.id,
title: localize('resolveSnippetsConflicts_global', "Sync: Show User Snippets Conflicts ({0})", conflicts?.length || 1),
},
when: resolveSnippetsConflictsWhenContext,
order: 2
}));
this._snippetsConflictsActionsDisposable.add(MenuRegistry.appendMenuItem(MenuId.MenubarPreferencesMenu, {
group: '5_sync',
command: {
id: resolveSnippetsConflictsCommand.id,
title: localize('resolveSnippetsConflicts_global', "Sync: Show User Snippets Conflicts ({0})", conflicts?.length || 1),
},
when: resolveSnippetsConflictsWhenContext,
order: 2
}));
this._snippetsConflictsActionsDisposable.add(MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
command: resolveSnippetsConflictsCommand,
when: resolveSnippetsConflictsWhenContext,
}));
}
private registerSyncStatusAction(): void {
@@ -938,6 +993,9 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
case SyncResource.Keybindings:
items.push({ id: resolveKeybindingsConflictsCommand.id, label: resolveKeybindingsConflictsCommand.title });
break;
case SyncResource.Snippets:
items.push({ id: resolveSnippetsConflictsCommand.id, label: resolveSnippetsConflictsCommand.title });
break;
}
}
items.push({ type: 'separator' });
@@ -1074,7 +1132,6 @@ class AcceptChangesContribution extends Disposable implements IEditorContributio
constructor(
private editor: ICodeEditor,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
@IUserDataSyncService private readonly userDataSyncService: IUserDataSyncService,
@INotificationService private readonly notificationService: INotificationService,
@IDialogService private readonly dialogService: IDialogService,
@@ -1088,7 +1145,8 @@ class AcceptChangesContribution extends Disposable implements IEditorContributio
}
private registerListeners(): void {
this._register(this.editor.onDidChangeModel(e => this.update()));
this._register(this.editor.onDidChangeModel(() => this.update()));
this._register(this.userDataSyncService.onDidChangeConflicts(() => this.update()));
this._register(Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('diffEditor.renderSideBySide'))(() => this.update()));
}
@@ -1107,11 +1165,16 @@ class AcceptChangesContribution extends Disposable implements IEditorContributio
return false; // we need a model
}
if (getSyncResourceFromLocalPreview(model.uri, this.environmentService) !== undefined) {
const syncResourceConflicts = this.getSyncResourceConflicts(model.uri);
if (!syncResourceConflicts) {
return false;
}
if (syncResourceConflicts.conflicts.some(({ local }) => isEqual(local, model.uri))) {
return true;
}
if (getSyncResourceFromRemotePreview(model.uri, this.environmentService) !== undefined) {
if (syncResourceConflicts.conflicts.some(({ remote }) => isEqual(remote, model.uri))) {
return this.configurationService.getValue<boolean>('diffEditor.renderSideBySide');
}
@@ -1121,16 +1184,17 @@ class AcceptChangesContribution extends Disposable implements IEditorContributio
private createAcceptChangesWidgetRenderer(): void {
if (!this.acceptChangesButton) {
const isRemote = getSyncResourceFromRemotePreview(this.editor.getModel()!.uri, this.environmentService) !== undefined;
const resource = this.editor.getModel()!.uri;
const syncResourceConflicts = this.getSyncResourceConflicts(resource)!;
const isRemote = syncResourceConflicts.conflicts.some(({ remote }) => isEqual(remote, resource));
const acceptRemoteLabel = localize('accept remote', "Accept Remote");
const acceptLocalLabel = localize('accept local', "Accept Local");
this.acceptChangesButton = this.instantiationService.createInstance(FloatingClickWidget, this.editor, isRemote ? acceptRemoteLabel : acceptLocalLabel, null);
this._register(this.acceptChangesButton.onClick(async () => {
const model = this.editor.getModel();
if (model) {
const conflictsSource = (getSyncResourceFromLocalPreview(model.uri, this.environmentService) || getSyncResourceFromRemotePreview(model.uri, this.environmentService))!;
this.telemetryService.publicLog2<{ source: string, action: string }, SyncConflictsClassification>('sync/handleConflicts', { source: conflictsSource, action: isRemote ? 'acceptRemote' : 'acceptLocal' });
const syncAreaLabel = getSyncAreaLabel(conflictsSource);
this.telemetryService.publicLog2<{ source: string, action: string }, SyncConflictsClassification>('sync/handleConflicts', { source: syncResourceConflicts.syncResource, action: isRemote ? 'acceptRemote' : 'acceptLocal' });
const syncAreaLabel = getSyncAreaLabel(syncResourceConflicts.syncResource);
const result = await this.dialogService.confirm({
type: 'info',
title: isRemote
@@ -1146,7 +1210,7 @@ class AcceptChangesContribution extends Disposable implements IEditorContributio
await this.userDataSyncService.acceptConflict(model.uri, model.getValue());
} catch (e) {
if (e instanceof UserDataSyncError && e.code === UserDataSyncErrorCode.LocalPreconditionFailed) {
const syncResourceCoflicts = this.userDataSyncService.conflicts.filter(({ syncResource }) => syncResource === conflictsSource)[0];
const syncResourceCoflicts = this.userDataSyncService.conflicts.filter(({ syncResource }) => syncResource === syncResourceConflicts.syncResource)[0];
if (syncResourceCoflicts && syncResourceCoflicts.conflicts.some(conflict => isEqual(conflict.local, model.uri) || isEqual(conflict.remote, model.uri))) {
this.notificationService.warn(localize('update conflicts', "Could not resolve conflicts as there is new local version available. Please try again."));
}
@@ -1162,6 +1226,10 @@ class AcceptChangesContribution extends Disposable implements IEditorContributio
}
}
private getSyncResourceConflicts(resource: URI): SyncResourceConflicts | undefined {
return this.userDataSyncService.conflicts.filter(({ conflicts }) => conflicts.some(({ local, remote }) => isEqual(local, resource) || isEqual(remote, resource)))[0];
}
private disposeAcceptChangesWidgetRenderer(): void {
dispose(this.acceptChangesButton);
this.acceptChangesButton = undefined;

View File

@@ -125,10 +125,11 @@
}`;
/**
* @param {boolean} allowMultipleAPIAcquire
* @param {*} [state]
* @return {string}
*/
function getVsCodeApiScript(state) {
function getVsCodeApiScript(allowMultipleAPIAcquire, state) {
return `
const acquireVsCodeApi = (function() {
const originalPostMessage = window.parent.postMessage.bind(window.parent);
@@ -138,7 +139,7 @@
let state = ${state ? `JSON.parse(${JSON.stringify(state)})` : undefined};
return () => {
if (acquired) {
if (acquired && !${allowMultipleAPIAcquire}) {
throw new Error('An instance of the VS Code API has already been acquired');
}
acquired = true;
@@ -325,7 +326,7 @@
if (options.allowScripts) {
const defaultScript = newDocument.createElement('script');
defaultScript.id = '_vscodeApiScript';
defaultScript.textContent = getVsCodeApiScript(data.state);
defaultScript.textContent = getVsCodeApiScript(options.allowMultipleAPIAcquire, data.state);
newDocument.head.prepend(defaultScript);
}

View File

@@ -59,6 +59,7 @@ export interface WebviewOptions {
}
export interface WebviewContentOptions {
readonly allowMultipleAPIAcquire?: boolean;
readonly allowScripts?: boolean;
readonly localResourceRoots?: ReadonlyArray<URI>;
readonly portMapping?: ReadonlyArray<modes.IWebviewPortMapping>;

View File

@@ -36,6 +36,7 @@ export function areWebviewInputOptionsEqual(a: WebviewInputOptions, b: WebviewIn
return a.enableCommandUris === b.enableCommandUris
&& a.enableFindWidget === b.enableFindWidget
&& a.allowScripts === b.allowScripts
&& a.allowMultipleAPIAcquire === b.allowMultipleAPIAcquire
&& a.retainContextWhenHidden === b.retainContextWhenHidden
&& a.tryRestoreScrollPosition === b.tryRestoreScrollPosition
&& equals(a.localResourceRoots, b.localResourceRoots, isEqual)

View File

@@ -102,6 +102,9 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment
@memoize
get argvResource(): URI { return joinPath(this.userRoamingDataHome, 'argv.json'); }
@memoize
get snippetsHome(): URI { return joinPath(this.userRoamingDataHome, 'snippets'); }
@memoize
get userDataSyncHome(): URI { return joinPath(this.userRoamingDataHome, 'sync'); }