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"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
|
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]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.3.0"
|
version = "1.3.0"
|
||||||
@ -569,6 +580,7 @@ version = "0.2.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
"atty",
|
||||||
"bytes",
|
"bytes",
|
||||||
"clap",
|
"clap",
|
||||||
"crossterm",
|
"crossterm",
|
||||||
@ -626,6 +638,15 @@ version = "0.5.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
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]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
version = "0.3.9"
|
version = "0.3.9"
|
||||||
@ -990,7 +1011,7 @@ version = "1.0.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec"
|
checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hermit-abi",
|
"hermit-abi 0.3.9",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"wasi",
|
"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"
|
ratatui = "0.28.1"
|
||||||
crossterm = { version = "0.28.0", features = ["event-stream"] }
|
crossterm = { version = "0.28.0", features = ["event-stream"] }
|
||||||
futures = "0.3.30"
|
futures = "0.3.30"
|
||||||
|
atty = "0.2.14"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
pretty_assertions = "1.4.0"
|
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 {
|
if clone {
|
||||||
let git_clone = self.app.git_clone();
|
let git_clone = self.app.git_clone();
|
||||||
|
|
||||||
let mut wrap_cmd =
|
if atty::is(atty::Stream::Stdout) && shell {
|
||||||
InlineCommand::new(format!("cloning: {}", repo.to_rel_path().display()));
|
let mut wrap_cmd =
|
||||||
let repo = repo.clone();
|
InlineCommand::new(format!("cloning: {}", repo.to_rel_path().display()));
|
||||||
wrap_cmd
|
let repo = repo.clone();
|
||||||
.execute(move || async move {
|
wrap_cmd
|
||||||
git_clone.clone_repo(&repo, force_refresh).await?;
|
.execute(move || async move {
|
||||||
|
git_clone.clone_repo(&repo, force_refresh).await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
|
} else {
|
||||||
|
eprintln!("cloning repository...");
|
||||||
|
git_clone.clone_repo(&repo, force_refresh).await?;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
tracing::info!("skipping clone for repo: {}", &repo.to_rel_path().display());
|
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 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 futures::{FutureExt, StreamExt};
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
crossterm,
|
crossterm,
|
||||||
@ -73,6 +80,8 @@ impl InlineCommand {
|
|||||||
|
|
||||||
drop(guard);
|
drop(guard);
|
||||||
|
|
||||||
|
println!();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,11 @@
|
|||||||
|
use std::io::stderr;
|
||||||
|
|
||||||
use app::App;
|
use app::App;
|
||||||
|
use crossterm::{
|
||||||
|
terminal::{enable_raw_mode, EnterAlternateScreen},
|
||||||
|
ExecutableCommand,
|
||||||
|
};
|
||||||
|
use ratatui::{prelude::CrosstermBackend, Terminal};
|
||||||
|
|
||||||
use crate::git_provider::Repository;
|
use crate::git_provider::Repository;
|
||||||
|
|
||||||
@ -15,8 +22,14 @@ impl Interactive {
|
|||||||
&mut self,
|
&mut self,
|
||||||
repositories: &[Repository],
|
repositories: &[Repository],
|
||||||
) -> anyhow::Result<Option<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);
|
let app_result = App::new(self.app, repositories).run(terminal);
|
||||||
|
|
||||||
ratatui::restore();
|
ratatui::restore();
|
||||||
|
|
||||||
app_result
|
app_result
|
||||||
@ -37,10 +50,11 @@ mod app {
|
|||||||
use ratatui::{
|
use ratatui::{
|
||||||
crossterm::event::{self, Event, KeyCode},
|
crossterm::event::{self, Event, KeyCode},
|
||||||
layout::{Constraint, Layout},
|
layout::{Constraint, Layout},
|
||||||
|
prelude::CrosstermBackend,
|
||||||
style::{Style, Stylize},
|
style::{Style, Stylize},
|
||||||
text::{Line, Span},
|
text::{Line, Span},
|
||||||
widgets::{ListItem, ListState, Paragraph, StatefulWidget},
|
widgets::{ListItem, ListState, Paragraph, StatefulWidget},
|
||||||
DefaultTerminal, Frame,
|
Frame, Terminal,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
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();
|
self.update_matched_repos();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
@ -99,14 +116,19 @@ mod app {
|
|||||||
self.update_matched_repos();
|
self.update_matched_repos();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
KeyCode::Esc => return Ok(None),
|
KeyCode::Esc => {
|
||||||
|
terminal.clear()?;
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
KeyCode::Enter => {
|
KeyCode::Enter => {
|
||||||
if let Some(selected) = self.list.selected() {
|
if let Some(selected) = self.list.selected() {
|
||||||
if let Some(repo) = self.matched_repos.get(selected).cloned() {
|
if let Some(repo) = self.matched_repos.get(selected).cloned() {
|
||||||
|
terminal.clear()?;
|
||||||
return Ok(Some(repo));
|
return Ok(Some(repo));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
terminal.clear()?;
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
KeyCode::Up => self.list.select_next(),
|
KeyCode::Up => self.list.select_next(),
|
||||||
|
@ -4,8 +4,7 @@ use std::path::PathBuf;
|
|||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use commands::root::RootCommand;
|
use commands::{root::RootCommand, shell::Shell};
|
||||||
use components::inline_command::InlineCommand;
|
|
||||||
use config::Config;
|
use config::Config;
|
||||||
use tracing::level_filters::LevelFilter;
|
use tracing::level_filters::LevelFilter;
|
||||||
use tracing_subscriber::EnvFilter;
|
use tracing_subscriber::EnvFilter;
|
||||||
@ -50,7 +49,7 @@ struct Command {
|
|||||||
|
|
||||||
#[derive(Subcommand)]
|
#[derive(Subcommand)]
|
||||||
enum Commands {
|
enum Commands {
|
||||||
Hello {},
|
Init(Shell),
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_CONFIG_PATH: &str = ".config/gitnow/gitnow.toml";
|
const DEFAULT_CONFIG_PATH: &str = ".config/gitnow/gitnow.toml";
|
||||||
@ -81,7 +80,7 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
tracing::debug!("Starting cli");
|
tracing::debug!("Starting cli");
|
||||||
|
|
||||||
match cli.command {
|
match cli.command {
|
||||||
Some(_) => todo!(),
|
Some(Commands::Init(mut shell)) => shell.execute().await?,
|
||||||
None => {
|
None => {
|
||||||
RootCommand::new(app)
|
RootCommand::new(app)
|
||||||
.execute(
|
.execute(
|
||||||
|
Loading…
Reference in New Issue
Block a user