Open
Description
opened on May 9, 2024
Overview
Opening this issue up as a discussion point for the current work around notebook formatting. As a way to accomplish this without the introduction of new API, the thought is to introduce a new Code Action Kind notebook.format.extensionID
. Looping in some relevant notebook formatting people.
cc: @rebornix @karthiknadig @charliermarsh
Proposed Plan
- Extension authors will provide a Code Action that wraps all of their formatting into a single action, with the kind
notebook.format.xyz
- We recommend that the
xyz
is unique to your extension, but this is not a restriction - We require that you have a complete
DocumentFilter
that containsnotebookType
- We recommend that the
- Only one formatting Code Action will be used against the notebook.
- If more than one extension registers a provider for this type, users will be prompted to choose between them and define a setting
"notebook.defaultFormatter": "extensionID"
(mirrors the editor setting) - If an extension registers multiple
notebook.format.xyz
providers, only the first will be used. - If a
notebook.format
Code Action is applied on save, the standardprovideDocumentFormatting
flow will be skipped
- If more than one extension registers a provider for this type, users will be prompted to choose between them and define a setting
- The
notebook.format
Code Action can be applied in the following ways:- Setting
"notebook.formatOnSave.enabled": true
(this means that there will only be explicit triggering of this for saves, due toformatOnSave
requiring the file to NOT be saved after a delay) - Command palette
Format Notebook
- Notebook Context Menu (π)
- Setting
Rough Example
- Extension (pseudo)Code:
export async function activate(context: vscode.ExtensionContext) {
registerCodeActionsProvider(DocumentFilter, new ProviderName(), providedKinds);
}
class ProviderName {
static readonly kind = "notebook.format.extensionID";
public provideCodeActions(
document: vscode.TextDocument,
_range: vscode.Range | vscode.Selection,
_context: vscode.CodeActionContext,
_token: vscode.CancellationToken
): vscode.CodeAction[] | undefined {
const nbEdits: NotebookEdit[] | TextEdit[] = {
// wrap all formatting edits here
}
const fix = new vscode.CodeAction(
'Apply Notebook Formatting',
ProviderName.kind,
);
fix.edit = new vscode.WorkspaceEdit();
fix.edit.set(notebookDocument.uri, nbEdits);
return [fix];
}
}
- User
settings.json
:
{
"notebook.defaultFormatter": "extensionID", // extensionID
"notebook.formatOnSave.enabled": true,
"notebook.codeActionsOnSave": { // these will occur BEFORE the formatter
"source.xyz": "explicit",
}
}
Other relevant notes
- Code Action Kind prefix rules
- Code Action Providers that return a kind prefixed with
notebook.
will only ever be called against the 0th cell of the notebook. Additionally, the providedTextDocument
will always correspond to the 0th cell in the notebook and contain auri
that can retrieve the notebook. It is the responsibility of the provider to extract theNotebookDocument
from this (an example will be provided in a sample extension, coming π). - If a Code Action is added to settings under
notebook.codeActionsOnSave
without thenotebook.
prefix, the codeaction will be applied to every valid cell asynchronously, in parallel.
- Code Action Providers that return a kind prefixed with
- Using
NotebookEdit.replaceCells()
is less performant than simply usingTextEdit.replace()
against that document. Additionally, usingNotebookEdit.replaceCells()
will fully replace cells, including output. When possible, useTextEdits
for editing just the content of a cell.
Questions
- Feel free to leave any and all thoughts below π
Activity