-
Notifications
You must be signed in to change notification settings - Fork 35.7k
Description
I just finished up a small extension using the notebooks API recently. Given that I don't have a ton of from scratch extension experience like some team members, I thought it might be useful to document some of the pain points that I hit along the way. Note, lots of these are just driver error issues or lack of knowledge on my part, but sometimes those are worth noting.
Icons
One of the first bits that I struggled with was getting what I wanted from custom icons. I think that a large part of the issue here was terminology. Searching for custom icons I was guided a lot to Product Icon Themes. Rolling a full theme wasn't what I was looking to do here, so I didn't dig too deep into that. From the command contribution points reference the reference for icons all seemed to be for existing product icons or for custom SVG, so I just went with light and dark theme SVG, which look..ok (I could tweak them to be better).

I think that what I actually wanted is here Product Icon Contribution Point but I only found that just recently and have not tried it out. Having a note or link from the commands page to indicate that the choices are not just A) having a full separate product icon theme or B) custom SVG might be helpful.
ContextKeys for NotebookCells
In my extension I'm changing the icons that are available on each notebook cell based on their membership in specific groups. When looking at the initial when context documentation I expected to do this via a context key list that contained all the cell URI strings in that specific group. Then in the command registration for the cell toolbar icons something like cellResource in groupOne would let me control the buttons per cell. My issue here was that I could create the groupOne right side of that equation, but I didn't have what I expected to use for the left hand side. In the context keys there is a lot for resources at the document level, but nothing at a notebook cell resource level that I could use.

If something here actually had the context of the cell URI then I think I could have easily done what I expected. Instead I went with just updating my icon visibilities for whatever the currently selected cell is. This basically works, but isn't ideal, and lead to some UI funkiness with multiselection or clicking the run button on a non-selected cell. Plan on going back to consider if there is a better way to do this.
Notebook API
The notebook API worked generally great for me. I was happy with how much I was able to do without any state stored in my extension. The one API that did give me a hitch was here:
export interface WorkspaceEdit {
// todo@API add NotebookEdit-type which handles all these cases?
replaceNotebookMetadata(uri: Uri, value: { [key: string]: any }): void;
replaceNotebookCells(uri: Uri, range: NotebookRange, cells: NotebookCellData[], metadata?: WorkspaceEditEntryMetadata): void;
replaceNotebookCellMetadata(uri: Uri, index: number, cellMetadata: { [key: string]: any }, metadata?: WorkspaceEditEntryMetadata): void;
}
When using replaceNotebookCellMetadata I accidentally did this:
wsEdit.replaceNotebookCellMetadata(cell.document.uri, cell.index, newMetadata);
Instead of the correct this:
wsEdit.replaceNotebookCellMetadata(cell.notebook.uri, cell.index, newMetadata);
This was difficult to debug at first, since it actually did appear to apply the metadata change locally. And the error message thrown didn't quite point me at the right place to fix.
NotebookModelResolveServiceImpl -> resolve CANNOT open a cell-uri as notebook coming from the bulk edit.
Something like replaceNotebookCellMetadata must be called with a NotebookDocument URI would have been much more helpful. In retrospect the index argument should have been a obvious tip off that I was using the API incorrectly here, but when operating on just replacing the metadata on a NotebookCell that I already have I didn't think that I'd need to step back to the document level for the API.
Command arguments
When working with commands I often found that I was poking around in the vscode core source to see how those commands were actually called. This works (great part of open source) but I was wondering if I was missing on a better way to look these up. For instance:
- If I put a command on a notebook cell toolbar, do I know that my arg for that command callback will always be a NotebookCell? I wasn't sure about how to check what contexts those callback would actually be called in.
- For using a build in command like
notebook.cell.executeit can take a range of notebook cells to run, but it took some probing around in the code to find this, actually quickest way that I found for usage here was the fact that I found a test that exercised this.
These questions obviously were not blockers and would be less of an issue the more I know the code base, but I'd love it if there was an easier way to answer these questions that I'm missing.