Skip to content

Commit ac8e6f3

Browse files
authored
feat: add autocorrect, a formatter for CJK spacing and punctuation (#372)
1 parent a05be41 commit ac8e6f3

File tree

3 files changed

+246
-1
lines changed

3 files changed

+246
-1
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,11 +221,12 @@ functions.
221221
<!-- `> bash ./supported-programs.sh` -->
222222

223223
<!-- BEGIN mdsh -->
224-
`treefmt-nix` currently supports 108 formatters:
224+
`treefmt-nix` currently supports 109 formatters:
225225

226226
* [actionlint](programs/actionlint.nix)
227227
* [alejandra](programs/alejandra.nix)
228228
* [asmfmt](programs/asmfmt.nix)
229+
* [autocorrect](programs/autocorrect.nix)
229230
* [beautysh](programs/beautysh.nix)
230231
* [biome](programs/biome.nix)
231232
* [black](programs/black.nix)

examples/formatter-autocorrect.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Example generated by ../examples.sh
2+
[formatter.autocorrect]
3+
command = "autocorrect"
4+
excludes = []
5+
includes = ["*"]
6+
options = ["--fix"]

programs/autocorrect.nix

Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
{
2+
lib,
3+
pkgs,
4+
config,
5+
mkFormatterModule,
6+
...
7+
}:
8+
let
9+
cfg = config.programs.autocorrect;
10+
configFormat = pkgs.formats.json { };
11+
12+
# 0 - off, 1 - error, 2 - warning
13+
ruleType = lib.types.nullOr (
14+
lib.types.enum [
15+
"off"
16+
"error"
17+
"warning"
18+
]
19+
);
20+
21+
# Configuration schema for Autocorrect, which we generate .autocorrectrc with.
22+
# Definition taken from: https://github.com/huacnlee/autocorrect/raw/refs/heads/main/.autocorrectrc.template
23+
settingsSchema = {
24+
rules = lib.mkOption {
25+
description = "Configure rules for autocorrect formatting.";
26+
type = lib.types.nullOr (
27+
lib.types.submodule {
28+
options = {
29+
space-word = lib.mkOption {
30+
description = "Auto add spacing between CJK (Chinese, Japanese, Korean) and English words.";
31+
type = ruleType;
32+
example = "off";
33+
default = null;
34+
};
35+
36+
space-punctuation = lib.mkOption {
37+
description = "Add space between some punctuations.";
38+
type = ruleType;
39+
example = "error";
40+
default = null;
41+
};
42+
43+
space-bracket = lib.mkOption {
44+
description = "Add space between brackets (), [] when near the CJK.";
45+
type = ruleType;
46+
example = "error";
47+
default = null;
48+
};
49+
50+
space-backticks = lib.mkOption {
51+
description = "Add space between ``, when near the CJK.";
52+
type = ruleType;
53+
example = "error";
54+
default = null;
55+
};
56+
57+
space-dash = lib.mkOption {
58+
description = "Add space between dash `-`.";
59+
type = ruleType;
60+
example = "off";
61+
default = null;
62+
};
63+
64+
space-dollar = lib.mkOption {
65+
description = "Add space between dollar $ when near the CJK.";
66+
type = ruleType;
67+
example = "off";
68+
default = null;
69+
};
70+
71+
fullwidth = lib.mkOption {
72+
description = "Convert to fullwidth.";
73+
type = ruleType;
74+
example = "error";
75+
default = null;
76+
};
77+
78+
no-space-fullwidth = lib.mkOption {
79+
description = "Remove space near the fullwidth.";
80+
type = ruleType;
81+
example = "error";
82+
default = null;
83+
};
84+
85+
halfwidth-word = lib.mkOption {
86+
description = "Fullwidth alphanumeric characters to halfwidth.";
87+
type = ruleType;
88+
example = "error";
89+
default = null;
90+
};
91+
92+
halfwidth-punctuation = lib.mkOption {
93+
description = "Fullwidth punctuations to halfwidth in english.";
94+
type = ruleType;
95+
example = "error";
96+
default = null;
97+
};
98+
99+
spellcheck = lib.mkOption {
100+
description = "Spellcheck.";
101+
type = ruleType;
102+
example = "warning";
103+
default = null;
104+
};
105+
};
106+
}
107+
);
108+
default = null;
109+
};
110+
111+
context = lib.mkOption {
112+
description = "Enable or disable in a specific context.";
113+
type = lib.types.nullOr (
114+
lib.types.submodule {
115+
options = {
116+
codeblock = lib.mkOption {
117+
description = "Enable or disable to format codeblock in Markdown or AsciiDoc etc.";
118+
type = ruleType;
119+
example = "error";
120+
default = null;
121+
};
122+
};
123+
}
124+
);
125+
default = null;
126+
};
127+
128+
textRules = lib.mkOption {
129+
description = "Configure special rules for some texts.";
130+
type = lib.types.nullOr (lib.types.attrsOf ruleType);
131+
example = {
132+
"Hello你好" = "warning";
133+
"Hi你好" = "off";
134+
};
135+
default = null;
136+
};
137+
138+
fileTypes = lib.mkOption {
139+
description = "Configure the files associations, you config is higher priority than default.";
140+
type = lib.types.nullOr (lib.types.attrsOf lib.types.str);
141+
example = {
142+
"rb" = "ruby";
143+
"Rakefile" = "ruby";
144+
"*.js" = "javascript";
145+
".mdx" = "markdown";
146+
};
147+
default = null;
148+
};
149+
150+
spellcheck = lib.mkOption {
151+
description = "Spellcheck configuration.";
152+
type = lib.types.nullOr (
153+
lib.types.submodule {
154+
options = {
155+
words = lib.mkOption {
156+
description = "Correct Words (Case insensitive) for by Spellcheck.";
157+
type = lib.types.nullOr (lib.types.listOf lib.types.str);
158+
example = [
159+
"GitHub"
160+
"App Store"
161+
"AppStore = App Store"
162+
"Git"
163+
"Node.js"
164+
"nodejs = Node.js"
165+
"VIM"
166+
"DNS"
167+
"HTTP"
168+
"SSL"
169+
];
170+
default = null;
171+
};
172+
};
173+
}
174+
);
175+
default = null;
176+
};
177+
};
178+
179+
settingsFile =
180+
let
181+
# Convert rule lib.types from strings to numeric values
182+
convertRuleTypes =
183+
attrs:
184+
lib.mapAttrsRecursive (
185+
_path: value:
186+
if isNull value then
187+
null
188+
else
189+
{
190+
"off" = 0;
191+
"error" = 1;
192+
"warning" = 2;
193+
}
194+
.${value} or value
195+
) attrs;
196+
197+
# remove all null values and convert rule lib.types
198+
settings = lib.filterAttrsRecursive (_n: v: v != null) (convertRuleTypes cfg.settings);
199+
in
200+
if settings != { } then configFormat.generate ".autocorrectrc" settings else null;
201+
in
202+
{
203+
meta.maintainers = [ "definfo" ];
204+
205+
imports = [
206+
(mkFormatterModule {
207+
name = "autocorrect";
208+
args = [ "--fix" ];
209+
includes = [ "*" ];
210+
})
211+
];
212+
213+
options.programs.autocorrect = {
214+
threads = lib.mkOption {
215+
description = "Number of threads, 0 - use number of CPU. [default: 0]";
216+
type = lib.types.nullOr lib.types.int;
217+
example = 2;
218+
default = null;
219+
};
220+
221+
# Represents the .autocorrectrc config schema
222+
settings = settingsSchema;
223+
};
224+
225+
config = lib.mkIf cfg.enable {
226+
settings.formatter.autocorrect = {
227+
options =
228+
(lib.optionals (!isNull cfg.threads) [
229+
"--threads"
230+
(toString cfg.threads)
231+
])
232+
++ (lib.optionals (settingsFile != null) [
233+
"--config"
234+
(toString settingsFile)
235+
]);
236+
};
237+
};
238+
}

0 commit comments

Comments
 (0)