Skip to content

Explore Notebook formatting via Code ActionsΒ #212381

Open
@Yoyokrazy

Description

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 contains notebookType
  • 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 standard provideDocumentFormatting flow will be skipped
  • 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 to formatOnSave requiring the file to NOT be saved after a delay)
    • Command palette Format Notebook
    • Notebook Context Menu (πŸ”œ)

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 provided TextDocument will always correspond to the 0th cell in the notebook and contain a uri that can retrieve the notebook. It is the responsibility of the provider to extract the NotebookDocument from this (an example will be provided in a sample extension, coming πŸ”œ).
    • If a Code Action is added to settings under notebook.codeActionsOnSave without the notebook. prefix, the codeaction will be applied to every valid cell asynchronously, in parallel.
  • Using NotebookEdit.replaceCells() is less performant than simply using TextEdit.replace() against that document. Additionally, using NotebookEdit.replaceCells() will fully replace cells, including output. When possible, use TextEdits for editing just the content of a cell.

Questions

  • Feel free to leave any and all thoughts below πŸ‘

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions