Skip to content

Commit

Permalink
feat: add more sophisticated formatter selection
Browse files Browse the repository at this point in the history
- allow the formatting provider to be set as auto, this means, select the best available one
- add internal priority for formatting providers
  • Loading branch information
Totto16 committed Feb 4, 2025
1 parent 869daf4 commit fbdbb97
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 11 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -192,12 +192,13 @@
},
"mesonbuild.formatting.provider": {
"type": "string",
"default": "muon",
"default": "auto",
"enum": [
"muon",
"meson"
"auto",
"meson",
"muon"
],
"description": "Select which formatting provider to use"
"description": "Select which formatting provider to use. If set to 'auto', the best available one is picked"
},
"mesonbuild.formatting.muonConfig": {
"type": "string",
Expand Down
76 changes: 70 additions & 6 deletions src/formatters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,39 +9,103 @@ type FormatterFunc = (tool: Tool, root: string, document: vscode.TextDocument) =
type FormatterDefinition = {
format: FormatterFunc;
check: ToolCheckFunc;
priority: number;
};

//NOTE: the highest priority number means it is tested first, the lowest is tested last
const formatters: Record<FormattingProvider, FormatterDefinition> = {
muon: {
format: muon.format,
check: muon.check,
priority: 0,
},
meson: {
format: meson.format,
check: meson.check,
priority: 1,
},
};

type FormatterError = { provider: FormattingProvider; error: string };

type BestTool = {
provider: FormattingProvider;
tool: Tool;
};

type BestFormatterResult = BestTool | FormatterError[];

async function getBestAvailableFormatter(provider: FormattingProvider | "auto"): Promise<BestFormatterResult> {
if (provider !== "auto") {
const props = formatters[provider];

const checkResult = await props.check();
if (checkResult.isError()) {
return [{ provider, error: checkResult.error }];
}

return { provider, tool: checkResult.tool };
}

// sort the available providers by priority
const providerPriority: FormattingProvider[] = (Object.keys(formatters) as FormattingProvider[]).sort(
(provider1: FormattingProvider, provider2: FormattingProvider) => {
return formatters[provider2].priority - formatters[provider1].priority;
},
);

const errors: FormatterError[] = [];

for (const providerName of providerPriority) {
const props = formatters[providerName];

const checkResult = await props.check();
if (checkResult.isError()) {
errors.push({ provider: providerName, error: checkResult.error });
continue;
}

return { provider: providerName, 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<vscode.Disposable[]> {
let disposables: vscode.Disposable[] = [];

if (!extensionConfiguration("formatting").enabled) {
return disposables;
}

const name = extensionConfiguration("formatting").provider;
const props = formatters[name];
const providerName = extensionConfiguration("formatting").provider;

const bestFormatter = await getBestAvailableFormatter(providerName);

const checkResult = await props.check();
if (checkResult.isError()) {
getOutputChannel().appendLine(`Failed to enable formatter ${name}: ${checkResult.error}`);
if (isFormaterErrors(bestFormatter)) {
getOutputChannel().appendLine(`Failed to find an available formatter: The user preference was '${providerName}'`);
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 '${providerName}'`,
);

const props = formatters[provider];

const sub = vscode.languages.registerDocumentFormattingEditProvider("meson", {
async provideDocumentFormattingEdits(document: vscode.TextDocument): Promise<vscode.TextEdit[]> {
return await props.format(checkResult.tool, sourceRoot, document);
return await props.format(tool, sourceRoot, document);
},
});

Expand Down
2 changes: 1 addition & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export interface ExtensionConfiguration {
};
formatting: {
enabled: boolean;
provider: FormattingProvider;
provider: FormattingProvider | "auto";
muonConfig: string | null;
mesonConfig: string | null;
};
Expand Down

0 comments on commit fbdbb97

Please sign in to comment.