refactor: Add Command trait for all commands

First step to make command configs possible, instead of modifying all
functions when a new field is added
This commit is contained in:
Sahaj Jain 2024-11-09 23:15:14 +05:30
parent 2caeea364f
commit 16f9ee281a
5 changed files with 118 additions and 39 deletions

28
src/command/draft.rs Normal file
View file

@ -0,0 +1,28 @@
use std::io::Write;
use async_trait::async_trait;
use crate::{
error::LumenError,
git_entity::{git_diff::GitDiff, GitEntity},
provider::{AIProvider, LumenProvider},
};
use super::Command;
pub struct DraftCommand {
pub context: Option<String>,
}
#[async_trait]
impl Command for DraftCommand {
async fn execute(&self, provider: &LumenProvider) -> Result<(), LumenError> {
let result = provider
.draft(GitEntity::Diff(GitDiff::new(true)?), self.context.clone())
.await?;
print!("{result}");
std::io::stdout().flush()?;
Ok(())
}
}

28
src/command/explain.rs Normal file
View file

@ -0,0 +1,28 @@
use async_trait::async_trait;
use spinoff::{spinners, Color, Spinner};
use crate::{
error::LumenError,
git_entity::GitEntity,
provider::{AIProvider, LumenProvider},
};
use super::{Command, LumenCommand};
pub struct ExplainCommand {
pub git_entity: GitEntity,
}
#[async_trait]
impl Command for ExplainCommand {
async fn execute(&self, provider: &LumenProvider) -> Result<(), LumenError> {
LumenCommand::print_with_mdcat(self.git_entity.format_static_details())?;
let mut spinner = Spinner::new(spinners::Dots, "Generating Summary...", Color::Blue);
let result = provider.explain(self.git_entity.clone()).await?;
spinner.success("Done");
LumenCommand::print_with_mdcat(result)?;
Ok(())
}
}

20
src/command/list.rs Normal file
View file

@ -0,0 +1,20 @@
use async_trait::async_trait;
use crate::{
error::LumenError,
git_entity::{git_commit::GitCommit, GitEntity},
provider::LumenProvider,
};
use super::{explain::ExplainCommand, Command, LumenCommand};
pub struct ListCommand;
#[async_trait]
impl Command for ListCommand {
async fn execute(&self, provider: &LumenProvider) -> Result<(), LumenError> {
let sha = LumenCommand::get_sha_from_fzf()?;
let git_entity = GitEntity::Commit(GitCommit::new(sha)?);
ExplainCommand { git_entity }.execute(provider).await
}
}

View file

@ -1,14 +1,38 @@
use std::io::Write;
use async_trait::async_trait;
use draft::DraftCommand;
use explain::ExplainCommand;
use list::ListCommand;
use std::process::Stdio;
use crate::error::LumenError;
use crate::git_entity::git_commit::GitCommit;
use crate::git_entity::git_diff::GitDiff;
use crate::git_entity::GitEntity;
use crate::provider::AIProvider;
use crate::provider::LumenProvider;
use spinoff::{spinners, Color, Spinner};
mod draft;
mod explain;
mod list;
#[derive(Debug)]
pub enum CommandType {
Explain(GitEntity),
List,
Draft(Option<String>),
}
#[async_trait]
pub trait Command {
async fn execute(&self, provider: &LumenProvider) -> Result<(), LumenError>;
}
impl CommandType {
pub fn create_command(self) -> Box<dyn Command> {
match self {
CommandType::Explain(git_entity) => Box::new(ExplainCommand { git_entity }),
CommandType::List => Box::new(ListCommand),
CommandType::Draft(context) => Box::new(DraftCommand { context }),
}
}
}
pub struct LumenCommand {
provider: LumenProvider,
@ -19,6 +43,10 @@ impl LumenCommand {
LumenCommand { provider }
}
pub async fn execute(&self, command_type: CommandType) -> Result<(), LumenError> {
command_type.create_command().execute(&self.provider).await
}
fn get_sha_from_fzf() -> Result<String, LumenError> {
let command = "git log --color=always --format='%C(auto)%h%d %s %C(black)%C(bold)%cr' | fzf --ansi --reverse --bind='enter:become(echo {1})' --wrap";
@ -80,35 +108,4 @@ impl LumenCommand {
}
Ok(())
}
pub async fn explain(&self, git_entity: &GitEntity) -> Result<(), LumenError> {
Self::print_with_mdcat(git_entity.format_static_details())?;
let mut spinner = Spinner::new(spinners::Dots, "Generating Summary...", Color::Blue);
let result = self.provider.explain(git_entity.clone()).await?;
spinner.success("Done");
Self::print_with_mdcat(result)?;
Ok(())
}
pub async fn list(&self) -> Result<(), LumenError> {
let sha = Self::get_sha_from_fzf()?;
let git_entity = GitEntity::Commit(GitCommit::new(sha)?);
self.explain(&git_entity).await
}
pub async fn draft(&self, context: Option<String>) -> Result<(), LumenError> {
let result = self
.provider
.draft(GitEntity::Diff(GitDiff::new(true)?), context)
.await?;
// print without newline
print!("{result}");
std::io::stdout().flush()?;
Ok(())
}
}

View file

@ -90,10 +90,16 @@ async fn run() -> Result<(), LumenError> {
));
};
command.explain(&git_entity).await?
command
.execute(command::CommandType::Explain(git_entity))
.await?;
}
Commands::List => command.execute(command::CommandType::List).await?,
Commands::Draft { context } => {
command
.execute(command::CommandType::Draft(context))
.await?
}
Commands::List => command.list().await?,
Commands::Draft { context } => command.draft(context).await?,
}
Ok(())