summaryrefslogtreecommitdiff
path: root/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs96
1 files changed, 96 insertions, 0 deletions
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..8f9ccea
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,96 @@
+use crate::run::run;
+use crate::verify::verify;
+use clap::{crate_version, App, Arg, SubCommand};
+use notify::DebouncedEvent;
+use notify::{RecommendedWatcher, RecursiveMode, Watcher};
+use std::io::BufRead;
+use std::sync::mpsc::channel;
+use std::time::Duration;
+use syntect::easy::HighlightFile;
+use syntect::highlighting::{Style, ThemeSet};
+use syntect::parsing::SyntaxSet;
+use syntect::util::as_24_bit_terminal_escaped;
+
+mod run;
+mod util;
+mod verify;
+
+fn main() {
+ let matches = App::new("rustlings")
+ .version(crate_version!())
+ .author("Olivia Hugger, Carol Nichols")
+ .about("Rustlings is a collection of small exercises to get you used to writing and reading Rust code")
+ .subcommand(SubCommand::with_name("verify").alias("v").about("Verifies all exercises according to the recommended order"))
+ .subcommand(SubCommand::with_name("watch").alias("w").about("Reruns `verify` when files were edited"))
+ .subcommand(
+ SubCommand::with_name("run")
+ .alias("r")
+ .about("Runs/Tests a single exercise")
+ .arg(Arg::with_name("file").required(true).index(1))
+ .arg(Arg::with_name("test").short("t").long("test").help("Run the file as a test")),
+ )
+ .get_matches();
+
+ let ss = SyntaxSet::load_defaults_newlines();
+ let ts = ThemeSet::load_defaults();
+
+ if None == matches.subcommand_name() {
+ println!("");
+ println!(r#" welcome to... "#);
+ println!(r#" _ _ _ "#);
+ println!(r#" _ __ _ _ ___| |_| (_)_ __ __ _ ___ "#);
+ println!(r#" | '__| | | / __| __| | | '_ \ / _` / __| "#);
+ println!(r#" | | | |_| \__ \ |_| | | | | | (_| \__ \ "#);
+ println!(r#" |_| \__,_|___/\__|_|_|_| |_|\__, |___/ "#);
+ println!(r#" |___/ "#);
+ println!("");
+ }
+
+ if let Some(matches) = matches.subcommand_matches("run") {
+ run(matches.clone());
+ }
+
+ if let Some(_) = matches.subcommand_matches("verify") {
+ match verify() {
+ Ok(_) => {}
+ Err(_) => std::process::exit(1),
+ }
+ }
+
+ if let Some(_) = matches.subcommand_matches("watch") {
+ watch().unwrap();
+ }
+
+ if let None = matches.subcommand_name() {
+ let mut highlighter =
+ HighlightFile::new("default_out.md", &ss, &ts.themes["base16-eighties.dark"]).unwrap();
+ for maybe_line in highlighter.reader.lines() {
+ let line = maybe_line.unwrap();
+ let regions: Vec<(Style, &str)> = highlighter.highlight_lines.highlight(&line, &ss);
+ println!("{}", as_24_bit_terminal_escaped(&regions[..], true));
+ }
+ }
+
+ println!("\x1b[0m");
+}
+
+fn watch() -> notify::Result<()> {
+ let (tx, rx) = channel();
+
+ let mut watcher: RecommendedWatcher = Watcher::new(tx, Duration::from_secs(2))?;
+ watcher.watch("./exercises", RecursiveMode::Recursive)?;
+
+ let _ignored = verify();
+
+ loop {
+ match rx.recv() {
+ Ok(event) => match event {
+ DebouncedEvent::Chmod(_) | DebouncedEvent::Write(_) => {
+ let _ignored = verify();
+ }
+ _ => {}
+ },
+ Err(e) => println!("watch error: {:?}", e),
+ }
+ }
+}