Compare commits

...

76 commits

Author SHA1 Message Date
dependabot[bot]
c594ecb58d
Bump sigstore/cosign-installer from 3.8.2 to 3.9.0 (#3902)
Some checks failed
checks / Check & Clippy (push) Has been cancelled
checks / Formatting (push) Has been cancelled
checks / Cargo Metadata (push) Has been cancelled
release-tests / check-tarball (push) Has been cancelled
tests / coverage (push) Has been cancelled
tests / Cargo Test (push) Has been cancelled
tests / tests (Mac OS 12.latest) (push) Has been cancelled
tests / tests (Mac OS 13.latest) (push) Has been cancelled
tests / tests (arch, Archlinux Base (Rolling), ubuntu-latest) (push) Has been cancelled
tests / tests (debiantesting, Debian Testing, ubuntu-latest) (push) Has been cancelled
tests / tests (fedora40, Fedora 40, ubuntu-latest) (push) Has been cancelled
tests / tests (fedora41, Fedora 41, ubuntu-latest) (push) Has been cancelled
tests / tests (opensuse, OpenSUSE Tumbleweed (Rolling), ubuntu-latest) (push) Has been cancelled
tests / tests (ubuntu2004, Ubuntu 20.04, ubuntu-latest) (push) Has been cancelled
tests / tests (ubuntu2204, Ubuntu 22.04, ubuntu-latest) (push) Has been cancelled
Bumps [sigstore/cosign-installer](https://github.com/sigstore/cosign-installer) from 3.8.2 to 3.9.0.
- [Release notes](https://github.com/sigstore/cosign-installer/releases)
- [Commits](https://github.com/sigstore/cosign-installer/compare/v3.8.2...v3.9.0)

---
updated-dependencies:
- dependency-name: sigstore/cosign-installer
  dependency-version: 3.9.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-23 10:18:30 -04:00
pre-commit-ci[bot]
baaf69202b
[pre-commit.ci] pre-commit autoupdate (#3897)
Some checks failed
checks / Check & Clippy (push) Has been cancelled
checks / Formatting (push) Has been cancelled
checks / Cargo Metadata (push) Has been cancelled
release-tests / check-tarball (push) Has been cancelled
tests / coverage (push) Has been cancelled
tests / Cargo Test (push) Has been cancelled
tests / tests (Mac OS 12.latest) (push) Has been cancelled
tests / tests (Mac OS 13.latest) (push) Has been cancelled
tests / tests (arch, Archlinux Base (Rolling), ubuntu-latest) (push) Has been cancelled
tests / tests (debiantesting, Debian Testing, ubuntu-latest) (push) Has been cancelled
tests / tests (fedora40, Fedora 40, ubuntu-latest) (push) Has been cancelled
tests / tests (fedora41, Fedora 41, ubuntu-latest) (push) Has been cancelled
tests / tests (opensuse, OpenSUSE Tumbleweed (Rolling), ubuntu-latest) (push) Has been cancelled
tests / tests (ubuntu2004, Ubuntu 20.04, ubuntu-latest) (push) Has been cancelled
tests / tests (ubuntu2204, Ubuntu 22.04, ubuntu-latest) (push) Has been cancelled
updates:
- [github.com/pre-commit/mirrors-clang-format: v20.1.5 → v20.1.6](https://github.com/pre-commit/mirrors-clang-format/compare/v20.1.5...v20.1.6)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-06-16 14:08:43 -04:00
pre-commit-ci[bot]
a949c698f9
[pre-commit.ci] pre-commit autoupdate (#3887)
Some checks failed
checks / Check & Clippy (push) Has been cancelled
checks / Formatting (push) Has been cancelled
checks / Cargo Metadata (push) Has been cancelled
release-tests / check-tarball (push) Has been cancelled
tests / coverage (push) Has been cancelled
tests / Cargo Test (push) Has been cancelled
tests / tests (Mac OS 12.latest) (push) Has been cancelled
tests / tests (Mac OS 13.latest) (push) Has been cancelled
tests / tests (arch, Archlinux Base (Rolling), ubuntu-latest) (push) Has been cancelled
tests / tests (debiantesting, Debian Testing, ubuntu-latest) (push) Has been cancelled
tests / tests (fedora40, Fedora 40, ubuntu-latest) (push) Has been cancelled
tests / tests (fedora41, Fedora 41, ubuntu-latest) (push) Has been cancelled
tests / tests (opensuse, OpenSUSE Tumbleweed (Rolling), ubuntu-latest) (push) Has been cancelled
tests / tests (ubuntu2004, Ubuntu 20.04, ubuntu-latest) (push) Has been cancelled
tests / tests (ubuntu2204, Ubuntu 22.04, ubuntu-latest) (push) Has been cancelled
updates:
- [github.com/pre-commit/mirrors-clang-format: v20.1.4 → v20.1.5](https://github.com/pre-commit/mirrors-clang-format/compare/v20.1.4...v20.1.5)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-06-14 17:34:59 +02:00
dependabot[bot]
ffa0d3e944
Bump src/taskchampion-cpp/corrosion from 00af456 to 4eccadd (#3893)
Bumps [src/taskchampion-cpp/corrosion](https://github.com/corrosion-rs/corrosion) from `00af456` to `4eccadd`.
- [Release notes](https://github.com/corrosion-rs/corrosion/releases)
- [Commits](00af456488...4eccadd678)

---
updated-dependencies:
- dependency-name: src/taskchampion-cpp/corrosion
  dependency-version: 4eccadd67819b427978ca540e0c31e6cce08f226
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-06 08:08:07 -04:00
dependabot[bot]
6d81c8cda0
Bump src/taskchampion-cpp/corrosion from 715c235 to 00af456 (#3891)
Bumps [src/taskchampion-cpp/corrosion](https://github.com/corrosion-rs/corrosion) from `715c235` to `00af456`.
- [Release notes](https://github.com/corrosion-rs/corrosion/releases)
- [Commits](715c235dae...00af456488)

---
updated-dependencies:
- dependency-name: src/taskchampion-cpp/corrosion
  dependency-version: 00af4564881e9fc031f6b3303c1d6d19ecfe00f3
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-05 11:49:04 -04:00
dependabot[bot]
440d3f8c92
Bump src/libshared from 8ad3646 to 121f757 (#3890)
Bumps [src/libshared](https://github.com/GothenburgBitFactory/libshared) from `8ad3646` to `121f757`.
- [Commits](8ad3646209...121f757c3e)

---
updated-dependencies:
- dependency-name: src/libshared
  dependency-version: 121f757c3ec1b1f548f7835208b8c72d85d141a7
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-02 09:01:53 -04:00
dependabot[bot]
e5b69afee2
Bump docker/build-push-action from 6.16.0 to 6.18.0 (#3889)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 6.16.0 to 6.18.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v6.16.0...v6.18.0)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-version: 6.18.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-02 09:01:38 -04:00
Dustin J. Mitchell
75d351afad
Do not auto-create .taskrc when stdout is not a TTY (#3888)
* Do not auto-create .taskrc when stdout is not a TTY

This avoids prompting or automatically creating such a file, both of
which are unexpected when performing command-line completion.

Fixes #3751.

* Test case for taskrc creation no longer works

A taskrc is only created when stdout is a tty, which would require
allocating a pty, which is very platform-dependent and definitely not
worth the trouble for this test.
2025-06-02 07:59:05 -04:00
Dustin J. Mitchell
f6824e90a1
Correctly handle undo with multiple tasks (#3886)
The `std::stringstream::clear` method does not, in fact, clear the
string -- it just resets some internal flags. Assigning a new
stringstream to the variable is not the most efficient way to do this,
but it's the clearest.
2025-05-26 13:07:35 -04:00
pre-commit-ci[bot]
89d84f0bdd
[pre-commit.ci] pre-commit autoupdate (#3878)
updates:
- [github.com/pre-commit/mirrors-clang-format: v20.1.3 → v20.1.4](https://github.com/pre-commit/mirrors-clang-format/compare/v20.1.3...v20.1.4)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-05-12 14:01:34 -04:00
Dustin J. Mitchell
4620b5fd25
Make tags.none: filter work again (#3877)
* Don't remove the legacy 'tags' property

* Simulate the `tags` DOM property

This refers to the deprecated "tags" property of tasks. This property
usually still exists, for compatibility with older versions, but should
not be relied on anymore.
2025-05-12 08:16:54 +02:00
Tobias Predel
6c60a8db84
Move timegm implementation to libshared (#3875)
Move `timegm` implementation to libshared
2025-05-09 20:26:21 -04:00
Dustin J. Mitchell
79eb38d582
Fix compiler warning about unused variable (#3873)
This was added to indicate that the return value of chdir was unused,
but newer compilers "see through" this and determine it to be unused.
The return value is not marked must-use, so just doing nothing with it
is sufficient.
2025-05-08 17:08:22 +00:00
Antoni Borowski
0e59a62ead
Fix #3571: Added detailed feedback for successful task synchronization (#3758)
* Fix #3571: Added detailed feedback for successful task synchronization

* Refactor sync logic and add verbose output for synchronization operations

* Give a count of local operations sent

---------

Co-authored-by: Antoni Borowski <antoniborowski11@gmail.com>
Co-authored-by: Dustin J. Mitchell <dustin@v.igoro.us>
2025-05-07 18:29:19 -04:00
pre-commit-ci[bot]
97bcc76ac1
[pre-commit.ci] pre-commit autoupdate (#3868)
updates:
- [github.com/pre-commit/mirrors-clang-format: v20.1.0 → v20.1.3](https://github.com/pre-commit/mirrors-clang-format/compare/v20.1.0...v20.1.3)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-05-05 16:55:43 +00:00
Felix Stupp
499f931f67
use cached urgency() for json exports (#3867) 2025-05-05 10:10:02 -04:00
dependabot[bot]
416c6d3ca4
Bump src/libshared from cb078b0 to 8ad3646 (#3864)
Bumps [src/libshared](https://github.com/GothenburgBitFactory/libshared) from `cb078b0` to `8ad3646`.
- [Commits](cb078b00c5...8ad3646209)

---
updated-dependencies:
- dependency-name: src/libshared
  dependency-version: 8ad3646209c8d2e7820c3cd59319a2be3b3d221e
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-05 07:56:13 -04:00
dependabot[bot]
36e5f8895d
Bump src/libshared from 2aa844c to cb078b0 (#3860)
Bumps [src/libshared](https://github.com/GothenburgBitFactory/libshared) from `2aa844c` to `cb078b0`.
- [Commits](2aa844cb9b...cb078b00c5)

---
updated-dependencies:
- dependency-name: src/libshared
  dependency-version: cb078b00c5201e116c9dfd7d6951d954473eaa8f
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-02 08:20:55 -04:00
Dustin J. Mitchell
b4e25fe42f
Do not decode a non-JSON value (#3859)
None of the other task modifications (modify, prepend, append) treat the
input as JSON, so this one shouldn't either. This works around
https://github.com/GothenburgBitFactory/libshared/issues/95
2025-04-30 19:22:44 -04:00
dependabot[bot]
7be313e91f
Bump docker/build-push-action from 6.15.0 to 6.16.0 (#3856)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 6.15.0 to 6.16.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v6.15.0...v6.16.0)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-version: 6.16.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-28 10:54:21 -04:00
dependabot[bot]
36a449c935
Bump sigstore/cosign-installer from 3.8.1 to 3.8.2 (#3855)
Bumps [sigstore/cosign-installer](https://github.com/sigstore/cosign-installer) from 3.8.1 to 3.8.2.
- [Release notes](https://github.com/sigstore/cosign-installer/releases)
- [Commits](https://github.com/sigstore/cosign-installer/compare/v3.8.1...v3.8.2)

---
updated-dependencies:
- dependency-name: sigstore/cosign-installer
  dependency-version: 3.8.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-28 10:54:06 -04:00
Ram-Z
31829d61fc
Add uuid UDA type (#3827)
Mainly so that UDAs that refer to another task can be formated as
"short".
2025-04-20 20:51:38 -04:00
dependabot[bot]
bae37d9448
Bump src/taskchampion-cpp/corrosion from bf065b8 to 715c235 (#3853)
Bumps [src/taskchampion-cpp/corrosion](https://github.com/corrosion-rs/corrosion) from `bf065b8` to `715c235`.
- [Release notes](https://github.com/corrosion-rs/corrosion/releases)
- [Commits](bf065b89a3...715c235dae)

---
updated-dependencies:
- dependency-name: src/taskchampion-cpp/corrosion
  dependency-version: 715c235daef4b8ee67278f12256334ad3dd4c4ae
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-18 13:46:42 -04:00
dependabot[bot]
bfea0f6836
Bump src/taskchampion-cpp/corrosion from c484074 to bf065b8 (#3850)
Bumps [src/taskchampion-cpp/corrosion](https://github.com/corrosion-rs/corrosion) from `c484074` to `bf065b8`.
- [Release notes](https://github.com/corrosion-rs/corrosion/releases)
- [Commits](c4840742d2...bf065b89a3)

---
updated-dependencies:
- dependency-name: src/taskchampion-cpp/corrosion
  dependency-version: bf065b89a33c4d6ce16cae626e8f15f9914ce4dc
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-17 11:45:17 -04:00
Felix Schurk
2a64b5c880
change implementation from has (#3849)
Change from get(uuid, task) to get_task_data to always have a full uuid
match and to improve read performance for the diagnostics command.

See #3848 for details.
2025-04-16 13:49:14 +00:00
Nick Grimshaw
15bb71764e
Redact HTTP credentials from "Syncing…" message (#3846) (#3847) 2025-04-14 17:08:32 +00:00
Adrian Wilkins
5b70ce6be2
Add note about uninstallation (#3845)
* Add note about uninstallation

* [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>
2025-04-10 08:33:52 -04:00
dependabot[bot]
22608cb44e
Bump tokio from 1.44.0 to 1.44.2 (#3843)
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.44.0 to 1.44.2.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.44.0...tokio-1.44.2)

---
updated-dependencies:
- dependency-name: tokio
  dependency-version: 1.44.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-07 22:24:53 -04:00
Dustin J. Mitchell
f1cb656f75
Update tokio to 1.44.2 (#3842) 2025-04-08 00:40:06 +00:00
Dustin J. Mitchell
db23195f4d
Remove duplicate word (#3834)
* Remove duplicate word

* [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>
2025-04-01 22:42:42 +02:00
dependabot[bot]
4a464c13a8
Bump src/taskchampion-cpp/corrosion from fcd8b41 to c484074 (#3836)
Bumps [src/taskchampion-cpp/corrosion](https://github.com/corrosion-rs/corrosion) from `fcd8b41` to `c484074`.
- [Release notes](https://github.com/corrosion-rs/corrosion/releases)
- [Commits](fcd8b41981...c4840742d2)

---
updated-dependencies:
- dependency-name: src/taskchampion-cpp/corrosion
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-31 17:58:09 -04:00
Ram-Z
a3b44bdef5
Replace inacurate comment (#3829) 2025-03-24 19:07:27 -04:00
soerenschneider
bc16297274
docs: Add note to disable AWS lifecycle policies (#3828)
* docs: Add note to disable AWS lifecycle policies

* fix grammar

---------

Co-authored-by: Dustin J. Mitchell <dustin@v.igoro.us>
2025-03-21 12:26:31 +00:00
Felix Schurk
7bf3be2f07
Update dependabot.yml (#3825) 2025-03-19 19:47:52 -04:00
dependabot[bot]
768d45197b
Bump docker/login-action from 3.3.0 to 3.4.0 (#3821)
Bumps [docker/login-action](https://github.com/docker/login-action) from 3.3.0 to 3.4.0.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/v3.3.0...v3.4.0)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-17 20:11:14 -04:00
pre-commit-ci[bot]
f9c17d9b5b
[pre-commit.ci] pre-commit autoupdate (#3822)
* [pre-commit.ci] pre-commit autoupdate

updates:
- [github.com/pre-commit/mirrors-clang-format: v19.1.7 → v20.1.0](https://github.com/pre-commit/mirrors-clang-format/compare/v19.1.7...v20.1.0)

* [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>
2025-03-17 19:50:44 -04:00
Dustin J. Mitchell
1f6e7de569
Release 3.4.1 (#3818) 2025-03-14 10:20:52 +01:00
Kalle Kietäväinen
2ee5fb287c
Fix suppressing news nag after reading the news (#3817)
The news nag suppression regressed again in 5c67d22. That commit
intended to remove the sponsorship outro from the news, but also removed
the bookkeeping that marks the news as read. This commit reverts that
part back to its previous state.
2025-03-13 20:01:16 -04:00
Dustin J. Mitchell
b792018c00
Updates after 3.4.0 (#3816)
* Cargo update
* Update submodules
2025-03-12 22:27:55 +00:00
Dustin J. Mitchell
063325b052
Release 3.4.0 (#3811) 2025-03-12 17:58:49 -04:00
Ram-Z
f73b42d23f
Allow dur/dur division (#3812)
It is perfectly valid to divide two durations, it is a ratio with no
unit.
2025-03-12 16:48:49 -04:00
Dustin J. Mitchell
5c67d22540 Remove sponsorship outro from 'task news' 2025-03-08 12:22:09 -05:00
Tobias Predel
5814526429
Remove headers (#3807) 2025-03-08 09:04:01 -05:00
Dustin J. Mitchell
0c9205aa17
Update ring (#3806) 2025-03-07 00:33:38 +00:00
Dustin J. Mitchell
74276b400c
Generate valid JSON even with invalid dates (#3801) 2025-03-06 16:59:14 +01:00
Dustin J. Mitchell
022650dbff
Make updates after releasing (#3803)
* add symlinks for ease of access
* Update things after making a release, to maximize testing time
2025-03-06 12:43:41 +00:00
Yong Li
5ec0f4ebc0
Update task.1.in (#3804)
Clearly this is an error. The example command should use foo.
2025-03-06 07:33:37 -05:00
Dustin J. Mitchell
3c12c0dfd0
Fix errors finding Rust toolchain (#3802)
* switch to dtolnay/toolchain
* Add .dockerignore to avoid copying target/ into images
* update corrosion
2025-03-06 06:59:04 -05:00
dependabot[bot]
bcb3f820ab
Bump docker/build-push-action from 6.14.0 to 6.15.0 (#3800)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 6.14.0 to 6.15.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v6.14.0...v6.15.0)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-03 16:30:31 -05:00
Tobias Predel
1567ea5c06
Remove header files out of CMakeLists (#3797)
It does not make any difference.
2025-03-03 12:14:39 -05:00
Dustin J. Mitchell
3bb71390a9
Ignore "target" in creating source_package (#3799)
Cargo creates this directory if run directly, but it shouldn't be in the
release tarball.
2025-03-03 17:43:20 +01:00
Tobias Predel
a3e0dada30
Remove unused includes (#3798) 2025-03-02 11:03:18 -05:00
Tobias Predel
81ca04fc8c
Declare in corresponding header files and dissolve main.h (#3796)
* Declare in corresponding header files and dissolve main.h

Apply include-what-you-use

* Remove further unncessary includes

* Incorporate review comment

* Do not declare static functions and variables in header

* Adapt test

* [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>
2025-03-01 14:47:42 -05:00
Tobias Predel
55c02f5420
Remove unused includes (#3795)
* Remove unused include in Variant.h

* Remove unused include in util.h

* Remove unused include directives in util.cpp

* Remove unused include directives in TF2.h

* Remove unused include directives in TF2.cpp

* Remove unused include directive in TDB2.h

* Remove unused include directives in TDB2.cpp

* Remove unused include directives in Task.h

* Remove unused include directive in rules.cpp

* Remove unused include directives in rules.cpp

* Remove unused include directives in nag.cpp

* Remove unused include directive in main.h

* Remove unused include directive in legacy.cpph

* Remove unused include directive in Hooks.cpp

* Remove unused include directive in Filter.h

* Remove unused include directive in Filter.cpp

* Remove unused include directive in feedback.cpp

* Remove unused include directive in Eval.cpp

* Remove unused include directives in dependency.cpp

* Remove unused include directivess in Context.cpp
2025-03-01 10:42:40 -05:00
dependabot[bot]
8e90dc1571
Bump sigstore/cosign-installer from 3.8.0 to 3.8.1 (#3790)
Bumps [sigstore/cosign-installer](https://github.com/sigstore/cosign-installer) from 3.8.0 to 3.8.1.
- [Release notes](https://github.com/sigstore/cosign-installer/releases)
- [Commits](https://github.com/sigstore/cosign-installer/compare/v3.8.0...v3.8.1)

---
updated-dependencies:
- dependency-name: sigstore/cosign-installer
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-24 09:30:15 -05:00
dependabot[bot]
284948d9f9
Bump docker/build-push-action from 6.13.0 to 6.14.0 (#3791)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 6.13.0 to 6.14.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v6.13.0...v6.14.0)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-24 09:30:06 -05:00
Dustin J. Mitchell
a701f8fc7d
Open Replica read-only when possible (#3776)
* Open Replica read-only when possible

Specifically, when either
 - the command is read-only; or
 - the command requires GC (including recurrence updates) but GC is disabled by config

* [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>
2025-02-14 10:25:19 +01:00
dependabot[bot]
a97deb0c84
Bump sigstore/cosign-installer from 3.7.0 to 3.8.0 (#3778)
Bumps [sigstore/cosign-installer](https://github.com/sigstore/cosign-installer) from 3.7.0 to 3.8.0.
- [Release notes](https://github.com/sigstore/cosign-installer/releases)
- [Commits](https://github.com/sigstore/cosign-installer/compare/v3.7.0...v3.8.0)

---
updated-dependencies:
- dependency-name: sigstore/cosign-installer
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-10 10:10:51 -05:00
Dustin J. Mitchell
d6658fe26f
Remove missed handleRecurrence/handleUntil calls (#3771)
These were missed in #3753.
2025-02-06 08:31:33 +01:00
Dustin J. Mitchell
7871617e9c
Only handleRecurrence/handleUntil when rc.gc=1 (#3772) 2025-02-06 08:30:41 +01:00
Dustin J. Mitchell
fdb7e5e020
Test for unusual task data (#3770)
* Test for unusual task data

A task might have any combination of keys and values, but Taskwarrior
often assumes that only valid values can occur, and crashes otherwise.
This is highly inconvenient, as it's often impossible to do anything
with the invalid task -- Taskwarrior just fails without modifying it.

So, this is the beginning of some testing for such invalid tasks, with
the goal of making Taskwarrior due something reasonable. In general, an
invalid attribute value is treated as if it was not set. This is not
exhaustive, and there are likely still bugs of this sort, but as we find
them we can fix and add regression tests to this script.

This introduces a new test-only binary that creates a "bare" task using
TaskChampion, avoiding Taskwarrior's efforts to not create "unusual"
tasks.

* [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>
2025-02-05 08:20:35 -05:00
pre-commit-ci[bot]
e1fc283da5
[pre-commit.ci] pre-commit autoupdate (#3773)
updates:
- [github.com/psf/black: 24.10.0 → 25.1.0](https://github.com/psf/black/compare/24.10.0...25.1.0)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-02-03 13:13:57 -05:00
dependabot[bot]
244513fad7
Bump docker/build-push-action from 6.12.0 to 6.13.0 (#3766)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 6.12.0 to 6.13.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v6.12.0...v6.13.0)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-01 15:51:35 -05:00
Matthew
3ae7413ebd
Update task.md json lines end with \n (0xA) not \r (0xD) (#3752)
Update task.md to fix mistake in json format.  In the code the json lines end with \n (0xA) not \r (0xD)
2025-02-01 15:37:43 -05:00
dependabot[bot]
8d210b5263
Bump docker/build-push-action from 6.11.0 to 6.12.0 (#3761)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 6.11.0 to 6.12.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v6.11.0...v6.12.0)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-20 18:00:57 -05:00
pre-commit-ci[bot]
20417b311e
[pre-commit.ci] pre-commit autoupdate (#3762)
updates:
- [github.com/pre-commit/mirrors-clang-format: v19.1.6 → v19.1.7](https://github.com/pre-commit/mirrors-clang-format/compare/v19.1.6...v19.1.7)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-01-20 13:27:51 -05:00
Dustin J. Mitchell
aeeec16984
Handle 'until' and 'recur' simiar to handling of 'gc' (#3753)
This centralizes updates to recurrence and 'until' in Command, instead
of doing so in each individual command implementation.

This is preparatory to opening the TaskChampion replica in read-only
mode.
2025-01-18 02:20:41 -05:00
Dustin J. Mitchell
1c9dddcae7
Remove unused, undefined method TDB2::dump (#3754) 2025-01-13 08:33:06 -05:00
dependabot[bot]
ffcd1c0d79
Bump docker/build-push-action from 6.10.0 to 6.11.0 (#3755)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 6.10.0 to 6.11.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v6.10.0...v6.11.0)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-13 08:32:46 -05:00
Dustin J. Mitchell
2e5177aa7c
Update to TaskChampion 2.0.2 (#3746) 2025-01-06 13:29:19 -05:00
pre-commit-ci[bot]
ae3651fd3f
[pre-commit.ci] pre-commit autoupdate (#3748)
updates:
- [github.com/pre-commit/mirrors-clang-format: v19.1.5 → v19.1.6](https://github.com/pre-commit/mirrors-clang-format/compare/v19.1.5...v19.1.6)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-01-06 12:48:12 -05:00
Dustin J. Mitchell
ddeec3512a
Add more CMake options to INSTALL (#3743) 2025-01-01 13:29:17 -05:00
Karl
630585d7b4
Update git log in CMakeLists.txt to not include potential signatures (#3742) 2024-12-31 13:51:35 -05:00
jrmarino
9105985c7c
Add offline build notes to INSTALL (#3705) (#3740)
Document additional steps that have been successful for NixOS and Ravenports.
2024-12-31 17:28:48 +00:00
Tejada-Omar
3bf0200602
Consider news read if news.version > current version (#3734)
Avoids two installations of taskwarrior with differing versions from
constantly nagging and rewriting `news.version`
2024-12-23 11:34:51 -05:00
Kalle Kietäväinen
1b9353dccc
Fix suppressing news nag after reading the news (#3731) 2024-12-20 13:13:23 +01:00
136 changed files with 2179 additions and 940 deletions

1
.dockerignore Normal file
View file

@ -0,0 +1 @@
target

View file

@ -5,6 +5,11 @@ updates:
directory: "/"
schedule:
interval: "weekly"
# Enable version updates for git submodules
- package-ecosystem: "gitsubmodule"
directory: "/"
schedule:
interval: "daily"
# Enable updates for Rust packages
- package-ecosystem: "cargo"
directory: "/" # Location of package manifests

View file

@ -15,25 +15,25 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
id: toolchain
with:
# If this version is old enough to cause errors, or older than the
# TaskChampion MSRV, bump it to the MSRV of the currently-required
# TaskChampion package; if necessary, bump that version as well.
toolchain: "1.81.0" # MSRV
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: ~/.cargo/registry
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
key: ${{ runner.os }}-cargo-registry-${{ steps.toolchain.outputs.cachekey }}-${{ hashFiles('**/Cargo.lock') }}
- name: Cache cargo build
uses: actions/cache@v4
with:
path: target
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}
- uses: actions-rs/toolchain@v1
with:
# If this version is old enough to cause errors, or older than the
# TaskChampion MSRV, bump it to the MSRV of the currently-required
# TaskChampion package; if necessary, bump that version as well.
toolchain: "1.78.0" # MSRV
override: true
key: ${{ runner.os }}-cargo-build-target-${{ steps.toolchain.outputs.cachekey }}-${{ hashFiles('**/Cargo.lock') }}
- uses: actions-rs/cargo@v1.0.3
with:
@ -53,12 +53,11 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: actions-rs/toolchain@v1
- uses: dtolnay/rust-toolchain@master
id: toolchain
with:
profile: minimal
components: rustfmt
toolchain: stable
override: true
toolchain: "stable"
components: "rustfmt"
- uses: actions-rs/cargo@v1.0.3
with:
@ -71,12 +70,11 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: actions-rs/toolchain@v1
- uses: dtolnay/rust-toolchain@master
id: toolchain
with:
profile: minimal
components: rustfmt
toolchain: stable
override: true
toolchain: "stable"
components: "rustfmt"
- name: "Check metadata"
run: ".github/workflows/metadata-check.sh"

View file

@ -33,10 +33,10 @@ jobs:
submodules: "recursive"
- name: Install cosign
uses: sigstore/cosign-installer@v3.7.0
uses: sigstore/cosign-installer@v3.9.0
- name: Log into registry ${{ env.REGISTRY }}
uses: docker/login-action@v3.3.0
uses: docker/login-action@v3.4.0
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.repository_owner }}
@ -44,7 +44,7 @@ jobs:
- name: Build and push Taskwarrior Docker image
id: build-and-push
uses: docker/build-push-action@v6.10.0
uses: docker/build-push-action@v6.18.0
with:
context: .
file: "./docker/task.dockerfile"

View file

@ -6,16 +6,14 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
id: toolchain
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: ~/.cargo/registry
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
- uses: actions-rs/toolchain@v1
with:
toolchain: "stable"
override: true
key: ${{ runner.os }}-cargo-registry-${{ steps.toolchain.outputs.cachekey }}-${{ hashFiles('**/Cargo.lock') }}
- name: Install uuid-dev
run: sudo apt install uuid-dev

View file

@ -43,22 +43,20 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
id: toolchain
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: ~/.cargo/registry
key: ${{ runner.os }}-stable-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
key: ${{ runner.os }}-cargo-registry-${{ steps.toolchain.outputs.cachekey }}-${{ hashFiles('**/Cargo.lock') }}
- name: Cache cargo build
uses: actions/cache@v4
with:
path: target
key: ${{ runner.os }}-stable-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}
- uses: actions-rs/toolchain@v1
with:
toolchain: "stable"
override: true
key: ${{ runner.os }}-cargo-build-target-${{ steps.toolchain.outputs.cachekey }}-${{ hashFiles('**/Cargo.lock') }}
- name: Test MacOS
run: bash test/scripts/test_macos.sh
@ -72,22 +70,20 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
id: toolchain
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: ~/.cargo/registry
key: ${{ runner.os }}-stable-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
key: ${{ runner.os }}-cargo-registry-${{ steps.toolchain.outputs.cachekey }}-${{ hashFiles('**/Cargo.lock') }}
- name: Cache cargo build
uses: actions/cache@v4
with:
path: target
key: ${{ runner.os }}-stable-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}
- uses: actions-rs/toolchain@v1
with:
toolchain: "stable"
override: true
key: ${{ runner.os }}-cargo-build-target-${{ steps.toolchain.outputs.cachekey }}-${{ hashFiles('**/Cargo.lock') }}
- name: Test MacOS
run: bash test/scripts/test_macos.sh
@ -101,26 +97,25 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
id: toolchain
with:
# If this version is old enough to cause errors, or older than the
# TaskChampion MSRV, bump it to the MSRV of the currently-required
# TaskChampion package; if necessary, bump that version as well.
toolchain: "1.81.0" # MSRV
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: ~/.cargo/registry
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
key: ${{ runner.os }}-cargo-registry-${{ steps.toolchain.outputs.cachekey }}-${{ hashFiles('**/Cargo.lock') }}
- name: Cache cargo build
uses: actions/cache@v4
with:
path: target
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}
- uses: actions-rs/toolchain@v1
with:
# If this version is old enough to cause errors, or older than the
# TaskChampion MSRV, bump it to the MSRV of the currently-required
# TaskChampion package; if necessary, bump that version as well.
# This should match the MSRV in `src/taskchampion-cpp/Cargo.toml`.
toolchain: "1.78.0" # MSRV
override: true
key: ${{ runner.os }}-cargo-build-target-${{ steps.toolchain.outputs.cachekey }}-${{ hashFiles('**/Cargo.lock') }}
- uses: actions-rs/cargo@v1.0.3
with:

View file

@ -9,11 +9,11 @@ repos:
- id: check-yaml
- id: check-added-large-files
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: v19.1.5
rev: v20.1.6
hooks:
- id: clang-format
types_or: [c++, c]
- repo: https://github.com/psf/black
rev: 24.10.0
rev: 25.1.0
hooks:
- id: black

View file

@ -4,7 +4,7 @@ enable_testing()
set (CMAKE_EXPORT_COMPILE_COMMANDS ON)
project (task
VERSION 3.3.0
VERSION 3.4.1
DESCRIPTION "Taskwarrior - a command-line TODO list manager"
HOMEPAGE_URL https://taskwarrior.org/)
@ -37,7 +37,7 @@ endif (EXISTS ${CMAKE_SOURCE_DIR}/src/libshared/src AND EXISTS ${CMAKE_SOURCE_DI
message ("-- Looking for SHA1 references")
if (EXISTS ${CMAKE_SOURCE_DIR}/.git/index)
set (HAVE_COMMIT true)
execute_process (COMMAND git log -1 --pretty=format:%h
execute_process (COMMAND git log -1 --pretty=format:%h --no-show-signature
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE COMMIT)
configure_file ( ${CMAKE_SOURCE_DIR}/commit.h.in
@ -67,7 +67,6 @@ SET (TASK_BINDIR bin CACHE STRING "Installation directory for the bi
# rust libs require these
set (TASK_LIBRARIES dl pthread)
check_function_exists (timegm HAVE_TIMEGM)
check_function_exists (get_current_dir_name HAVE_GET_CURRENT_DIR_NAME)
check_function_exists (wordexp HAVE_WORDEXP)
@ -162,6 +161,6 @@ endforeach (doc_FILE)
set (CPACK_SOURCE_GENERATOR "TGZ")
set (CPACK_SOURCE_PACKAGE_FILE_NAME ${PACKAGE_NAME}-${PACKAGE_VERSION})
set (CPACK_SOURCE_IGNORE_FILES "build" "test" "misc/*" "performance" "swp$" "src/lex$" "task-.*.tar.gz"
set (CPACK_SOURCE_IGNORE_FILES "build" "target" "test" "misc/*" "performance" "swp$" "src/lex$" "task-.*.tar.gz"
"commit.h" "cmake.h$" "\\\\.gitmodules" "src/libshared/\\\\.git" ".github/" ".*\\\\.gitignore$" "docker-compose.yml" "\\\\.git/")
include (CPack)

1
CONTRIBUTING.md Symbolic link
View file

@ -0,0 +1 @@
doc/devel/contrib/development.md

1165
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,11 +1,36 @@
------ current release ---------------------------
3.4.1 -
- The nagging to read `task news` has been fixed.
------ old releases ------------------------------
3.4.0 -
- Where possible, the task DB is now opened in read-only mode, which improves
performance. This is the case for reports (task lists) only when the `gc`
config is false.
- An updated version of corrosion fixes build errors trying to find the Rust
toolchain.
Thanks to the following people for contributions to this release:
- Dustin J. Mitchell
- Kalle Kietäväinen
- Karl
- Matthew
- Tejada-Omar
- Tobias Predel
- Yong Li
- jrmarino
3.3.0 -
- Sync now supports AWS S3 as a backend.
- A new `task import-v2` command allows importing Taskwarrior-2.x
data files directly.
3.3.0 -
Thanks to the following people for contributions to this release:
- Chongyun Lee
@ -18,8 +43,6 @@ Thanks to the following people for contributions to this release:
- Scott Mcdermott
- Thomas Lauf
------ old releases ------------------------------
3.2.0 -
- Support for the journal in `task info` has been restored (#3671) and the

53
INSTALL
View file

@ -22,7 +22,7 @@ You will need the following libraries:
- libuuid (not needed for OSX)
You will need a Rust toolchain of the Minimum Supported Rust Version (MSRV):
- rust 1.78.0
- rust 1.81.0
Basic Installation
------------------
@ -34,7 +34,7 @@ Briefly, these shell commands will unpack, build and install Taskwarrior:
$ cmake -S . -B build -DCMAKE_BUILD_TYPE=Release . [3]
$ cmake --build build [4]
$ sudo cmake --install build [5]
$ cd .. ; rm -r task-X.Y.Z [6]
$ cd .. ; rm -r task-X.Y.Z [6] (see: Uninstallation)
These commands are explained below:
@ -89,6 +89,11 @@ get absolute installation directories:
CMAKE_INSTALL_PREFIX/TASK_MAN1DIR /usr/local/share/man/man1
CMAKE_INSTALL_PREFIX/TASK_MAN5DIR /usr/local/share/man/man5
The following variables control aspects of the build process:
SYSTEM_CORROSION - Use system provided corrosion instead of vendored version
ENABLE_TLS_NATIVE_ROOTS - Use the system's TLS root certificates
Uninstallation
--------------
@ -98,6 +103,13 @@ There is no uninstall option in CMake makefiles. This is a manual process.
To uninstall Taskwarrior, remove the files listed in the install_manifest.txt
file that was generated when you built Taskwarrior.
```sh
cd task-X.Y.Z
sudo xargs rm < build/install_manifest.txt
```
If you want to uninstall this way, you will need to omit step [6] above and
retain the source folder after installation.
Taskwarrior Build Notes
-----------------------
@ -110,6 +122,43 @@ If Taskwarrior will not build on your system, first take a look at the Operating
System notes below. If this doesn't help, then go to the Troubleshooting
section, which includes instructions on how to contact us for help.
Offline Build Notes
-------------------
It is common for packaging systems (e.g. NixOS, FreeBSD Ports Collection, pkgsrc, etc)
to disable networking during builds. This restriction requires all distribution files
to be prepositioned after checksum verification as a prerequisite for the build. The
following steps have been successful in allowing Taskwarrior to be built in this
environment:
1. Extract all crates in a known location, e.g. ${WRKDIR}/cargo-crates
This includes crates needed for corrosion (search for Cargo.lock files)
2. Create .cargo-checksum.json for each crate
For example:
printf '{"package":"%s","files":{}}' $(sha256 -q ${DISTDIR}/rayon-core-1.12.1.tar.gz) \
> ${WRKDIR}/cargo-crates/rayon-core-1.12.1/.cargo-checksum.json
3. Create a custom config.toml file
For example, ${WRKDIR}/.cargo/config.toml
[source.cargo]
directory = '${WRKDIR}/cargo-crates'
[source.crates-io]
replace-with = 'cargo'
4. After running cmake, configure cargo
For example:
cd ${WRKSRC} && ${SETENV} ${MAKE_ENV} ${CARGO_ENV} \
/usr/local/bin/cargo update \
--manifest-path ${WRKDIR}/.cargo/config.toml \
--verbose
5. Set CARGO_HOME in environment
For example
CARGO_HOME=${WRKDIR}/.cargo
The build and installation steps should be the same as a standard build
at this point.
Operating System Notes
----------------------

1
RELEASING.md Symbolic link
View file

@ -0,0 +1 @@
doc/devel/contrib/releasing.md

View file

@ -41,9 +41,6 @@
/* Found tm_gmtoff */
#cmakedefine HAVE_TM_GMTOFF
/* Found timegm */
#cmakedefine HAVE_TIMEGM
/* Found st.st_birthtime struct member */
#cmakedefine HAVE_ST_BIRTHTIME

View file

@ -24,3 +24,6 @@ To release Taskwarrior, follow this process:
- Add a new item in `content/news`
- Update `data/projects.json` with the latest version and a fake next version for "devel"
- Update `data/releases.json` with the new version, and copy the tarball into `content/download`.
- Update various things, in a new PR:
- `cargo update`
- `git submodule update --remote --merge`

View file

@ -25,7 +25,7 @@ In brief: "MUST" (or "REQUIRED") means that the item is an absolute requirement
## General Format
The format is JSON, specifically a JSON object as a single line of text, terminated by a newline (U+000D).
The format is JSON, specifically a JSON object as a single line of text, terminated by a line feed (U+000A).
The JSON looks like this:

View file

@ -143,7 +143,9 @@ Then configure Taskwarrior with:
To synchronize your tasks to AWS, select a region near you and use the AWS
console to create a new S3 bucket. The default settings for the bucket are
adequate.
adequate. In particular, ensure that no lifecycle policies are enabled, as they
may automatically delete or transition objects, potentially impacting data
availability.
You will also need an AWS IAM user with the following policy, where BUCKETNAME
is the name of the bucket. The same user can be configured for multiple

View file

@ -1037,7 +1037,7 @@ modifier requires that the attribute contain the whole word specified, such
that this:
.nf
task description.word:bar list
task description.word:foo list
.fi
Will match the description 'foo bar baz' but does not match 'dog food'.

View file

@ -212,6 +212,9 @@ This is a path to the hook scripts directory. By default it is ~/.task/hooks.
.TP
.B gc=1
Can be used to temporarily suspend rebuilding, so that task IDs don't change.
Rebuilding requires read/write access to the database, so disabling `gc` may
result in better performance.
Note that this should be used in the form of a command line override (task
rc.gc=0 ...), and not permanently used in the .taskrc file, as this
significantly affects performance in the long term.
@ -1381,7 +1384,7 @@ if you define a UDA named 'estimate', Taskwarrior will not know that this value
is weeks, hours, minutes, money, or some other resource count.
.TP
.B uda.<name>.type=string|numeric|date|duration
.B uda.<name>.type=string|numeric|uuid|date|duration
.RS
Defines a UDA called '<name>', of the specified type.
.RE

View file

@ -6,20 +6,20 @@ include_directories (${CMAKE_SOURCE_DIR}
${CMAKE_SOURCE_DIR}/src/libshared/src
${TASK_INCLUDE_DIRS})
add_library (task STATIC CLI2.cpp CLI2.h
Context.cpp Context.h
DOM.cpp DOM.h
Eval.cpp Eval.h
Filter.cpp Filter.h
Hooks.cpp Hooks.h
Lexer.cpp Lexer.h
Operation.cpp Operation.h
TF2.cpp TF2.h
TDB2.cpp TDB2.h
Task.cpp Task.h
Variant.cpp Variant.h
Version.cpp Version.h
ViewTask.cpp ViewTask.h
add_library (task STATIC CLI2.cpp
Context.cpp
DOM.cpp
Eval.cpp
Filter.cpp
Hooks.cpp
Lexer.cpp
Operation.cpp
TF2.cpp
TDB2.cpp
Task.cpp
Variant.cpp
Version.cpp
ViewTask.cpp
dependency.cpp
feedback.cpp
legacy.cpp
@ -27,26 +27,25 @@ add_library (task STATIC CLI2.cpp CLI2.h
recur.cpp
rules.cpp
sort.cpp
util.cpp util.h)
util.cpp)
target_link_libraries(task taskchampion-cpp)
add_library (libshared STATIC libshared/src/Color.cpp libshared/src/Color.h
libshared/src/Configuration.cpp libshared/src/Configuration.h
libshared/src/Datetime.cpp libshared/src/Datetime.h
libshared/src/Duration.cpp libshared/src/Duration.h
libshared/src/FS.cpp libshared/src/FS.h
libshared/src/JSON.cpp libshared/src/JSON.h
libshared/src/Msg.cpp libshared/src/Msg.h
libshared/src/Pig.cpp libshared/src/Pig.h
libshared/src/RX.cpp libshared/src/RX.h
libshared/src/Table.cpp libshared/src/Table.h
libshared/src/Timer.cpp libshared/src/Timer.h
libshared/src/format.cpp libshared/src/format.h
add_library (libshared STATIC libshared/src/Color.cpp
libshared/src/Configuration.cpp
libshared/src/Datetime.cpp
libshared/src/Duration.cpp
libshared/src/FS.cpp
libshared/src/JSON.cpp
libshared/src/Msg.cpp
libshared/src/Pig.cpp
libshared/src/RX.cpp
libshared/src/Table.cpp
libshared/src/Timer.cpp
libshared/src/format.cpp
libshared/src/ip.cpp
libshared/src/shared.cpp libshared/src/shared.h
libshared/src/unicode.cpp libshared/src/unicode.h
libshared/src/utf8.cpp libshared/src/utf8.h
libshared/src/wcwidth.h)
libshared/src/shared.cpp
libshared/src/unicode.cpp
libshared/src/utf8.cpp)
add_executable (task_executable main.cpp)
add_executable (calc_executable calc.cpp)

View file

@ -36,16 +36,15 @@
#include <Version.h>
#include <assert.h>
#include <format.h>
#include <main.h>
#include <recur.h>
#include <rules.h>
#include <rust/cxx.h>
#include <shared.h>
#include <stdlib.h>
#include <string.h>
#include <taskchampion-cpp/lib.h>
#include <unistd.h>
#include <algorithm>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <regex>
@ -55,7 +54,6 @@
#include <commit.h>
#endif
#include <stdio.h>
#include <sys/ioctl.h>
#ifdef SOLARIS
@ -598,9 +596,6 @@ int Context::initialize(int argc, const char** argv) {
createDefaultConfig();
bool create_if_missing = !config.getBoolean("exit.on.missing.db");
tdb2.open_replica(data_dir, create_if_missing);
////////////////////////////////////////////////////////////////////////////
//
// [3] Instantiate Command objects and capture command entities.
@ -674,6 +669,21 @@ int Context::initialize(int argc, const char** argv) {
if (foundAssumed) header("No command specified - assuming 'information'.");
}
////////////////////////////////////////////////////////////////////////////
//
// [7.5] Open the Replica.
//
////////////////////////////////////////////////////////////////////////////
bool create_if_missing = !config.getBoolean("exit.on.missing.db");
Command* c = commands[cli2.getCommand()];
// We must allow writes if either 'gc' is enabled and the command performs GC, or the command
// itself is read-write.
bool read_write =
(config.getBoolean("gc") && (c->needs_gc() || c->needs_recur_update())) || !c->read_only();
tdb2.open_replica(data_dir, create_if_missing, read_write);
////////////////////////////////////////////////////////////////////////////
//
// [8] Initialize hooks.
@ -852,7 +862,7 @@ int Context::dispatch(std::string& out) {
Command* c = commands[command];
assert(c);
// The command know whether they need a GC.
// The command know whether they need a GC or recurrence update.
if (c->needs_gc()) {
tdb2.gc();
}
@ -869,6 +879,11 @@ int Context::dispatch(std::string& out) {
if (config.getBoolean("debug") && config.getInteger("debug.parser") == 1)
debug(cli2.dump("Parse Tree (before command-specifіc processing)"));
if (c->needs_recur_update() && Context::getContext().config.getBoolean("gc")) {
handleUntil();
handleRecurrence();
}
return c->execute(out);
}
@ -1158,6 +1173,13 @@ void Context::staticInitialization() {
void Context::createDefaultConfig() {
// Do we need to create a default rc?
if (rc_file._data != "" && !rc_file.exists()) {
// If stdout is not a file, we are probably executing in a completion context and should not
// prompt (as the user won't see it) or modify the config (as completion functions are typically
// read-only).
if (!isatty(STDOUT_FILENO)) {
throw std::string("Cannot proceed without rc file.");
}
if (config.getBoolean("confirmation") &&
!confirm(format("A configuration file could not be found in {1}\n\nWould you like a sample "
"{2} created, so Taskwarrior can proceed?",

View file

@ -286,6 +286,13 @@ bool getDOM(const std::string& name, const Task* task, Variant& value) {
return true;
}
// The "tags" property is deprecated, but it is documented as part of the DOM, so simulate it.
if (size == 1 && canonical == "tags") {
auto tags = ref->getTags();
value = Variant(join(",", tags));
return true;
}
Column* column = Context::getContext().columns[canonical];
if (size == 1 && column) {

View file

@ -34,7 +34,6 @@
#include <Task.h>
#include <format.h>
#include <shared.h>
#include <time.h>
#include <map>

View file

@ -36,8 +36,6 @@
#include <format.h>
#include <shared.h>
#include <algorithm>
////////////////////////////////////////////////////////////////////////////////
// Take an input set of tasks and filter into a subset.
void Filter::subset(const std::vector<Task>& input, std::vector<Task>& output) {

View file

@ -30,7 +30,6 @@
#include <Task.h>
#include <Variant.h>
#include <string>
#include <vector>
class Filter {

View file

@ -44,7 +44,6 @@
#include <Variant.h>
#include <format.h>
#include <shared.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
@ -276,7 +275,7 @@ void Hooks::onAdd(Task& task) const {
// - all emitted non-JSON lines are considered feedback or error messages
// depending on the status code.
//
void Hooks::onModify(const Task& before, Task& after) const {
void Hooks::onModify(Task& before, Task& after) const {
if (!_enabled) return;
Timer timer;

View file

@ -40,7 +40,7 @@ class Hooks {
void onLaunch() const;
void onExit() const;
void onAdd(Task&) const;
void onModify(const Task&, Task&) const;
void onModify(Task&, Task&) const;
std::vector<std::string> list() const;
private:

View file

@ -1,6 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
//
// Copyright 2006 - 2024, Tomas Babej, Paul Beckingham, Federico Hernandez.
// Copyright 2006 - 2025, Tomas Babej, Paul Beckingham, Federico Hernandez,
// Tobias Predel.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -24,8 +25,8 @@
//
////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDED_OPERATIOn
#define INCLUDED_OPERATIOn
#ifndef INCLUDED_OPERATION
#define INCLUDED_OPERATION
#include <taskchampion-cpp/lib.h>

View file

@ -33,16 +33,11 @@
#include <TDB2.h>
#include <Table.h>
#include <format.h>
#include <main.h>
#include <shared.h>
#include <signal.h>
#include <stdlib.h>
#include <util.h>
#include <algorithm>
#include <iostream>
#include <list>
#include <sstream>
#include <unordered_set>
#include <vector>
@ -50,17 +45,16 @@ bool TDB2::debug_mode = false;
static void dependency_scan(std::vector<Task>&);
////////////////////////////////////////////////////////////////////////////////
void TDB2::open_replica(const std::string& location, bool create_if_missing) {
_replica = tc::new_replica_on_disk(location, create_if_missing);
void TDB2::open_replica(const std::string& location, bool create_if_missing, bool read_write) {
_replica = tc::new_replica_on_disk(location, create_if_missing, read_write);
}
////////////////////////////////////////////////////////////////////////////////
void TDB2::open_replica_in_memory() { _replica = tc::new_replica_in_memory(); }
////////////////////////////////////////////////////////////////////////////////
// Add the new task to the replica.
void TDB2::add(Task& task) {
// Validate a task for addition. This is stricter than `task.validate`, as any
// inconsistency is probably user error.
task.validate_add();
// Ensure the task is consistent, and provide defaults if necessary.
// bool argument to validate() is "applyDefault", to apply default values for
// properties not otherwise given.
@ -194,11 +188,8 @@ void TDB2::purge(Task& task) {
////////////////////////////////////////////////////////////////////////////////
rust::Box<tc::Replica>& TDB2::replica() {
// Create a replica in-memory if `open_replica` has not been called. This
// occurs in tests.
if (!_replica) {
_replica = tc::new_replica_in_memory();
}
// One of the open_replica_ methods must be called before this one.
assert(_replica);
return _replica.value();
}
@ -363,8 +354,7 @@ bool TDB2::get(const std::string& uuid, Task& task) {
////////////////////////////////////////////////////////////////////////////////
// Locate task by UUID, wherever it is.
bool TDB2::has(const std::string& uuid) {
Task task;
return get(uuid, task);
return replica()->get_task_data(tc::uuid_from_string(uuid)).is_some();
}
////////////////////////////////////////////////////////////////////////////////
@ -450,11 +440,6 @@ int TDB2::num_local_changes() { return (int)replica()->num_local_operations(); }
////////////////////////////////////////////////////////////////////////////////
int TDB2::num_reverts_possible() { return (int)replica()->num_undo_points(); }
////////////////////////////////////////////////////////////////////////////////
void TDB2::dump() {
// TODO
}
////////////////////////////////////////////////////////////////////////////////
// For any task that has depenencies, follow the chain of dependencies until the
// end. Along the way, update the Task::is_blocked and Task::is_blocking data

View file

@ -27,9 +27,7 @@
#ifndef INCLUDED_TDB2
#define INCLUDED_TDB2
#include <FS.h>
#include <Task.h>
#include <stdio.h>
#include <taskchampion-cpp/lib.h>
#include <map>
@ -46,7 +44,8 @@ class TDB2 {
TDB2() = default;
void open_replica(const std::string &, bool create_if_missing);
void open_replica(const std::string &, bool create_if_missing, bool read_write);
void open_replica_in_memory();
void add(Task &);
void modify(Task &);
void purge(Task &);
@ -72,8 +71,6 @@ class TDB2 {
int num_local_changes();
int num_reverts_possible();
void dump();
rust::Box<tc::Replica> &replica();
private:

View file

@ -31,18 +31,12 @@
#include <Table.h>
#include <cmake.h>
#include <format.h>
#include <main.h>
#ifdef PRODUCT_TASKWARRIOR
#include <legacy.h>
#endif
#include <shared.h>
#include <signal.h>
#include <stdlib.h>
#include <util.h>
#include <algorithm>
#include <iostream>
#include <list>
#include <set>
#include <sstream>
#define STRING_TDB2_REVERTED "Modified task reverted."
////////////////////////////////////////////////////////////////////////////////

View file

@ -29,12 +29,9 @@
#include <FS.h>
#include <Task.h>
#include <stdio.h>
#include <map>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
// TF2 Class represents a single 2.x-style file in the task database.

View file

@ -58,7 +58,8 @@
#include <Eval.h>
#include <Filter.h>
#include <Variant.h>
#include <main.h>
#include <dependency.h>
#include <feedback.h>
#define APPROACHING_INFINITY 1000 // Close enough. This isn't rocket surgery.
@ -321,8 +322,8 @@ void Task::setStatus(Task::status status) {
////////////////////////////////////////////////////////////////////////////////
// Determines status of a date attribute.
Task::dateState Task::getDateState(const std::string& name) const {
std::string value = get(name);
if (value.length()) {
time_t value = get_date(name);
if (value > 0) {
Datetime reference(value);
Datetime now;
Datetime today("today");
@ -776,7 +777,7 @@ void Task::parseLegacy(const std::string& line) {
}
////////////////////////////////////////////////////////////////////////////////
std::string Task::composeJSON(bool decorate /*= false*/) const {
std::string Task::composeJSON(bool decorate /*= false*/) {
std::stringstream out;
out << '{';
@ -797,20 +798,23 @@ std::string Task::composeJSON(bool decorate /*= false*/) const {
// If value is an empty string, do not ever output it
if (i.second == "") continue;
if (attributes_written) out << ',';
std::string type = Task::attributes[i.first];
if (type == "") type = "string";
// Date fields are written as ISO 8601.
if (type == "date") {
Datetime d(i.second);
out << '"' << (i.first == "modification" ? "modified" : i.first)
<< "\":\""
// Date was deleted, do not export parsed empty string
<< (i.second == "" ? "" : d.toISO()) << '"';
time_t epoch = get_date(i.first);
if (epoch != 0) {
Datetime d(i.second);
if (attributes_written) out << ',';
++attributes_written;
out << '"' << (i.first == "modification" ? "modified" : i.first)
<< "\":\""
// Date was deleted, do not export parsed empty string
<< (i.second == "" ? "" : d.toISO()) << '"';
++attributes_written;
}
}
/*
@ -820,6 +824,8 @@ std::string Task::composeJSON(bool decorate /*= false*/) const {
}
*/
else if (type == "numeric") {
if (attributes_written) out << ',';
out << '"' << i.first << "\":" << i.second;
++attributes_written;
@ -827,6 +833,8 @@ std::string Task::composeJSON(bool decorate /*= false*/) const {
// Everything else is a quoted value.
else {
if (attributes_written) out << ',';
out << '"' << i.first << "\":\"" << (type == "string" ? json::encode(i.second) : i.second)
<< '"';
@ -886,7 +894,7 @@ std::string Task::composeJSON(bool decorate /*= false*/) const {
#ifdef PRODUCT_TASKWARRIOR
// Include urgency.
if (decorate) out << ',' << "\"urgency\":" << urgency_c();
if (decorate) out << ',' << "\"urgency\":" << urgency();
#endif
out << '}';
@ -920,7 +928,7 @@ void Task::addAnnotation(const std::string& description) {
++now;
} while (has(key));
data[key] = json::decode(description);
data[key] = description;
++annotation_count;
recalc_urgency = true;
}
@ -1991,7 +1999,7 @@ void Task::modify(modType type, bool text_required /* = false */) {
// Delegate modification to the column object or their base classes.
if (name == "depends" || name == "tags" || name == "recur" || column->type() == "date" ||
column->type() == "duration" || column->type() == "numeric" ||
column->type() == "string") {
column->type() == "string" || column->type() == "uuid") {
column->modify(*this, value);
mods = true;
}

View file

@ -30,7 +30,6 @@
#include <Datetime.h>
#include <JSON.h>
#include <Table.h>
#include <stdio.h>
#include <taskchampion-cpp/lib.h>
#include <time.h>
@ -69,7 +68,7 @@ class Task {
Task(rust::Box<tc::TaskData>);
void parse(const std::string&);
std::string composeJSON(bool decorate = false) const;
std::string composeJSON(bool decorate = false);
// Status values.
enum status { pending, completed, deleted, recurring, waiting };

View file

@ -75,7 +75,6 @@
#define STRING_VARIANT_DIV_DUR_BOOL "Cannot divide duration by Boolean"
#define STRING_VARIANT_DIV_DUR_STR "Cannot divide durations by strings"
#define STRING_VARIANT_DIV_DUR_DATE "Cannot divide durations by dates"
#define STRING_VARIANT_DIV_DUR_DUR "Cannot divide durations by durations"
#define STRING_VARIANT_MOD_BOOL "Cannot modulo Booleans"
#define STRING_VARIANT_MOD_DATE "Cannot modulo date values"
#define STRING_VARIANT_MOD_DUR "Cannot modulo duration values"
@ -1760,7 +1759,9 @@ Variant& Variant::operator/=(const Variant& other) {
throw std::string(STRING_VARIANT_DIV_DUR_DATE);
case type_duration:
throw std::string(STRING_VARIANT_DIV_DUR_DUR);
_type = type_real;
_real = static_cast<double>(_duration) / static_cast<double>(right._duration);
break;
}
break;
}

View file

@ -28,9 +28,7 @@
#define INCLUDED_VARIANT
#include <Task.h>
#include <time.h>
#include <map>
#include <string>
class Variant {

View file

@ -30,7 +30,7 @@
#include <Context.h>
#include <ViewTask.h>
#include <format.h>
#include <main.h>
#include <rules.h>
#include <utf8.h>
#include <util.h>

View file

@ -30,13 +30,10 @@
#include <ColDepends.h>
#include <Context.h>
#include <format.h>
#include <main.h>
#include <shared.h>
#include <stdlib.h>
#include <utf8.h>
#include <util.h>
#include <algorithm>
#include <regex>
#define STRING_COLUMN_LABEL_DEP "Depends"

View file

@ -32,8 +32,8 @@
#include <Eval.h>
#include <Filter.h>
#include <Variant.h>
#include <feedback.h>
#include <format.h>
#include <main.h>
#include <shared.h>
#include <utf8.h>

View file

@ -56,11 +56,9 @@ void ColumnTypeDuration::modify(Task& task, const std::string& value) {
evaluatedValue = Variant(value);
}
// The duration is stored in raw form, but it must still be valid,
// and therefore is parsed first.
// The duration is first parsed, then stored inside the variant as a `time_t`
std::string label = " MODIFICATION ";
if (evaluatedValue.type() == Variant::type_duration) {
// Store the raw value, for 'recur'.
Context::getContext().debug(label + _name + " <-- " + (std::string)evaluatedValue + " <-- '" +
value + '\'');
task.set(_name, evaluatedValue);

View file

@ -297,3 +297,23 @@ void ColumnUDADuration::render(std::vector<std::string>& lines, Task& task, int
}
////////////////////////////////////////////////////////////////////////////////
ColumnUDAUUID::ColumnUDAUUID() {
_name = "<uda>";
_type = "uuid";
_style = "long";
_label = "";
_modifiable = true;
_uda = true;
_styles = {"long", "short"};
_examples = {"f30cb9c3-3fc0-483f-bfb2-3bf134f00694", "f30cb9c3"};
}
////////////////////////////////////////////////////////////////////////////////
bool ColumnUDAUUID::validate(const std::string& input) const {
Lexer lex(input);
std::string token;
Lexer::Type type;
return lex.isUUID(token, type, true);
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -31,6 +31,7 @@
#include <ColTypeDuration.h>
#include <ColTypeNumeric.h>
#include <ColTypeString.h>
#include <ColUUID.h>
////////////////////////////////////////////////////////////////////////////////
class ColumnUDAString : public ColumnTypeString {
@ -83,5 +84,12 @@ class ColumnUDADuration : public ColumnTypeDuration {
std::vector<std::string> _values;
};
////////////////////////////////////////////////////////////////////////////////
class ColumnUDAUUID : public ColumnUUID {
public:
ColumnUDAUUID();
bool validate(const std::string&) const;
};
#endif
////////////////////////////////////////////////////////////////////////////////

View file

@ -246,9 +246,15 @@ Column* Column::uda(const std::string& name) {
c->_label = label;
if (values != "") c->_values = split(values, ',');
return c;
} else if (type == "uuid") {
auto c = new ColumnUDAUUID();
c->_name = name;
c->_label = label;
return c;
} else if (type != "")
throw std::string(
"User defined attributes may only be of type 'string', 'date', 'duration' or 'numeric'.");
"User defined attributes may only be of type 'string', 'uuid', date', 'duration' or "
"'numeric'.");
return nullptr;
}

View file

@ -29,8 +29,8 @@
#include <CmdAdd.h>
#include <Context.h>
#include <feedback.h>
#include <format.h>
#include <main.h>
////////////////////////////////////////////////////////////////////////////////
CmdAdd::CmdAdd() {
@ -40,6 +40,7 @@ CmdAdd::CmdAdd() {
_read_only = false;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = true;
_accepts_filter = false;
_accepts_modifications = true;
@ -55,6 +56,11 @@ int CmdAdd::execute(std::string& output) {
// the task is empty, but DOM references can refer to earlier parts of the
// command line, e.g., `task add due:20110101 wait:due`.
task.modify(Task::modReplace, true);
// Validate a task for addition. This is stricter than `task.validate`, as any
// inconsistency is probably user error.
task.validate_add();
Context::getContext().tdb2.add(task);
// Do not display ID 0, users cannot query by that

View file

@ -39,6 +39,7 @@ CmdCompletionAliases::CmdCompletionAliases() {
_read_only = true;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = false;
_accepts_filter = false;
_accepts_modifications = false;

View file

@ -30,8 +30,8 @@
#include <CmdAnnotate.h>
#include <Context.h>
#include <Filter.h>
#include <feedback.h>
#include <format.h>
#include <main.h>
#include <shared.h>
#include <iostream>
@ -44,6 +44,7 @@ CmdAnnotate::CmdAnnotate() {
_read_only = false;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = false;
_accepts_filter = true;
_accepts_modifications = true;

View file

@ -30,8 +30,8 @@
#include <CmdAppend.h>
#include <Context.h>
#include <Filter.h>
#include <feedback.h>
#include <format.h>
#include <main.h>
#include <shared.h>
#include <iostream>
@ -44,6 +44,7 @@ CmdAppend::CmdAppend() {
_read_only = false;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = false;
_accepts_filter = true;
_accepts_modifications = true;

View file

@ -42,6 +42,7 @@ CmdZshAttributes::CmdZshAttributes() {
_read_only = true;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = false;
_accepts_filter = false;
_accepts_modifications = false;

View file

@ -33,7 +33,6 @@
#include <Duration.h>
#include <Filter.h>
#include <format.h>
#include <main.h>
#include <math.h>
#include <shared.h>
#include <string.h>
@ -767,6 +766,7 @@ CmdBurndownMonthly::CmdBurndownMonthly() {
_read_only = true;
_displays_id = false;
_needs_gc = true;
_needs_recur_update = true;
_uses_context = true;
_accepts_filter = true;
_accepts_modifications = false;
@ -779,8 +779,6 @@ int CmdBurndownMonthly::execute(std::string& output) {
int rc = 0;
// Scan the pending tasks, applying any filter.
handleUntil();
handleRecurrence();
Filter filter;
std::vector<Task> filtered;
filter.subset(filtered);
@ -801,6 +799,7 @@ CmdBurndownWeekly::CmdBurndownWeekly() {
_read_only = true;
_displays_id = false;
_needs_gc = true;
_needs_recur_update = true;
_uses_context = true;
_accepts_filter = true;
_accepts_modifications = false;
@ -813,8 +812,6 @@ int CmdBurndownWeekly::execute(std::string& output) {
int rc = 0;
// Scan the pending tasks, applying any filter.
handleUntil();
handleRecurrence();
Filter filter;
std::vector<Task> filtered;
filter.subset(filtered);
@ -835,6 +832,7 @@ CmdBurndownDaily::CmdBurndownDaily() {
_read_only = true;
_displays_id = false;
_needs_gc = true;
_needs_recur_update = true;
_uses_context = true;
_accepts_filter = true;
_accepts_modifications = false;
@ -847,8 +845,6 @@ int CmdBurndownDaily::execute(std::string& output) {
int rc = 0;
// Scan the pending tasks, applying any filter.
handleUntil();
handleRecurrence();
Filter filter;
std::vector<Task> filtered;
filter.subset(filtered);

View file

@ -37,6 +37,7 @@ CmdCalc::CmdCalc() {
_read_only = true;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = false;
_accepts_filter = false;
_accepts_modifications = false;

View file

@ -32,7 +32,6 @@
#include <Lexer.h>
#include <Table.h>
#include <format.h>
#include <main.h>
#include <shared.h>
#include <stdlib.h>
#include <utf8.h>
@ -49,6 +48,7 @@ CmdCalendar::CmdCalendar() {
_read_only = true;
_displays_id = true;
_needs_gc = true;
_needs_recur_update = false;
_uses_context = false;
_accepts_filter = false;
_accepts_modifications = false;
@ -80,8 +80,6 @@ int CmdCalendar::execute(std::string& output) {
monthsPerLine = preferredMonthsPerLine;
// Load the pending tasks.
handleUntil();
handleRecurrence();
auto tasks = Context::getContext().tdb2.pending_tasks();
Datetime today;

View file

@ -32,7 +32,6 @@
#include <Context.h>
#include <Table.h>
#include <format.h>
#include <main.h>
#include <shared.h>
#include <sstream>
@ -45,6 +44,7 @@ CmdColor::CmdColor() {
_read_only = true;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = false;
_accepts_filter = false;
_accepts_modifications = false;

View file

@ -31,7 +31,6 @@
#include <Color.h>
#include <Context.h>
#include <Table.h>
#include <main.h>
#include <shared.h>
#include <util.h>
@ -45,6 +44,7 @@ CmdColumns::CmdColumns() {
_read_only = true;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = false;
_accepts_filter = false;
_accepts_modifications = false;
@ -119,6 +119,7 @@ CmdCompletionColumns::CmdCompletionColumns() {
_read_only = true;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = false;
_accepts_filter = false;
_accepts_modifications = false;

View file

@ -45,6 +45,7 @@ CmdCommands::CmdCommands() {
_read_only = true;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = false;
_accepts_filter = false;
_accepts_modifications = false;
@ -61,6 +62,7 @@ int CmdCommands::execute(std::string& output) {
view.add("R/W", false);
view.add("ID", false);
view.add("GC", false);
view.add("Recur", false);
view.add("Context", false);
view.add("Filter", false);
view.add("Mods", false);
@ -85,15 +87,17 @@ int CmdCommands::execute(std::string& output) {
if (command.second->needs_gc()) view.set(row, 4, "GC");
if (command.second->uses_context()) view.set(row, 5, "Ctxt");
if (command.second->needs_recur_update()) view.set(row, 5, "Recur");
if (command.second->accepts_filter()) view.set(row, 6, "Filt");
if (command.second->uses_context()) view.set(row, 6, "Ctxt");
if (command.second->accepts_modifications()) view.set(row, 7, "Mods");
if (command.second->accepts_filter()) view.set(row, 7, "Filt");
if (command.second->accepts_miscellaneous()) view.set(row, 8, "Misc");
if (command.second->accepts_modifications()) view.set(row, 8, "Mods");
view.set(row, 9, command.second->description());
if (command.second->accepts_miscellaneous()) view.set(row, 9, "Misc");
view.set(row, 10, command.second->description());
}
output = optionalBlankLine() + view.render() + optionalBlankLine() + '\n';

View file

@ -44,6 +44,7 @@ CmdConfig::CmdConfig() {
_read_only = true;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = false;
_accepts_filter = false;
_accepts_modifications = false;
@ -217,6 +218,7 @@ CmdCompletionConfig::CmdCompletionConfig() {
_read_only = true;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = false;
_accepts_filter = false;
_accepts_modifications = false;

View file

@ -33,7 +33,7 @@
#include <Filter.h>
#include <Table.h>
#include <format.h>
#include <main.h>
#include <rules.h>
#include <shared.h>
#include <util.h>
@ -49,6 +49,7 @@ CmdContext::CmdContext() {
_read_only = true;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = false;
_accepts_filter = false;
_accepts_modifications = false;
@ -217,8 +218,8 @@ void CmdContext::defineContext(const std::vector<std::string>& words, std::strin
if (!valid_write_context) {
std::stringstream warning;
warning
<< format("The filter '{1}' is not a valid modification string, because it contains {2}.",
value, reason)
<< format("The filter '{1}' is not a valid modification string, because it {2}.", value,
reason)
<< "\nAs such, value for the write context cannot be set (context will not apply on task "
"add / task log).\n\n"
<< format(
@ -414,6 +415,7 @@ CmdCompletionContext::CmdCompletionContext() {
_read_only = true;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = false;
_accepts_filter = false;
_accepts_modifications = false;

View file

@ -30,7 +30,6 @@
#include <CmdCount.h>
#include <Filter.h>
#include <format.h>
#include <main.h>
////////////////////////////////////////////////////////////////////////////////
CmdCount::CmdCount() {
@ -40,6 +39,7 @@ CmdCount::CmdCount() {
_read_only = true;
_displays_id = false;
_needs_gc = true;
_needs_recur_update = true;
_uses_context = true;
_accepts_filter = true;
_accepts_modifications = false;
@ -50,8 +50,6 @@ CmdCount::CmdCount() {
////////////////////////////////////////////////////////////////////////////////
int CmdCount::execute(std::string& output) {
// Apply filter.
handleUntil();
handleRecurrence();
Filter filter;
std::vector<Task> filtered;
filter.subset(filtered);

View file

@ -34,15 +34,15 @@
#include <Lexer.h>
#include <Version.h>
#include <ViewTask.h>
#include <feedback.h>
#include <format.h>
#include <main.h>
#include <legacy.h>
#include <shared.h>
#include <stdlib.h>
#include <sort.h>
#include <util.h>
#include <algorithm>
#include <iostream>
#include <map>
#include <sstream>
#include <vector>
@ -55,6 +55,7 @@ CmdCustom::CmdCustom(const std::string& keyword, const std::string& usage,
_read_only = true;
_displays_id = true;
_needs_gc = true;
_needs_recur_update = true;
_uses_context = true;
_accepts_filter = true;
_accepts_modifications = false;
@ -100,10 +101,6 @@ int CmdCustom::execute(std::string& output) {
// Add the report filter to any existing filter.
if (reportFilter != "") Context::getContext().cli2.addFilter(reportFilter);
// Make sure reccurent tasks are generated.
handleUntil();
handleRecurrence();
// Apply filter.
Filter filter;
std::vector<Task> filtered;

View file

@ -30,8 +30,10 @@
#include <CmdDelete.h>
#include <Context.h>
#include <Filter.h>
#include <dependency.h>
#include <feedback.h>
#include <format.h>
#include <main.h>
#include <recur.h>
#include <shared.h>
#include <iostream>
@ -49,6 +51,7 @@ CmdDelete::CmdDelete() {
_displays_id = false;
_needs_confirm = true;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = true;
_accepts_filter = true;
_accepts_modifications = true;

View file

@ -30,8 +30,8 @@
#include <CmdDenotate.h>
#include <Context.h>
#include <Filter.h>
#include <feedback.h>
#include <format.h>
#include <main.h>
#include <shared.h>
#include <util.h>
@ -49,6 +49,7 @@ CmdDenotate::CmdDenotate() {
_read_only = false;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = true;
_accepts_filter = true;
_accepts_modifications = false;

View file

@ -50,6 +50,7 @@ CmdDiagnostics::CmdDiagnostics() {
_read_only = true;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = false;
_accepts_filter = false;
_accepts_modifications = false;

View file

@ -30,8 +30,11 @@
#include <CmdDone.h>
#include <Context.h>
#include <Filter.h>
#include <dependency.h>
#include <feedback.h>
#include <format.h>
#include <main.h>
#include <nag.h>
#include <recur.h>
#include <util.h>
#include <iostream>
@ -44,6 +47,7 @@ CmdDone::CmdDone() {
_read_only = false;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = true;
_accepts_filter = true;
_accepts_modifications = true;

View file

@ -30,8 +30,8 @@
#include <CmdDuplicate.h>
#include <Context.h>
#include <Filter.h>
#include <feedback.h>
#include <format.h>
#include <main.h>
#include <util.h>
#include <iostream>
@ -44,6 +44,7 @@ CmdDuplicate::CmdDuplicate() {
_read_only = false;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = true;
_accepts_filter = true;
_accepts_modifications = true;

View file

@ -36,7 +36,6 @@
#include <Lexer.h>
#include <Pig.h>
#include <format.h>
#include <main.h>
#include <shared.h>
#include <unistd.h>
#include <util.h>
@ -64,6 +63,7 @@ CmdEdit::CmdEdit() {
_read_only = false;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = true;
_uses_context = true;
_accepts_filter = true;
_accepts_modifications = false;
@ -77,8 +77,6 @@ CmdEdit::CmdEdit() {
// wrench. To be used sparingly.
int CmdEdit::execute(std::string&) {
// Filter the tasks.
handleUntil();
handleRecurrence();
Filter filter;
std::vector<Task> filtered;
filter.subset(filtered);
@ -319,7 +317,6 @@ void CmdEdit::parseTask(Task& task, const std::string& after, const std::string&
// tags
value = findValue(after, "\n Tags:");
task.remove("tags");
task.setTags(split(value, ' '));
// description.
@ -621,10 +618,9 @@ CmdEdit::editResult CmdEdit::editFile(Task& task) {
auto dateformat = Context::getContext().config.get("dateformat.edit");
if (dateformat == "") dateformat = Context::getContext().config.get("dateformat");
// Change directory for the editor
// Change directory for the editor, doing nothing on error.
auto current_dir = Directory::cwd();
int ignored = chdir(location._data.c_str());
++ignored; // Keep compiler quiet.
chdir(location._data.c_str());
// Check if the file already exists, if so, bail out
Path filepath = Path(file.str());
@ -704,7 +700,7 @@ ARE_THESE_REALLY_HARMFUL:
// Cleanup.
File::remove(file.str());
ignored = chdir(current_dir.c_str());
chdir(current_dir.c_str());
return changes ? CmdEdit::editResult::changes : CmdEdit::editResult::nochanges;
}

View file

@ -40,6 +40,7 @@ CmdExec::CmdExec() {
_read_only = true;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = false;
_accepts_filter = false;
_accepts_modifications = false;

View file

@ -31,8 +31,9 @@
#include <Context.h>
#include <Filter.h>
#include <format.h>
#include <main.h>
#include <legacy.h>
#include <shared.h>
#include <sort.h>
////////////////////////////////////////////////////////////////////////////////
CmdExport::CmdExport() {
@ -42,6 +43,7 @@ CmdExport::CmdExport() {
_read_only = true;
_displays_id = true;
_needs_gc = true;
_needs_recur_update = true;
_uses_context = false;
_accepts_filter = true;
_accepts_modifications = false;
@ -82,10 +84,6 @@ int CmdExport::execute(std::string& output) {
// Add the report filter to any existing filter.
if (reportFilter != "") Context::getContext().cli2.addFilter(reportFilter);
// Make sure reccurent tasks are generated.
handleUntil();
handleRecurrence();
// Apply filter.
Filter filter;
std::vector<Task> filtered;

View file

@ -32,7 +32,6 @@
#include <DOM.h>
#include <Variant.h>
#include <format.h>
#include <main.h>
#include <shared.h>
////////////////////////////////////////////////////////////////////////////////
@ -43,6 +42,7 @@ CmdGet::CmdGet() {
_read_only = true;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = false;
_accepts_filter = false;
_accepts_modifications = false;

View file

@ -44,6 +44,7 @@ CmdHelp::CmdHelp() {
_read_only = true;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = false;
_accepts_filter = false;
_accepts_modifications = false;

View file

@ -33,7 +33,6 @@
#include <Filter.h>
#include <Table.h>
#include <format.h>
#include <main.h>
#include <util.h>
#include <sstream>
@ -55,6 +54,7 @@ CmdHistoryBase<HistoryStrategy>::CmdHistoryBase() {
_read_only = true;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = true;
_uses_context = true;
_accepts_filter = true;
_accepts_modifications = false;
@ -293,8 +293,6 @@ int CmdHistoryBase<HistoryStrategy>::execute(std::string& output) {
completedGroup.clear();
// Apply filter.
handleUntil();
handleRecurrence();
Filter filter;
std::vector<Task> filtered;
filter.subset(filtered);

View file

@ -30,7 +30,6 @@
#include <CmdIDs.h>
#include <Context.h>
#include <Filter.h>
#include <main.h>
#include <shared.h>
#include <algorithm>
@ -46,6 +45,7 @@ CmdIDs::CmdIDs() {
_read_only = true;
_displays_id = true;
_needs_gc = true;
_needs_recur_update = true;
_uses_context = false;
_accepts_filter = true;
_accepts_modifications = false;
@ -56,8 +56,6 @@ CmdIDs::CmdIDs() {
////////////////////////////////////////////////////////////////////////////////
int CmdIDs::execute(std::string& output) {
// Apply filter.
handleUntil();
handleRecurrence();
Filter filter;
std::vector<Task> filtered;
filter.subset(filtered);
@ -127,6 +125,7 @@ CmdCompletionIds::CmdCompletionIds() {
_read_only = true;
_displays_id = true;
_needs_gc = true;
_needs_recur_update = true;
_uses_context = false;
_accepts_filter = true;
_accepts_modifications = false;
@ -137,8 +136,6 @@ CmdCompletionIds::CmdCompletionIds() {
////////////////////////////////////////////////////////////////////////////////
int CmdCompletionIds::execute(std::string& output) {
// Apply filter.
handleUntil();
handleRecurrence();
Filter filter;
std::vector<Task> filtered;
filter.subset(filtered);
@ -163,6 +160,7 @@ CmdZshCompletionIds::CmdZshCompletionIds() {
_read_only = true;
_displays_id = true;
_needs_gc = true;
_needs_recur_update = true;
_uses_context = false;
_accepts_filter = true;
_accepts_modifications = false;
@ -173,8 +171,6 @@ CmdZshCompletionIds::CmdZshCompletionIds() {
////////////////////////////////////////////////////////////////////////////////
int CmdZshCompletionIds::execute(std::string& output) {
// Apply filter.
handleUntil();
handleRecurrence();
Filter filter;
std::vector<Task> filtered;
filter.subset(filtered);
@ -199,6 +195,7 @@ CmdUUIDs::CmdUUIDs() {
_read_only = true;
_displays_id = false;
_needs_gc = true;
_needs_recur_update = true;
_uses_context = false;
_accepts_filter = true;
_accepts_modifications = false;
@ -209,8 +206,6 @@ CmdUUIDs::CmdUUIDs() {
////////////////////////////////////////////////////////////////////////////////
int CmdUUIDs::execute(std::string& output) {
// Apply filter.
handleUntil();
handleRecurrence();
Filter filter;
std::vector<Task> filtered;
filter.subset(filtered);
@ -234,6 +229,7 @@ CmdCompletionUuids::CmdCompletionUuids() {
_read_only = true;
_displays_id = false;
_needs_gc = true;
_needs_recur_update = true;
_uses_context = false;
_accepts_filter = true;
_accepts_modifications = false;
@ -244,8 +240,6 @@ CmdCompletionUuids::CmdCompletionUuids() {
////////////////////////////////////////////////////////////////////////////////
int CmdCompletionUuids::execute(std::string& output) {
// Apply filter.
handleUntil();
handleRecurrence();
Filter filter;
std::vector<Task> filtered;
filter.subset(filtered);
@ -269,6 +263,7 @@ CmdZshCompletionUuids::CmdZshCompletionUuids() {
_read_only = true;
_displays_id = false;
_needs_gc = true;
_needs_recur_update = true;
_uses_context = false;
_accepts_filter = true;
_accepts_modifications = false;
@ -279,8 +274,6 @@ CmdZshCompletionUuids::CmdZshCompletionUuids() {
////////////////////////////////////////////////////////////////////////////////
int CmdZshCompletionUuids::execute(std::string& output) {
// Apply filter.
handleUntil();
handleRecurrence();
Filter filter;
std::vector<Task> filtered;
filter.subset(filtered);

View file

@ -45,6 +45,7 @@ CmdImport::CmdImport() {
_read_only = false;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = false;
_accepts_filter = false;
_accepts_modifications = false;

View file

@ -46,6 +46,7 @@ CmdImportV2::CmdImportV2() {
_read_only = false;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = false;
_accepts_filter = false;
_accepts_modifications = false;

View file

@ -31,7 +31,6 @@
#include <JSON.h>
#include <string>
#include <unordered_map>
class CmdImportV2 : public Command {
public:

View file

@ -34,9 +34,9 @@
#include <Filter.h>
#include <Lexer.h>
#include <Operation.h>
#include <feedback.h>
#include <format.h>
#include <main.h>
#include <math.h>
#include <rules.h>
#include <shared.h>
#include <stdlib.h>
#include <taskchampion-cpp/lib.h>
@ -59,6 +59,7 @@ CmdInfo::CmdInfo() {
// Once the test suite is completely modified, this can be corrected.
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = false;
_accepts_filter = true;
_accepts_modifications = false;
@ -119,9 +120,11 @@ int CmdInfo::execute(std::string& output) {
description += '\n' + std::string(indent, ' ') +
Datetime(anno.first.substr(11)).toString(dateformatanno) + ' ' + anno.second;
row = view.addRow();
view.set(row, 0, "Description");
view.set(row, 1, description, c);
if (task.has("description")) {
row = view.addRow();
view.set(row, 0, "Description");
view.set(row, 1, description, c);
}
// status
row = view.addRow();
@ -214,64 +217,76 @@ int CmdInfo::execute(std::string& output) {
}
// entry
row = view.addRow();
view.set(row, 0, "Entered");
Datetime dt(task.get_date("entry"));
std::string entry = dt.toString(dateformat);
if (task.has("entry") && task.get_date("entry")) {
row = view.addRow();
view.set(row, 0, "Entered");
Datetime dt(task.get_date("entry"));
std::string entry = dt.toString(dateformat);
std::string age;
auto created = task.get("entry");
if (created.length()) {
Datetime dt(strtoll(created.c_str(), nullptr, 10));
age = Duration(now - dt).formatVague();
std::string age;
auto created = task.get("entry");
if (created.length()) {
Datetime dt(strtoll(created.c_str(), nullptr, 10));
age = Duration(now - dt).formatVague();
}
view.set(row, 1, entry + " (" + age + ')');
}
view.set(row, 1, entry + " (" + age + ')');
auto validDate = [&](const char* prop) {
if (!task.has(prop)) {
return false;
}
if (task.get_date(prop) == 0) {
return false;
}
return true;
};
// wait
if (task.has("wait")) {
if (validDate("wait")) {
row = view.addRow();
view.set(row, 0, "Waiting until");
view.set(row, 1, Datetime(task.get_date("wait")).toString(dateformat));
}
// scheduled
if (task.has("scheduled")) {
if (validDate("scheduled")) {
row = view.addRow();
view.set(row, 0, "Scheduled");
view.set(row, 1, Datetime(task.get_date("scheduled")).toString(dateformat));
}
// start
if (task.has("start")) {
if (validDate("start")) {
row = view.addRow();
view.set(row, 0, "Start");
view.set(row, 1, Datetime(task.get_date("start")).toString(dateformat));
}
// due (colored)
if (task.has("due")) {
if (validDate("due")) {
row = view.addRow();
view.set(row, 0, "Due");
view.set(row, 1, Datetime(task.get_date("due")).toString(dateformat));
}
// end
if (task.has("end")) {
if (validDate("end")) {
row = view.addRow();
view.set(row, 0, "End");
view.set(row, 1, Datetime(task.get_date("end")).toString(dateformat));
}
// until
if (task.has("until")) {
if (validDate("until")) {
row = view.addRow();
view.set(row, 0, "Until");
view.set(row, 1, Datetime(task.get_date("until")).toString(dateformat));
}
// modified
if (task.has("modified")) {
if (validDate("modified")) {
row = view.addRow();
view.set(row, 0, "Last modified");
@ -631,7 +646,11 @@ std::optional<std::string> CmdInfo::formatForInfo(const std::vector<Operation>&
} else {
// Record the last start time for later duration calculation.
if (prop == "start") {
last_start = Datetime(value.value()).toEpoch();
try {
last_start = Datetime(value.value()).toEpoch();
} catch (std::string) {
// ignore invalid dates
}
}
out << format("{1} set to '{2}'.", Lexer::ucFirst(prop),

View file

@ -29,8 +29,8 @@
#include <CmdLog.h>
#include <Context.h>
#include <feedback.h>
#include <format.h>
#include <main.h>
////////////////////////////////////////////////////////////////////////////////
CmdLog::CmdLog() {
@ -40,6 +40,7 @@ CmdLog::CmdLog() {
_read_only = false;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = true;
_accepts_filter = false;
_accepts_modifications = true;

View file

@ -39,6 +39,7 @@ CmdLogo::CmdLogo() {
_read_only = true;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = false;
_accepts_filter = false;
_accepts_modifications = false;

View file

@ -30,8 +30,9 @@
#include <CmdModify.h>
#include <Context.h>
#include <Filter.h>
#include <feedback.h>
#include <format.h>
#include <main.h>
#include <recur.h>
#include <shared.h>
#include <iostream>
@ -48,6 +49,7 @@ CmdModify::CmdModify() {
_read_only = false;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = false;
_accepts_filter = true;
_accepts_modifications = true;
@ -118,7 +120,7 @@ void CmdModify::checkConsistency(Task &before, Task &after) {
throw std::string("You cannot remove the recurrence from a recurring task.");
if ((before.getStatus() == Task::pending) && (after.getStatus() == Task::pending) &&
(after.get("end") != ""))
(before.get("end") == "") && (after.get("end") != ""))
throw format("Could not modify task {1}. You cannot set an end date on a pending task.",
before.identifier(true));
}

View file

@ -33,7 +33,6 @@
#include <Duration.h>
#include <Table.h>
#include <format.h>
#include <main.h>
#include <shared.h>
#include <util.h>
@ -57,6 +56,7 @@ CmdNews::CmdNews() {
_read_only = true;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = false;
_accepts_filter = false;
_accepts_modifications = false;
@ -160,6 +160,7 @@ std::vector<NewsItem> NewsItem::all() {
version3_1_0(items);
version3_2_0(items);
version3_3_0(items);
version3_4_0(items);
return items;
}
@ -530,6 +531,21 @@ void NewsItem::version3_3_0(std::vector<NewsItem>& items) {
items.push_back(info);
}
void NewsItem::version3_4_0(std::vector<NewsItem>& items) {
Version version("3.4.0");
NewsItem info{version,
/*title=*/"Read-Only Access",
/*bg_title=*/"",
/*background=*/"",
/*punchline=*/"Some Taskwarrior commands operate faster in read-only mode",
/*update=*/
"Some commands do not need to write to the DB, so can open it in read-only\n"
"mode and thus more quickly. This does not include reports (task lists),\n"
"unless the `gc` config is false. Use `rc.gc=0` in command-lines to allow\n"
"read-only access.\n\n"};
items.push_back(info);
}
////////////////////////////////////////////////////////////////////////////////
int CmdNews::execute(std::string& output) {
auto words = Context::getContext().cli2.getWords();
@ -572,61 +588,10 @@ int CmdNews::execute(std::string& output) {
}
wait_for_enter();
// Display outro
Datetime now;
Datetime beginning(2006, 11, 29);
Duration development_time = Duration(now - beginning);
Color underline = Color("underline");
std::stringstream outro;
outro << underline.colorize(bold.colorize("Taskwarrior crowdfunding\n"));
outro << format(
"Taskwarrior has been in development for {1} years but its survival\n"
"depends on your support!\n\n"
"Please consider joining our {2} fundraiser to help us fund maintenance\n"
"and development of new features:\n\n",
std::lround(static_cast<float>(development_time.days()) / 365.25), now.year());
outro << bold.colorize(" https://github.com/sponsors/GothenburgBitFactory/\n\n");
outro << "Perks are available for our sponsors.\n";
std::cout << outro.str();
// Set a mark in the config to remember which version's release notes were displayed
if (news_version != current_version) {
if (news_version < current_version) {
CmdConfig::setConfigVariable("news.version", std::string(current_version), false);
// Revert back to default signal handling after displaying the outro
signal(SIGINT, SIG_DFL);
std::string question = format(
"\nWould you like to open Taskwarrior {1} fundraising campaign to read more?", now.year());
std::vector<std::string> options{"yes", "no"};
std::vector<std::string> matches;
std::cout << question << " (YES/no) ";
std::string answer;
std::getline(std::cin, answer);
if (std::cin.eof() || trim(answer).empty())
answer = "yes";
else
lowerCase(trim(answer));
autoComplete(answer, options, matches, 1); // Hard-coded 1.
if (matches.size() == 1 && matches[0] == "yes")
#if defined(DARWIN)
system("open 'https://github.com/sponsors/GothenburgBitFactory/'");
#else
system("xdg-open 'https://github.com/sponsors/GothenburgBitFactory/'");
#endif
std::cout << std::endl;
} else
wait_for_enter(); // Do not display the outro and footnote at once
}
return 0;
}
@ -641,8 +606,8 @@ bool CmdNews::should_nag() {
Version current_version = Version::Current();
if (news_version == current_version) {
return true;
if (news_version >= current_version) {
return false;
}
// Check if there are actually any interesting news items to show.

View file

@ -53,6 +53,7 @@ class NewsItem {
static void version3_1_0(std::vector<NewsItem>&);
static void version3_2_0(std::vector<NewsItem>&);
static void version3_3_0(std::vector<NewsItem>&);
static void version3_4_0(std::vector<NewsItem>&);
private:
NewsItem(Version, const std::string&, const std::string& = "", const std::string& = "",

View file

@ -30,8 +30,8 @@
#include <CmdPrepend.h>
#include <Context.h>
#include <Filter.h>
#include <feedback.h>
#include <format.h>
#include <main.h>
#include <shared.h>
#include <iostream>
@ -44,6 +44,7 @@ CmdPrepend::CmdPrepend() {
_read_only = false;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = true;
_accepts_filter = true;
_accepts_modifications = true;

View file

@ -32,10 +32,9 @@
#include <Filter.h>
#include <Table.h>
#include <format.h>
#include <main.h>
#include <sort.h>
#include <util.h>
#include <algorithm>
#include <list>
#include <sstream>
@ -47,6 +46,7 @@ CmdProjects::CmdProjects() {
_read_only = true;
_displays_id = false;
_needs_gc = true;
_needs_recur_update = true;
_uses_context = true;
_accepts_filter = true;
_accepts_modifications = false;
@ -59,8 +59,6 @@ int CmdProjects::execute(std::string& output) {
int rc = 0;
// Get all the tasks.
handleUntil();
handleRecurrence();
auto tasks = Context::getContext().tdb2.pending_tasks();
if (Context::getContext().config.getBoolean("list.all.projects"))
@ -141,6 +139,7 @@ CmdCompletionProjects::CmdCompletionProjects() {
_read_only = true;
_displays_id = false;
_needs_gc = true;
_needs_recur_update = true;
_uses_context = false;
_accepts_filter = true;
_accepts_modifications = false;
@ -151,8 +150,6 @@ CmdCompletionProjects::CmdCompletionProjects() {
////////////////////////////////////////////////////////////////////////////////
int CmdCompletionProjects::execute(std::string& output) {
// Get all the tasks.
handleUntil();
handleRecurrence();
auto tasks = Context::getContext().tdb2.pending_tasks();
if (Context::getContext().config.getBoolean("list.all.projects"))

View file

@ -30,8 +30,8 @@
#include <CmdPurge.h>
#include <Context.h>
#include <Filter.h>
#include <feedback.h>
#include <format.h>
#include <main.h>
#include <shared.h>
////////////////////////////////////////////////////////////////////////////////
@ -43,6 +43,7 @@ CmdPurge::CmdPurge() {
_displays_id = false;
_needs_confirm = true;
_needs_gc = true;
_needs_recur_update = false;
_uses_context = true;
_accepts_filter = true;
_accepts_modifications = false;

View file

@ -43,6 +43,7 @@ CmdReports::CmdReports() {
_read_only = true;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = false;
_accepts_filter = false;
_accepts_modifications = false;

View file

@ -32,7 +32,7 @@
#include <FS.h>
#include <Table.h>
#include <format.h>
#include <main.h>
#include <legacy.h>
#include <util.h>
#include <algorithm>
@ -53,6 +53,7 @@ CmdShow::CmdShow() {
_read_only = true;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = false;
_accepts_filter = false;
_accepts_modifications = false;

View file

@ -30,8 +30,11 @@
#include <CmdStart.h>
#include <Context.h>
#include <Filter.h>
#include <dependency.h>
#include <feedback.h>
#include <format.h>
#include <main.h>
#include <nag.h>
#include <recur.h>
#include <util.h>
#include <iostream>
@ -44,6 +47,7 @@ CmdStart::CmdStart() {
_read_only = false;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = true;
_accepts_filter = true;
_accepts_modifications = true;

View file

@ -34,7 +34,6 @@
#include <Filter.h>
#include <Table.h>
#include <format.h>
#include <main.h>
#include <stdlib.h>
#include <util.h>
@ -49,6 +48,7 @@ CmdStats::CmdStats() {
_read_only = true;
_displays_id = false;
_needs_gc = true;
_needs_recur_update = false;
_uses_context = true;
_accepts_filter = true;
_accepts_modifications = false;

View file

@ -30,8 +30,10 @@
#include <CmdStop.h>
#include <Context.h>
#include <Filter.h>
#include <dependency.h>
#include <feedback.h>
#include <format.h>
#include <main.h>
#include <recur.h>
#include <iostream>
@ -43,6 +45,7 @@ CmdStop::CmdStop() {
_read_only = false;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = true;
_accepts_filter = true;
_accepts_modifications = true;

View file

@ -33,11 +33,10 @@
#include <Filter.h>
#include <Table.h>
#include <format.h>
#include <main.h>
#include <sort.h>
#include <stdlib.h>
#include <util.h>
#include <algorithm>
#include <list>
#include <sstream>
@ -49,6 +48,7 @@ CmdSummary::CmdSummary() {
_read_only = true;
_displays_id = false;
_needs_gc = true;
_needs_recur_update = false;
_uses_context = true;
_accepts_filter = true;
_accepts_modifications = false;
@ -65,8 +65,6 @@ int CmdSummary::execute(std::string& output) {
bool showAllProjects = Context::getContext().config.getBoolean("summary.all.projects");
// Apply filter.
handleUntil();
handleRecurrence();
Filter filter;
std::vector<Task> filtered;
filter.subset(filtered);

View file

@ -32,13 +32,11 @@
#include <Context.h>
#include <Filter.h>
#include <format.h>
#include <inttypes.h>
#include <shared.h>
#include <signal.h>
#include <taskchampion-cpp/lib.h>
#include <util.h>
#include <iostream>
#include <regex>
#include <sstream>
////////////////////////////////////////////////////////////////////////////////
@ -49,6 +47,7 @@ CmdSync::CmdSync() {
_read_only = false;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = false;
_accepts_filter = false;
_accepts_modifications = false;
@ -80,6 +79,12 @@ int CmdSync::execute(std::string& output) {
out << "sync.server.origin is deprecated. Use sync.server.url instead.\n";
}
// redact credentials from `server_url`, if present
std::regex remove_creds_regex("^(https?://.+):(.+)@(.+)");
std::string safe_server_url = std::regex_replace(server_url, remove_creds_regex, "$1:****@$3");
auto num_local_operations = replica->num_local_operations();
if (server_dir != "") {
if (verbose) {
out << format("Syncing with {1}", server_dir) << '\n';
@ -132,6 +137,7 @@ int CmdSync::execute(std::string& output) {
replica->sync_to_aws_with_default_creds(aws_region, aws_bucket, encryption_secret,
avoid_snapshots);
}
} else if (gcp_bucket != "") {
std::string gcp_credential_path = Context::getContext().config.get("sync.gcp.credential_path");
if (encryption_secret == "") {
@ -141,15 +147,17 @@ int CmdSync::execute(std::string& output) {
out << format("Syncing with GCP bucket {1}", gcp_bucket) << '\n';
}
replica->sync_to_gcp(gcp_bucket, gcp_credential_path, encryption_secret, avoid_snapshots);
} else if (server_url != "") {
if (client_id == "" || encryption_secret == "") {
throw std::string("sync.server.client_id and sync.encryption_secret are required");
}
if (verbose) {
out << format("Syncing with sync server at {1}", server_url) << '\n';
out << format("Syncing with sync server at {1}", safe_server_url) << '\n';
}
replica->sync_to_remote(server_url, tc::uuid_from_string(client_id), encryption_secret,
avoid_snapshots);
} else {
throw std::string("No sync.* settings are configured. See task-sync(5).");
}
@ -158,6 +166,15 @@ int CmdSync::execute(std::string& output) {
context.tdb2.expire_tasks();
}
if (verbose) {
out << "Success!\n";
// Taskchampion does not provide a measure of the number of operations received from
// the server, but we can give some indication of the number sent.
if (num_local_operations) {
out << format("Sent {1} local operations to the server", num_local_operations) << '\n';
}
}
output = out.str();
return status;
}

View file

@ -32,7 +32,6 @@
#include <Filter.h>
#include <Table.h>
#include <format.h>
#include <stdlib.h>
#include <util.h>
#include <sstream>
@ -46,6 +45,7 @@ CmdTags::CmdTags() {
_read_only = true;
_displays_id = false;
_needs_gc = true;
_needs_recur_update = false;
_uses_context = true;
_accepts_filter = true;
_accepts_modifications = false;
@ -136,6 +136,7 @@ CmdCompletionTags::CmdCompletionTags() {
_read_only = true;
_displays_id = false;
_needs_gc = true;
_needs_recur_update = true;
_uses_context = false;
_accepts_filter = true;
_accepts_modifications = false;

View file

@ -33,8 +33,7 @@
#include <Filter.h>
#include <Table.h>
#include <format.h>
#include <main.h>
#include <stdlib.h>
#include <rules.h>
#include <util.h>
#include <algorithm>
@ -48,6 +47,7 @@ CmdTimesheet::CmdTimesheet() {
_read_only = true;
_displays_id = false;
_needs_gc = true;
_needs_recur_update = true;
_uses_context = false;
_accepts_filter = true;
_accepts_modifications = false;
@ -90,8 +90,6 @@ int CmdTimesheet::execute(std::string& output) {
}
// Apply filter to get a set of tasks.
handleUntil();
handleRecurrence();
Filter filter;
std::vector<Task> filtered;
filter.subset(filtered);

View file

@ -33,7 +33,6 @@
#include <Table.h>
#include <Task.h>
#include <format.h>
#include <main.h>
#include <shared.h>
#include <util.h>
@ -48,6 +47,7 @@ CmdUDAs::CmdUDAs() {
_read_only = true;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = false;
_accepts_filter = false;
_accepts_modifications = false;
@ -156,6 +156,7 @@ CmdCompletionUDAs::CmdCompletionUDAs() {
_read_only = true;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = false;
_accepts_filter = false;
_accepts_modifications = false;

View file

@ -31,12 +31,11 @@
#include <Context.h>
#include <Operation.h>
#include <Task.h>
#include <shared.h>
#include <iostream>
#include <sstream>
#include "shared.h"
////////////////////////////////////////////////////////////////////////////////
CmdUndo::CmdUndo() {
_keyword = "undo";
@ -45,6 +44,7 @@ CmdUndo::CmdUndo() {
_read_only = false;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = false;
_accepts_filter = false;
_accepts_modifications = false;
@ -102,7 +102,7 @@ bool CmdUndo::confirm_revert(const std::vector<Operation>& undo_ops) {
view.set(row, 1, mods.str());
}
last_uuid = op.get_uuid();
mods.clear();
mods = std::stringstream();
}
if (op.is_create()) {

View file

@ -43,6 +43,7 @@ CmdUnique::CmdUnique() {
_read_only = true;
_displays_id = true;
_needs_gc = true;
_needs_recur_update = false;
_uses_context = false;
_accepts_filter = true;
_accepts_modifications = false;

View file

@ -32,8 +32,6 @@
#include <Filter.h>
#include <Lexer.h>
#include <format.h>
#include <main.h>
#include <stdlib.h>
#include <sstream>
@ -45,6 +43,7 @@ CmdUrgency::CmdUrgency() {
_read_only = true;
_displays_id = false;
_needs_gc = true;
_needs_recur_update = false;
_uses_context = false;
_accepts_filter = true;
_accepts_modifications = false;

View file

@ -31,7 +31,6 @@
#include <Context.h>
#include <Datetime.h>
#include <Table.h>
#include <stdlib.h>
#include <sstream>
#ifdef HAVE_COMMIT
@ -48,6 +47,7 @@ CmdVersion::CmdVersion() {
_read_only = true;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = false;
_accepts_filter = false;
_accepts_modifications = false;
@ -101,6 +101,7 @@ CmdCompletionVersion::CmdCompletionVersion() {
_read_only = true;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = false;
_accepts_filter = false;
_accepts_modifications = false;

View file

@ -50,9 +50,7 @@
#include <CmdEdit.h>
#include <Command.h>
#include <format.h>
#include <main.h>
#include <shared.h>
#include <stdlib.h>
#include <util.h>
#include <iostream>
@ -295,6 +293,7 @@ Command::Command()
_displays_id(true),
_needs_confirm(false),
_needs_gc(true),
_needs_recur_update(false),
_uses_context(false),
_accepts_filter(false),
_accepts_modifications(false),
@ -322,6 +321,9 @@ bool Command::displays_id() const { return _displays_id; }
////////////////////////////////////////////////////////////////////////////////
bool Command::needs_gc() const { return _needs_gc; }
////////////////////////////////////////////////////////////////////////////////
bool Command::needs_recur_update() const { return _needs_recur_update; }
////////////////////////////////////////////////////////////////////////////////
bool Command::uses_context() const { return _uses_context; }

View file

@ -31,7 +31,6 @@
#include <map>
#include <string>
#include <vector>
class Command {
public:
@ -62,6 +61,7 @@ class Command {
bool read_only() const;
bool displays_id() const;
bool needs_gc() const;
bool needs_recur_update() const;
virtual bool uses_context() const;
bool accepts_filter() const;
bool accepts_modifications() const;
@ -81,6 +81,7 @@ class Command {
bool _displays_id;
bool _needs_confirm;
bool _needs_gc;
bool _needs_recur_update;
bool _uses_context;
bool _accepts_filter;
bool _accepts_modifications;

View file

@ -28,13 +28,11 @@
// cmake.h include header must come first
#include <Context.h>
#include <dependency.h>
#include <format.h>
#include <main.h>
#include <shared.h>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <stack>
#define STRING_DEPEND_BLOCKED "Task {1} is blocked by:"

43
src/dependency.h Normal file
View file

@ -0,0 +1,43 @@
////////////////////////////////////////////////////////////////////////////////
//
// Copyright 2006 - 2025, Tomas Babej, Paul Beckingham, Federico Hernandez,
// Tobias Predel.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// https://www.opensource.org/licenses/mit-license.php
//
////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDED_DEPENDENCY
#define INCLUDED_DEPENDENCY
#include <cmake.h>
// cmake.h include header must come first
#include <Task.h>
#define STRING_DEPEND_BLOCKED "Task {1} is blocked by:"
bool dependencyIsCircular(const Task& task);
void dependencyChainOnComplete(Task& task);
void dependencyChainOnStart(Task& task);
#endif
////////////////////////////////////////////////////////////////////////////////

Some files were not shown because too many files have changed in this diff Show more