Closed mjbvz closed 4 years ago
Two main parts of this that I see:
Custom views for resources (interactive but not editable)
A good example would be an image or 3d model viewer. To test out this api, we could even look into moving our builtin image preview into an extension
Custom editors for resources (hooking the custom views up to VS Code's text editor lifecycle)
These would be custom views that can be edited and saved like normal VS Code text editors
Some quick sketches
export enum WebviewEditorState {
Default = 1,
Dirty = 2,
}
export interface WebviewEditor extends WebviewPanel {
state: WebviewEditorState;
readonly onWillSave: Event<{ waitUntil: (thenable: Thenable<any>) => void }>
}
export interface WebviewEditorProvider {
/**
* Fills out a `WebviewEditor` for a given resource.
*
* The provider should take ownership of passed in `editor`.
*/
resolveWebviewEditor(
resource: Uri,
editor: WebviewEditor
): Thenable<void>;
}
export function registerWebviewEditorProvider(
viewType: string,
provider: WebviewEditorProvider,
): void;
{
"contributes": {
"webviewEditors": [
{
"viewType": "hexViewerExtension.hexEditor",
"displayName": "Hex Editor",
"languages": [
"hexdump"
]
}
]
}
}
User clicks on a hexdump file for the first time
If no custom view for a hexdump
file is registered.
If only a single extension is registered for a hexdump
file
registerWebviewEditorProvider
for hexViewerExtension.hexEditor
WebviewEditor
that the extension fills outIf multiple extensions are registered for a hexdump
file
User has a custom view open and wants to change to a different view
I like, I think this goes into the right direction. Other ideas/thoughts when looking at this
language
I would favour something like pattern
Is language the right abstraction? hexdump or png is not really a language but types of files and languages might just be a subset of that. So, instead or in addition to language I would favour something like pattern
Very good point. Think of files like WASM that can be represented and modified as text in multiple formats (parens form, linear form) as well as block diagram as well as hexadecimal...
Or SVG, which could be viewed inside an image editor as well as XML editor.
I'm very hyped about this.
Is it possible i read in the docs for extension developers (about a year ago) that functionality like this was deliberately not supported for performance and stability reasons?
Not that i'm not hyped as well.. ;)
An API proposal and a draft implementation is in #77789. That one ties custom editors to webviews specifically.
An alternative approach that @jrieken and @bpasero brought up is more generic "open handler" extension point. Here's a quick draft of what this could look like:
{
"contributes": {
"openHandler": [
{
"id": "imageView.imageViewer",
"displayName": "Image Viewer",
"extensions": [
"png",
"jpg"
]
}
]
}
}
/* ignoring all the editable stuff about webview editors for the moment */
export interface WebviewEditor extends WebviewPanel { }
export function createWebviewEditor(resoruce: Uri, viewType: string, showOptions: ViewColumn | { viewColumn: ViewColumn, preserveFocus?: boolean }, options?: WebviewPanelOptions & WebviewOptions): WebviewEditor;
export function registerOpenHandler(
id: string,
handler: (resource: Uri, viewColumn: ViewColumn) => void,
): void;
export function activate() {
vscode.window.registerOpenHandler('imageView.imageViewer', (resource: vscode.Uri, viewColumn: ViewColumn) => {
vscode.window.createWebviewEditor(resource, 'imageView.imageView', viewColumn);
...
});
}
createWebviewEditor
? Just as one example of why we may not want to allow this, we likey only want to allow one editor for a given resource per view column/cc @Tyriar @kieferrm Since I know you were also interested in the discussion around the "open handler" proposal
Some thoughts:
After talking over the "open handler" proposal with @Tyriar and thinking about it more, I agree that it is likely too open ended in its current form. Does anyone has any specific use cases for the "open handler" proposal that could not be addressed by the previous custom editor proposed API or by existing VS Code apis?
As for commands such as undo/redo in webview, a couple of options:
Add events for very common commands such as save, undo, and redo:
readonly onWillSave: Event<{ waitUntil: (thenable: Thenable<any>) => void }>
readonly onWillUndo: Event<{ waitUntil: (thenable: Thenable<any>) => void }>
readonly onWillRedo: Event<{ waitUntil: (thenable: Thenable<any>) => void }>
....
Add a generic way to listen for commands:
onWillExecuteCommand(command: 'workbench.action.files.save' | 'undo' | 'redo' | ..., handler: (e) => Thenable<any>>
Both solutions would require that extensions explicitly state which commands they are interested in. This lets us avoid sending all commands to extensions, and would also let us enable/disable the relevant buttons in the menubar. (We may still want to consider save
a special case since it will be very common and may have special requirements)
Does anyone has any specific use cases for the "open handler" proposal that could not be addressed by the previous custom editor proposed API
I think a use-case would be files that open as text but need some prior processing. E.g clicking a foo.class
-file shouldn't open a web view editor but, after a decompile-step, should open a foo.generated.java
-file. However, we can treat that as a different problem and think about it as a default text content provider so certain file-types.
Let's continue with the existing proposal.
I think undo and redo should definitely be considered from the beginning in order to make more useful non-read only editors.
@Tyriar Can you explain why? We have added save-logic because editors render the dirty state (in their titles) but undo/redo isn't part of the editor UX. I agree that undo/redo is important but to me it's just commands that an extension should register.
Does anyone has any specific use cases for the "open handler" proposal that could not be addressed by the previous custom editor proposed API or by existing VS Code apis?
So are we saying that https://marketplace.visualstudio.com/items?itemName=slevesque.vscode-hexdump needs to rewrite the extension so that the standalone editor is embedded into a webview? So they would have to ship the standalone editor as part of their extension? This scenario is quite popular (see https://github.com/Microsoft/vscode/issues/2582, has even more upvotes than https://github.com/Microsoft/vscode/issues/12176).
Maybe I misunderstood and we are still thinking of supporting text editors to open but with the previous API.
Maybe I misunderstood and we are still thinking of supporting text editors to open but with the previous API.
Yeah, I think that's still a valid scenario, e.g. the webview editor should have an option to let the workbench know that it wants to show to the side of a text editor. For hexdump but also for markdown
To be clear, here is what I expect:
I agree that I would not put the burden of finding out if the editor is already opened onto the extension but on us.
Can you explain why? We have added save-logic because editors render the dirty state (in their titles) but undo/redo isn't part of the editor UX. I agree that undo/redo is important but to me it's just commands that an extension should register.
@bpasero I don't mind so much on how this is done, but if the user has a custom keybindings for the regular undo/redo commands it should work in the custom editor too.
Does anyone has any specific use cases for the "open handler" proposal that could not be addressed by the previous custom editor proposed API or by existing VS Code apis?
The original resolveWebviewEditor proposal is, at a broad level, probably enough for our needs. One thing it's missing compared to createWebviewEditor is starting a new document with no backing file. Is there a path to supporting this in the resolveWebviewEditor API?
Add a generic way to listen for commands:
YES! There are so many commands that we want to hook into. In addition to Save/Undo/Redo: Save As, Find/Replace; the LSP commands like Go To Definition/Find References, and the DAP commands like Debug Start/Continue/Step Into/Step Over/Stop.
First iteration of custom editors proposal (#77789) is merged in order to get testing and feedback in VS insiders.
Here's what things stand:
export interface WebviewEditor extends WebviewPanel { }
export interface WebviewEditorProvider {
/**
* Fills out a `WebviewEditor` for a given resource.
*
* The provider should take ownership of passed in `editor`.
*/
resolveWebviewEditor(
resource: Uri,
editor: WebviewEditor
): Thenable<void>;
}
namespace window {
export function registerWebviewEditorProvider(
viewType: string,
provider: WebviewEditorProvider,
): Disposable;
}
"contributes": {
"webviewEditors": [
{
"viewType": "imagePreview.previewEditor",
"displayName": "%webviewEditors.displayName%",
"discretion": "default",
"selector": [
{
"filenamePattern": "*.{jpg,png}"
}
]
}
]
}
discretion
— Controls if the custom editor should be used by default or not when the extension is active (the default is true). selector
— Let you specify both a filenamePattern
and an optional scheme
that the custom editor should be enabled forVS Code's image preview has been moved into an extension powered by webview editors
A new workbench.experimental.editorAssociations
user setting allows configuring which custom editor to use for a given resource. The schema of setting will likely be reworked as it is not too user friendly ATM
A new open with
command has been added to the explorer context menu. This lets you select which editor to open the target resource with
A new reopen with
command has been added. This commands lets you re-open the current editor using a custom editor
Confirm #77789 didn't break the world ;)
Ux improvements, bug fixes, polish
Save + dirty file tracking
Command execution (copy, paste, ...)
Try to understand what we need to do for the new file case. The current implementation can already be used with untitled
files (obviously without save or anything hooked up)
Fantastic, thank you! Looking forward to Save :)
@mjbvz any thoughts on how to support an extension such as https://marketplace.visualstudio.com/items?itemName=slevesque.vscode-hexdump can open a monaco text editor?
Save + dirty file tracking
We might need to talk. Today this is entirely controlled by checking for the resource scheme (e.g. supported are everything the file service can handle + untitled). Would we support hot-exit for custom editors? Auto save?
I'm trying this API and it's looking great so far.
One thing that doesn't seem to work is opening a file programatically. I wrote an extension to handle .ipynb
files and set it as the default. This works for when I click a file in the Explorer.
But when I called vscode.window.showTextDocument('file:///path/to/my.ipynb')
, I got an exception:
Error: Failed to show text document file:///path/to/my.ipynb, should show in editor #undefined
Would it be hard to make showTextDocument work with custom editors?
Would it be hard to make showTextDocument work with custom editors?
You are not showing a text document as in "returns a text editor" - therefore the API won't be supported. However, you should be able to use the vscode.open
-command
Thanks, that worked! Didn't see that one because I was just looking in vscode.d.ts.
np - it does bring up an interesting point and raises the question if we should have something like showWebviewEditor
and if we should allow to enumerate/discover web views (my feeling is that we shouldn't since web views are pretty specific to an owner, unlike text editors which are pretty generic)
@bpasero Still not sure about handling that case.
None of us really liked the idea of a generic Open handler
api (see https://github.com/microsoft/vscode/issues/77131#issuecomment-522187431 and @Tyriar's comment: https://github.com/microsoft/vscode/issues/77131#issuecomment-523157471)
But revisiting the open handler
proposal for a moment: what if extensions didn't need to know anything about editors and instead only remapped uris? This would leave the actual editor opening up to VS Code. Something like:
export function registerOpenHandler(
id: string,
handler: (resource: Uri) => Promise<Uri>,
): void;
For the custom text editor case (like the hexdump extension), an open handler would map the incoming uri (file://Users/mat/cat.png
) to a uri that a TextDocumentContentProvider
could handle ( hexdump://Users/mat/cat.png
)
Custom webview editors would do the same, i.e. file://Users/mat/cat.png
-> my-webview-scheme://Users/mat/cat.png
Some other aspects of this api direction:
We would have an openers
contributions that would define the contributed custom editors for a given file type. We may not even to expose a registerOpenHandler
function since the contribution could tell us what scheme to remap the uri to:
"contributions": {
"openers": [
{
"id": "myExt.hexDump",
"displayName": "Hex Dump",
"filenamePattern": "*.png",
"scheme": "file",
"targetScheme": "hexdump"
}
]
}
WebviewEditors would be contributed for a scheme instead of for a file pattern like the current proposal, much like TextDocumentContentProvider
or the old vscode.previewHtml
command ;)
The remapped uris should be hidden to the user
Needs more thought but it seems like an interesting direction. Would be interested in hearing other's thoughts on the idea
For the custom text editor case (like the hexdump extension), an open handler would map the incoming uri (file://Users/mat/cat.png) to a uri that a TextDocumentContentProvider could handle ( hexdump://Users/mat/cat.png)
I like this idea 👍
I've been learning a lot while iterating on the custom editor proposal. I've also been thinking more about how custom editors need to fit into VS Code and have had to rethink some of my earlier assumptions about this.
Here I've attempted to capture what my current thoughts on the direction of custom editors, as well as noting the questions I still have and sketching out some potential approaches to addressing them.
First off, here are a few conclusions I've reached while working on the custom editor proposal:
Custom editors need to support non-disk resources
This includes:
Custom editors should support dirty resources
If I make a change in a text file and then open a custom editor on it, I expect the custom editor to reflect the dirty file (not the version on disk).
TextDocumentContentProvider
is not a custom editor
TextDocumentContentProvider
can only create readonly text buffers and cannot participate in save or any other editor actions.
A better analog for custom text editors is actually our file system provider api, as this both gives the resource a custom scheme and allows the extension to participate in save. However this API is a really heavyweight way to implement a custom text editor.
Extensions should not need to know where the resource data they are rendering comes from, nor should they need to know how the resource data itself will be used by VS Code.
The existing custom editor api works pretty well for readonly documents. However once we start talking about writable custom editors, the current proposal is vague on a number of important points:
On save, should the custom editor be responsible for writing data to disk?
Do we delegate file saving entirely to custom editors, or should save be more a notification to the custom editor that it should prepare its contents to be written to disk.
Does VS Code maintain editor history, or do custom editors maintain their own editor histories?
How does a custom editor know when its backing resource has changed?
How do we support custom editors for different versions of a file (the diff view case)?
When does a custom editor flush its contents back to VS Code?
For example: I edit a file using a custom editor and then switch to view the same file in VS Code's normal text editor without saving. In this case, I expect to see the modified content as text.
How does hot exit work?
What about save as?
Who provides Ui for all this?
I think most of these questions boil down to a debate of what exactly a custom editor should be and how it interacts with VS Code core. Should custom editors simply be views of a resource? or should they take over responsibility for that resource as well?
Let me quickly sketch out these two extremes to highlight this difference:
At one extreme, we could say that custom editors are simply views of resources. The custom editor takes in some resource state, renders itself, and can trigger events to tell VS Code that the resource has changed. This is a very React-style way of looking at the problem, so why not just express it in React terms:
<MyImageEditor
/* What we are rendering */
resource={'file:///Users/matb/cat.gif'}
/* Some abstraction so that the editor can read the file, since the file on disk may be different than VSCode's version */
resourceState={...}
/* Callback fired by the custom editor to signal the state of the editor has changed */
onContentChanged={...}
/* Some way to signal if editor is readonly or not? */
/>
Every time the resourceState
changes, the custom editor would be re-rendered.
If we take this approach, VS Code core would maintain the data for each resource (just like it does for text editors today). Core would be responsible for writing resources to disk on save, it would track editor history, and would handle reverts and other content operations, re-rendering the custom editor as needed as resource state changes.
At the other extreme, we could say that a custom editor both provides a view of a resource and is responsible for that resource. The API for this would be much closer to the existing proposal:
interface CustomEditor {
state: EditorState; // readonly, dirty, unchanged
/*
* Invoked when the user triggers save.
*
* Should write the file content to disk.
*/
save(): Thenable<void>;
/*
* Invoked when the user presses undo or redo.
*
* Should write the file content so that VS Code can read it
*/
undo(): Thenable<void>;
redo(): Thenable<void>;
...
}
But this proposal doesn't answer the questions I brought up. It also gives extensions a lot of room for interpretation, and we know that extensions will implement an api like this in different, incompatible ways.
My feeling is that considering custom editors to be simple views is the better approach (although perhaps not the simpler one for us to implement). It allows core to control resources so that edge cases are handled properly and so that the user experience is consistent no matter what type of custom editors user are using.
At an extremely high level, here's what this approach would mean for the various types of custom editors we have discussed:
Consider an image editor extension. Under this new proposal, this extension would need to:
Consider a hex dump extension (that is also writable). This extension would need to:
As @bpasero brought up, we may be able to leverage the filesystem provider api for this
Are there cases where custom editors as simple view do not work?
What would such an api look like in practice?
Can we implement it efficiently? I'm viewing a 100mb json file in a custom editor, we can't be sending around 100mb buffers all the time.
Other thoughts or concerns?
Is there an ETA on the API being available in a public build? Since the Python VS Code extension is using a webview based editor for Jupyter notebooks and need access to the File Save menu for our upcoming release in October. Thanks!
@mjbvz Door Number 1 sounds good to me. It's exactly what we'd need for editing notebooks. Although the write to disk problem isn't a big issue for us as the webview doesn't do the writing.
@jmew No. Proposed apis move out of proposed when they are ready. But it will certainly not be by October
Actually thinking more about your 'Door number 1' option, I don't think this is going to work for us unless we can also talk to the webview somehow.
We do a bunch of stuff on the extension side now (like starting the jupyter server) that we'd have to somehow do when the simple view was opened.
We also do conversions on the data using tools installed in the jupyter server, so we'd likely have to roundtrip the data anyway before showing it in the webview.
When the user makes a change in the image editor, flush that back to VS Code in some way (not to disk!) ... Can we implement it efficiently? I'm viewing a 100mb json file in a custom editor, we can't be sending around 100mb buffers all the time.
I'm concerned about this part, in an image editor it would be too expensive to generate a copy of the actual file on every single change. Instead you would probably maintain a grid of pixels and a bunch of transforms that can be applied and undone. Ideally the webview editor would handle undo/redo in their own way and saves (generating/sending the file) would only be done when absolutely necessary.
I'll echo the above concerns about Door Number 1.
In addition to the performance concerns, I also have concerns about the UI state preservation (eg. an authenticated Jupyter connection for a notebook editor). If the content changes on disk, I don't think the extension should forcibly reload with all the UI state reset.
I do see value in between the extremes though. For example, I don't see any need for the extension to read or write the file directly to disk. That seems better suited to a module which can read and write from a variety of sources.
@mjbvz I think the fundamental discussion is about how much control to give to the custom editor, and who should be responsible for file state. I don’t think we need to go with one extreme or the other, and can have a reasonable middle ground which allows VSCode to guarantee consistent experience across custom-editor extensions.
I think VSCode should be responsible for reading/writing the raw file to disk. There could be a getContents(stream)
API which the custom editor has to implement, which VSCode can call:
More formally, here are some ideas for the questions you raised:
On save, should the custom editor be responsible for writing data to disk?
VSCode should be responsible for writing data to disk. Given above approach the custom editor can provide contents to an output stream with getContents
API. The custom editor should be notified when data is about to be or has been written to disk (e.g. a didSave or willSave notification)
Do we delegate file saving entirely to custom editors, or should save be more a notification to the custom editor that it should prepare its contents to be written to disk.
See above
Does VS Code maintain editor history, or do custom editors maintain their own editor histories?
Perhaps the custom editor provides VSCode with state/commands for undo/redo stack, or maintains its own history. For Jupyter notebooks it could have been an “insert/delete cell” command (i.e. very context-specific to extension), and we probably don’t want VSCode to keep track of the underlying file’s contents on every keystroke.
How does a custom editor know when its backing resource has changed?
- Do we expect it to set up file watchers?
VSCode could provide this as a notification to the custom editor as well, notifying it that the underlying file has changed. Similar to LSP (textDocument/didChange)
- How do we handle conflicts?
Are you referring to source control merge conflicts? In that case perhaps it’s fine for VSCode to fallback to the text editor for merge conflicts, because SCM will insert merge markers into the file, so the regular text editor UI makes more sense for dealing with that.
How do we support custom editors for different versions of a file (the diff view case)?
Either by allowing the custom editor to provide text for the diff view (@alexandrudima's comment), or expect the custom editor to implement diff-view API’s as well.
When does a custom editor flush its contents back to VS Code? For example: I edit a file using a custom editor and then switch to view the same file in VS Code's normal text editor without saving. In this case, I expect to see the modified content as text.
The custom editor can be pulled for its contents by VSCode as it sees fit. This gives you control of how frequently to fetch state. I think it should only be onSave/SaveAs, and some periodic fetch (for hot exit case).
How does hot exit work?
Call getContents
periodically to fetch state from custom editor, or during an onExit call explicitly, if VSCode has that for hot exits.
What about save as?
This should be similar to Save, where VSCode is responsible for the saving, but notifies the custom editor about the Save As event. Should just be metadata on the notification, I don’t think the custom editor needs to do anything special for Save As.
Who provides Ui for all this?
As much as possible it should be VSCode, because that provides consistency across custom editor extensions, which is better for VSCode.
Hi @mjbvz, is there anything blocking retainContextWhenHidden being implemented for custom editors?
I tried adding the option at https://github.com/microsoft/vscode/blob/313ede61cbad8f9dc748907b3384e059ddddb79a/src/vs/workbench/api/common/extHostWebview.ts#L291 but it just didn't seem to do anything. Do you have any idea why that didn't work?
This is important for editors with complex state so they don't get destroyed when the user switches to another tab.
Just did some testing and one thing I noticed that was it was overly complicated to get the actual file data, I think what I'm meant to do is do all the webview uri mapping stuff and then load it via fetch. While this is certainly convenient when you're just displaying an image, it's more cumbersome for editing a file where you would typically want to deal directly with a buffer. Considering the following:
resolveWebviewEditor(
resource: Uri,
editor: WebviewEditor,
data: Promise<ArrayBuffer>
): Thenable<void>;
// alternatively
export interface WebviewEditor extends WebviewPanel {
readonly onLoad: Event<ArrayBuffer>
}
This seems like it would be very useful for building a binary or image editor as the extension would not need to deal with the file system at all, provided the method of saving the buffer is similar.
Looking at the use cases for extension-provided editors it seems prudent to allow them to embed VSCode's editor functionality somehow to get access to the editing-related features provided by other extensions - be it a code notebook or the thing that I'm currently building, which is an inline HTML editor.
dcecb9eea6158f561ee703cbcace49b84048e6e3 documents the current thinking on the Webview Editor API (although none of the functionality around edit/save has actually been implemented yet.
This direction takes the recent feedback into account and is a compromise between the two extremes originally proposed: it leaves the specifics of how files are saved up to extensions but abstracts away most of the details about how editor actions interact with custom editors and how editor state is shown to the user. Here's a quick review of the new proposed design:
To start with, resolveWebviewEditor
now returns a WebviewEditorCapabilities
object
export interface WebviewEditorProvider {
resolveWebviewEditor(
input: {
readonly resource: Uri
},
webview: WebviewPanel,
): Thenable<WebviewEditorCapabilities>;
}
The WebviewEditorCapabilities
describes how the webview editor interacts with VS Code:
interface WebviewEditorCapabilities {
rename?(newResource: Uri): Thenable<void>;
readonly editingCapability?: WebviewEditorEditingCapability;
}
interface WebviewEditorEditingCapability {
save(resource: Uri): Thenable<void>;
hotExit(hotExitPath: Uri): Thenable<void>;
readonly onEdit: Event<any>;
applyEdits(edits: any[]): Thenable<void>;
undoEdits(edits: any[]): Thenable<void>;
}
VS Code would then wire up these WebviewEditorCapabilities
to the editor itself. For example, pressing cmd+s on a webview editor would invoke the save
function. This model should give extensions a lot of freedom to implement the logic for save and undo/redo, while still letting VS Code drive the core user experience.
We will be working on implementing the first parts of the API in November. Keep in mind that the capabilities interfaces may change significantly as we learn more about it
Hi @mjbvz! Thanks for the update, the API looks very promising! I'm one of the maintainers of kogito-tooling and we are currently shipping a DMN/BPMN editor based on VSCode WebViews.
We've been working with the existing API for a while, so I'd like to offer my two cents on this discussion. Basically, the two major challenges we have today are:
Since the first one is most likely going to be solved by this new API, I'll focus on the second one. Native text editors on VSCode have a bunch of features that seem secondary, but actually do improve the UX a lot, like "Confirm before closing a modified file", "Show a "modified" indicator when a file is changed", "Show a (deleted) label on the tab title when the file is externally renamed/deleted", etc..
So for the new API, here are a few questions:
WebviewEditorCapabilities#rename
WebviewEditorEditingCapability#save
WebviewEditorEditingCapability#hotExit
WebviewEditorEditingCapability#onEdit
WebviewEditorEditingCapability#applyEdits
and WebviewEditorEditingCapability#undoEdits
onEdit
?Hope that's insighful!
One more thing I'd like to ask is do you guys have an estimate of when this will become a stable API?
Really interested in this feature. GJ guys so far. Thank you.
@mjbvz Are there any plans on providing some API to optionally pass line/column information to the webview. E.g. when users open a file from VS Code (in problems pane or debug stackframe), it opens a file and goes to a specific line number. We'd like to have this functionality in the notebook editor for DS functionality in the Python extension.
@kieferrm @greazer /cc
& yes, thanks for the awesome work in this space.
@tiagobento
Extensions would not invoked rename; it is invoked by VS Code on the extension after the user renames a file.
Yes, save
lets you hook into saving of files however that is triggered
The intended UX is to match how normal editors work. If hot exit is enabled, there is no popup in this case
Yes. However it is VS Code who decides to mark the file dirty or not based using the edits it knows about. Extensions cannot directly mark the editor as dirty (without pushing an edit)
Edits will need to be a json serializable objects. We do not care about the actual value of this object. That's why any
is used for now
@DonJayamanne An initial line number can be passed through the URI using the fragment or query parameters
At the moment, there is no way to reopen the same document again at the different line number. That is something we'll consider supporting in the future. It may be pushed to a separate API proposal after the core custom editor logic is finalized
Here's where things stand on the proposal:
The api is unchanged for the most part since the last update, although I have commented out or removed the non-functional parts of it. You can find the latest version in vscode.proposed.d.ts
Basic save
and undo/redo are now functional
I've been using this simple extension to test the apis: https://github.com/mjbvz/vscode-experimental-webview-editor-extension
The next goal is hook up saveAs
this iteration, and possibly rename
as well.
Hot exit support will require more time
If you have a use case in mind for writable custom editors, we'd appreciate your feedback on the newly enabled parts of the api:
Open bug reports for stuff that doesn't work
Can you implement undo/redo/save using this api? How difficult is it?
Are there uses cases around undo/redo/save that would not work with the current api?
@mjbvz Is it possible to use the new editor for customized schema?
In PROBLEMS view, Java language server reports the workspace root folder as the diagnostics resource of the project level errors. When the user clicks it, actually there are no editors able to open it. To address the issue, we want to open a customized web view to show the build path info. But because it doesn't have a specific file, it seems we cannot use filenamePattern to enable the webviewEditors in the contributes of package.json. If the custom editors support schema match, we'd like to return a special uri scheme for project root errors.
@testforstephen Not at the moment. That use case may be a good fit for the Text Document Content provider API?
@mjbvz Thanks. We have a try on text document content provider, but the limitation is it only supports plain text document. It's suitable for code presentation such as decompiled class, but not good for project config presentation. That's why we want to try WebView for more rich presentation.
@testforstephen Yes give text documents a try; you can probably get pretty far with them. As author of the webview API, my advice is always to not use webviews unless you really need to
@mjbvz, After trying out the new API, I'd suggest giving an option to opt out of the undo/redo capability while still being able to set the dirty bit and save, because undo/redo is significantly more complicated for an extension to implement.
The complication I've got is as follows:
I'm building a notebook editor which includes Monaco editors in the webview, so I want to integrate Monaco's undo stack to the Custom Editor undo stack. Monaco can't provide an event to notify when an "undoable edit" occurs because it doesn't know the extent of the edit until after the fact. ie. if I type "hello", it gives me a change event for each of the five keys typed, but pressing Undo at this point will remove the entire word even though the last edit event was only to insert the character "o". It doesn't make sense to delay the events until after all the keys are typed because we want to set the document to dirty immediately, but it also doesn't make sense for me to send five separate onEdit
events to your API because I want a single Undo to revert all five characters.
Monaco has the concept of a "current open stack element" which sits at the top of the undo stack. Each edit is coalesced into this element until the client calls pushStackElement, at which point a new open stack element is pushed on top. Each stack element represents one undo step, but can comprise many edits. I think the Custom Editor API should follow a similar model.
Caveat: Even with this system, it wouldn't solve my problem because the Monaco API doesn't currently expose when it internally decides to push a stack element, so I'd also need it expose that as an event.
Another suggestion: Complex webviews (like graphical editors) requires much communication with the extension code. maintaining it with post messages are hard, since you need to handle callbacks, etc'. I created an RPC library to ease this communication https://github.com/SAP/vscode-webview-rpc-lib. It could be great if it would be part of the VSCode APIs.
Funnily enough I was just thinking this morning about a custom view of .gitignore
files to make editing those easier. Especially when there are multiple .gitignore
files in a project, a GUI editor might be able to incorporate all of them into a tree view, allow drag/drop between branches, generate globs by selecting multiple files to match, all sorts of things.
@KevinWuWon What if we allowed saving of unchanged files too? (unchanged just being files that we don't have any edit stack for) I believe text editors already support saving unchanged files. I believe it is still best to keep the dirty indicator itself tied to the undo/redo/revert so that the UX is consistent with that of text editors
Updated: April 24, 2020
The Custom Text Editor API has shipped with VS Code 1.44! Checkout the documentation and example extension to get started creating your custom text editors.
If you encounter any issues using
CustomTextEditorProvider
, please open a new issue.This issue now tracks custom editors for binary files, which we aim to finalize for VS Code 1.46
Overview
The custom editor API aims to allow extensions to create fully customizable read/write editors that are used in place of VS Code's standard text editor for specific resources. These editors will be based on webviews. We will support editors for both binary and text resources
A XAML custom editor, for example, could show a WYSIWYG style editor for your
.xaml
files. Our end goal is to give extensions the most flexibility possible while keeping VS Code fast, lean, and consistent.Non-goals
Many features that are potentially related to custom editors are out of scope of this current proposal, including:
These all would fall under separate feature requests. Many also be a better fit for an external helper library instead of VS Code core
Tracking progress
This issue thread captures the evolution of the webview editor proposal. That means that many comments may now be out of date. Some of these have been minimized, others have not.
For the most up to date info, see:
vscode.proposed.d.ts