Document filter and modification syntax

This commit is contained in:
Dustin J. Mitchell 2020-12-24 17:04:51 +00:00
parent 9c94a7b753
commit 8c9e240e97
5 changed files with 141 additions and 2 deletions

View file

@ -1,6 +1,8 @@
use super::args::{arg_matching, id_list, minus_tag, plus_tag, TaskId}; use super::args::{arg_matching, id_list, minus_tag, plus_tag, TaskId};
use super::ArgList; use super::ArgList;
use crate::usage;
use nom::{branch::alt, combinator::*, multi::fold_many0, IResult}; use nom::{branch::alt, combinator::*, multi::fold_many0, IResult};
use textwrap::dedent;
/// A filter represents a selection of a particular set of tasks. /// A filter represents a selection of a particular set of tasks.
/// ///
@ -110,6 +112,36 @@ impl Filter {
} }
map_res(arg_matching(minus_tag), to_filterarg)(input) map_res(arg_matching(minus_tag), to_filterarg)(input)
} }
pub(super) fn get_usage(u: &mut usage::Usage) {
u.filters.push(usage::Filter {
syntax: "TASKID[,TASKID,..]".to_owned(),
summary: "Specific tasks".to_owned(),
description: dedent(
"
Select only specific tasks. Multiple tasks can be specified either separated by
commas or as separate arguments. Each task may be specfied by its working-set
index (a small number) or by its UUID. Prefixes of UUIDs broken at hyphens are
also supported, such as `b5664ef8-423d` or `b5664ef8`.",
),
});
u.filters.push(usage::Filter {
syntax: "+TAG".to_owned(),
summary: "Tagged tasks".to_owned(),
description: dedent(
"
Select tasks with the given tag.",
),
});
u.filters.push(usage::Filter {
syntax: "-TAG".to_owned(),
summary: "Un-tagged tasks".to_owned(),
description: dedent(
"
Select tasks that do not have the given tag.",
),
});
}
} }
#[cfg(test)] #[cfg(test)]

View file

@ -31,4 +31,6 @@ type ArgList<'a> = &'a [&'a str];
pub(crate) fn get_usage(usage: &mut Usage) { pub(crate) fn get_usage(usage: &mut Usage) {
Subcommand::get_usage(usage); Subcommand::get_usage(usage);
Filter::get_usage(usage);
Modification::get_usage(usage);
} }

View file

@ -1,8 +1,10 @@
use super::args::{any, arg_matching, minus_tag, plus_tag}; use super::args::{any, arg_matching, minus_tag, plus_tag};
use super::ArgList; use super::ArgList;
use crate::usage;
use nom::{branch::alt, combinator::*, multi::fold_many0, IResult}; use nom::{branch::alt, combinator::*, multi::fold_many0, IResult};
use std::collections::HashSet; use std::collections::HashSet;
use taskchampion::Status; use taskchampion::Status;
use textwrap::dedent;
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub enum DescriptionMod { pub enum DescriptionMod {
@ -107,6 +109,34 @@ impl Modification {
} }
map_res(arg_matching(minus_tag), to_modarg)(input) map_res(arg_matching(minus_tag), to_modarg)(input)
} }
pub(super) fn get_usage(u: &mut usage::Usage) {
u.modifications.push(usage::Modification {
syntax: "DESCRIPTION".to_owned(),
summary: "Set description".to_owned(),
description: dedent(
"
Set the task description. Multiple arguments are combined into a single
space-separated description.",
),
});
u.modifications.push(usage::Modification {
syntax: "+TAG".to_owned(),
summary: "Tag task".to_owned(),
description: dedent(
"
Add the given tag to the task.",
),
});
u.modifications.push(usage::Modification {
syntax: "-TAG".to_owned(),
summary: "Un-tag task".to_owned(),
description: dedent(
"
Remove the given tag from the task.",
),
});
}
} }
#[cfg(test)] #[cfg(test)]

View file

@ -243,7 +243,7 @@ impl Modify {
}); });
u.subcommands.push(usage::Subcommand { u.subcommands.push(usage::Subcommand {
name: "stop".to_owned(), name: "stop".to_owned(),
syntax: "[filter] start [modification]".to_owned(), syntax: "[filter] stop [modification]".to_owned(),
summary: "Stop tasks".to_owned(), summary: "Stop tasks".to_owned(),
description: dedent( description: dedent(
" "
@ -252,7 +252,7 @@ impl Modify {
}); });
u.subcommands.push(usage::Subcommand { u.subcommands.push(usage::Subcommand {
name: "done".to_owned(), name: "done".to_owned(),
syntax: "[filter] start [modification]".to_owned(), syntax: "[filter] done [modification]".to_owned(),
summary: "Mark tasks as completed".to_owned(), summary: "Mark tasks as completed".to_owned(),
description: dedent( description: dedent(
" "

View file

@ -9,6 +9,8 @@ use textwrap::indent;
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub(crate) struct Usage { pub(crate) struct Usage {
pub(crate) subcommands: Vec<Subcommand>, pub(crate) subcommands: Vec<Subcommand>,
pub(crate) filters: Vec<Filter>,
pub(crate) modifications: Vec<Modification>,
} }
impl Usage { impl Usage {
@ -43,6 +45,18 @@ impl Usage {
for subcommand in self.subcommands.iter() { for subcommand in self.subcommands.iter() {
subcommand.write_help(&mut w, summary)?; subcommand.write_help(&mut w, summary)?;
} }
write!(w, "Filter Expressions:\n\n")?;
write!(w, "Where [filter] appears above, zero or more of the following arguments can be used to limit\n")?;
write!(w, "the tasks concerned.\n\n")?;
for filter in self.filters.iter() {
filter.write_help(&mut w, summary)?;
}
write!(w, "Modifications:\n\n")?;
write!(w, "Where [modification] appears above, zero or more of the following arguments can be used\n")?;
write!(w, "to modify the selected tasks.\n\n")?;
for modification in self.modifications.iter() {
modification.write_help(&mut w, summary)?;
}
if !summary { if !summary {
write!(w, "\nSee `task help` for more detail\n")?; write!(w, "\nSee `task help` for more detail\n")?;
} }
@ -50,6 +64,7 @@ impl Usage {
} }
} }
/// Usage documentation for a subcommand
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub(crate) struct Subcommand { pub(crate) struct Subcommand {
/// Name of the subcommand /// Name of the subcommand
@ -81,3 +96,63 @@ impl Subcommand {
Ok(()) Ok(())
} }
} }
/// Usage documentation for a filter argument
#[derive(Debug, Default)]
pub(crate) struct Filter {
/// Syntax summary
pub(crate) syntax: String,
/// One-line description of the filter. Use all-caps words for placeholders.
pub(crate) summary: String,
/// Multi-line description of the filter. It's OK for this to duplicate summary, as the
/// two are not displayed together.
pub(crate) description: String,
}
impl Filter {
fn write_help<W: Write>(&self, mut w: W, summary: bool) -> Result<()> {
if summary {
write!(w, " {} - {}\n", self.syntax, self.summary)?;
} else {
write!(
w,
" {}\n{}\n",
self.syntax,
indent(self.description.trim(), " ")
)?;
}
Ok(())
}
}
/// Usage documentation for a modification argument
#[derive(Debug, Default)]
pub(crate) struct Modification {
/// Syntax summary
pub(crate) syntax: String,
/// One-line description of the modification. Use all-caps words for placeholders.
pub(crate) summary: String,
/// Multi-line description of the modification. It's OK for this to duplicate summary, as the
/// two are not displayed together.
pub(crate) description: String,
}
impl Modification {
fn write_help<W: Write>(&self, mut w: W, summary: bool) -> Result<()> {
if summary {
write!(w, " {} - {}\n", self.syntax, self.summary)?;
} else {
write!(
w,
" {}\n{}\n",
self.syntax,
indent(self.description.trim(), " ")
)?;
}
Ok(())
}
}