diff --git a/Cargo.lock b/Cargo.lock
index 42f7ac5..b53fd9f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -137,6 +137,17 @@ version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
+[[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+dependencies = [
+ "hermit-abi 0.1.19",
+ "libc",
+ "winapi",
+]
+
[[package]]
name = "autocfg"
version = "1.3.0"
@@ -569,6 +580,7 @@ version = "0.2.0"
dependencies = [
"anyhow",
"async-trait",
+ "atty",
"bytes",
"clap",
"crossterm",
@@ -626,6 +638,15 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+[[package]]
+name = "hermit-abi"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
+dependencies = [
+ "libc",
+]
+
[[package]]
name = "hermit-abi"
version = "0.3.9"
@@ -990,7 +1011,7 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec"
dependencies = [
- "hermit-abi",
+ "hermit-abi 0.3.9",
"libc",
"log",
"wasi",
diff --git a/crates/gitnow/.gitignore b/crates/gitnow/.gitignore
deleted file mode 100644
index ea8c4bf..0000000
--- a/crates/gitnow/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/target
diff --git a/crates/gitnow/Cargo.toml b/crates/gitnow/Cargo.toml
index 365239e..22fa600 100644
--- a/crates/gitnow/Cargo.toml
+++ b/crates/gitnow/Cargo.toml
@@ -28,6 +28,7 @@ nucleo-matcher = "0.3.1"
ratatui = "0.28.1"
crossterm = { version = "0.28.0", features = ["event-stream"] }
futures = "0.3.30"
+atty = "0.2.14"
[dev-dependencies]
pretty_assertions = "1.4.0"
diff --git a/crates/gitnow/include/shell/zsh.sh b/crates/gitnow/include/shell/zsh.sh
new file mode 100644
index 0000000..5db2478
--- /dev/null
+++ b/crates/gitnow/include/shell/zsh.sh
@@ -0,0 +1,15 @@
+function git-now {
+ choice=$(gitnow "$@")
+ if [[ $? -ne 0 ]]; then
+ return $?
+ fi
+
+ cd "$(echo "$choice" | tail --lines 1)"
+}
+
+function gn {
+ git-now "$@"
+ if [[ $? -ne 0 ]]; then
+ return $?
+ fi
+}
diff --git a/crates/gitnow/src/commands/root.rs b/crates/gitnow/src/commands/root.rs
index c39c844..f6531f0 100644
--- a/crates/gitnow/src/commands/root.rs
+++ b/crates/gitnow/src/commands/root.rs
@@ -88,16 +88,21 @@ impl RootCommand {
if clone {
let git_clone = self.app.git_clone();
- let mut wrap_cmd =
- InlineCommand::new(format!("cloning: {}", repo.to_rel_path().display()));
- let repo = repo.clone();
- wrap_cmd
- .execute(move || async move {
- git_clone.clone_repo(&repo, force_refresh).await?;
+ if atty::is(atty::Stream::Stdout) && shell {
+ let mut wrap_cmd =
+ InlineCommand::new(format!("cloning: {}", repo.to_rel_path().display()));
+ let repo = repo.clone();
+ wrap_cmd
+ .execute(move || async move {
+ git_clone.clone_repo(&repo, force_refresh).await?;
- Ok(())
- })
- .await?;
+ Ok(())
+ })
+ .await?;
+ } else {
+ eprintln!("cloning repository...");
+ git_clone.clone_repo(&repo, force_refresh).await?;
+ }
} else {
tracing::info!("skipping clone for repo: {}", &repo.to_rel_path().display());
}
diff --git a/crates/gitnow/src/commands/shell.rs b/crates/gitnow/src/commands/shell.rs
index e69de29..fcac32a 100644
--- a/crates/gitnow/src/commands/shell.rs
+++ b/crates/gitnow/src/commands/shell.rs
@@ -0,0 +1,33 @@
+use zsh::ZshShell;
+
+pub mod zsh;
+
+#[derive(clap::Parser)]
+pub struct Shell {
+ #[command(subcommand)]
+ shell: ShellSubcommands,
+}
+
+impl Shell {
+ pub async fn execute(&mut self) -> anyhow::Result<()> {
+ self.shell.execute().await?;
+
+ Ok(())
+ }
+}
+
+#[derive(clap::Subcommand)]
+pub enum ShellSubcommands {
+ #[command()]
+ Zsh(ZshShell),
+}
+
+impl ShellSubcommands {
+ pub async fn execute(&mut self) -> anyhow::Result<()> {
+ match self {
+ ShellSubcommands::Zsh(zsh) => zsh.execute().await?,
+ }
+
+ Ok(())
+ }
+}
diff --git a/crates/gitnow/src/commands/shell/zsh.rs b/crates/gitnow/src/commands/shell/zsh.rs
new file mode 100644
index 0000000..0c389e6
--- /dev/null
+++ b/crates/gitnow/src/commands/shell/zsh.rs
@@ -0,0 +1,12 @@
+#[derive(clap::Parser)]
+pub struct ZshShell {}
+
+const SCRIPT: &str = include_str!("../../../include/shell/zsh.sh");
+
+impl ZshShell {
+ pub async fn execute(&mut self) -> anyhow::Result<()> {
+ println!("{}", SCRIPT);
+
+ Ok(())
+ }
+}
diff --git a/crates/gitnow/src/components/inline_command.rs b/crates/gitnow/src/components/inline_command.rs
index 672e9ed..b090592 100644
--- a/crates/gitnow/src/components/inline_command.rs
+++ b/crates/gitnow/src/components/inline_command.rs
@@ -1,7 +1,14 @@
-use std::{io::Write, time::Duration};
+use std::{
+ io::{stderr, Write},
+ time::Duration,
+};
use anyhow::Context;
-use crossterm::event::{EventStream, KeyCode, KeyEventKind};
+use crossterm::{
+ event::{EventStream, KeyCode, KeyEventKind},
+ terminal::{enable_raw_mode, EnterAlternateScreen},
+ ExecutableCommand,
+};
use futures::{FutureExt, StreamExt};
use ratatui::{
crossterm,
@@ -73,6 +80,8 @@ impl InlineCommand {
drop(guard);
+ println!();
+
Ok(())
}
diff --git a/crates/gitnow/src/interactive.rs b/crates/gitnow/src/interactive.rs
index 304ce90..02f03a8 100644
--- a/crates/gitnow/src/interactive.rs
+++ b/crates/gitnow/src/interactive.rs
@@ -1,4 +1,11 @@
+use std::io::stderr;
+
use app::App;
+use crossterm::{
+ terminal::{enable_raw_mode, EnterAlternateScreen},
+ ExecutableCommand,
+};
+use ratatui::{prelude::CrosstermBackend, Terminal};
use crate::git_provider::Repository;
@@ -15,8 +22,14 @@ impl Interactive {
&mut self,
repositories: &[Repository],
) -> anyhow::Result