diff --git a/Cargo.toml b/Cargo.toml index a017fcc..e1e5cb4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,3 +43,4 @@ inquire = { git = "https://github.com/moritz-hoelting/rust-inquire.git", branch camino = "1.1.7" human-panic = "2.0.0" anyhow = "1.0.86" +pathdiff = "0.2.1" diff --git a/src/subcommands/build.rs b/src/subcommands/build.rs index f306c39..78f93bc 100644 --- a/src/subcommands/build.rs +++ b/src/subcommands/build.rs @@ -10,6 +10,7 @@ use crate::{ config::ProjectConfig, error::Error, terminal_output::{print_error, print_info, print_success, print_warning}, + util, }; use std::{ borrow::Cow, @@ -47,7 +48,7 @@ pub fn build(args: &BuildArgs) -> Result<()> { return Err(Error::FeatureNotEnabledError("zip".to_string()).into()); } - let path = args.path.as_path(); + let path = util::get_project_path(&args.path).unwrap_or(args.path.clone()); let dist_path = args .output .as_ref() @@ -56,12 +57,16 @@ pub fn build(args: &BuildArgs) -> Result<()> { let and_package_msg = if args.zip { " and packaging" } else { "" }; + let mut path_display = format!("{}", path.display()); + if path_display.is_empty() { + path_display.push('.'); + } + print_info(format!( - "Building{and_package_msg} project at {}", - path.absolutize()?.display() + "Building{and_package_msg} project at {path_display}" )); - let (project_config, toml_path) = get_pack_config(path)?; + let (project_config, toml_path) = get_pack_config(&path)?; let script_paths = get_script_paths( &toml_path @@ -198,6 +203,7 @@ fn _get_script_paths(path: &Path, prefix: &str) -> std::io::Result Result<(ProjectConfig, PathBuf)> { + let path = path.absolutize()?; let toml_path = if !path.exists() { print_error("The specified path does not exist."); return Err(Error::PathNotFoundError(path.to_path_buf()))?; diff --git a/src/subcommands/clean.rs b/src/subcommands/clean.rs index 5cd7cf2..9db7ab6 100644 --- a/src/subcommands/clean.rs +++ b/src/subcommands/clean.rs @@ -1,9 +1,12 @@ use std::{borrow::Cow, path::PathBuf}; use anyhow::Result; -use path_absolutize::Absolutize; +use path_absolutize::Absolutize as _; -use crate::terminal_output::{print_error, print_info, print_success}; +use crate::{ + terminal_output::{print_error, print_info, print_success}, + util, +}; #[derive(Debug, clap::Args, Clone)] pub struct CleanArgs { @@ -26,7 +29,7 @@ pub struct CleanArgs { pub fn clean(args: &CleanArgs) -> Result<()> { let verbose = args.verbose; - let path = args.path.as_path(); + let path = util::get_project_path(&args.path).unwrap_or(args.path.clone()); let dist_path = args .output .as_ref() @@ -35,7 +38,7 @@ pub fn clean(args: &CleanArgs) -> Result<()> { let mut delete_paths = Vec::new(); - let (project_config, _) = super::build::get_pack_config(path)?; + let (project_config, _) = super::build::get_pack_config(&path)?; if args.all { if args.force { @@ -50,7 +53,7 @@ pub fn clean(args: &CleanArgs) -> Result<()> { print_info(format!( "Cleaning project at {}", - path.absolutize_from(path)?.display() + path.absolutize_from(&path)?.display() )); for delete_path in delete_paths { diff --git a/src/subcommands/lang_debug.rs b/src/subcommands/lang_debug.rs index b8bd260..9f3584c 100644 --- a/src/subcommands/lang_debug.rs +++ b/src/subcommands/lang_debug.rs @@ -4,7 +4,7 @@ use anyhow::Result; use shulkerscript::base::FsProvider; use std::path::PathBuf; -use crate::config::PackConfig; +use crate::{config::PackConfig, util}; #[derive(Debug, clap::Args, Clone)] pub struct LangDebugArgs { @@ -49,7 +49,11 @@ pub fn lang_debug(args: &LangDebugArgs) -> Result<()> { } } DumpState::Datapack => { - let program_paths = super::build::get_script_paths(&args.path.join("src"))?; + let program_paths = super::build::get_script_paths( + &util::get_project_path(&args.path) + .unwrap_or(args.path.clone()) + .join("src"), + )?; let datapack = shulkerscript::transpile( &file_provider, PackConfig::DEFAULT_PACK_FORMAT, diff --git a/src/subcommands/watch.rs b/src/subcommands/watch.rs index f42977a..0b278ab 100644 --- a/src/subcommands/watch.rs +++ b/src/subcommands/watch.rs @@ -7,12 +7,14 @@ use std::{ }; use clap::Parser; +use colored::Colorize; use notify_debouncer_mini::{new_debouncer, notify::*, DebounceEventResult}; use crate::{ cli::Args, error::Result, terminal_output::{print_error, print_info, print_warning}, + util, }; #[derive(Debug, clap::Args, Clone)] @@ -57,7 +59,12 @@ pub struct WatchArgs { } pub fn watch(args: &WatchArgs) -> Result<()> { - print_info(format!("Watching project at {}", args.path.display())); + let path = util::get_project_path(&args.path).unwrap_or(args.path.clone()); + print_info(format!("Watching project at {}", path.display())); + print_info(format!( + "Press {} to stop watching", + "Ctrl-C".underline().blue() + )); let commands = args .execute @@ -78,9 +85,7 @@ pub fn watch(args: &WatchArgs) -> Result<()> { env::current_dir().ok() }; - if !args.no_inital - && (current_dir.is_none() || env::set_current_dir(args.path.as_path()).is_err()) - { + if !args.no_inital && (current_dir.is_none() || env::set_current_dir(&path).is_err()) { print_warning("Failed to change working directory to project path. Commands may not work."); } @@ -114,28 +119,25 @@ pub fn watch(args: &WatchArgs) -> Result<()> { env::set_current_dir(prev_cwd).expect("Failed to change working directory back"); } - let assets_path = super::build::get_pack_config(&args.path) + let assets_path = super::build::get_pack_config(&path) .ok() .and_then(|(conf, _)| conf.compiler.and_then(|c| c.assets)); let watcher = debouncer.watcher(); watcher - .watch(args.path.join("src").as_path(), RecursiveMode::Recursive) + .watch(path.join("src").as_path(), RecursiveMode::Recursive) .expect("Failed to watch project src"); watcher - .watch( - args.path.join("pack.png").as_path(), - RecursiveMode::NonRecursive, - ) + .watch(path.join("pack.png").as_path(), RecursiveMode::NonRecursive) .expect("Failed to watch project pack.png"); watcher .watch( - args.path.join("pack.toml").as_path(), + path.join("pack.toml").as_path(), RecursiveMode::NonRecursive, ) .expect("Failed to watch project pack.toml"); if let Some(assets_path) = assets_path { - let full_assets_path = args.path.join(assets_path); + let full_assets_path = path.join(assets_path); if full_assets_path.exists() { watcher .watch(full_assets_path.as_path(), RecursiveMode::Recursive) @@ -147,7 +149,7 @@ pub fn watch(args: &WatchArgs) -> Result<()> { for path in args.watch.iter() { if path.exists() { watcher - .watch(path.as_path(), RecursiveMode::Recursive) + .watch(path, RecursiveMode::Recursive) .expect("Failed to watch custom path"); } else { print_warning(format!( @@ -157,7 +159,7 @@ pub fn watch(args: &WatchArgs) -> Result<()> { } } - if env::set_current_dir(args.path.as_path()).is_err() { + if env::set_current_dir(path).is_err() { print_warning("Failed to change working directory to project path. Commands may not work."); } diff --git a/src/util.rs b/src/util.rs index cb00906..2d34c8c 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,8 +1,37 @@ -use std::collections::HashMap; +use std::{ + borrow::Cow, + collections::HashMap, + env, + path::{Path, PathBuf}, +}; use camino::Utf8PathBuf; use inquire::{autocompletion::Replacement, Autocomplete}; +use path_absolutize::Absolutize; + +pub fn get_project_path

(base_path: P) -> Option +where + P: AsRef, +{ + let base_path = base_path.as_ref(); + if base_path.is_absolute() { + Cow::Borrowed(base_path) + } else { + base_path.absolutize().ok()? + } + .ancestors() + .find(|p| p.join("pack.toml").exists()) + .map(|p| relativize(p).unwrap_or_else(|| p.to_path_buf())) +} + +pub fn relativize

(path: P) -> Option +where + P: AsRef, +{ + let cwd = env::current_dir().ok()?; + pathdiff::diff_paths(path, cwd) +} #[derive(Debug, Clone, Default, PartialEq, Eq)] pub struct PathAutocomplete {