Skip to content

Commit

Permalink
Error handling (#96)
Browse files Browse the repository at this point in the history
* Cleaner error handling with Result type alias

* Make clippy happy
  • Loading branch information
petersimonsson authored May 7, 2024
1 parent 56c0b1c commit fc95572
Show file tree
Hide file tree
Showing 8 changed files with 55 additions and 54 deletions.
36 changes: 16 additions & 20 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ use crate::{
repos::{find_repos, RepoContainer},
session_exists, set_up_tmux_env, switch_to_session,
tmux::Tmux,
TmsError,
Result, TmsError,
};
use clap::{Args, Parser, Subcommand};
use error_stack::{Result, ResultExt};
use error_stack::ResultExt;
use git2::{build::RepoBuilder, FetchOptions, RemoteCallbacks, Repository};

#[derive(Debug, Parser)]
Expand Down Expand Up @@ -115,7 +115,7 @@ pub struct CloneRepoCommand {
}

impl Cli {
pub fn handle_sub_commands(&self, tmux: &Tmux) -> Result<SubCommandGiven, TmsError> {
pub fn handle_sub_commands(&self, tmux: &Tmux) -> Result<SubCommandGiven> {
// Get the configuration from the config file
let config = Config::new().change_context(TmsError::ConfigError)?;

Expand Down Expand Up @@ -174,7 +174,7 @@ impl Cli {
}
}

fn start_command(config: Config, tmux: &Tmux) -> Result<(), TmsError> {
fn start_command(config: Config, tmux: &Tmux) -> Result<()> {
if let Some(sessions) = &config.sessions {
for session in sessions {
let session_path = session
Expand Down Expand Up @@ -212,7 +212,7 @@ fn start_command(config: Config, tmux: &Tmux) -> Result<(), TmsError> {
Ok(())
}

fn switch_command(config: Config, tmux: &Tmux) -> Result<(), TmsError> {
fn switch_command(config: Config, tmux: &Tmux) -> Result<()> {
let sessions = tmux
.list_sessions("'#{?session_attached,,#{session_name}#,#{session_last_attached}}'")
.replace('\'', "")
Expand All @@ -231,7 +231,7 @@ fn switch_command(config: Config, tmux: &Tmux) -> Result<(), TmsError> {
let mut sessions: Vec<String> = sessions.into_iter().map(|s| s.0.to_string()).collect();
if let Some(true) = config.switch_filter_unknown {
let repos = find_repos(
config.search_dirs()?,
config.search_dirs().change_context(TmsError::ConfigError)?,
config.excluded_dirs,
config.display_full_path,
config.search_submodules,
Expand All @@ -257,7 +257,7 @@ fn switch_command(config: Config, tmux: &Tmux) -> Result<(), TmsError> {
Ok(())
}

fn windows_command(config: Config, tmux: &Tmux) -> Result<(), TmsError> {
fn windows_command(config: Config, tmux: &Tmux) -> Result<()> {
let windows = tmux.list_windows("'#{?window_attached,,#{window_name}}'", None);

let windows: Vec<String> = windows
Expand All @@ -280,7 +280,7 @@ fn windows_command(config: Config, tmux: &Tmux) -> Result<(), TmsError> {
Ok(())
}

fn config_command(args: &ConfigCommand, mut config: Config) -> Result<(), TmsError> {
fn config_command(args: &ConfigCommand, mut config: Config) -> Result<()> {
let max_depths = args.max_depths.clone().unwrap_or_default();
config.search_dirs = match &args.search_paths {
Some(paths) => Some(
Expand All @@ -299,14 +299,14 @@ fn config_command(args: &ConfigCommand, mut config: Config) -> Result<(), TmsErr
.map(|val| (val.to_string(), depth))
.change_context(TmsError::IoError)
})
.collect::<Result<Vec<(String, usize)>, TmsError>>()?
.collect::<Result<Vec<(String, usize)>>>()?
.iter()
.map(|(path, depth)| {
canonicalize(path)
.map(|val| SearchDirectory::new(val, *depth))
.change_context(TmsError::IoError)
})
.collect::<Result<Vec<SearchDirectory>, TmsError>>()?,
.collect::<Result<Vec<SearchDirectory>>>()?,
),
None => config.search_dirs,
};
Expand Down Expand Up @@ -393,7 +393,7 @@ fn config_command(args: &ConfigCommand, mut config: Config) -> Result<(), TmsErr
Ok(())
}

fn kill_subcommand(config: Config, tmux: &Tmux) -> Result<(), TmsError> {
fn kill_subcommand(config: Config, tmux: &Tmux) -> Result<()> {
let mut current_session = tmux.display_message("'#S'");
current_session.retain(|x| x != '\'' && x != '\n');

Expand Down Expand Up @@ -430,7 +430,7 @@ fn kill_subcommand(config: Config, tmux: &Tmux) -> Result<(), TmsError> {
Ok(())
}

fn sessions_subcommand(tmux: &Tmux) -> Result<(), TmsError> {
fn sessions_subcommand(tmux: &Tmux) -> Result<()> {
let mut current_session = tmux.display_message("'#S'");
current_session.retain(|x| x != '\'' && x != '\n');
let current_session_star = format!("{current_session}*");
Expand Down Expand Up @@ -458,7 +458,7 @@ fn sessions_subcommand(tmux: &Tmux) -> Result<(), TmsError> {
Ok(())
}

fn rename_subcommand(args: &RenameCommand, tmux: &Tmux) -> Result<(), TmsError> {
fn rename_subcommand(args: &RenameCommand, tmux: &Tmux) -> Result<()> {
let new_session_name = &args.name;

let current_session = tmux.display_message("'#S'");
Expand Down Expand Up @@ -513,7 +513,7 @@ fn rename_subcommand(args: &RenameCommand, tmux: &Tmux) -> Result<(), TmsError>
Ok(())
}

fn refresh_command(args: &RefreshCommand, tmux: &Tmux) -> Result<(), TmsError> {
fn refresh_command(args: &RefreshCommand, tmux: &Tmux) -> Result<()> {
let session_name = args
.name
.clone()
Expand Down Expand Up @@ -569,11 +569,7 @@ fn refresh_command(args: &RefreshCommand, tmux: &Tmux) -> Result<(), TmsError> {
Ok(())
}

fn clone_repo_command(
args: &CloneRepoCommand,
config: Config,
tmux: &Tmux,
) -> Result<(), TmsError> {
fn clone_repo_command(args: &CloneRepoCommand, config: Config, tmux: &Tmux) -> Result<()> {
let search_dirs = config
.search_dirs
.ok_or(TmsError::ConfigError)
Expand Down Expand Up @@ -615,7 +611,7 @@ fn clone_repo_command(
Ok(())
}

fn git_clone(repo: &str, target: &Path) -> Result<Repository, TmsError> {
fn git_clone(repo: &str, target: &Path) -> Result<Repository> {
let mut callbacks = RemoteCallbacks::new();
callbacks.credentials(git_credentials_callback);
let mut fo = FetchOptions::new();
Expand Down
25 changes: 14 additions & 11 deletions src/configs.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
use clap::ValueEnum;
use error_stack::{Result, ResultExt};
use error_stack::ResultExt;
use serde_derive::{Deserialize, Serialize};
use std::{env, fmt::Display, fs::canonicalize, io::Write, path::PathBuf};

use ratatui::style::{Color, Style};

use crate::{keymap::Keymap, Suggestion, TmsError};
use crate::{keymap::Keymap, Suggestion};

type Result<T> = error_stack::Result<T, ConfigError>;

#[derive(Debug)]
pub enum ConfigError {
NoDefaultSearchPath,
LoadError,
TomlError,
FileWriteError,
IoError,
}

impl std::error::Error for ConfigError {}
Expand All @@ -24,6 +27,7 @@ impl Display for ConfigError {
Self::TomlError => write!(f, "Could not serialize config to TOML"),
Self::FileWriteError => write!(f, "Could not write to config file"),
Self::LoadError => write!(f, "Could not load configuration"),
Self::IoError => write!(f, "IO error"),
}
}
}
Expand All @@ -45,7 +49,7 @@ pub struct Config {
}

impl Config {
pub(crate) fn new() -> Result<Self, ConfigError> {
pub(crate) fn new() -> Result<Self> {
let config_builder = match env::var("TMS_CONFIG_FILE") {
Ok(path) => {
config::Config::builder().add_source(config::File::with_name(&path).required(false))
Expand Down Expand Up @@ -88,7 +92,7 @@ impl Config {
.attach_printable("Could not deserialize configuration")
}

pub(crate) fn save(&self) -> Result<(), ConfigError> {
pub(crate) fn save(&self) -> Result<()> {
let toml_pretty = toml::to_string_pretty(self)
.change_context(ConfigError::TomlError)?
.into_bytes();
Expand Down Expand Up @@ -127,18 +131,18 @@ impl Config {
Ok(())
}

pub fn search_dirs(&self) -> Result<Vec<SearchDirectory>, TmsError> {
pub fn search_dirs(&self) -> Result<Vec<SearchDirectory>> {
let mut search_dirs = if let Some(search_dirs) = self.search_dirs.as_ref() {
search_dirs
.iter()
.map(|search_dir| {
let expanded_path = shellexpand::full(&search_dir.path.to_string_lossy())
.change_context(TmsError::IoError)
.change_context(ConfigError::IoError)
.unwrap()
.to_string();

let path = canonicalize(expanded_path)
.change_context(TmsError::IoError)
.change_context(ConfigError::IoError)
.unwrap();

SearchDirectory::new(path, search_dir.depth)
Expand All @@ -155,11 +159,11 @@ impl Config {
SearchDirectory::new(
canonicalize(
shellexpand::full(&path)
.change_context(TmsError::IoError)
.change_context(ConfigError::IoError)
.unwrap()
.to_string(),
)
.change_context(TmsError::IoError)
.change_context(ConfigError::IoError)
.unwrap(),
10,
)
Expand All @@ -171,8 +175,7 @@ impl Config {
return Err(ConfigError::NoDefaultSearchPath)
.attach_printable(
"You must configure at least one default search path with the `config` subcommand. E.g `tms config` ",
)
.change_context(TmsError::ConfigError);
);
}

Ok(search_dirs)
Expand Down
12 changes: 6 additions & 6 deletions src/dirty_paths.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use error_stack::{Result, ResultExt};
use error_stack::ResultExt;

use crate::error::TmsError;
use crate::{Result, TmsError};

pub trait DirtyUtf8Path {
fn to_string(&self) -> Result<String, TmsError>;
fn to_string(&self) -> Result<String>;
}

impl DirtyUtf8Path for std::path::PathBuf {
fn to_string(&self) -> Result<String, TmsError> {
fn to_string(&self) -> Result<String> {
Ok(self
.to_str()
.ok_or(TmsError::NonUtf8Path)
Expand All @@ -16,7 +16,7 @@ impl DirtyUtf8Path for std::path::PathBuf {
}
}
impl DirtyUtf8Path for std::path::Path {
fn to_string(&self) -> Result<String, TmsError> {
fn to_string(&self) -> Result<String> {
Ok(self
.to_str()
.ok_or(TmsError::NonUtf8Path)
Expand All @@ -25,7 +25,7 @@ impl DirtyUtf8Path for std::path::Path {
}
}
impl DirtyUtf8Path for std::ffi::OsStr {
fn to_string(&self) -> Result<String, TmsError> {
fn to_string(&self) -> Result<String> {
Ok(self
.to_str()
.ok_or(TmsError::NonUtf8Path)
Expand Down
2 changes: 2 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::{error::Error, fmt::Display};

pub type Result<T> = error_stack::Result<T, TmsError>;

#[derive(Debug)]
pub enum TmsError {
GitError,
Expand Down
10 changes: 5 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ pub mod picker;
pub mod repos;
pub mod tmux;

use error_stack::{Result, ResultExt};
use error_stack::ResultExt;
use git2::Repository;
use std::{fmt::Display, process};

use crate::{
configs::PickerColorConfig,
dirty_paths::DirtyUtf8Path,
error::TmsError,
error::{Result, TmsError},
keymap::Keymap,
picker::{Picker, Preview},
tmux::Tmux,
Expand Down Expand Up @@ -43,7 +43,7 @@ pub fn session_exists(repo_short_name: &str, tmux: &Tmux) -> bool {
})
}

pub fn set_up_tmux_env(repo: &Repository, repo_name: &str, tmux: &Tmux) -> Result<(), TmsError> {
pub fn set_up_tmux_env(repo: &Repository, repo_name: &str, tmux: &Tmux) -> Result<()> {
if repo.is_bare() {
if repo
.worktrees()
Expand Down Expand Up @@ -104,10 +104,10 @@ pub fn get_single_selection(
colors: Option<PickerColorConfig>,
keymap: Option<Keymap>,
tmux: Tmux,
) -> Result<Option<String>, TmsError> {
) -> Result<Option<String>> {
let mut picker = Picker::new(list, preview, keymap, tmux).set_colors(colors);

Ok(picker.run()?)
picker.run()
}
#[derive(Debug)]
pub struct Suggestion(&'static str);
Expand Down
8 changes: 4 additions & 4 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use clap::Parser;
use error_stack::{Report, Result, ResultExt};
use error_stack::{Report, ResultExt};

use tms::{
cli::{Cli, SubCommandGiven},
dirty_paths::DirtyUtf8Path,
error::TmsError,
error::{Result, TmsError},
get_single_selection,
picker::Preview,
repos::find_repos,
Expand All @@ -14,7 +14,7 @@ use tms::{
Suggestion,
};

fn main() -> Result<(), TmsError> {
fn main() -> Result<()> {
// Install debug hooks for formatting of error handling
Report::install_debug_hook::<Suggestion>(|value, context| {
context.push_body(format!("{value}"));
Expand All @@ -34,7 +34,7 @@ fn main() -> Result<(), TmsError> {

// Find repositories and present them with the fuzzy finder
let repos = find_repos(
config.search_dirs()?,
config.search_dirs().change_context(TmsError::ConfigError)?,
config.excluded_dirs,
config.display_full_path,
config.search_submodules,
Expand Down
6 changes: 3 additions & 3 deletions src/picker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use crate::{
configs::PickerColorConfig,
keymap::{default_keymap, Keymap, PickerAction},
tmux::Tmux,
TmsError,
Result, TmsError,
};

pub enum Preview {
Expand Down Expand Up @@ -87,7 +87,7 @@ impl Picker {
self
}

pub fn run(&mut self) -> Result<Option<String>, TmsError> {
pub fn run(&mut self) -> Result<Option<String>> {
enable_raw_mode().map_err(|e| TmsError::TuiError(e.to_string()))?;
let mut stdout = io::stdout();
execute!(stdout, EnterAlternateScreen).map_err(|e| TmsError::TuiError(e.to_string()))?;
Expand All @@ -111,7 +111,7 @@ impl Picker {
fn main_loop(
&mut self,
terminal: &mut Terminal<CrosstermBackend<Stdout>>,
) -> Result<Option<String>, TmsError> {
) -> Result<Option<String>> {
loop {
terminal
.draw(|f| self.render(f))
Expand Down
Loading

0 comments on commit fc95572

Please sign in to comment.