Skip to content

Commit 48e11ee

Browse files
Totto16Jannik2099
authored andcommitted
feat: add new feature format for meson 1.9.0
add support for the new format cli argument "--source-file-path", as this helps in error messages Signed-off-by: Jannik Glückert <[email protected]>
1 parent e1d5f7d commit 48e11ee

File tree

6 files changed

+87
-49
lines changed

6 files changed

+87
-49
lines changed

src/formatters.ts

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,40 @@ import { ToolCheckFunc, Tool, type FormattingProvider } from "./types.js";
44
import * as muon from "./tools/muon.js";
55
import * as meson from "./tools/meson.js";
66

7-
type FormatterFunc = (tool: Tool, root: string, document: vscode.TextDocument) => Promise<vscode.TextEdit[]>;
8-
9-
type FormatterDefinition = {
10-
format: FormatterFunc;
11-
check: ToolCheckFunc;
7+
type FormatterFunc<Options> = (
8+
tool: Tool<Options>,
9+
root: string,
10+
document: vscode.TextDocument,
11+
) => Promise<vscode.TextEdit[]>;
12+
13+
type FormatterDefinition<Options> = {
14+
format: FormatterFunc<Options>;
15+
check: ToolCheckFunc<Options>;
1216
priority: number;
1317
};
1418

1519
//NOTE: the highest priority number means it is tested first, the lowest is tested last
16-
const formatters: Record<FormattingProvider, FormatterDefinition> = {
20+
const formatters: Record<
21+
FormattingProvider,
22+
FormatterDefinition<muon.MuonOptions> | FormatterDefinition<meson.MesonOptions>
23+
> = {
1724
muon: {
1825
format: muon.format,
1926
check: muon.check,
2027
priority: 0,
21-
},
28+
} as FormatterDefinition<muon.MuonOptions>,
2229
meson: {
2330
format: meson.format,
2431
check: meson.check,
2532
priority: 1,
26-
},
33+
} as FormatterDefinition<meson.MesonOptions>,
2734
};
2835

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

3138
type BestTool = {
3239
provider: FormattingProvider;
33-
tool: Tool;
40+
tool: Tool<muon.MuonOptions> | Tool<meson.MesonOptions>;
3441
};
3542

3643
type BestFormatterResult = BestTool | FormatterError[];
@@ -44,7 +51,7 @@ async function getBestAvailableFormatter(provider: FormattingProvider | "auto"):
4451
return [{ provider, error: checkResult.error }];
4552
}
4653

47-
return { provider, tool: checkResult.tool };
54+
return { provider, tool: checkResult.data };
4855
}
4956

5057
// sort the available providers by priority
@@ -65,7 +72,7 @@ async function getBestAvailableFormatter(provider: FormattingProvider | "auto"):
6572
continue;
6673
}
6774

68-
return { provider: providerName, tool: checkResult.tool };
75+
return { provider: providerName, tool: checkResult.data };
6976
}
7077

7178
return errors;
@@ -105,7 +112,7 @@ async function reloadFormatters(sourceRoot: string, context: vscode.ExtensionCon
105112

106113
const sub = vscode.languages.registerDocumentFormattingEditProvider("meson", {
107114
async provideDocumentFormattingEdits(document: vscode.TextDocument): Promise<vscode.TextEdit[]> {
108-
return await props.format(tool, sourceRoot, document);
115+
return await (props.format as FormatterFunc<unknown>)(tool as Tool<unknown>, sourceRoot, document);
109116
},
110117
});
111118

src/linters.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,15 @@ import { extensionConfiguration, getOutputChannel } from "./utils.js";
33
import { ExtensionConfiguration, LinterConfiguration, ToolCheckFunc, Tool } from "./types.js";
44
import * as muon from "./tools/muon.js";
55

6-
type LinterFunc = (tool: Tool, sourceRoot: string, document: vscode.TextDocument) => Promise<vscode.Diagnostic[]>;
6+
type LinterFunc = (
7+
tool: Tool<muon.MuonOptions>,
8+
sourceRoot: string,
9+
document: vscode.TextDocument,
10+
) => Promise<vscode.Diagnostic[]>;
711

812
type LinterDefinition = {
913
lint: LinterFunc;
10-
check: ToolCheckFunc;
14+
check: ToolCheckFunc<muon.MuonOptions>;
1115
};
1216

1317
const linters: Record<keyof ExtensionConfiguration["linter"], LinterDefinition> = {
@@ -45,7 +49,7 @@ async function reloadLinters(
4549
continue;
4650
}
4751

48-
const linter = async (document: vscode.TextDocument) => await props.lint(checkResult.tool, sourceRoot, document);
52+
const linter = async (document: vscode.TextDocument) => await props.lint(checkResult.data, sourceRoot, document);
4953
enabledLinters.push(linter);
5054
}
5155

src/tools/meson.ts

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
11
import * as vscode from "vscode";
22
import { execFeed, extensionConfiguration, getOutputChannel, mesonProgram } from "../utils.js";
3-
import { Tool, ToolCheckResult } from "../types.js";
3+
import { Tool, CheckResult } from "../types.js";
44
import { getMesonVersion } from "../introspection.js";
55
import { Version } from "../version.js";
66

7-
export async function format(meson: Tool, root: string, document: vscode.TextDocument): Promise<vscode.TextEdit[]> {
7+
export interface MesonOptions {
8+
supportsFileNameArgument: boolean;
9+
}
10+
11+
export type MesonTool = Tool<MesonOptions>;
12+
13+
export async function format(
14+
meson: MesonTool,
15+
root: string,
16+
document: vscode.TextDocument,
17+
): Promise<vscode.TextEdit[]> {
818
const originalDocumentText = document.getText();
919

1020
let args = ["format"];
@@ -15,6 +25,10 @@ export async function format(meson: Tool, root: string, document: vscode.TextDoc
1525
}
1626
args.push("-");
1727

28+
if (meson.options.supportsFileNameArgument) {
29+
args.push("--source-file-path", document.fileName);
30+
}
31+
1832
const { stdout, stderr, error } = await execFeed(meson.path, args, { cwd: root }, originalDocumentText);
1933
if (error) {
2034
//TODO: file a bug report, meson prints some errors on stdout :(
@@ -35,8 +49,9 @@ export async function format(meson: Tool, root: string, document: vscode.TextDoc
3549

3650
const formattingSupportedSinceVersion = new Version([1, 5, 0]);
3751
const formattingWithStdinSupportedSinceVersion = new Version([1, 7, 0]);
52+
const formattingWithFileNameArgumentSinceVersion = new Version([1, 9, 0]);
3853

39-
export async function check(): Promise<ToolCheckResult> {
54+
export async function check(): Promise<CheckResult<MesonTool>> {
4055
const meson_path = mesonProgram();
4156

4257
let mesonVersion;
@@ -45,23 +60,29 @@ export async function check(): Promise<ToolCheckResult> {
4560
} catch (e) {
4661
const error = e as Error;
4762
console.log(error);
48-
return ToolCheckResult.newError(error.message);
63+
return CheckResult.newError<MesonTool>(error.message);
4964
}
5065

5166
// meson format was introduced in 1.5.0
5267
// see https://mesonbuild.com/Commands.html#format
5368
if (mesonVersion.compareWithOther(formattingSupportedSinceVersion) < 0) {
54-
ToolCheckResult.newError(
69+
return CheckResult.newError<MesonTool>(
5570
`Meson supports formatting only since version ${formattingSupportedSinceVersion}, but you have version ${mesonVersion}`,
5671
);
5772
}
5873

5974
// using "-" as stdin is only supported since 1.7.0 (see https://github.com/mesonbuild/meson/pull/13793)
6075
if (mesonVersion.compareWithOther(formattingWithStdinSupportedSinceVersion) < 0) {
61-
return ToolCheckResult.newError(
76+
return CheckResult.newError<MesonTool>(
6277
`Meson supports formatting from stdin only since version ${formattingWithStdinSupportedSinceVersion}, but you have version ${mesonVersion}`,
6378
);
6479
}
6580

66-
return ToolCheckResult.newTool({ path: meson_path, version: mesonVersion });
81+
const supportsFileNameArgument = mesonVersion.compareWithOther(formattingWithFileNameArgumentSinceVersion) >= 0;
82+
83+
const options: MesonOptions = {
84+
supportsFileNameArgument,
85+
};
86+
87+
return CheckResult.newData<MesonTool>({ path: meson_path, version: mesonVersion, options });
6788
}

src/tools/muon.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
import * as vscode from "vscode";
22
import { ExecResult, exec, execFeed, extensionConfiguration, getOutputChannel } from "../utils.js";
3-
import { Tool, ToolCheckResult } from "../types.js";
3+
import { Tool, CheckResult } from "../types.js";
44
import { Version, type VersionArray } from "../version.js";
55

6-
export async function lint(muon: Tool, root: string, document: vscode.TextDocument): Promise<vscode.Diagnostic[]> {
6+
export interface MuonOptions {}
7+
8+
export type MuonTool = Tool<MuonOptions>;
9+
10+
export async function lint(muon: MuonTool, root: string, document: vscode.TextDocument): Promise<vscode.Diagnostic[]> {
711
const { stdout, stderr } = await execFeed(
812
muon.path,
913
["analyze", "-l", "-O", document.uri.fsPath],
@@ -51,7 +55,7 @@ export async function lint(muon: Tool, root: string, document: vscode.TextDocume
5155
return diagnostics;
5256
}
5357

54-
export async function format(muon: Tool, root: string, document: vscode.TextDocument): Promise<vscode.TextEdit[]> {
58+
export async function format(muon: MuonTool, root: string, document: vscode.TextDocument): Promise<vscode.TextEdit[]> {
5559
const originalDocumentText = document.getText();
5660

5761
let args = ["fmt"];
@@ -82,7 +86,7 @@ export async function format(muon: Tool, root: string, document: vscode.TextDocu
8286
return [new vscode.TextEdit(documentRange, stdout)];
8387
}
8488

85-
export async function check(): Promise<ToolCheckResult> {
89+
export async function check(): Promise<CheckResult<MuonTool>> {
8690
const muon_path = extensionConfiguration("muonPath");
8791
let stdout: string, stderr: string;
8892

@@ -91,12 +95,12 @@ export async function check(): Promise<ToolCheckResult> {
9195
} catch (e) {
9296
const { error, stdout, stderr } = e as ExecResult;
9397
console.log(error);
94-
return ToolCheckResult.newError(error!.message);
98+
return CheckResult.newError<MuonTool>(error!.message);
9599
}
96100

97101
const line1 = stdout.split("\n")[0].split(" ");
98102
if (line1.length !== 2) {
99-
return ToolCheckResult.newError(`Invalid version string: ${line1}`);
103+
return CheckResult.newError<MuonTool>(`Invalid version string: ${line1}`);
100104
}
101105

102106
const ver = line1[1]
@@ -110,5 +114,7 @@ export async function check(): Promise<ToolCheckResult> {
110114
return Number.parseInt(s);
111115
}) as VersionArray;
112116

113-
return ToolCheckResult.newTool({ path: muon_path, version: new Version(ver) });
117+
const options: MuonOptions = {};
118+
119+
return CheckResult.newData<MuonTool>({ path: muon_path, version: new Version(ver), options });
114120
}

src/types.ts

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,35 +3,35 @@ import type { Version } from "./version.js";
33

44
type Dict<T> = { [x: string]: T };
55

6-
export type Tool = { path: string; version: Version };
6+
export type Tool<Options> = { path: string; version: Version; options: Options };
77

8-
export type ToolCheckSuccessResult = {
9-
tool: Tool;
8+
export type CheckSuccessResult<Data> = {
9+
data: Data;
1010
error?: undefined;
1111
};
12-
export type ToolCheckErrorResult = {
13-
tool?: undefined;
12+
export type CheckErrorResult = {
13+
data?: undefined;
1414
error: string;
1515
};
1616

17-
type ResultImpl = ToolCheckSuccessResult | ToolCheckErrorResult;
17+
type ResultImpl<Data> = CheckSuccessResult<Data> | CheckErrorResult;
1818

19-
export class ToolCheckResult {
20-
private readonly result: ResultImpl;
19+
export class CheckResult<Data> {
20+
private readonly result: ResultImpl<Data>;
2121

22-
private constructor(result: ResultImpl) {
22+
private constructor(result: ResultImpl<Data>) {
2323
this.result = result;
2424
}
2525

26-
static newError(error: string) {
27-
return new ToolCheckResult({ error });
26+
static newError<D>(error: string): CheckResult<D> {
27+
return new CheckResult<D>({ error });
2828
}
2929

30-
static newTool(tool: Tool) {
31-
return new ToolCheckResult({ tool });
30+
static newData<D>(data: D): CheckResult<D> {
31+
return new CheckResult<D>({ data });
3232
}
3333

34-
private hasErrorImpl(result: ResultImpl): result is ToolCheckErrorResult {
34+
private hasErrorImpl(result: ResultImpl<Data>): result is CheckErrorResult {
3535
return !!result.error;
3636
}
3737

@@ -46,15 +46,15 @@ export class ToolCheckResult {
4646
return this.result.error;
4747
}
4848

49-
get tool(): Tool {
49+
get data(): Data {
5050
if (this.hasErrorImpl(this.result)) {
51-
throw new Error("Wrong invocation of getter for 'tool', check the state first");
51+
throw new Error("Wrong invocation of getter for 'data', check the state first");
5252
}
53-
return this.result.tool;
53+
return this.result.data;
5454
}
5555
}
5656

57-
export type ToolCheckFunc = () => Promise<ToolCheckResult>;
57+
export type ToolCheckFunc<D> = () => Promise<CheckResult<Tool<D>>>;
5858

5959
export type LinterConfiguration = {
6060
enabled: boolean;

src/utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ import {
1010
Target,
1111
SettingsKey,
1212
ModifiableExtension,
13-
type ToolCheckResult,
14-
type ToolCheckErrorResult,
13+
type CheckResult,
14+
type CheckErrorResult,
1515
} from "./types.js";
1616
import { getMesonBuildOptions } from "./introspection.js";
1717
import { extensionPath, workspaceState } from "./extension.js";

0 commit comments

Comments
 (0)