Compare commits
11 commits
c0e0618ec0
...
1b87de72d6
| Author | SHA1 | Date | |
|---|---|---|---|
| 1b87de72d6 | |||
| 30bac14577 | |||
| 6c791ef3c2 | |||
| 9aa0567d13 | |||
| 80b842baaf | |||
| 316ca3a901 | |||
| 37b7eb341f | |||
| a2c7ce34a3 | |||
| be362517fb | |||
| 431c67d43d | |||
| 7d9284bf91 |
3 changed files with 55 additions and 8 deletions
|
|
@ -23,7 +23,11 @@ struct Args {
|
||||||
#[derive(clap::Subcommand, Debug)]
|
#[derive(clap::Subcommand, Debug)]
|
||||||
enum Commands {
|
enum Commands {
|
||||||
/// List issues.
|
/// List issues.
|
||||||
List,
|
List {
|
||||||
|
/// Filter string, describes issues to include in the list.
|
||||||
|
#[arg(default_value_t = String::from("state=New,Backlog,Blocked,InProgress"))]
|
||||||
|
filter: String,
|
||||||
|
},
|
||||||
|
|
||||||
/// Create a new issue.
|
/// Create a new issue.
|
||||||
New { description: Option<String> },
|
New { description: Option<String> },
|
||||||
|
|
@ -64,19 +68,21 @@ enum Commands {
|
||||||
|
|
||||||
fn handle_command(args: &Args, issues_dir: &std::path::Path) -> anyhow::Result<()> {
|
fn handle_command(args: &Args, issues_dir: &std::path::Path) -> anyhow::Result<()> {
|
||||||
match &args.command {
|
match &args.command {
|
||||||
Commands::List => {
|
Commands::List { filter } => {
|
||||||
let issues =
|
let issues =
|
||||||
entomologist::issues::Issues::new_from_dir(std::path::Path::new(issues_dir))?;
|
entomologist::issues::Issues::new_from_dir(std::path::Path::new(issues_dir))?;
|
||||||
|
let filter = entomologist::parse_filter(filter)?;
|
||||||
let mut uuids_by_state = std::collections::HashMap::<
|
let mut uuids_by_state = std::collections::HashMap::<
|
||||||
entomologist::issue::State,
|
entomologist::issue::State,
|
||||||
Vec<&entomologist::issue::IssueHandle>,
|
Vec<&entomologist::issue::IssueHandle>,
|
||||||
>::new();
|
>::new();
|
||||||
for (uuid, issue) in issues.issues.iter() {
|
for (uuid, issue) in issues.issues.iter() {
|
||||||
uuids_by_state
|
if filter.include_states.contains(&issue.state) {
|
||||||
.entry(issue.state.clone())
|
uuids_by_state
|
||||||
.or_default()
|
.entry(issue.state.clone())
|
||||||
.push(uuid);
|
.or_default()
|
||||||
|
.push(uuid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use entomologist::issue::State;
|
use entomologist::issue::State;
|
||||||
|
|
@ -89,6 +95,9 @@ fn handle_command(args: &Args, issues_dir: &std::path::Path) -> anyhow::Result<(
|
||||||
State::WontDo,
|
State::WontDo,
|
||||||
] {
|
] {
|
||||||
let these_uuids = uuids_by_state.entry(state.clone()).or_default();
|
let these_uuids = uuids_by_state.entry(state.clone()).or_default();
|
||||||
|
if these_uuids.len() == 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
these_uuids.sort_by(|a_id, b_id| {
|
these_uuids.sort_by(|a_id, b_id| {
|
||||||
let a = issues.issues.get(*a_id).unwrap();
|
let a = issues.issues.get(*a_id).unwrap();
|
||||||
let b = issues.issues.get(*b_id).unwrap();
|
let b = issues.issues.get(*b_id).unwrap();
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,8 @@ pub enum IssueError {
|
||||||
CommentError(#[from] crate::comment::CommentError),
|
CommentError(#[from] crate::comment::CommentError),
|
||||||
#[error("Failed to parse issue")]
|
#[error("Failed to parse issue")]
|
||||||
IssueParseError,
|
IssueParseError,
|
||||||
|
#[error("Failed to parse state")]
|
||||||
|
StateParseError,
|
||||||
#[error("Failed to run git")]
|
#[error("Failed to run git")]
|
||||||
GitError(#[from] crate::git::GitError),
|
GitError(#[from] crate::git::GitError),
|
||||||
#[error("Failed to run editor")]
|
#[error("Failed to run editor")]
|
||||||
|
|
@ -64,7 +66,7 @@ impl FromStr for State {
|
||||||
} else if s == "wontdo" {
|
} else if s == "wontdo" {
|
||||||
Ok(State::WontDo)
|
Ok(State::WontDo)
|
||||||
} else {
|
} else {
|
||||||
Err(IssueError::IssueParseError)
|
Err(IssueError::StateParseError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
36
src/lib.rs
36
src/lib.rs
|
|
@ -1,4 +1,40 @@
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
pub mod comment;
|
pub mod comment;
|
||||||
pub mod git;
|
pub mod git;
|
||||||
pub mod issue;
|
pub mod issue;
|
||||||
pub mod issues;
|
pub mod issues;
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum ParseFilterError {
|
||||||
|
#[error("Failed to parse filter")]
|
||||||
|
ParseError,
|
||||||
|
#[error(transparent)]
|
||||||
|
IssueParseError(#[from] crate::issue::IssueError),
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: It's easy to imagine a full dsl for filtering issues, for now
|
||||||
|
// i'm starting with obvious easy things. Chumsky looks appealing but
|
||||||
|
// more research is needed.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Filter {
|
||||||
|
pub include_states: std::collections::HashSet<crate::issue::State>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parses a filter description matching "state=STATE[,STATE*]"
|
||||||
|
pub fn parse_filter(filter_str: &str) -> Result<Filter, ParseFilterError> {
|
||||||
|
let tokens: Vec<&str> = filter_str.split("=").collect();
|
||||||
|
if tokens.len() != 2 {
|
||||||
|
return Err(ParseFilterError::ParseError);
|
||||||
|
}
|
||||||
|
if tokens[0] != "state" {
|
||||||
|
return Err(ParseFilterError::ParseError);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut include_states = std::collections::HashSet::<crate::issue::State>::new();
|
||||||
|
for s in tokens[1].split(",") {
|
||||||
|
include_states.insert(crate::issue::State::from_str(s)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Filter { include_states })
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue