Implement 'roc format <dir_or_files>' command

This commit is contained in:
Joshua Warner 2021-11-22 16:34:20 -08:00
parent 047a11ddb1
commit 3f8c6be9e9
3 changed files with 90 additions and 3 deletions

39
cli/src/format.rs Normal file
View file

@ -0,0 +1,39 @@
use std::path::PathBuf;
use bumpalo::collections::String;
use bumpalo::Bump;
use roc_fmt::def::fmt_def;
use roc_fmt::module::fmt_module;
use roc_parse::{
module::{self, module_defs},
parser::{Parser, State},
};
use roc_reporting::user_error;
pub fn format(files: Vec<PathBuf>) {
for file in files {
let arena = Bump::new();
let src = std::fs::read_to_string(&file).unwrap();
match module::parse_header(&arena, State::new(src.as_bytes())) {
Ok((result, state)) => {
let mut buf = String::new_in(&arena);
fmt_module(&mut buf, &result);
match module_defs().parse(&arena, state) {
Ok((_, loc_defs, _)) => {
for loc_def in loc_defs {
fmt_def(&mut buf, arena.alloc(loc_def.value), 0);
}
}
Err(error) => user_error!("Unexpected parse failure when parsing this for defs formatting:\n\n{:?}\n\nParse error was:\n\n{:?}\n\n", src, error)
}
std::fs::write(&file, buf).unwrap();
}
Err(error) => user_error!("Unexpected parse failure when parsing this for module header formatting:\n\n{:?}\n\nParse error was:\n\n{:?}\n\n", src, error)
};
}
}

View file

@ -9,14 +9,17 @@ use roc_load::file::LoadingProblem;
use roc_mono::ir::OptLevel; use roc_mono::ir::OptLevel;
use std::env; use std::env;
use std::io; use std::io;
use std::path::{Path, PathBuf}; use std::path::Path;
use std::path::PathBuf;
use std::process; use std::process;
use std::process::Command; use std::process::Command;
use target_lexicon::BinaryFormat; use target_lexicon::BinaryFormat;
use target_lexicon::{Architecture, OperatingSystem, Triple, X86_32Architecture}; use target_lexicon::{Architecture, OperatingSystem, Triple, X86_32Architecture};
pub mod build; pub mod build;
mod format;
pub mod repl; pub mod repl;
pub use format::format;
pub const CMD_BUILD: &str = "build"; pub const CMD_BUILD: &str = "build";
pub const CMD_REPL: &str = "repl"; pub const CMD_REPL: &str = "repl";
@ -24,6 +27,7 @@ pub const CMD_EDIT: &str = "edit";
pub const CMD_DOCS: &str = "docs"; pub const CMD_DOCS: &str = "docs";
pub const CMD_CHECK: &str = "check"; pub const CMD_CHECK: &str = "check";
pub const CMD_VERSION: &str = "version"; pub const CMD_VERSION: &str = "version";
pub const CMD_FORMAT: &str = "format";
pub const FLAG_DEBUG: &str = "debug"; pub const FLAG_DEBUG: &str = "debug";
pub const FLAG_DEV: &str = "dev"; pub const FLAG_DEV: &str = "dev";
@ -35,6 +39,7 @@ pub const FLAG_LINK: &str = "roc-linker";
pub const FLAG_PRECOMPILED: &str = "precompiled-host"; pub const FLAG_PRECOMPILED: &str = "precompiled-host";
pub const FLAG_VALGRIND: &str = "valgrind"; pub const FLAG_VALGRIND: &str = "valgrind";
pub const ROC_FILE: &str = "ROC_FILE"; pub const ROC_FILE: &str = "ROC_FILE";
pub const ROC_DIR: &str = "ROC_DIR";
pub const BACKEND: &str = "BACKEND"; pub const BACKEND: &str = "BACKEND";
pub const DIRECTORY_OR_FILES: &str = "DIRECTORY_OR_FILES"; pub const DIRECTORY_OR_FILES: &str = "DIRECTORY_OR_FILES";
pub const ARGS_FOR_APP: &str = "ARGS_FOR_APP"; pub const ARGS_FOR_APP: &str = "ARGS_FOR_APP";
@ -111,6 +116,14 @@ pub fn build_app<'a>() -> App<'a> {
.subcommand(App::new(CMD_REPL) .subcommand(App::new(CMD_REPL)
.about("Launch the interactive Read Eval Print Loop (REPL)") .about("Launch the interactive Read Eval Print Loop (REPL)")
) )
.subcommand(App::new(CMD_FORMAT)
.about("Format Roc code")
.arg(
Arg::new(DIRECTORY_OR_FILES)
.index(1)
.multiple_values(true)
.required(false))
)
.subcommand(App::new(CMD_VERSION) .subcommand(App::new(CMD_VERSION)
.about("Print version information") .about("Print version information")
) )

View file

@ -1,7 +1,7 @@
use roc_cli::build::check_file; use roc_cli::build::check_file;
use roc_cli::{ use roc_cli::{
build_app, docs, repl, BuildConfig, CMD_BUILD, CMD_CHECK, CMD_DOCS, CMD_EDIT, CMD_REPL, build_app, docs, format, repl, BuildConfig, CMD_BUILD, CMD_CHECK, CMD_DOCS, CMD_EDIT,
CMD_VERSION, DIRECTORY_OR_FILES, FLAG_TIME, ROC_FILE, CMD_FORMAT, CMD_REPL, CMD_VERSION, DIRECTORY_OR_FILES, FLAG_TIME, ROC_FILE,
}; };
use roc_load::file::LoadingProblem; use roc_load::file::LoadingProblem;
use std::fs::{self, FileType}; use std::fs::{self, FileType};
@ -125,6 +125,41 @@ fn main() -> io::Result<()> {
Ok(0) Ok(0)
} }
Some(CMD_FORMAT) => {
let maybe_values = matches
.subcommand_matches(CMD_FORMAT)
.unwrap()
.values_of_os(DIRECTORY_OR_FILES);
let mut values: Vec<OsString> = Vec::new();
match maybe_values {
None => {
let mut os_string_values: Vec<OsString> = Vec::new();
read_all_roc_files(&OsStr::new("./").to_os_string(), &mut os_string_values)?;
for os_string in os_string_values {
values.push(os_string);
}
}
Some(os_values) => {
for os_str in os_values {
values.push(os_str.to_os_string());
}
}
}
let mut roc_files = Vec::new();
// Populate roc_files
for os_str in values {
let metadata = fs::metadata(os_str.clone())?;
roc_files_recursive(os_str.as_os_str(), metadata.file_type(), &mut roc_files)?;
}
format(roc_files);
Ok(0)
}
Some(CMD_VERSION) => { Some(CMD_VERSION) => {
println!("roc {}", concatcp!(include_str!("../../version.txt"), "\n")); println!("roc {}", concatcp!(include_str!("../../version.txt"), "\n"));