refactor: Move project logic into single submodule

This commit is contained in:
Patrick Auernig 2025-01-06 19:22:21 +01:00
parent 4ea4644b90
commit 005b80fc58
5 changed files with 122 additions and 86 deletions

View File

@ -3,8 +3,8 @@ use std::path::{self, Path, PathBuf};
use anyhow::{ensure, Result};
use clap::Subcommand;
use crate::state::write_projects_file;
use crate::{dirs, Project, Projects};
use crate::dirs;
use crate::projects::{write_projects_file, Project, Projects};
#[derive(Debug, Clone, clap::ValueEnum)]
@ -81,13 +81,13 @@ where
let project = Project::from(path);
ensure!(
!projects.list.contains(&project),
!projects.list().contains(&project),
"Project path already registered"
);
projects.list.push(project);
projects.add(project);
write_projects_file(projects)?;
println!("Added {}", projects.list.last().unwrap().path().display());
println!("Added {}", projects.list().last().unwrap().path().display());
Ok(())
}
@ -101,23 +101,22 @@ where
let project = Project::from(path);
ensure!(
projects.list.contains(&project),
projects.list().contains(&project),
"Project path not in registry"
);
let idx =
projects.list.iter().enumerate().find_map(
|(idx, elem)| {
if elem == &project {
Some(idx)
} else {
None
}
},
);
let idx = projects.iter().enumerate().find_map(
|(idx, elem)| {
if elem == &project {
Some(idx)
} else {
None
}
},
);
if let Some(idx) = idx {
let proj = projects.list.remove(idx);
let proj = projects.remove(idx);
write_projects_file(projects)?;
println!("Removed {}", proj.path().display());
}
@ -127,8 +126,13 @@ where
fn list_projects(projects: &Projects) -> Result<()> {
for (idx, project) in projects.list.iter().enumerate() {
println!("{}: {} ({})", idx + 1, project.name(), project.path().display())
for (idx, project) in projects.iter().enumerate() {
println!(
"{}: {} ({})",
idx + 1,
project.name(),
project.path().display()
)
}
Ok(())

View File

@ -1,15 +1,13 @@
mod cli;
mod dirs;
mod state;
mod projects;
mod tui;
use std::path::PathBuf;
use anyhow::Result;
use clap::Parser;
use cli::Command;
use state::read_projects_file;
use projects::read_projects_file;
#[derive(Debug, Parser)]
@ -19,35 +17,6 @@ struct Args {
}
#[derive(Debug, Default, serde::Serialize, serde::Deserialize)]
struct Projects {
pub list: Vec<Project>,
}
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
struct Project {
path: PathBuf,
}
impl Project {
pub fn path(&self) -> &PathBuf {
&self.path
}
pub fn name(&self) -> String {
let name = self.path.file_name().unwrap();
name.to_string_lossy().to_string()
}
}
impl From<PathBuf> for Project {
fn from(path: PathBuf) -> Self {
Self { path }
}
}
fn main() -> Result<()> {
init_tracing()?;

View File

@ -1,9 +1,75 @@
mod v1;
use std::fs;
use std::io::Write;
use anyhow::Result;
pub use v1::Project;
use crate::{dirs, Project, Projects};
use crate::dirs;
#[derive(Debug, Default, serde::Serialize, serde::Deserialize)]
pub struct Projects {
list: Vec<Project>,
}
impl Projects {
pub fn iter(&self) -> std::slice::Iter<'_, Project> {
self.list.iter()
}
pub fn list(&self) -> &[Project] {
&self.list
}
pub fn remove(&mut self, idx: usize) -> Project {
self.list.remove(idx)
}
pub fn add(&mut self, project: Project) {
self.list.push(project);
}
}
impl<'a> IntoIterator for &'a Projects {
type IntoIter = std::slice::Iter<'a, Project>;
type Item = &'a Project;
fn into_iter(self) -> Self::IntoIter {
self.list.iter()
}
}
pub fn read_projects_file() -> Result<Projects> {
let projects_file = dirs::data_path().join("projects");
if !projects_file.exists() {
return Ok(Projects::default());
}
let file = std::fs::File::open(projects_file)?;
let projects = bincode::deserialize_from(file)?;
Ok(projects)
}
pub fn write_projects_file(projects: &Projects) -> Result<()> {
let projects_file = dirs::data_path().join("projects");
let file = fs::OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(projects_file)?;
bincode::serialize_into(file, projects)?;
Ok(())
}
pub fn clear_selected_project_file() -> Result<()> {
@ -29,31 +95,3 @@ pub fn write_selected_project_file(project: &Project) -> Result<()> {
Ok(())
}
pub fn write_projects_file(projects: &Projects) -> Result<()> {
let projects_file = dirs::data_path().join("projects");
let file = fs::OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(projects_file)?;
bincode::serialize_into(file, projects)?;
Ok(())
}
pub fn read_projects_file() -> Result<Projects> {
let projects_file = dirs::data_path().join("projects");
if !projects_file.exists() {
return Ok(Projects::default());
}
let file = std::fs::File::open(projects_file)?;
let projects = bincode::deserialize_from(file)?;
Ok(projects)
}

24
src/projects/v1.rs Normal file
View File

@ -0,0 +1,24 @@
use std::path::PathBuf;
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct Project {
path: PathBuf,
}
impl Project {
pub fn path(&self) -> &PathBuf {
&self.path
}
pub fn name(&self) -> String {
let name = self.path.file_name().unwrap();
name.to_string_lossy().to_string()
}
}
impl From<PathBuf> for Project {
fn from(path: PathBuf) -> Self {
Self { path }
}
}

View File

@ -11,8 +11,9 @@ use ratatui::Frame;
use tracing::trace;
use tui_input::{Input, InputRequest};
use crate::state::{clear_selected_project_file, write_selected_project_file};
use crate::{Project, Projects};
use crate::projects::{
clear_selected_project_file, write_selected_project_file, Project, Projects,
};
#[derive(Debug, Clone, PartialEq, Eq)]
@ -219,14 +220,14 @@ fn draw_status(state: &mut State, frame: &mut Frame, area: Rect) {
fn draw_list(state: &mut State, frame: &mut Frame, area: Rect) {
let search_value = state.search.value();
let projects = &state.projects.list;
let projects = &state.projects;
state.filtered_projects = if search_value.is_empty() {
projects.clone()
projects.list().to_vec()
} else {
let mut filtered = VecDeque::new();
for project in projects.iter() {
for project in projects {
match fuzzy_search(search_value, &project.name()) {
Some(indices) => {
trace!(?search_value, ?project, ?indices);