roc/cli/src/main.rs

158 lines
4.6 KiB
Rust

use roc_cli::{
build_app, docs, repl, BuildConfig, CMD_BUILD, CMD_DOCS, CMD_EDIT, CMD_REPL, CMD_RUN,
DIRECTORY_OR_FILES, ROC_FILE,
};
use std::fs::{self, FileType};
use std::io;
use std::path::{Path, PathBuf};
use target_lexicon::Triple;
#[cfg(feature = "llvm")]
use roc_cli::build;
use std::ffi::{OsStr, OsString};
#[cfg(not(feature = "llvm"))]
fn build(_target: &Triple, _matches: &clap::ArgMatches, _config: BuildConfig) -> io::Result<i32> {
panic!("Building without LLVM is not currently supported.");
}
fn main() -> io::Result<()> {
let matches = build_app().get_matches();
let exit_code = match matches.subcommand_name() {
None => {
launch_editor(&[])?;
// rustc couldn't infer the error type here
Result::<i32, io::Error>::Ok(0)
}
Some(CMD_BUILD) => Ok(build(
&Triple::host(),
matches.subcommand_matches(CMD_BUILD).unwrap(),
BuildConfig::BuildOnly,
)?),
Some(CMD_RUN) => {
let subcmd_matches = matches.subcommand_matches(CMD_RUN).unwrap();
let roc_file_arg_index = subcmd_matches.index_of(ROC_FILE).unwrap() + 1; // Not sure why this +1 is necessary, but it is!
Ok(build(
&Triple::host(),
subcmd_matches,
BuildConfig::BuildAndRun { roc_file_arg_index },
)?)
}
Some(CMD_REPL) => {
repl::main()?;
// Exit 0 if the repl exited normally
Ok(0)
}
Some(CMD_EDIT) => {
match matches
.subcommand_matches(CMD_EDIT)
.unwrap()
.values_of_os(DIRECTORY_OR_FILES)
{
None => {
launch_editor(&[])?;
}
Some(values) => {
let paths = values
.map(|os_str| Path::new(os_str))
.collect::<Vec<&Path>>();
launch_editor(&paths)?;
}
}
// Exit 0 if the editor exited normally
Ok(0)
}
Some(CMD_DOCS) => {
let maybe_values = matches
.subcommand_matches(CMD_DOCS)
.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)?;
}
docs(roc_files);
Ok(0)
}
_ => unreachable!(),
}?;
std::process::exit(exit_code);
}
fn read_all_roc_files(
dir: &OsString,
mut roc_file_paths: &mut Vec<OsString>,
) -> Result<(), std::io::Error> {
let entries = fs::read_dir(dir)?;
for entry in entries {
let path = entry?.path();
if path.is_dir() {
read_all_roc_files(&path.into_os_string(), &mut roc_file_paths)?;
} else if path.extension().and_then(OsStr::to_str) == Some("roc") {
let file_path = path.into_os_string();
roc_file_paths.push(file_path);
}
}
Ok(())
}
fn roc_files_recursive<P: AsRef<Path>>(
path: P,
file_type: FileType,
roc_files: &mut Vec<PathBuf>,
) -> io::Result<()> {
if file_type.is_dir() {
for entry_res in fs::read_dir(path)? {
let entry = entry_res?;
roc_files_recursive(entry.path(), entry.file_type()?, roc_files)?;
}
} else {
roc_files.push(path.as_ref().to_path_buf());
}
Ok(())
}
#[cfg(feature = "editor")]
fn launch_editor(filepaths: &[&Path]) -> io::Result<()> {
roc_editor::launch(filepaths)
}
#[cfg(not(feature = "editor"))]
fn launch_editor(_filepaths: &[&Path]) -> io::Result<()> {
panic!("Cannot launch the editor because this build of roc did not include `feature = \"editor\"`!");
}