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{
700700 }),
701701};
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
703733fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
704734 var flags = try Args.parse(allocator, args_fmt_spec, args);
705735 defer flags.deinit();
......@@ -728,21 +758,38 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
728758 }
729759 };
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
732767 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
733774 var file = try os.File.openRead(allocator, file_path);
734775 defer file.close();
735776
736 const source_code = io.readFileAlloc(allocator, file_path) catch |err| {
737 try stderr.print("unable to open '{}': {}\n", file_path, err);
738 fmt_errors = true;
739 continue;
777 const source_code = io.readFileAlloc(allocator, file_path) catch |err| switch (err) {
778 error.IsDir => {
779 try fmt.addDirToQueue(file_path);
780 continue;
781 },
782 else => {
783 try stderr.print("unable to open '{}': {}\n", file_path, err);
784 fmt.any_error = true;
785 continue;
786 },
740787 };
741788 defer allocator.free(source_code);
742789
743790 var tree = std.zig.parse(allocator, source_code) catch |err| {
744791 try stderr.print("error parsing file '{}': {}\n", file_path, err);
745 fmt_errors = true;
792 fmt.any_error = true;
746793 continue;
747794 };
748795 defer tree.deinit();
......@@ -755,7 +802,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
755802 try errmsg.printToFile(&stderr_file, msg, color);
756803 }
757804 if (tree.errors.len != 0) {
758 fmt_errors = true;
805 fmt.any_error = true;
759806 continue;
760807 }
761808
......@@ -769,7 +816,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
769816 }
770817 }
771818
772 if (fmt_errors) {
819 if (fmt.any_error) {
773820 os.exit(1);
774821 }
775822}