authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-06-18 13:55:03-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-06-18 13:58:08-04:00
log1ca90b585692c9611c64412844d2f3a7b3e11340
tree6cf95158bbd2a5f527ae315305f40941a6d56b6b
parentcd4676a2338430d9e424f297b8b576143c5be180

zig fmt: support directories

zig fmt accepts any number of file paths. For each one, if it is a file, then it formats the file. If it is a directory, then zig recursively scans the directory, formatting all files that end in `.zig`. it maintains a map of paths that have been seen already, to avoid softlink loops. closes #1068

1 files changed, 55 insertions(+), 8 deletions(-)

src-self-hosted/main.zig+55-8
...@@ -700,6 +700,36 @@ const args_fmt_spec = []Flag{...@@ -700,6 +700,36 @@ const args_fmt_spec = []Flag{
700 }),700 }),
701};701};
702702
703const Fmt = struct {
704 seen: std.HashMap([]const u8, void, mem.hash_slice_u8, mem.eql_slice_u8),
705 queue: std.LinkedList([]const u8),
706 any_error: bool,
707
708 // file_path must outlive Fmt
709 fn addToQueue(self: *Fmt, file_path: []const u8) !void {
710 const new_node = try self.seen.allocator.construct(std.LinkedList([]const u8).Node{
711 .prev = undefined,
712 .next = undefined,
713 .data = file_path,
714 });
715
716 if (try self.seen.put(file_path, {})) |_| return;
717
718 self.queue.append(new_node);
719 }
720
721 fn addDirToQueue(self: *Fmt, file_path: []const u8) !void {
722 var dir = try std.os.Dir.open(self.seen.allocator, file_path);
723 defer dir.close();
724 while (try dir.next()) |entry| {
725 if (entry.kind == std.os.Dir.Entry.Kind.Directory or mem.endsWith(u8, entry.name, ".zig")) {
726 const full_path = try os.path.join(self.seen.allocator, file_path, entry.name);
727 try self.addToQueue(full_path);
728 }
729 }
730 }
731};
732
703fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {733fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
704 var flags = try Args.parse(allocator, args_fmt_spec, args);734 var flags = try Args.parse(allocator, args_fmt_spec, args);
705 defer flags.deinit();735 defer flags.deinit();
...@@ -728,21 +758,38 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {...@@ -728,21 +758,38 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
728 }758 }
729 };759 };
730760
731 var fmt_errors = false;761 var fmt = Fmt{
762 .seen = std.HashMap([]const u8, void, mem.hash_slice_u8, mem.eql_slice_u8).init(allocator),
763 .queue = std.LinkedList([]const u8).init(),
764 .any_error = false,
765 };
766
732 for (flags.positionals.toSliceConst()) |file_path| {767 for (flags.positionals.toSliceConst()) |file_path| {
768 try fmt.addToQueue(file_path);
769 }
770
771 while (fmt.queue.popFirst()) |node| {
772 const file_path = node.data;
773
733 var file = try os.File.openRead(allocator, file_path);774 var file = try os.File.openRead(allocator, file_path);
734 defer file.close();775 defer file.close();
735776
736 const source_code = io.readFileAlloc(allocator, file_path) catch |err| {777 const source_code = io.readFileAlloc(allocator, file_path) catch |err| switch (err) {
737 try stderr.print("unable to open '{}': {}\n", file_path, err);778 error.IsDir => {
738 fmt_errors = true;779 try fmt.addDirToQueue(file_path);
739 continue;780 continue;
781 },
782 else => {
783 try stderr.print("unable to open '{}': {}\n", file_path, err);
784 fmt.any_error = true;
785 continue;
786 },
740 };787 };
741 defer allocator.free(source_code);788 defer allocator.free(source_code);
742789
743 var tree = std.zig.parse(allocator, source_code) catch |err| {790 var tree = std.zig.parse(allocator, source_code) catch |err| {
744 try stderr.print("error parsing file '{}': {}\n", file_path, err);791 try stderr.print("error parsing file '{}': {}\n", file_path, err);
745 fmt_errors = true;792 fmt.any_error = true;
746 continue;793 continue;
747 };794 };
748 defer tree.deinit();795 defer tree.deinit();
...@@ -755,7 +802,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {...@@ -755,7 +802,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
755 try errmsg.printToFile(&stderr_file, msg, color);802 try errmsg.printToFile(&stderr_file, msg, color);
756 }803 }
757 if (tree.errors.len != 0) {804 if (tree.errors.len != 0) {
758 fmt_errors = true;805 fmt.any_error = true;
759 continue;806 continue;
760 }807 }
761808
...@@ -769,7 +816,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {...@@ -769,7 +816,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
769 }816 }
770 }817 }
771818
772 if (fmt_errors) {819 if (fmt.any_error) {
773 os.exit(1);820 os.exit(1);
774 }821 }
775}822}