diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 00000000..323b3928 --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,17 @@ +# Number of days of inactivity before an issue becomes stale +daysUntilStale: 60 +# Number of days of inactivity before a stale issue is closed +daysUntilClose: 7 +# Issues with these labels will never be considered stale +exemptLabels: + - ':star:' + - security +# Label to use when marking an issue as stale +staleLabel: stale +# Comment to post when marking an issue as stale. Set to `false` to disable +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. +# Comment to post when closing a stale issue. Set to `false` to disable +closeComment: false diff --git a/.gitignore b/.gitignore index 966cdaa9..713c3ca9 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ develop-eggs .installed.cfg lib lib64 +.python-version # Installer logs pip-log.txt @@ -28,10 +29,8 @@ Icon _build _sources _static -*.html objects.inv searchindex.js -docs/_themes/jrnl/static/css/jrnl.css # MS Visual Studio (PyTools) obj @@ -43,8 +42,6 @@ obj env/ env*/ -docs/_themes/jrnl/static/less/3L.less - # PyCharm Project files .idea/ @@ -53,3 +50,4 @@ exp/ _extras/ *.sublime-* +site/ diff --git a/.travis.yml b/.travis.yml index 6a195a7c..37fb379b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,7 @@ +dist: xenial # required for Python >= 3.7 language: python python: - - "2.7" - - "3.3" - - "3.4" + - "3.7" install: - "pip install -e ." - "pip install -q behave" diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..dc9e89f1 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,66 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers +pledge to making participation in our project and our community a harassment-free experience for +everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity +and expression, level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming and inclusive language Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism Focusing on what is best for the community Showing +* empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks Public or private +* harassment Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are +expected to take appropriate and fair corrective action in response to any instances of unacceptable +behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, +code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or +to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies within all project spaces, and it also applies when an individual is +representing the project or its community in public spaces. Examples of representing a project or +community include using an official project e-mail address, posting via an official social media +account, or acting as an appointed representative at an online or offline event. Representation of a +project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting +the project team. All complaints will be reviewed and investigated and will result in a response +that is deemed necessary and appropriate to the circumstances. The project team is obligated to +maintain confidentiality with regard to the reporter of an incident. Further details of specific +enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face +temporary or permanent repercussions as determined by other members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at +https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d4bbb29f..989ccf7e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,35 +1,35 @@ Contributing ============ -If you use jrnl, you can totally make my day by just saying "thanks for the code" or by [tweeting about jrnl](https://twitter.com/intent/tweet?text=Write+your+memoirs+on+the+command+line.+Like+a+boss.+%23jrnl&url=http%3A%2F%2Fmaebert.github.io%2Fjrnl&via=maebert). It's your chance to make a programmer happy today! If you have a minute or two, let me know what you use jrnl for and how, it'll help me to make it even better. If you blog about jrnl, I'll send you a post card! +If you use jrnl, you can totally make our day by just saying "thanks for the code." It's your chance to make a programmer happy today! If you have a moment, let us know what you use jrnl for and how; it'll help us to make it even better! Docs & Typos ------------ -If you find a typo or a mistake in the docs, just fix it right away and send a pull request. The Right Way™ to fix the docs is to edit the `docs/*.rst` files on the **master** branch. You can see the result if you run `make html` inside the project's root directory, and then open `docs/_build/html/index.html` in your browser. Note that this requires [lessc](http://lesscss.org/#using-less-installation) and [Sphinx](https://pypi.python.org/pypi/Sphinx) to be installed. Changes to the CSS or Javascript should be made on `docs/_themes/jrnl/`. The `gh-pages` branch is automatically maintained and updates from `master`; you should never have to edit that. +If you find a typo or a mistake in the docs, please fix it right away and send a pull request. The Right Way™ to fix the docs is to edit the `docs/*.md` files on the **master** branch. You can see the result if you run `make html` inside the project's root directory, which will open a browser that hot-reloads as you change the docs. This requires [mkdocs](https://www.mkdocs.org) to be installed. The `gh-pages` branch is automatically maintained and updates from `master`; you should never have to edit that. Bugs ---- -They unfortunately happen. Specifically, I don't have a Windows machine to test on, so expect a few rough spots. If you found a bug, please [open a new issue](https://www.github.com/maebert/jrnl/issues/new) and describe it as well as possible. If you're a programmer and have a little time time spare, go ahead, fork the code and fix bugs you spot, it'll be much appreciated! +Unfortunately, bugs happen. If you found one, please [open a new issue](https://github.com/jrnl-org/jrnl/issues/new) and describe it as well as possible. If you're a programmer with some time, go ahead and send us a pull request! We'll review as quickly as we can. Feature requests and ideas -------------------------- -So, you have an idea for a great feature? Awesome. I love you. As with bugs, first you should [open a new issue](https://www.github.com/maebert/jrnl/issues/new) on GitHub, describe the use case and what the feature should accomplish. If we agree that this feature is useful, it will sooner or later get implemented. Even sooner if you roll up your sleeves and code it yourself ;-) +So, you have an idea for a great feature? Awesome! We'd love to hear from you! Please [open a new issue](https://github.com/jrnl-org/jrnl/issues) and describe the goal of the feature, and any relvant use cases. We'll discuss the issue with you, and decide if it's a good fit for the project. -Keep in mind that the design goal of jrnl is to be _slim_. That means +When discussing new features, please keep in mind our design goals. jrnl strives to do one thing well. To us, that means: -* having as few dependencies as possible -* creating as little interface as possible to boost the learning curve -* doing one thing and one thing well - -Beyond that, it should also play nice with other software and tools -- however, avoid duplicating functionality that existing tools already provide. For example, we played around with the idea of a git integrated journal so new entries would be stored in commits. However, the proposed implementation required a rather heavy git module for python as an dependency, and the same feature could be implemented with a little bit of shell scripting around jrnl. +* be _slim_ +* have a simple interface +* avoid dupicating functionality A short note for new programmers and programmers new to python -------------------------------------------------------------- -Although jrnl grew quite a bit since I first started working on it, the overall complexity (for an end-user program) is fairly low, and I hope you'll find the code easy enough to understand -- if you have a question, don't hesitate to ask! Python is known for it's great community and openness to novice programmers. Feel free to fork the code and play around with it. If you think you created something worth sharing, create a pull request. I never expect pull requests to be perfect, idiomatic, instantly mergeable code, and we can work through it together. Go for it! +Although jrnl has grown quite a bit since its inception. The overall complexity (for an end-user program) is fairly low, and we hope you'll find the code easy enough to understand. + +If you have a question, please don't hesitate to ask! Python is known for its welcoming community and openness to novice programmers, so feel free to fork the code and play around with it! If you create something you want to share with us, please create a pull request. We never expect pull requests to be perfect, idiomatic, instantly mergeable code. We can work through it together! diff --git a/Makefile b/Makefile index 56eb4598..eb0ce646 100644 --- a/Makefile +++ b/Makefile @@ -11,28 +11,11 @@ clean: rm -f *.html html: - curl https://raw.githubusercontent.com/mateuszkocz/3l/master/3L/3L.less > docs/_themes/jrnl/static/less/3L.less ;\ - lessc --clean-css docs/_themes/jrnl/static/less/jrnl.less docs/_themes/jrnl/static/css/jrnl.css ;\ - cd docs ;\ - make html ;\ - cd .. ;\ - open docs/_build/html/index.html ;\ + mkdocs serve # Build GitHub Page from docs docs: - git checkout gh-pages ; \ - git checkout master docs ; \ - git checkout master jrnl ; \ - curl https://raw.githubusercontent.com/mateuszkocz/3l/master/3L/3L.less > docs/_themes/jrnl/static/less/3L.less ;\ - lessc --clean-css docs/_themes/jrnl/static/less/jrnl.less docs/_themes/jrnl/static/css/jrnl.css ; \ - cd docs ; \ - make html ; \ - cd .. ; \ - cp -r docs/_build/html/* . ; \ - git add -A ; \ - git commit -m "Updated docs from master" ; \ - git push -u origin gh-pages ; \ - git checkout master + mkdocs gh-deploy # Upload to pipy dist: diff --git a/README.md b/README.md index 4ea95240..0f444ab2 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,15 @@ -jrnl [![Build Status](http://img.shields.io/travis/maebert/jrnl.svg?style=flat)](https://travis-ci.org/maebert/jrnl) [![Downloads](http://img.shields.io/pypi/dm/jrnl.svg?style=flat)](https://pypi.python.org/pypi/jrnl/) [![Version](http://img.shields.io/pypi/v/jrnl.svg?style=flat)](https://pypi.python.org/pypi/jrnl/) +jrnl [![Build Status](https://travis-ci.com/jrnl-org/jrnl.svg?branch=master)](https://travis-ci.com/jrnl-org/jrnl) [![Downloads](https://pepy.tech/badge/jrnl)](https://pepy.tech/project/jrnl) [![Version](http://img.shields.io/pypi/v/jrnl.svg?style=flat)](https://pypi.python.org/pypi/jrnl/) ==== -_For news on updates or to get help, [read the docs](http://maebert.github.io/jrnl), follow [@maebert](https://twitter.com/maebert) or [submit an issue](https://github.com/maebert/jrnl/issues/new) on Github._ +_To get help, [submit an issue](https://github.com/jrnl-org/jrnl/issues/new) on Github._ *jrnl* is a simple journal application for your command line. Journals are stored as human readable plain text files - you can put them into a Dropbox folder for instant syncing and you can be assured that your journal will still be readable in 2050, when all your fancy iPad journal applications will long be forgotten. -*jrnl* also plays nice with the fabulous [DayOne](http://dayoneapp.com/) and can read and write directly from and to DayOne Journals. - Optionally, your journal can be encrypted using the [256-bit AES](http://en.wikipedia.org/wiki/Advanced_Encryption_Standard). ### Why keep a journal? -Journals aren't only for 13-year old girls and people who have too much time on their summer vacation. A journal helps you to keep track of the things you get done and how you did them. Your imagination may be limitless, but your memory isn't. For personal use, make it a good habit to write at least 20 words a day. Just to reflect what made this day special, why you haven't wasted it. For professional use, consider a text-based journal to be the perfect complement to your GTD todo list - a documentation of what and how you've done it. +Journals aren't just for people who have too much time on their summer vacation. A journal helps you to keep track of the things you get done and how you did them. Your imagination may be limitless, but your memory isn't. For personal use, make it a good habit to write at least 20 words a day. Just to reflect what made this day special, why you haven't wasted it. For professional use, consider a text-based journal to be the perfect complement to your GTD todo list - a documentation of what and how you've done it. In a Nutshell ------------- @@ -27,15 +25,17 @@ and hit return. `yesterday:` will be interpreted as a timestamp. Everything unti If you just call `jrnl`, you will be prompted to compose your entry - but you can also configure _jrnl_ to use your external editor. - -Installation +Known Issues ------------ +jrnl used to support integration with Day One, but no longer supports it since Day One 2 was released with a different backend. [See the GitHub issue for more information](https://github.com/jrnl-org/jrnl/issues/409). -Install _jrnl_ using pip: +Authors +------- +Current maintainers: - pip install jrnl + * Jonathan Wren ([wren](https://github.com/wren)) + * Micah Ellison ([micahellison](https://github.com/micahellison)) -Or, if you want the option to encrypt your journal, - - pip install jrnl[encrypted] +Original maintainer: + * Manuel Ebert ([maebert](https://github.com/maebert)) diff --git a/docs/CNAME b/docs/CNAME new file mode 100644 index 00000000..027bab94 --- /dev/null +++ b/docs/CNAME @@ -0,0 +1,2 @@ +jrnl.sh + diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index 43b60517..00000000 --- a/docs/Makefile +++ /dev/null @@ -1,177 +0,0 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = -BUILDDIR = _build - -# User-friendly check for sphinx-build -ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) -$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) -endif - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . -# the i18n builder cannot share the environment and doctrees with the others -I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . - -.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext - -help: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " singlehtml to make a single large HTML file" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " devhelp to make HTML files and a Devhelp project" - @echo " epub to make an epub" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " latexpdf to make LaTeX files and run them through pdflatex" - @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" - @echo " text to make text files" - @echo " man to make manual pages" - @echo " texinfo to make Texinfo files" - @echo " info to make Texinfo files and run them through makeinfo" - @echo " gettext to make PO message catalogs" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " xml to make Docutils-native XML files" - @echo " pseudoxml to make pseudoxml-XML files for display purposes" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - -clean: - rm -rf $(BUILDDIR)/* - -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml - @echo - @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." - -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/jrnl.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/jrnl.qhc" - -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp - @echo - @echo "Build finished." - @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/jrnl" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/jrnl" - @echo "# devhelp" - -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub." - -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make' in that directory to run these through (pdf)latex" \ - "(use \`make latexpdf' here to do that automatically)." - -latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through pdflatex..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -latexpdfja: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through platex and dvipdfmx..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -text: - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text - @echo - @echo "Build finished. The text files are in $(BUILDDIR)/text." - -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man - @echo - @echo "Build finished. The manual pages are in $(BUILDDIR)/man." - -texinfo: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo - @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." - @echo "Run \`make' in that directory to run these through makeinfo" \ - "(use \`make info' here to do that automatically)." - -info: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo "Running Texinfo files through makeinfo..." - make -C $(BUILDDIR)/texinfo info - @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." - -gettext: - $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale - @echo - @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." - -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." - -xml: - $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml - @echo - @echo "Build finished. The XML files are in $(BUILDDIR)/xml." - -pseudoxml: - $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml - @echo - @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/docs/_themes/jrnl/index.html b/docs/_themes/jrnl/index.html deleted file mode 100755 index 1ffbb851..00000000 --- a/docs/_themes/jrnl/index.html +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - - - - jrnl- The Command Line Journal - - - - - - - - - - -
- Tell your friends -
- -

Collect your thoughts and notes
without leaving the command line

-
-
-
-
$ jrnl today: Started writing my memoirs. On the command line. Like a boss.
-
-
-
- -
-
-
- -

Human friendly.

-

jrnl has a natural-language interface so you don't have to remember cryptic shortcuts when you're writing down your thoughts.

-
-
- -

Future-proof.

-

your journals are stored in plain-text files that will still be readable in 50 years when all your fancy iPad apps will have gone the way of the Dodo.

-
-
- -

Secure.

-

Encrypt your journals with the military-grade AES encryption. Even the NSA won't be able to read your dirty secrets.

-
-
-
-
- -

Accessible anywhere.

-

Sync your journals with Dropbox and capture your thoughts where ever you are

-
-
- -

DayOne compatible.

-

Read, write and search your DayOne journal from the command line.

-
-
- -

Free & Open Source.

-

jrnl is made by a bunch of really friendly and remarkably attractive people. Maybe even you?

-
-
- -

For work and play.

-

Effortlessly access several journals for all parts of your life.

-
-
- - -
- - - - - - diff --git a/docs/_themes/jrnl/layout.html b/docs/_themes/jrnl/layout.html deleted file mode 100755 index 8cf5e53c..00000000 --- a/docs/_themes/jrnl/layout.html +++ /dev/null @@ -1,29 +0,0 @@ -{% if pagename == "index" %} - {% include "index.html" %} -{% else %} - {%- extends "basic/layout.html" %} - - {%- block extrahead %} - {{ super() }} - - - - {% endblock %} - {%- block relbar1 %}{% endblock %} - {%- block relbar2 %}{% endblock %} - - {%- block sidebar2 %} - - {% endblock %} - - {%- block footer %} - - {%- endblock %} -{% endif %} diff --git a/docs/_themes/jrnl/relations.html b/docs/_themes/jrnl/relations.html deleted file mode 100755 index 3bbcde85..00000000 --- a/docs/_themes/jrnl/relations.html +++ /dev/null @@ -1,19 +0,0 @@ -

Related Topics

- diff --git a/docs/_themes/jrnl/static/img/favicon-152.png b/docs/_themes/jrnl/static/img/favicon-152.png deleted file mode 100644 index ac658d9c..00000000 Binary files a/docs/_themes/jrnl/static/img/favicon-152.png and /dev/null differ diff --git a/docs/_themes/jrnl/static/img/favicon.ico b/docs/_themes/jrnl/static/img/favicon.ico deleted file mode 100644 index 7c9c2c1e..00000000 Binary files a/docs/_themes/jrnl/static/img/favicon.ico and /dev/null differ diff --git a/docs/_themes/jrnl/static/img/icons.png b/docs/_themes/jrnl/static/img/icons.png deleted file mode 100644 index bb77ca65..00000000 Binary files a/docs/_themes/jrnl/static/img/icons.png and /dev/null differ diff --git a/docs/_themes/jrnl/static/img/icons@2x.png b/docs/_themes/jrnl/static/img/icons@2x.png deleted file mode 100644 index e9e920be..00000000 Binary files a/docs/_themes/jrnl/static/img/icons@2x.png and /dev/null differ diff --git a/docs/_themes/jrnl/static/img/logo.png b/docs/_themes/jrnl/static/img/logo.png deleted file mode 100644 index 1ea79cf1..00000000 Binary files a/docs/_themes/jrnl/static/img/logo.png and /dev/null differ diff --git a/docs/_themes/jrnl/static/img/logo@2x.png b/docs/_themes/jrnl/static/img/logo@2x.png deleted file mode 100644 index 9cc3d76b..00000000 Binary files a/docs/_themes/jrnl/static/img/logo@2x.png and /dev/null differ diff --git a/docs/_themes/jrnl/static/img/terminal.png b/docs/_themes/jrnl/static/img/terminal.png deleted file mode 100644 index b813980e..00000000 Binary files a/docs/_themes/jrnl/static/img/terminal.png and /dev/null differ diff --git a/docs/_themes/jrnl/static/img/twitter.png b/docs/_themes/jrnl/static/img/twitter.png deleted file mode 100644 index 29c5a89e..00000000 Binary files a/docs/_themes/jrnl/static/img/twitter.png and /dev/null differ diff --git a/docs/_themes/jrnl/static/js/landing.js b/docs/_themes/jrnl/static/js/landing.js deleted file mode 100644 index 4a5eb91a..00000000 --- a/docs/_themes/jrnl/static/js/landing.js +++ /dev/null @@ -1,109 +0,0 @@ -var phrases = [ - ["", "today: Started writing my memoirs. On the command line. Like a boss.", ""], - ["", "yesterday 2pm: used jrnl to keep track of accomplished tasks. The done.txt for my todo.txt", ""], - ["-from 2009 -until may", "", "(Displays all entries from January 2009 to last may)"], - ["", "A day on the beach with @beth and @frank. Taggidy-tag-tag.", ""], - ["--tags", "", "@idea 7
@beth 5"], - ["--export json", "", "(Exports your entire journal to json)"], - ["--encrypt", "", "(256 bit AES encryption. Crack this, NSA.)"] -] - -var args = document.getElementById("args"); -var input = document.getElementById("input"); -var output = document.getElementById("output"); -var current = 0 -var timer = null; -var fadeInTimer = null; -var fadeOutTimer = null; -var letterTimer = null; -var unletterTimer = null; - -var next = function() { - current = (current + 1) % phrases.length; - reveal(current); - timer = setTimeout(next, 5000); -} - -var prev = function() { - current = (current === 0) ? phrases.length - 1 : current - 1; - reveal(current); - timer = setTimeout(next, 5000); -} - -var reveal = function(idx) { - var args_text = phrases[idx][0]; - var input_text = phrases[idx][1]; - var output_text = phrases[idx][2]; - var old_dix = idx == 0 ? phrases.length - 1 : idx - 1; - console.log(idx, old_dix, "++++++++++++") - var old_args_text = args.innerHTML; - var old_input_text = input.innerHTML; - var old_output_text = output.innerHTML; - console.log(args_text, input_text, output_text) - console.log(old_args_text, old_input_text, old_output_text) - var s4 = function() {fadeIn(output_text, output);} - var s3 = function() {letter(input_text, input, s4);} - var s2 = function() {letter(args_text, args, s3);} - var s1 = function() {unletter(old_args_text, args, s2);} - var s0 = function() {unletter(old_input_text, input, s1);} - fadeOut(old_output_text, output, s0, 10); -} - -var fadeIn = function(text, element, next, step) { - step = step || 0 - var nx = function() { fadeIn(text, element, next, ++step); } - if (step==0) { - element.innerHTML = ""; - fadeInTimer = setTimeout(nx, 550); - return; - } - if (step==1) {element.innerHTML = text;} - if (step>10 || !text) { if (next) {next(); return;} else return;} - element.style.opacity = (step-1)/10; - element.style.filter = 'alpha(opacity=' + (step-1)*10 + ')'; - fadeInTimer = setTimeout(nx, 50); -} - -var fadeOut = function(text, element, next, step) { - if (step===10) element.innerHTML = text; - if (step<0 || !text) { - element.innerHTML = ""; - if (next) {next(); return;} - else return; - } - element.style.opacity = step/10; - element.style.filter = 'alpha(opacity=' + step*10 + ')'; - var nx = function() { fadeOut(text, element, next, --step); } - fadeOutTimer = setTimeout(nx, 50); -} - -var unletter = function(text, element, next, timeout, index) { - timeout = timeout||10; - if (index==null) index = text.length; - if (index==-1 || !text.length) { if (next) {next(); return;} else return;} - element.innerHTML = text.substring(0, index); - var nx = function() { unletter(text, element, next, timeout, --index); } - unletterTimer = setTimeout(nx, timeout); -} - -var letter = function(text, element, next, timeout, index) { - timeout = timeout||35; - index = index||0; - if (index > text.length || !text.length) { if (next) {next(); return;} else return;} - element.innerHTML = text.substring(0, index); - var nx = function() { letter(text, element, next, timeout, ++index); } - letterTimer = setTimeout(nx, timeout); -} - -var reset = function() { - var timers = [timer, fadeInTimer, fadeOutTimer, letterTimer, unletterTimer]; - timers.forEach(function (t) { - clearTimeout(t); - }); - - args.innerHTML = ""; - input.innerHTML = ""; - output.innerHTML = ""; -} - -timer = setTimeout(next, 3000); diff --git a/docs/_themes/jrnl/static/landing.svg b/docs/_themes/jrnl/static/landing.svg deleted file mode 100644 index cbdb9488..00000000 --- a/docs/_themes/jrnl/static/landing.svg +++ /dev/null @@ -1,3558 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - Collect your thoughts and noteswithout leaving the command line. - - - - - - - - - - - - - - - - - - - - - - - - - - Terminal - Terminal - - $ jrnl today: Started writing my Memoirs. On the command line. Like a boss. - - - - - - - - - - - - Collect your thoughts and noteswithout leaving the command line. - Secure.Ecnrypt your Journal with military-grade AES encryption so not even the NSA can read your dirty secrets. Human friendly. jrnl has a natural language interface so you don't have to remember cryptic shortcuts while writing down your thoghts. Future-proof.Your journals are stored as plain-text files and you will still be able to open them in 50 years when all your fancy iPad apps have gone the way of the Dodo. Accessible Anywhere.Ecnrypt your Journal with military-grade AES encryption so not even the NSA can read your dirty secrets. DayOne compatible.Your journals are stored as plain-text files and you will still be able to open them in 50 years when all . Free & Open SourceYour journals are stored as plain-text files and you will still be able to open them in 50 years when all . DayOne compatible.Your journals are stored as plain-text files and you will still be able to open them in 50 years when all . - - - - - - Download - - - Download - Documentation - Documentation - Fork me on Github - Fork me on Github - - jrnl is lovingly crafter by Manuel Ebert and other great people. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/_themes/jrnl/static/less/docs.less b/docs/_themes/jrnl/static/less/docs.less deleted file mode 100644 index eb12bb48..00000000 --- a/docs/_themes/jrnl/static/less/docs.less +++ /dev/null @@ -1,283 +0,0 @@ -body - { - font-family: "Open Sans", "Helvetica Neue", sans-serif; - font-weight: 300; - color: #333; - background: @white; - } -body:not(.landing) - { - padding:0px 20px; - padding-top: 40px; - h2 - { - margin-top: 40px; - } - } -input - { - background: transparent; - border: 1px solid #999; - .border-radius(3px); - padding: 2px 5px; - color: #666; - font-family: "Open Sans"; - font-weight: 300; - outline: none; - &:focus - { - background: white; - } - } -div.related - { - background: rgba(255,200,200,.2); - } - -* > a.headerlink - { - display: none; - } - -h1, h2, h3, h4, h5, h6 - { - font-weight: 300; - } - -a:link, a:visited - { - color: @orange; - text-decoration: none; - } -a:hover, a:active - { - text-decoration: underline; - color: lighten(@orange, 10); - } - -.literal - { - color: @purple; - font-size: 1em; - background: lighten(@purple-light, 45); - padding: 1px 2px; - .border-radius(2px); - .box-shadow(inset 0px 0px 0px 1px lighten(@purple-light, 30)); - } - -.note - { - .gradient(lighten(@purple-light, 10), lighten(@purple-light-shade, 10)); - .border-radius(5px); - .box-shadow(0px 2px 3px @purple-shade); - padding: 10px 20px 10px 70px; - position: relative; - color: white; - .admonition-title {display: none;} - a { color: lighten(@orange, 30);} - &:before - { - content: ""; - display: block; - .icon; - .icon.info; - position: absolute; - margin: auto; - top: 0; bottom: 0; left: 20px; - } - .literal, .highlight-note - { - color: white; - background: darken(@purple-light, 3); - padding: 1px 3px; - .border-radius(2px); - .box-shadow(inset 0px 0px 0px 1px lighten(@purple-light, 10)); - } - .highlight-note - { - padding: 1px 10px; - pre:before - { - content: "$ "; - color: @orange; - } - } - } - -.highlight - { - background:transparent !important; - } -.highlight-output, .highlight-javascript, .highlight-sh - { - .pre-block; - background: desaturate(lighten(@terminal,10), 10); - pre {color: white;} - } -.highlight-python - { - .terminal; - pre - { - margin: 0 0 10px 0; - &:before - { - content: "$ "; - color: @orange; - } - } - } - -*:hover > a.headerlink - { - display: inline; - color: lighten(@purple-light, 30); - margin-left: 10px; - text-decoration: none; - &:hover { color: @purple-light; } - } - -tt - { - color: @purple; - font-size: 1.2em; - } -ul li { - margin-bottom: 10px; -} - -div.document - { - max-width: 900px; - margin: 20px auto; - position: relative; - } -div.documentwrapper - { - margin-left: 240px; - padding: 0; - } -aside - { - position: absolute; - width: 220px; - top: 0px; - .logo - { - margin: 0 auto 20px auto; - display: block; - width: 90px; - height: 98px; - } - color: #999; - h2, h3, h3 a:link, h3 a:visited - { - color: #777; - } - - a:link, a:visited - { - color: #999; - } - a:hover, a:active - { - color: @orange; - } - input[type=submit] - { - display: none; - } - &>ul - { - margin: 0 4px; - padding: 0; - list-style: none; - &>li - { - margin-bottom: 10px; - font-size: 18px; - color: #777; - a:link, a:visited {color: #777;} - ul - { - margin: 10px 0 0 0; - padding-left: 20px; - font-size: 16px; - color: #999; - a:link, a:visited {color: #999;} - } - } - } - } - -div.footer - { - font-size: .8em; - text-align: center; - margin: 40px 0; - color: #999; - a:link, a:visited {color: #555;} - } - -@media screen and (max-width: 820px) - { - body:not(.landing){ - padding-top: 130px; - .highlight-output,.highlight-python, .highlight-javascript - { - width: auto; - max-width: 500px; - } - .highlight-python - { - pre { margin: -10px 0 10px 0;} - &:before - { - height: 24px !important; - line-height: 24px; - font-size: .7em; - } - &:after - { - background: none; - } - } - aside - { - position: static; - } - div.documentwrapper - { - margin: 0px; - } - h1, .section - { - margin: 0px !important; - } - aside - { - background-color: #f0f0f0; - width: 100%; - margin: 5px -20px; - padding: 5px 20px 10px 20px; - } - #logolink - { - position: absolute; - top: -120px; - left: 50%; - margin-left: -49px; - } - } - - } -@media (-webkit-min-device-pixel-ratio: 1.5), (min--moz-device-pixel-ratio: 1.5), (-o-min-device-pixel-ratio: 3/2), (min-resolution: 1.5dppx) - { - aside .logo, body#landing #upper #logo - { - width: 90px; - height: 98px; - content: url(../img/logo@2x.png); - } - - } diff --git a/docs/_themes/jrnl/static/less/jrnl.less b/docs/_themes/jrnl/static/less/jrnl.less deleted file mode 100644 index ce597b49..00000000 --- a/docs/_themes/jrnl/static/less/jrnl.less +++ /dev/null @@ -1,317 +0,0 @@ -@import "retina"; -@import "3L"; - -@white: #f7f8f9; -@blue: #5e7dc5; -@blue-light: #7c95ca; -@terminal: #2f1e34; -@purple: #47375d; -@purple-shade: #413155; -@purple-light: #725794; -@purple-light-shade: #564371; -@orange: #deaa09; - -.normalize(); -@import "docs.less"; - -.icon, - { - .sprite("../img/icons.png", 32px, 5, 3, 8px); - &.secure {.sprite(0, 0)}; - &.future {.sprite(1, 0)}; - &.search {.sprite(2, 0)}; - &.nli {.sprite(3, 0)}; - &.share {.sprite(0, 1)}; - &.sync {.sprite(0, 1)}; - &.dayone {.sprite(1, 1)}; - &.github {.sprite(2, 1)}; - &.folders{.sprite(3, 1)}; - &.cal {.sprite(4, 1)}; - &.left {.sprite(0, 2)}; - &.right {.sprite(1, 2)}; - &.info {.sprite(2, 2)}; - } - -.pre-block - { - background: @terminal; - .border-radius(6px); - padding: 1px 20px; - margin: 40px auto; - width: 500px; - .box-shadow(0px 1px 8px darken(@white, 30)); - position: relative; - color: @white; - font-family: "Monaco", "Courier New"; - font-size: 12pt; - #args {color: #f6f7b9} - #output {color: #9278b5} - } - -.terminal - { - .pre-block; - @p: 20px; - padding: @p + 30px @p (@p - 10px) @p; - &:before - { - content: "Terminal"; - display: block; - width: 100%; - position: absolute; - left: 0; - .box-shadow(inset 0px 1px 0px #f4f4f4, inset 0px -1px 0px #888); - margin-top: -50px; - // margin: -@p -@p 0px -@p; - text-align: center; - height: 30px; - line-height: 30px; - color: #777; - text-shadow: 0px 1px 0px #ddd; - .border-radius(5px 5px 0px 0px); - .gradient(#eaeaea, #bababa); - } - &:after - { - content: ""; - width: 48px; - height: 30px; - position: absolute; - top: 0px; - left: 10px; - background: url(../img/terminal.png) no-repeat center center; - } - } - -body#landing - { - background-color: @purple; - font-family: "Open Sans", "Helvetica Neue", sans-serif; - font-weight: 300; - #twitter - { - display: block; - position: absolute; - top: 20px; - right: 20px; - border: 1px solid @purple; - padding: 5px 10px 5px 30px; - color: @purple; - .border-radius(3px); - .opacity(.7); - background: url(../img/twitter.png) 8px center no-repeat transparent; - &:hover, &:active - { - .opacity(1); - text-decoration: none; - } - } - #title, .row3, .row4, #prompt - { - width: 900px; - margin: 0px auto; - } - #upper - { - .clearfix; - background: @white; - .box-shadow(inset 0px -6px 6px -3px darken(@white, 10)); - #title - { - width: 650px; - margin: 150px auto 75px auto; - } - img - { - float: left; - margin-right: 30px; - } - h1 - { - color: @purple-light-shade; - font-weight: 300; - } - #prompt - { - width: 640px; - margin: 0 auto; - .clearfix; - } - .terminal - { - .border-radius(6px 6px 0px 0px); - float: left; - margin: 0px; - width: 500px; - min-height: 134px; - .border-box-sizing; - } - .pleft, .pright - { - text-align: center; - .border-box-sizing; - float: left; - padding-top: 50px; - width: 70px; - i {.opacity(60);} - i:hover {.opacity(1000); cursor: pointer;} - } - } - #nav - { - .gradient(@blue-light, @blue); - height: 60px; - .box-shadow(0px 6px 6px -3px @purple-shade); - text-align: center; - a#twitter-nav {display: none;} - a - { - color: @white; - text-shadow: 0px -1px 0px darken(@blue, 30); - text-decoration: none; - font-size: 14pt; - line-height: 60px; - margin: 0 40px; - &:hover - { - color: lighten(@orange, 20); - text-shadow: 0px -1px 0px darken(@orange, 15); - } - } - a.cta - { - .gradient(@purple-light, @purple-light-shade); - .box-shadow(0px 1px 0px @purple-shade); - .border-radius(5px); - padding: 6px 10px 5px 10px; - white-space: nowrap; - &:hover - { - .gradient(lighten(@orange, 10), darken(@orange, 5)); - .box-shadow(0px 1px 0px darken(@orange, 15)); - text-shadow: 0px -1px 0px darken(@orange, 15); - color: @white; - - } - } - } - #lower - { - color: @white; - padding-top: 40px; - a - { - color: @orange; - text-decoration: none; - &:hover - { - color: lighten(@orange, 20); - text-decoration: underline; - } - } - .row3, .row4 { - .clearfix; - margin-bottom: 20px; - .col - { - position: relative; - padding-left: 40px; - i - { - position: absolute; - left: 0; - top: 16px; - } - h3 {font-size: 12pt; margin-bottom: .5em;} - p {font-size: 10pt; margin: 0;} - float: left; - width: 25%; - padding-right: 2%; - .border-box-sizing; - &:last-child {padding-right: 0;} - } - } - .row3 .col { width: 33.3333%; } - .row4 .col { color: mix(@white, @purple, 80); i {.opacity(80);}} - } - } - -@media screen and (max-width: 680px) - { - body#landing - { - #nav - { - height: auto; - padding-bottom: 10px; - a, a#twitter-nav - { - display: block; - } - a.cta - { - margin: 10px; - padding: 1px; - } - } - #upper - { - #twitter { display: none;} - #title - { - margin: 30px 0 10px 0; - } - #logo - { - backgound: red; - display: block; - float: none; - margin: 0px auto; - } - #title br {display: none;} - .pleft, .pright {display: none;} - #prompt, #title - { - width: 100%; - .border-box-sizing; - padding: 0px 20px; - } - .terminal - { - width: 100%; - } - } - } - } - -@media screen and (max-width: 900px) - { - body#landing - { - #lower - { - padding: 40px 20px; - .row3, .row4 - { - margin: 0px; - width: auto; - } - .row3 .col, .row4 .col - { - float: none; - width: 100%; - text-align: center; - padding: 0px; - margin: 0 0 40px 0; - h3 {font-size: 1.5em;} - p {font-size: 1em;} - - i - { - position: static; - margin-bottom: -20px; - } - } - } - } - } diff --git a/docs/_themes/jrnl/static/less/retina.less b/docs/_themes/jrnl/static/less/retina.less deleted file mode 100644 index 3c006c45..00000000 --- a/docs/_themes/jrnl/static/less/retina.less +++ /dev/null @@ -1,35 +0,0 @@ -// A helper mixin for applying high-resolution background images (http://www.retinajs.com) - -@highdpi: ~"(-webkit-min-device-pixel-ratio: 1.5), (min--moz-device-pixel-ratio: 1.5), (-o-min-device-pixel-ratio: 3/2), (min-resolution: 1.5dppx)"; - -.at2x(@path, @w: auto, @h: auto) { - background-image: url(@path); - @at2x_path: ~`@{path}.replace(/\.\w+$/, function(match) { return "@2x" + match; })`; - background-size: @w @h; - - @media @highdpi { - background-image: url("@{at2x_path}"); - } -} - -// Sprite mixin, see https://coderwall.com/p/oztebw - -.sprite (@path, @size, @w, @h, @pad: 0) when (isstring(@path)) - { - background-image: url(@path); - width: @size; - height: @size; - display: inline-block; - @at2x_path: ~`@{path}.replace(/\.[\w\?=]+$/, function(match) { return "@2x" + match; })`; - font-size: @size + @pad; - background-size: (@size + @pad) * @w (@size + @pad) * @h; - @media @highdpi - { - background-image: url("@{at2x_path}"); - } - } - -.sprite(@x, @y) - { - background-position: -@x * 1em -@y * 1em; - } diff --git a/docs/_themes/jrnl/static/sprites.svg b/docs/_themes/jrnl/static/sprites.svg deleted file mode 100755 index a8420b9b..00000000 --- a/docs/_themes/jrnl/static/sprites.svg +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - diff --git a/docs/_themes/jrnl/theme.conf b/docs/_themes/jrnl/theme.conf deleted file mode 100755 index fc3d3735..00000000 --- a/docs/_themes/jrnl/theme.conf +++ /dev/null @@ -1,7 +0,0 @@ -[theme] -inherit = basic -stylesheet = css/jrnl.css -pygments_style = flask_theme_support.FlaskyStyle - -[options] -touch_icon = diff --git a/docs/advanced.md b/docs/advanced.md new file mode 100644 index 00000000..2a6fd6b4 --- /dev/null +++ b/docs/advanced.md @@ -0,0 +1,145 @@ +# Advanced Usage + +## Configuration File + +You can configure the way jrnl behaves in a configuration file. By +default, this is `~/.jrnl_config`. If you have the `XDG_CONFIG_HOME` +variable set, the configuration file will be saved as +`$XDG_CONFIG_HOME/jrnl/.jrnl_config`. + +!!! note + On Windows, The configuration file is typically found at `C:\Users\[Your Username]\.jrnl_config`. + +The configuration file is a simple JSON file with the following options +and can be edited with any plain text editor. + + - `journals` + paths to your journal files + - `editor` + if set, executes this command to launch an external editor for + writing your entries, e.g. `vim`. Some editors require special + options to work properly, see `FAQ ` for details. + - `encrypt` + if `true`, encrypts your journal using AES. + - `tagsymbols` + Symbols to be interpreted as tags. (See note below) + - `default_hour` and `default_minute` + if you supply a date, such as `last thursday`, but no specific + time, the entry will be created at this time + - `timeformat` + how to format the timestamps in your journal, see the [python docs](http://docs.python.org/library/time.html#time.strftime) for reference + - `highlight` + if `true`, tags will be highlighted in cyan. + - `linewrap` + controls the width of the output. Set to `false` if you don't + want to wrap long lines. + +!!! note + Although it seems intuitive to use the `#` + character for tags, there's a drawback: on most shells, this is + interpreted as a meta-character starting a comment. This means that if + you type + + > `jrnl Implemented endless scrolling on the #frontend of our website.` + + your bash will chop off everything after the `#` before passing it to + `jrnl`. To avoid this, wrap your input into quotation marks like + this: + + > `jrnl "Implemented endless scrolling on the #frontend of our website."` + + Or use the built-in prompt or an external editor to compose your + entries. + +## DayOne Integration + +Using your DayOne journal instead of a flat text file is dead simple -- +instead of pointing to a text file, change your `.jrnl_config` to point +to your DayOne journal. This is a folder named something like +`Journal_dayone` or `Journal.dayone`, and it's located at + + - `~/Library/Application Support/Day One/` by default + - `~/Dropbox/Apps/Day One/` if you're syncing with Dropbox and + - `~/Library/Mobile + Documents/5U8NS4GX82~com~dayoneapp~dayone/Documents/` if you're + syncing with iCloud. + +Instead of all entries being in a single file, each entry will live in a +separate `plist` file. So your `.jrnl_config` should look like this: + +``` javascript +{ + ... + "journals": { + "default": "~/journal.txt", + "dayone": "~/Library/Mobile Documents/5U8NS4GX82~com~dayoneapp~dayone/Documents/Journal_dayone" + } +} +``` + +## Multiple journal files + +You can configure `jrnl`to use with multiple journals (eg. +`private` and `work`) by defining more journals in your `.jrnl_config`, +for example: + +``` javascript +{ +... + "journals": { + "default": "~/journal.txt", + "work": "~/work.txt" + } +} +``` + +The `default` journal gets created the first time you start `jrnl` +Now you can access the `work` journal by using `jrnl work` instead of +`jrnl`, eg. + +``` sh +jrnl work at 10am: Meeting with @Steve +jrnl work -n 3 +``` + +will both use `~/work.txt`, while `jrnl -n 3` will display the last +three entries from `~/journal.txt` (and so does `jrnl default -n 3`). + +You can also override the default options for each individual journal. +If you `.jrnl_config` looks like this: + +``` javascript +{ + ... + "encrypt": false + "journals": { + "default": "~/journal.txt", + "work": { + "journal": "~/work.txt", + "encrypt": true + }, + "food": "~/my_recipes.txt", +} +``` + +Your `default` and your `food` journals won't be encrypted, however your +`work` journal will! You can override all options that are present at +the top level of `.jrnl_config`, just make sure that at the very least +you specify a `"journal": ...` key that points to the journal file of +that journal. + +!!! note + Changing `encrypt` to a different value will not encrypt or decrypt your + journal file, it merely says whether or not your journal + is encrypted. Hence manually changing + this option will most likely result in your journal file being + impossible to load. + +## Known Issues + +### Unicode on Windows + +The Windows shell prior to Windows 7 has issues with unicode encoding. +To use non-ascii characters, first tweak Python to recognize the encoding by adding `'cp65001': 'utf_8'`, to `Lib/encoding/aliases.py`. Then, change the codepage with `chcp 1252` before using `jrnl`. + +(Related issue: [#486](https://github.com/jrnl-org/jrnl/issues/486)) diff --git a/docs/advanced.rst b/docs/advanced.rst deleted file mode 100644 index 827b8b0b..00000000 --- a/docs/advanced.rst +++ /dev/null @@ -1,129 +0,0 @@ -.. _advanced: - -Advanced Usage -============== - -Configuration File -------------------- - -You can configure the way jrnl behaves in a configuration file. By default, this is ``~/.jrnl_config``. If you have the ``XDG_CONFIG_HOME`` variable set, the configuration file will be saved under ``$XDG_CONFIG_HOME/jrnl``. - -.. note:: - - On Windows, The configuration file is typically found at ``C:\Users\[Your Username]\.jrnl_config``. - - -The configuration file is a simple JSON file with the following options and can be edited with any plain text editor. - -- ``journals`` - paths to your journal files -- ``editor`` - if set, executes this command to launch an external editor for writing your entries, e.g. ``vim``. Some editors require special options to work properly, see :doc:`FAQ ` for details. -- ``encrypt`` - if ``true``, encrypts your journal using AES. -- ``tagsymbols`` - Symbols to be interpreted as tags. (See note below) -- ``default_hour`` and ``default_minute`` - if you supply a date, such as ``last thursday``, but no specific time, the entry will be created at this time -- ``timeformat`` - how to format the timestamps in your journal, see the `python docs `_ for reference -- ``highlight`` - if ``true``, tags will be highlighted in cyan. -- ``linewrap`` - controls the width of the output. Set to ``false`` if you don't want to wrap long lines. - -.. note:: - - Although it seems intuitive to use the `#` character for tags, there's a drawback: on most shells, this is interpreted as a meta-character starting a comment. This means that if you type - - .. code-block:: note - - jrnl Implemented endless scrolling on the #frontend of our website. - - your bash will chop off everything after the ``#`` before passing it to _jrnl_). To avoid this, wrap your input into quotation marks like this: - - .. code-block:: note - - jrnl "Implemented endless scrolling on the #frontend of our website." - - Or use the built-in prompt or an external editor to compose your entries. - -DayOne Integration ------------------- - -Using your DayOne journal instead of a flat text file is dead simple -- instead of pointing to a text file, change your ``.jrnl_config`` to point to your DayOne journal. This is a folder named something like ``Journal_dayone`` or ``Journal.dayone``, and it's located at - -* ``~/Library/Application Support/Day One/`` by default -* ``~/Dropbox/Apps/Day One/`` if you're syncing with Dropbox and -* ``~/Library/Mobile Documents/5U8NS4GX82~com~dayoneapp~dayone/Documents/`` if you're syncing with iCloud. - -Instead of all entries being in a single file, each entry will live in a separate `plist` file. So your ``.jrnl_config`` should look like this: - -.. code-block:: javascript - - { - ... - "journals": { - "default": "~/journal.txt", - "dayone": "~/Library/Mobile Documents/5U8NS4GX82~com~dayoneapp~dayone/Documents/Journal_dayone" - } - - -Alfred Integration ------------------- - -You can use _jrnl_ with the popular `Alfred `_ app with `this handy workflow `_. - - -Multiple journal files ----------------------- - -You can configure _jrnl_ to use with multiple journals (eg. ``private`` and ``work``) by defining more journals in your ``.jrnl_config``, for example: - -.. code-block:: javascript - - { - ... - "journals": { - "default": "~/journal.txt", - "work": "~/work.txt" - } - } - -The ``default`` journal gets created the first time you start _jrnl_. Now you can access the ``work`` journal by using ``jrnl work`` instead of ``jrnl``, eg. :: - - jrnl work at 10am: Meeting with @Steve - -:: - - jrnl work -n 3 - -will both use ``~/work.txt``, while ``jrnl -n 3`` will display the last three entries from ``~/journal.txt`` (and so does ``jrnl default -n 3``). - -You can also override the default options for each individual journal. If you ``.jrnl_config`` looks like this: - -.. code-block:: javascript - - { - ... - "encrypt": false - "journals": { - "default": "~/journal.txt", - "work": { - "journal": "~/work.txt", - "encrypt": true - }, - "food": "~/my_recipes.txt", - } - -Your ``default`` and your ``food`` journals won't be encrypted, however your ``work`` journal will! You can override all options that are present at the top level of ``.jrnl_config``, just make sure that at the very least you specify a ``"journal": ...`` key that points to the journal file of that journal. - -.. note:: - - Changing ``encrypt`` to a different value will not encrypt or decrypt your journal file, it merely says whether or not your journal `is` encrypted. Hence manually changing this option will most likely result in your journal file being impossible to load. - -Known Issues -~~~~~~~~~~~~ - -- The Windows shell prior to Windows 7 has issues with Unicode encoding. If you want to use non-ASCII characters, change the code page with ``chcp 1252`` before using `jrnl` (Thanks to Yves Pouplard for solving this!) -- _jrnl_ relies on the `PyCrypto` package to encrypt journals, which has some known problems with installing on Windows and within virtual environments. diff --git a/docs/assets/highlight.css b/docs/assets/highlight.css new file mode 100644 index 00000000..46eeb25c --- /dev/null +++ b/docs/assets/highlight.css @@ -0,0 +1,79 @@ +/* + +Atom One Dark With support for ReasonML by Gidi Morris, based off work by Daniel Gamage + +Original One Dark Syntax theme from https://github.com/atom/one-dark-syntax + +*/ +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + line-height: 1.3em; + color: #e2e8f2; + background: #383e49; + border-radius: 5px; + font-size: 0.9rem; + line-height: 1.3rem; +} +.hljs-keyword, .hljs-operator { + color: #F92672; +} +.hljs-pattern-match { + color: #F92672; +} +.hljs-pattern-match .hljs-constructor { + color: #61aeee; +} +.hljs-function { + color: #61aeee; +} +.hljs-function .hljs-params { + color: #A6E22E; +} +.hljs-function .hljs-params .hljs-typing { + color: #FD971F; +} +.hljs-module-access .hljs-module { + color: #7e57c2; +} +.hljs-constructor { + color: #e2b93d; +} +.hljs-constructor .hljs-string { + color: #9CCC65; +} +.hljs-comment, .hljs-quote { + color: #b18eb1; + font-style: italic; +} +.hljs-doctag, .hljs-formula { + color: #c678dd; +} +.hljs-section, .hljs-name, .hljs-selector-tag, .hljs-deletion, .hljs-subst { + color: #e06c75; +} +.hljs-literal { + color: #56b6c2; +} +.hljs-string, .hljs-regexp, .hljs-addition, .hljs-attribute, .hljs-meta-string { + color: #98c379; +} +.hljs-built_in, .hljs-class .hljs-title { + color: #e6c07b; +} +.hljs-attr, .hljs-variable, .hljs-template-variable, .hljs-type, .hljs-selector-class, .hljs-selector-attr, .hljs-selector-pseudo, .hljs-number { + color: #d19a66; +} +.hljs-symbol, .hljs-bullet, .hljs-link, .hljs-meta, .hljs-selector-id, .hljs-title { + color: #61aeee; +} +.hljs-emphasis { + font-style: italic; +} +.hljs-strong { + font-weight: bold; +} +.hljs-link { + text-decoration: underline; +} diff --git a/docs/assets/theme.css b/docs/assets/theme.css new file mode 100644 index 00000000..a3de87a9 --- /dev/null +++ b/docs/assets/theme.css @@ -0,0 +1,196 @@ + +/* ------------------------------------------------------------ */ +/* Overrides for jrnl theme */ +/* ------------------------------------------------------------ */ + +:root { + --sidebar: #604385; + --sidebar-dark: #604385; + --off-white: rgba(255,255,255,.7); +} + +body.wy-body-for-nav, section.wy-nav-content-wrap { + background-color: rgb(252,252,252); +} + +pre { + background-color: transparent; + border: none; + margin: 1em -1em; +} + +pre code { + padding: 1em 1.5em !important; +} + +code { + background-color: transparent; +} + +h1,h2 ,h3, h4, h5, h6 { + font-family: "Open Sans", "Helvetica Neue", Helvetica, sans-serif; + font-weight: 600; + margin-top: 2rem; + margin-bottom: 0.5rem; +} +p, td, tr, div, li { + font-family: "Open Sans", "Helvetica Neue", Helvetica, sans-serif; + font-weight: 00; +} + +p { + margin: 1em 0em; +} + +/* No-one likes lines that are 400 characters long. */ +div.rst-content {max-width: 54em;} + +.wy-side-nav-search, .wy-nav-top, .wy-menu-vertical li.current { + background-color: transparent; +} +.wy-side-nav-search a.icon-home { + width: 100%; + max-width: 250px; + background-size: 100%; +} + +a.icon-home:before { + display: block; + width: 84px; + height: 70px; + content: ""; + background: url(../img/logo_white.svg) center center no-repeat; + margin: 10px auto; +} + +.wy-menu-vertical a, .wy-menu-vertical li ul li a {color: var(--off-white) !important; } + +.wy-menu-vertical a:hover, .wy-menu-vertical li.current a:hover { background-color: transparent !important; color: white !important;} +.wy-menu-vertical li.on a, .wy-menu-vertical li.current>a { + background: transparent; !important; + color: white !important; + border: none; + position: relative; + font-weight: 700 !important; + border-right: none !important; +} + +.wy-menu-vertical li.on a, .wy-menu-vertical li.current a { + border-right: none; +} + +.wy-menu-vertical li.on a, .wy-menu-vertical li.current>a:after { + display: block; + position: absolute; + right: 0em; + top: 0; + z-index: 999 !important; + content: ""; + width: 0; + height: 0; + border-top: 1em solid transparent; + border-bottom: 1em solid transparent; + border-right: 1em solid white; +} + +.rst-versions, .rst-versions .rst-current-version { display: none; } +.wy-menu-vertical span { + color: white !important; + font-size: 1.2em; + font-weight: 300 !important; +} +.wy-menu-vertical li a {color: var(--off-white) !important; font-weight: 300 !important;} + + +.wy-nav-side { + background-image: linear-gradient(211deg, #95699C 0%, #604385 100%); + font-weight: 300 !important; + height: 100%; +} + + +footer {display: none;} + +.wy-side-nav-search input[type=text], form .search-query { + background-color: rgba(0,0,0,.1) !important; + border: 1px solid rgba(255,255,255,.3); + box-shadow: none; + margin-bottom: 1em; + color: white !important; + font-weight: 500; +} + +.wy-side-nav-search input[type=text]::placeholder, form .search-query::placeholder { + color: var(--off-white) !important; +} + +.toctree-l2 a:first-child {display: none;} + +/* ------------------------------------------------------------ */ +/* Logo: ; */ +/* ------------------------------------------------------------ */ + +.logo { + width: 128px; + height: 128px; + vertical-align: middle; + margin-right: 1em; +} + +/* ------------------------------------------------------------ */ +/* Code blocks in callouts */ +/* ------------------------------------------------------------ */ + +div.admonition { + border-radius: 5px; + margin: 1em -1em; +} +div.admonition p.admonition-title { + border-top-left-radius: 5px; + border-top-right-radius: 5px; +} +div.admonition > p { + padding: 0em .5em; +} + + +div.admonition div.highlight { + background: none !important; +} +div.admonition div.highlight pre { + background-color: rgba(255,255,255,.5) !important; +} + +/* ------------------------------------------------------------ */ +/* Fancy ordered lists. */ +/* ------------------------------------------------------------ */ + +ol { + counter-reset:li; + margin-left: 0px; + padding: 0; +} + +ol li { + list-style: none !important; + margin-bottom: 1.5em; + margin-left: 3em !important; +} + +ol > li:before { + content:counter(li); + counter-increment:li; + background-color: var(--sidebar); + border-radius: 50%; + display: block; + float: left; + margin-left: -3em; + margin-top: -.3em; + width: 2em; + height: 2em; + color: var(--sidebar-dark); + text-align: center; + line-height: 2em; + font-weight: 600; +} + diff --git a/docs/conf.py b/docs/conf.py deleted file mode 100644 index f345ca58..00000000 --- a/docs/conf.py +++ /dev/null @@ -1,257 +0,0 @@ -# -*- coding: utf-8 -*- -# -# jrnl documentation build configuration file, created by -# sphinx-quickstart on Wed Aug 7 13:22:51 2013. -# -# This file is execfile()d with the current directory set to its containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -import sys, os -sys.path.insert(0, os.path.abspath('..')) -import jrnl -from jrnl import __version__ - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) - -# -- General configuration ----------------------------------------------------- - -# If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be extensions -# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.autodoc'] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -#source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'jrnl' -copyright = u'jrnl is made with love by Manuel Ebert and other fabulous people. If you need help, tweet to @maebert or submit an issue on Github.' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -version = __version__ -# The full version, including alpha/beta/rc tags. -release = version - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -#language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = ['_build'] - -# The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'native' - -# A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] - -# If true, keep warnings as "system message" paragraphs in the built documents. -#keep_warnings = False - - -# -- Options for HTML output --------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'jrnl' - -# On read the docs, use their standard theme. -RTD_NEW_THEME = True - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -#html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -#html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -#html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -#html_domain_indices = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -html_show_sourcelink = False - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -html_show_sphinx = False - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = 'jrnldoc' - - -# -- Options for LaTeX output -------------------------------------------------- - -latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', - -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', - -# Additional stuff for the LaTeX preamble. -#'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass [howto/manual]). -latex_documents = [ - ('index', 'jrnl.tex', u'jrnl Documentation', - u'Manuel Ebert', 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -#latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -#latex_use_parts = False - -# If true, show page references after internal links. -#latex_show_pagerefs = False - -# If true, show URL addresses after external links. -#latex_show_urls = False - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -#latex_domain_indices = True - - -# -- Options for manual page output -------------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'jrnl', u'jrnl Documentation', - [u'Manuel Ebert'], 1) -] - -# If true, show URL addresses after external links. -#man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------------ - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ('index', 'jrnl', u'jrnl Documentation', - u'Manuel Ebert', 'jrnl', 'One line description of project.', - 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -#texinfo_appendices = [] - -# If false, no module index is generated. -#texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' - -# If true, do not generate a @detailmenu in the "Top" node's menu. -#texinfo_no_detailmenu = False -sys.path.append(os.path.abspath('_themes')) -html_theme_path = ['_themes'] -html_theme = 'jrnl' diff --git a/docs/encryption.md b/docs/encryption.md new file mode 100644 index 00000000..19bb178b --- /dev/null +++ b/docs/encryption.md @@ -0,0 +1,93 @@ +# Encryption + +## Encrypting and decrypting + +If you don't choose to encrypt your file when you run +`jrnl` for the first time, you can encrypt +your existing journal file or change its password using + +``` sh +jrnl --encrypt +``` + +If it is already encrypted, you will first be asked for the current +password. You can then enter a new password and your plain journal will +replaced by the encrypted file. Conversely, + +``` sh +jrnl --decrypt +``` + +will replace your encrypted journal file by a Journal in plain text. You +can also specify a filename, ie. `jrnl --decrypt plain_text_copy.txt`, +to leave your original file untouched. + +## Storing passwords in your keychain + +Whenever you encrypt your journal, you are asked whether you want to +store the encryption password in your keychain. If you do this, you +won't have to enter your password every time you want to write or read +your journal. + +If you don't 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 +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 -- it's 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 you're concerned about security, disable +history logging for journal in your `.bashrc` + +``` sh +HISTIGNORE="$HISTIGNORE:jrnl *" +``` + +If you are using zsh instead of bash, you can get the same behaviour +adding this to your `zshrc` + +``` sh +setopt HIST_IGNORE_SPACE +alias jrnl=" jrnl" +``` + +## Manual decryption + +Should you ever want to decrypt your journal manually, you can do so +with any program that supports the AES algorithm in CBC. The key used +for encryption is the SHA-256-hash of your password, the IV +(initialisation vector) is stored in the first 16 bytes of the encrypted +file. The plain text is encoded in UTF-8 and padded according to PKCS\#7 +before being encrypted. Here's a Python script that you can use to +decrypt your journal + +``` python +#!/usr/bin/env python3 + +import argparse +from Crypto.Cipher import AES +import getpass +import hashlib +import sys + +parser = argparse.ArgumentParser() +parser.add_argument("filepath", help="journal file to decrypt") +args = parser.parse_args() + +pwd = getpass.getpass() +key = hashlib.sha256(pwd.encode('utf-8')).digest() + +with open(args.filepath, 'rb') as f: + ciphertext = f.read() + +crypto = AES.new(key, AES.MODE_CBC, ciphertext[:16]) +plain = crypto.decrypt(ciphertext[16:]) +plain = plain.strip(plain[-1:]) +plain = plain.decode("utf-8") +print(plain) +``` diff --git a/docs/encryption.rst b/docs/encryption.rst deleted file mode 100644 index 73128898..00000000 --- a/docs/encryption.rst +++ /dev/null @@ -1,47 +0,0 @@ -.. _encryption: - -Encryption -========== - -Encrypting and decrypting -------------------------- - - -If you don't choose to encrypt your file when you run `jrnl` for the first time, you can encrypt your existing journal file or change its password using :: - - jrnl --encrypt - -If it is already encrypted, you will first be asked for the current password. You can then enter a new password and your plain journal will replaced by the encrypted file. Conversely, :: - - jrnl --decrypt - -will replace your encrypted journal file by a Journal in plain text. You can also specify a filename, i.e. ``jrnl --decrypt plain_text_copy.txt``, to leave your original file untouched. - - -Storing passwords in your keychain ----------------------------------- - -Whenever you encrypt your journal, you are asked whether you want to store the encryption password in your keychain. If you do this, you won't have to enter your password every time you want to write or read your journal. - -If you don't 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 journal and use the same password again. - -A note on security ------------------- - -While jrnl follows best practices, true security is an illusion. Specifically, jrnl will leave traces in your memory and your shell history -- it's meant to keep journals secure in transit, for example when storing it on an `untrusted `_ services such as Dropbox. If you're concerned about security, disable history logging for journal in your ``.bashrc`` :: - - HISTIGNORE="jrnl *:" - -Manual decryption ------------------ - -Should you ever want to decrypt your journal manually, you can do so with any program that supports the AES algorithm in CBC. The key used for encryption is the SHA-256-hash of your password, the IV (initialisation vector) is stored in the first 16 bytes of the encrypted file. The plain text is encoded in UTF-8 and padded according to PKCS#7 before being encrypted. So, to decrypt a journal file in python, run:: - - import hashlib, Crypto.Cipher - key = hashlib.sha256(my_password).digest() - with open("my_journal.txt") as f: - cipher = f.read() - crypto = AES.new(key, AES.MODE_CBC, iv = cipher[:16]) - plain = crypto.decrypt(cipher[16:]) - plain = plain.strip(plain[-1]) - plain = plain.decode("utf-8") diff --git a/docs/export.md b/docs/export.md new file mode 100644 index 00000000..f786a318 --- /dev/null +++ b/docs/export.md @@ -0,0 +1,76 @@ +# Import and Export + +## Tag export + +With + +``` sh +jrnl --tags +``` + +you'll get a list of all tags you used in your journal, sorted by most +frequent. Tags occurring several times in the same entry are only +counted as one. + +## List of all entries + +``` sh +jrnl --short +``` + +Will only display the date and title of each entry. + +## JSON export + +Can do + +``` sh +jrnl --export json +``` + +Why not create a [beautiful timeline](http://timeline.verite.co/) of +your journal? + +## Markdown export + +Use + +``` sh +jrnl --export markdown +``` + +Markdown is a simple markup language that is human readable and can be +used to be rendered to other formats (html, pdf). This README for +example is formatted in markdown and github makes it look nice. + +## Text export + +``` sh +jrnl --export text +``` + +Pretty-prints your entire journal. + +## Export to files + +You can specify the output file of your exported journal using the +`-o` argument + +``` sh +jrnl --export md -o journal.md +``` + +The above command will generate a file named `journal.md`. If the`-o` argument is a directory, jrnl will export each entry into an individual file + +``` sh +jrnl --export json -o my_entries/ +``` + +The contents of `my\_entries/` will then look like this: + +``` output +my_entries/ +|- 2013_06_03_a-beautiful-day.json +|- 2013_06_07_dinner-with-gabriel.json +|- ... +``` diff --git a/docs/export.rst b/docs/export.rst deleted file mode 100644 index 8b16348e..00000000 --- a/docs/export.rst +++ /dev/null @@ -1,78 +0,0 @@ -.. _export: - -Import and Export -================= - -Tag export ----------- - -With:: - - jrnl --tags - -you'll get a list of all tags you used in your journal, sorted by most frequent. Tags occurring several times in the same entry are only counted as one. - -List of all entries -------------------- - -:: - - jrnl --short - -Will only display the date and title of each entry. - -JSON export ------------ - -Can do:: - - jrnl --export json - -Why not create a `beautiful timeline `_ of your journal? - -Markdown export ---------------- - -Use:: - - jrnl --export markdown - -Markdown is a simple markup language that is human readable and can be used to be rendered to other formats (html, pdf). This README for example is formatted in markdown and github makes it look nice. - -Text export ------------ - -:: - - jrnl --export text - -Pretty-prints your entire journal. - -XML export ------------ - -:: - - jrnl --export xml - -Why anyone would want to export stuff to XML is beyond me, but here you go. - -Export to files ---------------- - -You can specify the output file of your exported journal using the `-o` argument:: - - jrnl --export md -o journal.md - -The above command will generate a file named `journal.md`. If the `-o` argument is a directory, jrnl will export each entry into an individual file:: - - jrnl --export json -o my_entries/ - -The contents of `my_entries/` will then look like this: - -.. code-block:: output - - my_entries/ - |- 2013_06_03_a-beautiful-day.json - |- 2013_06_07_dinner-with-gabriel.json - |- ... diff --git a/docs/index.rst b/docs/index.rst deleted file mode 100644 index c7d7119b..00000000 --- a/docs/index.rst +++ /dev/null @@ -1,20 +0,0 @@ -.. jrnl documentation master file, created by - sphinx-quickstart on Wed Aug 7 13:22:51 2013. - -jrnl: The command-line journal -============================== - -Release v\ |version|. - -Contents: - -.. toctree:: - :maxdepth: 3 - - overview - installation - usage - encryption - export - advanced - recipes diff --git a/docs/installation.md b/docs/installation.md new file mode 100644 index 00000000..36b694ce --- /dev/null +++ b/docs/installation.md @@ -0,0 +1,55 @@ +# Getting started + +## Installation + +On OS X, the easiest way to install *jrnl* is using +[Homebrew](http://brew.sh/) + +``` sh +brew install jrnl +``` + +On other platforms, install *jrnl* using pip + +``` sh +pip install jrnl +``` + +Or, if you want the option to encrypt your journal, + +``` sh +pip install jrnl[encrypted] +``` + +to install the dependencies for encrypting journals as well. + + +!!! note + Installing the encryption library, `pycrypto`, requires a `gcc` compiler. For this reason, jrnl will + not install `pycrypto` unless explicitly told so like this. You can [install PyCrypto manually](https://www.dlitz.net/software/pycrypto/) + first or install it with `pip install pycrypto` if you have a `gcc` compiler. + Also note that when using zsh, the correct syntax is `pip install "jrnl[encrypted]"` (note the quotes). + +The first time you run `jrnl` you will be asked where your journal file +should be created and whether you wish to encrypt it. + +## Quickstart + +to make a new entry, just type + +``` sh +jrnl yesterday: Called in sick. Used the time to clean the house and spent 4h on writing my book. +``` + +and hit return. `yesterday:` will be interpreted as a time stamp. +Everything until the first sentence mark (`.?!:`) will be interpreted as +the title, the rest as the body. In your journal file, the result will +look like this: + +``` output +2012-03-29 09:00 Called in sick. +Used the time to clean the house and spent 4h on writing my book. +``` + +If you just call `jrnl`, you will be prompted to compose your entry - +but you can also configure *jrnl* to use your external editor. diff --git a/docs/installation.rst b/docs/installation.rst deleted file mode 100644 index 1cabd58a..00000000 --- a/docs/installation.rst +++ /dev/null @@ -1,35 +0,0 @@ -.. _download: - -Getting started -=============== - -Installation ------------- - -Install *jrnl* using pip :: - - pip install jrnl - -Alternatively, on OS X with [Homebrew](http://brew.sh/) installed: - - brew install jrnl - -The first time you run ``jrnl`` you will be asked where your journal file should be created and whether you wish to encrypt it. - - -Quickstart ----------- - -to make a new entry, just type:: - - jrnl yesterday: Called in sick. Used the time to clean the house and spent 4h on writing my book. - -and hit return. ``yesterday:`` will be interpreted as a time stamp. Everything until the first sentence mark (``.?!:``) will be interpreted as the title, the rest as the body. In your journal file, the result will look like this: - -.. code-block:: output - - 2012-03-29 09:00 Called in sick. - Used the time to clean the house and spent 4h on writing my book. - -If you just call ``jrnl``, you will be prompted to compose your entry - but you can also configure *jrnl* to use your external editor. - diff --git a/docs/overview.md b/docs/overview.md new file mode 100644 index 00000000..8a0ec10f --- /dev/null +++ b/docs/overview.md @@ -0,0 +1,31 @@ +# Overview + +## What is jrnl? + +`jrnl` is a simple journal application for +your command line. Journals are stored as human readable plain text +files - you can put them into a Dropbox folder for instant syncing and +you can be assured that your journal will still be readable in 2050, +when all your fancy iPad journal applications will long be forgotten. + +`jrnl` also plays nice with the fabulous +[DayOne](http://dayoneapp.com) and can read and write directly from and +to DayOne Journals. + +Optionally, your journal can be encrypted using the [256-bit +AES](http://en.wikipedia.org/wiki/Advanced_Encryption_Standard). + +## Why keep a journal? + +Journals aren't just for people who have too much +time on their summer vacation. A journal helps you to keep track of the +things you get done and how you did them. Your imagination may be +limitless, but your memory isn't. + +For personal use, make it a good habit to write at least 20 words a day. +Just to reflect what made this day special, why you haven't wasted it. + +For professional use, consider a text-based journal to be the perfect +complement to your GTD todo list - a documentation of what and how +you've done it. Or use it as a quick way to keep a change log. Or use it +to keep a lab book. diff --git a/docs/overview.rst b/docs/overview.rst deleted file mode 100644 index 726fbcf1..00000000 --- a/docs/overview.rst +++ /dev/null @@ -1,23 +0,0 @@ -.. _overview: - -Overview -=============== - -What is jrnl? -------------- - -`jrnl` is a simple journal application for your command line. Journals are stored as human readable plain text files - you can put them into a Dropbox folder for instant syncing and you can be assured that your journal will still be readable in 2050, when all your fancy iPad journal applications will long be forgotten. - -`jrnl` also plays nice with the fabulous `DayOne `_ and can read and write directly from and to DayOne Journals. - -Optionally, your journal can be encrypted using the `256-bit AES `_. - -Why keep a journal? -------------------- - -Journals aren't only for 13-year old girls and people who have too much time on their summer vacation. A journal helps you to keep track of the things you get done and how you did them. Your imagination may be limitless, but your memory isn't. - -For personal use, make it a good habit to write at least 20 words a day. Just to reflect what made this day special, why you haven't wasted it. - -For professional use, consider a text-based journal to be the perfect complement to your GTD todo list - a documentation of what and how you've done it. Or use it as a quick way to keep a change log. Or use it to keep a lab book. - diff --git a/docs/recipes.md b/docs/recipes.md new file mode 100644 index 00000000..7af5b246 --- /dev/null +++ b/docs/recipes.md @@ -0,0 +1,197 @@ +# FAQ + +## Recipes + +### Co-occurrence of tags + +If I want to find out how often I mentioned my flatmates Alberto and +Melo in the same entry, I run + +``` sh +jrnl @alberto --tags | grep @melo +``` + +And will get something like `@melo: 9`, meaning there are 9 entries +where both `@alberto` and `@melo` are tagged. How does this work? First, +`jrnl @alberto` will filter the journal to only entries containing the +tag `@alberto`, and then the `--tags` option will print out how often +each tag occurred in this filtered journal. Finally, we pipe this to +`grep` which will only display the line containing `@melo`. + +### Combining filters + +You can do things like + +``` sh +jrnl @fixed -starred -n 10 -until "jan 2013" --short +``` + +To get a short summary of the 10 most recent, favourited entries before +January 1, 2013 that are tagged with `@fixed`. + +### Statistics + +How much did I write last year? + +``` sh +jrnl -from "jan 1 2013" -until "dec 31 2013" | wc -w +``` + +Will give you the number of words you wrote in 2013. How long is my +average entry? + +``` sh +expr $(jrnl --export text | wc -w) / $(jrnl --short | wc -l) +``` + +This will first get the total number of words in the journal and divide +it by the number of entries (this works because `jrnl --short` will +print exactly one line per entry). + +### Importing older files + +If you want to import a file as an entry to jrnl, you can just do `jrnl +< entry.ext`. But what if you want the modification date of the file to +be the date of the entry in jrnl? Try this + +``` sh +echo `stat -f %Sm -t '%d %b %Y at %H:%M: ' entry.txt` `cat entry.txt` | jrnl +``` + +The first part will format the modification date of `entry.txt`, and +then combine it with the contents of the file before piping it to jrnl. +If you do that often, consider creating a function in your `.bashrc` or +`.bash_profile` + +``` sh +jrnlimport () { + echo `stat -f %Sm -t '%d %b %Y at %H:%M: ' $1` `cat $1` | jrnl +} +``` + +### Using templates + +Say you always want to use the same template for creating new entries. +If you have an [external editor](../advanced) set up, you can use this: + +```sh +jrnl < my_template.txt +jrnl -1 --edit +``` + +Another nice solution that allows you to define individual prompts comes +from [Jacobo de +Vera](https://github.com/maebert/jrnl/issues/194#issuecomment-47402869): + +``` sh +function log_question() +{ + echo $1 + read + jrnl today: ${1}. $REPLY +} +log_question 'What did I achieve today?' +log_question 'What did I make progress with?' +``` + +## External editors + +To use external editors for writing and editing journal entries, set +them up in your `.jrnl_config` (see `advanced usage ` for +details). Generally, after writing an entry, you will have to save and +close the file to save the changes to jrnl. + +### Sublime Text + +To use Sublime Text, install the command line tools for Sublime Text and +configure your `.jrnl_config` like this: + +``` json +{ + "editor": "subl -w" +} +``` + +Note the `-w` flag to make sure jrnl waits for Sublime Text to close the +file before writing into the journal. + +### MacVim + +Similar to Sublime Text, MacVim must be started with a flag that tells +the the process to wait until the file is closed before passing control +back to journal. In the case of MacVim, this is `-f`: + +``` json +{ + "editor": "mvim -f" +} +``` + +### iA Writer + +On OS X, you can use the fabulous [iA +Writer](http://www.iawriter.com/mac) to write entries. Configure your +`.jrnl_config` like this: + +``` json +{ + "editor": "open -b pro.writer.mac -Wn" +} +``` + +What does this do? `open -b ...` opens a file using the application +identified by the bundle identifier (a unique string for every app out +there). `-Wn` tells the application to wait until it's closed before +passing back control, and to use a new instance of the application. + +If the `pro.writer.mac` bundle identifier is not found on your system, +you can find the right string to use by inspecting iA Writer's +`Info.plist` file in your shell: + +``` sh +grep -A 1 CFBundleIdentifier /Applications/iA\ Writer.app/Contents/Info.plist +``` + +### Notepad++ on Windows + +To set [Notepad++](http://notepad-plus-plus.org/) as your editor, edit +the jrnl config file (`.jrnl_config`) like this: + +``` json +{ + "editor": "C:\\Program Files (x86)\\Notepad++\\notepad++.exe -multiInst -nosession", +} +``` + +The double backslashes are needed so jrnl can read the file path +correctly. The `-multiInst -nosession` options will cause jrnl to open +its own Notepad++ window. + +### Visual Studio Code + +To set [Visual Studo Code](https://code.visualstudio.com) as your editor on Linux, edit `.jrnl_config` like this: + +```json +{ + "editor": "/usr/bin/code --wait", +} +``` + +The `--wait` argument tells VS Code to wait for files to be written out before handing back control to jrnl. + +On MacOS you will need to add VS Code to your PATH. You can do that by adding: + +```sh +export PATH="\$PATH:/Applications/Visual Studio Code.app/Contents/Resources/app/bin" +``` +to your `.bash_profile`, or by running the **Install 'code' command in PATH** command from the command pallet in VS Code. + +Then you can add: + +```javascript +{ + "editor": "code --wait", +} +``` + +to ``.jrnl_config``. See also the [Visual Studio Code documentation](https://code.visualstudio.com/docs/setup/mac) diff --git a/docs/recipes.rst b/docs/recipes.rst deleted file mode 100644 index e1aef9a9..00000000 --- a/docs/recipes.rst +++ /dev/null @@ -1,125 +0,0 @@ -.. _recipes: - -FAQ -=== - -Recipes -------- - -Co-occurrence of tags -~~~~~~~~~~~~~~~~~~~~~ - -If I want to find out how often I mentioned my flatmates Alberto and Melo in the same entry, I run :: - - jrnl @alberto --tags | grep @melo - -And will get something like ``@melo: 9``, meaning there are 9 entries where both ``@alberto`` and ``@melo`` are tagged. How does this work? First, ``jrnl @alberto`` will filter the journal to only entries containing the tag ``@alberto``, and then the ``--tags`` option will print out how often each tag occurred in this `filtered` journal. Finally, we pipe this to ``grep`` which will only display the line containing ``@melo``. - -Combining filters -~~~~~~~~~~~~~~~~~ - -You can do things like :: - - jrnl @fixed -starred -n 10 -until "jan 2013" --short - -To get a short summary of the 10 most recent, favourited entries before January 1, 2013 that are tagged with ``@fixed``. - -Statistics -~~~~~~~~~~ - -How much did I write last year? :: - - jrnl -from "jan 1 2013" -until "dec 31 2013" | wc -w - -Will give you the number of words you wrote in 2013. How long is my average entry? :: - - expr $(jrnl --export text | wc -w) / $(jrnl --short | wc -l) - -This will first get the total number of words in the journal and divide it by the number of entries (this works because ``jrnl --short`` will print exactly one line per entry). - -Importing older files -~~~~~~~~~~~~~~~~~~~~~ - -If you want to import a file as an entry to jrnl, you can just do ``jrnl < entry.ext``. But what if you want the modification date of the file to be the date of the entry in jrnl? Try this :: - - echo `stat -f %Sm -t '%d %b %Y at %H:%M: ' entry.txt` `cat entry.txt` | jrnl - -The first part will format the modification date of ``entry.txt``, and then combine it with the contents of the file before piping it to jrnl. If you do that often, consider creating a function in your ``.bashrc`` or ``.bash_profile`` - -.. code-block:: sh - - jrnlimport () { - echo `stat -f %Sm -t '%d %b %Y at %H:%M: ' $1` `cat $1` | jrnl - } - - -Using templates -~~~~~~~~~~~~~~~ - -Say you always want to use the same template for creating new entries. If you have an :doc:`external editor ` set up, you can use this :: - - jrnl < my_template.txt - $ jrnl -1 --edit - -Another nice solution that allows you to define individual prompts comes from `Jacobo de Vera `_: - -.. code-block:: sh - - function log_question() - { - echo $1 - read - jrnl today: ${1}. $REPLY - } - log_question 'What did I achieve today?' - log_question 'What did I make progress with?' - - -External editors ----------------- - -To use external editors for writing and editing journal entries, set them up in your ``.jrnl_config`` (see :doc:`advanced usage ` for details). Generally, after writing an entry, you will have to save and close the file to save the changes to jrnl. - -Sublime Text -~~~~~~~~~~~~ - -To use Sublime Text, install the command line tools for Sublime Text and configure your ``.jrnl_config`` like this: - -.. code-block:: javascript - - "editor": "subl -w" - -Note the ``-w`` flag to make sure jrnl waits for Sublime Text to close the file before writing into the journal. - - -MacVim -~~~~~~ - -Similar to Sublime Text, MacVim must be started with a flag that tells the the process to wait until the file is closed before passing control back to journal. In the case of MacVim, this is ``-f``: - -.. code-block:: javascript - - "editor": "mvim -f" - -iA Writer -~~~~~~~~~ - -On OS X, you can use the fabulous `iA Writer `_ to write entries. Configure your ``.jrnl_config`` like this: - -.. code-block:: javascript - - "editor": "open -b jp.informationarchitects.WriterForMacOSX -Wn" - -What does this do? ``open -b ...`` opens a file using the application identified by the bundle identifier (a unique string for every app out there). ``-Wn`` tells the application to wait until it's closed before passing back control, and to use a new instance of the application. - - -Notepad++ on Windows -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -To set `Notepad++ `_ as your editor, edit the jrnl config file (``.jrnl_config``) like this: - -.. code-block:: javascript - - "editor": "C:\\Program Files (x86)\\Notepad++\\notepad++.exe -multiInst -nosession", - -The double backslashes are needed so jrnl can read the file path correctly. The ``-multiInst -nosession`` options will cause jrnl to open its own Notepad++ window. diff --git a/docs/theme/img/banner_og.png b/docs/theme/img/banner_og.png new file mode 100644 index 00000000..9c0ec3d4 Binary files /dev/null and b/docs/theme/img/banner_og.png differ diff --git a/docs/theme/img/banner_twitter.png b/docs/theme/img/banner_twitter.png new file mode 100644 index 00000000..eab327cb Binary files /dev/null and b/docs/theme/img/banner_twitter.png differ diff --git a/docs/theme/img/favicon.ico b/docs/theme/img/favicon.ico new file mode 100644 index 00000000..feee4906 Binary files /dev/null and b/docs/theme/img/favicon.ico differ diff --git a/docs/theme/img/favicon.svg b/docs/theme/img/favicon.svg new file mode 100644 index 00000000..21beb0db --- /dev/null +++ b/docs/theme/img/favicon.svg @@ -0,0 +1,15 @@ + + + + favicon + Created with Sketch. + + + + + + + + + + \ No newline at end of file diff --git a/docs/theme/img/jrnl_white.svg b/docs/theme/img/jrnl_white.svg new file mode 100644 index 00000000..c324ab91 --- /dev/null +++ b/docs/theme/img/jrnl_white.svg @@ -0,0 +1,10 @@ + + + + jrnl_white + Created with Sketch. + + + + + \ No newline at end of file diff --git a/docs/theme/img/logo.svg b/docs/theme/img/logo.svg new file mode 100644 index 00000000..b843bed8 --- /dev/null +++ b/docs/theme/img/logo.svg @@ -0,0 +1,16 @@ + + + + logo + Created with Sketch. + + + + + + + + \ No newline at end of file diff --git a/docs/theme/img/logo_white.svg b/docs/theme/img/logo_white.svg new file mode 100644 index 00000000..e4e8e078 --- /dev/null +++ b/docs/theme/img/logo_white.svg @@ -0,0 +1,9 @@ + + + + logo_white + Created with Sketch. + + + + \ No newline at end of file diff --git a/docs/theme/img/sprites.svg b/docs/theme/img/sprites.svg new file mode 100644 index 00000000..32091555 --- /dev/null +++ b/docs/theme/img/sprites.svg @@ -0,0 +1,18 @@ + + + + sprites + Created with Sketch. + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/theme/index.css b/docs/theme/index.css new file mode 100644 index 00000000..db3fb0c5 --- /dev/null +++ b/docs/theme/index.css @@ -0,0 +1,307 @@ +article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}[hidden]{display:none}html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{font-size:2em;margin:.67em 0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}mark{background:#ff0;color:#000}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}q{quotes:"\201C" "\201D" "\2018" "\2019"}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:0}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}button,input,select,textarea{font-family:inherit;font-size:100%;margin:0}button,input{line-height:normal}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0} + +body +{ + background-color: #FAFDFE; + background-color: #f7f8f9; + font-family: "Open Sans", "Helvetica Neue", sans-serif; + font-weight: 300; +} + +.icon { + background-image: url("img/sprites.svg"); + width: 32px; + height: 32px; + display: inline-block; + font-size: 40px; + background-size: 200px 80px; +} + +h3 { font-weight: 400; } + +.icon.secure { + background-position: 0em 0em; +} + +.icon.future { + background-position: -1em 0em; +} + +.icon.search { + background-position: -2em 0em; +} + +.icon.nli { + background-position: -3em 0em; +} + +.icon.share { + background-position: 0em -1em; +} + +.icon.sync { + background-position: 0em -1em; +} + +.icon.dayone { + background-position: -1em -1em; +} + +.icon.github { + background-position: -2em -1em; +} + +.icon.folders { + background-position: -3em -1em; +} + +.icon.twitter { + background-position: -4em -1em; +} + +header { + background-image: linear-gradient(211deg, #95699C 0%, #604385 100%); + color: white; + border: 0px solid transparent; + display: relative; + padding-top: 150px; + overflow: hidden; +} + +#terminal { + background: #1B1C2E; + max-width: 520px; + box-shadow: 0 -2px 16px 0 rgba(0,0,0,0.35); + border-radius: 6px 6px 0 0; + min-height: 100px; + margin: 0px auto; + position: relative; + /*transform: translateY(40px);*/ + color: #f7f8f9; + font-family: "Monaco", "Courier New"; + font-size: 12pt; + padding: 45px 20px 0px 20px; + line-height: 165%; +} + +#terminal b { + font-weight: normal; + color: #C2CDD9; +} + +#terminal i { + font-style: normal; + color: #BB97BA; +} + +#terminal:before { + content: ''; + position: absolute; + top: 15px; + left: 15px; + display: inline-block; + width: 15px; + height: 15px; + border-radius: 50%; + background: #3B3B4A; + box-shadow: 25px 0 0 #3B3B4A, 50px 0 0 #3B3B4A; +} + +#typed:before { + content: "$ "; + color: #A879A7; +} + +#twitter { + display: block; + position: absolute; + text-decoration: none; + top: 20px; + right: 20px; + border: 1px solid white; + padding: 5px 10px; + color: white; + border-radius: 3px; + opacity: .7; +} + +#twitter .icon { + transform: scale(.5); + vertical-align: -18%; + margin: 0; + padding: 0; +} + +#twitter:hover, +#twitter:active { + opacity: 1; + text-decoration: none; +} + +#title { + max-width: 630px; + margin: 0 auto; + padding: 0px 20px; +} + +#prompt { + max-width: 700px; + margin: 100px auto 0px auto; + padding: 0px 20px; +} + +header img { + float: left; + margin-right: 30px; +} + +h1 { + color: white; + font-weight: 300; +} + +nav { + text-align: center; +} + +nav a#twitter-nav { + display: none; +} + +a { + color: #684688; + text-decoration: underline; +} + +nav a { + font-size: 14pt; + line-height: 40pt; + margin: 0 40px; +} + +a:hover { + color: #A3629F; +} + +nav a.cta { + display: inline-block; + color: white; + background-image: linear-gradient(259deg, #A3629F 0%, #604385 100%); + box-shadow: 0 2px 8px 0 rgba(0,0,0,0.25); + border-radius: 50px; + padding: 0px 30pt; + white-space: nowrap; + transition: all .1s ease; + font-weight: 600; + text-decoration: none; +} + +nav a.cta:hover { + text-decoration: none; + background-image: linear-gradient(259deg, #AE57A8 0%, #68419C 100%); + box-shadow: 0 4px 16px 0 rgba(0,0,0,0.25); + color: #f7f8f9; +} + +main { + padding: 50px 0 0 0; +} + + +.flex { + display: flex; + margin: 0 auto; + max-width: 920px; + flex-wrap: wrap; + padding: 20px 20px; + justify-content: space-between; + +} + +.flex section { + /*margin: 20px;*/ + margin-top: 40px; + width: 32%; +} + +.flex section:first-child { + margin-left: 0px; +} +.flex section:last-child { + margin-right: 0px; +} + + +.flex section i { + float: left; + left: 0; + display: block; + margin: 0px auto 10px auto; +} + +.flex section h3 { + margin-top: 0; + font-size: 14pt; + color: #684688; + margin-bottom: .5em; + font-weight: 300; + margin-left: 40px; +} + +.flex section p { + padding-left: 40px; + color: #888; + font-size: 12pt; + margin: 0; +} + +footer { + max-width: 700px; + margin: 20px auto; + padding: 0 20px 20px 20px; + font-size: 10pt; + opacity: .5; + text-align: center; +} + +@media screen and (max-width: 680px) { + .flex { + display: block; + padding: 0; + } + .flex section { + width: 100%; + } + + main { + padding: 20px; + margin: 0; + width: calc(100% - 40px); + } + + nav a, + nav a#twitter-nav { + display: inline-block; + margin: 0px 10px; + } + + nav a.cta { + display: block; + margin: 20px; + } + + header #twitter { + display: none; + } + + header #logo { + display: block; + float: none; + margin: 0px auto; + } + + header #title br { + display: none; + } + +} diff --git a/docs/theme/index.html b/docs/theme/index.html new file mode 100755 index 00000000..0c179210 --- /dev/null +++ b/docs/theme/index.html @@ -0,0 +1,126 @@ + + + + + + jrnl - The Command Line Journal + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +

Collect your thoughts and notes
without leaving the command line.

+
+
+
+
+
+
+
+
+ +
+
+ +

Human friendly.

+

jrnl has a natural-language interface so you don't have to remember cryptic shortcuts when you're writing down your thoughts.

+
+
+ +

Future-proof.

+

Your journals are stored in plain-text files that will still be readable in 50 years when all your fancy iPad apps will have gone the way of the Dodo.

+
+
+ +

Secure.

+

Encrypt your journals with the industry-strength AES encryption. The NSA won't be able to read your dirty secrets.

+
+
+ +

Accessible anywhere.

+

Sync your journals with Dropbox and capture your thoughts where ever you are

+
+
+ +

DayOne compatible.

+

Read, write and search your DayOne journal from the command line.

+
+
+ +

Free & Open Source.

+

jrnl is made by a bunch of really friendly and remarkably attractive people. Maybe even you?

+
+
+ +

For work and play.

+

Effortlessly access several journals for all parts of your life.

+
+
+
+ + + + + + diff --git a/docs/theme/index.js b/docs/theme/index.js new file mode 100644 index 00000000..7ad89342 --- /dev/null +++ b/docs/theme/index.js @@ -0,0 +1 @@ +var typed2 = diff --git a/docs/usage.md b/docs/usage.md new file mode 100644 index 00000000..fa5050a0 --- /dev/null +++ b/docs/usage.md @@ -0,0 +1,182 @@ +# 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. + +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). + +## Listing Journals + +You can list the journals accessible by jrnl + +``` 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. +``` + +!!! 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 `). + +You can also import an entry directly from a file + +``` sh +jrnl < my_entry.txt +``` + +### Smart timestamps + +Timestamps that work: + + - at 6am + - yesterday + - last monday + - sunday at noon + - 2 march 2012 + - 7 apr + - 5/20/1998 at 23:42 + +### Starring entries + +To mark an entry as a favourite, simply "star" it + +``` 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: + + - `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). + +## Viewing + +``` sh +jrnl -n 10 +``` + +will list you the ten latest entries (if you're lazy, `jrnl -10` will do +the same), + +``` 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 + +``` sh +jrnl -starred +``` + +## Using Tags + +Keep track of people, projects or locations, by tagging them with an `@` +in your entries + +``` sh +jrnl Had a wonderful day on the @beach with @Tom and @Anna. +``` + +You can filter your journal entries just like this: + +``` sh +jrnl @pinkie @WorldDomination +``` + +Will print all entries in which either `@pinkie` or `@WorldDomination` +occurred. + +``` sh +jrnl -n 5 -and @pineapple @lubricant +``` + +the last five entries containing both `@pineapple` **and** `@lubricant`. +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. + +## Editing older entries + +You can edit selected entries after you wrote them. This is particularly +useful when your journal file is encrypted or if you're using a DayOne +journal. To use this feature, you need to have an editor configured in +your journal configuration file (see `advanced usage `) + +``` 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. + +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 + +``` sh +jrnl @girlfriend -until 'june 2012' --edit +``` + +Just select all text, press delete, and everything is gone... + +### Editing DayOne Journals + +DayOne journals can be edited exactly the same way, however the output +looks a little bit different because of the way DayOne stores its +entries: + +```md +# af8dbd0d43fb55458f11aad586ea2abf +2013-05-02 15:30 I told everyone I built my @robot wife for sex. +But late at night when we're alone we mostly play Battleship. + +# 2391048fe24111e1983ed49a20be6f9e +2013-08-10 03:22 I had all kinds of plans in case of a @zombie attack. +I just figured I'd be on the other side. +``` + +The long strings starting with hash symbol are the so-called UUIDs, +unique identifiers for each entry. Don't touch them. If you do, then the +old entry would get deleted and a new one written, which means that you +could lose DayOne data that jrnl can't handle (such as as the entry's +geolocation). diff --git a/docs/usage.rst b/docs/usage.rst deleted file mode 100644 index f9cdb60c..00000000 --- a/docs/usage.rst +++ /dev/null @@ -1,134 +0,0 @@ -.. _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. - -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). - -Listing Journals ----------------- - -You can list the journals accessible by jrnl:: - - 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:: - - jrnl today at 3am: I just met Steve Buscemi in a bar! He looked funny. - - -.. 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, :doc:`use an external editor `). - -You can also import an entry directly from a file:: - - jrnl < my_entry.txt - -Smart timestamps -~~~~~~~~~~~~~~~~ - -Timestamps that work: - -* at 6am -* yesterday -* last monday -* sunday at noon -* 2 march 2012 -* 7 apr -* 5/20/1998 at 23:42 - -Starring entries -~~~~~~~~~~~~~~~~ - -To mark an entry as a favourite, simply "star" it:: - - 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: - -* ``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). - -Viewing -------- - -:: - - jrnl -n 10 - -will list you the ten latest entries (if you're lazy, ``jrnl -10`` will do the same), :: - - 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 :: - - jrnl -starred - -Using Tags ----------- - -Keep track of people, projects or locations, by tagging them with an ``@`` in your entries :: - - jrnl Had a wonderful day on the @beach with @Tom and @Anna. - -You can filter your journal entries just like this: :: - - jrnl @pinkie @WorldDomination - -Will print all entries in which either ``@pinkie`` or ``@WorldDomination`` occurred. :: - - jrnl -n 5 -and @pineapple @lubricant - -the last five entries containing both ``@pineapple`` **and** ``@lubricant``. 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. - -Editing older entries ---------------------- - -You can edit selected entries after you wrote them. This is particularly useful when your journal file is encrypted or if you're using a DayOne journal. To use this feature, you need to have an editor configured in your journal configuration file (see :doc:`advanced usage `):: - - 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. - -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:: - - jrnl @girlfriend -until 'june 2012' --edit - -Just select all text, press delete, and everything is gone... - -Editing DayOne Journals -~~~~~~~~~~~~~~~~~~~~~~~ - -DayOne journals can be edited exactly the same way, however the output looks a little bit different because of the way DayOne stores its entries: - -.. code-block:: output - - # af8dbd0d43fb55458f11aad586ea2abf - 2013-05-02 15:30 I told everyone I built my @robot wife for sex. - But late at night when we're alone we mostly play Battleship. - - # 2391048fe24111e1983ed49a20be6f9e - 2013-08-10 03:22 I had all kinds of plans in case of a @zombie attack. - I just figured I'd be on the other side. - -The long strings starting with hash symbol are the so-called UUIDs, unique identifiers for each entry. Don't touch them. If you do, then the old entry would get deleted and a new one written, which means that you could lose DayOne data that jrnl can't handle (such as as the entry's geolocation). - diff --git a/features/data/configs/brackets.yaml b/features/data/configs/brackets.yaml new file mode 100644 index 00000000..e658947c --- /dev/null +++ b/features/data/configs/brackets.yaml @@ -0,0 +1,12 @@ +default_hour: 9 +default_minute: 0 +editor: "" +encrypt: false +highlight: true +journals: + default: features/journals/brackets.journal +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" diff --git a/features/data/configs/mostlyreadabledates.yaml b/features/data/configs/mostlyreadabledates.yaml new file mode 100644 index 00000000..5e3e1a15 --- /dev/null +++ b/features/data/configs/mostlyreadabledates.yaml @@ -0,0 +1,12 @@ +default_hour: 9 +default_minute: 0 +editor: "" +encrypt: false +highlight: true +journals: + default: features/journals/mostlyreadabledates.journal +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" diff --git a/features/data/configs/multiple.yaml b/features/data/configs/multiple.yaml index 1bbb872f..2e282232 100644 --- a/features/data/configs/multiple.yaml +++ b/features/data/configs/multiple.yaml @@ -9,6 +9,9 @@ journals: ideas: features/journals/nothing.journal simple: features/journals/simple.journal work: features/journals/work.journal + new_encrypted: + encrypt: true + journal: features/journals/new_encrypted.journal linewrap: 80 password: '' tagsymbols: '@' diff --git a/features/data/configs/unreadabledates.yaml b/features/data/configs/unreadabledates.yaml new file mode 100644 index 00000000..474e7aae --- /dev/null +++ b/features/data/configs/unreadabledates.yaml @@ -0,0 +1,12 @@ +default_hour: 9 +default_minute: 0 +editor: "" +encrypt: false +highlight: true +journals: + default: features/journals/unreadabledates.journal +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" diff --git a/features/data/journals/brackets.journal b/features/data/journals/brackets.journal new file mode 100644 index 00000000..4649ea3e --- /dev/null +++ b/features/data/journals/brackets.journal @@ -0,0 +1,2 @@ +[2019-07-08 05:42] Entry subject +[1] line starting with 1 diff --git a/features/data/journals/mostlyreadabledates.journal b/features/data/journals/mostlyreadabledates.journal new file mode 100644 index 00000000..bd211bf5 --- /dev/null +++ b/features/data/journals/mostlyreadabledates.journal @@ -0,0 +1,8 @@ +[2019-07-18 14:23] Entry subject +Time machines are possible. I know, because I've built one in my garage. + +[2019-07-19 14:23] Entry subject +I'm going to activate the machine. Nobody knows what comes next after this. Or before this? + +[2019-07 14:23] Entry subject +I've crossed so many timelines. Is there any going back? diff --git a/features/data/journals/simple_jrnl-1-9-5.journal b/features/data/journals/simple_jrnl-1-9-5.journal index f660305b..7bb6c5ac 100644 --- a/features/data/journals/simple_jrnl-1-9-5.journal +++ b/features/data/journals/simple_jrnl-1-9-5.journal @@ -1,3 +1,13 @@ 2010-06-10 15:00 A life without chocolate is like a bad analogy. 2013-06-10 15:40 He said "[this] is the best time to be alive". +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent malesuada +quis est ac dignissim. Aliquam dignissim rutrum pretium. Phasellus pellentesque +augue et venenatis facilisis. + +[2019-08-03 12:55] Some chat log or something + +Suspendisse potenti. Sed dignissim sed nisl eu consequat. Aenean ante ex, +elementum ut interdum et, mattis eget lacus. In commodo nulla nec tellus +placerat, sed ultricies metus bibendum. Duis eget venenatis erat. In at dolor +dui. diff --git a/features/data/journals/unreadabledates.journal b/features/data/journals/unreadabledates.journal new file mode 100644 index 00000000..53ef1d60 --- /dev/null +++ b/features/data/journals/unreadabledates.journal @@ -0,0 +1,5 @@ +[ashasd7zdskhz7asdkjasd] Entry subject +I've lost track of time. + +[sadfhakjsdf88sdf7sdff] Entry subject +Time has no meaning. diff --git a/features/dayone.feature b/features/dayone.feature deleted file mode 100644 index 6b3ef237..00000000 --- a/features/dayone.feature +++ /dev/null @@ -1,57 +0,0 @@ -Feature: DayOne Ingetration - - Scenario: Loading a DayOne Journal - Given we use the config "dayone.yaml" - When we run "jrnl -from 'feb 2013'" - Then we should get no error - and the output should be - """ - 2013-05-17 11:39 This entry has tags! - - 2013-06-17 20:38 This entry has a location. - - 2013-07-17 11:38 This entry is starred! - """ - - @skip - Scenario: Entries without timezone information will be interpreted as in the current timezone - Given we use the config "dayone.yaml" - When we run "jrnl -until 'feb 2013'" - Then we should get no error - and the output should contain "2013-01-17T18:37Z" in the local time - - Scenario: Writing into Dayone - Given we use the config "dayone.yaml" - When we run "jrnl 01 may 1979: Being born hurts." - and we run "jrnl -until 1980" - Then the output should be - """ - 1979-05-01 09:00 Being born hurts. - """ - - Scenario: Loading tags from a DayOne Journal - Given we use the config "dayone.yaml" - When we run "jrnl --tags" - Then the output should be - """ - @work : 1 - @play : 1 - """ - - Scenario: Saving tags from a DayOne Journal - Given we use the config "dayone.yaml" - When we run "jrnl A hard day at @work" - and we run "jrnl --tags" - Then the output should be - """ - @work : 2 - @play : 1 - """ - - Scenario: Filtering by tags from a DayOne Journal - Given we use the config "dayone.yaml" - When we run "jrnl @work" - Then the output should be - """ - 2013-05-17 11:39 This entry has tags! - """ diff --git a/features/encryption.feature b/features/encryption.feature index ebb3cc02..82d971eb 100644 --- a/features/encryption.feature +++ b/features/encryption.feature @@ -29,14 +29,3 @@ When we run "jrnl simple -n 1" Then we should not see the message "Password" and the output should contain "2013-06-10 15:40 Life is good" - - Scenario: Upgrading a journal encrypted with jrnl 1.x - Given we use the config "encrypted_old.json" - When we run "jrnl -n 1" and enter - """ - Y - bad doggie no biscuit - bad doggie no biscuit - """ - Then we should see the message "Password" - and the output should contain "2013-06-10 15:40 Life is good" diff --git a/features/exporting.feature b/features/exporting.feature index 78198aa5..db2ef5b3 100644 --- a/features/exporting.feature +++ b/features/exporting.feature @@ -20,13 +20,6 @@ Feature: Exporting a Journal and "tags" in the json output should contain "@journal" and "tags" in the json output should not contain "@dan" - Scenario: Exporting dayone to json - Given we use the config "dayone.yaml" - When we run "jrnl --export json" - Then we should get no error - and the output should be parsable as json - and the json output should contain entries.0.uuid = "4BB1F46946AD439996C9B59DE7C4DDC1" - Scenario: Exporting using custom templates Given we use the config "basic.yaml" Given we load template "sample.template" @@ -49,11 +42,9 @@ Feature: Exporting a Journal When we run "jrnl --export markdown" Then the output should be """ - 2015 - ==== + # 2015 - April - ----- + ## April ### 2015-04-14 13:23 Heading Test diff --git a/features/multiple_journals.feature b/features/multiple_journals.feature index fb26eef8..1d4943ee 100644 --- a/features/multiple_journals.feature +++ b/features/multiple_journals.feature @@ -39,3 +39,8 @@ Feature: Multiple journals Given we use the config "bug343.yaml" When we run "jrnl a long day in the office" Then we should see the message "No default journal configured" + + Scenario: Don't crash if no file exists for a configured encrypted journal + Given we use the config "multiple.yaml" + When we run "jrnl new_encrypted Adding first entry" and enter "these three eyes" + Then we should see the message "Journal 'new_encrypted' created" diff --git a/features/regression.feature b/features/regression.feature index aa78ae3b..3e644b19 100644 --- a/features/regression.feature +++ b/features/regression.feature @@ -43,32 +43,22 @@ Feature: Zapped bugs should stay dead. | Hope to get a lot of traffic. """ - Scenario: Upgrade and parse journals with square brackets - Given we use the config "upgrade_from_195.json" - When we run "jrnl -2" and enter "Y" - Then the output should contain - """ - 2010-06-10 15:00 A life without chocolate is like a bad analogy. + Scenario: Integers in square brackets should not be read as dates + Given we use the config "brackets.yaml" + When we run "jrnl -1" + Then the output should contain "[1] line starting with 1" - 2013-06-10 15:40 He said "[this] is the best time to be alive". - """ + Scenario: Journals with unreadable dates should still be viewable + Given we use the config "unreadabledates.yaml" + When we run "jrnl -2" + Then the output should contain "I've lost track of time." + Then the output should contain "Time has no meaning." - Scenario: Title with an embedded period on DayOne journal - Given we use the config "dayone.yaml" - When we run "jrnl 04-24-2014: "Ran 6.2 miles today in 1:02:03. I'm feeling sore because I forgot to stretch."" - Then we should see the message "Entry added" - When we run "jrnl -1" - Then the output should be - """ - 2014-04-24 09:00 Ran 6.2 miles today in 1:02:03. - | I'm feeling sore because I forgot to stretch. - """ + Scenario: Journals with readable dates AND unreadable dates should still contain all data. + Given we use the config "mostlyreadabledates.yaml" + When we run "jrnl -3" + Then the output should contain "Time machines are possible." + When we run "jrnl -1" + Then the output should contain "I'm going to activate the machine." + Then the output should contain "I've crossed so many timelines. Is there any going back?" - Scenario: DayOne tag searching should work with tags containing a mixture of upper and lower case. - # https://github.com/maebert/jrnl/issues/354 - Given we use the config "dayone.yaml" - When we run "jrnl @plAy" - Then the output should contain - """ - 2013-05-17 11:39 This entry has tags! - """ diff --git a/features/steps/core.py b/features/steps/core.py index 4fabfcd9..a6fcae16 100644 --- a/features/steps/core.py +++ b/features/steps/core.py @@ -225,7 +225,7 @@ def check_journal_content(context, text, journal_name="default"): @then('journal "{journal_name}" should not exist') def journal_doesnt_exist(context, journal_name="default"): with open(install.CONFIG_FILE_PATH) as config_file: - config = yaml.load(config_file) + config = yaml.load(config_file, Loader=yaml.FullLoader) journal_path = config['journals'][journal_name] assert not os.path.exists(journal_path) diff --git a/features/tagging.feature b/features/tagging.feature index cc686673..2cbf7ce1 100644 --- a/features/tagging.feature +++ b/features/tagging.feature @@ -50,3 +50,35 @@ Feature: Tagging @foo : 1 @bar : 1 """ + + Scenario: Excluding a tag should filter it + Given we use the config "basic.yaml" + When we run "jrnl today: @foo came over, we went to a bar" + When we run "jrnl I have decided I did not enjoy that @bar" + When we run "jrnl --tags -not @bar" + Then the output should be + """ + @foo : 1 + """ + + Scenario: Excluding a tag should filter an entry, even if an unfiltered tag is in that entry + Given we use the config "basic.yaml" + When we run "jrnl today: I do @not think this will show up @thought" + When we run "jrnl today: I think this will show up @thought" + When we run "jrnl --tags -not @not" + Then the output should be + """ + @thought : 1 + """ + + Scenario: Excluding multiple tags should filter them + Given we use the config "basic.yaml" + When we run "jrnl today: I do @not think this will show up @thought" + When we run "jrnl today: I think this will show up @thought" + When we run "jrnl today: This should @never show up @thought" + When we run "jrnl today: What a nice day for filtering @thought" + When we run "jrnl --tags -not @not @never" + Then the output should be + """ + @thought : 2 + """ diff --git a/features/upgrade.feature b/features/upgrade.feature new file mode 100644 index 00000000..bce026b8 --- /dev/null +++ b/features/upgrade.feature @@ -0,0 +1,23 @@ +Feature: Upgrading Journals from 1.x.x to 2.x.x + + Scenario: Upgrade and parse journals with square brackets + Given we use the config "upgrade_from_195.json" + When we run "jrnl -9" and enter "Y" + Then the output should contain + """ + 2010-06-10 15:00 A life without chocolate is like a bad analogy. + + 2013-06-10 15:40 He said "[this] is the best time to be alive". + """ + Then the journal should have 2 entries + + Scenario: Upgrading a journal encrypted with jrnl 1.x + Given we use the config "encrypted_old.json" + When we run "jrnl -n 1" and enter + """ + Y + bad doggie no biscuit + bad doggie no biscuit + """ + Then we should see the message "Password" + and the output should contain "2013-06-10 15:40 Life is good" diff --git a/jrnl/EncryptedJournal.py b/jrnl/EncryptedJournal.py index a29db554..a83651e4 100644 --- a/jrnl/EncryptedJournal.py +++ b/jrnl/EncryptedJournal.py @@ -5,7 +5,13 @@ 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 getpass +import logging + +log = logging.getLogger() def make_key(password): @@ -27,6 +33,33 @@ class EncryptedJournal(Journal.Journal): super(EncryptedJournal, self).__init__(name, **kwargs) self.config['encrypt'] = True + def open(self, filename=None): + """Opens the journal file defined in the config and parses it into a list of Entries. + Entries have the form (date, title, body).""" + filename = filename or self.config['journal'] + + if not os.path.exists(filename): + password = util.getpass("Enter password for new journal: ") + if password: + if util.yesno("Do you want to store the password in your keychain?", default=True): + util.set_keychain(self.name, password) + else: + util.set_keychain(self.name, None) + self.config['password'] = password + text = "" + self._store(filename, text) + util.prompt("[Journal '{0}' created at {1}]".format(self.name, filename)) + else: + util.prompt("No password supplied for encrypted journal") + sys.exit(1) + else: + text = self._load(filename) + self.entries = self._parse(text) + self.sort() + log.debug("opened %s with %d entries", self.__class__.__name__, len(self)) + return self + + def _load(self, filename, password=None): """Loads an encrypted journal from a file and tries to decrypt it. If password is not provided, will look for password in the keychain diff --git a/jrnl/Journal.py b/jrnl/Journal.py index 8eb1d2da..dd1bd370 100644 --- a/jrnl/Journal.py +++ b/jrnl/Journal.py @@ -84,9 +84,20 @@ class Journal(object): def write(self, filename=None): """Dumps the journal into the config file, overwriting it""" filename = filename or self.config['journal'] - text = "\n".join([e.__unicode__() for e in self.entries]) + text = self._to_text() self._store(filename, text) + def validate_parsing(self): + """Confirms that the jrnl is still parsed correctly after being dumped to text.""" + new_entries = self._parse(self._to_text()) + for i, entry in enumerate(self.entries): + if entry != new_entries[i]: + return False + return True + + def _to_text(self): + return "\n".join([e.__unicode__() for e in self.entries]) + def _load(self, filename): raise NotImplementedError @@ -99,8 +110,14 @@ class Journal(object): def _parse(self, journal_txt): """Parses a journal that's stored in a string and returns a list of entries""" + + # Return empty array if the journal is blank + if not journal_txt: + return [] + # Initialise our current entry entries = [] + date_blob_re = re.compile("(?:^|\n)\[([^\\]]+)\] ") last_entry_pos = 0 for match in date_blob_re.finditer(journal_txt): @@ -111,9 +128,13 @@ class Journal(object): entries[-1].text = journal_txt[last_entry_pos:match.start()] last_entry_pos = match.end() entries.append(Entry.Entry(self, date=new_date)) - # Finish the last entry - if entries: - entries[-1].text = journal_txt[last_entry_pos:] + + # If no entries were found, treat all the existing text as an entry made now + if not entries: + entries.append(Entry.Entry(self, date=time.parse("now"))) + + # Fill in the text of the last entry + entries[-1].text = journal_txt[last_entry_pos:] for entry in entries: entry._parse_text() @@ -165,7 +186,7 @@ class Journal(object): tag_counts = set([(tags.count(tag), tag) for tag in tags]) return [Tag(tag, count=count) for count, tag in sorted(tag_counts)] - def filter(self, tags=[], start_date=None, end_date=None, starred=False, strict=False, short=False): + def filter(self, tags=[], start_date=None, end_date=None, starred=False, strict=False, short=False, exclude=[]): """Removes all entries from the journal that don't match the filter. tags is a list of tags, each being a string that starts with one of the @@ -176,19 +197,24 @@ class Journal(object): starred limits journal to starred entries If strict is True, all tags must be present in an entry. If false, the - entry is kept if any tag is present.""" + + exclude is a list of the tags which should not appear in the results. + entry is kept if any tag is present, unless they appear in exclude.""" self.search_tags = set([tag.lower() for tag in tags]) + excluded_tags = set([tag.lower() for tag in exclude]) end_date = time.parse(end_date, inclusive=True) start_date = time.parse(start_date) # If strict mode is on, all tags have to be present in entry tagged = self.search_tags.issubset if strict else self.search_tags.intersection + excluded = lambda tags: len([tag for tag in tags if tag in excluded_tags]) > 0 result = [ entry for entry in self.entries if (not tags or tagged(entry.tags)) and (not starred or entry.starred) and (not start_date or entry.date >= start_date) and (not end_date or entry.date <= end_date) + and (not exclude or not excluded(entry.tags)) ] self.entries = result @@ -207,7 +233,11 @@ class Journal(object): if not date: colon_pos = first_line.find(": ") if colon_pos > 0: - date = time.parse(raw[:colon_pos], default_hour=self.config['default_hour'], default_minute=self.config['default_minute']) + date = time.parse( + raw[:colon_pos], + default_hour=self.config['default_hour'], + default_minute=self.config['default_minute'] + ) if date: # Parsed successfully, strip that from the raw text starred = raw[:colon_pos].strip().endswith("*") raw = raw[colon_pos + 1:].strip() @@ -269,6 +299,7 @@ class LegacyJournal(Journal): # Initialise our current entry entries = [] current_entry = None + new_date_format_regex = re.compile(r'(^\[[^\]]+\].*?$)') for line in journal_txt.splitlines(): line = line.rstrip() try: @@ -288,7 +319,9 @@ class LegacyJournal(Journal): current_entry = Entry.Entry(self, date=new_date, text=line[date_length + 1:], starred=starred) except ValueError: # Happens when we can't parse the start of the line as an date. - # In this case, just append line to our body. + # In this case, just append line to our body (after some + # escaping for the new format). + line = new_date_format_regex.sub(r' \1', line) if current_entry: current_entry.text += line + u"\n" diff --git a/jrnl/__init__.py b/jrnl/__init__.py index 796c58c4..da5c2df9 100644 --- a/jrnl/__init__.py +++ b/jrnl/__init__.py @@ -8,7 +8,7 @@ jrnl is a simple journal application for your command line. from __future__ import absolute_import __title__ = 'jrnl' -__version__ = '2.0.0-rc1' +__version__ = '2.0.0-rc3' __author__ = 'Manuel Ebert' __license__ = 'MIT License' __copyright__ = 'Copyright 2013 - 2015 Manuel Ebert' diff --git a/jrnl/cli.py b/jrnl/cli.py index 49bbcb6a..65a53516 100644 --- a/jrnl/cli.py +++ b/jrnl/cli.py @@ -13,7 +13,7 @@ from . import Journal from . import util from . import install from . import plugins -from .util import ERROR_COLOR, RESET_COLOR +from .util import ERROR_COLOR, RESET_COLOR, UserAbort import jrnl import argparse import sys @@ -39,6 +39,7 @@ def parse_args(args=None): reading.add_argument('-and', dest='strict', action="store_true", help='Filter by tags using AND (default: OR)') reading.add_argument('-starred', dest='starred', action="store_true", help='Show only starred entries') reading.add_argument('-n', dest='limit', default=None, metavar="N", help="Shows the last n entries matching the filter. '-n 3' and '-3' have the same effect.", nargs="?", type=int) + reading.add_argument('-not', dest='excluded', nargs='+', default=[], metavar="E", help="Exclude entries with these tags") exporting = parser.add_argument_group('Export / Import', 'Options for transmogrifying your journal') exporting.add_argument('-s', '--short', dest='short', action="store_true", help='Show only titles or line containing the search tags') @@ -143,7 +144,12 @@ def run(manual_args=None): print(util.py2encode(version_str)) sys.exit(0) - config = install.load_or_install_jrnl() + try: + config = install.load_or_install_jrnl() + except UserAbort as err: + util.prompt("\n{}".format(err)) + sys.exit(1) + if args.ls: util.prnt(list_journals(config)) sys.exit(0) @@ -206,7 +212,11 @@ def run(manual_args=None): mode_compose = False # This is where we finally open the journal! - journal = Journal.open_journal(journal_name, config) + try: + journal = Journal.open_journal(journal_name, config) + except KeyboardInterrupt: + util.prompt("[Interrupted while opening journal]".format(journal_name)) + sys.exit(1) # Import mode if mode_import: @@ -230,7 +240,8 @@ def run(manual_args=None): start_date=args.start_date, end_date=args.end_date, strict=args.strict, short=args.short, - starred=args.starred) + starred=args.starred, + exclude=args.excluded) journal.limit(args.limit) # Reading mode diff --git a/jrnl/install.py b/jrnl/install.py index 7cc8f880..77247508 100644 --- a/jrnl/install.py +++ b/jrnl/install.py @@ -12,8 +12,10 @@ from . import upgrade from . import __version__ from .Journal import PlainJournal from .EncryptedJournal import EncryptedJournal +from .util import UserAbort import yaml import logging +import sys DEFAULT_CONFIG_NAME = 'jrnl.yaml' DEFAULT_JOURNAL_NAME = 'journal.txt' @@ -85,12 +87,26 @@ def load_or_install_jrnl(): if os.path.exists(config_path): log.debug('Reading configuration from file %s', config_path) config = util.load_config(config_path) - upgrade.upgrade_jrnl_if_necessary(config_path) + + try: + upgrade.upgrade_jrnl_if_necessary(config_path) + except upgrade.UpgradeValidationException: + util.prompt("Aborting upgrade.") + util.prompt("Please tell us about this problem at the following URL:") + util.prompt("https://github.com/jrnl-org/jrnl/issues/new?title=UpgradeValidationException") + util.prompt("Exiting.") + sys.exit(1) + upgrade_config(config) + return config else: log.debug('Configuration file not found, installing jrnl...') - return install() + try: + config = install() + except KeyboardInterrupt: + raise UserAbort("Installation aborted") + return config def install(): diff --git a/jrnl/plugins/markdown_exporter.py b/jrnl/plugins/markdown_exporter.py index 147e8ac5..19b5404d 100644 --- a/jrnl/plugins/markdown_exporter.py +++ b/jrnl/plugins/markdown_exporter.py @@ -3,6 +3,7 @@ from __future__ import absolute_import, unicode_literals, print_function from .text_exporter import TextExporter +import os import re import sys from ..util import WARNING_COLOR, RESET_COLOR @@ -30,17 +31,17 @@ class MarkdownExporter(TextExporter): previous_line = '' warn_on_heading_level = False for line in body.splitlines(True): - if re.match(r"#+ ", line): + if re.match(r"^#+ ", line): """ATX style headings""" newbody = newbody + previous_line + heading + line - if re.match(r"#######+ ", heading + line): + if re.match(r"^#######+ ", heading + line): warn_on_heading_level = True line = '' - elif re.match(r"=+$", line) and not re.match(r"^$", previous_line): + elif re.match(r"^=+$", line.rstrip()) and not re.match(r"^$", previous_line.strip()): """Setext style H1""" newbody = newbody + heading + "# " + previous_line line = '' - elif re.match(r"-+$", line) and not re.match(r"^$", previous_line): + elif re.match(r"^-+$", line.rstrip()) and not re.match(r"^$", previous_line.strip()): """Setext style H2""" newbody = newbody + heading + "## " + previous_line line = '' @@ -68,12 +69,12 @@ class MarkdownExporter(TextExporter): for e in journal.entries: if not e.date.year == year: year = e.date.year - out.append(str(year)) - out.append("=" * len(str(year)) + "\n") + out.append("# " + str(year)) + out.append("") if not e.date.month == month: month = e.date.month - out.append(e.date.strftime("%B")) - out.append('-' * len(e.date.strftime("%B")) + "\n") + out.append("## " + e.date.strftime("%B")) + out.append("") out.append(cls.export_entry(e, False)) result = "\n".join(out) return result diff --git a/jrnl/plugins/template.py b/jrnl/plugins/template.py index 0b4c533d..21fb2896 100644 --- a/jrnl/plugins/template.py +++ b/jrnl/plugins/template.py @@ -23,7 +23,7 @@ class Template(object): def from_file(cls, filename): with open(filename) as f: front_matter, body = f.read().strip("-\n").split("---", 2) - front_matter = yaml.load(front_matter) + front_matter = yaml.load(front_matter, Loader=yaml.FullLoader) template = cls(body) template.__dict__.update(front_matter) return template @@ -39,7 +39,8 @@ class Template(object): return self._expand(self.blocks[block], **vars) def _eval_context(self, vars): - e = asteval.Interpreter(symtable=vars, use_numpy=False, writer=None) + e = asteval.Interpreter(use_numpy=False, writer=None) + e.symtable.update(vars) e.symtable['__last_iteration'] = vars.get("__last_iteration", False) return e diff --git a/jrnl/plugins/yaml_exporter.py b/jrnl/plugins/yaml_exporter.py index 1442adcc..c0735811 100644 --- a/jrnl/plugins/yaml_exporter.py +++ b/jrnl/plugins/yaml_exporter.py @@ -3,6 +3,7 @@ from __future__ import absolute_import, unicode_literals, print_function from .text_exporter import TextExporter +import os import re import sys from ..util import WARNING_COLOR, ERROR_COLOR, RESET_COLOR @@ -34,17 +35,17 @@ class YAMLExporter(TextExporter): previous_line = '' warn_on_heading_level = False for line in entry.body.splitlines(True): - if re.match(r"#+ ", line): + if re.match(r"^#+ ", line): """ATX style headings""" newbody = newbody + previous_line + heading + line - if re.match(r"#######+ ", heading + line): + if re.match(r"^#######+ ", heading + line): warn_on_heading_level = True line = '' - elif re.match(r"=+$", line) and not re.match(r"^$", previous_line): + elif re.match(r"^=+$", line.rstrip()) and not re.match(r"^$", previous_line.strip()): """Setext style H1""" newbody = newbody + heading + "# " + previous_line line = '' - elif re.match(r"-+$", line) and not re.match(r"^$", previous_line): + elif re.match(r"^-+$", line.rstrip()) and not re.match(r"^$", previous_line.strip()): """Setext style H2""" newbody = newbody + heading + "## " + previous_line line = '' diff --git a/jrnl/time.py b/jrnl/time.py index 531293de..9ff125aa 100644 --- a/jrnl/time.py +++ b/jrnl/time.py @@ -19,6 +19,10 @@ def parse(date_str, inclusive=False, default_hour=None, default_minute=None): elif isinstance(date_str, datetime): return date_str + # Don't try to parse anything with 6 or less characters. It's probably a markdown footnote + if len(date_str) <= 6: + return None + default_date = DEFAULT_FUTURE if inclusive else DEFAULT_PAST date = None year_present = False diff --git a/jrnl/upgrade.py b/jrnl/upgrade.py index 3784c9f6..f2b80af3 100644 --- a/jrnl/upgrade.py +++ b/jrnl/upgrade.py @@ -4,7 +4,7 @@ from . import __version__ from . import Journal from . import util from .EncryptedJournal import EncryptedJournal -import sys +from .util import UserAbort import os import codecs @@ -44,6 +44,7 @@ older versions of jrnl anymore. encrypted_journals = {} plain_journals = {} other_journals = {} + all_journals = [] for journal_name, journal_conf in config['journals'].items(): if isinstance(journal_conf, dict): @@ -76,28 +77,44 @@ older versions of jrnl anymore. for journal, path in other_journals.items(): util.prompt(" {:{pad}} -> {}".format(journal, path, pad=longest_journal_name)) - cont = util.yesno("\nContinue upgrading jrnl?", default=False) - if not cont: - util.prompt("jrnl NOT upgraded, exiting.") - sys.exit(1) + try: + cont = util.yesno("\nContinue upgrading jrnl?", default=False) + if not cont: + raise KeyboardInterrupt + except KeyboardInterrupt: + raise UserAbort("jrnl NOT upgraded, exiting.") for journal_name, path in encrypted_journals.items(): util.prompt("\nUpgrading encrypted '{}' journal stored in {}...".format(journal_name, path)) backup(path, binary=True) old_journal = Journal.open_journal(journal_name, util.scope_config(config, journal_name), legacy=True) - new_journal = EncryptedJournal.from_journal(old_journal) - new_journal.write() - util.prompt(" Done.") + all_journals.append(EncryptedJournal.from_journal(old_journal)) for journal_name, path in plain_journals.items(): util.prompt("\nUpgrading plain text '{}' journal stored in {}...".format(journal_name, path)) backup(path) old_journal = Journal.open_journal(journal_name, util.scope_config(config, journal_name), legacy=True) - new_journal = Journal.PlainJournal.from_journal(old_journal) - new_journal.write() - util.prompt(" Done.") + all_journals.append(Journal.PlainJournal.from_journal(old_journal)) + + # loop through lists to validate + failed_journals = [j for j in all_journals if not j.validate_parsing()] + + if len(failed_journals) > 0: + util.prompt("\nThe following journal{} failed to upgrade:\n{}".format( + 's' if len(failed_journals) > 1 else '', "\n".join(j.name for j in failed_journals)) + ) + + raise UpgradeValidationException + + # write all journals - or - don't + for j in all_journals: + j.write() util.prompt("\nUpgrading config...") backup(config_path) util.prompt("\nWe're all done here and you can start enjoying jrnl 2.".format(config_path)) + +class UpgradeValidationException(Exception): + """Raised when the contents of an upgraded journal do not match the old journal""" + pass diff --git a/jrnl/util.py b/jrnl/util.py index f6a7735f..bc36ba9b 100644 --- a/jrnl/util.py +++ b/jrnl/util.py @@ -47,6 +47,10 @@ SENTENCE_SPLITTER = re.compile(r""" )""", re.UNICODE | re.VERBOSE) +class UserAbort(Exception): + pass + + def getpass(prompt="Password: "): if not TEST: return gp.getpass(bytes(prompt)) @@ -141,7 +145,7 @@ def load_config(config_path): """Tries to load a config file from YAML. """ with open(config_path) as f: - return yaml.load(f) + return yaml.load(f, Loader=yaml.FullLoader) def scope_config(config, journal_name): @@ -163,7 +167,10 @@ def get_text_from_editor(config, template=""): with codecs.open(tmpfile, 'w', "utf-8") as f: if template: f.write(template) - subprocess.call(shlex.split(config['editor'], posix="win" not in sys.platform) + [tmpfile]) + try: + subprocess.call(shlex.split(config['editor'], posix="win" not in sys.platform) + [tmpfile]) + except AttributeError: + subprocess.call(config['editor'] + [tmpfile]) with codecs.open(tmpfile, "r", "utf-8") as f: raw = f.read() os.close(filehandle) diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 00000000..ed1795d1 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,23 @@ +site_name: jrnl +theme: + name: readthedocs + custom_dir: docs/theme + static_templates: + - index.html +extra_css: + - https://fonts.googleapis.com/css?family=Open+Sans:300,600 + - assets/theme.css + - assets/highlight.css +markdown_extensions: + - admonition +repo_url: https://github.com/jrnl-org/jrnl/ +site_author: Manuel Ebert +site_description: Never Worry about Money Again. +nav: + - Overview: overview.md + - Quickstart: installation.md + - Basic Usage: usage.md + - Encryption: encryption.md + - Import and Export: export.md + - Advanced Usage: advanced.md + - Recipes: recipes.md diff --git a/setup.py b/setup.py index f6097064..1cc8a3c5 100644 --- a/setup.py +++ b/setup.py @@ -83,7 +83,7 @@ setup( "parsedatetime>=1.5", "pytz>=2015.7", "six>=1.10.0", - "cryptography==1.4", + "cryptography>=1.4", "tzlocal>=1.2", "pyyaml>=3.11", "keyring>=7.3", @@ -105,10 +105,7 @@ setup( 'Natural Language :: English', 'Operating System :: OS Independent', 'Programming Language :: Python', - 'Programming Language :: Python :: 2.6', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3.3', - 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.7', 'Topic :: Office/Business :: News/Diary', 'Topic :: Text Processing' ],