├── .github ├── dependabot.yml └── workflows │ ├── docker-image.yaml │ ├── tests.yaml │ └── update-docs.yml ├── .gitignore ├── .gitmodules ├── .pre-commit-config.yaml ├── AUTHORS ├── CMakeLists.txt ├── CONTRIBUTING.md ├── ChangeLog ├── DCO ├── INSTALL ├── LICENSE ├── README.md ├── cmake.h.in ├── cmake ├── CXXSniffer.cmake └── FindAsciidoctor.cmake ├── commit.h.in ├── completion ├── README.md ├── timew-completion.bash ├── timew.fish └── timew.zsh ├── doc ├── CMakeLists.txt ├── holidays │ ├── CMakeLists.txt │ ├── README │ ├── holidays.en-US │ └── refresh ├── man1 │ ├── .gitignore │ ├── CMakeLists.txt │ ├── timew-annotate.1.adoc │ ├── timew-cancel.1.adoc │ ├── timew-chart.1.adoc │ ├── timew-config.1.adoc │ ├── timew-continue.1.adoc │ ├── timew-day.1 │ ├── timew-day.1.in │ ├── timew-delete.1.adoc │ ├── timew-diagnostics.1.adoc │ ├── timew-export.1.adoc │ ├── timew-extensions.1.adoc │ ├── timew-fill.1.adoc │ ├── timew-gaps.1.adoc │ ├── timew-get.1.adoc │ ├── timew-help.1.adoc │ ├── timew-join.1.adoc │ ├── timew-lengthen.1.adoc │ ├── timew-modify.1.adoc │ ├── timew-month.1 │ ├── timew-month.1.in │ ├── timew-move.1.adoc │ ├── timew-report.1.adoc │ ├── timew-resize.1.adoc │ ├── timew-retag.1.adoc │ ├── timew-shorten.1.adoc │ ├── timew-show.1.adoc │ ├── timew-split.1.adoc │ ├── timew-start.1.adoc │ ├── timew-stop.1.adoc │ ├── timew-summary.1.adoc │ ├── timew-tag.1.adoc │ ├── timew-tags.1.adoc │ ├── timew-track.1.adoc │ ├── timew-undo.1.adoc │ ├── timew-untag.1.adoc │ ├── timew-week.1 │ ├── timew-week.1.in │ └── timew.1.adoc ├── man7 │ ├── .gitignore │ ├── CMakeLists.txt │ ├── timew-config.7.adoc │ ├── timew-dates.7.adoc │ ├── timew-dom.7.adoc │ ├── timew-durations.7.adoc │ ├── timew-hints.7.adoc │ └── timew-ranges.7.adoc ├── report.day.1.txt ├── report.summary.txt ├── report.week.1.txt ├── rfc_command_definition.md ├── rules.txt └── themes │ ├── CMakeLists.txt │ ├── README │ ├── dark.theme │ ├── dark_blue.theme │ ├── dark_green.theme │ └── dark_red.theme ├── docker-compose.yml ├── docker └── timew.dockerfile ├── ext ├── CMakeLists.txt ├── README ├── csv.py ├── debug.py ├── on-modify.timewarrior └── totals.py ├── src ├── .gitignore ├── AtomicFile.cpp ├── AtomicFile.h ├── CLI.cpp ├── CLI.h ├── CMakeLists.txt ├── Chart.cpp ├── Chart.h ├── ChartConfig.h ├── Database.cpp ├── Database.h ├── Datafile.cpp ├── Datafile.h ├── DatetimeParser.cpp ├── DatetimeParser.h ├── Exclusion.cpp ├── Exclusion.h ├── Extensions.cpp ├── Extensions.h ├── ExtensionsTable.cpp ├── ExtensionsTable.h ├── GapsTable.cpp ├── GapsTable.h ├── Interval.cpp ├── Interval.h ├── IntervalFactory.cpp ├── IntervalFactory.h ├── IntervalFilter.cpp ├── IntervalFilter.h ├── IntervalFilterAllInRange.cpp ├── IntervalFilterAllInRange.h ├── IntervalFilterAllWithIds.cpp ├── IntervalFilterAllWithIds.h ├── IntervalFilterAllWithTags.cpp ├── IntervalFilterAllWithTags.h ├── IntervalFilterAndGroup.cpp ├── IntervalFilterAndGroup.h ├── IntervalFilterFirstOf.cpp ├── IntervalFilterFirstOf.h ├── Journal.cpp ├── Journal.h ├── Range.cpp ├── Range.h ├── Rules.cpp ├── Rules.h ├── SummaryTable.cpp ├── SummaryTable.h ├── TagDescription.cpp ├── TagDescription.h ├── TagInfo.cpp ├── TagInfo.h ├── TagInfoDatabase.cpp ├── TagInfoDatabase.h ├── TagsTable.cpp ├── TagsTable.h ├── Transaction.cpp ├── Transaction.h ├── TransactionsFactory.cpp ├── TransactionsFactory.h ├── UndoAction.cpp ├── UndoAction.h ├── commands │ ├── .gitignore │ ├── CMakeLists.txt │ ├── CmdAnnotate.cpp │ ├── CmdCancel.cpp │ ├── CmdChart.cpp │ ├── CmdConfig.cpp │ ├── CmdContinue.cpp │ ├── CmdDefault.cpp │ ├── CmdDelete.cpp │ ├── CmdDiagnostics.cpp │ ├── CmdExport.cpp │ ├── CmdExtensions.cpp │ ├── CmdFill.cpp │ ├── CmdGaps.cpp │ ├── CmdGet.cpp │ ├── CmdHelp.cpp │ ├── CmdJoin.cpp │ ├── CmdLengthen.cpp │ ├── CmdModify.cpp │ ├── CmdModifyEnd.cpp │ ├── CmdModifyRange.cpp │ ├── CmdModifyStart.cpp │ ├── CmdMove.cpp │ ├── CmdReport.cpp │ ├── CmdResize.cpp │ ├── CmdRetag.cpp │ ├── CmdShorten.cpp │ ├── CmdShow.cpp │ ├── CmdSplit.cpp │ ├── CmdStart.cpp │ ├── CmdStop.cpp │ ├── CmdSummary.cpp │ ├── CmdTag.cpp │ ├── CmdTags.cpp │ ├── CmdTrack.cpp │ ├── CmdUndo.cpp │ ├── CmdUntag.cpp │ ├── commands.h │ └── generate-additional-help.sh ├── data.cpp ├── dom.cpp ├── helper.cpp ├── init.cpp ├── lex.cpp ├── log.cpp ├── paths.cpp ├── paths.h ├── timew.cpp ├── timew.h ├── util.cpp └── validate.cpp └── test ├── .gitignore ├── AtomicFile.t ├── AtomicFileTest.cpp ├── CMakeLists.txt ├── Datafile.t.cpp ├── DatetimeParser.t.cpp ├── TagInfoDatabase.t.cpp ├── TempDir.h ├── annotate.t ├── basetest ├── __init__.py ├── exceptions.py ├── meta.py ├── testing.py ├── timew.py └── utils.py ├── bash_tap.sh ├── bash_tap_ti.sh ├── cancel.t ├── chart.t ├── cli.t ├── clock.t ├── config.t ├── continue.t ├── data.t.cpp ├── delete.t ├── docker ├── alpine-edge ├── alpine-latest ├── archlinux ├── centos-stream9 ├── debianstable ├── debiantesting ├── fedora41 ├── fedora42 ├── gentoo ├── opensuseleap ├── opensusetumbleweed ├── ubuntu2204 └── ubuntu2404 ├── dom.t ├── exclusion.t.cpp ├── export.t ├── extensions.t ├── fill.t ├── gaps.t ├── help.t ├── helper.t.cpp ├── ids.t ├── interval.t.cpp ├── join.t ├── lengthen.t ├── modify.t ├── move.t ├── performance-plot.py ├── performance-test.sh ├── problems ├── quiet.t ├── range.t.cpp ├── resize.t ├── retag.t ├── rules.t.cpp ├── run_all ├── scripts └── test_osx.sh ├── shorten.t ├── simpletap └── __init__.py ├── split.t ├── start.t ├── stop.t ├── summary.t ├── tag.t ├── tags.t ├── test.cpp ├── test.h ├── test_extensions ├── debug.py └── ext_echo ├── test_totals.t ├── timemachine ├── track.t ├── undo.t ├── untag.t ├── util.t.cpp ├── version.t └── write-failure.t /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | # Enable version updates for GitHub actions 4 | - package-ecosystem: "github-actions" 5 | directory: "/" 6 | schedule: 7 | interval: "weekly" 8 | -------------------------------------------------------------------------------- /.github/workflows/docker-image.yaml: -------------------------------------------------------------------------------- 1 | name: Timewarrior Docker image 2 | 3 | on: 4 | workflow_dispatch: 5 | workflow_run: 6 | workflows: [tests] 7 | branches: 8 | - develop 9 | - stable 10 | types: 11 | - completed 12 | 13 | env: 14 | REGISTRY: "ghcr.io" 15 | 16 | jobs: 17 | build-and-push-docker-image: 18 | runs-on: ubuntu-latest 19 | if: ${{ github.event_name == 'workflow_dispatch' || (github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success') }} 20 | permissions: 21 | contents: read 22 | packages: write 23 | id-token: write 24 | 25 | steps: 26 | - name: Create lowercase repository name 27 | run: | 28 | GHCR_REPOSITORY="${{ github.repository_owner }}" 29 | echo "REPOSITORY=${GHCR_REPOSITORY,,}" >> ${GITHUB_ENV} 30 | - name: Checkout repository 31 | uses: actions/checkout@v4 32 | with: 33 | submodules: "recursive" 34 | 35 | - name: Install cosign 36 | uses: sigstore/cosign-installer@v3.8.2 37 | 38 | - name: Log into registry ${{ env.REGISTRY }} 39 | uses: docker/login-action@v3.4.0 40 | with: 41 | registry: ${{ env.REGISTRY }} 42 | username: ${{ github.repository_owner }} 43 | password: ${{ secrets.GITHUB_TOKEN }} 44 | 45 | - name: Build and push Timewarrior Docker image 46 | id: build-and-push 47 | uses: docker/build-push-action@v6.17.0 48 | with: 49 | context: . 50 | file: "./docker/timew.dockerfile" 51 | push: true 52 | tags: ${{ env.REGISTRY }}/${{ env.REPOSITORY }}/timew:${{ github.ref_name }} 53 | 54 | - name: Sign the published Docker image 55 | env: 56 | COSIGN_EXPERIMENTAL: "true" 57 | run: cosign sign ${{ env.REGISTRY }}/${{ env.REPOSITORY }}/timew@${{ steps.build-and-push.outputs.digest }} 58 | -------------------------------------------------------------------------------- /.github/workflows/tests.yaml: -------------------------------------------------------------------------------- 1 | name: tests 2 | on: [push, pull_request, workflow_dispatch] 3 | jobs: 4 | tests: 5 | strategy: 6 | fail-fast: false 7 | matrix: 8 | include: 9 | - name: "Alpine Edge" 10 | runner: ubuntu-latest 11 | container: alpine-edge 12 | - name: "Alpine Latest" 13 | runner: ubuntu-latest 14 | container: alpine-latest 15 | - name: "Archlinux Base" 16 | runner: ubuntu-latest 17 | container: archlinux 18 | - name: "Centos Stream9" 19 | runner: ubuntu-latest 20 | container: centos-stream9 21 | - name: "Debian Stable" 22 | runner: ubuntu-latest 23 | container: debianstable 24 | - name: "Debian Testing" 25 | runner: ubuntu-latest 26 | container: debiantesting 27 | - name: "Fedora 41" 28 | runner: ubuntu-latest 29 | container: fedora41 30 | - name: "Fedora 42" 31 | runner: ubuntu-latest 32 | container: fedora42 33 | - name: "OpenSUSE Leap" 34 | runner: ubuntu-latest 35 | container: opensuseleap 36 | - name: "OpenSUSE Tumbleweed" 37 | runner: ubuntu-latest 38 | container: opensusetumbleweed 39 | - name: "Ubuntu 22.04" 40 | runner: ubuntu-latest 41 | container: ubuntu2204 42 | - name: "Ubuntu 24.04" 43 | runner: ubuntu-latest 44 | container: ubuntu2204 45 | - name: "macOS 13" 46 | runner: macos-13 47 | container: osx-13 48 | - name: "macOS 14" 49 | runner: macos-14 50 | container: osx-14 51 | - name: "macOS 15" 52 | runner: macos-15 53 | container: osx-15 54 | runs-on: ${{ matrix.runner }} 55 | continue-on-error: ${{ matrix.continue-on-error == true }} 56 | steps: 57 | - uses: actions/checkout@v4 58 | - name: Build ${{ matrix.name }} 59 | env: 60 | DOCKER_REGISTRY: docker.pkg.github.com 61 | DOCKER_CACHE_IMAGE: docker.pkg.github.com/${{ github.repository }}/timewarrior_cache 62 | GITHUB_USER: ${{ github.actor }} 63 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 64 | CONTAINER: ${{ matrix.container }} 65 | run: if [[ !( "${CONTAINER}" =~ osx-* ) ]] ; then docker compose build "test-${CONTAINER}" ; fi 66 | - name: Test ${{ matrix.name }} 67 | env: 68 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 69 | CONTAINER: ${{ matrix.container }} 70 | run: if [[ !( "${CONTAINER}" =~ osx-* ) ]]; then docker compose run "test-${CONTAINER}" ; else bash test/scripts/test_osx.sh ; fi 71 | -------------------------------------------------------------------------------- /.github/workflows/update-docs.yml: -------------------------------------------------------------------------------- 1 | name: Update docs on ti.net 2 | on: 3 | workflow_dispatch: 4 | release: 5 | types: 6 | - published 7 | jobs: 8 | trigger: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout Repository 12 | uses: actions/checkout@v4 13 | - name: Trigger remote workflow to update docs 14 | run: | 15 | repo_owner="GothenburgBitFactory" 16 | repo_name="ti.net" 17 | event_type="update-docs" 18 | version="${{ github.event.release.tag_name }}" 19 | 20 | # Collect .adoc documentation files 21 | doc_filenames=$(find doc/man1 -name '*.adoc' -type f; find doc/man7 -name '*.adoc' -type f) 22 | 23 | # Format doc_filenames with double quotes and commas 24 | formatted_doc_filenames="[ $(echo ${doc_filenames} | sed 's/\S\+/\"&\",/g; s/,$//') ]" 25 | 26 | base64_encoded_files=() 27 | while IFS= read -r filename; do 28 | base64_encoded_file=$(base64 "${filename}" | tr -d '\n') 29 | base64_encoded_files+=("\"${base64_encoded_file}\"") 30 | done <<< "${doc_filenames}" 31 | 32 | # Format encoded_file_contents with quotes and commas 33 | formatted_encoded_file_contents="[ $(IFS=,; echo "${base64_encoded_files[*]}") ]" 34 | 35 | curl -L \ 36 | -X POST \ 37 | -H "Accept: application/vnd.github+json" \ 38 | -H "Authorization: Bearer ${{ secrets.UPDATE_DOCS }}" \ 39 | -H "X-GitHub-Api-Version: 2022-11-28" \ 40 | https://api.github.com/repos/${repo_owner}/${repo_name}/dispatches \ 41 | -d "{\"event_type\": \"$event_type\", \"client_payload\": {\"version\": \"${version}\", \"doc_filenames\": ${formatted_doc_filenames}, \"encoded_file_contents\": ${formatted_encoded_file_contents} }}" 42 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | CMakeFiles/ 2 | CMakeCache.txt 3 | CPack* 4 | Makefile 5 | cmake.h 6 | commit.h 7 | cmake_install.cmake 8 | install_manifest.txt 9 | *.swp 10 | *.pyc 11 | *.cbp 12 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/libshared"] 2 | path = src/libshared 3 | url = https://github.com/GothenburgBitFactory/libshared.git 4 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: [] 2 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | The development of Timewarrior was made possible by the significant contributions of the following people: 2 | 3 | Thomas Lauf (Principal Author) 4 | Paul Beckingham (Contributing Author) 5 | Federico Hernandez (Contributing Author) 6 | Dirk Deimeke (Technical Advisor) 7 | Tomas Babej (Contributing Author) 8 | Shaun Ruffel (Contributing Author) 9 | 10 | The following submitted code, packages or analysis, and deserve special thanks: 11 | 12 | Renato Alves 13 | Wim Schuermann 14 | Jelle van der Waa 15 | Sergey Trofimov 16 | Gordon Ball 17 | Kent R. Spillner 18 | Ben Boeckel 19 | Michael Meier 20 | Martin Boeker 21 | Felix Wolfsteller 22 | Jörg Krause 23 | Richard Brown 24 | Armado Martinez 25 | A M 26 | asmyers 27 | Lukas Barth 28 | Paul J. Fenwick 29 | Michael Neumann 30 | davisdude 31 | Aaron Fields 32 | vedharish 33 | janikrabe 34 | Dennis Schridde 35 | quazgar 36 | Johannes Hertenstein 37 | Christian Rösch 38 | silent-at-gh 39 | Lim Ding Wen 40 | Stanisław Wysocki 41 | Scott Mcdermott 42 | Daniel Hornung 43 | Maxim Beder 44 | Ankur Sinha 45 | Povl Filip Sonne-Frederiksen 46 | Benedikt Fein 47 | Tadeas Uhlir 48 | Iúri Archer 49 | Ian Kenney 50 | 51 | Thanks to the following, who submitted detailed bug reports and excellent suggestions: 52 | 53 | Shawn Wilson 54 | creatid 55 | Frédéric Meynadier 56 | Bruno Vernay 57 | Wade Duvall 58 | Sebastian Uharek 59 | Aaron Curtis 60 | Matthew Lemon 61 | Rene Vergara 62 | Matthias Rieber 63 | lumbric 64 | Michel Crucifix 65 | Jonathon Bly 66 | Felix Wolfsteller 67 | hosaka 68 | Aaron Evers 69 | David Patrick 70 | Georg Sauthoff 71 | Josh Proehl 72 | Mattia Rizzolo 73 | m8r 74 | Jan Stolarek 75 | Yury Videneev 76 | Plup 77 | Bodo Graumann 78 | Lynoure 79 | Tim Ruffing 80 | Andreas Poisel 81 | Christian Decker 82 | chronitis 83 | rudis 84 | bognolo 85 | Antanas B. 86 | towo 87 | sclo 88 | ddombrowsky 89 | triclops200 90 | Valodim 91 | AlexLov 92 | Fabian Pflug 93 | OddBloke 94 | somospocos 95 | quazgar 96 | RainbowSwirls 97 | bzed 98 | Charlie Gorichanaz 99 | Clément Hermann 100 | Saulius Krasuckas 101 | Tom Dörr 102 | Joerg Kastning 103 | George Buckingham 104 | Maximilian Merz 105 | choppy812 106 | kbcb 107 | sclee15 108 | varac 109 | xeruf 110 | Rafael Oliveira 111 | agentcoffee 112 | eq0cdk 113 | squirrellyDave 114 | Edd Salkield 115 | Oivvio Polite 116 | Davide Crucitti 117 | Christian Kohlstedde 118 | apkawel 119 | Leon Grünewald 120 | Ivo Forlin 121 | aMOPel 122 | Per Møldrup-Dalum 123 | Beshoy Girgis 124 | Sergey Zhuravlevich 125 | catexis 126 | Aniket Meshram 127 | Joachim Meyer 128 | arxel-sc 129 | Eugene Morozov 130 | Stefan Herold 131 | Sebastian Carlos 132 | -------------------------------------------------------------------------------- /DCO: -------------------------------------------------------------------------------- 1 | ## Sign your work - the Developer's Certificate of Origin 2 | The sign-off is a simple line at the end of the explanation for the patch, which certifies that you wrote it or otherwise have the right to pass it on as an open-source patch. 3 | The rules are pretty simple: if you can certify the below (from developercertificate.org): 4 | 5 | > Developer's Certificate of Origin 1.1 6 | > 7 | > By making a contribution to this project, I certify that: 8 | > 9 | > (a) The contribution was created in whole or in part by me and I 10 | > have the right to submit it under the open source license 11 | > indicated in the file; or 12 | > 13 | > (b) The contribution is based upon previous work that, to the best 14 | > of my knowledge, is covered under an appropriate open source 15 | > license and I have the right under that license to submit that 16 | > work with modifications, whether created in whole or in part 17 | > by me, under the same open source license (unless I am 18 | > permitted to submit under a different license), as indicated 19 | > in the file; or 20 | > 21 | > (c) The contribution was provided directly to me by some other 22 | > person who certified (a), (b) or (c) and I have not modified 23 | > it. 24 | > 25 | > (d) I understand and agree that this project and the contribution 26 | > are public and that a record of the contribution (including all 27 | > personal information I submit with it, including my sign-off) is 28 | > maintained indefinitely and may be redistributed consistent with 29 | > this project or the open source license(s) involved. 30 | 31 | #### DCO Sign-Off Methods 32 | 33 | The DCO requires a sign-off message in the following format appear on each commit in the pull request: 34 | 35 | > Signed-off-by: Random J Developer 36 | 37 | using your real name (sorry, no pseudonyms or anonymous contributions.) 38 | 39 | The DCO text can either be manually added to your commit body, or you can add either **-s** or **--signoff** to your usual git commit commands. 40 | If you forget to add the sign-off you can also amend a previous commit with the sign-off by running **git commit --amend -s**. 41 | If you've pushed your changes to GitHub already you'll need to force push your branch after this with **git push -f**. 42 | 43 | 44 | #### Alternative Sign-Off Methods in rare cases 45 | 46 | If it is really no option for you to disclose your real name and email address, there might be a chance that you can get your contribution accepted. 47 | In this case please contact the maintainers directly and verify the adherence to the DCO of the contribution manually. 48 | This might include quite some legal overhead for both parties. 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT license 2 | 3 | https://opensource.org/licenses/mit-license.php 4 | 5 | Copyright 2015 - 2023, Thomas Lauf, Paul Beckingham, Federico Hernandez. 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included 15 | in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | 25 | -------------------------------------------------------------------------------- /cmake.h.in: -------------------------------------------------------------------------------- 1 | /* cmake.h.in. Creates cmake.h during a cmake run */ 2 | 3 | /* Package information */ 4 | #define PACKAGE "${PACKAGE}" 5 | #define VERSION "${VERSION}" 6 | #define PACKAGE_BUGREPORT "${PACKAGE_BUGREPORT}" 7 | #define PACKAGE_NAME "${PACKAGE_NAME}" 8 | #define PACKAGE_TARNAME "${PACKAGE_TARNAME}" 9 | #define PACKAGE_VERSION "${PACKAGE_VERSION}" 10 | #define PACKAGE_STRING "${PACKAGE_STRING}" 11 | 12 | #define CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}" 13 | 14 | /* git information */ 15 | #cmakedefine HAVE_COMMIT 16 | 17 | /* cmake information */ 18 | #cmakedefine HAVE_CMAKE 19 | #define CMAKE_VERSION "${CMAKE_VERSION}" 20 | 21 | /* Compiling platform */ 22 | #cmakedefine LINUX 23 | #cmakedefine DARWIN 24 | #cmakedefine CYGWIN 25 | #cmakedefine FREEBSD 26 | #cmakedefine OPENBSD 27 | #cmakedefine NETBSD 28 | #cmakedefine DRAGONFLY 29 | #cmakedefine HAIKU 30 | #cmakedefine SOLARIS 31 | #cmakedefine KFREEBSD 32 | #cmakedefine GNUHURD 33 | #cmakedefine UNKNOWN 34 | 35 | /* Found tm.tm_gmtoff struct member */ 36 | #cmakedefine HAVE_TM_GMTOFF 37 | 38 | /* Found st.st_birthtime struct member */ 39 | #cmakedefine HAVE_ST_BIRTHTIME 40 | 41 | /* Functions */ 42 | #cmakedefine HAVE_GET_CURRENT_DIR_NAME 43 | #cmakedefine HAVE_TIMEGM 44 | #cmakedefine HAVE_UUID_UNPARSE_LOWER 45 | -------------------------------------------------------------------------------- /cmake/CXXSniffer.cmake: -------------------------------------------------------------------------------- 1 | message ("-- System: ${CMAKE_SYSTEM_NAME}") 2 | 3 | if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") 4 | set (LINUX true) 5 | elseif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") 6 | set (DARWIN true) 7 | set (CMAKE_CXX_FLAGS "-stdlib=libc++ ${CMAKE_CXX_FLAGS}") 8 | elseif (${CMAKE_SYSTEM_NAME} MATCHES "kFreeBSD") 9 | set (KFREEBSD true) 10 | elseif (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") 11 | set (FREEBSD true) 12 | elseif (${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD") 13 | set (OPENBSD true) 14 | elseif (${CMAKE_SYSTEM_NAME} MATCHES "NetBSD") 15 | set (NETBSD true) 16 | elseif (${CMAKE_SYSTEM_NAME} MATCHES "DragonFly") 17 | set (DRAGONFLY true) 18 | elseif (${CMAKE_SYSTEM_NAME} MATCHES "SunOS") 19 | set (SOLARIS true) 20 | elseif (${CMAKE_SYSTEM_NAME} STREQUAL "GNU") 21 | set (GNUHURD true) 22 | elseif (${CMAKE_SYSTEM_NAME} STREQUAL "CYGWIN") 23 | set (CYGWIN true) 24 | else (${CMAKE_SYSTEM_NAME} MATCHES "Linux") 25 | set (UNKNOWN true) 26 | endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux") 27 | 28 | set (CMAKE_CXX_FLAGS "-Wall -Wextra -Wsign-compare -Wreturn-type ${CMAKE_CXX_FLAGS}") 29 | -------------------------------------------------------------------------------- /cmake/FindAsciidoctor.cmake: -------------------------------------------------------------------------------- 1 | message (CHECK_START "Detecting Asciidoctor") 2 | 3 | FIND_PROGRAM(ASCIIDOCTOR_EXECUTABLE asciidoctor 4 | PATHS "/usr/bin" "/usr/sbin") 5 | 6 | MARK_AS_ADVANCED(ASCIIDOCTOR_EXECUTABLE) 7 | 8 | if (ASCIIDOCTOR_EXECUTABLE) 9 | message(CHECK_PASS "found") 10 | message(DEBUG "Found executable ${ASCIIDOCTOR_EXECUTABLE}") 11 | set(ASCIIDOCTOR_FOUND "YES") 12 | else (ASCIIDOCTOR_EXECUTABLE) 13 | message(CHECK_FAIL "not found") 14 | message(NOTICE " Could not find Asciidoctor!") 15 | set(ASCIIDOCTOR_FOUND "NO") 16 | endif (ASCIIDOCTOR_EXECUTABLE) 17 | -------------------------------------------------------------------------------- /commit.h.in: -------------------------------------------------------------------------------- 1 | /* commit.h.in. Creates commit.h during a cmake run */ 2 | 3 | /* git information */ 4 | #define COMMIT "${COMMIT}" 5 | -------------------------------------------------------------------------------- /completion/README.md: -------------------------------------------------------------------------------- 1 | # Shell completions 2 | 3 | The completion scripts here are taken from separate projects. 4 | Issues and pull-requests regarding those should go there. 5 | The updated version of each script will then be included here. 6 | 7 | If you are missing a completion, feel free to contribute. 8 | 9 | * `timew.fish` is taken from [pfmephisto/timew-fishcompletion](https://github.com/pfmephisto/timew-fishcompletion) which is released under [MIT license](https://github.com/pfmephisto/timew-fishcompletion/blob/main/LICENSE) 10 | * `timew-completion.bash` is taken from [lauft/timew-bashcompletion](https://github.com/lauft/timew-bashcompletion) which is released under [MIT license](https://github.com/lauft/timew-bashcompletion/blob/master/LICENSE) 11 | * `timew.zsh` is taken from [ianmkenney/timewarrior_zsh_completion](https://github.com/ianmkenney/timewarrior_zsh_completion) which is released under [MIT license](https://github.com/ianmkenney/timewarrior_zsh_completion/blob/main/LICENSE) 12 | 13 | Huge thanks to everyone contributing! ❤️ 14 | -------------------------------------------------------------------------------- /doc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.10) 2 | 3 | message ("-- Configuring documentation") 4 | 5 | add_subdirectory (holidays) 6 | add_subdirectory (themes) 7 | 8 | if (ASCIIDOCTOR_FOUND) 9 | set (ASCIIDOCTOR_OPTIONS "--attribute=manmanual=User Manuals" 10 | "--attribute=mansource=timew ${PROJECT_VERSION}") 11 | endif (ASCIIDOCTOR_FOUND) 12 | 13 | add_subdirectory (man1) 14 | add_subdirectory (man7) 15 | 16 | add_custom_target (doc ALL DEPENDS man1 man7) 17 | -------------------------------------------------------------------------------- /doc/holidays/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.10) 2 | 3 | message ("-- Configuring holiday documentation") 4 | 5 | install (FILES README DESTINATION ${TIMEW_DOCDIR}/holidays) 6 | install (FILES holidays.en-US DESTINATION ${TIMEW_DOCDIR}/holidays) 7 | install (FILES refresh DESTINATION ${TIMEW_DOCDIR}/holidays) 8 | -------------------------------------------------------------------------------- /doc/holidays/README: -------------------------------------------------------------------------------- 1 | # Timewarrior Holiday Files 2 | 3 | The holiday files were created by the `refresh` script using data from [holidata.net](https://holidata.net). 4 | They can be updated using the following command: 5 | 6 | ```shell 7 | $ ./refresh 8 | ``` 9 | 10 | This updates all present holiday files with holiday data for the current and the following year (default). 11 | 12 | If you need another locale (for example `sv-SE`), do this: 13 | 14 | ```shell 15 | $ ./refresh --locale sv-SE 16 | ``` 17 | 18 | This creates a file `holidays.sv-SE` containing holiday data for the current and following year. 19 | The id for the locale is composed of the [ISO 639-1 language code](https://en.wikipedia.org/wiki/ISO_639-1) and the [ISO 3166-1 alpha-2 country code](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2). 20 | 21 | If you need a specific locale region, do this: 22 | 23 | ```shell 24 | $ ./refresh --locale de-CH --region BE 25 | ``` 26 | 27 | For regions use the corresponding [ISO 3166-2 code for principal subdivisions](https://en.wikipedia.org/wiki/ISO_3166-2). 28 | 29 | To specify a set of years to update, do this: 30 | 31 | ```shell 32 | $ ./refresh --locale en-US --year 2020 2021 2022 33 | ``` 34 | 35 | If the locale is not yet supported by [holidata.net](https://holidata.net), or there is no data available for the requested year, you will see an error. 36 | -------------------------------------------------------------------------------- /doc/holidays/holidays.en-US: -------------------------------------------------------------------------------- 1 | # Holiday data provided by holidata.net 2 | # Generated 2021-05-28T12:07:28 3 | 4 | define holidays: 5 | en-US: 6 | 2020_01_01 = New Year's Day 7 | 2020_01_20 = Birthday of Martin Luther King, Jr. 8 | 2020_02_17 = Washington's Birthday 9 | 2020_04_20 = Patriots' Day 10 | 2020_05_25 = Memorial Day 11 | 2020_07_04 = Independence Day 12 | 2020_09_07 = Labor Day 13 | 2020_10_12 = Columbus Day 14 | 2020_11_11 = Veterans Day 15 | 2020_11_26 = Thanksgiving Day 16 | 2020_11_27 = Day after Thanksgiving 17 | 2020_12_24 = Christmas Eve 18 | 2020_12_25 = Christmas Day 19 | 20 | 2021_01_01 = New Year's Day 21 | 2021_01_18 = Birthday of Martin Luther King, Jr. 22 | 2021_02_15 = Washington's Birthday 23 | 2021_04_19 = Patriots' Day 24 | 2021_05_31 = Memorial Day 25 | 2021_07_04 = Independence Day 26 | 2021_09_06 = Labor Day 27 | 2021_10_11 = Columbus Day 28 | 2021_11_11 = Veterans Day 29 | 2021_11_25 = Thanksgiving Day 30 | 2021_12_25 = Christmas Day 31 | 32 | -------------------------------------------------------------------------------- /doc/man1/.gitignore: -------------------------------------------------------------------------------- 1 | *.[0-9] 2 | !timew-day.1 3 | !timew-month.1 4 | !timew-week.1 5 | -------------------------------------------------------------------------------- /doc/man1/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.10) 2 | 3 | if (ASCIIDOCTOR_FOUND) 4 | file (GLOB DOC_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.1.adoc") 5 | set (DOC_FILES) 6 | 7 | foreach (SRC IN LISTS DOC_SOURCES) 8 | string (REPLACE ".adoc" "" OUTPUT_FILE_NAME "${SRC}") 9 | string (REPLACE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}" OUTPUT_FILE_NAME "${OUTPUT_FILE_NAME}") 10 | 11 | add_custom_command (OUTPUT "${OUTPUT_FILE_NAME}" 12 | COMMAND ${ASCIIDOCTOR_EXECUTABLE} -b manpage ${ASCIIDOCTOR_OPTIONS} "${SRC}" -o "${OUTPUT_FILE_NAME}" 13 | DEPENDS "${SRC}") 14 | 15 | list (APPEND DOC_FILES "${OUTPUT_FILE_NAME}") 16 | endforeach (SRC) 17 | 18 | add_custom_target (man1 DEPENDS ${DOC_FILES}) 19 | else (ASCIIDOCTOR_FOUND) 20 | file (GLOB MAN_PAGES "${CMAKE_CURRENT_SOURCE_DIR}/*.1") 21 | set (DOC_FILES ${MAN_PAGES}) 22 | endif (ASCIIDOCTOR_FOUND) 23 | 24 | install (FILES ${DOC_FILES} DESTINATION ${TIMEW_MAN1DIR}) 25 | -------------------------------------------------------------------------------- /doc/man1/timew-annotate.1.adoc: -------------------------------------------------------------------------------- 1 | = timew-annotate(1) 2 | 3 | == NAME 4 | timew-annotate - add an annotation to intervals 5 | 6 | == SYNOPSIS 7 | [verse] 8 | *timew annotate* [__**...**] __ 9 | 10 | == DESCRIPTION 11 | The 'annotate' command is used to add an annotation to an interval. 12 | 13 | See the 'summary' command on how to display the __ and __ of an interval. 14 | 15 | == EXAMPLES 16 | *Annotate a single interval*:: 17 | + 18 | Call the command with an _id_ and the _annotation_: 19 | + 20 | [source] 21 | ---- 22 | $ timew annotate @2 'Lorem ipsum' 23 | Annotated @2 with "Lorem ipsum" 24 | ---- 25 | 26 | *Remove an annotation*:: 27 | + 28 | Annotating an interval with an empty string removes the annotation: 29 | + 30 | [source] 31 | ---- 32 | $ timew annotate @1 '' 33 | Removed annotation from @1 34 | ---- 35 | 36 | *Annotate multiple intervals*:: 37 | + 38 | You can annotate multiple intervals with the same _annotation_ at once, by specifying their ids: 39 | + 40 | [source] 41 | ---- 42 | $ timew annotate @2 @10 @23 'Lorem ipsum' 43 | Annotated @1 with "Lorem ipsum" 44 | Annotated @10 with "Lorem ipsum" 45 | Annotated @23 with "Lorem ipsum" 46 | ---- 47 | 48 | *Annotate the current open interval*:: 49 | + 50 | If there is active time tracking, you can omit the ID when you want to add an annotation to the current open interval: 51 | + 52 | [source] 53 | ---- 54 | $ timew start foo 55 | ... 56 | $ timew annotate bar 57 | Annotated @1 with "bar" 58 | ---- 59 | + 60 | This results in the current interval having tag 'foo' and annotation 'bar'. 61 | 62 | == pass:[BUGS & LIMITATIONS] 63 | The summary command truncates annotations longer than 15 characters. 64 | To display longer annotations, one can use the 'export' command, or a custom report. 65 | 66 | Currently, the annotation command picks the last token from the command line and uses it as annotation. 67 | I.e. using no quotes in an annotation command like 68 | 69 | [source] 70 | ---- 71 | $ timew annotate @1 lorem ipsum 72 | ---- 73 | 74 | will result in interval @1 having only 'ipsum' as its annotation. 75 | Use quotes to avoid this. 76 | 77 | == SEE ALSO 78 | **timew-export**(1), 79 | **timew-summary**(1), 80 | **timew-tag**(1) 81 | -------------------------------------------------------------------------------- /doc/man1/timew-cancel.1.adoc: -------------------------------------------------------------------------------- 1 | = timew-cancel(1) 2 | 3 | == NAME 4 | timew-cancel - cancel time tracking 5 | 6 | == SYNOPSIS 7 | [verse] 8 | *timew cancel* 9 | 10 | == DESCRIPTION 11 | If there is an open interval, it is abandoned. 12 | 13 | == EXAMPLES 14 | 15 | *Cancel with active time tracking*:: 16 | + 17 | $ timew start 18 | ... 19 | $ timew cancel 20 | Canceled active time tracking. 21 | 22 | This deletes the open interval. 23 | 24 | *Cancel with no active time tracking*:: 25 | + 26 | ... 27 | $ timew stop 28 | $ timew cancel 29 | There is no active time tracking. 30 | 31 | Cancel has no effect, only a warning is printed. 32 | 33 | == SEE ALSO 34 | **timew-continue**(1), 35 | **timew-start**(1), 36 | **timew-stop**(1), 37 | **timew-track**(1) 38 | -------------------------------------------------------------------------------- /doc/man1/timew-config.1.adoc: -------------------------------------------------------------------------------- 1 | = timew-config(1) 2 | 3 | == NAME 4 | timew-config - get and set Timewarrior configuration 5 | 6 | == SYNOPSIS 7 | [verse] 8 | *timew config* [__ {__|*''*}] 9 | 10 | == DESCRIPTION 11 | Allows setting and removing configuration values, as an alternative to directly editing your _timewarrior.cfg_ file. 12 | 13 | == EXAMPLES 14 | For example: 15 | 16 | $ timew config verbose yes 17 | $ timew config verbose '' 18 | $ timew config verbose 19 | 20 | The first command sets 'verbose' to 'yes'. 21 | The second sets it to a blank value which overrides the default value. 22 | The third example deletes the 'verbose' setting. 23 | 24 | When modifying configuration in this way, interactive confirmation will be sought. 25 | To override this confirmation, use the ':yes' hint, which means you intend to answer 'yes' to the confirmation questions: 26 | 27 | $ timew config verbose '' :yes 28 | 29 | If no arguments are provided, all configuration settings are shown: 30 | 31 | $ timew config 32 | verbose = yes 33 | ... 34 | 35 | == SEE ALSO 36 | **timew-hints**(7), 37 | **timew-show**(1) 38 | -------------------------------------------------------------------------------- /doc/man1/timew-day.1: -------------------------------------------------------------------------------- 1 | .so man1/timew-chart.1 2 | -------------------------------------------------------------------------------- /doc/man1/timew-day.1.in: -------------------------------------------------------------------------------- 1 | .so man1/timew-chart.1 -------------------------------------------------------------------------------- /doc/man1/timew-delete.1.adoc: -------------------------------------------------------------------------------- 1 | = timew-delete(1) 2 | 3 | == NAME 4 | timew-delete - delete intervals 5 | 6 | == SYNOPSIS 7 | [verse] 8 | *timew delete* __**...** 9 | 10 | == DESCRIPTION 11 | Deletes an interval. 12 | Using the 'summary' command, and specifying the ':ids' hint shows interval IDs. 13 | Using the right ID, you can identify an interval to delete. 14 | 15 | == EXAMPLES 16 | For example, show the IDs: 17 | 18 | $ timew summary :week :ids 19 | 20 | Then having selected '@2' as the interval you wish to delete: 21 | 22 | $ timew delete @2 23 | 24 | 25 | == SEE ALSO 26 | **timew-cancel**(1) 27 | -------------------------------------------------------------------------------- /doc/man1/timew-diagnostics.1.adoc: -------------------------------------------------------------------------------- 1 | = timew-diagnostics(1) 2 | 3 | == NAME 4 | timew-diagnostics - show diagnostic information 5 | 6 | == SYNOPSIS 7 | [verse] 8 | *timew diagnostics* 9 | 10 | == DESCRIPTION 11 | This command shows details about your version of Timewarrior, your platform, how it was built, compiler features, configuration, file access, extensions and more. 12 | 13 | The purpose of this command is to help diagnose configuration problems and provide supplemental information when reporting a problem. 14 | 15 | == SEE ALSO 16 | **timew-extensions**(1) 17 | -------------------------------------------------------------------------------- /doc/man1/timew-export.1.adoc: -------------------------------------------------------------------------------- 1 | = timew-export(1) 2 | 3 | == NAME 4 | timew-export - export tracked time in JSON 5 | 6 | == SYNOPSIS 7 | [verse] 8 | *timew export* [ __**...** | ([__] [__**...**]) ] 9 | 10 | == DESCRIPTION 11 | Exports all the tracked time in JSON format. 12 | 13 | Supply either a list of interval IDs (e.g. `@1 @2`), or optional filters (see **timew-ranges**(7) and/or **timew-tags**(1)) 14 | 15 | == EXAMPLES 16 | 17 | *Export all intervals*:: 18 | [source] 19 | ---- 20 | $ timew export 21 | ... 22 | ---- 23 | 24 | *Export intervals filtered by range and tag*:: 25 | [source] 26 | ---- 27 | $ timew export from 2016-01-01 for 3wks tag1 28 | ... 29 | ---- 30 | 31 | *Export intervals by their ids*:: 32 | [source] 33 | ---- 34 | $ timew export @1 @3 @7 35 | ... 36 | ---- 37 | -------------------------------------------------------------------------------- /doc/man1/timew-extensions.1.adoc: -------------------------------------------------------------------------------- 1 | = timew-extensions(1) 2 | 3 | == NAME 4 | timew-extensions - list available extensions 5 | 6 | == SYNOPSIS 7 | [verse] 8 | *timew extensions* 9 | 10 | == DESCRIPTION 11 | Displays the directory containing the extension programs and a table showing each extension and its status. 12 | 13 | == SEE ALSO 14 | **timew-diagnostics**(1) 15 | -------------------------------------------------------------------------------- /doc/man1/timew-fill.1.adoc: -------------------------------------------------------------------------------- 1 | = timew-fill(1) 2 | 3 | == NAME 4 | timew-fill - adjust intervals to fill in surrounding gaps 5 | 6 | == SYNOPSIS 7 | [verse] 8 | *timew fill* __**...** 9 | 10 | == DESCRIPTION 11 | The 'fill' command is used to adjust any interval to fill in surrounding gaps. 12 | Using the 'summary' command, and specifying the ':ids' hint shows interval IDs. 13 | Using the right ID, you can identify an interval to fill. 14 | 15 | == EXAMPLES 16 | For example, show the IDs: 17 | 18 | $ timew summary :week :ids 19 | 20 | Then having selected '@2' as the interval you wish to fill: 21 | 22 | $ timew fill @2 23 | 24 | Note that you can fill multiple intervals: 25 | 26 | $ timew fill @2 @10 @23 27 | 28 | 29 | == SEE ALSO 30 | **timew-hints**(7) 31 | -------------------------------------------------------------------------------- /doc/man1/timew-gaps.1.adoc: -------------------------------------------------------------------------------- 1 | = timew-gaps(1) 2 | 3 | == NAME 4 | timew-gaps - display time tracking gaps 5 | 6 | == SYNOPSIS 7 | [verse] 8 | *timew gaps* [__] [__**...**] 9 | 10 | == DESCRIPTION 11 | Displays a summary of time that is neither tracked nor excluded from tracking. 12 | 13 | The 'reports.gaps.range' configuration setting overrides the default date range. 14 | The ':blank' hint causes only the excluded time to be shown, with no tracked time. 15 | The default date range shown is ':day'. 16 | 17 | == CONFIGURATION 18 | **reports.gaps.range**:: 19 | For reports that show a range of data, this setting will override the default value. 20 | The value should be a range hint, see **timew-hints**(7). 21 | 22 | == SEE ALSO 23 | **timew-summary**(1) 24 | -------------------------------------------------------------------------------- /doc/man1/timew-get.1.adoc: -------------------------------------------------------------------------------- 1 | = timew-get(1) 2 | 3 | == NAME 4 | timew-get - display DOM values 5 | 6 | == SYNOPSIS 7 | [verse] 8 | *timew get* __**...** 9 | 10 | == DESCRIPTION 11 | Validates the DOM reference, then obtains the value and displays it. 12 | 13 | == EXAMPLES 14 | For example: 15 | 16 | $ timew get dom.active 17 | 1 18 | 19 | It is an error to reference an interval or tag that does not exist. 20 | 21 | == SEE ALSO 22 | **timew-dom**(7) 23 | -------------------------------------------------------------------------------- /doc/man1/timew-help.1.adoc: -------------------------------------------------------------------------------- 1 | = timew-help(1) 2 | 3 | == NAME 4 | timew-help - display help 5 | 6 | == SYNOPSIS 7 | [verse] 8 | *timew help* {__|*interval*|*hints*|*date*|*duration*} 9 | 10 | == DESCRIPTION 11 | The help command shows detailed descriptions and examples of commands, interval syntax, supported hints, date and duration formats and DOM references. 12 | 13 | == EXAMPLES 14 | For example: 15 | 16 | $ timew help 17 | $ timew help start 18 | $ timew help hints 19 | $ timew help interval 20 | $ timew help date 21 | $ timew help duration 22 | $ timew help dom 23 | -------------------------------------------------------------------------------- /doc/man1/timew-join.1.adoc: -------------------------------------------------------------------------------- 1 | = timew-join(1) 2 | 3 | == NAME 4 | timew-join - join intervals 5 | 6 | == SYNOPSIS 7 | [verse] 8 | *timew join* _ _ 9 | 10 | == DESCRIPTION 11 | Joins two intervals, by using the earlier one of the two start times, and the later one of the two end times, and the combined set of tags. 12 | Using the 'summary' command, and specifying the ':ids' hint shows interval IDs. 13 | Using the correct IDs, you can identify an intervals to join. 14 | 15 | == EXAMPLES 16 | For example, show the IDs: 17 | 18 | $ timew summary :week :ids 19 | 20 | Then having selected '@1' and '@2' as the intervals you wish to join: 21 | 22 | $ timew join @1 @2 23 | 24 | == SEE ALSO 25 | **timew-lengthen**(1), 26 | **timew-resize**(1), 27 | **timew-shorten**(1), 28 | **timew-split**(1) 29 | -------------------------------------------------------------------------------- /doc/man1/timew-lengthen.1.adoc: -------------------------------------------------------------------------------- 1 | = timew-lengthen(1) 2 | 3 | == NAME 4 | timew-lengthen - lengthen intervals 5 | 6 | == SYNOPSIS 7 | [verse] 8 | *timew lengthen* __**...** __ 9 | 10 | == DESCRIPTION 11 | The 'lengthen' command is used to defer the end date of a closed interval. 12 | Using the 'summary' command, and specifying the ':ids' hint shows interval IDs. 13 | Using the right ID, you can identify an interval to lengthen. 14 | 15 | == EXAMPLES 16 | For example, show the IDs: 17 | 18 | $ timew summary :week :ids 19 | 20 | Then having selected '@2' as the interval you wish to lengthen: 21 | 22 | $ timew lengthen @2 10mins 23 | 24 | Note that you can lengthen multiple intervals,: 25 | 26 | $ timew lengthen @2 @10 @23 1hour 27 | 28 | == SEE ALSO 29 | **timew-modify**(1), 30 | **timew-resize**(1), 31 | **timew-shorten**(1), 32 | **timew-summary**(1), 33 | **timew-tag**(1), 34 | **timew-untag**(1) 35 | -------------------------------------------------------------------------------- /doc/man1/timew-modify.1.adoc: -------------------------------------------------------------------------------- 1 | = timew-modify(1) 2 | 3 | == NAME 4 | timew-modify - change the range of an interval 5 | 6 | == SYNOPSIS 7 | [verse] 8 | *timew modify* (*start*|*end*) __ __ 9 | *timew modify* range __ __ 10 | 11 | == DESCRIPTION 12 | The 'modify' command is used to change range of an interval. 13 | 14 | Using the 'start' or 'end' subcommand, one can either specify a new start or end date respectively, or with the 'range' subcommand, change the complete range. 15 | The interval to be modified is specified via its id. 16 | 17 | If the resulting interval overlaps with an existing interval, the command will return an error. 18 | One can add the ':adjust' hint to force an overwrite in this case. 19 | 20 | See **timew-summary**(1) on how to retrieve the interval id. 21 | 22 | == EXAMPLES 23 | *Modify the start date of an interval*:: 24 | + 25 | $ timew modify start @3 2020-12-28T17:00 26 | + 27 | This sets the start of interval '@3' to '17:00' of date '2020-12-28'. 28 | If this datetime is after the end of the interval, the command will return an error. 29 | 30 | *Modify the end date of an interval*:: 31 | + 32 | If the interval to be modified has the same date as today, it can be omitted: 33 | + 34 | $ timew modify end @3 18:00 35 | + 36 | Similar to when modifying the interval start, the end datetime has to be after the start datetime. 37 | 38 | *Modify the range of an interval*:: 39 | + 40 | Instead of modifying start and end separately, those can be combined into a single call of the 'range' subcommand: 41 | + 42 | $ timew modify range @3 2020-12-28T17:00 - 2020-12-28T18:00 43 | + 44 | As in the examples above, the date portion can be omitted, if the date of the interval is today. 45 | 46 | == SEE ALSO 47 | **timew-lengthen**(1), 48 | **timew-move**(1), 49 | **timew-resize**(1), 50 | **timew-shorten**(1), 51 | **timew-summary**(1) -------------------------------------------------------------------------------- /doc/man1/timew-month.1: -------------------------------------------------------------------------------- 1 | .so man1/timew-chart.1 2 | -------------------------------------------------------------------------------- /doc/man1/timew-month.1.in: -------------------------------------------------------------------------------- 1 | .so man1/timew-chart.1 -------------------------------------------------------------------------------- /doc/man1/timew-move.1.adoc: -------------------------------------------------------------------------------- 1 | = timew-move(1) 2 | 3 | == NAME 4 | timew-move - change interval start-time 5 | 6 | == SYNOPSIS 7 | [verse] 8 | *timew move* __ __ 9 | 10 | == DESCRIPTION 11 | The 'move' command is used to reposition an interval at a new start time. 12 | Using the 'summary' command, and specifying the ':ids' hint shows interval IDs. 13 | Using the right ID, you can identify an interval to move. 14 | 15 | == EXAMPLES 16 | For example, show the IDs: 17 | 18 | $ timew summary :week :ids 19 | 20 | Then having selected '@2' as the interval you wish to move: 21 | 22 | $ timew move @2 9am 23 | 24 | == SEE ALSO 25 | **timew-lengthen**(1), 26 | **timew-modify**(1), 27 | **timew-resize**(1), 28 | **timew-shorten**(1), 29 | **timew-summary**(1), 30 | **timew-tag**(1), 31 | **timew-untag**(1) 32 | -------------------------------------------------------------------------------- /doc/man1/timew-report.1.adoc: -------------------------------------------------------------------------------- 1 | = timew-report(1) 2 | 3 | == NAME 4 | timew-report - run an extension report 5 | 6 | == SYNOPSIS 7 | [verse] 8 | *timew* [*report*] __ [__] [__**...**] 9 | *timew* [*report*] __ __**...** 10 | 11 | == DESCRIPTION 12 | Runs an extension report, and supports filtering data. 13 | The 'report' command itself is optional, which means that these two commands are equivalent: 14 | 15 | $ timew report foo :week 16 | $ timew foo :week 17 | 18 | This does however assume there is a 'foo' extension installed. 19 | 20 | The return code is the return code of the extension. 21 | If the extension produces no output and a non-zero rc, then 255 is returned. 22 | 23 | Filtering is either possible by range and/or tags, or by ids. 24 | 25 | == CONFIGURATION 26 | 27 | **reports.range**:: 28 | Sets the default date range for all reports. 29 | The value has to correspond to a range hint, see **timew-hints**(7). 30 | Defaults to `all` 31 | 32 | **reports.**____**.range**:: 33 | Set the date range for report _name_, used if no _range_ is given on the command line. 34 | Here, _name_ is the name of the report executable without its extension (i.e. a report executable 'foo.py' is referred to by 'foo'). 35 | The value has to correspond to a range hint, see **timew-hints**(7). 36 | Defaults to the value of **reports.range**. 37 | -------------------------------------------------------------------------------- /doc/man1/timew-resize.1.adoc: -------------------------------------------------------------------------------- 1 | = timew-resize(1) 2 | 3 | == NAME 4 | timew-resize - set interval duration 5 | 6 | == SYNOPSIS 7 | [verse] 8 | *timew resize* __**...** __ 9 | 10 | == DESCRIPTION 11 | The 'resize' command is used to change the duration of a closed interval. 12 | Using the 'summary' command, and specifying the ':ids' hint shows interval IDs. 13 | Using the right ID, you can identify an interval to resize. 14 | 15 | == EXAMPLES 16 | For example, show the IDs: 17 | 18 | $ timew summary :week :ids 19 | 20 | Then having selected '@3' as the interval you wish to resize: 21 | 22 | $ timew resize @3 15mins 23 | 24 | Note that you can resize multiple intervals,: 25 | 26 | $ timew resize @3 @1 @13 1hour 27 | 28 | == SEE ALSO 29 | **timew-lengthen**(1), 30 | **timew-modify**(1), 31 | **timew-shorten**(1), 32 | **timew-summary**(1), 33 | **timew-tag**(1), 34 | **timew-untag**(1) 35 | -------------------------------------------------------------------------------- /doc/man1/timew-retag.1.adoc: -------------------------------------------------------------------------------- 1 | = timew-retag(1) 2 | 3 | == NAME 4 | timew-retag - replace all tags in intervals 5 | 6 | == SYNOPSIS 7 | [verse] 8 | *timew retag* [__**...**] __**...** 9 | 10 | == DESCRIPTION 11 | The 'retag' command is used to replace all tags in an interval with the newly provided tags. 12 | Using the 'summary' command, and specifying the ':ids' hint shows interval IDs. 13 | Using the right ID, you can identify an interval to retag. 14 | 15 | == EXAMPLES 16 | For example, show the IDs: 17 | 18 | $ timew summary :week :ids 19 | 20 | Then having selected '@2' as the interval you wish to retag: 21 | 22 | $ timew retag @2 'New Tag' 23 | 24 | Note that you can retag multiple intervals, with multiple tags: 25 | 26 | $ timew retag @2 @10 @23 'Tag One' tag2 tag3 27 | 28 | If there is active time tracking, you can omit the ID when you want to retag the current open interval: 29 | 30 | $ timew start foo 31 | $ timew retag bar 32 | 33 | This results in the current interval having only the 'bar' tag. 34 | 35 | == SEE ALSO 36 | **timew-lengthen**(1), 37 | **timew-shorten**(1), 38 | **timew-summary**(1), 39 | **timew-tag**(1), 40 | **timew-untag**(1) 41 | -------------------------------------------------------------------------------- /doc/man1/timew-shorten.1.adoc: -------------------------------------------------------------------------------- 1 | = timew-shorten(1) 2 | 3 | == NAME 4 | timew-shorten - shorten intervals 5 | 6 | == SYNOPSIS 7 | [verse] 8 | *timew shorten* __**...** __ 9 | 10 | == DESCRIPTION 11 | The 'shorten' command is used to advance the end date of a closed interval. 12 | Using the 'summary' command, and specifying the ':ids' hint shows interval IDs. 13 | Using the right ID, you can identify an interval to shorten. 14 | 15 | == EXAMPLES 16 | For example, show the IDs: 17 | 18 | $ timew summary :week :ids 19 | 20 | Then having selected '@2' as the interval you wish to shorten: 21 | 22 | $ timew shorten @2 10mins 23 | 24 | Note that you can shorten multiple intervals,: 25 | 26 | $ timew shorten @2 @10 @23 1hour 27 | 28 | == SEE ALSO 29 | **timew-lengthen**(1), 30 | **timew-modify**(1), 31 | **timew-resize**(1), 32 | **timew-summary**(1), 33 | **timew-tag**(1), 34 | **timew-untag**(1) 35 | -------------------------------------------------------------------------------- /doc/man1/timew-show.1.adoc: -------------------------------------------------------------------------------- 1 | = timew-show(1) 2 | 3 | == NAME 4 | timew-show - display configuration 5 | 6 | == SYNOPSIS 7 | [verse] 8 | *timew show* 9 | 10 | == DESCRIPTION 11 | Displays the effective configuration in hierarchical form. 12 | 13 | == SEE ALSO 14 | **timew-config**(1) 15 | -------------------------------------------------------------------------------- /doc/man1/timew-split.1.adoc: -------------------------------------------------------------------------------- 1 | = timew-split(1) 2 | 3 | == NAME 4 | timew-split - split intervals 5 | 6 | == SYNOPSIS 7 | [verse] 8 | *timew split* __**...** 9 | 10 | == DESCRIPTION 11 | Ѕplits an interval into two equally sized adjacent intervals, having the same tags. 12 | Using the 'summary' command, and specifying the ':ids' hint shows interval IDs. 13 | Using the right ID, you can identify an interval to split. 14 | 15 | == EXAMPLES 16 | For example, show the IDs: 17 | 18 | $ timew summary :week :ids 19 | 20 | Then having selected '@2' as the interval you wish to split: 21 | 22 | $ timew split @2 23 | 24 | == SEE ALSO 25 | **timew-join**(1), 26 | **timew-lengthen**(1), 27 | **timew-shorten**(1) 28 | -------------------------------------------------------------------------------- /doc/man1/timew-start.1.adoc: -------------------------------------------------------------------------------- 1 | = timew-start(1) 2 | 3 | == NAME 4 | timew-start - start time tracking 5 | 6 | == SYNOPSIS 7 | [verse] 8 | *timew start* [__] [__**...**] 9 | 10 | == DESCRIPTION 11 | Begins tracking using the current time with any specified set of tags. 12 | If a tag contains multiple words, therefore containing spaces, use quotes to surround the whole tag. 13 | 14 | == EXAMPLES 15 | For example, this command specifies two tags ('weekend' and 'Home & Garden'), the second of which requires quotes. 16 | 17 | $ timew start weekend 'Home & Garden' 18 | 19 | An optional date may be specified to indicate the intended start of the tracked time: 20 | 21 | $ timew start 8am weekend 'Home & Garden' 22 | 23 | If there is a previous open interval, it will be closed at the given start time. 24 | 25 | Quotes are harmless if used unnecessarily. 26 | 27 | == SEE ALSO 28 | **timew-cancel**(1), 29 | **timew-continue**(1), 30 | **timew-stop**(1), 31 | **timew-track**(1) 32 | -------------------------------------------------------------------------------- /doc/man1/timew-stop.1.adoc: -------------------------------------------------------------------------------- 1 | = timew-stop(1) 2 | 3 | == NAME 4 | timew-stop - stop time tracking 5 | 6 | == SYNOPSIS 7 | [verse] 8 | *timew stop* [__] [__**...**] 9 | 10 | == DESCRIPTION 11 | Stops tracking time. 12 | If tags are specified, then they are no longer tracked. 13 | If no tags are specified, all tracking stops. 14 | 15 | == EXAMPLES 16 | For example: 17 | 18 | $ timew start tag1 tag2 19 | ... 20 | $ timew stop tag1 21 | 22 | Initially time is tracked for both 'tag1' and 'tag2', then 'tag1' tracking is stopped, leaving tag2 active. 23 | To stop all tracking: 24 | 25 | $ timew stop 26 | 27 | 28 | == SEE ALSO 29 | **timew-cancel**(1), 30 | **timew-continue**(1), 31 | **timew-start**(1), 32 | **timew-track**(1) 33 | -------------------------------------------------------------------------------- /doc/man1/timew-tag.1.adoc: -------------------------------------------------------------------------------- 1 | = timew-tag(1) 2 | 3 | == NAME 4 | timew-tag - add tags to intervals 5 | 6 | == SYNOPSIS 7 | [verse] 8 | *timew tag* [__**...**] __**...** 9 | 10 | == DESCRIPTION 11 | The 'tag' command is used to add a tag to an interval. 12 | Using the 'summary' command, and specifying the ':ids' hint shows interval IDs. 13 | Using the right ID, you can identify an interval to tag. 14 | 15 | == EXAMPLES 16 | For example, show the IDs: 17 | 18 | $ timew summary :week :ids 19 | 20 | Then having selected '@2' as the interval you wish to tag: 21 | 22 | $ timew tag @2 'New Tag' 23 | 24 | Note that you can tag multiple intervals, with multiple tags: 25 | 26 | $ timew tag @2 @10 @23 'Tag One' tag2 tag3 27 | 28 | If there is active time tracking, you can omit the ID when you want to add tags to the current open interval: 29 | 30 | $ timew start foo 31 | $ timew tag bar 32 | 33 | This results in the current interval having tags 'foo' and 'bar'. 34 | 35 | == SEE ALSO 36 | **timew-lengthen**(1), 37 | **timew-retag**(1), 38 | **timew-shorten**(1), 39 | **timew-summary**(1), 40 | **timew-untag**(1) 41 | -------------------------------------------------------------------------------- /doc/man1/timew-tags.1.adoc: -------------------------------------------------------------------------------- 1 | = timew-tags(1) 2 | 3 | == NAME 4 | timew-tags - display a list of tags 5 | 6 | == SYNOPSIS 7 | [verse] 8 | *timew tags* [__] 9 | 10 | == DESCRIPTION 11 | Displays all the tags that have been used by default. 12 | When a filter is specified, shows only the tags that were used during that time. 13 | 14 | == CONFIGURATION 15 | 16 | **tags.**____**.color**:: 17 | Assigns a specific foreground and background color to a tag. 18 | Examples of valid colors include 'white', 'gray8', 'black on yellow', and 'rgb345'. 19 | -------------------------------------------------------------------------------- /doc/man1/timew-track.1.adoc: -------------------------------------------------------------------------------- 1 | = timew-track(1) 2 | 3 | == NAME 4 | timew-track - add intervals to the database 5 | 6 | == SYNOPSIS 7 | [verse] 8 | *timew track* __ [__**...**] 9 | 10 | == DESCRIPTION 11 | The track command is used to add tracked time in the past. 12 | Perhaps you forgot to record time, or are just filling in old entries. 13 | 14 | == EXAMPLES 15 | For example: 16 | 17 | $ timew track :yesterday 'Training Course' 18 | $ timew track 9am - 11am 'Staff Meeting' 19 | 20 | Note that the track command expects a closed interval (start and end time), when recording. 21 | If a closed interval is not provided, the 'track' command behaves the same as the 'start' command. 22 | 23 | == SEE ALSO 24 | **timew-cancel**(1), 25 | **timew-continue**(1), 26 | **timew-start**(1), 27 | **timew-stop**(1) 28 | -------------------------------------------------------------------------------- /doc/man1/timew-undo.1.adoc: -------------------------------------------------------------------------------- 1 | = timew-undo(1) 2 | 3 | == NAME 4 | timew-undo - revert Timewarrior commands 5 | 6 | == SYNOPSIS 7 | [verse] 8 | *timew undo* 9 | 10 | == DESCRIPTION 11 | The 'undo' command is used to revert the action of Timewarrior commands. 12 | Only commands affecting intervals or Timewarrior configuration can be reverted. 13 | Timewarrior keeps a journal of changes to the interval database and Timewarrior configuration. 14 | A call to 'undo' removes the last entry in the journal and restores the previous state. 15 | As long as there are entries in the journal, you can revert the respective action. 16 | The 'undo' command itself cannot be undone! 17 | 18 | == EXAMPLES 19 | Undo an interval modification:: 20 | + 21 | $ timew split @1 22 | $ timew undo 23 | -------------------------------------------------------------------------------- /doc/man1/timew-untag.1.adoc: -------------------------------------------------------------------------------- 1 | = timew-untag(1) 2 | 3 | == NAME 4 | timew-untag - remove tags from intervals 5 | 6 | == SYNOPSIS 7 | [verse] 8 | *timew untag* [__**...** ] __**...** 9 | 10 | == DESCRIPTION 11 | The 'untag' command is used to remove a tag from an interval. 12 | Using the 'summary' command, and specifying the ':ids' hint shows interval IDs. 13 | Using the right ID, you can identify an interval to untag. 14 | 15 | == EXAMPLES 16 | For example, show the IDs: 17 | 18 | $ timew summary :week :ids 19 | 20 | Then having selected '@2' as the interval you wish to untag: 21 | 22 | $ timew untag @2 'Old Tag' 23 | 24 | Note that you can untag multiple intervals, with multiple tags: 25 | 26 | $ timew untag @2 @10 @23 'Old Tag' tag2 tag3 27 | 28 | If there is active time tracking, you can omit the ID when you want to remove tags from the current open interval: 29 | 30 | $ timew start foo bar 31 | $ timew untag bar 32 | 33 | This results in the current interval having tag 'foo' but not 'bar'. 34 | 35 | == SEE ALSO 36 | **timew-lengthen**(1), 37 | **timew-retag**(1), 38 | **timew-shorten**(1), 39 | **timew-summary**(1), 40 | **timew-tag**(1) 41 | -------------------------------------------------------------------------------- /doc/man1/timew-week.1: -------------------------------------------------------------------------------- 1 | .so man1/timew-chart.1 2 | -------------------------------------------------------------------------------- /doc/man1/timew-week.1.in: -------------------------------------------------------------------------------- 1 | .so man1/timew-chart.1 -------------------------------------------------------------------------------- /doc/man7/.gitignore: -------------------------------------------------------------------------------- 1 | *.[0-9] 2 | -------------------------------------------------------------------------------- /doc/man7/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.10) 2 | 3 | if (ASCIIDOCTOR_FOUND) 4 | file (GLOB DOC_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.7.adoc") 5 | set (DOC_FILES) 6 | 7 | foreach (SRC IN LISTS DOC_SOURCES) 8 | string (REPLACE ".adoc" "" OUTPUT_FILE_NAME "${SRC}") 9 | string (REPLACE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}" OUTPUT_FILE_NAME "${OUTPUT_FILE_NAME}") 10 | 11 | add_custom_command (OUTPUT "${OUTPUT_FILE_NAME}" 12 | COMMAND ${ASCIIDOCTOR_EXECUTABLE} -b manpage ${ASCIIDOCTOR_OPTIONS} "${SRC}" -o "${OUTPUT_FILE_NAME}" 13 | DEPENDS "${SRC}") 14 | 15 | list (APPEND DOC_FILES "${OUTPUT_FILE_NAME}") 16 | endforeach (SRC) 17 | 18 | add_custom_target (man7 DEPENDS ${DOC_FILES}) 19 | else (ASCIIDOCTOR_FOUND) 20 | file (GLOB MAN_PAGES "${CMAKE_CURRENT_SOURCE_DIR}/*.7") 21 | set (DOC_FILES ${MAN_PAGES}) 22 | endif (ASCIIDOCTOR_FOUND) 23 | 24 | install (FILES ${DOC_FILES} DESTINATION ${TIMEW_MAN7DIR}) 25 | -------------------------------------------------------------------------------- /doc/man7/timew-config.7.adoc: -------------------------------------------------------------------------------- 1 | = timew-config(7) 2 | 3 | == NAME 4 | timew-config - Timewarrior configuration file and override options 5 | 6 | == SYNOPSIS 7 | **timew rc.**____**=**____ __ 8 | 9 | == DESCRIPTION 10 | Timewarrior stores its configuration in the user's home directory in _~/.timewarrior/timewarrior.cfg_ on non-Unix systems (e.g. Windows). 11 | 12 | On Unix systems, XDG Base Directory specification is supported, if _~/.timewarrior_ directory doesn't exist 13 | (old config directory is still supported and has precedence over XDG BD compliant locations). 14 | 15 | This means configuration is stored in _$XDG_CONFIG_HOME/timewarrior/timewarrior.cfg_, which defaults to _~/.config/timewarrior/timewarrior.cfg_ if _$XDG_CONFIG_HOME_ environment variable is not specified. 16 | 17 | Those wanting to migrate their data to a new directory scheme, might do that with following shell snippet: 18 | 19 | [source,shell] 20 | ---- 21 | LEGACY="${HOME}/.timewarrior" 22 | CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/timewarrior" 23 | DATA_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/timewarrior" 24 | mkdir -p "${CONFIG_DIR}" 25 | mkdir -p "${DATA_DIR}" 26 | mv "${LEGACY}/timewarrior.cfg" "${CONFIG_DIR}" 27 | mv "${LEGACY}/extensions" "${CONFIG_DIR}" 28 | mv "${LEGACY}/data" "${DATA_DIR}" 29 | rmdir "${LEGACY}" 30 | ---- 31 | 32 | This file contains a mix of rules and configuration settings. 33 | Note that the TIMEWARRIORDB environment variable can be set to override this location. 34 | 35 | The values 'true', '1', 'y', 'yes' and 'on' are all equivalent and enable a setting. 36 | Any other value means disable the setting. 37 | 38 | Default values may be overridden by timewarrior.cfg values, which may in turn be overridden on the command line using: **rc.**____**=**____ 39 | 40 | For example, to turn off verbose mode: 41 | 42 | rc.verbose=0 43 | 44 | Note that hints can also do this (:quiet). 45 | 46 | == CONFIGURATION 47 | 48 | *confirmation*:: 49 | Determines whether harmful operations require interactive confirmation. 50 | + 51 | May be overridden by the ':yes' hint. 52 | + 53 | Default value is 'yes'. 54 | 55 | *verbose*:: 56 | Determines whether Timewarrior generates feedback. 57 | + 58 | May be overridden by the ':quiet' hint. 59 | + 60 | Default value is 'yes'. 61 | 62 | *debug*:: 63 | Determines whether diagnostic debugging information is shown. 64 | + 65 | Useful for troubleshooting, but not for general use. 66 | + 67 | Default value is 'off'. 68 | 69 | *debug.indicator*:: 70 | The debug output prefix string. 71 | + 72 | Default value is '>>'. 73 | -------------------------------------------------------------------------------- /doc/man7/timew-dom.7.adoc: -------------------------------------------------------------------------------- 1 | = timew-dom(7) 2 | 3 | == NAME 4 | timew-dom - Timewarrior DOM 5 | 6 | == SYNOPSIS 7 | 8 | == DESCRIPTION 9 | Supported DOM references are: 10 | 11 | dom.tag.count Count of all tags 12 | dom.tag.1 Nth tag used 13 | 14 | dom.active '1' if there is active tracking, otherwise '0' 15 | dom.active.tag.count Count of active tags 16 | dom.active.tag.1 Active Nth tag 17 | dom.active.start Active start timestamp (ISO Extended local date) 18 | dom.active.duration Active elapsed (ISO Period) 19 | dom.active.json Active interval as JSON 20 | 21 | dom.tracked.count Count of tracked intervals 22 | dom.tracked.1.tag.count Count of active tags 23 | dom.tracked.1.tag.1 Tracked Nth, Nth tag 24 | dom.tracked.1.start Tracked Nth, start time 25 | dom.tracked.1.end Tracked Nth, end time, blank if closed 26 | dom.tracked.1.duration Tracked Nth, elapsed 27 | dom.tracked.1.json Tracked Nth, interval as JSON 28 | 29 | dom.rc. Configuration setting 30 | -------------------------------------------------------------------------------- /doc/man7/timew-durations.7.adoc: -------------------------------------------------------------------------------- 1 | = timew-durations(7) 2 | 3 | == NAME 4 | timew-durations - duration formats supported by Timewarrior 5 | 6 | == SYNOPSIS 7 | 8 | == DESCRIPTION 9 | Timewarrior supports the following duration formats based on ISO-8601: 10 | 11 | 'P' [nn 'Y'] [nn 'M'] [nn 'D'] ['T' [nn 'H'] [nn 'M'] [nn 'S']] 12 | PnnW 13 | 14 | Examples: 15 | 16 | P1Y 1 year 17 | P1.5M 1.5 months 18 | PT1S 1 second 19 | PT4.5H 4.5 hours 20 | PT4H30M 4.5 hours 21 | P600D 600 days 22 | P3W 3 weeks 23 | P1Y1DT1H1M1S 1 year and 25 hours, 61 seconds (imprecise term) 24 | 25 | Note that the year and month terms are imprecise, being defined as 365d and 30d respectively. 26 | For precision use the other terms. 27 | 28 | In addition to the standard duration formats, the following are supported: 29 | 30 | n[.n] 31 | 32 | Where the is one of: 33 | 34 | annual 35 | biannual 36 | bimonthly 37 | biweekly 38 | biyearly 39 | daily 40 | days, day, d 41 | fortnight 42 | hours, hour, hrs, hr, h 43 | minutes, minute, mins, min 44 | monthly, months, month, mnths, mths, mth, mos, mo, m 45 | quarterly, quarters, quarter, qrtrs, qtr, q 46 | semiannual 47 | sennight 48 | seconds, second, secs, sec, s 49 | weekdays 50 | weekly, weeks, week, wks, wk, w 51 | yearly, years, year, yrs, yr, y 52 | 53 | Examples: 54 | 1hour 60 minutes 55 | 1.5h 90 minutes 56 | 3mo 3 months 57 | 10d 10 days 58 | 59 | Note that the year, quarter and month terms are imprecise, being defined as 365d, 91d and 30d respectively. 60 | For precision use the other terms. 61 | -------------------------------------------------------------------------------- /doc/man7/timew-hints.7.adoc: -------------------------------------------------------------------------------- 1 | = timew-hints(7) 2 | 3 | == NAME 4 | timew-hints - Timewarrior hints 5 | 6 | == SYNOPSIS 7 | 8 | == DESCRIPTION 9 | Timewarrior supports hints, which are single-word command line features that start with a colon like this: 10 | 11 | :week 12 | 13 | Hints serve several purposes. 14 | This example is a shortcut for the date range that defines the current week. 15 | 16 | Other hints, such as: 17 | 18 | :quiet 19 | 20 | are ways to control the behavior of Timewarrior, in this case eliminating all forms of feedback, for purposes of automation. 21 | 22 | The supported hints are: 23 | 24 | :quiet Turns off all feedback. For automation 25 | :debug Runs in debug mode, shows many runtime details 26 | :yes Overrides confirmation by answering 'yes' to the questions 27 | 28 | :color Force color on, even if not connected to a TTY 29 | :nocolor Force color off, even if connected to a TTY 30 | :blank Leaves tracked time out of a report 31 | :fill Expand time to fill surrounding available gap 32 | :adjust Automatically correct overlaps 33 | :ids Displays interval ID numbers in the summary report 34 | 35 | Range hints provide convenient shortcuts to date ranges: 36 | 37 | :all All tracked time 38 | :yesterday The 24 hours of the previous day 39 | :day / :today The 24 hours of the current day 40 | :week This week 41 | :fortnight This week and the one before 42 | :month This month 43 | :quarter This quarter 44 | :year This year 45 | :lastweek Last week 46 | :lastmonth Last month 47 | :lastquarter Last quarter 48 | :lastyear Last year 49 | :monday Previous monday 50 | :tuesday Previous tuesday 51 | :wednesday Previous wednesday 52 | :thursday Previous thursday 53 | :friday Previous friday 54 | :saturday Previous saturday 55 | :sunday Previous sunday 56 | -------------------------------------------------------------------------------- /doc/man7/timew-ranges.7.adoc: -------------------------------------------------------------------------------- 1 | = timew-ranges(7) 2 | 3 | == NAME 4 | timew-ranges - date and time ranges supported by Timewarrior 5 | 6 | == SYNOPSIS 7 | 8 | == DESCRIPTION 9 | An interval defines a block of time that is tracked. 10 | The syntax for specifying an interval is flexible, and may be one of: 11 | 12 | [from] 13 | [from] to/- 14 | [from] for 15 | before/after 16 | ago 17 | [for] 18 | 19 | Examples are: 20 | 21 | from 9:00 22 | from 9am - 11am 23 | from 9:00:00 to 11:00 24 | from 9:00 for 2h 25 | 2h after 9am 26 | 2h before 11:00 27 | 2h ago 28 | for 2h 29 | 30 | An interval is called 'closed' if there is both a start date and an end date, and 'open' if there is no end date. 31 | 32 | There is also a number of useful hints for common ranges. 33 | 34 | == SEE ALSO 35 | **timew-hints**(7) 36 | -------------------------------------------------------------------------------- /doc/report.day.1.txt: -------------------------------------------------------------------------------- 1 | Report Mockup 2 | ============= 3 | 4 | $ timew report day monday 5 | 6 | Day Report, 2016-03-13 16:30:03, week 32 7 | 8 | Monday 9 | 8:00   10 | 9:00 Staff Meeting  11 | 10:00   12 | 11:00   13 | 12:00   14 | 1:00 Research for Product X  15 | 2:00   16 | 3:00   17 | 4:00   18 |  5:00  ... 19 | 6:00   20 | 21 | Tracked 7:30 22 | Untracked 0:30 23 | Total 8:00 24 | 25 | -------------------------------------------------------------------------------- /doc/report.week.1.txt: -------------------------------------------------------------------------------- 1 | Report Mockup 2 | ============= 3 | 4 | $ timew report week 5 | 6 | Week Report, 2016-03-13 15:14:03, week 32 7 | 8 | Mon Tue Wed Thu Fri Sat Sun 9 | 8:00               Research Research for Product X 10 | 9:00             Survey Conducting survey 5.2 11 | 10:00             Staff Staff Meeting 12 | 11:00             Interview Candidate Interview 13 | 12:00               14 | 1:00             15 | 2:00             16 |  3:00       ...     17 | 4:00           18 | 5:00           19 | 6:00               20 | 7:00               21 | 22 | Tracked 31:14 23 | Untracked 09:46 24 | Total 41:00 25 | 26 | -------------------------------------------------------------------------------- /doc/themes/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.10) 2 | 3 | message ("-- Configuring theme documentation") 4 | 5 | install (FILES README DESTINATION ${TIMEW_DOCDIR}/themes) 6 | install (FILES dark.theme DESTINATION ${TIMEW_DOCDIR}/themes) 7 | install (FILES dark_blue.theme DESTINATION ${TIMEW_DOCDIR}/themes) 8 | install (FILES dark_green.theme DESTINATION ${TIMEW_DOCDIR}/themes) 9 | install (FILES dark_red.theme DESTINATION ${TIMEW_DOCDIR}/themes) 10 | -------------------------------------------------------------------------------- /doc/themes/README: -------------------------------------------------------------------------------- 1 | # Timewarrior Color Themes 2 | 3 | The theme files define colors that Timewarrior uses in various situations. 4 | There are several themes provided with Timewarrior, and you use a theme by importing it into your configuration file. 5 | Edit this file: 6 | 7 | ~/.timewarrior/timewarrior.cfg (non-Unix systems or instalations using pre-XDG paths on Unix systems) 8 | ${XDG_CONFIG_HOME:-$HOME/.config}/timewarrior/timewarrior.cfg (Unix systems) 9 | 10 | And add the import line, which looks like this: 11 | 12 | import /path/to/theme/dark.theme 13 | 14 | You can find more themes online at ... 15 | 16 | TODO URL needed 17 | 18 | 19 | ## Create Your Own 20 | 21 | It is easy to create your own Timewarrior color theme. 22 | The simplest approach is to copy an existing theme and then modify the colors. 23 | 24 | There is no minimum requirement for a theme - it doesn't need to define any colors, but that isn't really the point of a theme. 25 | Ideally define a description which is shown in the 'diagnostics' command output: 26 | 27 | theme.description Description of the theme. 28 | 29 | The individual color settings are all used by Taskwarrior, and providing a color for each of these is best. 30 | If no color is provided for a setting, then no color is used, a default does not apply. 31 | Color settings include: 32 | 33 | theme.colors.exclusion Used to color excluded time in reports 34 | theme.colors.today Used to highlight today on reports that show dates 35 | theme.colors.label Used for non-critical labels in reports 36 | 37 | The color palette is used to automatically color tagged time in reports. 38 | When creating a color theme, the palette should be larger rather than smaller. 39 | It is recommended that you provide at least 16 colors, otherwise Timewarrior cycles through them, and you'll see repetitions. 40 | 41 | ## Share Your Theme 42 | 43 | Having created a color theme, share it in the spirit of Open Source. 44 | Make it available for download, or alternatively send it to us at: 45 | 46 | support@gothenburgbitfactory.org 47 | 48 | We will list (and attribute) your theme on the Timewarrior support pages, where you will find other themes and extensions. 49 | -------------------------------------------------------------------------------- /doc/themes/dark.theme: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # Copyright 2016, 2018, 2025, Gothenburg Bit Factory. 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included 13 | # in all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | # https://www.opensource.org/licenses/mit-license.php 24 | # 25 | ############################################################################### 26 | 27 | define theme: 28 | description = "dark.theme: A default, 256-color theme." 29 | colors: 30 | # General UI color. 31 | exclusion = "gray8 on gray4" 32 | today = "rgb521" 33 | holiday = "gray4" 34 | label = "gray4" 35 | ids = "color13" 36 | debug = "blue" 37 | 38 | # Rotating Color Palette for tags. The leading zeroes allow the order to be 39 | # preserved. 40 | palette: 41 | color01 = "white on red" 42 | color02 = "white on blue" 43 | color03 = "black on green" 44 | color04 = "black on magenta" 45 | color05 = "black on cyan" 46 | color06 = "black on yellow" 47 | color07 = "black on white" 48 | color08 = "white on bright red" 49 | color09 = "white on bright blue" 50 | color10 = "black on bright green" 51 | color11 = "black on bright magenta" 52 | color12 = "black on bright cyan" 53 | color13 = "black on bright yellow" 54 | 55 | -------------------------------------------------------------------------------- /doc/themes/dark_red.theme: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # Copyright 2016, 2018, Thomas Lauf, Paul Beckingham, Federico Hernandez. 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included 13 | # in all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | # https://www.opensource.org/licenses/mit-license.php 24 | # 25 | ############################################################################### 26 | 27 | define theme: 28 | description = "dark_red.theme: A dark red theme." 29 | colors: 30 | # General UI color. 31 | exclusion = "gray8 on gray4" 32 | today = "rgb521" 33 | holiday = "rgb100" 34 | label = "rgb100" 35 | ids = "rgb510" 36 | debug = "blue" 37 | 38 | # Rotating Color Palette for tags. The leading zeroes allow the order to be 39 | # preserved. 40 | palette: 41 | color01 = "white on rgb100" 42 | color02 = "white on rgb104" 43 | color03 = "white on rgb101" 44 | color04 = "white on rgb105" 45 | color05 = "white on rgb102" 46 | color06 = "white on rgb200" 47 | color07 = "white on rgb103" 48 | color08 = "white on rgb201" 49 | color09 = "white on rgb300" 50 | color10 = "white on rgb202" 51 | color11 = "white on rgb301" 52 | color12 = "white on rgb203" 53 | color13 = "white on rgb302" 54 | color14 = "white on rgb204" 55 | color15 = "white on rgb205" 56 | color16 = "white on rgb303" 57 | color17 = "white on rgb401" 58 | color18 = "white on rgb304" 59 | color19 = "white on rgb402" 60 | color20 = "white on rgb305" 61 | color21 = "white on rgb403" 62 | color22 = "white on rgb400" 63 | color23 = "white on rgb404" 64 | color24 = "white on rgb502" 65 | color25 = "white on rgb405" 66 | color26 = "white on rgb503" 67 | color27 = "white on rgb500" 68 | color28 = "white on rgb504" 69 | color29 = "white on rgb501" 70 | color30 = "white on rgb505" 71 | 72 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | test-alpine-edge: 3 | build: 4 | context: . 5 | dockerfile: test/docker/alpine-edge 6 | network_mode: "host" 7 | security_opt: 8 | - label=type:container_runtime_t 9 | tty: true 10 | test-alpine-latest: 11 | build: 12 | context: . 13 | dockerfile: test/docker/alpine-latest 14 | network_mode: "host" 15 | security_opt: 16 | - label=type:container_runtime_t 17 | tty: true 18 | test-archlinux: 19 | build: 20 | context: . 21 | dockerfile: test/docker/archlinux 22 | network_mode: "host" 23 | security_opt: 24 | - label=type:container_runtime_t 25 | tty: true 26 | test-centos-stream9: 27 | build: 28 | context: . 29 | dockerfile: test/docker/centos-stream9 30 | network_mode: "host" 31 | security_opt: 32 | - label=type:container_runtime_t 33 | tty: true 34 | test-debianstable: 35 | build: 36 | context: . 37 | dockerfile: test/docker/debianstable 38 | network_mode: "host" 39 | security_opt: 40 | - label=type:container_runtime_t 41 | tty: true 42 | test-debiantesting: 43 | build: 44 | context: . 45 | dockerfile: test/docker/debiantesting 46 | network_mode: "host" 47 | security_opt: 48 | - label=type:container_runtime_t 49 | tty: true 50 | test-fedora41: 51 | build: 52 | context: . 53 | dockerfile: test/docker/fedora41 54 | network_mode: "host" 55 | security_opt: 56 | - label=type:container_runtime_t 57 | tty: true 58 | test-fedora42: 59 | build: 60 | context: . 61 | dockerfile: test/docker/fedora42 62 | network_mode: "host" 63 | security_opt: 64 | - label=type:container_runtime_t 65 | tty: true 66 | test-opensuseleap: 67 | build: 68 | context: . 69 | dockerfile: test/docker/opensuseleap 70 | network_mode: "host" 71 | security_opt: 72 | - label=type:container_runtime_t 73 | tty: true 74 | test-opensusetumbleweed: 75 | build: 76 | context: . 77 | dockerfile: test/docker/opensusetumbleweed 78 | network_mode: "host" 79 | security_opt: 80 | - label=type:container_runtime_t 81 | tty: true 82 | test-ubuntu2204: 83 | build: 84 | context: . 85 | dockerfile: test/docker/ubuntu2204 86 | network_mode: "host" 87 | security_opt: 88 | - label=type:container_runtime_t 89 | tty: true 90 | test-ubuntu2404: 91 | build: 92 | context: . 93 | dockerfile: test/docker/ubuntu2404 94 | network_mode: "host" 95 | security_opt: 96 | - label=type:container_runtime_t 97 | tty: true 98 | -------------------------------------------------------------------------------- /docker/timew.dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04 AS base 2 | 3 | FROM base AS builder 4 | 5 | ENV DEBIAN_FRONTEND noninteractive 6 | 7 | RUN ( apt-get update && yes | unminimize ) && \ 8 | apt-get install -y \ 9 | cmake \ 10 | g++ \ 11 | git 12 | 13 | # Setup language environment 14 | ENV LC_ALL en_US.UTF-8 15 | ENV LANG en_US.UTF-8 16 | ENV LANGUAGE en_US.UTF-8 17 | 18 | # Add source directory 19 | ADD .. /root/code/ 20 | WORKDIR /root/code/ 21 | 22 | # Build Timewarrior 23 | RUN git clean -dfx && \ 24 | git submodule init && \ 25 | git submodule update && \ 26 | cmake -DCMAKE_BUILD_TYPE=release . && \ 27 | make -j8 28 | 29 | FROM base AS runner 30 | 31 | # Install Timewarrior 32 | COPY --from=builder /root/code/src/timew /usr/local/bin 33 | 34 | # Initialize Timewarrior 35 | RUN timew :yes 36 | -------------------------------------------------------------------------------- /ext/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.10) 2 | 3 | message ("-- Configuring extensions") 4 | 5 | install (FILES on-modify.timewarrior totals.py DESTINATION ${TIMEW_DOCDIR}/ext) 6 | -------------------------------------------------------------------------------- /ext/README: -------------------------------------------------------------------------------- 1 | # Timewarrior Extensions 2 | 3 | ## debug.py 4 | This is a debug extension that simply echoes back everything it sees in its input. 5 | It's useful for debugging to see how the command line affects what an extension sees. 6 | This will likely be removed before release. 7 | 8 | ## on-modify.timewarrior 9 | This is a Taskwarrior hook script that will integrate Timewarrior. 10 | It is taken from https://github.com/GothenburgBitFactory/task-timewarrior-hook which is released under [MIT license](https://github.com/GothenburgBitFactory/task-timewarrior-hook/blob/main/LICENSE) 11 | 12 | ## csv.py 13 | This extension exports the data in CSV format, with a variable number of tag fields. 14 | 15 | ## totals.py 16 | Sample extension report that shows totals by tag. 17 | -------------------------------------------------------------------------------- /ext/csv.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import json 4 | import sys 5 | 6 | # Skip the configuration settings. 7 | for line in sys.stdin: 8 | if line == '\n': 9 | break 10 | 11 | # Extract the JSON. 12 | doc = '' 13 | for line in sys.stdin: 14 | doc += line 15 | 16 | total_active_time = 0 17 | 18 | j = json.loads(doc) 19 | for object in j: 20 | line = '"{}","{}"'.format(object['start'], (object['end'] if 'end' in object else '')) 21 | 22 | if 'tags' in object: 23 | for tag in object['tags']: 24 | line += ',"{}"'.format(tag) 25 | 26 | print(line) 27 | -------------------------------------------------------------------------------- /ext/debug.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import sys 4 | 5 | for line in sys.stdin: 6 | print(line.strip()) 7 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | timew 2 | lex 3 | *.a 4 | CMakeFiles/ 5 | Makefile 6 | cmake_install.cmake 7 | lr0 8 | sax 9 | debug 10 | -------------------------------------------------------------------------------- /src/AtomicFile.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2020 - 2022, Shaun Ruffell, Thomas Lauf. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | #ifndef INCLUDED_ATOMICFILE 27 | #define INCLUDED_ATOMICFILE 28 | 29 | #include 30 | #include 31 | 32 | class Path; 33 | 34 | class AtomicFile 35 | { 36 | public: 37 | explicit AtomicFile (const Path& path); 38 | explicit AtomicFile (std::string path); 39 | AtomicFile (const AtomicFile&) = delete; 40 | AtomicFile (AtomicFile&&); 41 | AtomicFile& operator= (const AtomicFile&) = delete; 42 | AtomicFile& operator= (AtomicFile&&); 43 | ~AtomicFile (); 44 | 45 | std::string name () const; 46 | const std::string& path () const; 47 | bool exists () const; 48 | 49 | bool open (); 50 | void close (); 51 | void remove (); 52 | void truncate (); 53 | size_t size () const; 54 | void read (std::string& content); 55 | void read (std::vector & lines); 56 | void append (const std::string& content); 57 | void write_raw (const std::string& content); 58 | 59 | static void append (const Path& path, const std::string& data); 60 | 61 | static void write (const Path& path, const std::string& data); 62 | static void write (const Path& path, const std::vector & lines); 63 | 64 | static void read (const Path& path, std::string& content); 65 | static void read (const Path& path, std::vector & lines); 66 | 67 | static void finalize_all (); 68 | static void reset (); 69 | 70 | private: 71 | struct impl; 72 | std::shared_ptr pimpl; 73 | }; 74 | 75 | #endif // INCLUDED_ATOMICFILE 76 | -------------------------------------------------------------------------------- /src/ChartConfig.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2019, 2022 - 2023, Thomas Lauf, Paul Beckingham, Federico Hernandez. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | #ifndef INCLUDED_CHARTCONFIG 28 | #define INCLUDED_CHARTCONFIG 29 | 30 | #include 31 | #include 32 | #include 33 | 34 | class ChartConfig 35 | { 36 | public: 37 | Datetime reference_datetime; 38 | bool with_label_month; 39 | bool with_label_week; 40 | bool with_label_weekday; 41 | bool with_label_day; 42 | bool with_ids; 43 | bool with_summary; 44 | bool with_holidays; 45 | bool with_totals; 46 | bool with_internal_axis; 47 | bool show_intervals; 48 | bool determine_hour_range; 49 | int minutes_per_char; 50 | int spacing; 51 | int num_lines; 52 | Color color_today; 53 | Color color_holiday; 54 | Color color_label; 55 | Color color_exclusion; 56 | std::map tag_colors; 57 | }; 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /src/Datafile.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2016, 2018 - 2022, Thomas Lauf, Paul Beckingham, Federico Hernandez. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | #ifndef INCLUDED_DATAFILE 28 | #define INCLUDED_DATAFILE 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | class Datafile 37 | { 38 | public: 39 | Datafile () = default; 40 | void initialize (const std::string&); 41 | std::string name () const; 42 | 43 | std::string lastLine (); 44 | const std::vector & allLines (); 45 | 46 | void addInterval (const Interval&); 47 | void deleteInterval (const Interval&); 48 | void commit (); 49 | 50 | std::string dump () const; 51 | 52 | private: 53 | void load_lines (); 54 | 55 | private: 56 | Path _file {}; 57 | bool _dirty {false}; 58 | std::vector _lines {}; 59 | bool _lines_loaded {false}; 60 | Range _range {}; 61 | }; 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /src/Exclusion.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2016, 2018, 2022, Thomas Lauf, Paul Beckingham, Federico Hernandez. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | #ifndef INCLUDED_EXCLUSION 28 | #define INCLUDED_EXCLUSION 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | class Exclusion 36 | { 37 | public: 38 | Exclusion (const std::string&, const std::string&); 39 | std::vector tokens () const; 40 | std::vector ranges (const Range&) const; 41 | bool additive () const; 42 | std::string dump () const; 43 | 44 | private: 45 | Range rangeFromTimeBlock (const std::string&, const Datetime&, const Datetime&) const; 46 | 47 | private: 48 | std::vector _tokens {}; 49 | bool _additive {false}; 50 | }; 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /src/Extensions.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2016, 2018, 2022, Thomas Lauf, Paul Beckingham, Federico Hernandez. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | #ifndef INCLUDED_EXTENSIONS 28 | #define INCLUDED_EXTENSIONS 29 | 30 | #include 31 | #include 32 | 33 | class Extensions 34 | { 35 | public: 36 | Extensions () = default; 37 | void initialize (const std::string&); 38 | void debug (); 39 | std::vector all () const; 40 | int callExtension (const std::string&, const std::vector &, std::vector &) const; 41 | std::string dump () const; 42 | 43 | private: 44 | std::vector _scripts {}; 45 | bool _debug {false}; 46 | }; 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /src/ExtensionsTable.h: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2023, Gothenburg Bit Factory. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | ////////////////////////////////////////////////////////////////////////////// 26 | 27 | #ifndef INCLUDED_EXTENSIONSTABLE 28 | #define INCLUDED_EXTENSIONSTABLE 29 | 30 | #include 31 | #include 32 | 33 | class ExtensionsTable 34 | { 35 | class Builder 36 | { 37 | public: 38 | Builder& withExtensions (const Extensions&); 39 | 40 | Table build (); 41 | 42 | private: 43 | Extensions _extensions; 44 | }; 45 | 46 | public: 47 | static Builder builder (); 48 | }; 49 | 50 | #endif //INCLUDED_EXTENSIONSTABLE 51 | -------------------------------------------------------------------------------- /src/GapsTable.h: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2023, Gothenburg Bit Factory. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | ////////////////////////////////////////////////////////////////////////////// 26 | 27 | #ifndef INCLUDED_GAPSTABLE 28 | #define INCLUDED_GAPSTABLE 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | class GapsTable 36 | { 37 | class Builder 38 | { 39 | public: 40 | Builder& withRange (const Range&); 41 | Builder& withIntervals (const std::vector &); 42 | 43 | Table build (); 44 | 45 | private: 46 | std::vector _intervals; 47 | Range _range; 48 | }; 49 | 50 | public: 51 | static Builder builder (); 52 | }; 53 | 54 | #endif //INCLUDED_GAPSTABLE 55 | -------------------------------------------------------------------------------- /src/Interval.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2016 - 2023, Thomas Lauf, Paul Beckingham, Federico Hernandez. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | #ifndef INCLUDED_INTERVAL 28 | #define INCLUDED_INTERVAL 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | class Interval : public Range 36 | { 37 | public: 38 | Interval () = default; 39 | Interval (const Datetime& start, const Datetime& end) : Range (start, end) {} 40 | Interval (const Range& range, std::set tags) : Range (range), _tags(std::move(tags)) {} 41 | 42 | bool operator== (const Interval&) const; 43 | bool operator!= (const Interval&) const; 44 | 45 | bool empty () const; 46 | bool hasTag (const std::string&) const; 47 | const std::set & tags () const; 48 | void tag (const std::string&); 49 | void tag (const std::set &); 50 | void untag (const std::string&); 51 | void untag (const std::set &); 52 | void clearTags (); 53 | 54 | void setRange (const Range& range); 55 | void setRange (const Datetime& start, const Datetime& end); 56 | 57 | void setAnnotation(const std::string& annotation); 58 | std::string getAnnotation() const; 59 | 60 | std::string serialize () const; 61 | std::string json () const; 62 | std::string dump () const; 63 | 64 | public: 65 | int id {0}; 66 | bool synthetic {false}; 67 | std::string annotation {}; 68 | 69 | private: 70 | std::set _tags {}; 71 | }; 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /src/IntervalFactory.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2018 - 2019, Thomas Lauf, Paul Beckingham, Federico Hernandez. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | #ifndef INCLUDED_INTERVALFACTORY 28 | #define INCLUDED_INTERVALFACTORY 29 | 30 | #include 31 | #include 32 | 33 | class IntervalFactory 34 | { 35 | public: 36 | static Interval fromSerialization (const std::string& line); 37 | static Interval fromJson (const std::string& jsonString); 38 | }; 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /src/IntervalFilter.cpp: -------------------------------------------------------------------------------- 1 | // /////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2021, Thomas Lauf, Paul Beckingham, Federico Hernandez. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | // /////////////////////////////////////////////////////////////////////////// 26 | // 27 | 28 | #include 29 | 30 | bool IntervalFilter::is_done () const 31 | { 32 | return _done; 33 | } 34 | 35 | void IntervalFilter::set_done (bool done) 36 | { 37 | _done = done; 38 | } 39 | 40 | void IntervalFilter::reset () 41 | { 42 | set_done (false); 43 | } 44 | -------------------------------------------------------------------------------- /src/IntervalFilter.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2021, Thomas Lauf, Paul Beckingham, Federico Hernandez. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | #ifndef INCLUDED_INTERVALFILTER 28 | #define INCLUDED_INTERVALFILTER 29 | 30 | #include 31 | 32 | class IntervalFilter 33 | { 34 | public: 35 | virtual bool accepts (const Interval&) = 0; 36 | virtual void reset (); 37 | virtual ~IntervalFilter() = default; 38 | 39 | bool is_done () const; 40 | 41 | protected: 42 | void set_done (bool); 43 | 44 | private: 45 | bool _done = false; 46 | }; 47 | 48 | #endif //INCLUDED_INTERVALFILTER 49 | -------------------------------------------------------------------------------- /src/IntervalFilterAllInRange.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2021, 2023, Thomas Lauf, Paul Beckingham, Federico Hernandez. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | #include 28 | 29 | IntervalFilterAllInRange::IntervalFilterAllInRange (Range range): _range (std::move(range)) 30 | {} 31 | 32 | bool IntervalFilterAllInRange::accepts (const Interval& interval) 33 | { 34 | if (is_done()) 35 | { 36 | return false; 37 | } 38 | 39 | if ((! _range.is_started() && ! _range.is_ended()) || interval.intersects (_range)) 40 | { 41 | return true; 42 | } 43 | 44 | // Since we are moving backwards in time, and the intervals are in sorted order, 45 | // if the filter is after the interval and does not intersect, 46 | // we know there will be no more matches 47 | set_done (interval.start < _range.start); 48 | 49 | return false; 50 | } 51 | -------------------------------------------------------------------------------- /src/IntervalFilterAllInRange.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2021, Thomas Lauf, Paul Beckingham, Federico Hernandez. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | #ifndef INCLUDED_INTERVALFILTEALLINRRANGE 28 | #define INCLUDED_INTERVALFILTEALLINRRANGE 29 | 30 | #include 31 | #include 32 | 33 | class IntervalFilterAllInRange : public IntervalFilter 34 | { 35 | public: 36 | explicit IntervalFilterAllInRange (Range); 37 | 38 | bool accepts (const Interval&) final; 39 | 40 | private: 41 | const Range _range; 42 | }; 43 | 44 | #endif //INCLUDED_INTERVALFILTERRANGE 45 | -------------------------------------------------------------------------------- /src/IntervalFilterAllWithIds.cpp: -------------------------------------------------------------------------------- 1 | // /////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2021, 2023, Thomas Lauf, Paul Beckingham, Federico Hernandez. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | // /////////////////////////////////////////////////////////////////////////// 26 | // 27 | 28 | #include 29 | 30 | IntervalFilterAllWithIds::IntervalFilterAllWithIds (std::set ids) : _ids (std::move (ids)) 31 | { 32 | _id_it = _ids.begin (); 33 | _id_end = _ids.end (); 34 | } 35 | 36 | bool IntervalFilterAllWithIds::accepts (const Interval& interval) 37 | { 38 | if (is_done ()) 39 | { 40 | return false; 41 | } 42 | 43 | if (interval.id == *_id_it) 44 | { 45 | ++_id_it; 46 | return true; 47 | } 48 | 49 | set_done (_id_it == _id_end); 50 | 51 | return false; 52 | } 53 | 54 | void IntervalFilterAllWithIds::reset () 55 | { 56 | set_done (false); 57 | _id_it = _ids.begin (); 58 | } 59 | -------------------------------------------------------------------------------- /src/IntervalFilterAllWithIds.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2021 - 2023, Thomas Lauf, Paul Beckingham, Federico Hernandez. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | #ifndef INCLUDED_INTERVALFILTERALLWITHIDS 28 | #define INCLUDED_INTERVALFILTERALLWITHIDS 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | class IntervalFilterAllWithIds : public IntervalFilter 36 | { 37 | public: 38 | explicit IntervalFilterAllWithIds(std::set ); 39 | 40 | bool accepts (const Interval&) final; 41 | void reset () override; 42 | 43 | private: 44 | const std::set _ids {}; 45 | std::set ::iterator _id_it; 46 | std::set ::iterator _id_end; 47 | }; 48 | 49 | #endif //INCLUDE_INTERVALFILTERALLWITHIDS 50 | -------------------------------------------------------------------------------- /src/IntervalFilterAllWithTags.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2021 - 2023, Thomas Lauf, Paul Beckingham, Federico Hernandez. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | #include 28 | #include 29 | 30 | IntervalFilterAllWithTags::IntervalFilterAllWithTags (std::set tags): _tags (std::move (tags)) 31 | {} 32 | 33 | bool IntervalFilterAllWithTags::accepts (const Interval& interval) 34 | { 35 | for (auto& tag : _tags) 36 | { 37 | if (! interval.hasTag (tag)) 38 | { 39 | return false; 40 | } 41 | } 42 | 43 | return true; 44 | } 45 | -------------------------------------------------------------------------------- /src/IntervalFilterAllWithTags.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2021, Thomas Lauf, Paul Beckingham, Federico Hernandez. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | #ifndef INCLUDED_INTERVALFILTERALLWITHTAGSET 28 | #define INCLUDED_INTERVALFILTERALLWITHTAGSET 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | class IntervalFilterAllWithTags : public IntervalFilter 36 | { 37 | public: 38 | explicit IntervalFilterAllWithTags(std::set ); 39 | 40 | bool accepts (const Interval&) final; 41 | 42 | private: 43 | const std::set _tags {}; 44 | }; 45 | 46 | #endif //INCLUDED_INTERVALFILTERTAGSET 47 | -------------------------------------------------------------------------------- /src/IntervalFilterAndGroup.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2021, 2023, Thomas Lauf, Paul Beckingham, Federico Hernandez. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | #include 28 | 29 | IntervalFilterAndGroup::IntervalFilterAndGroup (std::vector > filters) : _filters (std::move (filters)) 30 | {} 31 | 32 | bool IntervalFilterAndGroup::accepts (const Interval& interval) 33 | { 34 | if (is_done ()) 35 | { 36 | return false; 37 | } 38 | 39 | for (auto& filter: _filters) 40 | { 41 | if (filter->accepts (interval)) 42 | { 43 | continue; 44 | } 45 | 46 | if (filter->is_done ()) 47 | { 48 | set_done (true); 49 | } 50 | 51 | return false; 52 | } 53 | 54 | return true; 55 | } 56 | 57 | void IntervalFilterAndGroup::reset () 58 | { 59 | for (auto& filter: _filters) 60 | { 61 | filter->reset (); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/IntervalFilterAndGroup.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2021 - 2023, Thomas Lauf, Paul Beckingham, Federico Hernandez. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | #ifndef INCLUDED_INTERVALFILTERANDGROUP 28 | #define INCLUDED_INTERVALFILTERANDGROUP 29 | 30 | #include 31 | #include 32 | 33 | class IntervalFilterAndGroup : public IntervalFilter 34 | { 35 | public: 36 | explicit IntervalFilterAndGroup (std::vector > filters); 37 | 38 | bool accepts (const Interval&) final; 39 | void reset () override; 40 | 41 | private: 42 | const std::vector > _filters = {}; 43 | }; 44 | 45 | #endif //INCLUDED_INTERVALFILTERANDGROUP 46 | -------------------------------------------------------------------------------- /src/IntervalFilterFirstOf.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2021, 2023, Thomas Lauf, Paul Beckingham, Federico Hernandez. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | #include 28 | 29 | IntervalFilterFirstOf::IntervalFilterFirstOf (std::shared_ptr filter) : _filter (filter) 30 | {} 31 | 32 | bool IntervalFilterFirstOf::accepts (const Interval& interval) 33 | { 34 | if (is_done ()) 35 | { 36 | return false; 37 | } 38 | 39 | auto accepted = _filter->accepts (interval); 40 | set_done (accepted); 41 | 42 | return accepted; 43 | } 44 | 45 | void IntervalFilterFirstOf::reset () 46 | { 47 | set_done (false); 48 | _filter->reset (); 49 | } 50 | -------------------------------------------------------------------------------- /src/IntervalFilterFirstOf.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2021, Thomas Lauf, Paul Beckingham, Federico Hernandez. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | #ifndef INCLUDED_INTERVALFILTERFIRSTOF 28 | #define INCLUDED_INTERVALFILTERFIRSTOF 29 | 30 | #include 31 | #include 32 | 33 | class IntervalFilterFirstOf : public IntervalFilter 34 | { 35 | public: 36 | explicit IntervalFilterFirstOf(std::shared_ptr filter); 37 | 38 | bool accepts (const Interval&) final; 39 | void reset (); 40 | 41 | private: 42 | std::shared_ptr _filter; 43 | }; 44 | 45 | #endif //INCLUDED_INTERVALFILTERFIRSTOF 46 | -------------------------------------------------------------------------------- /src/Journal.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2018 - 2023, Thomas Lauf, Paul Beckingham, Federico Hernandez. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | #ifndef INCLUDED_JOURNAL 28 | #define INCLUDED_JOURNAL 29 | 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | class Journal 37 | { 38 | public: 39 | Journal() = default; 40 | Journal(const Journal&) = delete; 41 | Journal& operator= (const Journal&) = delete; 42 | 43 | void initialize(const std::string&, int); 44 | 45 | void startTransaction (); 46 | void endTransaction (); 47 | void recordConfigAction(const std::string&, const std::string&); 48 | void recordIntervalAction(const std::string&, const std::string&); 49 | bool enabled () const; 50 | 51 | Transaction popLastTransaction(); 52 | 53 | private: 54 | void recordUndoAction (const std::string&, const std::string&, const std::string&); 55 | 56 | std::string _location {}; 57 | std::shared_ptr _currentTransaction = nullptr; 58 | int _size {0}; 59 | }; 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /src/Range.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2016 - 2019, 2023, Thomas Lauf, Paul Beckingham, Federico Hernandez. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | #ifndef INCLUDED_RANGE 28 | #define INCLUDED_RANGE 29 | 30 | #include 31 | #include 32 | 33 | class Range 34 | { 35 | public: 36 | Range () = default; 37 | virtual ~Range() = default; 38 | Range (const Datetime&, const Datetime&); 39 | bool operator== (const Range&) const; 40 | bool operator!= (const Range&) const; 41 | 42 | void open (); 43 | void open (const Datetime&); 44 | void close (); 45 | 46 | bool is_open () const; 47 | bool is_started () const; 48 | bool is_ended () const; 49 | bool is_empty () const; 50 | 51 | bool contains (const Datetime&) const; 52 | 53 | bool overlaps (const Range&) const; 54 | bool encloses (const Range&) const; 55 | bool startsWithin (const Range&) const; 56 | bool endsWithin (const Range&) const; 57 | Range intersect (const Range&) const; 58 | bool intersects (const Range&) const; 59 | Range combine (const Range&) const; 60 | std::vector subtract (const Range&) const; 61 | time_t total () const; 62 | 63 | virtual std::string dump () const; 64 | 65 | public: 66 | Datetime start {0}; 67 | Datetime end {0}; 68 | 69 | }; 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /src/SummaryTable.h: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2018, 2023, Gothenburg Bit Factory. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | ////////////////////////////////////////////////////////////////////////////// 26 | 27 | #ifndef INCLUDED_SUMMARYTABLE 28 | #define INCLUDED_SUMMARYTABLE 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | class SummaryTable 37 | { 38 | class Builder 39 | { 40 | public: 41 | Builder& withWeekFormat (const std::string&); 42 | Builder& withDateFormat (const std::string&); 43 | Builder& withTimeFormat (const std::string&); 44 | 45 | Builder& withAnnotations (bool); 46 | Builder& withIds (bool, Color); 47 | Builder& withTags (bool, std::map &); 48 | Builder& withWeeks (bool); 49 | Builder& withWeekdays (bool); 50 | 51 | Builder& withRange (const Range&); 52 | Builder& withIntervals (const std::vector &); 53 | 54 | Table build (); 55 | 56 | private: 57 | std::string _week_fmt; 58 | std::string _date_fmt; 59 | std::string _time_fmt; 60 | 61 | bool _show_annotations; 62 | bool _show_ids; 63 | bool _show_tags; 64 | bool _show_weekdays; 65 | bool _show_weeks; 66 | 67 | Range _range; 68 | std::vector _tracked; 69 | Color _color_id; 70 | std::map _color_tags; 71 | }; 72 | 73 | public: 74 | static Builder builder (); 75 | }; 76 | 77 | #endif // INCLUDED_SUMMARYTABLE 78 | -------------------------------------------------------------------------------- /src/TagDescription.cpp: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2023, Gothenburg Bit Factory. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | ////////////////////////////////////////////////////////////////////////////// 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | TagDescription::TagDescription (std::string name, Color color, std::string description) : 32 | name (std::move (name)), 33 | color (color), 34 | description (std::move (description)) 35 | {} 36 | -------------------------------------------------------------------------------- /src/TagDescription.h: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2023, Gothenburg Bit Factory. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | ////////////////////////////////////////////////////////////////////////////// 26 | 27 | #ifndef INCLUDED_TAGDESCRIPTION 28 | #define INCLUDED_TAGDESCRIPTION 29 | 30 | #include 31 | 32 | class TagDescription 33 | { 34 | public: 35 | TagDescription (std::string , Color, std::string); 36 | 37 | std::string name; 38 | Color color; 39 | std::string description; 40 | }; 41 | 42 | #endif //INCLUDED_TAGDESCRIPTION 43 | -------------------------------------------------------------------------------- /src/TagInfo.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2018 - 2019, Thomas Lauf, Paul Beckingham, Federico Hernandez. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | #include 28 | #include 29 | 30 | //////////////////////////////////////////////////////////////////////////////// 31 | TagInfo::TagInfo (unsigned int count) 32 | { 33 | _count = count; 34 | } 35 | 36 | //////////////////////////////////////////////////////////////////////////////// 37 | unsigned int TagInfo::increment () 38 | { 39 | return _count++; 40 | } 41 | 42 | //////////////////////////////////////////////////////////////////////////////// 43 | unsigned int TagInfo::decrement () 44 | { 45 | return --_count; 46 | } 47 | 48 | //////////////////////////////////////////////////////////////////////////////// 49 | bool TagInfo::hasCount () 50 | { 51 | return _count > 0; 52 | } 53 | 54 | //////////////////////////////////////////////////////////////////////////////// 55 | std::string TagInfo::toJson () 56 | { 57 | std::stringstream output; 58 | output << "{\"count\":" << _count << "}"; 59 | 60 | return output.str (); 61 | } 62 | -------------------------------------------------------------------------------- /src/TagInfo.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2018 - 2019, Thomas Lauf, Paul Beckingham, Federico Hernandez. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | #ifndef INCLUDED_TAGINFO 28 | #define INCLUDED_TAGINFO 29 | 30 | #include 31 | 32 | class TagInfo 33 | { 34 | public: 35 | explicit TagInfo (unsigned int); 36 | 37 | unsigned int increment (); 38 | unsigned int decrement (); 39 | 40 | bool hasCount (); 41 | 42 | std::string toJson (); 43 | 44 | private: 45 | unsigned int _count = 0; 46 | }; 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /src/TagInfoDatabase.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2018 - 2022, Thomas Lauf, Paul Beckingham, Federico Hernandez. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | #ifndef INCLUDED_TAGINFODATABASE 28 | #define INCLUDED_TAGINFODATABASE 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | class TagInfoDatabase 36 | { 37 | public: 38 | int incrementTag (const std::string&); 39 | int decrementTag (const std::string&); 40 | 41 | void add (const std::string&, const TagInfo&); 42 | 43 | std::set tags () const; 44 | 45 | std::string toJson (); 46 | 47 | bool is_modified () const; 48 | void clear_modified (); 49 | 50 | private: 51 | std::map _tagInformation {}; 52 | bool _is_modified {false}; 53 | }; 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /src/TagsTable.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2023, Gothenburg Bit Factory. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | #include 28 | #include 29 | 30 | //////////////////////////////////////////////////////////////////////////////// 31 | TagsTable::Builder TagsTable::builder () 32 | { 33 | return {}; 34 | } 35 | 36 | //////////////////////////////////////////////////////////////////////////////// 37 | TagsTable::Builder& TagsTable::Builder::withTagDescriptions (std::vector & tagDescriptions) 38 | { 39 | _tagDescriptions = tagDescriptions; 40 | return *this; 41 | } 42 | 43 | //////////////////////////////////////////////////////////////////////////////// 44 | Table TagsTable::Builder::build () 45 | { 46 | int terminalWidth = getTerminalWidth (); 47 | 48 | Table table; 49 | table.width (terminalWidth); 50 | table.colorHeader (Color ("underline")); 51 | table.add ("Tag"); 52 | table.add ("Description"); 53 | 54 | for (const auto& tagDescription : _tagDescriptions) 55 | { 56 | auto row = table.addRow (); 57 | table.set (row, 0, tagDescription.name, tagDescription.color); 58 | table.set (row, 1, tagDescription.description); 59 | } 60 | 61 | return table; 62 | } 63 | 64 | //////////////////////////////////////////////////////////////////////////////// 65 | -------------------------------------------------------------------------------- /src/TagsTable.h: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2023, Gothenburg Bit Factory. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | ////////////////////////////////////////////////////////////////////////////// 26 | 27 | #ifndef INCLUDED_TAGSTABLEBUILDER 28 | #define INCLUDED_TAGSTABLEBUILDER 29 | 30 | #include 31 | #include 32 | #include 33 | 34 | class TagsTable 35 | { 36 | class Builder 37 | { 38 | public: 39 | Builder& withTagDescriptions (std::vector &); 40 | 41 | Table build (); 42 | 43 | private: 44 | std::vector _tagDescriptions {}; 45 | }; 46 | 47 | public: 48 | static Builder builder (); 49 | }; 50 | 51 | #endif //INCLUDED_TAGSTABLEBUILDER 52 | -------------------------------------------------------------------------------- /src/Transaction.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2018 - 2019, 2023, Thomas Lauf, Paul Beckingham, Federico Hernandez. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | #include 28 | 29 | void Transaction::addUndoAction ( 30 | const std::string& type, 31 | const std::string& before, 32 | const std::string& after) 33 | { 34 | _actions.emplace_back (type, before, after); 35 | } 36 | 37 | std::vector Transaction::getActions () const 38 | { 39 | return _actions; 40 | } 41 | 42 | std::string Transaction::toString () const 43 | { 44 | std::string output = "txn:\n"; 45 | 46 | for (auto& action : _actions) 47 | { 48 | output += action.toString (); 49 | } 50 | 51 | return output; 52 | } 53 | -------------------------------------------------------------------------------- /src/Transaction.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2018 - 2019, 2023, Thomas Lauf, Paul Beckingham, Federico Hernandez. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | #ifndef INCLUDED_TRANSACTION 28 | #define INCLUDED_TRANSACTION 29 | 30 | #include 31 | #include 32 | 33 | class Transaction 34 | { 35 | public: 36 | void addUndoAction(const std::string&, const std::string&, const std::string&); 37 | 38 | std::string toString() const; 39 | 40 | std::vector getActions () const; 41 | 42 | private: 43 | std::vector _actions {}; 44 | }; 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /src/TransactionsFactory.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2018 - 2019, 2022 - 2023, Thomas Lauf, Paul Beckingham, Federico Hernandez. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | #include 28 | #include 29 | 30 | void TransactionsFactory::parseLine (const std::string& line) 31 | { 32 | if (! line.compare (0, 4, "txn:")) 33 | { 34 | _transactions.emplace_back (); 35 | } 36 | else if (! line.compare (0, 7, " type:")) 37 | { 38 | _type = line.substr (8, line.size ()); 39 | } 40 | else if (! line.compare (0, 9, " before:")) 41 | { 42 | _before = line.substr (10, line.size ()); 43 | } 44 | else if (! line.compare (0, 8, " after:")) 45 | { 46 | _after = line.substr (9, line.size ()); 47 | _transactions.back ().addUndoAction (_type, _before, _after); 48 | } 49 | else 50 | { 51 | throw "Cannot handle line '" + line + "'"; 52 | } 53 | } 54 | 55 | std::vector TransactionsFactory::get () 56 | { 57 | return _transactions; 58 | } 59 | -------------------------------------------------------------------------------- /src/TransactionsFactory.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2018 - 2019, 2022, Thomas Lauf, Paul Beckingham, Federico Hernandez. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | #ifndef INCLUDED_TRANSACTIONSFACTORY 28 | #define INCLUDED_TRANSACTIONSFACTORY 29 | 30 | #include 31 | #include 32 | 33 | class TransactionsFactory 34 | { 35 | public: 36 | void parseLine(const std::string& line); 37 | 38 | std::vector< Transaction > get(); 39 | 40 | private: 41 | std::string _type; 42 | std::string _before; 43 | std::string _after; 44 | 45 | std::vector< Transaction > _transactions {}; 46 | }; 47 | 48 | 49 | #endif //INCLUDED_TRANSACTIONSFACTORY 50 | -------------------------------------------------------------------------------- /src/UndoAction.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2018 - 2019, Thomas Lauf, Paul Beckingham, Federico Hernandez. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | #include 28 | #include 29 | 30 | UndoAction::UndoAction (std::string type, std::string before, std::string after) : 31 | _type (std::move (type)), _before (std::move (before)), _after (std::move (after)) 32 | {} 33 | 34 | std::string UndoAction::toString () const 35 | { 36 | return " type: " + _type + "\n" + 37 | " before: " + _before + "\n" + 38 | " after: " + _after + "\n"; 39 | } 40 | 41 | std::string UndoAction::getType () const 42 | { 43 | return _type; 44 | } 45 | 46 | std::string UndoAction::getBefore () const 47 | { 48 | return _before; 49 | } 50 | 51 | std::string UndoAction::getAfter () const 52 | { 53 | return _after; 54 | } 55 | 56 | 57 | -------------------------------------------------------------------------------- /src/UndoAction.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2018 - 2019, Thomas Lauf, Paul Beckingham, Federico Hernandez. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | #ifndef INCLUDED_UNDOACTION 28 | #define INCLUDED_UNDOACTION 29 | 30 | #include 31 | 32 | class UndoAction 33 | { 34 | public: 35 | UndoAction(std::string, std::string, std::string); 36 | 37 | std::string getType() const; 38 | std::string getBefore() const; 39 | std::string getAfter() const; 40 | 41 | std::string toString () const; 42 | 43 | private: 44 | const std::string _type; 45 | const std::string _before; 46 | const std::string _after; 47 | }; 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /src/commands/.gitignore: -------------------------------------------------------------------------------- 1 | libcommands.a 2 | additional-help.h 3 | -------------------------------------------------------------------------------- /src/commands/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.10) 2 | include_directories (${CMAKE_SOURCE_DIR} 3 | ${CMAKE_SOURCE_DIR}/src 4 | ${CMAKE_SOURCE_DIR}/src/commands 5 | ${CMAKE_SOURCE_DIR}/src/libshared/src 6 | ${TIMEW_INCLUDE_DIRS}) 7 | 8 | set (ADDITIONAL_HELP_H "additional-help.h") 9 | 10 | add_custom_command (OUTPUT ${ADDITIONAL_HELP_H} 11 | COMMAND /bin/sh src/commands/generate-additional-help.sh > src/commands/${ADDITIONAL_HELP_H} 12 | DEPENDS ${CMAKE_CURRENT_LIST_DIR}/generate-additional-help.sh 13 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} 14 | COMMENT "Generating ${ADDITIONAL_HELP_H}") 15 | 16 | add_custom_target (generate_additional_help 17 | DEPENDS ${ADDITIONAL_HELP_H}) 18 | 19 | set (commands_SRCS CmdAnnotate.cpp 20 | CmdCancel.cpp 21 | CmdChart.cpp 22 | CmdConfig.cpp 23 | CmdContinue.cpp 24 | CmdDefault.cpp 25 | CmdDelete.cpp 26 | CmdDiagnostics.cpp 27 | CmdExport.cpp 28 | CmdExtensions.cpp 29 | CmdFill.cpp 30 | CmdGaps.cpp 31 | CmdGet.cpp 32 | CmdHelp.cpp 33 | CmdJoin.cpp 34 | CmdLengthen.cpp 35 | CmdModify.cpp 36 | CmdModifyEnd.cpp 37 | CmdModifyRange.cpp 38 | CmdModifyStart.cpp 39 | CmdMove.cpp 40 | CmdReport.cpp 41 | CmdResize.cpp 42 | CmdRetag.cpp 43 | CmdStart.cpp 44 | CmdStop.cpp 45 | CmdSummary.cpp 46 | CmdShorten.cpp 47 | CmdShow.cpp 48 | CmdSplit.cpp 49 | CmdTag.cpp 50 | CmdTags.cpp 51 | CmdTrack.cpp 52 | CmdUndo.cpp 53 | CmdUntag.cpp) 54 | 55 | add_library (commands STATIC ${commands_SRCS}) 56 | add_dependencies (commands generate_additional_help) 57 | -------------------------------------------------------------------------------- /src/commands/CmdCancel.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2016 - 2023, Thomas Lauf, Paul Beckingham, Federico Hernandez. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | //////////////////////////////////////////////////////////////////////////////// 32 | int CmdCancel ( 33 | Rules& rules, 34 | Database& database, 35 | Journal& journal) 36 | { 37 | const bool verbose = rules.getBoolean ("verbose"); 38 | 39 | // If there is an open interval, cancel it by deleting it 40 | auto latest = getLatestInterval (database); 41 | 42 | if (! latest.is_open ()) 43 | { 44 | if (verbose) 45 | std::cout << "There is no active time tracking.\n"; 46 | 47 | return 0; 48 | } 49 | 50 | journal.startTransaction (); 51 | database.deleteInterval(latest); 52 | journal.endTransaction (); 53 | 54 | if (verbose) 55 | { 56 | std::cout << "Canceled active time tracking.\n"; 57 | } 58 | 59 | return 0; 60 | } 61 | 62 | //////////////////////////////////////////////////////////////////////////////// 63 | -------------------------------------------------------------------------------- /src/commands/CmdExtensions.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2016 - 2019, 2022 - 2023, Gothenburg Bit Factory. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | //////////////////////////////////////////////////////////////////////////////// 33 | // Enumerate all extensions. 34 | int CmdExtensions (const Extensions& extensions) 35 | { 36 | auto table = ExtensionsTable::builder() 37 | .withExtensions (extensions) 38 | .build (); 39 | 40 | Directory extDir (paths::extensionsDir ()); 41 | 42 | std::cout << '\n' 43 | << "Extensions located in:\n" 44 | << " " << extDir._data << '\n' 45 | << '\n' 46 | << table.render () 47 | << '\n'; 48 | 49 | return 0; 50 | } 51 | 52 | //////////////////////////////////////////////////////////////////////////////// 53 | -------------------------------------------------------------------------------- /src/commands/CmdGet.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2016 - 2018, 2020 - 2024, Gothenburg Bit Factory. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | //////////////////////////////////////////////////////////////////////////////// 34 | // Іdentify DOM references in cli, provide space-separated results. 35 | int CmdGet ( 36 | CLI& cli, 37 | Rules& rules, 38 | Database& database) 39 | { 40 | auto references = cli.getDomReferences (); 41 | auto filter = Interval {cli.getRange (), cli.getTags ()}; 42 | 43 | std::vector results; 44 | 45 | for (auto& reference : references) 46 | { 47 | std::string value; 48 | 49 | if (! domGet (database, filter, rules, reference, value)) 50 | { 51 | throw format ("DOM reference '{1}' is not valid.", reference); 52 | } 53 | 54 | results.push_back (value); 55 | } 56 | 57 | std::cout << join (" ", results) << '\n'; 58 | 59 | return 0; 60 | } 61 | 62 | //////////////////////////////////////////////////////////////////////////////// 63 | -------------------------------------------------------------------------------- /src/commands/CmdModify.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2018, 2020 - 2024, Gothenburg Bit Factory. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | #include 28 | #include 29 | 30 | //////////////////////////////////////////////////////////////////////////////// 31 | int CmdModify ( 32 | CLI& cli, 33 | Rules& rules, 34 | Database& database, 35 | Journal& journal) 36 | { 37 | const auto subCommand = cli.findSubCommand (std::set {"start", "end", "range"}); 38 | 39 | if (subCommand.empty()) 40 | { 41 | throw std::string ("Must specify start|end|range command to modify. See 'timew help modify'."); 42 | } 43 | 44 | if (subCommand == "start") 45 | { 46 | return CmdModifyStart (cli, rules, database, journal); 47 | } 48 | if (subCommand == "end") 49 | { 50 | return CmdModifyEnd (cli, rules, database, journal); 51 | } 52 | if (subCommand == "range") 53 | { 54 | return CmdModifyRange (cli, rules, database, journal); 55 | } 56 | 57 | throw format ("Command 'modify' has no subcommand '{1}' defined!", subCommand); 58 | } 59 | 60 | //////////////////////////////////////////////////////////////////////////////// 61 | -------------------------------------------------------------------------------- /src/commands/CmdStart.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2016 - 2020, 2022 - 2024, Gothenburg Bit Factory. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | //////////////////////////////////////////////////////////////////////////////// 32 | int CmdStart ( 33 | CLI& cli, 34 | Rules& rules, 35 | Database& database, 36 | Journal& journal) 37 | { 38 | const bool verbose = rules.getBoolean ("verbose"); 39 | const Datetime now {}; 40 | 41 | auto range = cli.getRange ({now, 0}); 42 | auto tags = cli.getTags (); 43 | 44 | if (range.start > now) 45 | { 46 | throw std::string ("Time tracking cannot be set in the future."); 47 | } 48 | else if (! range.is_started () || range.is_ended ()) 49 | { 50 | throw std::string ("The start command does not accept ranges but only a single datetime. " 51 | "Perhaps you want the track command?"); 52 | } 53 | 54 | // We expect no ids 55 | if (! cli.getIds ().empty ()) 56 | { 57 | throw std::string ("The start command does not accept ids. " 58 | "Perhaps you want the continue command?"); 59 | } 60 | 61 | journal.startTransaction (); 62 | auto interval = Interval {range, tags}; 63 | 64 | if (validate (cli, rules, database, interval)) 65 | { 66 | database.addInterval (interval, verbose); 67 | journal.endTransaction (); 68 | } 69 | if (verbose) 70 | { 71 | std::cout << intervalSummarize (rules, interval); 72 | } 73 | 74 | return 0; 75 | } 76 | 77 | //////////////////////////////////////////////////////////////////////////////// 78 | -------------------------------------------------------------------------------- /src/commands/generate-additional-help.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | CONCEPTS="$( find doc/man7 -name "timew-*.7*" | sed -E 's|doc/man7/timew-(.*)\.7.*|\1|' | sort -u )" 4 | COMMANDS="$( find doc/man1 -name "timew-*.1*" | sed -E 's|doc/man1/timew-(.*)\.1.*|\1|' | sort -u | tr '\n' ' ' )" 5 | 6 | echo "// Generated file. Do not modify" 7 | echo "#include " 8 | echo "#include " 9 | echo "static const std::vector timew_help_concepts = {" 10 | for concept in ${CONCEPTS} ; do 11 | ( echo "${COMMANDS}" | grep -vq "${concept}" ) && echo " \"${concept}\"," 12 | done 13 | echo "};" 14 | -------------------------------------------------------------------------------- /src/lex.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | 3 | #include 4 | #include 5 | 6 | int main (int argc, char** argv) 7 | { 8 | for (auto i = 1; i < argc; i++) 9 | { 10 | std::cout << "argument '" << argv[i] << "'\n"; 11 | 12 | Lexer l (argv[i]); 13 | std::string token; 14 | Lexer::Type type; 15 | while (l.token (token, type)) 16 | std::cout << " token '" << token << "' " << Lexer::typeToString (type) << '\n'; 17 | } 18 | } 19 | 20 | //////////////////////////////////////////////////////////////////////////////// 21 | -------------------------------------------------------------------------------- /src/log.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2016, 2018 - 2020, 2023, Thomas Lauf, Paul Beckingham, Federico Hernandez. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | static bool debugMode = false; 33 | static std::string debugIndicator = ">>"; 34 | static Color debugColor; 35 | 36 | //////////////////////////////////////////////////////////////////////////////// 37 | void enableDebugMode (bool value) 38 | { 39 | debugMode = value; 40 | } 41 | 42 | //////////////////////////////////////////////////////////////////////////////// 43 | void setDebugIndicator (const std::string& indicator) 44 | { 45 | debugIndicator = indicator; 46 | } 47 | 48 | //////////////////////////////////////////////////////////////////////////////// 49 | void setDebugColor (const Color& color) 50 | { 51 | debugColor = color; 52 | } 53 | 54 | //////////////////////////////////////////////////////////////////////////////// 55 | void debug (const std::string& msg) 56 | { 57 | if (debugMode) 58 | { 59 | std::stringstream sstr (msg); 60 | std::string line; 61 | while (std::getline (sstr, line, '\n')) 62 | { 63 | std::cout << debugColor.colorize (debugIndicator + " " + line) << "\n"; 64 | } 65 | } 66 | } 67 | 68 | //////////////////////////////////////////////////////////////////////////////// 69 | -------------------------------------------------------------------------------- /src/paths.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2022 - 2023, Thomas Lauf, Paul Beckingham, Federico Hernandez. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | #ifndef INCLUDED_PATH_RESOLVER 28 | #define INCLUDED_PATH_RESOLVER 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | namespace paths { 35 | void initializeDirs (const CLI&, Rules&); 36 | std::string configDir (); 37 | std::string configFile (); 38 | std::string dbDir (); 39 | std::string dbDataDir (); 40 | std::string extensionsDir (); 41 | } 42 | #endif 43 | -------------------------------------------------------------------------------- /test/.gitignore: -------------------------------------------------------------------------------- 1 | all.log 2 | AtomicFileTest 3 | data.t 4 | Datafile.t 5 | DatetimeParser.t 6 | exclusion.t 7 | helper.t 8 | interval.t 9 | range.t 10 | rules.t 11 | TagInfoDatabase.t 12 | util.t 13 | -------------------------------------------------------------------------------- /test/AtomicFile.t: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | BASEDIR="$( dirname "$0" )" 3 | 4 | if [ "$(uname -s)" = "Darwin" ] ; then 5 | DLL_TOOL="otool -L" 6 | else 7 | DLL_TOOL="ldd" 8 | fi 9 | 10 | if "${DLL_TOOL}" "${BASEDIR}/AtomicFileTest" | grep -q 'libfiu' ; then 11 | exec fiu-run -x "${BASEDIR}/AtomicFileTest" 12 | else 13 | exec "${BASEDIR}/AtomicFileTest" 14 | fi 15 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.10) 2 | 3 | # This is a work-around for the following CMake issue: 4 | # https://gitlab.kitware.com/cmake/cmake/issues/16062 5 | # The issue has been fixed in CMake 3.11.0; the policy is set 6 | # to OLD for compatibility with older versions of CMake only. 7 | if (POLICY CMP0037 AND ${CMAKE_VERSION} VERSION_LESS "3.11.0") 8 | cmake_policy(SET CMP0037 OLD) 9 | endif () 10 | 11 | # If this is a debug build, check if we have libfiu installed and available on 12 | # the system. If so, we will be able to use it to add additional tests of the 13 | # failure conditions 14 | 15 | if (uppercase_CMAKE_BUILD_TYPE MATCHES "DEBUG") 16 | find_library(FIU_ENABLE fiu) 17 | if (FIU_ENABLE) 18 | message (STATUS "libfiu found") 19 | add_definitions (-DFIU_ENABLE) 20 | set (test_LIBS fiu ${TIMEW_LIBRARIES}) 21 | else (FIU_ENABLE) 22 | message (STATUS "NOTE: install libfiu to run additional tests") 23 | set (test_LIBS ${TIMEW_LIBRARIES}) 24 | endif (FIU_ENABLE) 25 | else (uppercase_CMAKE_BUILD_TYPE MATCHES "DEBUG") 26 | set (test_LIBS ${TIMEW_LIBRARIES}) 27 | endif (uppercase_CMAKE_BUILD_TYPE MATCHES "DEBUG") 28 | 29 | include_directories (${CMAKE_SOURCE_DIR} 30 | ${CMAKE_SOURCE_DIR}/src 31 | ${CMAKE_SOURCE_DIR}/src/libshared/src 32 | ${CMAKE_SOURCE_DIR}/test) 33 | 34 | include_directories (${CMAKE_INSTALL_PREFIX}/include) 35 | link_directories(${CMAKE_INSTALL_PREFIX}/lib) 36 | 37 | set (test_SRCS AtomicFileTest data.t Datafile.t DatetimeParser.t exclusion.t helper.t interval.t range.t rules.t util.t TagInfoDatabase.t) 38 | 39 | add_custom_target (test ./run_all --verbose 40 | DEPENDS ${test_SRCS} timew_executable doc 41 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/test 42 | COMMENT "Running testsuite...") 43 | 44 | foreach (src_FILE ${test_SRCS}) 45 | add_executable (${src_FILE} "${src_FILE}.cpp" test.cpp) 46 | target_link_libraries (${src_FILE} timew libshared ${test_LIBS}) 47 | endforeach (src_FILE) 48 | 49 | configure_file(run_all run_all COPYONLY) 50 | configure_file(problems problems COPYONLY) 51 | -------------------------------------------------------------------------------- /test/Datafile.t.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2020 - 2022, Shaun Ruffell, Thomas Lauf. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | int main () 33 | { 34 | UnitTest t (2); 35 | TempDir tempDir; 36 | 37 | try 38 | { 39 | Datafile df; 40 | Interval interval {Datetime ("2020-06-01T01:00:00"), Datetime ("2020-06-01T02:00:00")}; 41 | 42 | df.initialize ("2020-06.data"); 43 | df.addInterval (interval); 44 | 45 | Interval modified {interval}; 46 | modified.tag ("foo"); 47 | 48 | std::string message = "Datafile::deleteInterval throws on error"; 49 | try { df.deleteInterval (modified); t.fail (message); } 50 | catch (...) { t.pass (message); } 51 | 52 | message = "Datafile::deleteInterval does not throw on success"; 53 | try { df.deleteInterval (interval); t.pass (message); } 54 | catch (...) { t.fail (message); } 55 | } 56 | catch (...) 57 | { 58 | t.fail ("Uncaught exception"); 59 | } 60 | return 0; 61 | } 62 | 63 | -------------------------------------------------------------------------------- /test/basetest/__init__.py: -------------------------------------------------------------------------------- 1 | from .testing import TestCase 2 | from .timew import Timew 3 | -------------------------------------------------------------------------------- /test/basetest/exceptions.py: -------------------------------------------------------------------------------- 1 | import signal 2 | 3 | sig_names = dict((k, v) for v, k in reversed(sorted(signal.__dict__.items())) 4 | if v.startswith("SIG") and not v.startswith("SIG_")) 5 | 6 | 7 | class CommandError(Exception): 8 | def __init__(self, cmd, code, out, err=None, msg=None): 9 | DEFAULT = ("Command '{{0}}' was {signal}'ed. " 10 | "SIGABRT usually means program timed out.\n") 11 | if msg is None: 12 | msg_suffix = "\n*** Start STDOUT ***\n{2}\n*** End STDOUT ***\n" 13 | if err is not None: 14 | msg_suffix += ( 15 | "\n*** Start STDERR ***\n{3}\n*** End STDERR ***\n" 16 | ) 17 | 18 | if code < 0: 19 | self.msg = DEFAULT.format(signal=sig_names[abs(code)]) 20 | else: 21 | self.msg = ("Command '{0}' finished with unexpected exit " 22 | "code '{1}'.\n") 23 | 24 | self.msg += msg_suffix 25 | else: 26 | self.msg = msg 27 | 28 | self.cmd = cmd 29 | self.out = out 30 | self.err = err 31 | self.code = code 32 | 33 | def __str__(self): 34 | return self.msg.format(self.cmd, self.code, self.out, self.err) 35 | 36 | 37 | class HookError(Exception): 38 | pass 39 | 40 | 41 | class TimeoutWaitingFor(object): 42 | def __init__(self, name): 43 | self.name = name 44 | 45 | def __repr__(self): 46 | return "*** Timeout reached while waiting for {0} ***".format( 47 | self.name) 48 | 49 | 50 | class StreamsAreMerged(object): 51 | def __repr__(self): 52 | return "*** Streams are merged, STDERR is not available ***" 53 | -------------------------------------------------------------------------------- /test/basetest/meta.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function, division 2 | 3 | 4 | class MetaTest(type): 5 | """Helper metaclass to simplify dynamic test creation 6 | 7 | Creates test_methods in the TestCase class dynamically named after the 8 | arguments used. 9 | """ 10 | @staticmethod 11 | def make_function(classname, *args, **kwargs): 12 | def test(self): 13 | # ### Body of the usual test_testcase ### # 14 | # Override and redefine this method # 15 | pass 16 | 17 | # Title of test in report 18 | test.__doc__ = "{0}".format(args[0]) 19 | 20 | return test 21 | 22 | def __new__(meta, classname, bases, dct): 23 | tests = dct.get("TESTS") 24 | kwargs = dct.get("EXTRA", {}) 25 | 26 | for i, args in enumerate(tests): 27 | func = meta.make_function(classname, *args, **kwargs) 28 | 29 | # Rename the function after a unique identifier 30 | # Name of function must start with test_ to be run by unittest 31 | func.__name__ = "test_{0}".format(i) 32 | 33 | # Attach the new test to the test class 34 | dct[func.__name__] = func 35 | 36 | return super(MetaTest, meta).__new__(meta, classname, bases, dct) 37 | -------------------------------------------------------------------------------- /test/bash_tap_ti.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # This file only contains helper functions for making Timewarrior testing 3 | # easier. The magic happens in bash_tap.sh sourced at the end of this file. 4 | # 5 | # "timew" is a bash function calling "TIMEWARRIORDB=dir /path/to/compiled/timew" 6 | # Only local paths are searched, see bash_tap_tw.sh:find_timew_binary(). 7 | # 8 | # "timewarrior.cfg" is a file set up in bash_tap_ti.sh:setup_cfg(), and can be 9 | # appended to or changed as needed. 10 | # 11 | # Subject to the MIT License. See LICENSE file or https://opensource.org/licenses/MIT 12 | # Copyright (c) 2015-2018 Wilhelm Schürmann 13 | 14 | function setup_cfg { 15 | # Configuration 16 | for i in data/*.data timewarrior.cfg; do 17 | if [[ -f "${i}" ]] ; then 18 | rm "${i}" >/dev/null 2>&1 19 | fi 20 | done 21 | 22 | export TIMEWARRIORDB=. 23 | 24 | #echo 'foo' >> timewarrior.cfg 25 | } 26 | 27 | function find_timew_binary { 28 | # $bashtap_org_pwd is set in bash_tap.sh. It is the directory the parent script is 29 | # run from. Check for the timew binary relative to that directory. 30 | # Do not use the system "timew" if no local one is found, error out instead. 31 | for t in "${bashtap_org_pwd}/timew" "${bashtap_org_pwd}/src/timew" "${bashtap_org_pwd}/../timew" "${bashtap_org_pwd}/../src/timew" "${bashtap_org_pwd}/../build/src/timew"; do 32 | if [ -f "$t" ] && [ -x "$t" ]; then 33 | t_abs=$(bashtap_get_absolute_path "$t") 34 | eval "function timew { ${t_abs} \"\$@\"; }" 35 | return 0 36 | fi 37 | done 38 | 39 | echo "# ERROR: Could not find timew binary!" 40 | 41 | # Needed for normal, i.e. "non-test" mode. 42 | eval "function timew { exit; }" 43 | 44 | # Set $line so we can have useful TAP output. 45 | line="bash_tap.sh:find_timew_binary()" 46 | 47 | return 1 48 | } 49 | 50 | function bashtap_setup { 51 | # This function is called by bash_tap.sh before running tests, or before 52 | # running the parent script normally. 53 | find_timew_binary 54 | setup_cfg 55 | } 56 | 57 | 58 | # Include the base script that does the actual work. 59 | source bash_tap.sh 60 | -------------------------------------------------------------------------------- /test/docker/alpine-edge: -------------------------------------------------------------------------------- 1 | FROM alpine:edge 2 | 3 | RUN apk add --no-cache \ 4 | asciidoctor \ 5 | bash \ 6 | cmake \ 7 | g++ \ 8 | git \ 9 | make \ 10 | mandoc \ 11 | musl-dev \ 12 | python3 \ 13 | py3-dateutil 14 | 15 | # Setup environment 16 | ENV LANG en_US.UTF-8 17 | ENV LANGUAGE en_US.UTF-8 18 | ENV MAN_DISABLE_SECCOMP 1 19 | 20 | # Setup timewarrior 21 | ADD . /root/code/ 22 | WORKDIR /root/code/ 23 | RUN git clean -dfx 24 | RUN git submodule init 25 | RUN git submodule update 26 | RUN cmake -DCMAKE_BUILD_TYPE=debug . 27 | RUN make -j2 28 | RUN make install 29 | 30 | # Setup tests 31 | WORKDIR /root/code/test/ 32 | RUN make -j2 33 | 34 | CMD ["bash", "-c", "./run_all -v ; cat all.log | grep 'not ok' ; ./problems ; FAILED=$? ; echo timew $( timew --version ) ; python --version ; cmake --version ; gcc --version ; asciidoctor --version ; exit $FAILED"] 35 | -------------------------------------------------------------------------------- /test/docker/alpine-latest: -------------------------------------------------------------------------------- 1 | FROM alpine:latest 2 | 3 | RUN apk add --no-cache \ 4 | asciidoctor \ 5 | bash \ 6 | cmake \ 7 | g++ \ 8 | git \ 9 | make \ 10 | man-db \ 11 | musl-dev \ 12 | python3 \ 13 | py3-dateutil 14 | 15 | # Setup environment 16 | ENV LANG en_US.UTF-8 17 | ENV LANGUAGE en_US.UTF-8 18 | ENV MAN_DISABLE_SECCOMP 1 19 | 20 | # Setup timewarrior 21 | ADD . /root/code/ 22 | WORKDIR /root/code/ 23 | RUN git clean -dfx 24 | RUN git submodule init 25 | RUN git submodule update 26 | RUN cmake -DCMAKE_BUILD_TYPE=debug . 27 | RUN make -j2 28 | RUN make install 29 | 30 | # Setup tests 31 | WORKDIR /root/code/test/ 32 | RUN make -j2 33 | 34 | CMD ["bash", "-c", "./run_all -v ; cat all.log | grep 'not ok' ; ./problems ; FAILED=$? ; echo timew $( timew --version ) ; python --version ; cmake --version ; gcc --version ; asciidoctor --version ; exit $FAILED"] 35 | -------------------------------------------------------------------------------- /test/docker/archlinux: -------------------------------------------------------------------------------- 1 | FROM archlinux:base 2 | 3 | RUN pacman-key --init 4 | RUN pacman -Sy --noconfirm archlinux-keyring 5 | RUN pacman -Syu --noconfirm 6 | RUN pacman -S --noconfirm \ 7 | asciidoctor \ 8 | cmake \ 9 | gcc \ 10 | git \ 11 | make \ 12 | man-db \ 13 | python \ 14 | python-dateutil 15 | 16 | # Setup environment 17 | ENV LANG en_US.UTF-8 18 | ENV LANGUAGE en_US.UTF-8 19 | ENV MAN_DISABLE_SECCOMP 1 20 | 21 | # Setup timewarrior 22 | ADD . /root/code/ 23 | WORKDIR /root/code/ 24 | RUN git clean -dfx 25 | RUN git submodule init 26 | RUN git submodule update 27 | RUN cmake -DCMAKE_BUILD_TYPE=debug . 28 | RUN make -j2 29 | RUN make install 30 | 31 | # Setup tests 32 | WORKDIR /root/code/test/ 33 | RUN make -j2 34 | 35 | CMD ["bash", "-c", "./run_all -v ; cat all.log | grep 'not ok' ; ./problems ; FAILED=$? ; echo timew $( timew --version ) ; python --version ; cmake --version ; gcc --version ; asciidoctor --version ; exit $FAILED"] 36 | -------------------------------------------------------------------------------- /test/docker/centos-stream9: -------------------------------------------------------------------------------- 1 | FROM quay.io/centos/centos:stream9 2 | 3 | RUN dnf -y distro-sync 4 | RUN dnf -y update 5 | RUN dnf -y install \ 6 | ruby \ 7 | cmake \ 8 | gcc-c++ \ 9 | git \ 10 | glibc-langpack-en.x86_64 \ 11 | make \ 12 | man \ 13 | python3 \ 14 | python3-dateutil 15 | 16 | RUN gem install asciidoctor 17 | 18 | # Setup environment 19 | RUN ln -sf /usr/bin/python3 /usr/bin/python 20 | 21 | ENV LC_ALL en_US.UTF-8 22 | ENV LANG en_US.UTF-8 23 | ENV LANGUAGE en_US.UTF-8 24 | 25 | # Setup timewarrior 26 | ADD . /root/code/ 27 | WORKDIR /root/code/ 28 | RUN git clean -dfx 29 | RUN git submodule init 30 | RUN git submodule update 31 | RUN cmake -DCMAKE_BUILD_TYPE=debug . 32 | RUN make -j2 33 | RUN make install 34 | 35 | # Setup tests 36 | WORKDIR /root/code/test/ 37 | RUN make -j2 38 | 39 | CMD ["bash", "-c", "./run_all -v ; cat all.log | grep 'not ok' ; ./problems ; FAILED=$? ; echo timew $( timew --version ) ; python --version ; cmake --version ; gcc --version ; asciidoctor --version ; exit $FAILED"] 40 | -------------------------------------------------------------------------------- /test/docker/debianstable: -------------------------------------------------------------------------------- 1 | FROM debian:stable 2 | 3 | ENV DEBIAN_FRONTEND noninteractive 4 | 5 | RUN apt-get update 6 | RUN apt-get install -y \ 7 | asciidoctor \ 8 | cmake \ 9 | g++ \ 10 | git \ 11 | locales \ 12 | man \ 13 | python3 \ 14 | python3-dateutil \ 15 | tzdata 16 | 17 | # Setup environment 18 | RUN update-alternatives --install /usr/bin/python python /usr/bin/python3 10 19 | RUN ln -fs /usr/share/zoneinfo/Europe/Berlin /etc/localtime 20 | RUN dpkg-reconfigure -f noninteractive tzdata 21 | 22 | RUN echo "LC_ALL=en_US.UTF-8" >> /etc/environment 23 | RUN echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen 24 | RUN echo "LANG=en_US.UTF-8" > /etc/locale.conf 25 | RUN locale-gen en_US.UTF-8 26 | 27 | # Setup timewarrior 28 | ADD . /root/code/ 29 | WORKDIR /root/code/ 30 | RUN git clean -dfx 31 | RUN git submodule init 32 | RUN git submodule update 33 | RUN cmake -DCMAKE_BUILD_TYPE=debug . 34 | RUN make -j2 35 | RUN make install 36 | 37 | # Setup tests 38 | WORKDIR /root/code/test/ 39 | RUN make -j2 40 | 41 | CMD ["bash", "-c", "./run_all -v ; cat all.log | grep 'not ok' ; ./problems ; FAILED=$? ; echo timew $( timew --version ) ; python --version ; cmake --version ; gcc --version ; asciidoctor --version ; exit $FAILED"] 42 | -------------------------------------------------------------------------------- /test/docker/debiantesting: -------------------------------------------------------------------------------- 1 | FROM debian:testing 2 | 3 | ENV DEBIAN_FRONTEND noninteractive 4 | 5 | RUN apt-get update && apt-get install -y \ 6 | asciidoctor \ 7 | cmake \ 8 | fiu-utils \ 9 | g++ \ 10 | git \ 11 | libfiu-dev \ 12 | locales \ 13 | man \ 14 | python3 \ 15 | python3-dateutil \ 16 | tzdata \ 17 | && rm -fr /var/lib/apt/lists/* 18 | 19 | # Setup environment 20 | RUN update-alternatives --install /usr/bin/python python /usr/bin/python3 10 21 | RUN ln -fs /usr/share/zoneinfo/Europe/Berlin /etc/localtime 22 | RUN dpkg-reconfigure -f noninteractive tzdata 23 | 24 | RUN echo "LC_ALL=en_US.UTF-8" >> /etc/environment 25 | RUN echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen 26 | RUN echo "LANG=en_US.UTF-8" > /etc/locale.conf 27 | RUN locale-gen en_US.UTF-8 28 | 29 | # Setup timewarrior 30 | ADD . /root/code/ 31 | WORKDIR /root/code/ 32 | RUN git clean -dfx 33 | RUN git submodule init 34 | RUN git submodule update 35 | RUN cmake -DCMAKE_BUILD_TYPE=debug . 36 | RUN make -j2 37 | RUN make install 38 | 39 | # Setup tests 40 | WORKDIR /root/code/test/ 41 | RUN make -j2 42 | 43 | CMD ["bash", "-c", "./run_all -v ; cat all.log | grep 'not ok' ; ./problems ; FAILED=$? ; echo timew $( timew --version ) ; python --version ; cmake --version ; gcc --version ; asciidoctor --version ; exit $FAILED"] 44 | -------------------------------------------------------------------------------- /test/docker/fedora41: -------------------------------------------------------------------------------- 1 | FROM fedora:41 2 | 3 | RUN dnf update -y 4 | RUN dnf install -y \ 5 | asciidoctor \ 6 | cmake \ 7 | findutils \ 8 | gcc-c++ \ 9 | glibc-locale-source \ 10 | git \ 11 | make \ 12 | man \ 13 | python3 \ 14 | python3-dateutil 15 | 16 | # Setup environment 17 | RUN alternatives --install /usr/bin/python python /usr/bin/python3 10 18 | RUN ln -fs /usr/share/zoneinfo/Europe/Berlin /etc/localtime 19 | 20 | # Setup timewarrior 21 | ADD . /root/code/ 22 | WORKDIR /root/code/ 23 | RUN git clean -dfx 24 | RUN git submodule init 25 | RUN git submodule update 26 | RUN cmake -DCMAKE_BUILD_TYPE=debug . 27 | RUN make -j2 28 | RUN make install 29 | 30 | # Setup tests 31 | WORKDIR /root/code/test/ 32 | RUN make -j2 33 | 34 | CMD ["bash", "-c", "./run_all -v ; cat all.log | grep 'not ok' ; ./problems ; FAILED=$? ; echo timew $( timew --version ) ; python --version ; cmake --version ; gcc --version ; asciidoctor --version ; exit $FAILED"] 35 | -------------------------------------------------------------------------------- /test/docker/fedora42: -------------------------------------------------------------------------------- 1 | FROM fedora:42 2 | 3 | RUN dnf update -y 4 | RUN dnf install -y \ 5 | asciidoctor \ 6 | cmake \ 7 | findutils \ 8 | gcc-c++ \ 9 | glibc-locale-source \ 10 | git \ 11 | make \ 12 | man \ 13 | python3 \ 14 | python3-dateutil 15 | 16 | # Setup environment 17 | RUN alternatives --install /usr/bin/python python /usr/bin/python3 10 18 | RUN ln -fs /usr/share/zoneinfo/Europe/Berlin /etc/localtime 19 | 20 | # Setup timewarrior 21 | ADD . /root/code/ 22 | WORKDIR /root/code/ 23 | RUN git clean -dfx 24 | RUN git submodule init 25 | RUN git submodule update 26 | RUN cmake -DCMAKE_BUILD_TYPE=debug . 27 | RUN make -j2 28 | RUN make install 29 | 30 | # Setup tests 31 | WORKDIR /root/code/test/ 32 | RUN make -j2 33 | 34 | CMD ["bash", "-c", "./run_all -v ; cat all.log | grep 'not ok' ; ./problems ; FAILED=$? ; echo timew $( timew --version ) ; python --version ; cmake --version ; gcc --version ; asciidoctor --version ; exit $FAILED"] 35 | -------------------------------------------------------------------------------- /test/docker/gentoo: -------------------------------------------------------------------------------- 1 | # Currently deactivated, see https://github.com/GothenburgBitFactory/timewarrior/issues/380 2 | # image is based on stage3-x86 3 | FROM gentoo/stage3-x86:latest 4 | 5 | # copy the entire portage volume in 6 | COPY --from=gentoo/portage:latest /var/db/repos/gentoo /var/db/repos/gentoo 7 | 8 | RUN ( CNT=60 ; while [[ ${CNT} -ne 0 ]] ; do echo "RUNNING (${CNT})" ; sleep 60 ; ((CNT--)) ; done ) & \ 9 | emerge -qv \ 10 | dev-util/cmake \ 11 | dev-vcs/git \ 12 | sys-devel/make \ 13 | sys-apps/man-db \ 14 | dev-lang/python \ 15 | dev-python/python-dateutil \ 16 | sys-libs/readline:0 \ 17 | sys-apps/util-linux ; \ 18 | kill %1 19 | 20 | # Setup environment 21 | ENV LC_ALL en_US.UTF-8 22 | ENV LANG en_US.UTF-8 23 | ENV LANGUAGE en_US.UTF-8 24 | 25 | # Setup timewarrior 26 | ADD . /root/code/ 27 | WORKDIR /root/code/ 28 | RUN git clean -dfx 29 | RUN git submodule init 30 | RUN git submodule update 31 | RUN cmake -DCMAKE_BUILD_TYPE=debug . 32 | RUN make -j2 33 | RUN make install 34 | 35 | # Setup tests 36 | WORKDIR /root/code/test/ 37 | RUN make -j2 38 | 39 | CMD ["bash", "-c", "./run_all -v ; cat all.log | grep 'not ok' ; ./problems ; FAILED=$? ; echo timew $( timew --version ) ; python --version ; cmake --version ; gcc --version ; exit $FAILED"] 40 | -------------------------------------------------------------------------------- /test/docker/opensuseleap: -------------------------------------------------------------------------------- 1 | FROM opensuse/leap 2 | 3 | RUN zypper install -y \ 4 | cmake \ 5 | coreutils \ 6 | gcc-c++ \ 7 | git \ 8 | make \ 9 | man \ 10 | python3 \ 11 | python3-python-dateutil \ 12 | ruby 13 | 14 | RUN gem install asciidoctor -v 2.0.17 15 | RUN update-alternatives --install /usr/bin/asciidoctor asciidoctor /usr/bin/asciidoctor.ruby2.5 10 16 | RUN update-alternatives --install /usr/bin/python python /usr/bin/python3 10 17 | ENV TZ=Europe/Berlin 18 | 19 | # Setup environment 20 | ENV LC_ALL en_US.UTF-8 21 | ENV LANG en_US.UTF-8 22 | ENV LANGUAGE en_US.UTF-8 23 | 24 | # Setup timewarrior 25 | ADD . /root/code/ 26 | WORKDIR /root/code/ 27 | RUN git clean -dfx 28 | RUN git submodule init 29 | RUN git submodule update 30 | RUN cmake -DCMAKE_BUILD_TYPE=debug . 31 | RUN make -j2 32 | RUN make install 33 | 34 | # Setup tests 35 | WORKDIR /root/code/test/ 36 | RUN make -j2 37 | 38 | CMD ["bash", "-c", "./run_all -v ; cat all.log | grep 'not ok' ; ./problems ; FAILED=$? ; echo timew $( timew --version ) ; python --version ; cmake --version ; gcc --version ; asciidoctor --version ; exit $FAILED"] 39 | -------------------------------------------------------------------------------- /test/docker/opensusetumbleweed: -------------------------------------------------------------------------------- 1 | FROM opensuse/tumbleweed 2 | 3 | RUN zypper install -y \ 4 | cmake \ 5 | gcc-c++ \ 6 | git \ 7 | man \ 8 | python3 \ 9 | python3-python-dateutil \ 10 | ruby \ 11 | ruby3.4-rubygem-asciidoctor 12 | 13 | RUN update-alternatives --install /usr/bin/python python /usr/bin/python3 10 14 | ENV TZ=Europe/Berlin 15 | 16 | # Setup environment 17 | ENV LC_ALL en_US.UTF-8 18 | ENV LANG en_US.UTF-8 19 | ENV LANGUAGE en_US.UTF-8 20 | 21 | # Setup timewarrior 22 | ADD . /root/code/ 23 | WORKDIR /root/code/ 24 | RUN git clean -dfx 25 | RUN git submodule init 26 | RUN git submodule update 27 | RUN cmake -DCMAKE_BUILD_TYPE=debug . 28 | RUN make -j2 29 | RUN make install 30 | 31 | # Setup tests 32 | WORKDIR /root/code/test/ 33 | RUN make -j2 34 | 35 | CMD ["bash", "-c", "./run_all -v ; cat all.log | grep 'not ok' ; ./problems ; FAILED=$? ; echo timew $( timew --version ) ; python --version ; cmake --version ; gcc --version ; asciidoctor --version ; exit $FAILED"] 36 | -------------------------------------------------------------------------------- /test/docker/ubuntu2204: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04 2 | 3 | ENV DEBIAN_FRONTEND noninteractive 4 | 5 | RUN apt-get update && yes | unminimize 6 | RUN apt-get install -y \ 7 | asciidoctor \ 8 | cmake \ 9 | g++ \ 10 | git \ 11 | locales \ 12 | man \ 13 | man-db \ 14 | python3 \ 15 | python3-dateutil \ 16 | tzdata 17 | 18 | # Setup environment 19 | RUN update-alternatives --install /usr/bin/python python /usr/bin/python3 10 20 | RUN ln -fs /usr/share/zoneinfo/Europe/Berlin /etc/localtime 21 | RUN dpkg-reconfigure -f noninteractive tzdata 22 | 23 | ENV LC_ALL en_US.UTF-8 24 | ENV LANG en_US.UTF-8 25 | ENV LANGUAGE en_US.UTF-8 26 | RUN locale-gen "en_US.UTF-8" 27 | 28 | # Setup timewarrior 29 | ADD . /root/code/ 30 | WORKDIR /root/code/ 31 | RUN git clean -dfx 32 | RUN git submodule init 33 | RUN git submodule update 34 | RUN cmake -DCMAKE_BUILD_TYPE=debug . 35 | RUN make -j2 36 | RUN make install 37 | 38 | # Setup tests 39 | WORKDIR /root/code/test/ 40 | RUN make -j2 41 | 42 | CMD ["bash", "-c", "./run_all -v ; cat all.log | grep 'not ok' ; ./problems ; FAILED=$? ; echo timew $( timew --version ) ; python --version ; cmake --version ; gcc --version ; asciidoctor --version ; exit $FAILED"] 43 | -------------------------------------------------------------------------------- /test/docker/ubuntu2404: -------------------------------------------------------------------------------- 1 | FROM ubuntu:24.04 2 | 3 | ENV DEBIAN_FRONTEND noninteractive 4 | 5 | RUN apt-get update 6 | RUN apt-get install -y \ 7 | asciidoctor \ 8 | cmake \ 9 | g++ \ 10 | git \ 11 | locales \ 12 | man \ 13 | man-db \ 14 | python3 \ 15 | python3-dateutil \ 16 | tzdata 17 | 18 | # Setup environment 19 | RUN update-alternatives --install /usr/bin/python python /usr/bin/python3 10 20 | RUN ln -fs /usr/share/zoneinfo/Europe/Berlin /etc/localtime 21 | RUN dpkg-reconfigure -f noninteractive tzdata 22 | 23 | ENV LC_ALL en_US.UTF-8 24 | ENV LANG en_US.UTF-8 25 | ENV LANGUAGE en_US.UTF-8 26 | RUN locale-gen "en_US.UTF-8" 27 | 28 | # Setup timewarrior 29 | ADD . /root/code/ 30 | WORKDIR /root/code/ 31 | RUN git clean -dfx 32 | RUN git submodule init 33 | RUN git submodule update 34 | RUN cmake -DCMAKE_BUILD_TYPE=debug . 35 | RUN make -j2 36 | RUN make install 37 | 38 | # Setup tests 39 | WORKDIR /root/code/test/ 40 | RUN make -j2 41 | 42 | CMD ["bash", "-c", "./run_all -v ; cat all.log | grep 'not ok' ; ./problems ; FAILED=$? ; echo timew $( timew --version ) ; python --version ; cmake --version ; gcc --version ; asciidoctor --version ; exit $FAILED"] 43 | -------------------------------------------------------------------------------- /test/gaps.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | ############################################################################### 4 | # 5 | # Copyright 2016 - 2019, 2022 Thomas Lauf, Paul Beckingham, Federico Hernandez. 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included 15 | # in all copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. 24 | # 25 | # https://www.opensource.org/licenses/mit-license.php 26 | # 27 | ############################################################################### 28 | 29 | import os 30 | import sys 31 | import unittest 32 | from datetime import time 33 | 34 | # Ensure python finds the local simpletap module 35 | sys.path.append(os.path.dirname(os.path.abspath(__file__))) 36 | 37 | from basetest import Timew, TestCase 38 | 39 | 40 | class TestGaps(TestCase): 41 | def setUp(self): 42 | """Executed before each test in the class""" 43 | self.t = Timew() 44 | 45 | def test_trivial_gaps(self): 46 | """Test trivial gaps""" 47 | code, out, err = self.t("gaps") 48 | self.assertRegex(out, r'\s{30}24:00:00') 49 | 50 | def test_single_unobstructed_interval(self): 51 | """Add one interval and export it as-is""" 52 | self.t("track 20160527T080000 - 20160527T200000 foo") 53 | 54 | code, out, err = self.t("gaps 2016-05-27 - 2016-05-28") 55 | self.assertRegex(out, r'\s{30}12:00:00') 56 | 57 | def test_single_unobstructed_interval_with_exclusions(self): 58 | """Add one interval, with exclusions""" 59 | self.t.configure_exclusions((time(18, 0, 0), time(9, 0, 0))) 60 | 61 | self.t("track 20160527T100000 - 20160527T140000 foo") 62 | 63 | code, out, err = self.t("gaps 2016-05-27 - 2016-05-28") 64 | self.assertRegex(out, r'\s{30}5:00:00') 65 | 66 | 67 | if __name__ == "__main__": 68 | from simpletap import TAPTestRunner 69 | 70 | unittest.main(testRunner=TAPTestRunner()) 71 | -------------------------------------------------------------------------------- /test/ids.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | ############################################################################### 4 | # 5 | # Copyright 2016 - 2019, Thomas Lauf, Paul Beckingham, Federico Hernandez. 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included 15 | # in all copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. 24 | # 25 | # https://www.opensource.org/licenses/mit-license.php 26 | # 27 | ############################################################################### 28 | 29 | import os 30 | import sys 31 | import unittest 32 | 33 | # Ensure python finds the local simpletap module 34 | sys.path.append(os.path.dirname(os.path.abspath(__file__))) 35 | 36 | from basetest import Timew, TestCase 37 | 38 | 39 | class TestIds(TestCase): 40 | def setUp(self): 41 | """Executed before each test in the class""" 42 | self.t = Timew() 43 | 44 | def test_ids_in_output(self): 45 | self.t("start a 10s ago") 46 | self.t("start b") 47 | code, out, err = self.t("summary :week :ids") 48 | self.assertIn(' @1 ', out) 49 | self.assertIn(' @2 ', out) 50 | 51 | def test_latest_interval_included_when_empty(self): 52 | """Count IDs when the last interval is empty 53 | Include the last interval in getTracked() even if it is a 54 | zero-width interval and there are other, earlier intervals. 55 | """ 56 | self.t("track 2018-01-01 - 2018-01-01") 57 | self.t("track 2018-01-02 - 2018-01-02") 58 | code, out, err = self.t("move @2 2018-01-03") 59 | self.assertIn('Moved @2 to 2018-01-03T00:00:00', out) 60 | 61 | def test_should_fail_on_zero_id(self): 62 | code, out, err = self.t.runError("delete @0") 63 | self.assertIn("'@0' is not a valid ID.", err) 64 | 65 | 66 | if __name__ == "__main__": 67 | from simpletap import TAPTestRunner 68 | 69 | unittest.main(testRunner=TAPTestRunner()) 70 | -------------------------------------------------------------------------------- /test/performance-plot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | 5 | import argparse 6 | import matplotlib.pyplot as plt 7 | import numpy as np 8 | 9 | parser = argparse.ArgumentParser(description='Display performance plots.') 10 | parser.add_argument('output_dir', help='directory containing the measurement files') 11 | parser.add_argument('commands', nargs='*', type=str) 12 | 13 | args = parser.parse_args() 14 | 15 | output_directory = args.output_dir 16 | commands = args.commands 17 | 18 | plt.axes([0.1, 0.1, 0.6, 0.75]) 19 | plt.xlabel("# database entries") 20 | plt.ylabel("time [s]") 21 | plt.title(output_directory) 22 | 23 | for filename in os.listdir(output_directory): 24 | if filename.endswith(".log"): 25 | cmd = "-".join(filename.split('-')[1:-1]) 26 | else: 27 | continue 28 | 29 | if len(commands) == 0 or cmd in commands: 30 | try: 31 | x, y = np.loadtxt(os.path.join(output_directory, filename), 32 | delimiter='\t', 33 | usecols=(1, 2), 34 | unpack=True) 35 | plt.plot(x, y, label=cmd, marker=".", linestyle='-') 36 | except ValueError as e: 37 | print("Invalid file: {} {}".format(filename, e)) 38 | 39 | plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0., ncol=2) 40 | plt.show() 41 | -------------------------------------------------------------------------------- /test/quiet.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | ############################################################################### 4 | # 5 | # Copyright 2016 - 2019, Thomas Lauf, Paul Beckingham, Federico Hernandez. 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included 15 | # in all copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. 24 | # 25 | # https://www.opensource.org/licenses/mit-license.php 26 | # 27 | ############################################################################### 28 | 29 | import os 30 | import sys 31 | import unittest 32 | 33 | # Ensure python finds the local simpletap module 34 | sys.path.append(os.path.dirname(os.path.abspath(__file__))) 35 | 36 | from basetest import Timew, TestCase 37 | 38 | 39 | class TestQuietMode(TestCase): 40 | def setUp(self): 41 | """Executed before each test in the class""" 42 | self.t = Timew() 43 | 44 | def test_default(self): 45 | """Default command should obey :quiet hint""" 46 | code, out, err = self.t.runError("") 47 | self.assertIn('There is no active time tracking.', out) 48 | 49 | code, out, err = self.t.runError(":quiet") 50 | self.assertNotIn('There is no active time tracking.', out) 51 | 52 | def test_stop(self): 53 | """Stop command should error on no active tracking""" 54 | code, out, err = self.t.runError("stop") 55 | self.assertIn('There is no active time tracking.', err) 56 | 57 | 58 | if __name__ == "__main__": 59 | from simpletap import TAPTestRunner 60 | 61 | unittest.main(testRunner=TAPTestRunner()) 62 | -------------------------------------------------------------------------------- /test/rules.t.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2015 - 2019, 2022, Thomas Lauf, Paul Beckingham, Federico Hernandez. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | // 23 | // https://www.opensource.org/licenses/mit-license.php 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | #include 28 | #include 29 | 30 | //////////////////////////////////////////////////////////////////////////////// 31 | int main (int, char**) 32 | { 33 | UnitTest t (8); 34 | 35 | Rules r; 36 | r.set ("string", "234"); 37 | t.is (r.get ("string"), "234", "Rules set string, get string"); 38 | t.is (r.getInteger ("string"), 234, "Rules set string, get string"); 39 | 40 | // Throws on error. 41 | r.set ("undefined", "foo"); 42 | try {r.getInteger ("undefined", -1); t.fail ("Rules set non-int string, get 0");} 43 | catch (...) {t.pass ("Rules set non-int string, get 0");} 44 | 45 | t.is (r.getBoolean ("undefined"), false, "Rules set non-bool string, get false"); 46 | 47 | r.set ("integer", 123); 48 | t.is (r.getInteger ("integer"), 123, "Rules set integer, get integer"); 49 | t.is (r.get ("integer"), "123", "Rules set integer, get string"); 50 | 51 | r.set ("one.two", 12); 52 | r.set ("one.two.three", 123); 53 | r.set ("one.two.four", 124); 54 | t.ok ((int) r.all ().size () > 30, "Rules all (\"\") --> >30"); 55 | t.ok (r.all ("one.two").size () == 3, "Rules all (\"one.two\") --> 3"); 56 | 57 | return 0; 58 | } 59 | 60 | //////////////////////////////////////////////////////////////////////////////// 61 | 62 | -------------------------------------------------------------------------------- /test/scripts/test_osx.sh: -------------------------------------------------------------------------------- 1 | set -x 2 | 3 | brew install pyenv 4 | brew install asciidoctor 5 | 6 | export PYTHON_VERSION="3.10.16" 7 | export PYENV_ROOT="$HOME/.pyenv" 8 | export PATH="${PYENV_ROOT}/bin:${PATH}" 9 | eval "$( pyenv init --path )" 10 | pyenv install "${PYTHON_VERSION}" 11 | pyenv global "${PYTHON_VERSION}" 12 | pip install --upgrade pip 13 | pip install python-dateutil 14 | 15 | git clean -dfx 16 | git submodule init 17 | git submodule update 18 | cmake -DCMAKE_BUILD_TYPE=debug . 19 | make -j2 20 | make install 21 | 22 | pushd test || exit 23 | make 24 | ./run_all -v 25 | set +x 26 | grep 'not ok' all.log 27 | ./problems 28 | EXIT_CODE=$? 29 | echo "timew $( timew --version )" 30 | asciidoctor --version 31 | python --version 32 | cmake --version 33 | clang --version 34 | exit ${EXIT_CODE} 35 | -------------------------------------------------------------------------------- /test/test_extensions/debug.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import sys 4 | 5 | for line in sys.stdin: 6 | # skip configuration 7 | if line == "\n": 8 | break 9 | 10 | for line in sys.stdin: 11 | print(line.strip()) 12 | -------------------------------------------------------------------------------- /test/test_extensions/ext_echo: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | echo "test works" 3 | -------------------------------------------------------------------------------- /test/version.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | ############################################################################### 4 | # 5 | # Copyright 2016 - 2021, Thomas Lauf, Paul Beckingham, Federico Hernandez. 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included 15 | # in all copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. 24 | # 25 | # https://www.opensource.org/licenses/mit-license.php 26 | # 27 | ############################################################################### 28 | 29 | import os 30 | import sys 31 | import unittest 32 | 33 | # Ensure python finds the local simpletap module 34 | sys.path.append(os.path.dirname(os.path.abspath(__file__))) 35 | 36 | from basetest import Timew, TestCase 37 | 38 | 39 | class TestVersion(TestCase): 40 | def setUp(self): 41 | self.t = Timew() 42 | 43 | def test_version_option(self): 44 | """Verify that 'timew --version' returns something valid""" 45 | code, out, err = self.t("--version") 46 | self.assertRegex(out, r'^\d\.\d+\.\d+(-\w+)?$') 47 | 48 | 49 | if __name__ == "__main__": 50 | from simpletap import TAPTestRunner 51 | 52 | unittest.main(testRunner=TAPTestRunner()) 53 | --------------------------------------------------------------------------------