Files
Odin/tools/odinfmt/main.odin
2021-06-08 12:18:55 +01:00

147 lines
3.3 KiB
Odin

package odinfmt
import "core:os"
import "core:odin/tokenizer"
import "core:odin/format"
import "core:fmt"
import "core:strings"
import "core:path/filepath"
import "core:time"
import "core:mem"
import "flag"
Args :: struct {
write: Maybe(bool) `flag:"w" usage:"write the new format to file"`,
}
print_help :: proc(args: []string) {
if len(args) == 0 {
fmt.eprint("odinfmt ");
} else {
fmt.eprintf("%s ", args[0]);
}
fmt.eprintln();
}
print_arg_error :: proc(args: []string, error: flag.Flag_Error) {
switch error {
case .None:
print_help(args);
case .No_Base_Struct:
fmt.eprintln(args[0], "no base struct");
case .Arg_Error:
fmt.eprintln(args[0], "argument error");
case .Arg_Unsupported_Field_Type:
fmt.eprintln(args[0], "argument: unsupported field type");
case .Arg_Not_Defined:
fmt.eprintln(args[0], "argument: no defined");
case .Arg_Non_Optional:
fmt.eprintln(args[0], "argument: non optional");
case .Value_Parse_Error:
fmt.eprintln(args[0], "argument: value parse error");
case .Tag_Error:
fmt.eprintln(args[0], "argument: tag error");
}
}
format_file :: proc(filepath: string) -> (string, bool) {
if data, ok := os.read_entire_file(filepath); ok {
return format.format(filepath, string(data), format.default_style);
} else {
return "", false;
}
}
files: [dynamic]string;
walk_files :: proc(info: os.File_Info, in_err: os.Errno) -> (err: os.Errno, skip_dir: bool) {
if info.is_dir {
return 0, false;
}
if filepath.ext(info.name) != ".odin" {
return 0, false;
}
append(&files, strings.clone(info.fullpath));
return 0, false;
}
main :: proc() {
init_global_temporary_allocator(mem.megabytes(100));
args: Args;
if len(os.args) < 2 {
print_help(os.args);
os.exit(1);
}
if res := flag.parse(args, os.args[1:len(os.args) - 1]); res != .None {
print_arg_error(os.args, res);
os.exit(1);
}
path := os.args[len(os.args) - 1];
tick_time := time.tick_now();
write_failure := false;
if os.is_file(path) {
if _, ok := args.write.(bool); ok {
backup_path := strings.concatenate({path, "_bk"});
defer delete(backup_path);
if data, ok := format_file(path); ok {
os.rename(path, backup_path);
if os.write_entire_file(path, transmute([]byte)data) {
os.remove(backup_path);
}
} else {
fmt.eprintf("failed to write %v", path);
write_failure = true;
}
} else {
if data, ok := format_file(path); ok {
fmt.println(data);
}
}
} else if os.is_dir(path) {
filepath.walk(path, walk_files);
for file in files {
fmt.println(file);
backup_path := strings.concatenate({file, "_bk"});
defer delete(backup_path);
if data, ok := format_file(file); ok {
if _, ok := args.write.(bool); ok {
os.rename(file, backup_path);
if os.write_entire_file(file, transmute([]byte)data) {
os.remove(backup_path);
}
} else {
fmt.println(data);
}
} else {
fmt.eprintf("failed to format %v", file);
write_failure = true;
}
}
fmt.printf("formatted %v files in %vms", len(files), time.duration_milliseconds(time.tick_lap_time(&tick_time)));
} else {
fmt.eprintf("%v is neither a directory nor a file \n", path);
os.exit(1);
}
os.exit(1 if write_failure else 0);
}