Skip to content

Disabled formatters must unregister #70314

@jrieken

Description

@jrieken

This is part of #41882 and tracks callers of registerDocumentFormattingEditProvider and registerDocumentRangeFormattingEditProvider that don't dispose their registrations when being disabled.

For VSCode calling registerDocument[Range]?FormattingEditProvider adds a formatter, that for instance drives enablement of context menu actions, like "Format Selection" or "Format Document". Most formatters follow our recommendation of having a setting to enable/disable them. However, some formatters don't unregister when being disabled, returning a null/empty-edit instead. That's problematic, because it doesn't allow VSCode to update the UI correctly (e.g hiding the "Format Document" action) and it contributes to the problem of multiple formatters (#41882). A disabled, but registered formatter is still a formatter in VSCode terms, meaning VSCode will continue to ask it for formatting edits and VSCode will continue to have multiple formatter available for a language.

A correct formatter unregisters when being disabled, as shown in the sample below. The following list is composed of those formatters that conflict most often:


The snippet below check with vsocde.workspace.getConfiguration() if the formatter is enabled and re-checks whenever the setting has changes (see vscode.workspace.onDidChangeConfiguration). Listening to the config-change is important for a smooth formatter update, without a restart.

    // document formatter
    const formatter: vscode.DocumentFormattingEditProvider = {
        provideDocumentFormattingEdits(document: vscode.TextDocument): vscode.TextEdit[] {
            const firstLine = document.lineAt(0);
            if (firstLine.text !== '42') {
                return [vscode.TextEdit.insert(firstLine.range.start, '42\n')];
            }
        }
    };

    // have a function that adds/removes the formatter based
    // on a configuration setting
    let registration: vscode.Disposable | undefined;
    function registerFormatterIfEnabled() {
        const isEnabled = vscode.workspace.getConfiguration().get('fooLang.formatter.enabled', true);
        if (isEnabled && !registration) {
            // 👍good - only enabled formatter is added
            registration = vscode.languages.registerDocumentFormattingEditProvider('fooLang', formatter);
        } else if (!isEnabled && registration) {
            // 👍good - disabled formatter is removed
            registration.dispose();
            registration = undefined;
        }
    }

    // register at activate-time
    registerFormatterIfEnabled();

    // add/remove formatter when config changes
    vscode.workspace.onDidChangeConfiguration(event => {
        if (event.affectsConfiguration('fooLang.formatter.enabled')) {
            registerFormatterIfEnabled();
        }
    });

Metadata

Metadata

Assignees

Labels

debtCode quality issuesformattingSource formatter issues

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions