diff --git a/CHANGELOG.md b/CHANGELOG.md index ff8625a..03d7fd7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ ## next - Add support for meson as formatter +- Use meson as default formatter +- Add auto select capability for formatting provider preference ## 1.26.0 diff --git a/package.json b/package.json index 1aa5e4b..107bc6e 100644 --- a/package.json +++ b/package.json @@ -192,12 +192,13 @@ }, "mesonbuild.formatting.provider": { "type": "string", - "default": "muon", + "default": null, "enum": [ - "muon", - "meson" + null, + "meson", + "muon" ], - "description": "Select which formatting provider to use" + "description": "Select which formatting provider to use. If not set, the best available one is picked" }, "mesonbuild.formatting.muonConfig": { "type": "string", diff --git a/src/formatters.ts b/src/formatters.ts index a707600..3710409 100644 --- a/src/formatters.ts +++ b/src/formatters.ts @@ -9,19 +9,68 @@ type FormatterFunc = (tool: Tool, root: string, document: vscode.TextDocument) = type FormatterDefinition = { format: FormatterFunc; check: ToolCheckFunc; + priority: number; }; const formatters: Record = { muon: { format: muon.format, check: muon.check, + priority: 1, }, meson: { format: meson.format, check: meson.check, + priority: 0, }, }; +type FormatterError = { provider: FormattingProvider; error: string }; + +type BestTool = { + provider: FormattingProvider; + tool: Tool; +}; + +type BestFormatterResult = BestTool | FormatterError[]; + +async function getBestAvailableFormatter(name: FormattingProvider | null | undefined): Promise { + // sort the available providers by priority, if the user specified a preference, us that as first element + const providerPriority: FormattingProvider[] = (Object.keys(formatters) as FormattingProvider[]).sort( + (provider1: FormattingProvider, provider2: FormattingProvider) => { + if (provider1 === name) { + return -1; + } + + if (provider2 === name) { + return 1; + } + + return formatters[provider1].priority - formatters[provider2].priority; + }, + ); + + const errors: FormatterError[] = []; + + for (const provider of providerPriority) { + const props = formatters[provider]; + + const checkResult = await props.check(); + if (checkResult.isError()) { + errors.push({ provider, error: checkResult.error }); + continue; + } + + return { provider, tool: checkResult.tool }; + } + + return errors; +} + +function isFormaterErrors(input: BestFormatterResult): input is FormatterError[] { + return Array.isArray(input); +} + async function reloadFormatters(sourceRoot: string, context: vscode.ExtensionContext): Promise { let disposables: vscode.Disposable[] = []; @@ -30,18 +79,31 @@ async function reloadFormatters(sourceRoot: string, context: vscode.ExtensionCon } const name = extensionConfiguration("formatting").provider; - const props = formatters[name]; - const checkResult = await props.check(); - if (checkResult.isError()) { - getOutputChannel().appendLine(`Failed to enable formatter ${name}: ${checkResult.error}`); + const bestFormatter = await getBestAvailableFormatter(name); + + if (isFormaterErrors(bestFormatter)) { + getOutputChannel().appendLine( + `Failed to find an available formatter: The user preference was ${!name ? "" : `'${name}'`}`, + ); + for (const { provider, error } of bestFormatter) { + getOutputChannel().appendLine(`Failed to enable formatter ${provider}: ${error}`); + } getOutputChannel().show(true); return disposables; } + const { tool, provider } = bestFormatter; + + getOutputChannel().appendLine( + `The best formatter was determined to be ${provider}: The user preference was ${!name ? "" : `'${name}'`}`, + ); + + const props = formatters[provider]; + const sub = vscode.languages.registerDocumentFormattingEditProvider("meson", { async provideDocumentFormattingEdits(document: vscode.TextDocument): Promise { - return await props.format(checkResult.tool, sourceRoot, document); + return await props.format(tool, sourceRoot, document); }, }); diff --git a/src/types.ts b/src/types.ts index 5a328d4..68fe7a4 100644 --- a/src/types.ts +++ b/src/types.ts @@ -82,7 +82,7 @@ export interface ExtensionConfiguration { }; formatting: { enabled: boolean; - provider: FormattingProvider; + provider: FormattingProvider | null | undefined; muonConfig: string | null; mesonConfig: string | null; };