Moved the file listing logic into the lib

master
Wynd 2025-05-10 21:25:13 +03:00
parent 1e05be83bb
commit c323c64e28
2 changed files with 65 additions and 49 deletions

View File

@ -1,8 +1,6 @@
use std::{
fs,
io::{self, Write},
path::PathBuf,
str::FromStr,
};
use clap::Parser;
@ -35,59 +33,20 @@ fn main() -> anyhow::Result<()> {
fn handle_files(args: FilesArgs) -> Result<()> {
let conn = try_database()?;
let mut sql = r#"SELECT path, group_concat(name) as tags FROM file_tag
JOIN file ON file.id = file_tag.file_id
JOIN tag ON tag.id = file_tag.tag_id"#
.to_string();
let mut show_tags = true;
let mut paths: Vec<PathBuf> = vec![];
if args.all {
paths = fs::read_dir(".")?
.filter_map(|f| f.ok())
.filter(|f| f.metadata().is_ok() && f.metadata().unwrap().is_file())
.map(|f| f.path())
.collect();
} else if let Some(query) = args.query {
let path = PathBuf::from_str(&query).unwrap_or_default();
match path.exists() {
true => {
sql.push_str(&format!(" WHERE path IN ('{}')", query));
paths = vec![path];
}
false => {
sql.push_str(&format!(" WHERE tag.name LIKE '%{}%'", query));
show_tags = false;
}
};
}
let mut all_paths: Vec<String> = paths
.iter_mut()
.map(|f| f.to_string_lossy().replace("./", "").to_string())
.collect();
sql.push_str(" GROUP BY path");
let mut stmt = conn.prepare(&sql)?;
let tagged_files: Vec<(String, String)> = stmt
.query_map([], |row| Ok((row.get(0)?, row.get(1)?)))?
.flatten()
.collect();
let mut files = taggo::list_files(&conn, args.all, args.query)?;
let mut w = io::stdout();
if !tagged_files.is_empty() {
if !files.files.is_empty() {
if args.all {
writeln!(&mut w, "{TERM_BOLD}Tagged Files: {TERM_RESET}")?;
}
for (file, tags) in tagged_files {
for (file, tags) in files.files {
// Remove already tagged files
if let Some(idx) = all_paths.iter().position(|v| *v == file) {
all_paths.swap_remove(idx);
if let Some(idx) = files.paths.iter().position(|v| *v == file) {
files.paths.swap_remove(idx);
}
if show_tags {
if files.show_tags {
writeln!(&mut w, "{}: {}", file, tags)?;
} else {
writeln!(&mut w, "{}", file)?;
@ -97,9 +56,9 @@ fn handle_files(args: FilesArgs) -> Result<()> {
writeln!(&mut w, "No files registered!")?;
}
if args.all && !all_paths.is_empty() {
if args.all && !files.paths.is_empty() {
writeln!(&mut w, "\n{TERM_BOLD}Untagged Files: {TERM_RESET}")?;
for path in all_paths {
for path in files.paths {
let path_str = path;
writeln!(&mut w, "{}", path_str)?;
}

View File

@ -1,4 +1,6 @@
use std::fs;
use std::io::Write;
use std::str::FromStr;
use std::{io, path::PathBuf};
use anyhow::{Result, anyhow};
@ -6,6 +8,12 @@ use rusqlite::{Connection, OpenFlags, params_from_iter, types::Value};
const DB_PATH: &str = ".tags";
pub struct Files {
pub files: Vec<(String, String)>,
pub paths: Vec<String>,
pub show_tags: bool,
}
pub fn init_db() -> anyhow::Result<()> {
let conn = Connection::open(DB_PATH)?;
@ -250,3 +258,52 @@ pub fn untag_file(conn: &mut Connection, file: PathBuf, tags: Option<Vec<String>
Ok(())
}
pub fn list_files(conn: &Connection, all_files: bool, query: Option<String>) -> Result<Files> {
let mut sql = r#"SELECT path, group_concat(name) as tags FROM file_tag
JOIN file ON file.id = file_tag.file_id
JOIN tag ON tag.id = file_tag.tag_id"#
.to_string();
let mut show_tags = true;
let mut paths: Vec<PathBuf> = vec![];
if all_files {
paths = fs::read_dir(".")?
.filter_map(|f| f.ok())
.filter(|f| f.metadata().is_ok() && f.metadata().unwrap().is_file())
.map(|f| f.path())
.collect();
} else if let Some(query) = query {
let path = PathBuf::from_str(&query).unwrap_or_default();
match path.exists() {
true => {
sql.push_str(&format!(" WHERE path IN ('{}')", query));
paths = vec![path];
}
false => {
sql.push_str(&format!(" WHERE tag.name LIKE '%{}%'", query));
show_tags = false;
}
};
}
let paths: Vec<String> = paths
.iter_mut()
.map(|f| f.to_string_lossy().replace("./", "").to_string())
.collect();
sql.push_str(" GROUP BY path");
let mut stmt = conn.prepare(&sql)?;
let files: Vec<(String, String)> = stmt
.query_map([], |row| Ok((row.get(0)?, row.get(1)?)))?
.flatten()
.collect();
Ok(Files {
files,
paths,
show_tags,
})
}