mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-07-07 20:06:36 +02:00
Merge pull request #236 from taskchampion/issue140
Generate usage documentation
This commit is contained in:
commit
adfde8be15
21 changed files with 1177 additions and 55 deletions
20
.github/workflows/publish-docs.yml
vendored
20
.github/workflows/publish-docs.yml
vendored
|
@ -17,6 +17,26 @@ jobs:
|
||||||
with:
|
with:
|
||||||
mdbook-version: 'latest'
|
mdbook-version: 'latest'
|
||||||
|
|
||||||
|
- name: Cache cargo registry
|
||||||
|
uses: actions/cache@v1
|
||||||
|
with:
|
||||||
|
path: ~/.cargo/registry
|
||||||
|
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
|
||||||
|
|
||||||
|
- name: Cache cargo build
|
||||||
|
uses: actions/cache@v1
|
||||||
|
with:
|
||||||
|
path: target
|
||||||
|
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}
|
||||||
|
|
||||||
|
- uses: actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
toolchain: stable
|
||||||
|
override: true
|
||||||
|
|
||||||
|
- name: Create usage-docs plugin
|
||||||
|
run: cargo build -p taskchampion-cli --features usage-docs --bin usage-docs
|
||||||
|
|
||||||
- run: mdbook build docs
|
- run: mdbook build docs
|
||||||
|
|
||||||
- name: Deploy
|
- name: Deploy
|
||||||
|
|
20
.github/workflows/rust-tests.yml
vendored
20
.github/workflows/rust-tests.yml
vendored
|
@ -75,5 +75,25 @@ jobs:
|
||||||
with:
|
with:
|
||||||
mdbook-version: 'latest'
|
mdbook-version: 'latest'
|
||||||
|
|
||||||
|
- name: Cache cargo registry
|
||||||
|
uses: actions/cache@v1
|
||||||
|
with:
|
||||||
|
path: ~/.cargo/registry
|
||||||
|
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
|
||||||
|
|
||||||
|
- name: Cache cargo build
|
||||||
|
uses: actions/cache@v1
|
||||||
|
with:
|
||||||
|
path: target
|
||||||
|
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}
|
||||||
|
|
||||||
|
- uses: actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
toolchain: stable
|
||||||
|
override: true
|
||||||
|
|
||||||
|
- name: Create usage-docs plugin
|
||||||
|
run: cargo build -p taskchampion-cli --features usage-docs --bin usage-docs
|
||||||
|
|
||||||
- run: mdbook test docs
|
- run: mdbook test docs
|
||||||
- run: mdbook build docs
|
- run: mdbook build docs
|
||||||
|
|
844
Cargo.lock
generated
844
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -33,3 +33,8 @@ There are three crates here:
|
||||||
* [taskchampion-cli](./cli) - the command-line binary
|
* [taskchampion-cli](./cli) - the command-line binary
|
||||||
* [taskchampion-sync-server](./sync-server) - the server against which `task sync` operates
|
* [taskchampion-sync-server](./sync-server) - the server against which `task sync` operates
|
||||||
|
|
||||||
|
## Documentation Generation
|
||||||
|
|
||||||
|
The `mdbook` configuration contains a "preprocessor" implemented in the `taskchampion-cli` crate in order to reflect CLI usage information into the generated book.
|
||||||
|
Tihs preprocessor is not built by default.
|
||||||
|
To (re)build it, run `cargo build -p taskchampion-cli --features usage-docs --bin usage-docs`.
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
1. Run `git tag vX.Y.Z`
|
1. Run `git tag vX.Y.Z`
|
||||||
1. Run `git push upstream`
|
1. Run `git push upstream`
|
||||||
1. Run `git push --tags upstream`
|
1. Run `git push --tags upstream`
|
||||||
1. Run `( cd docs; ./build.sh )`
|
1. Run `( ./build-docs.sh )`
|
||||||
1. Run `(cd taskchampion; cargo publish)` (note that the other crates do not get published)
|
1. Run `(cd taskchampion; cargo publish)` (note that the other crates do not get published)
|
||||||
1. Navigate to the tag in the GitHub releases UI and create a release with general comments about the changes in the release
|
1. Navigate to the tag in the GitHub releases UI and create a release with general comments about the changes in the release
|
||||||
1. Upload `./target/release/task` and `./target/release/task-sync-server` to the release
|
1. Upload `./target/release/task` and `./target/release/task-sync-server` to the release
|
||||||
|
|
31
build-docs.sh
Executable file
31
build-docs.sh
Executable file
|
@ -0,0 +1,31 @@
|
||||||
|
#! /bin/bash
|
||||||
|
|
||||||
|
REMOTE=origin
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if ! [ -f "docs/src/SUMMARY.md" ]; then
|
||||||
|
echo "Run this from the root of the repo"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# build the latest version of the mdbook plugin
|
||||||
|
cargo build -p taskchampion-cli --features usage-docs --bin usage-docs
|
||||||
|
|
||||||
|
# create a worktree of this repo, with the `gh-pages` branch checked out
|
||||||
|
if ! [ -d ./docs/tmp ]; then
|
||||||
|
git worktree add docs/tmp gh-pages
|
||||||
|
fi
|
||||||
|
|
||||||
|
# update the wortree
|
||||||
|
(cd docs/tmp && git pull $REMOTE gh-pages)
|
||||||
|
|
||||||
|
# remove all files in the worktree and regenerate the book there
|
||||||
|
rm -rf docs/tmp/*
|
||||||
|
mdbook build docs
|
||||||
|
cp -rp docs/book/* docs/tmp
|
||||||
|
|
||||||
|
# add everything in the worktree, commit, and push
|
||||||
|
(cd docs/tmp && git add -A)
|
||||||
|
(cd docs/tmp && git commit -am "update docs")
|
||||||
|
(cd docs/tmp && git push $REMOTE gh-pages:gh-pages)
|
|
@ -23,6 +23,10 @@ atty = "^0.2.14"
|
||||||
toml = "^0.5.8"
|
toml = "^0.5.8"
|
||||||
toml_edit = "^0.2.0"
|
toml_edit = "^0.2.0"
|
||||||
|
|
||||||
|
# only needed for usage-docs
|
||||||
|
mdbook = { version = "0.4", optional = true }
|
||||||
|
serde_json = { version = "*", optional = true }
|
||||||
|
|
||||||
[dependencies.taskchampion]
|
[dependencies.taskchampion]
|
||||||
path = "../taskchampion"
|
path = "../taskchampion"
|
||||||
|
|
||||||
|
@ -30,3 +34,14 @@ path = "../taskchampion"
|
||||||
assert_cmd = "^1.0.3"
|
assert_cmd = "^1.0.3"
|
||||||
predicates = "^1.0.7"
|
predicates = "^1.0.7"
|
||||||
tempfile = "3"
|
tempfile = "3"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
usage-docs = [ "mdbook", "serde_json" ]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "ta"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
# this is an mdbook plugin and only needed when running `mdbook`
|
||||||
|
name = "usage-docs"
|
||||||
|
required-features = [ "usage-docs" ]
|
||||||
|
|
|
@ -115,7 +115,9 @@ impl Modification {
|
||||||
summary: "Set description",
|
summary: "Set description",
|
||||||
description: "
|
description: "
|
||||||
Set the task description. Multiple arguments are combined into a single
|
Set the task description. Multiple arguments are combined into a single
|
||||||
space-separated description.",
|
space-separated description. To avoid surprises from shell quoting, prefer
|
||||||
|
to use a single quoted argument, for example `ta 19 modify \"return library
|
||||||
|
books\"`",
|
||||||
});
|
});
|
||||||
u.modifications.push(usage::Modification {
|
u.modifications.push(usage::Modification {
|
||||||
syntax: "+TAG",
|
syntax: "+TAG",
|
||||||
|
|
50
cli/src/bin/usage-docs.rs
Normal file
50
cli/src/bin/usage-docs.rs
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
use mdbook::book::{Book, BookItem};
|
||||||
|
use mdbook::errors::Error;
|
||||||
|
use mdbook::preprocess::{CmdPreprocessor, PreprocessorContext};
|
||||||
|
use std::io;
|
||||||
|
use std::process;
|
||||||
|
use taskchampion_cli::Usage;
|
||||||
|
|
||||||
|
/// This is a simple mdbook preprocessor designed to substitute information from the usage
|
||||||
|
/// into the documentation.
|
||||||
|
fn main() -> anyhow::Result<()> {
|
||||||
|
// cheap way to detect the "supports" arg
|
||||||
|
if std::env::args().len() > 1 {
|
||||||
|
// sure, whatever, we support it all
|
||||||
|
process::exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let (ctx, book) = CmdPreprocessor::parse_input(io::stdin())?;
|
||||||
|
|
||||||
|
if ctx.mdbook_version != mdbook::MDBOOK_VERSION {
|
||||||
|
eprintln!(
|
||||||
|
"Warning: This mdbook preprocessor was built against version {} of mdbook, \
|
||||||
|
but we're being called from version {}",
|
||||||
|
mdbook::MDBOOK_VERSION,
|
||||||
|
ctx.mdbook_version
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let processed_book = process(&ctx, book)?;
|
||||||
|
serde_json::to_writer(io::stdout(), &processed_book)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process(_ctx: &PreprocessorContext, mut book: Book) -> Result<Book, Error> {
|
||||||
|
let usage = Usage::new();
|
||||||
|
|
||||||
|
book.for_each_mut(|sect| {
|
||||||
|
if let BookItem::Chapter(ref mut chapter) = sect {
|
||||||
|
let new_content = usage.substitute_docs(&chapter.content).unwrap();
|
||||||
|
if new_content != chapter.content {
|
||||||
|
eprintln!(
|
||||||
|
"Substituting usage in {:?}",
|
||||||
|
chapter.source_path.as_ref().unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
chapter.content = new_content;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Ok(book)
|
||||||
|
}
|
|
@ -47,6 +47,9 @@ mod usage;
|
||||||
pub(crate) use errors::Error;
|
pub(crate) use errors::Error;
|
||||||
use settings::Settings;
|
use settings::Settings;
|
||||||
|
|
||||||
|
// used by the `generate` command
|
||||||
|
pub use usage::Usage;
|
||||||
|
|
||||||
/// The main entry point for the command-line interface. This builds an Invocation
|
/// The main entry point for the command-line interface. This builds an Invocation
|
||||||
/// from the particulars of the operating-system interface, and then executes it.
|
/// from the particulars of the operating-system interface, and then executes it.
|
||||||
pub fn main() -> Result<(), Error> {
|
pub fn main() -> Result<(), Error> {
|
||||||
|
|
|
@ -7,5 +7,5 @@ mod report;
|
||||||
mod settings;
|
mod settings;
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
pub(crate) use report::{Column, Property, Report, Sort, SortBy};
|
pub(crate) use report::{get_usage, Column, Property, Report, Sort, SortBy};
|
||||||
pub(crate) use settings::Settings;
|
pub(crate) use settings::Settings;
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
use crate::argparse::{Condition, Filter};
|
use crate::argparse::{Condition, Filter};
|
||||||
use crate::settings::util::table_with_keys;
|
use crate::settings::util::table_with_keys;
|
||||||
|
use crate::usage::{self, Usage};
|
||||||
use anyhow::{anyhow, bail, Result};
|
use anyhow::{anyhow, bail, Result};
|
||||||
use std::convert::{TryFrom, TryInto};
|
use std::convert::{TryFrom, TryInto};
|
||||||
|
|
||||||
|
@ -30,6 +31,7 @@ pub(crate) struct Column {
|
||||||
/// Task property to display in a report
|
/// Task property to display in a report
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub(crate) enum Property {
|
pub(crate) enum Property {
|
||||||
|
// NOTE: when adding a property here, add it to get_usage, below, as well.
|
||||||
/// The task's ID, either working-set index or Uuid if not in the working set
|
/// The task's ID, either working-set index or Uuid if not in the working set
|
||||||
Id,
|
Id,
|
||||||
|
|
||||||
|
@ -59,6 +61,7 @@ pub(crate) struct Sort {
|
||||||
/// Task property to sort by
|
/// Task property to sort by
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub(crate) enum SortBy {
|
pub(crate) enum SortBy {
|
||||||
|
// NOTE: when adding a property here, add it to get_usage, below, as well.
|
||||||
/// The task's ID, either working-set index or a UUID prefix; working
|
/// The task's ID, either working-set index or a UUID prefix; working
|
||||||
/// set tasks sort before others.
|
/// set tasks sort before others.
|
||||||
Id,
|
Id,
|
||||||
|
@ -212,6 +215,34 @@ impl TryFrom<&toml::Value> for SortBy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_usage(u: &mut Usage) {
|
||||||
|
u.report_properties.push(usage::ReportProperty {
|
||||||
|
name: "id",
|
||||||
|
as_sort_by: Some("Sort by the task's shorthand ID"),
|
||||||
|
as_column: Some("The task's shorthand ID"),
|
||||||
|
});
|
||||||
|
u.report_properties.push(usage::ReportProperty {
|
||||||
|
name: "uuid",
|
||||||
|
as_sort_by: Some("Sort by the task's full UUID"),
|
||||||
|
as_column: Some("The task's full UUID"),
|
||||||
|
});
|
||||||
|
u.report_properties.push(usage::ReportProperty {
|
||||||
|
name: "active",
|
||||||
|
as_sort_by: None,
|
||||||
|
as_column: Some("`*` if the task is active (started)"),
|
||||||
|
});
|
||||||
|
u.report_properties.push(usage::ReportProperty {
|
||||||
|
name: "description",
|
||||||
|
as_sort_by: Some("Sort by the task's description"),
|
||||||
|
as_column: Some("The task's description"),
|
||||||
|
});
|
||||||
|
u.report_properties.push(usage::ReportProperty {
|
||||||
|
name: "tags",
|
||||||
|
as_sort_by: None,
|
||||||
|
as_column: Some("The task's tags"),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
136
cli/src/usage.rs
136
cli/src/usage.rs
|
@ -2,26 +2,31 @@
|
||||||
//! a way that puts the source of that documentation near its implementation.
|
//! a way that puts the source of that documentation near its implementation.
|
||||||
|
|
||||||
use crate::argparse;
|
use crate::argparse;
|
||||||
use std::io::{Result, Write};
|
use crate::settings;
|
||||||
|
use anyhow::Result;
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
|
#[cfg(feature = "usage-docs")]
|
||||||
|
use std::fmt::Write as FmtWrite;
|
||||||
|
|
||||||
/// A top-level structure containing usage/help information for the entire CLI.
|
/// A top-level structure containing usage/help information for the entire CLI.
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub(crate) struct Usage {
|
pub struct Usage {
|
||||||
pub(crate) subcommands: Vec<Subcommand>,
|
pub(crate) subcommands: Vec<Subcommand>,
|
||||||
pub(crate) filters: Vec<Filter>,
|
pub(crate) filters: Vec<Filter>,
|
||||||
pub(crate) modifications: Vec<Modification>,
|
pub(crate) modifications: Vec<Modification>,
|
||||||
|
pub(crate) report_properties: Vec<ReportProperty>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Usage {
|
impl Usage {
|
||||||
/// Get a new, completely-filled-out usage object
|
/// Get a new, completely-filled-out usage object
|
||||||
pub(crate) fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let mut rv = Self {
|
let mut rv = Self {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
argparse::get_usage(&mut rv);
|
argparse::get_usage(&mut rv);
|
||||||
|
settings::get_usage(&mut rv);
|
||||||
// TODO: sort subcommands
|
|
||||||
|
|
||||||
rv
|
rv
|
||||||
}
|
}
|
||||||
|
@ -77,6 +82,62 @@ impl Usage {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "usage-docs")]
|
||||||
|
/// Substitute strings matching
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// <!-- INSERT GENERATED DOCUMENTATION - $type -->
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// With the appropriate documentation.
|
||||||
|
pub fn substitute_docs(&self, content: &str) -> Result<String> {
|
||||||
|
// this is not efficient, but it doesn't need to be
|
||||||
|
let mut lines = content.lines();
|
||||||
|
let mut w = String::new();
|
||||||
|
|
||||||
|
const DOC_HEADER_PREFIX: &str = "<!-- INSERT GENERATED DOCUMENTATION - ";
|
||||||
|
const DOC_HEADER_SUFFIX: &str = " -->";
|
||||||
|
|
||||||
|
for line in lines {
|
||||||
|
if line.starts_with(DOC_HEADER_PREFIX) && line.ends_with(DOC_HEADER_SUFFIX) {
|
||||||
|
let doc_type = &line[DOC_HEADER_PREFIX.len()..line.len() - DOC_HEADER_SUFFIX.len()];
|
||||||
|
|
||||||
|
match doc_type {
|
||||||
|
"subcommands" => {
|
||||||
|
for subcommand in self.subcommands.iter() {
|
||||||
|
subcommand.write_markdown(&mut w)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"filters" => {
|
||||||
|
for filter in self.filters.iter() {
|
||||||
|
filter.write_markdown(&mut w)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"modifications" => {
|
||||||
|
for modification in self.modifications.iter() {
|
||||||
|
modification.write_markdown(&mut w)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"report-columns" => {
|
||||||
|
for prop in self.report_properties.iter() {
|
||||||
|
prop.write_column_markdown(&mut w)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"report-sort-by" => {
|
||||||
|
for prop in self.report_properties.iter() {
|
||||||
|
prop.write_sort_by_markdown(&mut w)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => anyhow::bail!("Unkonwn doc type {}", doc_type),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
writeln!(w, "{}", line)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(w)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// wrap an indented string
|
/// wrap an indented string
|
||||||
|
@ -122,6 +183,15 @@ impl Subcommand {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "usage-docs")]
|
||||||
|
fn write_markdown<W: FmtWrite>(&self, mut w: W) -> Result<()> {
|
||||||
|
writeln!(w, "### `ta {}` - {}", self.name, self.summary)?;
|
||||||
|
writeln!(w, "```shell\nta {}\n```", self.syntax)?;
|
||||||
|
writeln!(w, "{}", indented(self.description, ""))?;
|
||||||
|
writeln!(w)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Usage documentation for a filter argument
|
/// Usage documentation for a filter argument
|
||||||
|
@ -152,6 +222,15 @@ impl Filter {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "usage-docs")]
|
||||||
|
fn write_markdown<W: FmtWrite>(&self, mut w: W) -> Result<()> {
|
||||||
|
writeln!(w, "* `{}` - {}", self.syntax, self.summary)?;
|
||||||
|
writeln!(w)?;
|
||||||
|
writeln!(w, "{}", indented(self.description, " "))?;
|
||||||
|
writeln!(w)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Usage documentation for a modification argument
|
/// Usage documentation for a modification argument
|
||||||
|
@ -182,4 +261,51 @@ impl Modification {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "usage-docs")]
|
||||||
|
fn write_markdown<W: FmtWrite>(&self, mut w: W) -> Result<()> {
|
||||||
|
writeln!(w, "* `{}` - {}", self.syntax, self.summary)?;
|
||||||
|
writeln!(w)?;
|
||||||
|
writeln!(w, "{}", indented(self.description, " "))?;
|
||||||
|
writeln!(w)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Usage documentation for a report property (which may be used for sorting, as a column, or
|
||||||
|
/// both).
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub(crate) struct ReportProperty {
|
||||||
|
/// Name of the property
|
||||||
|
pub(crate) name: &'static str,
|
||||||
|
|
||||||
|
/// Usage description for sorting, if any
|
||||||
|
pub(crate) as_sort_by: Option<&'static str>,
|
||||||
|
|
||||||
|
/// Usage description as a column, if any
|
||||||
|
pub(crate) as_column: Option<&'static str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ReportProperty {
|
||||||
|
#[cfg(feature = "usage-docs")]
|
||||||
|
fn write_sort_by_markdown<W: FmtWrite>(&self, mut w: W) -> Result<()> {
|
||||||
|
if let Some(as_sort_by) = self.as_sort_by {
|
||||||
|
writeln!(w, "* `{}`", self.name)?;
|
||||||
|
writeln!(w)?;
|
||||||
|
writeln!(w, "{}", indented(as_sort_by, " "))?;
|
||||||
|
writeln!(w)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "usage-docs")]
|
||||||
|
fn write_column_markdown<W: FmtWrite>(&self, mut w: W) -> Result<()> {
|
||||||
|
if let Some(as_column) = self.as_column {
|
||||||
|
writeln!(w, "* `{}`", self.name)?;
|
||||||
|
writeln!(w)?;
|
||||||
|
writeln!(w, "{}", indented(as_column, " "))?;
|
||||||
|
writeln!(w)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,10 @@
|
||||||
This is an [mdbook](https://rust-lang.github.io/mdBook/index.html) book.
|
This is an [mdbook](https://rust-lang.github.io/mdBook/index.html) book.
|
||||||
Minor modifications can be made without installing the mdbook tool, as the content is simple Markdown.
|
Minor modifications can be made without installing the mdbook tool, as the content is simple Markdown.
|
||||||
Changes are verified on pull requests.
|
Changes are verified on pull requests.
|
||||||
|
|
||||||
|
To build the docs locally, you will need to build `usage-docs`:
|
||||||
|
|
||||||
|
```
|
||||||
|
cargo build -p taskchampion-cli --feature usage-docs --bin usage-docs
|
||||||
|
mdbook build docs/
|
||||||
|
```
|
||||||
|
|
|
@ -7,3 +7,6 @@ title = "TaskChampion"
|
||||||
|
|
||||||
[output.html]
|
[output.html]
|
||||||
default-theme = "ayu"
|
default-theme = "ayu"
|
||||||
|
|
||||||
|
[preprocessor.usage-docs]
|
||||||
|
command = "target/debug/usage-docs"
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
#! /bin/bash
|
|
||||||
|
|
||||||
REMOTE=origin
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
if ! [ -f "./src/SUMMARY.md" ]; then
|
|
||||||
echo "Run this from the docs/ dir"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! [ -d ./tmp ]; then
|
|
||||||
git worktree add tmp gh-pages
|
|
||||||
fi
|
|
||||||
|
|
||||||
(cd tmp && git pull $REMOTE gh-pages)
|
|
||||||
|
|
||||||
rm -rf tmp/*
|
|
||||||
mdbook build
|
|
||||||
cp -rp book/* tmp
|
|
||||||
(cd tmp && git add -A)
|
|
||||||
(cd tmp && git commit -am "update docs")
|
|
||||||
(cd tmp && git push $REMOTE gh-pages:gh-pages)
|
|
|
@ -3,9 +3,11 @@
|
||||||
- [Welcome to TaskChampion](./welcome.md)
|
- [Welcome to TaskChampion](./welcome.md)
|
||||||
* [Installation](./installation.md)
|
* [Installation](./installation.md)
|
||||||
* [Using the Task Command](./using-task-command.md)
|
* [Using the Task Command](./using-task-command.md)
|
||||||
* [Configuration](./config-file.md)
|
|
||||||
* [Reports](./reports.md)
|
* [Reports](./reports.md)
|
||||||
* [Tags](./tags.md)
|
* [Tags](./tags.md)
|
||||||
|
* [Filters](./filters.md)
|
||||||
|
* [Modifications](./modifications.md)
|
||||||
|
* [Configuration](./config-file.md)
|
||||||
* [Environment](./environment.md)
|
* [Environment](./environment.md)
|
||||||
* [Synchronization](./task-sync.md)
|
* [Synchronization](./task-sync.md)
|
||||||
* [Running the Sync Server](./running-sync-server.md)
|
* [Running the Sync Server](./running-sync-server.md)
|
||||||
|
|
9
docs/src/filters.md
Normal file
9
docs/src/filters.md
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
# Filters
|
||||||
|
|
||||||
|
Filters are used to select specific tasks for reports or to specify tasks to be modified.
|
||||||
|
When more than one filter is given, only tasks which match all of the filters are selected.
|
||||||
|
When no filter is given, the command implicitly selects all tasks.
|
||||||
|
|
||||||
|
Filters can have the following forms:
|
||||||
|
|
||||||
|
<!-- INSERT GENERATED DOCUMENTATION - filters -->
|
5
docs/src/modifications.md
Normal file
5
docs/src/modifications.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
# Modifications
|
||||||
|
|
||||||
|
Modifications can have the following forms:
|
||||||
|
|
||||||
|
<!-- INSERT GENERATED DOCUMENTATION - modifications-->
|
|
@ -49,9 +49,8 @@ columns = [
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
The filter is a list of filter arguments, just like those that can be used on the command line.
|
The `filter` property is a list of [filters](./filters.md).
|
||||||
See the `ta help` output for more details on this syntax.
|
It will be merged with any filters provided on the command line when the report is invoked.
|
||||||
It will be merged with any filters provided on the command line, when the report is invoked.
|
|
||||||
|
|
||||||
The sort order is defined by an array of tables containing a `sort_by` property and an optional `ascending` property.
|
The sort order is defined by an array of tables containing a `sort_by` property and an optional `ascending` property.
|
||||||
Tasks are compared by the first criterion, and if that is equal by the second, and so on.
|
Tasks are compared by the first criterion, and if that is equal by the second, and so on.
|
||||||
|
@ -70,11 +69,11 @@ sort = [
|
||||||
|
|
||||||
The available values of `sort_by` are
|
The available values of `sort_by` are
|
||||||
|
|
||||||
(TODO: generate automatically)
|
<!-- INSERT GENERATED DOCUMENTATION - report-sort-by -->
|
||||||
|
|
||||||
Finally, the `columns` configuration specifies the list of columns to display.
|
Finally, the `columns` configuration specifies the list of columns to display.
|
||||||
Each element has a `label` and a `property`, as shown in the example above.
|
Each element has a `label` and a `property`, as shown in the example above.
|
||||||
|
|
||||||
The avaliable properties are:
|
The avaliable properties are:
|
||||||
|
|
||||||
(TODO: generate automatically)
|
<!-- INSERT GENERATED DOCUMENTATION - report-columns -->
|
||||||
|
|
|
@ -4,6 +4,13 @@ The main interface to your tasks is the `ta` command, which supports various sub
|
||||||
Customizable [reports](./reports.md) are also available as subcommands, such as `next`.
|
Customizable [reports](./reports.md) are also available as subcommands, such as `next`.
|
||||||
The command reads a [configuration file](./config-file.md) for its settings, including where to find the task database.
|
The command reads a [configuration file](./config-file.md) for its settings, including where to find the task database.
|
||||||
And the `sync` subcommand [synchronizes tasks with a sync server](./task-sync.md).
|
And the `sync` subcommand [synchronizes tasks with a sync server](./task-sync.md).
|
||||||
You can find a list of all subcommands, as well as the built-in reports, with `ta help`.
|
|
||||||
|
|
||||||
> NOTE: the `task` interface does not precisely match that of TaskWarrior.
|
> NOTE: the `task` interface does not precisely match that of TaskWarrior.
|
||||||
|
|
||||||
|
## Subcommands
|
||||||
|
|
||||||
|
The sections below describe each subcommand of the `ta` command.
|
||||||
|
The syntax of `[filter]` is defined in [filters](./filters.md), and that of `[modification]` in [modifications](./modifications.md).
|
||||||
|
You can also find a summary of all subcommands, as well as filters, built-in reports, and so on, with `ta help`.
|
||||||
|
|
||||||
|
<!-- INSERT GENERATED DOCUMENTATION - subcommands -->
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue