Compare commits

..

No commits in common. "develop" and "v3.3.0" have entirely different histories.

136 changed files with 933 additions and 2172 deletions

View file

@ -1 +0,0 @@
target

View file

@ -5,11 +5,6 @@ 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-${{ steps.toolchain.outputs.cachekey }}-${{ hashFiles('**/Cargo.lock') }}
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
- name: Cache cargo build
uses: actions/cache@v4
with:
path: target
key: ${{ runner.os }}-cargo-build-target-${{ steps.toolchain.outputs.cachekey }}-${{ hashFiles('**/Cargo.lock') }}
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
- uses: actions-rs/cargo@v1.0.3
with:
@ -53,11 +53,12 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
id: toolchain
- uses: actions-rs/toolchain@v1
with:
toolchain: "stable"
components: "rustfmt"
profile: minimal
components: rustfmt
toolchain: stable
override: true
- uses: actions-rs/cargo@v1.0.3
with:
@ -70,11 +71,12 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
id: toolchain
- uses: actions-rs/toolchain@v1
with:
toolchain: "stable"
components: "rustfmt"
profile: minimal
components: rustfmt
toolchain: stable
override: true
- 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.9.0
uses: sigstore/cosign-installer@v3.7.0
- name: Log into registry ${{ env.REGISTRY }}
uses: docker/login-action@v3.4.0
uses: docker/login-action@v3.3.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.18.0
uses: docker/build-push-action@v6.10.0
with:
context: .
file: "./docker/task.dockerfile"

View file

@ -6,14 +6,16 @@ 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-${{ steps.toolchain.outputs.cachekey }}-${{ hashFiles('**/Cargo.lock') }}
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
- uses: actions-rs/toolchain@v1
with:
toolchain: "stable"
override: true
- name: Install uuid-dev
run: sudo apt install uuid-dev

View file

@ -43,20 +43,22 @@ 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-${{ steps.toolchain.outputs.cachekey }}-${{ hashFiles('**/Cargo.lock') }}
key: ${{ runner.os }}-stable-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
- name: Cache cargo build
uses: actions/cache@v4
with:
path: target
key: ${{ runner.os }}-cargo-build-target-${{ steps.toolchain.outputs.cachekey }}-${{ hashFiles('**/Cargo.lock') }}
key: ${{ runner.os }}-stable-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}
- uses: actions-rs/toolchain@v1
with:
toolchain: "stable"
override: true
- name: Test MacOS
run: bash test/scripts/test_macos.sh
@ -70,20 +72,22 @@ 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-${{ steps.toolchain.outputs.cachekey }}-${{ hashFiles('**/Cargo.lock') }}
key: ${{ runner.os }}-stable-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
- name: Cache cargo build
uses: actions/cache@v4
with:
path: target
key: ${{ runner.os }}-cargo-build-target-${{ steps.toolchain.outputs.cachekey }}-${{ hashFiles('**/Cargo.lock') }}
key: ${{ runner.os }}-stable-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}
- uses: actions-rs/toolchain@v1
with:
toolchain: "stable"
override: true
- name: Test MacOS
run: bash test/scripts/test_macos.sh
@ -97,25 +101,26 @@ 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-${{ steps.toolchain.outputs.cachekey }}-${{ hashFiles('**/Cargo.lock') }}
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
- name: Cache cargo build
uses: actions/cache@v4
with:
path: target
key: ${{ runner.os }}-cargo-build-target-${{ steps.toolchain.outputs.cachekey }}-${{ hashFiles('**/Cargo.lock') }}
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
- 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: v20.1.6
rev: v19.1.5
hooks:
- id: clang-format
types_or: [c++, c]
- repo: https://github.com/psf/black
rev: 25.1.0
rev: 24.10.0
hooks:
- id: black

View file

@ -4,7 +4,7 @@ enable_testing()
set (CMAKE_EXPORT_COMPILE_COMMANDS ON)
project (task
VERSION 3.4.1
VERSION 3.3.0
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 --no-show-signature
execute_process (COMMAND git log -1 --pretty=format:%h
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE COMMIT)
configure_file ( ${CMAKE_SOURCE_DIR}/commit.h.in
@ -67,6 +67,7 @@ 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)
@ -161,6 +162,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" "target" "test" "misc/*" "performance" "swp$" "src/lex$" "task-.*.tar.gz"
set (CPACK_SOURCE_IGNORE_FILES "build" "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)

View file

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

1151
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,36 +1,11 @@
------ 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
@ -43,6 +18,8 @@ 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.81.0
- rust 1.78.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] (see: Uninstallation)
$ cd .. ; rm -r task-X.Y.Z [6]
These commands are explained below:
@ -89,11 +89,6 @@ 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
--------------
@ -103,13 +98,6 @@ 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
-----------------------
@ -122,43 +110,6 @@ 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
----------------------

View file

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

View file

@ -41,6 +41,9 @@
/* 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,6 +24,3 @@ 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 line feed (U+000A).
The format is JSON, specifically a JSON object as a single line of text, terminated by a newline (U+000D).
The JSON looks like this:

View file

@ -143,9 +143,7 @@ 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. In particular, ensure that no lifecycle policies are enabled, as they
may automatically delete or transition objects, potentially impacting data
availability.
adequate.
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:foo list
task description.word:bar list
.fi
Will match the description 'foo bar baz' but does not match 'dog food'.

View file

@ -212,9 +212,6 @@ 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.
@ -1384,7 +1381,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|uuid|date|duration
.B uda.<name>.type=string|numeric|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
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
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
dependency.cpp
feedback.cpp
legacy.cpp
@ -27,25 +27,26 @@ add_library (task STATIC CLI2.cpp
recur.cpp
rules.cpp
sort.cpp
util.cpp)
util.cpp util.h)
target_link_libraries(task taskchampion-cpp)
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
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
libshared/src/ip.cpp
libshared/src/shared.cpp
libshared/src/unicode.cpp
libshared/src/utf8.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)
add_executable (task_executable main.cpp)
add_executable (calc_executable calc.cpp)

View file

@ -36,15 +36,16 @@
#include <Version.h>
#include <assert.h>
#include <format.h>
#include <recur.h>
#include <rules.h>
#include <main.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>
@ -54,6 +55,7 @@
#include <commit.h>
#endif
#include <stdio.h>
#include <sys/ioctl.h>
#ifdef SOLARIS
@ -596,6 +598,9 @@ 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.
@ -669,21 +674,6 @@ 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.
@ -862,7 +852,7 @@ int Context::dispatch(std::string& out) {
Command* c = commands[command];
assert(c);
// The command know whether they need a GC or recurrence update.
// The command know whether they need a GC.
if (c->needs_gc()) {
tdb2.gc();
}
@ -879,11 +869,6 @@ 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);
}
@ -1173,13 +1158,6 @@ 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,13 +286,6 @@ 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,6 +34,7 @@
#include <Task.h>
#include <format.h>
#include <shared.h>
#include <time.h>
#include <map>

View file

@ -36,6 +36,8 @@
#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,6 +30,7 @@
#include <Task.h>
#include <Variant.h>
#include <string>
#include <vector>
class Filter {

View file

@ -44,6 +44,7 @@
#include <Variant.h>
#include <format.h>
#include <shared.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
@ -275,7 +276,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(Task& before, Task& after) const {
void Hooks::onModify(const 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(Task&, Task&) const;
void onModify(const Task&, Task&) const;
std::vector<std::string> list() const;
private:

View file

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

View file

@ -33,11 +33,16 @@
#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>
@ -45,16 +50,17 @@ bool TDB2::debug_mode = false;
static void dependency_scan(std::vector<Task>&);
////////////////////////////////////////////////////////////////////////////////
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(const std::string& location, bool create_if_missing) {
_replica = tc::new_replica_on_disk(location, create_if_missing);
}
////////////////////////////////////////////////////////////////////////////////
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.
@ -188,8 +194,11 @@ void TDB2::purge(Task& task) {
////////////////////////////////////////////////////////////////////////////////
rust::Box<tc::Replica>& TDB2::replica() {
// One of the open_replica_ methods must be called before this one.
assert(_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();
}
return _replica.value();
}
@ -354,7 +363,8 @@ bool TDB2::get(const std::string& uuid, Task& task) {
////////////////////////////////////////////////////////////////////////////////
// Locate task by UUID, wherever it is.
bool TDB2::has(const std::string& uuid) {
return replica()->get_task_data(tc::uuid_from_string(uuid)).is_some();
Task task;
return get(uuid, task);
}
////////////////////////////////////////////////////////////////////////////////
@ -440,6 +450,11 @@ 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,7 +27,9 @@
#ifndef INCLUDED_TDB2
#define INCLUDED_TDB2
#include <FS.h>
#include <Task.h>
#include <stdio.h>
#include <taskchampion-cpp/lib.h>
#include <map>
@ -44,8 +46,7 @@ class TDB2 {
TDB2() = default;
void open_replica(const std::string &, bool create_if_missing, bool read_write);
void open_replica_in_memory();
void open_replica(const std::string &, bool create_if_missing);
void add(Task &);
void modify(Task &);
void purge(Task &);
@ -71,6 +72,8 @@ class TDB2 {
int num_local_changes();
int num_reverts_possible();
void dump();
rust::Box<tc::Replica> &replica();
private:

View file

@ -31,12 +31,18 @@
#include <Table.h>
#include <cmake.h>
#include <format.h>
#ifdef PRODUCT_TASKWARRIOR
#include <legacy.h>
#endif
#include <main.h>
#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,9 +29,12 @@
#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,8 +58,7 @@
#include <Eval.h>
#include <Filter.h>
#include <Variant.h>
#include <dependency.h>
#include <feedback.h>
#include <main.h>
#define APPROACHING_INFINITY 1000 // Close enough. This isn't rocket surgery.
@ -322,8 +321,8 @@ void Task::setStatus(Task::status status) {
////////////////////////////////////////////////////////////////////////////////
// Determines status of a date attribute.
Task::dateState Task::getDateState(const std::string& name) const {
time_t value = get_date(name);
if (value > 0) {
std::string value = get(name);
if (value.length()) {
Datetime reference(value);
Datetime now;
Datetime today("today");
@ -777,7 +776,7 @@ void Task::parseLegacy(const std::string& line) {
}
////////////////////////////////////////////////////////////////////////////////
std::string Task::composeJSON(bool decorate /*= false*/) {
std::string Task::composeJSON(bool decorate /*= false*/) const {
std::stringstream out;
out << '{';
@ -798,23 +797,20 @@ std::string Task::composeJSON(bool decorate /*= false*/) {
// 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") {
time_t epoch = get_date(i.first);
if (epoch != 0) {
Datetime d(i.second);
if (attributes_written) out << ',';
Datetime d(i.second);
out << '"' << (i.first == "modification" ? "modified" : i.first)
<< "\":\""
// Date was deleted, do not export parsed empty string
<< (i.second == "" ? "" : d.toISO()) << '"';
out << '"' << (i.first == "modification" ? "modified" : i.first)
<< "\":\""
// Date was deleted, do not export parsed empty string
<< (i.second == "" ? "" : d.toISO()) << '"';
++attributes_written;
}
++attributes_written;
}
/*
@ -824,8 +820,6 @@ std::string Task::composeJSON(bool decorate /*= false*/) {
}
*/
else if (type == "numeric") {
if (attributes_written) out << ',';
out << '"' << i.first << "\":" << i.second;
++attributes_written;
@ -833,8 +827,6 @@ std::string Task::composeJSON(bool decorate /*= false*/) {
// Everything else is a quoted value.
else {
if (attributes_written) out << ',';
out << '"' << i.first << "\":\"" << (type == "string" ? json::encode(i.second) : i.second)
<< '"';
@ -894,7 +886,7 @@ std::string Task::composeJSON(bool decorate /*= false*/) {
#ifdef PRODUCT_TASKWARRIOR
// Include urgency.
if (decorate) out << ',' << "\"urgency\":" << urgency();
if (decorate) out << ',' << "\"urgency\":" << urgency_c();
#endif
out << '}';
@ -928,7 +920,7 @@ void Task::addAnnotation(const std::string& description) {
++now;
} while (has(key));
data[key] = description;
data[key] = json::decode(description);
++annotation_count;
recalc_urgency = true;
}
@ -1999,7 +1991,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() == "uuid") {
column->type() == "string") {
column->modify(*this, value);
mods = true;
}

View file

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

View file

@ -75,6 +75,7 @@
#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"
@ -1759,9 +1760,7 @@ Variant& Variant::operator/=(const Variant& other) {
throw std::string(STRING_VARIANT_DIV_DUR_DATE);
case type_duration:
_type = type_real;
_real = static_cast<double>(_duration) / static_cast<double>(right._duration);
break;
throw std::string(STRING_VARIANT_DIV_DUR_DUR);
}
break;
}

View file

@ -28,7 +28,9 @@
#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 <rules.h>
#include <main.h>
#include <utf8.h>
#include <util.h>

View file

@ -30,10 +30,13 @@
#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,9 +56,11 @@ void ColumnTypeDuration::modify(Task& task, const std::string& value) {
evaluatedValue = Variant(value);
}
// The duration is first parsed, then stored inside the variant as a `time_t`
// The duration is stored in raw form, but it must still be valid,
// and therefore is parsed first.
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,23 +297,3 @@ 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,7 +31,6 @@
#include <ColTypeDuration.h>
#include <ColTypeNumeric.h>
#include <ColTypeString.h>
#include <ColUUID.h>
////////////////////////////////////////////////////////////////////////////////
class ColumnUDAString : public ColumnTypeString {
@ -84,12 +83,5 @@ 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,15 +246,9 @@ 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', 'uuid', date', 'duration' or "
"'numeric'.");
"User defined attributes may only be of type 'string', '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,7 +40,6 @@ CmdAdd::CmdAdd() {
_read_only = false;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = true;
_accepts_filter = false;
_accepts_modifications = true;
@ -56,11 +55,6 @@ 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,7 +39,6 @@ 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,7 +44,6 @@ 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,7 +44,6 @@ 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,7 +42,6 @@ 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,6 +33,7 @@
#include <Duration.h>
#include <Filter.h>
#include <format.h>
#include <main.h>
#include <math.h>
#include <shared.h>
#include <string.h>
@ -766,7 +767,6 @@ 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,6 +779,8 @@ 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);
@ -799,7 +801,6 @@ CmdBurndownWeekly::CmdBurndownWeekly() {
_read_only = true;
_displays_id = false;
_needs_gc = true;
_needs_recur_update = true;
_uses_context = true;
_accepts_filter = true;
_accepts_modifications = false;
@ -812,6 +813,8 @@ 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);
@ -832,7 +835,6 @@ CmdBurndownDaily::CmdBurndownDaily() {
_read_only = true;
_displays_id = false;
_needs_gc = true;
_needs_recur_update = true;
_uses_context = true;
_accepts_filter = true;
_accepts_modifications = false;
@ -845,6 +847,8 @@ 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,7 +37,6 @@ 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,6 +32,7 @@
#include <Lexer.h>
#include <Table.h>
#include <format.h>
#include <main.h>
#include <shared.h>
#include <stdlib.h>
#include <utf8.h>
@ -48,7 +49,6 @@ 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,6 +80,8 @@ 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,6 +32,7 @@
#include <Context.h>
#include <Table.h>
#include <format.h>
#include <main.h>
#include <shared.h>
#include <sstream>
@ -44,7 +45,6 @@ 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,6 +31,7 @@
#include <Color.h>
#include <Context.h>
#include <Table.h>
#include <main.h>
#include <shared.h>
#include <util.h>
@ -44,7 +45,6 @@ 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,7 +119,6 @@ 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,7 +45,6 @@ CmdCommands::CmdCommands() {
_read_only = true;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = false;
_accepts_filter = false;
_accepts_modifications = false;
@ -62,7 +61,6 @@ 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);
@ -87,17 +85,15 @@ int CmdCommands::execute(std::string& output) {
if (command.second->needs_gc()) view.set(row, 4, "GC");
if (command.second->needs_recur_update()) view.set(row, 5, "Recur");
if (command.second->uses_context()) view.set(row, 5, "Ctxt");
if (command.second->uses_context()) view.set(row, 6, "Ctxt");
if (command.second->accepts_filter()) view.set(row, 6, "Filt");
if (command.second->accepts_filter()) view.set(row, 7, "Filt");
if (command.second->accepts_modifications()) view.set(row, 7, "Mods");
if (command.second->accepts_modifications()) view.set(row, 8, "Mods");
if (command.second->accepts_miscellaneous()) view.set(row, 8, "Misc");
if (command.second->accepts_miscellaneous()) view.set(row, 9, "Misc");
view.set(row, 10, command.second->description());
view.set(row, 9, command.second->description());
}
output = optionalBlankLine() + view.render() + optionalBlankLine() + '\n';

View file

@ -44,7 +44,6 @@ CmdConfig::CmdConfig() {
_read_only = true;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = false;
_accepts_filter = false;
_accepts_modifications = false;
@ -218,7 +217,6 @@ 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 <rules.h>
#include <main.h>
#include <shared.h>
#include <util.h>
@ -49,7 +49,6 @@ CmdContext::CmdContext() {
_read_only = true;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = false;
_accepts_filter = false;
_accepts_modifications = false;
@ -218,8 +217,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 {2}.", value,
reason)
<< format("The filter '{1}' is not a valid modification string, because it contains {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(
@ -415,7 +414,6 @@ 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,6 +30,7 @@
#include <CmdCount.h>
#include <Filter.h>
#include <format.h>
#include <main.h>
////////////////////////////////////////////////////////////////////////////////
CmdCount::CmdCount() {
@ -39,7 +40,6 @@ 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,6 +50,8 @@ 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 <legacy.h>
#include <main.h>
#include <shared.h>
#include <sort.h>
#include <stdlib.h>
#include <util.h>
#include <algorithm>
#include <iostream>
#include <map>
#include <sstream>
#include <vector>
@ -55,7 +55,6 @@ 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;
@ -101,6 +100,10 @@ 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,10 +30,8 @@
#include <CmdDelete.h>
#include <Context.h>
#include <Filter.h>
#include <dependency.h>
#include <feedback.h>
#include <format.h>
#include <recur.h>
#include <main.h>
#include <shared.h>
#include <iostream>
@ -51,7 +49,6 @@ 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,7 +49,6 @@ 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,7 +50,6 @@ 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,11 +30,8 @@
#include <CmdDone.h>
#include <Context.h>
#include <Filter.h>
#include <dependency.h>
#include <feedback.h>
#include <format.h>
#include <nag.h>
#include <recur.h>
#include <main.h>
#include <util.h>
#include <iostream>
@ -47,7 +44,6 @@ 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,7 +44,6 @@ 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,6 +36,7 @@
#include <Lexer.h>
#include <Pig.h>
#include <format.h>
#include <main.h>
#include <shared.h>
#include <unistd.h>
#include <util.h>
@ -63,7 +64,6 @@ 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,6 +77,8 @@ 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);
@ -317,6 +319,7 @@ 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.
@ -618,9 +621,10 @@ 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, doing nothing on error.
// Change directory for the editor
auto current_dir = Directory::cwd();
chdir(location._data.c_str());
int ignored = chdir(location._data.c_str());
++ignored; // Keep compiler quiet.
// Check if the file already exists, if so, bail out
Path filepath = Path(file.str());
@ -700,7 +704,7 @@ ARE_THESE_REALLY_HARMFUL:
// Cleanup.
File::remove(file.str());
chdir(current_dir.c_str());
ignored = chdir(current_dir.c_str());
return changes ? CmdEdit::editResult::changes : CmdEdit::editResult::nochanges;
}

View file

@ -40,7 +40,6 @@ 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,9 +31,8 @@
#include <Context.h>
#include <Filter.h>
#include <format.h>
#include <legacy.h>
#include <main.h>
#include <shared.h>
#include <sort.h>
////////////////////////////////////////////////////////////////////////////////
CmdExport::CmdExport() {
@ -43,7 +42,6 @@ CmdExport::CmdExport() {
_read_only = true;
_displays_id = true;
_needs_gc = true;
_needs_recur_update = true;
_uses_context = false;
_accepts_filter = true;
_accepts_modifications = false;
@ -84,6 +82,10 @@ 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,6 +32,7 @@
#include <DOM.h>
#include <Variant.h>
#include <format.h>
#include <main.h>
#include <shared.h>
////////////////////////////////////////////////////////////////////////////////
@ -42,7 +43,6 @@ 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,7 +44,6 @@ 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,6 +33,7 @@
#include <Filter.h>
#include <Table.h>
#include <format.h>
#include <main.h>
#include <util.h>
#include <sstream>
@ -54,7 +55,6 @@ 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,6 +293,8 @@ 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,6 +30,7 @@
#include <CmdIDs.h>
#include <Context.h>
#include <Filter.h>
#include <main.h>
#include <shared.h>
#include <algorithm>
@ -45,7 +46,6 @@ 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,6 +56,8 @@ CmdIDs::CmdIDs() {
////////////////////////////////////////////////////////////////////////////////
int CmdIDs::execute(std::string& output) {
// Apply filter.
handleUntil();
handleRecurrence();
Filter filter;
std::vector<Task> filtered;
filter.subset(filtered);
@ -125,7 +127,6 @@ CmdCompletionIds::CmdCompletionIds() {
_read_only = true;
_displays_id = true;
_needs_gc = true;
_needs_recur_update = true;
_uses_context = false;
_accepts_filter = true;
_accepts_modifications = false;
@ -136,6 +137,8 @@ CmdCompletionIds::CmdCompletionIds() {
////////////////////////////////////////////////////////////////////////////////
int CmdCompletionIds::execute(std::string& output) {
// Apply filter.
handleUntil();
handleRecurrence();
Filter filter;
std::vector<Task> filtered;
filter.subset(filtered);
@ -160,7 +163,6 @@ CmdZshCompletionIds::CmdZshCompletionIds() {
_read_only = true;
_displays_id = true;
_needs_gc = true;
_needs_recur_update = true;
_uses_context = false;
_accepts_filter = true;
_accepts_modifications = false;
@ -171,6 +173,8 @@ CmdZshCompletionIds::CmdZshCompletionIds() {
////////////////////////////////////////////////////////////////////////////////
int CmdZshCompletionIds::execute(std::string& output) {
// Apply filter.
handleUntil();
handleRecurrence();
Filter filter;
std::vector<Task> filtered;
filter.subset(filtered);
@ -195,7 +199,6 @@ CmdUUIDs::CmdUUIDs() {
_read_only = true;
_displays_id = false;
_needs_gc = true;
_needs_recur_update = true;
_uses_context = false;
_accepts_filter = true;
_accepts_modifications = false;
@ -206,6 +209,8 @@ CmdUUIDs::CmdUUIDs() {
////////////////////////////////////////////////////////////////////////////////
int CmdUUIDs::execute(std::string& output) {
// Apply filter.
handleUntil();
handleRecurrence();
Filter filter;
std::vector<Task> filtered;
filter.subset(filtered);
@ -229,7 +234,6 @@ CmdCompletionUuids::CmdCompletionUuids() {
_read_only = true;
_displays_id = false;
_needs_gc = true;
_needs_recur_update = true;
_uses_context = false;
_accepts_filter = true;
_accepts_modifications = false;
@ -240,6 +244,8 @@ CmdCompletionUuids::CmdCompletionUuids() {
////////////////////////////////////////////////////////////////////////////////
int CmdCompletionUuids::execute(std::string& output) {
// Apply filter.
handleUntil();
handleRecurrence();
Filter filter;
std::vector<Task> filtered;
filter.subset(filtered);
@ -263,7 +269,6 @@ CmdZshCompletionUuids::CmdZshCompletionUuids() {
_read_only = true;
_displays_id = false;
_needs_gc = true;
_needs_recur_update = true;
_uses_context = false;
_accepts_filter = true;
_accepts_modifications = false;
@ -274,6 +279,8 @@ CmdZshCompletionUuids::CmdZshCompletionUuids() {
////////////////////////////////////////////////////////////////////////////////
int CmdZshCompletionUuids::execute(std::string& output) {
// Apply filter.
handleUntil();
handleRecurrence();
Filter filter;
std::vector<Task> filtered;
filter.subset(filtered);

View file

@ -45,7 +45,6 @@ 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,7 +46,6 @@ 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,6 +31,7 @@
#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 <rules.h>
#include <main.h>
#include <math.h>
#include <shared.h>
#include <stdlib.h>
#include <taskchampion-cpp/lib.h>
@ -59,7 +59,6 @@ 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;
@ -120,11 +119,9 @@ int CmdInfo::execute(std::string& output) {
description += '\n' + std::string(indent, ' ') +
Datetime(anno.first.substr(11)).toString(dateformatanno) + ' ' + anno.second;
if (task.has("description")) {
row = view.addRow();
view.set(row, 0, "Description");
view.set(row, 1, description, c);
}
row = view.addRow();
view.set(row, 0, "Description");
view.set(row, 1, description, c);
// status
row = view.addRow();
@ -217,76 +214,64 @@ int CmdInfo::execute(std::string& output) {
}
// entry
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);
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();
}
view.set(row, 1, entry + " (" + age + ')');
std::string age;
auto created = task.get("entry");
if (created.length()) {
Datetime dt(strtoll(created.c_str(), nullptr, 10));
age = Duration(now - dt).formatVague();
}
auto validDate = [&](const char* prop) {
if (!task.has(prop)) {
return false;
}
if (task.get_date(prop) == 0) {
return false;
}
return true;
};
view.set(row, 1, entry + " (" + age + ')');
// wait
if (validDate("wait")) {
if (task.has("wait")) {
row = view.addRow();
view.set(row, 0, "Waiting until");
view.set(row, 1, Datetime(task.get_date("wait")).toString(dateformat));
}
// scheduled
if (validDate("scheduled")) {
if (task.has("scheduled")) {
row = view.addRow();
view.set(row, 0, "Scheduled");
view.set(row, 1, Datetime(task.get_date("scheduled")).toString(dateformat));
}
// start
if (validDate("start")) {
if (task.has("start")) {
row = view.addRow();
view.set(row, 0, "Start");
view.set(row, 1, Datetime(task.get_date("start")).toString(dateformat));
}
// due (colored)
if (validDate("due")) {
if (task.has("due")) {
row = view.addRow();
view.set(row, 0, "Due");
view.set(row, 1, Datetime(task.get_date("due")).toString(dateformat));
}
// end
if (validDate("end")) {
if (task.has("end")) {
row = view.addRow();
view.set(row, 0, "End");
view.set(row, 1, Datetime(task.get_date("end")).toString(dateformat));
}
// until
if (validDate("until")) {
if (task.has("until")) {
row = view.addRow();
view.set(row, 0, "Until");
view.set(row, 1, Datetime(task.get_date("until")).toString(dateformat));
}
// modified
if (validDate("modified")) {
if (task.has("modified")) {
row = view.addRow();
view.set(row, 0, "Last modified");
@ -646,11 +631,7 @@ std::optional<std::string> CmdInfo::formatForInfo(const std::vector<Operation>&
} else {
// Record the last start time for later duration calculation.
if (prop == "start") {
try {
last_start = Datetime(value.value()).toEpoch();
} catch (std::string) {
// ignore invalid dates
}
last_start = Datetime(value.value()).toEpoch();
}
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,7 +40,6 @@ 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,7 +39,6 @@ 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,9 +30,8 @@
#include <CmdModify.h>
#include <Context.h>
#include <Filter.h>
#include <feedback.h>
#include <format.h>
#include <recur.h>
#include <main.h>
#include <shared.h>
#include <iostream>
@ -49,7 +48,6 @@ CmdModify::CmdModify() {
_read_only = false;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = false;
_accepts_filter = true;
_accepts_modifications = true;
@ -120,7 +118,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) &&
(before.get("end") == "") && (after.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,6 +33,7 @@
#include <Duration.h>
#include <Table.h>
#include <format.h>
#include <main.h>
#include <shared.h>
#include <util.h>
@ -56,7 +57,6 @@ 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,7 +160,6 @@ std::vector<NewsItem> NewsItem::all() {
version3_1_0(items);
version3_2_0(items);
version3_3_0(items);
version3_4_0(items);
return items;
}
@ -531,21 +530,6 @@ 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();
@ -588,10 +572,61 @@ 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;
}
@ -606,8 +641,8 @@ bool CmdNews::should_nag() {
Version current_version = Version::Current();
if (news_version >= current_version) {
return false;
if (news_version == current_version) {
return true;
}
// Check if there are actually any interesting news items to show.

View file

@ -53,7 +53,6 @@ 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,7 +44,6 @@ 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,9 +32,10 @@
#include <Filter.h>
#include <Table.h>
#include <format.h>
#include <sort.h>
#include <main.h>
#include <util.h>
#include <algorithm>
#include <list>
#include <sstream>
@ -46,7 +47,6 @@ 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,6 +59,8 @@ 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"))
@ -139,7 +141,6 @@ CmdCompletionProjects::CmdCompletionProjects() {
_read_only = true;
_displays_id = false;
_needs_gc = true;
_needs_recur_update = true;
_uses_context = false;
_accepts_filter = true;
_accepts_modifications = false;
@ -150,6 +151,8 @@ 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,7 +43,6 @@ 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,7 +43,6 @@ 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 <legacy.h>
#include <main.h>
#include <util.h>
#include <algorithm>
@ -53,7 +53,6 @@ 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,11 +30,8 @@
#include <CmdStart.h>
#include <Context.h>
#include <Filter.h>
#include <dependency.h>
#include <feedback.h>
#include <format.h>
#include <nag.h>
#include <recur.h>
#include <main.h>
#include <util.h>
#include <iostream>
@ -47,7 +44,6 @@ 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,6 +34,7 @@
#include <Filter.h>
#include <Table.h>
#include <format.h>
#include <main.h>
#include <stdlib.h>
#include <util.h>
@ -48,7 +49,6 @@ 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,10 +30,8 @@
#include <CmdStop.h>
#include <Context.h>
#include <Filter.h>
#include <dependency.h>
#include <feedback.h>
#include <format.h>
#include <recur.h>
#include <main.h>
#include <iostream>
@ -45,7 +43,6 @@ 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,10 +33,11 @@
#include <Filter.h>
#include <Table.h>
#include <format.h>
#include <sort.h>
#include <main.h>
#include <stdlib.h>
#include <util.h>
#include <algorithm>
#include <list>
#include <sstream>
@ -48,7 +49,6 @@ 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,6 +65,8 @@ 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,11 +32,13 @@
#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 <regex>
#include <iostream>
#include <sstream>
////////////////////////////////////////////////////////////////////////////////
@ -47,7 +49,6 @@ CmdSync::CmdSync() {
_read_only = false;
_displays_id = false;
_needs_gc = false;
_needs_recur_update = false;
_uses_context = false;
_accepts_filter = false;
_accepts_modifications = false;
@ -79,12 +80,6 @@ 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';
@ -137,7 +132,6 @@ 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 == "") {
@ -147,17 +141,15 @@ 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}", safe_server_url) << '\n';
out << format("Syncing with sync server at {1}", 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).");
}
@ -166,15 +158,6 @@ 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,6 +32,7 @@
#include <Filter.h>
#include <Table.h>
#include <format.h>
#include <stdlib.h>
#include <util.h>
#include <sstream>
@ -45,7 +46,6 @@ 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,7 +136,6 @@ 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,7 +33,8 @@
#include <Filter.h>
#include <Table.h>
#include <format.h>
#include <rules.h>
#include <main.h>
#include <stdlib.h>
#include <util.h>
#include <algorithm>
@ -47,7 +48,6 @@ 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,6 +90,8 @@ 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,6 +33,7 @@
#include <Table.h>
#include <Task.h>
#include <format.h>
#include <main.h>
#include <shared.h>
#include <util.h>
@ -47,7 +48,6 @@ 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,7 +156,6 @@ 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,11 +31,12 @@
#include <Context.h>
#include <Operation.h>
#include <Task.h>
#include <shared.h>
#include <iostream>
#include <sstream>
#include "shared.h"
////////////////////////////////////////////////////////////////////////////////
CmdUndo::CmdUndo() {
_keyword = "undo";
@ -44,7 +45,6 @@ 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 = std::stringstream();
mods.clear();
}
if (op.is_create()) {

View file

@ -43,7 +43,6 @@ 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,6 +32,8 @@
#include <Filter.h>
#include <Lexer.h>
#include <format.h>
#include <main.h>
#include <stdlib.h>
#include <sstream>
@ -43,7 +45,6 @@ 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,6 +31,7 @@
#include <Context.h>
#include <Datetime.h>
#include <Table.h>
#include <stdlib.h>
#include <sstream>
#ifdef HAVE_COMMIT
@ -47,7 +48,6 @@ 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,7 +101,6 @@ 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,7 +50,9 @@
#include <CmdEdit.h>
#include <Command.h>
#include <format.h>
#include <main.h>
#include <shared.h>
#include <stdlib.h>
#include <util.h>
#include <iostream>
@ -293,7 +295,6 @@ Command::Command()
_displays_id(true),
_needs_confirm(false),
_needs_gc(true),
_needs_recur_update(false),
_uses_context(false),
_accepts_filter(false),
_accepts_modifications(false),
@ -321,9 +322,6 @@ 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,6 +31,7 @@
#include <map>
#include <string>
#include <vector>
class Command {
public:
@ -61,7 +62,6 @@ 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,7 +81,6 @@ 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,11 +28,13 @@
// 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:"

View file

@ -1,43 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
//
// 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