diff --git a/src/main.rs b/src/main.rs index 564aa62a8..bcdc661c3 100755 --- a/src/main.rs +++ b/src/main.rs @@ -24,6 +24,7 @@ mod exercise; mod project; mod run; mod scarb; +mod utils; mod verify; // In sync with crate version diff --git a/src/run.rs b/src/run.rs index 8b00273a7..185f9d96a 100755 --- a/src/run.rs +++ b/src/run.rs @@ -1,17 +1,22 @@ use std::process::Command; -use crate::exercise::{Exercise, Mode}; +use crate::{ + exercise::{Exercise, Mode}, + utils, +}; // Invoke the rust compiler on the path of the given exercise, // and run the ensuing binary. // The verbose argument helps determine whether or not to show // the output from the test harnesses (if the mode of the exercise is test) pub fn run(exercise: &Exercise) -> Result<(), ()> { - match exercise.mode { - Mode::Build => build_cairo(exercise)?, - Mode::Run => run_cairo(exercise)?, - Mode::Test => test_cairo(exercise)?, - } + let run_result = match exercise.mode { + Mode::Build => utils::build_exercise(exercise)?, + Mode::Run => utils::run_exercise(exercise)?, + Mode::Test => utils::test_exercise(exercise)?, + }; + utils::print_exercise_output(run_result); + utils::print_exercise_success(exercise); Ok(()) } @@ -27,57 +32,3 @@ pub fn reset(exercise: &Exercise) -> Result<(), ()> { Err(_) => Err(()), } } - -// Invoke the rust compiler on the path of the given exercise -// and run the ensuing binary. -// This is strictly for non-test binaries, so output is displayed -fn build_cairo(exercise: &Exercise) -> Result<(), ()> { - println!("\nBuilding {exercise}...\n"); - let output = exercise.build(); - - if let Some(error) = output.as_ref().err() { - println!("{error}"); - Err(()) - } else { - let message = output.unwrap(); - println!("{message}"); - success!("Successfully built {}", exercise); - Ok(()) - } -} - -// Invoke the rust compiler on the path of the given exercise -// and run the ensuing binary. -// This is strictly for non-test binaries, so output is displayed -fn run_cairo(exercise: &Exercise) -> Result<(), ()> { - println!("\nRunning {exercise}...\n"); - let output = exercise.run(); - - if let Some(error) = output.as_ref().err() { - println!("{error}"); - Err(()) - } else { - let message = output.unwrap(); - println!("{message}"); - success!("Successfully ran {}", exercise); - Ok(()) - } -} - -// Invoke the rust compiler on the path of the given exercise -// and run the ensuing binary. -// This is strictly for non-test binaries, so output is displayed -fn test_cairo(exercise: &Exercise) -> Result<(), ()> { - println!("\nTesting {exercise}...\n"); - let output = exercise.test(); - - if let Some(error) = output.as_ref().err() { - println!("{error}"); - Err(()) - } else { - let message = output.unwrap(); - println!("{message}"); - success!("Successfully tested {}", exercise); - Ok(()) - } -} diff --git a/src/scarb.rs b/src/scarb.rs index 25490c5f5..247b7f14c 100644 --- a/src/scarb.rs +++ b/src/scarb.rs @@ -1,11 +1,11 @@ -use std::{env::current_dir, fs, path::PathBuf}; - use anyhow::Context; use cairo_lang_runner::{RunResultValue, SierraCasmRunner, StarknetState}; use cairo_lang_sierra::program::VersionedProgram; use cairo_lang_test_plugin::TestCompilation; use cairo_lang_test_runner::{CompiledTestRunner, TestRunConfig}; use camino::Utf8PathBuf; +use console::style; +use std::{env::current_dir, fs, path::PathBuf}; use itertools::Itertools; use scarb::{ @@ -54,6 +54,12 @@ pub fn scarb_run(file_path: &PathBuf) -> anyhow::Result { // Compile before running tests, with test targets true compile(&config, false)?; + println!( + " {} {}\n", + style("Running").green().bold(), + file_path.to_str().unwrap() + ); + let metadata = collect_metadata( &MetadataOptions { version: 1, diff --git a/src/ui.rs b/src/ui.rs index 1ee463168..6f3f7663f 100755 --- a/src/ui.rs +++ b/src/ui.rs @@ -3,6 +3,7 @@ macro_rules! warn { use console::{style, Emoji}; use std::env; let formatstr = format!($fmt, $ex); + println!(); if env::var("NO_EMOJI").is_ok() { println!("{} {}", style("!").red(), style(formatstr).red()); } else { @@ -12,6 +13,7 @@ macro_rules! warn { style(formatstr).red() ); } + println!(); }}; } @@ -20,6 +22,7 @@ macro_rules! success { use console::{style, Emoji}; use std::env; let formatstr = format!($fmt, $ex); + println!(); if env::var("NO_EMOJI").is_ok() { println!("{} {}", style("✓").green(), style(formatstr).green()); } else { @@ -29,5 +32,25 @@ macro_rules! success { style(formatstr).green() ); } + println!(); + }}; +} + +macro_rules! progress { + ($fmt:literal, $ex:expr) => {{ + use console::{style, Emoji}; + use std::env; + let formatstr = format!($fmt, $ex); + println!(); + if env::var("NO_EMOJI").is_ok() { + println!("{} {}", style("○").yellow(), style(formatstr).yellow()); + } else { + println!( + "{} {}", + style(Emoji("🟡", "○")).yellow(), + style(formatstr).yellow() + ); + } + println!(); }}; } diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 000000000..f85bde9d3 --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,71 @@ +use console::style; + +use crate::exercise::{Exercise, Mode}; +// use crate::ui::progress; + +// Build the given Exercise and return an object with information +// about the state of the compilation +pub fn build_exercise(exercise: &Exercise) -> Result { + progress!("Building {} exercise...", exercise); + + let compilation_result = exercise.build(); + + if let Err(error) = compilation_result { + eprintln!("{error}"); + + warn!("Compiling of {} failed! Please try again.", exercise); + Err(()) + } else { + Ok(compilation_result.unwrap()) + } +} + +// Build the given Exercise and return an object with information +// about the state of the compilation +pub fn run_exercise(exercise: &Exercise) -> Result { + progress!("Running {} exercise...", exercise); + + let compilation_result = exercise.run(); + + if let Err(error) = compilation_result { + eprintln!("{error}"); + + warn!("Failed to run {}! Please try again.", exercise); + Err(()) + } else { + Ok(compilation_result.unwrap()) + } +} + +// Tests the given Exercise and return an object with information +// about the state of the tests +pub fn test_exercise(exercise: &Exercise) -> Result { + progress!("Testing {} exercise...", exercise); + + let compilation_result = exercise.test(); + + if let Some(error) = compilation_result.as_ref().err() { + warn!( + "Testing of {} failed! Please try again. Here's the output:", + exercise + ); + println!("{error}"); + Err(()) + } else { + Ok(compilation_result.unwrap()) + } +} + +pub fn print_exercise_output(exercise_output: String) { + if exercise_output.len() > 0 { + println!(" {} {exercise_output}", style("Output").green().bold()); + } +} + +pub fn print_exercise_success(exercise: &Exercise) { + match exercise.mode { + Mode::Build => success!("Successfully built {}!", exercise), + Mode::Run => success!("Successfully ran {}!", exercise), + Mode::Test => success!("Successfully tested {}!", exercise), + } +} diff --git a/src/verify.rs b/src/verify.rs index 82d0fddd0..c894e0c68 100755 --- a/src/verify.rs +++ b/src/verify.rs @@ -1,6 +1,7 @@ use crate::{ clear_screen, exercise::{Exercise, Mode, State}, + utils, }; use console::style; use indicatif::{ProgressBar, ProgressStyle}; @@ -25,12 +26,18 @@ pub fn verify<'a>( .progress_chars("#>-"), ); bar.set_position(num_done as u64); - let compile_result = match exercise.mode { - Mode::Build => build_interactively(exercise), - Mode::Run => compile_and_run_interactively(exercise), - Mode::Test => compile_and_test_interactively(exercise), + let exercise_result = { + let run_result = match exercise.mode { + Mode::Build => utils::build_exercise(exercise), + Mode::Run => utils::run_exercise(exercise), + Mode::Test => utils::test_exercise(exercise), + }; + match run_result { + Ok(run_state) => Ok(prompt_for_completion(exercise, Some(run_state))), + Err(_) => Err(()), + } }; - if !compile_result.unwrap_or(false) { + if !exercise_result.unwrap_or(false) { return Err(exercise); } let percentage = num_done as f32 / total as f32 * 100.0; @@ -40,93 +47,17 @@ pub fn verify<'a>( Ok(()) } -// Build the given Exercise -fn build_interactively(exercise: &Exercise) -> Result { - println!("Building {exercise} exercise..."); - - let run_state = build_cairo_sierra(exercise)?; - - Ok(prompt_for_completion(exercise, Some(run_state))) -} - -// Build the given Exercise -fn compile_and_run_interactively(exercise: &Exercise) -> Result { - println!("Running {exercise} exercise..."); - - let run_state = compile_and_run_cairo(exercise)?; - - Ok(prompt_for_completion(exercise, Some(run_state))) -} - -// Tests the given Exercise -fn compile_and_test_interactively(exercise: &Exercise) -> Result { - println!("Testing {exercise} exercise..."); - - let run_state = compile_and_test_cairo(exercise)?; - - Ok(prompt_for_completion(exercise, Some(run_state))) -} - -// Build the given Exercise and return an object with information -// about the state of the compilation -fn build_cairo_sierra(exercise: &Exercise) -> Result { - let compilation_result = exercise.build(); - - if let Err(error) = compilation_result { - eprintln!("{error}"); - - warn!("Compiling of {} failed! Please try again.", exercise); - Err(()) - } else { - Ok(compilation_result.unwrap()) - } -} - -// Build the given Exercise and return an object with information -// about the state of the compilation -fn compile_and_run_cairo(exercise: &Exercise) -> Result { - let compilation_result = exercise.run(); - - if let Err(error) = compilation_result { - eprintln!("{error}"); - - warn!("Failed to run {}! Please try again.", exercise); - Err(()) - } else { - Ok(compilation_result.unwrap()) - } -} - -// Tests the given Exercise and return an object with information -// about the state of the tests -fn compile_and_test_cairo(exercise: &Exercise) -> Result { - let compilation_result = exercise.test(); - - if let Some(error) = compilation_result.as_ref().err() { - warn!( - "Testing of {} failed! Please try again. Here's the output:", - exercise - ); - println!("{error}"); - Err(()) - } else { - Ok(compilation_result.unwrap()) - } -} - fn prompt_for_completion(exercise: &Exercise, prompt_output: Option) -> bool { let context = match exercise.state() { State::Done => return true, State::Pending(context) => context, }; - match exercise.mode { - Mode::Build => success!("Successfully built {}!", exercise), - Mode::Run => success!("Successfully ran {}!", exercise), - Mode::Test => success!("Successfully tested {}!", exercise), - // Mode::Clippy => success!("Successfully compiled {}!", exercise), + if let Some(output) = prompt_output { + utils::print_exercise_output(output); } + utils::print_exercise_success(exercise); let no_emoji = env::var("NO_EMOJI").is_ok(); let _clippy_success_msg = "The code is compiling, and Clippy is happy!"; @@ -138,7 +69,6 @@ fn prompt_for_completion(exercise: &Exercise, prompt_output: Option) -> // Mode::Clippy => clippy_success_msg, }; - println!(); if no_emoji { println!("~*~ {success_msg} ~*~") } else { @@ -146,16 +76,6 @@ fn prompt_for_completion(exercise: &Exercise, prompt_output: Option) -> } println!(); - if let Some(output) = prompt_output { - if output.len() > 0 { - println!("Output:"); - println!("{}", separator()); - println!("{output}"); - println!("{}", separator()); - println!(); - } - } - println!("You can keep working on this exercise,"); println!( "or jump into the next one by removing the {} comment:", @@ -179,7 +99,3 @@ fn prompt_for_completion(exercise: &Exercise, prompt_output: Option) -> false } - -fn separator() -> console::StyledObject<&'static str> { - style("====================").bold() -}