Merge branch 'develop' into 2.4-dayone-fixes

This commit is contained in:
MinchinWeb 2020-05-30 18:32:19 -06:00 committed by GitHub
commit 70e7d59396
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
52 changed files with 1133 additions and 442 deletions

View file

@ -59,6 +59,6 @@ git config --global user.email "jrnl.bot@gmail.com"
git config --global user.name "Jrnl Bot"
git checkout $BRANCH
git add "$FILENAME"
git commit -m "Updating changelog [ci skip]"
git commit -m "Update changelog [ci skip]"
git push https://${GITHUB_TOKEN}@github.com/jrnl-org/jrnl.git $BRANCH

36
.build/gitlab-ci.yml Normal file
View file

@ -0,0 +1,36 @@
# This file is a template, and might need editing before it works on your project.
# Official language image. Look for the different tagged releases at:
# https://hub.docker.com/r/library/python/tags/
image: python:latest
# Change pip's cache directory to be inside the project directory since we can
# only cache local items.
variables:
PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
# Pip's cache doesn't store the python packages
# https://pip.pypa.io/en/stable/reference/pip_install/#caching
#
# If you want to also cache the installed packages, you have to install
# them in a virtualenv and cache it as well.
cache:
paths:
- .cache/pip
before_script:
- python -V # Print out python version for debugging
- pip install poetry
release:
rules:
- if: $RELEASE != null
script:
- git config --global user.email "jrnl.bot@gmail.com"
- git config --global user.name "Jrnl Bot"
- git checkout "$CI_COMMIT_BRANCH"
- poetry version "$RELEASE"
- echo __version__ = \"$RELEASE\" > jrnl/__version__.py
- git add pyproject.toml jrnl/__version__.py
- git commit -m "Increment version to ${RELEASE}"
- git tag -a -m "$RELEASE" "$RELEASE"
- git push --follow-tags "https://${GITHUB_TOKEN}@github.com/jrnl-org/jrnl.git" "$CI_COMMIT_BRANCH"

2
.gitattributes vendored Normal file
View file

@ -0,0 +1,2 @@
*.journal text eol=lf
*.feature text eol=lf

View file

@ -7,20 +7,36 @@ assignees: ''
---
## Bug report
## Bug Report
<!--
Hello, and thank you for reporting an issue!
Please fill out the points below, as it will make our process much easier.
-->
Hello! Thank you for reporting an issue!
If you would fill out the below points, that would make our process a whole lot easier!
<!-- Please tell us about your environment -->
### Environment
- Jrnl version: <!-- Run `jrnl -v` -->
- Install method: <!-- How did you install jrnl? (pipx, brew, etc) -->
- OS <!-- What is your operating system? (MacOS, Linux, Windows) -->
* **Please tell us about your environment:**
- Jrnl version: (run `jrnl -v`)
- How you installed Jrnl
- Operating system [MacOS, Linux, Windows?]
### Current Behavior
<!--
Please put a short description of what is currently happening.
-->
* **What is the current behavior?**
### Expected Behavior
<!--
Please write a short description of what you would expect to happen
(instead of what is currently happening).
-->
* **Please provide the steps to reproduce and if possible a minimal demo of the problem**
### Repro Steps
<!--
Please provide the steps to reproduce the problem. It is important for you to
be as precise as possible here, since more info will let us help you faster.
-->
* **What is the expected behavior?**
* **Other information** (e.g. detailed explanation, stacktraces, related issues, suggestions how to fix, links for us to have context, eg. stackoverflow, gitter, etc)
### Other Information
<!-- (e.g. more detailed explanation, stacktraces, related
issues, suggestions how to fix, links for us to have context, eg.
stackoverflow, gitter, etc) -->

View file

@ -8,12 +8,24 @@ assignees: ''
---
## Feature Request
<!--
Hello, and thank you for reporting an issue!
Please fill out the points below, as it will make our process much easier.
-->
Hello! Thank you for reporting an issue!
If you would fill out the below points, that would make our process a whole lot easier!
### Use Case/Motivation
<!--
What is the motivation / use case for changing the behavior?
-->
* **What is the motivation / use case for changing the behavior?**
### Example Usage
<!--
Please provide examples of the usage you would like to see.
e.g `jrnl --new-flag="super cool new feature"`
-->
* **Please provide examples of the usage**
* **Other information** (e.g. detailed explanation, stacktraces, related issues, suggestions how to fix, links for us to have context, eg. stackoverflow, gitter, etc)
### Other information
<!--
Please provide any other relevant info about this request (e.g. stacktraces,
related issues, suggestions how to fix, etc)
-->

View file

@ -7,20 +7,33 @@ assignees: ''
---
## Support request
## Support Request
<!--
Hello, and thank you for reporting an issue!
Please fill out the points below, as it will make our process much easier.
-->
Hello! Thank you for reporting an issue!
If you would fill out the below points, that would make our process a whole lot easier!
### Environment
<!--
Please tell us about your environment
-->
- Jrnl version: <!-- Run `jrnl -v` -->
- Install method: <!-- How did you install jrnl? (pipx, brew, etc) -->
- OS <!-- What is your operating system? (MacOS, Linux, Windows) -->
* **Please tell us about your environment:**
### What are you trying to do?
<!--
Please write a short description of what is happening.
-->
- Jrnl version: (run `jrnl -v`)
- How you installed Jrnl
### What have you tried?
<!--
Have you tried anything to fix the problem? This can help give us more
information to help you with.
-->
- Operating system [MacOS, Linux, Windows?]
* **What are you trying to do?**
* **What have you tried?**
* **Other information** (e.g. detailed explanation, stacktraces, related issues, suggestions how to fix, links for us to have context, eg. stackoverflow, gitter, etc)
### Other Information
<!--
Is there anything else we should know that might be helpful?
e.g. detailed explanation, stacktraces, related issues, suggestions how to fix
-->

View file

@ -1,19 +1,26 @@
<!--
Thank you for wanting to contribute!
# **TEMPLATE PLEASE EDIT**
*Thank you for wanting to contribute! Please fill out this description as well as look at the checklist!*
Please fill out this description, and the checklist below.
Here are some key points to include in your description:
- What is this new code intended to do?
- Are there any related issues?
- What is the motivation for this change?
- What is an example of usage, or changes to config files? (if applicable)
-->
*Short block of text containing:
- Relevant changes in text form
- related issues
- Motivation (if applicable)
- Example of usage (if applicable)
- Example of changes to config files (if applicable)
*
### Checklist
- [ ] The code change is tested and works locally.
- [ ] Tests pass. Your PR cannot be merged unless tests pass
- [ ] There is no commented out code in this PR.
- [ ] Have you followed the guidelines in our Contributing document?
- [ ] Have you checked to ensure there aren't other open [Pull Requests](../pulls) for the same update/change?
- [ ] Have you added an explanation of what your changes do and why you'd like us to include them?
- [ ] Have you written new tests for your core changes, as applicable?
- [ ] I have read the [contributing doc](https://github.com/jrnl-org/jrnl/blob/develop/CONTRIBUTING.md).
- [ ] I have included a link to the relevant issue number.
- [ ] I have tested this code locally.
- [ ] I have checked to ensure there aren't other open [pull requests](../pulls)
for the same issue.
- [ ] I have you written new tests for these changes, as needed.
- [ ] All tests pass.
<!--
NOTE: Your PR may not be reviewed if there are any failing tests. You can run
tests locally with `make test` (see the contributing doc if you need help with
`make`), or use our automated tests after you submit your PR.
-->

39
.github/lock.yml vendored Normal file
View file

@ -0,0 +1,39 @@
# Configuration for Lock Threads - https://github.com/dessant/lock-threads-app
# Number of days of inactivity before a closed issue or pull request is locked
daysUntilLock: 90
# Skip issues and pull requests created before a given timestamp. Timestamp must
# follow ISO 8601 (`YYYY-MM-DD`). Set to `false` to disable
skipCreatedBefore: false
# Issues and pull requests with these labels will be ignored. Set to `[]` to disable
exemptLabels: []
# Label to add before locking, such as `outdated`. Set to `false` to disable
lockLabel: ':lock:'
# Comment to post before locking. Set to `false` to disable
lockComment: >
This thread has been automatically locked since there has not been
any recent activity after it was closed. Please open a new issue for
related bugs. You can link back here from your new issue to continue
the conversation.
# Assign `resolved` as the reason for locking. Set to `false` to disable
setLockReason: true
# Limit to only `issues` or `pulls`
# only: issues
# Optionally, specify configuration settings just for `issues` or `pulls`
# issues:
# exemptLabels:
# - help-wanted
# lockLabel: outdated
# pulls:
# daysUntilLock: 30
# Repository to extend settings from
# _extends: repo

View file

@ -129,19 +129,9 @@ jobs:
env:
TZ: America/Edmonton
# Changelog for Unreleased changes
- stage: Update Changelog
if: (tag IS present) OR (branch = develop AND type NOT IN (pull_request))
install:
- echo 'Skipping install'
script:
- ./.build/generate_changelog.sh
- stage: Deploy
if: tag IS present
before_deploy:
- poetry version "$TRAVIS_TAG"
- echo __version__ = \"$TRAVIS_TAG\" > jrnl/__version__.py
- poetry build
script:
- echo "Deployment starting..."
@ -150,12 +140,13 @@ jobs:
script: poetry publish
skip_cleanup: true
on:
branch: master
tags: true
after_deploy:
- git config --global user.email "jrnl.bot@gmail.com"
- git config --global user.name "Jrnl Bot"
- git checkout master
- git add pyproject.toml jrnl/__version__.py
- git commit -m "Incrementing version to ${TRAVIS_TAG} [ci skip]"
- git push https://${GITHUB_TOKEN}@github.com/jrnl-org/jrnl.git master
all_branches: true
# Changelog for Unreleased changes
- stage: Update Changelog
if: (tag IS present) OR (branch = develop AND type NOT IN (pull_request))
install:
- echo 'Skipping installation step'
script:
- ./.build/generate_changelog.sh

View file

@ -21,25 +21,59 @@
## [Unreleased](https://github.com/jrnl-org/jrnl/)
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.3.1...HEAD)
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.4.2...HEAD)
**Implemented enhancements:**
- Upgrade license to GPLv3 [\#918](https://github.com/jrnl-org/jrnl/pull/918) ([wren](https://github.com/wren))
- Speed up jrnl by 10%, improve slow imports [\#959](https://github.com/jrnl-org/jrnl/pull/959) ([wotgl](https://github.com/wotgl))
**Fixed bugs:**
- Fix title splitting logic to account for both newlines and periods [\#958](https://github.com/jrnl-org/jrnl/pull/958) ([eshrh](https://github.com/eshrh))
- Fix editor config when an argument with a space is used [\#953](https://github.com/jrnl-org/jrnl/pull/953) ([wren](https://github.com/wren))
- Ask for password before adding entry instead of after [\#951](https://github.com/jrnl-org/jrnl/pull/951) ([ollybritton](https://github.com/ollybritton))
- Fix duplicate text in multiple tag search [\#948](https://github.com/jrnl-org/jrnl/pull/948) ([micahellison](https://github.com/micahellison))
**Build:**
- Update makefile to match pipeline better [\#919](https://github.com/jrnl-org/jrnl/pull/919) ([wren](https://github.com/wren))
- Fix for hanging Windows tests on Travis [\#969](https://github.com/jrnl-org/jrnl/pull/969) ([wren](https://github.com/wren))
- Ensure test data is always checked out with LF line endings [\#965](https://github.com/jrnl-org/jrnl/pull/965) ([micahellison](https://github.com/micahellison))
- Update lockbot comment to encourage linking to issue [\#941](https://github.com/jrnl-org/jrnl/pull/941) ([MinchinWeb](https://github.com/MinchinWeb))
**Updated documentation:**
- Docs: editing config isn't always destructive [\#923](https://github.com/jrnl-org/jrnl/pull/923) ([Epskampie](https://github.com/Epskampie))
- Cleaned up usage.md for clarity, formatting, and grammar. [\#956](https://github.com/jrnl-org/jrnl/pull/956) ([guydebros](https://github.com/guydebros))
# Changelog
## [v2.4.2](https://pypi.org/project/jrnl/v2.4.2/) (2020-05-09)
## [Unreleased](https://github.com/jrnl-org/jrnl/)
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.4.1...v2.4.2)
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.3.1...HEAD)
**Fixed bugs:**
- Prevent filtered delete from deleting journal [\#935](https://github.com/jrnl-org/jrnl/pull/935) ([micahellison](https://github.com/micahellison))
**Build:**
- Make sure testing cleans up after itself [\#940](https://github.com/jrnl-org/jrnl/pull/940) ([wren](https://github.com/wren))
- Allow most recent pytz version and update dependencies [\#937](https://github.com/jrnl-org/jrnl/pull/937) ([micahellison](https://github.com/micahellison))
- Use gitlab to trigger releases in pipeline [\#947](https://github.com/jrnl-org/jrnl/pull/947) ([wren](https://github.com/wren))
**Updated documentation:**
- Change jrnl.sh GitHub new issue link to issue template chooser [\#936](https://github.com/jrnl-org/jrnl/pull/936) ([micahellison](https://github.com/micahellison))
- Improve privacy, security, and encryption documentation \#896 [\#925](https://github.com/jrnl-org/jrnl/pull/925) ([micahellison](https://github.com/micahellison))
## [v2.4.1](https://pypi.org/project/jrnl/v2.4.1/) (2020-05-02)
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.4...v2.4.1)
**Fixed bugs:**
- Disable --delete due to critical bug [\#934](https://github.com/jrnl-org/jrnl/pull/934) ([wren](https://github.com/wren))
## [v2.4](https://pypi.org/project/jrnl/v2.4/) (2020-04-25)
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.3.1...v2.4)
**Implemented enhancements:**
@ -67,6 +101,8 @@
- Update twitter buttons, contribution in footer [\#905](https://github.com/jrnl-org/jrnl/pull/905) ([wren](https://github.com/wren))
- Change install doc guideline from pip to pipx [\#904](https://github.com/jrnl-org/jrnl/pull/904) ([micahellison](https://github.com/micahellison))
- Update twitter buttons, contribution in footer [\#905](https://github.com/jrnl-org/jrnl/pull/905) ([wren](https://github.com/wren))
- Clean up readme file [\#924](https://github.com/jrnl-org/jrnl/pull/924) ([wren](https://github.com/wren))
- Clarify that editing config isn't always destructive [\#923](https://github.com/jrnl-org/jrnl/pull/923) ([Epskampie](https://github.com/Epskampie))
## [v2.3](https://pypi.org/project/jrnl/v2.3/) (2020-03-21)

View file

@ -31,40 +31,20 @@ your journal.
If you dont initially store the password in the keychain but decide to
do so at a later point or maybe want to store it on one computer but
not on another you can simply run `jrnl --encrypt` on an encrypted
not on another you can run `jrnl --encrypt` on an encrypted
journal and use the same password again.
## A note on security
While jrnl follows best practises, true security is an illusion.
Specifically, jrnl will leave traces in your memory and your shell
history its meant to keep journals secure in transit, for example
when storing it on an
[untrusted](http://techcrunch.com/2014/04/09/condoleezza-rice-joins-dropboxs-board/)
services such as Dropbox. If youre concerned about security, disable
history logging for journal in your `.bashrc`:
While `jrnl` follows best practices, total security is an illusion.
There are a number of ways that people can at least partially
compromise your `jrnl` data. See the [Privacy and Security](./security.md)
documentation for more information.
``` sh
HISTIGNORE="$HISTIGNORE:jrnl *"
```
## No password recovery
If you are using zsh instead of bash, you can get the same behaviour by
adding this to your `zshrc`:
``` sh
setopt HIST_IGNORE_SPACE
alias jrnl=" jrnl"
```
If you are using `fish` instead of `bash` or `zsh`, you can get the same behaviour by
adding this to your `fish` configuration:
``` sh
abbr --add jrnl " jrnl"
```
To delete existing `jrnl` commands from `fish`s history, run
`history delete --prefix 'jrnl '`.
There is no method to recover or reset your `jrnl` password. If you lose it,
your data is inaccessible.
## Manual decryption

View file

@ -73,7 +73,7 @@ jrnlimport () {
!!! note
Templates require an [external editor](./advanced.md) be configured.
A template is a code snippet that makes it easier to enter use repeated text
A template is a code snippet that makes it easier to use repeated text
each time a new journal entry is started. There are two ways you can utilize
templates in your entries.

74
docs/security.md Normal file
View file

@ -0,0 +1,74 @@
# Privacy and Security
`jrnl` is designed with privacy and security in mind, but there are some
limitations to be aware of.
## Password strength
`jrnl` doesn't enforce password strength requirements. Short or commonly-used
passwords can easily be circumvented by someone with basic security skills
and access to your encrypted `jrnl` file.
## Shell history
Since you can enter entries from the command line, any tool
that logs command line actions is a potential security risk. See
below for how to deal with this problem in various shells.
### bash
You can disable history logging for jrnl in your `.bashrc`:
``` sh
HISTIGNORE="$HISTIGNORE:jrnl *"
```
### zsh
Disable history logging by adding this to your `zshrc`:
``` sh
setopt HIST_IGNORE_SPACE
alias jrnl=" jrnl"
```
### fish
Add this abbreviation to your `fish` configuration to run jrnl with
a space before it, which prevents `fish` from logging it:
``` sh
abbr --add jrnl " jrnl"
```
To delete existing `jrnl` commands from `fish`s history, run
`history delete --prefix 'jrnl '`.
### Windows Command Prompt
Windows doesn't log history to disk, but it does keep it in your command
prompt session. Close the command prompt or press Alt+F7 to clear its
history after journaling.
## Files in transit from editor to jrnl
When creating or editing an entry, `jrnl` uses a plain text temporary file on disk
to give your editor access to it. `jrnl` deletes the temporary file when it
saves the entry back to your journal.
If you save an entry but haven't closed your editor yet, and your computer shuts
off or the `jrnl` process is killed, the entry remains on your disk as a
temporary file. You can mitigate this issue by only saving with your editor
right before closing it.
## Plausible deniability
You may be able to hide the contents of your journal behind a layer of encryption,
but if someone has access to your configuration file, then they can figure out that
you have a journal, where that journal file is, and when you last edited it.
With a sufficient power imbalance, someone may be able to force you to unencrypt
it through non-technical means.
## Notice any other risks?
Please let the maintainers know by [filing an issue on GitHub](https://github.com/jrnl-org/jrnl/issues).

View file

@ -95,7 +95,7 @@
</div>
</main>
<footer>
jrnl is made with love by <a href="https://github.com/jrnl-org/jrnl/graphs/contributors" title="Contributors">many fabulous people</a>. If you need help, <a href="https://github.com/jrnl-org/jrnl/issues/new" title="Open a new issue on Github">submit an issue</a> on Github.
jrnl is made with love by <a href="https://github.com/jrnl-org/jrnl/graphs/contributors" title="Contributors">many fabulous people</a>. If you need help, <a href="https://github.com/jrnl-org/jrnl/issues/new/choose" title="Open a new issue on Github">submit an issue</a> on Github.
</footer>
<script src="//cdnjs.cloudflare.com/ajax/libs/typed.js/2.0.10/typed.min.js"></script>
<script>

View file

@ -1,56 +1,44 @@
# Basic Usage
# Basic Usage #
`jrnl` has two modes: **composing** and **viewing**. Basically, whenever
you _don't_ supply any arguments that start
with a dash or double-dash, you're in composing mode, meaning you can
write your entry on the command line or an editor of your choice.
`jrnl` has two modes: **composing** and **viewing**. Whenever you don't enter
any arguments that start with a dash (`-`) or double-dash (`--`), you're in
composing mode, meaning that you can write your entry on the command line.
We intentionally break a convention on command line arguments: all
arguments starting with a _single dash_
will _filter_ your journal before viewing
it, and can be combined arbitrarily. Arguments with a
_double dash_ will control how your journal
is displayed or exported and are mutually exclusive (ie. you can only
specify one way to display or export your journal at a time).
We intentionally break a convention on command line arguments: all arguments
starting with a _single dash_ (`-`) will _filter_ your journal before viewing
it. Filter arguments can be combined arbitrarily. Arguments with a _double dash_
(`--`) will _control_ how your journal is displayed or exported. Control
arguments are mutually exclusive (i.e., you can only specify one way to display
or export your journal at a time).
## Listing Journals
## Composing Entries ##
You can list the journals accessible by jrnl
Composing mode is entered by either starting `jrnl` without any arguments --
which will launch an external editor -- or by just writing an entry on the
command line:
```sh
jrnl -ls
```
The journals displayed correspond to those specified in the jrnl
configuration file.
## Composing Entries
Composing mode is entered by either starting `jrnl` without any
arguments -- which will prompt you to write an entry or launch your
editor -- or by just writing an entry on the prompt, such as
```sh
jrnl today at 3am: I just met Steve Buscemi in a bar! He looked funny.
jrnl today at 3am: I just met Steve Buscemi in a bar! What a nice guy.
```
!!! note
Most shell contains a certain number of reserved characters, such as `#`
and `*`. Unbalanced quotes, parenthesis, and so on will also get into
the way of your editing.
For writing longer entries, just enter `jrnl`
and hit `return`. Only then enter the text of your journal entry.
Alternatively, `use an external editor <advanced>`).
Most shells contain a certain number of reserved characters, such as `#` and
`*`. These characters, as well as unbalanced single or double quotation
marks, parentheses, and others, likely will cause problems. Although
reserved characters can be escaped using `\`, this is not ideal for
long-form writing. The solution: first enter `jrnl` and hit `return`. You
can then enter the text of your journal entry. Alternatively, you can [use
an external editor](./advanced.md)).
You can also import an entry directly from a file
You can also import an entry directly from a file:
```sh
jrnl < my_entry.txt
```
### Smart timestamps
### Specifying Date and Time ###
Timestamps that work:
If you don't specify a date and time (e.g., `jrnl finished writing letter to brother`), `jrnl` will create an entry using the current date and time. For retrospective entries, you can use a timestamp to tell `jrnl` where to put the entry. Timestamps can be entered using a variety of formats. Here are some that work:
- at 6am
- yesterday
@ -59,102 +47,188 @@ Timestamps that work:
- 2 march 2012
- 7 apr
- 5/20/1998 at 23:42
- 2020-05-22T15:55-04:00
### Starring entries
If you don't use a timestamp, `jrnl` will create an entry using the current
time. If you use a date only (no time), `jrnl` will use the default time
specified in your configuration file (see [advanced usage](./advanced.md)).
Behind the scenes, `jrnl` reorganizes entries in chronological order.
To mark an entry as a favourite, simply "star" it
### Using Tags ###
`jrnl` supports tags. Note that because `#` is a reserved character, the default
tag symbol is `@`. You can specify your own tag symbol in the configuration
file. There is no limit to how many tags you can use in an entry. To use tags,
simply preface the desired tag with the symbol:
```sh
jrnl Had a wonderful day at the @beach with @Tom and @Anna.
```
Although you can use capitals while tagging an entry, searches by tag are
case-insensitive.
### Starring Entries ###
To mark an entry as a favorite, simply "star" it using an asterisk (`*`):
```sh
jrnl last sunday *: Best day of my life.
```
If you don't want to add a date (ie. your entry will be dated as now),
The following options are equivalent:
If you don't want to add a date (i.e., you want the date to be entered as
_now_), the following options are equivalent:
- `jrnl *: Best day of my life.`
- `jrnl *Best day of my life.`
- `jrnl Best day of my life.*`
!!! note
Just make sure that the asterisk sign is **not** surrounded by
whitespaces, e.g. `jrnl Best day of my life! *` will **not** work (the
reason being that the `*` sign has a special meaning on most shells).
!!! note Make sure that the asterisk (`*`) is **not** surrounded by whitespaces.
`jrnl Best day of my life! *` will not work because the `*` character has a
special meaning in most shells.
## Viewing
## Viewing Entries ##
`jrnl` can display entries in a variety of ways. Entries are filtered using commands preceded by a single dash (`-`). Type `jrnl -h` for a list of
commands.
It is possible to see all entries by entering `jrnl -until today`. However, in
most cases you will likely want to use a filter to see specific entries that
meet certain criteria. `jrnl` provides several filtering commands, prefaced by a
single dash (`-`), that allow you to find exactly what you're looking for. For
example,
```sh
jrnl -n 10
```
will list you the ten latest entries (if you're lazy, `jrnl -10` will do
the same),
lists the ten most recent entries. `jrnl -10` is even more concise and works the
same way. If you want to see all of the entries you wrote from the beginning of
last year until the end of this past March, you would enter
```sh
jrnl -from "last year" -until march
```
everything that happened from the start of last year to the start of
last march. To only see your favourite entries, use
Filter criteria that use more than one word require surrounding quotes (`""`).
### Text Search ###
The `-contains` command displays all entries containing a specific string. This
may be helpful when you're searching for entries and you can't remember if you
tagged any words when you wrote them.
You may realize that you use a word a lot and want to turn it into a tag in all
of your previous entries.
```sh
jrnl -starred
jrnl -contains "dogs" --edit
```
## Using Tags
opens your external editor so that you can add a tag symbol (`@` by default) to
all instances of the word "dogs."
Keep track of people, projects or locations, by tagging them with an `@`
in your entries
### Filtering by Tag ###
```sh
jrnl Had a wonderful day on the @beach with @Tom and @Anna.
```
You can filter your journal entries just like this:
You can filter your journal entries by tag. For example,
```sh
jrnl @pinkie @WorldDomination
```
Will print all entries in which either `@pinkie` or `@WorldDomination`
occurred.
displays all entries in which either `@pinkie` or `@WorldDomination`
occurred. Tag filters can be combined with other filters:
```sh
jrnl -n 5 -and @pinkie @WorldDomination
jrnl -n 5 @pinkie -and @WorldDomination
```
the last five entries containing both `@pinkie` **and** `@worldDomination`.
You can change which symbols you'd like to use for tagging in the
configuration.
displays the last five entries containing _both_ `@pinkie` _and_
`@worldDomination`. You can change which symbols you'd like to use for tagging
in the configuration.
!!! note
`jrnl @pinkie @WorldDomination` will switch to viewing mode because
although **no** command line arguments are given, all the input strings
look like tags - _jrnl_ will assume you want to filter by tag.
Entering `jrnl @pinkie @WorldDomination` will display entries in which both
tags are present because, although no command line arguments are given, all
of the input strings look like tags. `jrnl` will assume you want to filter
by tag, rather than create a new entry that consists only of tags.
## Editing older entries
### Viewing Starred Entries ###
You can edit selected entries after you wrote them. This is particularly
useful when your journal file is encrypted. To use this feature, you need
to have an editor configured in your journal configuration file (see
`advanced usage <advanced>`)
To display only your favorite (starred) entries, enter
```sh
jrnl -starred
```
## Editing Entries ##
You can edit entries after writing them. This is particularly useful when your
journal file is encrypted. To use this feature, you need to have an external
editor configured in your configuration file. You can also edit only the entries
that match specific search criteria. For example,
```sh
jrnl -until 1950 @texas -and @history --edit
```
Will open your editor with all entries tagged with `@texas` and
`@history` before 1950. You can make any changes to them you want; after
you save the file and close the editor, your journal will be updated.
opens your external editor displaying all entries tagged with `@texas` and
`@history` that were written before 1950. After making changes, save and close
the file, and only those entries will be modified (and encrypted, if
applicable).
Of course, if you are using multiple journals, you can also edit e.g.
the latest entry of your work journal with `jrnl work -n 1 --edit`. In
any case, this will bring up your editor and save (and, if applicable,
encrypt) your edited journal after you save and exit the editor.
You can also use this feature for deleting entries from your journal
If you are using multiple journals, it's easy to edit specific entries from
specific journals. Simply prefix the filter string with the name of the journal.
For example,
```sh
jrnl @texas -until 'june 2012' --edit
jrnl work -n 1 --edit
```
Just select all text, press delete, and everything is gone...
opens the most recent entry in the 'work' journal in your external editor.
## Deleting Entries ##
The `--delete` command opens an interactive interface for deleting entries. The
date and title of each entry in the journal are presented one at a time, and you
can choose whether to keep or delete each entry.
If no filters are specified, `jrnl` will ask you to keep or delete each entry in
the entire journal, one by one. If there are a lot of entries in the journal, it
may be more efficient to filter entries before passing the `--delete` command.
Here's an example. Say you have a journal into which you've imported the last 12
years of blog posts. You use the `@book` tag a lot, and for some reason you want
to delete some, but not all, of the entries in which you used that tag, but only
the ones you wrote at some point in 2004 or earlier. You're not sure which
entries you want to keep, and you want to look through them before deciding.
This is what you might enter:
```sh
jrnl -to 2004 @book --delete
```
`jrnl` will show you only the relevant entries, and you can choose the ones you
want to delete.
You may want to delete _all_ of the entries containing `@book` that you wrote in
2004 or earlier. If there are dozens or hundreds, the easiest way would be to
use an external editor. Open an editor with the entries you want to delete...
```sh
jrnl -to 2004 @book --edit
```
...select everything, delete it, save and close, and all of those entries are
removed from the journal.
## Listing Journals ##
To list all of your journals:
```sh
jrnl -ls
```
The journals displayed correspond to those specified in the `jrnl` configuration
file.

View file

@ -26,6 +26,18 @@ Feature: Basic reading and writing to a journal
| There is a blank line above this.
"""
Scenario: Multiline entry with punctuation
Given we use the config "basic.yaml"
When we run "jrnl This is. the title\\n This is the second line"
and we run "jrnl -n 1"
Then the output should contain "This is. the title"
Scenario: Single line entry with punctuation
Given we use the config "basic.yaml"
When we run "jrnl This is. the title"
and we run "jrnl -n 1"
Then the output should contain "| the title"
Scenario: Writing an entry from command line
Given we use the config "basic.yaml"
When we run "jrnl 23 july 2013: A cold and stormy day. I ate crisps on the sofa."
@ -33,12 +45,20 @@ Feature: Basic reading and writing to a journal
When we run "jrnl -n 1"
Then the output should contain "2013-07-23 09:00 A cold and stormy day."
@skip_win
Scenario: Writing an empty entry from the editor
Given we use the config "editor.yaml"
When we open the editor and enter nothing
Then we should see the message "[Nothing saved to file]"
Scenario: Sending an argument with spaces to the editor should work
Given we use the config "editor-args.yaml"
When we open the editor and enter "lorem ipsum"
Then the editor should have been called with 5 arguments
And one editor argument should be "vim"
And one editor argument should be "-f"
And one editor argument should be "-c"
And one editor argument should match "'?setf markdown'?"
Scenario: Writing an empty entry from the command line
Given we use the config "basic.yaml"
When we run "jrnl" and enter nothing

View file

@ -0,0 +1,12 @@
default_hour: 9
default_minute: 0
editor: ""
encrypt: false
highlight: true
journals:
default: features/journals/deletion_filters.journal
linewrap: 80
tagsymbols: "@"
template: false
timeformat: "%Y-%m-%d %H:%M"
indent_character: "|"

View file

@ -0,0 +1,12 @@
default_hour: 9
default_minute: 0
editor: vim -f -c 'setf markdown'
encrypt: false
highlight: true
journals:
default: features/journals/simple.journal
linewrap: 80
tagsymbols: "@"
template: false
timeformat: "%Y-%m-%d %H:%M"
indent_character: "|"

View file

@ -0,0 +1,14 @@
[2019-10-01 08:00] It's just another day in October.
Not much to write about.
[2020-01-01 08:00] Happy New Year!
So this is the New Year. @holidays
[2020-03-01 08:00] It's just another day in March.
A stick, a stone, it's the end of the road.
[2020-05-01 09:00] Happy May Day!
@holidays @springtime Several holidays fall on this date.
[2020-05-02 12:10] Writing tests. *
@springtime They will help prevent bugs.

View file

@ -1,5 +1,4 @@
Feature: Delete entries from journal
Scenario: --delete flag allows deletion of single entry
Given we use the config "deletion.yaml"
When we run "jrnl -n 1"
@ -18,3 +17,133 @@ Feature: Delete entries from journal
"""
2019-10-29 11:11 Second entry.
"""
Scenario: Backing out of interactive delete does not change journal
Given we use the config "deletion.yaml"
When we run "jrnl --delete -n 1" and enter
"""
N
"""
Then the journal should have 3 entries
And the journal should contain "[2019-10-29 11:11] First entry."
And the journal should contain "[2019-10-29 11:11] Second entry."
And the journal should contain "[2019-10-29 11:13] Third entry."
Scenario: --delete flag with nonsense input deletes nothing (issue #932)
Given we use the config "deletion.yaml"
When we run "jrnl --delete asdfasdf"
When we run "jrnl -n 1"
Then the output should contain
"""
2019-10-29 11:13 Third entry.
"""
And the journal should have 3 entries
Scenario: --delete flag with tag only deletes tagged entries
Given we use the config "deletion_filters.yaml"
When we run "jrnl --delete @holidays" and enter
"""
Y
Y
"""
Then the journal should have 3 entries
Then the journal should contain "[2019-10-01 08:00] It's just another day in October."
and the journal should contain "[2020-03-01 08:00] It's just another day in March."
and the journal should contain "[2020-05-02 12:10] Writing tests."
Scenario: --delete flag with multiple tags deletes all entries matching any of the tags
Given we use the config "deletion_filters.yaml"
When we run "jrnl --delete @holidays @springtime" and enter
"""
Y
Y
Y
"""
Then the journal should contain "[2019-10-01 08:00] It's just another day in October."
and the journal should not contain "[2020-01-01 08:00] Happy New Year!"
and the journal should contain "[2020-03-01 08:00] It's just another day in March."
and the journal should not contain "[2020-05-01 09:00] Happy May Day!"
and the journal should not contain "[2020-05-02 12:10] Writing tests. *"
and the journal should have 2 entries
Scenario: --delete flag with -and and tags only deletes boolean AND of tagged entries
Given we use the config "deletion_filters.yaml"
When we run "jrnl --delete -and @holidays @springtime" and enter
"""
Y
"""
Then the journal should contain "[2019-10-01 08:00] It's just another day in October."
and the journal should contain "[2020-01-01 08:00] Happy New Year!"
and the journal should contain "[2020-03-01 08:00] It's just another day in March."
and the journal should not contain "[2020-05-01 09:00] Happy May Day!"
and the journal should contain "[2020-05-02 12:10] Writing tests. *"
and the journal should have 4 entries
Scenario: --delete flag with -not does not delete entries with -not tag
Given we use the config "deletion_filters.yaml"
When we run "jrnl --delete @holidays -not @springtime" and enter
"""
Y
"""
Then the journal should contain "[2019-10-01 08:00] It's just another day in October."
and the journal should not contain "[2020-01-01 08:00] Happy New Year!"
and the journal should contain "[2020-03-01 08:00] It's just another day in March."
and the journal should contain "[2020-05-01 09:00] Happy May Day!"
and the journal should contain "[2020-05-02 12:10] Writing tests. *"
and the journal should have 4 entries
Scenario: --delete flag with -from only deletes entries since a specified date
Given we use the config "deletion_filters.yaml"
When we run "jrnl --delete -from 2020-01-02" and enter
"""
Y
Y
Y
"""
Then the journal should contain "[2019-10-01 08:00] It's just another day in October."
and the journal should contain "[2020-01-01 08:00] Happy New Year!"
and the journal should not contain "[2020-03-01 08:00] It's just another day in March."
and the journal should not contain "[2020-05-01 09:00] Happy May Day!"
and the journal should not contain "[2020-05-02 12:10] Writing tests."
and the journal should have 2 entries
Scenario: --delete flag with -to only deletes entries up to specified date
Given we use the config "deletion_filters.yaml"
When we run "jrnl --delete -to 2020-01-02" and enter
"""
Y
Y
"""
Then the journal should not contain "[2019-10-01 08:00] It's just another day in October."
and the journal should not contain "[2020-01-01 08:00] Happy New Year!"
and the journal should contain "[2020-03-01 08:00] It's just another day in March."
and the journal should contain "[2020-05-01 09:00] Happy May Day!"
and the journal should contain "[2020-05-02 12:10] Writing tests."
and the journal should have 3 entries
Scenario: --delete flag with -starred only deletes starred entries
Given we use the config "deletion_filters.yaml"
When we run "jrnl --delete -starred" and enter
"""
Y
"""
Then the journal should contain "[2019-10-01 08:00] It's just another day in October."
and the journal should contain "[2020-01-01 08:00] Happy New Year!"
and the journal should contain "[2020-03-01 08:00] It's just another day in March."
and the journal should contain "[2020-05-01 09:00] Happy May Day!"
and the journal should not contain "[2020-05-02 12:10] Writing tests. *"
and the journal should have 4 entries
Scenario: --delete flag with -contains only entries containing expression
Given we use the config "deletion_filters.yaml"
When we run "jrnl --delete -contains happy" and enter
"""
Y
Y
"""
Then the journal should contain "[2019-10-01 08:00] It's just another day in October."
and the journal should not contain "[2020-01-01 08:00] Happy New Year!"
and the journal should contain "[2020-03-01 08:00] It's just another day in March."
and the journal should not contain "[2020-05-01 09:00] Happy May Day!"
and the journal should contain "[2020-05-02 12:10] Writing tests. *"
and the journal should have 3 entries

View file

@ -55,3 +55,27 @@
Then the config for journal "simple" should have "encrypt" set to "bool:True"
When we run "jrnl simple -n 1"
Then the output should contain "2013-06-10 15:40 Life is good"
Scenario: Encrypt journal with no keyring backend and do not store in keyring
Given we use the config "basic.yaml"
When we disable the keychain
and we run "jrnl test entry"
and we run "jrnl --encrypt" and enter
"""
password
password
n
"""
Then we should get no error
Scenario: Encrypt journal with no keyring backend and do store in keyring
Given we use the config "basic.yaml"
When we disable the keychain
and we run "jrnl test entry"
and we run "jrnl --encrypt" and enter
"""
password
password
y
"""
Then we should get no error

View file

@ -1,8 +1,15 @@
import shutil
import os
import shutil
import sys
def clean_all_working_dirs():
for folder in ("configs", "journals", "cache"):
working_dir = os.path.join("features", folder)
if os.path.exists(working_dir):
shutil.rmtree(working_dir)
def before_feature(context, feature):
# add "skip" tag
# https://stackoverflow.com/a/42721605/4276230
@ -18,10 +25,7 @@ def before_feature(context, feature):
def before_scenario(context, scenario):
"""Before each scenario, backup all config and journal test data."""
# Clean up in case something went wrong
for folder in ("configs", "journals"):
working_dir = os.path.join("features", folder)
if os.path.exists(working_dir):
shutil.rmtree(working_dir)
clean_all_working_dirs()
for folder in ("configs", "journals"):
original = os.path.join("features", "data", folder)
@ -48,7 +52,4 @@ def before_scenario(context, scenario):
def after_scenario(context, scenario):
"""After each scenario, restore all test data and remove working_dirs."""
for folder in ("configs", "journals"):
working_dir = os.path.join("features", folder)
if os.path.exists(working_dir):
shutil.rmtree(working_dir)
clean_all_working_dirs()

View file

@ -122,10 +122,16 @@ Feature: Exporting a Journal
Scenario: Export to yaml
Given we use the config "tags.yaml"
And we created a directory named "exported_journal"
When we run "jrnl --export yaml -o exported_journal"
Then "exported_journal" should contain the files ["2013-04-09_i-have-an-idea.md", "2013-06-10_i-met-with-dan.md"]
And the content of exported yaml "exported_journal/2013-04-09_i-have-an-idea.md" should be
And we create cache directory "exported_journal"
When we run "jrnl --export yaml -o {cache_dir}" with cache directory "exported_journal"
Then cache directory "exported_journal" should contain the files
"""
[
"2013-04-09_i-have-an-idea.md",
"2013-06-10_i-met-with-dan.md"
]
"""
And the content of file "2013-04-09_i-have-an-idea.md" in cache directory "exported_journal" should be
"""
title: I have an @idea:
date: 2013-04-09 15:39

View file

@ -76,30 +76,30 @@ Feature: Zapped bugs should stay dead.
Then the output should not contain "But I'm better."
Scenario: Create entry using day of the week as entry date.
Given we use the config "basic.yaml"
When we run "jrnl monday: This is an entry on a Monday."
Then we should see the message "Entry added"
When we run "jrnl -1"
Given we use the config "basic.yaml"
When we run "jrnl monday: This is an entry on a Monday."
Then we should see the message "Entry added"
When we run "jrnl -1"
Then the output should contain "monday at 9am" in the local time
Then the output should contain "This is an entry on a Monday."
Scenario: Create entry using day of the week abbreviations as entry date.
Given we use the config "basic.yaml"
When we run "jrnl fri: This is an entry on a Friday."
Then we should see the message "Entry added"
When we run "jrnl -1"
Then the output should contain "friday at 9am" in the local time
Given we use the config "basic.yaml"
When we run "jrnl fri: This is an entry on a Friday."
Then we should see the message "Entry added"
When we run "jrnl -1"
Then the output should contain "friday at 9am" in the local time
Scenario: Displaying entries using -on today should display entries created today.
Given we use the config "basic.yaml"
When we run "jrnl today: Adding an entry right now."
When we run "jrnl today: Adding an entry right now."
Then we should see the message "Entry added"
When we run "jrnl -on today"
Then the output should contain "Adding an entry right now."
Scenario: Displaying entries using -from day should display correct entries
Given we use the config "basic.yaml"
When we run "jrnl yesterday: This thing happened yesterday"
When we run "jrnl yesterday: This thing happened yesterday"
Then we should see the message "Entry added"
When we run "jrnl today at 11:59pm: Adding an entry right now."
Then we should see the message "Entry added"
@ -112,7 +112,7 @@ Feature: Zapped bugs should stay dead.
Scenario: Displaying entries using -from and -to day should display correct entries
Given we use the config "basic.yaml"
When we run "jrnl yesterday: This thing happened yesterday"
When we run "jrnl yesterday: This thing happened yesterday"
Then we should see the message "Entry added"
When we run "jrnl today at 11:59pm: Adding an entry right now."
Then we should see the message "Entry added"
@ -148,10 +148,17 @@ Feature: Zapped bugs should stay dead.
# See issues #768 and #881
Scenario: Add a blank line to YAML export is there isn't one already
Given we use the config "deletion.yaml"
And we created a directory named "bug768"
When we run "jrnl --export yaml -o bug768"
Then "bug768" should contain the files ["2019-10-29_first-entry.md", "2019-10-29_second-entry.md", "2019-10-29_third-entry.md"]
And the content of exported yaml "bug768/2019-10-29_third-entry.md" should be
And we create cache directory "bug768"
When we run "jrnl --export yaml -o {cache_dir}" with cache directory "bug768"
Then cache directory "bug768" should contain the files
"""
[
"2019-10-29_first-entry.md",
"2019-10-29_second-entry.md",
"2019-10-29_third-entry.md"
]
"""
And the content of file "2019-10-29_third-entry.md" in cache directory "bug768" should be
"""
title: Third entry.
date: 2019-10-29 11:13

View file

@ -1,23 +1,24 @@
import ast
from collections import defaultdict
import os
from pathlib import Path
import re
import shlex
import sys
import time
from unittest.mock import patch
from behave import given, when, then
from jrnl import cli, install, Journal, util, plugins
from jrnl import __version__
from collections import defaultdict
import keyring
import toml
import yaml
from behave import given, then, when
from jrnl import Journal, __version__, cli, install, plugins, util
try:
import parsedatetime.parsedatetime_consts as pdt
except ImportError:
import parsedatetime as pdt
import time
import os
import ast
import yaml
import keyring
import shlex
import sys
from pathlib import Path
import toml
consts = pdt.Constants(usePyICU=False)
consts.DOWParseStyle = -1 # Prefers past weekdays
@ -40,14 +41,28 @@ class TestKeyring(keyring.backend.KeyringBackend):
self.keys[servicename][username] = None
class NoKeyring(keyring.backend.KeyringBackend):
"""A keyring that simulated an environment with no keyring backend."""
priority = 2
keys = defaultdict(dict)
def set_password(self, servicename, username, password):
raise keyring.errors.NoKeyringError
def get_password(self, servicename, username):
raise keyring.errors.NoKeyringError
def delete_password(self, servicename, username):
raise keyring.errors.NoKeyringError
# set the keyring for keyring lib
keyring.set_keyring(TestKeyring())
def ushlex(command):
if sys.version_info[0] == 3:
return shlex.split(command)
return map(lambda s: s.decode("UTF8"), shlex.split(command.encode("utf8")))
return shlex.split(command, posix="win32" not in sys.platform)
def read_journal(journal_name="default"):
@ -87,14 +102,43 @@ def open_editor_and_enter(context, text=""):
text = text or context.text or ""
def _mock_editor_function(command):
context.editor_command = command
tmpfile = command[-1]
with open(tmpfile, "w+") as f:
f.write(text)
return tmpfile
with patch("subprocess.call", side_effect=_mock_editor_function):
run(context, "jrnl")
# fmt: off
# see: https://github.com/psf/black/issues/664
with \
patch("subprocess.call", side_effect=_mock_editor_function), \
patch("sys.stdin.isatty", return_value=True) \
:
context.execute_steps('when we run "jrnl"')
# fmt: on
@then("the editor should have been called with {num} arguments")
def count_editor_args(context, num):
assert len(context.editor_command) == int(num)
@then('one editor argument should be "{arg}"')
def contains_editor_arg(context, arg):
args = context.editor_command
assert (
arg in args and args.count(arg) == 1
), f"\narg not in args exactly 1 time:\n{arg}\n{str(args)}"
@then('one editor argument should match "{regex}"')
def matches_editor_arg(context, regex):
args = context.editor_command
matches = list(filter(lambda x: re.match(regex, x), args))
assert (
len(matches) == 1
), f"\nRegex didn't match exactly 1 time:\n{regex}\n{str(args)}"
def _mock_getpass(inputs):
@ -128,11 +172,12 @@ def run_with_input(context, command, inputs=""):
args = ushlex(command)[1:]
# fmt: off
# see: https://github.com/psf/black/issues/557
with patch("builtins.input", side_effect=_mock_input(text)) as mock_input, \
patch("getpass.getpass", side_effect=_mock_getpass(text)) as mock_getpass, \
patch("sys.stdin.read", side_effect=text) as mock_read:
# see: https://github.com/psf/black/issues/664
with \
patch("builtins.input", side_effect=_mock_input(text)) as mock_input, \
patch("getpass.getpass", side_effect=_mock_getpass(text)) as mock_getpass, \
patch("sys.stdin.read", side_effect=text) as mock_read \
:
try:
cli.run(args or [])
context.exit_status = 0
@ -151,11 +196,18 @@ def run_with_input(context, command, inputs=""):
@when('we run "{command}"')
def run(context, command):
args = ushlex(command)[1:]
@when('we run "{command}" with cache directory "{cache_dir}"')
def run(context, command, cache_dir=None):
if cache_dir is not None:
cache_dir = os.path.join("features", "cache", cache_dir)
command = command.format(cache_dir=cache_dir)
args = ushlex(command)
try:
cli.run(args or None)
context.exit_status = 0
with patch("sys.argv", args):
cli.run(args[1:])
context.exit_status = 0
except SystemExit as e:
context.exit_status = e.code
@ -172,6 +224,11 @@ def set_keychain(context, journal, password):
keyring.set_password("jrnl", journal, password)
@when("we disable the keychain")
def disable_keychain(context):
keyring.core.set_keyring(NoKeyring())
@then("we should get an error")
def has_error(context):
assert context.exit_status != 0, context.exit_status
@ -257,6 +314,13 @@ def check_journal_content(context, text, journal_name="default"):
assert text in journal, journal
@then('the journal should not contain "{text}"')
@then('journal "{journal_name}" should not contain "{text}"')
def check_not_journal_content(context, text, journal_name="default"):
journal = read_journal(journal_name)
assert text not in journal, journal
@then('journal "{journal_name}" should not exist')
def journal_doesnt_exist(context, journal_name="default"):
with open(install.CONFIG_FILE_PATH) as config_file:

View file

@ -3,7 +3,7 @@ import os
import shutil
from xml.etree import ElementTree
from behave import then, given
from behave import given, then
@then("the output should be parsable as json")
@ -97,17 +97,24 @@ def assert_xml_output_tags(context, expected_tags_json_list):
assert actual_tags == set(expected_tags), [actual_tags, set(expected_tags)]
@given('we created a directory named "{dir_name}"')
@given('we create cache directory "{dir_name}"')
def create_directory(context, dir_name):
if os.path.exists(dir_name):
shutil.rmtree(dir_name)
os.mkdir(dir_name)
working_dir = os.path.join("features", "cache", dir_name)
if os.path.exists(working_dir):
shutil.rmtree(working_dir)
os.makedirs(working_dir)
@then('"{dir_name}" should contain the files {expected_files_json_list}')
def assert_dir_contains_files(context, dir_name, expected_files_json_list):
actual_files = os.listdir(dir_name)
expected_files = json.loads(expected_files_json_list)
@then('cache directory "{dir_name}" should contain the files')
@then(
'cache directory "{dir_name}" should contain the files {expected_files_json_list}'
)
def assert_dir_contains_files(context, dir_name, expected_files_json_list="[]"):
working_dir = os.path.join("features", "cache", dir_name)
actual_files = os.listdir(working_dir)
expected_files = context.text or expected_files_json_list
expected_files = json.loads(expected_files)
# sort to deal with inconsistent default file ordering on different OS's
actual_files.sort()
@ -116,11 +123,12 @@ def assert_dir_contains_files(context, dir_name, expected_files_json_list):
assert actual_files == expected_files, [actual_files, expected_files]
@then('the content of exported yaml "{file_path}" should be')
def assert_exported_yaml_file_content(context, file_path):
@then('the content of file "{file_path}" in cache directory "{cache_dir}" should be')
def assert_exported_yaml_file_content(context, file_path, cache_dir):
expected_content = context.text.strip().splitlines()
full_file_path = os.path.join("features", "cache", cache_dir, file_path)
with open(file_path, "r") as f:
with open(full_file_path, "r") as f:
actual_content = f.read().strip().splitlines()
for actual_line, expected_line in zip(actual_content, expected_content):

View file

@ -107,4 +107,15 @@ Feature: Tagging
2013-06-10 15:40 I met with @dan.
| As alway's he shared his latest @idea on how to rule the world with me.
| inst
"""
"""
Scenario: Searching a journal for multiple tags with -and should display entries with those tags.
Given we use the config "tags.yaml"
When we run "jrnl -and @idea @journal"
Then the output should be
"""
2013-04-09 15:39 I have an @idea:
| (1) write a command line @journal software
| (2) ???
| (3) PROFIT!
"""

8
issue_template.md Normal file
View file

@ -0,0 +1,8 @@
# Stop
Please don't file a blank issue.
Fill out one of the templates from the link below and we'll be better able to
help you.
https://github.com/jrnl-org/jrnl/issues/new/choose

View file

@ -1,24 +1,23 @@
#!/usr/bin/env python
from . import Entry
from . import Journal
from . import time as jrnl_time
from . import __title__ # 'jrnl'
from . import __version__
import os
import re
from datetime import datetime
import time
import fnmatch
import os
from pathlib import Path
import plistlib
import pytz
import re
import time
import uuid
import tzlocal
from xml.parsers.expat import ExpatError
import socket
import platform
import pytz
import tzlocal
from . import __title__, __version__, Entry, Journal
from . import time as jrnl_time
class DayOne(Journal.Journal):
"""A special Journal handling DayOne files"""

View file

@ -1,16 +1,17 @@
from . import util
from .Journal import Journal, LegacyJournal
import base64
import hashlib
import logging
import os
import sys
from cryptography.fernet import Fernet, InvalidToken
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, padding
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
import hashlib
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.backends import default_backend
import sys
import os
import base64
import logging
from . import util
from .Journal import Journal, LegacyJournal
log = logging.getLogger()

View file

@ -1,9 +1,11 @@
#!/usr/bin/env python
import re
import ansiwrap
from datetime import datetime
from .util import split_title, colorize, highlight_tags_with_background_color
import re
import ansiwrap
from .util import colorize, highlight_tags_with_background_color, split_title
class Entry:

View file

@ -1,11 +1,11 @@
#!/usr/bin/env python
# encoding: utf-8
from __future__ import absolute_import, unicode_literals
from . import Journal
import codecs
import os
import fnmatch
import os
from . import Journal
def get_files(journal_config):

View file

@ -1,12 +1,12 @@
#!/usr/bin/env python
from datetime import datetime
import logging
import os
import sys
import re
import sys
from datetime import datetime
from jrnl import Entry, util, time
from jrnl import Entry, time, util
log = logging.getLogger(__name__)
@ -234,8 +234,14 @@ class Journal:
self.entries = result
def delete_entries(self, entries_to_delete):
"""Deletes specific entries from a journal."""
for entry in entries_to_delete:
self.entries.remove(entry)
def prompt_delete_entries(self):
"""Prompts for deletion of entries in a journal."""
"""Prompts for deletion of each of the entries in a journal.
Returns the entries the user wishes to delete."""
to_delete = []
@ -248,8 +254,7 @@ class Journal:
if ask_delete(entry):
to_delete.append(entry)
self.entries = [entry for entry in self.entries if entry not in to_delete]
self.write()
return to_delete
def new_entry(self, raw, date=None, sort=True):
"""Constructs a new entry from some raw text input.

View file

@ -1,6 +1,5 @@
#!/usr/bin/env python
from . import cli
if __name__ == "__main__":
cli.run()

View file

@ -1 +1 @@
__version__ = "v2.4"
__version__ = "v2.4.3-beta"

View file

@ -19,17 +19,16 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
from .Journal import PlainJournal, open_journal
from .EncryptedJournal import EncryptedJournal
from . import util
from . import install
from . import plugins
from .util import ERROR_COLOR, RESET_COLOR, UserAbort
import jrnl
import argparse
import sys
import re
import logging
import re
import sys
import jrnl
from . import install, plugins, util
from .Journal import PlainJournal, open_journal
from .util import ERROR_COLOR, RESET_COLOR, UserAbort
log = logging.getLogger(__name__)
logging.getLogger("keyring.backend").setLevel(logging.ERROR)
@ -194,11 +193,14 @@ def parse_args(args=None):
help="Opens an interactive interface for deleting entries.",
)
if not args:
args = []
# Handle '-123' as a shortcut for '-n 123'
num = re.compile(r"^-(\d+)$")
if args is None:
args = sys.argv[1:]
return parser.parse_args([num.sub(r"-n \1", a) for a in args])
args = [num.sub(r"-n \1", arg) for arg in args]
return parser.parse_args(args)
def guess_mode(args, config):
@ -242,6 +244,8 @@ def guess_mode(args, config):
def encrypt(journal, filename=None):
""" Encrypt into new file. If filename is not set, we encrypt the journal file itself. """
from .EncryptedJournal import EncryptedJournal
journal.config["encrypt"] = True
new_journal = EncryptedJournal.from_journal(journal)
@ -300,7 +304,11 @@ def configure_logger(debug=False):
def run(manual_args=None):
if manual_args is None:
manual_args = sys.argv[1:]
args = parse_args(manual_args)
configure_logger(args.debug)
if args.version:
version_str = f"{jrnl.__title__} version {jrnl.__version__}"
@ -335,6 +343,7 @@ def run(manual_args=None):
config = util.scope_config(config, journal_name)
log.debug('Using journal "%s"', journal_name)
mode_compose, mode_export, mode_import = guess_mode(args, config)
# How to quit writing?
@ -343,6 +352,13 @@ def run(manual_args=None):
else:
_exit_multiline_code = "press Ctrl+D"
# This is where we finally open the journal!
try:
journal = open_journal(journal_name, config)
except KeyboardInterrupt:
print("[Interrupted while opening journal]", file=sys.stderr)
sys.exit(1)
if mode_compose and not args.text:
if not sys.stdin.isatty():
# Piping data into jrnl
@ -374,13 +390,6 @@ def run(manual_args=None):
else:
sys.exit()
# This is where we finally open the journal!
try:
journal = open_journal(journal_name, config)
except KeyboardInterrupt:
print("[Interrupted while opening journal]", file=sys.stderr)
sys.exit(1)
# Import mode
if mode_import:
plugins.get_importer(args.import_).import_(journal, args.input)
@ -478,5 +487,16 @@ def run(manual_args=None):
journal.write()
elif args.delete:
journal.prompt_delete_entries()
journal.write()
if journal.entries:
entries_to_delete = journal.prompt_delete_entries()
if entries_to_delete:
journal.entries = old_entries
journal.delete_entries(entries_to_delete)
journal.write()
else:
print(
"No entries deleted, because the search returned no results.",
file=sys.stderr,
)

View file

@ -1,16 +1,16 @@
#!/usr/bin/env python
import glob
import os
import xdg.BaseDirectory
from . import util
from . import upgrade
from . import __version__
from .util import UserAbort, verify_config
import yaml
import logging
import os
import sys
import xdg.BaseDirectory
import yaml
from . import __version__, util
from .util import UserAbort, verify_config
if "win32" not in sys.platform:
# readline is not included in Windows Active Python
import readline
@ -96,20 +96,23 @@ def load_or_install_jrnl():
log.debug("Reading configuration from file %s", config_path)
config = util.load_config(config_path)
try:
upgrade.upgrade_jrnl_if_necessary(config_path)
except upgrade.UpgradeValidationException:
print("Aborting upgrade.", file=sys.stderr)
print(
"Please tell us about this problem at the following URL:",
file=sys.stderr,
)
print(
"https://github.com/jrnl-org/jrnl/issues/new?title=UpgradeValidationException",
file=sys.stderr,
)
print("Exiting.", file=sys.stderr)
sys.exit(1)
if util.is_old_version(config_path):
from . import upgrade
try:
upgrade.upgrade_jrnl(config_path)
except upgrade.UpgradeValidationException:
print("Aborting upgrade.", file=sys.stderr)
print(
"Please tell us about this problem at the following URL:",
file=sys.stderr,
)
print(
"https://github.com/jrnl-org/jrnl/issues/new?title=UpgradeValidationException",
file=sys.stderr,
)
print("Exiting.", file=sys.stderr)
sys.exit(1)
upgrade_config(config)
verify_config(config)

View file

@ -1,15 +1,15 @@
#!/usr/bin/env python
# encoding: utf-8
from .text_exporter import TextExporter
from .fancy_exporter import FancyExporter
from .jrnl_importer import JRNLImporter
from .json_exporter import JSONExporter
from .markdown_exporter import MarkdownExporter
from .tag_exporter import TagExporter
from .template_exporter import __all__ as template_exporters
from .text_exporter import TextExporter
from .xml_exporter import XMLExporter
from .yaml_exporter import YAMLExporter
from .template_exporter import __all__ as template_exporters
from .fancy_exporter import FancyExporter
__exporters = [
JSONExporter,

View file

@ -1,10 +1,10 @@
#!/usr/bin/env python
# encoding: utf-8
from __future__ import absolute_import, unicode_literals, print_function
from .text_exporter import TextExporter
from textwrap import TextWrapper
from .text_exporter import TextExporter
class FancyExporter(TextExporter):
"""This Exporter can convert entries and journals into text with unicode box drawing characters."""

View file

@ -1,8 +1,9 @@
#!/usr/bin/env python
# encoding: utf-8
from .text_exporter import TextExporter
import json
from .text_exporter import TextExporter
from .util import get_tags_count

View file

@ -1,11 +1,12 @@
#!/usr/bin/env python
# encoding: utf-8
from .text_exporter import TextExporter
import re
import os
import re
import sys
from ..util import WARNING_COLOR, RESET_COLOR
from ..util import RESET_COLOR, WARNING_COLOR
from .text_exporter import TextExporter
class MarkdownExporter(TextExporter):

View file

@ -1,4 +1,5 @@
import re
import yaml
VAR_RE = r"[_a-zA-Z][a-zA-Z0-9_]*"

View file

@ -1,10 +1,11 @@
#!/usr/bin/env python
# encoding: utf-8
from .text_exporter import TextExporter
from .template import Template
import os
from glob import glob
import os
from .template import Template
from .text_exporter import TextExporter
class GenericTemplateExporter(TextExporter):

View file

@ -1,9 +1,9 @@
#!/usr/bin/env python
# encoding: utf-8
from ..util import slugify
import os
from ..util import ERROR_COLOR, RESET_COLOR
from ..util import ERROR_COLOR, RESET_COLOR, slugify
class TextExporter:

View file

@ -1,9 +1,10 @@
#!/usr/bin/env python
# encoding: utf-8
from xml.dom import minidom
from .json_exporter import JSONExporter
from .util import get_tags_count
from xml.dom import minidom
class XMLExporter(JSONExporter):

View file

@ -1,11 +1,12 @@
#!/usr/bin/env python
# encoding: utf-8
from .text_exporter import TextExporter
import os
import re
import sys
from ..util import WARNING_COLOR, ERROR_COLOR, RESET_COLOR
from ..util import ERROR_COLOR, RESET_COLOR, WARNING_COLOR
from .text_exporter import TextExporter
class YAMLExporter(TextExporter):

View file

@ -1,18 +1,22 @@
from datetime import datetime
from dateutil.parser import parse as dateparse
try:
import parsedatetime.parsedatetime_consts as pdt
except ImportError:
import parsedatetime as pdt
FAKE_YEAR = 9999
DEFAULT_FUTURE = datetime(FAKE_YEAR, 12, 31, 23, 59, 59)
DEFAULT_PAST = datetime(FAKE_YEAR, 1, 1, 0, 0)
consts = pdt.Constants(usePyICU=False)
consts.DOWParseStyle = -1 # "Monday" will be either today or the last Monday
CALENDAR = pdt.Calendar(consts)
def __get_pdt_calendar():
try:
import parsedatetime.parsedatetime_consts as pdt
except ImportError:
import parsedatetime as pdt
consts = pdt.Constants(usePyICU=False)
consts.DOWParseStyle = -1 # "Monday" will be either today or the last Monday
calendar = pdt.Calendar(consts)
return calendar
def parse(
@ -34,6 +38,8 @@ def parse(
year_present = False
while not date:
try:
from dateutil.parser import parse as dateparse
date = dateparse(date_str, default=default_date)
if date.year == FAKE_YEAR:
date = datetime(datetime.now().year, date.timetuple()[1:6])
@ -46,7 +52,8 @@ def parse(
y, m, d, H, M, S = default_date.timetuple()[:6]
default_date = datetime(y, m, d - 1, H, M, S)
else:
date, flag = CALENDAR.parse(date_str)
calendar = __get_pdt_calendar()
date, flag = calendar.parse(date_str)
if not flag: # Oops, unparsable.
try: # Try and parse this as a single year

View file

@ -1,11 +1,9 @@
import os
import sys
from . import __version__
from . import Journal
from . import util
from . import Journal, __version__, util
from .EncryptedJournal import EncryptedJournal
from .util import UserAbort
import os
def backup(filename, binary=False):
@ -36,12 +34,7 @@ def check_exists(path):
return os.path.exists(path)
def upgrade_jrnl_if_necessary(config_path):
with open(config_path, "r", encoding="utf-8") as f:
config_file = f.read()
if not config_file.strip().startswith("{"):
return
def upgrade_jrnl(config_path):
config = util.load_config(config_path)
print(

View file

@ -1,21 +1,23 @@
#!/usr/bin/env python
import sys
import os
import getpass as gp
import yaml
import logging
import os
import re
import shlex
from string import punctuation, whitespace
import subprocess
import sys
import tempfile
import textwrap
from typing import Callable, Optional
import unicodedata
import colorama
import yaml
if "win32" in sys.platform:
colorama.init()
import re
import tempfile
import subprocess
import unicodedata
import shlex
from string import punctuation, whitespace
import logging
from typing import Optional, Callable
log = logging.getLogger(__name__)
@ -32,11 +34,10 @@ SENTENCE_SPLITTER = re.compile(
[\'\u2019\"\u201D]? # an optional right quote,
[\]\)]* # optional closing brackets and
\s+ # a sequence of required spaces.
| # Otherwise,
\n # a sentence also terminates newlines.
)""",
re.VERBOSE,
)
SENTENCE_SPLITTER_ONLY_NEWLINE = re.compile("\n")
class UserAbort(Exception):
@ -58,9 +59,6 @@ def create_password(
if yesno("Do you want to store the password in your keychain?", default=True):
set_keychain(journal_name, pw)
else:
set_keychain(journal_name, None)
return pw
@ -106,7 +104,13 @@ def set_keychain(journal_name, password):
except keyring.errors.PasswordDeleteError:
pass
else:
keyring.set_password("jrnl", journal_name, password)
try:
keyring.set_password("jrnl", journal_name, password)
except keyring.errors.NoKeyringError:
print(
"Keyring backend not found. Please install one of the supported backends by visiting: https://pypi.org/project/keyring/",
file=sys.stderr,
)
def yesno(prompt, default=True):
@ -122,6 +126,16 @@ def load_config(config_path):
return yaml.load(f, Loader=yaml.FullLoader)
def is_config_json(config_path):
with open(config_path, "r", encoding="utf-8") as f:
config_file = f.read()
return config_file.strip().startswith("{")
def is_old_version(config_path):
return is_config_json(config_path)
def scope_config(config, journal_name):
if journal_name not in config["journals"]:
return config
@ -171,10 +185,17 @@ def get_text_from_editor(config, template=""):
try:
subprocess.call(
shlex.split(config["editor"], posix="win" not in sys.platform) + [tmpfile]
shlex.split(config["editor"], posix="win32" not in sys.platform) + [tmpfile]
)
except AttributeError:
subprocess.call(config["editor"] + [tmpfile])
except Exception as e:
error_msg = f"""
{ERROR_COLOR}{str(e)}{RESET_COLOR}
Please check the 'editor' key in your config file for errors:
{repr(config['editor'])}
"""
print(textwrap.dedent(error_msg).strip(), file=sys.stderr)
exit(1)
with open(tmpfile, "r", encoding="utf-8") as f:
raw = f.read()
@ -224,14 +245,7 @@ def highlight_tags_with_background_color(entry, text, color, is_title=False):
config = entry.journal.config
if config["highlight"]: # highlight tags
if entry.journal.search_tags:
text_fragments = []
for tag in entry.journal.search_tags:
text_fragments.extend(
re.split(re.compile(f"({re.escape(tag)})", re.IGNORECASE), text)
)
else:
text_fragments = re.split(entry.tag_regex(config["tagsymbols"]), text)
text_fragments = re.split(entry.tag_regex(config["tagsymbols"]), text)
# Colorizing tags inside of other blocks of text
final_text = ""
@ -269,7 +283,9 @@ def slugify(string):
def split_title(text):
"""Splits the first sentence off from a text."""
punkt = SENTENCE_SPLITTER.search(text)
if not punkt:
return text, ""
return text[: punkt.end()].strip(), text[punkt.end() :].strip()
sep = SENTENCE_SPLITTER_ONLY_NEWLINE.search(text.lstrip())
if not sep:
sep = SENTENCE_SPLITTER.search(text)
if not sep:
return text, ""
return text[: sep.end()].strip(), text[sep.end() :].strip()

View file

@ -18,6 +18,7 @@ nav:
- Quickstart: installation.md
- Basic Usage: usage.md
- Encryption: encryption.md
- Privacy and Security: security.md
- Import and Export: export.md
- Advanced Usage: advanced.md
- Recipes: recipes.md

112
poetry.lock generated
View file

@ -93,7 +93,7 @@ description = "Composable command line interface toolkit"
name = "click"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
version = "7.1.1"
version = "7.1.2"
[[package]]
category = "main"
@ -109,7 +109,7 @@ description = "cryptography is a package which provides cryptographic recipes an
name = "cryptography"
optional = false
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*"
version = "2.9"
version = "2.9.2"
[package.dependencies]
cffi = ">=1.8,<1.11.3 || >1.11.3"
@ -164,7 +164,7 @@ description = "A very fast and expressive template engine."
name = "jinja2"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
version = "2.11.1"
version = "2.11.2"
[package.dependencies]
MarkupSafe = ">=0.23"
@ -172,13 +172,21 @@ MarkupSafe = ">=0.23"
[package.extras]
i18n = ["Babel (>=0.8)"]
[[package]]
category = "dev"
description = "Lightweight pipelining: using Python functions as pipeline jobs."
name = "joblib"
optional = false
python-versions = "*"
version = "0.14.1"
[[package]]
category = "main"
description = "Store and access your passwords safely."
name = "keyring"
optional = false
python-versions = ">=3.6"
version = "21.2.0"
version = "21.2.1"
[package.dependencies]
SecretStorage = ">=3"
@ -191,7 +199,7 @@ version = "*"
[package.extras]
docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"]
testing = ["pytest (>=3.5,<3.7.3 || >3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-black-multipy", "pytest-cov"]
testing = ["pytest (>=3.5,<3.7.3 || >3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-black (>=0.3.7)", "pytest-cov"]
[[package]]
category = "dev"
@ -272,13 +280,16 @@ description = "Natural Language Toolkit"
name = "nltk"
optional = false
python-versions = "*"
version = "3.4.5"
version = "3.5"
[package.dependencies]
six = "*"
click = "*"
joblib = "*"
regex = "*"
tqdm = "*"
[package.extras]
all = ["pyparsing", "scikit-learn", "python-crfsuite", "matplotlib", "scipy", "gensim", "requests", "twython", "numpy"]
all = ["requests", "numpy", "python-crfsuite", "scikit-learn", "twython", "pyparsing", "scipy", "matplotlib", "gensim"]
corenlp = ["requests"]
machine_learning = ["gensim", "numpy", "python-crfsuite", "scikit-learn", "scipy"]
plot = ["matplotlib"]
@ -372,7 +383,7 @@ description = "World timezone definitions, modern and historical"
name = "pytz"
optional = false
python-versions = "*"
version = "2019.3"
version = "2020.1"
[[package]]
category = "main"
@ -452,6 +463,17 @@ optional = false
python-versions = ">= 3.5"
version = "6.0.4"
[[package]]
category = "dev"
description = "Fast, Extensible Progress Meter"
name = "tqdm"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*"
version = "4.46.0"
[package.extras]
dev = ["py-make (>=0.1.0)", "twine", "argopt", "pydoc-markdown"]
[[package]]
category = "dev"
description = "a fork of Python 2 and 3 ast modules with type comment support"
@ -485,7 +507,7 @@ docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"]
testing = ["jaraco.itertools", "func-timeout"]
[metadata]
content-hash = "128eb801852bc15aa7dcf3395a806560c0c82416c04a3435712a861081fbc46f"
content-hash = "561dafcf089c8db70bf9cbc2a2ea96ab3727792a2cfc7590f487a11db76fa3fb"
python-versions = ">=3.6.0, <3.9.0"
[metadata.files]
@ -543,33 +565,33 @@ cffi = [
{file = "cffi-1.14.0.tar.gz", hash = "sha256:2d384f4a127a15ba701207f7639d94106693b6cd64173d6c8988e2c25f3ac2b6"},
]
click = [
{file = "click-7.1.1-py2.py3-none-any.whl", hash = "sha256:e345d143d80bf5ee7534056164e5e112ea5e22716bbb1ce727941f4c8b471b9a"},
{file = "click-7.1.1.tar.gz", hash = "sha256:8a18b4ea89d8820c5d0c7da8a64b2c324b4dabb695804dbfea19b9be9d88c0cc"},
{file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"},
{file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"},
]
colorama = [
{file = "colorama-0.4.3-py2.py3-none-any.whl", hash = "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff"},
{file = "colorama-0.4.3.tar.gz", hash = "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"},
]
cryptography = [
{file = "cryptography-2.9-cp27-cp27m-macosx_10_9_intel.whl", hash = "sha256:ef9a55013676907df6c9d7dd943eb1770d014f68beaa7e73250fb43c759f4585"},
{file = "cryptography-2.9-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:2a2ad24d43398d89f92209289f15265107928f22a8d10385f70def7a698d6a02"},
{file = "cryptography-2.9-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:95e1296e0157361fe2f5f0ed307fd31f94b0ca13372e3673fa95095a627636a1"},
{file = "cryptography-2.9-cp27-cp27m-win32.whl", hash = "sha256:192ca04a36852a994ef21df13cca4d822adbbdc9d5009c0f96f1d2929e375d4f"},
{file = "cryptography-2.9-cp27-cp27m-win_amd64.whl", hash = "sha256:ed1d0760c7e46436ec90834d6f10477ff09475c692ed1695329d324b2c5cd547"},
{file = "cryptography-2.9-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:19ae795137682a9778892fb4390c07811828b173741bce91e30f899424b3934d"},
{file = "cryptography-2.9-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:d1bf5a1a0d60c7f9a78e448adcb99aa101f3f9588b16708044638881be15d6bc"},
{file = "cryptography-2.9-cp35-abi3-macosx_10_9_intel.whl", hash = "sha256:1b9b535d6b55936a79dbe4990b64bb16048f48747c76c29713fea8c50eca2acf"},
{file = "cryptography-2.9-cp35-abi3-manylinux1_x86_64.whl", hash = "sha256:7a279f33a081d436e90e91d1a7c338553c04e464de1c9302311a5e7e4b746088"},
{file = "cryptography-2.9-cp35-abi3-manylinux2010_x86_64.whl", hash = "sha256:49870684da168b90110bbaf86140d4681032c5e6a2461adc7afdd93be5634216"},
{file = "cryptography-2.9-cp35-cp35m-win32.whl", hash = "sha256:6b91cab3841b4c7cb70e4db1697c69f036c8bc0a253edc0baa6783154f1301e4"},
{file = "cryptography-2.9-cp35-cp35m-win_amd64.whl", hash = "sha256:587f98ce27ac4547177a0c6fe0986b8736058daffe9160dcf5f1bd411b7fbaa1"},
{file = "cryptography-2.9-cp36-cp36m-win32.whl", hash = "sha256:cc20316e3f5a6b582fc3b029d8dc03aabeb645acfcb7fc1d9848841a33265748"},
{file = "cryptography-2.9-cp36-cp36m-win_amd64.whl", hash = "sha256:3be7a5722d5bfe69894d3f7bbed15547b17619f3a88a318aab2e37f457524164"},
{file = "cryptography-2.9-cp37-cp37m-win32.whl", hash = "sha256:7598974f6879a338c785c513e7c5a4329fbc58b9f6b9a6305035fca5b1076552"},
{file = "cryptography-2.9-cp37-cp37m-win_amd64.whl", hash = "sha256:5aca6f00b2f42546b9bdf11a69f248d1881212ce5b9e2618b04935b87f6f82a1"},
{file = "cryptography-2.9-cp38-cp38-win32.whl", hash = "sha256:9fc9da390e98cb6975eadf251b6e5fa088820141061bf041cd5c72deba1dc526"},
{file = "cryptography-2.9-cp38-cp38-win_amd64.whl", hash = "sha256:6b744039b55988519cc183149cceb573189b3e46e16ccf6f8c46798bb767c9dc"},
{file = "cryptography-2.9.tar.gz", hash = "sha256:0cacd3ef5c604b8e5f59bf2582c076c98a37fe206b31430d0cd08138aff0986e"},
{file = "cryptography-2.9.2-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:daf54a4b07d67ad437ff239c8a4080cfd1cc7213df57d33c97de7b4738048d5e"},
{file = "cryptography-2.9.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:3b3eba865ea2754738616f87292b7f29448aec342a7c720956f8083d252bf28b"},
{file = "cryptography-2.9.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:c447cf087cf2dbddc1add6987bbe2f767ed5317adb2d08af940db517dd704365"},
{file = "cryptography-2.9.2-cp27-cp27m-win32.whl", hash = "sha256:f118a95c7480f5be0df8afeb9a11bd199aa20afab7a96bcf20409b411a3a85f0"},
{file = "cryptography-2.9.2-cp27-cp27m-win_amd64.whl", hash = "sha256:c4fd17d92e9d55b84707f4fd09992081ba872d1a0c610c109c18e062e06a2e55"},
{file = "cryptography-2.9.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d0d5aeaedd29be304848f1c5059074a740fa9f6f26b84c5b63e8b29e73dfc270"},
{file = "cryptography-2.9.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:1e4014639d3d73fbc5ceff206049c5a9a849cefd106a49fa7aaaa25cc0ce35cf"},
{file = "cryptography-2.9.2-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:96c080ae7118c10fcbe6229ab43eb8b090fccd31a09ef55f83f690d1ef619a1d"},
{file = "cryptography-2.9.2-cp35-abi3-manylinux1_x86_64.whl", hash = "sha256:e993468c859d084d5579e2ebee101de8f5a27ce8e2159959b6673b418fd8c785"},
{file = "cryptography-2.9.2-cp35-abi3-manylinux2010_x86_64.whl", hash = "sha256:88c881dd5a147e08d1bdcf2315c04972381d026cdb803325c03fe2b4a8ed858b"},
{file = "cryptography-2.9.2-cp35-cp35m-win32.whl", hash = "sha256:651448cd2e3a6bc2bb76c3663785133c40d5e1a8c1a9c5429e4354201c6024ae"},
{file = "cryptography-2.9.2-cp35-cp35m-win_amd64.whl", hash = "sha256:726086c17f94747cedbee6efa77e99ae170caebeb1116353c6cf0ab67ea6829b"},
{file = "cryptography-2.9.2-cp36-cp36m-win32.whl", hash = "sha256:091d31c42f444c6f519485ed528d8b451d1a0c7bf30e8ca583a0cac44b8a0df6"},
{file = "cryptography-2.9.2-cp36-cp36m-win_amd64.whl", hash = "sha256:bb1f0281887d89617b4c68e8db9a2c42b9efebf2702a3c5bf70599421a8623e3"},
{file = "cryptography-2.9.2-cp37-cp37m-win32.whl", hash = "sha256:18452582a3c85b96014b45686af264563e3e5d99d226589f057ace56196ec78b"},
{file = "cryptography-2.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:22e91636a51170df0ae4dcbd250d318fd28c9f491c4e50b625a49964b24fe46e"},
{file = "cryptography-2.9.2-cp38-cp38-win32.whl", hash = "sha256:844a76bc04472e5135b909da6aed84360f522ff5dfa47f93e3dd2a0b84a89fa0"},
{file = "cryptography-2.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:1dfa985f62b137909496e7fc182dac687206d8d089dd03eaeb28ae16eec8e7d5"},
{file = "cryptography-2.9.2.tar.gz", hash = "sha256:a0c30272fb4ddda5f5ffc1089d7405b7a71b0b0f51993cb4e5dbb4590b2fc229"},
]
future = [
{file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"},
@ -583,12 +605,16 @@ jeepney = [
{file = "jeepney-0.4.3.tar.gz", hash = "sha256:3479b861cc2b6407de5188695fa1a8d57e5072d7059322469b62628869b8e36e"},
]
jinja2 = [
{file = "Jinja2-2.11.1-py2.py3-none-any.whl", hash = "sha256:b0eaf100007721b5c16c1fc1eecb87409464edc10469ddc9a22a27a99123be49"},
{file = "Jinja2-2.11.1.tar.gz", hash = "sha256:93187ffbc7808079673ef52771baa950426fd664d3aad1d0fa3e95644360e250"},
{file = "Jinja2-2.11.2-py2.py3-none-any.whl", hash = "sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035"},
{file = "Jinja2-2.11.2.tar.gz", hash = "sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0"},
]
joblib = [
{file = "joblib-0.14.1-py2.py3-none-any.whl", hash = "sha256:bdb4fd9b72915ffb49fde2229ce482dd7ae79d842ed8c2b4c932441495af1403"},
{file = "joblib-0.14.1.tar.gz", hash = "sha256:0630eea4f5664c463f23fbf5dcfc54a2bc6168902719fa8e19daf033022786c8"},
]
keyring = [
{file = "keyring-21.2.0-py3-none-any.whl", hash = "sha256:8179b1cdcdcbc221456b5b74e6b7cfa06f8dd9f239eb81892166d9223d82c5ba"},
{file = "keyring-21.2.0.tar.gz", hash = "sha256:197fd5903901030ef7b82fe247f43cfed2c157a28e7747d1cfcf4bc5e699dd03"},
{file = "keyring-21.2.1-py3-none-any.whl", hash = "sha256:3401234209015144a5d75701e71cb47239e552b0882313e9f51e8976f9e27843"},
{file = "keyring-21.2.1.tar.gz", hash = "sha256:c53e0e5ccde3ad34284a40ce7976b5b3a3d6de70344c3f8ee44364cc340976ec"},
]
livereload = [
{file = "livereload-2.6.1-py2.py3-none-any.whl", hash = "sha256:78d55f2c268a8823ba499305dcac64e28ddeb9a92571e12d543cd304faf5817b"},
@ -630,6 +656,11 @@ markupsafe = [
{file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6"},
{file = "MarkupSafe-1.1.1-cp37-cp37m-win32.whl", hash = "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2"},
{file = "MarkupSafe-1.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c"},
{file = "MarkupSafe-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15"},
{file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2"},
{file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42"},
{file = "MarkupSafe-1.1.1-cp38-cp38-win32.whl", hash = "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b"},
{file = "MarkupSafe-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be"},
{file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"},
]
mkdocs = [
@ -637,8 +668,7 @@ mkdocs = [
{file = "mkdocs-1.1.tar.gz", hash = "sha256:9243291392f59e20b655e4e46210233453faf97787c2cf72176510e868143174"},
]
nltk = [
{file = "nltk-3.4.5.win32.exe", hash = "sha256:a08bdb4b8a1c13de16743068d9eb61c8c71c2e5d642e8e08205c528035843f82"},
{file = "nltk-3.4.5.zip", hash = "sha256:bed45551259aa2101381bbdd5df37d44ca2669c5c3dad72439fa459b29137d94"},
{file = "nltk-3.5.zip", hash = "sha256:845365449cd8c5f9731f7cb9f8bd6fd0767553b9d53af9eb1b3abf7700936b35"},
]
parse = [
{file = "parse-1.15.0.tar.gz", hash = "sha256:a6d4e2c2f1fbde6717d28084a191a052950f758c0cbd83805357e6575c2b95c0"},
@ -672,8 +702,8 @@ python-dateutil = [
{file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"},
]
pytz = [
{file = "pytz-2019.3-py2.py3-none-any.whl", hash = "sha256:1c557d7d0e871de1f5ccd5833f60fb2550652da6be2693c1e02300743d21500d"},
{file = "pytz-2019.3.tar.gz", hash = "sha256:b02c06db6cf09c12dd25137e563b31700d3b80fcc4ad23abb7a315f2789819be"},
{file = "pytz-2020.1-py2.py3-none-any.whl", hash = "sha256:a494d53b6d39c3c6e44c3bec237336e14305e4f29bbf800b599253057fbb79ed"},
{file = "pytz-2020.1.tar.gz", hash = "sha256:c35965d010ce31b23eeb663ed3cc8c906275d6be1a34393a1d73a41febf4a048"},
]
pywin32-ctypes = [
{file = "pywin32-ctypes-0.2.0.tar.gz", hash = "sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942"},
@ -747,6 +777,10 @@ tornado = [
{file = "tornado-6.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:c58d56003daf1b616336781b26d184023ea4af13ae143d9dda65e31e534940b9"},
{file = "tornado-6.0.4.tar.gz", hash = "sha256:0fe2d45ba43b00a41cd73f8be321a44936dc1aba233dee979f17a042b83eb6dc"},
]
tqdm = [
{file = "tqdm-4.46.0-py2.py3-none-any.whl", hash = "sha256:acdafb20f51637ca3954150d0405ff1a7edde0ff19e38fb99a80a66210d2a28f"},
{file = "tqdm-4.46.0.tar.gz", hash = "sha256:4733c4a10d0f2a4d098d801464bdaf5240c7dadd2a7fde4ee93b0a0efd9fb25e"},
]
typed-ast = [
{file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3"},
{file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb"},

View file

@ -1,6 +1,6 @@
[tool.poetry]
name = "jrnl"
version = "v2.4"
version = "v2.4.3-beta"
description = "Collect your thoughts and notes without leaving the command line."
authors = [
"Manuel Ebert <manuel@1450.me>",
@ -22,7 +22,7 @@ cryptography = "^2.7"
passlib = "^1.7"
parsedatetime = "^2.4"
keyring = ">19.0, <22.0"
pytz = "^2019.1"
pytz = ">=2019.1, <2021.0"
tzlocal = ">1.5, <3.0"
asteval = "^0.9.14"
colorama = "^0.4.1"
@ -40,6 +40,15 @@ pyflakes = "^2.2.0"
[tool.poetry.scripts]
jrnl = 'jrnl.cli:run'
[tool.isort]
multi_line_output = 3
include_trailing_comma = true
force_grid_wrap = 0
use_parentheses = true
line_length = 88
known_first_party = ["jrnl", "behave"]
force_sort_within_sections = true
[build-system]
requires = ["poetry>=0.12"]
build-backend = "poetry.masonry.api"