Added an arg for listing untagged files and added amount of files tagged with certain tags

master
Wynd 2025-05-05 01:42:48 +03:00
parent fb7f87fbbe
commit f0b43360d8
2 changed files with 57 additions and 13 deletions

View File

@ -51,4 +51,7 @@ pub struct UntagArgs {
#[derive(Debug, Args, PartialEq, Eq)]
pub struct FilesArgs {
pub query: Option<String>,
#[arg(long, short, exclusive = true, default_value_t = false)]
pub all: bool,
}

View File

@ -1,12 +1,16 @@
use std::{
fs,
io::{self, Write},
path::PathBuf,
path::{self, PathBuf},
str::FromStr,
};
use anyhow::{Result, anyhow};
use rusqlite::{Connection, params, params_from_iter, types::Value};
use rusqlite::{Connection, params_from_iter, types::Value};
pub const TERM_RESET: &str = "\x1b[0m";
pub const TERM_BOLD: &str = "\x1b[1m";
use crate::{
cli::{self, FilesArgs, TagArgs, TagsArgs, UntagArgs},
@ -23,11 +27,19 @@ pub fn handle_files(args: FilesArgs) -> Result<()> {
let mut show_tags = true;
if let Some(query) = args.query {
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));
@ -36,17 +48,30 @@ pub fn handle_files(args: FilesArgs) -> Result<()> {
};
}
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 result: Vec<(String, String)> = stmt
let tagged_files: Vec<(String, String)> = stmt
.query_map([], |row| Ok((row.get(0)?, row.get(1)?)))?
.flatten()
.collect();
let mut w = io::stdout();
if !result.is_empty() {
for (file, tags) in result {
if !tagged_files.is_empty() {
if args.all {
writeln!(&mut w, "{TERM_BOLD}Tagged Files: {TERM_RESET}")?;
}
for (file, tags) in tagged_files {
// Remove already tagged files
if let Some(idx) = all_paths.iter().position(|v| *v == file) {
all_paths.swap_remove(idx);
}
if show_tags {
writeln!(&mut w, "{}: {}", file, tags)?;
} else {
@ -56,6 +81,15 @@ pub fn handle_files(args: FilesArgs) -> Result<()> {
} else {
writeln!(&mut w, "No files registered!")?;
}
if args.all && !all_paths.is_empty() {
writeln!(&mut w, "\n{TERM_BOLD}Untagged Files: {TERM_RESET}")?;
for path in all_paths {
let path_str = path;
writeln!(&mut w, "{}", path_str)?;
}
}
w.flush()?;
Ok(())
@ -86,7 +120,7 @@ pub fn handle_tags(args: TagsArgs) -> Result<()> {
let tags = list_tags(&conn)?;
if !tags.is_empty() {
for tag in tags {
writeln!(&mut w, "{}", tag)?;
writeln!(&mut w, "{} - {}", tag.0, tag.1)?;
}
} else {
writeln!(&mut w, "No tags registered!")?;
@ -108,13 +142,20 @@ fn rename_tag(conn: &Connection, old: String, new: String) -> Result<()> {
Ok(())
}
fn list_tags(conn: &Connection) -> Result<Vec<String>> {
let mut stmt = conn.prepare("SELECT name FROM tag")?;
let result = stmt.query_map([], |row| row.get(0))?.flatten();
fn list_tags(conn: &Connection) -> Result<Vec<(String, i32)>> {
let mut stmt = conn.prepare(
r#"SELECT name, COUNT() as count FROM tag
INNER JOIN file_tag ON file_tag.tag_id = tag.id
GROUP BY name
ORDER BY count DESC"#,
)?;
let result = stmt
.query_map([], |row| Ok((row.get(0)?, row.get(1)?)))?
.flatten();
let mut tags = Vec::new();
for name in result {
tags.push(name);
let mut tags: Vec<(String, i32)> = Vec::new();
for entry in result {
tags.push(entry);
}
Ok(tags)