Skip to content

Commit

Permalink
Align custom editor API proposal with notebook API
Browse files Browse the repository at this point in the history
Fixes #95854
Fixes #95849
For #77131

- Move all editing functionality back onto the provider. This better matches the notebook API.

- Rename `CustomEditorProvider` to `CustomReadonlyEditorProvider`.  `CustomEditorProvider` is now how editable custom editors are implemented

- Give extension a full suggested backup path instead of just a folder
  • Loading branch information
mjbvz committed Apr 24, 2020
1 parent 37944c8 commit 4862602
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 130 deletions.
2 changes: 1 addition & 1 deletion extensions/image-preview/src/preview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { BinarySizeStatusBarEntry } from './binarySizeStatusBarEntry';
const localize = nls.loadMessageBundle();


export class PreviewManager implements vscode.CustomEditorProvider {
export class PreviewManager implements vscode.CustomReadonlyEditorProvider {

public static readonly viewType = 'imagePreview.previewEditor';

Expand Down
184 changes: 97 additions & 87 deletions src/vs/vscode.proposed.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1239,11 +1239,17 @@ declare module 'vscode' {
}

/**
* Event triggered by extensions to signal to VS Code that an edit has occurred on an [`CustomEditableDocument`](#CustomEditableDocument).
* Event triggered by extensions to signal to VS Code that an edit has occurred on an [`CustomDocument`](#CustomDocument).
*
* @see [`CustomEditableDocument.onDidChange`](#CustomEditableDocument.onDidChange).
* @see [`CustomDocumentProvider.onDidChangeCustomDocument`](#CustomDocumentProvider.onDidChangeCustomDocument).
*/
interface CustomDocumentEditEvent {

/**
* The document that the edit is for.
*/
readonly document: CustomDocument;

/**
* Undo the edit operation.
*
Expand All @@ -1267,25 +1273,28 @@ declare module 'vscode' {
}

/**
* Event triggered by extensions to signal to VS Code that the content of a [`CustomEditableDocument`](#CustomEditableDocument)
* Event triggered by extensions to signal to VS Code that the content of a [`CustomDocument`](#CustomDocument)
* has changed.
*
* @see [`CustomEditableDocument.onDidChange`](#CustomEditableDocument.onDidChange).
* @see [`CustomDocumentProvider.onDidChangeCustomDocument`](#CustomDocumentProvider.onDidChangeCustomDocument).
*/
interface CustomDocumentContentChangeEvent {
// marker interface
/**
* The document that the change is for.
*/
readonly document: CustomDocument;
}

/**
* A backup for an [`CustomEditableDocument`](#CustomEditableDocument).
* A backup for an [`CustomDocument`](#CustomDocument).
*/
interface CustomDocumentBackup {
/**
* Unique identifier for the backup.
*
* This id is passed back to your extension in `openCustomDocument` when opening a custom editor from a backup.
*/
readonly backupId: string;
readonly id: string;

/**
* Delete the current backup.
Expand All @@ -1301,21 +1310,76 @@ declare module 'vscode' {
*/
interface CustomDocumentBackupContext {
/**
* Uri of a workspace specific directory in which the extension can store backup data.
* Suggested file location to write the new backup.
*
* Note that your extension is free to ignore this and use its own strategy for backup.
*
* The directory might not exist on disk and creation is up to the extension.
* For editors for workspace resource, this destination will be in the workspace storage. The path may not
*/
readonly workspaceStorageUri: Uri | undefined;
readonly destination: Uri;
}

/**
* Represents an editable custom document used by a [`CustomEditorProvider`](#CustomEditorProvider).
* Additional information about the opening custom document.
*/
interface CustomDocumentOpenContext {
/**
* The id of the backup to restore the document from or `undefined` if there is no backup.
*
* If this is provided, your extension should restore the editor from the backup instead of reading the file
* the user's workspace.
*/
readonly backupId?: string;
}

/**
* Provider for custom editors that use a custom document model.
*
* `CustomEditableDocument` is how custom editors hook into standard VS Code operations such as save and undo. The
* document is also how custom editors notify VS Code that an edit has taken place.
* Custom editors use [`CustomDocument`](#CustomDocument) as their document model instead of a [`TextDocument`](#TextDocument).
* This gives extensions full control over actions such as edit, save, and backup.
*
* You should use this type of custom editor when dealing with binary files or more complex scenarios. For simple
* text based documents, use [`CustomTextEditorProvider`](#CustomTextEditorProvider) instead.
*
* @param T Type of the custom document returned by this provider.
*/
interface CustomEditableDocument extends CustomDocument {
export interface CustomReadonlyEditorProvider<T extends CustomDocument = CustomDocument> {

/**
* Create a new document for a given resource.
*
* `openCustomDocument` is called when the first editor for a given resource is opened, and the resolve document
* is passed to `resolveCustomEditor`. The resolved `CustomDocument` is re-used for subsequent editor opens.
* If all editors for a given resource are closed, the `CustomDocument` is disposed of. Opening an editor at
* this point will trigger another call to `openCustomDocument`.
*
* @param uri Uri of the document to open.
* @param openContext Additional information about the opening custom document.
* @param token A cancellation token that indicates the result is no longer needed.
*
* @return The custom document.
*/
openCustomDocument(uri: Uri, openContext: CustomDocumentOpenContext, token: CancellationToken): Thenable<T> | T;

/**
* Resolve a custom editor for a given resource.
*
* This is called whenever the user opens a new editor for this `CustomEditorProvider`.
*
* To resolve a custom editor, the provider must fill in its initial html content and hook up all
* the event listeners it is interested it. The provider can also hold onto the `WebviewPanel` to use later,
* for example in a command. See [`WebviewPanel`](#WebviewPanel) for additional details.
*
* @param document Document for the resource being resolved.
* @param webviewPanel Webview to resolve.
* @param token A cancellation token that indicates the result is no longer needed.
*
* @return Optional thenable indicating that the custom editor has been resolved.
*/
resolveCustomEditor(document: T, webviewPanel: WebviewPanel, token: CancellationToken): Thenable<void> | void;
}

export interface CustomEditorProvider<T extends CustomDocument = CustomDocument> extends CustomReadonlyEditorProvider<T> {
/**
* Signal that an edit has occurred inside a custom editor.
*
Expand All @@ -1336,10 +1400,10 @@ declare module 'vscode' {
*
* An editor should only ever fire `CustomDocumentEditEvent` events, or only ever fire `CustomDocumentContentChangeEvent` events.
*/
readonly onDidChange: Event<CustomDocumentEditEvent> | Event<CustomDocumentContentChangeEvent>;
readonly onDidChangeCustomDocument: Event<CustomDocumentEditEvent> | Event<CustomDocumentContentChangeEvent>;

/**
* Save the resource for a custom editor.
* Save a custom document.
*
* This method is invoked by VS Code when the user saves a custom editor. This can happen when the user
* triggers save while the custom editor is active, by commands such as `save all`, or by auto save if enabled.
Expand All @@ -1348,29 +1412,31 @@ declare module 'vscode' {
* file data for the custom document to disk. After `save` completes, any associated editor instances will
* no longer be marked as dirty.
*
* @param document Document to save.
* @param cancellation Token that signals the save is no longer required (for example, if another save was triggered).
*
* @return Thenable signaling that saving has completed.
*/
save(cancellation: CancellationToken): Thenable<void>;
saveCustomDocument(document: CustomDocument, cancellation: CancellationToken): Thenable<void>;

/**
* Save the resource for a custom editor to a different location.
* Save a custom document to a different location.
*
* This method is invoked by VS Code when the user triggers save as on a custom editor. The implementer must
* persist the custom editor to `targetResource`.
* This method is invoked by VS Code when the user triggers 'save as' on a custom editor. The implementer must
* persist the custom editor to `destination`.
*
* When the user accepts save as, the current editor is be replaced by an editor for the newly saved file.
*
* @param uri Location to save to.
* @param document Document to save.
* @param destination Location to save to.
* @param cancellation Token that signals the save is no longer required.
*
* @return Thenable signaling that saving has completed.
*/
saveAs(uri: Uri, cancellation: CancellationToken): Thenable<void>;
saveCustomDocumentAs(document: CustomDocument, destination: Uri, cancellation: CancellationToken): Thenable<void>;

/**
* Revert a custom editor to its last saved state.
* Revert a custom document to its last saved state.
*
* This method is invoked by VS Code when the user triggers `File: Revert File` in a custom editor. (Note that
* this is only used using VS Code's `File: Revert File` command and not on a `git revert` of the file).
Expand All @@ -1382,14 +1448,15 @@ declare module 'vscode' {
* During `revert`, your extension should also clear any backups for the custom editor. Backups are only needed
* when there is a difference between an editor's state in VS Code and its save state on disk.
*
* @param document Document to revert.
* @param cancellation Token that signals the revert is no longer required.
*
* @return Thenable signaling that the change has completed.
*/
revert(cancellation: CancellationToken): Thenable<void>;
revertCustomDocument(document: CustomDocument, cancellation: CancellationToken): Thenable<void>;

/**
* Back up the resource in its current state.
* Back up a dirty custom document.
*
* Backups are used for hot exit and to prevent data loss. Your `backup` method should persist the resource in
* its current state, i.e. with the edits applied. Most commonly this means saving the resource to disk in
Expand All @@ -1401,73 +1468,14 @@ declare module 'vscode' {
* made in quick succession, `backup` is only triggered after the last one. `backup` is not invoked when
* `auto save` is enabled (since auto save already persists resource ).
*
* @param document Document to backup.
* @param context Information that can be used to backup the document.
* @param cancellation Token that signals the current backup since a new backup is coming in. It is up to your
* extension to decided how to respond to cancellation. If for example your extension is backing up a large file
* in an operation that takes time to complete, your extension may decide to finish the ongoing backup rather
* than cancelling it to ensure that VS Code has some valid backup.
*/
backup(context: CustomDocumentBackupContext, cancellation: CancellationToken): Thenable<CustomDocumentBackup>;
}

/**
* Additional information about the opening custom document.
*/
interface CustomDocumentOpenContext {
/**
* The id of the backup to restore the document from or `undefined` if there is no backup.
*
* If this is provided, your extension should restore the editor from the backup instead of reading the file
* the user's workspace.
*/
readonly backupId?: string;
}

/**
* Provider for custom editors that use a custom document model.
*
* Custom editors use [`CustomDocument`](#CustomDocument) as their document model instead of a [`TextDocument`](#TextDocument).
* This gives extensions full control over actions such as edit, save, and backup.
*
* You should use this type of custom editor when dealing with binary files or more complex scenarios. For simple
* text based documents, use [`CustomTextEditorProvider`](#CustomTextEditorProvider) instead.
*
* @param T Type of the custom document returned by this provider.
*/
export interface CustomEditorProvider<T extends CustomDocument = CustomDocument> {

/**
* Create a new document for a given resource.
*
* `openCustomDocument` is called when the first editor for a given resource is opened, and the resolve document
* is passed to `resolveCustomEditor`. The resolved `CustomDocument` is re-used for subsequent editor opens.
* If all editors for a given resource are closed, the `CustomDocument` is disposed of. Opening an editor at
* this point will trigger another call to `openCustomDocument`.
*
* @param uri Uri of the document to open.
* @param openContext Additional information about the opening custom document.
* @param token A cancellation token that indicates the result is no longer needed.
*
* @return The custom document.
*/
openCustomDocument(uri: Uri, openContext: CustomDocumentOpenContext, token: CancellationToken): Thenable<T> | T;

/**
* Resolve a custom editor for a given resource.
*
* This is called whenever the user opens a new editor for this `CustomEditorProvider`.
*
* To resolve a custom editor, the provider must fill in its initial html content and hook up all
* the event listeners it is interested it. The provider can also hold onto the `WebviewPanel` to use later,
* for example in a command. See [`WebviewPanel`](#WebviewPanel) for additional details.
*
* @param document Document for the resource being resolved.
* @param webviewPanel Webview to resolve.
* @param token A cancellation token that indicates the result is no longer needed.
*
* @return Optional thenable indicating that the custom editor has been resolved.
*/
resolveCustomEditor(document: T, webviewPanel: WebviewPanel, token: CancellationToken): Thenable<void> | void;
backupCustomDocument(document: CustomDocument, context: CustomDocumentBackupContext, cancellation: CancellationToken): Thenable<CustomDocumentBackup>;
}

namespace window {
Expand All @@ -1476,11 +1484,13 @@ declare module 'vscode' {
*/
export function registerCustomEditorProvider2(
viewType: string,
provider: CustomEditorProvider,
provider: CustomReadonlyEditorProvider | CustomEditorProvider,
options?: {
readonly webviewOptions?: WebviewPanelOptions;

/**
* Only applies to `CustomReadonlyEditorProvider | CustomEditorProvider`.
*
* Indicates that the provider allows multiple editor instances to be open at the same time for
* the same resource.
*
Expand Down
2 changes: 1 addition & 1 deletion src/vs/workbench/api/common/extHost.api.impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -588,7 +588,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
registerCustomEditorProvider: (viewType: string, provider: vscode.CustomTextEditorProvider, options: { webviewOptions?: vscode.WebviewPanelOptions } = {}) => {
return extHostWebviews.registerCustomEditorProvider(extension, viewType, provider, options);
},
registerCustomEditorProvider2: (viewType: string, provider: vscode.CustomEditorProvider, options: { webviewOptions?: vscode.WebviewPanelOptions, supportsMultipleEditorsPerDocument?: boolean } = {}) => {
registerCustomEditorProvider2: (viewType: string, provider: vscode.CustomReadonlyEditorProvider, options: { webviewOptions?: vscode.WebviewPanelOptions, supportsMultipleEditorsPerDocument?: boolean } = {}) => {
checkProposedApiEnabled(extension);
return extHostWebviews.registerCustomEditorProvider(extension, viewType, provider, options);
},
Expand Down
Loading

0 comments on commit 4862602

Please sign in to comment.