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 null, this means, select the best available one
- add internal priority for formatting providers
  • Loading branch information
Totto16 committed Jan 28, 2025
1 parent 869daf4 commit 2e30f7b
Show file tree
Hide file tree
Showing 4 changed files with 79 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
12 changes: 7 additions & 5 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": 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",
Expand Down Expand Up @@ -582,5 +583,6 @@
},
"prettier": {
"proseWrap": "always"
}
},
"packageManager": "[email protected]+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
}
74 changes: 69 additions & 5 deletions src/formatters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,70 @@ type FormatterFunc = (tool: Tool, root: string, document: vscode.TextDocument) =
type FormatterDefinition = {
format: FormatterFunc;
check: ToolCheckFunc;
priority: number;
};

const formatters: Record<FormattingProvider, FormatterDefinition> = {
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<BestFormatterResult> {
// 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;
},
);

getOutputChannel().appendLine(JSON.stringify({ name, providerPriority }));

const errors: FormatterError[] = [];

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

const checkResult = await props.check();
if (checkResult.isError()) {
errors.push([provider, 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<vscode.Disposable[]> {
let disposables: vscode.Disposable[] = [];

Expand All @@ -30,18 +81,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 ? "<not set>" : `'${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 ? "<not set>" : `'${name}'`}`,
);

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 | null | undefined;
muonConfig: string | null;
mesonConfig: string | null;
};
Expand Down

0 comments on commit 2e30f7b

Please sign in to comment.