feat: add errout for interactive for script support and atty for clean output
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
c9aacf0ecd
commit
f0f81f8a0b
23
Cargo.lock
generated
23
Cargo.lock
generated
@ -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",
|
||||
|
1
crates/gitnow/.gitignore
vendored
1
crates/gitnow/.gitignore
vendored
@ -1 +0,0 @@
|
||||
/target
|
@ -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"
|
||||
|
15
crates/gitnow/include/shell/zsh.sh
Normal file
15
crates/gitnow/include/shell/zsh.sh
Normal file
@ -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
|
||||
}
|
@ -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());
|
||||
}
|
||||
|
@ -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(())
|
||||
}
|
||||
}
|
12
crates/gitnow/src/commands/shell/zsh.rs
Normal file
12
crates/gitnow/src/commands/shell/zsh.rs
Normal file
@ -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(())
|
||||
}
|
||||
}
|
@ -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(())
|
||||
}
|
||||
|
||||
|
@ -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<Option<Repository>> {
|
||||
let terminal = ratatui::init();
|
||||
let backend = CrosstermBackend::new(std::io::stderr());
|
||||
let terminal = Terminal::new(backend)?;
|
||||
|
||||
enable_raw_mode()?;
|
||||
stderr().execute(EnterAlternateScreen)?;
|
||||
|
||||
let app_result = App::new(self.app, repositories).run(terminal);
|
||||
|
||||
ratatui::restore();
|
||||
|
||||
app_result
|
||||
@ -37,10 +50,11 @@ mod app {
|
||||
use ratatui::{
|
||||
crossterm::event::{self, Event, KeyCode},
|
||||
layout::{Constraint, Layout},
|
||||
prelude::CrosstermBackend,
|
||||
style::{Style, Stylize},
|
||||
text::{Line, Span},
|
||||
widgets::{ListItem, ListState, Paragraph, StatefulWidget},
|
||||
DefaultTerminal, Frame,
|
||||
Frame, Terminal,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
@ -81,7 +95,10 @@ mod app {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(mut self, mut terminal: DefaultTerminal) -> anyhow::Result<Option<Repository>> {
|
||||
pub fn run<T: std::io::Write>(
|
||||
mut self,
|
||||
mut terminal: Terminal<CrosstermBackend<T>>,
|
||||
) -> anyhow::Result<Option<Repository>> {
|
||||
self.update_matched_repos();
|
||||
|
||||
loop {
|
||||
@ -99,14 +116,19 @@ mod app {
|
||||
self.update_matched_repos();
|
||||
}
|
||||
}
|
||||
KeyCode::Esc => return Ok(None),
|
||||
KeyCode::Esc => {
|
||||
terminal.clear()?;
|
||||
return Ok(None);
|
||||
}
|
||||
KeyCode::Enter => {
|
||||
if let Some(selected) = self.list.selected() {
|
||||
if let Some(repo) = self.matched_repos.get(selected).cloned() {
|
||||
terminal.clear()?;
|
||||
return Ok(Some(repo));
|
||||
}
|
||||
}
|
||||
|
||||
terminal.clear()?;
|
||||
return Ok(None);
|
||||
}
|
||||
KeyCode::Up => self.list.select_next(),
|
||||
|
@ -4,8 +4,7 @@ use std::path::PathBuf;
|
||||
|
||||
use anyhow::Context;
|
||||
use clap::{Parser, Subcommand};
|
||||
use commands::root::RootCommand;
|
||||
use components::inline_command::InlineCommand;
|
||||
use commands::{root::RootCommand, shell::Shell};
|
||||
use config::Config;
|
||||
use tracing::level_filters::LevelFilter;
|
||||
use tracing_subscriber::EnvFilter;
|
||||
@ -50,7 +49,7 @@ struct Command {
|
||||
|
||||
#[derive(Subcommand)]
|
||||
enum Commands {
|
||||
Hello {},
|
||||
Init(Shell),
|
||||
}
|
||||
|
||||
const DEFAULT_CONFIG_PATH: &str = ".config/gitnow/gitnow.toml";
|
||||
@ -81,7 +80,7 @@ async fn main() -> anyhow::Result<()> {
|
||||
tracing::debug!("Starting cli");
|
||||
|
||||
match cli.command {
|
||||
Some(_) => todo!(),
|
||||
Some(Commands::Init(mut shell)) => shell.execute().await?,
|
||||
None => {
|
||||
RootCommand::new(app)
|
||||
.execute(
|
||||
|
Loading…
Reference in New Issue
Block a user