Skip to content

Commit b0ea7ce

Browse files
committed
Support include and exclude on the command line
1 parent 1bc47a4 commit b0ea7ce

File tree

2 files changed

+61
-6
lines changed

2 files changed

+61
-6
lines changed

README.md

+13-2
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,9 @@ ziglint --check-format
7474
```
7575

7676
## `exclude`
77-
This rule excludes files from being linted (unless they are specified on the command line directly). Currently, it's only available in `ziglint.json`.
77+
This rule excludes files from being linted (unless they are specified on the command line directly).
78+
79+
Note that include/exclude directives are additive and there is no priority for specifying on the command line. (However, include directives take precedence over excludes.)
7880

7981
It accepts Gitignore-style globs to specify paths.
8082
### `ziglint.json`
@@ -83,9 +85,14 @@ It accepts Gitignore-style globs to specify paths.
8385
"exclude": <array of files to exclude>
8486
}
8587
```
88+
### Command line
89+
```bash
90+
ziglint --exclude <comma-separated list of paths to exclude>
91+
```
8692

8793
## `include`
88-
This rule negates exclusions. If the `include`d files aren't in the paths/working directory `ziglint` is searching in, they still won't be linted, but if they were listed in an `exclude` rule then they will be. Currently, this rule is only available in `ziglint.json`.
94+
This rule negates exclusions. If the `include`d files aren't in the paths/working directory `ziglint` is searching in, they still won't be linted, but if they were listed in an `exclude` rule then they will be.
95+
Note that include/exclude directives are additive and there is no priority for specifying on the command line. (However, include directives take precedence over excludes.)
8996

9097
Like `exclude`, it accepts Gitignore-style globs to match paths.
9198
### `ziglint.json`
@@ -94,6 +101,10 @@ Like `exclude`, it accepts Gitignore-style globs to match paths.
94101
"include": <array of files to include>
95102
}
96103
```
104+
### Command line
105+
```bash
106+
ziglint --include <comma-separated list of paths to include>
107+
```
97108

98109
## `max_line_length`
99110
This rule restricts the possible length of a line of source code. It will create a linting error if any line of Zig code is longer than the specified maximum. It defaults to 100 characters.

src/main.zig

+48-4
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,24 @@ const Configuration = struct {
5353
include: ?[][]const u8 = null,
5454

5555
/// Replaces our fields with its fields if the field is not null in other
56-
pub fn merge(self: *Configuration, other: *const Configuration) void {
56+
///
57+
/// Does NOT free potentially-allocated memory; we use an ArenaAllocator so it's all freed when ziglint exits.
58+
pub fn merge(self: *Configuration, other: *const Configuration, alloc: std.mem.Allocator) !void {
5759
inline for (std.meta.fields(Configuration)) |field| {
5860
if (@field(other, field.name)) |value| {
59-
@field(self, field.name) = value;
61+
const is_array = field.type == ?[][]const u8;
62+
const self_has_value = @field(self, field.name) != null;
63+
if (is_array and self_has_value) {
64+
// merge fields via concatenation
65+
@field(self, field.name) = try std.mem.concat(
66+
alloc,
67+
[]const u8,
68+
&.{ @field(self, field.name).?, value },
69+
);
70+
} else {
71+
// merge fields via replacement
72+
@field(self, field.name) = value;
73+
}
6074
}
6175
}
6276
}
@@ -85,6 +99,15 @@ fn show_help() !void {
8599
\\ --include-gitignored
86100
\\ lint files excluded by .gitignore directives
87101
\\
102+
\\ --exclude <paths>
103+
\\ exclude files or directories from linting
104+
\\ <paths> should be a comma-separated list of Gitignore-style globs
105+
\\ this doesn't take priority over inclusion directives from ziglint.json or .gitignore files
106+
\\
107+
\\ --include <paths>
108+
\\ include files or directories in linting
109+
\\ <paths> should be a comma-separated list of Gitignore-style globs
110+
\\
88111
\\ --require-const-pointer-params
89112
\\ require all unmutated pointer parameters to functions be `const` (not yet fully implemented)
90113
\\
@@ -134,6 +157,8 @@ pub fn main() anyerror!void {
134157
const arg = args[args_idx];
135158
if (arg.len > 2 and arg[0] == '-' and arg[1] == '-') { // switch
136159
const switch_name = arg[2..];
160+
const is_exclude = std.mem.eql(u8, switch_name, "exclude");
161+
const is_include = std.mem.eql(u8, switch_name, "include");
137162
if (std.mem.eql(u8, switch_name, "max-line-length")) {
138163
args_idx += 1;
139164
if (args_idx >= args.len) {
@@ -165,8 +190,27 @@ pub fn main() anyerror!void {
165190
switches.enforce_const_pointers = true;
166191
} else if (std.mem.eql(u8, switch_name, "include-gitignored")) {
167192
switches.include_gitignored = true;
193+
} else if (is_include or is_exclude) {
194+
args_idx += 1;
195+
if (args_idx >= args.len) {
196+
try stderr_print("{s} requires an argument of comma-spearated globs; " ++
197+
"use `ziglint help` for more information", .{arg});
198+
std.process.exit(1);
199+
}
200+
201+
var split = std.mem.splitScalar(u8, args[args_idx], ',');
202+
var globs = std.ArrayList([]const u8).init(arena_allocator);
203+
while (split.next()) |glob| {
204+
try globs.append(glob);
205+
}
206+
207+
if (is_include) {
208+
switches.include = try globs.toOwnedSlice();
209+
} else if (is_exclude) {
210+
switches.exclude = try globs.toOwnedSlice();
211+
} else unreachable;
168212
} else {
169-
try stderr_print("unknown switch: --{s}\n", .{switch_name});
213+
try stderr_print("unknown switch: {s}\n", .{arg});
170214
try show_help();
171215
std.process.exit(1);
172216
}
@@ -197,7 +241,7 @@ pub fn main() anyerror!void {
197241

198242
if (config_file_parsed) |c| {
199243
config = c.value;
200-
config.merge(&switches);
244+
try config.merge(&switches, arena_allocator);
201245
}
202246

203247
var analyzer = analysis.ASTAnalyzer{};

0 commit comments

Comments
 (0)