This replaces a loop over _all_ tasks with one that fetches only pending
tasks, as determined by the working set.
This should be faster for task DB's with large numbers of completed
tasks, although on my medium-sized installation (~5000 total tasks) the
difference is negligible.
The code for parsing epoch timestamps when displaying tasks only
supports values between year 1980 and 9999. Previous to this change, it
was possible to set e.g., the due timestamp to a value outside of these
limits, which would make it impossible to later on show the task.
With this change, we only allow setting values within the same limits
used by the code for displaying tasks.
* libshared: bump for weekstart, epoch defines, eopww fix
mainly those visible changes, and miscellaneous others
see GothenburgBitFactory/taskwarrior#3623 (weekstart)
see GothenburgBitFactory/taskwarrior#3651 (epoch limit defines)
see GothenburgBitFactory/libshared#73 (eopww fix)
* Initialize libshared's weekstart from user's rc.weekstart config
This enables use of newer libshared code that can parse week numbers
according to ISO8601 instead of existing code which is always using
Sunday-based weeks. To get ISO behavior, set rc.weekstart=monday.
Default is still Sunday / old algorithm, as before, since Sunday is in
the hardcoded default rcfile.
Weekstart does not yet fix week-relative shortcuts, which will still
always use Monday.
See #3623 for further details.
* Restore 'load' timer
* [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
---------
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This replicates what the Rust runtime does, and matches what Rust code
expects, for example when writing to a socket which is no longer
connected to the remote end.
There is no easy way to determine the MSRV for TaskChampion, other than
somehow pulling the right version of the source and grepping for it. In
practice, if we update the `taskchampion` dependency to one that has a
higher MSRV, we'll get a build error and find this comment. And if we
get an error building Taskwarrior due to an old MSRV (for example if
something changes on `crates.io`) then we will also find this comment.
This also removes some superfluous dependency versions from the root
workspace. `src/taskchampion-cpp/Cargo.toml` specifies versions
directly.
TC 0.7.0 introduces a new `TaskData` type that maps to Taskwarrior's
`Task` type more cleanly. It also introduces the idea of gathering lists
of operations and "committing" them to a replica.
A consequence of this change is that TaskChampion no longer
automatically maintains dependency information, so Taskwarrior must do
so, with its `TDB2::dependency_sync` method. This method does a very
similar thing to what TaskChampion had been doing, so this is a shift of
responsibility but not a major performance difference.
Cxx is .. not great. It is missing a lot of useful things that make a
general-purpose bridge impractical:
- no support for trait objects
- no support for `Option<T>` (https://github.com/dtolnay/cxx/issues/87)
- no support for `Vec<Box<..>>`
As a result, some creativity is required in writing the bridge, for
example returning a `Vec<OptionTaskData>` from `all_task_data` to allow
individual `TaskData` values to be "taken" from the vector.
That said, Cxx is the current state-of-the-art, and does a good job of
ensuring memory safety, at the cost of some slightly awkward APIs.
Subsequent work can remove the "TDB2" layer and allow commands and other
parts of Taskwarrior to interface directly with the `Replica`.
* Update google-cloud-auth to drop ring@0.16.20ring@0.16.20 doesn't build on ppc and risc-v, and updating
google-cloud-auth pulls in a newer version of jsonwebtoken,
which in turn depends on a newer version of ring that we depend on
already either way.
This necessitated an MSRV bump to 1.73.0
Two of these used EXPFAIL which, because nothing is interpreting the TAP
output, does not work. So, that functionality is removed, and the
expected-to-fail bits are commented out or removed.
There was a conditional on the filename in `bash_tap.sh` which caused it
to not actually do anything and just run the test as a simple shell
script. That, too, has been removed.
Taskwarrior uses "expire" to refer to deletion of tasks past their
"until" date, so let's use `purge` to link this semantically to the
`task purge` command.
We require faketime to be installed for running the tests, therefore its added.
Further for non-interactive usage apt-get is recommended, therefore the change.
Tasks can be due "today", as `task add foo due:today ..` is a common
form. However, recurrences before that are just not created.
This avoids a lengthy "hang" when recurrences are updated on an old task
database, as many tasks in the past are created.
* update performance script to work with out-of-source build
* update displayed messages and remove perf.rc file
* remove .gitignore in performance folder
Consistently exclude WAITING tasks from reports which filter by status
If I understand correctly, the virtual status "waiting" is deprecated.
This is why some reports include the explicit "-WAITING" filter even
though it is not necessary: The idea is that being explicit will be
needed in the future when the "waiting" status is removed.
But I noticed that some reports do not include the "-WAITING" filter, so
I added it to all reports that filter by status.
Update chrono, and include fewer deps
Somewhere in the process of moving TaskChampion back to its own repo,
Taskwarrior's `Cargo.toml` ended up containing all of its dependencies,
unnecessarily.
This included an old version of `chrono` (addressed in
https://github.com/GothenburgBitFactory/taskchampion/pull/399). Removing
the old version requirement from `Cargo.toml` results in using a newer
version, addressing a (benign) security vulnerability.
This would be immediately useful to improve the rendering of the man
pages in third-party websites such as manned.org and the arch man pagesk
- https://mankier.com/1/task
- https://man.archlinux.org/man/task.1
The regular console output, or websites which render the manpage in
monospaced fonts, will not be affected by this change.
This change could also help with eventually rendering the manpages in
the documentation website, and having a mix of monospaced and variable
width fonts.
To test the HTML output:
```bash
git clone git@github.com:jacksonp/manner.git # used by ManKier
./manner/manner.php task.1.in >| task.1.html && $BROWSER task.1.html
```
Co-authored-by: Sebastian Carlos <sebastiancarlos@gmail.com>
This has the effect that `task news` will unconditionally update the
config with the new version once news has been shown (assuming the user
does not kill the process first).
* add coveralls coverage actions to tests
* using Ninja for Build
* exclude build directory in coverage report
* let distro tests run after successful coverage run
* add coveralls badge to readme
Closes#3413.
Run cargo update
The build was failing on nightly-aarch64-apple-darwin
(rustc 1.81.0-nightly (d8a38b000 2024-06-19))
due issues like:
error[E0635]: unknown feature `stdsimd`
--> /Users/chromy/.cargo/registry/src/index.crates.io-6f17d22bba15001f/ahash-0.7.6/src/lib.rs:33:42
|
33 | #![cfg_attr(feature = "stdsimd", feature(stdsimd))]
| ^^^^^^^
This was due to:
https://users.rust-lang.org/t/error-e0635-unknown-feature-stdsimd/106445
And resolved by moving to a newer version of ahash.
I confirmed the build still works on:
stable-aarch64-apple-darwin (rustc 1.78.0 (9b00956e5 2024-04-29))
1.70.0-aarch64-apple-darwin (rustc 1.70.0 (90c541806 2023-05-31))
after this change.
I had to manually downgrade google-cloud-auth to v0.13.0
v0.13.2 depends on jsonwebtoken v9.3.0 which drops support for rustc
1.70.0.
* Only warn about .data files when showing reports
This avoids the warning appearing in shell completion, for example.
* Update src/commands/CmdCustom.cpp
Co-authored-by: ryneeverett <ryneeverett@gmail.com>
---------
Co-authored-by: ryneeverett <ryneeverett@gmail.com>
Update condition for inheritance value hack
If the parent and child task have the same urgency the parent task also
needs the 0.01 extra urgency to be sorted above the child.
* remove symbollic links in the src directory as they are no longer
working with the out-of-source build
* remove .gitignore in the documentation (is build in build folder not
needed)
* remove CMake folders as they are also no longer present in the source
directory
Closes#3420.
* move taskchampion-lib to src/tc/lib, remove the rest
* update references to taskchampion
* Use a top-level Cargo.toml so everything is consistent
* apply comments from ryneeverett
* fix path to task executable in pyton tests
The current approach would copy the current files into the `build/test`
directory. Updating the paths according to the custom user setup.
By the copy I appended `.py` to have a clear visible distingtion which
ones are the python tests.
As soon as a source file in the normal directory is changed, it is
copied over and the corresponding file is updated.
From now on the python tests would need to get run in the according
build directory.
* reflect the current build instruction in PR template
* update paths and globing in run_all
* add line break for every cpp test
* remove .gitignore in test folder
As now all the auxillary files such as `all.log` as well as the
executables are present in the `build` directory there is no longer a
need to ignore them.
* update paths in python test scripts and enable deactivated
* remove .py extension when copy to build
Further remove glob pattern for `*.t.py` tests.
* remove accidentally added template.t from test files
This crate has been moved to
https://github.com/GothenburgBitFactory/taskchampion-sync-server.
The integration-tests repo used the sync server to test integration
between taskchampion and the sync-server. We should do that again, but
after taskchampion moves to its own repo (#3209). In the interim, the
cross-sync integration test can simply test syncing between local
servers, but the snapshot test is no longer useful as the local server
does not support snapshots.
* Recommend LSP's in development docs
Per conversation in #3338.
There are already a lot of documented compile options so I think we're
better off suggesting that everybody create a compile_commands.json
whether or not they're using an LSP because it doesn't cost much.
While I was at it it seemed reasonable to mention rust LSP too. Now that
rls is deprecated I'm not sure there is any competitor to rust-analyzer
worth mentioning.
* Export compile commands by default.
Thanks to @felixschurk for the idea and telling me how to do it.
It took me a minute to figure out that this places the
compile_commands.json in the build directory rather than the root of the
project. But clangd still finds it there and that's a better place for
it anyway.
The on-exit hook gets all modified tasks as input, but this was omitted
in the previous release. This adds a test for the desired behavior, and
updates TDB2 to correctly store the required information.
This will enable nixpkgs -- and any other distribution that builds in a
network sandbox and/or wants to use their own corrosion package rather
than building another one -- to do so without patching taskwarrior.
Since we're already using submodules for libshared I don't think this
should make the build process any more complicated for anyone else.
See
https://github.com/NixOS/nixpkgs/issues/300679#issuecomment-2041252688
for context.
This adds a description as well as the homepage to the CMake settings.
Further it would also now use the numbering cheme as supposed to in
CMake, this way other people could now pin a specific version if
taskwarrior is included in another project.
Documentation from CMake is https://cmake.org/cmake/help/latest/command/project.html
* update build instructions
Usage of "modern" CMake syntax and using specific out of source build.
Further add example on how to build in parallel, build a specific target
and how to change the compiler.
This closes#3236.
* Fix invalid imports in `[{..}]` form
Before this change, if an import of data that takes the form of a JSON
array of JSON objects results in an error, the import would be re-tried
assuming that each line of the file is a JSON object (the old format).
However, no check was made that the value actually was an object before
casting it to `json::object`, resulting in a segfault.
This adds the check, and handles the failure with a useful error message
(from the first attempt to parse the file).
For an object store backend, none of the suggestions in this paragraph
make much sense. "May" is much softer, in terms of
https://datatracker.ietf.org/doc/html/rfc2119. And in particular, the
cloud server implementation does not do any of these things.
We don't know why we're doing this step so we probably shouldn't.
Cryptography isn't magic and extra steps are harmful in that they
obscure the important parts.
* Add support for cloud sync, specifically GCP
This adds generic support for sync to cloud services, with specific
spuport for GCP. Adding others -- so long as they support a
compare-and-set operation -- should be comparatively straightforward.
The cloud support includes cleanup of unnecessary data, and should keep
total space usage roughly proportional to the number of tasks.
Co-authored-by: ryneeverett <ryneeverett@gmail.com>
* Disable return-type-c-linkage warning on Clang.
This is emitted by the compiler when it can't tell if the incomplete
type being returned is a C++ type, which might not have a C-compatible
layout. In `taskchampion.h`, the types are not C++ types so this is not
an issue and the warning is unnecessary.
* Use an if instead
Fancy generator expressions appear to not work.
* Try some different CMake syntax
Dependencies are now implemented, and the docs should be clear about the
format of the keys and values.
Noticed while working on GothenburgBitFactory/tw.org#212.
* Fix annotations in year 2038
Fixes#3050
* Ensure 32-bit systems work better after 2038
Without this patch, their 32-bit signed long int could overflow.
This patch was done while working on reproducible builds for openSUSE.
The workflow is triggered by a successful run of the test suite and creates a Docker image with a Taskwarrior installation of the current branch (restricted to develop/stable)
* move doc/misc to top level, add READMEs
* Move docs -> doc/devel
This also consolidates the _three_ documents describing (differently)
how to build Taskwarrior into a signle document.
* Fix fish completions
As per [1] printf in fish does not support '--' as a delimiter of format
string and args.
It used to work (accidentally) earlier (fish 3.5, glibc 2.31) but it is
broken (fish 3.6, glibc 2.36) nowadays.
Fix it by using the simple form of printf invocation with no argument
escaping.
Fixes: #3048
[1] https://fishshell.com/docs/current/cmds/printf.html#description
* Fix fish completions with older fish
Older versions (fish 3.5) cannot cope with '-' in printf format hence
add a workaround for these.
* Add devcontainer spec from codespaces generator
I started a codespace and used the VSCode devcontainer generator to
generate the devcontainer.json, reinstall-cmake.sh, and Dockerfile.
* Add uuid-dev in Dockerfile
---------
Co-authored-by: Dathan Bennett <dathanb@netflix.com>
* Link test executables using system frameworks on Darwin
On an M1 MBP, running `cmake . && make test` yields the error
```
[ 69%] Linking CXX executable tc.t
Undefined symbols for architecture arm64:
"_CFRelease", referenced from:
_$LT$iana_time_zone..platform..system_time_zone..SystemTimeZone$u20$as$u20$core..ops..drop..Drop$GT$::drop::hcd3964de9573de30 in libtc_rust.a(iana_time_zone-0e2714c6ff24f5bb.iana_time_zone.4cacef0c-cgu.15.rcgu.o)
"_CFStringGetBytes", referenced from:
iana_time_zone::platform::string_ref::StringRef$LT$T$GT$::to_utf8::h39971b546d587152 in libtc_rust.a(iana_time_zone-0e2714c6ff24f5bb.iana_time_zone.4cacef0c-cgu.13.rcgu.o)
"_CFStringGetCStringPtr", referenced from:
iana_time_zone::platform::string_ref::StringRef$LT$T$GT$::as_utf8::h8bb5c2c0d091ded1 in libtc_rust.a(iana_time_zone-0e2714c6ff24f5bb.iana_time_zone.4cacef0c-cgu.13.rcgu.o)
"_CFStringGetLength", referenced from:
iana_time_zone::platform::string_ref::StringRef$LT$T$GT$::to_utf8::h39971b546d587152 in libtc_rust.a(iana_time_zone-0e2714c6ff24f5bb.iana_time_zone.4cacef0c-cgu.13.rcgu.o)
"_CFTimeZoneCopySystem", referenced from:
iana_time_zone::platform::system_time_zone::SystemTimeZone::new::hc42d30609914d79d in libtc_rust.a(iana_time_zone-0e2714c6ff24f5bb.iana_time_zone.4cacef0c-cgu.15.rcgu.o)
"_CFTimeZoneGetName", referenced from:
iana_time_zone::platform::system_time_zone::SystemTimeZone::name::h44947ee6deb3339a in libtc_rust.a(iana_time_zone-0e2714c6ff24f5bb.iana_time_zone.4cacef0c-cgu.15.rcgu.o)
"_SecRandomCopyBytes", referenced from:
ring::rand::darwin::fill::h0ad94d66d4e1a222 in libtc_rust.a(ring-e5f87a2e334d4c6a.ring.a21bac31-cgu.4.rcgu.o)
"_kSecRandomDefault", referenced from:
ring::rand::darwin::fill::h0ad94d66d4e1a222 in libtc_rust.a(ring-e5f87a2e334d4c6a.ring.a21bac31-cgu.4.rcgu.o)
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[3]: *** [test/tc.t] Error 1
make[2]: *** [test/CMakeFiles/tc.t.dir/all] Error 2
make[1]: *** [test/CMakeFiles/test.dir/rule] Error 2
```
This change resolves the error by updating the targets in
test/CMakeLists.txt to link against the CoreFoundation and Security
frameworks when building under Mac OS.
* Link executables against CoreFoundation and Security frameworks on Mac OS
* Rename test_osx.sh to test_macos.sh
---------
Co-authored-by: Dathan Bennett <dathanb@netflix.com>
In #3118 @ryneeverett mentioned that "key" suggests that this is a
secret, when in truth it's just a user identifier. So "ID" is a better
word for it than "key".
This removes use of gnutls and the TLS implementation, which is no
longer needed (task synchronization is handled via Taskchampion, which
uses `reqwest`, which handles TLS via other Rust dependencies). This
incidentally removes the following config options:
* `debug.tls`
* `taskd.ca`
* `taskd.certificate`
* `taskd.ciphers`
* `taskd.credentials`
* `taskd.key`
* `taskd.server`
* `taskd.trust`
This avoids a vulnerability in tokio (#3085). The major version updates
of both actix-web and actix-rt required some signficant changes. Chief
among those, it turns out we were relying on actix-rt to run the
HttpServer in a different thread from the rest of the test, so that we
could talk to it from sync code in the test thread. This no longer
works, so the sync code is now run in a dedicated thread with
`actix_rt::task::spawn_blocking`.
This directory is generated instead of the x86_64-unknown-linux-gnu
directory when building on an ARM64/AArch64 Mac, so this change adds
that directory to the gitignore config.
Add a function that returns a Timestamp from an i64. One advantage is
improved readability since this function is guaranteed to return a
`LocalResult::Single`. Anther advantage is that it will panic if
something other than a LocalResult::Single is returned by chrono, which
shouldn't be possible for UTC timestamps which can't have DST ambiguity.
More specifically, consider them dependent if a task in the working set
(regardless of status) depends on a task with status "pending"
(regardless of presence in the working set). This has the desired
user-visible effect of making a task no longer +BLOCKED when the task it
depends on is marked as done, without requiring a working-set rebuild in
the intervening time.
Per the TODO, use `__init__` to override the stream. There don't seem to
be any other substantial changes to the `run` method needed for TAP and
I'm assuming the additional code in the upstream `run` has been added
since this class was written.
My primary motivation was to set `result.buffer = self.buffer` in the
`run` method, which fixes the runner enough to be able to use
`breakpoint()`.
In addition, I updated the shebang in `tw-2189.t` for portability.
- update CI branch filters so workflows actually run on merge
- update CI docs deployment target
- update links
- fix typos
- remove references to `ta` cli which was removed
- remove build-docs.sh script which duplicates publish-docs.yml workflow
This sets `set -e` to ensure any errors in the test script are
propagated upwards and noticed by the Github workflow.
Prior to these changes failures in the build process of the tests would
be ignored, and the success / failure would be determined purely by the
return code of the `./problems` script.
This uses CMake to build a simple Rust library (in `src/tc/rust`) that
just re-exports everything from the `taskchampion-lib` crate.
The C++ wrappers then wrap this into C++ objects with proper lifecycle
maintenance, in the `tc` namespace.
The C++ wrappers are incomplete, and missing methods are tagged with
"TODO". These will be added as needed.
This is a vulnerability in tokio, which is required by Actix-web. For
the moment, ignore it, and then decide whether to upgrade actix to suit,
or switch to a different (simpler) web server package.
The stats command calls an API to provide this information in a way that
will still be relevant for TaskChampion, while CmdInfo's access to the
data remains. The TaskChampion interface for per-task hitsory is still
not ready.
The stats command gets this information from an API that will also work
for TaskChampion. The sync command still accesses the field directly,
as the command must be completely rewritten for TaskChampion.
These are somewhat expensive tags, as they require reference to values
outside of the task itself.
To accomplish this, the replica supplies a pre-computed DependencyMap
that is only calculated once per replica, and only from the working set.
This introduces `tc_task_list_take`, supporting taking ownership of an
item in a task list.
TCTaskList is the only pointer list, but this is a generic and could be
used for other types.
The previous logic duplicated the action of applying an operation to the
TaskDb with a "manual" application to the Task's local TaskMap. This
now uses the updated TaskMap fetched from the DB, which will help to
incorporate any other concurrent DB updates.
The docs refer to this as the "nil version ID" so let's do the same.
This started out more ambitiously, to change this to `VersionId::NIL`,
but that required making VersionId a newtype and all of the implicit
conversions from VersionId to Uuid would have to be explicit. That
didn't seem wortht the trouble.
Also simple process/script to manage entries in PR's without merge conflicts:
1. Unreleased entries area stored as text files in ".changelogs/"
2. On release these are concatenated together and put in CHANGELOG.md
Script basically just add line of text to a "YYYY-MM-DD-branch.txt" formatted file
This uses `toml_edit` to edit the config file in-place. For the moment,
it only supports top-level arguments, but can be extended to do other
things later.
Without this, setting an item to None that did not already exist failed,
because the kv delete operation did not find the referenced key.
This also checks that the index is not 0, which is not allowed as the
working set is 1-indexed.
Rather than allow addressing tasks either by working set ID or uuid,
with attendant performance issues, this moves the API for the working
set to a single struct that just serves as a 1-1 mapping of indexes to
UUIDs. It's up to the caller to use this information.
Universes are really an optimization of filtering tasks, so let's define
them there, and derive them from the set of conditions. This means that
complex filters might get missed and end up doing a full task scan, but
that's probably OK.
Note that this does not fix the working-set API issues (#108 and #123).
This implements client-side encryption, so that users' task information
is not availble to the server (or to anyone who does not have the
`encryption_secret`).
* Use a parser (rather than clap) to process the command line
* Outline some generic support for filtering, reporting, modifying, etc.
* Break argument parsing strictly from invocation, to allow independent testing
..with a fixed implementation of the replica / server protocol logic.
There isn't much logic yet, and there's a lot of boilerplate to take
care of, so this looks a little lopsided, but I'm confident this is the
right structure for this code's future.
The public API of the taskchampion crate now contains the expected parts
and no more, and has some better documentation.
This moves the crate's external `tests/` into internal tests, as the
TaskDB is no longer exposed as part of the crate API.
This abandons field-by-field compatibility with the TaskWarrior TDB2
format, which wasn't a sustainable strategy anyway.
Instead, tasks are represented as a TaskMap with custom key formats. In
this commit, there are only a few allowed keys, with room to grow.
Replica returns convenience wrappers Task (read-only) and TaskMut
(read-write) with getters and setters to make modifying tasks easier.
This refactors the working-set support so that taskdb knows how to
rebuild the working set (in a single transaction) but replica knows what
tasks should be in that set.
This also adds support for automatically adding tasks to the working set
when they are marked pending. Note that tasks are not *removed* from
the working set automatically, but only on a gc operation.
Please see the ["Contributing to Taskwarrior"](https://github.com/GothenburgBitFactory/taskwarrior/tree/develop/doc/devel/contrib) section of the developer documentation.
To report a vulnerability, please contact [dustin@cs.uchicago.edu](mailto:dustin@cs.uchicago.edu), you may use GPG public-key D8097934A92E4B4210368102FF8B7AC6154E3226 which is available [here](https://keybase.io/djmitche/pgp_keys.asc?fingerprint=d8097934a92e4b4210368102ff8b7ac6154e3226).
Initial response is expected within ~48h.
We kindly ask to follow the responsible disclosure model and refrain from sharing information until:
1. Vulnerabilities are patched in Taskwarrior + 60 days to coordinate with distributions.
2. 90 days since the vulnerability is disclosed to us.
We recognise the legitimacy of public interest and accept that security researchers can publish information after 90-days deadline unilaterally.
We will assist with obtaining CVE and acknowledge the vulnerabilities reported.
This directory contains Taskwarrior documentation that is built and installed along with the executable:
* [`man`](man/) contains the source for the Taskwarrior manual pages.
* [`rc`](rc/) contains rcfiles that will be installed in `/usr/share/doc/task/rc` or equivalent.
* [`ref`](ref/) contains reference documentation that will be installed in `/usr/share/doc/task` or equivalent.
It also contains [developer documentation](devel/README.md) with a high-level view of how Taskwarrior development is done and how the pieces of the system fit together.
The coding style used for the Taskwarrior is based on the [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html), with small modifications in the line length.
# Automatic formatting
In order to have consistancy and automatic formatting [pre-commit](https://pre-commit.com) is used to apply [clang-format](https://clang.llvm.org/docs/ClangFormat.html) and [black](https://github.com/psf/black) are used.
In order to set them up locally please run:
```python
pipinstallpre-commit
pre-commitinstall
```
For more information refer to the [quick-start of pre-commit](https://pre-commit.com/#quick-start).
The setup is also included in the CI, hence if one can not install it automatically then the CI will take care for it in the PR.
## Rust
Rust code should be formatted with `rustfmt` and generally follow Rust style guidelines.
Other possible build types can be `Release` and `Debug`.
This will build several executables, but the one you want is probably `src/task`, located in the `build` directory.
When you make changes, just run the last line again.
### Building a specific target
For **only** building the `task` executable, use
```sh
cmake --build build --target task_executable
```
### Building in parallel
If a parallel build is wanted use
```sh
cmake --build build -j <number-of-jobs>
```
### Building with clang as compiler
```sh
cmake -S . -B build-clang\
-DCMAKE_C_COMPILER=clang\
-DCMAKE_CXX_COMPILER=clang++
cmake --build build-clang
```
## Run the Test Suite:
For running the test suite [ctest](https://cmake.org/cmake/help/latest/manual/ctest.1.html) is used.
Before one can run the test suite the `task_executable` must be built.
After that also the `test_runner` target must be build, which can be done over:
```sh
cmake --build build --target test_runner
```
Again you may also use the `-j <number-of-jobs>` option for parallel builds.
Now one can invoke `ctest` to run the tests.
```sh
ctest --test-dir build
```
This would run all the test in serial and might take some time.
### Running tests in parallel
```sh
ctest --test-dir build -j <number-of-jobs>
```
Further it is adviced to add the `--output-on-failure` option to `ctest`, to recieve a verbose output if a test is failing as well as the `--rerun-failed` flag, to invoke in subsequent runs only the failed ones.
### Running specific tests
For this case one can use the `-R <regex>` or `--tests-regex <regex>` option to run only the tests matching the regular expression.
Running only the `cpp` tests can then be achieved over
```sh
ctest --test-dir build -R cpp
```
or running the `variant_*` tests
```sh
ctest --test-dir build -R variant
```
### Repeating a test case
In order to find sporadic test failures the `--repeat` flag can be used.
Welcome, potential new Open Source contributor! This is a guide to show you exactly how to make a contribution, and will lead you through the entire process.
There are many people who wish to start contributing, but don't know how or where to start.
If this might be the case for you, then please read on, this guide is for you.
Because we want you to join in the fun with Open Source - it can be fun and rewarding, improve your skills, or just give you a way to contribute back to a project.
## How to Help
Help is needed in all areas of Taskwarrior development - design, coding, testing, support and marketing.
Applicants must be friendly.
Perhaps you are looking to help, but don't know where to start.
Perhaps you have skills we are looking for, here are ways you may be able to help:
- Use Taskwarrior, become familiar with it, and make suggestions.
We get great feedback from both new users and veteran users.
New users have a fresh approach that we can no longer achieve, while veteran users develop clever and crafty ways to use the product.
- Report bugs and odd behavior when you see it.
We don't necessarily know it's broken, unless you tell us.
- Suggest enhancements.
We get lots of these, and it's great.
Some really good ideas have been suggested and implemented.
Sure, some are out of scope, or plain crazy, but the stream of suggestions is fascinating to think about.
- Participate in the [bug tracking](https://github.com/GothenburgBitFactory/taskwarrior/issues) database, to help others and maybe learn something yourself.
- Proofread the documentation and man pages.
- Improve the documentation.
- Improve the man pages.
- Help improve the tutorials.
Make your own tutorial.
- Confirm a bug.
Nothing gets fixed without confirmation.
- Refine a bug.
Provide relevant details, elaborate on the behavior.
- Fix a bug.
Send a patch.
For this you'll need to know some C++ or Rust, and understand the [GitHub flow](https://docs.github.com/en/get-started/quickstart/github-flow).
See [Developing Taskwarrior](./development.md) for more information.
We welcome all bug fixes, provided the work is done well and doesn't create other problems or introduce new dependencies.
We recommend talking to us before starting: we are happy to help you out!
- Write a unit test.
Unit tests are possibly the most useful contributions of all, because they not only improve the quality of the code, but prevent future regressions, therefore maintaining quality of subsequent releases.
Plus, broken tests are a great motivator for us to fix the causal defect.
You'll need Python skills.
- Spread the word.
Help others become more effective at managing tasks.
Share your methodology, to inspire others.
- Encouragement.
Tell us what works for you, and what doesn't.
It's all good.
- Donate! Help offset costs.
Please remember that we need contributions from all skillsets, however small.
Taskwarrior has historically been a C++ project, but as of taskwarrior-3.0.0, the storage backend is now provided by a Rust library called TaskChampion.
## TaskChampion
TaskChampion implements storage and access to "replicas" containing a user's tasks.
It defines an abstract model for this data, and also provides a simple Rust API for manipulating replicas.
It also defines a method of synchronizing replicas and provides an implementation of that method in the form of a sync server.
Other applications, besides Taskwarrior, can use TaskChampion to manage tasks.
Taskwarrior is just one application using the TaskChampion interface.
## Taskwarrior's use of TaskChampion
Taskwarrior's interface to TaskChampion is in `src/taskchampion-cpp`.
This links to `taskchampion` as a Rust dependency, and uses [cxx](https://cxx.rs) to build a C++ API for it.
That API is defined, and documented, in `src/taskchampion-cpp/src/lib.rs`, and available in the `tc` namespace in C++ code.
This design document is a work in progress, and subject to change. Once finalized, the feature will be scheduled for an upcoming release.
# CLI Syntax Update
The Taskwarrior command line syntax is being updated to allow more consistent and predictable results, while making room for new features.
Adding support for arbitrary expressions on the command line has become complicated because of the relaxed syntax of Taskwarrior. While the relaxed syntax allows for a very expressive command line, it also creates ambiguity for the parser, which needs to be reduced.
With some limited and careful changes it will be possible to have a clear and unambiguous command line syntax, which means a predictable and deterministic experience.
It should be stated that for straightforward and even current usage patterns, the command line will likely not change for you. Another goal is to not require changes to 3rd-party software, where possible. Only the more advanced and as-yet unintroduced features will require a more strict syntax. This is why now is an ideal time to tighten the requirements.
## Argument Types
The argument types supported remain the same, adding some new constructs.
* Config file override
*`rc:<file>`
* Configuration override
*`rc:<name>:<value>` Literal value
*`rc:<name>=<value>` Literal value
*`rc:<name>:=<value>` Calculated value
* Tag
*`+<tag>`
*`-<tag>`
*`'+tag one'` Multi-word tag
* Attribute modifier
*`rc:<name>.<modifier>:<value>`
* Modifier is one of:
*`before`
*`after`
*`under`
*`over`
*`above`
*`below`
*`none`
*`any`
*`is`
*`isnt`
*`equals`
*`not`
*`contains`
*`has`
*`hasnt`
*`left`
*`right`
*`startswith`
*`endswith`
*`word`
*`noword`
* Search pattern
*`/<pattern>/`
* Substitution
*`/<from>/<to>/`
*`/<from>/<to>/g`
* Command
*`add`
*`done`
*`delete`
*`list`
* etc.
* Separator
*`--`
* ID Ranges
*`<id>[-<id>][,<id>[-<id>]...]`
* UUID
*`<uuid>`
* Everything Else
*`<word>`
*`'<word> <word> ...'`
## New Command Line Rules
Certain command line constructs will no longer be supported, and this is imposed by the new rules:
1. Each command line argument may contain only one instance of one argument type, unless that type is `<word>`.
task add project:Home +tag Repair the thing # Good
task add project:Home +tag 'Repair the thing' # Good
task add 'project:Home +tag Repair the thing' # Bad
Putting two arguments into one quoted arg makes that arg a `<word>`.
2. If an argument type contains spaces, it must either be quoted or escaped.
task add project:'Home & Garden' ... # Good
task add 'project:Home & Garden' ... # Good
task add project:Home\ \&\ Garden ... # Good
task add project:Home' & 'Garden ... # Good
task add project:Home \& Garden ... # Bad
The parser will not combine multiple arguments, for example:
task '/one two/' list # Good
task /one two/ list # Bad
task /'one two'/ list # Bad, unless ' is part of the pattern
3. By default, *no* calculations are made, unless the `:=` eval operator is used, and if so, the whole argument may need to be quoted or escaped to satisfy Rule 1.
task add project:3.project+x # Literal
task add project:=3.project+x # DOM reference + concatenation
4. Bare word search terms are no longer supported.
Use the pattern type argument instead.
task /foo/ list # Good
task foo list # Bad
5. Expressions must be a series of arguments, not a quoted string.
task urgency \< 5.0 list # Good
task 'urgency < 5.0 list' # Bad
## Other Changes
Aside from the command line parser, there are other changes needed:
- Many online documents will need to be modified.
- Filters will be automatically parenthesized, so that every command line will now looke like:
title: "Taskwarrior - Creating a Taskserver Client"
---
# Creating a Taskserver Client
A Taskserver client is a todo-list manager.
It may be as simple as a program that captures a single task, as complex as Taskwarrior, or anything in between.
It can be a mobile client, a web application, or any other type of program.
This document describes how such a client would interact with the server.
A client to the Taskserver is a program that manages a task list, and wishes to exchange data with the server so that the task list may be shared.
In order to do this, a client must store tasks locally, upload local changes, download remote changes, and apply remote changes to the local tasks.
The client must consider that there may be no network connectivity, or no desire by the user to synchronize.
The client will need proper credentials to talk to the server.
## Requirements
In this document, we adopt the convention discussed in Section 1.3.2 of [RFC1122](https://tools.ietf.org/html/rfc1122#page-16) of using the capitalized words MUST, REQUIRED, SHOULD, RECOMMENDED, MAY, and OPTIONAL to define the significance of each particular requirement specified in this document.
In brief: "MUST" (or "REQUIRED") means that the item is an absolute requirement of the specification; "SHOULD" (or "RECOMMENDED") means there may exist valid reasons for ignoring this item, but the full implications should be understood before doing so; and "MAY" (or "OPTIONAL") means that this item is optional, and may be omitted without careful consideration.
## Taskserver Account
A Taskserver account must be created.
This process creates a storage area, and generates the necessary credentials.
## Credentials
A Taskserver client needs the following credentials in order to communicate with a server:
- Server address and port
- Organization name
- User name
- Password
- Certificate
- Key
The server address and port are the network location of the server.
An example of this value is:
foo.example.com:53589
In addition to a DNS name, this can be an IPv4 or IPv6 address.
The organization name is an arbitrary grouping, and is typically 'PUBLIC', reflecting the individual nature of server accounts.
Future capabilities will provide functionality that support groups of users, called an organization.
The user name is the full name.
This will be the name used to identify other users in an organization, in a future release.
Example 'John Doe'.
The password is a text string generated by the server at account creation time.
It should be considered a secret.
The certificate is an X.509 PEM file generated by the server at account creation time.
This is used for authentication.
It should be considered a secret.
The key is an X.509 PEM file generated by the server at account creation time.
This is used for encryption.
It should be considered a secret.
These credentials need to be stored on the client, and used during the sync operation.
## Description of a Taskserver Client
This section describes how a client might behave in order to facilitate integration with the Taskserver.
## Encryption
The Taskserver only communicates using encryption.
Therefore all user data is encrypted while in transit.
The Taskserver currently uses [GnuTLS](https://gnutls.org) to support this encryption, and therefore supports the following protocols:
- SSL 3.0
- TLS 1.0
- TLS 1.1
- TLS 1.2
The client may use any library that supports the above.
## Configuration
The client needs to store configuration, which matches the credentials needed for Taskserver communication.
See section 2.1 "Credentials".
The credentials may not be modified by the user without losing server access.
The server:port data may need to be changed automatically following a redirect response from the server.
See section 5 "Server Errors".
## Local Storage
The client needs to store task data locally.
The client will need to be able to find tasks by their UUID and overwrite them.
Uploaded and downloaded task changes will use the [Taskwarrior Data Interchange Format](/docs/design/task).
## Local Changes
Whenever local data is modified, that change MUST be synced with the server.
But this does not have to occur immediately, in fact the client SHOULD NOT assume connectivity at any time.
A client SHOULD NOT also assume that the server is available.
If the server is not available, the local changes should be retained, and the sync operation repeated later.
Ideally the client will give the user full control over sync operations.
Automatically syncing after all local modifications is not recommended.
If a client performs too many sync operations, the server MAY revoke the certificate.
Effectively, the client should maintain a separate list of tasks changed since the last successful sync operation.
Note that tasks have a "modified" attribute, which should be updated whenever a change is made.
This attribute contributes to conflict resolution on the server.
## Remote Changes
When a server sends remote changes to a client, in the response to a sync request, the changes have already been merged by the server, and therefore the client should simply store them intact.
Based on the UUID in the task, the client can determine whether a task is new (and should be added to the local list of tasks), or whether it represents a modification (and should overwrite it's existing entry).
The client MUST NOT perform any merges.
## Sync Key
Whenever a sync is performed, the server responds by sending a sync key and any remote changes.
The sync key is important, and should be included in the next sync request.
The client is REQUIRED to store the sync key in every server response message.
If a client omits the sync key in a sync message, the response will be a complete set of all tasks and modifications.
## Data Integrity
Although a task is guaranteed to contain at least 'entry', 'description' and 'uuid' attributes, it may also contain other known fields, and unknown user-defined fields.
An example might be an attribute named 'estimate'.
If a task is received via sync that contains an attribute named 'estimate', then a client has the responsibility of preserving the attribute intact.
If that data is shown, then it is assumed to be of type 'string', which is the format used by JSON for all values.
Conversely, if a client wishes to add a custom attribute, it is guaranteed that the server and other clients will preserve that attribute.
Using this rule, two clients of differing capabilities can exchange data and still maintain custom attributes.
This is a requirement.
Any client that does not obey this requirement is broken.
## Synchronizing
Synchronizing with the Taskserver consists of a single transaction.
Once an encrypted connection is made with the server, the client MUST compose a [sync request message](/docs/design/request).
This message includes credentials and local changes.
The response message contains status and remote changes, which MUST be stored locally.
## Establishing Encrypted Connection
All communication with the Taskserver is encrypted using the certificate and key provided to each user.
Using the 'server' configuration setting, establish a connection.
## Sync Request
See [sync request message](/docs/design/request).
A sync request MUST contain a sync key if one was provided by a previous sync.
A sync request MUST contain a list of modified tasks, in JSON format (see [Task JSON](/docs/design/task)), if local modifications have been made.
## Sync Response
A sync response WILL contain a 'code' and 'status' header variable, WILL contain a sync key in the payload, and MAY contain a list of tasks from the server in JSON format (see [Task JSON](/docs/design/task)).
## Server Messages
There are cases when the server needs to inform the user of some condition.
This may be anticipated server downtime, for example.
The response message is typically not present, but may be present in the header, containing a string:
...
message: Scheduled maintenance 2013-07-14 08:00UTC for 10 minutes.
...
If such a message is returned by the server, it SHOULD be made available to the user.
This is a recommendation, not a requirement.
## Server Errors
The server may generate many errors (See [Protocol](/docs/design/protocol)), but the following is a list of the ones most in need of special handling:
- 200 Success
- 201 No change
- 301 Redirect
- 430 Access denied
- 431 Account suspended
- 432 Account terminated
- 5xx Error
The 200 indicates success, and that a change was recorded.
The 201 indicates success but no changes were necessary.
The 301 is a redirect message indicating that the client MUST re-request from a new server.
The 43x series messages are account-related.
Any 5xx series code is a server error of some kind.
All errors consist of a code and a status message:
code: 200
status: Success
## Examples
Here are examples of properly formatted request and response messages.
Note that the messages are indented for clarity in this document, but is not the case in a properly formatted message.
Also note that newline characters U+000D are not shown, but are implied by the separate lines.
Because some messages have trailing newline characters, the text is delimited by the 'cut' markers:
foo
The example above illustrates text consisting of:
U+0066 f
U+006F o
U+006F o
U+000D newline
U+000D newline
Note that these values are left unspecified, but should be clear from the context, and the [message format](/docs/design/request) spec:
<size>
<organization>
<user>
<password>
## First Sync
The first time a client syncs, there is (perhaps) no data to upload, and no sync key from a previous sync.
<size>type: sync
org: <organization>
user: <user>
key: <password>
client: task 2.3.0
protocol: v1
Note the double newline character separating header from payload, with an empty payload.
## Request: Sync No Data
Ordinarily when a client syncs, there is a sync key from the previous sync response to send.
This example shows a sync with no local changes, but a sync key from a previous sync.
<size>type: sync
org: <organization>
user: <user>
key: <password>
client: task 2.3.0
protocol: v1
2e4685f8-34bc-4f9b-b7ed-399388e182e1
## Request: Sync Data
This sync request shows a sync key from the previous sync, and a locally modified task.
This design document is a work in progress, and subject to change.
Once finalized, the feature will be scheduled for an upcoming release.
# Full DOM Support
Taskwarrior currently supports DOM references that can access any stored data item.
The general forms supported are:
[ <id> | <uuid> ] <attribute> [ <part> ]
Examples include:
due
123.uuid
entry.month
123.annotations.0.entry.year
a87bc10f-931b-4558-a44a-e901a77db011.description
Additionally there are references for accessing configuration and system/program level items.
rc.<name>
context.program
context.args
context.width
context.height
system.version
system.os
While this is adequate for data retrieval, we have the possibility of extending it further to include data formats, higher-level constructs, and then to make use of DOM references in more locations.
This contributes to our goal of simplifying Taskwarrior.
## Proposed Format Support
When defining a custom report, the columns shown are defined like this:
Taskwarrior data has typically been shared in several ways.
Those include SCM (source code management) systems, directory synchronizing software (such as DropBox), and by use of the 'push', 'pull' and 'merge' commands introduced in version 1.9.3.
While these methods work, they each have problems associated with the merging of data.
In the case of directory synchronizing software, there is no merging at all - just simple file overwrite, despite many people believing that the data is somehow combined and preserved.
The Taskserver is a solution.
It is an online/cloud storage and sync service for taskwarrior data.
It performs conflict-free data merging, and minimizes bandwidth use.
The Taskserver also provides multi-client access, so that a task added using a web client could be immediately viewed using a mobile client, or modified using taskwarrior.
Choice of clients is important - people have widely varying behaviors and tastes.
The Taskserver also provides multi-user access, which introduces new capabilities, such as list sharing and delegation.
These will require later modification to this protocol.
The Taskserver protocol will be implemented by the taskd project and first used in taskwarrior 2.3.0.
Other clients will follow.
## Requirements
In this document, we adopt the convention discussed in Section 1.3.2 of [RFC1122](https://tools.ietf.org/html/rfc1122#page-16) of using the capitalized words MUST, REQUIRED, SHOULD, RECOMMENDED, MAY, and OPTIONAL to define the significance of each particular requirement specified in this document.
In brief: "MUST" (or "REQUIRED") means that the item is an absolute requirement of the specification; "SHOULD" (or "RECOMMENDED") means there may exist valid reasons for ignoring this item, but the full implications should be understood before doing so; and "MAY" (or "OPTIONAL") means that this item is optional, and may be omitted without careful consideration.
## Link Level
The Taskserver protocol assumes a reliable data stream such as provided by TCP.
When TCP is used, a Taskserver listens on a single predetermined port *for the given client* only.
This means the server may be using multiple ports to serve distinct sets of clients.
This server is only an interface between programs and the task data.
It does not perform any user interaction or presentation-level functions.
## Transactions
Each transaction is a single incoming message, with a single response message.
All communication therefore consists of a single 'send', followed by a single 'receive', then termination.
There are no sessions, and no continuously open connections.
The message format is described in the [Taskserver Message Format](/docs/design/request) document.
## Responsibilities of the Server
The server will maintain a set of transactions, in the original sequence, punctuated by sync keys which are UUIDs.
Each sync key represents a non- trivial sync operation by a client.
Each transaction is a [JSON-formatted task](/docs/design/task), followed by a newline (\\n) character.
The result is a single file that contains interleaved lines of two types: tasks and sync keys.
This design allows the server to maintain a set of deltas such that multiple clients may request a minimal set of changes since their last sync.
## Responsibilities of the Client
This describes how Taskwarrior implements sync.
All modifications to tasks (add, modify, done, delete \...) are recorded in the form of a fully-composed [JSON-formatted task](/docs/design/task).
The formatted task is added to a local backlog.data file.
If a task is modified a second time, it is added again to the backlog.data file - the lines are not combined.
Each task SHALL have a 'modified' date attribute that will help resolve conflicts.
On sync:
* Send a 'sync' type message with the entire contents of the backlog.data, unmodified, as the message payload.
* Receive one of the following response codes:
* 201: This means 'no change', and there is no further action to be taken.
* 200: This means 'success', and the message payload contains a set of tasks and a sync key:
* The formatted tasks are to be stored as-is.
These tasks will either be appended to the client data or will overwrite existing client data, based on the UUID of the task.
No merge logic is necessary.
* The sync key will be written to the backlog.data file, overwriting the previous contents, such that it will now contain only one line.
* 301: Redirect to : found in the 'info' response header, will force the client to resubmit the request to the new server.
* 3xx, 4xx, 5xx: The 'status' field contains an error message.
* If the response contained any error or warning, the error should be shown to the user.
This provides an opportunity for the server to announce downtime, or relocation.
If no sync key is sent, the server cannot provide an incremental delta, and so will send all task data, which should be stored as above.
This should be the case for a client making its first sync call.
If an unrecognized attribute is present in the task data, the client MUST preserve the attribute unmodified, and assume it is of type 'string'.
This permits individual clients to augment the task data without other clients stripping it meaningful data.
This is how UDAs (user defined attributes) are handled.
## Extensions
This protocol was designed so that extensions to the protocol will take the form of additional message types and status codes.
## Summary of Response Codes
Status responses indicate the server's response to the last command received from the client.
The codes consist of a 3 digit numeric code.
The first digit of the response broadly indicates the success, failure, or progress of the previous command (based generally on [RFC640](https://tools.ietf.org/html/rfc640) [RFC821](https://tools.ietf.org/html/rfc821)):
| 1yz | Positive Preliminary reply |
| 2yz | Positive Completion reply |
| 3yz | Positive Intermediate reply |
| 4yz | Transient Negative Completion reply |
| 5yz | Permanent Negative Completion reply |
The next digit in the code indicates the response category:
Your [feedback](mailto:support@taskwarrior.org?Subject=Feedback) is welcomed.
Recurrence
----------
Recurrence needs an overhaul to improve weaknesses and add new features.
# Terminology
- The hidden 'parent' task is called the template.
- Synthesis is the name for the generation of new recurring task instances when necessary.
- The synthesized tasks are called instances.
- The index is the zero-based monotonically increasing number of the instance.
- Drift is the accumulated errors in time that cause a due date to slowly change for each recurring task.
# Criticism of Current Implementation
- The `mask` attribute grows unbounded.
- Only strict recurrence cycles are supported.
The example of mowing the lawn is that you want to mow the lawn every seven days, but when you are four days late mowing the lawn, the next mowing should be in seven days, not in three.
- Intances generated on one machine and then synced, may collide with equivalent unsynced instances tasks on another device, because the UUIDs are different.
- You cannot `wait` a recurring task and have that wait period propagate to all other child tasks.
- Task instances cannot individually expire.
# Proposals
## Proposal: Eliminate `mask`, `imaѕk` Attributes
The `mask` attribute in the template is replaced by `last`, which indicates the most recent instance index synthesized.
Because instances are never synthesized out of order, we only need to store the most recent index.
The `imask` attribute in the instance is no longer needed.
## Proposal: Rename `parent` to `template`
The name `parent` implies subtasks, and confuses those who inspect the internals.
The value remains the UUID of the template.
This frees up the namespace for future use with subtasks.
## Proposal: New 'rtype' attribute
To indicate the flavor of recurrence, support the following values:
*`periodic` - Instances are created on a regular schedule.
Example: send birthday flowers.
It must occur on a regular schedule, and doesn't matter if you were late last year.
This is the default value.
*`chained` - Instances are created back to back, so when one instance ends, the next begins, with the same recurrence.
Example: mow the lawn.
If you mow two days late, the next instance is not two days early to compensate.
## Proposal: Use relative offsets
The delta between `wait` and `due` date in the template should be reflected in the delta between `wait` and `due` date in the instance.
Similarly, 'scheduled' must be handled the same way.
## Proposal: On load, auto-upgrade legacy tasks
Upgrade template:
- Add `rtype:periodic`
- Add `last:N` where `N` is the length of `mask`
- Delete `mask`
Upgrade instance:
- Rename `parent` to `template`
- Delete `imask`
- Update `wait` if not set to: `wait:due + (template.due - template.wait)`
- Update `scheduled` if not set to: `scheduled:due + (template.due - template.scheduled)`
## Proposal: Deleting a chained instance
Deleting a `rtype:chained` instance causes the next chained instance to be synthesized.
This gives the illusion that the due date is simply pushed out to `(now + template.recur)`.
## Proposal: Modification Propagation
TBD
## Proposal: Exotic Dates
Expand date specifications to use pattern phrases:
-`4th thursday in November`
-`4th thursday of November`
-`Friday before easter`
-`next Tuesday`
-`last Tuesday`
-`last July`
-`weekend`
-`3 days before eom`
-`in the morning`
-`4pm`
-`noon`
-`midnight`
Got suggestions?
## Proposal: User-Defined Week Start
TBD
# Implementation
## Implementation: Adding a new `periodic` template
These messages look somewhat like email, as defined in [RFC821](https://tools.ietf.org/html/rfc821), [RFC2822](https://tools.ietf.org/html/rfc2822).
The message format allows for data, metadata, and extensibility.
This combination allows the Taskserver to accommodate current and future needs.
This document describes the message format, and the supported message types.
## Requirements
In this document, we adopt the convention discussed in Section 1.3.2 of [RFC1122](https://tools.ietf.org/html/rfc1122#page-16) of using the capitalized words MUST, REQUIRED, SHOULD, RECOMMENDED, MAY, and OPTIONAL to define the significance of each particular requirement specified in this document.
In brief: "MUST" (or "REQUIRED") means that the item is an absolute requirement of the specification; "SHOULD" (or "RECOMMENDED") means there may exist valid reasons for ignoring this item, but the full implications should be understood before doing so; and "MAY" (or "OPTIONAL") means that this item is optional, and may be omitted without careful consideration.
## Encoding
All messages are UTF8-encoded text.
## Message Format
This format is based on [RFC2822](https://tools.ietf.org/html/rfc2822), 'Internet Message Format'.
Here is an example of the format:
<SIZE>
name: value
name2: value2
payload
There are three sections.
The first is the size, which is a 4-byte, big- Endian, binary byte count of the length of the message, including the 4 bytes for the size.
The header section is a set of name/value pairs separated by newline characters (U+000D).
The name is separated from the value by ': ' (colon U+003A, space U+0020) The header section is terminated by two consecutive newline (U+000D) characters.
All text is UTF8-encoded.
The payload section is arbitrary, and message type-specific.
However, it is still UTF8-encoded text.
## Message Requirements
Messages SHALL contain particular headers.
Those are:
- type
- protocol
- client
The 'type' value is what determines the interpretation of the payload.
The 'protocol' value should be 'v1', or any subsequently published protocol version.
The 'client' represent the client identifier, so that any special cases can be handled.
For example, an emergency fix that is client version-specific could be released, to support users that have not updated their client, or perhaps the client has not released a fix.
The form of the 'version' value is:
<product identifier> <version number>
As an example:
taskwarrior 2.3.0
DO NOT spoof any other software using this client value.
If another client is spoofed, then patches addressing protocol errors may break working software.
## Auth Data
Every request from the client SHALL contain "auth" information, which involves these header entries:
org: <organization>
user: <user>
key: <key>
The user and org fields uniquely identify a user.
The key field is generated when a new server account is set up.
It is a shared secret, equivalent to a password, and should be protected.
Authentication failure can result in these errors:
- 430 Authentication failed
- 431 Account suspended
## Status Data
Every response from the Taskserver SHALL contain status data:
code: <code>
status: <status text>
The code is a numeric status indicator defined in the [Sync Protocol](/docs/design/protocol).
## Payload Data
Payload data is optional, arbitrary and message type dependent.
It is always UTF8-encoded text.
## Message Types
The Taskserver supports several message types, thus providing a set of primitives for use by clients.
It is expected that the number of supported ticket types will increase over time.
## Sync Message
The "sync" message always originates from the client, but the response will contain data from the server.
A sync is therefore a single request with a single response.
The "sync" message type MUST contain the following headers:
The request contains the proper auth section, and the body contains the current sync key followed by a newline characters (U+000D), then a list of JSON-formatted tasks \[2\] each separated by a newline character (U+000D).
An example response message might be:
<size>type: response
client: taskd 1.0.0
protocol: v1
code: 200
status: Ok
45da7110-1bcc-4318-d33e-12267a774e0f
The status indicates success, and the payload contains zero remote task modifications, followed by a sync key.
## Statistics Message
The message format іs simply:
<size>type: statistics
org: <Organization>
user: <User>
key: <Key>
client: taskd 1.0.0
protocol: v1
There is no payload.
An example response message might be:
<size>type: response
client: taskd 1.0.0
protocol: v1
code: 200
status: Ok
average request bytes: 0
average response bytes: 0
average response time: 0.000000
errors: 0
idle: 1.000000
maximum response time: 0.000000
total bytes in: 0
total bytes out: 0
tps: 0.000000
transactions: 1
uptime: 28
There is no payload, and the results are in the header variables.
Note that the statistics gathered by the server are growing, which means new values are occasionally added to the response message.
This design document is a work in progress, and subject to change.
Once finalized, the feature will be scheduled for an upcoming release.
# Rule System
The rule system is a framework that supports highly configurable features, with runtime evaluation, DOM access and an internal API.
Implementing a rule system meets the goal of shrinking and stabilizing the product core, while adding new features, and enabling many more.
## Required Enhancements
To prepare for a Rules System, various subsystems must first be enhanced:
- DOM references need to be unambiguous, and will all have the `dom.` prefix.
- DOM references need to be able to access any Taskwarrior data, in any
- Custom reports will change from referencing `<column>[.<format>]` to simply
`<domref>`
- RC file syntax needs to be enhanced, so support rule definitions, which are
multi-line blocks that are indentation-sensitive
- RC file syntax will support two ways of specifying the same data:
a.b.c=...
a:
b:
c=...
- RC file syntax will allow the use of environment variables inline:
name=${TERM}
include ${HOME}/.taskrc_local
- The `Variant` object will migrate to `libshared`
- The expression evaluator `Eval` object will migrate to `libshared`
- The column objects will gain a more structured base class, and will serve as
providers for DOM references
- The 'exec' command will be able to run a rule, if the reference is correct
- Taskwarrior will store state data in a new `state.data` file
-`Config` object needs to use the `rat` parser, to tackle the more complex
syntax
- The RC file will support environment variable expansion, where `${NAME}`
will be replaced by its corresponding value at launch time
At that point, the rules system can be implemented in `libshared`, and will use a pluggable architecture to allow its integration into several projects.
## DOM Enhancements
DOM references will be enhanced, with many more references supported.
All DOM references will begin with `dom.`, yielding unambiguous references.
References will have a type.
Types will support sub-references (`<date>.<month>`, `<tags>.<N>`, `<annotation>.<description>`), and display formats included.
dom . [<id> .] <attribute> [. <sub-reference>] . <format>
dom . 123 . entry . year . yyyy
dom . 123 . entry
dom . 123 . tags
dom . 123 . tags . count
dom . 123 . tags . 1
In addition to direct attribute access, DOM references will also support tw references beyond the current set: dom.rc.<name>
dom.cli.args
dom.terminal.width
dom.terminal.height
dom.system.version
dom.system.oѕ
And will also support higher-level constructs that do not directly correlate to attributes, for example:
dom.active Boolean indicator of any active tasks
dom.synced Boolean indicator of the need to sync
dom.rc.path String path of .taskrc file (or override)
dom.data.path String path of data directory
dom.hooks.path String path of hooks directory
Finally, access to state:
dom.state.program
dom.state.sync.last
dom.state.sync.configured
dom.state.run.last
dom.state.context
## RC Syntax Changes
The current configuration system supports only two different forms of syntax:
<name> = [ <value> ]
include <file>
A rule is a new form of syntax that consists of the rule keyword, a name, optional trigger, followed by indented actions in the form of API calls and flow control.
For example:
rule myRule() on_launch:
# Some code here
A rule definition will appear in the RC file, alongside all the existing settings.
The rule syntax will require a blank line to terminate the rule definition, the result being that the RC file should be quite readable, although it will look like Python.
## Hook Scripts
While this functionality can also be implemented using hook scripts, rules will run in-process, and therefore do not require external interpreters to be launched every time.
This creates the potential to run faster than a hook script.
For complex processing, hook scripts will be the preferred mechanism, but as the rules system matures, rules will be made to run more quickly.
With adequate performance, a rule will be the preferred implementation over a hook script.
This is not expected to be the case at first.
Hook scripts are not likely to be extended beyond their current form, and with greater DOM access and a growing API, rules should be able to supplant most hook script use cases.
## Rule Triggers
The set of supported rule types will include:
*`on_launch` - Triggered on program launch.
*`on_add` - Triggered when a task is added.
A context task will be provided.
The rule can modify the task, and approve or reject it.
*`on_modify` - Triggered when a task is modified.
A before and after context task will be provided.
The rule can modify the task, and approve or reject it.
*`on_exit` - Triggered on program exit.
*`color` - Triggered when colors are being determined.
*`virtual tag` - Defines a new virtual tag.
*`format` - Triggered when an attribute needs formatting, defines are new format.
More rules types will be added for more capabilities in future releases.
## API
The API is a simple set of actions that may be taken by a rule.
*`debug(<string>)` - Displays the string in debug mode only and continues processing.
*`warn(<string>)` - Displays the string as a warning continues processing.
*`error(<string>)` - Displays the string as an error and terminates processing.
*`exec(<binary> [ <args> ... ])` - Executes the external program and passes arguments to it.
If the program exits with non-zero status, it is treated as an error.
*`return <value>` - Provides a result value for the rule, when necessary.
This is a very limited set at first, and more API calls will be added to support capabilities in future releases.
## Grammar
The grammar closely tracks that of Python.
Blocks are indented consistently.
*`if <condition>: ... else: ...` - The condition is a full Algebraic expression, and supports none of the command line conveniences.
Terms must be combined with logical operators.
The condition is an expression that is evaluated and converted to a Boolean value.
*`for <name> in <collection>:` - There is no native type for a collection, but there are DOM references (`tags` \...) that reference collections.
This provides a way to iterate.
*`set <name> = <expression>` - Writes to a named type.
The name may be a writable DOM object (`dom...`) or temporary variable storage (`tmp...`).
Writing to a read-only DOM reference is an error.
*`<function>([<args>])` - A function is either a rule or an API call.
Calling an undefined function is an error.
## Examples
Here are some example rules which illustrate the syntax and API.
The replacement for the nag feature:
rule Nag(before, after) on-modify:
if before.urgency < tasks.max.urgency:
warn ‘You have more urgent tasks’
if after.status == 'completed' and before.urgency < (dom.urgency.max - 2.0):
warn 'You have more urgent tasks!'
Correct commonly misspelled word:
rule CorrectSpelling(task) on_add:
set task.description = substitute(task.description, 'teh', 'the')
Abbreviation expansion:
rule ExpandAbbreviation(task) on_modify:
set task.description = substitute(task.description, '/TW-\d+/', 'https:\/\/github.com\/GothenburgBitFactory\/taskwarrior\/issues\/\1')
This document describes how task changes are merged by the Taskserver.
It does not describe [the protocol](/docs/design/protocol) used by the Taskserver.
The Taskserver merges tasks from multiple sources, resulting in conflict- free syncing of data.
The algorithm used to achieve this is simple and effective, paralleling what SCM systems do to perform a rebase.
## Requirements
In this document, we adopt the convention discussed in Section 1.3.2 of
[RFC1122](https://tools.ietf.org/html/rfc1122#page-16) of using the capitalized words MUST, REQUIRED, SHOULD, RECOMMENDED, MAY, and OPTIONAL to define the significance of each particular requirement specified in this document.
In brief: "MUST" (or "REQUIRED") means that the item is an absolute requirement of the specification; "SHOULD" (or "RECOMMENDED") means there may exist valid reasons for ignoring this item, but the full implications should be understood before doing so; and "MAY" (or "OPTIONAL") means that this item is optional, and may be omitted without careful consideration.
## Problem Definition
The sync algorithm considers a single task, with multiple changes occurring in two separate locations that must be resolved.
The two locations are the local machine and the server.
This results in two parallel change sequences.
Examples using multiple clients collapse down to the simple two-branch case because the clients are merged serially.
## Change Sequence
A sequence of changes to the same task is represented as:
T0 --> T1 --> T2
Although all examples are of the two-branch variety, some involve trivial branches.
Going through these examples will illustrate the algorithm.
First the legend:
T0 Represents the original task, the base.
T1 Represents the task with a non-trivial set of changes.
T2 Represents the task with further changes.
## Deltas
The transition from T0 \--\> T1 can be seen as a transform applied to T0, resulting in T1.
That transform is the delta (d1) between T0 and T1, which is a subtractive term:
d1 = (T1 - T0)
Therefore:
T0 --> T1 = T0 + d1
= T0 + (T1 - T0)
This states that the transition from T0 to T1 is the application of a delta to the original, T0, which results in T1.
Applying this to the whole change sequence yields:
T0 --> T1 --> T2 = T0 + d1 + d2
= T0 + (T1 - T0) + (T2 - T1)
## Use Case Classification
Because clients sync requests are processed serially, there is no need to consider the multiple client cases.
This means there is only ever the case with two parallel change sequences = the two branch case.
## Two Branch Case
The two branch case represents changes made to the same task in two locations, resulting in two deltas that must be applied to the same base.
T0 --> T1
T0 --> T2
This reduces to a base with two deltas, but the order in which the deltas are applied is important.
For example:
T0 + d1 + d2 =/= T0 + d2 + d1
The application of deltas is not commutative, except in the trivial case where the two deltas are identical, or the deltas do not overlap.
The deltas therefore need to be applied in the correct sequence.
Tasks have metadata that indicates the last modified time, which dictates the sequence.
Assuming d1 occurred before d2, this neatly collapses down to a single branch sequence:
T0 + d1 + d2 = T3
Note that the result in this case is T3, because it will be neither T1 nor T2, unless the deltas are identical.
## Two Branch, Multiple Changes Case
The two branch case can be complicated by multiple changes per branch:
T0 --> T1 --> T3 --> T5
T0 --> T2 --> T4
Note that the numbers were chosen to represent the order in which the changes were made.
First a list of deltas is generated:
T0 --> T1 = d1
T1 --> T3 = d3
T3 --> T5 = d5
T0 --> T2 = d2
T0 --> T4 = d4
d1, d3, d5, d2, d4
Then the deltas are sorted by modified time:
d1, d2, d3, d4, d5
Then epplied to the base, yielding T6:
T0 + d1 + d2 + d3 + d4 +d5 = T6
## Two Branch Case Example
Suppose the base task looks like this:
T0 project:ONE due:tomorrow priority:H +tag1 Original description
The first branch looks like this:
T1 project:TWO due:23rd priority:H +tag1 Original description
When Taskwarrior exchanges data, it uses [JSON](https://www.json.org/).
This document describes the structure and semantics for tasks exported from Taskwarrior, imported to Taskwarrior, or synced with the Taskserver.
Any client of the Taskserver will need to communicate task information.
This document describes the format of a single task.
It does not describe the communication and sync protocol between client and server.
This document is subject to change.
The data attributes are also subject to change.
## Requirements
In this document, we adopt the convention discussed in Section 1.3.2 of [RFC1122](https://tools.ietf.org/html/rfc1122#page-16) of using the capitalized words MUST, REQUIRED, SHOULD, RECOMMENDED, MAY, and OPTIONAL to define the significance of each particular requirement specified in this document.
In brief: "MUST" (or "REQUIRED") means that the item is an absolute requirement of the specification; "SHOULD" (or "RECOMMENDED") means there may exist valid reasons for ignoring this item, but the full implications should be understood before doing so; and "MAY" (or "OPTIONAL") means that this item is optional, and may be omitted without careful consideration.
## General Format
The format is JSON, specifically a JSON object as a single line of text, terminated by a newline (U+000D).
The JSON looks like this:
{"description":"One two three","status":"pending", ... }
While this is not a valid task (there are missing fields), the format is illustrated.
All attribute names are quoted with " (U+0022).
A name will always have a corresponding value, and if a value is blank, then the name/value pair is omitted from the line.
Newline characters are not permitted within the value, meaning that a task consists of a single line of text.
All data is UTF8.
## Data Types
There are five data types used in the task format.
## Data Type: String
Strings may consist of any UTF8 encoded characters.
## Data Type: Fixed String
A fixed string is one value from a set of acceptable values, such as a priority level, where the values may only be "", "L", "M" or "H".
## Data Type: UUID
A UUID is a 32-hex-character lower case string, formatted in this way:
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
An example:
296d835e-8f85-4224-8f36-c612cad1b9f8
## Data Type: Integer
Integers are rendered in a simple fashion:
123
## Data Type: Date
Dates are rendered in ISO 8601 combined date and time in UTC format using the template:
YYYYMMDDTHHMMSSZ
An example:
20120110T231200Z
No other formats are supported.
## Data Type: Duration
Duration values represent a time period.
They take the form:
[[<sign>] <number>] <unit>
Some examples include:
- -3days
- annual
- 4hrs
The supported units are:
- annual
- biannual
- bimonthly
- biweekly
- biyearly
- daily
- days
- day
- d
- fortnight
- hours
- hour
- hrs
- hr
- h
- minutes
- mins
- min
- monthly
- months
- month
- mnths
- mths
- mth
- mos
- mo
- quarterly
- quarters
- qrtrs
- qtrs
- qtr
- q
- seconds
- secs
- sec
- s
- semiannual
- sennight
- weekdays
- weekly
- weeks
- week
- wks
- wk
- w
- yearly
- years
- year
- yrs
- yr
- y
Note that some values lack precision, for example "2q" means two quarters, or half a year.
Note that not all combinations of number and unit make sense, for example "3annual" makes no sense, but evaluates to "3years".
## The Attributes
Here are the standard attributes that may comprise a task:
| Name | Type |
|--------------|---------|
| status | String |
| uuid | UUID |
| entry | Date |
| description | String |
| start | Date |
| end | Date |
| due | Date |
| until | Date |
| wait | Date |
| modified | Date |
| scheduled | Date |
| recur | String |
| mask | String |
| imask | Integer |
| parent | UUID |
| project | String |
| priority | String |
| depends | String |
| tags * | String |
| annotation * | String |
| (UDA) | ? |
\* Both tags and annotations are lists of strings and objects.
Any UDA fields are assumed to be of type string.
There are other forms, which are conditional upon the state of a task:
| Status Value | Pending | Deleted | Completed | Waiting | Recurring Parent | Recurring Child |
There are other states in which a task may exist, and the requirements change.
At a minimum, a valid task contains:
- uuid
- status
- entry
- description
*Deleted* - A deleted task MUST also have "status":"deleted", an "end" date and a "modified" date.
*Completed* - A completed task MUST also have "status":"completed", an "end" date and a "modified" date.
*Waiting* - A waiting task MUST also have "status":"waiting" and a "wait" date.
The task is hidden from the user, until that "wait" date has passed, whereupon the status reverts to "pending", and the "wait" date is removed.
*Recurring Parent* - When a recurring task is entered, it MUST have "status":"recurring", a "recur" period and a "due" date.
It MAY also have an "until" date.
Recurring parent tasks are hidden from the user.
*Recurring Child* - A recurring child task is not created by the user, but is cloned from the recurring parent task by the Taskserver.
It may be modified by the user.
On completion, there is special handling to be done.
See section 3.11.
## Additional Attributes
There MAY be other fields than those listed above in a task definition.
Such fields MUST be preserved intact by any client, which means that if a task is downloaded that contains an unrecognized field, that field MUST not be modified, and MUST continue to exist in the task..
User Defined Attributes (UDAs) are additional fields.
## Attribute Details
The individual fields convey important information about a task, and in some cases work only in collusion with other fields.
All such details are listed here.
## Attribute: status
The status field describes the state of the task, which may ONLY be one of these literal strings:
"status":"pending"
"status":"deleted"
"status":"completed"
"status":"waiting"
"status":"recurring"
A pending task is a task that has not yet been completed or deleted.
This is the typical state for a task.
A deleted task is one that has been removed from the pending state, and MUST have an "end" field specified.
Given the required "entry" and "end" field, it can be determined how long the task was pending.
A completed task is one that has been removed from the pending state by completion, and MUST have an "end" field specified.
Given the required "entry" and "end" fields, it can be determine how long the task was pending.
A waiting task is ostensibly a pending task that has been hidden from typical view, and MUST have a "wait" field containing the date when the task is automatically returned to the pending state.
If a client sees a task that is in the waiting state, and the "wait" field is earlier than the current date and time, the client MUST remove the "wait" field and set the "status" field to "pending".
A recurring task is essentially a parent template task from which child tasks are cloned.
The parent remains hidden from view, and contains a "mask" field that represents the recurrences.
Each cloned child task has an "imask" field that indexes into the parent "mask" field, as well as a "parent" field that lists the UUID of the parent.
## Attribute: uuid
When a task is created, it MUST be assigned a new UUID by the client.
Once assigned, a UUID field MUST NOT be modified.
UUID fields are permanent.
## Attribute: entry
When a task is created, it MUST be assigned an "entry" date by the client.
This is the creation date of the task.
## Attribute: description
When a task is created, it MUST have a "description" field value, which contains UTF8 characters.
A "description" field may not contain newline characters, but may contain other characters, properly escaped.
See <https://json.org> for details.
## Attribute: start
To indicate that a task is being worked on, it MAY be assigned a "start" field.
Such a task is then considered Active.
## Attribute: end
When a task is deleted or completed, is MUST be assigned an "end" field.
It is not valid for a task to have an "end" field unless the status is also "completed" or "deleted".
If a completed task is restored to the "pending" state, the "end" field is removed.
## Attribute: due
A task MAY have a "due" field, which indicates when the task should be completed.
## Attribute: until
A recurring task MAY have an "until" field, which is the date after which no more recurring tasks should be generated.
At that time, the parent recurring task is set to "completed".
## Attribute: wait
A task MAY have a "wait" field date, in conjunction with a "status" of "waiting".
A waiting task is one that is not typically shown on reports until it is past the wait date.
An example of this is a birthday reminder.
A task may be entered for a birthday reminder in 10 months time, but can have a "wait" date 9 months from now, which means the task remains hidden until 1 month before the due date.
This prevents long-term tasks from cluttering reports until they become relevant.
## Attribute: recur
The "recur" field is for recurring tasks, and specifies the period between child tasks, in the form of a duration value.
The value is kept in the raw state (such as "3wks") as a string, so that it may be evaluated each time it is needed.
## Attribute: mask
A parent recurring task has a "mask" field that is an array of child status indicators.
Suppose a task is created that is due every week for a month.
The "mask" field will look like:
"----"
This mask has four slots, indicating that there are four child tasks, and each slot indicates, in this case, that the child tasks are pending ("-").
The possible slot indicators are:
*`-` - Pending
*`+` - Completed
*`X` - Deleted
*`W` - Waiting
Suppose the first three tasks has been completed, the mask would look like this:
"+++-"
If there were only three indicators in the mask:
"+-+"
This would indicate that the second task is pending, the first and third are complete, and the fourth has not yet been generated.
## Attribute: imask
Child recurring tasks have an "imask" field instead of a "mask" field like their parent.
The "imask" field is a zero-based integer offset into the "mask" field of the parent.
If a child task is completed, one of the changes that MUST occur is to look up the parent task, and using "imask" set the "mask" of the parent to the correct indicator.
This prevents recurring tasks from being generated twice.
## Attribute: parent
A recurring task instance MUST have a "parent" field, which is the UUID of the task that has "status" of "recurring".
This linkage between tasks, established using "parent", "mask" and "imask" is used to track the need to generate more recurring tasks.
## Attribute: annotation\_\...
Annotations are strings with timestamps.
Each annotation itself has an "entry" field and a "description" field, similar to the task itself.
Annotations form an array named "annotations".
For example (lines broken for clarity):
"annotations":[
{"entry":"20120110T234212Z","description":"Remember to get the mail"},
{"entry":"20120110T234559Z","description":"Pay the bills"}
]
## Attribute: project
A project is a single string.
For example:
"project":"Personal Taxes"
Note that projects receive special handling, so that when a "." (U+002E) is used, it implies a hierarchy, which means the following two projects:
"Home.Kitchen"
"Home.Garden"
are both considered part of the "Home" project.
## Attribute: tags
The "tags" field is an array of string, where each string is a single word containing no spaces.
For example:
"tags":["home","garden"]
## Attribute: priority
The "priority" field, if present, MAY contain one of the following strings:
"priority":"H"
"priority":"M"
"priority":"L"
These represent High, Medium and Low priorities.
An absent priority field indicates no priority.
## Attribute: depends
The "depends" field is a string containing a comma-separated unique set of UUIDs.
If task 2 depends on task 1, then it is task 1 that must be completed first.
Task 1 is considered a "blocking" tasks, and task 2 is considered a "blocked" task.
For example:
"depends":",, ..."
Note that in a future version of this specification, this will be changed to a JSON array of strings, like the "tags" field.
## Attribute: modified
A task MUST have a "modified" field set if it is modified.
This field is of type "date", and is used as a reference when merging tasks.
## Attribute: scheduled
A task MAY have a "scheduled" field, which indicates when the task should be available to start.
A task that has passed its "scheduled" data is said to be "ready".
## User Defined Attributes
A User Defined Attribute (UDA) is a field that is defined via configuration.
Given that the configuration is not present in the JSON format of a task, any fields that are not recognized are to be treated as UDAs.
This means that if a task contains a UDA, unless the meaning of it is understood, it MUST be preserved.
UDAs may have one of four types: string, numeric, date and duration.
@@ -3963,7 +3963,7 @@ GLOUCESTER Give me the letter, sir.
EDMUND I shall offend, either to detain or give it. The contents, as in part I understand them, are to blame.
GLOUCESTER Lets see, lets see.
EDMUND I hope, for my brothers justification, he wrote this but as an essay or taste of my virtue.
GLOUCESTER This policy and reverence of age makes the world bitter to the best of our times, keeps our fortunes from us till our oldness cannot relish them. I begin to find an idle and fond bondage in the oppression of aged tyranny, who sways, not as it hath power, but as it is suffered. Come to me, that of this I may speak more. If our father would sleep till I waked him, you should enjoy half his revenue for ever, and live the beloved of your brother,
GLOUCESTER This policy and reverence of age makes the world bitter to the best of our times, keeps our fortunes from us till our oldness cannot relish them. I begin to find an idle and fond bondage in the oppression of aged tyranny, who sways, not as it hath power, but as it is suffered. Come to me, that of this I may speak more. If our father would sleep till I waked him, you should enjoy half his revenue for ever, and live the beloved of your brother,
EDMUND It was not brought me, my lord, theres the cunning of it, I found it thrown in at the casement of my closet.
GLOUCESTER You know the character to be your brothers?
EDMUND If the matter were good, my lord, I durst swear it were his, but, in respect of that, I would fain think it were not.
local _aliases=( ${(f)"$(task rc.hooks=0 _aliases)"} )
_describe 'task aliases' _aliases
}
@@ -230,7 +230,7 @@ _task_subcommands() {
local cmd category desc
local lastcategory=''
# The list is sorted by category, in the right order.
local _task_zshcmds=( ${(f)"$(task _zshcommands)"} sentinel:sentinel:sentinel )
local _task_zshcmds=( ${(f)"$(task rc.hooks=0 _zshcommands)"} sentinel:sentinel:sentinel )
for _zshcmd in "$_task_zshcmds[@]"; do
# Parse out the three fields
cmd=${_zshcmd%%:*}
@@ -254,7 +254,7 @@ _task_subcommands() {
## contexts
(( $+functions[_task_context] )) ||
_task_context() {
local _contexts=(${(f)"$(task _context)"})
local _contexts=(${(f)"$(task rc.hooks=0 _context)"})
_describe 'task contexts' _contexts
}
@@ -264,7 +264,7 @@ _task_default() {
local cmd ret=1
integer i=1
local _task_cmds=($(task _commands; task _aliases))
local _task_cmds=($(task rc.hooks=0 _commands; task _aliases))
while (( i < $#words ))
do
cmd="${_task_cmds[(r)$words[$i]]}"
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.